From 626d9efa74685720020e816f3a917b7591d3cf7a Mon Sep 17 00:00:00 2001 From: James <> Date: Sat, 26 Sep 2015 12:29:31 +0100 Subject: trunk-47048 --- target/linux/generic/PATCHES | 20 + target/linux/generic/base-files/init | 4 + target/linux/generic/config-3.18 | 4646 ++++++++++++++++++ target/linux/generic/config-4.0 | 4730 ++++++++++++++++++ target/linux/generic/config-4.1 | 4812 ++++++++++++++++++ .../files/Documentation/networking/adm6996.txt | 110 + .../generic/files/arch/mips/fw/myloader/Makefile | 5 + .../generic/files/arch/mips/fw/myloader/myloader.c | 63 + target/linux/generic/files/crypto/ocf/Config.in | 38 + target/linux/generic/files/crypto/ocf/Kconfig | 128 + target/linux/generic/files/crypto/ocf/Makefile | 148 + .../linux/generic/files/crypto/ocf/c7108/Makefile | 12 + .../generic/files/crypto/ocf/c7108/aes-7108.c | 841 ++++ .../generic/files/crypto/ocf/c7108/aes-7108.h | 134 + target/linux/generic/files/crypto/ocf/criov.c | 215 + target/linux/generic/files/crypto/ocf/crypto.c | 1766 +++++++ .../generic/files/crypto/ocf/cryptocteon/Makefile | 17 + .../files/crypto/ocf/cryptocteon/README.txt | 11 + .../files/crypto/ocf/cryptocteon/cavium_crypto.c | 2283 +++++++++ .../files/crypto/ocf/cryptocteon/cryptocteon.c | 576 +++ target/linux/generic/files/crypto/ocf/cryptodev.c | 1069 ++++ target/linux/generic/files/crypto/ocf/cryptodev.h | 480 ++ target/linux/generic/files/crypto/ocf/cryptosoft.c | 1322 +++++ .../generic/files/crypto/ocf/ep80579/Makefile | 119 + .../files/crypto/ocf/ep80579/environment.mk | 78 + .../generic/files/crypto/ocf/ep80579/icp_asym.c | 1334 +++++ .../generic/files/crypto/ocf/ep80579/icp_common.c | 773 +++ .../generic/files/crypto/ocf/ep80579/icp_ocf.h | 376 ++ .../generic/files/crypto/ocf/ep80579/icp_sym.c | 1153 +++++ .../crypto/ocf/ep80579/linux_2.6_kernel_space.mk | 69 + .../linux/generic/files/crypto/ocf/hifn/Makefile | 13 + .../linux/generic/files/crypto/ocf/hifn/hifn7751.c | 2954 +++++++++++ .../generic/files/crypto/ocf/hifn/hifn7751reg.h | 540 ++ .../generic/files/crypto/ocf/hifn/hifn7751var.h | 368 ++ .../linux/generic/files/crypto/ocf/hifn/hifnHIPP.c | 421 ++ .../generic/files/crypto/ocf/hifn/hifnHIPPreg.h | 46 + .../generic/files/crypto/ocf/hifn/hifnHIPPvar.h | 93 + .../linux/generic/files/crypto/ocf/ixp4xx/Makefile | 104 + .../linux/generic/files/crypto/ocf/ixp4xx/ixp4xx.c | 1339 +++++ .../generic/files/crypto/ocf/kirkwood/Makefile | 19 + .../files/crypto/ocf/kirkwood/cesa/AES/mvAes.h | 62 + .../files/crypto/ocf/kirkwood/cesa/AES/mvAesAlg.c | 317 ++ .../files/crypto/ocf/kirkwood/cesa/AES/mvAesAlg.h | 19 + .../files/crypto/ocf/kirkwood/cesa/AES/mvAesApi.c | 312 ++ .../crypto/ocf/kirkwood/cesa/AES/mvAesBoxes.dat | 123 + .../files/crypto/ocf/kirkwood/cesa/mvCesa.c | 3126 ++++++++++++ .../files/crypto/ocf/kirkwood/cesa/mvCesa.h | 412 ++ .../files/crypto/ocf/kirkwood/cesa/mvCesaDebug.c | 484 ++ .../files/crypto/ocf/kirkwood/cesa/mvCesaRegs.h | 357 ++ .../files/crypto/ocf/kirkwood/cesa/mvCesaTest.c | 3096 ++++++++++++ .../files/crypto/ocf/kirkwood/cesa/mvCompVer.txt | 4 + .../generic/files/crypto/ocf/kirkwood/cesa/mvLru.c | 158 + .../generic/files/crypto/ocf/kirkwood/cesa/mvLru.h | 112 + .../generic/files/crypto/ocf/kirkwood/cesa/mvMD5.c | 349 ++ .../generic/files/crypto/ocf/kirkwood/cesa/mvMD5.h | 93 + .../files/crypto/ocf/kirkwood/cesa/mvSHA1.c | 239 + .../files/crypto/ocf/kirkwood/cesa/mvSHA1.h | 88 + .../files/crypto/ocf/kirkwood/cesa_ocf_drv.c | 1302 +++++ .../crypto/ocf/kirkwood/mvHal/common/mv802_3.h | 213 + .../crypto/ocf/kirkwood/mvHal/common/mvCommon.c | 277 ++ .../crypto/ocf/kirkwood/mvHal/common/mvCommon.h | 308 ++ .../crypto/ocf/kirkwood/mvHal/common/mvCompVer.txt | 4 + .../crypto/ocf/kirkwood/mvHal/common/mvDebug.c | 326 ++ .../crypto/ocf/kirkwood/mvHal/common/mvDebug.h | 178 + .../crypto/ocf/kirkwood/mvHal/common/mvDeviceId.h | 225 + .../crypto/ocf/kirkwood/mvHal/common/mvHalVer.h | 73 + .../crypto/ocf/kirkwood/mvHal/common/mvStack.c | 100 + .../crypto/ocf/kirkwood/mvHal/common/mvStack.h | 140 + .../crypto/ocf/kirkwood/mvHal/common/mvTypes.h | 245 + .../files/crypto/ocf/kirkwood/mvHal/dbg-trace.c | 110 + .../files/crypto/ocf/kirkwood/mvHal/dbg-trace.h | 24 + .../mvHal/kw_family/boardEnv/mvBoardEnvLib.c | 2513 ++++++++++ .../mvHal/kw_family/boardEnv/mvBoardEnvLib.h | 376 ++ .../mvHal/kw_family/boardEnv/mvBoardEnvSpec.c | 848 ++++ .../mvHal/kw_family/boardEnv/mvBoardEnvSpec.h | 262 + .../ocf/kirkwood/mvHal/kw_family/cpu/mvCpu.c | 320 ++ .../ocf/kirkwood/mvHal/kw_family/cpu/mvCpu.h | 99 + .../mvHal/kw_family/ctrlEnv/mvCtrlEnvAddrDec.c | 296 ++ .../mvHal/kw_family/ctrlEnv/mvCtrlEnvAddrDec.h | 203 + .../mvHal/kw_family/ctrlEnv/mvCtrlEnvAsm.h | 98 + .../mvHal/kw_family/ctrlEnv/mvCtrlEnvLib.c | 1825 +++++++ .../mvHal/kw_family/ctrlEnv/mvCtrlEnvLib.h | 185 + .../mvHal/kw_family/ctrlEnv/mvCtrlEnvRegs.h | 419 ++ .../mvHal/kw_family/ctrlEnv/mvCtrlEnvSpec.h | 257 + .../mvHal/kw_family/ctrlEnv/sys/mvAhbToMbus.c | 1048 ++++ .../mvHal/kw_family/ctrlEnv/sys/mvAhbToMbus.h | 130 + .../mvHal/kw_family/ctrlEnv/sys/mvAhbToMbusRegs.h | 143 + .../kirkwood/mvHal/kw_family/ctrlEnv/sys/mvCpuIf.c | 1036 ++++ .../kirkwood/mvHal/kw_family/ctrlEnv/sys/mvCpuIf.h | 120 + .../mvHal/kw_family/ctrlEnv/sys/mvCpuIfInit.S | 163 + .../mvHal/kw_family/ctrlEnv/sys/mvCpuIfRegs.h | 304 ++ .../mvHal/kw_family/ctrlEnv/sys/mvSysAudio.c | 324 ++ .../mvHal/kw_family/ctrlEnv/sys/mvSysAudio.h | 123 + .../mvHal/kw_family/ctrlEnv/sys/mvSysCesa.c | 382 ++ .../mvHal/kw_family/ctrlEnv/sys/mvSysCesa.h | 100 + .../mvHal/kw_family/ctrlEnv/sys/mvSysDram.c | 348 ++ .../mvHal/kw_family/ctrlEnv/sys/mvSysDram.h | 80 + .../mvHal/kw_family/ctrlEnv/sys/mvSysGbe.c | 658 +++ .../mvHal/kw_family/ctrlEnv/sys/mvSysGbe.h | 113 + .../mvHal/kw_family/ctrlEnv/sys/mvSysPex.c | 1697 +++++++ .../mvHal/kw_family/ctrlEnv/sys/mvSysPex.h | 348 ++ .../mvHal/kw_family/ctrlEnv/sys/mvSysSata.c | 430 ++ .../mvHal/kw_family/ctrlEnv/sys/mvSysSata.h | 128 + .../mvHal/kw_family/ctrlEnv/sys/mvSysSdmmc.c | 427 ++ .../mvHal/kw_family/ctrlEnv/sys/mvSysSdmmc.h | 125 + .../mvHal/kw_family/ctrlEnv/sys/mvSysTdm.c | 462 ++ .../mvHal/kw_family/ctrlEnv/sys/mvSysTdm.h | 106 + .../kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysTs.c | 591 +++ .../kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysTs.h | 110 + .../mvHal/kw_family/ctrlEnv/sys/mvSysUsb.c | 497 ++ .../mvHal/kw_family/ctrlEnv/sys/mvSysUsb.h | 125 + .../mvHal/kw_family/ctrlEnv/sys/mvSysXor.c | 662 +++ .../mvHal/kw_family/ctrlEnv/sys/mvSysXor.h | 140 + .../ocf/kirkwood/mvHal/kw_family/device/mvDevice.c | 75 + .../ocf/kirkwood/mvHal/kw_family/device/mvDevice.h | 74 + .../kirkwood/mvHal/kw_family/device/mvDeviceRegs.h | 101 + .../ocf/kirkwood/mvHal/kw_family/mvCompVer.txt | 4 + .../crypto/ocf/kirkwood/mvHal/linux_oss/mvOs.c | 211 + .../crypto/ocf/kirkwood/mvHal/linux_oss/mvOs.h | 423 ++ .../crypto/ocf/kirkwood/mvHal/linux_oss/mvOsSata.h | 158 + .../crypto/ocf/kirkwood/mvHal/mvSysHwConfig.h | 375 ++ .../ocf/kirkwood/mvHal/mv_hal/cntmr/mvCntmr.c | 376 ++ .../ocf/kirkwood/mvHal/mv_hal/cntmr/mvCntmr.h | 121 + .../ocf/kirkwood/mvHal/mv_hal/cntmr/mvCntmrRegs.h | 121 + .../ocf/kirkwood/mvHal/mv_hal/cntmr/mvCompVer.txt | 4 + .../ocf/kirkwood/mvHal/mv_hal/cpu/mvCpuCntrs.c | 207 + .../ocf/kirkwood/mvHal/mv_hal/cpu/mvCpuCntrs.h | 213 + .../ocf/kirkwood/mvHal/mv_hal/cpu/mvCpuL2Cntrs.c | 143 + .../ocf/kirkwood/mvHal/mv_hal/cpu/mvCpuL2Cntrs.h | 151 + .../ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvCompVer.txt | 4 + .../ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvDram.c | 1479 ++++++ .../ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvDram.h | 191 + .../ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvDramIf.c | 1599 ++++++ .../ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvDramIf.h | 179 + .../mvHal/mv_hal/ddr1_2/mvDramIfBasicInit.S | 988 ++++ .../kirkwood/mvHal/mv_hal/ddr1_2/mvDramIfConfig.S | 668 +++ .../kirkwood/mvHal/mv_hal/ddr1_2/mvDramIfConfig.h | 192 + .../kirkwood/mvHal/mv_hal/ddr1_2/mvDramIfRegs.h | 306 ++ .../ocf/kirkwood/mvHal/mv_hal/ddr2/mvCompVer.txt | 4 + .../ocf/kirkwood/mvHal/mv_hal/ddr2/mvDramIf.c | 1855 +++++++ .../ocf/kirkwood/mvHal/mv_hal/ddr2/mvDramIf.h | 172 + .../kirkwood/mvHal/mv_hal/ddr2/mvDramIfBasicInit.S | 986 ++++ .../kirkwood/mvHal/mv_hal/ddr2/mvDramIfConfig.S | 528 ++ .../kirkwood/mvHal/mv_hal/ddr2/mvDramIfConfig.h | 157 + .../ocf/kirkwood/mvHal/mv_hal/ddr2/mvDramIfRegs.h | 423 ++ .../mvHal/mv_hal/ddr2/mvDramIfStaticInit.h | 179 + .../ocf/kirkwood/mvHal/mv_hal/ddr2/spd/mvSpd.c | 1474 ++++++ .../ocf/kirkwood/mvHal/mv_hal/ddr2/spd/mvSpd.h | 192 + .../ocf/kirkwood/mvHal/mv_hal/eth/gbe/mvEth.c | 2952 +++++++++++ .../ocf/kirkwood/mvHal/mv_hal/eth/gbe/mvEthDebug.c | 748 +++ .../ocf/kirkwood/mvHal/mv_hal/eth/gbe/mvEthDebug.h | 146 + .../ocf/kirkwood/mvHal/mv_hal/eth/gbe/mvEthGbe.h | 751 +++ .../ocf/kirkwood/mvHal/mv_hal/eth/gbe/mvEthRegs.h | 700 +++ .../ocf/kirkwood/mvHal/mv_hal/eth/mvCompVer.txt | 4 + .../crypto/ocf/kirkwood/mvHal/mv_hal/eth/mvEth.h | 356 ++ .../ocf/kirkwood/mvHal/mv_hal/gpp/mvCompVer.txt | 4 + .../crypto/ocf/kirkwood/mvHal/mv_hal/gpp/mvGpp.c | 362 ++ .../crypto/ocf/kirkwood/mvHal/mv_hal/gpp/mvGpp.h | 118 + .../ocf/kirkwood/mvHal/mv_hal/gpp/mvGppRegs.h | 116 + .../ocf/kirkwood/mvHal/mv_hal/pci-if/mvCompVer.txt | 4 + .../ocf/kirkwood/mvHal/mv_hal/pci-if/mvPciIf.c | 669 +++ .../ocf/kirkwood/mvHal/mv_hal/pci-if/mvPciIf.h | 134 + .../ocf/kirkwood/mvHal/mv_hal/pci-if/mvPciIfRegs.h | 245 + .../mvHal/mv_hal/pci-if/pci_util/mvPciUtils.c | 1006 ++++ .../mvHal/mv_hal/pci-if/pci_util/mvPciUtils.h | 323 ++ .../ocf/kirkwood/mvHal/mv_hal/pci/mvCompVer.txt | 4 + .../crypto/ocf/kirkwood/mvHal/mv_hal/pci/mvPci.c | 1047 ++++ .../crypto/ocf/kirkwood/mvHal/mv_hal/pci/mvPci.h | 185 + .../ocf/kirkwood/mvHal/mv_hal/pci/mvPciRegs.h | 411 ++ .../ocf/kirkwood/mvHal/mv_hal/pex/mvCompVer.txt | 4 + .../crypto/ocf/kirkwood/mvHal/mv_hal/pex/mvPex.c | 1143 +++++ .../crypto/ocf/kirkwood/mvHal/mv_hal/pex/mvPex.h | 168 + .../ocf/kirkwood/mvHal/mv_hal/pex/mvPexRegs.h | 751 +++ .../ocf/kirkwood/mvHal/mv_hal/pex/mvVrtBrgPex.c | 313 ++ .../ocf/kirkwood/mvHal/mv_hal/pex/mvVrtBrgPex.h | 82 + .../ocf/kirkwood/mvHal/mv_hal/sflash/mvCompVer.txt | 4 + .../ocf/kirkwood/mvHal/mv_hal/sflash/mvSFlash.c | 1522 ++++++ .../ocf/kirkwood/mvHal/mv_hal/sflash/mvSFlash.h | 166 + .../kirkwood/mvHal/mv_hal/sflash/mvSFlashSpec.h | 233 + .../ocf/kirkwood/mvHal/mv_hal/spi/mvCompVer.txt | 4 + .../crypto/ocf/kirkwood/mvHal/mv_hal/spi/mvSpi.c | 576 +++ .../crypto/ocf/kirkwood/mvHal/mv_hal/spi/mvSpi.h | 94 + .../ocf/kirkwood/mvHal/mv_hal/spi/mvSpiCmnd.c | 249 + .../ocf/kirkwood/mvHal/mv_hal/spi/mvSpiCmnd.h | 82 + .../ocf/kirkwood/mvHal/mv_hal/spi/mvSpiSpec.h | 98 + .../ocf/kirkwood/mvHal/mv_hal/twsi/mvCompVer.txt | 4 + .../crypto/ocf/kirkwood/mvHal/mv_hal/twsi/mvTwsi.c | 1023 ++++ .../crypto/ocf/kirkwood/mvHal/mv_hal/twsi/mvTwsi.h | 121 + .../ocf/kirkwood/mvHal/mv_hal/twsi/mvTwsiEeprom.S | 457 ++ .../ocf/kirkwood/mvHal/mv_hal/twsi/mvTwsiSpec.h | 160 + target/linux/generic/files/crypto/ocf/ocf-bench.c | 514 ++ target/linux/generic/files/crypto/ocf/ocf-compat.h | 380 ++ .../generic/files/crypto/ocf/ocfnull/Makefile | 12 + .../generic/files/crypto/ocf/ocfnull/ocfnull.c | 204 + .../linux/generic/files/crypto/ocf/pasemi/Makefile | 12 + .../linux/generic/files/crypto/ocf/pasemi/pasemi.c | 1007 ++++ .../generic/files/crypto/ocf/pasemi/pasemi_fnu.h | 410 ++ target/linux/generic/files/crypto/ocf/random.c | 317 ++ target/linux/generic/files/crypto/ocf/rndtest.c | 300 ++ target/linux/generic/files/crypto/ocf/rndtest.h | 54 + .../linux/generic/files/crypto/ocf/safe/Makefile | 12 + .../linux/generic/files/crypto/ocf/safe/hmachack.h | 37 + target/linux/generic/files/crypto/ocf/safe/md5.c | 308 ++ target/linux/generic/files/crypto/ocf/safe/md5.h | 76 + target/linux/generic/files/crypto/ocf/safe/safe.c | 2230 +++++++++ .../linux/generic/files/crypto/ocf/safe/safereg.h | 421 ++ .../linux/generic/files/crypto/ocf/safe/safevar.h | 229 + target/linux/generic/files/crypto/ocf/safe/sha1.c | 279 ++ target/linux/generic/files/crypto/ocf/safe/sha1.h | 72 + .../generic/files/crypto/ocf/talitos/Makefile | 12 + .../generic/files/crypto/ocf/talitos/talitos.c | 1355 ++++++ .../generic/files/crypto/ocf/talitos/talitos_dev.h | 277 ++ .../files/crypto/ocf/talitos/talitos_soft.h | 76 + .../generic/files/crypto/ocf/ubsec_ssb/Makefile | 12 + .../generic/files/crypto/ocf/ubsec_ssb/bsdqueue.h | 527 ++ .../generic/files/crypto/ocf/ubsec_ssb/ubsec_ssb.c | 2220 +++++++++ .../generic/files/crypto/ocf/ubsec_ssb/ubsecreg.h | 233 + .../generic/files/crypto/ocf/ubsec_ssb/ubsecvar.h | 228 + target/linux/generic/files/crypto/ocf/uio.h | 54 + .../generic/files/drivers/leds/ledtrig-morse.c | 366 ++ .../generic/files/drivers/leds/ledtrig-netdev.c | 438 ++ .../generic/files/drivers/leds/ledtrig-usbdev.c | 348 ++ .../generic/files/drivers/mtd/mtdsplit/Kconfig | 51 + .../generic/files/drivers/mtd/mtdsplit/Makefile | 8 + .../generic/files/drivers/mtd/mtdsplit/mtdsplit.c | 116 + .../generic/files/drivers/mtd/mtdsplit/mtdsplit.h | 55 + .../files/drivers/mtd/mtdsplit/mtdsplit_fit.c | 140 + .../files/drivers/mtd/mtdsplit/mtdsplit_lzma.c | 96 + .../files/drivers/mtd/mtdsplit/mtdsplit_seama.c | 103 + .../files/drivers/mtd/mtdsplit/mtdsplit_squashfs.c | 72 + .../files/drivers/mtd/mtdsplit/mtdsplit_tplink.c | 169 + .../files/drivers/mtd/mtdsplit/mtdsplit_trx.c | 147 + .../files/drivers/mtd/mtdsplit/mtdsplit_uimage.c | 361 ++ target/linux/generic/files/drivers/mtd/myloader.c | 182 + .../linux/generic/files/drivers/net/phy/adm6996.c | 1204 +++++ .../linux/generic/files/drivers/net/phy/adm6996.h | 186 + .../linux/generic/files/drivers/net/phy/ar8216.c | 2197 +++++++++ .../linux/generic/files/drivers/net/phy/ar8216.h | 628 +++ .../linux/generic/files/drivers/net/phy/ar8327.c | 1268 +++++ .../linux/generic/files/drivers/net/phy/ar8327.h | 252 + .../generic/files/drivers/net/phy/b53/Kconfig | 37 + .../generic/files/drivers/net/phy/b53/Makefile | 10 + .../generic/files/drivers/net/phy/b53/b53_common.c | 1457 ++++++ .../generic/files/drivers/net/phy/b53/b53_mdio.c | 425 ++ .../generic/files/drivers/net/phy/b53/b53_mmap.c | 241 + .../files/drivers/net/phy/b53/b53_phy_fixup.c | 55 + .../generic/files/drivers/net/phy/b53/b53_priv.h | 329 ++ .../generic/files/drivers/net/phy/b53/b53_regs.h | 347 ++ .../generic/files/drivers/net/phy/b53/b53_spi.c | 330 ++ .../generic/files/drivers/net/phy/b53/b53_srab.c | 378 ++ .../linux/generic/files/drivers/net/phy/ip17xx.c | 1410 ++++++ .../linux/generic/files/drivers/net/phy/mvsw61xx.c | 854 ++++ .../linux/generic/files/drivers/net/phy/mvsw61xx.h | 266 + .../linux/generic/files/drivers/net/phy/mvswitch.c | 433 ++ .../linux/generic/files/drivers/net/phy/mvswitch.h | 145 + .../linux/generic/files/drivers/net/phy/psb6970.c | 438 ++ .../linux/generic/files/drivers/net/phy/rtl8306.c | 1060 ++++ .../generic/files/drivers/net/phy/rtl8366_smi.c | 1449 ++++++ .../generic/files/drivers/net/phy/rtl8366_smi.h | 152 + .../generic/files/drivers/net/phy/rtl8366rb.c | 1496 ++++++ .../linux/generic/files/drivers/net/phy/rtl8366s.c | 1148 +++++ .../linux/generic/files/drivers/net/phy/rtl8367.c | 1835 +++++++ .../linux/generic/files/drivers/net/phy/rtl8367b.c | 1602 ++++++ .../linux/generic/files/drivers/net/phy/swconfig.c | 1153 +++++ .../generic/files/drivers/net/phy/swconfig_leds.c | 354 ++ target/linux/generic/files/fs/yaffs2/Kconfig | 171 + target/linux/generic/files/fs/yaffs2/Makefile | 18 + target/linux/generic/files/fs/yaffs2/NOTE.openwrt | 4 + .../generic/files/fs/yaffs2/yaffs_allocator.c | 357 ++ .../generic/files/fs/yaffs2/yaffs_allocator.h | 30 + .../linux/generic/files/fs/yaffs2/yaffs_attribs.c | 132 + .../linux/generic/files/fs/yaffs2/yaffs_attribs.h | 28 + .../linux/generic/files/fs/yaffs2/yaffs_bitmap.c | 97 + .../linux/generic/files/fs/yaffs2/yaffs_bitmap.h | 33 + .../generic/files/fs/yaffs2/yaffs_checkptrw.c | 466 ++ .../generic/files/fs/yaffs2/yaffs_checkptrw.h | 33 + target/linux/generic/files/fs/yaffs2/yaffs_ecc.c | 281 ++ target/linux/generic/files/fs/yaffs2/yaffs_ecc.h | 44 + .../generic/files/fs/yaffs2/yaffs_getblockinfo.h | 35 + target/linux/generic/files/fs/yaffs2/yaffs_guts.c | 5140 +++++++++++++++++++ target/linux/generic/files/fs/yaffs2/yaffs_guts.h | 1010 ++++ target/linux/generic/files/fs/yaffs2/yaffs_linux.h | 48 + target/linux/generic/files/fs/yaffs2/yaffs_mtdif.c | 310 ++ target/linux/generic/files/fs/yaffs2/yaffs_mtdif.h | 25 + .../linux/generic/files/fs/yaffs2/yaffs_nameval.c | 208 + .../linux/generic/files/fs/yaffs2/yaffs_nameval.h | 28 + target/linux/generic/files/fs/yaffs2/yaffs_nand.c | 122 + target/linux/generic/files/fs/yaffs2/yaffs_nand.h | 39 + .../generic/files/fs/yaffs2/yaffs_packedtags1.c | 56 + .../generic/files/fs/yaffs2/yaffs_packedtags1.h | 39 + .../generic/files/fs/yaffs2/yaffs_packedtags2.c | 197 + .../generic/files/fs/yaffs2/yaffs_packedtags2.h | 47 + .../linux/generic/files/fs/yaffs2/yaffs_summary.c | 312 ++ .../linux/generic/files/fs/yaffs2/yaffs_summary.h | 37 + .../generic/files/fs/yaffs2/yaffs_tagscompat.c | 381 ++ .../generic/files/fs/yaffs2/yaffs_tagscompat.h | 44 + .../generic/files/fs/yaffs2/yaffs_tagsmarshall.c | 199 + .../generic/files/fs/yaffs2/yaffs_tagsmarshall.h | 22 + target/linux/generic/files/fs/yaffs2/yaffs_trace.h | 57 + .../linux/generic/files/fs/yaffs2/yaffs_verify.c | 529 ++ .../linux/generic/files/fs/yaffs2/yaffs_verify.h | 43 + target/linux/generic/files/fs/yaffs2/yaffs_vfs.c | 3665 ++++++++++++++ .../linux/generic/files/fs/yaffs2/yaffs_yaffs1.c | 422 ++ .../linux/generic/files/fs/yaffs2/yaffs_yaffs1.h | 22 + .../linux/generic/files/fs/yaffs2/yaffs_yaffs2.c | 1532 ++++++ .../linux/generic/files/fs/yaffs2/yaffs_yaffs2.h | 39 + target/linux/generic/files/fs/yaffs2/yportenv.h | 85 + .../generic/files/include/linux/ar8216_platform.h | 133 + .../generic/files/include/linux/ath5k_platform.h | 30 + .../generic/files/include/linux/ath9k_platform.h | 49 + .../linux/generic/files/include/linux/myloader.h | 121 + .../include/linux/platform_data/adm6996-gpio.h | 30 + .../files/include/linux/platform_data/b53.h | 36 + .../include/linux/platform_data/brcmfmac-sdio.h | 124 + .../linux/generic/files/include/linux/routerboot.h | 106 + .../generic/files/include/linux/rt2x00_platform.h | 24 + target/linux/generic/files/include/linux/rtl8366.h | 40 + target/linux/generic/files/include/linux/rtl8367.h | 60 + target/linux/generic/files/include/linux/switch.h | 169 + .../generic/files/include/uapi/linux/switch.h | 103 + target/linux/generic/image/Makefile | 12 + .../linux/generic/image/initramfs-base-files.txt | 9 + target/linux/generic/image/lzma-loader/Makefile | 46 + .../generic/image/lzma-loader/src/LzmaDecode.c | 590 +++ .../generic/image/lzma-loader/src/LzmaDecode.h | 131 + .../linux/generic/image/lzma-loader/src/Makefile | 68 + .../generic/image/lzma-loader/src/decompress.c | 157 + .../generic/image/lzma-loader/src/lzma-copy.lds.in | 20 + .../generic/image/lzma-loader/src/lzma.lds.in | 24 + target/linux/generic/image/lzma-loader/src/print.c | 324 ++ target/linux/generic/image/lzma-loader/src/print.h | 36 + .../linux/generic/image/lzma-loader/src/printf.c | 35 + .../linux/generic/image/lzma-loader/src/printf.h | 18 + target/linux/generic/image/lzma-loader/src/start.S | 160 + .../generic/image/lzma-loader/src/uart16550.c | 86 + .../generic/image/lzma-loader/src/uart16550.h | 47 + target/linux/generic/image/relocate/Makefile | 74 + target/linux/generic/image/relocate/cacheops.h | 85 + target/linux/generic/image/relocate/cp0regdef.h | 39 + target/linux/generic/image/relocate/head.S | 159 + target/linux/generic/image/relocate/loader.lds | 16 + .../000-keep_initrafs_the_default.patch | 25 + .../generic/patches-3.18/020-ssb_update.patch | 134 + .../linux/generic/patches-3.18/021-ssb_sprom.patch | 32 + .../generic/patches-3.18/025-bcma_backport.patch | 286 ++ .../generic/patches-3.18/026-bcma-from-3.20.patch | 527 ++ .../generic/patches-3.18/027-bcma-from-4.1.patch | 680 +++ .../generic/patches-3.18/028-bcma-from-4.2.patch | 86 + ...nl80211-Allow-set-network-namespace-by-fd.patch | 21 + .../040-mtd-bcm47xxpart-backports-from-3.19.patch | 50 + .../041-mtd-bcm47xxpart-backports-from-3.20.patch | 95 + .../050-backport_netfilter_rtcache.patch | 509 ++ ...w-setting-hash_max-multicast_router-if-in.patch | 99 + .../060-mips_decompressor_memmove.patch | 22 + ...070-bgmac-register-napi-before-the-device.patch | 44 + ...ate-irqs-only-if-there-is-nothing-to-poll.patch | 30 + ...evice-initialization-on-Northstar-SoCs-co.patch | 40 + .../073-bgmac-Clean-warning-messages.patch | 50 + ...ter-fixed-PHY-for-ARM-BCM470X-BCM5301X-ch.patch | 76 + ...75-bgmac-allow-enabling-on-ARCH_BCM_5301X.patch | 28 + .../076-net-phy-export-fixed_phy_register.patch | 30 + ...ix-descriptor-frame-start-end-definitions.patch | 24 + ...-02-bgmac-implement-GRO-and-use-build_skb.patch | 189 + ...03-bgmac-implement-scatter-gather-support.patch | 267 + ...-04-bgmac-simplify-tx-ring-index-handling.patch | 125 + ...-interrupts-disabled-as-long-as-there-is-.patch | 87 + ...-set-received-skb-headroom-to-NET_SKB_PAD.patch | 66 + ...7-07-bgmac-simplify-rx-DMA-error-handling.patch | 130 + ...-08-bgmac-add-check-for-oversized-packets.patch | 27 + ...mac-increase-rx-ring-size-from-511-to-512.patch | 23 + .../077-10-bgmac-simplify-dma-init-cleanup.patch | 184 + .../077-11-bgmac-fix-DMA-rx-corruption.patch | 88 + .../077-12-bgmac-drop-ring-num_slots.patch | 132 + ...gmac-fix-MAC-soft-reset-bit-for-corerev-4.patch | 24 + ...7-14-bgmac-reset-all-4-GMAC-cores-on-init.patch | 28 + ...x-proc-net-fib_trie-when-CONFIG_IP_MULTIP.patch | 46 + ...x-trie-balancing-issue-if-new-node-pushes.patch | 72 + ...date-usage-stats-to-be-percpu-instead-of-.patch | 200 + ...fib_trie-Make-leaf-and-tnode-more-uniform.patch | 421 ++ ...rge-tnode_free-and-leaf_free-into-node_fr.patch | 209 + .../080-05-fib_trie-Merge-leaf-into-tnode.patch | 928 ++++ ...timize-fib_table_lookup-to-avoid-wasting-.patch | 343 ++ .../080-07-fib_trie-Optimize-fib_find_node.patch | 64 + ...080-08-fib_trie-Optimize-fib_table_insert.patch | 276 ++ ...date-meaning-of-pos-to-represent-unchecke.patch | 346 ++ ...e-unsigned-long-for-anything-dealing-with.patch | 186 + ...trie-Push-rcu_read_lock-unlock-to-callers.patch | 403 ++ ...b_trie-Move-resize-to-after-inflate-halve.patch | 345 ++ ...d-functions-should_inflate-and-should_hal.patch | 250 + ...sh-assignment-of-child-to-parent-down-int.patch | 336 ++ ...Push-tnode-flushing-down-to-inflate-halve.patch | 237 + ...flate-halve-nodes-in-a-more-RCU-friendly-.patch | 345 ++ ...move-checks-for-index-tnode_child_length-.patch | 95 + ...trie-Add-tracking-value-for-suffix-length.patch | 234 + ...e-index-0ul-n-bits-instead-of-index-n-bit.patch | 52 + ...x-RCU-bug-and-merge-similar-bits-of-infla.patch | 267 + ...ll-back-to-slen-update-on-inflate-halve-f.patch | 61 + ...dd-collapse-and-should_collapse-to-resize.patch | 206 + ...e-empty_children-instead-of-counting-empt.patch | 34 + ...ve-fib_find_alias-to-file-where-it-is-use.patch | 79 + ..._trie-Various-clean-ups-for-handling-slen.patch | 116 + ...orkqueue-to-die-properly-when-a-PADT-is-r.patch | 89 + ..._fragment-fix-headroom-tests-and-skb-leak.patch | 101 + ...pci-Increase-headroom-on-received-packets.patch | 54 + ...-overlayfs-fallback-to-readonly-when-full.patch | 109 + .../091-mtd-spi-nor-add-support-Spansion_S25FL164K | 10 + ...o-see-if-the-device-is-processing-a-messa.patch | 47 + ...ansfers-inside-calling-context-for-spi_sy.patch | 184 + ...le-the-message-pump-in-the-worker-kthread.patch | 83 + ...patibility-of-linux-in.h-with-netinet-in..patch | 146 + ..._freeing_init-new-hook-for-archs-before-m.patch | 182 + ...op-pppoe-device-in-pppoe_unbind_sock_work.patch | 27 + .../101-pppoe-fix-disconnect-crash.patch | 16 + .../patches-3.18/102-ehci_hcd_ignore_oc.patch | 82 + ...-.rename2-and-add-RENAME_WHITEOUT-support.patch | 86 + .../111-jffs2-add-RENAME_EXCHANGE-support.patch | 58 + ...-bridge_allow_receiption_on_disabled_port.patch | 54 + .../patches-3.18/132-mips_inline_dma_ops.patch | 688 +++ ...t-add-generic-parsing-of-linux-part-probe.patch | 175 + ...sb-xhci-make-USB_XHCI_PLATFORM-selectable.patch | 41 + ...upport_for_moving_ndp_to_end_of_ncm_frame.patch | 228 + ...-usb-ehci-orion-fix-probe-for-GENERIC_PHY.patch | 35 + .../patches-3.18/200-fix_localversion.patch | 11 + .../patches-3.18/201-extra_optimization.patch | 14 + .../patches-3.18/202-reduce_module_size.patch | 11 + .../patches-3.18/203-kallsyms_uncompressed.patch | 108 + .../generic/patches-3.18/204-module_strip.patch | 194 + .../patches-3.18/205-backtrace_module_info.patch | 36 + .../patches-3.18/210-darwin_scripts_include.patch | 3088 ++++++++++++ .../patches-3.18/212-byteshift_portability.patch | 51 + .../patches-3.18/213-x86_vdso_portability.patch | 13 + .../patches-3.18/214-spidev_h_portability.patch | 11 + .../generic/patches-3.18/220-gc_sections.patch | 531 ++ .../generic/patches-3.18/221-module_exports.patch | 88 + .../patches-3.18/230-openwrt_lzma_options.patch | 58 + .../patches-3.18/250-netfilter_depends.patch | 18 + .../generic/patches-3.18/251-sound_kconfig.patch | 18 + .../generic/patches-3.18/252-mv_cesa_depends.patch | 10 + .../patches-3.18/253-ssb_b43_default_on.patch | 29 + .../254-textsearch_kconfig_hacks.patch | 23 + .../patches-3.18/255-lib80211_kconfig_hacks.patch | 31 + .../256-crypto_add_kconfig_prompts.patch | 47 + .../257-wireless_ext_kconfig_hack.patch | 22 + .../258-netfilter_netlink_kconfig_hack.patch | 11 + .../generic/patches-3.18/259-regmap_dynamic.patch | 80 + .../260-crypto_test_dependencies.patch | 37 + .../patches-3.18/262-compressor_kconfig_hack.patch | 35 + ...l.h-glibc-specific-inclusion-of-sysinfo.h.patch | 34 + ...pi-libc-compat.h-do-not-rely-on-__GLIBC__.patch | 81 + ...er.h-prevent-redefinition-of-struct-ethhd.patch | 67 + .../patches-3.18/300-mips_expose_boot_raw.patch | 39 + .../patches-3.18/301-mips_image_cmdline_hack.patch | 28 + .../patches-3.18/302-mips_no_branch_likely.patch | 11 + .../patches-3.18/304-mips_disable_fpu.patch | 105 + .../patches-3.18/305-mips_module_reloc.patch | 353 ++ .../306-mips_mem_functions_performance.patch | 83 + .../patches-3.18/307-mips_highmem_offset.patch | 17 + .../patches-3.18/309-mips_fuse_workaround.patch | 32 + .../310-arm_module_unresolved_weak_sym.patch | 13 + .../patches-3.18/320-ppc4xx_optimization.patch | 31 + .../321-powerpc_crtsavres_prereq.patch | 10 + ...Accept-command-line-parameters-from-users.patch | 298 ++ .../400-mtd-add-rootfs-split-support.patch | 171 + ...port-for-different-partition-parser-types.patch | 113 + ...mtd-parsers-for-rootfs-and-firmware-split.patch | 72 + .../403-mtd-hook-mtdsplit-to-Kbuild.patch | 22 + .../404-mtd-add-more-helper-functions.patch | 101 + .../405-mtd-old-firmware-uimage-splitter.patch | 70 + .../406-mtd-old-rootfs-squashfs-splitter.patch | 76 + ...ve-forward-declaration-of-struct-mtd_info.patch | 18 + .../411-mtd-partial_eraseblock_write.patch | 142 + .../412-mtd-partial_eraseblock_unlock.patch | 18 + .../patches-3.18/420-mtd-redboot_space.patch | 30 + .../430-mtd-add-myloader-partition-parser.patch | 35 + ...part-support-for-Xiaomi-specific-board_da.patch | 34 + ...-mtd-bcm47xxpart-detect-T_Meter-partition.patch | 42 + .../generic/patches-3.18/440-block2mtd_init.patch | 107 + .../generic/patches-3.18/441-block2mtd_probe.patch | 110 + ...allow-to-use-platform-specific-chip-fixup.patch | 37 + ...return-code-of-nand_correct_data-function.patch | 11 + .../460-mtd-cfi_cmdset_0002-no-erase_suspend.patch | 11 + ..._cmdset_0002-add-buffer-write-cmd-timeout.patch | 18 + ...5p80-add-support-for-Winbond-W25X05-flash.patch | 20 + ...-add-support-for-the-Macronix-MX25L512E-S.patch | 21 + ...-add-support-for-the-ISSI-SI25CD512-SPI-f.patch | 22 + .../480-mtd-set-rootfs-to-be-root-dev.patch | 26 + ...tach-mtd-device-named-ubi-or-data-on-boot.patch | 76 + ...bi-auto-create-ubiblock-device-for-rootfs.patch | 69 + ...-mounting-ubi0-rootfs-in-init-do_mounts.c.patch | 53 + ...-set-ROOT_DEV-to-ubiblock-rootfs-if-unset.patch | 37 + .../494-mtd-ubi-add-EOF-marker-support.patch | 51 + .../500-yaffs-Kbuild-integration.patch | 18 + .../502-yaffs-fix-compat-tags-handling.patch | 239 + .../503-yaffs-add-tags-9bytes-mount-option.patch | 115 + .../patches-3.18/504-yaffs-3.16-new-fops.patch | 25 + .../520-squashfs_update_xz_comp_opts.patch | 25 + .../530-jffs2_make_lzma_available.patch | 5142 ++++++++++++++++++++ .../generic/patches-3.18/531-debloat_lzma.patch | 1024 ++++ .../generic/patches-3.18/532-jffs2_eofdetect.patch | 56 + .../540-crypto-xz-decompression-support.patch | 146 + .../541-ubifs-xz-decompression-support.patch | 92 + .../550-ubifs-symlink-xattr-support.patch | 55 + ...1-ubifs-fix-default-compression-selection.patch | 29 + .../600-netfilter_conntrack_flush.patch | 86 + ...610-netfilter_match_bypass_default_checks.patch | 93 + .../611-netfilter_match_bypass_default_table.patch | 94 + .../612-netfilter_match_reduce_memory_access.patch | 16 + .../613-netfilter_optional_tcp_window_check.patch | 36 + .../615-netfilter_add_xt_id_match.patch | 95 + .../patches-3.18/616-net_optimize_xfrm_calls.patch | 12 + .../generic/patches-3.18/620-sched_esfq.patch | 791 +++ .../patches-3.18/621-sched_act_connmark.patch | 161 + .../patches-3.18/630-packet_socket_type.patch | 134 + .../patches-3.18/640-bridge_no_eap_forward.patch | 23 + .../641-bridge_always_accept_eap.patch | 17 + .../patches-3.18/642-bridge_port_isolate.patch | 107 + .../643-bridge_remove_ipv6_dependency.patch | 123 + .../645-bridge_multicast_to_unicast.patch | 390 ++ .../patches-3.18/650-pppoe_header_pad.patch | 20 + .../patches-3.18/651-wireless_mesh_header.patch | 11 + .../patches-3.18/653-disable_netlink_trim.patch | 30 + .../patches-3.18/655-increase_skb_pad.patch | 11 + .../656-skb_reduce_truesize-helper.patch | 41 + .../patches-3.18/657-qdisc_reduce_truesize.patch | 63 + .../patches-3.18/660-fq_codel_defaults.patch | 14 + .../661-fq_codel_keep_dropped_stats.patch | 10 + .../patches-3.18/662-use_fq_codel_by_default.patch | 95 + .../patches-3.18/663-remove_pfifo_fast.patch | 143 + .../666-Add-support-for-MAP-E-FMRs-mesh-mode.patch | 481 ++ ...ed-source-specific-default-route-handling.patch | 96 + ...jecting-with-source-address-failed-policy.patch | 249 + ...-defines-for-_POLICY_FAILED-until-all-cod.patch | 53 + ...80-NET-skip-GRO-for-foreign-MAC-addresses.patch | 160 + .../681-NET-add-of_get_mac_address_mtd.patch | 88 + .../linux/generic/patches-3.18/700-swconfig.patch | 39 + .../generic/patches-3.18/701-phy_extension.patch | 63 + .../702-phy_add_aneg_done_function.patch | 27 + ...-add-detach-callback-to-struct-phy_driver.patch | 27 + .../704-phy-no-genphy-soft-reset.patch | 29 + .../710-phy-add-mdio_register_board_info.patch | 192 + .../generic/patches-3.18/720-phy_adm6996.patch | 26 + .../generic/patches-3.18/721-phy_packets.patch | 161 + .../generic/patches-3.18/722-phy_mvswitch.patch | 23 + .../generic/patches-3.18/723-phy_ip175c.patch | 23 + .../generic/patches-3.18/724-phy_ar8216.patch | 24 + .../generic/patches-3.18/725-phy_rtl8306.patch | 23 + .../generic/patches-3.18/726-phy_rtl8366.patch | 45 + .../generic/patches-3.18/727-phy-rtl8367.patch | 23 + .../generic/patches-3.18/728-phy-rtl8367b.patch | 23 + .../generic/patches-3.18/729-phy-tantos.patch | 21 + .../linux/generic/patches-3.18/730-phy_b53.patch | 21 + .../731-phy_mvswitch_3.10_compilation.patch | 35 + .../patches-3.18/732-phy-ar8216-led-support.patch | 13 + .../generic/patches-3.18/733-phy_mvsw61xx.patch | 23 + .../generic/patches-3.18/750-hostap_txpower.patch | 154 + .../patches-3.18/773-bgmac-add-srab-switch.patch | 72 + ...l-pointer-dereference-in-igb_reset_q_vect.patch | 40 + .../patches-3.18/785-hso-support-0af0-9300.patch | 25 + .../810-pci_disable_common_quirks.patch | 51 + .../811-pci_disable_usb_common_quirks.patch | 101 + .../820-usb_add_usb_find_device_by_name.patch | 84 + .../patches-3.18/821-usb-dwc2-dualrole.patch | 146 + .../generic/patches-3.18/830-ledtrig_morse.patch | 28 + .../generic/patches-3.18/831-ledtrig_netdev.patch | 60 + .../generic/patches-3.18/832-ledtrig_usbdev.patch | 31 + .../generic/patches-3.18/834-ledtrig-libata.patch | 153 + .../linux/generic/patches-3.18/840-rtc7301.patch | 250 + .../generic/patches-3.18/841-rtc_pt7c4338.patch | 247 + .../861-04_spi_gpio_implement_spi_delay.patch | 58 + .../generic/patches-3.18/862-gpio_spi_driver.patch | 373 ++ .../linux/generic/patches-3.18/863-gpiommc.patch | 844 ++++ .../864-gpiommc_configfs_locking.patch | 58 + .../patches-3.18/870-hifn795x_byteswap.patch | 17 + .../880-gateworks_system_controller.patch | 339 ++ .../patches-3.18/890-8250_optional_sysrq.patch | 24 + .../generic/patches-3.18/900-slab_maxsize.patch | 13 + .../patches-3.18/901-debloat_sock_diag.patch | 65 + .../generic/patches-3.18/902-debloat_proc.patch | 341 ++ .../patches-3.18/903-debloat_direct_io.patch | 83 + .../generic/patches-3.18/910-kobject_uevent.patch | 21 + .../911-kobject_add_broadcast_uevent.patch | 65 + .../patches-3.18/921-use_preinit_as_init.patch | 12 + ...2-always-create-console-node-in-initramfs.patch | 30 + .../linux/generic/patches-3.18/930-crashlog.patch | 276 ++ .../patches-3.18/940-ocf_kbuild_integration.patch | 20 + .../generic/patches-3.18/941-ocf_20120127.patch | 166 + .../patches-3.18/960-decompress_unlzo_fix.patch | 23 + ...unsane-filenames-from-deps_initramfs-list.patch | 29 + .../patches-3.18/980-arm_openwrt_machtypes.patch | 32 + .../linux/generic/patches-3.18/990-gpio_wdt.patch | 360 ++ .../generic/patches-3.18/995-mangle_bootargs.patch | 58 + .../patches-3.18/997-device_tree_cmdline.patch | 24 + ...98-enable_wilink_platform_without_drivers.patch | 15 + .../generic/patches-3.18/999-seccomp_log.patch | 34 + .../000-keep_initrafs_the_default.patch | 25 + .../linux/generic/patches-4.0/020-ssb_update.patch | 30 + .../generic/patches-4.0/021-bcma-from-4.1.patch | 680 +++ .../linux/generic/patches-4.0/021-ssb_sprom.patch | 32 + .../generic/patches-4.0/022-bcma-from-4.2.patch | 86 + .../050-backport_netfilter_rtcache.patch | 509 ++ .../060-mips_decompressor_memmove.patch | 22 + ...ter-fixed-PHY-for-ARM-BCM470X-BCM5301X-ch.patch | 76 + ...71-bgmac-allow-enabling-on-ARCH_BCM_5301X.patch | 28 + ...ix-descriptor-frame-start-end-definitions.patch | 24 + ...-02-bgmac-implement-GRO-and-use-build_skb.patch | 189 + ...03-bgmac-implement-scatter-gather-support.patch | 267 + ...-04-bgmac-simplify-tx-ring-index-handling.patch | 125 + ...-interrupts-disabled-as-long-as-there-is-.patch | 87 + ...-set-received-skb-headroom-to-NET_SKB_PAD.patch | 66 + ...2-07-bgmac-simplify-rx-DMA-error-handling.patch | 130 + ...-08-bgmac-add-check-for-oversized-packets.patch | 27 + ...mac-increase-rx-ring-size-from-511-to-512.patch | 23 + .../072-10-bgmac-simplify-dma-init-cleanup.patch | 184 + .../072-11-bgmac-fix-DMA-rx-corruption.patch | 88 + .../072-12-bgmac-drop-ring-num_slots.patch | 132 + ...gmac-fix-MAC-soft-reset-bit-for-corerev-4.patch | 24 + ...2-14-bgmac-reset-all-4-GMAC-cores-on-init.patch | 28 + ...equests-for-extra-polling-calls-from-NAPI.patch | 30 + ...orkqueue-to-die-properly-when-a-PADT-is-r.patch | 89 + .../091-mtd-spi-nor-add-support-Spansion_S25FL164K | 10 + ...patibility-of-linux-in.h-with-netinet-in..patch | 146 + ...op-pppoe-device-in-pppoe_unbind_sock_work.patch | 27 + .../patches-4.0/102-ehci_hcd_ignore_oc.patch | 82 + ...-.rename2-and-add-RENAME_WHITEOUT-support.patch | 86 + .../111-jffs2-add-RENAME_EXCHANGE-support.patch | 58 + ...-bridge_allow_receiption_on_disabled_port.patch | 54 + ...-fix-sched_getaffinity-with-MT-FPAFF-enab.patch | 35 + .../patches-4.0/132-mips_inline_dma_ops.patch | 693 +++ .../140-overlayfs_readdir_locking_fix.patch | 148 + ...sb-xhci-make-USB_XHCI_PLATFORM-selectable.patch | 41 + ...upport_for_moving_ndp_to_end_of_ncm_frame.patch | 228 + ...-usb-ehci-orion-fix-probe-for-GENERIC_PHY.patch | 35 + .../generic/patches-4.0/200-fix_localversion.patch | 11 + .../patches-4.0/201-extra_optimization.patch | 14 + .../patches-4.0/202-reduce_module_size.patch | 11 + .../patches-4.0/203-kallsyms_uncompressed.patch | 108 + .../generic/patches-4.0/204-module_strip.patch | 194 + .../patches-4.0/205-backtrace_module_info.patch | 36 + .../patches-4.0/210-darwin_scripts_include.patch | 3088 ++++++++++++ .../patches-4.0/212-byteshift_portability.patch | 51 + .../patches-4.0/214-spidev_h_portability.patch | 11 + .../generic/patches-4.0/220-gc_sections.patch | 532 ++ .../generic/patches-4.0/221-module_exports.patch | 88 + .../patches-4.0/230-openwrt_lzma_options.patch | 58 + .../patches-4.0/250-netfilter_depends.patch | 18 + .../generic/patches-4.0/251-sound_kconfig.patch | 18 + .../generic/patches-4.0/252-mv_cesa_depends.patch | 10 + .../patches-4.0/253-ssb_b43_default_on.patch | 29 + .../patches-4.0/254-textsearch_kconfig_hacks.patch | 23 + .../patches-4.0/255-lib80211_kconfig_hacks.patch | 31 + .../256-crypto_add_kconfig_prompts.patch | 47 + .../257-wireless_ext_kconfig_hack.patch | 22 + .../258-netfilter_netlink_kconfig_hack.patch | 11 + .../generic/patches-4.0/259-regmap_dynamic.patch | 84 + .../patches-4.0/260-crypto_test_dependencies.patch | 37 + .../patches-4.0/262-compressor_kconfig_hack.patch | 35 + ...l.h-glibc-specific-inclusion-of-sysinfo.h.patch | 34 + ...pi-libc-compat.h-do-not-rely-on-__GLIBC__.patch | 81 + ...er.h-prevent-redefinition-of-struct-ethhd.patch | 67 + .../patches-4.0/300-mips_expose_boot_raw.patch | 39 + .../patches-4.0/301-mips_image_cmdline_hack.patch | 28 + .../patches-4.0/302-mips_no_branch_likely.patch | 11 + .../generic/patches-4.0/304-mips_disable_fpu.patch | 105 + .../patches-4.0/305-mips_module_reloc.patch | 352 ++ .../306-mips_mem_functions_performance.patch | 83 + .../patches-4.0/307-mips_highmem_offset.patch | 17 + .../patches-4.0/309-mips_fuse_workaround.patch | 32 + .../310-arm_module_unresolved_weak_sym.patch | 13 + .../patches-4.0/320-ppc4xx_optimization.patch | 31 + .../patches-4.0/321-powerpc_crtsavres_prereq.patch | 10 + ...Accept-command-line-parameters-from-users.patch | 298 ++ .../400-mtd-add-rootfs-split-support.patch | 171 + ...port-for-different-partition-parser-types.patch | 113 + ...mtd-parsers-for-rootfs-and-firmware-split.patch | 72 + .../403-mtd-hook-mtdsplit-to-Kbuild.patch | 22 + .../404-mtd-add-more-helper-functions.patch | 101 + .../405-mtd-old-firmware-uimage-splitter.patch | 70 + .../406-mtd-old-rootfs-squashfs-splitter.patch | 76 + ...ve-forward-declaration-of-struct-mtd_info.patch | 18 + .../411-mtd-partial_eraseblock_write.patch | 142 + .../412-mtd-partial_eraseblock_unlock.patch | 18 + .../patches-4.0/420-mtd-redboot_space.patch | 30 + .../430-mtd-add-myloader-partition-parser.patch | 35 + ...part-support-for-Xiaomi-specific-board_da.patch | 34 + ...-mtd-bcm47xxpart-detect-T_Meter-partition.patch | 42 + .../generic/patches-4.0/440-block2mtd_init.patch | 107 + .../generic/patches-4.0/441-block2mtd_probe.patch | 110 + ...allow-to-use-platform-specific-chip-fixup.patch | 37 + ...return-code-of-nand_correct_data-function.patch | 11 + .../460-mtd-cfi_cmdset_0002-no-erase_suspend.patch | 11 + ..._cmdset_0002-add-buffer-write-cmd-timeout.patch | 18 + ...5p80-add-support-for-Winbond-W25X05-flash.patch | 20 + ...-add-support-for-the-Macronix-MX25L512E-S.patch | 21 + ...-add-support-for-the-ISSI-SI25CD512-SPI-f.patch | 22 + .../480-mtd-set-rootfs-to-be-root-dev.patch | 26 + ...tach-mtd-device-named-ubi-or-data-on-boot.patch | 76 + ...bi-auto-create-ubiblock-device-for-rootfs.patch | 69 + ...-mounting-ubi0-rootfs-in-init-do_mounts.c.patch | 53 + ...-set-ROOT_DEV-to-ubiblock-rootfs-if-unset.patch | 37 + .../494-mtd-ubi-add-EOF-marker-support.patch | 51 + .../patches-4.0/500-yaffs-Kbuild-integration.patch | 18 + .../502-yaffs-fix-compat-tags-handling.patch | 239 + .../503-yaffs-add-tags-9bytes-mount-option.patch | 115 + .../patches-4.0/504-yaffs-3.16-new-fops.patch | 25 + .../505-yaffs-3.19-f_dentry-remove.patch | 95 + .../520-squashfs_update_xz_comp_opts.patch | 25 + .../530-jffs2_make_lzma_available.patch | 5142 ++++++++++++++++++++ .../generic/patches-4.0/531-debloat_lzma.patch | 1024 ++++ .../generic/patches-4.0/532-jffs2_eofdetect.patch | 56 + .../540-crypto-xz-decompression-support.patch | 146 + .../541-ubifs-xz-decompression-support.patch | 92 + ...1-ubifs-fix-default-compression-selection.patch | 29 + .../600-netfilter_conntrack_flush.patch | 86 + ...610-netfilter_match_bypass_default_checks.patch | 93 + .../611-netfilter_match_bypass_default_table.patch | 94 + .../612-netfilter_match_reduce_memory_access.patch | 16 + .../613-netfilter_optional_tcp_window_check.patch | 36 + .../615-netfilter_add_xt_id_match.patch | 95 + .../patches-4.0/616-net_optimize_xfrm_calls.patch | 12 + .../linux/generic/patches-4.0/620-sched_esfq.patch | 791 +++ .../patches-4.0/630-packet_socket_type.patch | 134 + .../patches-4.0/640-bridge_no_eap_forward.patch | 23 + .../patches-4.0/641-bridge_always_accept_eap.patch | 17 + .../patches-4.0/642-bridge_port_isolate.patch | 107 + .../643-bridge_remove_ipv6_dependency.patch | 123 + .../645-bridge_multicast_to_unicast.patch | 383 ++ .../generic/patches-4.0/650-pppoe_header_pad.patch | 20 + .../patches-4.0/651-wireless_mesh_header.patch | 11 + .../patches-4.0/653-disable_netlink_trim.patch | 30 + .../generic/patches-4.0/655-increase_skb_pad.patch | 11 + .../656-skb_reduce_truesize-helper.patch | 41 + .../patches-4.0/657-qdisc_reduce_truesize.patch | 63 + .../patches-4.0/660-fq_codel_defaults.patch | 14 + .../661-fq_codel_keep_dropped_stats.patch | 10 + .../patches-4.0/662-use_fq_codel_by_default.patch | 75 + .../patches-4.0/663-remove_pfifo_fast.patch | 143 + .../generic/patches-4.0/664-codel_fix_3_12.patch | 22 + .../666-Add-support-for-MAP-E-FMRs-mesh-mode.patch | 495 ++ ...ed-source-specific-default-route-handling.patch | 97 + ...jecting-with-source-address-failed-policy.patch | 249 + ...-defines-for-_POLICY_FAILED-until-all-cod.patch | 53 + ...80-NET-skip-GRO-for-foreign-MAC-addresses.patch | 160 + .../681-NET-add-of_get_mac_address_mtd.patch | 88 + .../linux/generic/patches-4.0/700-swconfig.patch | 39 + .../generic/patches-4.0/701-phy_extension.patch | 63 + .../702-phy_add_aneg_done_function.patch | 27 + ...-add-detach-callback-to-struct-phy_driver.patch | 27 + .../patches-4.0/704-phy-no-genphy-soft-reset.patch | 29 + .../710-phy-add-mdio_register_board_info.patch | 193 + .../generic/patches-4.0/720-phy_adm6996.patch | 26 + .../generic/patches-4.0/721-phy_packets.patch | 161 + .../generic/patches-4.0/722-phy_mvswitch.patch | 23 + .../linux/generic/patches-4.0/723-phy_ip175c.patch | 23 + .../linux/generic/patches-4.0/724-phy_ar8216.patch | 24 + .../generic/patches-4.0/725-phy_rtl8306.patch | 23 + .../generic/patches-4.0/726-phy_rtl8366.patch | 45 + .../generic/patches-4.0/727-phy-rtl8367.patch | 23 + .../generic/patches-4.0/728-phy-rtl8367b.patch | 23 + .../linux/generic/patches-4.0/729-phy-tantos.patch | 21 + target/linux/generic/patches-4.0/730-phy_b53.patch | 21 + .../731-phy_mvswitch_3.10_compilation.patch | 35 + .../patches-4.0/732-phy-ar8216-led-support.patch | 13 + .../generic/patches-4.0/733-phy_mvsw61xx.patch | 23 + .../generic/patches-4.0/750-hostap_txpower.patch | 154 + .../patches-4.0/773-bgmac-add-srab-switch.patch | 72 + ...l-pointer-dereference-in-igb_reset_q_vect.patch | 40 + .../patches-4.0/785-hso-support-0af0-9300.patch | 25 + .../810-pci_disable_common_quirks.patch | 51 + .../811-pci_disable_usb_common_quirks.patch | 101 + .../820-usb_add_usb_find_device_by_name.patch | 84 + .../generic/patches-4.0/830-ledtrig_morse.patch | 28 + .../generic/patches-4.0/831-ledtrig_netdev.patch | 60 + .../generic/patches-4.0/832-ledtrig_usbdev.patch | 31 + .../generic/patches-4.0/834-ledtrig-libata.patch | 153 + target/linux/generic/patches-4.0/840-rtc7301.patch | 250 + .../generic/patches-4.0/841-rtc_pt7c4338.patch | 247 + .../861-04_spi_gpio_implement_spi_delay.patch | 58 + .../generic/patches-4.0/862-gpio_spi_driver.patch | 373 ++ target/linux/generic/patches-4.0/863-gpiommc.patch | 844 ++++ .../patches-4.0/864-gpiommc_configfs_locking.patch | 58 + .../patches-4.0/870-hifn795x_byteswap.patch | 17 + .../880-gateworks_system_controller.patch | 339 ++ .../patches-4.0/890-8250_optional_sysrq.patch | 24 + .../generic/patches-4.0/900-slab_maxsize.patch | 13 + .../patches-4.0/901-debloat_sock_diag.patch | 45 + .../generic/patches-4.0/902-debloat_proc.patch | 341 ++ .../patches-4.0/903-debloat_direct_io.patch | 79 + .../generic/patches-4.0/910-kobject_uevent.patch | 21 + .../911-kobject_add_broadcast_uevent.patch | 65 + .../patches-4.0/921-use_preinit_as_init.patch | 12 + ...2-always-create-console-node-in-initramfs.patch | 30 + .../linux/generic/patches-4.0/930-crashlog.patch | 276 ++ .../patches-4.0/940-ocf_kbuild_integration.patch | 20 + .../generic/patches-4.0/941-ocf_20120127.patch | 166 + .../patches-4.0/960-decompress_unlzo_fix.patch | 23 + ...unsane-filenames-from-deps_initramfs-list.patch | 29 + .../patches-4.0/980-arm_openwrt_machtypes.patch | 32 + .../linux/generic/patches-4.0/990-gpio_wdt.patch | 360 ++ .../generic/patches-4.0/995-mangle_bootargs.patch | 58 + .../patches-4.0/997-device_tree_cmdline.patch | 24 + ...98-enable_wilink_platform_without_drivers.patch | 15 + .../000-keep_initrafs_the_default.patch | 25 + .../linux/generic/patches-4.1/021-ssb_sprom.patch | 32 + .../generic/patches-4.1/022-bcma-from-4.2.patch | 86 + .../050-backport_netfilter_rtcache.patch | 505 ++ .../060-mips_decompressor_memmove.patch | 22 + ...gmac-fix-MAC-soft-reset-bit-for-corerev-4.patch | 24 + ...2-14-bgmac-reset-all-4-GMAC-cores-on-init.patch | 28 + ..._fragment-fix-headroom-tests-and-skb-leak.patch | 101 + ...pci-Increase-headroom-on-received-packets.patch | 54 + .../091-mtd-spi-nor-add-support-Spansion_S25FL164K | 10 + ...patibility-of-linux-in.h-with-netinet-in..patch | 146 + ...-one-in-continuation-handling-in-proc-net.patch | 46 + .../101-pppoe-fix-disconnect-crash.patch | 16 + .../patches-4.1/102-ehci_hcd_ignore_oc.patch | 82 + ...-.rename2-and-add-RENAME_WHITEOUT-support.patch | 86 + .../111-jffs2-add-RENAME_EXCHANGE-support.patch | 58 + ...-bridge_allow_receiption_on_disabled_port.patch | 54 + .../patches-4.1/132-mips_inline_dma_ops.patch | 697 +++ ...t-add-generic-parsing-of-linux-part-probe.patch | 175 + ...sb-xhci-make-USB_XHCI_PLATFORM-selectable.patch | 41 + ...upport_for_moving_ndp_to_end_of_ncm_frame.patch | 228 + ...-usb-ehci-orion-fix-probe-for-GENERIC_PHY.patch | 35 + .../generic/patches-4.1/200-fix_localversion.patch | 11 + .../patches-4.1/201-extra_optimization.patch | 14 + .../patches-4.1/202-reduce_module_size.patch | 11 + .../patches-4.1/203-kallsyms_uncompressed.patch | 108 + .../generic/patches-4.1/204-module_strip.patch | 194 + .../patches-4.1/205-backtrace_module_info.patch | 36 + .../patches-4.1/210-darwin_scripts_include.patch | 3088 ++++++++++++ .../patches-4.1/212-byteshift_portability.patch | 51 + .../patches-4.1/214-spidev_h_portability.patch | 11 + .../generic/patches-4.1/220-gc_sections.patch | 536 ++ .../generic/patches-4.1/221-module_exports.patch | 88 + .../patches-4.1/230-openwrt_lzma_options.patch | 58 + .../patches-4.1/250-netfilter_depends.patch | 18 + .../generic/patches-4.1/251-sound_kconfig.patch | 18 + .../generic/patches-4.1/252-mv_cesa_depends.patch | 10 + .../patches-4.1/253-ssb_b43_default_on.patch | 29 + .../patches-4.1/254-textsearch_kconfig_hacks.patch | 23 + .../patches-4.1/255-lib80211_kconfig_hacks.patch | 31 + .../256-crypto_add_kconfig_prompts.patch | 47 + .../257-wireless_ext_kconfig_hack.patch | 22 + .../258-netfilter_netlink_kconfig_hack.patch | 11 + .../generic/patches-4.1/259-regmap_dynamic.patch | 87 + .../patches-4.1/260-crypto_test_dependencies.patch | 37 + .../patches-4.1/262-compressor_kconfig_hack.patch | 35 + ...l.h-glibc-specific-inclusion-of-sysinfo.h.patch | 34 + ...pi-libc-compat.h-do-not-rely-on-__GLIBC__.patch | 81 + ...er.h-prevent-redefinition-of-struct-ethhd.patch | 67 + .../patches-4.1/300-mips_expose_boot_raw.patch | 39 + .../patches-4.1/301-mips_image_cmdline_hack.patch | 28 + .../patches-4.1/302-mips_no_branch_likely.patch | 11 + .../generic/patches-4.1/304-mips_disable_fpu.patch | 106 + .../patches-4.1/305-mips_module_reloc.patch | 352 ++ .../306-mips_mem_functions_performance.patch | 83 + .../patches-4.1/307-mips_highmem_offset.patch | 17 + .../patches-4.1/309-mips_fuse_workaround.patch | 32 + .../310-arm_module_unresolved_weak_sym.patch | 13 + .../patches-4.1/320-ppc4xx_optimization.patch | 31 + .../patches-4.1/321-powerpc_crtsavres_prereq.patch | 10 + ...Accept-command-line-parameters-from-users.patch | 298 ++ .../400-mtd-add-rootfs-split-support.patch | 146 + ...port-for-different-partition-parser-types.patch | 113 + ...mtd-parsers-for-rootfs-and-firmware-split.patch | 72 + .../403-mtd-hook-mtdsplit-to-Kbuild.patch | 22 + .../404-mtd-add-more-helper-functions.patch | 101 + .../405-mtd-old-firmware-uimage-splitter.patch | 70 + ...ve-forward-declaration-of-struct-mtd_info.patch | 18 + .../411-mtd-partial_eraseblock_write.patch | 142 + .../412-mtd-partial_eraseblock_unlock.patch | 18 + .../patches-4.1/420-mtd-redboot_space.patch | 30 + .../430-mtd-add-myloader-partition-parser.patch | 35 + ...part-support-for-Xiaomi-specific-board_da.patch | 34 + ...-mtd-bcm47xxpart-detect-T_Meter-partition.patch | 42 + .../generic/patches-4.1/440-block2mtd_init.patch | 108 + .../generic/patches-4.1/441-block2mtd_probe.patch | 39 + ...allow-to-use-platform-specific-chip-fixup.patch | 37 + ...return-code-of-nand_correct_data-function.patch | 11 + .../460-mtd-cfi_cmdset_0002-no-erase_suspend.patch | 11 + ..._cmdset_0002-add-buffer-write-cmd-timeout.patch | 18 + ...-add-support-for-the-Macronix-MX25L512E-S.patch | 21 + ...-add-support-for-the-ISSI-SI25CD512-SPI-f.patch | 22 + .../480-mtd-set-rootfs-to-be-root-dev.patch | 26 + ...tach-mtd-device-named-ubi-or-data-on-boot.patch | 76 + ...bi-auto-create-ubiblock-device-for-rootfs.patch | 69 + ...-mounting-ubi0-rootfs-in-init-do_mounts.c.patch | 53 + ...-set-ROOT_DEV-to-ubiblock-rootfs-if-unset.patch | 37 + .../494-mtd-ubi-add-EOF-marker-support.patch | 51 + .../patches-4.1/500-yaffs-Kbuild-integration.patch | 18 + .../502-yaffs-fix-compat-tags-handling.patch | 239 + .../503-yaffs-add-tags-9bytes-mount-option.patch | 115 + .../patches-4.1/504-yaffs-3.16-new-fops.patch | 29 + .../505-yaffs-3.19-f_dentry-remove.patch | 95 + .../520-squashfs_update_xz_comp_opts.patch | 25 + .../530-jffs2_make_lzma_available.patch | 5142 ++++++++++++++++++++ .../generic/patches-4.1/531-debloat_lzma.patch | 1024 ++++ .../generic/patches-4.1/532-jffs2_eofdetect.patch | 56 + .../540-crypto-xz-decompression-support.patch | 146 + .../541-ubifs-xz-decompression-support.patch | 92 + ...1-ubifs-fix-default-compression-selection.patch | 29 + .../600-netfilter_conntrack_flush.patch | 86 + ...610-netfilter_match_bypass_default_checks.patch | 93 + .../611-netfilter_match_bypass_default_table.patch | 94 + .../612-netfilter_match_reduce_memory_access.patch | 16 + .../613-netfilter_optional_tcp_window_check.patch | 36 + .../615-netfilter_add_xt_id_match.patch | 95 + .../patches-4.1/616-net_optimize_xfrm_calls.patch | 12 + .../linux/generic/patches-4.1/620-sched_esfq.patch | 791 +++ .../patches-4.1/630-packet_socket_type.patch | 134 + .../patches-4.1/640-bridge_no_eap_forward.patch | 23 + .../patches-4.1/641-bridge_always_accept_eap.patch | 17 + .../patches-4.1/642-bridge_port_isolate.patch | 107 + .../643-bridge_remove_ipv6_dependency.patch | 123 + .../645-bridge_multicast_to_unicast.patch | 397 ++ .../generic/patches-4.1/650-pppoe_header_pad.patch | 20 + .../patches-4.1/651-wireless_mesh_header.patch | 11 + .../patches-4.1/653-disable_netlink_trim.patch | 30 + .../generic/patches-4.1/655-increase_skb_pad.patch | 11 + .../656-skb_reduce_truesize-helper.patch | 41 + .../patches-4.1/657-qdisc_reduce_truesize.patch | 63 + .../patches-4.1/660-fq_codel_defaults.patch | 14 + .../661-fq_codel_keep_dropped_stats.patch | 10 + .../patches-4.1/662-use_fq_codel_by_default.patch | 75 + .../patches-4.1/663-remove_pfifo_fast.patch | 143 + .../generic/patches-4.1/664-codel_fix_3_12.patch | 22 + .../666-Add-support-for-MAP-E-FMRs-mesh-mode.patch | 495 ++ ...jecting-with-source-address-failed-policy.patch | 249 + ...-defines-for-_POLICY_FAILED-until-all-cod.patch | 53 + ...80-NET-skip-GRO-for-foreign-MAC-addresses.patch | 160 + .../681-NET-add-of_get_mac_address_mtd.patch | 88 + .../linux/generic/patches-4.1/700-swconfig.patch | 39 + .../generic/patches-4.1/701-phy_extension.patch | 63 + .../702-phy_add_aneg_done_function.patch | 27 + ...-add-detach-callback-to-struct-phy_driver.patch | 27 + .../patches-4.1/704-phy-no-genphy-soft-reset.patch | 29 + .../710-phy-add-mdio_register_board_info.patch | 193 + .../generic/patches-4.1/720-phy_adm6996.patch | 26 + .../generic/patches-4.1/721-phy_packets.patch | 161 + .../generic/patches-4.1/722-phy_mvswitch.patch | 23 + .../linux/generic/patches-4.1/723-phy_ip175c.patch | 23 + .../linux/generic/patches-4.1/724-phy_ar8216.patch | 24 + .../generic/patches-4.1/725-phy_rtl8306.patch | 23 + .../generic/patches-4.1/726-phy_rtl8366.patch | 45 + .../generic/patches-4.1/727-phy-rtl8367.patch | 23 + .../generic/patches-4.1/728-phy-rtl8367b.patch | 23 + .../linux/generic/patches-4.1/729-phy-tantos.patch | 21 + target/linux/generic/patches-4.1/730-phy_b53.patch | 21 + .../731-phy_mvswitch_3.10_compilation.patch | 35 + .../patches-4.1/732-phy-ar8216-led-support.patch | 13 + .../generic/patches-4.1/733-phy_mvsw61xx.patch | 23 + .../generic/patches-4.1/750-hostap_txpower.patch | 154 + .../patches-4.1/773-bgmac-add-srab-switch.patch | 72 + ...l-pointer-dereference-in-igb_reset_q_vect.patch | 40 + .../patches-4.1/785-hso-support-0af0-9300.patch | 25 + .../810-pci_disable_common_quirks.patch | 51 + .../811-pci_disable_usb_common_quirks.patch | 101 + .../820-usb_add_usb_find_device_by_name.patch | 84 + .../generic/patches-4.1/830-ledtrig_morse.patch | 28 + .../generic/patches-4.1/831-ledtrig_netdev.patch | 60 + .../generic/patches-4.1/832-ledtrig_usbdev.patch | 31 + .../generic/patches-4.1/834-ledtrig-libata.patch | 153 + target/linux/generic/patches-4.1/840-rtc7301.patch | 250 + .../generic/patches-4.1/841-rtc_pt7c4338.patch | 247 + .../861-04_spi_gpio_implement_spi_delay.patch | 58 + .../generic/patches-4.1/862-gpio_spi_driver.patch | 373 ++ target/linux/generic/patches-4.1/863-gpiommc.patch | 844 ++++ .../patches-4.1/864-gpiommc_configfs_locking.patch | 58 + .../patches-4.1/870-hifn795x_byteswap.patch | 17 + .../880-gateworks_system_controller.patch | 339 ++ .../patches-4.1/890-8250_optional_sysrq.patch | 24 + .../generic/patches-4.1/900-slab_maxsize.patch | 13 + .../patches-4.1/901-debloat_sock_diag.patch | 65 + .../generic/patches-4.1/902-debloat_proc.patch | 341 ++ .../patches-4.1/903-debloat_direct_io.patch | 80 + .../generic/patches-4.1/910-kobject_uevent.patch | 21 + .../911-kobject_add_broadcast_uevent.patch | 65 + .../patches-4.1/921-use_preinit_as_init.patch | 12 + ...2-always-create-console-node-in-initramfs.patch | 30 + .../linux/generic/patches-4.1/930-crashlog.patch | 276 ++ .../patches-4.1/940-ocf_kbuild_integration.patch | 20 + .../generic/patches-4.1/941-ocf_20120127.patch | 166 + .../patches-4.1/960-decompress_unlzo_fix.patch | 23 + ...unsane-filenames-from-deps_initramfs-list.patch | 29 + .../patches-4.1/980-arm_openwrt_machtypes.patch | 32 + .../linux/generic/patches-4.1/990-gpio_wdt.patch | 360 ++ .../generic/patches-4.1/995-mangle_bootargs.patch | 58 + .../patches-4.1/997-device_tree_cmdline.patch | 24 + ...98-enable_wilink_platform_without_drivers.patch | 15 + 989 files changed, 244363 insertions(+) create mode 100644 target/linux/generic/PATCHES create mode 100755 target/linux/generic/base-files/init create mode 100644 target/linux/generic/config-3.18 create mode 100644 target/linux/generic/config-4.0 create mode 100644 target/linux/generic/config-4.1 create mode 100644 target/linux/generic/files/Documentation/networking/adm6996.txt create mode 100644 target/linux/generic/files/arch/mips/fw/myloader/Makefile create mode 100644 target/linux/generic/files/arch/mips/fw/myloader/myloader.c create mode 100644 target/linux/generic/files/crypto/ocf/Config.in create mode 100644 target/linux/generic/files/crypto/ocf/Kconfig create mode 100644 target/linux/generic/files/crypto/ocf/Makefile create mode 100644 target/linux/generic/files/crypto/ocf/c7108/Makefile create mode 100644 target/linux/generic/files/crypto/ocf/c7108/aes-7108.c create mode 100644 target/linux/generic/files/crypto/ocf/c7108/aes-7108.h create mode 100644 target/linux/generic/files/crypto/ocf/criov.c create mode 100644 target/linux/generic/files/crypto/ocf/crypto.c create mode 100644 target/linux/generic/files/crypto/ocf/cryptocteon/Makefile create mode 100644 target/linux/generic/files/crypto/ocf/cryptocteon/README.txt create mode 100644 target/linux/generic/files/crypto/ocf/cryptocteon/cavium_crypto.c create mode 100644 target/linux/generic/files/crypto/ocf/cryptocteon/cryptocteon.c create mode 100644 target/linux/generic/files/crypto/ocf/cryptodev.c create mode 100644 target/linux/generic/files/crypto/ocf/cryptodev.h create mode 100644 target/linux/generic/files/crypto/ocf/cryptosoft.c create mode 100644 target/linux/generic/files/crypto/ocf/ep80579/Makefile create mode 100644 target/linux/generic/files/crypto/ocf/ep80579/environment.mk create mode 100644 target/linux/generic/files/crypto/ocf/ep80579/icp_asym.c create mode 100644 target/linux/generic/files/crypto/ocf/ep80579/icp_common.c create mode 100644 target/linux/generic/files/crypto/ocf/ep80579/icp_ocf.h create mode 100644 target/linux/generic/files/crypto/ocf/ep80579/icp_sym.c create mode 100644 target/linux/generic/files/crypto/ocf/ep80579/linux_2.6_kernel_space.mk create mode 100644 target/linux/generic/files/crypto/ocf/hifn/Makefile create mode 100644 target/linux/generic/files/crypto/ocf/hifn/hifn7751.c create mode 100644 target/linux/generic/files/crypto/ocf/hifn/hifn7751reg.h create mode 100644 target/linux/generic/files/crypto/ocf/hifn/hifn7751var.h create mode 100644 target/linux/generic/files/crypto/ocf/hifn/hifnHIPP.c create mode 100644 target/linux/generic/files/crypto/ocf/hifn/hifnHIPPreg.h create mode 100644 target/linux/generic/files/crypto/ocf/hifn/hifnHIPPvar.h create mode 100644 target/linux/generic/files/crypto/ocf/ixp4xx/Makefile create mode 100644 target/linux/generic/files/crypto/ocf/ixp4xx/ixp4xx.c create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/Makefile create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/cesa/AES/mvAes.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/cesa/AES/mvAesAlg.c create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/cesa/AES/mvAesAlg.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/cesa/AES/mvAesApi.c create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/cesa/AES/mvAesBoxes.dat create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/cesa/mvCesa.c create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/cesa/mvCesa.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/cesa/mvCesaDebug.c create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/cesa/mvCesaRegs.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/cesa/mvCesaTest.c create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/cesa/mvCompVer.txt create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/cesa/mvLru.c create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/cesa/mvLru.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/cesa/mvMD5.c create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/cesa/mvMD5.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/cesa/mvSHA1.c create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/cesa/mvSHA1.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/cesa_ocf_drv.c create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/common/mv802_3.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/common/mvCommon.c create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/common/mvCommon.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/common/mvCompVer.txt create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/common/mvDebug.c create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/common/mvDebug.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/common/mvDeviceId.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/common/mvHalVer.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/common/mvStack.c create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/common/mvStack.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/common/mvTypes.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/dbg-trace.c create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/dbg-trace.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/boardEnv/mvBoardEnvLib.c create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/boardEnv/mvBoardEnvLib.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/boardEnv/mvBoardEnvSpec.c create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/boardEnv/mvBoardEnvSpec.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/cpu/mvCpu.c create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/cpu/mvCpu.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/mvCtrlEnvAddrDec.c create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/mvCtrlEnvAddrDec.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/mvCtrlEnvAsm.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/mvCtrlEnvLib.c create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/mvCtrlEnvLib.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/mvCtrlEnvRegs.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/mvCtrlEnvSpec.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvAhbToMbus.c create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvAhbToMbus.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvAhbToMbusRegs.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvCpuIf.c create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvCpuIf.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvCpuIfInit.S create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvCpuIfRegs.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysAudio.c create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysAudio.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysCesa.c create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysCesa.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysDram.c create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysDram.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysGbe.c create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysGbe.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysPex.c create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysPex.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysSata.c create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysSata.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysSdmmc.c create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysSdmmc.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysTdm.c create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysTdm.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysTs.c create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysTs.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysUsb.c create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysUsb.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysXor.c create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysXor.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/device/mvDevice.c create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/device/mvDevice.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/device/mvDeviceRegs.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/mvCompVer.txt create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/linux_oss/mvOs.c create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/linux_oss/mvOs.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/linux_oss/mvOsSata.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mvSysHwConfig.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/cntmr/mvCntmr.c create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/cntmr/mvCntmr.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/cntmr/mvCntmrRegs.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/cntmr/mvCompVer.txt create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/cpu/mvCpuCntrs.c create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/cpu/mvCpuCntrs.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/cpu/mvCpuL2Cntrs.c create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/cpu/mvCpuL2Cntrs.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvCompVer.txt create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvDram.c create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvDram.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvDramIf.c create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvDramIf.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvDramIfBasicInit.S create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvDramIfConfig.S create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvDramIfConfig.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvDramIfRegs.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr2/mvCompVer.txt create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr2/mvDramIf.c create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr2/mvDramIf.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr2/mvDramIfBasicInit.S create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr2/mvDramIfConfig.S create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr2/mvDramIfConfig.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr2/mvDramIfRegs.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr2/mvDramIfStaticInit.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr2/spd/mvSpd.c create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr2/spd/mvSpd.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/eth/gbe/mvEth.c create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/eth/gbe/mvEthDebug.c create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/eth/gbe/mvEthDebug.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/eth/gbe/mvEthGbe.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/eth/gbe/mvEthRegs.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/eth/mvCompVer.txt create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/eth/mvEth.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/gpp/mvCompVer.txt create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/gpp/mvGpp.c create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/gpp/mvGpp.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/gpp/mvGppRegs.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/pci-if/mvCompVer.txt create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/pci-if/mvPciIf.c create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/pci-if/mvPciIf.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/pci-if/mvPciIfRegs.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/pci-if/pci_util/mvPciUtils.c create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/pci-if/pci_util/mvPciUtils.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/pci/mvCompVer.txt create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/pci/mvPci.c create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/pci/mvPci.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/pci/mvPciRegs.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/pex/mvCompVer.txt create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/pex/mvPex.c create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/pex/mvPex.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/pex/mvPexRegs.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/pex/mvVrtBrgPex.c create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/pex/mvVrtBrgPex.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/sflash/mvCompVer.txt create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/sflash/mvSFlash.c create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/sflash/mvSFlash.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/sflash/mvSFlashSpec.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/spi/mvCompVer.txt create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/spi/mvSpi.c create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/spi/mvSpi.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/spi/mvSpiCmnd.c create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/spi/mvSpiCmnd.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/spi/mvSpiSpec.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/twsi/mvCompVer.txt create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/twsi/mvTwsi.c create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/twsi/mvTwsi.h create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/twsi/mvTwsiEeprom.S create mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/twsi/mvTwsiSpec.h create mode 100644 target/linux/generic/files/crypto/ocf/ocf-bench.c create mode 100644 target/linux/generic/files/crypto/ocf/ocf-compat.h create mode 100644 target/linux/generic/files/crypto/ocf/ocfnull/Makefile create mode 100644 target/linux/generic/files/crypto/ocf/ocfnull/ocfnull.c create mode 100644 target/linux/generic/files/crypto/ocf/pasemi/Makefile create mode 100644 target/linux/generic/files/crypto/ocf/pasemi/pasemi.c create mode 100644 target/linux/generic/files/crypto/ocf/pasemi/pasemi_fnu.h create mode 100644 target/linux/generic/files/crypto/ocf/random.c create mode 100644 target/linux/generic/files/crypto/ocf/rndtest.c create mode 100644 target/linux/generic/files/crypto/ocf/rndtest.h create mode 100644 target/linux/generic/files/crypto/ocf/safe/Makefile create mode 100644 target/linux/generic/files/crypto/ocf/safe/hmachack.h create mode 100644 target/linux/generic/files/crypto/ocf/safe/md5.c create mode 100644 target/linux/generic/files/crypto/ocf/safe/md5.h create mode 100644 target/linux/generic/files/crypto/ocf/safe/safe.c create mode 100644 target/linux/generic/files/crypto/ocf/safe/safereg.h create mode 100644 target/linux/generic/files/crypto/ocf/safe/safevar.h create mode 100644 target/linux/generic/files/crypto/ocf/safe/sha1.c create mode 100644 target/linux/generic/files/crypto/ocf/safe/sha1.h create mode 100644 target/linux/generic/files/crypto/ocf/talitos/Makefile create mode 100644 target/linux/generic/files/crypto/ocf/talitos/talitos.c create mode 100644 target/linux/generic/files/crypto/ocf/talitos/talitos_dev.h create mode 100644 target/linux/generic/files/crypto/ocf/talitos/talitos_soft.h create mode 100644 target/linux/generic/files/crypto/ocf/ubsec_ssb/Makefile create mode 100644 target/linux/generic/files/crypto/ocf/ubsec_ssb/bsdqueue.h create mode 100644 target/linux/generic/files/crypto/ocf/ubsec_ssb/ubsec_ssb.c create mode 100644 target/linux/generic/files/crypto/ocf/ubsec_ssb/ubsecreg.h create mode 100644 target/linux/generic/files/crypto/ocf/ubsec_ssb/ubsecvar.h create mode 100644 target/linux/generic/files/crypto/ocf/uio.h create mode 100644 target/linux/generic/files/drivers/leds/ledtrig-morse.c create mode 100644 target/linux/generic/files/drivers/leds/ledtrig-netdev.c create mode 100644 target/linux/generic/files/drivers/leds/ledtrig-usbdev.c create mode 100644 target/linux/generic/files/drivers/mtd/mtdsplit/Kconfig create mode 100644 target/linux/generic/files/drivers/mtd/mtdsplit/Makefile create mode 100644 target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit.c create mode 100644 target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit.h create mode 100644 target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_fit.c create mode 100644 target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_lzma.c create mode 100644 target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_seama.c create mode 100644 target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_squashfs.c create mode 100644 target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_tplink.c create mode 100644 target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_trx.c create mode 100644 target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_uimage.c create mode 100644 target/linux/generic/files/drivers/mtd/myloader.c create mode 100644 target/linux/generic/files/drivers/net/phy/adm6996.c create mode 100644 target/linux/generic/files/drivers/net/phy/adm6996.h create mode 100644 target/linux/generic/files/drivers/net/phy/ar8216.c create mode 100644 target/linux/generic/files/drivers/net/phy/ar8216.h create mode 100644 target/linux/generic/files/drivers/net/phy/ar8327.c create mode 100644 target/linux/generic/files/drivers/net/phy/ar8327.h create mode 100644 target/linux/generic/files/drivers/net/phy/b53/Kconfig create mode 100644 target/linux/generic/files/drivers/net/phy/b53/Makefile create mode 100644 target/linux/generic/files/drivers/net/phy/b53/b53_common.c create mode 100644 target/linux/generic/files/drivers/net/phy/b53/b53_mdio.c create mode 100644 target/linux/generic/files/drivers/net/phy/b53/b53_mmap.c create mode 100644 target/linux/generic/files/drivers/net/phy/b53/b53_phy_fixup.c create mode 100644 target/linux/generic/files/drivers/net/phy/b53/b53_priv.h create mode 100644 target/linux/generic/files/drivers/net/phy/b53/b53_regs.h create mode 100644 target/linux/generic/files/drivers/net/phy/b53/b53_spi.c create mode 100644 target/linux/generic/files/drivers/net/phy/b53/b53_srab.c create mode 100644 target/linux/generic/files/drivers/net/phy/ip17xx.c create mode 100644 target/linux/generic/files/drivers/net/phy/mvsw61xx.c create mode 100644 target/linux/generic/files/drivers/net/phy/mvsw61xx.h create mode 100644 target/linux/generic/files/drivers/net/phy/mvswitch.c create mode 100644 target/linux/generic/files/drivers/net/phy/mvswitch.h create mode 100644 target/linux/generic/files/drivers/net/phy/psb6970.c create mode 100644 target/linux/generic/files/drivers/net/phy/rtl8306.c create mode 100644 target/linux/generic/files/drivers/net/phy/rtl8366_smi.c create mode 100644 target/linux/generic/files/drivers/net/phy/rtl8366_smi.h create mode 100644 target/linux/generic/files/drivers/net/phy/rtl8366rb.c create mode 100644 target/linux/generic/files/drivers/net/phy/rtl8366s.c create mode 100644 target/linux/generic/files/drivers/net/phy/rtl8367.c create mode 100644 target/linux/generic/files/drivers/net/phy/rtl8367b.c create mode 100644 target/linux/generic/files/drivers/net/phy/swconfig.c create mode 100644 target/linux/generic/files/drivers/net/phy/swconfig_leds.c create mode 100644 target/linux/generic/files/fs/yaffs2/Kconfig create mode 100644 target/linux/generic/files/fs/yaffs2/Makefile create mode 100644 target/linux/generic/files/fs/yaffs2/NOTE.openwrt create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_allocator.c create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_allocator.h create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_attribs.c create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_attribs.h create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_bitmap.c create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_bitmap.h create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_checkptrw.c create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_checkptrw.h create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_ecc.c create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_ecc.h create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_getblockinfo.h create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_guts.c create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_guts.h create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_linux.h create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_mtdif.c create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_mtdif.h create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_nameval.c create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_nameval.h create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_nand.c create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_nand.h create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_packedtags1.c create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_packedtags1.h create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_packedtags2.c create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_packedtags2.h create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_summary.c create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_summary.h create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_tagscompat.c create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_tagscompat.h create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_tagsmarshall.c create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_tagsmarshall.h create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_trace.h create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_verify.c create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_verify.h create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_vfs.c create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_yaffs1.c create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_yaffs1.h create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_yaffs2.c create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_yaffs2.h create mode 100644 target/linux/generic/files/fs/yaffs2/yportenv.h create mode 100644 target/linux/generic/files/include/linux/ar8216_platform.h create mode 100644 target/linux/generic/files/include/linux/ath5k_platform.h create mode 100644 target/linux/generic/files/include/linux/ath9k_platform.h create mode 100644 target/linux/generic/files/include/linux/myloader.h create mode 100644 target/linux/generic/files/include/linux/platform_data/adm6996-gpio.h create mode 100644 target/linux/generic/files/include/linux/platform_data/b53.h create mode 100644 target/linux/generic/files/include/linux/platform_data/brcmfmac-sdio.h create mode 100644 target/linux/generic/files/include/linux/routerboot.h create mode 100644 target/linux/generic/files/include/linux/rt2x00_platform.h create mode 100644 target/linux/generic/files/include/linux/rtl8366.h create mode 100644 target/linux/generic/files/include/linux/rtl8367.h create mode 100644 target/linux/generic/files/include/linux/switch.h create mode 100644 target/linux/generic/files/include/uapi/linux/switch.h create mode 100644 target/linux/generic/image/Makefile create mode 100644 target/linux/generic/image/initramfs-base-files.txt create mode 100644 target/linux/generic/image/lzma-loader/Makefile create mode 100644 target/linux/generic/image/lzma-loader/src/LzmaDecode.c create mode 100644 target/linux/generic/image/lzma-loader/src/LzmaDecode.h create mode 100644 target/linux/generic/image/lzma-loader/src/Makefile create mode 100644 target/linux/generic/image/lzma-loader/src/decompress.c create mode 100644 target/linux/generic/image/lzma-loader/src/lzma-copy.lds.in create mode 100644 target/linux/generic/image/lzma-loader/src/lzma.lds.in create mode 100644 target/linux/generic/image/lzma-loader/src/print.c create mode 100644 target/linux/generic/image/lzma-loader/src/print.h create mode 100644 target/linux/generic/image/lzma-loader/src/printf.c create mode 100644 target/linux/generic/image/lzma-loader/src/printf.h create mode 100644 target/linux/generic/image/lzma-loader/src/start.S create mode 100644 target/linux/generic/image/lzma-loader/src/uart16550.c create mode 100644 target/linux/generic/image/lzma-loader/src/uart16550.h create mode 100644 target/linux/generic/image/relocate/Makefile create mode 100644 target/linux/generic/image/relocate/cacheops.h create mode 100644 target/linux/generic/image/relocate/cp0regdef.h create mode 100644 target/linux/generic/image/relocate/head.S create mode 100644 target/linux/generic/image/relocate/loader.lds create mode 100644 target/linux/generic/patches-3.18/000-keep_initrafs_the_default.patch create mode 100644 target/linux/generic/patches-3.18/020-ssb_update.patch create mode 100644 target/linux/generic/patches-3.18/021-ssb_sprom.patch create mode 100644 target/linux/generic/patches-3.18/025-bcma_backport.patch create mode 100644 target/linux/generic/patches-3.18/026-bcma-from-3.20.patch create mode 100644 target/linux/generic/patches-3.18/027-bcma-from-4.1.patch create mode 100644 target/linux/generic/patches-3.18/028-bcma-from-4.2.patch create mode 100644 target/linux/generic/patches-3.18/030-nl80211-Allow-set-network-namespace-by-fd.patch create mode 100644 target/linux/generic/patches-3.18/040-mtd-bcm47xxpart-backports-from-3.19.patch create mode 100644 target/linux/generic/patches-3.18/041-mtd-bcm47xxpart-backports-from-3.20.patch create mode 100644 target/linux/generic/patches-3.18/050-backport_netfilter_rtcache.patch create mode 100644 target/linux/generic/patches-3.18/051-02-bridge-allow-setting-hash_max-multicast_router-if-in.patch create mode 100644 target/linux/generic/patches-3.18/060-mips_decompressor_memmove.patch create mode 100644 target/linux/generic/patches-3.18/070-bgmac-register-napi-before-the-device.patch create mode 100644 target/linux/generic/patches-3.18/071-bgmac-activate-irqs-only-if-there-is-nothing-to-poll.patch create mode 100644 target/linux/generic/patches-3.18/072-bgmac-fix-device-initialization-on-Northstar-SoCs-co.patch create mode 100644 target/linux/generic/patches-3.18/073-bgmac-Clean-warning-messages.patch create mode 100644 target/linux/generic/patches-3.18/074-bgmac-register-fixed-PHY-for-ARM-BCM470X-BCM5301X-ch.patch create mode 100644 target/linux/generic/patches-3.18/075-bgmac-allow-enabling-on-ARCH_BCM_5301X.patch create mode 100644 target/linux/generic/patches-3.18/076-net-phy-export-fixed_phy_register.patch create mode 100644 target/linux/generic/patches-3.18/077-01-bgmac-fix-descriptor-frame-start-end-definitions.patch create mode 100644 target/linux/generic/patches-3.18/077-02-bgmac-implement-GRO-and-use-build_skb.patch create mode 100644 target/linux/generic/patches-3.18/077-03-bgmac-implement-scatter-gather-support.patch create mode 100644 target/linux/generic/patches-3.18/077-04-bgmac-simplify-tx-ring-index-handling.patch create mode 100644 target/linux/generic/patches-3.18/077-05-bgmac-leave-interrupts-disabled-as-long-as-there-is-.patch create mode 100644 target/linux/generic/patches-3.18/077-06-bgmac-set-received-skb-headroom-to-NET_SKB_PAD.patch create mode 100644 target/linux/generic/patches-3.18/077-07-bgmac-simplify-rx-DMA-error-handling.patch create mode 100644 target/linux/generic/patches-3.18/077-08-bgmac-add-check-for-oversized-packets.patch create mode 100644 target/linux/generic/patches-3.18/077-09-bgmac-increase-rx-ring-size-from-511-to-512.patch create mode 100644 target/linux/generic/patches-3.18/077-10-bgmac-simplify-dma-init-cleanup.patch create mode 100644 target/linux/generic/patches-3.18/077-11-bgmac-fix-DMA-rx-corruption.patch create mode 100644 target/linux/generic/patches-3.18/077-12-bgmac-drop-ring-num_slots.patch create mode 100644 target/linux/generic/patches-3.18/077-13-bgmac-fix-MAC-soft-reset-bit-for-corerev-4.patch create mode 100644 target/linux/generic/patches-3.18/077-14-bgmac-reset-all-4-GMAC-cores-on-init.patch create mode 100644 target/linux/generic/patches-3.18/080-00-fib_trie-Fix-proc-net-fib_trie-when-CONFIG_IP_MULTIP.patch create mode 100644 target/linux/generic/patches-3.18/080-01-fib_trie-Fix-trie-balancing-issue-if-new-node-pushes.patch create mode 100644 target/linux/generic/patches-3.18/080-02-fib_trie-Update-usage-stats-to-be-percpu-instead-of-.patch create mode 100644 target/linux/generic/patches-3.18/080-03-fib_trie-Make-leaf-and-tnode-more-uniform.patch create mode 100644 target/linux/generic/patches-3.18/080-04-fib_trie-Merge-tnode_free-and-leaf_free-into-node_fr.patch create mode 100644 target/linux/generic/patches-3.18/080-05-fib_trie-Merge-leaf-into-tnode.patch create mode 100644 target/linux/generic/patches-3.18/080-06-fib_trie-Optimize-fib_table_lookup-to-avoid-wasting-.patch create mode 100644 target/linux/generic/patches-3.18/080-07-fib_trie-Optimize-fib_find_node.patch create mode 100644 target/linux/generic/patches-3.18/080-08-fib_trie-Optimize-fib_table_insert.patch create mode 100644 target/linux/generic/patches-3.18/080-09-fib_trie-Update-meaning-of-pos-to-represent-unchecke.patch create mode 100644 target/linux/generic/patches-3.18/080-10-fib_trie-Use-unsigned-long-for-anything-dealing-with.patch create mode 100644 target/linux/generic/patches-3.18/080-11-fib_trie-Push-rcu_read_lock-unlock-to-callers.patch create mode 100644 target/linux/generic/patches-3.18/080-12-fib_trie-Move-resize-to-after-inflate-halve.patch create mode 100644 target/linux/generic/patches-3.18/080-13-fib_trie-Add-functions-should_inflate-and-should_hal.patch create mode 100644 target/linux/generic/patches-3.18/080-14-fib_trie-Push-assignment-of-child-to-parent-down-int.patch create mode 100644 target/linux/generic/patches-3.18/080-15-fib_trie-Push-tnode-flushing-down-to-inflate-halve.patch create mode 100644 target/linux/generic/patches-3.18/080-16-fib_trie-inflate-halve-nodes-in-a-more-RCU-friendly-.patch create mode 100644 target/linux/generic/patches-3.18/080-17-fib_trie-Remove-checks-for-index-tnode_child_length-.patch create mode 100644 target/linux/generic/patches-3.18/080-18-fib_trie-Add-tracking-value-for-suffix-length.patch create mode 100644 target/linux/generic/patches-3.18/080-19-fib_trie-Use-index-0ul-n-bits-instead-of-index-n-bit.patch create mode 100644 target/linux/generic/patches-3.18/080-20-fib_trie-Fix-RCU-bug-and-merge-similar-bits-of-infla.patch create mode 100644 target/linux/generic/patches-3.18/080-21-fib_trie-Fall-back-to-slen-update-on-inflate-halve-f.patch create mode 100644 target/linux/generic/patches-3.18/080-22-fib_trie-Add-collapse-and-should_collapse-to-resize.patch create mode 100644 target/linux/generic/patches-3.18/080-23-fib_trie-Use-empty_children-instead-of-counting-empt.patch create mode 100644 target/linux/generic/patches-3.18/080-24-fib_trie-Move-fib_find_alias-to-file-where-it-is-use.patch create mode 100644 target/linux/generic/patches-3.18/080-25-fib_trie-Various-clean-ups-for-handling-slen.patch create mode 100644 target/linux/generic/patches-3.18/081-pppoe-Use-workqueue-to-die-properly-when-a-PADT-is-r.patch create mode 100644 target/linux/generic/patches-3.18/082-ipv6-ip6_fragment-fix-headroom-tests-and-skb-leak.patch create mode 100644 target/linux/generic/patches-3.18/083-solos-pci-Increase-headroom-on-received-packets.patch create mode 100644 target/linux/generic/patches-3.18/090-overlayfs-fallback-to-readonly-when-full.patch create mode 100644 target/linux/generic/patches-3.18/091-mtd-spi-nor-add-support-Spansion_S25FL164K create mode 100644 target/linux/generic/patches-3.18/092-01-spi-Check-to-see-if-the-device-is-processing-a-messa.patch create mode 100644 target/linux/generic/patches-3.18/092-02-spi-Pump-transfers-inside-calling-context-for-spi_sy.patch create mode 100644 target/linux/generic/patches-3.18/092-03-spi-Only-idle-the-message-pump-in-the-worker-kthread.patch create mode 100644 target/linux/generic/patches-3.18/095-api-fix-compatibility-of-linux-in.h-with-netinet-in..patch create mode 100644 target/linux/generic/patches-3.18/099-module_arch_freeing_init-new-hook-for-archs-before-m.patch create mode 100644 target/linux/generic/patches-3.18/100-pppoe-drop-pppoe-device-in-pppoe_unbind_sock_work.patch create mode 100644 target/linux/generic/patches-3.18/101-pppoe-fix-disconnect-crash.patch create mode 100644 target/linux/generic/patches-3.18/102-ehci_hcd_ignore_oc.patch create mode 100644 target/linux/generic/patches-3.18/110-jffs2-use-.rename2-and-add-RENAME_WHITEOUT-support.patch create mode 100644 target/linux/generic/patches-3.18/111-jffs2-add-RENAME_EXCHANGE-support.patch create mode 100644 target/linux/generic/patches-3.18/120-bridge_allow_receiption_on_disabled_port.patch create mode 100644 target/linux/generic/patches-3.18/132-mips_inline_dma_ops.patch create mode 100644 target/linux/generic/patches-3.18/140-mtd-part-add-generic-parsing-of-linux-part-probe.patch create mode 100644 target/linux/generic/patches-3.18/180-usb-xhci-make-USB_XHCI_PLATFORM-selectable.patch create mode 100644 target/linux/generic/patches-3.18/190-cdc_ncm_add_support_for_moving_ndp_to_end_of_ncm_frame.patch create mode 100644 target/linux/generic/patches-3.18/191-usb-ehci-orion-fix-probe-for-GENERIC_PHY.patch create mode 100644 target/linux/generic/patches-3.18/200-fix_localversion.patch create mode 100644 target/linux/generic/patches-3.18/201-extra_optimization.patch create mode 100644 target/linux/generic/patches-3.18/202-reduce_module_size.patch create mode 100644 target/linux/generic/patches-3.18/203-kallsyms_uncompressed.patch create mode 100644 target/linux/generic/patches-3.18/204-module_strip.patch create mode 100644 target/linux/generic/patches-3.18/205-backtrace_module_info.patch create mode 100644 target/linux/generic/patches-3.18/210-darwin_scripts_include.patch create mode 100644 target/linux/generic/patches-3.18/212-byteshift_portability.patch create mode 100644 target/linux/generic/patches-3.18/213-x86_vdso_portability.patch create mode 100644 target/linux/generic/patches-3.18/214-spidev_h_portability.patch create mode 100644 target/linux/generic/patches-3.18/220-gc_sections.patch create mode 100644 target/linux/generic/patches-3.18/221-module_exports.patch create mode 100644 target/linux/generic/patches-3.18/230-openwrt_lzma_options.patch create mode 100644 target/linux/generic/patches-3.18/250-netfilter_depends.patch create mode 100644 target/linux/generic/patches-3.18/251-sound_kconfig.patch create mode 100644 target/linux/generic/patches-3.18/252-mv_cesa_depends.patch create mode 100644 target/linux/generic/patches-3.18/253-ssb_b43_default_on.patch create mode 100644 target/linux/generic/patches-3.18/254-textsearch_kconfig_hacks.patch create mode 100644 target/linux/generic/patches-3.18/255-lib80211_kconfig_hacks.patch create mode 100644 target/linux/generic/patches-3.18/256-crypto_add_kconfig_prompts.patch create mode 100644 target/linux/generic/patches-3.18/257-wireless_ext_kconfig_hack.patch create mode 100644 target/linux/generic/patches-3.18/258-netfilter_netlink_kconfig_hack.patch create mode 100644 target/linux/generic/patches-3.18/259-regmap_dynamic.patch create mode 100644 target/linux/generic/patches-3.18/260-crypto_test_dependencies.patch create mode 100644 target/linux/generic/patches-3.18/262-compressor_kconfig_hack.patch create mode 100644 target/linux/generic/patches-3.18/270-uapi-kernel.h-glibc-specific-inclusion-of-sysinfo.h.patch create mode 100644 target/linux/generic/patches-3.18/271-uapi-libc-compat.h-do-not-rely-on-__GLIBC__.patch create mode 100644 target/linux/generic/patches-3.18/272-uapi-if_ether.h-prevent-redefinition-of-struct-ethhd.patch create mode 100644 target/linux/generic/patches-3.18/300-mips_expose_boot_raw.patch create mode 100644 target/linux/generic/patches-3.18/301-mips_image_cmdline_hack.patch create mode 100644 target/linux/generic/patches-3.18/302-mips_no_branch_likely.patch create mode 100644 target/linux/generic/patches-3.18/304-mips_disable_fpu.patch create mode 100644 target/linux/generic/patches-3.18/305-mips_module_reloc.patch create mode 100644 target/linux/generic/patches-3.18/306-mips_mem_functions_performance.patch create mode 100644 target/linux/generic/patches-3.18/307-mips_highmem_offset.patch create mode 100644 target/linux/generic/patches-3.18/309-mips_fuse_workaround.patch create mode 100644 target/linux/generic/patches-3.18/310-arm_module_unresolved_weak_sym.patch create mode 100644 target/linux/generic/patches-3.18/320-ppc4xx_optimization.patch create mode 100644 target/linux/generic/patches-3.18/321-powerpc_crtsavres_prereq.patch create mode 100644 target/linux/generic/patches-3.18/330-MIPS-kexec-Accept-command-line-parameters-from-users.patch create mode 100644 target/linux/generic/patches-3.18/400-mtd-add-rootfs-split-support.patch create mode 100644 target/linux/generic/patches-3.18/401-mtd-add-support-for-different-partition-parser-types.patch create mode 100644 target/linux/generic/patches-3.18/402-mtd-use-typed-mtd-parsers-for-rootfs-and-firmware-split.patch create mode 100644 target/linux/generic/patches-3.18/403-mtd-hook-mtdsplit-to-Kbuild.patch create mode 100644 target/linux/generic/patches-3.18/404-mtd-add-more-helper-functions.patch create mode 100644 target/linux/generic/patches-3.18/405-mtd-old-firmware-uimage-splitter.patch create mode 100644 target/linux/generic/patches-3.18/406-mtd-old-rootfs-squashfs-splitter.patch create mode 100644 target/linux/generic/patches-3.18/410-mtd-move-forward-declaration-of-struct-mtd_info.patch create mode 100644 target/linux/generic/patches-3.18/411-mtd-partial_eraseblock_write.patch create mode 100644 target/linux/generic/patches-3.18/412-mtd-partial_eraseblock_unlock.patch create mode 100644 target/linux/generic/patches-3.18/420-mtd-redboot_space.patch create mode 100644 target/linux/generic/patches-3.18/430-mtd-add-myloader-partition-parser.patch create mode 100644 target/linux/generic/patches-3.18/431-mtd-bcm47xxpart-support-for-Xiaomi-specific-board_da.patch create mode 100644 target/linux/generic/patches-3.18/432-mtd-bcm47xxpart-detect-T_Meter-partition.patch create mode 100644 target/linux/generic/patches-3.18/440-block2mtd_init.patch create mode 100644 target/linux/generic/patches-3.18/441-block2mtd_probe.patch create mode 100644 target/linux/generic/patches-3.18/450-mtd-nand-allow-to-use-platform-specific-chip-fixup.patch create mode 100644 target/linux/generic/patches-3.18/451-mtd-nand-fix-return-code-of-nand_correct_data-function.patch create mode 100644 target/linux/generic/patches-3.18/460-mtd-cfi_cmdset_0002-no-erase_suspend.patch create mode 100644 target/linux/generic/patches-3.18/461-mtd-cfi_cmdset_0002-add-buffer-write-cmd-timeout.patch create mode 100644 target/linux/generic/patches-3.18/472-mtd-m25p80-add-support-for-Winbond-W25X05-flash.patch create mode 100644 target/linux/generic/patches-3.18/473-mtd-spi-nor-add-support-for-the-Macronix-MX25L512E-S.patch create mode 100644 target/linux/generic/patches-3.18/474-mtd-spi-nor-add-support-for-the-ISSI-SI25CD512-SPI-f.patch create mode 100644 target/linux/generic/patches-3.18/480-mtd-set-rootfs-to-be-root-dev.patch create mode 100644 target/linux/generic/patches-3.18/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch create mode 100644 target/linux/generic/patches-3.18/491-ubi-auto-create-ubiblock-device-for-rootfs.patch create mode 100644 target/linux/generic/patches-3.18/492-try-auto-mounting-ubi0-rootfs-in-init-do_mounts.c.patch create mode 100644 target/linux/generic/patches-3.18/493-ubi-set-ROOT_DEV-to-ubiblock-rootfs-if-unset.patch create mode 100644 target/linux/generic/patches-3.18/494-mtd-ubi-add-EOF-marker-support.patch create mode 100644 target/linux/generic/patches-3.18/500-yaffs-Kbuild-integration.patch create mode 100644 target/linux/generic/patches-3.18/502-yaffs-fix-compat-tags-handling.patch create mode 100644 target/linux/generic/patches-3.18/503-yaffs-add-tags-9bytes-mount-option.patch create mode 100644 target/linux/generic/patches-3.18/504-yaffs-3.16-new-fops.patch create mode 100644 target/linux/generic/patches-3.18/520-squashfs_update_xz_comp_opts.patch create mode 100644 target/linux/generic/patches-3.18/530-jffs2_make_lzma_available.patch create mode 100644 target/linux/generic/patches-3.18/531-debloat_lzma.patch create mode 100644 target/linux/generic/patches-3.18/532-jffs2_eofdetect.patch create mode 100644 target/linux/generic/patches-3.18/540-crypto-xz-decompression-support.patch create mode 100644 target/linux/generic/patches-3.18/541-ubifs-xz-decompression-support.patch create mode 100644 target/linux/generic/patches-3.18/550-ubifs-symlink-xattr-support.patch create mode 100644 target/linux/generic/patches-3.18/551-ubifs-fix-default-compression-selection.patch create mode 100644 target/linux/generic/patches-3.18/600-netfilter_conntrack_flush.patch create mode 100644 target/linux/generic/patches-3.18/610-netfilter_match_bypass_default_checks.patch create mode 100644 target/linux/generic/patches-3.18/611-netfilter_match_bypass_default_table.patch create mode 100644 target/linux/generic/patches-3.18/612-netfilter_match_reduce_memory_access.patch create mode 100644 target/linux/generic/patches-3.18/613-netfilter_optional_tcp_window_check.patch create mode 100644 target/linux/generic/patches-3.18/615-netfilter_add_xt_id_match.patch create mode 100644 target/linux/generic/patches-3.18/616-net_optimize_xfrm_calls.patch create mode 100644 target/linux/generic/patches-3.18/620-sched_esfq.patch create mode 100644 target/linux/generic/patches-3.18/621-sched_act_connmark.patch create mode 100644 target/linux/generic/patches-3.18/630-packet_socket_type.patch create mode 100644 target/linux/generic/patches-3.18/640-bridge_no_eap_forward.patch create mode 100644 target/linux/generic/patches-3.18/641-bridge_always_accept_eap.patch create mode 100644 target/linux/generic/patches-3.18/642-bridge_port_isolate.patch create mode 100644 target/linux/generic/patches-3.18/643-bridge_remove_ipv6_dependency.patch create mode 100644 target/linux/generic/patches-3.18/645-bridge_multicast_to_unicast.patch create mode 100644 target/linux/generic/patches-3.18/650-pppoe_header_pad.patch create mode 100644 target/linux/generic/patches-3.18/651-wireless_mesh_header.patch create mode 100644 target/linux/generic/patches-3.18/653-disable_netlink_trim.patch create mode 100644 target/linux/generic/patches-3.18/655-increase_skb_pad.patch create mode 100644 target/linux/generic/patches-3.18/656-skb_reduce_truesize-helper.patch create mode 100644 target/linux/generic/patches-3.18/657-qdisc_reduce_truesize.patch create mode 100644 target/linux/generic/patches-3.18/660-fq_codel_defaults.patch create mode 100644 target/linux/generic/patches-3.18/661-fq_codel_keep_dropped_stats.patch create mode 100644 target/linux/generic/patches-3.18/662-use_fq_codel_by_default.patch create mode 100644 target/linux/generic/patches-3.18/663-remove_pfifo_fast.patch create mode 100644 target/linux/generic/patches-3.18/666-Add-support-for-MAP-E-FMRs-mesh-mode.patch create mode 100644 target/linux/generic/patches-3.18/667-ipv6-Fixed-source-specific-default-route-handling.patch create mode 100644 target/linux/generic/patches-3.18/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch create mode 100644 target/linux/generic/patches-3.18/671-net-provide-defines-for-_POLICY_FAILED-until-all-cod.patch create mode 100644 target/linux/generic/patches-3.18/680-NET-skip-GRO-for-foreign-MAC-addresses.patch create mode 100644 target/linux/generic/patches-3.18/681-NET-add-of_get_mac_address_mtd.patch create mode 100644 target/linux/generic/patches-3.18/700-swconfig.patch create mode 100644 target/linux/generic/patches-3.18/701-phy_extension.patch create mode 100644 target/linux/generic/patches-3.18/702-phy_add_aneg_done_function.patch create mode 100644 target/linux/generic/patches-3.18/703-phy-add-detach-callback-to-struct-phy_driver.patch create mode 100644 target/linux/generic/patches-3.18/704-phy-no-genphy-soft-reset.patch create mode 100644 target/linux/generic/patches-3.18/710-phy-add-mdio_register_board_info.patch create mode 100644 target/linux/generic/patches-3.18/720-phy_adm6996.patch create mode 100644 target/linux/generic/patches-3.18/721-phy_packets.patch create mode 100644 target/linux/generic/patches-3.18/722-phy_mvswitch.patch create mode 100644 target/linux/generic/patches-3.18/723-phy_ip175c.patch create mode 100644 target/linux/generic/patches-3.18/724-phy_ar8216.patch create mode 100644 target/linux/generic/patches-3.18/725-phy_rtl8306.patch create mode 100644 target/linux/generic/patches-3.18/726-phy_rtl8366.patch create mode 100644 target/linux/generic/patches-3.18/727-phy-rtl8367.patch create mode 100644 target/linux/generic/patches-3.18/728-phy-rtl8367b.patch create mode 100644 target/linux/generic/patches-3.18/729-phy-tantos.patch create mode 100644 target/linux/generic/patches-3.18/730-phy_b53.patch create mode 100644 target/linux/generic/patches-3.18/731-phy_mvswitch_3.10_compilation.patch create mode 100644 target/linux/generic/patches-3.18/732-phy-ar8216-led-support.patch create mode 100644 target/linux/generic/patches-3.18/733-phy_mvsw61xx.patch create mode 100644 target/linux/generic/patches-3.18/750-hostap_txpower.patch create mode 100644 target/linux/generic/patches-3.18/773-bgmac-add-srab-switch.patch create mode 100644 target/linux/generic/patches-3.18/780-igb-Fix-Null-pointer-dereference-in-igb_reset_q_vect.patch create mode 100644 target/linux/generic/patches-3.18/785-hso-support-0af0-9300.patch create mode 100644 target/linux/generic/patches-3.18/810-pci_disable_common_quirks.patch create mode 100644 target/linux/generic/patches-3.18/811-pci_disable_usb_common_quirks.patch create mode 100644 target/linux/generic/patches-3.18/820-usb_add_usb_find_device_by_name.patch create mode 100644 target/linux/generic/patches-3.18/821-usb-dwc2-dualrole.patch create mode 100644 target/linux/generic/patches-3.18/830-ledtrig_morse.patch create mode 100644 target/linux/generic/patches-3.18/831-ledtrig_netdev.patch create mode 100644 target/linux/generic/patches-3.18/832-ledtrig_usbdev.patch create mode 100644 target/linux/generic/patches-3.18/834-ledtrig-libata.patch create mode 100644 target/linux/generic/patches-3.18/840-rtc7301.patch create mode 100644 target/linux/generic/patches-3.18/841-rtc_pt7c4338.patch create mode 100644 target/linux/generic/patches-3.18/861-04_spi_gpio_implement_spi_delay.patch create mode 100644 target/linux/generic/patches-3.18/862-gpio_spi_driver.patch create mode 100644 target/linux/generic/patches-3.18/863-gpiommc.patch create mode 100644 target/linux/generic/patches-3.18/864-gpiommc_configfs_locking.patch create mode 100644 target/linux/generic/patches-3.18/870-hifn795x_byteswap.patch create mode 100644 target/linux/generic/patches-3.18/880-gateworks_system_controller.patch create mode 100644 target/linux/generic/patches-3.18/890-8250_optional_sysrq.patch create mode 100644 target/linux/generic/patches-3.18/900-slab_maxsize.patch create mode 100644 target/linux/generic/patches-3.18/901-debloat_sock_diag.patch create mode 100644 target/linux/generic/patches-3.18/902-debloat_proc.patch create mode 100644 target/linux/generic/patches-3.18/903-debloat_direct_io.patch create mode 100644 target/linux/generic/patches-3.18/910-kobject_uevent.patch create mode 100644 target/linux/generic/patches-3.18/911-kobject_add_broadcast_uevent.patch create mode 100644 target/linux/generic/patches-3.18/921-use_preinit_as_init.patch create mode 100644 target/linux/generic/patches-3.18/922-always-create-console-node-in-initramfs.patch create mode 100644 target/linux/generic/patches-3.18/930-crashlog.patch create mode 100644 target/linux/generic/patches-3.18/940-ocf_kbuild_integration.patch create mode 100644 target/linux/generic/patches-3.18/941-ocf_20120127.patch create mode 100644 target/linux/generic/patches-3.18/960-decompress_unlzo_fix.patch create mode 100644 target/linux/generic/patches-3.18/970-remove-unsane-filenames-from-deps_initramfs-list.patch create mode 100644 target/linux/generic/patches-3.18/980-arm_openwrt_machtypes.patch create mode 100644 target/linux/generic/patches-3.18/990-gpio_wdt.patch create mode 100644 target/linux/generic/patches-3.18/995-mangle_bootargs.patch create mode 100644 target/linux/generic/patches-3.18/997-device_tree_cmdline.patch create mode 100644 target/linux/generic/patches-3.18/998-enable_wilink_platform_without_drivers.patch create mode 100644 target/linux/generic/patches-3.18/999-seccomp_log.patch create mode 100644 target/linux/generic/patches-4.0/000-keep_initrafs_the_default.patch create mode 100644 target/linux/generic/patches-4.0/020-ssb_update.patch create mode 100644 target/linux/generic/patches-4.0/021-bcma-from-4.1.patch create mode 100644 target/linux/generic/patches-4.0/021-ssb_sprom.patch create mode 100644 target/linux/generic/patches-4.0/022-bcma-from-4.2.patch create mode 100644 target/linux/generic/patches-4.0/050-backport_netfilter_rtcache.patch create mode 100644 target/linux/generic/patches-4.0/060-mips_decompressor_memmove.patch create mode 100644 target/linux/generic/patches-4.0/070-bgmac-register-fixed-PHY-for-ARM-BCM470X-BCM5301X-ch.patch create mode 100644 target/linux/generic/patches-4.0/071-bgmac-allow-enabling-on-ARCH_BCM_5301X.patch create mode 100644 target/linux/generic/patches-4.0/072-01-bgmac-fix-descriptor-frame-start-end-definitions.patch create mode 100644 target/linux/generic/patches-4.0/072-02-bgmac-implement-GRO-and-use-build_skb.patch create mode 100644 target/linux/generic/patches-4.0/072-03-bgmac-implement-scatter-gather-support.patch create mode 100644 target/linux/generic/patches-4.0/072-04-bgmac-simplify-tx-ring-index-handling.patch create mode 100644 target/linux/generic/patches-4.0/072-05-bgmac-leave-interrupts-disabled-as-long-as-there-is-.patch create mode 100644 target/linux/generic/patches-4.0/072-06-bgmac-set-received-skb-headroom-to-NET_SKB_PAD.patch create mode 100644 target/linux/generic/patches-4.0/072-07-bgmac-simplify-rx-DMA-error-handling.patch create mode 100644 target/linux/generic/patches-4.0/072-08-bgmac-add-check-for-oversized-packets.patch create mode 100644 target/linux/generic/patches-4.0/072-09-bgmac-increase-rx-ring-size-from-511-to-512.patch create mode 100644 target/linux/generic/patches-4.0/072-10-bgmac-simplify-dma-init-cleanup.patch create mode 100644 target/linux/generic/patches-4.0/072-11-bgmac-fix-DMA-rx-corruption.patch create mode 100644 target/linux/generic/patches-4.0/072-12-bgmac-drop-ring-num_slots.patch create mode 100644 target/linux/generic/patches-4.0/072-13-bgmac-fix-MAC-soft-reset-bit-for-corerev-4.patch create mode 100644 target/linux/generic/patches-4.0/072-14-bgmac-reset-all-4-GMAC-cores-on-init.patch create mode 100644 target/linux/generic/patches-4.0/072-15-bgmac-fix-requests-for-extra-polling-calls-from-NAPI.patch create mode 100644 target/linux/generic/patches-4.0/073-pppoe-Use-workqueue-to-die-properly-when-a-PADT-is-r.patch create mode 100644 target/linux/generic/patches-4.0/091-mtd-spi-nor-add-support-Spansion_S25FL164K create mode 100644 target/linux/generic/patches-4.0/095-api-fix-compatibility-of-linux-in.h-with-netinet-in..patch create mode 100644 target/linux/generic/patches-4.0/100-pppoe-drop-pppoe-device-in-pppoe_unbind_sock_work.patch create mode 100644 target/linux/generic/patches-4.0/102-ehci_hcd_ignore_oc.patch create mode 100644 target/linux/generic/patches-4.0/110-jffs2-use-.rename2-and-add-RENAME_WHITEOUT-support.patch create mode 100644 target/linux/generic/patches-4.0/111-jffs2-add-RENAME_EXCHANGE-support.patch create mode 100644 target/linux/generic/patches-4.0/120-bridge_allow_receiption_on_disabled_port.patch create mode 100644 target/linux/generic/patches-4.0/130-MIPS-kernel-fix-sched_getaffinity-with-MT-FPAFF-enab.patch create mode 100644 target/linux/generic/patches-4.0/132-mips_inline_dma_ops.patch create mode 100644 target/linux/generic/patches-4.0/140-overlayfs_readdir_locking_fix.patch create mode 100644 target/linux/generic/patches-4.0/180-usb-xhci-make-USB_XHCI_PLATFORM-selectable.patch create mode 100644 target/linux/generic/patches-4.0/190-cdc_ncm_add_support_for_moving_ndp_to_end_of_ncm_frame.patch create mode 100644 target/linux/generic/patches-4.0/191-usb-ehci-orion-fix-probe-for-GENERIC_PHY.patch create mode 100644 target/linux/generic/patches-4.0/200-fix_localversion.patch create mode 100644 target/linux/generic/patches-4.0/201-extra_optimization.patch create mode 100644 target/linux/generic/patches-4.0/202-reduce_module_size.patch create mode 100644 target/linux/generic/patches-4.0/203-kallsyms_uncompressed.patch create mode 100644 target/linux/generic/patches-4.0/204-module_strip.patch create mode 100644 target/linux/generic/patches-4.0/205-backtrace_module_info.patch create mode 100644 target/linux/generic/patches-4.0/210-darwin_scripts_include.patch create mode 100644 target/linux/generic/patches-4.0/212-byteshift_portability.patch create mode 100644 target/linux/generic/patches-4.0/214-spidev_h_portability.patch create mode 100644 target/linux/generic/patches-4.0/220-gc_sections.patch create mode 100644 target/linux/generic/patches-4.0/221-module_exports.patch create mode 100644 target/linux/generic/patches-4.0/230-openwrt_lzma_options.patch create mode 100644 target/linux/generic/patches-4.0/250-netfilter_depends.patch create mode 100644 target/linux/generic/patches-4.0/251-sound_kconfig.patch create mode 100644 target/linux/generic/patches-4.0/252-mv_cesa_depends.patch create mode 100644 target/linux/generic/patches-4.0/253-ssb_b43_default_on.patch create mode 100644 target/linux/generic/patches-4.0/254-textsearch_kconfig_hacks.patch create mode 100644 target/linux/generic/patches-4.0/255-lib80211_kconfig_hacks.patch create mode 100644 target/linux/generic/patches-4.0/256-crypto_add_kconfig_prompts.patch create mode 100644 target/linux/generic/patches-4.0/257-wireless_ext_kconfig_hack.patch create mode 100644 target/linux/generic/patches-4.0/258-netfilter_netlink_kconfig_hack.patch create mode 100644 target/linux/generic/patches-4.0/259-regmap_dynamic.patch create mode 100644 target/linux/generic/patches-4.0/260-crypto_test_dependencies.patch create mode 100644 target/linux/generic/patches-4.0/262-compressor_kconfig_hack.patch create mode 100644 target/linux/generic/patches-4.0/270-uapi-kernel.h-glibc-specific-inclusion-of-sysinfo.h.patch create mode 100644 target/linux/generic/patches-4.0/271-uapi-libc-compat.h-do-not-rely-on-__GLIBC__.patch create mode 100644 target/linux/generic/patches-4.0/272-uapi-if_ether.h-prevent-redefinition-of-struct-ethhd.patch create mode 100644 target/linux/generic/patches-4.0/300-mips_expose_boot_raw.patch create mode 100644 target/linux/generic/patches-4.0/301-mips_image_cmdline_hack.patch create mode 100644 target/linux/generic/patches-4.0/302-mips_no_branch_likely.patch create mode 100644 target/linux/generic/patches-4.0/304-mips_disable_fpu.patch create mode 100644 target/linux/generic/patches-4.0/305-mips_module_reloc.patch create mode 100644 target/linux/generic/patches-4.0/306-mips_mem_functions_performance.patch create mode 100644 target/linux/generic/patches-4.0/307-mips_highmem_offset.patch create mode 100644 target/linux/generic/patches-4.0/309-mips_fuse_workaround.patch create mode 100644 target/linux/generic/patches-4.0/310-arm_module_unresolved_weak_sym.patch create mode 100644 target/linux/generic/patches-4.0/320-ppc4xx_optimization.patch create mode 100644 target/linux/generic/patches-4.0/321-powerpc_crtsavres_prereq.patch create mode 100644 target/linux/generic/patches-4.0/330-MIPS-kexec-Accept-command-line-parameters-from-users.patch create mode 100644 target/linux/generic/patches-4.0/400-mtd-add-rootfs-split-support.patch create mode 100644 target/linux/generic/patches-4.0/401-mtd-add-support-for-different-partition-parser-types.patch create mode 100644 target/linux/generic/patches-4.0/402-mtd-use-typed-mtd-parsers-for-rootfs-and-firmware-split.patch create mode 100644 target/linux/generic/patches-4.0/403-mtd-hook-mtdsplit-to-Kbuild.patch create mode 100644 target/linux/generic/patches-4.0/404-mtd-add-more-helper-functions.patch create mode 100644 target/linux/generic/patches-4.0/405-mtd-old-firmware-uimage-splitter.patch create mode 100644 target/linux/generic/patches-4.0/406-mtd-old-rootfs-squashfs-splitter.patch create mode 100644 target/linux/generic/patches-4.0/410-mtd-move-forward-declaration-of-struct-mtd_info.patch create mode 100644 target/linux/generic/patches-4.0/411-mtd-partial_eraseblock_write.patch create mode 100644 target/linux/generic/patches-4.0/412-mtd-partial_eraseblock_unlock.patch create mode 100644 target/linux/generic/patches-4.0/420-mtd-redboot_space.patch create mode 100644 target/linux/generic/patches-4.0/430-mtd-add-myloader-partition-parser.patch create mode 100644 target/linux/generic/patches-4.0/431-mtd-bcm47xxpart-support-for-Xiaomi-specific-board_da.patch create mode 100644 target/linux/generic/patches-4.0/432-mtd-bcm47xxpart-detect-T_Meter-partition.patch create mode 100644 target/linux/generic/patches-4.0/440-block2mtd_init.patch create mode 100644 target/linux/generic/patches-4.0/441-block2mtd_probe.patch create mode 100644 target/linux/generic/patches-4.0/450-mtd-nand-allow-to-use-platform-specific-chip-fixup.patch create mode 100644 target/linux/generic/patches-4.0/451-mtd-nand-fix-return-code-of-nand_correct_data-function.patch create mode 100644 target/linux/generic/patches-4.0/460-mtd-cfi_cmdset_0002-no-erase_suspend.patch create mode 100644 target/linux/generic/patches-4.0/461-mtd-cfi_cmdset_0002-add-buffer-write-cmd-timeout.patch create mode 100644 target/linux/generic/patches-4.0/472-mtd-m25p80-add-support-for-Winbond-W25X05-flash.patch create mode 100644 target/linux/generic/patches-4.0/473-mtd-spi-nor-add-support-for-the-Macronix-MX25L512E-S.patch create mode 100644 target/linux/generic/patches-4.0/474-mtd-spi-nor-add-support-for-the-ISSI-SI25CD512-SPI-f.patch create mode 100644 target/linux/generic/patches-4.0/480-mtd-set-rootfs-to-be-root-dev.patch create mode 100644 target/linux/generic/patches-4.0/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch create mode 100644 target/linux/generic/patches-4.0/491-ubi-auto-create-ubiblock-device-for-rootfs.patch create mode 100644 target/linux/generic/patches-4.0/492-try-auto-mounting-ubi0-rootfs-in-init-do_mounts.c.patch create mode 100644 target/linux/generic/patches-4.0/493-ubi-set-ROOT_DEV-to-ubiblock-rootfs-if-unset.patch create mode 100644 target/linux/generic/patches-4.0/494-mtd-ubi-add-EOF-marker-support.patch create mode 100644 target/linux/generic/patches-4.0/500-yaffs-Kbuild-integration.patch create mode 100644 target/linux/generic/patches-4.0/502-yaffs-fix-compat-tags-handling.patch create mode 100644 target/linux/generic/patches-4.0/503-yaffs-add-tags-9bytes-mount-option.patch create mode 100644 target/linux/generic/patches-4.0/504-yaffs-3.16-new-fops.patch create mode 100644 target/linux/generic/patches-4.0/505-yaffs-3.19-f_dentry-remove.patch create mode 100644 target/linux/generic/patches-4.0/520-squashfs_update_xz_comp_opts.patch create mode 100644 target/linux/generic/patches-4.0/530-jffs2_make_lzma_available.patch create mode 100644 target/linux/generic/patches-4.0/531-debloat_lzma.patch create mode 100644 target/linux/generic/patches-4.0/532-jffs2_eofdetect.patch create mode 100644 target/linux/generic/patches-4.0/540-crypto-xz-decompression-support.patch create mode 100644 target/linux/generic/patches-4.0/541-ubifs-xz-decompression-support.patch create mode 100644 target/linux/generic/patches-4.0/551-ubifs-fix-default-compression-selection.patch create mode 100644 target/linux/generic/patches-4.0/600-netfilter_conntrack_flush.patch create mode 100644 target/linux/generic/patches-4.0/610-netfilter_match_bypass_default_checks.patch create mode 100644 target/linux/generic/patches-4.0/611-netfilter_match_bypass_default_table.patch create mode 100644 target/linux/generic/patches-4.0/612-netfilter_match_reduce_memory_access.patch create mode 100644 target/linux/generic/patches-4.0/613-netfilter_optional_tcp_window_check.patch create mode 100644 target/linux/generic/patches-4.0/615-netfilter_add_xt_id_match.patch create mode 100644 target/linux/generic/patches-4.0/616-net_optimize_xfrm_calls.patch create mode 100644 target/linux/generic/patches-4.0/620-sched_esfq.patch create mode 100644 target/linux/generic/patches-4.0/630-packet_socket_type.patch create mode 100644 target/linux/generic/patches-4.0/640-bridge_no_eap_forward.patch create mode 100644 target/linux/generic/patches-4.0/641-bridge_always_accept_eap.patch create mode 100644 target/linux/generic/patches-4.0/642-bridge_port_isolate.patch create mode 100644 target/linux/generic/patches-4.0/643-bridge_remove_ipv6_dependency.patch create mode 100644 target/linux/generic/patches-4.0/645-bridge_multicast_to_unicast.patch create mode 100644 target/linux/generic/patches-4.0/650-pppoe_header_pad.patch create mode 100644 target/linux/generic/patches-4.0/651-wireless_mesh_header.patch create mode 100644 target/linux/generic/patches-4.0/653-disable_netlink_trim.patch create mode 100644 target/linux/generic/patches-4.0/655-increase_skb_pad.patch create mode 100644 target/linux/generic/patches-4.0/656-skb_reduce_truesize-helper.patch create mode 100644 target/linux/generic/patches-4.0/657-qdisc_reduce_truesize.patch create mode 100644 target/linux/generic/patches-4.0/660-fq_codel_defaults.patch create mode 100644 target/linux/generic/patches-4.0/661-fq_codel_keep_dropped_stats.patch create mode 100644 target/linux/generic/patches-4.0/662-use_fq_codel_by_default.patch create mode 100644 target/linux/generic/patches-4.0/663-remove_pfifo_fast.patch create mode 100644 target/linux/generic/patches-4.0/664-codel_fix_3_12.patch create mode 100644 target/linux/generic/patches-4.0/666-Add-support-for-MAP-E-FMRs-mesh-mode.patch create mode 100644 target/linux/generic/patches-4.0/667-ipv6-Fixed-source-specific-default-route-handling.patch create mode 100644 target/linux/generic/patches-4.0/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch create mode 100644 target/linux/generic/patches-4.0/671-net-provide-defines-for-_POLICY_FAILED-until-all-cod.patch create mode 100644 target/linux/generic/patches-4.0/680-NET-skip-GRO-for-foreign-MAC-addresses.patch create mode 100644 target/linux/generic/patches-4.0/681-NET-add-of_get_mac_address_mtd.patch create mode 100644 target/linux/generic/patches-4.0/700-swconfig.patch create mode 100644 target/linux/generic/patches-4.0/701-phy_extension.patch create mode 100644 target/linux/generic/patches-4.0/702-phy_add_aneg_done_function.patch create mode 100644 target/linux/generic/patches-4.0/703-phy-add-detach-callback-to-struct-phy_driver.patch create mode 100644 target/linux/generic/patches-4.0/704-phy-no-genphy-soft-reset.patch create mode 100644 target/linux/generic/patches-4.0/710-phy-add-mdio_register_board_info.patch create mode 100644 target/linux/generic/patches-4.0/720-phy_adm6996.patch create mode 100644 target/linux/generic/patches-4.0/721-phy_packets.patch create mode 100644 target/linux/generic/patches-4.0/722-phy_mvswitch.patch create mode 100644 target/linux/generic/patches-4.0/723-phy_ip175c.patch create mode 100644 target/linux/generic/patches-4.0/724-phy_ar8216.patch create mode 100644 target/linux/generic/patches-4.0/725-phy_rtl8306.patch create mode 100644 target/linux/generic/patches-4.0/726-phy_rtl8366.patch create mode 100644 target/linux/generic/patches-4.0/727-phy-rtl8367.patch create mode 100644 target/linux/generic/patches-4.0/728-phy-rtl8367b.patch create mode 100644 target/linux/generic/patches-4.0/729-phy-tantos.patch create mode 100644 target/linux/generic/patches-4.0/730-phy_b53.patch create mode 100644 target/linux/generic/patches-4.0/731-phy_mvswitch_3.10_compilation.patch create mode 100644 target/linux/generic/patches-4.0/732-phy-ar8216-led-support.patch create mode 100644 target/linux/generic/patches-4.0/733-phy_mvsw61xx.patch create mode 100644 target/linux/generic/patches-4.0/750-hostap_txpower.patch create mode 100644 target/linux/generic/patches-4.0/773-bgmac-add-srab-switch.patch create mode 100644 target/linux/generic/patches-4.0/780-igb-Fix-Null-pointer-dereference-in-igb_reset_q_vect.patch create mode 100644 target/linux/generic/patches-4.0/785-hso-support-0af0-9300.patch create mode 100644 target/linux/generic/patches-4.0/810-pci_disable_common_quirks.patch create mode 100644 target/linux/generic/patches-4.0/811-pci_disable_usb_common_quirks.patch create mode 100644 target/linux/generic/patches-4.0/820-usb_add_usb_find_device_by_name.patch create mode 100644 target/linux/generic/patches-4.0/830-ledtrig_morse.patch create mode 100644 target/linux/generic/patches-4.0/831-ledtrig_netdev.patch create mode 100644 target/linux/generic/patches-4.0/832-ledtrig_usbdev.patch create mode 100644 target/linux/generic/patches-4.0/834-ledtrig-libata.patch create mode 100644 target/linux/generic/patches-4.0/840-rtc7301.patch create mode 100644 target/linux/generic/patches-4.0/841-rtc_pt7c4338.patch create mode 100644 target/linux/generic/patches-4.0/861-04_spi_gpio_implement_spi_delay.patch create mode 100644 target/linux/generic/patches-4.0/862-gpio_spi_driver.patch create mode 100644 target/linux/generic/patches-4.0/863-gpiommc.patch create mode 100644 target/linux/generic/patches-4.0/864-gpiommc_configfs_locking.patch create mode 100644 target/linux/generic/patches-4.0/870-hifn795x_byteswap.patch create mode 100644 target/linux/generic/patches-4.0/880-gateworks_system_controller.patch create mode 100644 target/linux/generic/patches-4.0/890-8250_optional_sysrq.patch create mode 100644 target/linux/generic/patches-4.0/900-slab_maxsize.patch create mode 100644 target/linux/generic/patches-4.0/901-debloat_sock_diag.patch create mode 100644 target/linux/generic/patches-4.0/902-debloat_proc.patch create mode 100644 target/linux/generic/patches-4.0/903-debloat_direct_io.patch create mode 100644 target/linux/generic/patches-4.0/910-kobject_uevent.patch create mode 100644 target/linux/generic/patches-4.0/911-kobject_add_broadcast_uevent.patch create mode 100644 target/linux/generic/patches-4.0/921-use_preinit_as_init.patch create mode 100644 target/linux/generic/patches-4.0/922-always-create-console-node-in-initramfs.patch create mode 100644 target/linux/generic/patches-4.0/930-crashlog.patch create mode 100644 target/linux/generic/patches-4.0/940-ocf_kbuild_integration.patch create mode 100644 target/linux/generic/patches-4.0/941-ocf_20120127.patch create mode 100644 target/linux/generic/patches-4.0/960-decompress_unlzo_fix.patch create mode 100644 target/linux/generic/patches-4.0/970-remove-unsane-filenames-from-deps_initramfs-list.patch create mode 100644 target/linux/generic/patches-4.0/980-arm_openwrt_machtypes.patch create mode 100644 target/linux/generic/patches-4.0/990-gpio_wdt.patch create mode 100644 target/linux/generic/patches-4.0/995-mangle_bootargs.patch create mode 100644 target/linux/generic/patches-4.0/997-device_tree_cmdline.patch create mode 100644 target/linux/generic/patches-4.0/998-enable_wilink_platform_without_drivers.patch create mode 100644 target/linux/generic/patches-4.1/000-keep_initrafs_the_default.patch create mode 100644 target/linux/generic/patches-4.1/021-ssb_sprom.patch create mode 100644 target/linux/generic/patches-4.1/022-bcma-from-4.2.patch create mode 100644 target/linux/generic/patches-4.1/050-backport_netfilter_rtcache.patch create mode 100644 target/linux/generic/patches-4.1/060-mips_decompressor_memmove.patch create mode 100644 target/linux/generic/patches-4.1/072-13-bgmac-fix-MAC-soft-reset-bit-for-corerev-4.patch create mode 100644 target/linux/generic/patches-4.1/072-14-bgmac-reset-all-4-GMAC-cores-on-init.patch create mode 100644 target/linux/generic/patches-4.1/080-ipv6-ip6_fragment-fix-headroom-tests-and-skb-leak.patch create mode 100644 target/linux/generic/patches-4.1/081-solos-pci-Increase-headroom-on-received-packets.patch create mode 100644 target/linux/generic/patches-4.1/091-mtd-spi-nor-add-support-Spansion_S25FL164K create mode 100644 target/linux/generic/patches-4.1/095-api-fix-compatibility-of-linux-in.h-with-netinet-in..patch create mode 100644 target/linux/generic/patches-4.1/096-ipv4-off-by-one-in-continuation-handling-in-proc-net.patch create mode 100644 target/linux/generic/patches-4.1/101-pppoe-fix-disconnect-crash.patch create mode 100644 target/linux/generic/patches-4.1/102-ehci_hcd_ignore_oc.patch create mode 100644 target/linux/generic/patches-4.1/110-jffs2-use-.rename2-and-add-RENAME_WHITEOUT-support.patch create mode 100644 target/linux/generic/patches-4.1/111-jffs2-add-RENAME_EXCHANGE-support.patch create mode 100644 target/linux/generic/patches-4.1/120-bridge_allow_receiption_on_disabled_port.patch create mode 100644 target/linux/generic/patches-4.1/132-mips_inline_dma_ops.patch create mode 100644 target/linux/generic/patches-4.1/140-mtd-part-add-generic-parsing-of-linux-part-probe.patch create mode 100644 target/linux/generic/patches-4.1/180-usb-xhci-make-USB_XHCI_PLATFORM-selectable.patch create mode 100644 target/linux/generic/patches-4.1/190-cdc_ncm_add_support_for_moving_ndp_to_end_of_ncm_frame.patch create mode 100644 target/linux/generic/patches-4.1/191-usb-ehci-orion-fix-probe-for-GENERIC_PHY.patch create mode 100644 target/linux/generic/patches-4.1/200-fix_localversion.patch create mode 100644 target/linux/generic/patches-4.1/201-extra_optimization.patch create mode 100644 target/linux/generic/patches-4.1/202-reduce_module_size.patch create mode 100644 target/linux/generic/patches-4.1/203-kallsyms_uncompressed.patch create mode 100644 target/linux/generic/patches-4.1/204-module_strip.patch create mode 100644 target/linux/generic/patches-4.1/205-backtrace_module_info.patch create mode 100644 target/linux/generic/patches-4.1/210-darwin_scripts_include.patch create mode 100644 target/linux/generic/patches-4.1/212-byteshift_portability.patch create mode 100644 target/linux/generic/patches-4.1/214-spidev_h_portability.patch create mode 100644 target/linux/generic/patches-4.1/220-gc_sections.patch create mode 100644 target/linux/generic/patches-4.1/221-module_exports.patch create mode 100644 target/linux/generic/patches-4.1/230-openwrt_lzma_options.patch create mode 100644 target/linux/generic/patches-4.1/250-netfilter_depends.patch create mode 100644 target/linux/generic/patches-4.1/251-sound_kconfig.patch create mode 100644 target/linux/generic/patches-4.1/252-mv_cesa_depends.patch create mode 100644 target/linux/generic/patches-4.1/253-ssb_b43_default_on.patch create mode 100644 target/linux/generic/patches-4.1/254-textsearch_kconfig_hacks.patch create mode 100644 target/linux/generic/patches-4.1/255-lib80211_kconfig_hacks.patch create mode 100644 target/linux/generic/patches-4.1/256-crypto_add_kconfig_prompts.patch create mode 100644 target/linux/generic/patches-4.1/257-wireless_ext_kconfig_hack.patch create mode 100644 target/linux/generic/patches-4.1/258-netfilter_netlink_kconfig_hack.patch create mode 100644 target/linux/generic/patches-4.1/259-regmap_dynamic.patch create mode 100644 target/linux/generic/patches-4.1/260-crypto_test_dependencies.patch create mode 100644 target/linux/generic/patches-4.1/262-compressor_kconfig_hack.patch create mode 100644 target/linux/generic/patches-4.1/270-uapi-kernel.h-glibc-specific-inclusion-of-sysinfo.h.patch create mode 100644 target/linux/generic/patches-4.1/271-uapi-libc-compat.h-do-not-rely-on-__GLIBC__.patch create mode 100644 target/linux/generic/patches-4.1/272-uapi-if_ether.h-prevent-redefinition-of-struct-ethhd.patch create mode 100644 target/linux/generic/patches-4.1/300-mips_expose_boot_raw.patch create mode 100644 target/linux/generic/patches-4.1/301-mips_image_cmdline_hack.patch create mode 100644 target/linux/generic/patches-4.1/302-mips_no_branch_likely.patch create mode 100644 target/linux/generic/patches-4.1/304-mips_disable_fpu.patch create mode 100644 target/linux/generic/patches-4.1/305-mips_module_reloc.patch create mode 100644 target/linux/generic/patches-4.1/306-mips_mem_functions_performance.patch create mode 100644 target/linux/generic/patches-4.1/307-mips_highmem_offset.patch create mode 100644 target/linux/generic/patches-4.1/309-mips_fuse_workaround.patch create mode 100644 target/linux/generic/patches-4.1/310-arm_module_unresolved_weak_sym.patch create mode 100644 target/linux/generic/patches-4.1/320-ppc4xx_optimization.patch create mode 100644 target/linux/generic/patches-4.1/321-powerpc_crtsavres_prereq.patch create mode 100644 target/linux/generic/patches-4.1/330-MIPS-kexec-Accept-command-line-parameters-from-users.patch create mode 100644 target/linux/generic/patches-4.1/400-mtd-add-rootfs-split-support.patch create mode 100644 target/linux/generic/patches-4.1/401-mtd-add-support-for-different-partition-parser-types.patch create mode 100644 target/linux/generic/patches-4.1/402-mtd-use-typed-mtd-parsers-for-rootfs-and-firmware-split.patch create mode 100644 target/linux/generic/patches-4.1/403-mtd-hook-mtdsplit-to-Kbuild.patch create mode 100644 target/linux/generic/patches-4.1/404-mtd-add-more-helper-functions.patch create mode 100644 target/linux/generic/patches-4.1/405-mtd-old-firmware-uimage-splitter.patch create mode 100644 target/linux/generic/patches-4.1/410-mtd-move-forward-declaration-of-struct-mtd_info.patch create mode 100644 target/linux/generic/patches-4.1/411-mtd-partial_eraseblock_write.patch create mode 100644 target/linux/generic/patches-4.1/412-mtd-partial_eraseblock_unlock.patch create mode 100644 target/linux/generic/patches-4.1/420-mtd-redboot_space.patch create mode 100644 target/linux/generic/patches-4.1/430-mtd-add-myloader-partition-parser.patch create mode 100644 target/linux/generic/patches-4.1/431-mtd-bcm47xxpart-support-for-Xiaomi-specific-board_da.patch create mode 100644 target/linux/generic/patches-4.1/432-mtd-bcm47xxpart-detect-T_Meter-partition.patch create mode 100644 target/linux/generic/patches-4.1/440-block2mtd_init.patch create mode 100644 target/linux/generic/patches-4.1/441-block2mtd_probe.patch create mode 100644 target/linux/generic/patches-4.1/450-mtd-nand-allow-to-use-platform-specific-chip-fixup.patch create mode 100644 target/linux/generic/patches-4.1/451-mtd-nand-fix-return-code-of-nand_correct_data-function.patch create mode 100644 target/linux/generic/patches-4.1/460-mtd-cfi_cmdset_0002-no-erase_suspend.patch create mode 100644 target/linux/generic/patches-4.1/461-mtd-cfi_cmdset_0002-add-buffer-write-cmd-timeout.patch create mode 100644 target/linux/generic/patches-4.1/473-mtd-spi-nor-add-support-for-the-Macronix-MX25L512E-S.patch create mode 100644 target/linux/generic/patches-4.1/474-mtd-spi-nor-add-support-for-the-ISSI-SI25CD512-SPI-f.patch create mode 100644 target/linux/generic/patches-4.1/480-mtd-set-rootfs-to-be-root-dev.patch create mode 100644 target/linux/generic/patches-4.1/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch create mode 100644 target/linux/generic/patches-4.1/491-ubi-auto-create-ubiblock-device-for-rootfs.patch create mode 100644 target/linux/generic/patches-4.1/492-try-auto-mounting-ubi0-rootfs-in-init-do_mounts.c.patch create mode 100644 target/linux/generic/patches-4.1/493-ubi-set-ROOT_DEV-to-ubiblock-rootfs-if-unset.patch create mode 100644 target/linux/generic/patches-4.1/494-mtd-ubi-add-EOF-marker-support.patch create mode 100644 target/linux/generic/patches-4.1/500-yaffs-Kbuild-integration.patch create mode 100644 target/linux/generic/patches-4.1/502-yaffs-fix-compat-tags-handling.patch create mode 100644 target/linux/generic/patches-4.1/503-yaffs-add-tags-9bytes-mount-option.patch create mode 100644 target/linux/generic/patches-4.1/504-yaffs-3.16-new-fops.patch create mode 100644 target/linux/generic/patches-4.1/505-yaffs-3.19-f_dentry-remove.patch create mode 100644 target/linux/generic/patches-4.1/520-squashfs_update_xz_comp_opts.patch create mode 100644 target/linux/generic/patches-4.1/530-jffs2_make_lzma_available.patch create mode 100644 target/linux/generic/patches-4.1/531-debloat_lzma.patch create mode 100644 target/linux/generic/patches-4.1/532-jffs2_eofdetect.patch create mode 100644 target/linux/generic/patches-4.1/540-crypto-xz-decompression-support.patch create mode 100644 target/linux/generic/patches-4.1/541-ubifs-xz-decompression-support.patch create mode 100644 target/linux/generic/patches-4.1/551-ubifs-fix-default-compression-selection.patch create mode 100644 target/linux/generic/patches-4.1/600-netfilter_conntrack_flush.patch create mode 100644 target/linux/generic/patches-4.1/610-netfilter_match_bypass_default_checks.patch create mode 100644 target/linux/generic/patches-4.1/611-netfilter_match_bypass_default_table.patch create mode 100644 target/linux/generic/patches-4.1/612-netfilter_match_reduce_memory_access.patch create mode 100644 target/linux/generic/patches-4.1/613-netfilter_optional_tcp_window_check.patch create mode 100644 target/linux/generic/patches-4.1/615-netfilter_add_xt_id_match.patch create mode 100644 target/linux/generic/patches-4.1/616-net_optimize_xfrm_calls.patch create mode 100644 target/linux/generic/patches-4.1/620-sched_esfq.patch create mode 100644 target/linux/generic/patches-4.1/630-packet_socket_type.patch create mode 100644 target/linux/generic/patches-4.1/640-bridge_no_eap_forward.patch create mode 100644 target/linux/generic/patches-4.1/641-bridge_always_accept_eap.patch create mode 100644 target/linux/generic/patches-4.1/642-bridge_port_isolate.patch create mode 100644 target/linux/generic/patches-4.1/643-bridge_remove_ipv6_dependency.patch create mode 100644 target/linux/generic/patches-4.1/645-bridge_multicast_to_unicast.patch create mode 100644 target/linux/generic/patches-4.1/650-pppoe_header_pad.patch create mode 100644 target/linux/generic/patches-4.1/651-wireless_mesh_header.patch create mode 100644 target/linux/generic/patches-4.1/653-disable_netlink_trim.patch create mode 100644 target/linux/generic/patches-4.1/655-increase_skb_pad.patch create mode 100644 target/linux/generic/patches-4.1/656-skb_reduce_truesize-helper.patch create mode 100644 target/linux/generic/patches-4.1/657-qdisc_reduce_truesize.patch create mode 100644 target/linux/generic/patches-4.1/660-fq_codel_defaults.patch create mode 100644 target/linux/generic/patches-4.1/661-fq_codel_keep_dropped_stats.patch create mode 100644 target/linux/generic/patches-4.1/662-use_fq_codel_by_default.patch create mode 100644 target/linux/generic/patches-4.1/663-remove_pfifo_fast.patch create mode 100644 target/linux/generic/patches-4.1/664-codel_fix_3_12.patch create mode 100644 target/linux/generic/patches-4.1/666-Add-support-for-MAP-E-FMRs-mesh-mode.patch create mode 100644 target/linux/generic/patches-4.1/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch create mode 100644 target/linux/generic/patches-4.1/671-net-provide-defines-for-_POLICY_FAILED-until-all-cod.patch create mode 100644 target/linux/generic/patches-4.1/680-NET-skip-GRO-for-foreign-MAC-addresses.patch create mode 100644 target/linux/generic/patches-4.1/681-NET-add-of_get_mac_address_mtd.patch create mode 100644 target/linux/generic/patches-4.1/700-swconfig.patch create mode 100644 target/linux/generic/patches-4.1/701-phy_extension.patch create mode 100644 target/linux/generic/patches-4.1/702-phy_add_aneg_done_function.patch create mode 100644 target/linux/generic/patches-4.1/703-phy-add-detach-callback-to-struct-phy_driver.patch create mode 100644 target/linux/generic/patches-4.1/704-phy-no-genphy-soft-reset.patch create mode 100644 target/linux/generic/patches-4.1/710-phy-add-mdio_register_board_info.patch create mode 100644 target/linux/generic/patches-4.1/720-phy_adm6996.patch create mode 100644 target/linux/generic/patches-4.1/721-phy_packets.patch create mode 100644 target/linux/generic/patches-4.1/722-phy_mvswitch.patch create mode 100644 target/linux/generic/patches-4.1/723-phy_ip175c.patch create mode 100644 target/linux/generic/patches-4.1/724-phy_ar8216.patch create mode 100644 target/linux/generic/patches-4.1/725-phy_rtl8306.patch create mode 100644 target/linux/generic/patches-4.1/726-phy_rtl8366.patch create mode 100644 target/linux/generic/patches-4.1/727-phy-rtl8367.patch create mode 100644 target/linux/generic/patches-4.1/728-phy-rtl8367b.patch create mode 100644 target/linux/generic/patches-4.1/729-phy-tantos.patch create mode 100644 target/linux/generic/patches-4.1/730-phy_b53.patch create mode 100644 target/linux/generic/patches-4.1/731-phy_mvswitch_3.10_compilation.patch create mode 100644 target/linux/generic/patches-4.1/732-phy-ar8216-led-support.patch create mode 100644 target/linux/generic/patches-4.1/733-phy_mvsw61xx.patch create mode 100644 target/linux/generic/patches-4.1/750-hostap_txpower.patch create mode 100644 target/linux/generic/patches-4.1/773-bgmac-add-srab-switch.patch create mode 100644 target/linux/generic/patches-4.1/780-igb-Fix-Null-pointer-dereference-in-igb_reset_q_vect.patch create mode 100644 target/linux/generic/patches-4.1/785-hso-support-0af0-9300.patch create mode 100644 target/linux/generic/patches-4.1/810-pci_disable_common_quirks.patch create mode 100644 target/linux/generic/patches-4.1/811-pci_disable_usb_common_quirks.patch create mode 100644 target/linux/generic/patches-4.1/820-usb_add_usb_find_device_by_name.patch create mode 100644 target/linux/generic/patches-4.1/830-ledtrig_morse.patch create mode 100644 target/linux/generic/patches-4.1/831-ledtrig_netdev.patch create mode 100644 target/linux/generic/patches-4.1/832-ledtrig_usbdev.patch create mode 100644 target/linux/generic/patches-4.1/834-ledtrig-libata.patch create mode 100644 target/linux/generic/patches-4.1/840-rtc7301.patch create mode 100644 target/linux/generic/patches-4.1/841-rtc_pt7c4338.patch create mode 100644 target/linux/generic/patches-4.1/861-04_spi_gpio_implement_spi_delay.patch create mode 100644 target/linux/generic/patches-4.1/862-gpio_spi_driver.patch create mode 100644 target/linux/generic/patches-4.1/863-gpiommc.patch create mode 100644 target/linux/generic/patches-4.1/864-gpiommc_configfs_locking.patch create mode 100644 target/linux/generic/patches-4.1/870-hifn795x_byteswap.patch create mode 100644 target/linux/generic/patches-4.1/880-gateworks_system_controller.patch create mode 100644 target/linux/generic/patches-4.1/890-8250_optional_sysrq.patch create mode 100644 target/linux/generic/patches-4.1/900-slab_maxsize.patch create mode 100644 target/linux/generic/patches-4.1/901-debloat_sock_diag.patch create mode 100644 target/linux/generic/patches-4.1/902-debloat_proc.patch create mode 100644 target/linux/generic/patches-4.1/903-debloat_direct_io.patch create mode 100644 target/linux/generic/patches-4.1/910-kobject_uevent.patch create mode 100644 target/linux/generic/patches-4.1/911-kobject_add_broadcast_uevent.patch create mode 100644 target/linux/generic/patches-4.1/921-use_preinit_as_init.patch create mode 100644 target/linux/generic/patches-4.1/922-always-create-console-node-in-initramfs.patch create mode 100644 target/linux/generic/patches-4.1/930-crashlog.patch create mode 100644 target/linux/generic/patches-4.1/940-ocf_kbuild_integration.patch create mode 100644 target/linux/generic/patches-4.1/941-ocf_20120127.patch create mode 100644 target/linux/generic/patches-4.1/960-decompress_unlzo_fix.patch create mode 100644 target/linux/generic/patches-4.1/970-remove-unsane-filenames-from-deps_initramfs-list.patch create mode 100644 target/linux/generic/patches-4.1/980-arm_openwrt_machtypes.patch create mode 100644 target/linux/generic/patches-4.1/990-gpio_wdt.patch create mode 100644 target/linux/generic/patches-4.1/995-mangle_bootargs.patch create mode 100644 target/linux/generic/patches-4.1/997-device_tree_cmdline.patch create mode 100644 target/linux/generic/patches-4.1/998-enable_wilink_platform_without_drivers.patch (limited to 'target/linux/generic') diff --git a/target/linux/generic/PATCHES b/target/linux/generic/PATCHES new file mode 100644 index 0000000..86ced46 --- /dev/null +++ b/target/linux/generic/PATCHES @@ -0,0 +1,20 @@ +The patches-* subdirectories contain the kernel patches applied for every +OpenWrt target. All patches should be named 'NNN-lowercase_shortname.patch' +and sorted into the following categories: + +0xx - upstream backports +1xx - code awaiting upstream merge +2xx - kernel build / config / header patches +3xx - architecture specific patches +4xx - mtd related patches (subsystem and drivers) +5xx - filesystem related patches +6xx - generic network patches +7xx - network / phy driver patches +8xx - other drivers +9xx - uncategorized other patches + +ALL patches must be in a way that they are potentially upstreamable, meaning: + +- they must contain a proper subject +- they must contain a proper commit message explaining what they change +- they must contain a valid Signed-off-by line diff --git a/target/linux/generic/base-files/init b/target/linux/generic/base-files/init new file mode 100755 index 0000000..514be57 --- /dev/null +++ b/target/linux/generic/base-files/init @@ -0,0 +1,4 @@ +#!/bin/sh +# Copyright (C) 2006 OpenWrt.org +export INITRAMFS=1 +exec /sbin/init diff --git a/target/linux/generic/config-3.18 b/target/linux/generic/config-3.18 new file mode 100644 index 0000000..dfb4d50 --- /dev/null +++ b/target/linux/generic/config-3.18 @@ -0,0 +1,4646 @@ +CONFIG_32BIT=y +# CONFIG_6LOWPAN is not set +# CONFIG_6PACK is not set +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_9P_FS is not set +# CONFIG_AB3100_CORE is not set +# CONFIG_AB8500_CORE is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_ACCESSIBILITY is not set +# CONFIG_ACENIC is not set +# CONFIG_ACERHDF is not set +# CONFIG_ACORN_PARTITION is not set +# CONFIG_ACPI_APEI is not set +# CONFIG_ACPI_CUSTOM_METHOD is not set +# CONFIG_ACPI_EXTLOG is not set +# CONFIG_ACPI_HED is not set +# CONFIG_ACPI_INT3403_THERMAL is not set +# CONFIG_ACPI_POWER_METER is not set +# CONFIG_ACPI_QUICKSTART is not set +# CONFIG_ACPI_REDUCED_HARDWARE_ONLY is not set +# CONFIG_AD2S1200 is not set +# CONFIG_AD2S1210 is not set +# CONFIG_AD2S90 is not set +# CONFIG_AD5064 is not set +# CONFIG_AD525X_DPOT is not set +# CONFIG_AD5360 is not set +# CONFIG_AD5380 is not set +# CONFIG_AD5421 is not set +# CONFIG_AD5446 is not set +# CONFIG_AD5449 is not set +# CONFIG_AD5504 is not set +# CONFIG_AD5624R_SPI is not set +# CONFIG_AD5686 is not set +# CONFIG_AD5755 is not set +# CONFIG_AD5764 is not set +# CONFIG_AD5791 is not set +# CONFIG_AD5930 is not set +# CONFIG_AD5933 is not set +# CONFIG_AD7150 is not set +# CONFIG_AD7152 is not set +# CONFIG_AD7192 is not set +# CONFIG_AD7266 is not set +# CONFIG_AD7280 is not set +# CONFIG_AD7291 is not set +# CONFIG_AD7298 is not set +# CONFIG_AD7303 is not set +# CONFIG_AD7476 is not set +# CONFIG_AD7606 is not set +# CONFIG_AD7746 is not set +# CONFIG_AD7780 is not set +# CONFIG_AD7791 is not set +# CONFIG_AD7793 is not set +# CONFIG_AD7816 is not set +# CONFIG_AD7887 is not set +# CONFIG_AD7923 is not set +# CONFIG_AD799X is not set +# CONFIG_AD8366 is not set +# CONFIG_AD9523 is not set +# CONFIG_AD9832 is not set +# CONFIG_AD9834 is not set +# CONFIG_AD9850 is not set +# CONFIG_AD9852 is not set +# CONFIG_AD9910 is not set +# CONFIG_AD9951 is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_ADE7753 is not set +# CONFIG_ADE7754 is not set +# CONFIG_ADE7758 is not set +# CONFIG_ADE7759 is not set +# CONFIG_ADE7854 is not set +# CONFIG_ADF4350 is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADIS16060 is not set +# CONFIG_ADIS16080 is not set +# CONFIG_ADIS16130 is not set +# CONFIG_ADIS16136 is not set +# CONFIG_ADIS16201 is not set +# CONFIG_ADIS16203 is not set +# CONFIG_ADIS16204 is not set +# CONFIG_ADIS16209 is not set +# CONFIG_ADIS16220 is not set +# CONFIG_ADIS16240 is not set +# CONFIG_ADIS16255 is not set +# CONFIG_ADIS16260 is not set +# CONFIG_ADIS16400 is not set +# CONFIG_ADIS16480 is not set +# CONFIG_ADJD_S311 is not set +# CONFIG_ADM6996_PHY is not set +# CONFIG_ADM8211 is not set +# CONFIG_ADT7316 is not set +# CONFIG_ADVISE_SYSCALLS is not set +# CONFIG_ADXRS450 is not set +CONFIG_AEABI=y +# CONFIG_AFFS_FS is not set +# CONFIG_AFS_FS is not set +# CONFIG_AF_RXRPC is not set +# CONFIG_AGP is not set +# CONFIG_AHCI_MVEBU is not set +CONFIG_AIO=y +# CONFIG_AIRO is not set +# CONFIG_AIRO_CS is not set +# CONFIG_AIX_PARTITION is not set +# CONFIG_AK09911 is not set +# CONFIG_AK8975 is not set +# CONFIG_AL3320A is not set +# CONFIG_ALCHEMY_GPIO_INDIRECT is not set +# CONFIG_ALIM7101_WDT is not set +CONFIG_ALLOW_DEV_COREDUMP=y +# CONFIG_ALTERA_STAPL is not set +# CONFIG_ALTERA_TSE is not set +# CONFIG_ALX is not set +# CONFIG_AM335X_PHY_USB is not set +# CONFIG_AMD8111_ETH is not set +# CONFIG_AMD_XGBE is not set +# CONFIG_AMD_XGBE_PHY is not set +# CONFIG_AMD_PHY is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_AMILO_RFKILL is not set +# CONFIG_ANDROID is not set +CONFIG_ANON_INODES=y +# CONFIG_APDS9300 is not set +# CONFIG_APDS9802ALS is not set +# CONFIG_APM8018X is not set +# CONFIG_APPLICOM is not set +# CONFIG_AR5523 is not set +# CONFIG_AR7 is not set +# CONFIG_AR8216_PHY is not set +# CONFIG_AR8216_PHY_LEDS is not set +# CONFIG_ARCH_AT91 is not set +# CONFIG_ARCH_BCM is not set +# CONFIG_ARCH_BCM2835 is not set +# CONFIG_ARCH_BCMRING is not set +# CONFIG_ARCH_BERLIN is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CNS3XXX is not set +# CONFIG_ARCH_DAVINCI is not set +# CONFIG_ARCH_DMA_ADDR_T_64BIT is not set +# CONFIG_ARCH_DOVE is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_EP93XX is not set +# CONFIG_ARCH_EXYNOS is not set +CONFIG_ARCH_FLATMEM_ENABLE=y +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_GEMINI is not set +# CONFIG_ARCH_H720X is not set +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +# CONFIG_ARCH_HI3xxx is not set +# CONFIG_ARCH_HIGHBANK is not set +# CONFIG_ARCH_HISI is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_IOP13XX is not set +# CONFIG_ARCH_IOP32X is not set +# CONFIG_ARCH_IOP33X is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_IXP23XX is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_KEYSTONE is not set +# CONFIG_ARCH_KIRKWOOD is not set +# CONFIG_ARCH_KS8695 is not set +# CONFIG_ARCH_LPC32XX is not set +# CONFIG_ARCH_MEDIATEK is not set +# CONFIG_ARCH_MESON is not set +# CONFIG_ARCH_MMP is not set +# CONFIG_ARCH_MSM is not set +# CONFIG_ARCH_MSM_DT is not set +# CONFIG_ARCH_MSM_NODT is not set +# CONFIG_ARCH_MULTIPLATFORM is not set +# CONFIG_ARCH_MULTI_V6 is not set +# CONFIG_ARCH_MULTI_V7 is not set +# CONFIG_ARCH_MV78XX0 is not set +# CONFIG_ARCH_MVEBU is not set +# CONFIG_ARCH_MXC is not set +# CONFIG_ARCH_MXS is not set +# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set +# CONFIG_ARCH_NETX is not set +# CONFIG_ARCH_NOMADIK is not set +# CONFIG_ARCH_NSPIRE is not set +# CONFIG_ARCH_NUC93X is not set +# CONFIG_ARCH_OMAP is not set +# CONFIG_ARCH_OMAP1 is not set +# CONFIG_ARCH_OMAP2PLUS is not set +# CONFIG_ARCH_OMAP3 is not set +# CONFIG_ARCH_OMAP4 is not set +# CONFIG_ARCH_ORION5X is not set +# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set +# CONFIG_ARCH_PICOXCELL is not set +# CONFIG_ARCH_PNX4008 is not set +# CONFIG_ARCH_PRIMA2 is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_QCOM is not set +# CONFIG_ARCH_REALVIEW is not set +# CONFIG_ARCH_ROCKCHIP is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_S3C24XX is not set +# CONFIG_ARCH_S3C64XX is not set +# CONFIG_ARCH_S5P64X0 is not set +# CONFIG_ARCH_S5PC100 is not set +# CONFIG_ARCH_S5PV210 is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_SHMOBILE is not set +# CONFIG_ARCH_SHMOBILE_LEGACY is not set +# CONFIG_ARCH_SHMOBILE_MULTI is not set +# CONFIG_ARCH_SIRF is not set +# CONFIG_ARCH_SOCFPGA is not set +# CONFIG_ARCH_STI is not set +# CONFIG_ARCH_SUNXI is not set +# CONFIG_ARCH_SUPPORTS_MSI is not set +# CONFIG_ARCH_TCC_926 is not set +# CONFIG_ARCH_TEGRA is not set +# CONFIG_ARCH_U300 is not set +# CONFIG_ARCH_U8500 is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_VEXPRESS is not set +# CONFIG_ARCH_VIRT is not set +# CONFIG_ARCH_VT8500 is not set +# CONFIG_ARCH_W90X900 is not set +# CONFIG_ARCH_WM8505 is not set +# CONFIG_ARCH_WM8850 is not set +# CONFIG_ARCH_ZYNQ is not set +# CONFIG_ARCNET is not set +# CONFIG_ARC_EMAC is not set +# CONFIG_ARM_APPENDED_DTB is not set +# CONFIG_ARM_ARCH_TIMER is not set +# CONFIG_ARM_AT91_ETHER is not set +# CONFIG_ARM_CCI is not set +# CONFIG_ARM_CCN is not set +CONFIG_ARM_CPU_TOPOLOGY=y +CONFIG_ARM_DMA_MEM_BUFFERABLE=y +# CONFIG_ARM_ERRATA_326103 is not set +# CONFIG_ARM_ERRATA_364296 is not set +# CONFIG_ARM_ERRATA_411920 is not set +# CONFIG_ARM_ERRATA_430973 is not set +# CONFIG_ARM_ERRATA_458693 is not set +# CONFIG_ARM_ERRATA_460075 is not set +# CONFIG_ARM_ERRATA_643719 is not set +# CONFIG_ARM_ERRATA_720789 is not set +# CONFIG_ARM_ERRATA_742230 is not set +# CONFIG_ARM_ERRATA_742231 is not set +# CONFIG_ARM_ERRATA_743622 is not set +# CONFIG_ARM_ERRATA_751472 is not set +# CONFIG_ARM_ERRATA_754322 is not set +# CONFIG_ARM_ERRATA_754327 is not set +# CONFIG_ARM_ERRATA_764369 is not set +# CONFIG_ARM_ERRATA_773022 is not set +# CONFIG_ARM_ERRATA_775420 is not set +# CONFIG_ARM_ERRATA_798181 is not set +# CONFIG_ARM_KPROBES_TEST is not set +# CONFIG_ARM_PATCH_PHYS_VIRT is not set +# CONFIG_ARM_PSCI is not set +# CONFIG_ARM_PTDUMP is not set +# CONFIG_ARM_UNWIND is not set +# CONFIG_ARM_VIRT_EXT is not set +CONFIG_ARPD=y +# CONFIG_ARTHUR is not set +# CONFIG_AS3935 is not set +# CONFIG_ASUS_OLED is not set +# CONFIG_ASYMMETRIC_KEY_TYPE is not set +# CONFIG_ASYNC_RAID6_TEST is not set +# CONFIG_ASYNC_TX_DMA is not set +# CONFIG_AT76C50X_USB is not set +# CONFIG_AT803X_PHY is not set +# CONFIG_ATA is not set +# CONFIG_ATAGS is not set +CONFIG_ATAGS_PROC=y +# CONFIG_ATALK is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_ATA_ACPI is not set +CONFIG_ATA_BMDMA=y +# CONFIG_ATA_GENERIC is not set +# CONFIG_ATA_NONSTANDARD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_ATA_PIIX is not set +CONFIG_ATA_SFF=y +# CONFIG_ATA_VERBOSE_ERROR is not set +# CONFIG_ATH10K is not set +# CONFIG_ATH5K is not set +# CONFIG_ATH6KL is not set +# CONFIG_ATH6K_LEGACY is not set +# CONFIG_ATH79 is not set +# CONFIG_ATH9K is not set +# CONFIG_ATH9K_HTC is not set +# CONFIG_ATH_CARDS is not set +# CONFIG_ATH_DEBUG is not set +# CONFIG_ATL1 is not set +# CONFIG_ATL1C is not set +# CONFIG_ATL1E is not set +# CONFIG_ATL2 is not set +# CONFIG_ATM is not set +# CONFIG_ATMEL is not set +# CONFIG_ATMEL_PIT is not set +# CONFIG_ATMEL_PWM is not set +# CONFIG_ATMEL_SSC is not set +# CONFIG_ATM_AMBASSADOR is not set +# CONFIG_ATM_BR2684 is not set +CONFIG_ATM_BR2684_IPFILTER=y +# CONFIG_ATM_CLIP is not set +CONFIG_ATM_CLIP_NO_ICMP=y +# CONFIG_ATM_DRIVERS is not set +# CONFIG_ATM_DUMMY is not set +# CONFIG_ATM_ENI is not set +# CONFIG_ATM_FIRESTREAM is not set +# CONFIG_ATM_FORE200E is not set +# CONFIG_ATM_HE is not set +# CONFIG_ATM_HORIZON is not set +# CONFIG_ATM_IA is not set +# CONFIG_ATM_IDT77252 is not set +# CONFIG_ATM_LANAI is not set +# CONFIG_ATM_LANE is not set +# CONFIG_ATM_MPOA is not set +# CONFIG_ATM_NICSTAR is not set +# CONFIG_ATM_SOLOS is not set +# CONFIG_ATM_TCP is not set +# CONFIG_ATM_ZATM is not set +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_ATP is not set +# CONFIG_AUDIT is not set +# CONFIG_AUDIT_ARCH_COMPAT_GENERIC is not set +# CONFIG_AUDIT_LOGINUID_IMMUTABLE is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_AUTO_ZRELADDR is not set +# CONFIG_AUXDISPLAY is not set +# CONFIG_AVERAGE is not set +# CONFIG_AX25 is not set +# CONFIG_AX25_DAMA_SLAVE is not set +# CONFIG_AX88796 is not set +# CONFIG_B43 is not set +# CONFIG_B43LEGACY is not set +# CONFIG_B44 is not set +# CONFIG_B53 is not set +# CONFIG_B53_SPI_DRIVER is not set +# CONFIG_BACKLIGHT_BD6107 is not set +# CONFIG_BACKLIGHT_GPIO is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set +# CONFIG_BACKLIGHT_LM3630 is not set +# CONFIG_BACKLIGHT_LM3630A is not set +# CONFIG_BACKLIGHT_LM3639 is not set +# CONFIG_BACKLIGHT_LP855X is not set +# CONFIG_BACKLIGHT_LV5207LP is not set +# CONFIG_BACKLIGHT_PANDORA is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +CONFIG_BASE_FULL=y +CONFIG_BASE_SMALL=0 +# CONFIG_BATMAN_ADV is not set +# CONFIG_BATTERY_BQ27x00 is not set +# CONFIG_BATTERY_DS2760 is not set +# CONFIG_BATTERY_DS2780 is not set +# CONFIG_BATTERY_DS2781 is not set +# CONFIG_BATTERY_DS2782 is not set +# CONFIG_BATTERY_GOLDFISH is not set +# CONFIG_BATTERY_MAX17040 is not set +# CONFIG_BATTERY_MAX17042 is not set +# CONFIG_BATTERY_SBS is not set +# CONFIG_BAYCOM_EPP is not set +# CONFIG_BAYCOM_PAR is not set +# CONFIG_BAYCOM_SER_FDX is not set +# CONFIG_BAYCOM_SER_HDX is not set +# CONFIG_BCACHE is not set +# CONFIG_BCM47XX is not set +# CONFIG_BCM63XX is not set +# CONFIG_BCM63XX_PHY is not set +# CONFIG_BCM7XXX_PHY is not set +# CONFIG_BCM87XX_PHY is not set +# CONFIG_BCMA is not set +# CONFIG_BCMA_DRIVER_GPIO is not set +CONFIG_BCMA_POSSIBLE=y +# CONFIG_BCMGENET is not set +# CONFIG_BCM_KONA_USB2_PHY is not set +# CONFIG_BCM_WIMAX is not set +# CONFIG_BDI_SWITCH is not set +# CONFIG_BE2ISCSI is not set +# CONFIG_BE2NET is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_BGMAC is not set +# CONFIG_BIG_KEYS is not set +# CONFIG_BIG_LITTLE is not set +# CONFIG_BINARY_PRINTF is not set +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +CONFIG_BINFMT_SCRIPT=y +CONFIG_BITREVERSE=y +# CONFIG_BLK_CMDLINE_PARSER is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_CPQ_DA is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_BLK_DEV_4DRIVES is not set +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_BLK_DEV_ALI14XX is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_BLK_DEV_AMD74XX is not set +# CONFIG_BLK_DEV_ATIIXP is not set +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_BLK_DEV_BSGLIB is not set +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD64X is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_CS5520 is not set +# CONFIG_BLK_DEV_CS5530 is not set +# CONFIG_BLK_DEV_CS5535 is not set +# CONFIG_BLK_DEV_CS5536 is not set +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_DELKIN is not set +# CONFIG_BLK_DEV_DRBD is not set +# CONFIG_BLK_DEV_DTC2278 is not set +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_GENERIC is not set +# CONFIG_BLK_DEV_HD is not set +# CONFIG_BLK_DEV_HPT366 is not set +# CONFIG_BLK_DEV_HT6560B is not set +# CONFIG_BLK_DEV_IDEACPI is not set +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDECS is not set +# CONFIG_BLK_DEV_IDEPCI is not set +# CONFIG_BLK_DEV_IDEPNP is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDE_AU1XXX is not set +# CONFIG_BLK_DEV_IDE_SATA is not set +CONFIG_BLK_DEV_INITRD=y +# CONFIG_BLK_DEV_INTEGRITY is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_BLK_DEV_IT8172 is not set +# CONFIG_BLK_DEV_IT8213 is not set +# CONFIG_BLK_DEV_IT821X is not set +# CONFIG_BLK_DEV_JMICRON is not set +# CONFIG_BLK_DEV_LOOP is not set +CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_NULL_BLK is not set +# CONFIG_BLK_DEV_NVME is not set +# CONFIG_BLK_DEV_OFFBOARD is not set +# CONFIG_BLK_DEV_OPTI621 is not set +# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set +# CONFIG_BLK_DEV_PDC202XX_NEW is not set +# CONFIG_BLK_DEV_PDC202XX_OLD is not set +# CONFIG_BLK_DEV_PIIX is not set +# CONFIG_BLK_DEV_PLATFORM is not set +# CONFIG_BLK_DEV_QD65XX is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_RBD is not set +# CONFIG_BLK_DEV_RSXX is not set +# CONFIG_BLK_DEV_RZ1000 is not set +# CONFIG_BLK_DEV_SC1200 is not set +# CONFIG_BLK_DEV_SD is not set +# CONFIG_BLK_DEV_SIIMAGE is not set +# CONFIG_BLK_DEV_SIS5513 is not set +# CONFIG_BLK_DEV_SKD is not set +# CONFIG_BLK_DEV_SL82C105 is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_BLK_DEV_SVWKS is not set +# CONFIG_BLK_DEV_SX8 is not set +# CONFIG_BLK_DEV_TC86C001 is not set +# CONFIG_BLK_DEV_THROTTLING is not set +# CONFIG_BLK_DEV_TRIFLEX is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_UB is not set +# CONFIG_BLK_DEV_UMC8672 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_VIA82CXXX is not set +# CONFIG_BLK_DEV_XIP is not set +CONFIG_BLOCK=y +# CONFIG_BMA180 is not set +# CONFIG_BMC150_ACCEL is not set +# CONFIG_BMG160 is not set +# CONFIG_BMP085 is not set +# CONFIG_BMP085_I2C is not set +# CONFIG_BMP085_SPI is not set +# CONFIG_BNA is not set +# CONFIG_BNX2 is not set +# CONFIG_BNX2X is not set +# CONFIG_BONDING is not set +# CONFIG_BOOKE_WDT is not set +CONFIG_BOOKE_WDT_DEFAULT_TIMEOUT=3 +# CONFIG_BOOT_PRINTK_DELAY is not set +CONFIG_BOOT_RAW=y +# CONFIG_BPCTL is not set +CONFIG_BPF=y +# CONFIG_BPF_JIT is not set +CONFIG_BPF_SYSCALL=y +# CONFIG_BPQETHER is not set +CONFIG_BQL=y +CONFIG_BRANCH_PROFILE_NONE=y +# CONFIG_BRCMFMAC is not set +# CONFIG_BRCMSMAC is not set +# CONFIG_BRCMSTB_GISB_ARB is not set +CONFIG_BRIDGE=y +# CONFIG_BRIDGE_EBT_802_3 is not set +# CONFIG_BRIDGE_EBT_AMONG is not set +# CONFIG_BRIDGE_EBT_ARP is not set +# CONFIG_BRIDGE_EBT_ARPREPLY is not set +# CONFIG_BRIDGE_EBT_BROUTE is not set +# CONFIG_BRIDGE_EBT_DNAT is not set +# CONFIG_BRIDGE_EBT_IP is not set +# CONFIG_BRIDGE_EBT_IP6 is not set +# CONFIG_BRIDGE_EBT_LIMIT is not set +# CONFIG_BRIDGE_EBT_LOG is not set +# CONFIG_BRIDGE_EBT_MARK is not set +# CONFIG_BRIDGE_EBT_MARK_T is not set +# CONFIG_BRIDGE_EBT_NFLOG is not set +# CONFIG_BRIDGE_EBT_PKTTYPE is not set +# CONFIG_BRIDGE_EBT_REDIRECT is not set +# CONFIG_BRIDGE_EBT_SNAT is not set +# CONFIG_BRIDGE_EBT_STP is not set +# CONFIG_BRIDGE_EBT_T_FILTER is not set +# CONFIG_BRIDGE_EBT_T_NAT is not set +# CONFIG_BRIDGE_EBT_ULOG is not set +# CONFIG_BRIDGE_EBT_VLAN is not set +CONFIG_BRIDGE_IGMP_SNOOPING=y +# CONFIG_BRIDGE_NETFILTER is not set +# CONFIG_BRIDGE_NF_EBTABLES is not set +# CONFIG_BRIDGE_VLAN_FILTERING is not set +# CONFIG_BROADCOM_PHY is not set +CONFIG_BROKEN_ON_SMP=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_BSD_PROCESS_ACCT_V3 is not set +# CONFIG_BT is not set +# CONFIG_BTRFS_ASSERT is not set +# CONFIG_BTRFS_DEBUG is not set +# CONFIG_BTRFS_FS is not set +# CONFIG_BTRFS_FS_RUN_SANITY_TESTS is not set +# CONFIG_BT_ATH3K is not set +# CONFIG_BT_BNEP is not set +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +# CONFIG_BT_CMTP is not set +# CONFIG_BT_HCIBCM203X is not set +# CONFIG_BT_HCIBFUSB is not set +# CONFIG_BT_HCIBLUECARD is not set +# CONFIG_BT_HCIBPA10X is not set +# CONFIG_BT_HCIBT3C is not set +# CONFIG_BT_HCIBTSDIO is not set +# CONFIG_BT_HCIBTUART is not set +# CONFIG_BT_HCIBTUSB is not set +# CONFIG_BT_HCIDTL1 is not set +# CONFIG_BT_HCIUART is not set +# CONFIG_BT_HCIUART_3WIRE is not set +# CONFIG_BT_HCIUART_ATH3K is not set +CONFIG_BT_HCIUART_BCSP=y +CONFIG_BT_HCIUART_H4=y +# CONFIG_BT_HCIUART_LL is not set +# CONFIG_BT_HCIVHCI is not set +# CONFIG_BT_HIDP is not set +CONFIG_BT_L2CAP=y +# CONFIG_BT_MRVL is not set +# CONFIG_BT_RFCOMM is not set +# CONFIG_BUILD_BIN2C is not set +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_SCO=y +CONFIG_BUG=y +CONFIG_BUILDTIME_EXTABLE_SORT=y +# CONFIG_C2PORT is not set +# CONFIG_CADENCE_WATCHDOG is not set +# CONFIG_CAIF is not set +# CONFIG_CAN is not set +# CONFIG_CAN_GS_USB is not set +# CONFIG_CAN_M_CAN is not set +# CONFIG_CAN_RCAR is not set +# CONFIG_CAPI_AVM is not set +# CONFIG_CAPI_EICON is not set +# CONFIG_CAPI_TRACE is not set +CONFIG_CARDBUS=y +# CONFIG_CARDMAN_4000 is not set +# CONFIG_CARDMAN_4040 is not set +# CONFIG_CARL9170 is not set +# CONFIG_CARMA_FPGA is not set +# CONFIG_CARMA_FPGA_PROGRAM is not set +# CONFIG_CASSINI is not set +CONFIG_CAVIUM_OCTEON_HELPER=y +# CONFIG_CAVIUM_OCTEON_REFERENCE_BOARD is not set +# CONFIG_CAVIUM_OCTEON_SIMULATOR is not set +# CONFIG_CAVIUM_OCTEON_SOC is not set +# CONFIG_CB710_CORE is not set +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +# CONFIG_CC_STACKPROTECTOR is not set +CONFIG_CC_STACKPROTECTOR_NONE=y +# CONFIG_CC_STACKPROTECTOR_REGULAR is not set +# CONFIG_CC_STACKPROTECTOR_STRONG is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_CED1401 is not set +# CONFIG_CEPH_FS is not set +# CONFIG_CEPH_LIB is not set +# CONFIG_CFG80211 is not set +# CONFIG_CFG80211_CERTIFICATION_ONUS is not set +# CONFIG_CFG80211_DEBUGFS is not set +# CONFIG_CFG80211_DEFAULT_PS is not set +# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set +# CONFIG_CFG80211_INTERNAL_REGDB is not set +# CONFIG_CFG80211_REG_DEBUG is not set +# CONFIG_CFG80211_WEXT is not set +# CONFIG_CGROUPS is not set +# CONFIG_CGROUP_DEBUG is not set +# CONFIG_CGROUP_NET_PRIO is not set +# CONFIG_CHARGER_BQ2415X is not set +# CONFIG_CHARGER_BQ24190 is not set +# CONFIG_CHARGER_BQ24735 is not set +# CONFIG_CHARGER_GPIO is not set +# CONFIG_CHARGER_ISP1704 is not set +# CONFIG_CHARGER_LP8727 is not set +# CONFIG_CHARGER_MANAGER is not set +# CONFIG_CHARGER_MAX8903 is not set +# CONFIG_CHARGER_SMB347 is not set +# CONFIG_CHARGER_TWL4030 is not set +# CONFIG_CHECKPOINT_RESTORE is not set +# CONFIG_CHELSIO_T1 is not set +# CONFIG_CHELSIO_T3 is not set +# CONFIG_CHELSIO_T4 is not set +# CONFIG_CHELSIO_T4VF is not set +# CONFIG_CHROME_PLATFORMS is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_CHR_DEV_SCH is not set +# CONFIG_CHR_DEV_SG is not set +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_CIFS is not set +# CONFIG_CIFS_ACL is not set +# CONFIG_CIFS_DEBUG is not set +# CONFIG_CIFS_DEBUG2 is not set +# CONFIG_CIFS_FSCACHE is not set +# CONFIG_CIFS_NFSD_EXPORT is not set +CONFIG_CIFS_POSIX=y +# CONFIG_CIFS_SMB2 is not set +CONFIG_CIFS_STATS=y +# CONFIG_CIFS_STATS2 is not set +# CONFIG_CIFS_WEAK_PW_HASH is not set +# CONFIG_CIFS_XATTR is not set +# CONFIG_CLEANCACHE is not set +# CONFIG_CLKSRC_VERSATILE is not set +CONFIG_CLS_U32_MARK=y +# CONFIG_CLS_U32_PERF is not set +# CONFIG_CM32181 is not set +# CONFIG_CM36651 is not set +# CONFIG_CMA is not set +CONFIG_CMDLINE="" +# CONFIG_CMDLINE_BOOL is not set +# CONFIG_CMDLINE_EXTEND is not set +# CONFIG_CMDLINE_FORCE is not set +# CONFIG_CMDLINE_FROM_BOOTLOADER is not set +# CONFIG_CMDLINE_PARTITION is not set +# CONFIG_CNIC is not set +# CONFIG_CODA_FS is not set +# CONFIG_CODE_PATCHING_SELFTEST is not set +# CONFIG_COMEDI is not set +# CONFIG_COMMON_CLK_DEBUG is not set +# CONFIG_COMMON_CLK_PXA is not set +# CONFIG_COMMON_CLK_QCOM is not set +# CONFIG_COMMON_CLK_SI5351 is not set +# CONFIG_COMMON_CLK_SI570 is not set +# CONFIG_COMPACTION is not set +# CONFIG_COMPAL_LAPTOP is not set +# CONFIG_COMPAT_BRK is not set +# CONFIG_COMPILE_TEST is not set +# CONFIG_CONFIGFS_FS is not set +# CONFIG_CONNECTOR is not set +CONFIG_CONSTRUCTORS=y +# CONFIG_CONTEXT_SWITCH_TRACER is not set +# CONFIG_COPS is not set +# CONFIG_CORDIC is not set +# CONFIG_COREDUMP is not set +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +# CONFIG_CPA_DEBUG is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_FREQ is not set +# CONFIG_CPU_IDLE is not set +# CONFIG_CPU_IDLE_GOV_MENU is not set +# CONFIG_CPU_IDLE_MULTIPLE_DRIVERS is not set +# CONFIG_CRAMFS is not set +CONFIG_CRASHLOG=y +# CONFIG_CRASH_DUMP is not set +# CONFIG_CRC16 is not set +CONFIG_CRC32=y +# CONFIG_CRC32_BIT is not set +CONFIG_CRC32_SARWATE=y +# CONFIG_CRC32_SELFTEST is not set +# CONFIG_CRC32_SLICEBY4 is not set +# CONFIG_CRC32_SLICEBY8 is not set +# CONFIG_CRC7 is not set +# CONFIG_CRC8 is not set +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC_ITU_T is not set +# CONFIG_CRC_T10DIF is not set +CONFIG_CROSS_COMPILE="" +# CONFIG_CROSS_MEMORY_ATTACH is not set +CONFIG_CRYPTO=y +# CONFIG_CRYPTO_AEAD is not set +CONFIG_CRYPTO_AES=y +# CONFIG_CRYPTO_AES_586 is not set +# CONFIG_CRYPTO_AES_ARM is not set +# CONFIG_CRYPTO_AES_ARM_BS is not set +# CONFIG_CRYPTO_AES_NI_INTEL is not set +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +# CONFIG_CRYPTO_ANSI_CPRNG is not set +# CONFIG_CRYPTO_ANUBIS is not set +CONFIG_CRYPTO_ARC4=y +# CONFIG_CRYPTO_AUTHENC is not set +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_BLKCIPHER2=y +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_CBC is not set +# CONFIG_CRYPTO_CCM is not set +# CONFIG_CRYPTO_CMAC is not set +# CONFIG_CRYPTO_CRC32 is not set +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_CRC32C_INTEL is not set +# CONFIG_CRYPTO_CRCT10DIF is not set +# CONFIG_CRYPTO_CRYPTD is not set +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_CTS is not set +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_DES is not set +# CONFIG_CRYPTO_DEV_ATMEL_AES is not set +# CONFIG_CRYPTO_DEV_ATMEL_SHA is not set +# CONFIG_CRYPTO_DEV_ATMEL_TDES is not set +# CONFIG_CRYPTO_DEV_CCP is not set +# CONFIG_CRYPTO_DEV_FSL_CAAM is not set +# CONFIG_CRYPTO_DEV_HIFN_795X is not set +# CONFIG_CRYPTO_DEV_MV_CESA is not set +# CONFIG_CRYPTO_DEV_QAT_DH895xCC is not set +# CONFIG_CRYPTO_DEV_QCE is not set +# CONFIG_CRYPTO_DEV_SAHARA is not set +# CONFIG_CRYPTO_DEV_TALITOS is not set +# CONFIG_CRYPTO_DRBG_MENU is not set +# CONFIG_CRYPTO_ECB is not set +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_FIPS is not set +# CONFIG_CRYPTO_GCM is not set +# CONFIG_CRYPTO_GF128MUL is not set +# CONFIG_CRYPTO_GHASH is not set +# CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL is not set +# CONFIG_CRYPTO_HASH is not set +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_HW is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_LZ4 is not set +# CONFIG_CRYPTO_LZ4HC is not set +# CONFIG_CRYPTO_LZO is not set +# CONFIG_CRYPTO_MANAGER is not set +# CONFIG_CRYPTO_MANAGER2 is not set +CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y +# CONFIG_CRYPTO_MCRYPTD is not set +# CONFIG_CRYPTO_MD4 is not set +# CONFIG_CRYPTO_MD5 is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_PCBC is not set +# CONFIG_CRYPTO_PCOMP is not set +# CONFIG_CRYPTO_PCOMP2 is not set +# CONFIG_CRYPTO_PCRYPT is not set +# CONFIG_CRYPTO_RMD128 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_RMD256 is not set +# CONFIG_CRYPTO_RMD320 is not set +# CONFIG_CRYPTO_RNG is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_SALSA20_586 is not set +# CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_SEQIV is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA1_ARM is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_TEST is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_TWOFISH_586 is not set +# CONFIG_CRYPTO_TWOFISH_COMMON is not set +# CONFIG_CRYPTO_USER is not set +# CONFIG_CRYPTO_USER_API_HASH is not set +# CONFIG_CRYPTO_USER_API_SKCIPHER is not set +# CONFIG_CRYPTO_VMAC is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_XTS is not set +# CONFIG_CRYPTO_XZ is not set +# CONFIG_CRYPTO_ZLIB is not set +# CONFIG_CRYSTALHD is not set +# CONFIG_CS5535_MFGPT is not set +# CONFIG_CS89x0 is not set +# CONFIG_CUSE is not set +# CONFIG_CW1200 is not set +# CONFIG_CXL_BASE is not set +# CONFIG_CXT1E1 is not set +# CONFIG_CYPRESS_FIRMWARE is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_DCB is not set +# CONFIG_DDR is not set +# CONFIG_DE600 is not set +# CONFIG_DE620 is not set +# CONFIG_DEBUG_ATOMIC_SLEEP is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_CREDENTIALS is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +CONFIG_DEBUG_FS=y +# CONFIG_DEBUG_GPIO is not set +# CONFIG_DEBUG_HIGHMEM is not set +# CONFIG_DEBUG_ICEDCC is not set +# CONFIG_DEBUG_INFO is not set +# CONFIG_DEBUG_INFO_DWARF4 is not set +CONFIG_DEBUG_INFO_REDUCED=y +# CONFIG_DEBUG_INFO_SPLIT is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_KMEMLEAK is not set +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_KOBJECT_RELEASE is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_LL is not set +# CONFIG_DEBUG_LL_UART_8250 is not set +# CONFIG_DEBUG_LL_UART_PL01X is not set +# CONFIG_DEBUG_LOCKDEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_DEBUG_NX_TEST is not set +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_DEBUG_PAGEALLOC is not set +# CONFIG_DEBUG_PERF_USE_VMALLOC is not set +# CONFIG_DEBUG_PER_CPU_MAPS is not set +# CONFIG_DEBUG_PI_LIST is not set +# CONFIG_DEBUG_PINCTRL is not set +# CONFIG_DEBUG_PREEMPT is not set +# CONFIG_DEBUG_RODATA is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_DEBUG_SECTION_MISMATCH is not set +# CONFIG_DEBUG_SEMIHOSTING is not set +# CONFIG_DEBUG_SET_MODULE_RONX is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_SHIRQ is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_STACKOVERFLOW is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_STRICT_USER_COPY_CHECKS is not set +# CONFIG_DEBUG_UART_BCM63XX is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_WRITECOUNT is not set +# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set +# CONFIG_DEBUG_ZBOOT is not set +# CONFIG_DECNET is not set +CONFIG_DEFAULT_CUBIC=y +CONFIG_DEFAULT_DEADLINE=y +CONFIG_DEFAULT_HOSTNAME="(none)" +CONFIG_DEFAULT_IOSCHED="deadline" +CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4 +CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 +# CONFIG_DEFAULT_NOOP is not set +# CONFIG_DEFAULT_RENO is not set +CONFIG_DEFAULT_SECURITY="" +CONFIG_DEFAULT_SECURITY_DAC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +# CONFIG_DELL_SMO8800 is not set +# CONFIG_DEPRECATED_PARAM_STRUCT is not set +# CONFIG_DETECT_HUNG_TASK is not set +# CONFIG_DEVKMEM is not set +CONFIG_DEVPORT=y +# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set +# CONFIG_DEVTMPFS is not set +# CONFIG_DEVTMPFS_MOUNT is not set +# CONFIG_DGAP is not set +# CONFIG_DGNC is not set +# CONFIG_DGRP is not set +# CONFIG_DHT11 is not set +# CONFIG_DIRECT_IO is not set +CONFIG_DISABLE_DEV_COREDUMP=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_DISPLAY_CONNECTOR_ANALOG_TV is not set +# CONFIG_DISPLAY_CONNECTOR_DVI is not set +# CONFIG_DISPLAY_CONNECTOR_HDMI is not set +# CONFIG_DISPLAY_ENCODER_TFP410 is not set +# CONFIG_DISPLAY_ENCODER_TPD12S015 is not set +# CONFIG_DISPLAY_PANEL_DPI is not set +# CONFIG_DISPLAY_PANEL_LGPHILIPS_LB035Q02 is not set +# CONFIG_DISPLAY_PANEL_TPO_TD028TTEC1 is not set +# CONFIG_DISPLAY_PANEL_TPO_TD043MTEA1 is not set +# CONFIG_DISPLAY_SUPPORT is not set +# CONFIG_DL2K is not set +# CONFIG_DLM is not set +# CONFIG_DM9000 is not set +# CONFIG_DMADEVICES is not set +# CONFIG_DMADEVICES_DEBUG is not set +# CONFIG_DMASCC is not set +# CONFIG_DMATEST is not set +# CONFIG_DMA_API_DEBUG is not set +# CONFIG_DMA_ENGINE is not set +# CONFIG_DMA_SHARED_BUFFER is not set +# CONFIG_DM_CACHE is not set +# CONFIG_DM_DEBUG is not set +# CONFIG_DM_DELAY is not set +# CONFIG_DM_ERA is not set +# CONFIG_DM_FLAKEY is not set +# CONFIG_DM_LOG_USERSPACE is not set +# CONFIG_DM_MULTIPATH is not set +# CONFIG_DM_RAID is not set +# CONFIG_DM_SWITCH is not set +# CONFIG_DM_THIN_PROVISIONING is not set +# CONFIG_DM_UEVENT is not set +# CONFIG_DM_VERITY is not set +# CONFIG_DM_ZERO is not set +# CONFIG_DNET is not set +# CONFIG_DNOTIFY is not set +# CONFIG_DNS_RESOLVER is not set +CONFIG_DOUBLEFAULT=y +CONFIG_DQL=y +# CONFIG_DRAGONRISE_FF is not set +# CONFIG_DRM is not set +# CONFIG_DS1682 is not set +# CONFIG_DTLK is not set +# CONFIG_DUMMY is not set +# CONFIG_DUMMY_IRQ is not set +# CONFIG_DVB_AU8522_V4L is not set +# CONFIG_DVB_CORE is not set +# CONFIG_DVB_DUMMY_FE is not set +# CONFIG_DVB_TUNER_DIB0070 is not set +# CONFIG_DVB_TUNER_DIB0090 is not set +# CONFIG_DW_DMAC is not set +# CONFIG_DW_WATCHDOG is not set +# CONFIG_DWC3_HOST_USB3_LPM_ENABLE is not set +# CONFIG_DX_SEP is not set +# CONFIG_DYNAMIC_DEBUG is not set +# CONFIG_E100 is not set +# CONFIG_E1000 is not set +# CONFIG_E1000E is not set +# CONFIG_E2100 is not set +# CONFIG_EARLY_PRINTK_8250 is not set +# CONFIG_EASYCAP is not set +# CONFIG_ECHO is not set +# CONFIG_ECONET is not set +# CONFIG_ECRYPT_FS is not set +# CONFIG_EDAC is not set +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_EEPROM_93XX46 is not set +# CONFIG_EEPROM_AT24 is not set +# CONFIG_EEPROM_AT25 is not set +# CONFIG_EEPROM_DIGSY_MTC_CFG is not set +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +# CONFIG_EEXPRESS is not set +# CONFIG_EEXPRESS_PRO is not set +CONFIG_EFI_PARTITION=y +# CONFIG_EFS_FS is not set +# CONFIG_ELF_CORE is not set +# CONFIG_EMAC_ROCKCHIP is not set +CONFIG_EMBEDDED=y +# CONFIG_EM_TIMER_STI is not set +# CONFIG_ENABLE_MUST_CHECK is not set +CONFIG_ENABLE_WARN_DEPRECATED=y +# CONFIG_ENC28J60 is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_ENCRYPTED_KEYS is not set +# CONFIG_ENIC is not set +# CONFIG_EPAPR_PARAVIRT is not set +# CONFIG_EPIC100 is not set +CONFIG_EPOLL=y +# CONFIG_EQUALIZER is not set +# CONFIG_ET131X is not set +# CONFIG_GATEWORKS_GW16083 is not set +# CONFIG_GLOB_SELFTEST is not set +# CONFIG_GS_FPGABOOT is not set +# CONFIG_ETH16I is not set +CONFIG_ETHERNET=y +# CONFIG_ETHOC is not set +CONFIG_EVENTFD=y +# CONFIG_EVENT_POWER_TRACING_DEPRECATED is not set +# CONFIG_EWRK3 is not set +CONFIG_EXPERIMENTAL=y +CONFIG_EXPERT=y +# CONFIG_EXPORTFS is not set +# CONFIG_EXT2_FS is not set +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set +# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set +# CONFIG_EXT3_FS is not set +# CONFIG_EXT3_FS_XATTR is not set +# CONFIG_EXT4_DEBUG is not set +# CONFIG_EXT4_FS is not set +# CONFIG_EXT4_FS_POSIX_ACL is not set +# CONFIG_EXT4_FS_SECURITY is not set +CONFIG_EXT4_FS_XATTR=y +CONFIG_EXT4_USE_FOR_EXT23=y +# CONFIG_EXTCON is not set +CONFIG_EXTRA_FIRMWARE="" +CONFIG_EXTRA_TARGETS="" +# CONFIG_EXYNOS_ADC is not set +# CONFIG_EXYNOS_VIDEO is not set +# CONFIG_EZX_PCAP is not set +# CONFIG_F2FS_FS is not set +# CONFIG_FAIR_GROUP_SCHED is not set +# CONFIG_FANOTIFY is not set +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_FAT_FS is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_FB is not set +# CONFIG_FB_3DFX is not set +# CONFIG_FB_ARC is not set +# CONFIG_FB_ARK is not set +# CONFIG_FB_ARMCLCD is not set +# CONFIG_FB_ASILIANT is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_AUO_K190X is not set +# CONFIG_FB_BACKLIGHT is not set +# CONFIG_FB_BOOT_VESA_SUPPORT is not set +# CONFIG_FB_BROADSHEET is not set +# CONFIG_FB_CARMINE is not set +# CONFIG_FB_CFB_COPYAREA is not set +# CONFIG_FB_CFB_FILLRECT is not set +# CONFIG_FB_CFB_IMAGEBLIT is not set +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set +# CONFIG_FB_CIRRUS is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_DA8XX is not set +# CONFIG_FB_DDC is not set +# CONFIG_FB_FOREIGN_ENDIAN is not set +# CONFIG_FB_GEODE is not set +# CONFIG_FB_GOLDFISH is not set +# CONFIG_FB_HGA is not set +# CONFIG_FB_I740 is not set +# CONFIG_FB_IBM_GXT4500 is not set +# CONFIG_FB_IMSTT is not set +# CONFIG_FB_IMX is not set +# CONFIG_FB_KYRO is not set +# CONFIG_FB_LE80578 is not set +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_MB862XX is not set +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_N411 is not set +# CONFIG_FB_NEOMAGIC is not set +# CONFIG_FB_NVIDIA is not set +# CONFIG_FB_OF is not set +# CONFIG_FB_OPENCORES is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_PM3 is not set +# CONFIG_FB_PS3 is not set +# CONFIG_FB_PXA is not set +# CONFIG_FB_RADEON is not set +# CONFIG_FB_RIVA is not set +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_S3 is not set +# CONFIG_FB_SAVAGE is not set +# CONFIG_FB_SIMPLE is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_SM7XX is not set +# CONFIG_FB_SMSCUFX is not set +# CONFIG_FB_SSD1307 is not set +# CONFIG_FB_SVGALIB is not set +# CONFIG_FB_SYS_COPYAREA is not set +# CONFIG_FB_SYS_FILLRECT is not set +# CONFIG_FB_SYS_FOPS is not set +# CONFIG_FB_SYS_IMAGEBLIT is not set +# CONFIG_FB_TILEBLITTING is not set +# CONFIG_FB_TMIO is not set +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_UDL is not set +# CONFIG_FB_UVESA is not set +# CONFIG_FB_VGA16 is not set +# CONFIG_FB_VIA is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_VT8623 is not set +# CONFIG_FB_XGI is not set +# CONFIG_FCOE is not set +# CONFIG_FCOE_FNIC is not set +# CONFIG_FDDI is not set +# CONFIG_FEALNX is not set +# CONFIG_FENCE_TRACE is not set +# CONFIG_FHANDLE is not set +CONFIG_FIB_RULES=y +CONFIG_FILE_LOCKING=y +# CONFIG_FIREWIRE is not set +# CONFIG_FIREWIRE_NOSY is not set +# CONFIG_FIREWIRE_SERIAL is not set +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FIRMWARE_IN_KERNEL is not set +# CONFIG_FIRMWARE_MEMMAP is not set +# CONFIG_FIXED_PHY is not set +CONFIG_FLATMEM=y +CONFIG_FLATMEM_MANUAL=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_FM10K is not set +# CONFIG_FMC is not set +# CONFIG_FORCEDETH is not set +CONFIG_FORCE_MAX_ZONEORDER=11 +# CONFIG_FRAMEBUFFER_CONSOLE is not set +# CONFIG_FRAME_POINTER is not set +CONFIG_FRAME_WARN=1024 +# CONFIG_FREEZER is not set +# CONFIG_FRONTSWAP is not set +# CONFIG_FSCACHE is not set +# CONFIG_FSL_EDMA is not set +# CONFIG_FSL_XGMAC_MDIO is not set +CONFIG_FSNOTIFY=y +# CONFIG_FS_POSIX_ACL is not set +# CONFIG_FT1000 is not set +# CONFIG_FTGMAC100 is not set +# CONFIG_FTL is not set +# CONFIG_FTMAC100 is not set +# CONFIG_FTRACE is not set +# CONFIG_FTRACE_STARTUP_TEST is not set +# CONFIG_FTR_FIXUP_SELFTEST is not set +# CONFIG_FUJITSU_TABLET is not set +# CONFIG_FUNCTION_TRACER is not set +# CONFIG_FUSE_FS is not set +# CONFIG_FUSION is not set +# CONFIG_FUSION_FC is not set +# CONFIG_FUSION_SAS is not set +# CONFIG_FUSION_SPI is not set +CONFIG_FUTEX=y +CONFIG_FW_LOADER=y +CONFIG_FW_LOADER_USER_HELPER=y +CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y +CONFIG_GACT_PROB=y +# CONFIG_GADGET_UAC1 is not set +# CONFIG_GAMEPORT is not set +# CONFIG_GCOV is not set +# CONFIG_GCOV_KERNEL is not set +# CONFIG_GENEVE is not set +# CONFIG_GENERIC_ADC_BATTERY is not set +CONFIG_GENERIC_CALIBRATE_DELAY=y +# CONFIG_GENERIC_CPU_DEVICES is not set +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_NET_UTILS=y +# CONFIG_GENERIC_PHY is not set +CONFIG_GENERIC_TIME=y +# CONFIG_GENWQE is not set +# CONFIG_GFS2_FS is not set +# CONFIG_GIGASET_CAPI is not set +# CONFIG_GIGASET_DEBUG is not set +# CONFIG_GP2AP020A00F is not set +# CONFIG_GPIOLIB is not set +# CONFIG_GPIO_74X164 is not set +# CONFIG_GPIO_ADNP is not set +# CONFIG_GPIO_ADP5588 is not set +# CONFIG_GPIO_AMD8111 is not set +# CONFIG_GPIO_BCM_KONA is not set +# CONFIG_GPIO_BT8XX is not set +# CONFIG_GPIO_CS5535 is not set +# CONFIG_GPIO_DWAPB is not set +# CONFIG_GPIO_EM is not set +# CONFIG_GPIO_GENERIC_PLATFORM is not set +# CONFIG_GPIO_GRGPIO is not set +# CONFIG_GPIO_ICH is not set +# CONFIG_GPIO_IT8761E is not set +# CONFIG_GPIO_LANGWELL is not set +# CONFIG_GPIO_MAX7300 is not set +# CONFIG_GPIO_MAX7301 is not set +# CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_MC33880 is not set +# CONFIG_GPIO_MCP23S08 is not set +# CONFIG_GPIO_ML_IOH is not set +# CONFIG_GPIO_PCA953X is not set +# CONFIG_GPIO_PCF857X is not set +# CONFIG_GPIO_PCH is not set +# CONFIG_GPIO_PL061 is not set +# CONFIG_GPIO_RCAR is not set +# CONFIG_GPIO_RDC321X is not set +# CONFIG_GPIO_SCH is not set +# CONFIG_GPIO_SCH311X is not set +# CONFIG_GPIO_SX150X is not set +# CONFIG_GPIO_SYSCON is not set +# CONFIG_GPIO_SYSFS is not set +# CONFIG_GPIO_TS5500 is not set +# CONFIG_GPIO_VX855 is not set +# CONFIG_GPIO_WATCHDOG is not set +# CONFIG_GPIO_WDT is not set +# CONFIG_GPIO_XILINX is not set +# CONFIG_GPIO_ZEVIO is not set +# CONFIG_GREENASIA_FF is not set +# CONFIG_HAMACHI is not set +# CONFIG_HAMRADIO is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_HARDLOCKUP_DETECTOR is not set +# CONFIG_HAVE_AOUT is not set +# CONFIG_HAVE_ARM_ARCH_TIMER is not set +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +# CONFIG_HCALL_STATS is not set +# CONFIG_HDLC is not set +# CONFIG_HDLC_CISCO is not set +# CONFIG_HDLC_FR is not set +# CONFIG_HDLC_PPP is not set +# CONFIG_HDLC_RAW is not set +# CONFIG_HDLC_RAW_ETH is not set +# CONFIG_HDQ_MASTER_OMAP is not set +# CONFIG_HEADERS_CHECK is not set +# CONFIG_HERMES is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_HFSPLUS_FS_POSIX_ACL is not set +# CONFIG_HFS_FS is not set +# CONFIG_HIBERNATION is not set +# CONFIG_HID is not set +# CONFIG_HIDRAW is not set +# CONFIG_HID_A4TECH is not set +# CONFIG_HID_ACRUX is not set +# CONFIG_HID_ACRUX_FF is not set +# CONFIG_HID_APPLE is not set +# CONFIG_HID_APPLEIR is not set +# CONFIG_HID_AUREAL is not set +# CONFIG_HID_BELKIN is not set +# CONFIG_HID_CHERRY is not set +# CONFIG_HID_CHICONY is not set +# CONFIG_HID_CP2112 is not set +# CONFIG_HID_CYPRESS is not set +# CONFIG_HID_DRAGONRISE is not set +# CONFIG_HID_ELECOM is not set +# CONFIG_HID_ELO is not set +# CONFIG_HID_EMS_FF is not set +# CONFIG_HID_EZKEY is not set +# CONFIG_HID_GENERIC is not set +# CONFIG_HID_GREENASIA is not set +# CONFIG_HID_GT683R is not set +# CONFIG_HID_GYRATION is not set +# CONFIG_HID_HOLTEK is not set +# CONFIG_HID_HUION is not set +# CONFIG_HID_ICADE is not set +# CONFIG_HID_KENSINGTON is not set +# CONFIG_HID_KEYTOUCH is not set +# CONFIG_HID_KYE is not set +# CONFIG_HID_LCPOWER is not set +# CONFIG_HID_LENOVO is not set +# CONFIG_HID_LENOVO_TPKBD is not set +# CONFIG_HID_LOGITECH is not set +# CONFIG_HID_LOGITECH_DJ is not set +# CONFIG_HID_LOGITECH_HIDPP is not set +# CONFIG_HID_MAGICMOUSE is not set +# CONFIG_HID_MICROSOFT is not set +# CONFIG_HID_MONTEREY is not set +# CONFIG_HID_MULTITOUCH is not set +# CONFIG_HID_NTRIG is not set +# CONFIG_HID_ORTEK is not set +# CONFIG_HID_PANTHERLORD is not set +# CONFIG_HID_PENMOUNT is not set +# CONFIG_HID_PETALYNX is not set +# CONFIG_HID_PICOLCD is not set +# CONFIG_HID_PID is not set +# CONFIG_HID_PRIMAX is not set +# CONFIG_HID_PRODIKEYS is not set +# CONFIG_HID_PS3REMOTE is not set +# CONFIG_HID_QUANTA is not set +# CONFIG_HID_RMI is not set +# CONFIG_HID_ROCCAT is not set +# CONFIG_HID_ROCCAT_ARVO is not set +# CONFIG_HID_ROCCAT_KONE is not set +# CONFIG_HID_ROCCAT_KONEPLUS is not set +# CONFIG_HID_ROCCAT_KOVAPLUS is not set +# CONFIG_HID_ROCCAT_PYRA is not set +# CONFIG_HID_SAITEK is not set +# CONFIG_HID_SAMSUNG is not set +# CONFIG_HID_SENSOR_HUB is not set +# CONFIG_HID_SMARTJOYPLUS is not set +# CONFIG_HID_SONY is not set +# CONFIG_HID_SPEEDLINK is not set +# CONFIG_HID_STEELSERIES is not set +# CONFIG_HID_SUNPLUS is not set +# CONFIG_HID_SUPPORT is not set +# CONFIG_HID_THINGM is not set +# CONFIG_HID_THRUSTMASTER is not set +# CONFIG_HID_TIVO is not set +# CONFIG_HID_TOPSEED is not set +# CONFIG_HID_TWINHAN is not set +# CONFIG_HID_UCLOGIC is not set +# CONFIG_HID_WACOM is not set +# CONFIG_HID_WALTOP is not set +# CONFIG_HID_WIIMOTE is not set +# CONFIG_HID_XINMO is not set +# CONFIG_HID_ZEROPLUS is not set +# CONFIG_HID_ZYDACRON is not set +# CONFIG_HIGHMEM is not set +CONFIG_HIGH_RES_TIMERS=y +# CONFIG_HIPPI is not set +# CONFIG_HIX5HD2_GMAC is not set +# CONFIG_HMC6352 is not set +# CONFIG_HOSTAP is not set +# CONFIG_HOSTAP_CS is not set +# CONFIG_HOSTAP_PCI is not set +# CONFIG_HOSTAP_PLX is not set +CONFIG_HOTPLUG=y +# CONFIG_HOTPLUG_CPU is not set +# CONFIG_HOTPLUG_PCI is not set +# CONFIG_HP100 is not set +CONFIG_HPET_MMAP_DEFAULT=y +# CONFIG_HPFS_FS is not set +# CONFIG_HPLAN is not set +# CONFIG_HPLAN_PLUS is not set +# CONFIG_HP_ILO is not set +# CONFIG_HP_WIRELESS is not set +# CONFIG_HSI is not set +# CONFIG_HSR is not set +# CONFIG_HTC_EGPIO is not set +# CONFIG_HTC_I2CPLD is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_HUGETLB_PAGE is not set +# CONFIG_HVC_DCC is not set +# CONFIG_HVC_UDBG is not set +# CONFIG_HWMON is not set +# CONFIG_HWMON_DEBUG_CHIP is not set +# CONFIG_HWMON_VID is not set +# CONFIG_HWSPINLOCK_OMAP is not set +CONFIG_HW_PERF_EVENTS=y +# CONFIG_HW_RANDOM is not set +# CONFIG_HW_RANDOM_AMD is not set +# CONFIG_HW_RANDOM_ATMEL is not set +# CONFIG_HW_RANDOM_EXYNOS is not set +# CONFIG_HW_RANDOM_GEODE is not set +# CONFIG_HW_RANDOM_INTEL is not set +# CONFIG_HW_RANDOM_OMAP3_ROM is not set +# CONFIG_HW_RANDOM_PPC4XX is not set +# CONFIG_HW_RANDOM_TIMERIOMEM is not set +# CONFIG_HW_RANDOM_VIA is not set +# CONFIG_HYPERV is not set +# CONFIG_HYSDN is not set +CONFIG_HZ=100 +CONFIG_HZ_100=y +# CONFIG_HZ_1000 is not set +# CONFIG_HZ_1024 is not set +# CONFIG_HZ_128 is not set +# CONFIG_HZ_200 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_256 is not set +# CONFIG_HZ_300 is not set +# CONFIG_HZ_48 is not set +# CONFIG_HZ_500 is not set +# CONFIG_HZ_PERIODIC is not set +# CONFIG_I2C is not set +# CONFIG_I2C_ALGOBIT is not set +# CONFIG_I2C_ALGOPCA is not set +# CONFIG_I2C_ALGOPCF is not set +# CONFIG_I2C_ALI1535 is not set +# CONFIG_I2C_ALI1563 is not set +# CONFIG_I2C_ALI15X3 is not set +# CONFIG_I2C_AMD756 is not set +# CONFIG_I2C_AMD8111 is not set +# CONFIG_I2C_ARB_GPIO_CHALLENGE is not set +# CONFIG_I2C_AU1550 is not set +# CONFIG_I2C_BCM2835 is not set +# CONFIG_I2C_CBUS_GPIO is not set +# CONFIG_I2C_CHARDEV is not set +# CONFIG_I2C_COMPAT is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DESIGNWARE is not set +# CONFIG_I2C_DESIGNWARE_PCI is not set +# CONFIG_I2C_DESIGNWARE_PLATFORM is not set +# CONFIG_I2C_DIOLAN_U2C is not set +# CONFIG_I2C_EG20T is not set +# CONFIG_I2C_ELEKTOR is not set +# CONFIG_I2C_GPIO is not set +# CONFIG_I2C_HELPER_AUTO is not set +# CONFIG_I2C_HID is not set +# CONFIG_I2C_I801 is not set +# CONFIG_I2C_IBM_IIC is not set +# CONFIG_I2C_INTEL_MID is not set +# CONFIG_I2C_ISCH is not set +# CONFIG_I2C_ISMT is not set +# CONFIG_I2C_MPC is not set +# CONFIG_I2C_MUX is not set +# CONFIG_I2C_MUX_PINCTRL is not set +# CONFIG_I2C_MV64XXX is not set +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_NOMADIK is not set +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_OCTEON is not set +# CONFIG_I2C_PARPORT is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_PCA_ISA is not set +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_PIIX4 is not set +# CONFIG_I2C_PXA_PCI is not set +# CONFIG_I2C_RCAR is not set +# CONFIG_I2C_RK3X is not set +# CONFIG_I2C_ROBOTFUZZ_OSIF is not set +# CONFIG_I2C_SCMI is not set +# CONFIG_I2C_SH_MOBILE is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_SMBUS is not set +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_TINY_USB is not set +# CONFIG_I2C_VERSATILE is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set +# CONFIG_I2C_XILINX is not set +# CONFIG_I2O is not set +# CONFIG_I40E is not set +# CONFIG_I40EVF is not set +# CONFIG_I6300ESB_WDT is not set +# CONFIG_I82092 is not set +# CONFIG_I82365 is not set +# CONFIG_IBM_ASM is not set +# CONFIG_IBM_EMAC_DEBUG is not set +# CONFIG_IBM_EMAC_EMAC4 is not set +# CONFIG_IBM_EMAC_MAL_CLR_ICINTSTAT is not set +# CONFIG_IBM_EMAC_MAL_COMMON_ERR is not set +# CONFIG_IBM_EMAC_NO_FLOW_CTRL is not set +# CONFIG_IBM_EMAC_RGMII is not set +# CONFIG_IBM_EMAC_TAH is not set +# CONFIG_IBM_EMAC_ZMII is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_ICS932S401 is not set +# CONFIG_IDE is not set +# CONFIG_IDEAPAD_LAPTOP is not set +# CONFIG_IDE_GD is not set +# CONFIG_IDE_PHISON is not set +# CONFIG_IDE_PROC_FS is not set +# CONFIG_IDE_TASK_IOCTL is not set +# CONFIG_IEEE802154 is not set +# CONFIG_IEEE802154_FAKEHARD is not set +# CONFIG_IFB is not set +# CONFIG_IGB is not set +# CONFIG_IGBVF is not set +# CONFIG_IIO is not set +# CONFIG_IIO_BUFFER_CB is not set +CONFIG_IIO_CONSUMERS_PER_TRIGGER=2 +# CONFIG_IIO_GPIO_TRIGGER is not set +# CONFIG_IIO_INTERRUPT_TRIGGER is not set +# CONFIG_IIO_PERIODIC_RTC_TRIGGER is not set +# CONFIG_IIO_SIMPLE_DUMMY is not set +# CONFIG_IIO_ST_ACCEL_3AXIS is not set +# CONFIG_IIO_ST_GYRO_3AXIS is not set +# CONFIG_IIO_ST_MAGN_3AXIS is not set +# CONFIG_IIO_ST_PRESS is not set +# CONFIG_IIO_SYSFS_TRIGGER is not set +# CONFIG_IKCONFIG is not set +# CONFIG_IKCONFIG_PROC is not set +# CONFIG_IMAGE_CMDLINE_HACK is not set +# CONFIG_IMX_IPUV3_CORE is not set +CONFIG_INET=y +# CONFIG_INET6_AH is not set +# CONFIG_INET6_ESP is not set +# CONFIG_INET6_IPCOMP is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_INET6_XFRM_MODE_BEET is not set +# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set +# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET6_XFRM_MODE_TUNNEL is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_DIAG is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_LRO is not set +# CONFIG_INET_TCP_DIAG is not set +# CONFIG_INET_TUNNEL is not set +# CONFIG_INET_UDP_DIAG is not set +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET_XFRM_MODE_TUNNEL is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INFINIBAND is not set +# CONFIG_INFTL is not set +# CONFIG_INITRAMFS_COMPRESSION_BZIP2 is not set +# CONFIG_INITRAMFS_COMPRESSION_GZIP is not set +# CONFIG_INITRAMFS_COMPRESSION_LZMA is not set +CONFIG_INITRAMFS_COMPRESSION_NONE=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +# CONFIG_INLINE_READ_LOCK is not set +# CONFIG_INLINE_READ_LOCK_BH is not set +# CONFIG_INLINE_READ_LOCK_IRQ is not set +# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set +# CONFIG_INLINE_READ_TRYLOCK is not set +CONFIG_INLINE_READ_UNLOCK=y +# CONFIG_INLINE_READ_UNLOCK_BH is not set +CONFIG_INLINE_READ_UNLOCK_IRQ=y +# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_SPIN_LOCK is not set +# CONFIG_INLINE_SPIN_LOCK_BH is not set +# CONFIG_INLINE_SPIN_LOCK_IRQ is not set +# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set +# CONFIG_INLINE_SPIN_TRYLOCK is not set +# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set +CONFIG_INLINE_SPIN_UNLOCK=y +# CONFIG_INLINE_SPIN_UNLOCK_BH is not set +CONFIG_INLINE_SPIN_UNLOCK_IRQ=y +# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_WRITE_LOCK is not set +# CONFIG_INLINE_WRITE_LOCK_BH is not set +# CONFIG_INLINE_WRITE_LOCK_IRQ is not set +# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set +# CONFIG_INLINE_WRITE_TRYLOCK is not set +CONFIG_INLINE_WRITE_UNLOCK=y +# CONFIG_INLINE_WRITE_UNLOCK_BH is not set +CONFIG_INLINE_WRITE_UNLOCK_IRQ=y +# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set +CONFIG_INOTIFY_USER=y +# CONFIG_INPUT is not set +# CONFIG_INPUT_AD714X is not set +# CONFIG_INPUT_ADXL34X is not set +# CONFIG_INPUT_APANEL is not set +# CONFIG_INPUT_ATI_REMOTE is not set +# CONFIG_INPUT_ATI_REMOTE2 is not set +# CONFIG_INPUT_ATLAS_BTNS is not set +# CONFIG_INPUT_BMA150 is not set +# CONFIG_INPUT_CM109 is not set +# CONFIG_INPUT_CMA3000 is not set +# CONFIG_INPUT_DRV260X_HAPTICS is not set +# CONFIG_INPUT_DRV2667_HAPTICS is not set +# CONFIG_INPUT_EVBUG is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_GP2A is not set +# CONFIG_INPUT_GPIO_BEEPER is not set +# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set +# CONFIG_INPUT_GPIO_TILT_POLLED is not set +# CONFIG_INPUT_IDEAPAD_SLIDEBAR is not set +# CONFIG_INPUT_IMS_PCU is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_KEYSPAN_REMOTE is not set +# CONFIG_INPUT_KXTJ9 is not set +# CONFIG_INPUT_MATRIXKMAP is not set +CONFIG_INPUT_MISC=y +# CONFIG_INPUT_MMA8450 is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_MPU3050 is not set +# CONFIG_INPUT_PCF8574 is not set +# CONFIG_INPUT_PCSPKR is not set +# CONFIG_INPUT_POLLDEV is not set +# CONFIG_INPUT_POWERMATE is not set +# CONFIG_INPUT_PWM_BEEPER is not set +# CONFIG_INPUT_SOC_BUTTON_ARRAY is not set +# CONFIG_INPUT_SPARSEKMAP is not set +# CONFIG_INPUT_TABLET is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_UINPUT is not set +# CONFIG_INPUT_WISTRON_BTNS is not set +# CONFIG_INPUT_YEALINK is not set +# CONFIG_INT340X_THERMAL is not set +# CONFIG_INTEL_IDLE is not set +# CONFIG_INTEL_MEI is not set +# CONFIG_INTEL_MEI_ME is not set +# CONFIG_INTEL_MEI_TXE is not set +# CONFIG_INTEL_MIC_CARD is not set +# CONFIG_INTEL_MIC_HOST is not set +# CONFIG_INTEL_MID_PTI is not set +# CONFIG_INTEL_OAKTRAIL is not set +# CONFIG_INTEL_RST is not set +# CONFIG_INTEL_SMARTCONNECT is not set +# CONFIG_INTEL_SOC_PMIC is not set +# CONFIG_INTERVAL_TREE_TEST is not set +# CONFIG_INV_MPU6050_IIO is not set +# CONFIG_IOMMU_SUPPORT is not set +# CONFIG_IOSCHED_CFQ is not set +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_NOOP=y +# CONFIG_IP1000 is not set +# CONFIG_IP17XX_PHY is not set +# CONFIG_IP6_NF_FILTER is not set +# CONFIG_IP6_NF_IPTABLES is not set +# CONFIG_IP6_NF_MANGLE is not set +# CONFIG_IP6_NF_MATCH_AH is not set +# CONFIG_IP6_NF_MATCH_EUI64 is not set +# CONFIG_IP6_NF_MATCH_FRAG is not set +# CONFIG_IP6_NF_MATCH_HL is not set +# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set +# CONFIG_IP6_NF_MATCH_MH is not set +# CONFIG_IP6_NF_MATCH_OPTS is not set +# CONFIG_IP6_NF_MATCH_RPFILTER is not set +# CONFIG_IP6_NF_MATCH_RT is not set +# CONFIG_IP6_NF_NAT is not set +# CONFIG_IP6_NF_QUEUE is not set +# CONFIG_IP6_NF_RAW is not set +# CONFIG_IP6_NF_TARGET_HL is not set +# CONFIG_IP6_NF_TARGET_LOG is not set +# CONFIG_IP6_NF_TARGET_REJECT is not set +# CONFIG_IP6_NF_TARGET_SYNPROXY is not set +# CONFIG_IPACK_BUS is not set +# CONFIG_IPC_NS is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_IPV6 is not set +# CONFIG_IPV6_MIP6 is not set +# CONFIG_IPV6_MROUTE is not set +# CONFIG_IPV6_MROUTE_MULTIPLE_TABLES is not set +# CONFIG_IPV6_MULTIPLE_TABLES is not set +CONFIG_IPV6_NDISC_NODETYPE=y +# CONFIG_IPV6_OPTIMISTIC_DAD is not set +# CONFIG_IPV6_PRIVACY is not set +# CONFIG_IPV6_ROUTER_PREF is not set +# CONFIG_IPV6_ROUTE_INFO is not set +# CONFIG_IPV6_SIT is not set +# CONFIG_IPV6_SIT_6RD is not set +# CONFIG_IPV6_TUNNEL is not set +# CONFIG_IPV6_VTI is not set +# CONFIG_IPW2100 is not set +# CONFIG_IPW2100_DEBUG is not set +CONFIG_IPW2100_MONITOR=y +# CONFIG_IPW2200 is not set +# CONFIG_IPW2200_DEBUG is not set +CONFIG_IPW2200_MONITOR=y +# CONFIG_IPW2200_PROMISCUOUS is not set +# CONFIG_IPW2200_QOS is not set +# CONFIG_IPW2200_RADIOTAP is not set +# CONFIG_IPWIRELESS is not set +# CONFIG_IPX is not set +CONFIG_IP_ADVANCED_ROUTER=y +# CONFIG_IP_DCCP is not set +# CONFIG_IP_FIB_TRIE_STATS is not set +CONFIG_IP_MROUTE=y +CONFIG_IP_MROUTE_MULTIPLE_TABLES=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_MULTIPLE_TABLES=y +# CONFIG_IP_NF_ARPFILTER is not set +# CONFIG_IP_NF_ARPTABLES is not set +# CONFIG_IP_NF_ARP_MANGLE is not set +# CONFIG_IP_NF_FILTER is not set +# CONFIG_IP_NF_IPTABLES is not set +# CONFIG_IP_NF_MANGLE is not set +# CONFIG_IP_NF_MATCH_AH is not set +# CONFIG_IP_NF_MATCH_ECN is not set +# CONFIG_IP_NF_MATCH_RPFILTER is not set +# CONFIG_IP_NF_MATCH_TTL is not set +# CONFIG_IP_NF_QUEUE is not set +# CONFIG_IP_NF_RAW is not set +# CONFIG_IP_NF_SECURITY is not set +# CONFIG_IP_NF_TARGET_CLUSTERIP is not set +# CONFIG_IP_NF_TARGET_ECN is not set +# CONFIG_IP_NF_TARGET_LOG is not set +# CONFIG_IP_NF_TARGET_MASQUERADE is not set +# CONFIG_IP_NF_TARGET_NETMAP is not set +# CONFIG_IP_NF_TARGET_REDIRECT is not set +# CONFIG_IP_NF_TARGET_REJECT is not set +# CONFIG_IP_NF_TARGET_SYNPROXY is not set +# CONFIG_IP_NF_TARGET_TTL is not set +# CONFIG_IP_NF_TARGET_ULOG is not set +# CONFIG_IP_PIMSM_V1 is not set +# CONFIG_IP_PIMSM_V2 is not set +# CONFIG_IP_PNP is not set +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_VERBOSE=y +# CONFIG_IP_SCTP is not set +# CONFIG_IP_SET is not set +# CONFIG_IP_VS is not set +# CONFIG_IRDA is not set +# CONFIG_IRQSOFF_TRACER is not set +# CONFIG_IRQ_ALL_CPUS is not set +# CONFIG_IRQ_DOMAIN_DEBUG is not set +# CONFIG_IRQ_TIME_ACCOUNTING is not set +# CONFIG_IR_GPIO_CIR is not set +# CONFIG_IR_HIX5HD2 is not set +# CONFIG_IR_IGUANA is not set +# CONFIG_IR_IMG is not set +# CONFIG_IR_IMON is not set +# CONFIG_IR_JVC_DECODER is not set +# CONFIG_IR_LIRC_CODEC is not set +# CONFIG_IR_MCEUSB is not set +# CONFIG_IR_NEC_DECODER is not set +# CONFIG_IR_RC5_DECODER is not set +# CONFIG_IR_RC5_SZ_DECODER is not set +# CONFIG_IR_RC6_DECODER is not set +# CONFIG_IR_REDRAT3 is not set +# CONFIG_IR_SONY_DECODER is not set +# CONFIG_IR_STREAMZAP is not set +# CONFIG_IR_TTUSBIR is not set +# CONFIG_ISCSI_BOOT_SYSFS is not set +# CONFIG_ISCSI_TCP is not set +CONFIG_ISDN=y +# CONFIG_ISDN_AUDIO is not set +# CONFIG_ISDN_CAPI is not set +# CONFIG_ISDN_CAPI_CAPIDRV is not set +# CONFIG_ISDN_DIVERSION is not set +# CONFIG_ISDN_DRV_ACT2000 is not set +# CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON is not set +# CONFIG_ISDN_DRV_GIGASET is not set +# CONFIG_ISDN_DRV_HISAX is not set +# CONFIG_ISDN_DRV_ICN is not set +# CONFIG_ISDN_DRV_LOOP is not set +# CONFIG_ISDN_DRV_PCBIT is not set +# CONFIG_ISDN_DRV_SC is not set +# CONFIG_ISDN_I4L is not set +# CONFIG_ISL29003 is not set +# CONFIG_ISL29020 is not set +# CONFIG_ISL29125 is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_ISS4xx is not set +# CONFIG_ITG3200 is not set +# CONFIG_IWL3945 is not set +# CONFIG_IWLAGN is not set +# CONFIG_IWLWIFI is not set +# CONFIG_IWMC3200TOP is not set +# CONFIG_IXGB is not set +# CONFIG_IXGBE is not set +# CONFIG_IXGBEVF is not set +# CONFIG_JBD is not set +# CONFIG_JBD2_DEBUG is not set +# CONFIG_JBD_DEBUG is not set +# CONFIG_JFFS2_CMODE_FAVOURLZO is not set +# CONFIG_JFFS2_CMODE_NONE is not set +CONFIG_JFFS2_CMODE_PRIORITY=y +# CONFIG_JFFS2_CMODE_SIZE is not set +CONFIG_JFFS2_COMPRESSION_OPTIONS=y +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +# CONFIG_JFFS2_FS_POSIX_ACL is not set +# CONFIG_JFFS2_FS_SECURITY is not set +# CONFIG_JFFS2_FS_WBUF_VERIFY is not set +CONFIG_JFFS2_FS_WRITEBUFFER=y +CONFIG_JFFS2_FS_XATTR=y +CONFIG_JFFS2_LZMA=y +# CONFIG_JFFS2_LZO is not set +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +CONFIG_JFFS2_SUMMARY=y +# CONFIG_JFFS2_ZLIB is not set +# CONFIG_JFS_DEBUG is not set +# CONFIG_JFS_FS is not set +# CONFIG_JFS_POSIX_ACL is not set +# CONFIG_JFS_SECURITY is not set +# CONFIG_JFS_STATISTICS is not set +# CONFIG_JME is not set +CONFIG_JOLIET=y +# CONFIG_JUMP_LABEL is not set +# CONFIG_KALLSYMS is not set +# CONFIG_KALLSYMS_ALL is not set +# CONFIG_KALLSYMS_UNCOMPRESSED is not set +# CONFIG_KARMA_PARTITION is not set +# CONFIG_KERNEL_BZIP2 is not set +# CONFIG_KERNEL_GZIP is not set +# CONFIG_KERNEL_LZ4 is not set +# CONFIG_KERNEL_LZMA is not set +# CONFIG_KERNEL_LZO is not set +CONFIG_KERNEL_MODE_NEON=y +CONFIG_KERNEL_XZ=y +CONFIG_KERNFS=y +# CONFIG_KEXEC is not set +# CONFIG_KEYBOARD_ADP5588 is not set +# CONFIG_KEYBOARD_ADP5589 is not set +# CONFIG_KEYBOARD_ATKBD is not set +# CONFIG_KEYBOARD_CAP1106 is not set +# CONFIG_KEYBOARD_GPIO_POLLED is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_LM8323 is not set +# CONFIG_KEYBOARD_LM8333 is not set +# CONFIG_KEYBOARD_MATRIX is not set +# CONFIG_KEYBOARD_MAX7359 is not set +# CONFIG_KEYBOARD_MCS is not set +# CONFIG_KEYBOARD_MPR121 is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_OMAP4 is not set +# CONFIG_KEYBOARD_OPENCORES is not set +# CONFIG_KEYBOARD_PXA27x is not set +# CONFIG_KEYBOARD_QT1070 is not set +# CONFIG_KEYBOARD_QT2160 is not set +# CONFIG_KEYBOARD_SAMSUNG is not set +# CONFIG_KEYBOARD_SH_KEYSC is not set +# CONFIG_KEYBOARD_STOWAWAY is not set +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_TCA6416 is not set +# CONFIG_KEYBOARD_TCA8418 is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYS is not set +# CONFIG_KEYS_DEBUG_PROC_KEYS is not set +# CONFIG_KGDB is not set +# CONFIG_KMEMCHECK is not set +# CONFIG_KPROBES is not set +# CONFIG_KPROBES_SANITY_TEST is not set +# CONFIG_KS8842 is not set +# CONFIG_KS8851 is not set +# CONFIG_KS8851_MLL is not set +# CONFIG_KSM is not set +# CONFIG_KSZ884X_PCI is not set +CONFIG_KUSER_HELPERS=y +# CONFIG_KVM_GUEST is not set +# CONFIG_KXCJK1013 is not set +# CONFIG_KXSD9 is not set +# CONFIG_L2TP is not set +# CONFIG_L2TP_ETH is not set +# CONFIG_L2TP_IP is not set +# CONFIG_L2TP_V3 is not set +# CONFIG_LANMEDIA is not set +# CONFIG_LANTIQ is not set +# CONFIG_LAPB is not set +# CONFIG_LASAT is not set +# CONFIG_LATENCYTOP is not set +# CONFIG_LATTICE_ECP3_CONFIG is not set +CONFIG_LBDAF=y +# CONFIG_LCD_HX8357 is not set +# CONFIG_LCD_ILI922X is not set +# CONFIG_LCD_ILI9320 is not set +# CONFIG_LCD_LMS501KF03 is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_LEDS_ATMEL_PWM is not set +# CONFIG_LEDS_BD2802 is not set +# CONFIG_LEDS_BLINKM is not set +CONFIG_LEDS_CLASS=y +# CONFIG_LEDS_DAC124S085 is not set +# CONFIG_LEDS_GPIO is not set +CONFIG_LEDS_GPIO_OF=y +CONFIG_LEDS_GPIO_PLATFORM=y +# CONFIG_LEDS_INTEL_SS4200 is not set +# CONFIG_LEDS_LM3530 is not set +# CONFIG_LEDS_LM3556 is not set +# CONFIG_LEDS_LM355x is not set +# CONFIG_LEDS_LM3642 is not set +# CONFIG_LEDS_LP3944 is not set +# CONFIG_LEDS_LP5521 is not set +# CONFIG_LEDS_LP5523 is not set +# CONFIG_LEDS_LP5562 is not set +# CONFIG_LEDS_LP8501 is not set +# CONFIG_LEDS_LT3593 is not set +# CONFIG_LEDS_NET5501 is not set +# CONFIG_LEDS_OT200 is not set +# CONFIG_LEDS_PCA9532 is not set +# CONFIG_LEDS_PCA955X is not set +# CONFIG_LEDS_PCA9633 is not set +# CONFIG_LEDS_PCA963X is not set +# CONFIG_LEDS_PCA9685 is not set +# CONFIG_LEDS_PWM is not set +# CONFIG_LEDS_RENESAS_TPU is not set +# CONFIG_LEDS_SYSCON is not set +# CONFIG_LEDS_TCA6507 is not set +CONFIG_LEDS_TRIGGERS=y +# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set +# CONFIG_LEDS_TRIGGER_CAMERA is not set +# CONFIG_LEDS_TRIGGER_CPU is not set +CONFIG_LEDS_TRIGGER_DEFAULT_ON=y +# CONFIG_LEDS_TRIGGER_GPIO is not set +# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set +# CONFIG_LEDS_TRIGGER_IDE_DISK is not set +# CONFIG_LEDS_TRIGGER_MORSE is not set +CONFIG_LEDS_TRIGGER_NETDEV=y +# CONFIG_LEDS_TRIGGER_ONESHOT is not set +CONFIG_LEDS_TRIGGER_TIMER=y +# CONFIG_LEDS_TRIGGER_TRANSIENT is not set +# CONFIG_LEDS_TRIGGER_USBDEV is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_LIB80211 is not set +# CONFIG_LIB80211_CRYPT_CCMP is not set +# CONFIG_LIB80211_CRYPT_TKIP is not set +# CONFIG_LIB80211_CRYPT_WEP is not set +# CONFIG_LIB80211_DEBUG is not set +# CONFIG_LIBCRC32C is not set +# CONFIG_LIBERTAS is not set +# CONFIG_LIBERTAS_THINFIRM is not set +# CONFIG_LIBERTAS_USB is not set +# CONFIG_LIBFC is not set +# CONFIG_LIBFCOE is not set +# CONFIG_LIBIPW_DEBUG is not set +# CONFIG_LINE6_USB is not set +# CONFIG_LIRC_STAGING is not set +# CONFIG_LIS3L02DQ is not set +# CONFIG_LKDTM is not set +CONFIG_LLC=y +# CONFIG_LLC2 is not set +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +# CONFIG_LOCKD is not set +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_LOCKD_V4=y +# CONFIG_LOCKUP_DETECTOR is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_LOCK_TORTURE_TEST is not set +# CONFIG_LOGFS is not set +# CONFIG_LOGIG940_FF is not set +# CONFIG_LOGIRUMBLEPAD2_FF is not set +# CONFIG_LOGITECH_FF is not set +# CONFIG_LOGIWHEELS_FF is not set +# CONFIG_LOGO is not set +CONFIG_LOG_BUF_SHIFT=17 +CONFIG_LOG_CPU_MAX_BUF_SHIFT=12 +# CONFIG_LOONGSON_MC146818 is not set +# CONFIG_LP486E is not set +# CONFIG_LPC_ICH is not set +# CONFIG_LPC_SCH is not set +# CONFIG_LP_CONSOLE is not set +# CONFIG_LSI_ET1011C_PHY is not set +# CONFIG_LTE_GDM724X is not set +# CONFIG_LTR501 is not set +# CONFIG_LTPC is not set +# CONFIG_LUSTRE_FS is not set +# CONFIG_LXT_PHY is not set +CONFIG_LZMA_COMPRESS=y +CONFIG_LZMA_DECOMPRESS=y +# CONFIG_LZO_COMPRESS is not set +# CONFIG_LZO_DECOMPRESS is not set +# CONFIG_LZ4_COMPRESS is not set +# CONFIG_LZ4_DECOMPRESS is not set +# CONFIG_LZ4HC_COMPRESS is not set +# CONFIG_M25PXX_PREFER_SMALL_SECTOR_ERASE is not set +# CONFIG_MAC80211 is not set +# CONFIG_MAC80211_MESSAGE_TRACING is not set +# CONFIG_MACB is not set +# CONFIG_MACH_DECSTATION is not set +# CONFIG_MACH_JAZZ is not set +# CONFIG_MACH_JZ4740 is not set +# CONFIG_MACH_LOONGSON is not set +# CONFIG_MACH_LOONGSON1 is not set +# CONFIG_MACH_NO_WESTBRIDGE is not set +# CONFIG_MACH_TX39XX is not set +# CONFIG_MACH_TX49XX is not set +# CONFIG_MACH_VR41XX is not set +# CONFIG_MACINTOSH_DRIVERS is not set +# CONFIG_MACVLAN is not set +# CONFIG_MACVTAP is not set +# CONFIG_MAC_EMUMOUSEBTN is not set +# CONFIG_MAC_PARTITION is not set +# CONFIG_MAG3110 is not set +# CONFIG_MAGIC_SYSRQ is not set +CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1 +# CONFIG_MAILBOX is not set +# CONFIG_MANGLE_BOOTARGS is not set +# CONFIG_MARVELL_PHY is not set +# CONFIG_MAX1027 is not set +# CONFIG_MAX1363 is not set +# CONFIG_MAX517 is not set +# CONFIG_MAX5821 is not set +# CONFIG_MAX63XX_WATCHDOG is not set +# CONFIG_MCB is not set +# CONFIG_MCP320X is not set +# CONFIG_MCP3422 is not set +# CONFIG_MCP4725 is not set +# CONFIG_MCP4922 is not set +# CONFIG_MCPM is not set +# CONFIG_MD is not set +# CONFIG_MDIO_BCM_UNIMAC is not set +# CONFIG_MDIO_BITBANG is not set +# CONFIG_MDIO_BUS_MUX_GPIO is not set +# CONFIG_MDIO_BUS_MUX_MMIOREG is not set +# CONFIG_MD_FAULTY is not set +# CONFIG_MEDIA_ANALOG_TV_SUPPORT is not set +# CONFIG_MEDIA_ATTACH is not set +# CONFIG_MEDIA_CAMERA_SUPPORT is not set +# CONFIG_MEDIA_CONTROLLER is not set +# CONFIG_MEDIA_DIGITAL_TV_SUPPORT is not set +# CONFIG_MEDIA_PARPORT_SUPPORT is not set +# CONFIG_MEDIA_PCI_SUPPORT is not set +# CONFIG_MEDIA_RADIO_SUPPORT is not set +# CONFIG_MEDIA_RC_SUPPORT is not set +# CONFIG_MEDIA_SDR_SUPPORT is not set +# CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set +# CONFIG_MEDIA_SUPPORT is not set +# CONFIG_MEDIA_TUNER_CUSTOMISE is not set +# CONFIG_MEDIA_USB_SUPPORT is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_SAS is not set +# CONFIG_MEMORY is not set +# CONFIG_MEMORY_FAILURE is not set +# CONFIG_MEMSTICK is not set +# CONFIG_MEN_A21_WDT is not set +CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4 +# CONFIG_MFD_88PM800 is not set +# CONFIG_MFD_88PM805 is not set +# CONFIG_MFD_88PM860X is not set +# CONFIG_MFD_AAT2870_CORE is not set +# CONFIG_MFD_ARIZONA_I2C is not set +# CONFIG_MFD_ARIZONA_SPI is not set +# CONFIG_MFD_AS3711 is not set +# CONFIG_MFD_AS3722 is not set +# CONFIG_MFD_ASIC3 is not set +# CONFIG_MFD_AXP20X is not set +# CONFIG_MFD_BCM590XX is not set +# CONFIG_MFD_CORE is not set +# CONFIG_MFD_CROS_EC is not set +# CONFIG_MFD_CS5535 is not set +# CONFIG_MFD_DA9052_I2C is not set +# CONFIG_MFD_DA9052_SPI is not set +# CONFIG_MFD_DA9055 is not set +# CONFIG_MFD_DA9063 is not set +# CONFIG_MFD_HI6421_PMIC is not set +# CONFIG_MFD_JANZ_CMODIO is not set +# CONFIG_MFD_KEMPLD is not set +# CONFIG_MFD_LM3533 is not set +# CONFIG_MFD_LP3943 is not set +# CONFIG_MFD_LP8788 is not set +# CONFIG_MFD_MAX14577 is not set +# CONFIG_MFD_MAX77686 is not set +# CONFIG_MFD_MAX77693 is not set +# CONFIG_MFD_MAX8907 is not set +# CONFIG_MFD_MAX8925 is not set +# CONFIG_MFD_MAX8997 is not set +# CONFIG_MFD_MAX8998 is not set +# CONFIG_MFD_MC13783 is not set +# CONFIG_MFD_MC13XXX is not set +# CONFIG_MFD_MC13XXX_I2C is not set +# CONFIG_MFD_MC13XXX_SPI is not set +# CONFIG_MFD_MENF21BMC is not set +# CONFIG_MFD_OMAP_USB_HOST is not set +# CONFIG_MFD_PALMAS is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_MFD_PM8921_CORE is not set +# CONFIG_MFD_RC5T583 is not set +# CONFIG_MFD_RDC321X is not set +# CONFIG_MFD_RETU is not set +# CONFIG_MFD_RK808 is not set +# CONFIG_MFD_RN5T618 is not set +# CONFIG_MFD_RTSX_PCI is not set +# CONFIG_MFD_RTSX_USB is not set +# CONFIG_MFD_S5M_CORE is not set +# CONFIG_MFD_SEC_CORE is not set +# CONFIG_MFD_SI476X_CORE is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_SMSC is not set +# CONFIG_MFD_STMPE is not set +CONFIG_MFD_SUPPORT=y +# CONFIG_MFD_SYSCON is not set +# CONFIG_MFD_T7L66XB is not set +# CONFIG_MFD_TC3589X is not set +# CONFIG_MFD_TC6387XB is not set +# CONFIG_MFD_TC6393XB is not set +# CONFIG_MFD_TIMBERDALE is not set +# CONFIG_MFD_TI_AM335X_TSCADC is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_MFD_TPS65090 is not set +# CONFIG_MFD_TPS65217 is not set +# CONFIG_MFD_TPS65218 is not set +# CONFIG_MFD_TPS6586X is not set +# CONFIG_MFD_TPS65910 is not set +# CONFIG_MFD_TPS65912 is not set +# CONFIG_MFD_TPS65912_I2C is not set +# CONFIG_MFD_TPS65912_SPI is not set +# CONFIG_MFD_TPS80031 is not set +# CONFIG_MFD_VIPERBOARD is not set +# CONFIG_MFD_VX855 is not set +# CONFIG_MFD_WL1273_CORE is not set +# CONFIG_MFD_WM831X is not set +# CONFIG_MFD_WM831X_I2C is not set +# CONFIG_MFD_WM831X_SPI is not set +# CONFIG_MFD_WM8350_I2C is not set +# CONFIG_MFD_WM8400 is not set +# CONFIG_MFD_WM8994 is not set +# CONFIG_MG_DISK is not set +# CONFIG_MICREL_KS8995MA is not set +# CONFIG_MICREL_PHY is not set +# CONFIG_MIGRATION is not set +CONFIG_MII=y +# CONFIG_MIKROTIK_RB532 is not set +# CONFIG_MINIX_FS is not set +# CONFIG_MINIX_FS_NATIVE_ENDIAN is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_MIPS_ALCHEMY is not set +# CONFIG_MIPS_COBALT is not set +# CONFIG_MIPS_FPU_EMULATOR is not set +# CONFIG_MIPS_MALTA is not set +# CONFIG_MIPS_O32_FP64_SUPPORT is not set +# CONFIG_MIPS_PARAVIRT is not set +# CONFIG_MIPS_SEAD3 is not set +# CONFIG_MIPS_SIM is not set +CONFIG_MISC_DEVICES=y +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_MISDN is not set +# CONFIG_MISDN_AVMFRITZ is not set +# CONFIG_MISDN_HFCPCI is not set +# CONFIG_MISDN_HFCUSB is not set +# CONFIG_MISDN_INFINEON is not set +# CONFIG_MISDN_NETJET is not set +# CONFIG_MISDN_SPEEDFAX is not set +# CONFIG_MISDN_W6692 is not set +# CONFIG_MKISS is not set +# CONFIG_MLX4_CORE is not set +# CONFIG_MLX4_EN is not set +# CONFIG_MLX5_CORE is not set +# CONFIG_MLX90614 is not set +# CONFIG_MMA8452 is not set +# CONFIG_MMC is not set +# CONFIG_MMC_ARMMMCI is not set +# CONFIG_MMC_AU1X is not set +# CONFIG_MMC_BLOCK is not set +CONFIG_MMC_BLOCK_BOUNCE=y +CONFIG_MMC_BLOCK_MINORS=8 +# CONFIG_MMC_CB710 is not set +# CONFIG_MMC_CLKGATE is not set +# CONFIG_MMC_DEBUG is not set +# CONFIG_MMC_DW is not set +# CONFIG_MMC_MVSDIO is not set +# CONFIG_MMC_S3C is not set +# CONFIG_MMC_SDHCI is not set +# CONFIG_MMC_SDHCI_ACPI is not set +# CONFIG_MMC_SDHCI_BCM_KONA is not set +# CONFIG_MMC_SDHCI_MSM is not set +# CONFIG_MMC_SDHCI_OF_ARASAN is not set +# CONFIG_MMC_SDHCI_OF_ESDHC is not set +# CONFIG_MMC_SDHCI_OF_HLWD is not set +# CONFIG_MMC_SDHCI_PXAV2 is not set +# CONFIG_MMC_SDHCI_PXAV3 is not set +# CONFIG_MMC_SDRICOH_CS is not set +# CONFIG_MMC_SPI is not set +# CONFIG_MMC_TEST is not set +# CONFIG_MMC_UNSAFE_RESUME is not set +# CONFIG_MMC_USDHI6ROL0 is not set +# CONFIG_MMC_USHC is not set +# CONFIG_MMC_VIA_SDMMC is not set +# CONFIG_MMC_VUB300 is not set +# CONFIG_MMIOTRACE is not set +CONFIG_MMU=y +CONFIG_MODULES=y +# CONFIG_MODULE_COMPRESS is not set +# CONFIG_MODULE_FORCE_LOAD is not set +# CONFIG_MODULE_FORCE_UNLOAD is not set +# CONFIG_MODULE_SIG is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_MODULE_STRIPPED=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MOUSE_APPLETOUCH is not set +# CONFIG_MOUSE_GPIO is not set +# CONFIG_MOUSE_INPORT is not set +# CONFIG_MOUSE_LOGIBM is not set +# CONFIG_MOUSE_PC110PAD is not set +# CONFIG_MOUSE_PS2_SENTELIC is not set +# CONFIG_MOUSE_SYNAPTICS_I2C is not set +# CONFIG_MOUSE_SYNAPTICS_USB is not set +# CONFIG_MPL115 is not set +# CONFIG_MPL3115 is not set +# CONFIG_MSDOS_FS is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_MSI_BITMAP_SELFTEST is not set +# CONFIG_MSI_LAPTOP is not set +CONFIG_MTD=y +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_AFS_PARTS is not set +# CONFIG_MTD_ALAUDA is not set +# CONFIG_MTD_AR7_PARTS is not set +# CONFIG_MTD_ARM_INTEGRATOR is not set +CONFIG_MTD_BLKDEVS=y +CONFIG_MTD_BLOCK=y +# CONFIG_MTD_BLOCK2MTD is not set +CONFIG_MTD_CFI=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_CFI_AMDSTD=y +# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set +CONFIG_MTD_CFI_NOSWAP=y +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +CONFIG_MTD_CHAR=y +# CONFIG_MTD_CMDLINE_PARTS is not set +CONFIG_MTD_COMPLEX_MAPPINGS=y +# CONFIG_MTD_DATAFLASH is not set +# CONFIG_MTD_DEBUG is not set +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set +# CONFIG_MTD_DOCG3 is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_GPIO_ADDR is not set +# CONFIG_MTD_INTEL_VR_NOR is not set +# CONFIG_MTD_JEDECPROBE is not set +# CONFIG_MTD_LATCH_ADDR is not set +# CONFIG_MTD_LPDDR is not set +# CONFIG_MTD_LPDDR2_NVM is not set +# CONFIG_MTD_M25P80 is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +CONFIG_MTD_MAP_BANK_WIDTH_2=y +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_MYLOADER_PARTS is not set +# CONFIG_MTD_NAND is not set +# CONFIG_MTD_NAND_AMS_DELTA is not set +# CONFIG_MTD_NAND_AR934X is not set +# CONFIG_MTD_NAND_AR934X_HW_ECC is not set +# CONFIG_MTD_NAND_ATMEL is not set +# CONFIG_MTD_NAND_AU1550 is not set +# CONFIG_MTD_NAND_AUTCPU12 is not set +# CONFIG_MTD_NAND_BCH is not set +# CONFIG_MTD_NAND_BCM_UMI is not set +# CONFIG_MTD_NAND_BF5XX is not set +# CONFIG_MTD_NAND_CAFE is not set +# CONFIG_MTD_NAND_CM_X270 is not set +# CONFIG_MTD_NAND_CS553X is not set +# CONFIG_MTD_NAND_DAVINCI is not set +# CONFIG_MTD_NAND_DENALI is not set +CONFIG_MTD_NAND_DENALI_SCRATCH_REG_ADDR=0xff108018 +# CONFIG_MTD_NAND_DISKONCHIP is not set +# CONFIG_MTD_NAND_DOCG4 is not set +# CONFIG_MTD_NAND_ECC is not set +# CONFIG_MTD_NAND_ECC_BCH is not set +# CONFIG_MTD_NAND_ECC_SMC is not set +# CONFIG_MTD_NAND_FSL_ELBC is not set +# CONFIG_MTD_NAND_FSL_IFC is not set +# CONFIG_MTD_NAND_FSL_UPM is not set +# CONFIG_MTD_NAND_FSMC is not set +# CONFIG_MTD_NAND_GPIO is not set +# CONFIG_MTD_NAND_GPMI_NAND is not set +# CONFIG_MTD_NAND_H1900 is not set +CONFIG_MTD_NAND_IDS=y +# CONFIG_MTD_NAND_JZ4740 is not set +# CONFIG_MTD_NAND_MPC5121_NFC is not set +# CONFIG_MTD_NAND_MUSEUM_IDS is not set +# CONFIG_MTD_NAND_MXC is not set +# CONFIG_MTD_NAND_NANDSIM is not set +# CONFIG_MTD_NAND_NDFC is not set +# CONFIG_MTD_NAND_NOMADIK is not set +# CONFIG_MTD_NAND_NUC900 is not set +# CONFIG_MTD_NAND_OMAP2 is not set +# CONFIG_MTD_NAND_OMAP_BCH_BUILD is not set +# CONFIG_MTD_NAND_ORION is not set +# CONFIG_MTD_NAND_PASEMI is not set +# CONFIG_MTD_NAND_PLATFORM is not set +# CONFIG_MTD_NAND_PPCHAMELEONEVB is not set +# CONFIG_MTD_NAND_PXA3xx is not set +# CONFIG_MTD_NAND_RB4XX is not set +# CONFIG_MTD_NAND_RB750 is not set +# CONFIG_MTD_NAND_RICOH is not set +# CONFIG_MTD_NAND_RTC_FROM4 is not set +# CONFIG_MTD_NAND_S3C2410 is not set +# CONFIG_MTD_NAND_SHARPSL is not set +# CONFIG_MTD_NAND_SH_FLCTL is not set +# CONFIG_MTD_NAND_SOCRATES is not set +# CONFIG_MTD_NAND_SPIA is not set +# CONFIG_MTD_NAND_TMIO is not set +# CONFIG_MTD_NAND_TXX9NDFMC is not set +# CONFIG_MTD_NAND_VERIFY_WRITE is not set +CONFIG_MTD_OF_PARTS=y +# CONFIG_MTD_ONENAND is not set +# CONFIG_MTD_OOPS is not set +# CONFIG_MTD_OTP is not set +# CONFIG_MTD_PCI is not set +# CONFIG_MTD_PCMCIA is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_PHYSMAP_COMPAT is not set +CONFIG_MTD_PHYSMAP_OF=y +# CONFIG_MTD_PLATRAM is not set +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_RAM is not set +CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1 +# CONFIG_MTD_REDBOOT_PARTS is not set +# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set +# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set +# CONFIG_MTD_ROM is not set +CONFIG_MTD_ROOTFS_ROOT_DEV=y +CONFIG_MTD_ROOTFS_SPLIT=y +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_SM_COMMON is not set +# CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is not set +# CONFIG_MTD_SPI_NOR is not set +# CONFIG_MTD_SPINAND_MT29F is not set +CONFIG_MTD_SPLIT=y +# CONFIG_MTD_SPLIT_FIRMWARE is not set +CONFIG_MTD_SPLIT_FIRMWARE_NAME="firmware" +# CONFIG_MTD_SPLIT_FIT_FW is not set +# CONFIG_MTD_SPLIT_LZMA_FW is not set +# CONFIG_MTD_SPLIT_SEAMA_FW is not set +CONFIG_MTD_SPLIT_SQUASHFS_ROOT=y +CONFIG_MTD_SPLIT_SUPPORT=y +# CONFIG_MTD_SPLIT_TRX_FW is not set +# CONFIG_MTD_SPLIT_TPLINK_FW is not set +# CONFIG_MTD_SPLIT_UIMAGE_FW is not set +# CONFIG_MTD_SST25L is not set +# CONFIG_MTD_SWAP is not set +# CONFIG_MTD_TESTS is not set +# CONFIG_MTD_UBI is not set +# CONFIG_MTD_UIMAGE_SPLIT is not set +# CONFIG_MUTEX_SPIN_ON_OWNER is not set +# CONFIG_MV643XX_ETH is not set +# CONFIG_MVMDIO is not set +# CONFIG_MVSW61XX_PHY is not set +# CONFIG_MVSW6171_PHY is not set +# CONFIG_MVSWITCH_PHY is not set +# CONFIG_MWAVE is not set +# CONFIG_MWIFIEX is not set +# CONFIG_MWL8K is not set +# CONFIG_MYRI10GE is not set +# CONFIG_NAMESPACES is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_NATSEMI is not set +# CONFIG_NAU7802 is not set +# CONFIG_NBPFAXI_DMA is not set +# CONFIG_NCP_FS is not set +# CONFIG_NE2000 is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_NEC_MARKEINS is not set +CONFIG_NET=y +# CONFIG_NETCONSOLE is not set +CONFIG_NETDEVICES=y +CONFIG_NETDEV_1000=y +# CONFIG_NETDEV_10000 is not set +# CONFIG_NETFILTER is not set +# CONFIG_NETFILTER_ADVANCED is not set +# CONFIG_NETFILTER_DEBUG is not set +# CONFIG_NETFILTER_NETLINK is not set +# CONFIG_NETFILTER_NETLINK_ACCT is not set +# CONFIG_NETFILTER_NETLINK_LOG is not set +# CONFIG_NETFILTER_NETLINK_QUEUE is not set +# CONFIG_NETFILTER_NETLINK_QUEUE_CT is not set +# CONFIG_NETFILTER_TPROXY is not set +# CONFIG_NETFILTER_XTABLES is not set +# CONFIG_NETFILTER_XT_CONNMARK is not set +# CONFIG_NETFILTER_XT_MARK is not set +# CONFIG_NETFILTER_XT_MATCH_ADDRTYPE is not set +# CONFIG_NETFILTER_XT_MATCH_BPF is not set +# CONFIG_NETFILTER_XT_MATCH_CGROUP is not set +# CONFIG_NETFILTER_XT_MATCH_CLUSTER is not set +# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set +# CONFIG_NETFILTER_XT_MATCH_CONNBYTES is not set +# CONFIG_NETFILTER_XT_MATCH_CONNLABEL is not set +# CONFIG_NETFILTER_XT_MATCH_CONNLIMIT is not set +# CONFIG_NETFILTER_XT_MATCH_CONNMARK is not set +# CONFIG_NETFILTER_XT_MATCH_CONNTRACK is not set +# CONFIG_NETFILTER_XT_MATCH_CPU is not set +# CONFIG_NETFILTER_XT_MATCH_DCCP is not set +# CONFIG_NETFILTER_XT_MATCH_DEVGROUP is not set +# CONFIG_NETFILTER_XT_MATCH_DSCP is not set +# CONFIG_NETFILTER_XT_MATCH_ECN is not set +# CONFIG_NETFILTER_XT_MATCH_ESP is not set +# CONFIG_NETFILTER_XT_MATCH_HASHLIMIT is not set +# CONFIG_NETFILTER_XT_MATCH_HELPER is not set +# CONFIG_NETFILTER_XT_MATCH_HL is not set +# CONFIG_NETFILTER_XT_MATCH_IPCOMP is not set +# CONFIG_NETFILTER_XT_MATCH_IPRANGE is not set +# CONFIG_NETFILTER_XT_MATCH_L2TP is not set +# CONFIG_NETFILTER_XT_MATCH_LAYER7 is not set +# CONFIG_NETFILTER_XT_MATCH_LAYER7_DEBUG is not set +# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set +# CONFIG_NETFILTER_XT_MATCH_LIMIT is not set +# CONFIG_NETFILTER_XT_MATCH_MAC is not set +# CONFIG_NETFILTER_XT_MATCH_MARK is not set +# CONFIG_NETFILTER_XT_MATCH_MULTIPORT is not set +# CONFIG_NETFILTER_XT_MATCH_NFACCT is not set +# CONFIG_NETFILTER_XT_MATCH_OSF is not set +# CONFIG_NETFILTER_XT_MATCH_OWNER is not set +# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set +# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set +# CONFIG_NETFILTER_XT_MATCH_POLICY is not set +# CONFIG_NETFILTER_XT_MATCH_QUOTA is not set +# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set +# CONFIG_NETFILTER_XT_MATCH_REALM is not set +# CONFIG_NETFILTER_XT_MATCH_RECENT is not set +# CONFIG_NETFILTER_XT_MATCH_SCTP is not set +# CONFIG_NETFILTER_XT_MATCH_SOCKET is not set +# CONFIG_NETFILTER_XT_MATCH_STATE is not set +# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set +# CONFIG_NETFILTER_XT_MATCH_STRING is not set +# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set +# CONFIG_NETFILTER_XT_MATCH_TIME is not set +# CONFIG_NETFILTER_XT_MATCH_U32 is not set +# CONFIG_NETFILTER_XT_TARGET_AUDIT is not set +# CONFIG_NETFILTER_XT_TARGET_CHECKSUM is not set +# CONFIG_NETFILTER_XT_TARGET_CLASSIFY is not set +# CONFIG_NETFILTER_XT_TARGET_CONNMARK is not set +# CONFIG_NETFILTER_XT_TARGET_CT is not set +# CONFIG_NETFILTER_XT_TARGET_DSCP is not set +# CONFIG_NETFILTER_XT_TARGET_HL is not set +# CONFIG_NETFILTER_XT_TARGET_HMARK is not set +# CONFIG_NETFILTER_XT_TARGET_IDLETIMER is not set +# CONFIG_NETFILTER_XT_TARGET_LED is not set +# CONFIG_NETFILTER_XT_TARGET_LOG is not set +# CONFIG_NETFILTER_XT_TARGET_MARK is not set +# CONFIG_NETFILTER_XT_TARGET_NETMAP is not set +# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set +# CONFIG_NETFILTER_XT_TARGET_NFQUEUE is not set +# CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set +# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set +# CONFIG_NETFILTER_XT_TARGET_REDIRECT is not set +# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set +# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set +# CONFIG_NETFILTER_XT_TARGET_TEE is not set +# CONFIG_NETFILTER_XT_TARGET_TPROXY is not set +# CONFIG_NETFILTER_XT_TARGET_TRACE is not set +# CONFIG_NETLINK_DIAG is not set +# CONFIG_NETLINK_MMAP is not set +# CONFIG_NETPOLL is not set +# CONFIG_NETROM is not set +CONFIG_NETWORK_FILESYSTEMS=y +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETXEN_NIC is not set +# CONFIG_NET_9P is not set +# CONFIG_NET_ACT_CSUM is not set +# CONFIG_NET_ACT_GACT is not set +# CONFIG_NET_ACT_IPT is not set +# CONFIG_NET_ACT_MIRRED is not set +# CONFIG_NET_ACT_NAT is not set +# CONFIG_NET_ACT_PEDIT is not set +# CONFIG_NET_ACT_POLICE is not set +# CONFIG_NET_ACT_SIMP is not set +# CONFIG_NET_ACT_SKBEDIT is not set +CONFIG_NET_CADENCE=y +# CONFIG_NET_CALXEDA_XGMAC is not set +CONFIG_NET_CLS=y +# CONFIG_NET_CLS_ACT is not set +# CONFIG_NET_CLS_BASIC is not set +# CONFIG_NET_CLS_BPF is not set +# CONFIG_NET_CLS_FLOW is not set +# CONFIG_NET_CLS_FW is not set +CONFIG_NET_CLS_IND=y +# CONFIG_NET_CLS_ROUTE4 is not set +# CONFIG_NET_CLS_RSVP is not set +# CONFIG_NET_CLS_RSVP6 is not set +# CONFIG_NET_CLS_TCINDEX is not set +# CONFIG_NET_CLS_U32 is not set +CONFIG_NET_CORE=y +# CONFIG_NET_DROP_MONITOR is not set +# CONFIG_NET_DSA is not set +# CONFIG_NET_DSA_BCM_SF2 is not set +# CONFIG_NET_DSA_MV88E6060 is not set +# CONFIG_NET_DSA_MV88E6123_61_65 is not set +# CONFIG_NET_DSA_MV88E6131 is not set +# CONFIG_NET_DSA_MV88E6171 is not set +# CONFIG_NET_DSA_MV88E6XXX is not set +# CONFIG_NET_DSA_MV88E6XXX_NEED_PPU is not set +# CONFIG_NET_DSA_TAG_DSA is not set +# CONFIG_NET_DSA_TAG_EDSA is not set +# CONFIG_NET_EMATCH is not set +# CONFIG_NET_EMATCH_CMP is not set +# CONFIG_NET_EMATCH_META is not set +# CONFIG_NET_EMATCH_NBYTE is not set +CONFIG_NET_EMATCH_STACK=32 +# CONFIG_NET_EMATCH_TEXT is not set +# CONFIG_NET_EMATCH_U32 is not set +CONFIG_NET_ETHERNET=y +# CONFIG_NET_FC is not set +# CONFIG_NET_FOU is not set +# CONFIG_NET_IPGRE is not set +CONFIG_NET_IPGRE_BROADCAST=y +# CONFIG_NET_IPGRE_DEMUX is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPVTI is not set +# CONFIG_NET_IP_TUNNEL is not set +# CONFIG_NET_ISA is not set +# CONFIG_NET_KEY is not set +# CONFIG_NET_KEY_MIGRATE is not set +# CONFIG_NET_MPLS_GSO is not set +# CONFIG_NET_PACKET_ENGINE is not set +CONFIG_NET_PCI=y +# CONFIG_NET_PCMCIA is not set +# CONFIG_NET_PKTGEN is not set +# CONFIG_NET_POCKET is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_NET_PTP_CLASSIFY is not set +CONFIG_NET_RX_BUSY_POLL=y +# CONFIG_NET_SB1000 is not set +CONFIG_NET_SCHED=y +# CONFIG_NET_SCH_ATM is not set +# CONFIG_NET_SCH_CBQ is not set +# CONFIG_NET_SCH_CHOKE is not set +# CONFIG_NET_SCH_CODEL is not set +# CONFIG_NET_SCH_DRR is not set +# CONFIG_NET_SCH_DSMARK is not set +# CONFIG_NET_SCH_ESFQ is not set +CONFIG_NET_SCH_ESFQ_NFCT=y +CONFIG_NET_SCH_FIFO=y +# CONFIG_NET_SCH_FQ is not set +CONFIG_NET_SCH_FQ_CODEL=y +# CONFIG_NET_SCH_GRED is not set +# CONFIG_NET_SCH_HFSC is not set +# CONFIG_NET_SCH_HHF is not set +# CONFIG_NET_SCH_HTB is not set +# CONFIG_NET_SCH_INGRESS is not set +# CONFIG_NET_SCH_MQPRIO is not set +# CONFIG_NET_SCH_MULTIQ is not set +# CONFIG_NET_SCH_NETEM is not set +# CONFIG_NET_SCH_PIE is not set +# CONFIG_NET_SCH_PLUG is not set +# CONFIG_NET_SCH_PRIO is not set +# CONFIG_NET_SCH_QFQ is not set +# CONFIG_NET_SCH_RED is not set +# CONFIG_NET_SCH_SFB is not set +# CONFIG_NET_SCH_SFQ is not set +# CONFIG_NET_SCH_TBF is not set +# CONFIG_NET_SCH_TEQL is not set +# CONFIG_NET_SCTPPROBE is not set +# CONFIG_NET_TCPPROBE is not set +# CONFIG_NET_TEAM is not set +# CONFIG_NET_TULIP is not set +# CONFIG_NET_UDP_TUNNEL is not set +CONFIG_NET_VENDOR_3COM=y +CONFIG_NET_VENDOR_8390=y +CONFIG_NET_VENDOR_ADAPTEC=y +CONFIG_NET_VENDOR_AGERE=y +CONFIG_NET_VENDOR_ALTEON=y +CONFIG_NET_VENDOR_AMD=y +CONFIG_NET_VENDOR_ARC=y +CONFIG_NET_VENDOR_ATHEROS=y +CONFIG_NET_VENDOR_BROADCOM=y +CONFIG_NET_VENDOR_BROCADE=y +CONFIG_NET_VENDOR_CHELSIO=y +CONFIG_NET_VENDOR_CIRRUS=y +CONFIG_NET_VENDOR_CISCO=y +CONFIG_NET_VENDOR_DEC=y +CONFIG_NET_VENDOR_DLINK=y +CONFIG_NET_VENDOR_EMULEX=y +CONFIG_NET_VENDOR_EXAR=y +CONFIG_NET_VENDOR_FARADAY=y +CONFIG_NET_VENDOR_FREESCALE=y +CONFIG_NET_VENDOR_FUJITSU=y +CONFIG_NET_VENDOR_HISILICON=y +CONFIG_NET_VENDOR_HP=y +CONFIG_NET_VENDOR_I825XX=y +CONFIG_NET_VENDOR_IBM=y +CONFIG_NET_VENDOR_INTEL=y +CONFIG_NET_VENDOR_MARVELL=y +CONFIG_NET_VENDOR_MELLANOX=y +CONFIG_NET_VENDOR_MICREL=y +CONFIG_NET_VENDOR_MICROCHIP=y +CONFIG_NET_VENDOR_MYRI=y +CONFIG_NET_VENDOR_NATSEMI=y +CONFIG_NET_VENDOR_NVIDIA=y +CONFIG_NET_VENDOR_OKI=y +CONFIG_NET_VENDOR_QLOGIC=y +CONFIG_NET_VENDOR_QUALCOMM=y +CONFIG_NET_VENDOR_RDC=y +CONFIG_NET_VENDOR_REALTEK=y +CONFIG_NET_VENDOR_SAMSUNG=y +CONFIG_NET_VENDOR_SEEQ=y +CONFIG_NET_VENDOR_SILAN=y +CONFIG_NET_VENDOR_SILICOM=y +CONFIG_NET_VENDOR_SIS=y +CONFIG_NET_VENDOR_SMSC=y +CONFIG_NET_VENDOR_STMICRO=y +CONFIG_NET_VENDOR_SUN=y +CONFIG_NET_VENDOR_TEHUTI=y +CONFIG_NET_VENDOR_TI=y +CONFIG_NET_VENDOR_TOSHIBA=y +CONFIG_NET_VENDOR_VIA=y +# CONFIG_NET_VENDOR_WIZNET is not set +CONFIG_NET_VENDOR_XILINX=y +CONFIG_NET_VENDOR_XIRCOM=y +# CONFIG_NET_XGENE is not set +CONFIG_NEW_LEDS=y +# CONFIG_NFC is not set +# CONFIG_NFC_DEVICES is not set +# CONFIG_NFSD is not set +# CONFIG_NFSD_DEPRECATED is not set +# CONFIG_NFSD_V2_ACL is not set +CONFIG_NFSD_V3=y +# CONFIG_NFSD_V3_ACL is not set +# CONFIG_NFSD_V4 is not set +# CONFIG_NFS_ACL_SUPPORT is not set +CONFIG_NFS_COMMON=y +# CONFIG_NFS_FS is not set +# CONFIG_NFS_FSCACHE is not set +# CONFIG_NFS_SWAP is not set +# CONFIG_NFS_V2 is not set +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_V4_1 is not set +# CONFIG_NFTL is not set +# CONFIG_NF_CONNTRACK is not set +# CONFIG_NF_CONNTRACK_AMANDA is not set +# CONFIG_NF_CONNTRACK_EVENTS is not set +# CONFIG_NF_CONNTRACK_FTP is not set +# CONFIG_NF_CONNTRACK_H323 is not set +# CONFIG_NF_CONNTRACK_IPV4 is not set +# CONFIG_NF_CONNTRACK_IPV6 is not set +# CONFIG_NF_CONNTRACK_IRC is not set +# CONFIG_NF_CONNTRACK_MARK is not set +# CONFIG_NF_CONNTRACK_NETBIOS_NS is not set +# CONFIG_NF_CONNTRACK_PPTP is not set +CONFIG_NF_CONNTRACK_PROCFS=y +# CONFIG_NF_CONNTRACK_PROC_COMPAT is not set +# CONFIG_NF_CONNTRACK_RTSP is not set +# CONFIG_NF_CONNTRACK_SANE is not set +# CONFIG_NF_CONNTRACK_SIP is not set +# CONFIG_NF_CONNTRACK_SNMP is not set +# CONFIG_NF_CONNTRACK_TFTP is not set +# CONFIG_NF_CONNTRACK_TIMEOUT is not set +# CONFIG_NF_CONNTRACK_TIMESTAMP is not set +# CONFIG_NF_CONNTRACK_ZONES is not set +# CONFIG_NF_CT_NETLINK is not set +# CONFIG_NF_CT_NETLINK_TIMEOUT is not set +# CONFIG_NF_CT_PROTO_DCCP is not set +# CONFIG_NF_CT_PROTO_GRE is not set +# CONFIG_NF_CT_PROTO_SCTP is not set +# CONFIG_NF_CT_PROTO_UDPLITE is not set +# CONFIG_NF_DEFRAG_IPV4 is not set +# CONFIG_NF_LOG_ARP is not set +# CONFIG_NF_LOG_IPV4 is not set +# CONFIG_NF_NAT is not set +# CONFIG_NF_NAT_AMANDA is not set +# CONFIG_NF_NAT_FTP is not set +# CONFIG_NF_NAT_H323 is not set +# CONFIG_NF_NAT_IPV6 is not set +# CONFIG_NF_NAT_IRC is not set +# CONFIG_NF_NAT_MASQUERADE_IPV4 is not set +# CONFIG_NF_NAT_MASQUERADE_IPV6 is not set +# CONFIG_NF_NAT_NEEDED is not set +# CONFIG_NF_NAT_PPTP is not set +# CONFIG_NF_NAT_PROTO_GRE is not set +# CONFIG_NF_NAT_RTSP is not set +# CONFIG_NF_NAT_SIP is not set +# CONFIG_NF_NAT_SNMP_BASIC is not set +# CONFIG_NF_NAT_TFTP is not set +# CONFIG_NF_REJECT_IPV4 is not set +# CONFIG_NF_TABLES is not set +# CONFIG_NI52 is not set +# CONFIG_NI65 is not set +# CONFIG_NILFS2_FS is not set +# CONFIG_NIU is not set +# CONFIG_NL80211_TESTMODE is not set +CONFIG_NLATTR=y +# CONFIG_NLMON is not set +# CONFIG_NLM_XLP_BOARD is not set +# CONFIG_NLM_XLR_BOARD is not set +# CONFIG_NLS is not set +# CONFIG_NLS_ASCII is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +CONFIG_NLS_DEFAULT="iso8859-1" +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_MAC_CELTIC is not set +# CONFIG_NLS_MAC_CENTEURO is not set +# CONFIG_NLS_MAC_CROATIAN is not set +# CONFIG_NLS_MAC_CYRILLIC is not set +# CONFIG_NLS_MAC_GAELIC is not set +# CONFIG_NLS_MAC_GREEK is not set +# CONFIG_NLS_MAC_ICELAND is not set +# CONFIG_NLS_MAC_INUIT is not set +# CONFIG_NLS_MAC_ROMAN is not set +# CONFIG_NLS_MAC_ROMANIAN is not set +# CONFIG_NLS_MAC_TURKISH is not set +# CONFIG_NLS_UTF8 is not set +# CONFIG_NOP_USB_XCEIV is not set +# CONFIG_NORTEL_HERMES is not set +# CONFIG_NOTIFIER_ERROR_INJECTION is not set +# CONFIG_NOZOMI is not set +# CONFIG_NO_BOOTMEM is not set +# CONFIG_NO_HZ is not set +# CONFIG_NO_HZ_FULL is not set +# CONFIG_NO_HZ_IDLE is not set +# CONFIG_NO_IOPORT is not set +# CONFIG_NS83820 is not set +# CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_NTP_PPS is not set +# CONFIG_NVRAM is not set +# CONFIG_NV_TCO is not set +# CONFIG_NXP_STB220 is not set +# CONFIG_NXP_STB225 is not set +# CONFIG_N_GSM is not set +# CONFIG_OABI_COMPAT is not set +# CONFIG_OBS600 is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_OCF_BENCH is not set +# CONFIG_OCF_C7108 is not set +# CONFIG_OCF_CRYPTOCTEON is not set +# CONFIG_OCF_EP80579 is not set +# CONFIG_OCF_HIFN is not set +# CONFIG_OCF_HIFNHIPP is not set +# CONFIG_OCF_IXP4XX is not set +# CONFIG_OCF_KIRKWOOD is not set +# CONFIG_OCF_OCF is not set +# CONFIG_OCF_OCFNULL is not set +# CONFIG_OCF_SAFE is not set +# CONFIG_OCF_TALITOS is not set +# CONFIG_OCF_UBSEC_SSB is not set +# CONFIG_OC_ETM is not set +# CONFIG_OF_SELFTEST is not set +# CONFIG_OMAP2_DSS_DEBUG is not set +# CONFIG_OMAP2_DSS_DEBUGFS is not set +# CONFIG_OMAP2_DSS_SDI is not set +# CONFIG_OMAP_CONTROL_USB is not set +# CONFIG_OMAP_OCP2SCP is not set +# CONFIG_OMAP_USB2 is not set +# CONFIG_OMAP_USB3 is not set +# CONFIG_OMFS_FS is not set +# CONFIG_OPENVSWITCH is not set +# CONFIG_OPROFILE_EVENT_MULTIPLEX is not set +# CONFIG_ORION_WATCHDOG is not set +# CONFIG_OSF_PARTITION is not set +CONFIG_OVERLAY_FS=y +# CONFIG_P54_COMMON is not set +CONFIG_PACKET=y +# CONFIG_PACKET_DIAG is not set +# CONFIG_PAGE_POISONING is not set +# CONFIG_PAGE_SIZE_16KB is not set +# CONFIG_PAGE_SIZE_32KB is not set +CONFIG_PAGE_SIZE_4KB=y +# CONFIG_PAGE_SIZE_64KB is not set +# CONFIG_PAGE_SIZE_8KB is not set +# CONFIG_PANEL is not set +# CONFIG_PANIC_ON_OOPS is not set +CONFIG_PANIC_ON_OOPS_VALUE=0 +CONFIG_PANIC_TIMEOUT=0 +# CONFIG_PANTHERLORD_FF is not set +# CONFIG_PARPORT is not set +# CONFIG_PARPORT_1284 is not set +# CONFIG_PARPORT_AX88796 is not set +# CONFIG_PARPORT_PC is not set +CONFIG_PARTITION_ADVANCED=y +# CONFIG_PATA_ALI is not set +# CONFIG_PATA_AMD is not set +# CONFIG_PATA_ARASAN_CF is not set +# CONFIG_PATA_ARTOP is not set +# CONFIG_PATA_ATIIXP is not set +# CONFIG_PATA_ATP867X is not set +# CONFIG_PATA_CMD640_PCI is not set +# CONFIG_PATA_CMD64X is not set +# CONFIG_PATA_CS5520 is not set +# CONFIG_PATA_CS5530 is not set +# CONFIG_PATA_CS5535 is not set +# CONFIG_PATA_CS5536 is not set +# CONFIG_PATA_CYPRESS is not set +# CONFIG_PATA_EFAR is not set +# CONFIG_PATA_HPT366 is not set +# CONFIG_PATA_HPT37X is not set +# CONFIG_PATA_HPT3X2N is not set +# CONFIG_PATA_HPT3X3 is not set +# CONFIG_PATA_ISAPNP is not set +# CONFIG_PATA_IT8213 is not set +# CONFIG_PATA_IT821X is not set +# CONFIG_PATA_JMICRON is not set +# CONFIG_PATA_LEGACY is not set +# CONFIG_PATA_MARVELL is not set +# CONFIG_PATA_MPIIX is not set +# CONFIG_PATA_NETCELL is not set +# CONFIG_PATA_NINJA32 is not set +# CONFIG_PATA_NS87410 is not set +# CONFIG_PATA_NS87415 is not set +# CONFIG_PATA_OCTEON_CF is not set +# CONFIG_PATA_OF_PLATFORM is not set +# CONFIG_PATA_OLDPIIX is not set +# CONFIG_PATA_OPTI is not set +# CONFIG_PATA_OPTIDMA is not set +# CONFIG_PATA_PCMCIA is not set +# CONFIG_PATA_PDC2027X is not set +# CONFIG_PATA_PDC_OLD is not set +# CONFIG_PATA_PLATFORM is not set +# CONFIG_PATA_QDI is not set +# CONFIG_PATA_RADISYS is not set +# CONFIG_PATA_RDC is not set +# CONFIG_PATA_RZ1000 is not set +# CONFIG_PATA_SC1200 is not set +# CONFIG_PATA_SCH is not set +# CONFIG_PATA_SERVERWORKS is not set +# CONFIG_PATA_SIL680 is not set +# CONFIG_PATA_SIS is not set +# CONFIG_PATA_TOSHIBA is not set +# CONFIG_PATA_TRIFLEX is not set +# CONFIG_PATA_VIA is not set +# CONFIG_PATA_WINBOND is not set +# CONFIG_PATA_WINBOND_VLB is not set +# CONFIG_PC300TOO is not set +# CONFIG_PCCARD is not set +# CONFIG_PCH_GBE is not set +# CONFIG_PCH_PHUB is not set +# CONFIG_PCI200SYN is not set +# CONFIG_PCIEAER_INJECT is not set +# CONFIG_PCIEASPM is not set +# CONFIG_PCIEPORTBUS is not set +# CONFIG_PCIE_ECRC is not set +# CONFIG_PCIPCWATCHDOG is not set +# CONFIG_PCI_ATMEL is not set +# CONFIG_PCI_CNB20LE_QUIRK is not set +# CONFIG_PCI_DEBUG is not set +# CONFIG_PCI_DISABLE_COMMON_QUIRKS is not set +# CONFIG_PCI_HERMES is not set +# CONFIG_PCI_HOST_GENERIC is not set +# CONFIG_PCI_IOV is not set +# CONFIG_PCI_MSI is not set +# CONFIG_PCI_PASID is not set +# CONFIG_PCI_PRI is not set +CONFIG_PCI_QUIRKS=y +# CONFIG_PCI_REALLOC_ENABLE_AUTO is not set +# CONFIG_PCI_STUB is not set +CONFIG_PCI_SYSCALL=y +# CONFIG_PCMCIA is not set +# CONFIG_PCMCIA_3C574 is not set +# CONFIG_PCMCIA_3C589 is not set +# CONFIG_PCMCIA_AHA152X is not set +# CONFIG_PCMCIA_ATMEL is not set +# CONFIG_PCMCIA_AXNET is not set +# CONFIG_PCMCIA_DEBUG is not set +# CONFIG_PCMCIA_FDOMAIN is not set +# CONFIG_PCMCIA_FMVJ18X is not set +# CONFIG_PCMCIA_HERMES is not set +# CONFIG_PCMCIA_LOAD_CIS is not set +# CONFIG_PCMCIA_NINJA_SCSI is not set +# CONFIG_PCMCIA_NMCLAN is not set +# CONFIG_PCMCIA_PCNET is not set +# CONFIG_PCMCIA_QLOGIC is not set +# CONFIG_PCMCIA_RAYCS is not set +# CONFIG_PCMCIA_SMC91C92 is not set +# CONFIG_PCMCIA_SPECTRUM is not set +# CONFIG_PCMCIA_SYM53C500 is not set +# CONFIG_PCMCIA_WL3501 is not set +# CONFIG_PCMCIA_XIRC2PS is not set +# CONFIG_PCMCIA_XIRCOM is not set +# CONFIG_PCNET32 is not set +# CONFIG_PCSPKR_PLATFORM is not set +# CONFIG_PD6729 is not set +# CONFIG_PDA_POWER is not set +# CONFIG_PDC_ADMA is not set +# CONFIG_PERCPU_TEST is not set +# CONFIG_PERF_COUNTERS is not set +# CONFIG_PERF_EVENTS is not set +# CONFIG_PERSISTENT_KEYRINGS is not set +# CONFIG_PHANTOM is not set +# CONFIG_PHONE is not set +# CONFIG_PHONET is not set +# CONFIG_PHYLIB is not set +# CONFIG_PHYS_ADDR_T_64BIT is not set +# CONFIG_PHY_EXYNOS_DP_VIDEO is not set +# CONFIG_PHY_EXYNOS_MIPI_VIDEO is not set +# CONFIG_PHY_QCOM_DWC3 is not set +# CONFIG_PHY_SAMSUNG_USB2 is not set +# CONFIG_PID_IN_CONTEXTIDR is not set +# CONFIG_PID_NS is not set +CONFIG_PINCONF=y +# CONFIG_PINCTRL is not set +# CONFIG_PINCTRL_CAPRI is not set +# CONFIG_PINCTRL_EXYNOS is not set +# CONFIG_PINCTRL_EXYNOS5440 is not set +# CONFIG_PINCTRL_MSM8X74 is not set +CONFIG_PINCTRL_SINGLE=y +CONFIG_PINMUX=y +# CONFIG_PLAT_SPEAR is not set +# CONFIG_PLIP is not set +# CONFIG_PLX_HERMES is not set +# CONFIG_PM is not set +# CONFIG_PMBUS is not set +# CONFIG_PMC_MSP is not set +# CONFIG_PMC_YOSEMITE is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_PM_AUTOSLEEP is not set +# CONFIG_PM_DEVFREQ is not set +# CONFIG_PM_RUNTIME is not set +# CONFIG_PM_WAKELOCKS is not set +# CONFIG_PNX8550_JBS is not set +# CONFIG_PNX8550_STB810 is not set +# CONFIG_POHMELFS is not set +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_POWERCAP is not set +# CONFIG_POWERTV is not set +# CONFIG_POWER_AVS is not set +# CONFIG_POWER_RESET is not set +# CONFIG_POWER_RESET_RESTART is not set +# CONFIG_POWER_RESET_VERSATILE is not set +# CONFIG_POWER_SUPPLY is not set +# CONFIG_POWER_SUPPLY_DEBUG is not set +# CONFIG_PPC4xx_GPIO is not set +# CONFIG_PPC_16K_PAGES is not set +# CONFIG_PPC_256K_PAGES is not set +CONFIG_PPC_4K_PAGES=y +# CONFIG_PPC_64K_PAGES is not set +# CONFIG_PPC_DISABLE_WERROR is not set +# CONFIG_PPC_EMULATED_STATS is not set +# CONFIG_PPC_EPAPR_HV_BYTECHAN is not set +# CONFIG_PPP is not set +# CONFIG_PPPOATM is not set +# CONFIG_PPPOE is not set +# CONFIG_PPPOL2TP is not set +# CONFIG_PPP_ASYNC is not set +# CONFIG_PPP_BSDCOMP is not set +# CONFIG_PPP_DEFLATE is not set +CONFIG_PPP_FILTER=y +# CONFIG_PPP_MPPE is not set +CONFIG_PPP_MULTILINK=y +# CONFIG_PPP_SYNC_TTY is not set +# CONFIG_PPS is not set +# CONFIG_PPS_CLIENT_GPIO is not set +# CONFIG_PPS_CLIENT_KTIMER is not set +# CONFIG_PPS_CLIENT_LDISC is not set +# CONFIG_PPS_CLIENT_PARPORT is not set +# CONFIG_PPS_DEBUG is not set +# CONFIG_PPTP is not set +# CONFIG_PREEMPT is not set +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_TRACER is not set +# CONFIG_PREEMPT_VOLUNTARY is not set +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_PRINTK=y +# CONFIG_PRINTK_TIME is not set +CONFIG_PRINT_STACK_DEPTH=64 +# CONFIG_PRISM2_USB is not set +# CONFIG_PRISM54 is not set +# CONFIG_PROBE_INITRD_HEADER is not set +CONFIG_PROC_FS=y +# CONFIG_PROC_KCORE is not set +# CONFIG_PROC_PAGE_MONITOR is not set +CONFIG_PROC_STRIPPED=y +CONFIG_PROC_SYSCTL=y +# CONFIG_PROFILE_ALL_BRANCHES is not set +# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set +# CONFIG_PROFILING is not set +# CONFIG_PROVE_LOCKING is not set +# CONFIG_PROVE_RCU is not set +# CONFIG_PROVE_RCU_DELAY is not set +# CONFIG_PSB6970_PHY is not set +# CONFIG_PSTORE is not set +# CONFIG_PTP_1588_CLOCK is not set +# CONFIG_PTP_1588_CLOCK_IXP46X is not set +# CONFIG_PTP_1588_CLOCK_PCH is not set +# CONFIG_PWM is not set +# CONFIG_PWM_PCA9685 is not set +# CONFIG_QCA7000 is not set +# CONFIG_QLA3XXX is not set +# CONFIG_QLCNIC is not set +# CONFIG_QLGE is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX6FS_FS is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_QUOTA is not set +# CONFIG_QUOTACTL is not set +# CONFIG_QUOTA_DEBUG is not set +# CONFIG_R3964 is not set +# CONFIG_R6040 is not set +# CONFIG_R8169 is not set +# CONFIG_R8187SE is not set +# CONFIG_R8188EU is not set +# CONFIG_R8712U is not set +# CONFIG_R8723AU is not set +# CONFIG_RADIO_ADAPTERS is not set +# CONFIG_RADIO_AZTECH is not set +# CONFIG_RADIO_CADET is not set +# CONFIG_RADIO_GEMTEK is not set +# CONFIG_RADIO_MAXIRADIO is not set +# CONFIG_RADIO_RTRACK is not set +# CONFIG_RADIO_RTRACK2 is not set +# CONFIG_RADIO_SF16FMI is not set +# CONFIG_RADIO_SF16FMR2 is not set +# CONFIG_RADIO_TERRATEC is not set +# CONFIG_RADIO_TRUST is not set +# CONFIG_RADIO_TYPHOON is not set +# CONFIG_RADIO_ZOLTRIX is not set +# CONFIG_RAID_ATTRS is not set +# CONFIG_RALINK is not set +# CONFIG_RAMOOPS is not set +# CONFIG_RANDOM32_SELFTEST is not set +# CONFIG_RAPIDIO is not set +# CONFIG_RAR_REGISTER is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_RBTREE_TEST is not set +# CONFIG_RCU_CPU_STALL_INFO is not set +CONFIG_RCU_CPU_STALL_TIMEOUT=60 +CONFIG_RCU_FANOUT=32 +# CONFIG_RCU_FANOUT_EXACT is not set +CONFIG_RCU_FANOUT_LEAF=16 +# CONFIG_RCU_FAST_NO_HZ is not set +# CONFIG_RCU_NOCB_CPU is not set +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_RCU_TRACE is not set +# CONFIG_RCU_USER_QS is not set +# CONFIG_RC_ATI_REMOTE is not set +# CONFIG_RC_CORE is not set +# CONFIG_RC_DECODERS is not set +# CONFIG_RC_LOOPBACK is not set +# CONFIG_RC_MAP is not set +# CONFIG_RDS is not set +# CONFIG_RD_BZIP2 is not set +# CONFIG_RD_GZIP is not set +# CONFIG_RD_LZ4 is not set +# CONFIG_RD_LZMA is not set +# CONFIG_RD_LZO is not set +# CONFIG_RD_XZ is not set +# CONFIG_READABLE_ASM is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_REDWOOD is not set +# CONFIG_REGMAP is not set +# CONFIG_REGMAP_I2C is not set +# CONFIG_REGMAP_MMIO is not set +# CONFIG_REGMAP_SPI is not set +# CONFIG_REGULATOR is not set +# CONFIG_REGULATOR_ACT8865 is not set +# CONFIG_REGULATOR_AD5398 is not set +# CONFIG_REGULATOR_ANATOP is not set +# CONFIG_REGULATOR_BQ24022 is not set +# CONFIG_REGULATOR_DA9210 is not set +# CONFIG_REGULATOR_DA9211 is not set +# CONFIG_REGULATOR_FAN53555 is not set +# CONFIG_REGULATOR_FIXED_VOLTAGE is not set +# CONFIG_REGULATOR_GPIO is not set +# CONFIG_REGULATOR_ISL6271A is not set +# CONFIG_REGULATOR_ISL9305 is not set +# CONFIG_REGULATOR_LP3971 is not set +# CONFIG_REGULATOR_LP3972 is not set +# CONFIG_REGULATOR_LP872X is not set +# CONFIG_REGULATOR_LP8755 is not set +# CONFIG_REGULATOR_LTC3589 is not set +# CONFIG_REGULATOR_MAX1586 is not set +# CONFIG_REGULATOR_MAX8649 is not set +# CONFIG_REGULATOR_MAX8660 is not set +# CONFIG_REGULATOR_MAX8952 is not set +# CONFIG_REGULATOR_MAX8973 is not set +# CONFIG_REGULATOR_PFUZE100 is not set +# CONFIG_REGULATOR_TI_ABB is not set +# CONFIG_REGULATOR_TPS51632 is not set +# CONFIG_REGULATOR_TPS62360 is not set +# CONFIG_REGULATOR_TPS65023 is not set +# CONFIG_REGULATOR_TPS6507X is not set +# CONFIG_REGULATOR_TPS6524X is not set +# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_FS_POSIX_ACL is not set +# CONFIG_REISERFS_FS_SECURITY is not set +# CONFIG_REISERFS_FS_XATTR is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_RELAY is not set +# CONFIG_RESET_CONTROLLER is not set +# CONFIG_RFD_FTL is not set +# CONFIG_RFKILL is not set +# CONFIG_RFKILL_INPUT is not set +# CONFIG_RFKILL_REGULATOR is not set +# CONFIG_RING_BUFFER_BENCHMARK is not set +# CONFIG_RING_BUFFER_STARTUP_TEST is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_ROSE is not set +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RT2X00 is not set +# CONFIG_RTC_CLASS is not set +# CONFIG_RTC_DEBUG is not set +# CONFIG_RTC_DRV_AU1XXX is not set +# CONFIG_RTC_DRV_BQ32K is not set +# CONFIG_RTC_DRV_BQ4802 is not set +CONFIG_RTC_DRV_CMOS=y +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1305 is not set +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1343 is not set +# CONFIG_RTC_DRV_DS1347 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1390 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_DS2404 is not set +# CONFIG_RTC_DRV_DS3232 is not set +# CONFIG_RTC_DRV_DS3234 is not set +# CONFIG_RTC_DRV_EM3027 is not set +# CONFIG_RTC_DRV_EP93XX is not set +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_GENERIC is not set +# CONFIG_RTC_DRV_HID_SENSOR_TIME is not set +# CONFIG_RTC_DRV_HYM8563 is not set +# CONFIG_RTC_DRV_ISL12022 is not set +# CONFIG_RTC_DRV_ISL12057 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_M41T80 is not set +# CONFIG_RTC_DRV_M41T93 is not set +# CONFIG_RTC_DRV_M41T94 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_MCP795 is not set +# CONFIG_RTC_DRV_MOXART is not set +# CONFIG_RTC_DRV_MPC5121 is not set +# CONFIG_RTC_DRV_MSM6242 is not set +# CONFIG_RTC_DRV_OMAP is not set +# CONFIG_RTC_DRV_PCF2123 is not set +# CONFIG_RTC_DRV_PCF2127 is not set +# CONFIG_RTC_DRV_PCF85063 is not set +# CONFIG_RTC_DRV_PCF8523 is not set +# CONFIG_RTC_DRV_PCF8563 is not set +# CONFIG_RTC_DRV_PCF8583 is not set +# CONFIG_RTC_DRV_PL030 is not set +# CONFIG_RTC_DRV_PL031 is not set +# CONFIG_RTC_DRV_PS3 is not set +# CONFIG_RTC_DRV_PT7C4338 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RP5C01 is not set +# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_RTC7301 is not set +# CONFIG_RTC_DRV_RV3029C2 is not set +# CONFIG_RTC_DRV_RX4581 is not set +# CONFIG_RTC_DRV_RX8025 is not set +# CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_S35390A is not set +# CONFIG_RTC_DRV_SNVS is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_SUN6I is not set +# CONFIG_RTC_DRV_TEST is not set +# CONFIG_RTC_DRV_V3020 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_XGENE is not set +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_LIB=y +CONFIG_RTC_SYSTOHC=y +# CONFIG_RTL8180 is not set +# CONFIG_RTL8187 is not set +# CONFIG_RTL8192E is not set +# CONFIG_RTL8192U is not set +# CONFIG_RTL8306_PHY is not set +# CONFIG_RTL8366RB_PHY is not set +# CONFIG_RTL8366S_PHY is not set +# CONFIG_RTL8366_SMI is not set +# CONFIG_RTL8366_SMI_DEBUG_FS is not set +# CONFIG_RTL8367B_PHY is not set +# CONFIG_RTL8367_PHY is not set +# CONFIG_RTLLIB is not set +# CONFIG_RTL_CARDS is not set +# CONFIG_RTS5139 is not set +# CONFIG_RTS5208 is not set +# CONFIG_RTS_PSTOR is not set +CONFIG_RT_MUTEXES=y +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_RUNTIME_DEBUG is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_S2IO is not set +# CONFIG_SAMPLES is not set +# CONFIG_SAMSUNG_LAPTOP is not set +# CONFIG_SAMSUNG_USB2PHY is not set +# CONFIG_SAMSUNG_USB3PHY is not set +# CONFIG_SATA_ACARD_AHCI is not set +# CONFIG_SATA_AHCI is not set +# CONFIG_SATA_AHCI_PLATFORM is not set +# CONFIG_SATA_DWC is not set +# CONFIG_SATA_FSL is not set +# CONFIG_SATA_HIGHBANK is not set +# CONFIG_SATA_INIC162X is not set +# CONFIG_SATA_MV is not set +# CONFIG_SATA_NV is not set +# CONFIG_SATA_PMP is not set +# CONFIG_SATA_PROMISE is not set +# CONFIG_SATA_QSTOR is not set +# CONFIG_SATA_RCAR is not set +# CONFIG_SATA_SIL is not set +# CONFIG_SATA_SIL24 is not set +# CONFIG_SATA_SIS is not set +# CONFIG_SATA_SVW is not set +# CONFIG_SATA_SX4 is not set +# CONFIG_SATA_ULI is not set +# CONFIG_SATA_VIA is not set +# CONFIG_SATA_VITESSE is not set +# CONFIG_SBC_FITPC2_WATCHDOG is not set +# CONFIG_SBE_2T3E3 is not set +# CONFIG_SBYPASS is not set +# CONFIG_SC92031 is not set +# CONFIG_SCA3000 is not set +# CONFIG_SCC is not set +# CONFIG_SCHEDSTATS is not set +# CONFIG_SCHED_AUTOGROUP is not set +# CONFIG_SCHED_DEBUG is not set +# CONFIG_SCHED_MC is not set +CONFIG_SCHED_OMIT_FRAME_POINTER=y +# CONFIG_SCHED_SMT is not set +# CONFIG_SCHED_STACK_END_CHECK is not set +# CONFIG_SCHED_TRACER is not set +# CONFIG_SCSI is not set +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_3W_SAS is not set +# CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AHA1542 is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_AIC94XX is not set +# CONFIG_SCSI_ARCMSR is not set +# CONFIG_SCSI_BFA_FC is not set +# CONFIG_SCSI_BNX2X_FCOE is not set +# CONFIG_SCSI_BNX2_ISCSI is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_CHELSIO_FCOE is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_CXGB3_ISCSI is not set +# CONFIG_SCSI_CXGB4_ISCSI is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_DH is not set +CONFIG_SCSI_DMA=y +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_ESAS2R is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set +# CONFIG_SCSI_HPSA is not set +# CONFIG_SCSI_HPTIOP is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_ISCI is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_LOGGING is not set +CONFIG_SCSI_LOWLEVEL=y +# CONFIG_SCSI_LOWLEVEL_PCMCIA is not set +# CONFIG_SCSI_LPFC is not set +CONFIG_SCSI_MOD=y +# CONFIG_SCSI_MPT2SAS is not set +# CONFIG_SCSI_MPT3SAS is not set +# CONFIG_SCSI_MQ_DEFAULT is not set +CONFIG_SCSI_MULTI_LUN=y +# CONFIG_SCSI_MVSAS is not set +# CONFIG_SCSI_MVSAS_DEBUG is not set +# CONFIG_SCSI_MVUMI is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_NETLINK is not set +# CONFIG_SCSI_NSP32 is not set +# CONFIG_SCSI_OSD_INITIATOR is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PM8001 is not set +# CONFIG_SCSI_PMCRAID is not set +CONFIG_SCSI_PROC_FS=y +# CONFIG_SCSI_QLA_FC is not set +# CONFIG_SCSI_QLA_ISCSI is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SCAN_ASYNC is not set +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_SRP is not set +# CONFIG_SCSI_SRP_ATTRS is not set +# CONFIG_SCSI_STEX is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_TGT is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_UFSHCD is not set +# CONFIG_SCSI_ULTRASTOR is not set +# CONFIG_SCSI_VIRTIO is not set +# CONFIG_SCx200_ACB is not set +# CONFIG_SDIO_UART is not set +# CONFIG_SECCOMP is not set +# CONFIG_SECURITY is not set +# CONFIG_SECURITYFS is not set +# CONFIG_SECURITY_DMESG_RESTRICT is not set +# CONFIG_SEEQ8005 is not set +CONFIG_SELECT_MEMORY_MODEL=y +# CONFIG_SENSORS_ABITUGURU is not set +# CONFIG_SENSORS_ABITUGURU3 is not set +# CONFIG_SENSORS_ACPI_POWER is not set +# CONFIG_SENSORS_AD7314 is not set +# CONFIG_SENSORS_AD7414 is not set +# CONFIG_SENSORS_AD7418 is not set +# CONFIG_SENSORS_ADC128D818 is not set +# CONFIG_SENSORS_ADCXX is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1029 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_ADS1015 is not set +# CONFIG_SENSORS_ADS7828 is not set +# CONFIG_SENSORS_ADS7871 is not set +# CONFIG_SENSORS_ADT7310 is not set +# CONFIG_SENSORS_ADT7410 is not set +# CONFIG_SENSORS_ADT7411 is not set +# CONFIG_SENSORS_ADT7462 is not set +# CONFIG_SENSORS_ADT7470 is not set +# CONFIG_SENSORS_ADT7475 is not set +# CONFIG_SENSORS_AMC6821 is not set +# CONFIG_SENSORS_APDS990X is not set +# CONFIG_SENSORS_APPLESMC is not set +# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_ASC7621 is not set +# CONFIG_SENSORS_ATK0110 is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_BH1770 is not set +# CONFIG_SENSORS_BH1780 is not set +# CONFIG_SENSORS_CORETEMP is not set +# CONFIG_SENSORS_DME1737 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_DS620 is not set +# CONFIG_SENSORS_EMC1403 is not set +# CONFIG_SENSORS_EMC2103 is not set +# CONFIG_SENSORS_EMC6W201 is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_F75375S is not set +# CONFIG_SENSORS_FAM15H_POWER is not set +# CONFIG_SENSORS_FSCHMD is not set +# CONFIG_SENSORS_G760A is not set +# CONFIG_SENSORS_G762 is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_GPIO_FAN is not set +# CONFIG_SENSORS_GSC is not set +# CONFIG_SENSORS_HDAPS is not set +# CONFIG_SENSORS_HIH6130 is not set +# CONFIG_SENSORS_HMC5843 is not set +# CONFIG_SENSORS_HMC5843_I2C is not set +# CONFIG_SENSORS_HMC5843_SPI is not set +# CONFIG_SENSORS_HTU21 is not set +# CONFIG_SENSORS_I5500 is not set +# CONFIG_SENSORS_I5K_AMB is not set +# CONFIG_SENSORS_IIO_HWMON is not set +# CONFIG_SENSORS_INA209 is not set +# CONFIG_SENSORS_INA2XX is not set +# CONFIG_SENSORS_ISL29018 is not set +# CONFIG_SENSORS_ISL29028 is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_JC42 is not set +# CONFIG_SENSORS_K10TEMP is not set +# CONFIG_SENSORS_K8TEMP is not set +# CONFIG_SENSORS_LINEAGE is not set +# CONFIG_SENSORS_LIS3LV02D is not set +# CONFIG_SENSORS_LIS3_I2C is not set +# CONFIG_SENSORS_LIS3_SPI is not set +# CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM70 is not set +# CONFIG_SENSORS_LM73 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_LM93 is not set +# CONFIG_SENSORS_LM95234 is not set +# CONFIG_SENSORS_LM95241 is not set +# CONFIG_SENSORS_LM95245 is not set +# CONFIG_SENSORS_LTC2945 is not set +# CONFIG_SENSORS_LTC4151 is not set +# CONFIG_SENSORS_LTC4215 is not set +# CONFIG_SENSORS_LTC4222 is not set +# CONFIG_SENSORS_LTC4245 is not set +# CONFIG_SENSORS_LTC4260 is not set +# CONFIG_SENSORS_LTC4261 is not set +# CONFIG_SENSORS_MAX1111 is not set +# CONFIG_SENSORS_MAX16065 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_MAX1668 is not set +# CONFIG_SENSORS_MAX197 is not set +# CONFIG_SENSORS_MAX6639 is not set +# CONFIG_SENSORS_MAX6642 is not set +# CONFIG_SENSORS_MAX6650 is not set +# CONFIG_SENSORS_MAX6697 is not set +# CONFIG_SENSORS_MCP3021 is not set +# CONFIG_SENSORS_NCT6683 is not set +# CONFIG_SENSORS_NCT6775 is not set +# CONFIG_SENSORS_NTC_THERMISTOR is not set +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_POWR1220 is not set +# CONFIG_SENSORS_SCH5627 is not set +# CONFIG_SENSORS_SCH5636 is not set +# CONFIG_SENSORS_SCH56XX_COMMON is not set +# CONFIG_SENSORS_SHT15 is not set +# CONFIG_SENSORS_SHT21 is not set +# CONFIG_SENSORS_SHTC1 is not set +# CONFIG_SENSORS_SIS5595 is not set +# CONFIG_SENSORS_SMM665 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_THMC50 is not set +# CONFIG_SENSORS_TMP102 is not set +# CONFIG_SENSORS_TMP103 is not set +# CONFIG_SENSORS_TMP401 is not set +# CONFIG_SENSORS_TMP421 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_SENSORS_TSL2563 is not set +# CONFIG_SENSORS_VEXPRESS is not set +# CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_VIA_CPUTEMP is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_VT8231 is not set +# CONFIG_SENSORS_W83627EHF is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83791D is not set +# CONFIG_SENSORS_W83792D is not set +# CONFIG_SENSORS_W83793 is not set +# CONFIG_SENSORS_W83795 is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83L786NG is not set +CONFIG_SERIAL_8250=y +# CONFIG_SERIAL_8250_ACCENT is not set +# CONFIG_SERIAL_8250_BOCA is not set +CONFIG_SERIAL_8250_CONSOLE=y +# CONFIG_SERIAL_8250_CS is not set +# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +CONFIG_SERIAL_8250_DMA=y +# CONFIG_SERIAL_8250_DW is not set +# CONFIG_SERIAL_8250_EM is not set +# CONFIG_SERIAL_8250_EXAR_ST16C554 is not set +# CONFIG_SERIAL_8250_EXTENDED is not set +# CONFIG_SERIAL_8250_FOURPORT is not set +# CONFIG_SERIAL_8250_FINTEK is not set +# CONFIG_SERIAL_8250_HUB6 is not set +# CONFIG_SERIAL_8250_MANY_PORTS is not set +CONFIG_SERIAL_8250_NR_UARTS=2 +# CONFIG_SERIAL_8250_PCI is not set +# CONFIG_SERIAL_8250_RSA is not set +CONFIG_SERIAL_8250_RUNTIME_UARTS=2 +# CONFIG_SERIAL_8250_SYSRQ is not set +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +# CONFIG_SERIAL_ARC is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_SERIAL_EARLYCON=y +# CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST is not set +# CONFIG_SERIAL_FSL_LPUART is not set +# CONFIG_SERIAL_GRLIB_GAISLER_APBUART is not set +# CONFIG_SERIAL_IFX6X60 is not set +# CONFIG_SERIAL_JSM is not set +# CONFIG_SERIAL_MAX3100 is not set +# CONFIG_SERIAL_MAX3107 is not set +# CONFIG_SERIAL_MAX310X is not set +# CONFIG_SERIAL_MFD_HSU is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_SERIAL_OF_PLATFORM is not set +# CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL is not set +# CONFIG_SERIAL_PCH_UART is not set +# CONFIG_SERIAL_RP2 is not set +# CONFIG_SERIAL_SC16IS7XX is not set +# CONFIG_SERIAL_SCCNXP is not set +# CONFIG_SERIAL_SH_SCI is not set +# CONFIG_SERIAL_ST_ASC is not set +# CONFIG_SERIAL_TIMBERDALE is not set +# CONFIG_SERIAL_UARTLITE is not set +# CONFIG_SERIAL_XILINX_PS_UART is not set +# CONFIG_SERIO is not set +# CONFIG_SERIO_ALTERA_PS2 is not set +# CONFIG_SERIO_AMBAKMI is not set +# CONFIG_SERIO_ARC_PS2 is not set +# CONFIG_SERIO_I8042 is not set +# CONFIG_SERIO_LIBPS2 is not set +# CONFIG_SERIO_PARKBD is not set +# CONFIG_SERIO_PCIPS2 is not set +# CONFIG_SERIO_PS2MULT is not set +# CONFIG_SERIO_RAW is not set +# CONFIG_SERIO_SERPORT is not set +# CONFIG_SFC is not set +# CONFIG_SFI is not set +# CONFIG_SGETMASK_SYSCALL is not set +# CONFIG_SGI_IOC4 is not set +# CONFIG_SGI_IP22 is not set +# CONFIG_SGI_IP27 is not set +# CONFIG_SGI_IP28 is not set +# CONFIG_SGI_IP32 is not set +# CONFIG_SGI_PARTITION is not set +CONFIG_SHMEM=y +# CONFIG_SH_ETH is not set +# CONFIG_SH_TIMER_CMT is not set +# CONFIG_SH_TIMER_MTU2 is not set +# CONFIG_SH_TIMER_TMU is not set +# CONFIG_SI7005 is not set +# CONFIG_SIBYTE_BIGSUR is not set +# CONFIG_SIBYTE_CARMEL is not set +# CONFIG_SIBYTE_CRHINE is not set +# CONFIG_SIBYTE_CRHONE is not set +# CONFIG_SIBYTE_LITTLESUR is not set +# CONFIG_SIBYTE_RHONE is not set +# CONFIG_SIBYTE_SENTOSA is not set +# CONFIG_SIBYTE_SWARM is not set +# CONFIG_SIGMA is not set +CONFIG_SIGNALFD=y +# CONFIG_SIMPLE_GPIO is not set +# CONFIG_SIS190 is not set +# CONFIG_SIS900 is not set +# CONFIG_SKGE is not set +# CONFIG_SKY2 is not set +# CONFIG_SKY2_DEBUG is not set +CONFIG_SLAB=y +CONFIG_SLABINFO=y +# CONFIG_SLHC is not set +# CONFIG_SLICOSS is not set +# CONFIG_SLIP is not set +# CONFIG_SLOB is not set +# CONFIG_SLUB is not set +# CONFIG_SLUB_DEBUG is not set +# CONFIG_SLUB_STATS is not set +# CONFIG_SMARTJOYPLUS_FF is not set +# CONFIG_SMC911X is not set +# CONFIG_SMC9194 is not set +# CONFIG_SMC91X is not set +# CONFIG_SMP is not set +# CONFIG_SMSC911X is not set +# CONFIG_SMSC9420 is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_SM_FTL is not set +# CONFIG_SND is not set +# CONFIG_SND_AC97_POWER_SAVE is not set +# CONFIG_SND_AD1816A is not set +# CONFIG_SND_AD1848 is not set +# CONFIG_SND_AD1889 is not set +# CONFIG_SND_ADLIB is not set +# CONFIG_SND_ALI5451 is not set +# CONFIG_SND_ALOOP is not set +# CONFIG_SND_ALS100 is not set +# CONFIG_SND_ALS300 is not set +# CONFIG_SND_ALS4000 is not set +# CONFIG_SND_ARM is not set +# CONFIG_SND_ASIHPI is not set +# CONFIG_SND_ATIIXP is not set +# CONFIG_SND_ATIIXP_MODEM is not set +# CONFIG_SND_ATMEL_AC97C is not set +# CONFIG_SND_ATMEL_SOC is not set +# CONFIG_SND_AU8810 is not set +# CONFIG_SND_AU8820 is not set +# CONFIG_SND_AU8830 is not set +# CONFIG_SND_AW2 is not set +# CONFIG_SND_AZT2320 is not set +# CONFIG_SND_AZT3328 is not set +# CONFIG_SND_BCD2000 is not set +# CONFIG_SND_BT87X is not set +# CONFIG_SND_CA0106 is not set +# CONFIG_SND_CMI8330 is not set +# CONFIG_SND_CMIPCI is not set +# CONFIG_SND_CS4231 is not set +# CONFIG_SND_CS4236 is not set +# CONFIG_SND_CS4281 is not set +# CONFIG_SND_CS46XX is not set +# CONFIG_SND_CS5530 is not set +# CONFIG_SND_CS5535AUDIO is not set +# CONFIG_SND_CTXFI is not set +# CONFIG_SND_DARLA20 is not set +# CONFIG_SND_DARLA24 is not set +# CONFIG_SND_DEBUG is not set +# CONFIG_SND_DESIGNWARE_I2S is not set +CONFIG_SND_DRIVERS=y +# CONFIG_SND_DUMMY is not set +# CONFIG_SND_DYNAMIC_MINORS is not set +# CONFIG_SND_ECHO3G is not set +# CONFIG_SND_EMU10K1 is not set +# CONFIG_SND_EMU10K1X is not set +# CONFIG_SND_ENS1370 is not set +# CONFIG_SND_ENS1371 is not set +# CONFIG_SND_ES1688 is not set +# CONFIG_SND_ES18XX is not set +# CONFIG_SND_ES1938 is not set +# CONFIG_SND_ES1968 is not set +# CONFIG_SND_FIREWIRE is not set +# CONFIG_SND_FM801 is not set +# CONFIG_SND_GINA20 is not set +# CONFIG_SND_GINA24 is not set +# CONFIG_SND_GUSCLASSIC is not set +# CONFIG_SND_GUSEXTREME is not set +# CONFIG_SND_GUSMAX is not set +# CONFIG_SND_HDA_INTEL is not set +# CONFIG_SND_HDSP is not set +# CONFIG_SND_HDSPM is not set +# CONFIG_SND_HRTIMER is not set +# CONFIG_SND_HWDEP is not set +# CONFIG_SND_ICE1712 is not set +# CONFIG_SND_ICE1724 is not set +# CONFIG_SND_INDIGO is not set +# CONFIG_SND_INDIGODJ is not set +# CONFIG_SND_INDIGODJX is not set +# CONFIG_SND_INDIGOIO is not set +# CONFIG_SND_INDIGOIOX is not set +# CONFIG_SND_INTEL8X0 is not set +# CONFIG_SND_INTEL8X0M is not set +# CONFIG_SND_INTERWAVE is not set +# CONFIG_SND_INTERWAVE_STB is not set +# CONFIG_SND_ISA is not set +# CONFIG_SND_KIRKWOOD_SOC is not set +# CONFIG_SND_KORG1212 is not set +# CONFIG_SND_LAYLA20 is not set +# CONFIG_SND_LAYLA24 is not set +# CONFIG_SND_LOLA is not set +# CONFIG_SND_LX6464ES is not set +# CONFIG_SND_MAESTRO3 is not set +# CONFIG_SND_MIA is not set +# CONFIG_SND_MIPS is not set +# CONFIG_SND_MIRO is not set +# CONFIG_SND_MIXART is not set +# CONFIG_SND_MIXER_OSS is not set +# CONFIG_SND_MONA is not set +# CONFIG_SND_MPC52xx_SOC_EFIKA is not set +# CONFIG_SND_MPU401 is not set +# CONFIG_SND_MTPAV is not set +# CONFIG_SND_MTS64 is not set +# CONFIG_SND_MXS_SOC is not set +# CONFIG_SND_NM256 is not set +# CONFIG_SND_OPL3SA2 is not set +# CONFIG_SND_OPTI92X_AD1848 is not set +# CONFIG_SND_OPTI92X_CS4231 is not set +# CONFIG_SND_OPTI93X is not set +CONFIG_SND_OSSEMUL=y +# CONFIG_SND_OXYGEN is not set +CONFIG_SND_PCI=y +# CONFIG_SND_PCM is not set +# CONFIG_SND_PCMCIA is not set +# CONFIG_SND_PCM_OSS is not set +CONFIG_SND_PCM_OSS_PLUGINS=y +# CONFIG_SND_PCXHR is not set +# CONFIG_SND_PDAUDIOCF is not set +# CONFIG_SND_PORTMAN2X4 is not set +# CONFIG_SND_POWERPC_SOC is not set +# CONFIG_SND_PPC is not set +# CONFIG_SND_RAWMIDI is not set +# CONFIG_SND_RIPTIDE is not set +# CONFIG_SND_RME32 is not set +# CONFIG_SND_RME96 is not set +# CONFIG_SND_RME9652 is not set +# CONFIG_SND_RTCTIMER is not set +# CONFIG_SND_SB16 is not set +# CONFIG_SND_SB8 is not set +# CONFIG_SND_SBAWE is not set +# CONFIG_SND_SEQUENCER is not set +# CONFIG_SND_SERIAL_U16550 is not set +# CONFIG_SND_SIMPLE_CARD is not set +# CONFIG_SND_SIS7019 is not set +# CONFIG_SND_SOC is not set +# CONFIG_SND_SOC_ADAU1701 is not set +# CONFIG_SND_SOC_AK4104 is not set +# CONFIG_SND_SOC_AK4554 is not set +# CONFIG_SND_SOC_AK4642 is not set +# CONFIG_SND_SOC_AK5386 is not set +# CONFIG_SND_SOC_ALC5623 is not set +# CONFIG_SND_SOC_AU1XAUDIO is not set +# CONFIG_SND_SOC_AU1XPSC is not set +# CONFIG_SND_SOC_CACHE_LZO is not set +# CONFIG_SND_SOC_CS35L32 is not set +# CONFIG_SND_SOC_CS4265 is not set +# CONFIG_SND_SOC_CS4270 is not set +# CONFIG_SND_SOC_CS4271 is not set +# CONFIG_SND_SOC_CS42L52 is not set +# CONFIG_SND_SOC_CS42L56 is not set +# CONFIG_SND_SOC_CS42L73 is not set +# CONFIG_SND_SOC_CS42XX8_I2C is not set +# CONFIG_SND_SOC_ES8328 is not set +# CONFIG_SND_SOC_EUKREA_TLV320 is not set +# CONFIG_SND_SOC_FSL_ASOC_CARD is not set +# CONFIG_SND_SOC_FSL_ASRC is not set +# CONFIG_SND_SOC_FSL_ESAI is not set +# CONFIG_SND_SOC_FSL_SAI is not set +# CONFIG_SND_SOC_FSL_SPDIF is not set +# CONFIG_SND_SOC_HDMI_CODEC is not set +# CONFIG_SND_SOC_IMX_ES8328 is not set +# CONFIG_SND_SOC_IMX_SPDIF is not set +# CONFIG_SND_SOC_IMX_WM8962 is not set +# CONFIG_SND_SOC_INTEL_SST is not set +# CONFIG_SND_SOC_MPC5200_AC97 is not set +# CONFIG_SND_SOC_MPC5200_I2S is not set +# CONFIG_SND_SOC_PCM1681 is not set +# CONFIG_SND_SOC_PCM1792A is not set +# CONFIG_SND_SOC_PCM512x_I2C is not set +# CONFIG_SND_SOC_PCM512x_SPI is not set +# CONFIG_SND_SOC_SGTL5000 is not set +# CONFIG_SND_SOC_SIRF_AUDIO_CODEC is not set +# CONFIG_SND_SOC_SPDIF is not set +# CONFIG_SND_SOC_SSM2602_I2C is not set +# CONFIG_SND_SOC_SSM2602_SPI is not set +# CONFIG_SND_SOC_SSM4567 is not set +# CONFIG_SND_SOC_STA350 is not set +# CONFIG_SND_SOC_TAS2552 is not set +# CONFIG_SND_SOC_TAS5086 is not set +# CONFIG_SND_SOC_TLV320AIC31XX is not set +# CONFIG_SND_SOC_TLV320AIC3X is not set +# CONFIG_SND_SOC_TPA6130A2 is not set +# CONFIG_SND_SOC_WM8510 is not set +# CONFIG_SND_SOC_WM8523 is not set +# CONFIG_SND_SOC_WM8580 is not set +# CONFIG_SND_SOC_WM8711 is not set +# CONFIG_SND_SOC_WM8728 is not set +# CONFIG_SND_SOC_WM8731 is not set +# CONFIG_SND_SOC_WM8737 is not set +# CONFIG_SND_SOC_WM8741 is not set +# CONFIG_SND_SOC_WM8750 is not set +# CONFIG_SND_SOC_WM8753 is not set +# CONFIG_SND_SOC_WM8770 is not set +# CONFIG_SND_SOC_WM8776 is not set +# CONFIG_SND_SOC_WM8804 is not set +# CONFIG_SND_SOC_WM8903 is not set +# CONFIG_SND_SOC_WM8962 is not set +# CONFIG_SND_SOC_WM8978 is not set +# CONFIG_SND_SONICVIBES is not set +# CONFIG_SND_SPI is not set +# CONFIG_SND_SSCAPE is not set +# CONFIG_SND_SUPPORT_OLD_API is not set +# CONFIG_SND_TIMER is not set +# CONFIG_SND_TRIDENT is not set +CONFIG_SND_USB=y +# CONFIG_SND_USB_6FIRE is not set +# CONFIG_SND_USB_AUDIO is not set +# CONFIG_SND_USB_CAIAQ is not set +# CONFIG_SND_USB_HIFACE is not set +# CONFIG_SND_USB_UA101 is not set +# CONFIG_SND_USB_US122L is not set +# CONFIG_SND_USB_USX2Y is not set +# CONFIG_SND_VERBOSE_PRINTK is not set +CONFIG_SND_VERBOSE_PROCFS=y +# CONFIG_SND_VIA82XX is not set +# CONFIG_SND_VIA82XX_MODEM is not set +# CONFIG_SND_VIRTUOSO is not set +# CONFIG_SND_VX222 is not set +# CONFIG_SND_VXPOCKET is not set +# CONFIG_SND_WAVEFRONT is not set +# CONFIG_SND_YMFPCI is not set +# CONFIG_SNI_RM is not set +# CONFIG_SOC_AM33XX is not set +# CONFIG_SOC_AM43XX is not set +# CONFIG_SOC_CAMERA is not set +# CONFIG_SOC_DRA7XX is not set +# CONFIG_SOC_HAS_OMAP2_SDRC is not set +# CONFIG_SOC_OMAP5 is not set +# CONFIG_SOC_TI is not set +# CONFIG_SOFT_WATCHDOG is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_SOLO6X10 is not set +# CONFIG_SONYPI is not set +# CONFIG_SONY_LAPTOP is not set +# CONFIG_SOUND is not set +# CONFIG_SOUND_PRIME is not set +# CONFIG_SP5100_TCO is not set +# CONFIG_SPARSEMEM_MANUAL is not set +# CONFIG_SPARSEMEM_STATIC is not set +# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set +# CONFIG_SPARSE_IRQ is not set +# CONFIG_SPARSE_RCU_POINTER is not set +# CONFIG_SPEAKUP is not set +# CONFIG_SPI is not set +# CONFIG_SPINLOCK_TEST is not set +# CONFIG_SPI_ALTERA is not set +# CONFIG_SPI_AU1550 is not set +# CONFIG_SPI_BCM2835 is not set +# CONFIG_SPI_BITBANG is not set +# CONFIG_SPI_BUTTERFLY is not set +# CONFIG_SPI_CADENCE is not set +# CONFIG_SPI_DEBUG is not set +# CONFIG_SPI_DESIGNWARE is not set +# CONFIG_SPI_FSL_DSPI is not set +# CONFIG_SPI_FSL_ESPI is not set +# CONFIG_SPI_FSL_SPI is not set +# CONFIG_SPI_GPIO is not set +# CONFIG_SPI_GPIO_OLD is not set +# CONFIG_SPI_LM70_LLP is not set +# CONFIG_SPI_MASTER is not set +# CONFIG_SPI_MPC52xx is not set +# CONFIG_SPI_MPC52xx_PSC is not set +# CONFIG_SPI_OC_TINY is not set +# CONFIG_SPI_OCTEON is not set +# CONFIG_SPI_ORION is not set +# CONFIG_SPI_PL022 is not set +# CONFIG_SPI_PPC4xx is not set +# CONFIG_SPI_PXA2XX is not set +# CONFIG_SPI_PXA2XX_PCI is not set +# CONFIG_SPI_RAMIPS is not set +# CONFIG_SPI_ROCKCHIP is not set +# CONFIG_SPI_SC18IS602 is not set +# CONFIG_SPI_SPIDEV is not set +# CONFIG_SPI_TI_QSPI is not set +# CONFIG_SPI_TLE62X0 is not set +# CONFIG_SPI_TOPCLIFF_PCH is not set +# CONFIG_SPI_XCOMM is not set +# CONFIG_SPI_XILINX is not set +# CONFIG_SPI_XWAY is not set +# CONFIG_SPMI is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_SQUASHFS=y +# CONFIG_SQUASHFS_4K_DEVBLK_SIZE is not set +# CONFIG_SQUASHFS_DECOMP_MULTI is not set +CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU=y +# CONFIG_SQUASHFS_DECOMP_SINGLE is not set +# CONFIG_SQUASHFS_EMBEDDED is not set +# CONFIG_SQUASHFS_FILE_CACHE is not set +CONFIG_SQUASHFS_FILE_DIRECT=y +CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3 +# CONFIG_SQUASHFS_LZO is not set +# CONFIG_SQUASHFS_XATTR is not set +CONFIG_SQUASHFS_XZ=y +# CONFIG_SQUASHFS_ZLIB is not set +# CONFIG_SRAM is not set +# CONFIG_SSB is not set +# CONFIG_SSBI is not set +# CONFIG_SSB_DEBUG is not set +# CONFIG_SSB_DRIVER_GPIO is not set +# CONFIG_SSB_PCMCIAHOST is not set +CONFIG_SSB_POSSIBLE=y +# CONFIG_SSB_SDIOHOST is not set +# CONFIG_SSB_SILENT is not set +# CONFIG_SSFDC is not set +CONFIG_STACKTRACE_SUPPORT=y +# CONFIG_STACKTRACE is not set +# CONFIG_STACK_TRACER is not set +CONFIG_STAGING=y +# CONFIG_STAGING_MEDIA is not set +CONFIG_STANDALONE=y +CONFIG_STDBINUTILS=y +# CONFIG_STE10XP is not set +# CONFIG_STE_MODEM_RPROC is not set +# CONFIG_STMMAC_ETH is not set +# CONFIG_STMMAC_PLATFORM is not set +# CONFIG_STMMAC_PCI is not set +CONFIG_STP=y +# CONFIG_STRICT_DEVMEM is not set +CONFIG_STRIP_ASM_SYMS=y +# CONFIG_STUB_POULSBO is not set +# CONFIG_SUNDANCE is not set +# CONFIG_SUNGEM is not set +# CONFIG_SUNRPC is not set +# CONFIG_SUNRPC_DEBUG is not set +# CONFIG_SUNRPC_GSS is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_SUSPEND is not set +CONFIG_SWAP=y +# CONFIG_SWCONFIG is not set +# CONFIG_SWCONFIG_LEDS is not set +# CONFIG_SXGBE_ETH is not set +# CONFIG_SYNCLINK_CS is not set +CONFIG_SYN_COOKIES=y +CONFIG_SYSCTL=y +# CONFIG_SYSCTL_SYSCALL is not set +# CONFIG_SYSCTL_SYSCALL_CHECK is not set +CONFIG_SYSFS=y +# CONFIG_SYSFS_DEPRECATED is not set +# CONFIG_SYSFS_DEPRECATED_V2 is not set +# CONFIG_SYSFS_SYSCALL is not set +# CONFIG_SYSTEMPORT is not set +# CONFIG_SYSTEM_TRUSTED_KEYRING is not set +# CONFIG_SYSV68_PARTITION is not set +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +# CONFIG_SYSV_FS is not set +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_T5403 is not set +# CONFIG_TARGET_CORE is not set +# CONFIG_TASKSTATS is not set +# CONFIG_TASKS_RCU is not set +# CONFIG_TC35815 is not set +# CONFIG_TCG_TPM is not set +# CONFIG_TCIC is not set +CONFIG_TCP_CONG_ADVANCED=y +# CONFIG_TCP_CONG_BIC is not set +CONFIG_TCP_CONG_CUBIC=y +# CONFIG_TCP_CONG_DCTCP is not set +# CONFIG_TCP_CONG_HSTCP is not set +# CONFIG_TCP_CONG_HTCP is not set +# CONFIG_TCP_CONG_HYBLA is not set +# CONFIG_TCP_CONG_ILLINOIS is not set +# CONFIG_TCP_CONG_LP is not set +# CONFIG_TCP_CONG_SCALABLE is not set +# CONFIG_TCP_CONG_VEGAS is not set +# CONFIG_TCP_CONG_VENO is not set +# CONFIG_TCP_CONG_WESTWOOD is not set +# CONFIG_TCP_CONG_YEAH is not set +# CONFIG_TCP_MD5SIG is not set +# CONFIG_TCS3414 is not set +# CONFIG_TCS3472 is not set +# CONFIG_TEGRA_HOST1X is not set +# CONFIG_TEHUTI is not set +# CONFIG_TEST_BPF is not set +# CONFIG_TEST_UDELAY is not set +# CONFIG_TEST_FIRMWARE is not set +# CONFIG_TEST_KSTRTOX is not set +# CONFIG_TEST_LIST_SORT is not set +# CONFIG_TEST_LKM is not set +# CONFIG_TEST_MODULE is not set +# CONFIG_TEST_POWER is not set +# CONFIG_TEST_RHASHTABLE is not set +# CONFIG_TEST_STRING_HELPERS is not set +# CONFIG_TEST_USER_COPY is not set +CONFIG_TEXTSEARCH=y +# CONFIG_TEXTSEARCH_BM is not set +# CONFIG_TEXTSEARCH_FSM is not set +# CONFIG_TEXTSEARCH_KMP is not set +# CONFIG_THERMAL is not set +# CONFIG_THERMAL_GOV_BANG_BANG is not set +# CONFIG_THERMAL_HWMON is not set +# CONFIG_THRUSTMASTER_FF is not set +# CONFIG_THUNDERBOLT is not set +# CONFIG_TICK_CPU_ACCOUNTING is not set +CONFIG_TICK_ONESHOT=y +# CONFIG_TIFM_CORE is not set +# CONFIG_TIGON3 is not set +# CONFIG_TIMB_DMA is not set +CONFIG_TIMERFD=y +# CONFIG_TIMER_STATS is not set +CONFIG_TINY_RCU=y +# CONFIG_TIPC is not set +# CONFIG_TI_ADC081C is not set +# CONFIG_TI_ADC128S052 is not set +# CONFIG_TI_AM335X_ADC is not set +# CONFIG_TI_CPSW is not set +# CONFIG_TI_CPTS is not set +# CONFIG_TI_DAC7512 is not set +# CONFIG_TI_DAVINCI_CPDMA is not set +# CONFIG_TI_DAVINCI_MDIO is not set +# CONFIG_TI_ST is not set +# CONFIG_TLAN is not set +# CONFIG_TWL4030_MADC is not set +# CONFIG_TMD_HERMES is not set +# CONFIG_TMP006 is not set +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +CONFIG_TMPFS_XATTR=y +# CONFIG_TORTURE_TEST is not set +# CONFIG_TOSHIBA_HAPS is not set +# CONFIG_TOUCHSCREEN_AD7877 is not set +# CONFIG_TOUCHSCREEN_AD7879 is not set +# CONFIG_TOUCHSCREEN_AD7879_I2C is not set +# CONFIG_TOUCHSCREEN_AD7879_SPI is not set +# CONFIG_TOUCHSCREEN_ADS7846 is not set +# CONFIG_TOUCHSCREEN_AR1021_I2C is not set +# CONFIG_TOUCHSCREEN_ATMEL_MXT is not set +# CONFIG_TOUCHSCREEN_AUO_PIXCIR is not set +# CONFIG_TOUCHSCREEN_BU21013 is not set +# CONFIG_TOUCHSCREEN_CLEARPAD_TM1217 is not set +# CONFIG_TOUCHSCREEN_CY8CTMG110 is not set +# CONFIG_TOUCHSCREEN_CYTTSP_CORE is not set +# CONFIG_TOUCHSCREEN_CYTTSP4_CORE is not set +# CONFIG_TOUCHSCREEN_DYNAPRO is not set +# CONFIG_TOUCHSCREEN_EDT_FT5X06 is not set +# CONFIG_TOUCHSCREEN_EETI is not set +# CONFIG_TOUCHSCREEN_EGALAX is not set +# CONFIG_TOUCHSCREEN_ELO is not set +# CONFIG_TOUCHSCREEN_FUJITSU is not set +# CONFIG_TOUCHSCREEN_GUNZE is not set +# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set +# CONFIG_TOUCHSCREEN_ILI210X is not set +# CONFIG_TOUCHSCREEN_INEXIO is not set +# CONFIG_TOUCHSCREEN_MAX11801 is not set +# CONFIG_TOUCHSCREEN_MCS5000 is not set +# CONFIG_TOUCHSCREEN_MK712 is not set +# CONFIG_TOUCHSCREEN_MMS114 is not set +# CONFIG_TOUCHSCREEN_MTOUCH is not set +# CONFIG_TOUCHSCREEN_PENMOUNT is not set +# CONFIG_TOUCHSCREEN_PIXCIR is not set +# CONFIG_TOUCHSCREEN_S3C2410 is not set +# CONFIG_TOUCHSCREEN_ST1232 is not set +# CONFIG_TOUCHSCREEN_SUR40 is not set +# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4 is not set +# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set +# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set +# CONFIG_TOUCHSCREEN_TOUCHWIN is not set +# CONFIG_TOUCHSCREEN_TPS6507X is not set +# CONFIG_TOUCHSCREEN_TSC2005 is not set +# CONFIG_TOUCHSCREEN_TSC2007 is not set +# CONFIG_TOUCHSCREEN_TSC_SERIO is not set +# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set +# CONFIG_TOUCHSCREEN_W90X900 is not set +# CONFIG_TOUCHSCREEN_WACOM_I2C is not set +# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set +# CONFIG_TOUCHSCREEN_WM97XX is not set +# CONFIG_TOUCHSCREEN_ZFORCE is not set +# CONFIG_TPS6105X is not set +# CONFIG_TPS65010 is not set +# CONFIG_TPS6507X is not set +# CONFIG_TR is not set +# CONFIG_TRACEPOINT_BENCHMARK is not set +# CONFIG_TRACER_SNAPSHOT is not set +# CONFIG_TRACER_SNAPSHOT_PER_CPU_SWAP is not set +# CONFIG_TRACE_BRANCH_PROFILING is not set +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +# CONFIG_TRACE_SINK is not set +CONFIG_TRACING_SUPPORT=y +CONFIG_TRAD_SIGNALS=y +# CONFIG_TRANSPARENT_HUGEPAGE is not set +# CONFIG_TRANZPORT is not set +# CONFIG_TREE_PREEMPT_RCU is not set +# CONFIG_TREE_RCU is not set +# CONFIG_TREE_RCU_TRACE is not set +# CONFIG_TSL2583 is not set +# CONFIG_TSL2x7x is not set +# CONFIG_TSL4531 is not set +CONFIG_TTY=y +# CONFIG_TTY_PRINTK is not set +# CONFIG_TUN is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_TWL6030_GPADC is not set +# CONFIG_TWL6040_CORE is not set +# CONFIG_TYPHOON is not set +# CONFIG_UACCESS_WITH_MEMCPY is not set +# CONFIG_UCB1400_CORE is not set +# CONFIG_UDF_FS is not set +CONFIG_UDF_NLS=y +CONFIG_UEVENT_HELPER=y +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +# CONFIG_UFS_FS is not set +# CONFIG_UHID is not set +CONFIG_UIDGID_STRICT_TYPE_CHECKS=y +# CONFIG_UIO is not set +# CONFIG_ULTRA is not set +# CONFIG_ULTRIX_PARTITION is not set +CONFIG_UNIX=y +CONFIG_UNIX98_PTYS=y +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_UNIX_DIAG is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_UPROBE_EVENT is not set +# CONFIG_UPROBES is not set +# CONFIG_USB is not set +# CONFIG_USBIP_CORE is not set +# CONFIG_USBPCWATCHDOG is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_ADUTUX is not set +CONFIG_USB_ALI_M5632=y +# CONFIG_USB_AMD5536UDC is not set +CONFIG_USB_AN2720=y +# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set +# CONFIG_USB_APPLEDISPLAY is not set +CONFIG_USB_ARCH_HAS_EHCI=y +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +CONFIG_USB_ARMLINUX=y +# CONFIG_USB_ATM is not set +CONFIG_USB_BELKIN=y +# CONFIG_USB_BTMTK is not set +# CONFIG_USB_C67X00_HCD is not set +# CONFIG_USB_CATC is not set +# CONFIG_USB_CDC_COMPOSITE is not set +# CONFIG_USB_CHIPIDEA is not set +# CONFIG_USB_CONFIGFS is not set +# CONFIG_USB_CXACRU is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_DEBUG is not set +CONFIG_USB_DEFAULT_PERSIST=y +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_DEVICE_CLASS is not set +# CONFIG_USB_DSBR is not set +# CONFIG_USB_DUMMY_HCD is not set +# CONFIG_USB_DWC2 is not set +# CONFIG_USB_DWC2_DUAL_ROLE is not set +# CONFIG_USB_DWC2_HOST is not set +# CONFIG_USB_DWC2_PERIPHERAL is not set +# CONFIG_USB_DWC3 is not set +# CONFIG_USB_DWC3_EXYNOS is not set +# CONFIG_USB_DWC3_QCOM is not set +# CONFIG_USB_DWC3_PCI is not set +# CONFIG_USB_DWC3_KEYSTONE is not set +# CONFIG_USB_DWC_OTG_LPM is not set +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_EG20T is not set +# CONFIG_USB_EHCI_HCD_AT91 is not set +# CONFIG_USB_EHCI_HCD_PPC_OF is not set +# CONFIG_USB_EHCI_MSM is not set +# CONFIG_USB_EHCI_MV is not set +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_TT_NEWSCHED=y +# CONFIG_USB_EHSET_TEST_FIXTURE is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_ENESTORAGE is not set +# CONFIG_USB_EPSON2888 is not set +# CONFIG_USB_ET61X251 is not set +CONFIG_USB_EZUSB=y +# CONFIG_USB_EZUSB_FX2 is not set +# CONFIG_USB_FILE_STORAGE is not set +# CONFIG_USB_FOTG210_HCD is not set +# CONFIG_USB_FOTG210_UDC is not set +# CONFIG_USB_FSL_USB2 is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_FUNCTIONFS is not set +# CONFIG_USB_FUSB300 is not set +# CONFIG_USB_FUSBH200_HCD is not set +# CONFIG_USB_GADGET is not set +# CONFIG_USB_GADGETFS is not set +# CONFIG_USB_GADGET_DEBUG is not set +# CONFIG_USB_GADGET_DEBUG_FILES is not set +# CONFIG_USB_GADGET_DEBUG_FS is not set +CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2 +CONFIG_USB_GADGET_VBUS_DRAW=2 +# CONFIG_USB_GADGET_XILINX is not set +# CONFIG_USB_GL860 is not set +# CONFIG_USB_GOKU is not set +# CONFIG_USB_GPIO_VBUS is not set +# CONFIG_USB_GR_UDC is not set +# CONFIG_USB_GSPCA is not set +# CONFIG_USB_GSPCA_BENQ is not set +# CONFIG_USB_GSPCA_CONEX is not set +# CONFIG_USB_GSPCA_CPIA1 is not set +# CONFIG_USB_GSPCA_DTCS033 is not set +# CONFIG_USB_GSPCA_ETOMS is not set +# CONFIG_USB_GSPCA_FINEPIX is not set +# CONFIG_USB_GSPCA_JEILINJ is not set +# CONFIG_USB_GSPCA_JL2005BCD is not set +# CONFIG_USB_GSPCA_KINECT is not set +# CONFIG_USB_GSPCA_KONICA is not set +# CONFIG_USB_GSPCA_MARS is not set +# CONFIG_USB_GSPCA_MR97310A is not set +# CONFIG_USB_GSPCA_NW80X is not set +# CONFIG_USB_GSPCA_OV519 is not set +# CONFIG_USB_GSPCA_OV534 is not set +# CONFIG_USB_GSPCA_OV534_9 is not set +# CONFIG_USB_GSPCA_PAC207 is not set +# CONFIG_USB_GSPCA_PAC7302 is not set +# CONFIG_USB_GSPCA_PAC7311 is not set +# CONFIG_USB_GSPCA_SE401 is not set +# CONFIG_USB_GSPCA_SN9C2028 is not set +# CONFIG_USB_GSPCA_SN9C20X is not set +# CONFIG_USB_GSPCA_SONIXB is not set +# CONFIG_USB_GSPCA_SONIXJ is not set +# CONFIG_USB_GSPCA_SPCA1528 is not set +# CONFIG_USB_GSPCA_SPCA500 is not set +# CONFIG_USB_GSPCA_SPCA501 is not set +# CONFIG_USB_GSPCA_SPCA505 is not set +# CONFIG_USB_GSPCA_SPCA506 is not set +# CONFIG_USB_GSPCA_SPCA508 is not set +# CONFIG_USB_GSPCA_SPCA561 is not set +# CONFIG_USB_GSPCA_SQ905 is not set +# CONFIG_USB_GSPCA_SQ905C is not set +# CONFIG_USB_GSPCA_SQ930X is not set +# CONFIG_USB_GSPCA_STK014 is not set +# CONFIG_USB_GSPCA_STK1135 is not set +# CONFIG_USB_GSPCA_STV0680 is not set +# CONFIG_USB_GSPCA_SUNPLUS is not set +# CONFIG_USB_GSPCA_T613 is not set +# CONFIG_USB_GSPCA_TOPRO is not set +# CONFIG_USB_GSPCA_TV8532 is not set +# CONFIG_USB_GSPCA_VC032X is not set +# CONFIG_USB_GSPCA_VICAM is not set +# CONFIG_USB_GSPCA_XIRLINK_CIT is not set +# CONFIG_USB_GSPCA_ZC3XX is not set +# CONFIG_USB_G_ACM_MS is not set +# CONFIG_USB_G_DBGP is not set +# CONFIG_USB_G_HID is not set +# CONFIG_USB_G_MULTI is not set +# CONFIG_USB_G_NCM is not set +# CONFIG_USB_G_NOKIA is not set +# CONFIG_USB_G_PRINTER is not set +# CONFIG_USB_G_SERIAL is not set +# CONFIG_USB_G_WEBCAM is not set +# CONFIG_USB_HCD_TEST_MODE is not set +# CONFIG_USB_HID is not set +# CONFIG_USB_HIDDEV is not set +# CONFIG_USB_HSIC_USB3503 is not set +# CONFIG_USB_HSO is not set +# CONFIG_USB_HWA_HCD is not set +# CONFIG_USB_IBMCAM is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_INPUT_IMS_PCU is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_IPHETH is not set +# CONFIG_USB_IP_COMMON is not set +# CONFIG_USB_ISIGHTFW is not set +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_ISP1301 is not set +# CONFIG_USB_ISP1362_HCD is not set +# CONFIG_USB_ISP1760_HCD is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_KBD is not set +# CONFIG_USB_KC2190 is not set +# CONFIG_USB_KONICAWC is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_LED_TRIG is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LIBUSUAL is not set +# CONFIG_USB_LINK_LAYER_TEST is not set +# CONFIG_USB_M5602 is not set +# CONFIG_USB_M66592 is not set +# CONFIG_USB_MASS_STORAGE is not set +# CONFIG_USB_MAX3421_HCD is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_MIDI_GADGET is not set +# CONFIG_USB_MON is not set +# CONFIG_USB_MOUSE is not set +# CONFIG_USB_MSM_OTG is not set +# CONFIG_USB_MUSB_HDRC is not set +# CONFIG_USB_MV_U3D is not set +# CONFIG_USB_MV_UDC is not set +# CONFIG_USB_NET2272 is not set +# CONFIG_USB_NET2280 is not set +# CONFIG_USB_NET_AX88179_178A is not set +# CONFIG_USB_NET_AX8817X is not set +# CONFIG_USB_NET_CDCETHER is not set +# CONFIG_USB_NET_CDC_EEM is not set +# CONFIG_USB_NET_CDC_MBIM is not set +# CONFIG_USB_NET_CDC_NCM is not set +# CONFIG_USB_NET_CDC_SUBSET is not set +# CONFIG_USB_NET_CX82310_ETH is not set +# CONFIG_USB_NET_DM9601 is not set +# CONFIG_USB_NET_DRIVERS is not set +# CONFIG_USB_NET_GL620A is not set +# CONFIG_USB_NET_HUAWEI_CDC_NCM is not set +# CONFIG_USB_NET_INT51X1 is not set +# CONFIG_USB_NET_KALMIA is not set +# CONFIG_USB_NET_MCS7830 is not set +# CONFIG_USB_NET_NET1080 is not set +# CONFIG_USB_NET_PLUSB is not set +# CONFIG_USB_NET_QMI_WWAN is not set +# CONFIG_USB_NET_RNDIS_HOST is not set +# CONFIG_USB_NET_RNDIS_WLAN is not set +# CONFIG_USB_NET_SMSC75XX is not set +# CONFIG_USB_NET_SMSC95XX is not set +# CONFIG_USB_NET_SR9700 is not set +# CONFIG_USB_NET_SR9800 is not set +# CONFIG_USB_NET_ZAURUS is not set +# CONFIG_USB_OHCI_HCD is not set +# CONFIG_USB_OHCI_HCD_PCI is not set +# CONFIG_USB_OHCI_HCD_PPC_OF is not set +# CONFIG_USB_OHCI_HCD_PPC_OF_BE is not set +# CONFIG_USB_OHCI_HCD_PPC_OF_LE is not set +# CONFIG_USB_OHCI_HCD_PPC_SOC is not set +# CONFIG_USB_OHCI_HCD_SSB is not set +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +# CONFIG_USB_OTG is not set +# CONFIG_USB_OTG_BLACKLIST_HUB is not set +# CONFIG_USB_OTG_FSM is not set +# CONFIG_USB_OTG_WHITELIST is not set +# CONFIG_USB_OXU210HP_HCD is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_PHY is not set +# CONFIG_USB_PRINTER is not set +# CONFIG_USB_PWC_INPUT_EVDEV is not set +# CONFIG_USB_PXA27X is not set +# CONFIG_USB_R8A66597 is not set +# CONFIG_USB_R8A66597_HCD is not set +# CONFIG_USB_RCAR_PHY is not set +# CONFIG_USB_RENESAS_USBHS is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_RTL8152 is not set +# CONFIG_USB_S2255 is not set +# CONFIG_USB_S3C_HSOTG is not set +# CONFIG_USB_SE401 is not set +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_SERIAL_AIRCABLE is not set +# CONFIG_USB_SERIAL_ARK3116 is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_CH341 is not set +# CONFIG_USB_SERIAL_CP210X is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_CYPRESS_M8 is not set +# CONFIG_USB_SERIAL_DEBUG is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_EDGEPORT_TI is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_F81232 is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_FUNSOFT is not set +# CONFIG_USB_SERIAL_GARMIN is not set +CONFIG_USB_SERIAL_GENERIC=y +# CONFIG_USB_SERIAL_HP4X is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IPW is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_IUU is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +CONFIG_USB_SERIAL_KEYSPAN_MPR=y +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +CONFIG_USB_SERIAL_KEYSPAN_USA18X=y +CONFIG_USB_SERIAL_KEYSPAN_USA19=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y +CONFIG_USB_SERIAL_KEYSPAN_USA19W=y +CONFIG_USB_SERIAL_KEYSPAN_USA28=y +CONFIG_USB_SERIAL_KEYSPAN_USA28X=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y +CONFIG_USB_SERIAL_KEYSPAN_USA49W=y +CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y +# CONFIG_USB_SERIAL_KLSI is not set +# CONFIG_USB_SERIAL_KOBIL_SCT is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_METRO is not set +# CONFIG_USB_SERIAL_MOS7715_PARPORT is not set +# CONFIG_USB_SERIAL_MOS7720 is not set +# CONFIG_USB_SERIAL_MOS7840 is not set +# CONFIG_USB_SERIAL_MOTOROLA is not set +# CONFIG_USB_SERIAL_MXUPORT is not set +# CONFIG_USB_SERIAL_NAVMAN is not set +# CONFIG_USB_SERIAL_OMNINET is not set +# CONFIG_USB_SERIAL_OPTICON is not set +# CONFIG_USB_SERIAL_OPTION is not set +# CONFIG_USB_SERIAL_OTI6858 is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_QCAUX is not set +# CONFIG_USB_SERIAL_QT2 is not set +# CONFIG_USB_SERIAL_QUALCOMM is not set +# CONFIG_USB_SERIAL_QUATECH2 is not set +# CONFIG_USB_SERIAL_QUATECH_USB2 is not set +# CONFIG_USB_SERIAL_SAFE is not set +CONFIG_USB_SERIAL_SAFE_PADDED=y +# CONFIG_USB_SERIAL_SIEMENS_MPI is not set +# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set +# CONFIG_USB_SERIAL_SIMPLE is not set +# CONFIG_USB_SERIAL_SPCP8X5 is not set +# CONFIG_USB_SERIAL_SSU100 is not set +# CONFIG_USB_SERIAL_SYMBOL is not set +# CONFIG_USB_SERIAL_TI is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_VIVOPAY_SERIAL is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_WISHBONE is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_XSENS_MT is not set +# CONFIG_USB_SERIAL_ZIO is not set +# CONFIG_USB_SERIAL_ZTE is not set +# CONFIG_USB_SEVSEG is not set +# CONFIG_USB_SIERRA_NET is not set +# CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_SN9C102 is not set +# CONFIG_USB_SPEEDTOUCH is not set +# CONFIG_USB_STKWEBCAM is not set +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_STORAGE_ALAUDA is not set +# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_ENE_UB6250 is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_KARMA is not set +# CONFIG_USB_STORAGE_ONETOUCH is not set +# CONFIG_USB_STORAGE_REALTEK is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_USBAT is not set +# CONFIG_USB_STV06XX is not set +# CONFIG_USB_SUPPORT is not set +# CONFIG_USB_SUSPEND is not set +# CONFIG_USB_SWITCH_FSA9480 is not set +# CONFIG_USB_TEST is not set +# CONFIG_USB_TMC is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_UAS is not set +# CONFIG_USB_UEAGLEATM is not set +# CONFIG_USB_ULPI is not set +# CONFIG_USB_USBNET is not set +# CONFIG_USB_USS720 is not set +# CONFIG_USB_VIDEO_CLASS is not set +CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y +# CONFIG_USB_VL600 is not set +# CONFIG_USB_WDM is not set +# CONFIG_USB_WHCI_HCD is not set +# CONFIG_USB_WPAN_HCD is not set +# CONFIG_USB_WUSB is not set +# CONFIG_USB_WUSB_CBAF is not set +# CONFIG_USB_XHCI_HCD is not set +# CONFIG_USB_XUSBATM is not set +# CONFIG_USB_YUREX is not set +# CONFIG_USB_ZD1201 is not set +# CONFIG_USB_ZERO is not set +# CONFIG_USB_ZR364XX is not set +# CONFIG_USELIB is not set +# CONFIG_USE_GENERIC_SMP_HELPERS is not set +# CONFIG_USE_OF is not set +# CONFIG_UTS_NS is not set +# CONFIG_UWB is not set +# CONFIG_V4L_MEM2MEM_DRIVERS is not set +# CONFIG_V4L_TEST_DRIVERS is not set +# CONFIG_VCNL4000 is not set +# CONFIG_VETH is not set +# CONFIG_VEXPRESS_CONFIG is not set +# CONFIG_VF610_ADC is not set +# CONFIG_VFAT_FS is not set +# CONFIG_VGASTATE is not set +# CONFIG_VGA_ARB is not set +# CONFIG_VGA_SWITCHEROO is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_VIA_VELOCITY is not set +# CONFIG_VIDEO_ADV7170 is not set +# CONFIG_VIDEO_ADV7175 is not set +# CONFIG_VIDEO_ADV7180 is not set +# CONFIG_VIDEO_ADV7183 is not set +# CONFIG_VIDEO_ADV7343 is not set +# CONFIG_VIDEO_ADV7393 is not set +# CONFIG_VIDEO_ADV_DEBUG is not set +# CONFIG_VIDEO_AK881X is not set +# CONFIG_VIDEO_BT819 is not set +# CONFIG_VIDEO_BT848 is not set +# CONFIG_VIDEO_BT856 is not set +# CONFIG_VIDEO_BT866 is not set +# CONFIG_VIDEO_BWQCAM is not set +# CONFIG_VIDEO_CAFE_CCIC is not set +# CONFIG_VIDEO_CAPTURE_DRIVERS is not set +# CONFIG_VIDEO_CPIA is not set +# CONFIG_VIDEO_CQCAM is not set +# CONFIG_VIDEO_CS5345 is not set +# CONFIG_VIDEO_CS53L32A is not set +# CONFIG_VIDEO_CX231XX is not set +# CONFIG_VIDEO_CX2341X is not set +# CONFIG_VIDEO_CX25840 is not set +# CONFIG_VIDEO_CX88 is not set +# CONFIG_VIDEO_DEV is not set +# CONFIG_VIDEO_DM6446_CCDC is not set +# CONFIG_VIDEO_DT3155 is not set +# CONFIG_VIDEO_EM28XX is not set +# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set +# CONFIG_VIDEO_GO7007 is not set +# CONFIG_VIDEO_HDPVR is not set +# CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set +# CONFIG_VIDEO_HEXIUM_GEMINI is not set +# CONFIG_VIDEO_HEXIUM_ORION is not set +# CONFIG_VIDEO_IR_I2C is not set +# CONFIG_VIDEO_IVTV is not set +# CONFIG_VIDEO_KS0127 is not set +# CONFIG_VIDEO_M52790 is not set +# CONFIG_VIDEO_MEDIA is not set +# CONFIG_VIDEO_MEM2MEM_TESTDEV is not set +# CONFIG_VIDEO_ML86V7667 is not set +# CONFIG_VIDEO_MSP3400 is not set +# CONFIG_VIDEO_MT9V011 is not set +# CONFIG_VIDEO_MXB is not set +# CONFIG_VIDEO_NOON010PC30 is not set +# CONFIG_VIDEO_OMAP2_VOUT is not set +# CONFIG_VIDEO_OUTPUT_CONTROL is not set +# CONFIG_VIDEO_OV7640 is not set +# CONFIG_VIDEO_OV7670 is not set +# CONFIG_VIDEO_PMS is not set +# CONFIG_VIDEO_PVRUSB2 is not set +# CONFIG_VIDEO_SAA6588 is not set +# CONFIG_VIDEO_SAA6752HS is not set +# CONFIG_VIDEO_SAA7110 is not set +# CONFIG_VIDEO_SAA711X is not set +# CONFIG_VIDEO_SAA7127 is not set +# CONFIG_VIDEO_SAA7134 is not set +# CONFIG_VIDEO_SAA717X is not set +# CONFIG_VIDEO_SAA7185 is not set +# CONFIG_VIDEO_SAA7191 is not set +# CONFIG_VIDEO_SH_MOBILE_CEU is not set +# CONFIG_VIDEO_SONY_BTF_MPX is not set +# CONFIG_VIDEO_SR030PC30 is not set +# CONFIG_VIDEO_TCM825X is not set +# CONFIG_VIDEO_TDA7432 is not set +# CONFIG_VIDEO_TDA9840 is not set +# CONFIG_VIDEO_TEA6415C is not set +# CONFIG_VIDEO_TEA6420 is not set +# CONFIG_VIDEO_THS7303 is not set +# CONFIG_VIDEO_THS8200 is not set +# CONFIG_VIDEO_TIMBERDALE is not set +# CONFIG_VIDEO_TLV320AIC23B is not set +# CONFIG_VIDEO_TM6000 is not set +# CONFIG_VIDEO_TVAUDIO is not set +# CONFIG_VIDEO_TVP514X is not set +# CONFIG_VIDEO_TVP5150 is not set +# CONFIG_VIDEO_TVP7002 is not set +# CONFIG_VIDEO_TW2804 is not set +# CONFIG_VIDEO_TW9903 is not set +# CONFIG_VIDEO_TW9906 is not set +# CONFIG_VIDEO_UDA1342 is not set +# CONFIG_VIDEO_UPD64031A is not set +# CONFIG_VIDEO_UPD64083 is not set +# CONFIG_VIDEO_USBTV is not set +# CONFIG_VIDEO_USBVISION is not set +# CONFIG_VIDEO_V4L2 is not set +# CONFIG_VIDEO_V4L2_COMMON is not set +# CONFIG_VIDEO_V4L2_INT_DEVICE is not set +# CONFIG_VIDEO_VIVI is not set +# CONFIG_VIDEO_VP27SMPX is not set +# CONFIG_VIDEO_VPX3220 is not set +# CONFIG_VIDEO_VS6624 is not set +# CONFIG_VIDEO_WM8739 is not set +# CONFIG_VIDEO_WM8775 is not set +# CONFIG_VIDEO_ZORAN is not set +# CONFIG_VIRQ_DEBUG is not set +# CONFIG_VIRTIO_BALLOON is not set +# CONFIG_VIRTIO_MMIO is not set +# CONFIG_VIRTIO_PCI is not set +# CONFIG_VIRTUALIZATION is not set +# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set +# CONFIG_VIRT_DRIVERS is not set +CONFIG_VIRT_TO_BUS=y +# CONFIG_VITESSE_PHY is not set +CONFIG_VLAN_8021Q=y +# CONFIG_VLAN_8021Q_GVRP is not set +# CONFIG_VLAN_8021Q_MVRP is not set +# CONFIG_VME_BUS is not set +# CONFIG_VMSPLIT_1G is not set +# CONFIG_VMSPLIT_2G is not set +# CONFIG_VMSPLIT_2G_OPT is not set +CONFIG_VMSPLIT_3G=y +# CONFIG_VMSPLIT_3G_OPT is not set +# CONFIG_VMWARE_PVSCSI is not set +# CONFIG_VMXNET3 is not set +# CONFIG_VM_EVENT_COUNTERS is not set +# CONFIG_VORTEX is not set +# CONFIG_VSOCKETS is not set +# CONFIG_VT is not set +# CONFIG_VT6655 is not set +# CONFIG_VT6656 is not set +# CONFIG_VXFS_FS is not set +# CONFIG_VXGE is not set +# CONFIG_VXLAN is not set +# CONFIG_W1 is not set +# CONFIG_W1_CON is not set +# CONFIG_W1_MASTER_DS1WM is not set +# CONFIG_W1_MASTER_DS2482 is not set +# CONFIG_W1_MASTER_DS2490 is not set +# CONFIG_W1_MASTER_GPIO is not set +# CONFIG_W1_MASTER_MATROX is not set +# CONFIG_W1_SLAVE_BQ27000 is not set +# CONFIG_W1_SLAVE_DS2406 is not set +# CONFIG_W1_SLAVE_DS2408 is not set +# CONFIG_W1_SLAVE_DS2413 is not set +# CONFIG_W1_SLAVE_DS2423 is not set +# CONFIG_W1_SLAVE_DS2431 is not set +# CONFIG_W1_SLAVE_DS2433 is not set +# CONFIG_W1_SLAVE_DS2760 is not set +# CONFIG_W1_SLAVE_DS2780 is not set +# CONFIG_W1_SLAVE_DS2781 is not set +# CONFIG_W1_SLAVE_DS28E04 is not set +# CONFIG_W1_SLAVE_SMEM is not set +# CONFIG_W1_SLAVE_THERM is not set +# CONFIG_W35UND is not set +# CONFIG_W83627HF_WDT is not set +# CONFIG_W83697HF_WDT is not set +# CONFIG_W83877F_WDT is not set +# CONFIG_W83977F_WDT is not set +# CONFIG_WAN is not set +# CONFIG_WANXL is not set +# CONFIG_WAN_ROUTER is not set +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_CORE is not set +# CONFIG_WATCHDOG_NOWAYOUT is not set +# CONFIG_WD80x3 is not set +# CONFIG_WDTPCI is not set +CONFIG_WEXT_CORE=y +CONFIG_WEXT_PRIV=y +CONFIG_WEXT_PROC=y +CONFIG_WEXT_SPY=y +CONFIG_WILINK_PLATFORM_DATA=y +# CONFIG_WIMAX is not set +# CONFIG_WIMAX_GDM72XX is not set +CONFIG_WIRELESS=y +CONFIG_WIRELESS_EXT=y +# CONFIG_WIRELESS_EXT_SYSFS is not set +# CONFIG_WL1251 is not set +# CONFIG_WL12XX is not set +# CONFIG_WL18XX is not set +# CONFIG_WLAGS49_H2 is not set +# CONFIG_WLAGS49_H25 is not set +CONFIG_WLAN=y +# CONFIG_WLCORE is not set +CONFIG_WL_TI=y +CONFIG_WQ_POWER_EFFICIENT_DEFAULT=y +# CONFIG_WR_PPMC is not set +# CONFIG_X25 is not set +# CONFIG_X86_DEBUG_STATIC_CPU_HAS is not set +# CONFIG_X86_PKG_TEMP_THERMAL is not set +CONFIG_X86_SYSFB=y +# CONFIG_XEN is not set +CONFIG_XFRM=y +# CONFIG_XFRM_IPCOMP is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_USER is not set +# CONFIG_XFS_DEBUG is not set +# CONFIG_XFS_FS is not set +# CONFIG_XFS_POSIX_ACL is not set +# CONFIG_XFS_QUOTA is not set +# CONFIG_XFS_RT is not set +# CONFIG_XFS_WARN is not set +# CONFIG_XILINX_AXI_EMAC is not set +# CONFIG_XILINX_EMACLITE is not set +# CONFIG_XILINX_LL_TEMAC is not set +# CONFIG_XILINX_WATCHDOG is not set +# CONFIG_XILLYBUS is not set +# CONFIG_XIP_KERNEL is not set +# CONFIG_XMON is not set +# CONFIG_XVMALLOC is not set +CONFIG_XZ_DEC=y +# CONFIG_XZ_DEC_ARM is not set +# CONFIG_XZ_DEC_ARMTHUMB is not set +# CONFIG_XZ_DEC_BCJ is not set +# CONFIG_XZ_DEC_IA64 is not set +# CONFIG_XZ_DEC_POWERPC is not set +# CONFIG_XZ_DEC_SPARC is not set +# CONFIG_XZ_DEC_TEST is not set +# CONFIG_XZ_DEC_X86 is not set +# CONFIG_YAFFS_DISABLE_BAD_BLOCK_MARKING is not set +# CONFIG_YAFFS_FS is not set +# CONFIG_YAM is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_YENTA is not set +# CONFIG_YENTA_O2 is not set +# CONFIG_YENTA_RICOH is not set +# CONFIG_YENTA_TI is not set +# CONFIG_YENTA_TOSHIBA is not set +# CONFIG_ZBUD is not set +# CONFIG_ZD1211RW is not set +# CONFIG_ZD1211RW_DEBUG is not set +# CONFIG_ZEROPLUS_FF is not set +# CONFIG_ZISOFS is not set +# CONFIG_ZLIB_DEFLATE is not set +# CONFIG_ZLIB_INFLATE is not set +# CONFIG_ZNET is not set +# CONFIG_ZPOOL is not set +CONFIG_ZONE_DMA=y +CONFIG_ZONE_DMA_FLAG=1 +# CONFIG_ZRAM is not set +# CONFIG_ZRAM_LZ4_COMPRESS is not set +# CONFIG_ZSMALLOC is not set diff --git a/target/linux/generic/config-4.0 b/target/linux/generic/config-4.0 new file mode 100644 index 0000000..0c630ea --- /dev/null +++ b/target/linux/generic/config-4.0 @@ -0,0 +1,4730 @@ +CONFIG_32BIT=y +# CONFIG_6LOWPAN is not set +# CONFIG_6PACK is not set +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_9P_FS is not set +# CONFIG_AB3100_CORE is not set +# CONFIG_AB8500_CORE is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_ACCESSIBILITY is not set +# CONFIG_ACENIC is not set +# CONFIG_ACERHDF is not set +# CONFIG_ACORN_PARTITION is not set +# CONFIG_ACPI_APEI is not set +# CONFIG_ACPI_CUSTOM_METHOD is not set +# CONFIG_ACPI_EXTLOG is not set +# CONFIG_ACPI_HED is not set +# CONFIG_ACPI_INT3403_THERMAL is not set +# CONFIG_ACPI_POWER_METER is not set +# CONFIG_ACPI_QUICKSTART is not set +# CONFIG_ACPI_REDUCED_HARDWARE_ONLY is not set +# CONFIG_AD2S1200 is not set +# CONFIG_AD2S1210 is not set +# CONFIG_AD2S90 is not set +# CONFIG_AD5064 is not set +# CONFIG_AD525X_DPOT is not set +# CONFIG_AD5360 is not set +# CONFIG_AD5380 is not set +# CONFIG_AD5421 is not set +# CONFIG_AD5446 is not set +# CONFIG_AD5449 is not set +# CONFIG_AD5504 is not set +# CONFIG_AD5624R_SPI is not set +# CONFIG_AD5686 is not set +# CONFIG_AD5755 is not set +# CONFIG_AD5764 is not set +# CONFIG_AD5791 is not set +# CONFIG_AD5930 is not set +# CONFIG_AD5933 is not set +# CONFIG_AD7150 is not set +# CONFIG_AD7152 is not set +# CONFIG_AD7192 is not set +# CONFIG_AD7266 is not set +# CONFIG_AD7280 is not set +# CONFIG_AD7291 is not set +# CONFIG_AD7298 is not set +# CONFIG_AD7303 is not set +# CONFIG_AD7476 is not set +# CONFIG_AD7606 is not set +# CONFIG_AD7746 is not set +# CONFIG_AD7780 is not set +# CONFIG_AD7791 is not set +# CONFIG_AD7793 is not set +# CONFIG_AD7816 is not set +# CONFIG_AD7887 is not set +# CONFIG_AD7923 is not set +# CONFIG_AD799X is not set +# CONFIG_AD8366 is not set +# CONFIG_AD9523 is not set +# CONFIG_AD9832 is not set +# CONFIG_AD9834 is not set +# CONFIG_AD9850 is not set +# CONFIG_AD9852 is not set +# CONFIG_AD9910 is not set +# CONFIG_AD9951 is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_ADE7753 is not set +# CONFIG_ADE7754 is not set +# CONFIG_ADE7758 is not set +# CONFIG_ADE7759 is not set +# CONFIG_ADE7854 is not set +# CONFIG_ADF4350 is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADIS16060 is not set +# CONFIG_ADIS16080 is not set +# CONFIG_ADIS16130 is not set +# CONFIG_ADIS16136 is not set +# CONFIG_ADIS16201 is not set +# CONFIG_ADIS16203 is not set +# CONFIG_ADIS16204 is not set +# CONFIG_ADIS16209 is not set +# CONFIG_ADIS16220 is not set +# CONFIG_ADIS16240 is not set +# CONFIG_ADIS16255 is not set +# CONFIG_ADIS16260 is not set +# CONFIG_ADIS16400 is not set +# CONFIG_ADIS16480 is not set +# CONFIG_ADJD_S311 is not set +# CONFIG_ADM6996_PHY is not set +# CONFIG_ADM8211 is not set +# CONFIG_ADT7316 is not set +# CONFIG_ADVISE_SYSCALLS is not set +# CONFIG_ADXRS450 is not set +CONFIG_AEABI=y +# CONFIG_AFFS_FS is not set +# CONFIG_AFS_FS is not set +# CONFIG_AF_RXRPC is not set +# CONFIG_AGP is not set +# CONFIG_AHCI_MVEBU is not set +CONFIG_AIO=y +# CONFIG_AIRO is not set +# CONFIG_AIRO_CS is not set +# CONFIG_AIX_PARTITION is not set +# CONFIG_AK09911 is not set +# CONFIG_AK8975 is not set +# CONFIG_AL3320A is not set +# CONFIG_ALCHEMY_GPIO_INDIRECT is not set +# CONFIG_ALIM7101_WDT is not set +CONFIG_ALLOW_DEV_COREDUMP=y +# CONFIG_ALTERA_STAPL is not set +# CONFIG_ALTERA_TSE is not set +# CONFIG_ALX is not set +# CONFIG_AM335X_PHY_USB is not set +# CONFIG_AMD8111_ETH is not set +# CONFIG_AMD_XGBE is not set +# CONFIG_AMD_XGBE_PHY is not set +# CONFIG_AMD_PHY is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_AMILO_RFKILL is not set +# CONFIG_ANDROID is not set +CONFIG_ANON_INODES=y +# CONFIG_APDS9300 is not set +# CONFIG_APDS9802ALS is not set +# CONFIG_APM8018X is not set +# CONFIG_APPLICOM is not set +# CONFIG_AR5523 is not set +# CONFIG_AR7 is not set +# CONFIG_AR8216_PHY is not set +# CONFIG_AR8216_PHY_LEDS is not set +# CONFIG_ARCH_AT91 is not set +# CONFIG_ARCH_BCM is not set +# CONFIG_ARCH_BCM2835 is not set +# CONFIG_ARCH_BCMRING is not set +# CONFIG_ARCH_BERLIN is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CNS3XXX is not set +# CONFIG_ARCH_DAVINCI is not set +# CONFIG_ARCH_DIGICOLOR is not set +# CONFIG_ARCH_DMA_ADDR_T_64BIT is not set +# CONFIG_ARCH_DOVE is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_EP93XX is not set +# CONFIG_ARCH_EXYNOS is not set +CONFIG_ARCH_FLATMEM_ENABLE=y +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_GEMINI is not set +# CONFIG_ARCH_H720X is not set +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +# CONFIG_ARCH_HI3xxx is not set +# CONFIG_ARCH_HIGHBANK is not set +# CONFIG_ARCH_HISI is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_IOP13XX is not set +# CONFIG_ARCH_IOP32X is not set +# CONFIG_ARCH_IOP33X is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_IXP23XX is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_KEYSTONE is not set +# CONFIG_ARCH_KIRKWOOD is not set +# CONFIG_ARCH_KS8695 is not set +# CONFIG_ARCH_LPC32XX is not set +# CONFIG_ARCH_MEDIATEK is not set +# CONFIG_ARCH_MESON is not set +# CONFIG_ARCH_MMP is not set +# CONFIG_ARCH_MSM is not set +# CONFIG_ARCH_MSM_DT is not set +# CONFIG_ARCH_MSM_NODT is not set +# CONFIG_ARCH_MULTIPLATFORM is not set +# CONFIG_ARCH_MULTI_V6 is not set +# CONFIG_ARCH_MULTI_V7 is not set +# CONFIG_ARCH_MV78XX0 is not set +# CONFIG_ARCH_MVEBU is not set +# CONFIG_ARCH_MXC is not set +# CONFIG_ARCH_MXS is not set +# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set +# CONFIG_ARCH_NETX is not set +# CONFIG_ARCH_NOMADIK is not set +# CONFIG_ARCH_NSPIRE is not set +# CONFIG_ARCH_NUC93X is not set +# CONFIG_ARCH_OMAP is not set +# CONFIG_ARCH_OMAP1 is not set +# CONFIG_ARCH_OMAP2PLUS is not set +# CONFIG_ARCH_OMAP3 is not set +# CONFIG_ARCH_OMAP4 is not set +# CONFIG_ARCH_ORION5X is not set +# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set +# CONFIG_ARCH_PICOXCELL is not set +# CONFIG_ARCH_PNX4008 is not set +# CONFIG_ARCH_PRIMA2 is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_QCOM is not set +# CONFIG_ARCH_REALVIEW is not set +# CONFIG_ARCH_ROCKCHIP is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_S3C24XX is not set +# CONFIG_ARCH_S3C64XX is not set +# CONFIG_ARCH_S5P64X0 is not set +# CONFIG_ARCH_S5PC100 is not set +# CONFIG_ARCH_S5PV210 is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_SHMOBILE is not set +# CONFIG_ARCH_SHMOBILE_LEGACY is not set +# CONFIG_ARCH_SHMOBILE_MULTI is not set +# CONFIG_ARCH_SIRF is not set +# CONFIG_ARCH_SOCFPGA is not set +# CONFIG_ARCH_STI is not set +# CONFIG_ARCH_SUNXI is not set +# CONFIG_ARCH_SUPPORTS_MSI is not set +# CONFIG_ARCH_TCC_926 is not set +# CONFIG_ARCH_TEGRA is not set +# CONFIG_ARCH_U300 is not set +# CONFIG_ARCH_U8500 is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_VEXPRESS is not set +# CONFIG_ARCH_VIRT is not set +# CONFIG_ARCH_VT8500 is not set +# CONFIG_ARCH_W90X900 is not set +# CONFIG_ARCH_WM8505 is not set +# CONFIG_ARCH_WM8850 is not set +# CONFIG_ARCH_ZYNQ is not set +# CONFIG_ARCNET is not set +# CONFIG_ARC_EMAC is not set +# CONFIG_ARM_APPENDED_DTB is not set +# CONFIG_ARM_ARCH_TIMER is not set +# CONFIG_ARM_AT91_ETHER is not set +# CONFIG_ARM_CCI is not set +# CONFIG_ARM_CCN is not set +CONFIG_ARM_CPU_TOPOLOGY=y +CONFIG_ARM_DMA_MEM_BUFFERABLE=y +# CONFIG_ARM_ERRATA_326103 is not set +# CONFIG_ARM_ERRATA_364296 is not set +# CONFIG_ARM_ERRATA_411920 is not set +# CONFIG_ARM_ERRATA_430973 is not set +# CONFIG_ARM_ERRATA_458693 is not set +# CONFIG_ARM_ERRATA_460075 is not set +# CONFIG_ARM_ERRATA_643719 is not set +# CONFIG_ARM_ERRATA_720789 is not set +# CONFIG_ARM_ERRATA_742230 is not set +# CONFIG_ARM_ERRATA_742231 is not set +# CONFIG_ARM_ERRATA_743622 is not set +# CONFIG_ARM_ERRATA_751472 is not set +# CONFIG_ARM_ERRATA_754322 is not set +# CONFIG_ARM_ERRATA_754327 is not set +# CONFIG_ARM_ERRATA_764369 is not set +# CONFIG_ARM_ERRATA_773022 is not set +# CONFIG_ARM_ERRATA_775420 is not set +# CONFIG_ARM_ERRATA_798181 is not set +# CONFIG_ARM_KERNMEM_PERMS is not set +# CONFIG_ARM_KPROBES_TEST is not set +# CONFIG_ARM_PATCH_PHYS_VIRT is not set +# CONFIG_ARM_PSCI is not set +# CONFIG_ARM_PTDUMP is not set +# CONFIG_ARM_UNWIND is not set +# CONFIG_ARM_VIRT_EXT is not set +CONFIG_ARPD=y +# CONFIG_ARTHUR is not set +# CONFIG_AS3935 is not set +# CONFIG_ASM9260_TIMER is not set +# CONFIG_ASUS_LAPTOP is not set +# CONFIG_ASUS_OLED is not set +# CONFIG_ASYMMETRIC_KEY_TYPE is not set +# CONFIG_ASYNC_RAID6_TEST is not set +# CONFIG_ASYNC_TX_DMA is not set +# CONFIG_AT76C50X_USB is not set +# CONFIG_AT803X_PHY is not set +# CONFIG_ATA is not set +# CONFIG_ATAGS is not set +CONFIG_ATAGS_PROC=y +# CONFIG_ATALK is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_ATA_ACPI is not set +CONFIG_ATA_BMDMA=y +# CONFIG_ATA_GENERIC is not set +# CONFIG_ATA_NONSTANDARD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_ATA_PIIX is not set +CONFIG_ATA_SFF=y +# CONFIG_ATA_VERBOSE_ERROR is not set +# CONFIG_ATH10K is not set +# CONFIG_ATH25 is not set +# CONFIG_ATH5K is not set +# CONFIG_ATH6KL is not set +# CONFIG_ATH6K_LEGACY is not set +# CONFIG_ATH79 is not set +# CONFIG_ATH9K is not set +# CONFIG_ATH9K_HTC is not set +# CONFIG_ATH_DEBUG is not set +# CONFIG_ATL1 is not set +# CONFIG_ATL1C is not set +# CONFIG_ATL1E is not set +# CONFIG_ATL2 is not set +# CONFIG_ATM is not set +# CONFIG_ATMEL is not set +# CONFIG_ATMEL_PIT is not set +# CONFIG_ATMEL_PWM is not set +# CONFIG_ATMEL_SSC is not set +# CONFIG_ATM_AMBASSADOR is not set +# CONFIG_ATM_BR2684 is not set +CONFIG_ATM_BR2684_IPFILTER=y +# CONFIG_ATM_CLIP is not set +CONFIG_ATM_CLIP_NO_ICMP=y +# CONFIG_ATM_DRIVERS is not set +# CONFIG_ATM_DUMMY is not set +# CONFIG_ATM_ENI is not set +# CONFIG_ATM_FIRESTREAM is not set +# CONFIG_ATM_FORE200E is not set +# CONFIG_ATM_HE is not set +# CONFIG_ATM_HORIZON is not set +# CONFIG_ATM_IA is not set +# CONFIG_ATM_IDT77252 is not set +# CONFIG_ATM_LANAI is not set +# CONFIG_ATM_LANE is not set +# CONFIG_ATM_MPOA is not set +# CONFIG_ATM_NICSTAR is not set +# CONFIG_ATM_SOLOS is not set +# CONFIG_ATM_TCP is not set +# CONFIG_ATM_ZATM is not set +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_ATP is not set +# CONFIG_AUDIT is not set +# CONFIG_AUDIT_ARCH_COMPAT_GENERIC is not set +# CONFIG_AUDIT_LOGINUID_IMMUTABLE is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_AUTO_ZRELADDR is not set +# CONFIG_AUXDISPLAY is not set +# CONFIG_AVERAGE is not set +# CONFIG_AX25 is not set +# CONFIG_AX25_DAMA_SLAVE is not set +# CONFIG_AX88796 is not set +# CONFIG_B43 is not set +# CONFIG_B43LEGACY is not set +# CONFIG_B44 is not set +# CONFIG_B53 is not set +# CONFIG_B53_SPI_DRIVER is not set +# CONFIG_BACKLIGHT_BD6107 is not set +# CONFIG_BACKLIGHT_GPIO is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set +# CONFIG_BACKLIGHT_LM3630 is not set +# CONFIG_BACKLIGHT_LM3630A is not set +# CONFIG_BACKLIGHT_LM3639 is not set +# CONFIG_BACKLIGHT_LP855X is not set +# CONFIG_BACKLIGHT_LV5207LP is not set +# CONFIG_BACKLIGHT_PANDORA is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +CONFIG_BASE_FULL=y +CONFIG_BASE_SMALL=0 +# CONFIG_BATMAN_ADV is not set +# CONFIG_BATTERY_BQ27x00 is not set +# CONFIG_BATTERY_DS2760 is not set +# CONFIG_BATTERY_DS2780 is not set +# CONFIG_BATTERY_DS2781 is not set +# CONFIG_BATTERY_DS2782 is not set +# CONFIG_BATTERY_GAUGE_LTC2941 is not set +# CONFIG_BATTERY_GOLDFISH is not set +# CONFIG_BATTERY_MAX17040 is not set +# CONFIG_BATTERY_MAX17042 is not set +# CONFIG_BATTERY_SBS is not set +# CONFIG_BAYCOM_EPP is not set +# CONFIG_BAYCOM_PAR is not set +# CONFIG_BAYCOM_SER_FDX is not set +# CONFIG_BAYCOM_SER_HDX is not set +# CONFIG_BCACHE is not set +# CONFIG_BCM3384 is not set +# CONFIG_BCM47XX is not set +# CONFIG_BCM63XX is not set +# CONFIG_BCM63XX_PHY is not set +# CONFIG_BCM7XXX_PHY is not set +# CONFIG_BCM87XX_PHY is not set +# CONFIG_BCMA is not set +# CONFIG_BCMA_DRIVER_GPIO is not set +CONFIG_BCMA_POSSIBLE=y +# CONFIG_BCMGENET is not set +# CONFIG_BCM_KONA_USB2_PHY is not set +# CONFIG_BCM_WIMAX is not set +# CONFIG_BDI_SWITCH is not set +# CONFIG_BE2ISCSI is not set +# CONFIG_BE2NET is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_BGMAC is not set +# CONFIG_BIG_KEYS is not set +# CONFIG_BIG_LITTLE is not set +# CONFIG_BINARY_PRINTF is not set +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +CONFIG_BINFMT_SCRIPT=y +CONFIG_BITREVERSE=y +# CONFIG_BLK_CMDLINE_PARSER is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_CPQ_DA is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_BLK_DEV_4DRIVES is not set +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_BLK_DEV_ALI14XX is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_BLK_DEV_AMD74XX is not set +# CONFIG_BLK_DEV_ATIIXP is not set +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_BLK_DEV_BSGLIB is not set +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD64X is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_CS5520 is not set +# CONFIG_BLK_DEV_CS5530 is not set +# CONFIG_BLK_DEV_CS5535 is not set +# CONFIG_BLK_DEV_CS5536 is not set +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_DELKIN is not set +# CONFIG_BLK_DEV_DRBD is not set +# CONFIG_BLK_DEV_DTC2278 is not set +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_GENERIC is not set +# CONFIG_BLK_DEV_HD is not set +# CONFIG_BLK_DEV_HPT366 is not set +# CONFIG_BLK_DEV_HT6560B is not set +# CONFIG_BLK_DEV_IDEACPI is not set +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDECS is not set +# CONFIG_BLK_DEV_IDEPCI is not set +# CONFIG_BLK_DEV_IDEPNP is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDE_AU1XXX is not set +# CONFIG_BLK_DEV_IDE_SATA is not set +CONFIG_BLK_DEV_INITRD=y +# CONFIG_BLK_DEV_INTEGRITY is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_BLK_DEV_IT8172 is not set +# CONFIG_BLK_DEV_IT8213 is not set +# CONFIG_BLK_DEV_IT821X is not set +# CONFIG_BLK_DEV_JMICRON is not set +# CONFIG_BLK_DEV_LOOP is not set +CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_NULL_BLK is not set +# CONFIG_BLK_DEV_NVME is not set +# CONFIG_BLK_DEV_OFFBOARD is not set +# CONFIG_BLK_DEV_OPTI621 is not set +# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set +# CONFIG_BLK_DEV_PDC202XX_NEW is not set +# CONFIG_BLK_DEV_PDC202XX_OLD is not set +# CONFIG_BLK_DEV_PIIX is not set +# CONFIG_BLK_DEV_PLATFORM is not set +# CONFIG_BLK_DEV_QD65XX is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_RBD is not set +# CONFIG_BLK_DEV_RSXX is not set +# CONFIG_BLK_DEV_RZ1000 is not set +# CONFIG_BLK_DEV_SC1200 is not set +# CONFIG_BLK_DEV_SD is not set +# CONFIG_BLK_DEV_SIIMAGE is not set +# CONFIG_BLK_DEV_SIS5513 is not set +# CONFIG_BLK_DEV_SKD is not set +# CONFIG_BLK_DEV_SL82C105 is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_BLK_DEV_SVWKS is not set +# CONFIG_BLK_DEV_SX8 is not set +# CONFIG_BLK_DEV_TC86C001 is not set +# CONFIG_BLK_DEV_THROTTLING is not set +# CONFIG_BLK_DEV_TRIFLEX is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_UB is not set +# CONFIG_BLK_DEV_UMC8672 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_VIA82CXXX is not set +# CONFIG_BLK_DEV_XIP is not set +CONFIG_BLOCK=y +# CONFIG_BMA180 is not set +# CONFIG_BMC150_ACCEL is not set +# CONFIG_BMG160 is not set +# CONFIG_BMP085 is not set +# CONFIG_BMP085_I2C is not set +# CONFIG_BMP085_SPI is not set +# CONFIG_BMP280 is not set +# CONFIG_BNA is not set +# CONFIG_BNX2 is not set +# CONFIG_BNX2X is not set +# CONFIG_BONDING is not set +# CONFIG_BOOKE_WDT is not set +CONFIG_BOOKE_WDT_DEFAULT_TIMEOUT=3 +# CONFIG_BOOT_PRINTK_DELAY is not set +CONFIG_BOOT_RAW=y +# CONFIG_BPCTL is not set +CONFIG_BPF=y +# CONFIG_BPF_JIT is not set +CONFIG_BPF_SYSCALL=y +# CONFIG_BPQETHER is not set +CONFIG_BQL=y +CONFIG_BRANCH_PROFILE_NONE=y +# CONFIG_BRCMFMAC is not set +# CONFIG_BRCMSMAC is not set +# CONFIG_BRCMSTB_GISB_ARB is not set +CONFIG_BRIDGE=y +# CONFIG_BRIDGE_EBT_802_3 is not set +# CONFIG_BRIDGE_EBT_AMONG is not set +# CONFIG_BRIDGE_EBT_ARP is not set +# CONFIG_BRIDGE_EBT_ARPREPLY is not set +# CONFIG_BRIDGE_EBT_BROUTE is not set +# CONFIG_BRIDGE_EBT_DNAT is not set +# CONFIG_BRIDGE_EBT_IP is not set +# CONFIG_BRIDGE_EBT_IP6 is not set +# CONFIG_BRIDGE_EBT_LIMIT is not set +# CONFIG_BRIDGE_EBT_LOG is not set +# CONFIG_BRIDGE_EBT_MARK is not set +# CONFIG_BRIDGE_EBT_MARK_T is not set +# CONFIG_BRIDGE_EBT_NFLOG is not set +# CONFIG_BRIDGE_EBT_PKTTYPE is not set +# CONFIG_BRIDGE_EBT_REDIRECT is not set +# CONFIG_BRIDGE_EBT_SNAT is not set +# CONFIG_BRIDGE_EBT_STP is not set +# CONFIG_BRIDGE_EBT_T_FILTER is not set +# CONFIG_BRIDGE_EBT_T_NAT is not set +# CONFIG_BRIDGE_EBT_ULOG is not set +# CONFIG_BRIDGE_EBT_VLAN is not set +CONFIG_BRIDGE_IGMP_SNOOPING=y +# CONFIG_BRIDGE_NETFILTER is not set +# CONFIG_BRIDGE_NF_EBTABLES is not set +# CONFIG_BRIDGE_VLAN_FILTERING is not set +# CONFIG_BROADCOM_PHY is not set +CONFIG_BROKEN_ON_SMP=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_BSD_PROCESS_ACCT_V3 is not set +# CONFIG_BT is not set +# CONFIG_BTRFS_ASSERT is not set +# CONFIG_BTRFS_DEBUG is not set +# CONFIG_BTRFS_FS is not set +# CONFIG_BTRFS_FS_RUN_SANITY_TESTS is not set +# CONFIG_BT_ATH3K is not set +# CONFIG_BT_BNEP is not set +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +# CONFIG_BT_BREDR is not set +# CONFIG_BT_CMTP is not set +# CONFIG_BT_HCIBCM203X is not set +# CONFIG_BT_HCIBFUSB is not set +# CONFIG_BT_HCIBLUECARD is not set +# CONFIG_BT_HCIBPA10X is not set +# CONFIG_BT_HCIBT3C is not set +# CONFIG_BT_HCIBTSDIO is not set +# CONFIG_BT_HCIBTUART is not set +# CONFIG_BT_HCIBTUSB is not set +# CONFIG_BT_HCIDTL1 is not set +# CONFIG_BT_HCIUART is not set +# CONFIG_BT_HCIUART_3WIRE is not set +# CONFIG_BT_HCIUART_ATH3K is not set +CONFIG_BT_HCIUART_BCSP=y +CONFIG_BT_HCIUART_H4=y +# CONFIG_BT_HCIUART_LL is not set +# CONFIG_BT_HCIVHCI is not set +# CONFIG_BT_HIDP is not set +CONFIG_BT_L2CAP=y +# CONFIG_BT_LE is not set +# CONFIG_BT_MRVL is not set +# CONFIG_BT_RFCOMM is not set +# CONFIG_BUILD_BIN2C is not set +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_SCO=y +# CONFIG_BT_SELFTEST is not set +CONFIG_BUG=y +CONFIG_BUILDTIME_EXTABLE_SORT=y +# CONFIG_C2PORT is not set +# CONFIG_CADENCE_WATCHDOG is not set +# CONFIG_CAIF is not set +# CONFIG_CAN is not set +# CONFIG_CAN_GS_USB is not set +# CONFIG_CAN_M_CAN is not set +# CONFIG_CAN_RCAR is not set +# CONFIG_CAPI_AVM is not set +# CONFIG_CAPI_EICON is not set +# CONFIG_CAPI_TRACE is not set +CONFIG_CARDBUS=y +# CONFIG_CARDMAN_4000 is not set +# CONFIG_CARDMAN_4040 is not set +# CONFIG_CARL9170 is not set +# CONFIG_CARMA_FPGA is not set +# CONFIG_CARMA_FPGA_PROGRAM is not set +# CONFIG_CASSINI is not set +CONFIG_CAVIUM_OCTEON_HELPER=y +# CONFIG_CAVIUM_OCTEON_REFERENCE_BOARD is not set +# CONFIG_CAVIUM_OCTEON_SIMULATOR is not set +# CONFIG_CAVIUM_OCTEON_SOC is not set +# CONFIG_CB710_CORE is not set +# CONFIG_CC10001_ADC is not set +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +# CONFIG_CC_STACKPROTECTOR is not set +CONFIG_CC_STACKPROTECTOR_NONE=y +# CONFIG_CC_STACKPROTECTOR_REGULAR is not set +# CONFIG_CC_STACKPROTECTOR_STRONG is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_CED1401 is not set +# CONFIG_CEPH_FS is not set +# CONFIG_CEPH_LIB is not set +# CONFIG_CFG80211 is not set +# CONFIG_CFG80211_CERTIFICATION_ONUS is not set +# CONFIG_CGROUPS is not set +# CONFIG_CGROUP_DEBUG is not set +# CONFIG_CGROUP_NET_PRIO is not set +# CONFIG_CHARGER_BQ2415X is not set +# CONFIG_CHARGER_BQ24190 is not set +# CONFIG_CHARGER_BQ24735 is not set +# CONFIG_CHARGER_GPIO is not set +# CONFIG_CHARGER_ISP1704 is not set +# CONFIG_CHARGER_LP8727 is not set +# CONFIG_CHARGER_MANAGER is not set +# CONFIG_CHARGER_MAX8903 is not set +# CONFIG_CHARGER_SMB347 is not set +# CONFIG_CHARGER_TWL4030 is not set +# CONFIG_CHECKPOINT_RESTORE is not set +# CONFIG_CHELSIO_T1 is not set +# CONFIG_CHELSIO_T3 is not set +# CONFIG_CHELSIO_T4 is not set +# CONFIG_CHELSIO_T4VF is not set +# CONFIG_CHROME_PLATFORMS is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_CHR_DEV_SCH is not set +# CONFIG_CHR_DEV_SG is not set +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_CIFS is not set +# CONFIG_CIFS_ACL is not set +# CONFIG_CIFS_DEBUG is not set +# CONFIG_CIFS_DEBUG2 is not set +# CONFIG_CIFS_FSCACHE is not set +# CONFIG_CIFS_NFSD_EXPORT is not set +CONFIG_CIFS_POSIX=y +# CONFIG_CIFS_SMB2 is not set +CONFIG_CIFS_STATS=y +# CONFIG_CIFS_STATS2 is not set +# CONFIG_CIFS_WEAK_PW_HASH is not set +# CONFIG_CIFS_XATTR is not set +# CONFIG_CLEANCACHE is not set +# CONFIG_CLK_QORIQ is not set +# CONFIG_CLKSRC_VERSATILE is not set +# CONFIG_CLOCK_THERMAL is not set +CONFIG_CLS_U32_MARK=y +# CONFIG_CLS_U32_PERF is not set +# CONFIG_CM32181 is not set +# CONFIG_CM3232 is not set +# CONFIG_CM36651 is not set +# CONFIG_CMA is not set +CONFIG_CMDLINE="" +# CONFIG_CMDLINE_BOOL is not set +# CONFIG_CMDLINE_EXTEND is not set +# CONFIG_CMDLINE_FORCE is not set +# CONFIG_CMDLINE_FROM_BOOTLOADER is not set +# CONFIG_CMDLINE_PARTITION is not set +# CONFIG_CNIC is not set +# CONFIG_CODA_FS is not set +# CONFIG_CODE_PATCHING_SELFTEST is not set +# CONFIG_COMEDI is not set +# CONFIG_COMMON_CLK_CDCE706 is not set +# CONFIG_COMMON_CLK_DEBUG is not set +# CONFIG_COMMON_CLK_PXA is not set +# CONFIG_COMMON_CLK_QCOM is not set +# CONFIG_COMMON_CLK_SI5351 is not set +# CONFIG_COMMON_CLK_SI570 is not set +# CONFIG_COMMON_CLK_XLNX_CLKWZRD is not set +# CONFIG_COMPACTION is not set +# CONFIG_COMPAL_LAPTOP is not set +# CONFIG_COMPAT_BRK is not set +# CONFIG_COMPILE_TEST is not set +# CONFIG_CONFIGFS_FS is not set +# CONFIG_CONNECTOR is not set +CONFIG_CONSTRUCTORS=y +# CONFIG_CONTEXT_SWITCH_TRACER is not set +# CONFIG_COPS is not set +# CONFIG_CORDIC is not set +# CONFIG_COREDUMP is not set +# CONFIG_CORESIGHT is not set +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +# CONFIG_CPA_DEBUG is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_FREQ is not set +# CONFIG_CPU_IDLE is not set +# CONFIG_CPU_IDLE_GOV_MENU is not set +# CONFIG_CPU_IDLE_MULTIPLE_DRIVERS is not set +# CONFIG_CRAMFS is not set +CONFIG_CRASHLOG=y +# CONFIG_CRASH_DUMP is not set +# CONFIG_CRC16 is not set +CONFIG_CRC32=y +# CONFIG_CRC32_BIT is not set +CONFIG_CRC32_SARWATE=y +# CONFIG_CRC32_SELFTEST is not set +# CONFIG_CRC32_SLICEBY4 is not set +# CONFIG_CRC32_SLICEBY8 is not set +# CONFIG_CRC7 is not set +# CONFIG_CRC8 is not set +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC_ITU_T is not set +# CONFIG_CRC_T10DIF is not set +CONFIG_CROSS_COMPILE="" +# CONFIG_CROSS_MEMORY_ATTACH is not set +CONFIG_CRYPTO=y +# CONFIG_CRYPTO_AEAD is not set +CONFIG_CRYPTO_AES=y +# CONFIG_CRYPTO_AES_586 is not set +# CONFIG_CRYPTO_AES_ARM is not set +# CONFIG_CRYPTO_AES_ARM_BS is not set +# CONFIG_CRYPTO_AES_NI_INTEL is not set +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +# CONFIG_CRYPTO_ANSI_CPRNG is not set +# CONFIG_CRYPTO_ANUBIS is not set +CONFIG_CRYPTO_ARC4=y +# CONFIG_CRYPTO_AUTHENC is not set +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_BLKCIPHER2=y +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_CBC is not set +# CONFIG_CRYPTO_CCM is not set +# CONFIG_CRYPTO_CMAC is not set +# CONFIG_CRYPTO_CRC32 is not set +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_CRC32C_INTEL is not set +# CONFIG_CRYPTO_CRCT10DIF is not set +# CONFIG_CRYPTO_CRYPTD is not set +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_CTS is not set +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_DES is not set +# CONFIG_CRYPTO_DEV_ATMEL_AES is not set +# CONFIG_CRYPTO_DEV_ATMEL_SHA is not set +# CONFIG_CRYPTO_DEV_ATMEL_TDES is not set +# CONFIG_CRYPTO_DEV_CCP is not set +# CONFIG_CRYPTO_DEV_FSL_CAAM is not set +# CONFIG_CRYPTO_DEV_HIFN_795X is not set +# CONFIG_CRYPTO_DEV_MV_CESA is not set +# CONFIG_CRYPTO_DEV_QAT_DH895xCC is not set +# CONFIG_CRYPTO_DEV_QCE is not set +# CONFIG_CRYPTO_DEV_SAHARA is not set +# CONFIG_CRYPTO_DEV_TALITOS is not set +# CONFIG_CRYPTO_DRBG_MENU is not set +# CONFIG_CRYPTO_ECB is not set +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_FIPS is not set +# CONFIG_CRYPTO_GCM is not set +# CONFIG_CRYPTO_GF128MUL is not set +# CONFIG_CRYPTO_GHASH is not set +# CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL is not set +# CONFIG_CRYPTO_HASH is not set +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_HW is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_LZ4 is not set +# CONFIG_CRYPTO_LZ4HC is not set +# CONFIG_CRYPTO_LZO is not set +# CONFIG_CRYPTO_MANAGER is not set +# CONFIG_CRYPTO_MANAGER2 is not set +CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y +# CONFIG_CRYPTO_MCRYPTD is not set +# CONFIG_CRYPTO_MD4 is not set +# CONFIG_CRYPTO_MD5 is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_PCBC is not set +# CONFIG_CRYPTO_PCOMP is not set +# CONFIG_CRYPTO_PCOMP2 is not set +# CONFIG_CRYPTO_PCRYPT is not set +# CONFIG_CRYPTO_RMD128 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_RMD256 is not set +# CONFIG_CRYPTO_RMD320 is not set +# CONFIG_CRYPTO_RNG is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_SALSA20_586 is not set +# CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_SEQIV is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA1_ARM is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_TEST is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_TWOFISH_586 is not set +# CONFIG_CRYPTO_TWOFISH_COMMON is not set +# CONFIG_CRYPTO_USER is not set +# CONFIG_CRYPTO_USER_API_HASH is not set +# CONFIG_CRYPTO_USER_API_RNG is not set +# CONFIG_CRYPTO_USER_API_SKCIPHER is not set +# CONFIG_CRYPTO_VMAC is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_XTS is not set +# CONFIG_CRYPTO_XZ is not set +# CONFIG_CRYPTO_ZLIB is not set +# CONFIG_CRYSTALHD is not set +# CONFIG_CS5535_MFGPT is not set +# CONFIG_CS89x0 is not set +# CONFIG_CUSE is not set +# CONFIG_CW1200 is not set +# CONFIG_CXL_BASE is not set +# CONFIG_CXT1E1 is not set +# CONFIG_CYPRESS_FIRMWARE is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_DCB is not set +# CONFIG_DDR is not set +# CONFIG_DE600 is not set +# CONFIG_DE620 is not set +# CONFIG_DEBUG_ATOMIC_SLEEP is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_CREDENTIALS is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +CONFIG_DEBUG_FS=y +# CONFIG_DEBUG_GPIO is not set +# CONFIG_DEBUG_HIGHMEM is not set +# CONFIG_DEBUG_ICEDCC is not set +# CONFIG_DEBUG_INFO is not set +# CONFIG_DEBUG_INFO_DWARF4 is not set +CONFIG_DEBUG_INFO_REDUCED=y +# CONFIG_DEBUG_INFO_SPLIT is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_KMEMLEAK is not set +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_KOBJECT_RELEASE is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_LL is not set +# CONFIG_DEBUG_LL_UART_8250 is not set +# CONFIG_DEBUG_LL_UART_PL01X is not set +# CONFIG_DEBUG_LOCKDEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_DEBUG_NX_TEST is not set +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_DEBUG_PAGEALLOC is not set +# CONFIG_DEBUG_PERF_USE_VMALLOC is not set +# CONFIG_DEBUG_PER_CPU_MAPS is not set +# CONFIG_DEBUG_PI_LIST is not set +# CONFIG_DEBUG_PINCTRL is not set +# CONFIG_DEBUG_PREEMPT is not set +# CONFIG_DEBUG_RODATA is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_DEBUG_SECTION_MISMATCH is not set +# CONFIG_DEBUG_SEMIHOSTING is not set +# CONFIG_DEBUG_SET_MODULE_RONX is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_SHIRQ is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_STACKOVERFLOW is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_STRICT_USER_COPY_CHECKS is not set +# CONFIG_DEBUG_UART_BCM63XX is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_WRITECOUNT is not set +# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set +# CONFIG_DEBUG_ZBOOT is not set +# CONFIG_DECNET is not set +CONFIG_DEFAULT_CUBIC=y +CONFIG_DEFAULT_DEADLINE=y +CONFIG_DEFAULT_HOSTNAME="(none)" +CONFIG_DEFAULT_IOSCHED="deadline" +CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4 +CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 +# CONFIG_DEFAULT_NOOP is not set +# CONFIG_DEFAULT_RENO is not set +CONFIG_DEFAULT_SECURITY="" +CONFIG_DEFAULT_SECURITY_DAC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +# CONFIG_DELL_SMO8800 is not set +# CONFIG_DEPRECATED_PARAM_STRUCT is not set +# CONFIG_DETECT_HUNG_TASK is not set +# CONFIG_DEVKMEM is not set +# CONFIG_DEVMEM is not set +CONFIG_DEVPORT=y +# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set +# CONFIG_DEVTMPFS is not set +# CONFIG_DEVTMPFS_MOUNT is not set +# CONFIG_DGAP is not set +# CONFIG_DGNC is not set +# CONFIG_DGRP is not set +# CONFIG_DHT11 is not set +# CONFIG_DIRECT_IO is not set +CONFIG_DISABLE_DEV_COREDUMP=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_DISPLAY_CONNECTOR_ANALOG_TV is not set +# CONFIG_DISPLAY_CONNECTOR_DVI is not set +# CONFIG_DISPLAY_CONNECTOR_HDMI is not set +# CONFIG_DISPLAY_ENCODER_TFP410 is not set +# CONFIG_DISPLAY_ENCODER_TPD12S015 is not set +# CONFIG_DISPLAY_PANEL_DPI is not set +# CONFIG_DISPLAY_PANEL_LGPHILIPS_LB035Q02 is not set +# CONFIG_DISPLAY_PANEL_TPO_TD028TTEC1 is not set +# CONFIG_DISPLAY_PANEL_TPO_TD043MTEA1 is not set +# CONFIG_DISPLAY_SUPPORT is not set +# CONFIG_DL2K is not set +# CONFIG_DLM is not set +# CONFIG_DM9000 is not set +# CONFIG_DMADEVICES is not set +# CONFIG_DMADEVICES_DEBUG is not set +# CONFIG_DMASCC is not set +# CONFIG_DMATEST is not set +# CONFIG_DMA_API_DEBUG is not set +# CONFIG_DMA_ENGINE is not set +# CONFIG_DMA_SHARED_BUFFER is not set +# CONFIG_DM_CACHE is not set +# CONFIG_DM_DEBUG is not set +# CONFIG_DM_DELAY is not set +# CONFIG_DM_ERA is not set +# CONFIG_DM_FLAKEY is not set +# CONFIG_DM_LOG_USERSPACE is not set +# CONFIG_DM_MULTIPATH is not set +# CONFIG_DM_RAID is not set +# CONFIG_DM_SWITCH is not set +# CONFIG_DM_THIN_PROVISIONING is not set +# CONFIG_DM_UEVENT is not set +# CONFIG_DM_VERITY is not set +# CONFIG_DM_ZERO is not set +# CONFIG_DNET is not set +# CONFIG_DNOTIFY is not set +# CONFIG_DNS_RESOLVER is not set +CONFIG_DOUBLEFAULT=y +CONFIG_DQL=y +# CONFIG_DRAGONRISE_FF is not set +# CONFIG_DRM is not set +# CONFIG_DS1682 is not set +# CONFIG_DTLK is not set +# CONFIG_DUMMY is not set +# CONFIG_DUMMY_IRQ is not set +# CONFIG_DVB_AU8522_V4L is not set +# CONFIG_DVB_CORE is not set +# CONFIG_DVB_DUMMY_FE is not set +# CONFIG_DVB_TUNER_DIB0070 is not set +# CONFIG_DVB_TUNER_DIB0090 is not set +# CONFIG_DW_DMAC is not set +# CONFIG_DW_WATCHDOG is not set +# CONFIG_DWC3_HOST_USB3_LPM_ENABLE is not set +# CONFIG_DX_SEP is not set +# CONFIG_DYNAMIC_DEBUG is not set +# CONFIG_E100 is not set +# CONFIG_E1000 is not set +# CONFIG_E1000E is not set +# CONFIG_E2100 is not set +# CONFIG_EARLY_PRINTK_8250 is not set +# CONFIG_EASYCAP is not set +# CONFIG_ECHO is not set +# CONFIG_ECONET is not set +# CONFIG_ECRYPT_FS is not set +# CONFIG_EDAC is not set +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_EEPROM_93XX46 is not set +# CONFIG_EEPROM_AT24 is not set +# CONFIG_EEPROM_AT25 is not set +# CONFIG_EEPROM_DIGSY_MTC_CFG is not set +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +# CONFIG_EEXPRESS is not set +# CONFIG_EEXPRESS_PRO is not set +CONFIG_EFI_PARTITION=y +# CONFIG_EFS_FS is not set +# CONFIG_ELF_CORE is not set +# CONFIG_EMAC_ROCKCHIP is not set +CONFIG_EMBEDDED=y +# CONFIG_EM_TIMER_STI is not set +# CONFIG_ENABLE_MUST_CHECK is not set +CONFIG_ENABLE_WARN_DEPRECATED=y +# CONFIG_ENC28J60 is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_ENCRYPTED_KEYS is not set +# CONFIG_ENIC is not set +# CONFIG_EPAPR_PARAVIRT is not set +# CONFIG_EPIC100 is not set +CONFIG_EPOLL=y +# CONFIG_EQUALIZER is not set +# CONFIG_ET131X is not set +# CONFIG_GATEWORKS_GW16083 is not set +# CONFIG_GDB_SCRIPTS is not set +# CONFIG_GLOB_SELFTEST is not set +# CONFIG_GS_FPGABOOT is not set +# CONFIG_ETH16I is not set +CONFIG_ETHERNET=y +# CONFIG_ETHOC is not set +CONFIG_EVENTFD=y +# CONFIG_EVENT_POWER_TRACING_DEPRECATED is not set +# CONFIG_EWRK3 is not set +CONFIG_EXPERIMENTAL=y +CONFIG_EXPERT=y +# CONFIG_EXPORTFS is not set +# CONFIG_EXT2_FS is not set +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set +# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set +# CONFIG_EXT3_FS is not set +# CONFIG_EXT3_FS_XATTR is not set +# CONFIG_EXT4_DEBUG is not set +# CONFIG_EXT4_FS is not set +# CONFIG_EXT4_FS_POSIX_ACL is not set +# CONFIG_EXT4_FS_SECURITY is not set +CONFIG_EXT4_FS_XATTR=y +CONFIG_EXT4_USE_FOR_EXT23=y +# CONFIG_EXTCON is not set +CONFIG_EXTRA_FIRMWARE="" +CONFIG_EXTRA_TARGETS="" +# CONFIG_EXYNOS_ADC is not set +# CONFIG_EXYNOS_VIDEO is not set +# CONFIG_EZX_PCAP is not set +# CONFIG_F2FS_FS is not set +# CONFIG_FAIR_GROUP_SCHED is not set +# CONFIG_FANOTIFY is not set +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_FAT_FS is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_FB is not set +# CONFIG_FB_3DFX is not set +# CONFIG_FB_ARC is not set +# CONFIG_FB_ARK is not set +# CONFIG_FB_ARMCLCD is not set +# CONFIG_FB_ASILIANT is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_AUO_K190X is not set +# CONFIG_FB_BACKLIGHT is not set +# CONFIG_FB_BOOT_VESA_SUPPORT is not set +# CONFIG_FB_BROADSHEET is not set +# CONFIG_FB_CARMINE is not set +# CONFIG_FB_CFB_COPYAREA is not set +# CONFIG_FB_CFB_FILLRECT is not set +# CONFIG_FB_CFB_IMAGEBLIT is not set +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set +# CONFIG_FB_CIRRUS is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_DA8XX is not set +# CONFIG_FB_DDC is not set +# CONFIG_FB_FOREIGN_ENDIAN is not set +# CONFIG_FB_GEODE is not set +# CONFIG_FB_GOLDFISH is not set +# CONFIG_FB_HGA is not set +# CONFIG_FB_I740 is not set +# CONFIG_FB_IBM_GXT4500 is not set +# CONFIG_FB_IMSTT is not set +# CONFIG_FB_IMX is not set +# CONFIG_FB_KYRO is not set +# CONFIG_FB_LE80578 is not set +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_MB862XX is not set +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_N411 is not set +# CONFIG_FB_NEOMAGIC is not set +# CONFIG_FB_NVIDIA is not set +# CONFIG_FB_OF is not set +# CONFIG_FB_OPENCORES is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_PM3 is not set +# CONFIG_FB_PS3 is not set +# CONFIG_FB_PXA is not set +# CONFIG_FB_RADEON is not set +# CONFIG_FB_RIVA is not set +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_S3 is not set +# CONFIG_FB_SAVAGE is not set +# CONFIG_FB_SIMPLE is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_SM7XX is not set +# CONFIG_FB_SMSCUFX is not set +# CONFIG_FB_SSD1307 is not set +# CONFIG_FB_SVGALIB is not set +# CONFIG_FB_SYS_COPYAREA is not set +# CONFIG_FB_SYS_FILLRECT is not set +# CONFIG_FB_SYS_FOPS is not set +# CONFIG_FB_SYS_IMAGEBLIT is not set +# CONFIG_FB_TILEBLITTING is not set +# CONFIG_FB_TMIO is not set +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_UDL is not set +# CONFIG_FB_UVESA is not set +# CONFIG_FB_VGA16 is not set +# CONFIG_FB_VIA is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_VT8623 is not set +# CONFIG_FB_XGI is not set +# CONFIG_FCOE is not set +# CONFIG_FCOE_FNIC is not set +# CONFIG_FDDI is not set +# CONFIG_FEALNX is not set +# CONFIG_FENCE_TRACE is not set +# CONFIG_FHANDLE is not set +CONFIG_FIB_RULES=y +CONFIG_FILE_LOCKING=y +# CONFIG_FIREWIRE is not set +# CONFIG_FIREWIRE_NOSY is not set +# CONFIG_FIREWIRE_SERIAL is not set +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FIRMWARE_IN_KERNEL is not set +# CONFIG_FIRMWARE_MEMMAP is not set +# CONFIG_FIXED_PHY is not set +CONFIG_FLATMEM=y +CONFIG_FLATMEM_MANUAL=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_FM10K is not set +# CONFIG_FMC is not set +# CONFIG_FORCEDETH is not set +CONFIG_FORCE_MAX_ZONEORDER=11 +# CONFIG_FRAMEBUFFER_CONSOLE is not set +# CONFIG_FRAME_POINTER is not set +CONFIG_FRAME_WARN=1024 +# CONFIG_FREEZER is not set +# CONFIG_FRONTSWAP is not set +# CONFIG_FSCACHE is not set +# CONFIG_FSL_EDMA is not set +# CONFIG_FSL_XGMAC_MDIO is not set +CONFIG_FSNOTIFY=y +# CONFIG_FS_POSIX_ACL is not set +# CONFIG_FT1000 is not set +# CONFIG_FTGMAC100 is not set +# CONFIG_FTL is not set +# CONFIG_FTMAC100 is not set +# CONFIG_FTRACE is not set +# CONFIG_FTRACE_STARTUP_TEST is not set +# CONFIG_FTR_FIXUP_SELFTEST is not set +# CONFIG_FUJITSU_TABLET is not set +# CONFIG_FUNCTION_TRACER is not set +# CONFIG_FUSE_FS is not set +# CONFIG_FUSION is not set +# CONFIG_FUSION_FC is not set +# CONFIG_FUSION_SAS is not set +# CONFIG_FUSION_SPI is not set +CONFIG_FUTEX=y +CONFIG_FW_LOADER=y +CONFIG_FW_LOADER_USER_HELPER=y +CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y +CONFIG_GACT_PROB=y +# CONFIG_GADGET_UAC1 is not set +# CONFIG_GAMEPORT is not set +# CONFIG_GCOV is not set +# CONFIG_GCOV_KERNEL is not set +# CONFIG_GENEVE is not set +# CONFIG_GENERIC_ADC_BATTERY is not set +CONFIG_GENERIC_CALIBRATE_DELAY=y +# CONFIG_GENERIC_CPU_DEVICES is not set +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_NET_UTILS=y +# CONFIG_GENERIC_PHY is not set +CONFIG_GENERIC_TIME=y +# CONFIG_GENWQE is not set +# CONFIG_GFS2_FS is not set +# CONFIG_GIGASET_CAPI is not set +# CONFIG_GIGASET_DEBUG is not set +# CONFIG_GP2AP020A00F is not set +# CONFIG_GPIOLIB is not set +# CONFIG_GPIO_74X164 is not set +# CONFIG_GPIO_74XX_MMIO is not set +# CONFIG_GPIO_ADNP is not set +# CONFIG_GPIO_ADP5588 is not set +# CONFIG_GPIO_AMD8111 is not set +# CONFIG_GPIO_BCM_KONA is not set +# CONFIG_GPIO_BT8XX is not set +# CONFIG_GPIO_CS5535 is not set +# CONFIG_GPIO_DWAPB is not set +# CONFIG_GPIO_EM is not set +# CONFIG_GPIO_GENERIC_PLATFORM is not set +# CONFIG_GPIO_GRGPIO is not set +# CONFIG_GPIO_ICH is not set +# CONFIG_GPIO_IT8761E is not set +# CONFIG_GPIO_LANGWELL is not set +# CONFIG_GPIO_MAX7300 is not set +# CONFIG_GPIO_MAX7301 is not set +# CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_MC33880 is not set +# CONFIG_GPIO_MCP23S08 is not set +# CONFIG_GPIO_ML_IOH is not set +# CONFIG_GPIO_PCA953X is not set +# CONFIG_GPIO_PCF857X is not set +# CONFIG_GPIO_PCH is not set +# CONFIG_GPIO_PL061 is not set +# CONFIG_GPIO_RCAR is not set +# CONFIG_GPIO_RDC321X is not set +# CONFIG_GPIO_SCH is not set +# CONFIG_GPIO_SCH311X is not set +# CONFIG_GPIO_SX150X is not set +# CONFIG_GPIO_SYSCON is not set +# CONFIG_GPIO_SYSFS is not set +# CONFIG_GPIO_TS5500 is not set +# CONFIG_GPIO_VX855 is not set +# CONFIG_GPIO_WATCHDOG is not set +# CONFIG_GPIO_WDT is not set +# CONFIG_GPIO_XILINX is not set +# CONFIG_GPIO_ZEVIO is not set +# CONFIG_GREENASIA_FF is not set +# CONFIG_HAMACHI is not set +# CONFIG_HAMRADIO is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_HARDLOCKUP_DETECTOR is not set +# CONFIG_HAVE_AOUT is not set +# CONFIG_HAVE_ARM_ARCH_TIMER is not set +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +# CONFIG_HCALL_STATS is not set +# CONFIG_HDLC is not set +# CONFIG_HDLC_CISCO is not set +# CONFIG_HDLC_FR is not set +# CONFIG_HDLC_PPP is not set +# CONFIG_HDLC_RAW is not set +# CONFIG_HDLC_RAW_ETH is not set +# CONFIG_HDQ_MASTER_OMAP is not set +# CONFIG_HEADERS_CHECK is not set +# CONFIG_HERMES is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_HFSPLUS_FS_POSIX_ACL is not set +# CONFIG_HFS_FS is not set +# CONFIG_HIBERNATION is not set +# CONFIG_HID is not set +# CONFIG_HIDRAW is not set +# CONFIG_HID_A4TECH is not set +# CONFIG_HID_ACRUX is not set +# CONFIG_HID_ACRUX_FF is not set +# CONFIG_HID_APPLE is not set +# CONFIG_HID_APPLEIR is not set +# CONFIG_HID_AUREAL is not set +# CONFIG_HID_BATTERY_STRENGTH is not set +# CONFIG_HID_BELKIN is not set +# CONFIG_HID_BETOP_FF is not set +# CONFIG_HID_CHERRY is not set +# CONFIG_HID_CHICONY is not set +# CONFIG_HID_CP2112 is not set +# CONFIG_HID_CYPRESS is not set +# CONFIG_HID_DRAGONRISE is not set +# CONFIG_HID_ELECOM is not set +# CONFIG_HID_ELO is not set +# CONFIG_HID_EMS_FF is not set +# CONFIG_HID_EZKEY is not set +# CONFIG_HID_GENERIC is not set +# CONFIG_HID_GREENASIA is not set +# CONFIG_HID_GT683R is not set +# CONFIG_HID_GYRATION is not set +# CONFIG_HID_HOLTEK is not set +# CONFIG_HID_HUION is not set +# CONFIG_HID_ICADE is not set +# CONFIG_HID_KENSINGTON is not set +# CONFIG_HID_KEYTOUCH is not set +# CONFIG_HID_KYE is not set +# CONFIG_HID_LCPOWER is not set +# CONFIG_HID_LENOVO is not set +# CONFIG_HID_LENOVO_TPKBD is not set +# CONFIG_HID_LOGITECH is not set +# CONFIG_HID_LOGITECH_DJ is not set +# CONFIG_HID_LOGITECH_HIDPP is not set +# CONFIG_HID_MAGICMOUSE is not set +# CONFIG_HID_MICROSOFT is not set +# CONFIG_HID_MONTEREY is not set +# CONFIG_HID_MULTITOUCH is not set +# CONFIG_HID_NTRIG is not set +# CONFIG_HID_ORTEK is not set +# CONFIG_HID_PANTHERLORD is not set +# CONFIG_HID_PENMOUNT is not set +# CONFIG_HID_PETALYNX is not set +# CONFIG_HID_PICOLCD is not set +# CONFIG_HID_PID is not set +# CONFIG_HID_PLANTRONICS is not set +# CONFIG_HID_PRIMAX is not set +# CONFIG_HID_PRODIKEYS is not set +# CONFIG_HID_PS3REMOTE is not set +# CONFIG_HID_QUANTA is not set +# CONFIG_HID_RMI is not set +# CONFIG_HID_ROCCAT is not set +# CONFIG_HID_ROCCAT_ARVO is not set +# CONFIG_HID_ROCCAT_KONE is not set +# CONFIG_HID_ROCCAT_KONEPLUS is not set +# CONFIG_HID_ROCCAT_KOVAPLUS is not set +# CONFIG_HID_ROCCAT_PYRA is not set +# CONFIG_HID_SAITEK is not set +# CONFIG_HID_SAMSUNG is not set +# CONFIG_HID_SENSOR_HUB is not set +# CONFIG_HID_SMARTJOYPLUS is not set +# CONFIG_HID_SONY is not set +# CONFIG_HID_SPEEDLINK is not set +# CONFIG_HID_STEELSERIES is not set +# CONFIG_HID_SUNPLUS is not set +# CONFIG_HID_SUPPORT is not set +# CONFIG_HID_THINGM is not set +# CONFIG_HID_THRUSTMASTER is not set +# CONFIG_HID_TIVO is not set +# CONFIG_HID_TOPSEED is not set +# CONFIG_HID_TWINHAN is not set +# CONFIG_HID_UCLOGIC is not set +# CONFIG_HID_WACOM is not set +# CONFIG_HID_WALTOP is not set +# CONFIG_HID_WIIMOTE is not set +# CONFIG_HID_XINMO is not set +# CONFIG_HID_ZEROPLUS is not set +# CONFIG_HID_ZYDACRON is not set +# CONFIG_HIGHMEM is not set +CONFIG_HIGH_RES_TIMERS=y +# CONFIG_HIP04_ETH is not set +# CONFIG_HIPPI is not set +# CONFIG_HIX5HD2_GMAC is not set +# CONFIG_HMC6352 is not set +# CONFIG_HOSTAP is not set +# CONFIG_HOSTAP_CS is not set +# CONFIG_HOSTAP_PCI is not set +# CONFIG_HOSTAP_PLX is not set +CONFIG_HOTPLUG=y +# CONFIG_HOTPLUG_CPU is not set +# CONFIG_HOTPLUG_PCI is not set +# CONFIG_HP100 is not set +CONFIG_HPET_MMAP_DEFAULT=y +# CONFIG_HPFS_FS is not set +# CONFIG_HPLAN is not set +# CONFIG_HPLAN_PLUS is not set +# CONFIG_HP_ILO is not set +# CONFIG_HP_WIRELESS is not set +# CONFIG_HSI is not set +# CONFIG_HSR is not set +# CONFIG_HTC_EGPIO is not set +# CONFIG_HTC_I2CPLD is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_HUGETLB_PAGE is not set +# CONFIG_HVC_DCC is not set +# CONFIG_HVC_UDBG is not set +# CONFIG_HWMON is not set +# CONFIG_HWMON_DEBUG_CHIP is not set +# CONFIG_HWMON_VID is not set +# CONFIG_HWSPINLOCK_OMAP is not set +CONFIG_HW_PERF_EVENTS=y +# CONFIG_HW_RANDOM is not set +# CONFIG_HW_RANDOM_AMD is not set +# CONFIG_HW_RANDOM_ATMEL is not set +# CONFIG_HW_RANDOM_EXYNOS is not set +# CONFIG_HW_RANDOM_GEODE is not set +# CONFIG_HW_RANDOM_INTEL is not set +# CONFIG_HW_RANDOM_OMAP3_ROM is not set +# CONFIG_HW_RANDOM_PPC4XX is not set +# CONFIG_HW_RANDOM_TIMERIOMEM is not set +# CONFIG_HW_RANDOM_VIA is not set +# CONFIG_HYPERV is not set +# CONFIG_HYSDN is not set +CONFIG_HZ=100 +CONFIG_HZ_100=y +# CONFIG_HZ_1000 is not set +# CONFIG_HZ_1024 is not set +# CONFIG_HZ_128 is not set +# CONFIG_HZ_200 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_256 is not set +# CONFIG_HZ_300 is not set +# CONFIG_HZ_48 is not set +# CONFIG_HZ_500 is not set +# CONFIG_HZ_PERIODIC is not set +# CONFIG_I2C is not set +# CONFIG_I2C_ALGOBIT is not set +# CONFIG_I2C_ALGOPCA is not set +# CONFIG_I2C_ALGOPCF is not set +# CONFIG_I2C_ALI1535 is not set +# CONFIG_I2C_ALI1563 is not set +# CONFIG_I2C_ALI15X3 is not set +# CONFIG_I2C_AMD756 is not set +# CONFIG_I2C_AMD8111 is not set +# CONFIG_I2C_ARB_GPIO_CHALLENGE is not set +# CONFIG_I2C_AU1550 is not set +# CONFIG_I2C_BCM2835 is not set +# CONFIG_I2C_CBUS_GPIO is not set +# CONFIG_I2C_CHARDEV is not set +# CONFIG_I2C_COMPAT is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DESIGNWARE is not set +# CONFIG_I2C_DESIGNWARE_PCI is not set +# CONFIG_I2C_DESIGNWARE_PLATFORM is not set +# CONFIG_I2C_DIOLAN_U2C is not set +# CONFIG_I2C_EG20T is not set +# CONFIG_I2C_ELEKTOR is not set +# CONFIG_I2C_GPIO is not set +# CONFIG_I2C_HELPER_AUTO is not set +# CONFIG_I2C_HID is not set +# CONFIG_I2C_I801 is not set +# CONFIG_I2C_IBM_IIC is not set +# CONFIG_I2C_INTEL_MID is not set +# CONFIG_I2C_ISCH is not set +# CONFIG_I2C_ISMT is not set +# CONFIG_I2C_MPC is not set +# CONFIG_I2C_MUX is not set +# CONFIG_I2C_MUX_PINCTRL is not set +# CONFIG_I2C_MV64XXX is not set +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_NOMADIK is not set +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_OCTEON is not set +# CONFIG_I2C_PARPORT is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_PCA_ISA is not set +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_PIIX4 is not set +# CONFIG_I2C_PXA_PCI is not set +# CONFIG_I2C_RCAR is not set +# CONFIG_I2C_RK3X is not set +# CONFIG_I2C_ROBOTFUZZ_OSIF is not set +# CONFIG_I2C_SCMI is not set +# CONFIG_I2C_SH_MOBILE is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_SLAVE is not set +# CONFIG_I2C_SMBUS is not set +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_TINY_USB is not set +# CONFIG_I2C_VERSATILE is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set +# CONFIG_I2C_XILINX is not set +# CONFIG_I2O is not set +# CONFIG_I40E is not set +# CONFIG_I40EVF is not set +# CONFIG_I6300ESB_WDT is not set +# CONFIG_I82092 is not set +# CONFIG_I82365 is not set +# CONFIG_IBM_ASM is not set +# CONFIG_IBM_EMAC_DEBUG is not set +# CONFIG_IBM_EMAC_EMAC4 is not set +# CONFIG_IBM_EMAC_MAL_CLR_ICINTSTAT is not set +# CONFIG_IBM_EMAC_MAL_COMMON_ERR is not set +# CONFIG_IBM_EMAC_NO_FLOW_CTRL is not set +# CONFIG_IBM_EMAC_RGMII is not set +# CONFIG_IBM_EMAC_TAH is not set +# CONFIG_IBM_EMAC_ZMII is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_ICS932S401 is not set +# CONFIG_IDE is not set +# CONFIG_IDEAPAD_LAPTOP is not set +# CONFIG_IDE_GD is not set +# CONFIG_IDE_PHISON is not set +# CONFIG_IDE_PROC_FS is not set +# CONFIG_IDE_TASK_IOCTL is not set +# CONFIG_IEEE802154 is not set +# CONFIG_IFB is not set +# CONFIG_IGB is not set +# CONFIG_IGBVF is not set +# CONFIG_IIO is not set +# CONFIG_IIO_BUFFER_CB is not set +CONFIG_IIO_CONSUMERS_PER_TRIGGER=2 +# CONFIG_IIO_GPIO_TRIGGER is not set +# CONFIG_IIO_INTERRUPT_TRIGGER is not set +# CONFIG_IIO_PERIODIC_RTC_TRIGGER is not set +# CONFIG_IIO_SIMPLE_DUMMY is not set +# CONFIG_IIO_SSP_SENSORHUB is not set +# CONFIG_IIO_ST_ACCEL_3AXIS is not set +# CONFIG_IIO_ST_GYRO_3AXIS is not set +# CONFIG_IIO_ST_MAGN_3AXIS is not set +# CONFIG_IIO_ST_PRESS is not set +# CONFIG_IIO_SYSFS_TRIGGER is not set +# CONFIG_IKCONFIG is not set +# CONFIG_IKCONFIG_PROC is not set +# CONFIG_IMAGE_CMDLINE_HACK is not set +# CONFIG_IMGPDC_WDT is not set +# CONFIG_IMX_IPUV3_CORE is not set +CONFIG_INET=y +# CONFIG_INET6_AH is not set +# CONFIG_INET6_ESP is not set +# CONFIG_INET6_IPCOMP is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_INET6_XFRM_MODE_BEET is not set +# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set +# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET6_XFRM_MODE_TUNNEL is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_DIAG is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_LRO is not set +# CONFIG_INET_TCP_DIAG is not set +# CONFIG_INET_TUNNEL is not set +# CONFIG_INET_UDP_DIAG is not set +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET_XFRM_MODE_TUNNEL is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INFINIBAND is not set +# CONFIG_INFTL is not set +# CONFIG_INITRAMFS_COMPRESSION_BZIP2 is not set +# CONFIG_INITRAMFS_COMPRESSION_GZIP is not set +# CONFIG_INITRAMFS_COMPRESSION_LZMA is not set +CONFIG_INITRAMFS_COMPRESSION_NONE=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +# CONFIG_INIT_FALLBACK is not set +# CONFIG_INLINE_READ_LOCK is not set +# CONFIG_INLINE_READ_LOCK_BH is not set +# CONFIG_INLINE_READ_LOCK_IRQ is not set +# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set +# CONFIG_INLINE_READ_TRYLOCK is not set +CONFIG_INLINE_READ_UNLOCK=y +# CONFIG_INLINE_READ_UNLOCK_BH is not set +CONFIG_INLINE_READ_UNLOCK_IRQ=y +# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_SPIN_LOCK is not set +# CONFIG_INLINE_SPIN_LOCK_BH is not set +# CONFIG_INLINE_SPIN_LOCK_IRQ is not set +# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set +# CONFIG_INLINE_SPIN_TRYLOCK is not set +# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set +CONFIG_INLINE_SPIN_UNLOCK=y +# CONFIG_INLINE_SPIN_UNLOCK_BH is not set +CONFIG_INLINE_SPIN_UNLOCK_IRQ=y +# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_WRITE_LOCK is not set +# CONFIG_INLINE_WRITE_LOCK_BH is not set +# CONFIG_INLINE_WRITE_LOCK_IRQ is not set +# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set +# CONFIG_INLINE_WRITE_TRYLOCK is not set +CONFIG_INLINE_WRITE_UNLOCK=y +# CONFIG_INLINE_WRITE_UNLOCK_BH is not set +CONFIG_INLINE_WRITE_UNLOCK_IRQ=y +# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set +CONFIG_INOTIFY_USER=y +# CONFIG_INPUT is not set +# CONFIG_INPUT_AD714X is not set +# CONFIG_INPUT_ADXL34X is not set +# CONFIG_INPUT_APANEL is not set +# CONFIG_INPUT_ATI_REMOTE is not set +# CONFIG_INPUT_ATI_REMOTE2 is not set +# CONFIG_INPUT_ATLAS_BTNS is not set +# CONFIG_INPUT_BMA150 is not set +# CONFIG_INPUT_CM109 is not set +# CONFIG_INPUT_CMA3000 is not set +# CONFIG_INPUT_DRV260X_HAPTICS is not set +# CONFIG_INPUT_DRV2667_HAPTICS is not set +# CONFIG_INPUT_EVBUG is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_E3X0_BUTTON is not set +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_GP2A is not set +# CONFIG_INPUT_GPIO_BEEPER is not set +# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set +# CONFIG_INPUT_GPIO_TILT_POLLED is not set +# CONFIG_INPUT_IDEAPAD_SLIDEBAR is not set +# CONFIG_INPUT_IMS_PCU is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_KEYSPAN_REMOTE is not set +# CONFIG_INPUT_KXTJ9 is not set +# CONFIG_INPUT_MATRIXKMAP is not set +CONFIG_INPUT_MISC=y +# CONFIG_INPUT_MMA8450 is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_MPU3050 is not set +# CONFIG_INPUT_PCF8574 is not set +# CONFIG_INPUT_PCSPKR is not set +# CONFIG_INPUT_POLLDEV is not set +# CONFIG_INPUT_POWERMATE is not set +# CONFIG_INPUT_PWM_BEEPER is not set +# CONFIG_INPUT_REGULATOR_HAPTIC is not set +# CONFIG_INPUT_SOC_BUTTON_ARRAY is not set +# CONFIG_INPUT_SPARSEKMAP is not set +# CONFIG_INPUT_TABLET is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_UINPUT is not set +# CONFIG_INPUT_WISTRON_BTNS is not set +# CONFIG_INPUT_YEALINK is not set +# CONFIG_INT340X_THERMAL is not set +# CONFIG_INTEL_IDLE is not set +# CONFIG_INTEL_MEI is not set +# CONFIG_INTEL_MEI_ME is not set +# CONFIG_INTEL_MEI_TXE is not set +# CONFIG_INTEL_MIC_CARD is not set +# CONFIG_INTEL_MIC_HOST is not set +# CONFIG_INTEL_MID_PTI is not set +# CONFIG_INTEL_OAKTRAIL is not set +# CONFIG_INTEL_RST is not set +# CONFIG_INTEL_SMARTCONNECT is not set +# CONFIG_INTEL_SOC_PMIC is not set +# CONFIG_INTERVAL_TREE_TEST is not set +# CONFIG_INV_MPU6050_IIO is not set +# CONFIG_IOMMU_SUPPORT is not set +# CONFIG_IOSCHED_CFQ is not set +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_NOOP=y +# CONFIG_IP1000 is not set +# CONFIG_IP17XX_PHY is not set +# CONFIG_IP6_NF_FILTER is not set +# CONFIG_IP6_NF_IPTABLES is not set +# CONFIG_IP6_NF_MANGLE is not set +# CONFIG_IP6_NF_MATCH_AH is not set +# CONFIG_IP6_NF_MATCH_EUI64 is not set +# CONFIG_IP6_NF_MATCH_FRAG is not set +# CONFIG_IP6_NF_MATCH_HL is not set +# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set +# CONFIG_IP6_NF_MATCH_MH is not set +# CONFIG_IP6_NF_MATCH_OPTS is not set +# CONFIG_IP6_NF_MATCH_RPFILTER is not set +# CONFIG_IP6_NF_MATCH_RT is not set +# CONFIG_IP6_NF_NAT is not set +# CONFIG_IP6_NF_QUEUE is not set +# CONFIG_IP6_NF_RAW is not set +# CONFIG_IP6_NF_TARGET_HL is not set +# CONFIG_IP6_NF_TARGET_LOG is not set +# CONFIG_IP6_NF_TARGET_REJECT is not set +# CONFIG_IP6_NF_TARGET_SYNPROXY is not set +# CONFIG_IPACK_BUS is not set +# CONFIG_IPC_NS is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_IPV6 is not set +# CONFIG_IPV6_MIP6 is not set +# CONFIG_IPV6_MROUTE is not set +# CONFIG_IPV6_MROUTE_MULTIPLE_TABLES is not set +# CONFIG_IPV6_MULTIPLE_TABLES is not set +CONFIG_IPV6_NDISC_NODETYPE=y +# CONFIG_IPV6_OPTIMISTIC_DAD is not set +# CONFIG_IPV6_PRIVACY is not set +# CONFIG_IPV6_ROUTER_PREF is not set +# CONFIG_IPV6_ROUTE_INFO is not set +# CONFIG_IPV6_SIT is not set +# CONFIG_IPV6_SIT_6RD is not set +# CONFIG_IPV6_TUNNEL is not set +# CONFIG_IPV6_VTI is not set +# CONFIG_IPVLAN is not set +# CONFIG_IPW2100 is not set +# CONFIG_IPW2100_DEBUG is not set +CONFIG_IPW2100_MONITOR=y +# CONFIG_IPW2200 is not set +# CONFIG_IPW2200_DEBUG is not set +CONFIG_IPW2200_MONITOR=y +# CONFIG_IPW2200_PROMISCUOUS is not set +# CONFIG_IPW2200_QOS is not set +# CONFIG_IPW2200_RADIOTAP is not set +# CONFIG_IPWIRELESS is not set +# CONFIG_IPX is not set +CONFIG_IP_ADVANCED_ROUTER=y +# CONFIG_IP_DCCP is not set +# CONFIG_IP_FIB_TRIE_STATS is not set +CONFIG_IP_MROUTE=y +CONFIG_IP_MROUTE_MULTIPLE_TABLES=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_MULTIPLE_TABLES=y +# CONFIG_IP_NF_ARPFILTER is not set +# CONFIG_IP_NF_ARPTABLES is not set +# CONFIG_IP_NF_ARP_MANGLE is not set +# CONFIG_IP_NF_FILTER is not set +# CONFIG_IP_NF_IPTABLES is not set +# CONFIG_IP_NF_MANGLE is not set +# CONFIG_IP_NF_MATCH_AH is not set +# CONFIG_IP_NF_MATCH_ECN is not set +# CONFIG_IP_NF_MATCH_RPFILTER is not set +# CONFIG_IP_NF_MATCH_TTL is not set +# CONFIG_IP_NF_QUEUE is not set +# CONFIG_IP_NF_RAW is not set +# CONFIG_IP_NF_SECURITY is not set +# CONFIG_IP_NF_TARGET_CLUSTERIP is not set +# CONFIG_IP_NF_TARGET_ECN is not set +# CONFIG_IP_NF_TARGET_LOG is not set +# CONFIG_IP_NF_TARGET_MASQUERADE is not set +# CONFIG_IP_NF_TARGET_NETMAP is not set +# CONFIG_IP_NF_TARGET_REDIRECT is not set +# CONFIG_IP_NF_TARGET_REJECT is not set +# CONFIG_IP_NF_TARGET_SYNPROXY is not set +# CONFIG_IP_NF_TARGET_TTL is not set +# CONFIG_IP_NF_TARGET_ULOG is not set +# CONFIG_IP_PIMSM_V1 is not set +# CONFIG_IP_PIMSM_V2 is not set +# CONFIG_IP_PNP is not set +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_VERBOSE=y +# CONFIG_IP_SCTP is not set +# CONFIG_IP_SET is not set +# CONFIG_IP_VS is not set +# CONFIG_IRDA is not set +# CONFIG_IRQSOFF_TRACER is not set +# CONFIG_IRQ_ALL_CPUS is not set +# CONFIG_IRQ_DOMAIN_DEBUG is not set +# CONFIG_IRQ_TIME_ACCOUNTING is not set +# CONFIG_IR_GPIO_CIR is not set +# CONFIG_IR_HIX5HD2 is not set +# CONFIG_IR_IGUANA is not set +# CONFIG_IR_IMG is not set +# CONFIG_IR_IMON is not set +# CONFIG_IR_JVC_DECODER is not set +# CONFIG_IR_LIRC_CODEC is not set +# CONFIG_IR_MCEUSB is not set +# CONFIG_IR_NEC_DECODER is not set +# CONFIG_IR_RC5_DECODER is not set +# CONFIG_IR_RC5_SZ_DECODER is not set +# CONFIG_IR_RC6_DECODER is not set +# CONFIG_IR_REDRAT3 is not set +# CONFIG_IR_SONY_DECODER is not set +# CONFIG_IR_STREAMZAP is not set +# CONFIG_IR_TTUSBIR is not set +# CONFIG_ISCSI_BOOT_SYSFS is not set +# CONFIG_ISCSI_TCP is not set +CONFIG_ISDN=y +# CONFIG_ISDN_AUDIO is not set +# CONFIG_ISDN_CAPI is not set +# CONFIG_ISDN_CAPI_CAPIDRV is not set +# CONFIG_ISDN_DIVERSION is not set +# CONFIG_ISDN_DRV_ACT2000 is not set +# CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON is not set +# CONFIG_ISDN_DRV_GIGASET is not set +# CONFIG_ISDN_DRV_HISAX is not set +# CONFIG_ISDN_DRV_ICN is not set +# CONFIG_ISDN_DRV_LOOP is not set +# CONFIG_ISDN_DRV_PCBIT is not set +# CONFIG_ISDN_DRV_SC is not set +# CONFIG_ISDN_I4L is not set +# CONFIG_ISL29003 is not set +# CONFIG_ISL29020 is not set +# CONFIG_ISL29125 is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_ISS4xx is not set +# CONFIG_ITG3200 is not set +# CONFIG_IWL3945 is not set +# CONFIG_IWLAGN is not set +# CONFIG_IWLWIFI is not set +# CONFIG_IWMC3200TOP is not set +# CONFIG_IXGB is not set +# CONFIG_IXGBE is not set +# CONFIG_IXGBEVF is not set +# CONFIG_JBD is not set +# CONFIG_JBD2_DEBUG is not set +# CONFIG_JBD_DEBUG is not set +# CONFIG_JFFS2_CMODE_FAVOURLZO is not set +# CONFIG_JFFS2_CMODE_NONE is not set +CONFIG_JFFS2_CMODE_PRIORITY=y +# CONFIG_JFFS2_CMODE_SIZE is not set +CONFIG_JFFS2_COMPRESSION_OPTIONS=y +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +# CONFIG_JFFS2_FS_POSIX_ACL is not set +# CONFIG_JFFS2_FS_SECURITY is not set +# CONFIG_JFFS2_FS_WBUF_VERIFY is not set +CONFIG_JFFS2_FS_WRITEBUFFER=y +CONFIG_JFFS2_FS_XATTR=y +CONFIG_JFFS2_LZMA=y +# CONFIG_JFFS2_LZO is not set +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +CONFIG_JFFS2_SUMMARY=y +# CONFIG_JFFS2_ZLIB is not set +# CONFIG_JFS_DEBUG is not set +# CONFIG_JFS_FS is not set +# CONFIG_JFS_POSIX_ACL is not set +# CONFIG_JFS_SECURITY is not set +# CONFIG_JFS_STATISTICS is not set +# CONFIG_JME is not set +CONFIG_JOLIET=y +# CONFIG_JSA1212 is not set +# CONFIG_JUMP_LABEL is not set +# CONFIG_KALLSYMS is not set +# CONFIG_KALLSYMS_ALL is not set +# CONFIG_KALLSYMS_UNCOMPRESSED is not set +# CONFIG_KARMA_PARTITION is not set +# CONFIG_KERNEL_BZIP2 is not set +# CONFIG_KERNEL_GZIP is not set +# CONFIG_KERNEL_LZ4 is not set +# CONFIG_KERNEL_LZMA is not set +# CONFIG_KERNEL_LZO is not set +CONFIG_KERNEL_MODE_NEON=y +CONFIG_KERNEL_XZ=y +CONFIG_KERNFS=y +# CONFIG_KEXEC is not set +# CONFIG_KEYBOARD_ADP5588 is not set +# CONFIG_KEYBOARD_ADP5589 is not set +# CONFIG_KEYBOARD_ATKBD is not set +# CONFIG_KEYBOARD_CAP1106 is not set +# CONFIG_KEYBOARD_GPIO_POLLED is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_LM8323 is not set +# CONFIG_KEYBOARD_LM8333 is not set +# CONFIG_KEYBOARD_MATRIX is not set +# CONFIG_KEYBOARD_MAX7359 is not set +# CONFIG_KEYBOARD_MCS is not set +# CONFIG_KEYBOARD_MPR121 is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_OMAP4 is not set +# CONFIG_KEYBOARD_OPENCORES is not set +# CONFIG_KEYBOARD_PXA27x is not set +# CONFIG_KEYBOARD_QT1070 is not set +# CONFIG_KEYBOARD_QT2160 is not set +# CONFIG_KEYBOARD_SAMSUNG is not set +# CONFIG_KEYBOARD_SH_KEYSC is not set +# CONFIG_KEYBOARD_STOWAWAY is not set +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_TCA6416 is not set +# CONFIG_KEYBOARD_TCA8418 is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_CAP11XX is not set +# CONFIG_KEYS is not set +# CONFIG_KEYS_DEBUG_PROC_KEYS is not set +# CONFIG_KGDB is not set +# CONFIG_KMEMCHECK is not set +# CONFIG_KMX61 is not set +# CONFIG_KPROBES is not set +# CONFIG_KPROBES_SANITY_TEST is not set +# CONFIG_KS8842 is not set +# CONFIG_KS8851 is not set +# CONFIG_KS8851_MLL is not set +# CONFIG_KSM is not set +# CONFIG_KSZ884X_PCI is not set +CONFIG_KUSER_HELPERS=y +# CONFIG_KVM_GUEST is not set +# CONFIG_KXCJK1013 is not set +# CONFIG_KXSD9 is not set +# CONFIG_L2TP is not set +# CONFIG_L2TP_ETH is not set +# CONFIG_L2TP_IP is not set +# CONFIG_L2TP_V3 is not set +# CONFIG_LANMEDIA is not set +# CONFIG_LANTIQ is not set +# CONFIG_LAPB is not set +# CONFIG_LASAT is not set +# CONFIG_LATENCYTOP is not set +# CONFIG_LATTICE_ECP3_CONFIG is not set +CONFIG_LBDAF=y +# CONFIG_LCD_HX8357 is not set +# CONFIG_LCD_ILI922X is not set +# CONFIG_LCD_ILI9320 is not set +# CONFIG_LCD_LMS501KF03 is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_LEDS_ATMEL_PWM is not set +# CONFIG_LEDS_BD2802 is not set +# CONFIG_LEDS_BLINKM is not set +CONFIG_LEDS_CLASS=y +# CONFIG_LEDS_CLASS_FLASH is not set +# CONFIG_LEDS_DAC124S085 is not set +# CONFIG_LEDS_GPIO is not set +CONFIG_LEDS_GPIO_OF=y +CONFIG_LEDS_GPIO_PLATFORM=y +# CONFIG_LEDS_INTEL_SS4200 is not set +# CONFIG_LEDS_LM3530 is not set +# CONFIG_LEDS_LM3556 is not set +# CONFIG_LEDS_LM355x is not set +# CONFIG_LEDS_LM3642 is not set +# CONFIG_LEDS_LP3944 is not set +# CONFIG_LEDS_LP5521 is not set +# CONFIG_LEDS_LP5523 is not set +# CONFIG_LEDS_LP5562 is not set +# CONFIG_LEDS_LP8501 is not set +# CONFIG_LEDS_LP8860 is not set +# CONFIG_LEDS_LT3593 is not set +# CONFIG_LEDS_NET5501 is not set +# CONFIG_LEDS_OT200 is not set +# CONFIG_LEDS_PCA9532 is not set +# CONFIG_LEDS_PCA955X is not set +# CONFIG_LEDS_PCA9633 is not set +# CONFIG_LEDS_PCA963X is not set +# CONFIG_LEDS_PCA9685 is not set +# CONFIG_LEDS_PWM is not set +# CONFIG_LEDS_RENESAS_TPU is not set +# CONFIG_LEDS_SYSCON is not set +# CONFIG_LEDS_TCA6507 is not set +CONFIG_LEDS_TRIGGERS=y +# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set +# CONFIG_LEDS_TRIGGER_CAMERA is not set +# CONFIG_LEDS_TRIGGER_CPU is not set +CONFIG_LEDS_TRIGGER_DEFAULT_ON=y +# CONFIG_LEDS_TRIGGER_GPIO is not set +# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set +# CONFIG_LEDS_TRIGGER_IDE_DISK is not set +# CONFIG_LEDS_TRIGGER_MORSE is not set +CONFIG_LEDS_TRIGGER_NETDEV=y +# CONFIG_LEDS_TRIGGER_ONESHOT is not set +CONFIG_LEDS_TRIGGER_TIMER=y +# CONFIG_LEDS_TRIGGER_TRANSIENT is not set +# CONFIG_LEDS_TRIGGER_USBDEV is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_LIB80211 is not set +# CONFIG_LIB80211_CRYPT_CCMP is not set +# CONFIG_LIB80211_CRYPT_TKIP is not set +# CONFIG_LIB80211_CRYPT_WEP is not set +# CONFIG_LIB80211_DEBUG is not set +# CONFIG_LIBCRC32C is not set +# CONFIG_LIBERTAS is not set +# CONFIG_LIBERTAS_THINFIRM is not set +# CONFIG_LIBERTAS_USB is not set +# CONFIG_LIBFC is not set +# CONFIG_LIBFCOE is not set +# CONFIG_LIBIPW_DEBUG is not set +# CONFIG_LINE6_USB is not set +# CONFIG_LIRC_STAGING is not set +# CONFIG_LIS3L02DQ is not set +# CONFIG_LKDTM is not set +CONFIG_LLC=y +# CONFIG_LLC2 is not set +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +# CONFIG_LOCKD is not set +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_LOCKD_V4=y +# CONFIG_LOCKUP_DETECTOR is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_LOCK_TORTURE_TEST is not set +# CONFIG_LOGFS is not set +# CONFIG_LOGIG940_FF is not set +# CONFIG_LOGIRUMBLEPAD2_FF is not set +# CONFIG_LOGITECH_FF is not set +# CONFIG_LOGIWHEELS_FF is not set +# CONFIG_LOGO is not set +CONFIG_LOG_BUF_SHIFT=17 +CONFIG_LOG_CPU_MAX_BUF_SHIFT=12 +# CONFIG_LOONGSON_MC146818 is not set +# CONFIG_LP486E is not set +# CONFIG_LPC_ICH is not set +# CONFIG_LPC_SCH is not set +# CONFIG_LP_CONSOLE is not set +# CONFIG_LSI_ET1011C_PHY is not set +# CONFIG_LTE_GDM724X is not set +# CONFIG_LTR501 is not set +# CONFIG_LTPC is not set +# CONFIG_LUSTRE_FS is not set +# CONFIG_LXT_PHY is not set +# CONFIG_LZ4HC_COMPRESS is not set +CONFIG_LZMA_COMPRESS=y +CONFIG_LZMA_DECOMPRESS=y +# CONFIG_LZO_COMPRESS is not set +# CONFIG_LZO_DECOMPRESS is not set +# CONFIG_M25PXX_PREFER_SMALL_SECTOR_ERASE is not set +# CONFIG_MAC80211 is not set +# CONFIG_MAC80211_MESSAGE_TRACING is not set +# CONFIG_MACB is not set +# CONFIG_MACH_ASM9260 is not set +# CONFIG_MACH_DECSTATION is not set +# CONFIG_MACH_JAZZ is not set +# CONFIG_MACH_JZ4740 is not set +# CONFIG_MACH_LOONGSON is not set +# CONFIG_MACH_LOONGSON1 is not set +# CONFIG_MACH_NO_WESTBRIDGE is not set +# CONFIG_MACH_TX39XX is not set +# CONFIG_MACH_TX49XX is not set +# CONFIG_MACH_VR41XX is not set +# CONFIG_MACINTOSH_DRIVERS is not set +# CONFIG_MACVLAN is not set +# CONFIG_MACVTAP is not set +# CONFIG_MAC_EMUMOUSEBTN is not set +# CONFIG_MAC_PARTITION is not set +# CONFIG_MAG3110 is not set +# CONFIG_MAGIC_SYSRQ is not set +CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1 +# CONFIG_MAILBOX is not set +# CONFIG_MANGLE_BOOTARGS is not set +# CONFIG_MARVELL_PHY is not set +# CONFIG_MAX1027 is not set +# CONFIG_MAX1363 is not set +# CONFIG_MAX517 is not set +# CONFIG_MAX5821 is not set +# CONFIG_MAX63XX_WATCHDOG is not set +# CONFIG_MCB is not set +# CONFIG_MCP320X is not set +# CONFIG_MCP3422 is not set +# CONFIG_MCP4725 is not set +# CONFIG_MCP4922 is not set +# CONFIG_MCPM is not set +# CONFIG_MD is not set +# CONFIG_MDIO_BCM_UNIMAC is not set +# CONFIG_MDIO_BITBANG is not set +# CONFIG_MDIO_BUS_MUX_GPIO is not set +# CONFIG_MDIO_BUS_MUX_MMIOREG is not set +# CONFIG_MD_FAULTY is not set +# CONFIG_MEDIA_ANALOG_TV_SUPPORT is not set +# CONFIG_MEDIA_ATTACH is not set +# CONFIG_MEDIA_CAMERA_SUPPORT is not set +# CONFIG_MEDIA_CONTROLLER is not set +# CONFIG_MEDIA_DIGITAL_TV_SUPPORT is not set +# CONFIG_MEDIA_PARPORT_SUPPORT is not set +# CONFIG_MEDIA_PCI_SUPPORT is not set +# CONFIG_MEDIA_RADIO_SUPPORT is not set +# CONFIG_MEDIA_RC_SUPPORT is not set +# CONFIG_MEDIA_SDR_SUPPORT is not set +# CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set +# CONFIG_MEDIA_SUPPORT is not set +# CONFIG_MEDIA_TUNER_CUSTOMISE is not set +# CONFIG_MEDIA_USB_SUPPORT is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_SAS is not set +# CONFIG_MEMORY is not set +# CONFIG_MEMORY_FAILURE is not set +# CONFIG_MEMSTICK is not set +# CONFIG_MEN_A21_WDT is not set +CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4 +# CONFIG_MFD_88PM800 is not set +# CONFIG_MFD_88PM805 is not set +# CONFIG_MFD_88PM860X is not set +# CONFIG_MFD_AAT2870_CORE is not set +# CONFIG_MFD_ARIZONA_I2C is not set +# CONFIG_MFD_ARIZONA_SPI is not set +# CONFIG_MFD_AS3711 is not set +# CONFIG_MFD_AS3722 is not set +# CONFIG_MFD_ASIC3 is not set +# CONFIG_MFD_ATMEL_HLCDC is not set +# CONFIG_MFD_AXP20X is not set +# CONFIG_MFD_BCM590XX is not set +# CONFIG_MFD_CORE is not set +# CONFIG_MFD_CROS_EC is not set +# CONFIG_MFD_CS5535 is not set +# CONFIG_MFD_DA9052_I2C is not set +# CONFIG_MFD_DA9052_SPI is not set +# CONFIG_MFD_DA9055 is not set +# CONFIG_MFD_DA9063 is not set +# CONFIG_MFD_DA9150 is not set +# CONFIG_MFD_DLN2 is not set +# CONFIG_MFD_HI6421_PMIC is not set +# CONFIG_MFD_JANZ_CMODIO is not set +# CONFIG_MFD_KEMPLD is not set +# CONFIG_MFD_LM3533 is not set +# CONFIG_MFD_LP3943 is not set +# CONFIG_MFD_LP8788 is not set +# CONFIG_MFD_MAX14577 is not set +# CONFIG_MFD_MAX77686 is not set +# CONFIG_MFD_MAX77693 is not set +# CONFIG_MFD_MAX8907 is not set +# CONFIG_MFD_MAX8925 is not set +# CONFIG_MFD_MAX8997 is not set +# CONFIG_MFD_MAX8998 is not set +# CONFIG_MFD_MC13783 is not set +# CONFIG_MFD_MC13XXX is not set +# CONFIG_MFD_MC13XXX_I2C is not set +# CONFIG_MFD_MC13XXX_SPI is not set +# CONFIG_MFD_MENF21BMC is not set +# CONFIG_MFD_OMAP_USB_HOST is not set +# CONFIG_MFD_PALMAS is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_MFD_PM8921_CORE is not set +# CONFIG_MFD_RC5T583 is not set +# CONFIG_MFD_RDC321X is not set +# CONFIG_MFD_RETU is not set +# CONFIG_MFD_RK808 is not set +# CONFIG_MFD_RN5T618 is not set +# CONFIG_MFD_RT5033 is not set +# CONFIG_MFD_RTSX_PCI is not set +# CONFIG_MFD_RTSX_USB is not set +# CONFIG_MFD_S5M_CORE is not set +# CONFIG_MFD_SEC_CORE is not set +# CONFIG_MFD_SI476X_CORE is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_SMSC is not set +# CONFIG_MFD_STMPE is not set +CONFIG_MFD_SUPPORT=y +# CONFIG_MFD_SYSCON is not set +# CONFIG_MFD_T7L66XB is not set +# CONFIG_MFD_TC3589X is not set +# CONFIG_MFD_TC6387XB is not set +# CONFIG_MFD_TC6393XB is not set +# CONFIG_MFD_TIMBERDALE is not set +# CONFIG_MFD_TI_AM335X_TSCADC is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_MFD_TPS65090 is not set +# CONFIG_MFD_TPS65217 is not set +# CONFIG_MFD_TPS65218 is not set +# CONFIG_MFD_TPS6586X is not set +# CONFIG_MFD_TPS65910 is not set +# CONFIG_MFD_TPS65912 is not set +# CONFIG_MFD_TPS65912_I2C is not set +# CONFIG_MFD_TPS65912_SPI is not set +# CONFIG_MFD_TPS80031 is not set +# CONFIG_MFD_VIPERBOARD is not set +# CONFIG_MFD_VX855 is not set +# CONFIG_MFD_WL1273_CORE is not set +# CONFIG_MFD_WM831X is not set +# CONFIG_MFD_WM831X_I2C is not set +# CONFIG_MFD_WM831X_SPI is not set +# CONFIG_MFD_WM8350_I2C is not set +# CONFIG_MFD_WM8400 is not set +# CONFIG_MFD_WM8994 is not set +# CONFIG_MG_DISK is not set +# CONFIG_MICREL_KS8995MA is not set +# CONFIG_MICREL_PHY is not set +# CONFIG_MIGRATION is not set +CONFIG_MII=y +# CONFIG_MIKROTIK_RB532 is not set +# CONFIG_MINIX_FS is not set +# CONFIG_MINIX_FS_NATIVE_ENDIAN is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_MIPS_ALCHEMY is not set +# CONFIG_MIPS_COBALT is not set +# CONFIG_MIPS_FPU_EMULATOR is not set +# CONFIG_MIPS_O32_FP64_SUPPORT is not set +# CONFIG_MIPS_MALTA is not set +# CONFIG_MIPS_PARAVIRT is not set +# CONFIG_MIPS_SEAD3 is not set +# CONFIG_MIPS_SIM is not set +CONFIG_MISC_DEVICES=y +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_MISDN is not set +# CONFIG_MISDN_AVMFRITZ is not set +# CONFIG_MISDN_HFCPCI is not set +# CONFIG_MISDN_HFCUSB is not set +# CONFIG_MISDN_INFINEON is not set +# CONFIG_MISDN_NETJET is not set +# CONFIG_MISDN_SPEEDFAX is not set +# CONFIG_MISDN_W6692 is not set +# CONFIG_MKISS is not set +# CONFIG_MLX4_CORE is not set +# CONFIG_MLX4_EN is not set +# CONFIG_MLX5_CORE is not set +# CONFIG_MLX90614 is not set +# CONFIG_MMA8452 is not set +# CONFIG_MMA9551 is not set +# CONFIG_MMA9553 is not set +# CONFIG_MMC is not set +# CONFIG_MMC_ARMMMCI is not set +# CONFIG_MMC_AU1X is not set +# CONFIG_MMC_BLOCK is not set +CONFIG_MMC_BLOCK_BOUNCE=y +CONFIG_MMC_BLOCK_MINORS=8 +# CONFIG_MMC_CB710 is not set +# CONFIG_MMC_CLKGATE is not set +# CONFIG_MMC_DEBUG is not set +# CONFIG_MMC_DW is not set +# CONFIG_MMC_MVSDIO is not set +# CONFIG_MMC_S3C is not set +# CONFIG_MMC_SDHCI is not set +# CONFIG_MMC_SDHCI_ACPI is not set +# CONFIG_MMC_SDHCI_BCM_KONA is not set +# CONFIG_MMC_SDHCI_MSM is not set +# CONFIG_MMC_SDHCI_OF_ARASAN is not set +# CONFIG_MMC_SDHCI_OF_ESDHC is not set +# CONFIG_MMC_SDHCI_OF_HLWD is not set +# CONFIG_MMC_SDHCI_PXAV2 is not set +# CONFIG_MMC_SDHCI_PXAV3 is not set +# CONFIG_MMC_SDHCI_F_SDH30 is not set +# CONFIG_MMC_SDRICOH_CS is not set +# CONFIG_MMC_SPI is not set +# CONFIG_MMC_TEST is not set +# CONFIG_MMC_TOSHIBA_PCI is not set +# CONFIG_MMC_UNSAFE_RESUME is not set +# CONFIG_MMC_USDHI6ROL0 is not set +# CONFIG_MMC_USHC is not set +# CONFIG_MMC_VIA_SDMMC is not set +# CONFIG_MMC_VUB300 is not set +# CONFIG_MMIOTRACE is not set +CONFIG_MMU=y +CONFIG_MODULES=y +# CONFIG_MODULE_COMPRESS is not set +# CONFIG_MODULE_FORCE_LOAD is not set +# CONFIG_MODULE_FORCE_UNLOAD is not set +# CONFIG_MODULE_SIG is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_MODULE_STRIPPED=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MOUSE_APPLETOUCH is not set +# CONFIG_MOUSE_GPIO is not set +# CONFIG_MOUSE_INPORT is not set +# CONFIG_MOUSE_LOGIBM is not set +# CONFIG_MOUSE_PC110PAD is not set +# CONFIG_MOUSE_PS2_SENTELIC is not set +# CONFIG_MOUSE_SYNAPTICS_I2C is not set +# CONFIG_MOUSE_SYNAPTICS_USB is not set +# CONFIG_MPL115 is not set +# CONFIG_MPL3115 is not set +# CONFIG_MSDOS_FS is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_MSI_BITMAP_SELFTEST is not set +# CONFIG_MSI_LAPTOP is not set +CONFIG_MTD=y +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_AFS_PARTS is not set +# CONFIG_MTD_ALAUDA is not set +# CONFIG_MTD_AR7_PARTS is not set +# CONFIG_MTD_ARM_INTEGRATOR is not set +CONFIG_MTD_BLKDEVS=y +CONFIG_MTD_BLOCK=y +# CONFIG_MTD_BLOCK2MTD is not set +CONFIG_MTD_CFI=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_CFI_AMDSTD=y +# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set +CONFIG_MTD_CFI_NOSWAP=y +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +CONFIG_MTD_CHAR=y +# CONFIG_MTD_CMDLINE_PARTS is not set +CONFIG_MTD_COMPLEX_MAPPINGS=y +# CONFIG_MTD_DATAFLASH is not set +# CONFIG_MTD_DEBUG is not set +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set +# CONFIG_MTD_DOCG3 is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_GPIO_ADDR is not set +# CONFIG_MTD_INTEL_VR_NOR is not set +# CONFIG_MTD_JEDECPROBE is not set +# CONFIG_MTD_LATCH_ADDR is not set +# CONFIG_MTD_LPDDR is not set +# CONFIG_MTD_LPDDR2_NVM is not set +# CONFIG_MTD_M25P80 is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +CONFIG_MTD_MAP_BANK_WIDTH_2=y +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_MYLOADER_PARTS is not set +# CONFIG_MTD_NAND is not set +# CONFIG_MTD_NAND_AMS_DELTA is not set +# CONFIG_MTD_NAND_AR934X is not set +# CONFIG_MTD_NAND_AR934X_HW_ECC is not set +# CONFIG_MTD_NAND_ATMEL is not set +# CONFIG_MTD_NAND_AU1550 is not set +# CONFIG_MTD_NAND_AUTCPU12 is not set +# CONFIG_MTD_NAND_BCH is not set +# CONFIG_MTD_NAND_BCM_UMI is not set +# CONFIG_MTD_NAND_BF5XX is not set +# CONFIG_MTD_NAND_CAFE is not set +# CONFIG_MTD_NAND_CM_X270 is not set +# CONFIG_MTD_NAND_CS553X is not set +# CONFIG_MTD_NAND_DAVINCI is not set +# CONFIG_MTD_NAND_DENALI is not set +CONFIG_MTD_NAND_DENALI_SCRATCH_REG_ADDR=0xff108018 +# CONFIG_MTD_NAND_DISKONCHIP is not set +# CONFIG_MTD_NAND_DOCG4 is not set +# CONFIG_MTD_NAND_ECC is not set +# CONFIG_MTD_NAND_ECC_BCH is not set +# CONFIG_MTD_NAND_ECC_SMC is not set +# CONFIG_MTD_NAND_FSL_ELBC is not set +# CONFIG_MTD_NAND_FSL_IFC is not set +# CONFIG_MTD_NAND_FSL_UPM is not set +# CONFIG_MTD_NAND_FSMC is not set +# CONFIG_MTD_NAND_GPIO is not set +# CONFIG_MTD_NAND_GPMI_NAND is not set +# CONFIG_MTD_NAND_H1900 is not set +# CONFIG_MTD_NAND_HISI504 is not set +CONFIG_MTD_NAND_IDS=y +# CONFIG_MTD_NAND_JZ4740 is not set +# CONFIG_MTD_NAND_MPC5121_NFC is not set +# CONFIG_MTD_NAND_MUSEUM_IDS is not set +# CONFIG_MTD_NAND_MXC is not set +# CONFIG_MTD_NAND_NANDSIM is not set +# CONFIG_MTD_NAND_NDFC is not set +# CONFIG_MTD_NAND_NOMADIK is not set +# CONFIG_MTD_NAND_NUC900 is not set +# CONFIG_MTD_NAND_OMAP2 is not set +# CONFIG_MTD_NAND_OMAP_BCH_BUILD is not set +# CONFIG_MTD_NAND_ORION is not set +# CONFIG_MTD_NAND_PASEMI is not set +# CONFIG_MTD_NAND_PLATFORM is not set +# CONFIG_MTD_NAND_PPCHAMELEONEVB is not set +# CONFIG_MTD_NAND_PXA3xx is not set +# CONFIG_MTD_NAND_RB4XX is not set +# CONFIG_MTD_NAND_RB750 is not set +# CONFIG_MTD_NAND_RICOH is not set +# CONFIG_MTD_NAND_RTC_FROM4 is not set +# CONFIG_MTD_NAND_S3C2410 is not set +# CONFIG_MTD_NAND_SHARPSL is not set +# CONFIG_MTD_NAND_SH_FLCTL is not set +# CONFIG_MTD_NAND_SOCRATES is not set +# CONFIG_MTD_NAND_SPIA is not set +# CONFIG_MTD_NAND_TMIO is not set +# CONFIG_MTD_NAND_TXX9NDFMC is not set +# CONFIG_MTD_NAND_VERIFY_WRITE is not set +CONFIG_MTD_OF_PARTS=y +# CONFIG_MTD_ONENAND is not set +# CONFIG_MTD_OOPS is not set +# CONFIG_MTD_OTP is not set +# CONFIG_MTD_PCI is not set +# CONFIG_MTD_PCMCIA is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_PHYSMAP_COMPAT is not set +CONFIG_MTD_PHYSMAP_OF=y +# CONFIG_MTD_PLATRAM is not set +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_RAM is not set +CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1 +# CONFIG_MTD_REDBOOT_PARTS is not set +# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set +# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set +# CONFIG_MTD_ROM is not set +CONFIG_MTD_ROOTFS_ROOT_DEV=y +CONFIG_MTD_ROOTFS_SPLIT=y +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_SM_COMMON is not set +# CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is not set +# CONFIG_MTD_SPI_NOR is not set +# CONFIG_MTD_SPINAND_MT29F is not set +CONFIG_MTD_SPLIT=y +# CONFIG_MTD_SPLIT_FIRMWARE is not set +CONFIG_MTD_SPLIT_FIRMWARE_NAME="firmware" +# CONFIG_MTD_SPLIT_FIT_FW is not set +# CONFIG_MTD_SPLIT_LZMA_FW is not set +# CONFIG_MTD_SPLIT_SEAMA_FW is not set +CONFIG_MTD_SPLIT_SQUASHFS_ROOT=y +CONFIG_MTD_SPLIT_SUPPORT=y +# CONFIG_MTD_SPLIT_TRX_FW is not set +# CONFIG_MTD_SPLIT_TPLINK_FW is not set +# CONFIG_MTD_SPLIT_UIMAGE_FW is not set +# CONFIG_MTD_SST25L is not set +# CONFIG_MTD_SWAP is not set +# CONFIG_MTD_TESTS is not set +# CONFIG_MTD_UBI is not set +# CONFIG_MTD_UIMAGE_SPLIT is not set +# CONFIG_MUTEX_SPIN_ON_OWNER is not set +# CONFIG_MV643XX_ETH is not set +# CONFIG_MVMDIO is not set +# CONFIG_MVSW61XX_PHY is not set +# CONFIG_MVSW6171_PHY is not set +# CONFIG_MVSWITCH_PHY is not set +# CONFIG_MWAVE is not set +# CONFIG_MWL8K is not set +# CONFIG_MYRI10GE is not set +# CONFIG_NAMESPACES is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_NATSEMI is not set +# CONFIG_NAU7802 is not set +# CONFIG_NBPFAXI_DMA is not set +# CONFIG_NCP_FS is not set +# CONFIG_NE2000 is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_NEC_MARKEINS is not set +CONFIG_NET=y +# CONFIG_NETCONSOLE is not set +CONFIG_NETDEVICES=y +CONFIG_NETDEV_1000=y +# CONFIG_NETDEV_10000 is not set +# CONFIG_NETFILTER is not set +# CONFIG_NETFILTER_ADVANCED is not set +# CONFIG_NETFILTER_DEBUG is not set +# CONFIG_NETFILTER_NETLINK is not set +# CONFIG_NETFILTER_NETLINK_ACCT is not set +# CONFIG_NETFILTER_NETLINK_LOG is not set +# CONFIG_NETFILTER_NETLINK_QUEUE is not set +# CONFIG_NETFILTER_NETLINK_QUEUE_CT is not set +# CONFIG_NETFILTER_TPROXY is not set +# CONFIG_NETFILTER_XTABLES is not set +# CONFIG_NETFILTER_XT_CONNMARK is not set +# CONFIG_NETFILTER_XT_MARK is not set +# CONFIG_NETFILTER_XT_MATCH_ADDRTYPE is not set +# CONFIG_NETFILTER_XT_MATCH_BPF is not set +# CONFIG_NETFILTER_XT_MATCH_CGROUP is not set +# CONFIG_NETFILTER_XT_MATCH_CLUSTER is not set +# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set +# CONFIG_NETFILTER_XT_MATCH_CONNBYTES is not set +# CONFIG_NETFILTER_XT_MATCH_CONNLABEL is not set +# CONFIG_NETFILTER_XT_MATCH_CONNLIMIT is not set +# CONFIG_NETFILTER_XT_MATCH_CONNMARK is not set +# CONFIG_NETFILTER_XT_MATCH_CONNTRACK is not set +# CONFIG_NETFILTER_XT_MATCH_CPU is not set +# CONFIG_NETFILTER_XT_MATCH_DCCP is not set +# CONFIG_NETFILTER_XT_MATCH_DEVGROUP is not set +# CONFIG_NETFILTER_XT_MATCH_DSCP is not set +# CONFIG_NETFILTER_XT_MATCH_ECN is not set +# CONFIG_NETFILTER_XT_MATCH_ESP is not set +# CONFIG_NETFILTER_XT_MATCH_HASHLIMIT is not set +# CONFIG_NETFILTER_XT_MATCH_HELPER is not set +# CONFIG_NETFILTER_XT_MATCH_HL is not set +# CONFIG_NETFILTER_XT_MATCH_IPCOMP is not set +# CONFIG_NETFILTER_XT_MATCH_IPRANGE is not set +# CONFIG_NETFILTER_XT_MATCH_L2TP is not set +# CONFIG_NETFILTER_XT_MATCH_LAYER7 is not set +# CONFIG_NETFILTER_XT_MATCH_LAYER7_DEBUG is not set +# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set +# CONFIG_NETFILTER_XT_MATCH_LIMIT is not set +# CONFIG_NETFILTER_XT_MATCH_MAC is not set +# CONFIG_NETFILTER_XT_MATCH_MARK is not set +# CONFIG_NETFILTER_XT_MATCH_MULTIPORT is not set +# CONFIG_NETFILTER_XT_MATCH_NFACCT is not set +# CONFIG_NETFILTER_XT_MATCH_OSF is not set +# CONFIG_NETFILTER_XT_MATCH_OWNER is not set +# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set +# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set +# CONFIG_NETFILTER_XT_MATCH_POLICY is not set +# CONFIG_NETFILTER_XT_MATCH_QUOTA is not set +# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set +# CONFIG_NETFILTER_XT_MATCH_REALM is not set +# CONFIG_NETFILTER_XT_MATCH_RECENT is not set +# CONFIG_NETFILTER_XT_MATCH_SCTP is not set +# CONFIG_NETFILTER_XT_MATCH_SOCKET is not set +# CONFIG_NETFILTER_XT_MATCH_STATE is not set +# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set +# CONFIG_NETFILTER_XT_MATCH_STRING is not set +# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set +# CONFIG_NETFILTER_XT_MATCH_TIME is not set +# CONFIG_NETFILTER_XT_MATCH_U32 is not set +# CONFIG_NETFILTER_XT_TARGET_AUDIT is not set +# CONFIG_NETFILTER_XT_TARGET_CHECKSUM is not set +# CONFIG_NETFILTER_XT_TARGET_CLASSIFY is not set +# CONFIG_NETFILTER_XT_TARGET_CONNMARK is not set +# CONFIG_NETFILTER_XT_TARGET_CT is not set +# CONFIG_NETFILTER_XT_TARGET_DSCP is not set +# CONFIG_NETFILTER_XT_TARGET_HL is not set +# CONFIG_NETFILTER_XT_TARGET_HMARK is not set +# CONFIG_NETFILTER_XT_TARGET_IDLETIMER is not set +# CONFIG_NETFILTER_XT_TARGET_LED is not set +# CONFIG_NETFILTER_XT_TARGET_LOG is not set +# CONFIG_NETFILTER_XT_TARGET_MARK is not set +# CONFIG_NETFILTER_XT_TARGET_NETMAP is not set +# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set +# CONFIG_NETFILTER_XT_TARGET_NFQUEUE is not set +# CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set +# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set +# CONFIG_NETFILTER_XT_TARGET_REDIRECT is not set +# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set +# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set +# CONFIG_NETFILTER_XT_TARGET_TEE is not set +# CONFIG_NETFILTER_XT_TARGET_TPROXY is not set +# CONFIG_NETFILTER_XT_TARGET_TRACE is not set +# CONFIG_NETLINK_DIAG is not set +# CONFIG_NETLINK_MMAP is not set +# CONFIG_NETPOLL is not set +# CONFIG_NETROM is not set +CONFIG_NETWORK_FILESYSTEMS=y +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETXEN_NIC is not set +# CONFIG_NET_9P is not set +# CONFIG_NET_ACT_BPF is not set +# CONFIG_NET_ACT_CSUM is not set +# CONFIG_NET_ACT_GACT is not set +# CONFIG_NET_ACT_IPT is not set +# CONFIG_NET_ACT_MIRRED is not set +# CONFIG_NET_ACT_NAT is not set +# CONFIG_NET_ACT_PEDIT is not set +# CONFIG_NET_ACT_POLICE is not set +# CONFIG_NET_ACT_SIMP is not set +# CONFIG_NET_ACT_SKBEDIT is not set +# CONFIG_NET_ACT_VLAN is not set +CONFIG_NET_CADENCE=y +# CONFIG_NET_CALXEDA_XGMAC is not set +CONFIG_NET_CLS=y +# CONFIG_NET_CLS_ACT is not set +# CONFIG_NET_CLS_BASIC is not set +# CONFIG_NET_CLS_BPF is not set +# CONFIG_NET_CLS_FLOW is not set +# CONFIG_NET_CLS_FW is not set +CONFIG_NET_CLS_IND=y +# CONFIG_NET_CLS_ROUTE4 is not set +# CONFIG_NET_CLS_RSVP is not set +# CONFIG_NET_CLS_RSVP6 is not set +# CONFIG_NET_CLS_TCINDEX is not set +# CONFIG_NET_CLS_U32 is not set +CONFIG_NET_CORE=y +# CONFIG_NET_DROP_MONITOR is not set +# CONFIG_NET_DSA is not set +# CONFIG_NET_DSA_BCM_SF2 is not set +# CONFIG_NET_DSA_MV88E6060 is not set +# CONFIG_NET_DSA_MV88E6123_61_65 is not set +# CONFIG_NET_DSA_MV88E6131 is not set +# CONFIG_NET_DSA_MV88E6171 is not set +# CONFIG_NET_DSA_MV88E6352 is not set +# CONFIG_NET_DSA_MV88E6XXX is not set +# CONFIG_NET_DSA_MV88E6XXX_NEED_PPU is not set +# CONFIG_NET_DSA_TAG_DSA is not set +# CONFIG_NET_DSA_TAG_EDSA is not set +# CONFIG_NET_EMATCH is not set +# CONFIG_NET_EMATCH_CMP is not set +# CONFIG_NET_EMATCH_META is not set +# CONFIG_NET_EMATCH_NBYTE is not set +CONFIG_NET_EMATCH_STACK=32 +# CONFIG_NET_EMATCH_TEXT is not set +# CONFIG_NET_EMATCH_U32 is not set +CONFIG_NET_ETHERNET=y +# CONFIG_NET_FC is not set +# CONFIG_NET_FOU is not set +# CONFIG_NET_FOU_IP_TUNNELS is not set +# CONFIG_NET_IPGRE is not set +CONFIG_NET_IPGRE_BROADCAST=y +# CONFIG_NET_IPGRE_DEMUX is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPVTI is not set +# CONFIG_NET_IP_TUNNEL is not set +# CONFIG_NET_ISA is not set +# CONFIG_NET_KEY is not set +# CONFIG_NET_KEY_MIGRATE is not set +# CONFIG_NET_MPLS_GSO is not set +# CONFIG_NET_PACKET_ENGINE is not set +CONFIG_NET_PCI=y +# CONFIG_NET_PCMCIA is not set +# CONFIG_NET_PKTGEN is not set +# CONFIG_NET_POCKET is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_NET_PTP_CLASSIFY is not set +CONFIG_NET_RX_BUSY_POLL=y +# CONFIG_NET_SB1000 is not set +CONFIG_NET_SCHED=y +# CONFIG_NET_SCH_ATM is not set +# CONFIG_NET_SCH_CBQ is not set +# CONFIG_NET_SCH_CHOKE is not set +# CONFIG_NET_SCH_CODEL is not set +# CONFIG_NET_SCH_DRR is not set +# CONFIG_NET_SCH_DSMARK is not set +# CONFIG_NET_SCH_ESFQ is not set +CONFIG_NET_SCH_ESFQ_NFCT=y +CONFIG_NET_SCH_FIFO=y +# CONFIG_NET_SCH_FQ is not set +CONFIG_NET_SCH_FQ_CODEL=y +# CONFIG_NET_SCH_GRED is not set +# CONFIG_NET_SCH_HFSC is not set +# CONFIG_NET_SCH_HHF is not set +# CONFIG_NET_SCH_HTB is not set +# CONFIG_NET_SCH_INGRESS is not set +# CONFIG_NET_SCH_MQPRIO is not set +# CONFIG_NET_SCH_MULTIQ is not set +# CONFIG_NET_SCH_NETEM is not set +# CONFIG_NET_SCH_PIE is not set +# CONFIG_NET_SCH_PLUG is not set +# CONFIG_NET_SCH_PRIO is not set +# CONFIG_NET_SCH_QFQ is not set +# CONFIG_NET_SCH_RED is not set +# CONFIG_NET_SCH_SFB is not set +# CONFIG_NET_SCH_SFQ is not set +# CONFIG_NET_SCH_TBF is not set +# CONFIG_NET_SCH_TEQL is not set +# CONFIG_NET_SCTPPROBE is not set +# CONFIG_NET_SWITCHDEV is not set +# CONFIG_NET_TCPPROBE is not set +# CONFIG_NET_TEAM is not set +# CONFIG_NET_TULIP is not set +# CONFIG_NET_UDP_TUNNEL is not set +CONFIG_NET_VENDOR_3COM=y +CONFIG_NET_VENDOR_8390=y +CONFIG_NET_VENDOR_ADAPTEC=y +CONFIG_NET_VENDOR_AGERE=y +CONFIG_NET_VENDOR_ALTEON=y +CONFIG_NET_VENDOR_AMD=y +CONFIG_NET_VENDOR_ARC=y +CONFIG_NET_VENDOR_ATHEROS=y +CONFIG_NET_VENDOR_BROADCOM=y +CONFIG_NET_VENDOR_BROCADE=y +CONFIG_NET_VENDOR_CHELSIO=y +CONFIG_NET_VENDOR_CIRRUS=y +CONFIG_NET_VENDOR_CISCO=y +CONFIG_NET_VENDOR_DEC=y +CONFIG_NET_VENDOR_DLINK=y +CONFIG_NET_VENDOR_EMULEX=y +CONFIG_NET_VENDOR_EXAR=y +CONFIG_NET_VENDOR_FARADAY=y +CONFIG_NET_VENDOR_FREESCALE=y +CONFIG_NET_VENDOR_FUJITSU=y +CONFIG_NET_VENDOR_HISILICON=y +CONFIG_NET_VENDOR_HP=y +CONFIG_NET_VENDOR_I825XX=y +CONFIG_NET_VENDOR_IBM=y +CONFIG_NET_VENDOR_INTEL=y +CONFIG_NET_VENDOR_MARVELL=y +CONFIG_NET_VENDOR_MELLANOX=y +CONFIG_NET_VENDOR_MICREL=y +CONFIG_NET_VENDOR_MICROCHIP=y +CONFIG_NET_VENDOR_MYRI=y +CONFIG_NET_VENDOR_NATSEMI=y +CONFIG_NET_VENDOR_NVIDIA=y +CONFIG_NET_VENDOR_OKI=y +CONFIG_NET_VENDOR_QLOGIC=y +CONFIG_NET_VENDOR_QUALCOMM=y +CONFIG_NET_VENDOR_RDC=y +CONFIG_NET_VENDOR_REALTEK=y +CONFIG_NET_VENDOR_ROCKER=y +CONFIG_NET_VENDOR_SAMSUNG=y +CONFIG_NET_VENDOR_SEEQ=y +CONFIG_NET_VENDOR_SILAN=y +CONFIG_NET_VENDOR_SILICOM=y +CONFIG_NET_VENDOR_SIS=y +CONFIG_NET_VENDOR_SMSC=y +CONFIG_NET_VENDOR_STMICRO=y +CONFIG_NET_VENDOR_SUN=y +CONFIG_NET_VENDOR_TEHUTI=y +CONFIG_NET_VENDOR_TI=y +CONFIG_NET_VENDOR_TOSHIBA=y +CONFIG_NET_VENDOR_VIA=y +# CONFIG_NET_VENDOR_WIZNET is not set +CONFIG_NET_VENDOR_XILINX=y +CONFIG_NET_VENDOR_XIRCOM=y +# CONFIG_NET_XGENE is not set +CONFIG_NEW_LEDS=y +# CONFIG_NFC is not set +# CONFIG_NFC_DEVICES is not set +# CONFIG_NFSD is not set +# CONFIG_NFSD_DEPRECATED is not set +# CONFIG_NFSD_V2_ACL is not set +CONFIG_NFSD_V3=y +# CONFIG_NFSD_V3_ACL is not set +# CONFIG_NFSD_V4 is not set +# CONFIG_NFS_ACL_SUPPORT is not set +CONFIG_NFS_COMMON=y +# CONFIG_NFS_FS is not set +# CONFIG_NFS_FSCACHE is not set +# CONFIG_NFS_SWAP is not set +# CONFIG_NFS_V2 is not set +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_V4_1 is not set +# CONFIG_NFTL is not set +# CONFIG_NF_CONNTRACK is not set +# CONFIG_NF_CONNTRACK_AMANDA is not set +# CONFIG_NF_CONNTRACK_EVENTS is not set +# CONFIG_NF_CONNTRACK_FTP is not set +# CONFIG_NF_CONNTRACK_H323 is not set +# CONFIG_NF_CONNTRACK_IPV4 is not set +# CONFIG_NF_CONNTRACK_IPV6 is not set +# CONFIG_NF_CONNTRACK_IRC is not set +# CONFIG_NF_CONNTRACK_MARK is not set +# CONFIG_NF_CONNTRACK_NETBIOS_NS is not set +# CONFIG_NF_CONNTRACK_PPTP is not set +CONFIG_NF_CONNTRACK_PROCFS=y +# CONFIG_NF_CONNTRACK_PROC_COMPAT is not set +# CONFIG_NF_CONNTRACK_RTSP is not set +# CONFIG_NF_CONNTRACK_SANE is not set +# CONFIG_NF_CONNTRACK_SIP is not set +# CONFIG_NF_CONNTRACK_SNMP is not set +# CONFIG_NF_CONNTRACK_TFTP is not set +# CONFIG_NF_CONNTRACK_TIMEOUT is not set +# CONFIG_NF_CONNTRACK_TIMESTAMP is not set +# CONFIG_NF_CONNTRACK_ZONES is not set +# CONFIG_NF_CT_NETLINK is not set +# CONFIG_NF_CT_NETLINK_TIMEOUT is not set +# CONFIG_NF_CT_PROTO_DCCP is not set +# CONFIG_NF_CT_PROTO_GRE is not set +# CONFIG_NF_CT_PROTO_SCTP is not set +# CONFIG_NF_CT_PROTO_UDPLITE is not set +# CONFIG_NF_DEFRAG_IPV4 is not set +# CONFIG_NF_LOG_ARP is not set +# CONFIG_NF_LOG_IPV4 is not set +# CONFIG_NF_NAT is not set +# CONFIG_NF_NAT_AMANDA is not set +# CONFIG_NF_NAT_FTP is not set +# CONFIG_NF_NAT_H323 is not set +# CONFIG_NF_NAT_IPV6 is not set +# CONFIG_NF_NAT_IRC is not set +# CONFIG_NF_NAT_MASQUERADE_IPV4 is not set +# CONFIG_NF_NAT_MASQUERADE_IPV6 is not set +# CONFIG_NF_NAT_NEEDED is not set +# CONFIG_NF_NAT_PPTP is not set +# CONFIG_NF_NAT_PROTO_GRE is not set +# CONFIG_NF_NAT_RTSP is not set +# CONFIG_NF_NAT_SIP is not set +# CONFIG_NF_NAT_SNMP_BASIC is not set +# CONFIG_NF_NAT_TFTP is not set +# CONFIG_NF_REJECT_IPV4 is not set +# CONFIG_NF_TABLES is not set +# CONFIG_NI52 is not set +# CONFIG_NI65 is not set +# CONFIG_NILFS2_FS is not set +# CONFIG_NIU is not set +CONFIG_NLATTR=y +# CONFIG_NLMON is not set +# CONFIG_NLM_XLP_BOARD is not set +# CONFIG_NLM_XLR_BOARD is not set +# CONFIG_NLS is not set +# CONFIG_NLS_ASCII is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +CONFIG_NLS_DEFAULT="iso8859-1" +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_MAC_CELTIC is not set +# CONFIG_NLS_MAC_CENTEURO is not set +# CONFIG_NLS_MAC_CROATIAN is not set +# CONFIG_NLS_MAC_CYRILLIC is not set +# CONFIG_NLS_MAC_GAELIC is not set +# CONFIG_NLS_MAC_GREEK is not set +# CONFIG_NLS_MAC_ICELAND is not set +# CONFIG_NLS_MAC_INUIT is not set +# CONFIG_NLS_MAC_ROMAN is not set +# CONFIG_NLS_MAC_ROMANIAN is not set +# CONFIG_NLS_MAC_TURKISH is not set +# CONFIG_NLS_UTF8 is not set +# CONFIG_NOP_USB_XCEIV is not set +# CONFIG_NORTEL_HERMES is not set +# CONFIG_NOTIFIER_ERROR_INJECTION is not set +# CONFIG_NOZOMI is not set +# CONFIG_NO_BOOTMEM is not set +# CONFIG_NO_HZ is not set +# CONFIG_NO_HZ_FULL is not set +# CONFIG_NO_HZ_IDLE is not set +# CONFIG_NO_IOPORT is not set +# CONFIG_NS83820 is not set +# CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_NTP_PPS is not set +# CONFIG_NVRAM is not set +# CONFIG_NV_TCO is not set +# CONFIG_NXP_STB220 is not set +# CONFIG_NXP_STB225 is not set +# CONFIG_N_GSM is not set +# CONFIG_OABI_COMPAT is not set +# CONFIG_OBS600 is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_OCF_BENCH is not set +# CONFIG_OCF_C7108 is not set +# CONFIG_OCF_CRYPTOCTEON is not set +# CONFIG_OCF_EP80579 is not set +# CONFIG_OCF_HIFN is not set +# CONFIG_OCF_HIFNHIPP is not set +# CONFIG_OCF_IXP4XX is not set +# CONFIG_OCF_KIRKWOOD is not set +# CONFIG_OCF_OCF is not set +# CONFIG_OCF_OCFNULL is not set +# CONFIG_OCF_SAFE is not set +# CONFIG_OCF_TALITOS is not set +# CONFIG_OCF_UBSEC_SSB is not set +# CONFIG_OC_ETM is not set +# CONFIG_OF_OVERLAY is not set +# CONFIG_OF_SELFTEST is not set +# CONFIG_OF_UNITTEST is not set +# CONFIG_OMAP2_DSS_DEBUG is not set +# CONFIG_OMAP2_DSS_DEBUGFS is not set +# CONFIG_OMAP2_DSS_SDI is not set +# CONFIG_OMAP_CONTROL_USB is not set +# CONFIG_OMAP_OCP2SCP is not set +# CONFIG_OMAP_USB2 is not set +# CONFIG_OMAP_USB3 is not set +# CONFIG_OMFS_FS is not set +# CONFIG_OPENVSWITCH is not set +# CONFIG_OPROFILE_EVENT_MULTIPLEX is not set +# CONFIG_ORION_WATCHDOG is not set +# CONFIG_OSF_PARTITION is not set +CONFIG_OVERLAY_FS=y +# CONFIG_P54_COMMON is not set +CONFIG_PACKET=y +# CONFIG_PACKET_DIAG is not set +# CONFIG_PAGE_EXTENSION is not set +# CONFIG_PAGE_OWNER is not set +# CONFIG_PAGE_POISONING is not set +# CONFIG_PAGE_SIZE_16KB is not set +# CONFIG_PAGE_SIZE_32KB is not set +CONFIG_PAGE_SIZE_4KB=y +# CONFIG_PAGE_SIZE_64KB is not set +# CONFIG_PAGE_SIZE_8KB is not set +# CONFIG_PANEL is not set +# CONFIG_PANIC_ON_OOPS is not set +CONFIG_PANIC_ON_OOPS_VALUE=0 +CONFIG_PANIC_TIMEOUT=0 +# CONFIG_PANTHERLORD_FF is not set +# CONFIG_PARPORT is not set +# CONFIG_PARPORT_1284 is not set +# CONFIG_PARPORT_AX88796 is not set +# CONFIG_PARPORT_PC is not set +CONFIG_PARTITION_ADVANCED=y +# CONFIG_PATA_ALI is not set +# CONFIG_PATA_AMD is not set +# CONFIG_PATA_ARASAN_CF is not set +# CONFIG_PATA_ARTOP is not set +# CONFIG_PATA_ATIIXP is not set +# CONFIG_PATA_ATP867X is not set +# CONFIG_PATA_CMD640_PCI is not set +# CONFIG_PATA_CMD64X is not set +# CONFIG_PATA_CS5520 is not set +# CONFIG_PATA_CS5530 is not set +# CONFIG_PATA_CS5535 is not set +# CONFIG_PATA_CS5536 is not set +# CONFIG_PATA_CYPRESS is not set +# CONFIG_PATA_EFAR is not set +# CONFIG_PATA_HPT366 is not set +# CONFIG_PATA_HPT37X is not set +# CONFIG_PATA_HPT3X2N is not set +# CONFIG_PATA_HPT3X3 is not set +# CONFIG_PATA_ISAPNP is not set +# CONFIG_PATA_IT8213 is not set +# CONFIG_PATA_IT821X is not set +# CONFIG_PATA_JMICRON is not set +# CONFIG_PATA_LEGACY is not set +# CONFIG_PATA_MARVELL is not set +# CONFIG_PATA_MPIIX is not set +# CONFIG_PATA_NETCELL is not set +# CONFIG_PATA_NINJA32 is not set +# CONFIG_PATA_NS87410 is not set +# CONFIG_PATA_NS87415 is not set +# CONFIG_PATA_OCTEON_CF is not set +# CONFIG_PATA_OF_PLATFORM is not set +# CONFIG_PATA_OLDPIIX is not set +# CONFIG_PATA_OPTI is not set +# CONFIG_PATA_OPTIDMA is not set +# CONFIG_PATA_PCMCIA is not set +# CONFIG_PATA_PDC2027X is not set +# CONFIG_PATA_PDC_OLD is not set +# CONFIG_PATA_PLATFORM is not set +# CONFIG_PATA_QDI is not set +# CONFIG_PATA_RADISYS is not set +# CONFIG_PATA_RDC is not set +# CONFIG_PATA_RZ1000 is not set +# CONFIG_PATA_SC1200 is not set +# CONFIG_PATA_SCH is not set +# CONFIG_PATA_SERVERWORKS is not set +# CONFIG_PATA_SIL680 is not set +# CONFIG_PATA_SIS is not set +# CONFIG_PATA_TOSHIBA is not set +# CONFIG_PATA_TRIFLEX is not set +# CONFIG_PATA_VIA is not set +# CONFIG_PATA_WINBOND is not set +# CONFIG_PATA_WINBOND_VLB is not set +# CONFIG_PC300TOO is not set +# CONFIG_PCCARD is not set +# CONFIG_PCH_GBE is not set +# CONFIG_PCH_PHUB is not set +# CONFIG_PCI200SYN is not set +# CONFIG_PCIEAER_INJECT is not set +# CONFIG_PCIEASPM is not set +# CONFIG_PCIEPORTBUS is not set +# CONFIG_PCIE_ECRC is not set +# CONFIG_PCIPCWATCHDOG is not set +# CONFIG_PCI_ATMEL is not set +# CONFIG_PCI_CNB20LE_QUIRK is not set +# CONFIG_PCI_DEBUG is not set +# CONFIG_PCI_DISABLE_COMMON_QUIRKS is not set +# CONFIG_PCI_HERMES is not set +# CONFIG_PCI_HOST_GENERIC is not set +# CONFIG_PCI_IOV is not set +# CONFIG_PCI_LAYERSCAPE is not set +# CONFIG_PCI_MSI is not set +# CONFIG_PCI_PASID is not set +# CONFIG_PCI_PRI is not set +CONFIG_PCI_QUIRKS=y +# CONFIG_PCI_REALLOC_ENABLE_AUTO is not set +# CONFIG_PCI_STUB is not set +CONFIG_PCI_SYSCALL=y +# CONFIG_PCMCIA is not set +# CONFIG_PCMCIA_3C574 is not set +# CONFIG_PCMCIA_3C589 is not set +# CONFIG_PCMCIA_AHA152X is not set +# CONFIG_PCMCIA_ATMEL is not set +# CONFIG_PCMCIA_AXNET is not set +# CONFIG_PCMCIA_DEBUG is not set +# CONFIG_PCMCIA_FDOMAIN is not set +# CONFIG_PCMCIA_FMVJ18X is not set +# CONFIG_PCMCIA_HERMES is not set +# CONFIG_PCMCIA_LOAD_CIS is not set +# CONFIG_PCMCIA_NINJA_SCSI is not set +# CONFIG_PCMCIA_NMCLAN is not set +# CONFIG_PCMCIA_PCNET is not set +# CONFIG_PCMCIA_QLOGIC is not set +# CONFIG_PCMCIA_RAYCS is not set +# CONFIG_PCMCIA_SMC91C92 is not set +# CONFIG_PCMCIA_SPECTRUM is not set +# CONFIG_PCMCIA_SYM53C500 is not set +# CONFIG_PCMCIA_WL3501 is not set +# CONFIG_PCMCIA_XIRC2PS is not set +# CONFIG_PCMCIA_XIRCOM is not set +# CONFIG_PCNET32 is not set +# CONFIG_PCSPKR_PLATFORM is not set +# CONFIG_PD6729 is not set +# CONFIG_PDA_POWER is not set +# CONFIG_PDC_ADMA is not set +# CONFIG_PERCPU_TEST is not set +# CONFIG_PERF_COUNTERS is not set +# CONFIG_PERF_EVENTS is not set +# CONFIG_PERSISTENT_KEYRINGS is not set +# CONFIG_PHANTOM is not set +# CONFIG_PHONE is not set +# CONFIG_PHONET is not set +# CONFIG_PHYLIB is not set +# CONFIG_PHYS_ADDR_T_64BIT is not set +# CONFIG_PHY_EXYNOS_DP_VIDEO is not set +# CONFIG_PHY_EXYNOS_MIPI_VIDEO is not set +# CONFIG_PHY_SAMSUNG_USB2 is not set +# CONFIG_PHY_QCOM_DWC3 is not set +# CONFIG_PID_IN_CONTEXTIDR is not set +# CONFIG_PID_NS is not set +CONFIG_PINCONF=y +# CONFIG_PINCTRL is not set +# CONFIG_PINCTRL_CAPRI is not set +# CONFIG_PINCTRL_EXYNOS is not set +# CONFIG_PINCTRL_EXYNOS5440 is not set +# CONFIG_PINCTRL_MSM8X74 is not set +CONFIG_PINCTRL_SINGLE=y +CONFIG_PINMUX=y +# CONFIG_PLAT_SPEAR is not set +# CONFIG_PLIP is not set +# CONFIG_PLX_HERMES is not set +# CONFIG_PM is not set +# CONFIG_PMBUS is not set +# CONFIG_PMC_MSP is not set +# CONFIG_PMC_YOSEMITE is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_PM_AUTOSLEEP is not set +# CONFIG_PM_DEVFREQ is not set +# CONFIG_PM_RUNTIME is not set +# CONFIG_PM_WAKELOCKS is not set +# CONFIG_PNX8550_JBS is not set +# CONFIG_PNX8550_STB810 is not set +# CONFIG_POHMELFS is not set +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_POWERCAP is not set +# CONFIG_POWERTV is not set +# CONFIG_POWER_AVS is not set +# CONFIG_POWER_RESET is not set +# CONFIG_POWER_RESET_RESTART is not set +# CONFIG_POWER_RESET_VERSATILE is not set +# CONFIG_POWER_SUPPLY is not set +# CONFIG_POWER_SUPPLY_DEBUG is not set +# CONFIG_PPC4xx_GPIO is not set +# CONFIG_PPC_16K_PAGES is not set +# CONFIG_PPC_256K_PAGES is not set +CONFIG_PPC_4K_PAGES=y +# CONFIG_PPC_64K_PAGES is not set +# CONFIG_PPC_DISABLE_WERROR is not set +# CONFIG_PPC_EMULATED_STATS is not set +# CONFIG_PPC_EPAPR_HV_BYTECHAN is not set +# CONFIG_PPP is not set +# CONFIG_PPPOATM is not set +# CONFIG_PPPOE is not set +# CONFIG_PPPOL2TP is not set +# CONFIG_PPP_ASYNC is not set +# CONFIG_PPP_BSDCOMP is not set +# CONFIG_PPP_DEFLATE is not set +CONFIG_PPP_FILTER=y +# CONFIG_PPP_MPPE is not set +CONFIG_PPP_MULTILINK=y +# CONFIG_PPP_SYNC_TTY is not set +# CONFIG_PPS is not set +# CONFIG_PPS_CLIENT_GPIO is not set +# CONFIG_PPS_CLIENT_KTIMER is not set +# CONFIG_PPS_CLIENT_LDISC is not set +# CONFIG_PPS_CLIENT_PARPORT is not set +# CONFIG_PPS_DEBUG is not set +# CONFIG_PPTP is not set +# CONFIG_PREEMPT is not set +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_TRACER is not set +# CONFIG_PREEMPT_VOLUNTARY is not set +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_PRINTK=y +# CONFIG_PRINTK_TIME is not set +CONFIG_PRINT_STACK_DEPTH=64 +# CONFIG_PRISM2_USB is not set +# CONFIG_PRISM54 is not set +# CONFIG_PROBE_INITRD_HEADER is not set +CONFIG_PROC_FS=y +# CONFIG_PROC_KCORE is not set +# CONFIG_PROC_PAGE_MONITOR is not set +CONFIG_PROC_STRIPPED=y +CONFIG_PROC_SYSCTL=y +# CONFIG_PROFILE_ALL_BRANCHES is not set +# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set +# CONFIG_PROFILING is not set +# CONFIG_PROVE_LOCKING is not set +# CONFIG_PROVE_RCU is not set +# CONFIG_PROVE_RCU_DELAY is not set +# CONFIG_PSB6970_PHY is not set +# CONFIG_PSTORE is not set +# CONFIG_PTP_1588_CLOCK is not set +# CONFIG_PTP_1588_CLOCK_IXP46X is not set +# CONFIG_PTP_1588_CLOCK_PCH is not set +# CONFIG_PWM is not set +# CONFIG_PWM_PCA9685 is not set +# CONFIG_QCA7000 is not set +# CONFIG_QLA3XXX is not set +# CONFIG_QLCNIC is not set +# CONFIG_QLGE is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX6FS_FS is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_QUOTA is not set +# CONFIG_QUOTACTL is not set +# CONFIG_QUOTA_DEBUG is not set +# CONFIG_R3964 is not set +# CONFIG_R6040 is not set +# CONFIG_R8169 is not set +# CONFIG_R8187SE is not set +# CONFIG_R8188EU is not set +# CONFIG_R8712U is not set +# CONFIG_R8723AU is not set +# CONFIG_RADIO_ADAPTERS is not set +# CONFIG_RADIO_AZTECH is not set +# CONFIG_RADIO_CADET is not set +# CONFIG_RADIO_GEMTEK is not set +# CONFIG_RADIO_MAXIRADIO is not set +# CONFIG_RADIO_RTRACK is not set +# CONFIG_RADIO_RTRACK2 is not set +# CONFIG_RADIO_SF16FMI is not set +# CONFIG_RADIO_SF16FMR2 is not set +# CONFIG_RADIO_TERRATEC is not set +# CONFIG_RADIO_TRUST is not set +# CONFIG_RADIO_TYPHOON is not set +# CONFIG_RADIO_ZOLTRIX is not set +# CONFIG_RAID_ATTRS is not set +# CONFIG_RALINK is not set +# CONFIG_RAMOOPS is not set +# CONFIG_RANDOM32_SELFTEST is not set +# CONFIG_RAPIDIO is not set +# CONFIG_RAR_REGISTER is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_RBTREE_TEST is not set +# CONFIG_RCU_CPU_STALL_INFO is not set +CONFIG_RCU_CPU_STALL_TIMEOUT=60 +CONFIG_RCU_FANOUT=32 +# CONFIG_RCU_FANOUT_EXACT is not set +CONFIG_RCU_FANOUT_LEAF=16 +# CONFIG_RCU_FAST_NO_HZ is not set +CONFIG_RCU_KTHREAD_PRIO=0 +# CONFIG_RCU_NOCB_CPU is not set +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_RCU_TRACE is not set +# CONFIG_RCU_USER_QS is not set +# CONFIG_RC_ATI_REMOTE is not set +# CONFIG_RC_CORE is not set +# CONFIG_RC_DECODERS is not set +# CONFIG_RC_LOOPBACK is not set +# CONFIG_RC_MAP is not set +# CONFIG_RDS is not set +# CONFIG_RD_BZIP2 is not set +# CONFIG_RD_GZIP is not set +# CONFIG_RD_LZ4 is not set +# CONFIG_RD_LZMA is not set +# CONFIG_RD_LZO is not set +# CONFIG_RD_XZ is not set +# CONFIG_READABLE_ASM is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_REDWOOD is not set +# CONFIG_REGMAP is not set +# CONFIG_REGMAP_I2C is not set +# CONFIG_REGMAP_MMIO is not set +# CONFIG_REGMAP_SPI is not set +# CONFIG_REGULATOR is not set +# CONFIG_REGULATOR_ACT8865 is not set +# CONFIG_REGULATOR_AD5398 is not set +# CONFIG_REGULATOR_ANATOP is not set +# CONFIG_REGULATOR_BQ24022 is not set +# CONFIG_REGULATOR_DA9210 is not set +# CONFIG_REGULATOR_DA9211 is not set +# CONFIG_REGULATOR_FAN53555 is not set +# CONFIG_REGULATOR_FIXED_VOLTAGE is not set +# CONFIG_REGULATOR_GPIO is not set +# CONFIG_REGULATOR_ISL6271A is not set +# CONFIG_REGULATOR_ISL9305 is not set +# CONFIG_REGULATOR_LP3971 is not set +# CONFIG_REGULATOR_LP3972 is not set +# CONFIG_REGULATOR_LP872X is not set +# CONFIG_REGULATOR_LP8755 is not set +# CONFIG_REGULATOR_LTC3589 is not set +# CONFIG_REGULATOR_MAX1586 is not set +# CONFIG_REGULATOR_MAX8649 is not set +# CONFIG_REGULATOR_MAX8660 is not set +# CONFIG_REGULATOR_MAX8952 is not set +# CONFIG_REGULATOR_MAX8973 is not set +# CONFIG_REGULATOR_PFUZE100 is not set +# CONFIG_REGULATOR_TI_ABB is not set +# CONFIG_REGULATOR_TPS51632 is not set +# CONFIG_REGULATOR_TPS62360 is not set +# CONFIG_REGULATOR_TPS65023 is not set +# CONFIG_REGULATOR_TPS6507X is not set +# CONFIG_REGULATOR_TPS6524X is not set +# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_FS_POSIX_ACL is not set +# CONFIG_REISERFS_FS_SECURITY is not set +# CONFIG_REISERFS_FS_XATTR is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_RELAY is not set +# CONFIG_RESET_CONTROLLER is not set +# CONFIG_RFD_FTL is not set +# CONFIG_RFKILL is not set +# CONFIG_RFKILL_INPUT is not set +# CONFIG_RFKILL_REGULATOR is not set +# CONFIG_RING_BUFFER_BENCHMARK is not set +# CONFIG_RING_BUFFER_STARTUP_TEST is not set +# CONFIG_ROCKER is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_ROSE is not set +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RT2X00 is not set +# CONFIG_RTC_CLASS is not set +# CONFIG_RTC_DEBUG is not set +# CONFIG_RTC_DRV_ABB5ZES3 is not set +# CONFIG_RTC_DRV_ARMADA38X is not set +# CONFIG_RTC_DRV_AU1XXX is not set +# CONFIG_RTC_DRV_BQ32K is not set +# CONFIG_RTC_DRV_BQ4802 is not set +CONFIG_RTC_DRV_CMOS=y +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1305 is not set +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1343 is not set +# CONFIG_RTC_DRV_DS1347 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1390 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_DS1685_FAMILY is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_DS2404 is not set +# CONFIG_RTC_DRV_DS3232 is not set +# CONFIG_RTC_DRV_DS3234 is not set +# CONFIG_RTC_DRV_EM3027 is not set +# CONFIG_RTC_DRV_EP93XX is not set +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_GENERIC is not set +# CONFIG_RTC_DRV_HID_SENSOR_TIME is not set +# CONFIG_RTC_DRV_HYM8563 is not set +# CONFIG_RTC_DRV_ISL12022 is not set +# CONFIG_RTC_DRV_ISL12057 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_M41T80 is not set +# CONFIG_RTC_DRV_M41T93 is not set +# CONFIG_RTC_DRV_M41T94 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_MCP795 is not set +# CONFIG_RTC_DRV_MOXART is not set +# CONFIG_RTC_DRV_MPC5121 is not set +# CONFIG_RTC_DRV_MSM6242 is not set +# CONFIG_RTC_DRV_OMAP is not set +# CONFIG_RTC_DRV_PCF2123 is not set +# CONFIG_RTC_DRV_PCF2127 is not set +# CONFIG_RTC_DRV_PCF85063 is not set +# CONFIG_RTC_DRV_PCF8523 is not set +# CONFIG_RTC_DRV_PCF8563 is not set +# CONFIG_RTC_DRV_PCF8583 is not set +# CONFIG_RTC_DRV_PL030 is not set +# CONFIG_RTC_DRV_PL031 is not set +# CONFIG_RTC_DRV_PS3 is not set +# CONFIG_RTC_DRV_PT7C4338 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RP5C01 is not set +# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_RTC7301 is not set +# CONFIG_RTC_DRV_RV3029C2 is not set +# CONFIG_RTC_DRV_RX4581 is not set +# CONFIG_RTC_DRV_RX8025 is not set +# CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_S35390A is not set +# CONFIG_RTC_DRV_SNVS is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_SUN6I is not set +# CONFIG_RTC_DRV_TEST is not set +# CONFIG_RTC_DRV_V3020 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_XGENE is not set +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_LIB=y +CONFIG_RTC_SYSTOHC=y +# CONFIG_RTL8180 is not set +# CONFIG_RTL8187 is not set +# CONFIG_RTL8192E is not set +# CONFIG_RTL8192U is not set +# CONFIG_RTL8306_PHY is not set +# CONFIG_RTL8366RB_PHY is not set +# CONFIG_RTL8366S_PHY is not set +# CONFIG_RTL8366_SMI is not set +# CONFIG_RTL8366_SMI_DEBUG_FS is not set +# CONFIG_RTL8367B_PHY is not set +# CONFIG_RTL8367_PHY is not set +# CONFIG_RTLLIB is not set +# CONFIG_RTL_CARDS is not set +# CONFIG_RTS5139 is not set +# CONFIG_RTS5208 is not set +# CONFIG_RTS_PSTOR is not set +CONFIG_RT_MUTEXES=y +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_RUNTIME_DEBUG is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_S2IO is not set +# CONFIG_SAMPLES is not set +# CONFIG_SAMSUNG_LAPTOP is not set +# CONFIG_SAMSUNG_USB2PHY is not set +# CONFIG_SAMSUNG_USB3PHY is not set +# CONFIG_SATA_ACARD_AHCI is not set +# CONFIG_SATA_AHCI is not set +# CONFIG_SATA_AHCI_PLATFORM is not set +# CONFIG_SATA_DWC is not set +# CONFIG_SATA_FSL is not set +# CONFIG_SATA_HIGHBANK is not set +# CONFIG_SATA_INIC162X is not set +# CONFIG_SATA_MV is not set +# CONFIG_SATA_NV is not set +# CONFIG_SATA_PMP is not set +# CONFIG_SATA_PROMISE is not set +# CONFIG_SATA_QSTOR is not set +# CONFIG_SATA_RCAR is not set +# CONFIG_SATA_SIL is not set +# CONFIG_SATA_SIL24 is not set +# CONFIG_SATA_SIS is not set +# CONFIG_SATA_SVW is not set +# CONFIG_SATA_SX4 is not set +# CONFIG_SATA_ULI is not set +# CONFIG_SATA_VIA is not set +# CONFIG_SATA_VITESSE is not set +# CONFIG_SBC_FITPC2_WATCHDOG is not set +# CONFIG_SBE_2T3E3 is not set +# CONFIG_SBYPASS is not set +# CONFIG_SC92031 is not set +# CONFIG_SCA3000 is not set +# CONFIG_SCC is not set +# CONFIG_SCHEDSTATS is not set +# CONFIG_SCHED_AUTOGROUP is not set +# CONFIG_SCHED_DEBUG is not set +# CONFIG_SCHED_MC is not set +CONFIG_SCHED_OMIT_FRAME_POINTER=y +# CONFIG_SCHED_SMT is not set +# CONFIG_SCHED_STACK_END_CHECK is not set +# CONFIG_SCHED_TRACER is not set +# CONFIG_SCSI is not set +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_3W_SAS is not set +# CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AHA1542 is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_AIC94XX is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_ARCMSR is not set +# CONFIG_SCSI_BFA_FC is not set +# CONFIG_SCSI_BNX2X_FCOE is not set +# CONFIG_SCSI_BNX2_ISCSI is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_CHELSIO_FCOE is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_CXGB3_ISCSI is not set +# CONFIG_SCSI_CXGB4_ISCSI is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_DH is not set +CONFIG_SCSI_DMA=y +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_ESAS2R is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set +# CONFIG_SCSI_HPSA is not set +# CONFIG_SCSI_HPTIOP is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_ISCI is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_LOGGING is not set +CONFIG_SCSI_LOWLEVEL=y +# CONFIG_SCSI_LOWLEVEL_PCMCIA is not set +# CONFIG_SCSI_LPFC is not set +CONFIG_SCSI_MOD=y +# CONFIG_SCSI_MPT2SAS is not set +# CONFIG_SCSI_MPT3SAS is not set +# CONFIG_SCSI_MQ_DEFAULT is not set +CONFIG_SCSI_MULTI_LUN=y +# CONFIG_SCSI_MVSAS is not set +# CONFIG_SCSI_MVSAS_DEBUG is not set +# CONFIG_SCSI_MVUMI is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_NETLINK is not set +# CONFIG_SCSI_NSP32 is not set +# CONFIG_SCSI_OSD_INITIATOR is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PM8001 is not set +# CONFIG_SCSI_PMCRAID is not set +CONFIG_SCSI_PROC_FS=y +# CONFIG_SCSI_QLA_FC is not set +# CONFIG_SCSI_QLA_ISCSI is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SCAN_ASYNC is not set +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_SRP is not set +# CONFIG_SCSI_SRP_ATTRS is not set +# CONFIG_SCSI_STEX is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_TGT is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_UFSHCD is not set +# CONFIG_SCSI_ULTRASTOR is not set +# CONFIG_SCSI_VIRTIO is not set +# CONFIG_SCSI_WD719X is not set +# CONFIG_SCx200_ACB is not set +# CONFIG_SDIO_UART is not set +# CONFIG_SECCOMP is not set +# CONFIG_SECURITY is not set +# CONFIG_SECURITYFS is not set +# CONFIG_SECURITY_DMESG_RESTRICT is not set +# CONFIG_SEEQ8005 is not set +CONFIG_SELECT_MEMORY_MODEL=y +# CONFIG_SENSORS_ABITUGURU is not set +# CONFIG_SENSORS_ABITUGURU3 is not set +# CONFIG_SENSORS_ACPI_POWER is not set +# CONFIG_SENSORS_AD7314 is not set +# CONFIG_SENSORS_AD7414 is not set +# CONFIG_SENSORS_AD7418 is not set +# CONFIG_SENSORS_ADC128D818 is not set +# CONFIG_SENSORS_ADCXX is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1029 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_ADS1015 is not set +# CONFIG_SENSORS_ADS7828 is not set +# CONFIG_SENSORS_ADS7871 is not set +# CONFIG_SENSORS_ADT7310 is not set +# CONFIG_SENSORS_ADT7410 is not set +# CONFIG_SENSORS_ADT7411 is not set +# CONFIG_SENSORS_ADT7462 is not set +# CONFIG_SENSORS_ADT7470 is not set +# CONFIG_SENSORS_ADT7475 is not set +# CONFIG_SENSORS_AMC6821 is not set +# CONFIG_SENSORS_APDS990X is not set +# CONFIG_SENSORS_APPLESMC is not set +# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_ASC7621 is not set +# CONFIG_SENSORS_ATK0110 is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_BH1770 is not set +# CONFIG_SENSORS_BH1780 is not set +# CONFIG_SENSORS_CORETEMP is not set +# CONFIG_SENSORS_DME1737 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_DS620 is not set +# CONFIG_SENSORS_EMC1403 is not set +# CONFIG_SENSORS_EMC2103 is not set +# CONFIG_SENSORS_EMC6W201 is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_F75375S is not set +# CONFIG_SENSORS_FAM15H_POWER is not set +# CONFIG_SENSORS_FSCHMD is not set +# CONFIG_SENSORS_G760A is not set +# CONFIG_SENSORS_G762 is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_GPIO_FAN is not set +# CONFIG_SENSORS_GSC is not set +# CONFIG_SENSORS_HDAPS is not set +# CONFIG_SENSORS_HIH6130 is not set +# CONFIG_SENSORS_HMC5843 is not set +# CONFIG_SENSORS_HMC5843_I2C is not set +# CONFIG_SENSORS_HMC5843_SPI is not set +# CONFIG_SENSORS_HTU21 is not set +# CONFIG_SENSORS_I5500 is not set +# CONFIG_SENSORS_I5K_AMB is not set +# CONFIG_SENSORS_IIO_HWMON is not set +# CONFIG_SENSORS_INA209 is not set +# CONFIG_SENSORS_INA2XX is not set +# CONFIG_SENSORS_ISL29018 is not set +# CONFIG_SENSORS_ISL29028 is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_JC42 is not set +# CONFIG_SENSORS_K10TEMP is not set +# CONFIG_SENSORS_K8TEMP is not set +# CONFIG_SENSORS_LINEAGE is not set +# CONFIG_SENSORS_LIS3LV02D is not set +# CONFIG_SENSORS_LIS3_I2C is not set +# CONFIG_SENSORS_LIS3_SPI is not set +# CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM70 is not set +# CONFIG_SENSORS_LM73 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_LM93 is not set +# CONFIG_SENSORS_LM95234 is not set +# CONFIG_SENSORS_LM95241 is not set +# CONFIG_SENSORS_LM95245 is not set +# CONFIG_SENSORS_LTC2945 is not set +# CONFIG_SENSORS_LTC4151 is not set +# CONFIG_SENSORS_LTC4215 is not set +# CONFIG_SENSORS_LTC4222 is not set +# CONFIG_SENSORS_LTC4245 is not set +# CONFIG_SENSORS_LTC4260 is not set +# CONFIG_SENSORS_LTC4261 is not set +# CONFIG_SENSORS_MAX1111 is not set +# CONFIG_SENSORS_MAX16065 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_MAX1668 is not set +# CONFIG_SENSORS_MAX197 is not set +# CONFIG_SENSORS_MAX6639 is not set +# CONFIG_SENSORS_MAX6642 is not set +# CONFIG_SENSORS_MAX6650 is not set +# CONFIG_SENSORS_MAX6697 is not set +# CONFIG_SENSORS_MCP3021 is not set +# CONFIG_SENSORS_NCT6683 is not set +# CONFIG_SENSORS_NCT6775 is not set +# CONFIG_SENSORS_NCT7802 is not set +# CONFIG_SENSORS_NTC_THERMISTOR is not set +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_POWR1220 is not set +# CONFIG_SENSORS_SCH5627 is not set +# CONFIG_SENSORS_SCH5636 is not set +# CONFIG_SENSORS_SCH56XX_COMMON is not set +# CONFIG_SENSORS_SHT15 is not set +# CONFIG_SENSORS_SHT21 is not set +# CONFIG_SENSORS_SHTC1 is not set +# CONFIG_SENSORS_SIS5595 is not set +# CONFIG_SENSORS_SMM665 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_THMC50 is not set +# CONFIG_SENSORS_TMP102 is not set +# CONFIG_SENSORS_TMP103 is not set +# CONFIG_SENSORS_TMP401 is not set +# CONFIG_SENSORS_TMP421 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_SENSORS_TSL2563 is not set +# CONFIG_SENSORS_VEXPRESS is not set +# CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_VIA_CPUTEMP is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_VT8231 is not set +# CONFIG_SENSORS_W83627EHF is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83791D is not set +# CONFIG_SENSORS_W83792D is not set +# CONFIG_SENSORS_W83793 is not set +# CONFIG_SENSORS_W83795 is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83L786NG is not set +CONFIG_SERIAL_8250=y +# CONFIG_SERIAL_8250_ACCENT is not set +# CONFIG_SERIAL_8250_BOCA is not set +CONFIG_SERIAL_8250_CONSOLE=y +# CONFIG_SERIAL_8250_CS is not set +# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +CONFIG_SERIAL_8250_DMA=y +# CONFIG_SERIAL_8250_DW is not set +# CONFIG_SERIAL_8250_EM is not set +# CONFIG_SERIAL_8250_EXAR_ST16C554 is not set +# CONFIG_SERIAL_8250_EXTENDED is not set +# CONFIG_SERIAL_8250_FINTEK is not set +# CONFIG_SERIAL_8250_FOURPORT is not set +# CONFIG_SERIAL_8250_HUB6 is not set +# CONFIG_SERIAL_8250_MANY_PORTS is not set +CONFIG_SERIAL_8250_NR_UARTS=2 +# CONFIG_SERIAL_8250_PCI is not set +# CONFIG_SERIAL_8250_RSA is not set +CONFIG_SERIAL_8250_RUNTIME_UARTS=2 +# CONFIG_SERIAL_8250_SYSRQ is not set +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +# CONFIG_SERIAL_ARC is not set +# CONFIG_SERIAL_BCM63XX is not set +# CONFIG_SERIAL_CONEXANT_DIGICOLOR is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_SERIAL_EARLYCON=y +# CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST is not set +# CONFIG_SERIAL_FSL_LPUART is not set +# CONFIG_SERIAL_GRLIB_GAISLER_APBUART is not set +# CONFIG_SERIAL_IFX6X60 is not set +# CONFIG_SERIAL_JSM is not set +# CONFIG_SERIAL_MAX3100 is not set +# CONFIG_SERIAL_MAX3107 is not set +# CONFIG_SERIAL_MAX310X is not set +# CONFIG_SERIAL_MFD_HSU is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_SERIAL_OF_PLATFORM is not set +# CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL is not set +# CONFIG_SERIAL_PCH_UART is not set +# CONFIG_SERIAL_RP2 is not set +# CONFIG_SERIAL_SC16IS7XX is not set +# CONFIG_SERIAL_SCCNXP is not set +# CONFIG_SERIAL_SH_SCI is not set +# CONFIG_SERIAL_ST_ASC is not set +# CONFIG_SERIAL_TIMBERDALE is not set +# CONFIG_SERIAL_UARTLITE is not set +# CONFIG_SERIAL_XILINX_PS_UART is not set +# CONFIG_SERIO is not set +# CONFIG_SERIO_ALTERA_PS2 is not set +# CONFIG_SERIO_AMBAKMI is not set +# CONFIG_SERIO_ARC_PS2 is not set +# CONFIG_SERIO_I8042 is not set +# CONFIG_SERIO_LIBPS2 is not set +# CONFIG_SERIO_PARKBD is not set +# CONFIG_SERIO_PCIPS2 is not set +# CONFIG_SERIO_PS2MULT is not set +# CONFIG_SERIO_RAW is not set +# CONFIG_SERIO_SERPORT is not set +# CONFIG_SFC is not set +# CONFIG_SFI is not set +# CONFIG_SGETMASK_SYSCALL is not set +# CONFIG_SGI_IOC4 is not set +# CONFIG_SGI_IP22 is not set +# CONFIG_SGI_IP27 is not set +# CONFIG_SGI_IP28 is not set +# CONFIG_SGI_IP32 is not set +# CONFIG_SGI_PARTITION is not set +CONFIG_SHMEM=y +# CONFIG_SH_ETH is not set +# CONFIG_SH_TIMER_CMT is not set +# CONFIG_SH_TIMER_MTU2 is not set +# CONFIG_SH_TIMER_TMU is not set +# CONFIG_SI7005 is not set +# CONFIG_SI7020 is not set +# CONFIG_SIBYTE_BIGSUR is not set +# CONFIG_SIBYTE_CARMEL is not set +# CONFIG_SIBYTE_CRHINE is not set +# CONFIG_SIBYTE_CRHONE is not set +# CONFIG_SIBYTE_LITTLESUR is not set +# CONFIG_SIBYTE_RHONE is not set +# CONFIG_SIBYTE_SENTOSA is not set +# CONFIG_SIBYTE_SWARM is not set +# CONFIG_SIGMA is not set +CONFIG_SIGNALFD=y +# CONFIG_SIMPLE_GPIO is not set +# CONFIG_SIS190 is not set +# CONFIG_SIS900 is not set +# CONFIG_SKGE is not set +# CONFIG_SKY2 is not set +# CONFIG_SKY2_DEBUG is not set +CONFIG_SLAB=y +CONFIG_SLABINFO=y +# CONFIG_SLHC is not set +# CONFIG_SLICOSS is not set +# CONFIG_SLIP is not set +# CONFIG_SLOB is not set +# CONFIG_SLUB is not set +# CONFIG_SLUB_DEBUG is not set +# CONFIG_SLUB_STATS is not set +# CONFIG_SMARTJOYPLUS_FF is not set +# CONFIG_SMC911X is not set +# CONFIG_SMC9194 is not set +# CONFIG_SMC91X is not set +# CONFIG_SMP is not set +# CONFIG_SMSC911X is not set +# CONFIG_SMSC9420 is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_SM_FTL is not set +# CONFIG_SND is not set +# CONFIG_SND_AC97_POWER_SAVE is not set +# CONFIG_SND_AD1816A is not set +# CONFIG_SND_AD1848 is not set +# CONFIG_SND_AD1889 is not set +# CONFIG_SND_ADLIB is not set +# CONFIG_SND_ALI5451 is not set +# CONFIG_SND_ALOOP is not set +# CONFIG_SND_ALS100 is not set +# CONFIG_SND_ALS300 is not set +# CONFIG_SND_ALS4000 is not set +# CONFIG_SND_ARM is not set +# CONFIG_SND_ASIHPI is not set +# CONFIG_SND_ATIIXP is not set +# CONFIG_SND_ATIIXP_MODEM is not set +# CONFIG_SND_ATMEL_AC97C is not set +# CONFIG_SND_ATMEL_SOC is not set +# CONFIG_SND_AU8810 is not set +# CONFIG_SND_AU8820 is not set +# CONFIG_SND_AU8830 is not set +# CONFIG_SND_AW2 is not set +# CONFIG_SND_AZT2320 is not set +# CONFIG_SND_AZT3328 is not set +# CONFIG_SND_BCD2000 is not set +# CONFIG_SND_BT87X is not set +# CONFIG_SND_CA0106 is not set +# CONFIG_SND_CMI8330 is not set +# CONFIG_SND_CMIPCI is not set +# CONFIG_SND_CS4231 is not set +# CONFIG_SND_CS4236 is not set +# CONFIG_SND_CS4281 is not set +# CONFIG_SND_CS46XX is not set +# CONFIG_SND_CS5530 is not set +# CONFIG_SND_CS5535AUDIO is not set +# CONFIG_SND_CTXFI is not set +# CONFIG_SND_DARLA20 is not set +# CONFIG_SND_DARLA24 is not set +# CONFIG_SND_DEBUG is not set +# CONFIG_SND_DESIGNWARE_I2S is not set +CONFIG_SND_DRIVERS=y +# CONFIG_SND_DUMMY is not set +# CONFIG_SND_DYNAMIC_MINORS is not set +# CONFIG_SND_ECHO3G is not set +# CONFIG_SND_EMU10K1 is not set +# CONFIG_SND_EMU10K1X is not set +# CONFIG_SND_ENS1370 is not set +# CONFIG_SND_ENS1371 is not set +# CONFIG_SND_ES1688 is not set +# CONFIG_SND_ES18XX is not set +# CONFIG_SND_ES1938 is not set +# CONFIG_SND_ES1968 is not set +# CONFIG_SND_FIREWIRE is not set +# CONFIG_SND_FM801 is not set +# CONFIG_SND_GINA20 is not set +# CONFIG_SND_GINA24 is not set +# CONFIG_SND_GUSCLASSIC is not set +# CONFIG_SND_GUSEXTREME is not set +# CONFIG_SND_GUSMAX is not set +# CONFIG_SND_HDA_INTEL is not set +# CONFIG_SND_HDSP is not set +# CONFIG_SND_HDSPM is not set +# CONFIG_SND_HRTIMER is not set +# CONFIG_SND_HWDEP is not set +# CONFIG_SND_ICE1712 is not set +# CONFIG_SND_ICE1724 is not set +# CONFIG_SND_INDIGO is not set +# CONFIG_SND_INDIGODJ is not set +# CONFIG_SND_INDIGODJX is not set +# CONFIG_SND_INDIGOIO is not set +# CONFIG_SND_INDIGOIOX is not set +# CONFIG_SND_INTEL8X0 is not set +# CONFIG_SND_INTEL8X0M is not set +# CONFIG_SND_INTERWAVE is not set +# CONFIG_SND_INTERWAVE_STB is not set +# CONFIG_SND_ISA is not set +# CONFIG_SND_KIRKWOOD_SOC is not set +# CONFIG_SND_KORG1212 is not set +# CONFIG_SND_LAYLA20 is not set +# CONFIG_SND_LAYLA24 is not set +# CONFIG_SND_LOLA is not set +# CONFIG_SND_LX6464ES is not set +# CONFIG_SND_MAESTRO3 is not set +# CONFIG_SND_MIA is not set +# CONFIG_SND_MIPS is not set +# CONFIG_SND_MIRO is not set +# CONFIG_SND_MIXART is not set +# CONFIG_SND_MIXER_OSS is not set +# CONFIG_SND_MONA is not set +# CONFIG_SND_MPC52xx_SOC_EFIKA is not set +# CONFIG_SND_MPU401 is not set +# CONFIG_SND_MTPAV is not set +# CONFIG_SND_MTS64 is not set +# CONFIG_SND_MXS_SOC is not set +# CONFIG_SND_NM256 is not set +# CONFIG_SND_OPL3SA2 is not set +# CONFIG_SND_OPTI92X_AD1848 is not set +# CONFIG_SND_OPTI92X_CS4231 is not set +# CONFIG_SND_OPTI93X is not set +CONFIG_SND_OSSEMUL=y +# CONFIG_SND_OXYGEN is not set +CONFIG_SND_PCI=y +# CONFIG_SND_PCM is not set +# CONFIG_SND_PCMCIA is not set +# CONFIG_SND_PCM_OSS is not set +CONFIG_SND_PCM_OSS_PLUGINS=y +# CONFIG_SND_PCXHR is not set +# CONFIG_SND_PDAUDIOCF is not set +# CONFIG_SND_PORTMAN2X4 is not set +# CONFIG_SND_POWERPC_SOC is not set +# CONFIG_SND_PPC is not set +# CONFIG_SND_RAWMIDI is not set +# CONFIG_SND_RIPTIDE is not set +# CONFIG_SND_RME32 is not set +# CONFIG_SND_RME96 is not set +# CONFIG_SND_RME9652 is not set +# CONFIG_SND_SE6X is not set +# CONFIG_SND_RTCTIMER is not set +# CONFIG_SND_SB16 is not set +# CONFIG_SND_SB8 is not set +# CONFIG_SND_SBAWE is not set +# CONFIG_SND_SEQUENCER is not set +# CONFIG_SND_SERIAL_U16550 is not set +# CONFIG_SND_SIMPLE_CARD is not set +# CONFIG_SND_SIS7019 is not set +# CONFIG_SND_SOC is not set +# CONFIG_SND_SOC_ADAU1701 is not set +# CONFIG_SND_SOC_AK4104 is not set +# CONFIG_SND_SOC_AK4554 is not set +# CONFIG_SND_SOC_AK4642 is not set +# CONFIG_SND_SOC_AK5386 is not set +# CONFIG_SND_SOC_ALC5623 is not set +# CONFIG_SND_SOC_AU1XAUDIO is not set +# CONFIG_SND_SOC_AU1XPSC is not set +# CONFIG_SND_SOC_CACHE_LZO is not set +# CONFIG_SND_SOC_CS35L32 is not set +# CONFIG_SND_SOC_CS4265 is not set +# CONFIG_SND_SOC_CS4270 is not set +# CONFIG_SND_SOC_CS4271 is not set +# CONFIG_SND_SOC_CS4271_I2C is not set +# CONFIG_SND_SOC_CS4271_SND is not set +# CONFIG_SND_SOC_CS4271_SPI is not set +# CONFIG_SND_SOC_CS42L51_I2C is not set +# CONFIG_SND_SOC_CS42L52 is not set +# CONFIG_SND_SOC_CS42L56 is not set +# CONFIG_SND_SOC_CS42L73 is not set +# CONFIG_SND_SOC_CS42L73 is not set +# CONFIG_SND_SOC_CS42XX8_I2C is not set +# CONFIG_SND_SOC_ES8328 is not set +# CONFIG_SND_SOC_EUKREA_TLV320 is not set +# CONFIG_SND_SOC_FSL_ASOC_CARD is not set +# CONFIG_SND_SOC_FSL_ASRC is not set +# CONFIG_SND_SOC_FSL_ESAI is not set +# CONFIG_SND_SOC_FSL_SAI is not set +# CONFIG_SND_SOC_FSL_SPDIF is not set +# CONFIG_SND_SOC_HDMI_CODEC is not set +# CONFIG_SND_SOC_IMX_ES8328 is not set +# CONFIG_SND_SOC_IMX_SPDIF is not set +# CONFIG_SND_SOC_IMX_WM8962 is not set +# CONFIG_SND_SOC_INTEL_SST is not set +# CONFIG_SND_SOC_MPC5200_AC97 is not set +# CONFIG_SND_SOC_MPC5200_I2S is not set +# CONFIG_SND_SOC_PCM1681 is not set +# CONFIG_SND_SOC_PCM1792A is not set +# CONFIG_SND_SOC_PCM512x_I2C is not set +# CONFIG_SND_SOC_PCM512x_SPI is not set +# CONFIG_SND_SOC_RT5631 is not set +# CONFIG_SND_SOC_SGTL5000 is not set +# CONFIG_SND_SOC_SIRF_AUDIO_CODEC is not set +# CONFIG_SND_SOC_SPDIF is not set +# CONFIG_SND_SOC_SSM2602_I2C is not set +# CONFIG_SND_SOC_SSM2602_SPI is not set +# CONFIG_SND_SOC_SSM4567 is not set +# CONFIG_SND_SOC_STA32X is not set +# CONFIG_SND_SOC_STA350 is not set +# CONFIG_SND_SOC_TAS2552 is not set +# CONFIG_SND_SOC_TAS5086 is not set +# CONFIG_SND_SOC_TFA9879 is not set +# CONFIG_SND_SOC_TLV320AIC23_I2C is not set +# CONFIG_SND_SOC_TLV320AIC23_SPI is not set +# CONFIG_SND_SOC_TLV320AIC31XX is not set +# CONFIG_SND_SOC_TLV320AIC3X is not set +# CONFIG_SND_SOC_TPA6130A2 is not set +# CONFIG_SND_SOC_TS3A227E is not set +# CONFIG_SND_SOC_WM8510 is not set +# CONFIG_SND_SOC_WM8523 is not set +# CONFIG_SND_SOC_WM8580 is not set +# CONFIG_SND_SOC_WM8711 is not set +# CONFIG_SND_SOC_WM8728 is not set +# CONFIG_SND_SOC_WM8731 is not set +# CONFIG_SND_SOC_WM8737 is not set +# CONFIG_SND_SOC_WM8741 is not set +# CONFIG_SND_SOC_WM8750 is not set +# CONFIG_SND_SOC_WM8753 is not set +# CONFIG_SND_SOC_WM8770 is not set +# CONFIG_SND_SOC_WM8776 is not set +# CONFIG_SND_SOC_WM8804 is not set +# CONFIG_SND_SOC_WM8903 is not set +# CONFIG_SND_SOC_WM8962 is not set +# CONFIG_SND_SOC_WM8978 is not set +# CONFIG_SND_SOC_XTFPGA_I2S is not set +# CONFIG_SND_SONICVIBES is not set +# CONFIG_SND_SPI is not set +# CONFIG_SND_SSCAPE is not set +# CONFIG_SND_SUPPORT_OLD_API is not set +# CONFIG_SND_TIMER is not set +# CONFIG_SND_TRIDENT is not set +CONFIG_SND_USB=y +# CONFIG_SND_USB_6FIRE is not set +# CONFIG_SND_USB_AUDIO is not set +# CONFIG_SND_USB_CAIAQ is not set +# CONFIG_SND_USB_HIFACE is not set +# CONFIG_SND_USB_POD is not set +# CONFIG_SND_USB_PODHD is not set +# CONFIG_SND_USB_TONEPORT is not set +# CONFIG_SND_USB_UA101 is not set +# CONFIG_SND_USB_US122L is not set +# CONFIG_SND_USB_USX2Y is not set +# CONFIG_SND_USB_VARIAX is not set +# CONFIG_SND_VERBOSE_PRINTK is not set +CONFIG_SND_VERBOSE_PROCFS=y +# CONFIG_SND_VIA82XX is not set +# CONFIG_SND_VIA82XX_MODEM is not set +# CONFIG_SND_VIRTUOSO is not set +# CONFIG_SND_VX222 is not set +# CONFIG_SND_VXPOCKET is not set +# CONFIG_SND_WAVEFRONT is not set +# CONFIG_SND_YMFPCI is not set +# CONFIG_SNI_RM is not set +# CONFIG_SOC_AM33XX is not set +# CONFIG_SOC_AM43XX is not set +# CONFIG_SOC_CAMERA is not set +# CONFIG_SOC_DRA7XX is not set +# CONFIG_SOC_HAS_OMAP2_SDRC is not set +# CONFIG_SOC_OMAP5 is not set +# CONFIG_SOC_TI is not set +# CONFIG_SOFT_WATCHDOG is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_SOLO6X10 is not set +# CONFIG_SONYPI is not set +# CONFIG_SONY_LAPTOP is not set +# CONFIG_SOUND is not set +# CONFIG_SOUND_PRIME is not set +# CONFIG_SP5100_TCO is not set +# CONFIG_SPARSEMEM_MANUAL is not set +# CONFIG_SPARSEMEM_STATIC is not set +# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set +# CONFIG_SPARSE_IRQ is not set +# CONFIG_SPARSE_RCU_POINTER is not set +# CONFIG_SPEAKUP is not set +# CONFIG_SPI is not set +# CONFIG_SPINLOCK_TEST is not set +# CONFIG_SPI_ALTERA is not set +# CONFIG_SPI_AU1550 is not set +# CONFIG_SPI_BCM2835 is not set +# CONFIG_SPI_BITBANG is not set +# CONFIG_SPI_BUTTERFLY is not set +# CONFIG_SPI_CADENCE is not set +# CONFIG_SPI_DEBUG is not set +# CONFIG_SPI_DESIGNWARE is not set +# CONFIG_SPI_FSL_DSPI is not set +# CONFIG_SPI_FSL_ESPI is not set +# CONFIG_SPI_FSL_SPI is not set +# CONFIG_SPI_GPIO is not set +# CONFIG_SPI_GPIO_OLD is not set +# CONFIG_SPI_IMG_SPFI is not set +# CONFIG_SPI_LM70_LLP is not set +# CONFIG_SPI_MASTER is not set +# CONFIG_SPI_MPC52xx is not set +# CONFIG_SPI_MPC52xx_PSC is not set +# CONFIG_SPI_OC_TINY is not set +# CONFIG_SPI_OCTEON is not set +# CONFIG_SPI_ORION is not set +# CONFIG_SPI_PL022 is not set +# CONFIG_SPI_PPC4xx is not set +# CONFIG_SPI_PXA2XX is not set +# CONFIG_SPI_PXA2XX_PCI is not set +# CONFIG_SPI_RAMIPS is not set +# CONFIG_SPI_ROCKCHIP is not set +# CONFIG_SPI_SC18IS602 is not set +# CONFIG_SPI_SPIDEV is not set +# CONFIG_SPI_TI_QSPI is not set +# CONFIG_SPI_TLE62X0 is not set +# CONFIG_SPI_TOPCLIFF_PCH is not set +# CONFIG_SPI_XCOMM is not set +# CONFIG_SPI_XILINX is not set +# CONFIG_SPI_XWAY is not set +# CONFIG_SPMI is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_SQUASHFS=y +# CONFIG_SQUASHFS_4K_DEVBLK_SIZE is not set +# CONFIG_SQUASHFS_DECOMP_MULTI is not set +CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU=y +# CONFIG_SQUASHFS_DECOMP_SINGLE is not set +# CONFIG_SQUASHFS_EMBEDDED is not set +# CONFIG_SQUASHFS_FILE_CACHE is not set +CONFIG_SQUASHFS_FILE_DIRECT=y +CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3 +# CONFIG_SQUASHFS_LZ4 is not set +# CONFIG_SQUASHFS_LZO is not set +# CONFIG_SQUASHFS_XATTR is not set +CONFIG_SQUASHFS_XZ=y +# CONFIG_SQUASHFS_ZLIB is not set +# CONFIG_SRAM is not set +# CONFIG_SSB is not set +# CONFIG_SSBI is not set +# CONFIG_SSB_DEBUG is not set +# CONFIG_SSB_DRIVER_GPIO is not set +# CONFIG_SSB_PCMCIAHOST is not set +CONFIG_SSB_POSSIBLE=y +# CONFIG_SSB_SDIOHOST is not set +# CONFIG_SSB_SILENT is not set +# CONFIG_SSFDC is not set +CONFIG_STACKTRACE_SUPPORT=y +# CONFIG_STACKTRACE is not set +# CONFIG_STACK_TRACER is not set +CONFIG_STAGING=y +# CONFIG_STAGING_MEDIA is not set +CONFIG_STANDALONE=y +CONFIG_STDBINUTILS=y +# CONFIG_STE10XP is not set +# CONFIG_STE_MODEM_RPROC is not set +# CONFIG_STMMAC_ETH is not set +# CONFIG_STMMAC_PLATFORM is not set +# CONFIG_STMMAC_PCI is not set +CONFIG_STP=y +# CONFIG_STRICT_DEVMEM is not set +CONFIG_STRIP_ASM_SYMS=y +# CONFIG_STUB_POULSBO is not set +# CONFIG_SUNDANCE is not set +# CONFIG_SUNGEM is not set +# CONFIG_SUNRPC is not set +# CONFIG_SUNRPC_DEBUG is not set +# CONFIG_SUNRPC_GSS is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_SUSPEND is not set +CONFIG_SWAP=y +# CONFIG_SWCONFIG is not set +# CONFIG_SWCONFIG_LEDS is not set +# CONFIG_SX9500 is not set +# CONFIG_SXGBE_ETH is not set +# CONFIG_SYNCLINK_CS is not set +CONFIG_SYN_COOKIES=y +CONFIG_SYSCTL=y +# CONFIG_SYSCTL_SYSCALL is not set +# CONFIG_SYSCTL_SYSCALL_CHECK is not set +CONFIG_SYSFS=y +# CONFIG_SYSFS_DEPRECATED is not set +# CONFIG_SYSFS_DEPRECATED_V2 is not set +# CONFIG_SYSFS_SYSCALL is not set +# CONFIG_SYSTEMPORT is not set +# CONFIG_SYSTEM_TRUSTED_KEYRING is not set +# CONFIG_SYSV68_PARTITION is not set +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +# CONFIG_SYSV_FS is not set +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_T5403 is not set +# CONFIG_TARGET_CORE is not set +# CONFIG_TASKSTATS is not set +# CONFIG_TASKS_RCU is not set +# CONFIG_TC35815 is not set +# CONFIG_TCG_TPM is not set +# CONFIG_TCIC is not set +CONFIG_TCP_CONG_ADVANCED=y +# CONFIG_TCP_CONG_BIC is not set +CONFIG_TCP_CONG_CUBIC=y +# CONFIG_TCP_CONG_DCTCP is not set +# CONFIG_TCP_CONG_HSTCP is not set +# CONFIG_TCP_CONG_HTCP is not set +# CONFIG_TCP_CONG_HYBLA is not set +# CONFIG_TCP_CONG_ILLINOIS is not set +# CONFIG_TCP_CONG_LP is not set +# CONFIG_TCP_CONG_SCALABLE is not set +# CONFIG_TCP_CONG_VEGAS is not set +# CONFIG_TCP_CONG_VENO is not set +# CONFIG_TCP_CONG_WESTWOOD is not set +# CONFIG_TCP_CONG_YEAH is not set +# CONFIG_TCP_MD5SIG is not set +# CONFIG_TCS3414 is not set +# CONFIG_TCS3472 is not set +# CONFIG_TEGRA_AHB is not set +# CONFIG_TEGRA_HOST1X is not set +# CONFIG_TEHUTI is not set +# CONFIG_TEST_BPF is not set +# CONFIG_TEST_UDELAY is not set +# CONFIG_TEST_FIRMWARE is not set +# CONFIG_TEST_HEXDUMP is not set +# CONFIG_TEST_KSTRTOX is not set +# CONFIG_TEST_LIST_SORT is not set +# CONFIG_TEST_LKM is not set +# CONFIG_TEST_MODULE is not set +# CONFIG_TEST_POWER is not set +# CONFIG_TEST_RHASHTABLE is not set +# CONFIG_TEST_STRING_HELPERS is not set +# CONFIG_TEST_USER_COPY is not set +CONFIG_TEXTSEARCH=y +# CONFIG_TEXTSEARCH_BM is not set +# CONFIG_TEXTSEARCH_FSM is not set +# CONFIG_TEXTSEARCH_KMP is not set +# CONFIG_THERMAL is not set +# CONFIG_THERMAL_GOV_BANG_BANG is not set +# CONFIG_THERMAL_HWMON is not set +# CONFIG_THINKPAD_ACPI is not set +# CONFIG_THRUSTMASTER_FF is not set +# CONFIG_THUNDERBOLT is not set +# CONFIG_TICK_CPU_ACCOUNTING is not set +CONFIG_TICK_ONESHOT=y +# CONFIG_TIFM_CORE is not set +# CONFIG_TIGON3 is not set +# CONFIG_TIMB_DMA is not set +CONFIG_TIMERFD=y +# CONFIG_TIMER_STATS is not set +CONFIG_TINY_RCU=y +# CONFIG_TIPC is not set +# CONFIG_TI_ADC081C is not set +# CONFIG_TI_ADC128S052 is not set +# CONFIG_TI_AM335X_ADC is not set +# CONFIG_TI_CPSW is not set +# CONFIG_TI_CPSW_ALE is not set +# CONFIG_TI_CPTS is not set +# CONFIG_TI_DAC7512 is not set +# CONFIG_TI_DAVINCI_CPDMA is not set +# CONFIG_TI_DAVINCI_MDIO is not set +# CONFIG_TI_ST is not set +# CONFIG_TLAN is not set +# CONFIG_TMD_HERMES is not set +# CONFIG_TMP006 is not set +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +CONFIG_TMPFS_XATTR=y +# CONFIG_TOPSTAR_LAPTOP is not set +# CONFIG_TORTURE_TEST is not set +# CONFIG_TOSHIBA_HAPS is not set +# CONFIG_TOUCHSCREEN_AD7877 is not set +# CONFIG_TOUCHSCREEN_AD7879 is not set +# CONFIG_TOUCHSCREEN_AD7879_I2C is not set +# CONFIG_TOUCHSCREEN_AD7879_SPI is not set +# CONFIG_TOUCHSCREEN_ADS7846 is not set +# CONFIG_TOUCHSCREEN_AR1021_I2C is not set +# CONFIG_TOUCHSCREEN_ATMEL_MXT is not set +# CONFIG_TOUCHSCREEN_AUO_PIXCIR is not set +# CONFIG_TOUCHSCREEN_BU21013 is not set +# CONFIG_TOUCHSCREEN_CLEARPAD_TM1217 is not set +# CONFIG_TOUCHSCREEN_CY8CTMG110 is not set +# CONFIG_TOUCHSCREEN_CYTTSP_CORE is not set +# CONFIG_TOUCHSCREEN_CYTTSP4_CORE is not set +# CONFIG_TOUCHSCREEN_DYNAPRO is not set +# CONFIG_TOUCHSCREEN_EDT_FT5X06 is not set +# CONFIG_TOUCHSCREEN_EETI is not set +# CONFIG_TOUCHSCREEN_EGALAX is not set +# CONFIG_TOUCHSCREEN_ELO is not set +# CONFIG_TOUCHSCREEN_FUJITSU is not set +# CONFIG_TOUCHSCREEN_GUNZE is not set +# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set +# CONFIG_TOUCHSCREEN_ILI210X is not set +# CONFIG_TOUCHSCREEN_INEXIO is not set +# CONFIG_TOUCHSCREEN_MAX11801 is not set +# CONFIG_TOUCHSCREEN_MCS5000 is not set +# CONFIG_TOUCHSCREEN_MK712 is not set +# CONFIG_TOUCHSCREEN_MMS114 is not set +# CONFIG_TOUCHSCREEN_MTOUCH is not set +# CONFIG_TOUCHSCREEN_PENMOUNT is not set +# CONFIG_TOUCHSCREEN_PIXCIR is not set +# CONFIG_TOUCHSCREEN_S3C2410 is not set +# CONFIG_TOUCHSCREEN_ST1232 is not set +# CONFIG_TOUCHSCREEN_SUR40 is not set +# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4 is not set +# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set +# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set +# CONFIG_TOUCHSCREEN_TOUCHWIN is not set +# CONFIG_TOUCHSCREEN_TPS6507X is not set +# CONFIG_TOUCHSCREEN_TSC2005 is not set +# CONFIG_TOUCHSCREEN_TSC2007 is not set +# CONFIG_TOUCHSCREEN_TSC_SERIO is not set +# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set +# CONFIG_TOUCHSCREEN_W90X900 is not set +# CONFIG_TOUCHSCREEN_WACOM_I2C is not set +# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set +# CONFIG_TOUCHSCREEN_WM97XX is not set +# CONFIG_TOUCHSCREEN_ZFORCE is not set +# CONFIG_TPS6105X is not set +# CONFIG_TPS65010 is not set +# CONFIG_TPS6507X is not set +# CONFIG_TR is not set +# CONFIG_TRACEPOINT_BENCHMARK is not set +# CONFIG_TRACER_SNAPSHOT is not set +# CONFIG_TRACER_SNAPSHOT_PER_CPU_SWAP is not set +# CONFIG_TRACE_BRANCH_PROFILING is not set +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +# CONFIG_TRACE_SINK is not set +CONFIG_TRACING_SUPPORT=y +CONFIG_TRAD_SIGNALS=y +# CONFIG_TRANSPARENT_HUGEPAGE is not set +# CONFIG_TRANZPORT is not set +# CONFIG_TREE_PREEMPT_RCU is not set +# CONFIG_TREE_RCU is not set +# CONFIG_TREE_RCU_TRACE is not set +# CONFIG_TSL2583 is not set +# CONFIG_TSL2x7x is not set +# CONFIG_TSL4531 is not set +CONFIG_TTY=y +# CONFIG_TTY_PRINTK is not set +# CONFIG_TUN is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_TWL6030_GPADC is not set +# CONFIG_TWL6040_CORE is not set +# CONFIG_TYPHOON is not set +# CONFIG_UACCESS_WITH_MEMCPY is not set +# CONFIG_UCB1400_CORE is not set +# CONFIG_UDF_FS is not set +CONFIG_UDF_NLS=y +CONFIG_UEVENT_HELPER=y +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +# CONFIG_UFS_FS is not set +# CONFIG_UHID is not set +CONFIG_UIDGID_STRICT_TYPE_CHECKS=y +# CONFIG_UIO is not set +# CONFIG_ULTRA is not set +# CONFIG_ULTRIX_PARTITION is not set +CONFIG_UNIX=y +CONFIG_UNIX98_PTYS=y +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_UNIX_DIAG is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_UPROBE_EVENT is not set +# CONFIG_UPROBES is not set +# CONFIG_USB is not set +# CONFIG_USBIP_CORE is not set +# CONFIG_USBPCWATCHDOG is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_ADUTUX is not set +CONFIG_USB_ALI_M5632=y +# CONFIG_USB_AMD5536UDC is not set +CONFIG_USB_AN2720=y +# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set +# CONFIG_USB_APPLEDISPLAY is not set +CONFIG_USB_ARCH_HAS_EHCI=y +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +CONFIG_USB_ARMLINUX=y +# CONFIG_USB_ATM is not set +# CONFIG_USB_BDC_UDC is not set +CONFIG_USB_BELKIN=y +# CONFIG_USB_BTMTK is not set +# CONFIG_USB_C67X00_HCD is not set +# CONFIG_USB_CATC is not set +# CONFIG_USB_CDC_COMPOSITE is not set +# CONFIG_USB_CHIPIDEA is not set +# CONFIG_USB_CONFIGFS is not set +# CONFIG_USB_CXACRU is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_DEBUG is not set +CONFIG_USB_DEFAULT_PERSIST=y +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_DEVICE_CLASS is not set +# CONFIG_USB_DSBR is not set +# CONFIG_USB_DUMMY_HCD is not set +# CONFIG_USB_DWC2 is not set +# CONFIG_USB_DWC2_DUAL_ROLE is not set +# CONFIG_USB_DWC2_HOST is not set +# CONFIG_USB_DWC2_PERIPHERAL is not set +# CONFIG_USB_DWC3 is not set +# CONFIG_USB_DWC3_EXYNOS is not set +# CONFIG_USB_DWC3_QCOM is not set +# CONFIG_USB_DWC3_PCI is not set +# CONFIG_USB_DWC3_KEYSTONE is not set +# CONFIG_USB_DWC_OTG_LPM is not set +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_EG20T is not set +# CONFIG_USB_EHCI_HCD_AT91 is not set +# CONFIG_USB_EHCI_HCD_PPC_OF is not set +# CONFIG_USB_EHCI_MSM is not set +# CONFIG_USB_EHCI_MV is not set +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_TT_NEWSCHED=y +# CONFIG_USB_EHSET_TEST_FIXTURE is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_ENESTORAGE is not set +# CONFIG_USB_EPSON2888 is not set +# CONFIG_USB_ET61X251 is not set +CONFIG_USB_EZUSB=y +# CONFIG_USB_EZUSB_FX2 is not set +# CONFIG_USB_FILE_STORAGE is not set +# CONFIG_USB_FOTG210_HCD is not set +# CONFIG_USB_FOTG210_UDC is not set +# CONFIG_USB_FSL_USB2 is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_FUNCTIONFS is not set +# CONFIG_USB_FUSB300 is not set +# CONFIG_USB_FUSBH200_HCD is not set +# CONFIG_USB_GADGET is not set +# CONFIG_USB_GADGETFS is not set +# CONFIG_USB_GADGET_DEBUG is not set +# CONFIG_USB_GADGET_DEBUG_FILES is not set +# CONFIG_USB_GADGET_DEBUG_FS is not set +CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2 +CONFIG_USB_GADGET_VBUS_DRAW=2 +# CONFIG_USB_GADGET_XILINX is not set +# CONFIG_USB_GL860 is not set +# CONFIG_USB_GOKU is not set +# CONFIG_USB_GPIO_VBUS is not set +# CONFIG_USB_GR_UDC is not set +# CONFIG_USB_GSPCA is not set +# CONFIG_USB_GSPCA_BENQ is not set +# CONFIG_USB_GSPCA_CONEX is not set +# CONFIG_USB_GSPCA_CPIA1 is not set +# CONFIG_USB_GSPCA_DTCS033 is not set +# CONFIG_USB_GSPCA_ETOMS is not set +# CONFIG_USB_GSPCA_FINEPIX is not set +# CONFIG_USB_GSPCA_JEILINJ is not set +# CONFIG_USB_GSPCA_JL2005BCD is not set +# CONFIG_USB_GSPCA_KINECT is not set +# CONFIG_USB_GSPCA_KONICA is not set +# CONFIG_USB_GSPCA_MARS is not set +# CONFIG_USB_GSPCA_MR97310A is not set +# CONFIG_USB_GSPCA_NW80X is not set +# CONFIG_USB_GSPCA_OV519 is not set +# CONFIG_USB_GSPCA_OV534 is not set +# CONFIG_USB_GSPCA_OV534_9 is not set +# CONFIG_USB_GSPCA_PAC207 is not set +# CONFIG_USB_GSPCA_PAC7302 is not set +# CONFIG_USB_GSPCA_PAC7311 is not set +# CONFIG_USB_GSPCA_SE401 is not set +# CONFIG_USB_GSPCA_SN9C2028 is not set +# CONFIG_USB_GSPCA_SN9C20X is not set +# CONFIG_USB_GSPCA_SONIXB is not set +# CONFIG_USB_GSPCA_SONIXJ is not set +# CONFIG_USB_GSPCA_SPCA1528 is not set +# CONFIG_USB_GSPCA_SPCA500 is not set +# CONFIG_USB_GSPCA_SPCA501 is not set +# CONFIG_USB_GSPCA_SPCA505 is not set +# CONFIG_USB_GSPCA_SPCA506 is not set +# CONFIG_USB_GSPCA_SPCA508 is not set +# CONFIG_USB_GSPCA_SPCA561 is not set +# CONFIG_USB_GSPCA_SQ905 is not set +# CONFIG_USB_GSPCA_SQ905C is not set +# CONFIG_USB_GSPCA_SQ930X is not set +# CONFIG_USB_GSPCA_STK014 is not set +# CONFIG_USB_GSPCA_STK1135 is not set +# CONFIG_USB_GSPCA_STV0680 is not set +# CONFIG_USB_GSPCA_SUNPLUS is not set +# CONFIG_USB_GSPCA_T613 is not set +# CONFIG_USB_GSPCA_TOPRO is not set +# CONFIG_USB_GSPCA_TOUPTEK is not set +# CONFIG_USB_GSPCA_TV8532 is not set +# CONFIG_USB_GSPCA_VC032X is not set +# CONFIG_USB_GSPCA_VICAM is not set +# CONFIG_USB_GSPCA_XIRLINK_CIT is not set +# CONFIG_USB_GSPCA_ZC3XX is not set +# CONFIG_USB_G_ACM_MS is not set +# CONFIG_USB_G_DBGP is not set +# CONFIG_USB_G_HID is not set +# CONFIG_USB_G_MULTI is not set +# CONFIG_USB_G_NCM is not set +# CONFIG_USB_G_NOKIA is not set +# CONFIG_USB_G_PRINTER is not set +# CONFIG_USB_G_SERIAL is not set +# CONFIG_USB_G_WEBCAM is not set +# CONFIG_USB_HCD_TEST_MODE is not set +# CONFIG_USB_HID is not set +# CONFIG_USB_HIDDEV is not set +# CONFIG_USB_HSIC_USB3503 is not set +# CONFIG_USB_HSO is not set +# CONFIG_USB_HWA_HCD is not set +# CONFIG_USB_IBMCAM is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_INPUT_IMS_PCU is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_IPHETH is not set +# CONFIG_USB_IP_COMMON is not set +# CONFIG_USB_ISIGHTFW is not set +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_ISP1301 is not set +# CONFIG_USB_ISP1362_HCD is not set +# CONFIG_USB_ISP1760 is not set +# CONFIG_USB_ISP1760_HCD is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_KBD is not set +# CONFIG_USB_KC2190 is not set +# CONFIG_USB_KONICAWC is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_LED_TRIG is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LIBUSUAL is not set +# CONFIG_USB_LINK_LAYER_TEST is not set +# CONFIG_USB_M5602 is not set +# CONFIG_USB_M66592 is not set +# CONFIG_USB_MASS_STORAGE is not set +# CONFIG_USB_MAX3421_HCD is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_MIDI_GADGET is not set +# CONFIG_USB_MON is not set +# CONFIG_USB_MOUSE is not set +# CONFIG_USB_MSM_OTG is not set +# CONFIG_USB_MUSB_HDRC is not set +# CONFIG_USB_MV_U3D is not set +# CONFIG_USB_MV_UDC is not set +# CONFIG_USB_NET2272 is not set +# CONFIG_USB_NET2280 is not set +# CONFIG_USB_NET_AX88179_178A is not set +# CONFIG_USB_NET_AX8817X is not set +# CONFIG_USB_NET_CDCETHER is not set +# CONFIG_USB_NET_CDC_EEM is not set +# CONFIG_USB_NET_CDC_MBIM is not set +# CONFIG_USB_NET_CDC_NCM is not set +# CONFIG_USB_NET_CDC_SUBSET is not set +# CONFIG_USB_NET_CX82310_ETH is not set +# CONFIG_USB_NET_DM9601 is not set +# CONFIG_USB_NET_DRIVERS is not set +# CONFIG_USB_NET_GL620A is not set +# CONFIG_USB_NET_HUAWEI_CDC_NCM is not set +# CONFIG_USB_NET_INT51X1 is not set +# CONFIG_USB_NET_KALMIA is not set +# CONFIG_USB_NET_MCS7830 is not set +# CONFIG_USB_NET_NET1080 is not set +# CONFIG_USB_NET_PLUSB is not set +# CONFIG_USB_NET_QMI_WWAN is not set +# CONFIG_USB_NET_RNDIS_HOST is not set +# CONFIG_USB_NET_RNDIS_WLAN is not set +# CONFIG_USB_NET_SMSC75XX is not set +# CONFIG_USB_NET_SMSC95XX is not set +# CONFIG_USB_NET_SR9700 is not set +# CONFIG_USB_NET_SR9800 is not set +# CONFIG_USB_NET_ZAURUS is not set +# CONFIG_USB_OHCI_HCD is not set +# CONFIG_USB_OHCI_HCD_PCI is not set +# CONFIG_USB_OHCI_HCD_PPC_OF is not set +# CONFIG_USB_OHCI_HCD_PPC_OF_BE is not set +# CONFIG_USB_OHCI_HCD_PPC_OF_LE is not set +# CONFIG_USB_OHCI_HCD_PPC_SOC is not set +# CONFIG_USB_OHCI_HCD_SSB is not set +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +# CONFIG_USB_OTG is not set +# CONFIG_USB_OTG_BLACKLIST_HUB is not set +# CONFIG_USB_OTG_FSM is not set +# CONFIG_USB_OTG_WHITELIST is not set +# CONFIG_USB_OXU210HP_HCD is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_PHY is not set +# CONFIG_USB_PRINTER is not set +# CONFIG_USB_PWC_INPUT_EVDEV is not set +# CONFIG_USB_PXA27X is not set +# CONFIG_USB_R8A66597 is not set +# CONFIG_USB_R8A66597_HCD is not set +# CONFIG_USB_RCAR_PHY is not set +# CONFIG_USB_RENESAS_USBHS is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_RTL8152 is not set +# CONFIG_USB_S2255 is not set +# CONFIG_USB_S3C_HSOTG is not set +# CONFIG_USB_SE401 is not set +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_SERIAL_AIRCABLE is not set +# CONFIG_USB_SERIAL_ARK3116 is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_CH341 is not set +# CONFIG_USB_SERIAL_CP210X is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_CYPRESS_M8 is not set +# CONFIG_USB_SERIAL_DEBUG is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_EDGEPORT_TI is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_F81232 is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_FUNSOFT is not set +# CONFIG_USB_SERIAL_GARMIN is not set +CONFIG_USB_SERIAL_GENERIC=y +# CONFIG_USB_SERIAL_HP4X is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IPW is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_IUU is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +CONFIG_USB_SERIAL_KEYSPAN_MPR=y +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +CONFIG_USB_SERIAL_KEYSPAN_USA18X=y +CONFIG_USB_SERIAL_KEYSPAN_USA19=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y +CONFIG_USB_SERIAL_KEYSPAN_USA19W=y +CONFIG_USB_SERIAL_KEYSPAN_USA28=y +CONFIG_USB_SERIAL_KEYSPAN_USA28X=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y +CONFIG_USB_SERIAL_KEYSPAN_USA49W=y +CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y +# CONFIG_USB_SERIAL_KLSI is not set +# CONFIG_USB_SERIAL_KOBIL_SCT is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_METRO is not set +# CONFIG_USB_SERIAL_MOS7715_PARPORT is not set +# CONFIG_USB_SERIAL_MOS7720 is not set +# CONFIG_USB_SERIAL_MOS7840 is not set +# CONFIG_USB_SERIAL_MOTOROLA is not set +# CONFIG_USB_SERIAL_MXUPORT is not set +# CONFIG_USB_SERIAL_NAVMAN is not set +# CONFIG_USB_SERIAL_OMNINET is not set +# CONFIG_USB_SERIAL_OPTICON is not set +# CONFIG_USB_SERIAL_OPTION is not set +# CONFIG_USB_SERIAL_OTI6858 is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_QCAUX is not set +# CONFIG_USB_SERIAL_QT2 is not set +# CONFIG_USB_SERIAL_QUALCOMM is not set +# CONFIG_USB_SERIAL_QUATECH2 is not set +# CONFIG_USB_SERIAL_QUATECH_USB2 is not set +# CONFIG_USB_SERIAL_SAFE is not set +CONFIG_USB_SERIAL_SAFE_PADDED=y +# CONFIG_USB_SERIAL_SIEMENS_MPI is not set +# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set +# CONFIG_USB_SERIAL_SIMPLE is not set +# CONFIG_USB_SERIAL_SPCP8X5 is not set +# CONFIG_USB_SERIAL_SSU100 is not set +# CONFIG_USB_SERIAL_SYMBOL is not set +# CONFIG_USB_SERIAL_TI is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_VIVOPAY_SERIAL is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_WISHBONE is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_XSENS_MT is not set +# CONFIG_USB_SERIAL_ZIO is not set +# CONFIG_USB_SERIAL_ZTE is not set +# CONFIG_USB_SEVSEG is not set +# CONFIG_USB_SIERRA_NET is not set +# CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_SN9C102 is not set +# CONFIG_USB_SPEEDTOUCH is not set +# CONFIG_USB_STKWEBCAM is not set +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_STORAGE_ALAUDA is not set +# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_ENE_UB6250 is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_KARMA is not set +# CONFIG_USB_STORAGE_ONETOUCH is not set +# CONFIG_USB_STORAGE_REALTEK is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_USBAT is not set +# CONFIG_USB_STV06XX is not set +# CONFIG_USB_SUPPORT is not set +# CONFIG_USB_SUSPEND is not set +# CONFIG_USB_SWITCH_FSA9480 is not set +# CONFIG_USB_TEST is not set +# CONFIG_USB_TMC is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_UAS is not set +# CONFIG_USB_UEAGLEATM is not set +# CONFIG_USB_ULPI is not set +# CONFIG_USB_USBNET is not set +# CONFIG_USB_USS720 is not set +# CONFIG_USB_VIDEO_CLASS is not set +CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y +# CONFIG_USB_VL600 is not set +# CONFIG_USB_WDM is not set +# CONFIG_USB_WHCI_HCD is not set +# CONFIG_USB_WPAN_HCD is not set +# CONFIG_USB_WUSB is not set +# CONFIG_USB_WUSB_CBAF is not set +# CONFIG_USB_XHCI_HCD is not set +# CONFIG_USB_XUSBATM is not set +# CONFIG_USB_YUREX is not set +# CONFIG_USB_ZD1201 is not set +# CONFIG_USB_ZERO is not set +# CONFIG_USB_ZR364XX is not set +# CONFIG_USELIB is not set +# CONFIG_USE_GENERIC_SMP_HELPERS is not set +# CONFIG_USE_OF is not set +# CONFIG_UTS_NS is not set +# CONFIG_UWB is not set +# CONFIG_V4L_MEM2MEM_DRIVERS is not set +# CONFIG_V4L_TEST_DRIVERS is not set +# CONFIG_VCNL4000 is not set +# CONFIG_VETH is not set +# CONFIG_VEXPRESS_CONFIG is not set +# CONFIG_VF610_ADC is not set +# CONFIG_VFAT_FS is not set +# CONFIG_VGASTATE is not set +# CONFIG_VGA_ARB is not set +# CONFIG_VGA_SWITCHEROO is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_VIA_VELOCITY is not set +# CONFIG_VIDEO_ADV7170 is not set +# CONFIG_VIDEO_ADV7175 is not set +# CONFIG_VIDEO_ADV7180 is not set +# CONFIG_VIDEO_ADV7183 is not set +# CONFIG_VIDEO_ADV7343 is not set +# CONFIG_VIDEO_ADV7393 is not set +# CONFIG_VIDEO_ADV_DEBUG is not set +# CONFIG_VIDEO_AK881X is not set +# CONFIG_VIDEO_BT819 is not set +# CONFIG_VIDEO_BT848 is not set +# CONFIG_VIDEO_BT856 is not set +# CONFIG_VIDEO_BT866 is not set +# CONFIG_VIDEO_BWQCAM is not set +# CONFIG_VIDEO_CAFE_CCIC is not set +# CONFIG_VIDEO_CAPTURE_DRIVERS is not set +# CONFIG_VIDEO_CPIA is not set +# CONFIG_VIDEO_CQCAM is not set +# CONFIG_VIDEO_CS5345 is not set +# CONFIG_VIDEO_CS53L32A is not set +# CONFIG_VIDEO_CX231XX is not set +# CONFIG_VIDEO_CX2341X is not set +# CONFIG_VIDEO_CX25840 is not set +# CONFIG_VIDEO_CX88 is not set +# CONFIG_VIDEO_DEV is not set +# CONFIG_VIDEO_DM6446_CCDC is not set +# CONFIG_VIDEO_DT3155 is not set +# CONFIG_VIDEO_EM28XX is not set +# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set +# CONFIG_VIDEO_GO7007 is not set +# CONFIG_VIDEO_HDPVR is not set +# CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set +# CONFIG_VIDEO_HEXIUM_GEMINI is not set +# CONFIG_VIDEO_HEXIUM_ORION is not set +# CONFIG_VIDEO_IR_I2C is not set +# CONFIG_VIDEO_IVTV is not set +# CONFIG_VIDEO_KS0127 is not set +# CONFIG_VIDEO_M52790 is not set +# CONFIG_VIDEO_MEDIA is not set +# CONFIG_VIDEO_MEM2MEM_TESTDEV is not set +# CONFIG_VIDEO_ML86V7667 is not set +# CONFIG_VIDEO_MSP3400 is not set +# CONFIG_VIDEO_MT9V011 is not set +# CONFIG_VIDEO_MXB is not set +# CONFIG_VIDEO_NOON010PC30 is not set +# CONFIG_VIDEO_OMAP2_VOUT is not set +# CONFIG_VIDEO_OUTPUT_CONTROL is not set +# CONFIG_VIDEO_OV7640 is not set +# CONFIG_VIDEO_OV7670 is not set +# CONFIG_VIDEO_PMS is not set +# CONFIG_VIDEO_PVRUSB2 is not set +# CONFIG_VIDEO_SAA6588 is not set +# CONFIG_VIDEO_SAA6752HS is not set +# CONFIG_VIDEO_SAA7110 is not set +# CONFIG_VIDEO_SAA711X is not set +# CONFIG_VIDEO_SAA7127 is not set +# CONFIG_VIDEO_SAA7134 is not set +# CONFIG_VIDEO_SAA717X is not set +# CONFIG_VIDEO_SAA7185 is not set +# CONFIG_VIDEO_SAA7191 is not set +# CONFIG_VIDEO_SH_MOBILE_CEU is not set +# CONFIG_VIDEO_SONY_BTF_MPX is not set +# CONFIG_VIDEO_SR030PC30 is not set +# CONFIG_VIDEO_TCM825X is not set +# CONFIG_VIDEO_TDA7432 is not set +# CONFIG_VIDEO_TDA9840 is not set +# CONFIG_VIDEO_TEA6415C is not set +# CONFIG_VIDEO_TEA6420 is not set +# CONFIG_VIDEO_THS7303 is not set +# CONFIG_VIDEO_THS8200 is not set +# CONFIG_VIDEO_TIMBERDALE is not set +# CONFIG_VIDEO_TLV320AIC23B is not set +# CONFIG_VIDEO_TM6000 is not set +# CONFIG_VIDEO_TVAUDIO is not set +# CONFIG_VIDEO_TVP514X is not set +# CONFIG_VIDEO_TVP5150 is not set +# CONFIG_VIDEO_TVP7002 is not set +# CONFIG_VIDEO_TW2804 is not set +# CONFIG_VIDEO_TW9903 is not set +# CONFIG_VIDEO_TW9906 is not set +# CONFIG_VIDEO_UDA1342 is not set +# CONFIG_VIDEO_UPD64031A is not set +# CONFIG_VIDEO_UPD64083 is not set +# CONFIG_VIDEO_USBTV is not set +# CONFIG_VIDEO_USBVISION is not set +# CONFIG_VIDEO_V4L2 is not set +# CONFIG_VIDEO_V4L2_COMMON is not set +# CONFIG_VIDEO_V4L2_INT_DEVICE is not set +# CONFIG_VIDEO_VIVI is not set +# CONFIG_VIDEO_VP27SMPX is not set +# CONFIG_VIDEO_VPX3220 is not set +# CONFIG_VIDEO_VS6624 is not set +# CONFIG_VIDEO_WM8739 is not set +# CONFIG_VIDEO_WM8775 is not set +# CONFIG_VIDEO_ZORAN is not set +# CONFIG_VIRQ_DEBUG is not set +# CONFIG_VIRTIO_BALLOON is not set +# CONFIG_VIRTIO_MMIO is not set +# CONFIG_VIRTIO_PCI is not set +# CONFIG_VIRTUALIZATION is not set +# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set +# CONFIG_VIRT_DRIVERS is not set +CONFIG_VIRT_TO_BUS=y +# CONFIG_VITESSE_PHY is not set +CONFIG_VLAN_8021Q=y +# CONFIG_VLAN_8021Q_GVRP is not set +# CONFIG_VLAN_8021Q_MVRP is not set +# CONFIG_VME_BUS is not set +# CONFIG_VMSPLIT_1G is not set +# CONFIG_VMSPLIT_2G is not set +# CONFIG_VMSPLIT_2G_OPT is not set +CONFIG_VMSPLIT_3G=y +# CONFIG_VMSPLIT_3G_OPT is not set +# CONFIG_VMWARE_PVSCSI is not set +# CONFIG_VMXNET3 is not set +# CONFIG_VM_EVENT_COUNTERS is not set +# CONFIG_VORTEX is not set +# CONFIG_VSOCKETS is not set +# CONFIG_VT is not set +# CONFIG_VT6655 is not set +# CONFIG_VT6656 is not set +# CONFIG_VXFS_FS is not set +# CONFIG_VXGE is not set +# CONFIG_VXLAN is not set +# CONFIG_W1 is not set +# CONFIG_W1_CON is not set +# CONFIG_W1_MASTER_DS1WM is not set +# CONFIG_W1_MASTER_DS2482 is not set +# CONFIG_W1_MASTER_DS2490 is not set +# CONFIG_W1_MASTER_GPIO is not set +# CONFIG_W1_MASTER_MATROX is not set +# CONFIG_W1_SLAVE_BQ27000 is not set +# CONFIG_W1_SLAVE_DS2406 is not set +# CONFIG_W1_SLAVE_DS2408 is not set +# CONFIG_W1_SLAVE_DS2413 is not set +# CONFIG_W1_SLAVE_DS2423 is not set +# CONFIG_W1_SLAVE_DS2431 is not set +# CONFIG_W1_SLAVE_DS2433 is not set +# CONFIG_W1_SLAVE_DS2760 is not set +# CONFIG_W1_SLAVE_DS2780 is not set +# CONFIG_W1_SLAVE_DS2781 is not set +# CONFIG_W1_SLAVE_DS28E04 is not set +# CONFIG_W1_SLAVE_SMEM is not set +# CONFIG_W1_SLAVE_THERM is not set +# CONFIG_W35UND is not set +# CONFIG_W83627HF_WDT is not set +# CONFIG_W83697HF_WDT is not set +# CONFIG_W83877F_WDT is not set +# CONFIG_W83977F_WDT is not set +# CONFIG_WAN is not set +# CONFIG_WANXL is not set +# CONFIG_WAN_ROUTER is not set +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_CORE is not set +# CONFIG_WATCHDOG_NOWAYOUT is not set +# CONFIG_WD80x3 is not set +# CONFIG_WDTPCI is not set +CONFIG_WEXT_CORE=y +CONFIG_WEXT_PRIV=y +CONFIG_WEXT_PROC=y +CONFIG_WEXT_SPY=y +CONFIG_WILINK_PLATFORM_DATA=y +# CONFIG_WIMAX is not set +# CONFIG_WIMAX_GDM72XX is not set +CONFIG_WIRELESS=y +CONFIG_WIRELESS_EXT=y +# CONFIG_WIRELESS_EXT_SYSFS is not set +# CONFIG_WL1251 is not set +# CONFIG_WL12XX is not set +# CONFIG_WL18XX is not set +# CONFIG_WLAGS49_H2 is not set +# CONFIG_WLAGS49_H25 is not set +CONFIG_WLAN=y +# CONFIG_WLCORE is not set +CONFIG_WL_TI=y +CONFIG_WQ_POWER_EFFICIENT_DEFAULT=y +# CONFIG_WR_PPMC is not set +# CONFIG_X25 is not set +# CONFIG_X86_DEBUG_STATIC_CPU_HAS is not set +# CONFIG_X86_PKG_TEMP_THERMAL is not set +CONFIG_X86_SYSFB=y +# CONFIG_XEN is not set +CONFIG_XFRM=y +# CONFIG_XFRM_IPCOMP is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_USER is not set +# CONFIG_XFS_DEBUG is not set +# CONFIG_XFS_FS is not set +# CONFIG_XFS_POSIX_ACL is not set +# CONFIG_XFS_QUOTA is not set +# CONFIG_XFS_RT is not set +# CONFIG_XFS_WARN is not set +# CONFIG_XILINX_AXI_EMAC is not set +# CONFIG_XILINX_EMACLITE is not set +# CONFIG_XILINX_LL_TEMAC is not set +# CONFIG_XILINX_WATCHDOG is not set +# CONFIG_XILLYBUS is not set +# CONFIG_XIP_KERNEL is not set +# CONFIG_XMON is not set +# CONFIG_XVMALLOC is not set +CONFIG_XZ_DEC=y +# CONFIG_XZ_DEC_ARM is not set +# CONFIG_XZ_DEC_ARMTHUMB is not set +# CONFIG_XZ_DEC_BCJ is not set +# CONFIG_XZ_DEC_IA64 is not set +# CONFIG_XZ_DEC_POWERPC is not set +# CONFIG_XZ_DEC_SPARC is not set +# CONFIG_XZ_DEC_TEST is not set +# CONFIG_XZ_DEC_X86 is not set +# CONFIG_YAFFS_DISABLE_BAD_BLOCK_MARKING is not set +# CONFIG_YAFFS_FS is not set +# CONFIG_YAM is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_YENTA is not set +# CONFIG_YENTA_O2 is not set +# CONFIG_YENTA_RICOH is not set +# CONFIG_YENTA_TI is not set +# CONFIG_YENTA_TOSHIBA is not set +# CONFIG_ZBUD is not set +# CONFIG_ZD1211RW is not set +# CONFIG_ZD1211RW_DEBUG is not set +# CONFIG_ZEROPLUS_FF is not set +# CONFIG_ZISOFS is not set +# CONFIG_ZLIB_DEFLATE is not set +# CONFIG_ZLIB_INFLATE is not set +# CONFIG_ZNET is not set +# CONFIG_ZPOOL is not set +CONFIG_ZONE_DMA=y +CONFIG_ZONE_DMA_FLAG=1 +# CONFIG_ZRAM is not set +# CONFIG_ZSMALLOC is not set diff --git a/target/linux/generic/config-4.1 b/target/linux/generic/config-4.1 new file mode 100644 index 0000000..9eb6f8c --- /dev/null +++ b/target/linux/generic/config-4.1 @@ -0,0 +1,4812 @@ +CONFIG_32BIT=y +# CONFIG_6LOWPAN is not set +# CONFIG_6PACK is not set +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_9P_FS is not set +# CONFIG_AB3100_CORE is not set +# CONFIG_AB8500_CORE is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_ACCESSIBILITY is not set +# CONFIG_ACENIC is not set +# CONFIG_ACERHDF is not set +# CONFIG_ACORN_PARTITION is not set +# CONFIG_ACPI_APEI is not set +# CONFIG_ACPI_CUSTOM_METHOD is not set +# CONFIG_ACPI_EXTLOG is not set +# CONFIG_ACPI_HED is not set +# CONFIG_ACPI_INT3403_THERMAL is not set +# CONFIG_ACPI_POWER_METER is not set +# CONFIG_ACPI_QUICKSTART is not set +# CONFIG_ACPI_REDUCED_HARDWARE_ONLY is not set +# CONFIG_AD2S1200 is not set +# CONFIG_AD2S1210 is not set +# CONFIG_AD2S90 is not set +# CONFIG_AD5064 is not set +# CONFIG_AD525X_DPOT is not set +# CONFIG_AD5360 is not set +# CONFIG_AD5380 is not set +# CONFIG_AD5421 is not set +# CONFIG_AD5446 is not set +# CONFIG_AD5449 is not set +# CONFIG_AD5504 is not set +# CONFIG_AD5624R_SPI is not set +# CONFIG_AD5686 is not set +# CONFIG_AD5755 is not set +# CONFIG_AD5764 is not set +# CONFIG_AD5791 is not set +# CONFIG_AD5930 is not set +# CONFIG_AD5933 is not set +# CONFIG_AD7150 is not set +# CONFIG_AD7152 is not set +# CONFIG_AD7192 is not set +# CONFIG_AD7266 is not set +# CONFIG_AD7280 is not set +# CONFIG_AD7291 is not set +# CONFIG_AD7298 is not set +# CONFIG_AD7303 is not set +# CONFIG_AD7476 is not set +# CONFIG_AD7606 is not set +# CONFIG_AD7746 is not set +# CONFIG_AD7780 is not set +# CONFIG_AD7791 is not set +# CONFIG_AD7793 is not set +# CONFIG_AD7816 is not set +# CONFIG_AD7887 is not set +# CONFIG_AD7923 is not set +# CONFIG_AD799X is not set +# CONFIG_AD8366 is not set +# CONFIG_AD9523 is not set +# CONFIG_AD9832 is not set +# CONFIG_AD9834 is not set +# CONFIG_AD9850 is not set +# CONFIG_AD9852 is not set +# CONFIG_AD9910 is not set +# CONFIG_AD9951 is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_ADE7753 is not set +# CONFIG_ADE7754 is not set +# CONFIG_ADE7758 is not set +# CONFIG_ADE7759 is not set +# CONFIG_ADE7854 is not set +# CONFIG_ADF4350 is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADIS16060 is not set +# CONFIG_ADIS16080 is not set +# CONFIG_ADIS16130 is not set +# CONFIG_ADIS16136 is not set +# CONFIG_ADIS16201 is not set +# CONFIG_ADIS16203 is not set +# CONFIG_ADIS16204 is not set +# CONFIG_ADIS16209 is not set +# CONFIG_ADIS16220 is not set +# CONFIG_ADIS16240 is not set +# CONFIG_ADIS16255 is not set +# CONFIG_ADIS16260 is not set +# CONFIG_ADIS16400 is not set +# CONFIG_ADIS16480 is not set +# CONFIG_ADJD_S311 is not set +# CONFIG_ADM6996_PHY is not set +# CONFIG_ADM8211 is not set +# CONFIG_ADT7316 is not set +# CONFIG_ADVISE_SYSCALLS is not set +# CONFIG_ADXRS450 is not set +CONFIG_AEABI=y +# CONFIG_AFFS_FS is not set +# CONFIG_AFS_FS is not set +# CONFIG_AF_RXRPC is not set +# CONFIG_AGP is not set +# CONFIG_AHCI_MVEBU is not set +CONFIG_AIO=y +# CONFIG_AIRO is not set +# CONFIG_AIRO_CS is not set +# CONFIG_AIX_PARTITION is not set +# CONFIG_AK09911 is not set +# CONFIG_AK8975 is not set +# CONFIG_AL3320A is not set +# CONFIG_ALCHEMY_GPIO_INDIRECT is not set +# CONFIG_ALIM7101_WDT is not set +CONFIG_ALLOW_DEV_COREDUMP=y +# CONFIG_ALTERA_MBOX is not set +# CONFIG_ALTERA_STAPL is not set +# CONFIG_ALTERA_TSE is not set +# CONFIG_ALX is not set +# CONFIG_AM335X_PHY_USB is not set +# CONFIG_AMD8111_ETH is not set +# CONFIG_AMD_XGBE is not set +# CONFIG_AMD_XGBE_PHY is not set +# CONFIG_AMD_PHY is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_AMILO_RFKILL is not set +# CONFIG_ANDROID is not set +CONFIG_ANON_INODES=y +# CONFIG_APDS9300 is not set +# CONFIG_APDS9802ALS is not set +# CONFIG_APM8018X is not set +# CONFIG_APPLICOM is not set +# CONFIG_AR5523 is not set +# CONFIG_AR7 is not set +# CONFIG_AR8216_PHY is not set +# CONFIG_AR8216_PHY_LEDS is not set +# CONFIG_ARCH_ALPINE is not set +# CONFIG_ARCH_AT91 is not set +# CONFIG_ARCH_BCM is not set +# CONFIG_ARCH_BCM2835 is not set +# CONFIG_ARCH_BCMRING is not set +# CONFIG_ARCH_BERLIN is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CNS3XXX is not set +# CONFIG_ARCH_DAVINCI is not set +# CONFIG_ARCH_DIGICOLOR is not set +# CONFIG_ARCH_DMA_ADDR_T_64BIT is not set +# CONFIG_ARCH_DOVE is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_EP93XX is not set +# CONFIG_ARCH_EXYNOS is not set +CONFIG_ARCH_FLATMEM_ENABLE=y +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_GEMINI is not set +# CONFIG_ARCH_H720X is not set +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +# CONFIG_ARCH_HI3xxx is not set +# CONFIG_ARCH_HIGHBANK is not set +# CONFIG_ARCH_HISI is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_IOP13XX is not set +# CONFIG_ARCH_IOP32X is not set +# CONFIG_ARCH_IOP33X is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_IXP23XX is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_KEYSTONE is not set +# CONFIG_ARCH_KIRKWOOD is not set +# CONFIG_ARCH_KS8695 is not set +# CONFIG_ARCH_LPC32XX is not set +# CONFIG_ARCH_MEDIATEK is not set +# CONFIG_ARCH_MESON is not set +# CONFIG_ARCH_MMP is not set +# CONFIG_ARCH_MSM is not set +# CONFIG_ARCH_MSM_DT is not set +# CONFIG_ARCH_MSM_NODT is not set +# CONFIG_ARCH_MULTIPLATFORM is not set +# CONFIG_ARCH_MULTI_V6 is not set +# CONFIG_ARCH_MULTI_V7 is not set +# CONFIG_ARCH_MV78XX0 is not set +# CONFIG_ARCH_MVEBU is not set +# CONFIG_ARCH_MXC is not set +# CONFIG_ARCH_MXS is not set +# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set +# CONFIG_ARCH_NETX is not set +# CONFIG_ARCH_NOMADIK is not set +# CONFIG_ARCH_NSPIRE is not set +# CONFIG_ARCH_NUC93X is not set +# CONFIG_ARCH_OMAP is not set +# CONFIG_ARCH_OMAP1 is not set +# CONFIG_ARCH_OMAP2PLUS is not set +# CONFIG_ARCH_OMAP3 is not set +# CONFIG_ARCH_OMAP4 is not set +# CONFIG_ARCH_ORION5X is not set +# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set +# CONFIG_ARCH_PICOXCELL is not set +# CONFIG_ARCH_PNX4008 is not set +# CONFIG_ARCH_PRIMA2 is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_QCOM is not set +# CONFIG_ARCH_REALVIEW is not set +# CONFIG_ARCH_ROCKCHIP is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_S3C24XX is not set +# CONFIG_ARCH_S3C64XX is not set +# CONFIG_ARCH_S5P64X0 is not set +# CONFIG_ARCH_S5PC100 is not set +# CONFIG_ARCH_S5PV210 is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_SHMOBILE is not set +# CONFIG_ARCH_SHMOBILE_LEGACY is not set +# CONFIG_ARCH_SHMOBILE_MULTI is not set +# CONFIG_ARCH_SIRF is not set +# CONFIG_ARCH_SOCFPGA is not set +# CONFIG_ARCH_STI is not set +# CONFIG_ARCH_SUNXI is not set +# CONFIG_ARCH_SUPPORTS_MSI is not set +# CONFIG_ARCH_TCC_926 is not set +# CONFIG_ARCH_TEGRA is not set +# CONFIG_ARCH_U300 is not set +# CONFIG_ARCH_U8500 is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_VEXPRESS is not set +# CONFIG_ARCH_VIRT is not set +# CONFIG_ARCH_VT8500 is not set +# CONFIG_ARCH_W90X900 is not set +# CONFIG_ARCH_WM8505 is not set +# CONFIG_ARCH_WM8850 is not set +# CONFIG_ARCH_ZYNQ is not set +# CONFIG_ARCNET is not set +# CONFIG_ARC_EMAC is not set +# CONFIG_ARM_APPENDED_DTB is not set +# CONFIG_ARM_ARCH_TIMER is not set +# CONFIG_ARM_AT91_ETHER is not set +# CONFIG_ARM_CCI is not set +# CONFIG_ARM_CCI400_PMU is not set +# CONFIG_ARM_CCN is not set +# CONFIG_ARM_CRYPTO is not set +CONFIG_ARM_CPU_TOPOLOGY=y +CONFIG_ARM_DMA_MEM_BUFFERABLE=y +# CONFIG_ARM_ERRATA_326103 is not set +# CONFIG_ARM_ERRATA_364296 is not set +# CONFIG_ARM_ERRATA_411920 is not set +# CONFIG_ARM_ERRATA_430973 is not set +# CONFIG_ARM_ERRATA_458693 is not set +# CONFIG_ARM_ERRATA_460075 is not set +# CONFIG_ARM_ERRATA_643719 is not set +# CONFIG_ARM_ERRATA_720789 is not set +# CONFIG_ARM_ERRATA_742230 is not set +# CONFIG_ARM_ERRATA_742231 is not set +# CONFIG_ARM_ERRATA_743622 is not set +# CONFIG_ARM_ERRATA_751472 is not set +# CONFIG_ARM_ERRATA_754322 is not set +# CONFIG_ARM_ERRATA_754327 is not set +# CONFIG_ARM_ERRATA_764369 is not set +# CONFIG_ARM_ERRATA_773022 is not set +# CONFIG_ARM_ERRATA_775420 is not set +# CONFIG_ARM_ERRATA_798181 is not set +# CONFIG_ARM_KERNMEM_PERMS is not set +# CONFIG_ARM_KIRKWOOD_CPUFREQ is not set +# CONFIG_ARM_KPROBES_TEST is not set +# CONFIG_ARM_MHU is not set +# CONFIG_ARM_PATCH_PHYS_VIRT is not set +# CONFIG_ARM_PSCI is not set +# CONFIG_ARM_PTDUMP is not set +# CONFIG_ARM_UNWIND is not set +# CONFIG_ARM_VIRT_EXT is not set +CONFIG_ARPD=y +# CONFIG_ARTHUR is not set +# CONFIG_AS3935 is not set +# CONFIG_ASM9260_TIMER is not set +# CONFIG_ASUS_LAPTOP is not set +# CONFIG_ASUS_OLED is not set +# CONFIG_ASYMMETRIC_KEY_TYPE is not set +# CONFIG_ASYNC_RAID6_TEST is not set +# CONFIG_ASYNC_TX_DMA is not set +# CONFIG_AT76C50X_USB is not set +# CONFIG_AT803X_PHY is not set +# CONFIG_ATA is not set +# CONFIG_ATAGS is not set +CONFIG_ATAGS_PROC=y +# CONFIG_ATALK is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_ATA_ACPI is not set +CONFIG_ATA_BMDMA=y +# CONFIG_ATA_GENERIC is not set +# CONFIG_ATA_NONSTANDARD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_ATA_PIIX is not set +CONFIG_ATA_SFF=y +# CONFIG_ATA_VERBOSE_ERROR is not set +# CONFIG_ATH10K is not set +# CONFIG_ATH25 is not set +# CONFIG_ATH5K is not set +# CONFIG_ATH6KL is not set +# CONFIG_ATH6K_LEGACY is not set +# CONFIG_ATH79 is not set +# CONFIG_ATH9K is not set +# CONFIG_ATH9K_HTC is not set +# CONFIG_ATH_DEBUG is not set +# CONFIG_ATL1 is not set +# CONFIG_ATL1C is not set +# CONFIG_ATL1E is not set +# CONFIG_ATL2 is not set +# CONFIG_ATM is not set +# CONFIG_ATMEL is not set +# CONFIG_ATMEL_PIT is not set +# CONFIG_ATMEL_PWM is not set +# CONFIG_ATMEL_SSC is not set +# CONFIG_ATM_AMBASSADOR is not set +# CONFIG_ATM_BR2684 is not set +CONFIG_ATM_BR2684_IPFILTER=y +# CONFIG_ATM_CLIP is not set +CONFIG_ATM_CLIP_NO_ICMP=y +# CONFIG_ATM_DRIVERS is not set +# CONFIG_ATM_DUMMY is not set +# CONFIG_ATM_ENI is not set +# CONFIG_ATM_FIRESTREAM is not set +# CONFIG_ATM_FORE200E is not set +# CONFIG_ATM_HE is not set +# CONFIG_ATM_HORIZON is not set +# CONFIG_ATM_IA is not set +# CONFIG_ATM_IDT77252 is not set +# CONFIG_ATM_LANAI is not set +# CONFIG_ATM_LANE is not set +# CONFIG_ATM_MPOA is not set +# CONFIG_ATM_NICSTAR is not set +# CONFIG_ATM_SOLOS is not set +# CONFIG_ATM_TCP is not set +# CONFIG_ATM_ZATM is not set +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_ATP is not set +# CONFIG_AUDIT is not set +# CONFIG_AUDIT_ARCH_COMPAT_GENERIC is not set +# CONFIG_AUDIT_LOGINUID_IMMUTABLE is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_AUTO_ZRELADDR is not set +# CONFIG_AUXDISPLAY is not set +# CONFIG_AVERAGE is not set +# CONFIG_AX25 is not set +# CONFIG_AX25_DAMA_SLAVE is not set +# CONFIG_AX88796 is not set +# CONFIG_AXP288_ADC is not set +# CONFIG_AXP288_FUEL_GAUGE is not set +# CONFIG_B43 is not set +# CONFIG_B43LEGACY is not set +# CONFIG_B44 is not set +# CONFIG_B53 is not set +# CONFIG_B53_SPI_DRIVER is not set +# CONFIG_BACKLIGHT_ADP8860 is not set +# CONFIG_BACKLIGHT_ADP8870 is not set +# CONFIG_BACKLIGHT_BD6107 is not set +# CONFIG_BACKLIGHT_GPIO is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set +# CONFIG_BACKLIGHT_LM3630 is not set +# CONFIG_BACKLIGHT_LM3630A is not set +# CONFIG_BACKLIGHT_LM3639 is not set +# CONFIG_BACKLIGHT_LP855X is not set +# CONFIG_BACKLIGHT_LV5207LP is not set +# CONFIG_BACKLIGHT_PANDORA is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +CONFIG_BASE_FULL=y +CONFIG_BASE_SMALL=0 +# CONFIG_BATMAN_ADV is not set +# CONFIG_BATTERY_BQ27x00 is not set +# CONFIG_BATTERY_DS2760 is not set +# CONFIG_BATTERY_DS2780 is not set +# CONFIG_BATTERY_DS2781 is not set +# CONFIG_BATTERY_DS2782 is not set +# CONFIG_BATTERY_GAUGE_LTC2941 is not set +# CONFIG_BATTERY_GOLDFISH is not set +# CONFIG_BATTERY_MAX17040 is not set +# CONFIG_BATTERY_MAX17042 is not set +# CONFIG_BATTERY_SBS is not set +# CONFIG_BAYCOM_EPP is not set +# CONFIG_BAYCOM_PAR is not set +# CONFIG_BAYCOM_SER_FDX is not set +# CONFIG_BAYCOM_SER_HDX is not set +# CONFIG_BCACHE is not set +# CONFIG_BCM3384 is not set +# CONFIG_BCM47XX is not set +# CONFIG_BCM63XX is not set +# CONFIG_BCM63XX_PHY is not set +# CONFIG_BCM7XXX_PHY is not set +# CONFIG_BCM87XX_PHY is not set +# CONFIG_BCMA is not set +# CONFIG_BCMA_DRIVER_GPIO is not set +CONFIG_BCMA_POSSIBLE=y +# CONFIG_BCMGENET is not set +# CONFIG_BCM_KONA_USB2_PHY is not set +# CONFIG_BCM_WIMAX is not set +# CONFIG_BDI_SWITCH is not set +# CONFIG_BE2ISCSI is not set +# CONFIG_BE2NET is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_BGMAC is not set +# CONFIG_BIG_KEYS is not set +# CONFIG_BIG_LITTLE is not set +# CONFIG_BINARY_PRINTF is not set +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +CONFIG_BINFMT_SCRIPT=y +CONFIG_BITREVERSE=y +# CONFIG_BLK_CMDLINE_PARSER is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_CPQ_DA is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_BLK_DEV_4DRIVES is not set +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_BLK_DEV_ALI14XX is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_BLK_DEV_AMD74XX is not set +# CONFIG_BLK_DEV_ATIIXP is not set +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_BLK_DEV_BSGLIB is not set +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD64X is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_CS5520 is not set +# CONFIG_BLK_DEV_CS5530 is not set +# CONFIG_BLK_DEV_CS5535 is not set +# CONFIG_BLK_DEV_CS5536 is not set +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_DELKIN is not set +# CONFIG_BLK_DEV_DRBD is not set +# CONFIG_BLK_DEV_DTC2278 is not set +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_GENERIC is not set +# CONFIG_BLK_DEV_HD is not set +# CONFIG_BLK_DEV_HPT366 is not set +# CONFIG_BLK_DEV_HT6560B is not set +# CONFIG_BLK_DEV_IDEACPI is not set +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDECS is not set +# CONFIG_BLK_DEV_IDEPCI is not set +# CONFIG_BLK_DEV_IDEPNP is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDE_AU1XXX is not set +# CONFIG_BLK_DEV_IDE_SATA is not set +CONFIG_BLK_DEV_INITRD=y +# CONFIG_BLK_DEV_INTEGRITY is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_BLK_DEV_IT8172 is not set +# CONFIG_BLK_DEV_IT8213 is not set +# CONFIG_BLK_DEV_IT821X is not set +# CONFIG_BLK_DEV_JMICRON is not set +# CONFIG_BLK_DEV_LOOP is not set +CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_NULL_BLK is not set +# CONFIG_BLK_DEV_NVME is not set +# CONFIG_BLK_DEV_OFFBOARD is not set +# CONFIG_BLK_DEV_OPTI621 is not set +# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set +# CONFIG_BLK_DEV_PDC202XX_NEW is not set +# CONFIG_BLK_DEV_PDC202XX_OLD is not set +# CONFIG_BLK_DEV_PIIX is not set +# CONFIG_BLK_DEV_PMEM is not set +# CONFIG_BLK_DEV_PLATFORM is not set +# CONFIG_BLK_DEV_QD65XX is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_RBD is not set +# CONFIG_BLK_DEV_RSXX is not set +# CONFIG_BLK_DEV_RZ1000 is not set +# CONFIG_BLK_DEV_SC1200 is not set +# CONFIG_BLK_DEV_SD is not set +# CONFIG_BLK_DEV_SIIMAGE is not set +# CONFIG_BLK_DEV_SIS5513 is not set +# CONFIG_BLK_DEV_SKD is not set +# CONFIG_BLK_DEV_SL82C105 is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_BLK_DEV_SVWKS is not set +# CONFIG_BLK_DEV_SX8 is not set +# CONFIG_BLK_DEV_TC86C001 is not set +# CONFIG_BLK_DEV_THROTTLING is not set +# CONFIG_BLK_DEV_TRIFLEX is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_UB is not set +# CONFIG_BLK_DEV_UMC8672 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_VIA82CXXX is not set +# CONFIG_BLK_DEV_XIP is not set +CONFIG_BLOCK=y +# CONFIG_BMA180 is not set +# CONFIG_BMC150_ACCEL is not set +# CONFIG_BMG160 is not set +# CONFIG_BMIPS_GENERIC is not set +# CONFIG_BMP085 is not set +# CONFIG_BMP085_I2C is not set +# CONFIG_BMP085_SPI is not set +# CONFIG_BMP280 is not set +# CONFIG_BNA is not set +# CONFIG_BNX2 is not set +# CONFIG_BNX2X is not set +# CONFIG_BONDING is not set +# CONFIG_BOOKE_WDT is not set +CONFIG_BOOKE_WDT_DEFAULT_TIMEOUT=3 +# CONFIG_BOOT_PRINTK_DELAY is not set +CONFIG_BOOT_RAW=y +# CONFIG_BPCTL is not set +CONFIG_BPF=y +# CONFIG_BPF_JIT is not set +CONFIG_BPF_SYSCALL=y +# CONFIG_BPQETHER is not set +CONFIG_BQL=y +CONFIG_BRANCH_PROFILE_NONE=y +# CONFIG_BRCMFMAC is not set +# CONFIG_BRCMSMAC is not set +# CONFIG_BRCMSTB_GISB_ARB is not set +CONFIG_BRIDGE=y +# CONFIG_BRIDGE_EBT_802_3 is not set +# CONFIG_BRIDGE_EBT_AMONG is not set +# CONFIG_BRIDGE_EBT_ARP is not set +# CONFIG_BRIDGE_EBT_ARPREPLY is not set +# CONFIG_BRIDGE_EBT_BROUTE is not set +# CONFIG_BRIDGE_EBT_DNAT is not set +# CONFIG_BRIDGE_EBT_IP is not set +# CONFIG_BRIDGE_EBT_IP6 is not set +# CONFIG_BRIDGE_EBT_LIMIT is not set +# CONFIG_BRIDGE_EBT_LOG is not set +# CONFIG_BRIDGE_EBT_MARK is not set +# CONFIG_BRIDGE_EBT_MARK_T is not set +# CONFIG_BRIDGE_EBT_NFLOG is not set +# CONFIG_BRIDGE_EBT_PKTTYPE is not set +# CONFIG_BRIDGE_EBT_REDIRECT is not set +# CONFIG_BRIDGE_EBT_SNAT is not set +# CONFIG_BRIDGE_EBT_STP is not set +# CONFIG_BRIDGE_EBT_T_FILTER is not set +# CONFIG_BRIDGE_EBT_T_NAT is not set +# CONFIG_BRIDGE_EBT_ULOG is not set +# CONFIG_BRIDGE_EBT_VLAN is not set +CONFIG_BRIDGE_IGMP_SNOOPING=y +# CONFIG_BRIDGE_NETFILTER is not set +# CONFIG_BRIDGE_NF_EBTABLES is not set +# CONFIG_BRIDGE_VLAN_FILTERING is not set +# CONFIG_BROADCOM_PHY is not set +CONFIG_BROKEN_ON_SMP=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_BSD_PROCESS_ACCT_V3 is not set +# CONFIG_BT is not set +# CONFIG_BTRFS_ASSERT is not set +# CONFIG_BTRFS_DEBUG is not set +# CONFIG_BTRFS_FS is not set +# CONFIG_BTRFS_FS_RUN_SANITY_TESTS is not set +# CONFIG_BT_ATH3K is not set +# CONFIG_BT_BNEP is not set +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +# CONFIG_BT_BREDR is not set +# CONFIG_BT_CMTP is not set +# CONFIG_BT_HCIBCM203X is not set +# CONFIG_BT_HCIBFUSB is not set +# CONFIG_BT_HCIBLUECARD is not set +# CONFIG_BT_HCIBPA10X is not set +# CONFIG_BT_HCIBT3C is not set +# CONFIG_BT_HCIBTSDIO is not set +# CONFIG_BT_HCIBTUART is not set +# CONFIG_BT_HCIBTUSB is not set +# CONFIG_BT_HCIDTL1 is not set +# CONFIG_BT_HCIUART is not set +# CONFIG_BT_HCIUART_3WIRE is not set +# CONFIG_BT_HCIUART_ATH3K is not set +CONFIG_BT_HCIUART_BCSP=y +CONFIG_BT_HCIUART_H4=y +# CONFIG_BT_HCIUART_LL is not set +# CONFIG_BT_HCIVHCI is not set +# CONFIG_BT_HIDP is not set +CONFIG_BT_L2CAP=y +# CONFIG_BT_LE is not set +# CONFIG_BT_MRVL is not set +# CONFIG_BT_RFCOMM is not set +# CONFIG_BUILD_BIN2C is not set +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_SCO=y +# CONFIG_BT_SELFTEST is not set +CONFIG_BUG=y +CONFIG_BUILDTIME_EXTABLE_SORT=y +# CONFIG_C2PORT is not set +# CONFIG_CADENCE_WATCHDOG is not set +# CONFIG_CAIF is not set +# CONFIG_CAN is not set +# CONFIG_CAN_GS_USB is not set +# CONFIG_CAN_M_CAN is not set +# CONFIG_CAN_RCAR is not set +# CONFIG_CAPI_AVM is not set +# CONFIG_CAPI_EICON is not set +# CONFIG_CAPI_TRACE is not set +CONFIG_CARDBUS=y +# CONFIG_CARDMAN_4000 is not set +# CONFIG_CARDMAN_4040 is not set +# CONFIG_CARL9170 is not set +# CONFIG_CARMA_FPGA is not set +# CONFIG_CARMA_FPGA_PROGRAM is not set +# CONFIG_CASSINI is not set +CONFIG_CAVIUM_OCTEON_HELPER=y +# CONFIG_CAVIUM_OCTEON_REFERENCE_BOARD is not set +# CONFIG_CAVIUM_OCTEON_SIMULATOR is not set +# CONFIG_CAVIUM_OCTEON_SOC is not set +# CONFIG_CB710_CORE is not set +# CONFIG_CC10001_ADC is not set +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +# CONFIG_CC_STACKPROTECTOR is not set +CONFIG_CC_STACKPROTECTOR_NONE=y +# CONFIG_CC_STACKPROTECTOR_REGULAR is not set +# CONFIG_CC_STACKPROTECTOR_STRONG is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_CED1401 is not set +# CONFIG_CEPH_FS is not set +# CONFIG_CEPH_LIB is not set +# CONFIG_CFG80211 is not set +# CONFIG_CFG80211_CERTIFICATION_ONUS is not set +# CONFIG_CGROUPS is not set +# CONFIG_CGROUP_DEBUG is not set +# CONFIG_CGROUP_NET_PRIO is not set +# CONFIG_CHARGER_BQ2415X is not set +# CONFIG_CHARGER_BQ24190 is not set +# CONFIG_CHARGER_BQ24735 is not set +# CONFIG_CHARGER_GPIO is not set +# CONFIG_CHARGER_ISP1704 is not set +# CONFIG_CHARGER_LP8727 is not set +# CONFIG_CHARGER_MANAGER is not set +# CONFIG_CHARGER_MAX8903 is not set +# CONFIG_CHARGER_SMB347 is not set +# CONFIG_CHARGER_TWL4030 is not set +# CONFIG_CHECKPOINT_RESTORE is not set +# CONFIG_CHELSIO_T1 is not set +# CONFIG_CHELSIO_T3 is not set +# CONFIG_CHELSIO_T4 is not set +# CONFIG_CHELSIO_T4VF is not set +# CONFIG_CHROME_PLATFORMS is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_CHR_DEV_SCH is not set +# CONFIG_CHR_DEV_SG is not set +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_CIFS is not set +# CONFIG_CIFS_ACL is not set +# CONFIG_CIFS_DEBUG is not set +# CONFIG_CIFS_DEBUG2 is not set +# CONFIG_CIFS_FSCACHE is not set +# CONFIG_CIFS_NFSD_EXPORT is not set +CONFIG_CIFS_POSIX=y +# CONFIG_CIFS_SMB2 is not set +CONFIG_CIFS_STATS=y +# CONFIG_CIFS_STATS2 is not set +# CONFIG_CIFS_WEAK_PW_HASH is not set +# CONFIG_CIFS_XATTR is not set +# CONFIG_CLEANCACHE is not set +# CONFIG_CLK_QORIQ is not set +# CONFIG_CLKSRC_VERSATILE is not set +# CONFIG_CLOCK_THERMAL is not set +CONFIG_CLS_U32_MARK=y +# CONFIG_CLS_U32_PERF is not set +# CONFIG_CM32181 is not set +# CONFIG_CM3232 is not set +# CONFIG_CM3323 is not set +# CONFIG_CM36651 is not set +# CONFIG_CMA is not set +CONFIG_CMDLINE="" +# CONFIG_CMDLINE_BOOL is not set +# CONFIG_CMDLINE_EXTEND is not set +# CONFIG_CMDLINE_FORCE is not set +# CONFIG_CMDLINE_FROM_BOOTLOADER is not set +# CONFIG_CMDLINE_PARTITION is not set +# CONFIG_CNIC is not set +# CONFIG_CODA_FS is not set +# CONFIG_CODE_PATCHING_SELFTEST is not set +# CONFIG_COMEDI is not set +# CONFIG_COMMON_CLK_CDCE706 is not set +# CONFIG_COMMON_CLK_DEBUG is not set +# CONFIG_COMMON_CLK_PWM is not set +# CONFIG_COMMON_CLK_PXA is not set +# CONFIG_COMMON_CLK_QCOM is not set +# CONFIG_COMMON_CLK_SI5351 is not set +# CONFIG_COMMON_CLK_SI570 is not set +# CONFIG_COMMON_CLK_XLNX_CLKWZRD is not set +# CONFIG_COMPACTION is not set +# CONFIG_COMPAL_LAPTOP is not set +# CONFIG_COMPAT_BRK is not set +# CONFIG_COMPILE_TEST is not set +# CONFIG_CONFIGFS_FS is not set +# CONFIG_CONNECTOR is not set +CONFIG_CONSTRUCTORS=y +# CONFIG_CONTEXT_SWITCH_TRACER is not set +# CONFIG_COPS is not set +# CONFIG_CORDIC is not set +# CONFIG_COREDUMP is not set +# CONFIG_CORESIGHT is not set +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +# CONFIG_CPA_DEBUG is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_FREQ is not set +# CONFIG_CPU_IDLE is not set +# CONFIG_CPU_IDLE_GOV_MENU is not set +# CONFIG_CPU_IDLE_MULTIPLE_DRIVERS is not set +# CONFIG_CRAMFS is not set +CONFIG_CRASHLOG=y +# CONFIG_CRASH_DUMP is not set +# CONFIG_CRC16 is not set +CONFIG_CRC32=y +# CONFIG_CRC32_BIT is not set +CONFIG_CRC32_SARWATE=y +# CONFIG_CRC32_SELFTEST is not set +# CONFIG_CRC32_SLICEBY4 is not set +# CONFIG_CRC32_SLICEBY8 is not set +# CONFIG_CRC7 is not set +# CONFIG_CRC8 is not set +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC_ITU_T is not set +# CONFIG_CRC_T10DIF is not set +CONFIG_CROSS_COMPILE="" +# CONFIG_CROSS_MEMORY_ATTACH is not set +CONFIG_CRYPTO=y +# CONFIG_CRYPTO_AEAD is not set +CONFIG_CRYPTO_AES=y +# CONFIG_CRYPTO_AES_586 is not set +# CONFIG_CRYPTO_AES_ARM is not set +# CONFIG_CRYPTO_AES_ARM_BS is not set +# CONFIG_CRYPTO_AES_NI_INTEL is not set +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +# CONFIG_CRYPTO_ANSI_CPRNG is not set +# CONFIG_CRYPTO_ANUBIS is not set +CONFIG_CRYPTO_ARC4=y +# CONFIG_CRYPTO_AUTHENC is not set +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_BLKCIPHER2=y +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_CBC is not set +# CONFIG_CRYPTO_CCM is not set +# CONFIG_CRYPTO_CMAC is not set +# CONFIG_CRYPTO_CRC32 is not set +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_CRC32C_INTEL is not set +# CONFIG_CRYPTO_CRCT10DIF is not set +# CONFIG_CRYPTO_CRYPTD is not set +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_CTS is not set +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_DES is not set +# CONFIG_CRYPTO_DEV_ATMEL_AES is not set +# CONFIG_CRYPTO_DEV_ATMEL_SHA is not set +# CONFIG_CRYPTO_DEV_ATMEL_TDES is not set +# CONFIG_CRYPTO_DEV_CCP is not set +# CONFIG_CRYPTO_DEV_FSL_CAAM is not set +# CONFIG_CRYPTO_DEV_HIFN_795X is not set +# CONFIG_CRYPTO_DEV_IMGTEC_HASH is not set +# CONFIG_CRYPTO_DEV_MV_CESA is not set +# CONFIG_CRYPTO_DEV_QAT_DH895xCC is not set +# CONFIG_CRYPTO_DEV_QCE is not set +# CONFIG_CRYPTO_DEV_SAHARA is not set +# CONFIG_CRYPTO_DEV_TALITOS is not set +# CONFIG_CRYPTO_DRBG_MENU is not set +# CONFIG_CRYPTO_ECB is not set +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_FIPS is not set +# CONFIG_CRYPTO_GCM is not set +# CONFIG_CRYPTO_GF128MUL is not set +# CONFIG_CRYPTO_GHASH is not set +# CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL is not set +# CONFIG_CRYPTO_HASH is not set +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_HW is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_LZ4 is not set +# CONFIG_CRYPTO_LZ4HC is not set +# CONFIG_CRYPTO_LZO is not set +# CONFIG_CRYPTO_MANAGER is not set +# CONFIG_CRYPTO_MANAGER2 is not set +CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y +# CONFIG_CRYPTO_MCRYPTD is not set +# CONFIG_CRYPTO_MD4 is not set +# CONFIG_CRYPTO_MD5 is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_PCBC is not set +# CONFIG_CRYPTO_PCOMP is not set +# CONFIG_CRYPTO_PCOMP2 is not set +# CONFIG_CRYPTO_PCRYPT is not set +# CONFIG_CRYPTO_RMD128 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_RMD256 is not set +# CONFIG_CRYPTO_RMD320 is not set +# CONFIG_CRYPTO_RNG is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_SALSA20_586 is not set +# CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_SEQIV is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA1_ARM is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_TEST is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_TWOFISH_586 is not set +# CONFIG_CRYPTO_TWOFISH_COMMON is not set +# CONFIG_CRYPTO_USER is not set +# CONFIG_CRYPTO_USER_API_AEAD is not set +# CONFIG_CRYPTO_USER_API_HASH is not set +# CONFIG_CRYPTO_USER_API_RNG is not set +# CONFIG_CRYPTO_USER_API_SKCIPHER is not set +# CONFIG_CRYPTO_VMAC is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_XTS is not set +# CONFIG_CRYPTO_XZ is not set +# CONFIG_CRYPTO_ZLIB is not set +# CONFIG_CRYSTALHD is not set +# CONFIG_CS5535_MFGPT is not set +# CONFIG_CS89x0 is not set +# CONFIG_CUSE is not set +# CONFIG_CW1200 is not set +# CONFIG_CXL_BASE is not set +# CONFIG_CXT1E1 is not set +# CONFIG_CYPRESS_FIRMWARE is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_DCB is not set +# CONFIG_DDR is not set +# CONFIG_DE600 is not set +# CONFIG_DE620 is not set +# CONFIG_DEBUG_ATOMIC_SLEEP is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_CREDENTIALS is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +CONFIG_DEBUG_FS=y +# CONFIG_DEBUG_GPIO is not set +# CONFIG_DEBUG_HIGHMEM is not set +# CONFIG_DEBUG_ICEDCC is not set +# CONFIG_DEBUG_INFO is not set +# CONFIG_DEBUG_INFO_DWARF4 is not set +CONFIG_DEBUG_INFO_REDUCED=y +# CONFIG_DEBUG_INFO_SPLIT is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_KMEMLEAK is not set +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_KOBJECT_RELEASE is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_LL is not set +# CONFIG_DEBUG_LL_UART_8250 is not set +# CONFIG_DEBUG_LL_UART_PL01X is not set +# CONFIG_DEBUG_LOCKDEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_DEBUG_NX_TEST is not set +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_DEBUG_PAGEALLOC is not set +# CONFIG_DEBUG_PERF_USE_VMALLOC is not set +# CONFIG_DEBUG_PER_CPU_MAPS is not set +# CONFIG_DEBUG_PI_LIST is not set +# CONFIG_DEBUG_PINCTRL is not set +# CONFIG_DEBUG_PREEMPT is not set +# CONFIG_DEBUG_RODATA is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_DEBUG_SECTION_MISMATCH is not set +# CONFIG_DEBUG_SEMIHOSTING is not set +# CONFIG_DEBUG_SET_MODULE_RONX is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_SHIRQ is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_STACKOVERFLOW is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_STRICT_USER_COPY_CHECKS is not set +# CONFIG_DEBUG_TIMEKEEPING is not set +# CONFIG_DEBUG_UART_BCM63XX is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_WRITECOUNT is not set +# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set +# CONFIG_DEBUG_ZBOOT is not set +# CONFIG_DECNET is not set +CONFIG_DEFAULT_CUBIC=y +CONFIG_DEFAULT_DEADLINE=y +CONFIG_DEFAULT_HOSTNAME="(none)" +CONFIG_DEFAULT_IOSCHED="deadline" +CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4 +CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 +# CONFIG_DEFAULT_NOOP is not set +# CONFIG_DEFAULT_RENO is not set +CONFIG_DEFAULT_SECURITY="" +CONFIG_DEFAULT_SECURITY_DAC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +# CONFIG_DELL_SMO8800 is not set +# CONFIG_DEPRECATED_PARAM_STRUCT is not set +# CONFIG_DETECT_HUNG_TASK is not set +# CONFIG_DEVKMEM is not set +# CONFIG_DEVMEM is not set +CONFIG_DEVPORT=y +# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set +# CONFIG_DEVTMPFS is not set +# CONFIG_DEVTMPFS_MOUNT is not set +# CONFIG_DGAP is not set +# CONFIG_DGNC is not set +# CONFIG_DGRP is not set +# CONFIG_DHT11 is not set +# CONFIG_DIRECT_IO is not set +CONFIG_DISABLE_DEV_COREDUMP=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_DISPLAY_CONNECTOR_ANALOG_TV is not set +# CONFIG_DISPLAY_CONNECTOR_DVI is not set +# CONFIG_DISPLAY_CONNECTOR_HDMI is not set +# CONFIG_DISPLAY_ENCODER_TFP410 is not set +# CONFIG_DISPLAY_ENCODER_TPD12S015 is not set +# CONFIG_DISPLAY_PANEL_DPI is not set +# CONFIG_DISPLAY_PANEL_LGPHILIPS_LB035Q02 is not set +# CONFIG_DISPLAY_PANEL_TPO_TD028TTEC1 is not set +# CONFIG_DISPLAY_PANEL_TPO_TD043MTEA1 is not set +# CONFIG_DISPLAY_SUPPORT is not set +# CONFIG_DL2K is not set +# CONFIG_DLM is not set +# CONFIG_DM9000 is not set +# CONFIG_DMADEVICES is not set +# CONFIG_DMADEVICES_DEBUG is not set +# CONFIG_DMASCC is not set +# CONFIG_DMATEST is not set +# CONFIG_DMA_API_DEBUG is not set +# CONFIG_DMA_ENGINE is not set +# CONFIG_DMA_SHARED_BUFFER is not set +# CONFIG_DM_CACHE is not set +# CONFIG_DM_DEBUG is not set +# CONFIG_DM_DELAY is not set +# CONFIG_DM_ERA is not set +# CONFIG_DM_FLAKEY is not set +# CONFIG_DM_LOG_USERSPACE is not set +# CONFIG_DM_MULTIPATH is not set +# CONFIG_DM_RAID is not set +# CONFIG_DM_SWITCH is not set +# CONFIG_DM_THIN_PROVISIONING is not set +# CONFIG_DM_UEVENT is not set +# CONFIG_DM_VERITY is not set +# CONFIG_DM_ZERO is not set +# CONFIG_DNET is not set +# CONFIG_DNOTIFY is not set +# CONFIG_DNS_RESOLVER is not set +CONFIG_DOUBLEFAULT=y +CONFIG_DQL=y +# CONFIG_DRAGONRISE_FF is not set +# CONFIG_DRM is not set +# CONFIG_DS1682 is not set +# CONFIG_DTLK is not set +# CONFIG_DUMMY is not set +# CONFIG_DUMMY_IRQ is not set +# CONFIG_DVB_AU8522_V4L is not set +# CONFIG_DVB_CORE is not set +# CONFIG_DVB_DUMMY_FE is not set +# CONFIG_DVB_TUNER_DIB0070 is not set +# CONFIG_DVB_TUNER_DIB0090 is not set +# CONFIG_DW_DMAC is not set +# CONFIG_DW_WATCHDOG is not set +# CONFIG_DWC3_HOST_USB3_LPM_ENABLE is not set +# CONFIG_DX_SEP is not set +# CONFIG_DYNAMIC_DEBUG is not set +# CONFIG_E100 is not set +# CONFIG_E1000 is not set +# CONFIG_E1000E is not set +# CONFIG_E2100 is not set +# CONFIG_EARLY_PRINTK_8250 is not set +# CONFIG_EASYCAP is not set +# CONFIG_ECHO is not set +# CONFIG_ECONET is not set +# CONFIG_ECRYPT_FS is not set +# CONFIG_EDAC is not set +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_EEPROM_93XX46 is not set +# CONFIG_EEPROM_AT24 is not set +# CONFIG_EEPROM_AT25 is not set +# CONFIG_EEPROM_DIGSY_MTC_CFG is not set +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +# CONFIG_EEXPRESS is not set +# CONFIG_EEXPRESS_PRO is not set +CONFIG_EFI_PARTITION=y +# CONFIG_EFS_FS is not set +# CONFIG_ELF_CORE is not set +# CONFIG_EMAC_ROCKCHIP is not set +CONFIG_EMBEDDED=y +# CONFIG_EM_TIMER_STI is not set +# CONFIG_ENABLE_MUST_CHECK is not set +CONFIG_ENABLE_WARN_DEPRECATED=y +# CONFIG_ENC28J60 is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_ENCRYPTED_KEYS is not set +# CONFIG_ENIC is not set +# CONFIG_EPAPR_PARAVIRT is not set +# CONFIG_EPIC100 is not set +CONFIG_EPOLL=y +# CONFIG_EQUALIZER is not set +# CONFIG_ET131X is not set +# CONFIG_GATEWORKS_GW16083 is not set +# CONFIG_GDB_SCRIPTS is not set +# CONFIG_GLOB_SELFTEST is not set +# CONFIG_GS_FPGABOOT is not set +# CONFIG_ETH16I is not set +CONFIG_ETHERNET=y +# CONFIG_ETHOC is not set +CONFIG_EVENTFD=y +# CONFIG_EVENT_POWER_TRACING_DEPRECATED is not set +# CONFIG_EWRK3 is not set +CONFIG_EXPERIMENTAL=y +CONFIG_EXPERT=y +# CONFIG_EXPORTFS is not set +# CONFIG_EXT2_FS is not set +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set +# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set +# CONFIG_EXT3_FS is not set +# CONFIG_EXT3_FS_XATTR is not set +# CONFIG_EXT4_DEBUG is not set +# CONFIG_EXT4_ENCRYPTION is not set +# CONFIG_EXT4_FS is not set +# CONFIG_EXT4_FS_POSIX_ACL is not set +# CONFIG_EXT4_FS_SECURITY is not set +CONFIG_EXT4_FS_XATTR=y +CONFIG_EXT4_USE_FOR_EXT23=y +# CONFIG_EXTCON is not set +CONFIG_EXTRA_FIRMWARE="" +CONFIG_EXTRA_TARGETS="" +# CONFIG_EXYNOS_ADC is not set +# CONFIG_EXYNOS_VIDEO is not set +# CONFIG_EZX_PCAP is not set +# CONFIG_F2FS_FS is not set +# CONFIG_F2FS_IO_TRACE is not set +# CONFIG_FAIR_GROUP_SCHED is not set +# CONFIG_FANOTIFY is not set +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_FAT_FS is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_FB is not set +# CONFIG_FB_3DFX is not set +# CONFIG_FB_ARC is not set +# CONFIG_FB_ARK is not set +# CONFIG_FB_ARMCLCD is not set +# CONFIG_FB_ASILIANT is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_AUO_K190X is not set +# CONFIG_FB_BACKLIGHT is not set +# CONFIG_FB_BOOT_VESA_SUPPORT is not set +# CONFIG_FB_BROADSHEET is not set +# CONFIG_FB_CARMINE is not set +# CONFIG_FB_CFB_COPYAREA is not set +# CONFIG_FB_CFB_FILLRECT is not set +# CONFIG_FB_CFB_IMAGEBLIT is not set +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set +# CONFIG_FB_CIRRUS is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_DA8XX is not set +# CONFIG_FB_DDC is not set +# CONFIG_FB_FOREIGN_ENDIAN is not set +# CONFIG_FB_GEODE is not set +# CONFIG_FB_GOLDFISH is not set +# CONFIG_FB_HGA is not set +# CONFIG_FB_I740 is not set +# CONFIG_FB_IBM_GXT4500 is not set +# CONFIG_FB_IMSTT is not set +# CONFIG_FB_IMX is not set +# CONFIG_FB_KYRO is not set +# CONFIG_FB_LE80578 is not set +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_MB862XX is not set +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_N411 is not set +# CONFIG_FB_NEOMAGIC is not set +# CONFIG_FB_NVIDIA is not set +# CONFIG_FB_OF is not set +# CONFIG_FB_OPENCORES is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_PM3 is not set +# CONFIG_FB_PS3 is not set +# CONFIG_FB_PXA is not set +# CONFIG_FB_RADEON is not set +# CONFIG_FB_RIVA is not set +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_S3 is not set +# CONFIG_FB_SAVAGE is not set +# CONFIG_FB_SIMPLE is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_SM7XX is not set +# CONFIG_FB_SMSCUFX is not set +# CONFIG_FB_SSD1307 is not set +# CONFIG_FB_SVGALIB is not set +# CONFIG_FB_SYS_COPYAREA is not set +# CONFIG_FB_SYS_FILLRECT is not set +# CONFIG_FB_SYS_FOPS is not set +# CONFIG_FB_SYS_IMAGEBLIT is not set +# CONFIG_FB_TFT is not set +# CONFIG_FB_TILEBLITTING is not set +# CONFIG_FB_TMIO is not set +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_UDL is not set +# CONFIG_FB_UVESA is not set +# CONFIG_FB_VGA16 is not set +# CONFIG_FB_VIA is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_VT8623 is not set +# CONFIG_FB_XGI is not set +# CONFIG_FCOE is not set +# CONFIG_FCOE_FNIC is not set +# CONFIG_FDDI is not set +# CONFIG_FEALNX is not set +# CONFIG_FENCE_TRACE is not set +# CONFIG_FHANDLE is not set +CONFIG_FIB_RULES=y +CONFIG_FILE_LOCKING=y +# CONFIG_FIREWIRE is not set +# CONFIG_FIREWIRE_NOSY is not set +# CONFIG_FIREWIRE_SERIAL is not set +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FIRMWARE_IN_KERNEL is not set +# CONFIG_FIRMWARE_MEMMAP is not set +# CONFIG_FIXED_PHY is not set +CONFIG_FLATMEM=y +CONFIG_FLATMEM_MANUAL=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_FM10K is not set +# CONFIG_FMC is not set +# CONFIG_FORCEDETH is not set +CONFIG_FORCE_MAX_ZONEORDER=11 +# CONFIG_FRAMEBUFFER_CONSOLE is not set +# CONFIG_FRAME_POINTER is not set +CONFIG_FRAME_WARN=1024 +# CONFIG_FREEZER is not set +# CONFIG_FRONTSWAP is not set +# CONFIG_FSCACHE is not set +# CONFIG_FSL_EDMA is not set +# CONFIG_FSL_XGMAC_MDIO is not set +CONFIG_FSNOTIFY=y +# CONFIG_FS_POSIX_ACL is not set +# CONFIG_FT1000 is not set +# CONFIG_FTGMAC100 is not set +# CONFIG_FTL is not set +# CONFIG_FTMAC100 is not set +# CONFIG_FTRACE is not set +# CONFIG_FTRACE_STARTUP_TEST is not set +# CONFIG_FTR_FIXUP_SELFTEST is not set +# CONFIG_FUJITSU_TABLET is not set +# CONFIG_FUNCTION_TRACER is not set +# CONFIG_FUSE_FS is not set +# CONFIG_FUSION is not set +# CONFIG_FUSION_FC is not set +# CONFIG_FUSION_SAS is not set +# CONFIG_FUSION_SPI is not set +CONFIG_FUTEX=y +CONFIG_FW_LOADER=y +CONFIG_FW_LOADER_USER_HELPER=y +CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y +CONFIG_GACT_PROB=y +# CONFIG_GADGET_UAC1 is not set +# CONFIG_GAMEPORT is not set +# CONFIG_GCOV is not set +# CONFIG_GCOV_KERNEL is not set +# CONFIG_GENEVE is not set +# CONFIG_GENERIC_ADC_BATTERY is not set +CONFIG_GENERIC_CALIBRATE_DELAY=y +# CONFIG_GENERIC_CPU_DEVICES is not set +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_NET_UTILS=y +# CONFIG_GENERIC_PHY is not set +CONFIG_GENERIC_TIME=y +# CONFIG_GENWQE is not set +# CONFIG_GFS2_FS is not set +# CONFIG_GIGASET_CAPI is not set +# CONFIG_GIGASET_DEBUG is not set +# CONFIG_GP2AP020A00F is not set +# CONFIG_GPIOLIB is not set +# CONFIG_GPIO_74X164 is not set +# CONFIG_GPIO_74XX_MMIO is not set +# CONFIG_GPIO_ADNP is not set +# CONFIG_GPIO_ADP5588 is not set +# CONFIG_GPIO_ALTERA is not set +# CONFIG_GPIO_AMD8111 is not set +# CONFIG_GPIO_BCM_KONA is not set +# CONFIG_GPIO_BT8XX is not set +# CONFIG_GPIO_CS5535 is not set +# CONFIG_GPIO_DWAPB is not set +# CONFIG_GPIO_EM is not set +# CONFIG_GPIO_GENERIC_PLATFORM is not set +# CONFIG_GPIO_GRGPIO is not set +# CONFIG_GPIO_ICH is not set +# CONFIG_GPIO_IT8761E is not set +# CONFIG_GPIO_LANGWELL is not set +# CONFIG_GPIO_MAX7300 is not set +# CONFIG_GPIO_MAX7301 is not set +# CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_MC33880 is not set +# CONFIG_GPIO_MCP23S08 is not set +# CONFIG_GPIO_ML_IOH is not set +# CONFIG_GPIO_PCA953X is not set +# CONFIG_GPIO_PCF857X is not set +# CONFIG_GPIO_PCH is not set +# CONFIG_GPIO_PL061 is not set +# CONFIG_GPIO_RCAR is not set +# CONFIG_GPIO_RDC321X is not set +# CONFIG_GPIO_SCH is not set +# CONFIG_GPIO_SCH311X is not set +# CONFIG_GPIO_SX150X is not set +# CONFIG_GPIO_SYSCON is not set +# CONFIG_GPIO_SYSFS is not set +# CONFIG_GPIO_TS5500 is not set +# CONFIG_GPIO_VX855 is not set +# CONFIG_GPIO_WATCHDOG is not set +# CONFIG_GPIO_WDT is not set +# CONFIG_GPIO_XILINX is not set +# CONFIG_GPIO_ZEVIO is not set +# CONFIG_GREENASIA_FF is not set +# CONFIG_HAMACHI is not set +# CONFIG_HAMRADIO is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_HARDLOCKUP_DETECTOR is not set +# CONFIG_HAVE_AOUT is not set +# CONFIG_HAVE_ARM_ARCH_TIMER is not set +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +# CONFIG_HCALL_STATS is not set +# CONFIG_HDLC is not set +# CONFIG_HDLC_CISCO is not set +# CONFIG_HDLC_FR is not set +# CONFIG_HDLC_PPP is not set +# CONFIG_HDLC_RAW is not set +# CONFIG_HDLC_RAW_ETH is not set +# CONFIG_HDQ_MASTER_OMAP is not set +# CONFIG_HEADERS_CHECK is not set +# CONFIG_HERMES is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_HFSPLUS_FS_POSIX_ACL is not set +# CONFIG_HFS_FS is not set +# CONFIG_HIBERNATION is not set +# CONFIG_HID is not set +# CONFIG_HIDRAW is not set +# CONFIG_HID_A4TECH is not set +# CONFIG_HID_ACRUX is not set +# CONFIG_HID_ACRUX_FF is not set +# CONFIG_HID_APPLE is not set +# CONFIG_HID_APPLEIR is not set +# CONFIG_HID_AUREAL is not set +# CONFIG_HID_BATTERY_STRENGTH is not set +# CONFIG_HID_BELKIN is not set +# CONFIG_HID_BETOP_FF is not set +# CONFIG_HID_CHERRY is not set +# CONFIG_HID_CHICONY is not set +# CONFIG_HID_CP2112 is not set +# CONFIG_HID_CYPRESS is not set +# CONFIG_HID_DRAGONRISE is not set +# CONFIG_HID_ELECOM is not set +# CONFIG_HID_ELO is not set +# CONFIG_HID_EMS_FF is not set +# CONFIG_HID_EZKEY is not set +# CONFIG_HID_GENERIC is not set +# CONFIG_HID_GREENASIA is not set +# CONFIG_HID_GT683R is not set +# CONFIG_HID_GYRATION is not set +# CONFIG_HID_HOLTEK is not set +# CONFIG_HID_HUION is not set +# CONFIG_HID_ICADE is not set +# CONFIG_HID_KENSINGTON is not set +# CONFIG_HID_KEYTOUCH is not set +# CONFIG_HID_KYE is not set +# CONFIG_HID_LCPOWER is not set +# CONFIG_HID_LENOVO is not set +# CONFIG_HID_LENOVO_TPKBD is not set +# CONFIG_HID_LOGITECH is not set +# CONFIG_HID_LOGITECH_DJ is not set +# CONFIG_HID_LOGITECH_HIDPP is not set +# CONFIG_HID_MAGICMOUSE is not set +# CONFIG_HID_MICROSOFT is not set +# CONFIG_HID_MONTEREY is not set +# CONFIG_HID_MULTITOUCH is not set +# CONFIG_HID_NTRIG is not set +# CONFIG_HID_ORTEK is not set +# CONFIG_HID_PANTHERLORD is not set +# CONFIG_HID_PENMOUNT is not set +# CONFIG_HID_PETALYNX is not set +# CONFIG_HID_PICOLCD is not set +# CONFIG_HID_PID is not set +# CONFIG_HID_PLANTRONICS is not set +# CONFIG_HID_PRIMAX is not set +# CONFIG_HID_PRODIKEYS is not set +# CONFIG_HID_PS3REMOTE is not set +# CONFIG_HID_QUANTA is not set +# CONFIG_HID_RMI is not set +# CONFIG_HID_ROCCAT is not set +# CONFIG_HID_ROCCAT_ARVO is not set +# CONFIG_HID_ROCCAT_KONE is not set +# CONFIG_HID_ROCCAT_KONEPLUS is not set +# CONFIG_HID_ROCCAT_KOVAPLUS is not set +# CONFIG_HID_ROCCAT_PYRA is not set +# CONFIG_HID_SAITEK is not set +# CONFIG_HID_SAMSUNG is not set +# CONFIG_HID_SENSOR_HUB is not set +# CONFIG_HID_SMARTJOYPLUS is not set +# CONFIG_HID_SONY is not set +# CONFIG_HID_SPEEDLINK is not set +# CONFIG_HID_STEELSERIES is not set +# CONFIG_HID_SUNPLUS is not set +# CONFIG_HID_SUPPORT is not set +# CONFIG_HID_THINGM is not set +# CONFIG_HID_THRUSTMASTER is not set +# CONFIG_HID_TIVO is not set +# CONFIG_HID_TOPSEED is not set +# CONFIG_HID_TWINHAN is not set +# CONFIG_HID_UCLOGIC is not set +# CONFIG_HID_WACOM is not set +# CONFIG_HID_WALTOP is not set +# CONFIG_HID_WIIMOTE is not set +# CONFIG_HID_XINMO is not set +# CONFIG_HID_ZEROPLUS is not set +# CONFIG_HID_ZYDACRON is not set +# CONFIG_HIGHMEM is not set +CONFIG_HIGH_RES_TIMERS=y +# CONFIG_HIP04_ETH is not set +# CONFIG_HIPPI is not set +# CONFIG_HIX5HD2_GMAC is not set +# CONFIG_HMC6352 is not set +# CONFIG_HOSTAP is not set +# CONFIG_HOSTAP_CS is not set +# CONFIG_HOSTAP_PCI is not set +# CONFIG_HOSTAP_PLX is not set +CONFIG_HOTPLUG=y +# CONFIG_HOTPLUG_CPU is not set +# CONFIG_HOTPLUG_PCI is not set +# CONFIG_HP100 is not set +CONFIG_HPET_MMAP_DEFAULT=y +# CONFIG_HPFS_FS is not set +# CONFIG_HPLAN is not set +# CONFIG_HPLAN_PLUS is not set +# CONFIG_HP_ILO is not set +# CONFIG_HP_WIRELESS is not set +# CONFIG_HSI is not set +# CONFIG_HSR is not set +# CONFIG_HTC_EGPIO is not set +# CONFIG_HTC_I2CPLD is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_HUGETLB_PAGE is not set +# CONFIG_HVC_DCC is not set +# CONFIG_HVC_UDBG is not set +# CONFIG_HWMON is not set +# CONFIG_HWMON_DEBUG_CHIP is not set +# CONFIG_HWMON_VID is not set +# CONFIG_HWSPINLOCK_OMAP is not set +CONFIG_HW_PERF_EVENTS=y +# CONFIG_HW_RANDOM is not set +# CONFIG_HW_RANDOM_AMD is not set +# CONFIG_HW_RANDOM_ATMEL is not set +# CONFIG_HW_RANDOM_EXYNOS is not set +# CONFIG_HW_RANDOM_GEODE is not set +# CONFIG_HW_RANDOM_INTEL is not set +# CONFIG_HW_RANDOM_IPROC_RNG200 is not set +# CONFIG_HW_RANDOM_OMAP3_ROM is not set +# CONFIG_HW_RANDOM_PPC4XX is not set +# CONFIG_HW_RANDOM_TIMERIOMEM is not set +# CONFIG_HW_RANDOM_VIA is not set +# CONFIG_HYPERV is not set +# CONFIG_HYSDN is not set +CONFIG_HZ=100 +CONFIG_HZ_100=y +# CONFIG_HZ_1000 is not set +# CONFIG_HZ_1024 is not set +# CONFIG_HZ_128 is not set +# CONFIG_HZ_200 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_256 is not set +# CONFIG_HZ_300 is not set +# CONFIG_HZ_48 is not set +# CONFIG_HZ_500 is not set +# CONFIG_HZ_PERIODIC is not set +# CONFIG_I2C is not set +# CONFIG_I2C_ALGOBIT is not set +# CONFIG_I2C_ALGOPCA is not set +# CONFIG_I2C_ALGOPCF is not set +# CONFIG_I2C_ALI1535 is not set +# CONFIG_I2C_ALI1563 is not set +# CONFIG_I2C_ALI15X3 is not set +# CONFIG_I2C_AMD756 is not set +# CONFIG_I2C_AMD8111 is not set +# CONFIG_I2C_ARB_GPIO_CHALLENGE is not set +# CONFIG_I2C_AU1550 is not set +# CONFIG_I2C_BCM2835 is not set +# CONFIG_I2C_BCM_IPROC is not set +# CONFIG_I2C_CBUS_GPIO is not set +# CONFIG_I2C_CHARDEV is not set +# CONFIG_I2C_COMPAT is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DESIGNWARE is not set +# CONFIG_I2C_DESIGNWARE_PCI is not set +# CONFIG_I2C_DESIGNWARE_PLATFORM is not set +# CONFIG_I2C_DIOLAN_U2C is not set +# CONFIG_I2C_EG20T is not set +# CONFIG_I2C_ELEKTOR is not set +# CONFIG_I2C_GPIO is not set +# CONFIG_I2C_HELPER_AUTO is not set +# CONFIG_I2C_HID is not set +# CONFIG_I2C_I801 is not set +# CONFIG_I2C_IBM_IIC is not set +# CONFIG_I2C_IMG is not set +# CONFIG_I2C_INTEL_MID is not set +# CONFIG_I2C_ISCH is not set +# CONFIG_I2C_ISMT is not set +# CONFIG_I2C_MPC is not set +# CONFIG_I2C_MUX is not set +# CONFIG_I2C_MUX_PINCTRL is not set +# CONFIG_I2C_MV64XXX is not set +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_NOMADIK is not set +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_OCTEON is not set +# CONFIG_I2C_PARPORT is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_PCA_ISA is not set +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_PIIX4 is not set +# CONFIG_I2C_PXA_PCI is not set +# CONFIG_I2C_RCAR is not set +# CONFIG_I2C_RK3X is not set +# CONFIG_I2C_ROBOTFUZZ_OSIF is not set +# CONFIG_I2C_SCMI is not set +# CONFIG_I2C_SH_MOBILE is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_SLAVE is not set +# CONFIG_I2C_SMBUS is not set +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_TINY_USB is not set +# CONFIG_I2C_VERSATILE is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set +# CONFIG_I2C_XILINX is not set +# CONFIG_I2O is not set +# CONFIG_I40E is not set +# CONFIG_I40EVF is not set +# CONFIG_I6300ESB_WDT is not set +# CONFIG_I82092 is not set +# CONFIG_I82365 is not set +# CONFIG_IBM_ASM is not set +# CONFIG_IBM_EMAC_DEBUG is not set +# CONFIG_IBM_EMAC_EMAC4 is not set +# CONFIG_IBM_EMAC_MAL_CLR_ICINTSTAT is not set +# CONFIG_IBM_EMAC_MAL_COMMON_ERR is not set +# CONFIG_IBM_EMAC_NO_FLOW_CTRL is not set +# CONFIG_IBM_EMAC_RGMII is not set +# CONFIG_IBM_EMAC_TAH is not set +# CONFIG_IBM_EMAC_ZMII is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_ICS932S401 is not set +# CONFIG_IDE is not set +# CONFIG_IDEAPAD_LAPTOP is not set +# CONFIG_IDE_GD is not set +# CONFIG_IDE_PHISON is not set +# CONFIG_IDE_PROC_FS is not set +# CONFIG_IDE_TASK_IOCTL is not set +# CONFIG_IEEE802154 is not set +# CONFIG_IFB is not set +# CONFIG_IGB is not set +# CONFIG_IGBVF is not set +# CONFIG_IIO is not set +# CONFIG_IIO_BUFFER_CB is not set +CONFIG_IIO_CONSUMERS_PER_TRIGGER=2 +# CONFIG_IIO_GPIO_TRIGGER is not set +# CONFIG_IIO_INTERRUPT_TRIGGER is not set +# CONFIG_IIO_PERIODIC_RTC_TRIGGER is not set +# CONFIG_IIO_SIMPLE_DUMMY is not set +# CONFIG_IIO_SSP_SENSORHUB is not set +# CONFIG_IIO_ST_ACCEL_3AXIS is not set +# CONFIG_IIO_ST_GYRO_3AXIS is not set +# CONFIG_IIO_ST_MAGN_3AXIS is not set +# CONFIG_IIO_ST_PRESS is not set +# CONFIG_IIO_SYSFS_TRIGGER is not set +# CONFIG_IKCONFIG is not set +# CONFIG_IKCONFIG_PROC is not set +# CONFIG_IMAGE_CMDLINE_HACK is not set +# CONFIG_IMGPDC_WDT is not set +# CONFIG_IMX_IPUV3_CORE is not set +CONFIG_INET=y +# CONFIG_INET6_AH is not set +# CONFIG_INET6_ESP is not set +# CONFIG_INET6_IPCOMP is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_INET6_XFRM_MODE_BEET is not set +# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set +# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET6_XFRM_MODE_TUNNEL is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_DIAG is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_LRO is not set +# CONFIG_INET_TCP_DIAG is not set +# CONFIG_INET_TUNNEL is not set +# CONFIG_INET_UDP_DIAG is not set +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET_XFRM_MODE_TUNNEL is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INFINIBAND is not set +# CONFIG_INFTL is not set +# CONFIG_INITRAMFS_COMPRESSION_BZIP2 is not set +# CONFIG_INITRAMFS_COMPRESSION_GZIP is not set +# CONFIG_INITRAMFS_COMPRESSION_LZMA is not set +CONFIG_INITRAMFS_COMPRESSION_NONE=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +# CONFIG_INIT_FALLBACK is not set +# CONFIG_INLINE_READ_LOCK is not set +# CONFIG_INLINE_READ_LOCK_BH is not set +# CONFIG_INLINE_READ_LOCK_IRQ is not set +# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set +# CONFIG_INLINE_READ_TRYLOCK is not set +CONFIG_INLINE_READ_UNLOCK=y +# CONFIG_INLINE_READ_UNLOCK_BH is not set +CONFIG_INLINE_READ_UNLOCK_IRQ=y +# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_SPIN_LOCK is not set +# CONFIG_INLINE_SPIN_LOCK_BH is not set +# CONFIG_INLINE_SPIN_LOCK_IRQ is not set +# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set +# CONFIG_INLINE_SPIN_TRYLOCK is not set +# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set +CONFIG_INLINE_SPIN_UNLOCK=y +# CONFIG_INLINE_SPIN_UNLOCK_BH is not set +CONFIG_INLINE_SPIN_UNLOCK_IRQ=y +# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_WRITE_LOCK is not set +# CONFIG_INLINE_WRITE_LOCK_BH is not set +# CONFIG_INLINE_WRITE_LOCK_IRQ is not set +# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set +# CONFIG_INLINE_WRITE_TRYLOCK is not set +CONFIG_INLINE_WRITE_UNLOCK=y +# CONFIG_INLINE_WRITE_UNLOCK_BH is not set +CONFIG_INLINE_WRITE_UNLOCK_IRQ=y +# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set +CONFIG_INOTIFY_USER=y +# CONFIG_INPUT is not set +# CONFIG_INPUT_AD714X is not set +# CONFIG_INPUT_ADXL34X is not set +# CONFIG_INPUT_APANEL is not set +# CONFIG_INPUT_ATI_REMOTE is not set +# CONFIG_INPUT_ATI_REMOTE2 is not set +# CONFIG_INPUT_ATLAS_BTNS is not set +# CONFIG_INPUT_BMA150 is not set +# CONFIG_INPUT_CM109 is not set +# CONFIG_INPUT_CMA3000 is not set +# CONFIG_INPUT_DRV260X_HAPTICS is not set +# CONFIG_INPUT_DRV2667_HAPTICS is not set +# CONFIG_INPUT_EVBUG is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_E3X0_BUTTON is not set +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_GP2A is not set +# CONFIG_INPUT_GPIO_BEEPER is not set +# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set +# CONFIG_INPUT_GPIO_TILT_POLLED is not set +# CONFIG_INPUT_IDEAPAD_SLIDEBAR is not set +# CONFIG_INPUT_IMS_PCU is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_KEYSPAN_REMOTE is not set +# CONFIG_INPUT_KXTJ9 is not set +# CONFIG_INPUT_MATRIXKMAP is not set +CONFIG_INPUT_MISC=y +# CONFIG_INPUT_MMA8450 is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_MPU3050 is not set +# CONFIG_INPUT_PCF8574 is not set +# CONFIG_INPUT_PCSPKR is not set +# CONFIG_INPUT_POLLDEV is not set +# CONFIG_INPUT_POWERMATE is not set +# CONFIG_INPUT_PWM_BEEPER is not set +# CONFIG_INPUT_REGULATOR_HAPTIC is not set +# CONFIG_INPUT_SOC_BUTTON_ARRAY is not set +# CONFIG_INPUT_SPARSEKMAP is not set +# CONFIG_INPUT_TABLET is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_UINPUT is not set +# CONFIG_INPUT_WISTRON_BTNS is not set +# CONFIG_INPUT_YEALINK is not set +# CONFIG_INT340X_THERMAL is not set +# CONFIG_INTEL_IDLE is not set +# CONFIG_INTEL_MEI is not set +# CONFIG_INTEL_MEI_ME is not set +# CONFIG_INTEL_MEI_TXE is not set +# CONFIG_INTEL_MIC_CARD is not set +# CONFIG_INTEL_MIC_HOST is not set +# CONFIG_INTEL_MID_PTI is not set +# CONFIG_INTEL_OAKTRAIL is not set +# CONFIG_INTEL_RST is not set +# CONFIG_INTEL_SMARTCONNECT is not set +# CONFIG_INTEL_SOC_PMIC is not set +# CONFIG_INTERVAL_TREE_TEST is not set +# CONFIG_INV_MPU6050_IIO is not set +# CONFIG_IOMMU_SUPPORT is not set +# CONFIG_IOSCHED_CFQ is not set +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_NOOP=y +# CONFIG_IP1000 is not set +# CONFIG_IP17XX_PHY is not set +# CONFIG_IP6_NF_FILTER is not set +# CONFIG_IP6_NF_IPTABLES is not set +# CONFIG_IP6_NF_MANGLE is not set +# CONFIG_IP6_NF_MATCH_AH is not set +# CONFIG_IP6_NF_MATCH_EUI64 is not set +# CONFIG_IP6_NF_MATCH_FRAG is not set +# CONFIG_IP6_NF_MATCH_HL is not set +# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set +# CONFIG_IP6_NF_MATCH_MH is not set +# CONFIG_IP6_NF_MATCH_OPTS is not set +# CONFIG_IP6_NF_MATCH_RPFILTER is not set +# CONFIG_IP6_NF_MATCH_RT is not set +# CONFIG_IP6_NF_NAT is not set +# CONFIG_IP6_NF_QUEUE is not set +# CONFIG_IP6_NF_RAW is not set +# CONFIG_IP6_NF_TARGET_HL is not set +# CONFIG_IP6_NF_TARGET_LOG is not set +# CONFIG_IP6_NF_TARGET_REJECT is not set +# CONFIG_IP6_NF_TARGET_SYNPROXY is not set +# CONFIG_IPACK_BUS is not set +# CONFIG_IPC_NS is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_IPV6 is not set +# CONFIG_IPV6_MIP6 is not set +# CONFIG_IPV6_MROUTE is not set +# CONFIG_IPV6_MROUTE_MULTIPLE_TABLES is not set +# CONFIG_IPV6_MULTIPLE_TABLES is not set +CONFIG_IPV6_NDISC_NODETYPE=y +# CONFIG_IPV6_OPTIMISTIC_DAD is not set +# CONFIG_IPV6_PRIVACY is not set +# CONFIG_IPV6_ROUTER_PREF is not set +# CONFIG_IPV6_ROUTE_INFO is not set +# CONFIG_IPV6_SIT is not set +# CONFIG_IPV6_SIT_6RD is not set +# CONFIG_IPV6_TUNNEL is not set +# CONFIG_IPV6_VTI is not set +# CONFIG_IPVLAN is not set +# CONFIG_IPW2100 is not set +# CONFIG_IPW2100_DEBUG is not set +CONFIG_IPW2100_MONITOR=y +# CONFIG_IPW2200 is not set +# CONFIG_IPW2200_DEBUG is not set +CONFIG_IPW2200_MONITOR=y +# CONFIG_IPW2200_PROMISCUOUS is not set +# CONFIG_IPW2200_QOS is not set +# CONFIG_IPW2200_RADIOTAP is not set +# CONFIG_IPWIRELESS is not set +# CONFIG_IPX is not set +CONFIG_IP_ADVANCED_ROUTER=y +# CONFIG_IP_DCCP is not set +# CONFIG_IP_FIB_TRIE_STATS is not set +CONFIG_IP_MROUTE=y +CONFIG_IP_MROUTE_MULTIPLE_TABLES=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_MULTIPLE_TABLES=y +# CONFIG_IP_NF_ARPFILTER is not set +# CONFIG_IP_NF_ARPTABLES is not set +# CONFIG_IP_NF_ARP_MANGLE is not set +# CONFIG_IP_NF_FILTER is not set +# CONFIG_IP_NF_IPTABLES is not set +# CONFIG_IP_NF_MANGLE is not set +# CONFIG_IP_NF_MATCH_AH is not set +# CONFIG_IP_NF_MATCH_ECN is not set +# CONFIG_IP_NF_MATCH_RPFILTER is not set +# CONFIG_IP_NF_MATCH_TTL is not set +# CONFIG_IP_NF_QUEUE is not set +# CONFIG_IP_NF_RAW is not set +# CONFIG_IP_NF_SECURITY is not set +# CONFIG_IP_NF_TARGET_CLUSTERIP is not set +# CONFIG_IP_NF_TARGET_ECN is not set +# CONFIG_IP_NF_TARGET_LOG is not set +# CONFIG_IP_NF_TARGET_MASQUERADE is not set +# CONFIG_IP_NF_TARGET_NETMAP is not set +# CONFIG_IP_NF_TARGET_REDIRECT is not set +# CONFIG_IP_NF_TARGET_REJECT is not set +# CONFIG_IP_NF_TARGET_SYNPROXY is not set +# CONFIG_IP_NF_TARGET_TTL is not set +# CONFIG_IP_NF_TARGET_ULOG is not set +# CONFIG_IP_PIMSM_V1 is not set +# CONFIG_IP_PIMSM_V2 is not set +# CONFIG_IP_PNP is not set +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_VERBOSE=y +# CONFIG_IP_SCTP is not set +# CONFIG_IP_SET is not set +# CONFIG_IP_VS is not set +# CONFIG_IRDA is not set +# CONFIG_IRQSOFF_TRACER is not set +# CONFIG_IRQ_ALL_CPUS is not set +# CONFIG_IRQ_DOMAIN_DEBUG is not set +# CONFIG_IRQ_TIME_ACCOUNTING is not set +# CONFIG_IR_GPIO_CIR is not set +# CONFIG_IR_HIX5HD2 is not set +# CONFIG_IR_IGORPLUGUSB is not set +# CONFIG_IR_IGUANA is not set +# CONFIG_IR_IMG is not set +# CONFIG_IR_IMON is not set +# CONFIG_IR_JVC_DECODER is not set +# CONFIG_IR_LIRC_CODEC is not set +# CONFIG_IR_MCEUSB is not set +# CONFIG_IR_NEC_DECODER is not set +# CONFIG_IR_RC5_DECODER is not set +# CONFIG_IR_RC5_SZ_DECODER is not set +# CONFIG_IR_RC6_DECODER is not set +# CONFIG_IR_REDRAT3 is not set +# CONFIG_IR_SONY_DECODER is not set +# CONFIG_IR_STREAMZAP is not set +# CONFIG_IR_TTUSBIR is not set +# CONFIG_ISCSI_BOOT_SYSFS is not set +# CONFIG_ISCSI_TCP is not set +CONFIG_ISDN=y +# CONFIG_ISDN_AUDIO is not set +# CONFIG_ISDN_CAPI is not set +# CONFIG_ISDN_CAPI_CAPIDRV is not set +# CONFIG_ISDN_DIVERSION is not set +# CONFIG_ISDN_DRV_ACT2000 is not set +# CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON is not set +# CONFIG_ISDN_DRV_GIGASET is not set +# CONFIG_ISDN_DRV_HISAX is not set +# CONFIG_ISDN_DRV_ICN is not set +# CONFIG_ISDN_DRV_LOOP is not set +# CONFIG_ISDN_DRV_PCBIT is not set +# CONFIG_ISDN_DRV_SC is not set +# CONFIG_ISDN_I4L is not set +# CONFIG_ISL29003 is not set +# CONFIG_ISL29020 is not set +# CONFIG_ISL29125 is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_ISS4xx is not set +# CONFIG_ITG3200 is not set +# CONFIG_IWL3945 is not set +# CONFIG_IWLAGN is not set +# CONFIG_IWLWIFI is not set +# CONFIG_IWMC3200TOP is not set +# CONFIG_IXGB is not set +# CONFIG_IXGBE is not set +# CONFIG_IXGBEVF is not set +# CONFIG_JBD is not set +# CONFIG_JBD2_DEBUG is not set +# CONFIG_JBD_DEBUG is not set +# CONFIG_JFFS2_CMODE_FAVOURLZO is not set +# CONFIG_JFFS2_CMODE_NONE is not set +CONFIG_JFFS2_CMODE_PRIORITY=y +# CONFIG_JFFS2_CMODE_SIZE is not set +CONFIG_JFFS2_COMPRESSION_OPTIONS=y +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +# CONFIG_JFFS2_FS_POSIX_ACL is not set +# CONFIG_JFFS2_FS_SECURITY is not set +# CONFIG_JFFS2_FS_WBUF_VERIFY is not set +CONFIG_JFFS2_FS_WRITEBUFFER=y +CONFIG_JFFS2_FS_XATTR=y +CONFIG_JFFS2_LZMA=y +# CONFIG_JFFS2_LZO is not set +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +CONFIG_JFFS2_SUMMARY=y +# CONFIG_JFFS2_ZLIB is not set +# CONFIG_JFS_DEBUG is not set +# CONFIG_JFS_FS is not set +# CONFIG_JFS_POSIX_ACL is not set +# CONFIG_JFS_SECURITY is not set +# CONFIG_JFS_STATISTICS is not set +# CONFIG_JME is not set +CONFIG_JOLIET=y +# CONFIG_JSA1212 is not set +# CONFIG_JUMP_LABEL is not set +# CONFIG_KALLSYMS is not set +# CONFIG_KALLSYMS_ALL is not set +# CONFIG_KALLSYMS_UNCOMPRESSED is not set +# CONFIG_KARMA_PARTITION is not set +# CONFIG_KERNEL_BZIP2 is not set +# CONFIG_KERNEL_GZIP is not set +# CONFIG_KERNEL_LZ4 is not set +# CONFIG_KERNEL_LZMA is not set +# CONFIG_KERNEL_LZO is not set +CONFIG_KERNEL_MODE_NEON=y +CONFIG_KERNEL_XZ=y +CONFIG_KERNFS=y +# CONFIG_KEXEC is not set +# CONFIG_KEYBOARD_ADP5588 is not set +# CONFIG_KEYBOARD_ADP5589 is not set +# CONFIG_KEYBOARD_ATKBD is not set +# CONFIG_KEYBOARD_BCM is not set +# CONFIG_KEYBOARD_CAP1106 is not set +# CONFIG_KEYBOARD_GPIO is not set +# CONFIG_KEYBOARD_GPIO_POLLED is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_LM8323 is not set +# CONFIG_KEYBOARD_LM8333 is not set +# CONFIG_KEYBOARD_MATRIX is not set +# CONFIG_KEYBOARD_MAX7359 is not set +# CONFIG_KEYBOARD_MCS is not set +# CONFIG_KEYBOARD_MPR121 is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_OMAP4 is not set +# CONFIG_KEYBOARD_OPENCORES is not set +# CONFIG_KEYBOARD_PXA27x is not set +# CONFIG_KEYBOARD_QT1070 is not set +# CONFIG_KEYBOARD_QT2160 is not set +# CONFIG_KEYBOARD_SAMSUNG is not set +# CONFIG_KEYBOARD_SH_KEYSC is not set +# CONFIG_KEYBOARD_STOWAWAY is not set +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_TCA6416 is not set +# CONFIG_KEYBOARD_TCA8418 is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_CAP11XX is not set +# CONFIG_KEYS is not set +# CONFIG_KEYS_DEBUG_PROC_KEYS is not set +# CONFIG_KGDB is not set +# CONFIG_KMEMCHECK is not set +# CONFIG_KMX61 is not set +# CONFIG_KPROBES is not set +# CONFIG_KPROBES_SANITY_TEST is not set +# CONFIG_KS8842 is not set +# CONFIG_KS8851 is not set +# CONFIG_KS8851_MLL is not set +# CONFIG_KSM is not set +# CONFIG_KSZ884X_PCI is not set +CONFIG_KUSER_HELPERS=y +# CONFIG_KVM_GUEST is not set +# CONFIG_KXCJK1013 is not set +# CONFIG_KXSD9 is not set +# CONFIG_L2TP is not set +# CONFIG_L2TP_ETH is not set +# CONFIG_L2TP_IP is not set +# CONFIG_L2TP_V3 is not set +# CONFIG_LANMEDIA is not set +# CONFIG_LANTIQ is not set +# CONFIG_LAPB is not set +# CONFIG_LASAT is not set +# CONFIG_LATENCYTOP is not set +# CONFIG_LATTICE_ECP3_CONFIG is not set +CONFIG_LBDAF=y +# CONFIG_LCD_AMS369FG06 is not set +# CONFIG_LCD_HX8357 is not set +# CONFIG_LCD_ILI922X is not set +# CONFIG_LCD_ILI9320 is not set +# CONFIG_LCD_L4F00242T03 is not set +# CONFIG_LCD_LD9040 is not set +# CONFIG_LCD_LMS283GF05 is not set +# CONFIG_LCD_LMS501KF03 is not set +# CONFIG_LCD_LTV350QV is not set +# CONFIG_LCD_S6E63M0 is not set +# CONFIG_LCD_TDO24M is not set +# CONFIG_LCD_VGG2432A4 is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_LEDS_ATMEL_PWM is not set +# CONFIG_LEDS_BD2802 is not set +# CONFIG_LEDS_BLINKM is not set +CONFIG_LEDS_CLASS=y +# CONFIG_LEDS_CLASS_FLASH is not set +# CONFIG_LEDS_DAC124S085 is not set +# CONFIG_LEDS_GPIO is not set +CONFIG_LEDS_GPIO_OF=y +CONFIG_LEDS_GPIO_PLATFORM=y +# CONFIG_LEDS_INTEL_SS4200 is not set +# CONFIG_LEDS_LM3530 is not set +# CONFIG_LEDS_LM3556 is not set +# CONFIG_LEDS_LM355x is not set +# CONFIG_LEDS_LM3642 is not set +# CONFIG_LEDS_LP3944 is not set +# CONFIG_LEDS_LP5521 is not set +# CONFIG_LEDS_LP5523 is not set +# CONFIG_LEDS_LP5562 is not set +# CONFIG_LEDS_LP8501 is not set +# CONFIG_LEDS_LP8860 is not set +# CONFIG_LEDS_LT3593 is not set +# CONFIG_LEDS_NET5501 is not set +# CONFIG_LEDS_OT200 is not set +# CONFIG_LEDS_PCA9532 is not set +# CONFIG_LEDS_PCA955X is not set +# CONFIG_LEDS_PCA9633 is not set +# CONFIG_LEDS_PCA963X is not set +# CONFIG_LEDS_PCA9685 is not set +# CONFIG_LEDS_PM8941_WLED is not set +# CONFIG_LEDS_PWM is not set +# CONFIG_LEDS_REGULATOR is not set +# CONFIG_LEDS_RENESAS_TPU is not set +# CONFIG_LEDS_SYSCON is not set +# CONFIG_LEDS_TCA6507 is not set +CONFIG_LEDS_TRIGGERS=y +# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set +# CONFIG_LEDS_TRIGGER_CAMERA is not set +# CONFIG_LEDS_TRIGGER_CPU is not set +CONFIG_LEDS_TRIGGER_DEFAULT_ON=y +# CONFIG_LEDS_TRIGGER_GPIO is not set +# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set +# CONFIG_LEDS_TRIGGER_IDE_DISK is not set +# CONFIG_LEDS_TRIGGER_MORSE is not set +CONFIG_LEDS_TRIGGER_NETDEV=y +# CONFIG_LEDS_TRIGGER_ONESHOT is not set +CONFIG_LEDS_TRIGGER_TIMER=y +# CONFIG_LEDS_TRIGGER_TRANSIENT is not set +# CONFIG_LEDS_TRIGGER_USBDEV is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_LIB80211 is not set +# CONFIG_LIB80211_CRYPT_CCMP is not set +# CONFIG_LIB80211_CRYPT_TKIP is not set +# CONFIG_LIB80211_CRYPT_WEP is not set +# CONFIG_LIB80211_DEBUG is not set +# CONFIG_LIBCRC32C is not set +# CONFIG_LIBERTAS is not set +# CONFIG_LIBERTAS_THINFIRM is not set +# CONFIG_LIBERTAS_USB is not set +# CONFIG_LIBFC is not set +# CONFIG_LIBFCOE is not set +# CONFIG_LIBIPW_DEBUG is not set +# CONFIG_LINE6_USB is not set +# CONFIG_LIRC_STAGING is not set +# CONFIG_LIS3L02DQ is not set +# CONFIG_LKDTM is not set +CONFIG_LLC=y +# CONFIG_LLC2 is not set +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +# CONFIG_LOCKD is not set +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_LOCKD_V4=y +# CONFIG_LOCKUP_DETECTOR is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_LOCK_TORTURE_TEST is not set +# CONFIG_LOGFS is not set +# CONFIG_LOGIG940_FF is not set +# CONFIG_LOGIRUMBLEPAD2_FF is not set +# CONFIG_LOGITECH_FF is not set +# CONFIG_LOGIWHEELS_FF is not set +# CONFIG_LOGO is not set +CONFIG_LOG_BUF_SHIFT=17 +CONFIG_LOG_CPU_MAX_BUF_SHIFT=12 +# CONFIG_LOONGSON_MC146818 is not set +# CONFIG_LP486E is not set +# CONFIG_LPC_ICH is not set +# CONFIG_LPC_SCH is not set +# CONFIG_LP_CONSOLE is not set +# CONFIG_LSI_ET1011C_PHY is not set +# CONFIG_LTE_GDM724X is not set +# CONFIG_LTR501 is not set +# CONFIG_LTPC is not set +# CONFIG_LUSTRE_FS is not set +# CONFIG_LXT_PHY is not set +# CONFIG_LZ4_COMPRESS is not set +# CONFIG_LZ4_DECOMPRESS is not set +# CONFIG_LZ4HC_COMPRESS is not set +CONFIG_LZMA_COMPRESS=y +CONFIG_LZMA_DECOMPRESS=y +# CONFIG_LZO_COMPRESS is not set +# CONFIG_LZO_DECOMPRESS is not set +# CONFIG_M25PXX_PREFER_SMALL_SECTOR_ERASE is not set +# CONFIG_MAC80211 is not set +# CONFIG_MAC80211_MESSAGE_TRACING is not set +# CONFIG_MACB is not set +# CONFIG_MACH_ASM9260 is not set +# CONFIG_MACH_DECSTATION is not set +# CONFIG_MACH_JAZZ is not set +# CONFIG_MACH_JZ4740 is not set +# CONFIG_MACH_LOONGSON is not set +# CONFIG_MACH_LOONGSON1 is not set +# CONFIG_MACH_NO_WESTBRIDGE is not set +# CONFIG_MACH_PISTACHIO is not set +# CONFIG_MACH_TX39XX is not set +# CONFIG_MACH_TX49XX is not set +# CONFIG_MACH_VR41XX is not set +# CONFIG_MACINTOSH_DRIVERS is not set +# CONFIG_MACVLAN is not set +# CONFIG_MACVTAP is not set +# CONFIG_MAC_EMUMOUSEBTN is not set +# CONFIG_MAC_PARTITION is not set +# CONFIG_MAG3110 is not set +# CONFIG_MAGIC_SYSRQ is not set +CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1 +# CONFIG_MAILBOX is not set +# CONFIG_MANGLE_BOOTARGS is not set +# CONFIG_MARVELL_PHY is not set +# CONFIG_MAX1027 is not set +# CONFIG_MAX1363 is not set +# CONFIG_MAX517 is not set +# CONFIG_MAX5821 is not set +# CONFIG_MAX63XX_WATCHDOG is not set +# CONFIG_MCB is not set +# CONFIG_MCP320X is not set +# CONFIG_MCP3422 is not set +# CONFIG_MCP4725 is not set +# CONFIG_MCP4922 is not set +# CONFIG_MCPM is not set +# CONFIG_MD is not set +# CONFIG_MDIO_BCM_UNIMAC is not set +# CONFIG_MDIO_BITBANG is not set +# CONFIG_MDIO_BUS_MUX_GPIO is not set +# CONFIG_MDIO_BUS_MUX_MMIOREG is not set +# CONFIG_MD_FAULTY is not set +# CONFIG_MEDIA_ANALOG_TV_SUPPORT is not set +# CONFIG_MEDIA_ATTACH is not set +# CONFIG_MEDIA_CAMERA_SUPPORT is not set +# CONFIG_MEDIA_CONTROLLER is not set +# CONFIG_MEDIA_DIGITAL_TV_SUPPORT is not set +# CONFIG_MEDIA_PARPORT_SUPPORT is not set +# CONFIG_MEDIA_PCI_SUPPORT is not set +# CONFIG_MEDIA_RADIO_SUPPORT is not set +# CONFIG_MEDIA_RC_SUPPORT is not set +# CONFIG_MEDIA_SDR_SUPPORT is not set +# CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set +# CONFIG_MEDIA_SUPPORT is not set +# CONFIG_MEDIA_TUNER_CUSTOMISE is not set +# CONFIG_MEDIA_USB_SUPPORT is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_SAS is not set +# CONFIG_MEMORY is not set +# CONFIG_MEMORY_FAILURE is not set +# CONFIG_MEMSTICK is not set +# CONFIG_MEMTEST is not set +# CONFIG_MEN_A21_WDT is not set +CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4 +# CONFIG_MFD_88PM800 is not set +# CONFIG_MFD_88PM805 is not set +# CONFIG_MFD_88PM860X is not set +# CONFIG_MFD_AAT2870_CORE is not set +# CONFIG_MFD_ARIZONA_I2C is not set +# CONFIG_MFD_ARIZONA_SPI is not set +# CONFIG_MFD_AS3711 is not set +# CONFIG_MFD_AS3722 is not set +# CONFIG_MFD_ASIC3 is not set +# CONFIG_MFD_ATMEL_HLCDC is not set +# CONFIG_MFD_AXP20X is not set +# CONFIG_MFD_BCM590XX is not set +# CONFIG_MFD_CORE is not set +# CONFIG_MFD_CROS_EC is not set +# CONFIG_MFD_CS5535 is not set +# CONFIG_MFD_DA9052_I2C is not set +# CONFIG_MFD_DA9052_SPI is not set +# CONFIG_MFD_DA9055 is not set +# CONFIG_MFD_DA9063 is not set +# CONFIG_MFD_DA9150 is not set +# CONFIG_MFD_DLN2 is not set +# CONFIG_MFD_HI6421_PMIC is not set +# CONFIG_MFD_JANZ_CMODIO is not set +# CONFIG_MFD_KEMPLD is not set +# CONFIG_MFD_LM3533 is not set +# CONFIG_MFD_LP3943 is not set +# CONFIG_MFD_LP8788 is not set +# CONFIG_MFD_MAX14577 is not set +# CONFIG_MFD_MAX77686 is not set +# CONFIG_MFD_MAX77693 is not set +# CONFIG_MFD_MAX77843 is not set +# CONFIG_MFD_MAX8907 is not set +# CONFIG_MFD_MAX8925 is not set +# CONFIG_MFD_MAX8997 is not set +# CONFIG_MFD_MAX8998 is not set +# CONFIG_MFD_MC13783 is not set +# CONFIG_MFD_MC13XXX is not set +# CONFIG_MFD_MC13XXX_I2C is not set +# CONFIG_MFD_MC13XXX_SPI is not set +# CONFIG_MFD_MENF21BMC is not set +# CONFIG_MFD_MT6397 is not set +# CONFIG_MFD_OMAP_USB_HOST is not set +# CONFIG_MFD_PALMAS is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_MFD_PM8921_CORE is not set +# CONFIG_MFD_RC5T583 is not set +# CONFIG_MFD_RDC321X is not set +# CONFIG_MFD_RETU is not set +# CONFIG_MFD_RK808 is not set +# CONFIG_MFD_RN5T618 is not set +# CONFIG_MFD_RT5033 is not set +# CONFIG_MFD_RTSX_PCI is not set +# CONFIG_MFD_RTSX_USB is not set +# CONFIG_MFD_S5M_CORE is not set +# CONFIG_MFD_SEC_CORE is not set +# CONFIG_MFD_SI476X_CORE is not set +# CONFIG_MFD_SKY81452 is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_SMSC is not set +# CONFIG_MFD_STMPE is not set +CONFIG_MFD_SUPPORT=y +# CONFIG_MFD_SYSCON is not set +# CONFIG_MFD_T7L66XB is not set +# CONFIG_MFD_TC3589X is not set +# CONFIG_MFD_TC6387XB is not set +# CONFIG_MFD_TC6393XB is not set +# CONFIG_MFD_TIMBERDALE is not set +# CONFIG_MFD_TI_AM335X_TSCADC is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_MFD_TPS65090 is not set +# CONFIG_MFD_TPS65217 is not set +# CONFIG_MFD_TPS65218 is not set +# CONFIG_MFD_TPS6586X is not set +# CONFIG_MFD_TPS65910 is not set +# CONFIG_MFD_TPS65912 is not set +# CONFIG_MFD_TPS65912_I2C is not set +# CONFIG_MFD_TPS65912_SPI is not set +# CONFIG_MFD_TPS80031 is not set +# CONFIG_MFD_VIPERBOARD is not set +# CONFIG_MFD_VX855 is not set +# CONFIG_MFD_WL1273_CORE is not set +# CONFIG_MFD_WM831X is not set +# CONFIG_MFD_WM831X_I2C is not set +# CONFIG_MFD_WM831X_SPI is not set +# CONFIG_MFD_WM8350_I2C is not set +# CONFIG_MFD_WM8400 is not set +# CONFIG_MFD_WM8994 is not set +# CONFIG_MG_DISK is not set +# CONFIG_MICREL_KS8995MA is not set +# CONFIG_MICREL_PHY is not set +# CONFIG_MIGRATION is not set +CONFIG_MII=y +# CONFIG_MIKROTIK_RB532 is not set +# CONFIG_MINIX_FS is not set +# CONFIG_MINIX_FS_NATIVE_ENDIAN is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_MIPS_ALCHEMY is not set +# CONFIG_MIPS_CDMM is not set +# CONFIG_MIPS_COBALT is not set +# CONFIG_MIPS_FPU_EMULATOR is not set +# CONFIG_MIPS_MALTA is not set +# CONFIG_MIPS_O32_FP64_SUPPORT is not set +# CONFIG_MIPS_PARAVIRT is not set +# CONFIG_MIPS_PLATFORM_DEVICES is not set +# CONFIG_MIPS_SEAD3 is not set +# CONFIG_MIPS_SIM is not set +CONFIG_MISC_DEVICES=y +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_MISDN is not set +# CONFIG_MISDN_AVMFRITZ is not set +# CONFIG_MISDN_HFCPCI is not set +# CONFIG_MISDN_HFCUSB is not set +# CONFIG_MISDN_INFINEON is not set +# CONFIG_MISDN_NETJET is not set +# CONFIG_MISDN_SPEEDFAX is not set +# CONFIG_MISDN_W6692 is not set +# CONFIG_MKISS is not set +# CONFIG_MLX4_CORE is not set +# CONFIG_MLX4_EN is not set +# CONFIG_MLX5_CORE is not set +# CONFIG_MLX90614 is not set +# CONFIG_MMA8452 is not set +# CONFIG_MMA9551 is not set +# CONFIG_MMA9553 is not set +# CONFIG_MMC is not set +# CONFIG_MMC_ARMMMCI is not set +# CONFIG_MMC_AU1X is not set +# CONFIG_MMC_BLOCK is not set +CONFIG_MMC_BLOCK_BOUNCE=y +CONFIG_MMC_BLOCK_MINORS=8 +# CONFIG_MMC_CB710 is not set +# CONFIG_MMC_CLKGATE is not set +# CONFIG_MMC_DEBUG is not set +# CONFIG_MMC_DW is not set +# CONFIG_MMC_MVSDIO is not set +# CONFIG_MMC_S3C is not set +# CONFIG_MMC_SDHCI is not set +# CONFIG_MMC_SDHCI_ACPI is not set +# CONFIG_MMC_SDHCI_BCM_KONA is not set +# CONFIG_MMC_SDHCI_IPROC is not set +# CONFIG_MMC_SDHCI_MSM is not set +# CONFIG_MMC_SDHCI_OF_ARASAN is not set +# CONFIG_MMC_SDHCI_OF_ESDHC is not set +# CONFIG_MMC_SDHCI_OF_HLWD is not set +# CONFIG_MMC_SDHCI_PXAV2 is not set +# CONFIG_MMC_SDHCI_PXAV3 is not set +# CONFIG_MMC_SDHCI_F_SDH30 is not set +# CONFIG_MMC_SDRICOH_CS is not set +# CONFIG_MMC_SPI is not set +# CONFIG_MMC_TEST is not set +# CONFIG_MMC_TOSHIBA_PCI is not set +# CONFIG_MMC_UNSAFE_RESUME is not set +# CONFIG_MMC_USDHI6ROL0 is not set +# CONFIG_MMC_USHC is not set +# CONFIG_MMC_VIA_SDMMC is not set +# CONFIG_MMC_VUB300 is not set +# CONFIG_MMIOTRACE is not set +CONFIG_MMU=y +CONFIG_MODULES=y +# CONFIG_MODULE_COMPRESS is not set +# CONFIG_MODULE_FORCE_LOAD is not set +# CONFIG_MODULE_FORCE_UNLOAD is not set +# CONFIG_MODULE_SIG is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_MODULE_STRIPPED=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MOUSE_APPLETOUCH is not set +# CONFIG_MOUSE_GPIO is not set +# CONFIG_MOUSE_INPORT is not set +# CONFIG_MOUSE_LOGIBM is not set +# CONFIG_MOUSE_PC110PAD is not set +# CONFIG_MOUSE_PS2_SENTELIC is not set +# CONFIG_MOUSE_SYNAPTICS_I2C is not set +# CONFIG_MOUSE_SYNAPTICS_USB is not set +# CONFIG_MPL115 is not set +# CONFIG_MPL3115 is not set +# CONFIG_MPLS is not set +# CONFIG_MS5611 is not set +# CONFIG_MSDOS_FS is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_MSI_BITMAP_SELFTEST is not set +# CONFIG_MSI_LAPTOP is not set +CONFIG_MTD=y +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_AFS_PARTS is not set +# CONFIG_MTD_ALAUDA is not set +# CONFIG_MTD_AR7_PARTS is not set +# CONFIG_MTD_ARM_INTEGRATOR is not set +CONFIG_MTD_BLKDEVS=y +CONFIG_MTD_BLOCK=y +# CONFIG_MTD_BLOCK2MTD is not set +CONFIG_MTD_CFI=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_CFI_AMDSTD=y +# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set +CONFIG_MTD_CFI_NOSWAP=y +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +CONFIG_MTD_CHAR=y +# CONFIG_MTD_CMDLINE_PARTS is not set +CONFIG_MTD_COMPLEX_MAPPINGS=y +# CONFIG_MTD_DATAFLASH is not set +# CONFIG_MTD_DEBUG is not set +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set +# CONFIG_MTD_DOCG3 is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_GPIO_ADDR is not set +# CONFIG_MTD_INTEL_VR_NOR is not set +# CONFIG_MTD_JEDECPROBE is not set +# CONFIG_MTD_LATCH_ADDR is not set +# CONFIG_MTD_LPDDR is not set +# CONFIG_MTD_LPDDR2_NVM is not set +# CONFIG_MTD_M25P80 is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +CONFIG_MTD_MAP_BANK_WIDTH_2=y +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_MYLOADER_PARTS is not set +# CONFIG_MTD_NAND is not set +# CONFIG_MTD_NAND_AMS_DELTA is not set +# CONFIG_MTD_NAND_AR934X is not set +# CONFIG_MTD_NAND_AR934X_HW_ECC is not set +# CONFIG_MTD_NAND_ATMEL is not set +# CONFIG_MTD_NAND_AU1550 is not set +# CONFIG_MTD_NAND_AUTCPU12 is not set +# CONFIG_MTD_NAND_BCH is not set +# CONFIG_MTD_NAND_BCM_UMI is not set +# CONFIG_MTD_NAND_BF5XX is not set +# CONFIG_MTD_NAND_CAFE is not set +# CONFIG_MTD_NAND_CM_X270 is not set +# CONFIG_MTD_NAND_CS553X is not set +# CONFIG_MTD_NAND_DAVINCI is not set +# CONFIG_MTD_NAND_DENALI is not set +CONFIG_MTD_NAND_DENALI_SCRATCH_REG_ADDR=0xff108018 +# CONFIG_MTD_NAND_DISKONCHIP is not set +# CONFIG_MTD_NAND_DOCG4 is not set +# CONFIG_MTD_NAND_ECC is not set +# CONFIG_MTD_NAND_ECC_BCH is not set +# CONFIG_MTD_NAND_ECC_SMC is not set +# CONFIG_MTD_NAND_FSL_ELBC is not set +# CONFIG_MTD_NAND_FSL_IFC is not set +# CONFIG_MTD_NAND_FSL_UPM is not set +# CONFIG_MTD_NAND_FSMC is not set +# CONFIG_MTD_NAND_GPIO is not set +# CONFIG_MTD_NAND_GPMI_NAND is not set +# CONFIG_MTD_NAND_H1900 is not set +# CONFIG_MTD_NAND_HISI504 is not set +CONFIG_MTD_NAND_IDS=y +# CONFIG_MTD_NAND_JZ4740 is not set +# CONFIG_MTD_NAND_MPC5121_NFC is not set +# CONFIG_MTD_NAND_MUSEUM_IDS is not set +# CONFIG_MTD_NAND_MXC is not set +# CONFIG_MTD_NAND_NANDSIM is not set +# CONFIG_MTD_NAND_NDFC is not set +# CONFIG_MTD_NAND_NOMADIK is not set +# CONFIG_MTD_NAND_NUC900 is not set +# CONFIG_MTD_NAND_OMAP2 is not set +# CONFIG_MTD_NAND_OMAP_BCH_BUILD is not set +# CONFIG_MTD_NAND_ORION is not set +# CONFIG_MTD_NAND_PASEMI is not set +# CONFIG_MTD_NAND_PLATFORM is not set +# CONFIG_MTD_NAND_PPCHAMELEONEVB is not set +# CONFIG_MTD_NAND_PXA3xx is not set +# CONFIG_MTD_NAND_RB4XX is not set +# CONFIG_MTD_NAND_RB750 is not set +# CONFIG_MTD_NAND_RICOH is not set +# CONFIG_MTD_NAND_RTC_FROM4 is not set +# CONFIG_MTD_NAND_S3C2410 is not set +# CONFIG_MTD_NAND_SHARPSL is not set +# CONFIG_MTD_NAND_SH_FLCTL is not set +# CONFIG_MTD_NAND_SOCRATES is not set +# CONFIG_MTD_NAND_SPIA is not set +# CONFIG_MTD_NAND_TMIO is not set +# CONFIG_MTD_NAND_TXX9NDFMC is not set +# CONFIG_MTD_NAND_VERIFY_WRITE is not set +CONFIG_MTD_OF_PARTS=y +# CONFIG_MTD_ONENAND is not set +# CONFIG_MTD_OOPS is not set +# CONFIG_MTD_OTP is not set +# CONFIG_MTD_PARTITIONED_MASTER is not set +# CONFIG_MTD_PCI is not set +# CONFIG_MTD_PCMCIA is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_PHYSMAP_COMPAT is not set +CONFIG_MTD_PHYSMAP_OF=y +# CONFIG_MTD_PLATRAM is not set +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_RAM is not set +CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1 +# CONFIG_MTD_REDBOOT_PARTS is not set +# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set +# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set +# CONFIG_MTD_ROM is not set +CONFIG_MTD_ROOTFS_ROOT_DEV=y +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_SM_COMMON is not set +# CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is not set +# CONFIG_MTD_SPI_NOR is not set +# CONFIG_MTD_SPINAND_MT29F is not set +CONFIG_MTD_SPLIT=y +# CONFIG_MTD_SPLIT_FIRMWARE is not set +CONFIG_MTD_SPLIT_FIRMWARE_NAME="firmware" +# CONFIG_MTD_SPLIT_FIT_FW is not set +# CONFIG_MTD_SPLIT_LZMA_FW is not set +# CONFIG_MTD_SPLIT_SEAMA_FW is not set +CONFIG_MTD_SPLIT_SQUASHFS_ROOT=y +CONFIG_MTD_SPLIT_SUPPORT=y +# CONFIG_MTD_SPLIT_TRX_FW is not set +# CONFIG_MTD_SPLIT_TPLINK_FW is not set +# CONFIG_MTD_SPLIT_UIMAGE_FW is not set +# CONFIG_MTD_SST25L is not set +# CONFIG_MTD_SWAP is not set +# CONFIG_MTD_TESTS is not set +# CONFIG_MTD_UBI is not set +# CONFIG_MTD_UIMAGE_SPLIT is not set +CONFIG_MULTIUSER=y +# CONFIG_MUTEX_SPIN_ON_OWNER is not set +# CONFIG_MV643XX_ETH is not set +# CONFIG_MVMDIO is not set +# CONFIG_MVSW61XX_PHY is not set +# CONFIG_MVSW6171_PHY is not set +# CONFIG_MVSWITCH_PHY is not set +# CONFIG_MWAVE is not set +# CONFIG_MWL8K is not set +# CONFIG_MYRI10GE is not set +# CONFIG_NAMESPACES is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_NATSEMI is not set +# CONFIG_NAU7802 is not set +# CONFIG_NBPFAXI_DMA is not set +# CONFIG_NCP_FS is not set +# CONFIG_NE2000 is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_NEC_MARKEINS is not set +CONFIG_NET=y +# CONFIG_NETCONSOLE is not set +CONFIG_NETDEVICES=y +CONFIG_NETDEV_1000=y +# CONFIG_NETDEV_10000 is not set +# CONFIG_NETFILTER is not set +# CONFIG_NETFILTER_ADVANCED is not set +# CONFIG_NETFILTER_DEBUG is not set +# CONFIG_NETFILTER_NETLINK is not set +# CONFIG_NETFILTER_NETLINK_ACCT is not set +# CONFIG_NETFILTER_NETLINK_LOG is not set +# CONFIG_NETFILTER_NETLINK_QUEUE is not set +# CONFIG_NETFILTER_NETLINK_QUEUE_CT is not set +# CONFIG_NETFILTER_TPROXY is not set +# CONFIG_NETFILTER_XTABLES is not set +# CONFIG_NETFILTER_XT_CONNMARK is not set +# CONFIG_NETFILTER_XT_MARK is not set +# CONFIG_NETFILTER_XT_MATCH_ADDRTYPE is not set +# CONFIG_NETFILTER_XT_MATCH_BPF is not set +# CONFIG_NETFILTER_XT_MATCH_CGROUP is not set +# CONFIG_NETFILTER_XT_MATCH_CLUSTER is not set +# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set +# CONFIG_NETFILTER_XT_MATCH_CONNBYTES is not set +# CONFIG_NETFILTER_XT_MATCH_CONNLABEL is not set +# CONFIG_NETFILTER_XT_MATCH_CONNLIMIT is not set +# CONFIG_NETFILTER_XT_MATCH_CONNMARK is not set +# CONFIG_NETFILTER_XT_MATCH_CONNTRACK is not set +# CONFIG_NETFILTER_XT_MATCH_CPU is not set +# CONFIG_NETFILTER_XT_MATCH_DCCP is not set +# CONFIG_NETFILTER_XT_MATCH_DEVGROUP is not set +# CONFIG_NETFILTER_XT_MATCH_DSCP is not set +# CONFIG_NETFILTER_XT_MATCH_ECN is not set +# CONFIG_NETFILTER_XT_MATCH_ESP is not set +# CONFIG_NETFILTER_XT_MATCH_HASHLIMIT is not set +# CONFIG_NETFILTER_XT_MATCH_HELPER is not set +# CONFIG_NETFILTER_XT_MATCH_HL is not set +# CONFIG_NETFILTER_XT_MATCH_IPCOMP is not set +# CONFIG_NETFILTER_XT_MATCH_IPRANGE is not set +# CONFIG_NETFILTER_XT_MATCH_L2TP is not set +# CONFIG_NETFILTER_XT_MATCH_LAYER7 is not set +# CONFIG_NETFILTER_XT_MATCH_LAYER7_DEBUG is not set +# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set +# CONFIG_NETFILTER_XT_MATCH_LIMIT is not set +# CONFIG_NETFILTER_XT_MATCH_MAC is not set +# CONFIG_NETFILTER_XT_MATCH_MARK is not set +# CONFIG_NETFILTER_XT_MATCH_MULTIPORT is not set +# CONFIG_NETFILTER_XT_MATCH_NFACCT is not set +# CONFIG_NETFILTER_XT_MATCH_OSF is not set +# CONFIG_NETFILTER_XT_MATCH_OWNER is not set +# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set +# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set +# CONFIG_NETFILTER_XT_MATCH_POLICY is not set +# CONFIG_NETFILTER_XT_MATCH_QUOTA is not set +# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set +# CONFIG_NETFILTER_XT_MATCH_REALM is not set +# CONFIG_NETFILTER_XT_MATCH_RECENT is not set +# CONFIG_NETFILTER_XT_MATCH_SCTP is not set +# CONFIG_NETFILTER_XT_MATCH_SOCKET is not set +# CONFIG_NETFILTER_XT_MATCH_STATE is not set +# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set +# CONFIG_NETFILTER_XT_MATCH_STRING is not set +# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set +# CONFIG_NETFILTER_XT_MATCH_TIME is not set +# CONFIG_NETFILTER_XT_MATCH_U32 is not set +# CONFIG_NETFILTER_XT_TARGET_AUDIT is not set +# CONFIG_NETFILTER_XT_TARGET_CHECKSUM is not set +# CONFIG_NETFILTER_XT_TARGET_CLASSIFY is not set +# CONFIG_NETFILTER_XT_TARGET_CONNMARK is not set +# CONFIG_NETFILTER_XT_TARGET_CT is not set +# CONFIG_NETFILTER_XT_TARGET_DSCP is not set +# CONFIG_NETFILTER_XT_TARGET_HL is not set +# CONFIG_NETFILTER_XT_TARGET_HMARK is not set +# CONFIG_NETFILTER_XT_TARGET_IDLETIMER is not set +# CONFIG_NETFILTER_XT_TARGET_LED is not set +# CONFIG_NETFILTER_XT_TARGET_LOG is not set +# CONFIG_NETFILTER_XT_TARGET_MARK is not set +# CONFIG_NETFILTER_XT_TARGET_NETMAP is not set +# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set +# CONFIG_NETFILTER_XT_TARGET_NFQUEUE is not set +# CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set +# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set +# CONFIG_NETFILTER_XT_TARGET_REDIRECT is not set +# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set +# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set +# CONFIG_NETFILTER_XT_TARGET_TEE is not set +# CONFIG_NETFILTER_XT_TARGET_TPROXY is not set +# CONFIG_NETFILTER_XT_TARGET_TRACE is not set +# CONFIG_NETLINK_DIAG is not set +# CONFIG_NETLINK_MMAP is not set +# CONFIG_NETPOLL is not set +# CONFIG_NETROM is not set +CONFIG_NETWORK_FILESYSTEMS=y +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETXEN_NIC is not set +# CONFIG_NET_9P is not set +# CONFIG_NET_ACT_BPF is not set +# CONFIG_NET_ACT_CSUM is not set +# CONFIG_NET_ACT_GACT is not set +# CONFIG_NET_ACT_IPT is not set +# CONFIG_NET_ACT_MIRRED is not set +# CONFIG_NET_ACT_NAT is not set +# CONFIG_NET_ACT_PEDIT is not set +# CONFIG_NET_ACT_POLICE is not set +# CONFIG_NET_ACT_SIMP is not set +# CONFIG_NET_ACT_SKBEDIT is not set +# CONFIG_NET_ACT_VLAN is not set +CONFIG_NET_CADENCE=y +# CONFIG_NET_CALXEDA_XGMAC is not set +CONFIG_NET_CLS=y +# CONFIG_NET_CLS_ACT is not set +# CONFIG_NET_CLS_BASIC is not set +# CONFIG_NET_CLS_BPF is not set +# CONFIG_NET_CLS_FLOW is not set +# CONFIG_NET_CLS_FW is not set +CONFIG_NET_CLS_IND=y +# CONFIG_NET_CLS_ROUTE4 is not set +# CONFIG_NET_CLS_RSVP is not set +# CONFIG_NET_CLS_RSVP6 is not set +# CONFIG_NET_CLS_TCINDEX is not set +# CONFIG_NET_CLS_U32 is not set +CONFIG_NET_CORE=y +# CONFIG_NET_DROP_MONITOR is not set +# CONFIG_NET_DSA is not set +# CONFIG_NET_DSA_BCM_SF2 is not set +# CONFIG_NET_DSA_MV88E6060 is not set +# CONFIG_NET_DSA_MV88E6123_61_65 is not set +# CONFIG_NET_DSA_MV88E6131 is not set +# CONFIG_NET_DSA_MV88E6171 is not set +# CONFIG_NET_DSA_MV88E6352 is not set +# CONFIG_NET_DSA_MV88E6XXX is not set +# CONFIG_NET_DSA_MV88E6XXX_NEED_PPU is not set +# CONFIG_NET_DSA_TAG_DSA is not set +# CONFIG_NET_DSA_TAG_EDSA is not set +# CONFIG_NET_EMATCH is not set +# CONFIG_NET_EMATCH_CMP is not set +# CONFIG_NET_EMATCH_META is not set +# CONFIG_NET_EMATCH_NBYTE is not set +CONFIG_NET_EMATCH_STACK=32 +# CONFIG_NET_EMATCH_TEXT is not set +# CONFIG_NET_EMATCH_U32 is not set +CONFIG_NET_ETHERNET=y +# CONFIG_NET_FC is not set +# CONFIG_NET_FOU is not set +# CONFIG_NET_FOU_IP_TUNNELS is not set +# CONFIG_NET_IPGRE is not set +CONFIG_NET_IPGRE_BROADCAST=y +# CONFIG_NET_IPGRE_DEMUX is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPVTI is not set +# CONFIG_NET_IP_TUNNEL is not set +# CONFIG_NET_ISA is not set +# CONFIG_NET_KEY is not set +# CONFIG_NET_KEY_MIGRATE is not set +# CONFIG_NET_MPLS_GSO is not set +# CONFIG_NET_PACKET_ENGINE is not set +CONFIG_NET_PCI=y +# CONFIG_NET_PCMCIA is not set +# CONFIG_NET_PKTGEN is not set +# CONFIG_NET_POCKET is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_NET_PTP_CLASSIFY is not set +CONFIG_NET_RX_BUSY_POLL=y +# CONFIG_NET_SB1000 is not set +CONFIG_NET_SCHED=y +# CONFIG_NET_SCH_ATM is not set +# CONFIG_NET_SCH_CBQ is not set +# CONFIG_NET_SCH_CHOKE is not set +# CONFIG_NET_SCH_CODEL is not set +# CONFIG_NET_SCH_DRR is not set +# CONFIG_NET_SCH_DSMARK is not set +# CONFIG_NET_SCH_ESFQ is not set +CONFIG_NET_SCH_ESFQ_NFCT=y +CONFIG_NET_SCH_FIFO=y +# CONFIG_NET_SCH_FQ is not set +CONFIG_NET_SCH_FQ_CODEL=y +# CONFIG_NET_SCH_GRED is not set +# CONFIG_NET_SCH_HFSC is not set +# CONFIG_NET_SCH_HHF is not set +# CONFIG_NET_SCH_HTB is not set +# CONFIG_NET_SCH_INGRESS is not set +# CONFIG_NET_SCH_MQPRIO is not set +# CONFIG_NET_SCH_MULTIQ is not set +# CONFIG_NET_SCH_NETEM is not set +# CONFIG_NET_SCH_PIE is not set +# CONFIG_NET_SCH_PLUG is not set +# CONFIG_NET_SCH_PRIO is not set +# CONFIG_NET_SCH_QFQ is not set +# CONFIG_NET_SCH_RED is not set +# CONFIG_NET_SCH_SFB is not set +# CONFIG_NET_SCH_SFQ is not set +# CONFIG_NET_SCH_TBF is not set +# CONFIG_NET_SCH_TEQL is not set +# CONFIG_NET_SCTPPROBE is not set +# CONFIG_NET_SWITCHDEV is not set +# CONFIG_NET_TCPPROBE is not set +# CONFIG_NET_TEAM is not set +# CONFIG_NET_TULIP is not set +# CONFIG_NET_UDP_TUNNEL is not set +CONFIG_NET_VENDOR_3COM=y +CONFIG_NET_VENDOR_8390=y +CONFIG_NET_VENDOR_ADAPTEC=y +CONFIG_NET_VENDOR_AGERE=y +CONFIG_NET_VENDOR_ALTEON=y +CONFIG_NET_VENDOR_AMD=y +CONFIG_NET_VENDOR_ARC=y +CONFIG_NET_VENDOR_ATHEROS=y +CONFIG_NET_VENDOR_BROADCOM=y +CONFIG_NET_VENDOR_BROCADE=y +CONFIG_NET_VENDOR_CHELSIO=y +CONFIG_NET_VENDOR_CIRRUS=y +CONFIG_NET_VENDOR_CISCO=y +CONFIG_NET_VENDOR_DEC=y +CONFIG_NET_VENDOR_DLINK=y +CONFIG_NET_VENDOR_EMULEX=y +CONFIG_NET_VENDOR_EXAR=y +CONFIG_NET_VENDOR_FARADAY=y +CONFIG_NET_VENDOR_FREESCALE=y +CONFIG_NET_VENDOR_FUJITSU=y +CONFIG_NET_VENDOR_HISILICON=y +CONFIG_NET_VENDOR_HP=y +CONFIG_NET_VENDOR_I825XX=y +CONFIG_NET_VENDOR_IBM=y +CONFIG_NET_VENDOR_INTEL=y +CONFIG_NET_VENDOR_MARVELL=y +CONFIG_NET_VENDOR_MELLANOX=y +CONFIG_NET_VENDOR_MICREL=y +CONFIG_NET_VENDOR_MICROCHIP=y +CONFIG_NET_VENDOR_MYRI=y +CONFIG_NET_VENDOR_NATSEMI=y +CONFIG_NET_VENDOR_NVIDIA=y +CONFIG_NET_VENDOR_OKI=y +CONFIG_NET_VENDOR_QLOGIC=y +CONFIG_NET_VENDOR_QUALCOMM=y +CONFIG_NET_VENDOR_RDC=y +CONFIG_NET_VENDOR_REALTEK=y +CONFIG_NET_VENDOR_ROCKER=y +CONFIG_NET_VENDOR_SAMSUNG=y +CONFIG_NET_VENDOR_SEEQ=y +CONFIG_NET_VENDOR_SILAN=y +CONFIG_NET_VENDOR_SILICOM=y +CONFIG_NET_VENDOR_SIS=y +CONFIG_NET_VENDOR_SMSC=y +CONFIG_NET_VENDOR_STMICRO=y +CONFIG_NET_VENDOR_SUN=y +CONFIG_NET_VENDOR_TEHUTI=y +CONFIG_NET_VENDOR_TI=y +CONFIG_NET_VENDOR_TOSHIBA=y +CONFIG_NET_VENDOR_VIA=y +# CONFIG_NET_VENDOR_WIZNET is not set +CONFIG_NET_VENDOR_XILINX=y +CONFIG_NET_VENDOR_XIRCOM=y +# CONFIG_NET_XGENE is not set +CONFIG_NEW_LEDS=y +# CONFIG_NFC is not set +# CONFIG_NFC_DEVICES is not set +# CONFIG_NFSD is not set +# CONFIG_NFSD_DEPRECATED is not set +# CONFIG_NFSD_V2_ACL is not set +CONFIG_NFSD_V3=y +# CONFIG_NFSD_V3_ACL is not set +# CONFIG_NFSD_V4 is not set +# CONFIG_NFS_ACL_SUPPORT is not set +CONFIG_NFS_COMMON=y +# CONFIG_NFS_FS is not set +# CONFIG_NFS_FSCACHE is not set +# CONFIG_NFS_SWAP is not set +# CONFIG_NFS_V2 is not set +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_V4_1 is not set +# CONFIG_NFTL is not set +# CONFIG_NF_CONNTRACK is not set +# CONFIG_NF_CONNTRACK_AMANDA is not set +# CONFIG_NF_CONNTRACK_EVENTS is not set +# CONFIG_NF_CONNTRACK_FTP is not set +# CONFIG_NF_CONNTRACK_H323 is not set +# CONFIG_NF_CONNTRACK_IPV4 is not set +# CONFIG_NF_CONNTRACK_IPV6 is not set +# CONFIG_NF_CONNTRACK_IRC is not set +# CONFIG_NF_CONNTRACK_MARK is not set +# CONFIG_NF_CONNTRACK_NETBIOS_NS is not set +# CONFIG_NF_CONNTRACK_PPTP is not set +CONFIG_NF_CONNTRACK_PROCFS=y +# CONFIG_NF_CONNTRACK_PROC_COMPAT is not set +# CONFIG_NF_CONNTRACK_RTSP is not set +# CONFIG_NF_CONNTRACK_SANE is not set +# CONFIG_NF_CONNTRACK_SIP is not set +# CONFIG_NF_CONNTRACK_SNMP is not set +# CONFIG_NF_CONNTRACK_TFTP is not set +# CONFIG_NF_CONNTRACK_TIMEOUT is not set +# CONFIG_NF_CONNTRACK_TIMESTAMP is not set +# CONFIG_NF_CONNTRACK_ZONES is not set +# CONFIG_NF_CT_NETLINK is not set +# CONFIG_NF_CT_NETLINK_TIMEOUT is not set +# CONFIG_NF_CT_PROTO_DCCP is not set +# CONFIG_NF_CT_PROTO_GRE is not set +# CONFIG_NF_CT_PROTO_SCTP is not set +# CONFIG_NF_CT_PROTO_UDPLITE is not set +# CONFIG_NF_DEFRAG_IPV4 is not set +# CONFIG_NF_LOG_ARP is not set +# CONFIG_NF_LOG_IPV4 is not set +# CONFIG_NF_NAT is not set +# CONFIG_NF_NAT_AMANDA is not set +# CONFIG_NF_NAT_FTP is not set +# CONFIG_NF_NAT_H323 is not set +# CONFIG_NF_NAT_IPV6 is not set +# CONFIG_NF_NAT_IRC is not set +# CONFIG_NF_NAT_MASQUERADE_IPV4 is not set +# CONFIG_NF_NAT_MASQUERADE_IPV6 is not set +# CONFIG_NF_NAT_NEEDED is not set +# CONFIG_NF_NAT_PPTP is not set +# CONFIG_NF_NAT_PROTO_GRE is not set +# CONFIG_NF_NAT_RTSP is not set +# CONFIG_NF_NAT_SIP is not set +# CONFIG_NF_NAT_SNMP_BASIC is not set +# CONFIG_NF_NAT_TFTP is not set +# CONFIG_NF_REJECT_IPV4 is not set +# CONFIG_NF_TABLES is not set +# CONFIG_NI52 is not set +# CONFIG_NI65 is not set +# CONFIG_NILFS2_FS is not set +# CONFIG_NIU is not set +CONFIG_NLATTR=y +# CONFIG_NLMON is not set +# CONFIG_NLM_XLP_BOARD is not set +# CONFIG_NLM_XLR_BOARD is not set +# CONFIG_NLS is not set +# CONFIG_NLS_ASCII is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +CONFIG_NLS_DEFAULT="iso8859-1" +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_MAC_CELTIC is not set +# CONFIG_NLS_MAC_CENTEURO is not set +# CONFIG_NLS_MAC_CROATIAN is not set +# CONFIG_NLS_MAC_CYRILLIC is not set +# CONFIG_NLS_MAC_GAELIC is not set +# CONFIG_NLS_MAC_GREEK is not set +# CONFIG_NLS_MAC_ICELAND is not set +# CONFIG_NLS_MAC_INUIT is not set +# CONFIG_NLS_MAC_ROMAN is not set +# CONFIG_NLS_MAC_ROMANIAN is not set +# CONFIG_NLS_MAC_TURKISH is not set +# CONFIG_NLS_UTF8 is not set +# CONFIG_NOP_USB_XCEIV is not set +# CONFIG_NORTEL_HERMES is not set +# CONFIG_NOTIFIER_ERROR_INJECTION is not set +# CONFIG_NOZOMI is not set +# CONFIG_NO_BOOTMEM is not set +# CONFIG_NO_HZ is not set +# CONFIG_NO_HZ_FULL is not set +# CONFIG_NO_HZ_IDLE is not set +# CONFIG_NO_IOPORT is not set +# CONFIG_NS83820 is not set +# CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_NTP_PPS is not set +# CONFIG_NVRAM is not set +# CONFIG_NV_TCO is not set +# CONFIG_NXP_STB220 is not set +# CONFIG_NXP_STB225 is not set +# CONFIG_N_GSM is not set +# CONFIG_OABI_COMPAT is not set +# CONFIG_OBS600 is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_OCF_BENCH is not set +# CONFIG_OCF_C7108 is not set +# CONFIG_OCF_CRYPTOCTEON is not set +# CONFIG_OCF_EP80579 is not set +# CONFIG_OCF_HIFN is not set +# CONFIG_OCF_HIFNHIPP is not set +# CONFIG_OCF_IXP4XX is not set +# CONFIG_OCF_KIRKWOOD is not set +# CONFIG_OCF_OCF is not set +# CONFIG_OCF_OCFNULL is not set +# CONFIG_OCF_SAFE is not set +# CONFIG_OCF_TALITOS is not set +# CONFIG_OCF_UBSEC_SSB is not set +# CONFIG_OC_ETM is not set +# CONFIG_OF_OVERLAY is not set +# CONFIG_OF_SELFTEST is not set +# CONFIG_OF_UNITTEST is not set +# CONFIG_OMAP2_DSS_DEBUG is not set +# CONFIG_OMAP2_DSS_DEBUGFS is not set +# CONFIG_OMAP2_DSS_SDI is not set +# CONFIG_OMAP_CONTROL_USB is not set +# CONFIG_OMAP_OCP2SCP is not set +# CONFIG_OMAP_USB2 is not set +# CONFIG_OMAP_USB3 is not set +# CONFIG_OMFS_FS is not set +# CONFIG_OPENVSWITCH is not set +# CONFIG_OPROFILE_EVENT_MULTIPLEX is not set +# CONFIG_ORION_WATCHDOG is not set +# CONFIG_OSF_PARTITION is not set +CONFIG_OVERLAY_FS=y +# CONFIG_P54_COMMON is not set +CONFIG_PACKET=y +# CONFIG_PACKET_DIAG is not set +# CONFIG_PAGE_EXTENSION is not set +# CONFIG_PAGE_OWNER is not set +# CONFIG_PAGE_POISONING is not set +# CONFIG_PAGE_SIZE_16KB is not set +# CONFIG_PAGE_SIZE_32KB is not set +CONFIG_PAGE_SIZE_4KB=y +# CONFIG_PAGE_SIZE_64KB is not set +# CONFIG_PAGE_SIZE_8KB is not set +# CONFIG_PANEL is not set +# CONFIG_PANIC_ON_OOPS is not set +CONFIG_PANIC_ON_OOPS_VALUE=0 +CONFIG_PANIC_TIMEOUT=0 +# CONFIG_PANTHERLORD_FF is not set +# CONFIG_PARPORT is not set +# CONFIG_PARPORT_1284 is not set +# CONFIG_PARPORT_AX88796 is not set +# CONFIG_PARPORT_PC is not set +CONFIG_PARTITION_ADVANCED=y +# CONFIG_PATA_ALI is not set +# CONFIG_PATA_AMD is not set +# CONFIG_PATA_ARASAN_CF is not set +# CONFIG_PATA_ARTOP is not set +# CONFIG_PATA_ATIIXP is not set +# CONFIG_PATA_ATP867X is not set +# CONFIG_PATA_CMD640_PCI is not set +# CONFIG_PATA_CMD64X is not set +# CONFIG_PATA_CS5520 is not set +# CONFIG_PATA_CS5530 is not set +# CONFIG_PATA_CS5535 is not set +# CONFIG_PATA_CS5536 is not set +# CONFIG_PATA_CYPRESS is not set +# CONFIG_PATA_EFAR is not set +# CONFIG_PATA_HPT366 is not set +# CONFIG_PATA_HPT37X is not set +# CONFIG_PATA_HPT3X2N is not set +# CONFIG_PATA_HPT3X3 is not set +# CONFIG_PATA_ISAPNP is not set +# CONFIG_PATA_IT8213 is not set +# CONFIG_PATA_IT821X is not set +# CONFIG_PATA_JMICRON is not set +# CONFIG_PATA_LEGACY is not set +# CONFIG_PATA_MARVELL is not set +# CONFIG_PATA_MPIIX is not set +# CONFIG_PATA_NETCELL is not set +# CONFIG_PATA_NINJA32 is not set +# CONFIG_PATA_NS87410 is not set +# CONFIG_PATA_NS87415 is not set +# CONFIG_PATA_OCTEON_CF is not set +# CONFIG_PATA_OF_PLATFORM is not set +# CONFIG_PATA_OLDPIIX is not set +# CONFIG_PATA_OPTI is not set +# CONFIG_PATA_OPTIDMA is not set +# CONFIG_PATA_PCMCIA is not set +# CONFIG_PATA_PDC2027X is not set +# CONFIG_PATA_PDC_OLD is not set +# CONFIG_PATA_PLATFORM is not set +# CONFIG_PATA_QDI is not set +# CONFIG_PATA_RADISYS is not set +# CONFIG_PATA_RDC is not set +# CONFIG_PATA_RZ1000 is not set +# CONFIG_PATA_SC1200 is not set +# CONFIG_PATA_SCH is not set +# CONFIG_PATA_SERVERWORKS is not set +# CONFIG_PATA_SIL680 is not set +# CONFIG_PATA_SIS is not set +# CONFIG_PATA_TOSHIBA is not set +# CONFIG_PATA_TRIFLEX is not set +# CONFIG_PATA_VIA is not set +# CONFIG_PATA_WINBOND is not set +# CONFIG_PATA_WINBOND_VLB is not set +# CONFIG_PC300TOO is not set +# CONFIG_PCCARD is not set +# CONFIG_PCH_GBE is not set +# CONFIG_PCH_PHUB is not set +# CONFIG_PCI200SYN is not set +# CONFIG_PCIEAER_INJECT is not set +# CONFIG_PCIEASPM is not set +# CONFIG_PCIEPORTBUS is not set +# CONFIG_PCIE_ECRC is not set +# CONFIG_PCIPCWATCHDOG is not set +# CONFIG_PCI_ATMEL is not set +# CONFIG_PCI_CNB20LE_QUIRK is not set +# CONFIG_PCI_DEBUG is not set +# CONFIG_PCI_DISABLE_COMMON_QUIRKS is not set +# CONFIG_PCI_HERMES is not set +# CONFIG_PCI_HOST_GENERIC is not set +# CONFIG_PCI_IOV is not set +# CONFIG_PCI_LAYERSCAPE is not set +# CONFIG_PCI_MSI is not set +# CONFIG_PCI_PASID is not set +# CONFIG_PCI_PRI is not set +CONFIG_PCI_QUIRKS=y +# CONFIG_PCI_REALLOC_ENABLE_AUTO is not set +# CONFIG_PCI_STUB is not set +CONFIG_PCI_SYSCALL=y +# CONFIG_PCMCIA is not set +# CONFIG_PCMCIA_3C574 is not set +# CONFIG_PCMCIA_3C589 is not set +# CONFIG_PCMCIA_AHA152X is not set +# CONFIG_PCMCIA_ATMEL is not set +# CONFIG_PCMCIA_AXNET is not set +# CONFIG_PCMCIA_DEBUG is not set +# CONFIG_PCMCIA_FDOMAIN is not set +# CONFIG_PCMCIA_FMVJ18X is not set +# CONFIG_PCMCIA_HERMES is not set +# CONFIG_PCMCIA_LOAD_CIS is not set +# CONFIG_PCMCIA_NINJA_SCSI is not set +# CONFIG_PCMCIA_NMCLAN is not set +# CONFIG_PCMCIA_PCNET is not set +# CONFIG_PCMCIA_QLOGIC is not set +# CONFIG_PCMCIA_RAYCS is not set +# CONFIG_PCMCIA_SMC91C92 is not set +# CONFIG_PCMCIA_SPECTRUM is not set +# CONFIG_PCMCIA_SYM53C500 is not set +# CONFIG_PCMCIA_WL3501 is not set +# CONFIG_PCMCIA_XIRC2PS is not set +# CONFIG_PCMCIA_XIRCOM is not set +# CONFIG_PCNET32 is not set +# CONFIG_PCSPKR_PLATFORM is not set +# CONFIG_PD6729 is not set +# CONFIG_PDA_POWER is not set +# CONFIG_PDC_ADMA is not set +# CONFIG_PERCPU_TEST is not set +# CONFIG_PERF_COUNTERS is not set +# CONFIG_PERF_EVENTS is not set +# CONFIG_PERSISTENT_KEYRINGS is not set +# CONFIG_PHANTOM is not set +# CONFIG_PHONE is not set +# CONFIG_PHONET is not set +# CONFIG_PHYLIB is not set +# CONFIG_PHYS_ADDR_T_64BIT is not set +# CONFIG_PHY_EXYNOS_DP_VIDEO is not set +# CONFIG_PHY_EXYNOS_MIPI_VIDEO is not set +# CONFIG_PHY_SAMSUNG_USB2 is not set +# CONFIG_PHY_QCOM_DWC3 is not set +# CONFIG_PID_IN_CONTEXTIDR is not set +# CONFIG_PID_NS is not set +CONFIG_PINCONF=y +# CONFIG_PINCTRL is not set +# CONFIG_PINCTRL_AMD is not set +# CONFIG_PINCTRL_CAPRI is not set +# CONFIG_PINCTRL_EXYNOS is not set +# CONFIG_PINCTRL_EXYNOS5440 is not set +# CONFIG_PINCTRL_MSM8X74 is not set +CONFIG_PINCTRL_SINGLE=y +CONFIG_PINMUX=y +# CONFIG_PL320_MBOX is not set +# CONFIG_PLAT_SPEAR is not set +# CONFIG_PLIP is not set +# CONFIG_PLX_HERMES is not set +# CONFIG_PM is not set +# CONFIG_PMBUS is not set +# CONFIG_PMC_MSP is not set +# CONFIG_PMC_YOSEMITE is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_PM_AUTOSLEEP is not set +# CONFIG_PM_DEVFREQ is not set +# CONFIG_PM_RUNTIME is not set +# CONFIG_PM_WAKELOCKS is not set +# CONFIG_PNX8550_JBS is not set +# CONFIG_PNX8550_STB810 is not set +# CONFIG_POHMELFS is not set +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_POWERCAP is not set +# CONFIG_POWERTV is not set +# CONFIG_POWER_AVS is not set +# CONFIG_POWER_RESET is not set +# CONFIG_POWER_RESET_GPIO is not set +# CONFIG_POWER_RESET_GPIO_RESTART is not set +# CONFIG_POWER_RESET_LTC2952 is not set +# CONFIG_POWER_RESET_RESTART is not set +# CONFIG_POWER_RESET_SYSCON is not set +# CONFIG_POWER_RESET_SYSCON_POWEROFF is not set +# CONFIG_POWER_RESET_VERSATILE is not set +# CONFIG_POWER_SUPPLY is not set +# CONFIG_POWER_SUPPLY_DEBUG is not set +# CONFIG_PPC4xx_GPIO is not set +# CONFIG_PPC_16K_PAGES is not set +# CONFIG_PPC_256K_PAGES is not set +CONFIG_PPC_4K_PAGES=y +# CONFIG_PPC_64K_PAGES is not set +# CONFIG_PPC_DISABLE_WERROR is not set +# CONFIG_PPC_EMULATED_STATS is not set +# CONFIG_PPC_EPAPR_HV_BYTECHAN is not set +# CONFIG_PPP is not set +# CONFIG_PPPOATM is not set +# CONFIG_PPPOE is not set +# CONFIG_PPPOL2TP is not set +# CONFIG_PPP_ASYNC is not set +# CONFIG_PPP_BSDCOMP is not set +# CONFIG_PPP_DEFLATE is not set +CONFIG_PPP_FILTER=y +# CONFIG_PPP_MPPE is not set +CONFIG_PPP_MULTILINK=y +# CONFIG_PPP_SYNC_TTY is not set +# CONFIG_PPS is not set +# CONFIG_PPS_CLIENT_GPIO is not set +# CONFIG_PPS_CLIENT_KTIMER is not set +# CONFIG_PPS_CLIENT_LDISC is not set +# CONFIG_PPS_CLIENT_PARPORT is not set +# CONFIG_PPS_DEBUG is not set +# CONFIG_PPTP is not set +# CONFIG_PREEMPT is not set +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_TRACER is not set +# CONFIG_PREEMPT_VOLUNTARY is not set +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_PRINTK=y +# CONFIG_PRINTK_TIME is not set +CONFIG_PRINT_STACK_DEPTH=64 +# CONFIG_PRISM2_USB is not set +# CONFIG_PRISM54 is not set +# CONFIG_PROBE_INITRD_HEADER is not set +CONFIG_PROC_FS=y +# CONFIG_PROC_KCORE is not set +# CONFIG_PROC_PAGE_MONITOR is not set +CONFIG_PROC_STRIPPED=y +CONFIG_PROC_SYSCTL=y +# CONFIG_PROFILE_ALL_BRANCHES is not set +# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set +# CONFIG_PROFILING is not set +# CONFIG_PROVE_LOCKING is not set +# CONFIG_PROVE_RCU is not set +# CONFIG_PROVE_RCU_DELAY is not set +# CONFIG_PROVE_RCU_REPEATEDLY is not set +# CONFIG_PSB6970_PHY is not set +# CONFIG_PSTORE is not set +# CONFIG_PTP_1588_CLOCK is not set +# CONFIG_PTP_1588_CLOCK_IXP46X is not set +# CONFIG_PTP_1588_CLOCK_PCH is not set +# CONFIG_PWM is not set +# CONFIG_PWM_FSL_FTM is not set +# CONFIG_PWM_PCA9685 is not set +# CONFIG_QCA7000 is not set +# CONFIG_QLA3XXX is not set +# CONFIG_QLCNIC is not set +# CONFIG_QLGE is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX6FS_FS is not set +# CONFIG_QORIQ_CPUFREQ is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_QUOTA is not set +# CONFIG_QUOTACTL is not set +# CONFIG_QUOTA_DEBUG is not set +# CONFIG_R3964 is not set +# CONFIG_R6040 is not set +# CONFIG_R8169 is not set +# CONFIG_R8187SE is not set +# CONFIG_R8188EU is not set +# CONFIG_R8712U is not set +# CONFIG_R8723AU is not set +# CONFIG_RADIO_ADAPTERS is not set +# CONFIG_RADIO_AZTECH is not set +# CONFIG_RADIO_CADET is not set +# CONFIG_RADIO_GEMTEK is not set +# CONFIG_RADIO_MAXIRADIO is not set +# CONFIG_RADIO_RTRACK is not set +# CONFIG_RADIO_RTRACK2 is not set +# CONFIG_RADIO_SF16FMI is not set +# CONFIG_RADIO_SF16FMR2 is not set +# CONFIG_RADIO_TERRATEC is not set +# CONFIG_RADIO_TRUST is not set +# CONFIG_RADIO_TYPHOON is not set +# CONFIG_RADIO_ZOLTRIX is not set +# CONFIG_RAID_ATTRS is not set +# CONFIG_RALINK is not set +# CONFIG_RAMOOPS is not set +# CONFIG_RANDOM32_SELFTEST is not set +# CONFIG_RAPIDIO is not set +# CONFIG_RAR_REGISTER is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_RBTREE_TEST is not set +# CONFIG_RCU_CPU_STALL_INFO is not set +CONFIG_RCU_CPU_STALL_TIMEOUT=60 +# CONFIG_RCU_EXPEDITE_BOOT is not set +CONFIG_RCU_FANOUT=32 +# CONFIG_RCU_FANOUT_EXACT is not set +CONFIG_RCU_FANOUT_LEAF=16 +# CONFIG_RCU_FAST_NO_HZ is not set +CONFIG_RCU_KTHREAD_PRIO=0 +# CONFIG_RCU_NOCB_CPU is not set +# CONFIG_RCU_TORTURE_TEST is not set +CONFIG_RCU_TORTURE_TEST_SLOW_INIT_DELAY=3 +# CONFIG_RCU_TRACE is not set +# CONFIG_RCU_USER_QS is not set +# CONFIG_RC_ATI_REMOTE is not set +# CONFIG_RC_CORE is not set +# CONFIG_RC_DECODERS is not set +# CONFIG_RC_LOOPBACK is not set +# CONFIG_RC_MAP is not set +# CONFIG_RDS is not set +# CONFIG_RD_BZIP2 is not set +# CONFIG_RD_GZIP is not set +# CONFIG_RD_LZ4 is not set +# CONFIG_RD_LZMA is not set +# CONFIG_RD_LZO is not set +# CONFIG_RD_XZ is not set +# CONFIG_READABLE_ASM is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_REDWOOD is not set +# CONFIG_REGMAP is not set +# CONFIG_REGMAP_I2C is not set +# CONFIG_REGMAP_MMIO is not set +# CONFIG_REGMAP_SPI is not set +# CONFIG_REGULATOR is not set +# CONFIG_REGULATOR_ACT8865 is not set +# CONFIG_REGULATOR_AD5398 is not set +# CONFIG_REGULATOR_ANATOP is not set +# CONFIG_REGULATOR_BQ24022 is not set +# CONFIG_REGULATOR_DA9210 is not set +# CONFIG_REGULATOR_DA9211 is not set +# CONFIG_REGULATOR_DEBUG is not set +# CONFIG_REGULATOR_FAN53555 is not set +# CONFIG_REGULATOR_FIXED_VOLTAGE is not set +# CONFIG_REGULATOR_GPIO is not set +# CONFIG_REGULATOR_ISL6271A is not set +# CONFIG_REGULATOR_ISL9305 is not set +# CONFIG_REGULATOR_LP3971 is not set +# CONFIG_REGULATOR_LP3972 is not set +# CONFIG_REGULATOR_LP872X is not set +# CONFIG_REGULATOR_LP8755 is not set +# CONFIG_REGULATOR_LTC3589 is not set +# CONFIG_REGULATOR_MAX1586 is not set +# CONFIG_REGULATOR_MAX8649 is not set +# CONFIG_REGULATOR_MAX8660 is not set +# CONFIG_REGULATOR_MAX8952 is not set +# CONFIG_REGULATOR_MAX8973 is not set +# CONFIG_REGULATOR_PFUZE100 is not set +# CONFIG_REGULATOR_PWM is not set +# CONFIG_REGULATOR_TI_ABB is not set +# CONFIG_REGULATOR_TPS51632 is not set +# CONFIG_REGULATOR_TPS62360 is not set +# CONFIG_REGULATOR_TPS65023 is not set +# CONFIG_REGULATOR_TPS6507X is not set +# CONFIG_REGULATOR_TPS6524X is not set +# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set +# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_FS_POSIX_ACL is not set +# CONFIG_REISERFS_FS_SECURITY is not set +# CONFIG_REISERFS_FS_XATTR is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_RELAY is not set +# CONFIG_RESET_CONTROLLER is not set +# CONFIG_RFD_FTL is not set +# CONFIG_RFKILL is not set +# CONFIG_RFKILL_INPUT is not set +# CONFIG_RFKILL_REGULATOR is not set +# CONFIG_RING_BUFFER_BENCHMARK is not set +# CONFIG_RING_BUFFER_STARTUP_TEST is not set +# CONFIG_ROCKER is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_ROSE is not set +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RT2X00 is not set +# CONFIG_RTC_CLASS is not set +# CONFIG_RTC_DEBUG is not set +# CONFIG_RTC_DRV_ABB5ZES3 is not set +# CONFIG_RTC_DRV_ABX80X is not set +# CONFIG_RTC_DRV_ARMADA38X is not set +# CONFIG_RTC_DRV_AU1XXX is not set +# CONFIG_RTC_DRV_BQ32K is not set +# CONFIG_RTC_DRV_BQ4802 is not set +CONFIG_RTC_DRV_CMOS=y +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1305 is not set +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1343 is not set +# CONFIG_RTC_DRV_DS1347 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1390 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_DS1685_FAMILY is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_DS2404 is not set +# CONFIG_RTC_DRV_DS3232 is not set +# CONFIG_RTC_DRV_DS3234 is not set +# CONFIG_RTC_DRV_EM3027 is not set +# CONFIG_RTC_DRV_EP93XX is not set +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_GENERIC is not set +# CONFIG_RTC_DRV_HID_SENSOR_TIME is not set +# CONFIG_RTC_DRV_HYM8563 is not set +# CONFIG_RTC_DRV_ISL12022 is not set +# CONFIG_RTC_DRV_ISL12057 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_M41T80 is not set +# CONFIG_RTC_DRV_M41T93 is not set +# CONFIG_RTC_DRV_M41T94 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_MCP795 is not set +# CONFIG_RTC_DRV_MOXART is not set +# CONFIG_RTC_DRV_MPC5121 is not set +# CONFIG_RTC_DRV_MSM6242 is not set +# CONFIG_RTC_DRV_OMAP is not set +# CONFIG_RTC_DRV_PCF2123 is not set +# CONFIG_RTC_DRV_PCF2127 is not set +# CONFIG_RTC_DRV_PCF85063 is not set +# CONFIG_RTC_DRV_PCF8523 is not set +# CONFIG_RTC_DRV_PCF8563 is not set +# CONFIG_RTC_DRV_PCF8583 is not set +# CONFIG_RTC_DRV_PL030 is not set +# CONFIG_RTC_DRV_PL031 is not set +# CONFIG_RTC_DRV_PS3 is not set +# CONFIG_RTC_DRV_PT7C4338 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RP5C01 is not set +# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_RTC7301 is not set +# CONFIG_RTC_DRV_RV3029C2 is not set +# CONFIG_RTC_DRV_RX4581 is not set +# CONFIG_RTC_DRV_RX8025 is not set +# CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_S35390A is not set +# CONFIG_RTC_DRV_SNVS is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_SUN6I is not set +# CONFIG_RTC_DRV_TEST is not set +# CONFIG_RTC_DRV_V3020 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_XGENE is not set +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_LIB=y +CONFIG_RTC_SYSTOHC=y +# CONFIG_RTL8180 is not set +# CONFIG_RTL8187 is not set +# CONFIG_RTL8192E is not set +# CONFIG_RTL8192U is not set +# CONFIG_RTL8306_PHY is not set +# CONFIG_RTL8366RB_PHY is not set +# CONFIG_RTL8366S_PHY is not set +# CONFIG_RTL8366_SMI is not set +# CONFIG_RTL8366_SMI_DEBUG_FS is not set +# CONFIG_RTL8367B_PHY is not set +# CONFIG_RTL8367_PHY is not set +# CONFIG_RTLLIB is not set +# CONFIG_RTL_CARDS is not set +# CONFIG_RTS5139 is not set +# CONFIG_RTS5208 is not set +# CONFIG_RTS_PSTOR is not set +CONFIG_RT_MUTEXES=y +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_RUNTIME_DEBUG is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_S2IO is not set +# CONFIG_SAMPLES is not set +# CONFIG_SAMSUNG_LAPTOP is not set +# CONFIG_SAMSUNG_USB2PHY is not set +# CONFIG_SAMSUNG_USB3PHY is not set +# CONFIG_SATA_ACARD_AHCI is not set +# CONFIG_SATA_AHCI is not set +# CONFIG_SATA_AHCI_PLATFORM is not set +# CONFIG_SATA_DWC is not set +# CONFIG_SATA_FSL is not set +# CONFIG_SATA_HIGHBANK is not set +# CONFIG_SATA_INIC162X is not set +# CONFIG_SATA_MV is not set +# CONFIG_SATA_NV is not set +# CONFIG_SATA_PMP is not set +# CONFIG_SATA_PROMISE is not set +# CONFIG_SATA_QSTOR is not set +# CONFIG_SATA_RCAR is not set +# CONFIG_SATA_SIL is not set +# CONFIG_SATA_SIL24 is not set +# CONFIG_SATA_SIS is not set +# CONFIG_SATA_SVW is not set +# CONFIG_SATA_SX4 is not set +# CONFIG_SATA_ULI is not set +# CONFIG_SATA_VIA is not set +# CONFIG_SATA_VITESSE is not set +# CONFIG_SBC_FITPC2_WATCHDOG is not set +# CONFIG_SBE_2T3E3 is not set +# CONFIG_SBYPASS is not set +# CONFIG_SC92031 is not set +# CONFIG_SCA3000 is not set +# CONFIG_SCC is not set +# CONFIG_SCHEDSTATS is not set +# CONFIG_SCHED_AUTOGROUP is not set +# CONFIG_SCHED_DEBUG is not set +# CONFIG_SCHED_MC is not set +CONFIG_SCHED_OMIT_FRAME_POINTER=y +# CONFIG_SCHED_SMT is not set +# CONFIG_SCHED_STACK_END_CHECK is not set +# CONFIG_SCHED_TRACER is not set +# CONFIG_SCSI is not set +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_3W_SAS is not set +# CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AHA1542 is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_AIC94XX is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_ARCMSR is not set +# CONFIG_SCSI_BFA_FC is not set +# CONFIG_SCSI_BNX2X_FCOE is not set +# CONFIG_SCSI_BNX2_ISCSI is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_CHELSIO_FCOE is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_CXGB3_ISCSI is not set +# CONFIG_SCSI_CXGB4_ISCSI is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_DH is not set +CONFIG_SCSI_DMA=y +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_ESAS2R is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set +# CONFIG_SCSI_HPSA is not set +# CONFIG_SCSI_HPTIOP is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_ISCI is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_LOGGING is not set +CONFIG_SCSI_LOWLEVEL=y +# CONFIG_SCSI_LOWLEVEL_PCMCIA is not set +# CONFIG_SCSI_LPFC is not set +CONFIG_SCSI_MOD=y +# CONFIG_SCSI_MPT2SAS is not set +# CONFIG_SCSI_MPT3SAS is not set +# CONFIG_SCSI_MQ_DEFAULT is not set +CONFIG_SCSI_MULTI_LUN=y +# CONFIG_SCSI_MVSAS is not set +# CONFIG_SCSI_MVSAS_DEBUG is not set +# CONFIG_SCSI_MVUMI is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_NETLINK is not set +# CONFIG_SCSI_NSP32 is not set +# CONFIG_SCSI_OSD_INITIATOR is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PM8001 is not set +# CONFIG_SCSI_PMCRAID is not set +CONFIG_SCSI_PROC_FS=y +# CONFIG_SCSI_QLA_FC is not set +# CONFIG_SCSI_QLA_ISCSI is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SCAN_ASYNC is not set +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_SRP is not set +# CONFIG_SCSI_SRP_ATTRS is not set +# CONFIG_SCSI_STEX is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_TGT is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_UFSHCD is not set +# CONFIG_SCSI_ULTRASTOR is not set +# CONFIG_SCSI_VIRTIO is not set +# CONFIG_SCSI_WD719X is not set +# CONFIG_SCx200_ACB is not set +# CONFIG_SDIO_UART is not set +# CONFIG_SECCOMP is not set +# CONFIG_SECURITY is not set +# CONFIG_SECURITYFS is not set +# CONFIG_SECURITY_DMESG_RESTRICT is not set +# CONFIG_SEEQ8005 is not set +CONFIG_SELECT_MEMORY_MODEL=y +# CONFIG_SENSORS_ABITUGURU is not set +# CONFIG_SENSORS_ABITUGURU3 is not set +# CONFIG_SENSORS_ACPI_POWER is not set +# CONFIG_SENSORS_AD7314 is not set +# CONFIG_SENSORS_AD7414 is not set +# CONFIG_SENSORS_AD7418 is not set +# CONFIG_SENSORS_ADC128D818 is not set +# CONFIG_SENSORS_ADCXX is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1029 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_ADS1015 is not set +# CONFIG_SENSORS_ADS7828 is not set +# CONFIG_SENSORS_ADS7871 is not set +# CONFIG_SENSORS_ADT7310 is not set +# CONFIG_SENSORS_ADT7410 is not set +# CONFIG_SENSORS_ADT7411 is not set +# CONFIG_SENSORS_ADT7462 is not set +# CONFIG_SENSORS_ADT7470 is not set +# CONFIG_SENSORS_ADT7475 is not set +# CONFIG_SENSORS_AMC6821 is not set +# CONFIG_SENSORS_APDS990X is not set +# CONFIG_SENSORS_APPLESMC is not set +# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_ASC7621 is not set +# CONFIG_SENSORS_ATK0110 is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_BH1770 is not set +# CONFIG_SENSORS_BH1780 is not set +# CONFIG_SENSORS_CORETEMP is not set +# CONFIG_SENSORS_DME1737 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_DS620 is not set +# CONFIG_SENSORS_EMC1403 is not set +# CONFIG_SENSORS_EMC2103 is not set +# CONFIG_SENSORS_EMC6W201 is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_F75375S is not set +# CONFIG_SENSORS_FAM15H_POWER is not set +# CONFIG_SENSORS_FSCHMD is not set +# CONFIG_SENSORS_G760A is not set +# CONFIG_SENSORS_G762 is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_GPIO_FAN is not set +# CONFIG_SENSORS_GSC is not set +# CONFIG_SENSORS_HDAPS is not set +# CONFIG_SENSORS_HIH6130 is not set +# CONFIG_SENSORS_HMC5843 is not set +# CONFIG_SENSORS_HMC5843_I2C is not set +# CONFIG_SENSORS_HMC5843_SPI is not set +# CONFIG_SENSORS_HTU21 is not set +# CONFIG_SENSORS_I5500 is not set +# CONFIG_SENSORS_I5K_AMB is not set +# CONFIG_SENSORS_IIO_HWMON is not set +# CONFIG_SENSORS_INA209 is not set +# CONFIG_SENSORS_INA2XX is not set +# CONFIG_SENSORS_ISL29018 is not set +# CONFIG_SENSORS_ISL29028 is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_JC42 is not set +# CONFIG_SENSORS_K10TEMP is not set +# CONFIG_SENSORS_K8TEMP is not set +# CONFIG_SENSORS_LINEAGE is not set +# CONFIG_SENSORS_LIS3LV02D is not set +# CONFIG_SENSORS_LIS3_I2C is not set +# CONFIG_SENSORS_LIS3_SPI is not set +# CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM70 is not set +# CONFIG_SENSORS_LM73 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_LM93 is not set +# CONFIG_SENSORS_LM95234 is not set +# CONFIG_SENSORS_LM95241 is not set +# CONFIG_SENSORS_LM95245 is not set +# CONFIG_SENSORS_LTC2945 is not set +# CONFIG_SENSORS_LTC4151 is not set +# CONFIG_SENSORS_LTC4215 is not set +# CONFIG_SENSORS_LTC4222 is not set +# CONFIG_SENSORS_LTC4245 is not set +# CONFIG_SENSORS_LTC4260 is not set +# CONFIG_SENSORS_LTC4261 is not set +# CONFIG_SENSORS_MAX1111 is not set +# CONFIG_SENSORS_MAX16065 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_MAX1668 is not set +# CONFIG_SENSORS_MAX197 is not set +# CONFIG_SENSORS_MAX6639 is not set +# CONFIG_SENSORS_MAX6642 is not set +# CONFIG_SENSORS_MAX6650 is not set +# CONFIG_SENSORS_MAX6697 is not set +# CONFIG_SENSORS_MCP3021 is not set +# CONFIG_SENSORS_NCT6683 is not set +# CONFIG_SENSORS_NCT6775 is not set +# CONFIG_SENSORS_NCT7802 is not set +# CONFIG_SENSORS_NCT7904 is not set +# CONFIG_SENSORS_NTC_THERMISTOR is not set +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_POWR1220 is not set +# CONFIG_SENSORS_PWM_FAN is not set +# CONFIG_SENSORS_SCH5627 is not set +# CONFIG_SENSORS_SCH5636 is not set +# CONFIG_SENSORS_SCH56XX_COMMON is not set +# CONFIG_SENSORS_SHT15 is not set +# CONFIG_SENSORS_SHT21 is not set +# CONFIG_SENSORS_SHTC1 is not set +# CONFIG_SENSORS_SIS5595 is not set +# CONFIG_SENSORS_SMM665 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_THMC50 is not set +# CONFIG_SENSORS_TMP102 is not set +# CONFIG_SENSORS_TMP103 is not set +# CONFIG_SENSORS_TMP401 is not set +# CONFIG_SENSORS_TMP421 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_SENSORS_TSL2563 is not set +# CONFIG_SENSORS_VEXPRESS is not set +# CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_VIA_CPUTEMP is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_VT8231 is not set +# CONFIG_SENSORS_W83627EHF is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83791D is not set +# CONFIG_SENSORS_W83792D is not set +# CONFIG_SENSORS_W83793 is not set +# CONFIG_SENSORS_W83795 is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83L786NG is not set +CONFIG_SERIAL_8250=y +# CONFIG_SERIAL_8250_ACCENT is not set +# CONFIG_SERIAL_8250_BOCA is not set +CONFIG_SERIAL_8250_CONSOLE=y +# CONFIG_SERIAL_8250_CS is not set +# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +CONFIG_SERIAL_8250_DMA=y +# CONFIG_SERIAL_8250_DW is not set +# CONFIG_SERIAL_8250_EM is not set +# CONFIG_SERIAL_8250_EXAR_ST16C554 is not set +# CONFIG_SERIAL_8250_EXTENDED is not set +# CONFIG_SERIAL_8250_FINTEK is not set +# CONFIG_SERIAL_8250_FOURPORT is not set +# CONFIG_SERIAL_8250_HUB6 is not set +# CONFIG_SERIAL_8250_MANY_PORTS is not set +CONFIG_SERIAL_8250_NR_UARTS=2 +# CONFIG_SERIAL_8250_PCI is not set +# CONFIG_SERIAL_8250_RSA is not set +CONFIG_SERIAL_8250_RUNTIME_UARTS=2 +# CONFIG_SERIAL_8250_SYSRQ is not set +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +# CONFIG_SERIAL_ARC is not set +# CONFIG_SERIAL_BCM63XX is not set +# CONFIG_SERIAL_CONEXANT_DIGICOLOR is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_SERIAL_EARLYCON=y +# CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST is not set +# CONFIG_SERIAL_FSL_LPUART is not set +# CONFIG_SERIAL_GRLIB_GAISLER_APBUART is not set +# CONFIG_SERIAL_IFX6X60 is not set +# CONFIG_SERIAL_JSM is not set +# CONFIG_SERIAL_MAX3100 is not set +# CONFIG_SERIAL_MAX3107 is not set +# CONFIG_SERIAL_MAX310X is not set +# CONFIG_SERIAL_MFD_HSU is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_SERIAL_OF_PLATFORM is not set +# CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL is not set +# CONFIG_SERIAL_PCH_UART is not set +# CONFIG_SERIAL_RP2 is not set +# CONFIG_SERIAL_SC16IS7XX is not set +# CONFIG_SERIAL_SCCNXP is not set +# CONFIG_SERIAL_SH_SCI is not set +# CONFIG_SERIAL_ST_ASC is not set +# CONFIG_SERIAL_TIMBERDALE is not set +# CONFIG_SERIAL_UARTLITE is not set +# CONFIG_SERIAL_XILINX_PS_UART is not set +# CONFIG_SERIO is not set +# CONFIG_SERIO_ALTERA_PS2 is not set +# CONFIG_SERIO_AMBAKMI is not set +# CONFIG_SERIO_APBPS2 is not set +# CONFIG_SERIO_ARC_PS2 is not set +# CONFIG_SERIO_I8042 is not set +# CONFIG_SERIO_LIBPS2 is not set +# CONFIG_SERIO_PARKBD is not set +# CONFIG_SERIO_PCIPS2 is not set +# CONFIG_SERIO_PS2MULT is not set +# CONFIG_SERIO_RAW is not set +# CONFIG_SERIO_SERPORT is not set +# CONFIG_SERIO_SUN4I_PS2 is not set +# CONFIG_SFC is not set +# CONFIG_SFI is not set +# CONFIG_SGETMASK_SYSCALL is not set +# CONFIG_SGI_IOC4 is not set +# CONFIG_SGI_IP22 is not set +# CONFIG_SGI_IP27 is not set +# CONFIG_SGI_IP28 is not set +# CONFIG_SGI_IP32 is not set +# CONFIG_SGI_PARTITION is not set +CONFIG_SHMEM=y +# CONFIG_SH_ETH is not set +# CONFIG_SH_TIMER_CMT is not set +# CONFIG_SH_TIMER_MTU2 is not set +# CONFIG_SH_TIMER_TMU is not set +# CONFIG_SI7005 is not set +# CONFIG_SI7020 is not set +# CONFIG_SIBYTE_BIGSUR is not set +# CONFIG_SIBYTE_CARMEL is not set +# CONFIG_SIBYTE_CRHINE is not set +# CONFIG_SIBYTE_CRHONE is not set +# CONFIG_SIBYTE_LITTLESUR is not set +# CONFIG_SIBYTE_RHONE is not set +# CONFIG_SIBYTE_SENTOSA is not set +# CONFIG_SIBYTE_SWARM is not set +# CONFIG_SIGMA is not set +CONFIG_SIGNALFD=y +# CONFIG_SIMPLE_GPIO is not set +# CONFIG_SIS190 is not set +# CONFIG_SIS900 is not set +# CONFIG_SKGE is not set +# CONFIG_SKY2 is not set +# CONFIG_SKY2_DEBUG is not set +CONFIG_SLAB=y +CONFIG_SLABINFO=y +# CONFIG_SLHC is not set +# CONFIG_SLICOSS is not set +# CONFIG_SLIP is not set +# CONFIG_SLOB is not set +# CONFIG_SLUB is not set +# CONFIG_SLUB_DEBUG is not set +# CONFIG_SLUB_STATS is not set +# CONFIG_SMARTJOYPLUS_FF is not set +# CONFIG_SMC911X is not set +# CONFIG_SMC9194 is not set +# CONFIG_SMC91X is not set +# CONFIG_SMP is not set +# CONFIG_SMSC911X is not set +# CONFIG_SMSC9420 is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_SM_FTL is not set +# CONFIG_SND is not set +# CONFIG_SND_AC97_POWER_SAVE is not set +# CONFIG_SND_AD1816A is not set +# CONFIG_SND_AD1848 is not set +# CONFIG_SND_AD1889 is not set +# CONFIG_SND_ADLIB is not set +# CONFIG_SND_ALI5451 is not set +# CONFIG_SND_ALOOP is not set +# CONFIG_SND_ALS100 is not set +# CONFIG_SND_ALS300 is not set +# CONFIG_SND_ALS4000 is not set +# CONFIG_SND_ARM is not set +# CONFIG_SND_ASIHPI is not set +# CONFIG_SND_ATIIXP is not set +# CONFIG_SND_ATIIXP_MODEM is not set +# CONFIG_SND_ATMEL_AC97C is not set +# CONFIG_SND_ATMEL_SOC is not set +# CONFIG_SND_AU8810 is not set +# CONFIG_SND_AU8820 is not set +# CONFIG_SND_AU8830 is not set +# CONFIG_SND_AW2 is not set +# CONFIG_SND_AZT2320 is not set +# CONFIG_SND_AZT3328 is not set +# CONFIG_SND_BCD2000 is not set +# CONFIG_SND_BT87X is not set +# CONFIG_SND_CA0106 is not set +# CONFIG_SND_CMI8330 is not set +# CONFIG_SND_CMIPCI is not set +# CONFIG_SND_CS4231 is not set +# CONFIG_SND_CS4236 is not set +# CONFIG_SND_CS4281 is not set +# CONFIG_SND_CS46XX is not set +# CONFIG_SND_CS5530 is not set +# CONFIG_SND_CS5535AUDIO is not set +# CONFIG_SND_CTXFI is not set +# CONFIG_SND_DARLA20 is not set +# CONFIG_SND_DARLA24 is not set +# CONFIG_SND_DEBUG is not set +# CONFIG_SND_DESIGNWARE_I2S is not set +CONFIG_SND_DRIVERS=y +# CONFIG_SND_DUMMY is not set +# CONFIG_SND_DYNAMIC_MINORS is not set +# CONFIG_SND_ECHO3G is not set +# CONFIG_SND_EMU10K1 is not set +# CONFIG_SND_EMU10K1X is not set +# CONFIG_SND_ENS1370 is not set +# CONFIG_SND_ENS1371 is not set +# CONFIG_SND_ES1688 is not set +# CONFIG_SND_ES18XX is not set +# CONFIG_SND_ES1938 is not set +# CONFIG_SND_ES1968 is not set +# CONFIG_SND_FIREWIRE is not set +# CONFIG_SND_FM801 is not set +# CONFIG_SND_GINA20 is not set +# CONFIG_SND_GINA24 is not set +# CONFIG_SND_GUSCLASSIC is not set +# CONFIG_SND_GUSEXTREME is not set +# CONFIG_SND_GUSMAX is not set +# CONFIG_SND_HDA_INTEL is not set +# CONFIG_SND_HDSP is not set +# CONFIG_SND_HDSPM is not set +# CONFIG_SND_HRTIMER is not set +# CONFIG_SND_HWDEP is not set +# CONFIG_SND_ICE1712 is not set +# CONFIG_SND_ICE1724 is not set +# CONFIG_SND_INDIGO is not set +# CONFIG_SND_INDIGODJ is not set +# CONFIG_SND_INDIGODJX is not set +# CONFIG_SND_INDIGOIO is not set +# CONFIG_SND_INDIGOIOX is not set +# CONFIG_SND_INTEL8X0 is not set +# CONFIG_SND_INTEL8X0M is not set +# CONFIG_SND_INTERWAVE is not set +# CONFIG_SND_INTERWAVE_STB is not set +# CONFIG_SND_ISA is not set +# CONFIG_SND_KIRKWOOD_SOC is not set +# CONFIG_SND_KORG1212 is not set +# CONFIG_SND_LAYLA20 is not set +# CONFIG_SND_LAYLA24 is not set +# CONFIG_SND_LOLA is not set +# CONFIG_SND_LX6464ES is not set +# CONFIG_SND_MAESTRO3 is not set +# CONFIG_SND_MIA is not set +# CONFIG_SND_MIPS is not set +# CONFIG_SND_MIRO is not set +# CONFIG_SND_MIXART is not set +# CONFIG_SND_MIXER_OSS is not set +# CONFIG_SND_MONA is not set +# CONFIG_SND_MPC52xx_SOC_EFIKA is not set +# CONFIG_SND_MPU401 is not set +# CONFIG_SND_MTPAV is not set +# CONFIG_SND_MTS64 is not set +# CONFIG_SND_MXS_SOC is not set +# CONFIG_SND_NM256 is not set +# CONFIG_SND_OPL3SA2 is not set +# CONFIG_SND_OPTI92X_AD1848 is not set +# CONFIG_SND_OPTI92X_CS4231 is not set +# CONFIG_SND_OPTI93X is not set +CONFIG_SND_OSSEMUL=y +# CONFIG_SND_OXYGEN is not set +CONFIG_SND_PCI=y +# CONFIG_SND_PCM is not set +# CONFIG_SND_PCMCIA is not set +# CONFIG_SND_PCM_OSS is not set +CONFIG_SND_PCM_OSS_PLUGINS=y +# CONFIG_SND_PCXHR is not set +# CONFIG_SND_PDAUDIOCF is not set +# CONFIG_SND_PORTMAN2X4 is not set +# CONFIG_SND_POWERPC_SOC is not set +# CONFIG_SND_PPC is not set +# CONFIG_SND_RAWMIDI is not set +# CONFIG_SND_RIPTIDE is not set +# CONFIG_SND_RME32 is not set +# CONFIG_SND_RME96 is not set +# CONFIG_SND_RME9652 is not set +# CONFIG_SND_SE6X is not set +# CONFIG_SND_RTCTIMER is not set +# CONFIG_SND_SB16 is not set +# CONFIG_SND_SB8 is not set +# CONFIG_SND_SBAWE is not set +# CONFIG_SND_SEQUENCER is not set +# CONFIG_SND_SERIAL_U16550 is not set +# CONFIG_SND_SIMPLE_CARD is not set +# CONFIG_SND_SIS7019 is not set +# CONFIG_SND_SOC is not set +# CONFIG_SND_SOC_ADAU1701 is not set +# CONFIG_SND_SOC_AK4104 is not set +# CONFIG_SND_SOC_AK4554 is not set +# CONFIG_SND_SOC_AK4642 is not set +# CONFIG_SND_SOC_AK5386 is not set +# CONFIG_SND_SOC_ALC5623 is not set +# CONFIG_SND_SOC_AU1XAUDIO is not set +# CONFIG_SND_SOC_AU1XPSC is not set +# CONFIG_SND_SOC_CACHE_LZO is not set +# CONFIG_SND_SOC_CS35L32 is not set +# CONFIG_SND_SOC_CS4265 is not set +# CONFIG_SND_SOC_CS4270 is not set +# CONFIG_SND_SOC_CS4271 is not set +# CONFIG_SND_SOC_CS4271_I2C is not set +# CONFIG_SND_SOC_CS4271_SND is not set +# CONFIG_SND_SOC_CS4271_SPI is not set +# CONFIG_SND_SOC_CS42L51_I2C is not set +# CONFIG_SND_SOC_CS42L52 is not set +# CONFIG_SND_SOC_CS42L56 is not set +# CONFIG_SND_SOC_CS42L73 is not set +# CONFIG_SND_SOC_CS42L73 is not set +# CONFIG_SND_SOC_CS42XX8_I2C is not set +# CONFIG_SND_SOC_ES8328 is not set +# CONFIG_SND_SOC_EUKREA_TLV320 is not set +# CONFIG_SND_SOC_FSL_ASOC_CARD is not set +# CONFIG_SND_SOC_FSL_ASRC is not set +# CONFIG_SND_SOC_FSL_ESAI is not set +# CONFIG_SND_SOC_FSL_SAI is not set +# CONFIG_SND_SOC_FSL_SPDIF is not set +# CONFIG_SND_SOC_HDMI_CODEC is not set +# CONFIG_SND_SOC_IMX_ES8328 is not set +# CONFIG_SND_SOC_IMX_SPDIF is not set +# CONFIG_SND_SOC_IMX_WM8962 is not set +# CONFIG_SND_SOC_INTEL_SST is not set +# CONFIG_SND_SOC_MPC5200_AC97 is not set +# CONFIG_SND_SOC_MPC5200_I2S is not set +# CONFIG_SND_SOC_PCM1681 is not set +# CONFIG_SND_SOC_PCM1792A is not set +# CONFIG_SND_SOC_PCM512x_I2C is not set +# CONFIG_SND_SOC_PCM512x_SPI is not set +# CONFIG_SND_SOC_QCOM is not set +# CONFIG_SND_SOC_RT5631 is not set +# CONFIG_SND_SOC_SGTL5000 is not set +# CONFIG_SND_SOC_SIRF_AUDIO_CODEC is not set +# CONFIG_SND_SOC_SPDIF is not set +# CONFIG_SND_SOC_SSM2602_I2C is not set +# CONFIG_SND_SOC_SSM2602_SPI is not set +# CONFIG_SND_SOC_SSM4567 is not set +# CONFIG_SND_SOC_STA32X is not set +# CONFIG_SND_SOC_STA350 is not set +# CONFIG_SND_SOC_TAS2552 is not set +# CONFIG_SND_SOC_TAS5086 is not set +# CONFIG_SND_SOC_TFA9879 is not set +# CONFIG_SND_SOC_TLV320AIC23_I2C is not set +# CONFIG_SND_SOC_TLV320AIC23_SPI is not set +# CONFIG_SND_SOC_TLV320AIC31XX is not set +# CONFIG_SND_SOC_TLV320AIC3X is not set +# CONFIG_SND_SOC_TPA6130A2 is not set +# CONFIG_SND_SOC_TS3A227E is not set +# CONFIG_SND_SOC_WM8510 is not set +# CONFIG_SND_SOC_WM8523 is not set +# CONFIG_SND_SOC_WM8580 is not set +# CONFIG_SND_SOC_WM8711 is not set +# CONFIG_SND_SOC_WM8728 is not set +# CONFIG_SND_SOC_WM8731 is not set +# CONFIG_SND_SOC_WM8737 is not set +# CONFIG_SND_SOC_WM8741 is not set +# CONFIG_SND_SOC_WM8750 is not set +# CONFIG_SND_SOC_WM8753 is not set +# CONFIG_SND_SOC_WM8770 is not set +# CONFIG_SND_SOC_WM8776 is not set +# CONFIG_SND_SOC_WM8804_I2C is not set +# CONFIG_SND_SOC_WM8804_SPI is not set +# CONFIG_SND_SOC_WM8903 is not set +# CONFIG_SND_SOC_WM8962 is not set +# CONFIG_SND_SOC_WM8978 is not set +# CONFIG_SND_SOC_XTFPGA_I2S is not set +# CONFIG_SND_SONICVIBES is not set +# CONFIG_SND_SPI is not set +# CONFIG_SND_SSCAPE is not set +# CONFIG_SND_SUPPORT_OLD_API is not set +# CONFIG_SND_TIMER is not set +# CONFIG_SND_TRIDENT is not set +CONFIG_SND_USB=y +# CONFIG_SND_USB_6FIRE is not set +# CONFIG_SND_USB_AUDIO is not set +# CONFIG_SND_USB_CAIAQ is not set +# CONFIG_SND_USB_HIFACE is not set +# CONFIG_SND_USB_POD is not set +# CONFIG_SND_USB_PODHD is not set +# CONFIG_SND_USB_TONEPORT is not set +# CONFIG_SND_USB_UA101 is not set +# CONFIG_SND_USB_US122L is not set +# CONFIG_SND_USB_USX2Y is not set +# CONFIG_SND_USB_VARIAX is not set +# CONFIG_SND_VERBOSE_PRINTK is not set +CONFIG_SND_VERBOSE_PROCFS=y +# CONFIG_SND_VIA82XX is not set +# CONFIG_SND_VIA82XX_MODEM is not set +# CONFIG_SND_VIRTUOSO is not set +# CONFIG_SND_VX222 is not set +# CONFIG_SND_VXPOCKET is not set +# CONFIG_SND_WAVEFRONT is not set +# CONFIG_SND_YMFPCI is not set +# CONFIG_SNI_RM is not set +# CONFIG_SOC_AM33XX is not set +# CONFIG_SOC_AM43XX is not set +# CONFIG_SOC_CAMERA is not set +# CONFIG_SOC_DRA7XX is not set +# CONFIG_SOC_HAS_OMAP2_SDRC is not set +# CONFIG_SOC_OMAP5 is not set +# CONFIG_SOC_TI is not set +# CONFIG_SOFT_WATCHDOG is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_SOLO6X10 is not set +# CONFIG_SONYPI is not set +# CONFIG_SONY_LAPTOP is not set +# CONFIG_SOUND is not set +# CONFIG_SOUND_PRIME is not set +# CONFIG_SP5100_TCO is not set +# CONFIG_SPARSEMEM_MANUAL is not set +# CONFIG_SPARSEMEM_STATIC is not set +# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set +# CONFIG_SPARSE_IRQ is not set +# CONFIG_SPARSE_RCU_POINTER is not set +# CONFIG_SPEAKUP is not set +# CONFIG_SPI is not set +# CONFIG_SPINLOCK_TEST is not set +# CONFIG_SPI_ALTERA is not set +# CONFIG_SPI_AU1550 is not set +# CONFIG_SPI_BCM2835 is not set +# CONFIG_SPI_BITBANG is not set +# CONFIG_SPI_BUTTERFLY is not set +# CONFIG_SPI_CADENCE is not set +# CONFIG_SPI_DEBUG is not set +# CONFIG_SPI_DESIGNWARE is not set +# CONFIG_SPI_FSL_DSPI is not set +# CONFIG_SPI_FSL_ESPI is not set +# CONFIG_SPI_FSL_SPI is not set +# CONFIG_SPI_GPIO is not set +# CONFIG_SPI_GPIO_OLD is not set +# CONFIG_SPI_IMG_SPFI is not set +# CONFIG_SPI_LM70_LLP is not set +# CONFIG_SPI_MASTER is not set +# CONFIG_SPI_MPC52xx is not set +# CONFIG_SPI_MPC52xx_PSC is not set +# CONFIG_SPI_OC_TINY is not set +# CONFIG_SPI_OCTEON is not set +# CONFIG_SPI_ORION is not set +# CONFIG_SPI_PL022 is not set +# CONFIG_SPI_PPC4xx is not set +# CONFIG_SPI_PXA2XX is not set +# CONFIG_SPI_PXA2XX_PCI is not set +# CONFIG_SPI_RAMIPS is not set +# CONFIG_SPI_ROCKCHIP is not set +# CONFIG_SPI_SC18IS602 is not set +# CONFIG_SPI_SPIDEV is not set +# CONFIG_SPI_TI_QSPI is not set +# CONFIG_SPI_TLE62X0 is not set +# CONFIG_SPI_TOPCLIFF_PCH is not set +# CONFIG_SPI_XCOMM is not set +# CONFIG_SPI_XILINX is not set +# CONFIG_SPI_XWAY is not set +# CONFIG_SPMI is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_SQUASHFS=y +# CONFIG_SQUASHFS_4K_DEVBLK_SIZE is not set +# CONFIG_SQUASHFS_DECOMP_MULTI is not set +CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU=y +# CONFIG_SQUASHFS_DECOMP_SINGLE is not set +# CONFIG_SQUASHFS_EMBEDDED is not set +# CONFIG_SQUASHFS_FILE_CACHE is not set +CONFIG_SQUASHFS_FILE_DIRECT=y +CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3 +# CONFIG_SQUASHFS_LZ4 is not set +# CONFIG_SQUASHFS_LZO is not set +# CONFIG_SQUASHFS_XATTR is not set +CONFIG_SQUASHFS_XZ=y +# CONFIG_SQUASHFS_ZLIB is not set +# CONFIG_SRAM is not set +# CONFIG_SSB is not set +# CONFIG_SSBI is not set +# CONFIG_SSB_DEBUG is not set +# CONFIG_SSB_DRIVER_GPIO is not set +# CONFIG_SSB_PCMCIAHOST is not set +CONFIG_SSB_POSSIBLE=y +# CONFIG_SSB_SDIOHOST is not set +# CONFIG_SSB_SILENT is not set +# CONFIG_SSFDC is not set +CONFIG_STACKTRACE_SUPPORT=y +# CONFIG_STACKTRACE is not set +# CONFIG_STACK_TRACER is not set +CONFIG_STAGING=y +# CONFIG_STAGING_MEDIA is not set +CONFIG_STANDALONE=y +CONFIG_STDBINUTILS=y +# CONFIG_STE10XP is not set +# CONFIG_STE_MODEM_RPROC is not set +# CONFIG_STMMAC_ETH is not set +# CONFIG_STMMAC_PLATFORM is not set +# CONFIG_STMMAC_PCI is not set +CONFIG_STP=y +# CONFIG_STRICT_DEVMEM is not set +CONFIG_STRIP_ASM_SYMS=y +# CONFIG_STUB_POULSBO is not set +# CONFIG_SUNDANCE is not set +# CONFIG_SUNGEM is not set +# CONFIG_SUNRPC is not set +# CONFIG_SUNRPC_DEBUG is not set +# CONFIG_SUNRPC_GSS is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_SUSPEND is not set +CONFIG_SWAP=y +# CONFIG_SWCONFIG is not set +# CONFIG_SWCONFIG_LEDS is not set +# CONFIG_SX9500 is not set +# CONFIG_SXGBE_ETH is not set +# CONFIG_SYNCLINK_CS is not set +CONFIG_SYN_COOKIES=y +CONFIG_SYSCTL=y +# CONFIG_SYSCTL_SYSCALL is not set +# CONFIG_SYSCTL_SYSCALL_CHECK is not set +CONFIG_SYSFS=y +# CONFIG_SYSFS_DEPRECATED is not set +# CONFIG_SYSFS_DEPRECATED_V2 is not set +# CONFIG_SYSFS_SYSCALL is not set +# CONFIG_SYSTEMPORT is not set +# CONFIG_SYSTEM_TRUSTED_KEYRING is not set +# CONFIG_SYSV68_PARTITION is not set +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +# CONFIG_SYSV_FS is not set +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_T5403 is not set +# CONFIG_TARGET_CORE is not set +# CONFIG_TASKSTATS is not set +# CONFIG_TASKS_RCU is not set +# CONFIG_TC35815 is not set +# CONFIG_TCG_TPM is not set +# CONFIG_TCIC is not set +CONFIG_TCP_CONG_ADVANCED=y +# CONFIG_TCP_CONG_BIC is not set +CONFIG_TCP_CONG_CUBIC=y +# CONFIG_TCP_CONG_DCTCP is not set +# CONFIG_TCP_CONG_HSTCP is not set +# CONFIG_TCP_CONG_HTCP is not set +# CONFIG_TCP_CONG_HYBLA is not set +# CONFIG_TCP_CONG_ILLINOIS is not set +# CONFIG_TCP_CONG_LP is not set +# CONFIG_TCP_CONG_SCALABLE is not set +# CONFIG_TCP_CONG_VEGAS is not set +# CONFIG_TCP_CONG_VENO is not set +# CONFIG_TCP_CONG_WESTWOOD is not set +# CONFIG_TCP_CONG_YEAH is not set +# CONFIG_TCP_MD5SIG is not set +# CONFIG_TCS3414 is not set +# CONFIG_TCS3472 is not set +# CONFIG_TEGRA_AHB is not set +# CONFIG_TEGRA_HOST1X is not set +# CONFIG_TEHUTI is not set +# CONFIG_TEST_BPF is not set +# CONFIG_TEST_UDELAY is not set +# CONFIG_TEST_FIRMWARE is not set +# CONFIG_TEST_HEXDUMP is not set +# CONFIG_TEST_KSTRTOX is not set +# CONFIG_TEST_LIST_SORT is not set +# CONFIG_TEST_LKM is not set +# CONFIG_TEST_MODULE is not set +# CONFIG_TEST_POWER is not set +# CONFIG_TEST_RHASHTABLE is not set +# CONFIG_TEST_STRING_HELPERS is not set +# CONFIG_TEST_USER_COPY is not set +CONFIG_TEXTSEARCH=y +# CONFIG_TEXTSEARCH_BM is not set +# CONFIG_TEXTSEARCH_FSM is not set +# CONFIG_TEXTSEARCH_KMP is not set +# CONFIG_THERMAL is not set +# CONFIG_THERMAL_GOV_BANG_BANG is not set +# CONFIG_THERMAL_HWMON is not set +# CONFIG_THINKPAD_ACPI is not set +# CONFIG_THRUSTMASTER_FF is not set +# CONFIG_THUNDERBOLT is not set +# CONFIG_TICK_CPU_ACCOUNTING is not set +CONFIG_TICK_ONESHOT=y +# CONFIG_TIFM_CORE is not set +# CONFIG_TIGON3 is not set +# CONFIG_TIMB_DMA is not set +CONFIG_TIMERFD=y +# CONFIG_TIMER_STATS is not set +CONFIG_TINY_RCU=y +# CONFIG_TIPC is not set +# CONFIG_TI_ADC081C is not set +# CONFIG_TI_ADC128S052 is not set +# CONFIG_TI_AM335X_ADC is not set +# CONFIG_TI_CPSW is not set +# CONFIG_TI_CPSW_ALE is not set +# CONFIG_TI_CPTS is not set +# CONFIG_TI_DAC7512 is not set +# CONFIG_TI_DAVINCI_CPDMA is not set +# CONFIG_TI_DAVINCI_MDIO is not set +# CONFIG_TI_ST is not set +# CONFIG_TLAN is not set +# CONFIG_TMD_HERMES is not set +# CONFIG_TMP006 is not set +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +CONFIG_TMPFS_XATTR=y +# CONFIG_TOPSTAR_LAPTOP is not set +# CONFIG_TORTURE_TEST is not set +# CONFIG_TOSHIBA_HAPS is not set +# CONFIG_TOUCHSCREEN_AD7877 is not set +# CONFIG_TOUCHSCREEN_AD7879 is not set +# CONFIG_TOUCHSCREEN_AD7879_I2C is not set +# CONFIG_TOUCHSCREEN_AD7879_SPI is not set +# CONFIG_TOUCHSCREEN_ADS7846 is not set +# CONFIG_TOUCHSCREEN_AR1021_I2C is not set +# CONFIG_TOUCHSCREEN_ATMEL_MXT is not set +# CONFIG_TOUCHSCREEN_AUO_PIXCIR is not set +# CONFIG_TOUCHSCREEN_BU21013 is not set +# CONFIG_TOUCHSCREEN_CHIPONE_ICN8318 is not set +# CONFIG_TOUCHSCREEN_CLEARPAD_TM1217 is not set +# CONFIG_TOUCHSCREEN_CY8CTMG110 is not set +# CONFIG_TOUCHSCREEN_CYTTSP_CORE is not set +# CONFIG_TOUCHSCREEN_CYTTSP4_CORE is not set +# CONFIG_TOUCHSCREEN_DYNAPRO is not set +# CONFIG_TOUCHSCREEN_EDT_FT5X06 is not set +# CONFIG_TOUCHSCREEN_EETI is not set +# CONFIG_TOUCHSCREEN_EGALAX is not set +# CONFIG_TOUCHSCREEN_ELAN is not set +# CONFIG_TOUCHSCREEN_ELO is not set +# CONFIG_TOUCHSCREEN_FUJITSU is not set +# CONFIG_TOUCHSCREEN_GOODIX is not set +# CONFIG_TOUCHSCREEN_GUNZE is not set +# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set +# CONFIG_TOUCHSCREEN_ILI210X is not set +# CONFIG_TOUCHSCREEN_INEXIO is not set +# CONFIG_TOUCHSCREEN_MAX11801 is not set +# CONFIG_TOUCHSCREEN_MCS5000 is not set +# CONFIG_TOUCHSCREEN_MK712 is not set +# CONFIG_TOUCHSCREEN_MMS114 is not set +# CONFIG_TOUCHSCREEN_MTOUCH is not set +# CONFIG_TOUCHSCREEN_PENMOUNT is not set +# CONFIG_TOUCHSCREEN_PIXCIR is not set +# CONFIG_TOUCHSCREEN_S3C2410 is not set +# CONFIG_TOUCHSCREEN_ST1232 is not set +# CONFIG_TOUCHSCREEN_SUR40 is not set +# CONFIG_TOUCHSCREEN_SX8654 is not set +# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4 is not set +# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set +# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set +# CONFIG_TOUCHSCREEN_TOUCHWIN is not set +# CONFIG_TOUCHSCREEN_TPS6507X is not set +# CONFIG_TOUCHSCREEN_TSC2005 is not set +# CONFIG_TOUCHSCREEN_TSC2007 is not set +# CONFIG_TOUCHSCREEN_TSC_SERIO is not set +# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set +# CONFIG_TOUCHSCREEN_W90X900 is not set +# CONFIG_TOUCHSCREEN_WACOM_I2C is not set +# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set +# CONFIG_TOUCHSCREEN_WM97XX is not set +# CONFIG_TOUCHSCREEN_ZFORCE is not set +# CONFIG_TPS6105X is not set +# CONFIG_TPS65010 is not set +# CONFIG_TPS6507X is not set +# CONFIG_TR is not set +# CONFIG_TRACE_ENUM_MAP_FILE is not set +# CONFIG_TRACEPOINT_BENCHMARK is not set +# CONFIG_TRACER_SNAPSHOT is not set +# CONFIG_TRACER_SNAPSHOT_PER_CPU_SWAP is not set +# CONFIG_TRACE_BRANCH_PROFILING is not set +# CONFIG_TRACE_ENUM_MAP_FILE is not set +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +# CONFIG_TRACE_SINK is not set +CONFIG_TRACING_SUPPORT=y +CONFIG_TRAD_SIGNALS=y +# CONFIG_TRANSPARENT_HUGEPAGE is not set +# CONFIG_TRANZPORT is not set +# CONFIG_TREE_PREEMPT_RCU is not set +# CONFIG_TREE_RCU is not set +# CONFIG_TREE_RCU_TRACE is not set +# CONFIG_TSL2583 is not set +# CONFIG_TSL2x7x is not set +# CONFIG_TSL4531 is not set +CONFIG_TTY=y +# CONFIG_TTY_PRINTK is not set +# CONFIG_TUN is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_TWL6030_GPADC is not set +# CONFIG_TWL6040_CORE is not set +# CONFIG_TYPHOON is not set +# CONFIG_UACCESS_WITH_MEMCPY is not set +# CONFIG_UCB1400_CORE is not set +# CONFIG_UDF_FS is not set +CONFIG_UDF_NLS=y +CONFIG_UEVENT_HELPER=y +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +# CONFIG_UFS_FS is not set +# CONFIG_UHID is not set +CONFIG_UIDGID_STRICT_TYPE_CHECKS=y +# CONFIG_UIO is not set +# CONFIG_ULTRA is not set +# CONFIG_ULTRIX_PARTITION is not set +CONFIG_UNIX=y +CONFIG_UNIX98_PTYS=y +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_UNIX_DIAG is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_UPROBE_EVENT is not set +# CONFIG_UPROBES is not set +# CONFIG_USB is not set +# CONFIG_USBIP_CORE is not set +# CONFIG_USBPCWATCHDOG is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_ADUTUX is not set +CONFIG_USB_ALI_M5632=y +# CONFIG_USB_AMD5536UDC is not set +CONFIG_USB_AN2720=y +# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set +# CONFIG_USB_APPLEDISPLAY is not set +CONFIG_USB_ARCH_HAS_EHCI=y +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +CONFIG_USB_ARMLINUX=y +# CONFIG_USB_ATM is not set +# CONFIG_USB_BDC_UDC is not set +CONFIG_USB_BELKIN=y +# CONFIG_USB_BTMTK is not set +# CONFIG_USB_C67X00_HCD is not set +# CONFIG_USB_CATC is not set +# CONFIG_USB_CDC_COMPOSITE is not set +# CONFIG_USB_CHAOSKEY is not set +# CONFIG_USB_CHIPIDEA is not set +# CONFIG_USB_CONFIGFS is not set +# CONFIG_USB_CXACRU is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_DEBUG is not set +CONFIG_USB_DEFAULT_PERSIST=y +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_DEVICE_CLASS is not set +# CONFIG_USB_DSBR is not set +# CONFIG_USB_DUMMY_HCD is not set +# CONFIG_USB_DWC2 is not set +# CONFIG_USB_DWC2_DUAL_ROLE is not set +# CONFIG_USB_DWC2_HOST is not set +# CONFIG_USB_DWC2_PERIPHERAL is not set +# CONFIG_USB_DWC3 is not set +# CONFIG_USB_DWC3_EXYNOS is not set +# CONFIG_USB_DWC3_QCOM is not set +# CONFIG_USB_DWC3_PCI is not set +# CONFIG_USB_DWC3_KEYSTONE is not set +# CONFIG_USB_DWC_OTG_LPM is not set +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_EG20T is not set +# CONFIG_USB_EHCI_HCD_AT91 is not set +# CONFIG_USB_EHCI_HCD_PPC_OF is not set +# CONFIG_USB_EHCI_MSM is not set +# CONFIG_USB_EHCI_MV is not set +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_TT_NEWSCHED=y +# CONFIG_USB_EHSET_TEST_FIXTURE is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_ENESTORAGE is not set +# CONFIG_USB_EPSON2888 is not set +# CONFIG_USB_ET61X251 is not set +CONFIG_USB_EZUSB=y +# CONFIG_USB_EZUSB_FX2 is not set +# CONFIG_USB_FILE_STORAGE is not set +# CONFIG_USB_FOTG210_HCD is not set +# CONFIG_USB_FOTG210_UDC is not set +# CONFIG_USB_FSL_USB2 is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_FUNCTIONFS is not set +# CONFIG_USB_FUSB300 is not set +# CONFIG_USB_FUSBH200_HCD is not set +# CONFIG_USB_GADGET is not set +# CONFIG_USB_GADGETFS is not set +# CONFIG_USB_GADGET_DEBUG is not set +# CONFIG_USB_GADGET_DEBUG_FILES is not set +# CONFIG_USB_GADGET_DEBUG_FS is not set +CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2 +CONFIG_USB_GADGET_VBUS_DRAW=2 +# CONFIG_USB_GADGET_XILINX is not set +# CONFIG_USB_GL860 is not set +# CONFIG_USB_GOKU is not set +# CONFIG_USB_GPIO_VBUS is not set +# CONFIG_USB_GR_UDC is not set +# CONFIG_USB_GSPCA is not set +# CONFIG_USB_GSPCA_BENQ is not set +# CONFIG_USB_GSPCA_CONEX is not set +# CONFIG_USB_GSPCA_CPIA1 is not set +# CONFIG_USB_GSPCA_DTCS033 is not set +# CONFIG_USB_GSPCA_ETOMS is not set +# CONFIG_USB_GSPCA_FINEPIX is not set +# CONFIG_USB_GSPCA_JEILINJ is not set +# CONFIG_USB_GSPCA_JL2005BCD is not set +# CONFIG_USB_GSPCA_KINECT is not set +# CONFIG_USB_GSPCA_KONICA is not set +# CONFIG_USB_GSPCA_MARS is not set +# CONFIG_USB_GSPCA_MR97310A is not set +# CONFIG_USB_GSPCA_NW80X is not set +# CONFIG_USB_GSPCA_OV519 is not set +# CONFIG_USB_GSPCA_OV534 is not set +# CONFIG_USB_GSPCA_OV534_9 is not set +# CONFIG_USB_GSPCA_PAC207 is not set +# CONFIG_USB_GSPCA_PAC7302 is not set +# CONFIG_USB_GSPCA_PAC7311 is not set +# CONFIG_USB_GSPCA_SE401 is not set +# CONFIG_USB_GSPCA_SN9C2028 is not set +# CONFIG_USB_GSPCA_SN9C20X is not set +# CONFIG_USB_GSPCA_SONIXB is not set +# CONFIG_USB_GSPCA_SONIXJ is not set +# CONFIG_USB_GSPCA_SPCA1528 is not set +# CONFIG_USB_GSPCA_SPCA500 is not set +# CONFIG_USB_GSPCA_SPCA501 is not set +# CONFIG_USB_GSPCA_SPCA505 is not set +# CONFIG_USB_GSPCA_SPCA506 is not set +# CONFIG_USB_GSPCA_SPCA508 is not set +# CONFIG_USB_GSPCA_SPCA561 is not set +# CONFIG_USB_GSPCA_SQ905 is not set +# CONFIG_USB_GSPCA_SQ905C is not set +# CONFIG_USB_GSPCA_SQ930X is not set +# CONFIG_USB_GSPCA_STK014 is not set +# CONFIG_USB_GSPCA_STK1135 is not set +# CONFIG_USB_GSPCA_STV0680 is not set +# CONFIG_USB_GSPCA_SUNPLUS is not set +# CONFIG_USB_GSPCA_T613 is not set +# CONFIG_USB_GSPCA_TOPRO is not set +# CONFIG_USB_GSPCA_TOUPTEK is not set +# CONFIG_USB_GSPCA_TV8532 is not set +# CONFIG_USB_GSPCA_VC032X is not set +# CONFIG_USB_GSPCA_VICAM is not set +# CONFIG_USB_GSPCA_XIRLINK_CIT is not set +# CONFIG_USB_GSPCA_ZC3XX is not set +# CONFIG_USB_G_ACM_MS is not set +# CONFIG_USB_G_DBGP is not set +# CONFIG_USB_G_HID is not set +# CONFIG_USB_G_MULTI is not set +# CONFIG_USB_G_NCM is not set +# CONFIG_USB_G_NOKIA is not set +# CONFIG_USB_G_PRINTER is not set +# CONFIG_USB_G_SERIAL is not set +# CONFIG_USB_G_WEBCAM is not set +# CONFIG_USB_HCD_TEST_MODE is not set +# CONFIG_USB_HID is not set +# CONFIG_USB_HIDDEV is not set +# CONFIG_USB_HSIC_USB3503 is not set +# CONFIG_USB_HSO is not set +# CONFIG_USB_HWA_HCD is not set +# CONFIG_USB_IBMCAM is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_INPUT_IMS_PCU is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_IPHETH is not set +# CONFIG_USB_IP_COMMON is not set +# CONFIG_USB_ISIGHTFW is not set +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_ISP1301 is not set +# CONFIG_USB_ISP1362_HCD is not set +# CONFIG_USB_ISP1760 is not set +# CONFIG_USB_ISP1760_HCD is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_KBD is not set +# CONFIG_USB_KC2190 is not set +# CONFIG_USB_KONICAWC is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_LED_TRIG is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LIBUSUAL is not set +# CONFIG_USB_LINK_LAYER_TEST is not set +# CONFIG_USB_M5602 is not set +# CONFIG_USB_M66592 is not set +# CONFIG_USB_MASS_STORAGE is not set +# CONFIG_USB_MAX3421_HCD is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_MIDI_GADGET is not set +# CONFIG_USB_MON is not set +# CONFIG_USB_MOUSE is not set +# CONFIG_USB_MSM_OTG is not set +# CONFIG_USB_MUSB_HDRC is not set +# CONFIG_USB_MV_U3D is not set +# CONFIG_USB_MV_UDC is not set +# CONFIG_USB_NET2272 is not set +# CONFIG_USB_NET2280 is not set +# CONFIG_USB_NET_AX88179_178A is not set +# CONFIG_USB_NET_AX8817X is not set +# CONFIG_USB_NET_CDCETHER is not set +# CONFIG_USB_NET_CDC_EEM is not set +# CONFIG_USB_NET_CDC_MBIM is not set +# CONFIG_USB_NET_CDC_NCM is not set +# CONFIG_USB_NET_CDC_SUBSET is not set +# CONFIG_USB_NET_CX82310_ETH is not set +# CONFIG_USB_NET_DM9601 is not set +# CONFIG_USB_NET_DRIVERS is not set +# CONFIG_USB_NET_GL620A is not set +# CONFIG_USB_NET_HUAWEI_CDC_NCM is not set +# CONFIG_USB_NET_INT51X1 is not set +# CONFIG_USB_NET_KALMIA is not set +# CONFIG_USB_NET_MCS7830 is not set +# CONFIG_USB_NET_NET1080 is not set +# CONFIG_USB_NET_PLUSB is not set +# CONFIG_USB_NET_QMI_WWAN is not set +# CONFIG_USB_NET_RNDIS_HOST is not set +# CONFIG_USB_NET_RNDIS_WLAN is not set +# CONFIG_USB_NET_SMSC75XX is not set +# CONFIG_USB_NET_SMSC95XX is not set +# CONFIG_USB_NET_SR9700 is not set +# CONFIG_USB_NET_SR9800 is not set +# CONFIG_USB_NET_ZAURUS is not set +# CONFIG_USB_OHCI_HCD is not set +# CONFIG_USB_OHCI_HCD_PCI is not set +# CONFIG_USB_OHCI_HCD_PPC_OF is not set +# CONFIG_USB_OHCI_HCD_PPC_OF_BE is not set +# CONFIG_USB_OHCI_HCD_PPC_OF_LE is not set +# CONFIG_USB_OHCI_HCD_PPC_SOC is not set +# CONFIG_USB_OHCI_HCD_SSB is not set +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +# CONFIG_USB_OTG is not set +# CONFIG_USB_OTG_BLACKLIST_HUB is not set +# CONFIG_USB_OTG_FSM is not set +# CONFIG_USB_OTG_WHITELIST is not set +# CONFIG_USB_OXU210HP_HCD is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_PHY is not set +# CONFIG_USB_PRINTER is not set +# CONFIG_USB_PWC_INPUT_EVDEV is not set +# CONFIG_USB_PXA27X is not set +# CONFIG_USB_R8A66597 is not set +# CONFIG_USB_R8A66597_HCD is not set +# CONFIG_USB_RCAR_PHY is not set +# CONFIG_USB_RENESAS_USBHS is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_RTL8152 is not set +# CONFIG_USB_S2255 is not set +# CONFIG_USB_S3C_HSOTG is not set +# CONFIG_USB_SE401 is not set +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_SERIAL_AIRCABLE is not set +# CONFIG_USB_SERIAL_ARK3116 is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_CH341 is not set +# CONFIG_USB_SERIAL_CP210X is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_CYPRESS_M8 is not set +# CONFIG_USB_SERIAL_DEBUG is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_EDGEPORT_TI is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_F81232 is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_FUNSOFT is not set +# CONFIG_USB_SERIAL_GARMIN is not set +CONFIG_USB_SERIAL_GENERIC=y +# CONFIG_USB_SERIAL_HP4X is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IPW is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_IUU is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +CONFIG_USB_SERIAL_KEYSPAN_MPR=y +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +CONFIG_USB_SERIAL_KEYSPAN_USA18X=y +CONFIG_USB_SERIAL_KEYSPAN_USA19=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y +CONFIG_USB_SERIAL_KEYSPAN_USA19W=y +CONFIG_USB_SERIAL_KEYSPAN_USA28=y +CONFIG_USB_SERIAL_KEYSPAN_USA28X=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y +CONFIG_USB_SERIAL_KEYSPAN_USA49W=y +CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y +# CONFIG_USB_SERIAL_KLSI is not set +# CONFIG_USB_SERIAL_KOBIL_SCT is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_METRO is not set +# CONFIG_USB_SERIAL_MOS7715_PARPORT is not set +# CONFIG_USB_SERIAL_MOS7720 is not set +# CONFIG_USB_SERIAL_MOS7840 is not set +# CONFIG_USB_SERIAL_MOTOROLA is not set +# CONFIG_USB_SERIAL_MXUPORT is not set +# CONFIG_USB_SERIAL_NAVMAN is not set +# CONFIG_USB_SERIAL_OMNINET is not set +# CONFIG_USB_SERIAL_OPTICON is not set +# CONFIG_USB_SERIAL_OPTION is not set +# CONFIG_USB_SERIAL_OTI6858 is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_QCAUX is not set +# CONFIG_USB_SERIAL_QT2 is not set +# CONFIG_USB_SERIAL_QUALCOMM is not set +# CONFIG_USB_SERIAL_QUATECH2 is not set +# CONFIG_USB_SERIAL_QUATECH_USB2 is not set +# CONFIG_USB_SERIAL_SAFE is not set +CONFIG_USB_SERIAL_SAFE_PADDED=y +# CONFIG_USB_SERIAL_SIEMENS_MPI is not set +# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set +# CONFIG_USB_SERIAL_SIMPLE is not set +# CONFIG_USB_SERIAL_SPCP8X5 is not set +# CONFIG_USB_SERIAL_SSU100 is not set +# CONFIG_USB_SERIAL_SYMBOL is not set +# CONFIG_USB_SERIAL_TI is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_VIVOPAY_SERIAL is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_WISHBONE is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_XSENS_MT is not set +# CONFIG_USB_SERIAL_ZIO is not set +# CONFIG_USB_SERIAL_ZTE is not set +# CONFIG_USB_SEVSEG is not set +# CONFIG_USB_SIERRA_NET is not set +# CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_SN9C102 is not set +# CONFIG_USB_SPEEDTOUCH is not set +# CONFIG_USB_STKWEBCAM is not set +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_STORAGE_ALAUDA is not set +# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_ENE_UB6250 is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_KARMA is not set +# CONFIG_USB_STORAGE_ONETOUCH is not set +# CONFIG_USB_STORAGE_REALTEK is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_USBAT is not set +# CONFIG_USB_STV06XX is not set +# CONFIG_USB_SUPPORT is not set +# CONFIG_USB_SUSPEND is not set +# CONFIG_USB_SWITCH_FSA9480 is not set +# CONFIG_USB_TEST is not set +# CONFIG_USB_TMC is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_UAS is not set +# CONFIG_USB_UEAGLEATM is not set +# CONFIG_USB_ULPI is not set +# CONFIG_USB_USBNET is not set +# CONFIG_USB_USS720 is not set +# CONFIG_USB_VIDEO_CLASS is not set +CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y +# CONFIG_USB_VL600 is not set +# CONFIG_USB_WDM is not set +# CONFIG_USB_WHCI_HCD is not set +# CONFIG_USB_WPAN_HCD is not set +# CONFIG_USB_WUSB is not set +# CONFIG_USB_WUSB_CBAF is not set +# CONFIG_USB_XHCI_HCD is not set +# CONFIG_USB_XUSBATM is not set +# CONFIG_USB_YUREX is not set +# CONFIG_USB_ZD1201 is not set +# CONFIG_USB_ZERO is not set +# CONFIG_USB_ZR364XX is not set +# CONFIG_USELIB is not set +# CONFIG_USE_GENERIC_SMP_HELPERS is not set +# CONFIG_USE_OF is not set +# CONFIG_UTS_NS is not set +# CONFIG_UWB is not set +# CONFIG_V4L_MEM2MEM_DRIVERS is not set +# CONFIG_V4L_TEST_DRIVERS is not set +# CONFIG_VCNL4000 is not set +# CONFIG_VDSO is not set +# CONFIG_VETH is not set +# CONFIG_VEXPRESS_CONFIG is not set +# CONFIG_VF610_ADC is not set +# CONFIG_VFAT_FS is not set +# CONFIG_VGASTATE is not set +# CONFIG_VGA_ARB is not set +# CONFIG_VGA_SWITCHEROO is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_VIA_VELOCITY is not set +# CONFIG_VIDEO_ADV7170 is not set +# CONFIG_VIDEO_ADV7175 is not set +# CONFIG_VIDEO_ADV7180 is not set +# CONFIG_VIDEO_ADV7183 is not set +# CONFIG_VIDEO_ADV7343 is not set +# CONFIG_VIDEO_ADV7393 is not set +# CONFIG_VIDEO_ADV_DEBUG is not set +# CONFIG_VIDEO_AK881X is not set +# CONFIG_VIDEO_BT819 is not set +# CONFIG_VIDEO_BT848 is not set +# CONFIG_VIDEO_BT856 is not set +# CONFIG_VIDEO_BT866 is not set +# CONFIG_VIDEO_BWQCAM is not set +# CONFIG_VIDEO_CAFE_CCIC is not set +# CONFIG_VIDEO_CAPTURE_DRIVERS is not set +# CONFIG_VIDEO_CPIA is not set +# CONFIG_VIDEO_CQCAM is not set +# CONFIG_VIDEO_CS5345 is not set +# CONFIG_VIDEO_CS53L32A is not set +# CONFIG_VIDEO_CX231XX is not set +# CONFIG_VIDEO_CX2341X is not set +# CONFIG_VIDEO_CX25840 is not set +# CONFIG_VIDEO_CX88 is not set +# CONFIG_VIDEO_DEV is not set +# CONFIG_VIDEO_DM6446_CCDC is not set +# CONFIG_VIDEO_DT3155 is not set +# CONFIG_VIDEO_EM28XX is not set +# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set +# CONFIG_VIDEO_GO7007 is not set +# CONFIG_VIDEO_HDPVR is not set +# CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set +# CONFIG_VIDEO_HEXIUM_GEMINI is not set +# CONFIG_VIDEO_HEXIUM_ORION is not set +# CONFIG_VIDEO_IR_I2C is not set +# CONFIG_VIDEO_IVTV is not set +# CONFIG_VIDEO_KS0127 is not set +# CONFIG_VIDEO_M52790 is not set +# CONFIG_VIDEO_MEDIA is not set +# CONFIG_VIDEO_MEM2MEM_TESTDEV is not set +# CONFIG_VIDEO_ML86V7667 is not set +# CONFIG_VIDEO_MSP3400 is not set +# CONFIG_VIDEO_MT9V011 is not set +# CONFIG_VIDEO_MXB is not set +# CONFIG_VIDEO_NOON010PC30 is not set +# CONFIG_VIDEO_OMAP2_VOUT is not set +# CONFIG_VIDEO_OUTPUT_CONTROL is not set +# CONFIG_VIDEO_OV2659 is not set +# CONFIG_VIDEO_OV7640 is not set +# CONFIG_VIDEO_OV7670 is not set +# CONFIG_VIDEO_PMS is not set +# CONFIG_VIDEO_PVRUSB2 is not set +# CONFIG_VIDEO_SAA6588 is not set +# CONFIG_VIDEO_SAA6752HS is not set +# CONFIG_VIDEO_SAA7110 is not set +# CONFIG_VIDEO_SAA711X is not set +# CONFIG_VIDEO_SAA7127 is not set +# CONFIG_VIDEO_SAA7134 is not set +# CONFIG_VIDEO_SAA717X is not set +# CONFIG_VIDEO_SAA7185 is not set +# CONFIG_VIDEO_SAA7191 is not set +# CONFIG_VIDEO_SH_MOBILE_CEU is not set +# CONFIG_VIDEO_SONY_BTF_MPX is not set +# CONFIG_VIDEO_SR030PC30 is not set +# CONFIG_VIDEO_TCM825X is not set +# CONFIG_VIDEO_TDA7432 is not set +# CONFIG_VIDEO_TDA9840 is not set +# CONFIG_VIDEO_TEA6415C is not set +# CONFIG_VIDEO_TEA6420 is not set +# CONFIG_VIDEO_THS7303 is not set +# CONFIG_VIDEO_THS8200 is not set +# CONFIG_VIDEO_TIMBERDALE is not set +# CONFIG_VIDEO_TLV320AIC23B is not set +# CONFIG_VIDEO_TM6000 is not set +# CONFIG_VIDEO_TVAUDIO is not set +# CONFIG_VIDEO_TVP514X is not set +# CONFIG_VIDEO_TVP5150 is not set +# CONFIG_VIDEO_TVP7002 is not set +# CONFIG_VIDEO_TW2804 is not set +# CONFIG_VIDEO_TW9903 is not set +# CONFIG_VIDEO_TW9906 is not set +# CONFIG_VIDEO_UDA1342 is not set +# CONFIG_VIDEO_UPD64031A is not set +# CONFIG_VIDEO_UPD64083 is not set +# CONFIG_VIDEO_USBTV is not set +# CONFIG_VIDEO_USBVISION is not set +# CONFIG_VIDEO_V4L2 is not set +# CONFIG_VIDEO_V4L2_COMMON is not set +# CONFIG_VIDEO_V4L2_INT_DEVICE is not set +# CONFIG_VIDEO_VIVI is not set +# CONFIG_VIDEO_VP27SMPX is not set +# CONFIG_VIDEO_VPX3220 is not set +# CONFIG_VIDEO_VS6624 is not set +# CONFIG_VIDEO_WM8739 is not set +# CONFIG_VIDEO_WM8775 is not set +# CONFIG_VIDEO_ZORAN is not set +# CONFIG_VIRQ_DEBUG is not set +# CONFIG_VIRTIO_BALLOON is not set +# CONFIG_VIRTIO_INPUT is not set +# CONFIG_VIRTIO_MMIO is not set +# CONFIG_VIRTIO_PCI is not set +# CONFIG_VIRTUALIZATION is not set +# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set +# CONFIG_VIRT_DRIVERS is not set +CONFIG_VIRT_TO_BUS=y +# CONFIG_VITESSE_PHY is not set +CONFIG_VLAN_8021Q=y +# CONFIG_VLAN_8021Q_GVRP is not set +# CONFIG_VLAN_8021Q_MVRP is not set +# CONFIG_VME_BUS is not set +# CONFIG_VMSPLIT_1G is not set +# CONFIG_VMSPLIT_2G is not set +# CONFIG_VMSPLIT_2G_OPT is not set +CONFIG_VMSPLIT_3G=y +# CONFIG_VMSPLIT_3G_OPT is not set +# CONFIG_VMWARE_PVSCSI is not set +# CONFIG_VMXNET3 is not set +# CONFIG_VM_EVENT_COUNTERS is not set +# CONFIG_VORTEX is not set +# CONFIG_VSOCKETS is not set +# CONFIG_VT is not set +# CONFIG_VT6655 is not set +# CONFIG_VT6656 is not set +# CONFIG_VXFS_FS is not set +# CONFIG_VXGE is not set +# CONFIG_VXLAN is not set +# CONFIG_W1 is not set +# CONFIG_W1_CON is not set +# CONFIG_W1_MASTER_DS1WM is not set +# CONFIG_W1_MASTER_DS2482 is not set +# CONFIG_W1_MASTER_DS2490 is not set +# CONFIG_W1_MASTER_GPIO is not set +# CONFIG_W1_MASTER_MATROX is not set +# CONFIG_W1_SLAVE_BQ27000 is not set +# CONFIG_W1_SLAVE_DS2406 is not set +# CONFIG_W1_SLAVE_DS2408 is not set +# CONFIG_W1_SLAVE_DS2413 is not set +# CONFIG_W1_SLAVE_DS2423 is not set +# CONFIG_W1_SLAVE_DS2431 is not set +# CONFIG_W1_SLAVE_DS2433 is not set +# CONFIG_W1_SLAVE_DS2760 is not set +# CONFIG_W1_SLAVE_DS2780 is not set +# CONFIG_W1_SLAVE_DS2781 is not set +# CONFIG_W1_SLAVE_DS28E04 is not set +# CONFIG_W1_SLAVE_SMEM is not set +# CONFIG_W1_SLAVE_THERM is not set +# CONFIG_W35UND is not set +# CONFIG_W83627HF_WDT is not set +# CONFIG_W83697HF_WDT is not set +# CONFIG_W83877F_WDT is not set +# CONFIG_W83977F_WDT is not set +# CONFIG_WAN is not set +# CONFIG_WANXL is not set +# CONFIG_WAN_ROUTER is not set +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_CORE is not set +# CONFIG_WATCHDOG_NOWAYOUT is not set +# CONFIG_WD80x3 is not set +# CONFIG_WDTPCI is not set +CONFIG_WEXT_CORE=y +CONFIG_WEXT_PRIV=y +CONFIG_WEXT_PROC=y +CONFIG_WEXT_SPY=y +CONFIG_WILINK_PLATFORM_DATA=y +# CONFIG_WIMAX is not set +# CONFIG_WIMAX_GDM72XX is not set +CONFIG_WIRELESS=y +CONFIG_WIRELESS_EXT=y +# CONFIG_WIRELESS_EXT_SYSFS is not set +# CONFIG_WL1251 is not set +# CONFIG_WL12XX is not set +# CONFIG_WL18XX is not set +# CONFIG_WLAGS49_H2 is not set +# CONFIG_WLAGS49_H25 is not set +CONFIG_WLAN=y +# CONFIG_WLCORE is not set +CONFIG_WL_TI=y +CONFIG_WQ_POWER_EFFICIENT_DEFAULT=y +# CONFIG_WR_PPMC is not set +# CONFIG_X25 is not set +# CONFIG_X86_DEBUG_STATIC_CPU_HAS is not set +# CONFIG_X86_PKG_TEMP_THERMAL is not set +CONFIG_X86_SYSFB=y +# CONFIG_XEN is not set +CONFIG_XFRM=y +# CONFIG_XFRM_IPCOMP is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_USER is not set +# CONFIG_XFS_DEBUG is not set +# CONFIG_XFS_FS is not set +# CONFIG_XFS_POSIX_ACL is not set +# CONFIG_XFS_QUOTA is not set +# CONFIG_XFS_RT is not set +# CONFIG_XFS_WARN is not set +# CONFIG_XILINX_AXI_EMAC is not set +# CONFIG_XILINX_EMACLITE is not set +# CONFIG_XILINX_LL_TEMAC is not set +# CONFIG_XILINX_WATCHDOG is not set +# CONFIG_XILLYBUS is not set +# CONFIG_XIP_KERNEL is not set +# CONFIG_XMON is not set +# CONFIG_XVMALLOC is not set +CONFIG_XZ_DEC=y +# CONFIG_XZ_DEC_ARM is not set +# CONFIG_XZ_DEC_ARMTHUMB is not set +# CONFIG_XZ_DEC_BCJ is not set +# CONFIG_XZ_DEC_IA64 is not set +# CONFIG_XZ_DEC_POWERPC is not set +# CONFIG_XZ_DEC_SPARC is not set +# CONFIG_XZ_DEC_TEST is not set +# CONFIG_XZ_DEC_X86 is not set +# CONFIG_YAFFS_DISABLE_BAD_BLOCK_MARKING is not set +# CONFIG_YAFFS_FS is not set +# CONFIG_YAM is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_YENTA is not set +# CONFIG_YENTA_O2 is not set +# CONFIG_YENTA_RICOH is not set +# CONFIG_YENTA_TI is not set +# CONFIG_YENTA_TOSHIBA is not set +# CONFIG_ZBUD is not set +# CONFIG_ZD1211RW is not set +# CONFIG_ZD1211RW_DEBUG is not set +# CONFIG_ZEROPLUS_FF is not set +# CONFIG_ZISOFS is not set +# CONFIG_ZLIB_DEFLATE is not set +# CONFIG_ZLIB_INFLATE is not set +# CONFIG_ZNET is not set +# CONFIG_ZPOOL is not set +CONFIG_ZONE_DMA=y +CONFIG_ZONE_DMA_FLAG=1 +# CONFIG_ZRAM is not set +# CONFIG_ZSMALLOC is not set diff --git a/target/linux/generic/files/Documentation/networking/adm6996.txt b/target/linux/generic/files/Documentation/networking/adm6996.txt new file mode 100644 index 0000000..ab59f1d --- /dev/null +++ b/target/linux/generic/files/Documentation/networking/adm6996.txt @@ -0,0 +1,110 @@ +------- + +ADM6996FC / ADM6996M switch chip driver + + +1. General information + + This driver supports the FC and M models only. The ADM6996F and L are + completely different chips. + + Support for the FC model is extremely limited at the moment. There is no VLAN + support as of yet. The driver will not offer an swconfig interface for the FC + chip. + +1.1 VLAN IDs + + It is possible to define 16 different VLANs. Every VLAN has an identifier, its + VLAN ID. It is easiest if you use at most VLAN IDs 0-15. In that case, the + swconfig based configuration is very straightforward. To define two VLANs with + IDs 4 and 5, you can invoke, for example: + + # swconfig dev ethX vlan 4 set ports '0 1t 2 5t' + # swconfig dev ethX vlan 5 set ports '0t 1t 5t' + + The swconfig framework will automatically invoke 'port Y set pvid Z' for every + port that is an untagged member of VLAN Y, setting its Primary VLAN ID. In + this example, ports 0 and 2 would get "pvid 4". The Primary VLAN ID of a port + is the VLAN ID associated with untagged packets coming in on that port. + + But if you wish to use VLAN IDs outside the range 0-15, this automatic + behaviour of the swconfig framework becomes a problem. The 16 VLANs that + swconfig can configure on the ADM6996 also have a "vid" setting. By default, + this is the same as the number of the VLAN entry, to make the simple behaviour + above possible. To still support a VLAN with a VLAN ID higher than 15 + (presumably because you are in a network where such VLAN IDs are already in + use), you can change the "vid" setting of the VLAN to anything in the range + 0-1023. But suppose you did the following: + + # swconfig dev ethX vlan 0 set vid 998 + # swconfig dev ethX vlan 0 set ports '0 2 5t' + + Now the swconfig framework will issue 'port 0 set pvid 0' and 'port 2 set pvid + 0'. But the "pvid" should be set to 998, so you are responsible for manually + fixing this! + +1.2 VLAN filtering + + The switch is configured to apply source port filtering. This means that + packets are only accepted when the port the packets came in on is a member of + the VLAN the packet should go to. + + Only membership of a VLAN is tested, it does not matter whether it is a tagged + or untagged membership. + + For untagged packets, the destination VLAN is the Primary VLAN ID of the + incoming port. So if the PVID of a port is 0, but that port is not a member of + the VLAN with ID 0, this means that untagged packets on that port are dropped. + This can be used as a roundabout way of dropping untagged packets from a port, + a mode often referred to as "Admit only tagged packets". + +1.3 Reset + + The two supported chip models do not have a sofware-initiated reset. When the + driver is initialised, as well as when the 'reset' swconfig option is invoked, + the driver will set those registers it knows about and supports to the correct + default value. But there are a lot of registers in the chip that the driver + does not support. If something changed those registers, invoking 'reset' or + performing a warm reboot might still leave the chip in a "broken" state. Only + a hardware reset will bring it back in the default state. + +2. Technical details on PHYs and the ADM6996 + + From the viewpoint of the Linux kernel, it is common that an Ethernet adapter + can be seen as a separate MAC entity and a separate PHY entity. The PHY entity + can be queried and set through registers accessible via an MDIO bus. A PHY + normally has a single address on that bus, in the range 0 through 31. + + The ADM6996 has special-purpose registers in the range of PHYs 0 through 10. + Even though all these registers control a single ADM6996 chip, the Linux + kernel treats this as 11 separate PHYs. The driver will bind to these + addresses to prevent a different PHY driver from binding and corrupting these + registers. + + What Linux sees as the PHY on address 0 is meant for the Ethernet MAC + connected to the CPU port of the ADM6996 switch chip (port 5). This is the + Ethernet MAC you will use to send and receive data through the switch. + + The PHYs at addresses 16 through 20 map to the PHYs on ports 0 through 4 of + the switch chip. These can be accessed with the Generic PHY driver, as the + registers have the common layout. + + If a second Ethernet MAC on your board is wired to the port 4 PHY, that MAC + needs to bind to PHY address 20 for the port to work correctly. + + The ADM6996 switch driver will reset the ports 0 through 3 on startup and when + 'reset' is invoked. This could clash with a different PHY driver if the kernel + binds a PHY driver to address 16 through 19. + + If Linux binds a PHY on addresses 1 through 10 to an Ethernet MAC, the ADM6996 + driver will simply always report a connected 100 Mbit/s full-duplex link for + that PHY, and provide no other functionality. This is most likely not what you + want. So if you see a message in your log + + ethX: PHY overlaps ADM6996, providing fixed PHY yy. + + This is most likely an indication that ethX will not work properly, and your + kernel needs to be configured to attach a different PHY to that Ethernet MAC. + + Controlling the mapping between MACs and PHYs is usually done in platform- or + board-specific fixup code. The ADM6996 driver has no influence over this. diff --git a/target/linux/generic/files/arch/mips/fw/myloader/Makefile b/target/linux/generic/files/arch/mips/fw/myloader/Makefile new file mode 100644 index 0000000..34acfd0 --- /dev/null +++ b/target/linux/generic/files/arch/mips/fw/myloader/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for the Compex's MyLoader support on MIPS architecture +# + +lib-y += myloader.o diff --git a/target/linux/generic/files/arch/mips/fw/myloader/myloader.c b/target/linux/generic/files/arch/mips/fw/myloader/myloader.c new file mode 100644 index 0000000..a26f9ad --- /dev/null +++ b/target/linux/generic/files/arch/mips/fw/myloader/myloader.c @@ -0,0 +1,63 @@ +/* + * Compex's MyLoader specific prom routines + * + * Copyright (C) 2007-2008 Gabor Juhos + * + * 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. + * + */ + +#include +#include +#include +#include + +#include +#include + +#define SYS_PARAMS_ADDR KSEG1ADDR(0x80000800) +#define BOARD_PARAMS_ADDR KSEG1ADDR(0x80000A00) +#define PART_TABLE_ADDR KSEG1ADDR(0x80000C00) +#define BOOT_PARAMS_ADDR KSEG1ADDR(0x80000E00) + +static struct myloader_info myloader_info __initdata; +static int myloader_found __initdata; + +struct myloader_info * __init myloader_get_info(void) +{ + struct mylo_system_params *sysp; + struct mylo_board_params *boardp; + struct mylo_partition_table *parts; + + if (myloader_found) + return &myloader_info; + + sysp = (struct mylo_system_params *)(SYS_PARAMS_ADDR); + boardp = (struct mylo_board_params *)(BOARD_PARAMS_ADDR); + parts = (struct mylo_partition_table *)(PART_TABLE_ADDR); + + printk(KERN_DEBUG "MyLoader: sysp=%08x, boardp=%08x, parts=%08x\n", + sysp->magic, boardp->magic, parts->magic); + + /* Check for some magic numbers */ + if (sysp->magic != MYLO_MAGIC_SYS_PARAMS || + boardp->magic != MYLO_MAGIC_BOARD_PARAMS || + le32_to_cpu(parts->magic) != MYLO_MAGIC_PARTITIONS) + return NULL; + + printk(KERN_DEBUG "MyLoader: id=%04x:%04x, sub_id=%04x:%04x\n", + sysp->vid, sysp->did, sysp->svid, sysp->sdid); + + myloader_info.vid = sysp->vid; + myloader_info.did = sysp->did; + myloader_info.svid = sysp->svid; + myloader_info.sdid = sysp->sdid; + + memcpy(myloader_info.macs, boardp->addr, sizeof(myloader_info.macs)); + + myloader_found = 1; + + return &myloader_info; +} diff --git a/target/linux/generic/files/crypto/ocf/Config.in b/target/linux/generic/files/crypto/ocf/Config.in new file mode 100644 index 0000000..652f76e --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/Config.in @@ -0,0 +1,38 @@ +############################################################################# + +mainmenu_option next_comment +comment 'OCF Configuration' +tristate 'OCF (Open Cryptograhic Framework)' CONFIG_OCF_OCF +dep_mbool ' enable fips RNG checks (fips check on RNG data before use)' \ + CONFIG_OCF_FIPS $CONFIG_OCF_OCF +dep_mbool ' enable harvesting entropy for /dev/random' \ + CONFIG_OCF_RANDOMHARVEST $CONFIG_OCF_OCF +dep_tristate ' cryptodev (user space support)' \ + CONFIG_OCF_CRYPTODEV $CONFIG_OCF_OCF +dep_tristate ' cryptosoft (software crypto engine)' \ + CONFIG_OCF_CRYPTOSOFT $CONFIG_OCF_OCF +dep_tristate ' safenet (HW crypto engine)' \ + CONFIG_OCF_SAFE $CONFIG_OCF_OCF +dep_tristate ' IXP4xx (HW crypto engine)' \ + CONFIG_OCF_IXP4XX $CONFIG_OCF_OCF +dep_mbool ' Enable IXP4xx HW to perform SHA1 and MD5 hashing (very slow)' \ + CONFIG_OCF_IXP4XX_SHA1_MD5 $CONFIG_OCF_IXP4XX +dep_tristate ' hifn (HW crypto engine)' \ + CONFIG_OCF_HIFN $CONFIG_OCF_OCF +dep_tristate ' talitos (HW crypto engine)' \ + CONFIG_OCF_TALITOS $CONFIG_OCF_OCF +dep_tristate ' pasemi (HW crypto engine)' \ + CONFIG_OCF_PASEMI $CONFIG_OCF_OCF +dep_tristate ' ep80579 (HW crypto engine)' \ + CONFIG_OCF_EP80579 $CONFIG_OCF_OCF +dep_tristate ' Micronas c7108 (HW crypto engine)' \ + CONFIG_OCF_C7108 $CONFIG_OCF_OCF +dep_tristate ' uBsec BCM5365 (HW crypto engine)' + CONFIG_OCF_UBSEC_SSB $CONFIG_OCF_OCF +dep_tristate ' ocfnull (does no crypto)' \ + CONFIG_OCF_OCFNULL $CONFIG_OCF_OCF +dep_tristate ' ocf-bench (HW crypto in-kernel benchmark)' \ + CONFIG_OCF_BENCH $CONFIG_OCF_OCF +endmenu + +############################################################################# diff --git a/target/linux/generic/files/crypto/ocf/Kconfig b/target/linux/generic/files/crypto/ocf/Kconfig new file mode 100644 index 0000000..3b3e1d1 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/Kconfig @@ -0,0 +1,128 @@ +menu "OCF Configuration" + +config OCF_OCF + tristate "OCF (Open Cryptograhic Framework)" + help + A linux port of the OpenBSD/FreeBSD crypto framework. + +config OCF_RANDOMHARVEST + bool "crypto random --- harvest entropy for /dev/random" + depends on OCF_OCF + help + Includes code to harvest random numbers from devices that support it. + +config OCF_FIPS + bool "enable fips RNG checks" + depends on OCF_OCF && OCF_RANDOMHARVEST + help + Run all RNG provided data through a fips check before + adding it /dev/random's entropy pool. + +config OCF_CRYPTODEV + tristate "cryptodev (user space support)" + depends on OCF_OCF + help + The user space API to access crypto hardware. + +config OCF_CRYPTOSOFT + tristate "cryptosoft (software crypto engine)" + depends on OCF_OCF + select CRYPTO + select CRYPTO_HASH + select CRYPTO_BLKCIPHER + help + A software driver for the OCF framework that uses + the kernel CryptoAPI. + +config OCF_SAFE + tristate "safenet (HW crypto engine)" + depends on OCF_OCF + help + A driver for a number of the safenet Excel crypto accelerators. + Currently tested and working on the 1141 and 1741. + +config OCF_IXP4XX + tristate "IXP4xx (HW crypto engine)" + depends on OCF_OCF + help + XScale IXP4xx crypto accelerator driver. Requires the + Intel Access library. + +config OCF_IXP4XX_SHA1_MD5 + bool "IXP4xx SHA1 and MD5 Hashing" + depends on OCF_IXP4XX + help + Allows the IXP4xx crypto accelerator to perform SHA1 and MD5 hashing. + Note: this is MUCH slower than using cryptosoft (software crypto engine). + +config OCF_HIFN + tristate "hifn (HW crypto engine)" + depends on OCF_OCF && PCI + help + OCF driver for various HIFN based crypto accelerators. + (7951, 7955, 7956, 7751, 7811) + +config OCF_HIFNHIPP + tristate "Hifn HIPP (HW packet crypto engine)" + depends on OCF_OCF + help + OCF driver for various HIFN (HIPP) based crypto accelerators + (7855) + +config OCF_TALITOS + tristate "talitos (HW crypto engine)" + depends on OCF_OCF + help + OCF driver for Freescale's security engine (SEC/talitos). + +config OCF_PASEMI + tristate "pasemi (HW crypto engine)" + depends on OCF_OCF && PPC_PASEMI + help + OCF driver for the PA Semi PWRficient DMA Engine + +config OCF_EP80579 + tristate "ep80579 (HW crypto engine)" + depends on OCF_OCF + help + OCF driver for the Intel EP80579 Integrated Processor Product Line. + +config OCF_CRYPTOCTEON + tristate "cryptocteon (HW crypto engine)" + depends on OCF_OCF + help + OCF driver for the Cavium OCTEON Processors. + +config OCF_KIRKWOOD + tristate "kirkwood (HW crypto engine)" + depends on OCF_OCF + help + OCF driver for the Marvell Kirkwood (88F6xxx) Processors. + +config OCF_C7108 + tristate "Micronas 7108 (HW crypto engine)" + depends on OCF_OCF + help + OCF driver for the Microna 7108 Cipher processors. + +config OCF_UBSEC_SSB + tristate "uBsec BCM5365 (HW crypto engine)" + depends on OCF_OCF + help + OCF driver for uBsec BCM5365 hardware crypto accelerator. + +config OCF_OCFNULL + tristate "ocfnull (fake crypto engine)" + depends on OCF_OCF + help + OCF driver for measuring ipsec overheads (does no crypto) + +config OCF_BENCH + tristate "ocf-bench (HW crypto in-kernel benchmark)" + depends on OCF_OCF + help + A very simple encryption test for the in-kernel interface + of OCF. Also includes code to benchmark the IXP Access library + for comparison. + +endmenu diff --git a/target/linux/generic/files/crypto/ocf/Makefile b/target/linux/generic/files/crypto/ocf/Makefile new file mode 100644 index 0000000..78d052c --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/Makefile @@ -0,0 +1,148 @@ +# for SGlinux builds +-include $(ROOTDIR)/modules/.config + +OCF_OBJS = crypto.o criov.o + +ifdef CONFIG_OCF_RANDOMHARVEST + OCF_OBJS += random.o +endif + +ifdef CONFIG_OCF_FIPS + OCF_OBJS += rndtest.o +endif + +# Add in autoconf.h to get #defines for CONFIG_xxx +AUTOCONF_H=$(ROOTDIR)/modules/autoconf.h +ifeq ($(AUTOCONF_H), $(wildcard $(AUTOCONF_H))) + EXTRA_CFLAGS += -include $(AUTOCONF_H) + export EXTRA_CFLAGS +endif + +ifndef obj + obj ?= . + _obj = subdir + mod-subdirs := safe hifn ixp4xx talitos ocfnull + export-objs += crypto.o criov.o random.o + list-multi += ocf.o + _slash := +else + _obj = obj + _slash := / +endif + +EXTRA_CFLAGS += -I$(obj)/. + +obj-$(CONFIG_OCF_OCF) += ocf.o +obj-$(CONFIG_OCF_CRYPTODEV) += cryptodev.o +obj-$(CONFIG_OCF_CRYPTOSOFT) += cryptosoft.o +obj-$(CONFIG_OCF_BENCH) += ocf-bench.o + +$(_obj)-$(CONFIG_OCF_SAFE) += safe$(_slash) +$(_obj)-$(CONFIG_OCF_HIFN) += hifn$(_slash) +$(_obj)-$(CONFIG_OCF_IXP4XX) += ixp4xx$(_slash) +$(_obj)-$(CONFIG_OCF_TALITOS) += talitos$(_slash) +$(_obj)-$(CONFIG_OCF_PASEMI) += pasemi$(_slash) +$(_obj)-$(CONFIG_OCF_EP80579) += ep80579$(_slash) +$(_obj)-$(CONFIG_OCF_CRYPTOCTEON) += cryptocteon$(_slash) +$(_obj)-$(CONFIG_OCF_KIRKWOOD) += kirkwood$(_slash) +$(_obj)-$(CONFIG_OCF_OCFNULL) += ocfnull$(_slash) +$(_obj)-$(CONFIG_OCF_C7108) += c7108$(_slash) +$(_obj)-$(CONFIG_OCF_UBSEC_SSB) += ubsec_ssb$(_slash) + +ocf-objs := $(OCF_OBJS) + +dummy: + @echo "Please consult the README for how to build OCF." + @echo "If you can't wait then the following should do it:" + @echo "" + @echo " make ocf_modules" + @echo " sudo make ocf_install" + @echo "" + @exit 1 + +$(list-multi) dummy1: $(ocf-objs) + $(LD) -r -o $@ $(ocf-objs) + +.PHONY: +clean: + rm -f *.o *.ko .*.o.flags .*.ko.cmd .*.o.cmd .*.mod.o.cmd *.mod.c + rm -f */*.o */*.ko */.*.o.cmd */.*.ko.cmd */.*.mod.o.cmd */*.mod.c */.*.o.flags + rm -f */modules.order */modules.builtin modules.order modules.builtin + +ifdef TOPDIR +-include $(TOPDIR)/Rules.make +endif + +# +# targets to build easily on the current machine +# + +ocf_make: + make -C /lib/modules/$(shell uname -r)/build M=`pwd` $(OCF_TARGET) CONFIG_OCF_OCF=m + make -C /lib/modules/$(shell uname -r)/build M=`pwd` $(OCF_TARGET) CONFIG_OCF_OCF=m CONFIG_OCF_CRYPTOSOFT=m + -make -C /lib/modules/$(shell uname -r)/build M=`pwd` $(OCF_TARGET) CONFIG_OCF_OCF=m CONFIG_OCF_BENCH=m + -make -C /lib/modules/$(shell uname -r)/build M=`pwd` $(OCF_TARGET) CONFIG_OCF_OCF=m CONFIG_OCF_OCFNULL=m + -make -C /lib/modules/$(shell uname -r)/build M=`pwd` $(OCF_TARGET) CONFIG_OCF_OCF=m CONFIG_OCF_HIFN=m + +ocf_modules: + $(MAKE) ocf_make OCF_TARGET=modules + +ocf_install: + $(MAKE) ocf_make OCF_TARGET="modules modules_install" + depmod + mkdir -p /usr/include/crypto + cp cryptodev.h /usr/include/crypto/. + +# +# generate full kernel patches for 2.4 and 2.6 kernels to make patching +# your kernel easier +# + +.PHONY: patch +patch: + patchbase=.; \ + [ -d $$patchbase/patches ] || patchbase=..; \ + patch=ocf-linux-base.patch; \ + patch24=ocf-linux-24.patch; \ + patch26=ocf-linux-26.patch; \ + patch3=ocf-linux-3.patch; \ + ( \ + find . -name Makefile; \ + find . -name Config.in; \ + find . -name Kconfig; \ + find . -name README; \ + find . -name '*.[ch]' | grep -v '.mod.c'; \ + ) | while read t; do \ + diff -Nau /dev/null $$t | sed 's?^+++ \./?+++ linux/crypto/ocf/?'; \ + done > $$patch; \ + cat $$patchbase/patches/linux-2.4.35-ocf.patch $$patch > $$patch24; \ + cat $$patchbase/patches/linux-2.6.38-ocf.patch $$patch > $$patch26; \ + cat $$patchbase/patches/linux-3.2.1-ocf.patch $$patch > $$patch3; \ + + +# +# this target probably does nothing for anyone but me - davidm +# + +.PHONY: release +release: + REL=`date +%Y%m%d`; RELDIR=/tmp/ocf-linux-$$REL; \ + CURDIR=`pwd`; \ + rm -rf /tmp/ocf-linux-$$REL*; \ + mkdir -p $$RELDIR/ocf; \ + mkdir -p $$RELDIR/patches; \ + mkdir -p $$RELDIR/crypto-tools; \ + cp README* $$RELDIR/.; \ + cp patches/[!C]* $$RELDIR/patches/.; \ + cp tools/[!C]* $$RELDIR/crypto-tools/.; \ + cp -r [!C]* Config.in $$RELDIR/ocf/.; \ + rm -rf $$RELDIR/ocf/patches $$RELDIR/ocf/tools; \ + rm -f $$RELDIR/ocf/README*; \ + cp $$CURDIR/../../user/crypto-tools/[!C]* $$RELDIR/crypto-tools/.; \ + make -C $$RELDIR/crypto-tools clean; \ + make -C $$RELDIR/ocf clean; \ + find $$RELDIR/ocf -name CVS | xargs rm -rf; \ + cd $$RELDIR/..; \ + tar cvf ocf-linux-$$REL.tar ocf-linux-$$REL; \ + gzip -9n ocf-linux-$$REL.tar + diff --git a/target/linux/generic/files/crypto/ocf/c7108/Makefile b/target/linux/generic/files/crypto/ocf/c7108/Makefile new file mode 100644 index 0000000..e7e634b --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/c7108/Makefile @@ -0,0 +1,12 @@ +# for SGlinux builds +-include $(ROOTDIR)/modules/.config + +obj-$(CONFIG_OCF_C7108) += aes-7108.o + +obj ?= . +EXTRA_CFLAGS += -I$(obj)/.. -I$(obj)/ + +ifdef TOPDIR +-include $(TOPDIR)/Rules.make +endif + diff --git a/target/linux/generic/files/crypto/ocf/c7108/aes-7108.c b/target/linux/generic/files/crypto/ocf/c7108/aes-7108.c new file mode 100644 index 0000000..f4841f5 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/c7108/aes-7108.c @@ -0,0 +1,841 @@ +/* + * Copyright (C) 2006 Micronas USA + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Effort sponsored in part by the Defense Advanced Research Projects + * Agency (DARPA) and Air Force Research Laboratory, Air Force + * Materiel Command, USAF, under agreement number F30602-01-2-0537. + * + */ + +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include +#include +#include +#include +#include + +/* Runtime mode */ +static int c7108_crypto_mode = C7108_AES_CTRL_MODE_CTR; +//static int c7108_crypto_mode = C7108_AES_CTRL_MODE_CBC; + +static int32_t c7108_id = -1; +static struct cipher_7108 **c7108_sessions = NULL; +static u_int32_t c7108_sesnum = 0; +static unsigned long iobar; + +/* Crypto entry points */ +static int c7108_process(void *, struct cryptop *, int); +static int c7108_newsession(void *, u_int32_t *, struct cryptoini *); +static int c7108_freesession(void *, u_int64_t); + +/* Globals */ +static int debug = 0; +static spinlock_t csr_mutex; + +/* Generic controller-based lock */ +#define AES_LOCK()\ + spin_lock(&csr_mutex) +#define AES_UNLOCK()\ + spin_unlock(&csr_mutex) + +/* 7108 AES register access */ +#define c7108_reg_wr8(a,d) iowrite8(d, (void*)(iobar+(a))) +#define c7108_reg_wr16(a,d) iowrite16(d, (void*)(iobar+(a))) +#define c7108_reg_wr32(a,d) iowrite32(d, (void*)(iobar+(a))) +#define c7108_reg_rd8(a) ioread8((void*)(iobar+(a))) +#define c7108_reg_rd16(a) ioread16((void*)(iobar+(a))) +#define c7108_reg_rd32(a) ioread32((void*)(iobar+(a))) + +static int +c7108_xlate_key(int klen, u8* k8ptr, u32* k32ptr) +{ + int i, nw=0; + nw = ((klen >= 256) ? 8 : (klen >= 192) ? 6 : 4); + for ( i = 0; i < nw; i++) { + k32ptr[i] = (k8ptr[i+3] << 24) | (k8ptr[i+2] << 16) | + (k8ptr[i+1] << 8) | k8ptr[i]; + + } + return 0; +} + +static int +c7108_cache_key(int klen, u32* k32ptr, u8* k8ptr) +{ + int i, nb=0; + u8* ptr = (u8*)k32ptr; + nb = ((klen >= 256) ? 32 : (klen >= 192) ? 24 : 16); + for ( i = 0; i < nb; i++) + k8ptr[i] = ptr[i]; + return 0; +} + +static int +c7108_aes_setup_dma(u32 src, u32 dst, u32 len) +{ + if (len < 16) { + printk("len < 16\n"); + return -10; + } + if (len % 16) { + printk("len not multiple of 16\n"); + return -11; + } + c7108_reg_wr16(C7108_AES_DMA_SRC0_LO, (u16) src); + c7108_reg_wr16(C7108_AES_DMA_SRC0_HI, (u16)((src & 0xffff0000) >> 16)); + c7108_reg_wr16(C7108_AES_DMA_DST0_LO, (u16) dst); + c7108_reg_wr16(C7108_AES_DMA_DST0_HI, (u16)((dst & 0xffff0000) >> 16)); + c7108_reg_wr16(C7108_AES_DMA_LEN, (u16) ((len / 16) - 1)); + + return 0; +} + +static int +c7108_aes_set_hw_iv(u8 iv[16]) +{ + c7108_reg_wr16(C7108_AES_IV0_LO, (u16) ((iv[1] << 8) | iv[0])); + c7108_reg_wr16(C7108_AES_IV0_HI, (u16) ((iv[3] << 8) | iv[2])); + c7108_reg_wr16(C7108_AES_IV1_LO, (u16) ((iv[5] << 8) | iv[4])); + c7108_reg_wr16(C7108_AES_IV1_HI, (u16) ((iv[7] << 8) | iv[6])); + c7108_reg_wr16(C7108_AES_IV2_LO, (u16) ((iv[9] << 8) | iv[8])); + c7108_reg_wr16(C7108_AES_IV2_HI, (u16) ((iv[11] << 8) | iv[10])); + c7108_reg_wr16(C7108_AES_IV3_LO, (u16) ((iv[13] << 8) | iv[12])); + c7108_reg_wr16(C7108_AES_IV3_HI, (u16) ((iv[15] << 8) | iv[14])); + + return 0; +} + +static void +c7108_aes_read_dkey(u32 * dkey) +{ + dkey[0] = (c7108_reg_rd16(C7108_AES_EKEY0_HI) << 16) | + c7108_reg_rd16(C7108_AES_EKEY0_LO); + dkey[1] = (c7108_reg_rd16(C7108_AES_EKEY1_HI) << 16) | + c7108_reg_rd16(C7108_AES_EKEY1_LO); + dkey[2] = (c7108_reg_rd16(C7108_AES_EKEY2_HI) << 16) | + c7108_reg_rd16(C7108_AES_EKEY2_LO); + dkey[3] = (c7108_reg_rd16(C7108_AES_EKEY3_HI) << 16) | + c7108_reg_rd16(C7108_AES_EKEY3_LO); + dkey[4] = (c7108_reg_rd16(C7108_AES_EKEY4_HI) << 16) | + c7108_reg_rd16(C7108_AES_EKEY4_LO); + dkey[5] = (c7108_reg_rd16(C7108_AES_EKEY5_HI) << 16) | + c7108_reg_rd16(C7108_AES_EKEY5_LO); + dkey[6] = (c7108_reg_rd16(C7108_AES_EKEY6_HI) << 16) | + c7108_reg_rd16(C7108_AES_EKEY6_LO); + dkey[7] = (c7108_reg_rd16(C7108_AES_EKEY7_HI) << 16) | + c7108_reg_rd16(C7108_AES_EKEY7_LO); +} + +static int +c7108_aes_cipher(int op, + u32 dst, + u32 src, + u32 len, + int klen, + u16 mode, + u32 key[8], + u8 iv[16]) +{ + int rv = 0, cnt=0; + u16 ctrl = 0, stat = 0; + + AES_LOCK(); + + /* Setup key length */ + if (klen == 128) { + ctrl |= C7108_AES_KEY_LEN_128; + } else if (klen == 192) { + ctrl |= C7108_AES_KEY_LEN_192; + } else if (klen == 256) { + ctrl |= C7108_AES_KEY_LEN_256; + } else { + AES_UNLOCK(); + return -3; + } + + /* Check opcode */ + if (C7108_AES_ENCRYPT == op) { + ctrl |= C7108_AES_ENCRYPT; + } else if (C7108_AES_DECRYPT == op) { + ctrl |= C7108_AES_DECRYPT; + } else { + AES_UNLOCK(); + return -4; + } + + /* check mode */ + if ( (mode != C7108_AES_CTRL_MODE_CBC) && + (mode != C7108_AES_CTRL_MODE_CFB) && + (mode != C7108_AES_CTRL_MODE_OFB) && + (mode != C7108_AES_CTRL_MODE_CTR) && + (mode != C7108_AES_CTRL_MODE_ECB) ) { + AES_UNLOCK(); + return -5; + } + + /* Now set mode */ + ctrl |= mode; + + /* For CFB, OFB, and CTR, neither backward key + * expansion nor key inversion is required. + */ + if ( (C7108_AES_DECRYPT == op) && + (C7108_AES_CTRL_MODE_CBC == mode || + C7108_AES_CTRL_MODE_ECB == mode ) ){ + + /* Program Key */ + c7108_reg_wr16(C7108_AES_KEY0_LO, (u16) key[4]); + c7108_reg_wr16(C7108_AES_KEY0_HI, (u16) (key[4] >> 16)); + c7108_reg_wr16(C7108_AES_KEY1_LO, (u16) key[5]); + c7108_reg_wr16(C7108_AES_KEY1_HI, (u16) (key[5] >> 16)); + c7108_reg_wr16(C7108_AES_KEY2_LO, (u16) key[6]); + c7108_reg_wr16(C7108_AES_KEY2_HI, (u16) (key[6] >> 16)); + c7108_reg_wr16(C7108_AES_KEY3_LO, (u16) key[7]); + c7108_reg_wr16(C7108_AES_KEY3_HI, (u16) (key[7] >> 16)); + c7108_reg_wr16(C7108_AES_KEY6_LO, (u16) key[2]); + c7108_reg_wr16(C7108_AES_KEY6_HI, (u16) (key[2] >> 16)); + c7108_reg_wr16(C7108_AES_KEY7_LO, (u16) key[3]); + c7108_reg_wr16(C7108_AES_KEY7_HI, (u16) (key[3] >> 16)); + + + if (192 == klen) { + c7108_reg_wr16(C7108_AES_KEY4_LO, (u16) key[7]); + c7108_reg_wr16(C7108_AES_KEY4_HI, (u16) (key[7] >> 16)); + c7108_reg_wr16(C7108_AES_KEY5_LO, (u16) key[7]); + c7108_reg_wr16(C7108_AES_KEY5_HI, (u16) (key[7] >> 16)); + + } else if (256 == klen) { + /* 256 */ + c7108_reg_wr16(C7108_AES_KEY4_LO, (u16) key[0]); + c7108_reg_wr16(C7108_AES_KEY4_HI, (u16) (key[0] >> 16)); + c7108_reg_wr16(C7108_AES_KEY5_LO, (u16) key[1]); + c7108_reg_wr16(C7108_AES_KEY5_HI, (u16) (key[1] >> 16)); + + } + + } else { + /* Program Key */ + c7108_reg_wr16(C7108_AES_KEY0_LO, (u16) key[0]); + c7108_reg_wr16(C7108_AES_KEY0_HI, (u16) (key[0] >> 16)); + c7108_reg_wr16(C7108_AES_KEY1_LO, (u16) key[1]); + c7108_reg_wr16(C7108_AES_KEY1_HI, (u16) (key[1] >> 16)); + c7108_reg_wr16(C7108_AES_KEY2_LO, (u16) key[2]); + c7108_reg_wr16(C7108_AES_KEY2_HI, (u16) (key[2] >> 16)); + c7108_reg_wr16(C7108_AES_KEY3_LO, (u16) key[3]); + c7108_reg_wr16(C7108_AES_KEY3_HI, (u16) (key[3] >> 16)); + c7108_reg_wr16(C7108_AES_KEY4_LO, (u16) key[4]); + c7108_reg_wr16(C7108_AES_KEY4_HI, (u16) (key[4] >> 16)); + c7108_reg_wr16(C7108_AES_KEY5_LO, (u16) key[5]); + c7108_reg_wr16(C7108_AES_KEY5_HI, (u16) (key[5] >> 16)); + c7108_reg_wr16(C7108_AES_KEY6_LO, (u16) key[6]); + c7108_reg_wr16(C7108_AES_KEY6_HI, (u16) (key[6] >> 16)); + c7108_reg_wr16(C7108_AES_KEY7_LO, (u16) key[7]); + c7108_reg_wr16(C7108_AES_KEY7_HI, (u16) (key[7] >> 16)); + + } + + /* Set IV always */ + c7108_aes_set_hw_iv(iv); + + /* Program DMA addresses */ + if ((rv = c7108_aes_setup_dma(src, dst, len)) < 0) { + AES_UNLOCK(); + return rv; + } + + + /* Start AES cipher */ + c7108_reg_wr16(C7108_AES_CTRL, ctrl | C7108_AES_GO); + + //printk("Ctrl: 0x%x\n", ctrl | C7108_AES_GO); + do { + /* TODO: interrupt mode */ + // printk("aes_stat=0x%x\n", stat); + //udelay(100); + } while ((cnt++ < 1000000) && + !((stat=c7108_reg_rd16(C7108_AES_CTRL))&C7108_AES_OP_DONE)); + + + if ((mode == C7108_AES_CTRL_MODE_ECB)|| + (mode == C7108_AES_CTRL_MODE_CBC)) { + /* Save out key when the lock is held ... */ + c7108_aes_read_dkey(key); + } + + AES_UNLOCK(); + return 0; + +} + +/* + * Generate a new crypto device session. + */ +static int +c7108_newsession(void *arg, u_int32_t *sid, struct cryptoini *cri) +{ + struct cipher_7108 **swd; + u_int32_t i; + char *algo; + int mode, xfm_type; + + dprintk("%s()\n", __FUNCTION__); + if (sid == NULL || cri == NULL) { + dprintk("%s,%d - EINVAL\n", __FILE__, __LINE__); + return EINVAL; + } + + if (c7108_sessions) { + for (i = 1; i < c7108_sesnum; i++) + if (c7108_sessions[i] == NULL) + break; + } else + i = 1; /* NB: to silence compiler warning */ + + if (c7108_sessions == NULL || i == c7108_sesnum) { + if (c7108_sessions == NULL) { + i = 1; /* We leave c7108_sessions[0] empty */ + c7108_sesnum = CRYPTO_SW_SESSIONS; + } else + c7108_sesnum *= 2; + + swd = kmalloc(c7108_sesnum * sizeof(struct cipher_7108 *), + GFP_ATOMIC); + if (swd == NULL) { + /* Reset session number */ + if (c7108_sesnum == CRYPTO_SW_SESSIONS) + c7108_sesnum = 0; + else + c7108_sesnum /= 2; + dprintk("%s,%d: ENOBUFS\n", __FILE__, __LINE__); + return ENOBUFS; + } + memset(swd, 0, c7108_sesnum * sizeof(struct cipher_7108 *)); + + /* Copy existing sessions */ + if (c7108_sessions) { + memcpy(swd, c7108_sessions, + (c7108_sesnum / 2) * sizeof(struct cipher_7108 *)); + kfree(c7108_sessions); + } + + c7108_sessions = swd; + + } + + swd = &c7108_sessions[i]; + *sid = i; + + while (cri) { + *swd = (struct cipher_7108 *) + kmalloc(sizeof(struct cipher_7108), GFP_ATOMIC); + if (*swd == NULL) { + c7108_freesession(NULL, i); + dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__); + return ENOBUFS; + } + memset(*swd, 0, sizeof(struct cipher_7108)); + + algo = NULL; + mode = 0; + xfm_type = HW_TYPE_CIPHER; + + switch (cri->cri_alg) { + + case CRYPTO_AES_CBC: + algo = "aes"; + mode = CRYPTO_TFM_MODE_CBC; + c7108_crypto_mode = C7108_AES_CTRL_MODE_CBC; + break; +#if 0 + case CRYPTO_AES_CTR: + algo = "aes_ctr"; + mode = CRYPTO_TFM_MODE_CBC; + c7108_crypto_mode = C7108_AES_CTRL_MODE_CTR; + break; + case CRYPTO_AES_ECB: + algo = "aes_ecb"; + mode = CRYPTO_TFM_MODE_CBC; + c7108_crypto_mode = C7108_AES_CTRL_MODE_ECB; + break; + case CRYPTO_AES_OFB: + algo = "aes_ofb"; + mode = CRYPTO_TFM_MODE_CBC; + c7108_crypto_mode = C7108_AES_CTRL_MODE_OFB; + break; + case CRYPTO_AES_CFB: + algo = "aes_cfb"; + mode = CRYPTO_TFM_MODE_CBC; + c7108_crypto_mode = C7108_AES_CTRL_MODE_CFB; + break; +#endif + default: + printk("unsupported crypto algorithm: %d\n", + cri->cri_alg); + return -EINVAL; + break; + } + + + if (!algo || !*algo) { + printk("cypher_7108_crypto: Unknown algo 0x%x\n", + cri->cri_alg); + c7108_freesession(NULL, i); + return EINVAL; + } + + if (xfm_type == HW_TYPE_CIPHER) { + if (debug) { + dprintk("%s key:", __FUNCTION__); + for (i = 0; i < (cri->cri_klen + 7) / 8; i++) + dprintk("%s0x%02x", (i % 8) ? " " : "\n ", + cri->cri_key[i]); + dprintk("\n"); + } + + } else if (xfm_type == SW_TYPE_HMAC || + xfm_type == SW_TYPE_HASH) { + printk("cypher_7108_crypto: HMAC unsupported!\n"); + return -EINVAL; + c7108_freesession(NULL, i); + } else { + printk("cypher_7108_crypto: " + "Unhandled xfm_type %d\n", xfm_type); + c7108_freesession(NULL, i); + return EINVAL; + } + + (*swd)->cri_alg = cri->cri_alg; + (*swd)->xfm_type = xfm_type; + + cri = cri->cri_next; + swd = &((*swd)->next); + } + return 0; +} + +/* + * Free a session. + */ +static int +c7108_freesession(void *arg, u_int64_t tid) +{ + struct cipher_7108 *swd; + u_int32_t sid = CRYPTO_SESID2LID(tid); + + dprintk("%s()\n", __FUNCTION__); + if (sid > c7108_sesnum || c7108_sessions == NULL || + c7108_sessions[sid] == NULL) { + dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__); + return(EINVAL); + } + + /* Silently accept and return */ + if (sid == 0) + return(0); + + while ((swd = c7108_sessions[sid]) != NULL) { + c7108_sessions[sid] = swd->next; + kfree(swd); + } + return 0; +} + +/* + * Process a hardware request. + */ +static int +c7108_process(void *arg, struct cryptop *crp, int hint) +{ + struct cryptodesc *crd; + struct cipher_7108 *sw; + u_int32_t lid; + int type; + u32 hwkey[8]; + +#define SCATTERLIST_MAX 16 + struct scatterlist sg[SCATTERLIST_MAX]; + int sg_num, sg_len, skip; + struct sk_buff *skb = NULL; + struct uio *uiop = NULL; + + dprintk("%s()\n", __FUNCTION__); + /* Sanity check */ + if (crp == NULL) { + dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__); + return EINVAL; + } + + crp->crp_etype = 0; + + if (crp->crp_desc == NULL || crp->crp_buf == NULL) { + dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__); + crp->crp_etype = EINVAL; + goto done; + } + + lid = crp->crp_sid & 0xffffffff; + if (lid >= c7108_sesnum || lid == 0 || c7108_sessions == NULL || + c7108_sessions[lid] == NULL) { + crp->crp_etype = ENOENT; + dprintk("%s,%d: ENOENT\n", __FILE__, __LINE__); + goto done; + } + + /* + * do some error checking outside of the loop for SKB and IOV + * processing this leaves us with valid skb or uiop pointers + * for later + */ + if (crp->crp_flags & CRYPTO_F_SKBUF) { + skb = (struct sk_buff *) crp->crp_buf; + if (skb_shinfo(skb)->nr_frags >= SCATTERLIST_MAX) { + printk("%s,%d: %d nr_frags > SCATTERLIST_MAX", + __FILE__, __LINE__, + skb_shinfo(skb)->nr_frags); + goto done; + } + } else if (crp->crp_flags & CRYPTO_F_IOV) { + uiop = (struct uio *) crp->crp_buf; + if (uiop->uio_iovcnt > SCATTERLIST_MAX) { + printk("%s,%d: %d uio_iovcnt > SCATTERLIST_MAX", + __FILE__, __LINE__, + uiop->uio_iovcnt); + goto done; + } + } + + /* Go through crypto descriptors, processing as we go */ + for (crd = crp->crp_desc; crd; crd = crd->crd_next) { + /* + * Find the crypto context. + * + * XXX Note that the logic here prevents us from having + * XXX the same algorithm multiple times in a session + * XXX (or rather, we can but it won't give us the right + * XXX results). To do that, we'd need some way of differentiating + * XXX between the various instances of an algorithm (so we can + * XXX locate the correct crypto context). + */ + for (sw = c7108_sessions[lid]; + sw && sw->cri_alg != crd->crd_alg; + sw = sw->next) + ; + + /* No such context ? */ + if (sw == NULL) { + crp->crp_etype = EINVAL; + dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__); + goto done; + } + + skip = crd->crd_skip; + + /* + * setup the SG list skip from the start of the buffer + */ + memset(sg, 0, sizeof(sg)); + if (crp->crp_flags & CRYPTO_F_SKBUF) { + int i, len; + type = CRYPTO_BUF_SKBUF; + + sg_num = 0; + sg_len = 0; + + if (skip < skb_headlen(skb)) { + //sg[sg_num].page = virt_to_page(skb->data + skip); + //sg[sg_num].offset = offset_in_page(skb->data + skip); + len = skb_headlen(skb) - skip; + if (len + sg_len > crd->crd_len) + len = crd->crd_len - sg_len; + //sg[sg_num].length = len; + sg_set_page(&sg[sg_num], virt_to_page(skb->data + skip), len, offset_in_page(skb->data + skip)); + sg_len += sg[sg_num].length; + sg_num++; + skip = 0; + } else + skip -= skb_headlen(skb); + + for (i = 0; sg_len < crd->crd_len && + i < skb_shinfo(skb)->nr_frags && + sg_num < SCATTERLIST_MAX; i++) { + if (skip < skb_shinfo(skb)->frags[i].size) { + //sg[sg_num].page = skb_frag_page(&skb_shinfo(skb)->frags[i]); + //sg[sg_num].offset = skb_shinfo(skb)->frags[i].page_offset + skip; + len = skb_shinfo(skb)->frags[i].size - skip; + if (len + sg_len > crd->crd_len) + len = crd->crd_len - sg_len; + //sg[sg_num].length = len; + sg_set_page(&sg[sg_num], skb_frag_page(&skb_shinfo(skb)->frags[i]), len, skb_shinfo(skb)->frags[i].page_offset + skip); + sg_len += sg[sg_num].length; + sg_num++; + skip = 0; + } else + skip -= skb_shinfo(skb)->frags[i].size; + } + } else if (crp->crp_flags & CRYPTO_F_IOV) { + int len; + type = CRYPTO_BUF_IOV; + sg_len = 0; + for (sg_num = 0; sg_len < crd->crd_len && + sg_num < uiop->uio_iovcnt && + sg_num < SCATTERLIST_MAX; sg_num++) { + if (skip < uiop->uio_iov[sg_num].iov_len) { + //sg[sg_num].page = virt_to_page(uiop->uio_iov[sg_num].iov_base+skip); + //sg[sg_num].offset = offset_in_page(uiop->uio_iov[sg_num].iov_base+skip); + len = uiop->uio_iov[sg_num].iov_len - skip; + if (len + sg_len > crd->crd_len) + len = crd->crd_len - sg_len; + //sg[sg_num].length = len; + sg_set_page(&sg[sg_num], virt_to_page(uiop->uio_iov[sg_num].iov_base+skip), len, offset_in_page(uiop->uio_iov[sg_num].iov_base+skip)); + sg_len += sg[sg_num].length; + skip = 0; + } else + skip -= uiop->uio_iov[sg_num].iov_len; + } + } else { + type = CRYPTO_BUF_CONTIG; + //sg[0].page = virt_to_page(crp->crp_buf + skip); + //sg[0].offset = offset_in_page(crp->crp_buf + skip); + sg_len = (crp->crp_ilen - skip); + if (sg_len > crd->crd_len) + sg_len = crd->crd_len; + //sg[0].length = sg_len; + sg_set_page(&sg[0], virt_to_page(crp->crp_buf + skip), sg_len, offset_in_page(crp->crp_buf + skip)); + sg_num = 1; + } + if (sg_num > 0) + sg_mark_end(&sg[sg_num-1]); + + + switch (sw->xfm_type) { + + case HW_TYPE_CIPHER: { + + unsigned char iv[64]; + unsigned char *ivp = iv; + int i; + int ivsize = 16; /* fixed for AES */ + int blocksize = 16; /* fixed for AES */ + + if (sg_len < blocksize) { + crp->crp_etype = EINVAL; + dprintk("%s,%d: EINVAL len %d < %d\n", + __FILE__, __LINE__, + sg_len, + blocksize); + goto done; + } + + if (ivsize > sizeof(iv)) { + crp->crp_etype = EINVAL; + dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__); + goto done; + } + + if (crd->crd_flags & CRD_F_ENCRYPT) { /* encrypt */ + + if (crd->crd_flags & CRD_F_IV_EXPLICIT) { + ivp = crd->crd_iv; + } else { + get_random_bytes(ivp, ivsize); + } + /* + * do we have to copy the IV back to the buffer ? + */ + if ((crd->crd_flags & CRD_F_IV_PRESENT) == 0) { + crypto_copyback(crp->crp_buf, + crd->crd_inject, + ivsize, + (caddr_t)ivp); + } + + c7108_xlate_key(crd->crd_klen, + (u8*)crd->crd_key, (u32*)hwkey); + + /* Encrypt SG list */ + for (i = 0; i < sg_num; i++) { + sg[i].dma_address = + dma_map_single(NULL, + kmap(sg_page(&sg[i])) + sg[i].offset, sg_len, DMA_BIDIRECTIONAL); +#if 0 + printk("sg[%d]:0x%08x, off 0x%08x " + "kmap 0x%08x phys 0x%08x\n", + i, sg[i].page, sg[i].offset, + kmap(sg[i].page) + sg[i].offset, + sg[i].dma_address); +#endif + c7108_aes_cipher(C7108_AES_ENCRYPT, + sg[i].dma_address, + sg[i].dma_address, + sg_len, + crd->crd_klen, + c7108_crypto_mode, + hwkey, + ivp); + + if ((c7108_crypto_mode == C7108_AES_CTRL_MODE_CBC)|| + (c7108_crypto_mode == C7108_AES_CTRL_MODE_ECB)) { + /* Read back expanded key and cache it in key + * context. + * NOTE: for ECB/CBC modes only (not CTR, CFB, OFB) + * where you set the key once. + */ + c7108_cache_key(crd->crd_klen, + (u32*)hwkey, (u8*)crd->crd_key); +#if 0 + printk("%s expanded key:", __FUNCTION__); + for (i = 0; i < (crd->crd_klen + 7) / 8; i++) + printk("%s0x%02x", (i % 8) ? " " : "\n ", + crd->crd_key[i]); + printk("\n"); +#endif + } + } + } + else { /*decrypt */ + + if (crd->crd_flags & CRD_F_IV_EXPLICIT) { + ivp = crd->crd_iv; + } else { + crypto_copydata(crp->crp_buf, crd->crd_inject, + ivsize, (caddr_t)ivp); + } + + c7108_xlate_key(crd->crd_klen, + (u8*)crd->crd_key, (u32*)hwkey); + + /* Decrypt SG list */ + for (i = 0; i < sg_num; i++) { + sg[i].dma_address = + dma_map_single(NULL, + kmap(sg_page(&sg[i])) + sg[i].offset, + sg_len, DMA_BIDIRECTIONAL); + +#if 0 + printk("sg[%d]:0x%08x, off 0x%08x " + "kmap 0x%08x phys 0x%08x\n", + i, sg[i].page, sg[i].offset, + kmap(sg[i].page) + sg[i].offset, + sg[i].dma_address); +#endif + c7108_aes_cipher(C7108_AES_DECRYPT, + sg[i].dma_address, + sg[i].dma_address, + sg_len, + crd->crd_klen, + c7108_crypto_mode, + hwkey, + ivp); + } + } + } break; + case SW_TYPE_HMAC: + case SW_TYPE_HASH: + crp->crp_etype = EINVAL; + goto done; + break; + + case SW_TYPE_COMP: + crp->crp_etype = EINVAL; + goto done; + break; + + default: + /* Unknown/unsupported algorithm */ + dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__); + crp->crp_etype = EINVAL; + goto done; + } + } + +done: + crypto_done(crp); + return 0; +} + +static struct { + softc_device_decl sc_dev; +} a7108dev; + +static device_method_t a7108_methods = { +/* crypto device methods */ + DEVMETHOD(cryptodev_newsession, c7108_newsession), + DEVMETHOD(cryptodev_freesession, c7108_freesession), + DEVMETHOD(cryptodev_process, c7108_process), + DEVMETHOD(cryptodev_kprocess, NULL) +}; + +static int +cypher_7108_crypto_init(void) +{ + dprintk("%s(%p)\n", __FUNCTION__, cypher_7108_crypto_init); + + iobar = (unsigned long)ioremap(CCU_AES_REG_BASE, 0x4000); + printk("7108: AES @ 0x%08x (0x%08x phys) %s mode\n", + iobar, CCU_AES_REG_BASE, + c7108_crypto_mode & C7108_AES_CTRL_MODE_CBC ? "CBC" : + c7108_crypto_mode & C7108_AES_CTRL_MODE_ECB ? "ECB" : + c7108_crypto_mode & C7108_AES_CTRL_MODE_CTR ? "CTR" : + c7108_crypto_mode & C7108_AES_CTRL_MODE_CFB ? "CFB" : + c7108_crypto_mode & C7108_AES_CTRL_MODE_OFB ? "OFB" : "???"); + csr_mutex = SPIN_LOCK_UNLOCKED; + + memset(&a7108dev, 0, sizeof(a7108dev)); + softc_device_init(&a7108dev, "aes7108", 0, a7108_methods); + + c7108_id = crypto_get_driverid(softc_get_device(&a7108dev), CRYPTOCAP_F_HARDWARE); + if (c7108_id < 0) + panic("7108: crypto device cannot initialize!"); + +// crypto_register(c7108_id, CRYPTO_AES_CBC, 0, 0, c7108_newsession, c7108_freesession, c7108_process, NULL); + crypto_register(c7108_id, CRYPTO_AES_CBC, 0, 0); + + return(0); +} + +static void +cypher_7108_crypto_exit(void) +{ + dprintk("%s()\n", __FUNCTION__); + crypto_unregister_all(c7108_id); + c7108_id = -1; +} + +module_init(cypher_7108_crypto_init); +module_exit(cypher_7108_crypto_exit); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_DESCRIPTION("Cypher 7108 Crypto (OCF module for kernel crypto)"); diff --git a/target/linux/generic/files/crypto/ocf/c7108/aes-7108.h b/target/linux/generic/files/crypto/ocf/c7108/aes-7108.h new file mode 100644 index 0000000..0c7bfcb --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/c7108/aes-7108.h @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2006 Micronas USA + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Effort sponsored in part by the Defense Advanced Research Projects + * Agency (DARPA) and Air Force Research Laboratory, Air Force + * Materiel Command, USAF, under agreement number F30602-01-2-0537. + * + */ + +#ifndef __AES_7108_H__ +#define __AES_7108_H__ + +/* Cypher 7108 AES Controller Hardware */ +#define CCU_REG_BASE 0x1b500000 +#define CCU_AES_REG_BASE (CCU_REG_BASE + 0x100) +#define C7108_AES_KEY0_LO (0x0000) +#define C7108_AES_KEY0_HI (0x0004) +#define C7108_AES_KEY1_LO (0x0008) +#define C7108_AES_KEY1_HI (0x000c) +#define C7108_AES_KEY2_LO (0x0010) +#define C7108_AES_KEY2_HI (0x0014) +#define C7108_AES_KEY3_LO (0x0018) +#define C7108_AES_KEY3_HI (0x001c) +#define C7108_AES_KEY4_LO (0x0020) +#define C7108_AES_KEY4_HI (0x0024) +#define C7108_AES_KEY5_LO (0x0028) +#define C7108_AES_KEY5_HI (0x002c) +#define C7108_AES_KEY6_LO (0x0030) +#define C7108_AES_KEY6_HI (0x0034) +#define C7108_AES_KEY7_LO (0x0038) +#define C7108_AES_KEY7_HI (0x003c) +#define C7108_AES_IV0_LO (0x0040) +#define C7108_AES_IV0_HI (0x0044) +#define C7108_AES_IV1_LO (0x0048) +#define C7108_AES_IV1_HI (0x004c) +#define C7108_AES_IV2_LO (0x0050) +#define C7108_AES_IV2_HI (0x0054) +#define C7108_AES_IV3_LO (0x0058) +#define C7108_AES_IV3_HI (0x005c) + +#define C7108_AES_DMA_SRC0_LO (0x0068) /* Bits 0:15 */ +#define C7108_AES_DMA_SRC0_HI (0x006c) /* Bits 27:16 */ +#define C7108_AES_DMA_DST0_LO (0x0070) /* Bits 0:15 */ +#define C7108_AES_DMA_DST0_HI (0x0074) /* Bits 27:16 */ +#define C7108_AES_DMA_LEN (0x0078) /*Bytes:(Count+1)x16 */ + +/* AES/Copy engine control register */ +#define C7108_AES_CTRL (0x007c) /* AES control */ +#define C7108_AES_CTRL_RS (1<<0) /* Which set of src/dst to use */ + +/* AES Cipher mode, controlled by setting Bits 2:0 */ +#define C7108_AES_CTRL_MODE_CBC 0 +#define C7108_AES_CTRL_MODE_CFB (1<<0) +#define C7108_AES_CTRL_MODE_OFB (1<<1) +#define C7108_AES_CTRL_MODE_CTR ((1<<0)|(1<<1)) +#define C7108_AES_CTRL_MODE_ECB (1<<2) + +/* AES Key length , Bits 5:4 */ +#define C7108_AES_KEY_LEN_128 0 /* 00 */ +#define C7108_AES_KEY_LEN_192 (1<<4) /* 01 */ +#define C7108_AES_KEY_LEN_256 (1<<5) /* 10 */ + +/* AES Operation (crypt/decrypt), Bit 3 */ +#define C7108_AES_DECRYPT (1<<3) /* Clear for encrypt */ +#define C7108_AES_ENCRYPT 0 +#define C7108_AES_INTR (1<<13) /* Set on done trans from 0->1*/ +#define C7108_AES_GO (1<<14) /* Run */ +#define C7108_AES_OP_DONE (1<<15) /* Set when complete */ + + +/* Expanded key registers */ +#define C7108_AES_EKEY0_LO (0x0080) +#define C7108_AES_EKEY0_HI (0x0084) +#define C7108_AES_EKEY1_LO (0x0088) +#define C7108_AES_EKEY1_HI (0x008c) +#define C7108_AES_EKEY2_LO (0x0090) +#define C7108_AES_EKEY2_HI (0x0094) +#define C7108_AES_EKEY3_LO (0x0098) +#define C7108_AES_EKEY3_HI (0x009c) +#define C7108_AES_EKEY4_LO (0x00a0) +#define C7108_AES_EKEY4_HI (0x00a4) +#define C7108_AES_EKEY5_LO (0x00a8) +#define C7108_AES_EKEY5_HI (0x00ac) +#define C7108_AES_EKEY6_LO (0x00b0) +#define C7108_AES_EKEY6_HI (0x00b4) +#define C7108_AES_EKEY7_LO (0x00b8) +#define C7108_AES_EKEY7_HI (0x00bc) +#define C7108_AES_OK (0x00fc) /* Reset: "OK" */ + +#define offset_in_page(p) ((unsigned long)(p) & ~PAGE_MASK) + +/* Software session entry */ + +#define HW_TYPE_CIPHER 0 +#define SW_TYPE_HMAC 1 +#define SW_TYPE_AUTH2 2 +#define SW_TYPE_HASH 3 +#define SW_TYPE_COMP 4 + +struct cipher_7108 { + int xfm_type; + int cri_alg; + union { + struct { + char sw_key[HMAC_BLOCK_LEN]; + int sw_klen; + int sw_authlen; + } hmac; + } u; + struct cipher_7108 *next; +}; + + + +#endif /* __C7108_AES_7108_H__ */ diff --git a/target/linux/generic/files/crypto/ocf/criov.c b/target/linux/generic/files/crypto/ocf/criov.c new file mode 100644 index 0000000..a8c1a8c --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/criov.c @@ -0,0 +1,215 @@ +/* $OpenBSD: criov.c,v 1.9 2002/01/29 15:48:29 jason Exp $ */ + +/* + * Linux port done by David McCullough + * Copyright (C) 2006-2010 David McCullough + * Copyright (C) 2004-2005 Intel Corporation. + * The license and original author are listed below. + * + * Copyright (c) 1999 Theo de Raadt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * +__FBSDID("$FreeBSD: src/sys/opencrypto/criov.c,v 1.5 2006/06/04 22:15:13 pjd Exp $"); + */ + +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) && !defined(AUTOCONF_INCLUDED) +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* + * This macro is only for avoiding code duplication, as we need to skip + * given number of bytes in the same way in three functions below. + */ +#define CUIO_SKIP() do { \ + KASSERT(off >= 0, ("%s: off %d < 0", __func__, off)); \ + KASSERT(len >= 0, ("%s: len %d < 0", __func__, len)); \ + while (off > 0) { \ + KASSERT(iol >= 0, ("%s: empty in skip", __func__)); \ + if (off < iov->iov_len) \ + break; \ + off -= iov->iov_len; \ + iol--; \ + iov++; \ + } \ +} while (0) + +void +cuio_copydata(struct uio* uio, int off, int len, caddr_t cp) +{ + struct iovec *iov = uio->uio_iov; + int iol = uio->uio_iovcnt; + unsigned count; + + CUIO_SKIP(); + while (len > 0) { + KASSERT(iol >= 0, ("%s: empty", __func__)); + count = min((int)(iov->iov_len - off), len); + memcpy(cp, ((caddr_t)iov->iov_base) + off, count); + len -= count; + cp += count; + off = 0; + iol--; + iov++; + } +} + +void +cuio_copyback(struct uio* uio, int off, int len, caddr_t cp) +{ + struct iovec *iov = uio->uio_iov; + int iol = uio->uio_iovcnt; + unsigned count; + + CUIO_SKIP(); + while (len > 0) { + KASSERT(iol >= 0, ("%s: empty", __func__)); + count = min((int)(iov->iov_len - off), len); + memcpy(((caddr_t)iov->iov_base) + off, cp, count); + len -= count; + cp += count; + off = 0; + iol--; + iov++; + } +} + +/* + * Return a pointer to iov/offset of location in iovec list. + */ +struct iovec * +cuio_getptr(struct uio *uio, int loc, int *off) +{ + struct iovec *iov = uio->uio_iov; + int iol = uio->uio_iovcnt; + + while (loc >= 0) { + /* Normal end of search */ + if (loc < iov->iov_len) { + *off = loc; + return (iov); + } + + loc -= iov->iov_len; + if (iol == 0) { + if (loc == 0) { + /* Point at the end of valid data */ + *off = iov->iov_len; + return (iov); + } else + return (NULL); + } else { + iov++, iol--; + } + } + + return (NULL); +} + +EXPORT_SYMBOL(cuio_copyback); +EXPORT_SYMBOL(cuio_copydata); +EXPORT_SYMBOL(cuio_getptr); + +static void +skb_copy_bits_back(struct sk_buff *skb, int offset, caddr_t cp, int len) +{ + int i; + if (offset < skb_headlen(skb)) { + memcpy(skb->data + offset, cp, min_t(int, skb_headlen(skb), len)); + len -= skb_headlen(skb); + cp += skb_headlen(skb); + } + offset -= skb_headlen(skb); + for (i = 0; len > 0 && i < skb_shinfo(skb)->nr_frags; i++) { + if (offset < skb_shinfo(skb)->frags[i].size) { + memcpy(page_address(skb_frag_page(&skb_shinfo(skb)->frags[i])) + + skb_shinfo(skb)->frags[i].page_offset, + cp, min_t(int, skb_shinfo(skb)->frags[i].size, len)); + len -= skb_shinfo(skb)->frags[i].size; + cp += skb_shinfo(skb)->frags[i].size; + } + offset -= skb_shinfo(skb)->frags[i].size; + } +} + +void +crypto_copyback(int flags, caddr_t buf, int off, int size, caddr_t in) +{ + + if ((flags & CRYPTO_F_SKBUF) != 0) + skb_copy_bits_back((struct sk_buff *)buf, off, in, size); + else if ((flags & CRYPTO_F_IOV) != 0) + cuio_copyback((struct uio *)buf, off, size, in); + else + bcopy(in, buf + off, size); +} + +void +crypto_copydata(int flags, caddr_t buf, int off, int size, caddr_t out) +{ + + if ((flags & CRYPTO_F_SKBUF) != 0) + skb_copy_bits((struct sk_buff *)buf, off, out, size); + else if ((flags & CRYPTO_F_IOV) != 0) + cuio_copydata((struct uio *)buf, off, size, out); + else + bcopy(buf + off, out, size); +} + +int +crypto_apply(int flags, caddr_t buf, int off, int len, + int (*f)(void *, void *, u_int), void *arg) +{ +#if 0 + int error; + + if ((flags & CRYPTO_F_SKBUF) != 0) + error = XXXXXX((struct mbuf *)buf, off, len, f, arg); + else if ((flags & CRYPTO_F_IOV) != 0) + error = cuio_apply((struct uio *)buf, off, len, f, arg); + else + error = (*f)(arg, buf + off, len); + return (error); +#else + KASSERT(0, ("crypto_apply not implemented!\n")); +#endif + return 0; +} + +EXPORT_SYMBOL(crypto_copyback); +EXPORT_SYMBOL(crypto_copydata); +EXPORT_SYMBOL(crypto_apply); + diff --git a/target/linux/generic/files/crypto/ocf/crypto.c b/target/linux/generic/files/crypto/ocf/crypto.c new file mode 100644 index 0000000..dab3427 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/crypto.c @@ -0,0 +1,1766 @@ +/*- + * Linux port done by David McCullough + * Copyright (C) 2006-2010 David McCullough + * Copyright (C) 2004-2005 Intel Corporation. + * The license and original author are listed below. + * + * Redistribution and use in source and binary forms, with or without + * Copyright (c) 2002-2006 Sam Leffler. All rights reserved. + * + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#if 0 +#include +__FBSDID("$FreeBSD: src/sys/opencrypto/crypto.c,v 1.27 2007/03/21 03:42:51 sam Exp $"); +#endif + +/* + * Cryptographic Subsystem. + * + * This code is derived from the Openbsd Cryptographic Framework (OCF) + * that has the copyright shown below. Very little of the original + * code remains. + */ +/*- + * The author of this code is Angelos D. Keromytis (angelos@cis.upenn.edu) + * + * This code was written by Angelos D. Keromytis in Athens, Greece, in + * February 2000. Network Security Technologies Inc. (NSTI) kindly + * supported the development of this code. + * + * Copyright (c) 2000, 2001 Angelos D. Keromytis + * + * Permission to use, copy, and modify this software with or without fee + * is hereby granted, provided that this entire notice is included in + * all source code copies of any software which is or includes a copy or + * modification of this software. + * + * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY + * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE + * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR + * PURPOSE. + * +__FBSDID("$FreeBSD: src/sys/opencrypto/crypto.c,v 1.16 2005/01/07 02:29:16 imp Exp $"); + */ + + +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) && !defined(AUTOCONF_INCLUDED) +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,4) +#include +#endif +#include + +/* + * keep track of whether or not we have been initialised, a big + * issue if we are linked into the kernel and a driver gets started before + * us + */ +static int crypto_initted = 0; + +/* + * Crypto drivers register themselves by allocating a slot in the + * crypto_drivers table with crypto_get_driverid() and then registering + * each algorithm they support with crypto_register() and crypto_kregister(). + */ + +/* + * lock on driver table + * we track its state as spin_is_locked does not do anything on non-SMP boxes + */ +static spinlock_t crypto_drivers_lock; +static int crypto_drivers_locked; /* for non-SMP boxes */ + +#define CRYPTO_DRIVER_LOCK() \ + ({ \ + spin_lock_irqsave(&crypto_drivers_lock, d_flags); \ + crypto_drivers_locked = 1; \ + dprintk("%s,%d: DRIVER_LOCK()\n", __FILE__, __LINE__); \ + }) +#define CRYPTO_DRIVER_UNLOCK() \ + ({ \ + dprintk("%s,%d: DRIVER_UNLOCK()\n", __FILE__, __LINE__); \ + crypto_drivers_locked = 0; \ + spin_unlock_irqrestore(&crypto_drivers_lock, d_flags); \ + }) +#define CRYPTO_DRIVER_ASSERT() \ + ({ \ + if (!crypto_drivers_locked) { \ + dprintk("%s,%d: DRIVER_ASSERT!\n", __FILE__, __LINE__); \ + } \ + }) + +/* + * Crypto device/driver capabilities structure. + * + * Synchronization: + * (d) - protected by CRYPTO_DRIVER_LOCK() + * (q) - protected by CRYPTO_Q_LOCK() + * Not tagged fields are read-only. + */ +struct cryptocap { + device_t cc_dev; /* (d) device/driver */ + u_int32_t cc_sessions; /* (d) # of sessions */ + u_int32_t cc_koperations; /* (d) # os asym operations */ + /* + * Largest possible operator length (in bits) for each type of + * encryption algorithm. XXX not used + */ + u_int16_t cc_max_op_len[CRYPTO_ALGORITHM_MAX + 1]; + u_int8_t cc_alg[CRYPTO_ALGORITHM_MAX + 1]; + u_int8_t cc_kalg[CRK_ALGORITHM_MAX + 1]; + + int cc_flags; /* (d) flags */ +#define CRYPTOCAP_F_CLEANUP 0x80000000 /* needs resource cleanup */ + int cc_qblocked; /* (q) symmetric q blocked */ + int cc_kqblocked; /* (q) asymmetric q blocked */ + + int cc_unqblocked; /* (q) symmetric q blocked */ + int cc_unkqblocked; /* (q) asymmetric q blocked */ +}; +static struct cryptocap *crypto_drivers = NULL; +static int crypto_drivers_num = 0; + +/* + * There are two queues for crypto requests; one for symmetric (e.g. + * cipher) operations and one for asymmetric (e.g. MOD)operations. + * A single mutex is used to lock access to both queues. We could + * have one per-queue but having one simplifies handling of block/unblock + * operations. + */ +static LIST_HEAD(crp_q); /* crypto request queue */ +static LIST_HEAD(crp_kq); /* asym request queue */ + +static spinlock_t crypto_q_lock; + +int crypto_all_qblocked = 0; /* protect with Q_LOCK */ +module_param(crypto_all_qblocked, int, 0444); +MODULE_PARM_DESC(crypto_all_qblocked, "Are all crypto queues blocked"); + +int crypto_all_kqblocked = 0; /* protect with Q_LOCK */ +module_param(crypto_all_kqblocked, int, 0444); +MODULE_PARM_DESC(crypto_all_kqblocked, "Are all asym crypto queues blocked"); + +#define CRYPTO_Q_LOCK() \ + ({ \ + spin_lock_irqsave(&crypto_q_lock, q_flags); \ + dprintk("%s,%d: Q_LOCK()\n", __FILE__, __LINE__); \ + }) +#define CRYPTO_Q_UNLOCK() \ + ({ \ + dprintk("%s,%d: Q_UNLOCK()\n", __FILE__, __LINE__); \ + spin_unlock_irqrestore(&crypto_q_lock, q_flags); \ + }) + +/* + * There are two queues for processing completed crypto requests; one + * for the symmetric and one for the asymmetric ops. We only need one + * but have two to avoid type futzing (cryptop vs. cryptkop). A single + * mutex is used to lock access to both queues. Note that this lock + * must be separate from the lock on request queues to insure driver + * callbacks don't generate lock order reversals. + */ +static LIST_HEAD(crp_ret_q); /* callback queues */ +static LIST_HEAD(crp_ret_kq); + +static spinlock_t crypto_ret_q_lock; +#define CRYPTO_RETQ_LOCK() \ + ({ \ + spin_lock_irqsave(&crypto_ret_q_lock, r_flags); \ + dprintk("%s,%d: RETQ_LOCK\n", __FILE__, __LINE__); \ + }) +#define CRYPTO_RETQ_UNLOCK() \ + ({ \ + dprintk("%s,%d: RETQ_UNLOCK\n", __FILE__, __LINE__); \ + spin_unlock_irqrestore(&crypto_ret_q_lock, r_flags); \ + }) +#define CRYPTO_RETQ_EMPTY() (list_empty(&crp_ret_q) && list_empty(&crp_ret_kq)) + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) +static kmem_cache_t *cryptop_zone; +static kmem_cache_t *cryptodesc_zone; +#else +static struct kmem_cache *cryptop_zone; +static struct kmem_cache *cryptodesc_zone; +#endif + +#define debug crypto_debug +int crypto_debug = 0; +module_param(crypto_debug, int, 0644); +MODULE_PARM_DESC(crypto_debug, "Enable debug"); +EXPORT_SYMBOL(crypto_debug); + +/* + * Maximum number of outstanding crypto requests before we start + * failing requests. We need this to prevent DOS when too many + * requests are arriving for us to keep up. Otherwise we will + * run the system out of memory. Since crypto is slow, we are + * usually the bottleneck that needs to say, enough is enough. + * + * We cannot print errors when this condition occurs, we are already too + * slow, printing anything will just kill us + */ + +static int crypto_q_cnt = 0; +module_param(crypto_q_cnt, int, 0444); +MODULE_PARM_DESC(crypto_q_cnt, + "Current number of outstanding crypto requests"); + +static int crypto_q_max = 1000; +module_param(crypto_q_max, int, 0644); +MODULE_PARM_DESC(crypto_q_max, + "Maximum number of outstanding crypto requests"); + +#define bootverbose crypto_verbose +static int crypto_verbose = 0; +module_param(crypto_verbose, int, 0644); +MODULE_PARM_DESC(crypto_verbose, + "Enable verbose crypto startup"); + +int crypto_usercrypto = 1; /* userland may do crypto reqs */ +module_param(crypto_usercrypto, int, 0644); +MODULE_PARM_DESC(crypto_usercrypto, + "Enable/disable user-mode access to crypto support"); + +int crypto_userasymcrypto = 1; /* userland may do asym crypto reqs */ +module_param(crypto_userasymcrypto, int, 0644); +MODULE_PARM_DESC(crypto_userasymcrypto, + "Enable/disable user-mode access to asymmetric crypto support"); + +int crypto_devallowsoft = 0; /* only use hardware crypto */ +module_param(crypto_devallowsoft, int, 0644); +MODULE_PARM_DESC(crypto_devallowsoft, + "Enable/disable use of software crypto support"); + +/* + * This parameter controls the maximum number of crypto operations to + * do consecutively in the crypto kernel thread before scheduling to allow + * other processes to run. Without it, it is possible to get into a + * situation where the crypto thread never allows any other processes to run. + * Default to 1000 which should be less than one second. + */ +static int crypto_max_loopcount = 1000; +module_param(crypto_max_loopcount, int, 0644); +MODULE_PARM_DESC(crypto_max_loopcount, + "Maximum number of crypto ops to do before yielding to other processes"); + +#ifndef CONFIG_NR_CPUS +#define CONFIG_NR_CPUS 1 +#endif + +static struct task_struct *cryptoproc[CONFIG_NR_CPUS]; +static struct task_struct *cryptoretproc[CONFIG_NR_CPUS]; +static DECLARE_WAIT_QUEUE_HEAD(cryptoproc_wait); +static DECLARE_WAIT_QUEUE_HEAD(cryptoretproc_wait); + +static int crypto_proc(void *arg); +static int crypto_ret_proc(void *arg); +static int crypto_invoke(struct cryptocap *cap, struct cryptop *crp, int hint); +static int crypto_kinvoke(struct cryptkop *krp, int flags); +static void crypto_exit(void); +static int crypto_init(void); + +static struct cryptostats cryptostats; + +static struct cryptocap * +crypto_checkdriver(u_int32_t hid) +{ + if (crypto_drivers == NULL) + return NULL; + return (hid >= crypto_drivers_num ? NULL : &crypto_drivers[hid]); +} + +/* + * Compare a driver's list of supported algorithms against another + * list; return non-zero if all algorithms are supported. + */ +static int +driver_suitable(const struct cryptocap *cap, const struct cryptoini *cri) +{ + const struct cryptoini *cr; + + /* See if all the algorithms are supported. */ + for (cr = cri; cr; cr = cr->cri_next) + if (cap->cc_alg[cr->cri_alg] == 0) + return 0; + return 1; +} + + +/* + * Select a driver for a new session that supports the specified + * algorithms and, optionally, is constrained according to the flags. + * The algorithm we use here is pretty stupid; just use the + * first driver that supports all the algorithms we need. If there + * are multiple drivers we choose the driver with the fewest active + * sessions. We prefer hardware-backed drivers to software ones. + * + * XXX We need more smarts here (in real life too, but that's + * XXX another story altogether). + */ +static struct cryptocap * +crypto_select_driver(const struct cryptoini *cri, int flags) +{ + struct cryptocap *cap, *best; + int match, hid; + + CRYPTO_DRIVER_ASSERT(); + + /* + * Look first for hardware crypto devices if permitted. + */ + if (flags & CRYPTOCAP_F_HARDWARE) + match = CRYPTOCAP_F_HARDWARE; + else + match = CRYPTOCAP_F_SOFTWARE; + best = NULL; +again: + for (hid = 0; hid < crypto_drivers_num; hid++) { + cap = &crypto_drivers[hid]; + /* + * If it's not initialized, is in the process of + * going away, or is not appropriate (hardware + * or software based on match), then skip. + */ + if (cap->cc_dev == NULL || + (cap->cc_flags & CRYPTOCAP_F_CLEANUP) || + (cap->cc_flags & match) == 0) + continue; + + /* verify all the algorithms are supported. */ + if (driver_suitable(cap, cri)) { + if (best == NULL || + cap->cc_sessions < best->cc_sessions) + best = cap; + } + } + if (best != NULL) + return best; + if (match == CRYPTOCAP_F_HARDWARE && (flags & CRYPTOCAP_F_SOFTWARE)) { + /* sort of an Algol 68-style for loop */ + match = CRYPTOCAP_F_SOFTWARE; + goto again; + } + return best; +} + +/* + * Create a new session. The crid argument specifies a crypto + * driver to use or constraints on a driver to select (hardware + * only, software only, either). Whatever driver is selected + * must be capable of the requested crypto algorithms. + */ +int +crypto_newsession(u_int64_t *sid, struct cryptoini *cri, int crid) +{ + struct cryptocap *cap; + u_int32_t hid, lid; + int err; + unsigned long d_flags; + + CRYPTO_DRIVER_LOCK(); + if ((crid & (CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE)) == 0) { + /* + * Use specified driver; verify it is capable. + */ + cap = crypto_checkdriver(crid); + if (cap != NULL && !driver_suitable(cap, cri)) + cap = NULL; + } else { + /* + * No requested driver; select based on crid flags. + */ + cap = crypto_select_driver(cri, crid); + /* + * if NULL then can't do everything in one session. + * XXX Fix this. We need to inject a "virtual" session + * XXX layer right about here. + */ + } + if (cap != NULL) { + /* Call the driver initialization routine. */ + hid = cap - crypto_drivers; + lid = hid; /* Pass the driver ID. */ + cap->cc_sessions++; + CRYPTO_DRIVER_UNLOCK(); + err = CRYPTODEV_NEWSESSION(cap->cc_dev, &lid, cri); + CRYPTO_DRIVER_LOCK(); + if (err == 0) { + (*sid) = (cap->cc_flags & 0xff000000) + | (hid & 0x00ffffff); + (*sid) <<= 32; + (*sid) |= (lid & 0xffffffff); + } else + cap->cc_sessions--; + } else + err = EINVAL; + CRYPTO_DRIVER_UNLOCK(); + return err; +} + +static void +crypto_remove(struct cryptocap *cap) +{ + CRYPTO_DRIVER_ASSERT(); + if (cap->cc_sessions == 0 && cap->cc_koperations == 0) + bzero(cap, sizeof(*cap)); +} + +/* + * Delete an existing session (or a reserved session on an unregistered + * driver). + */ +int +crypto_freesession(u_int64_t sid) +{ + struct cryptocap *cap; + u_int32_t hid; + int err = 0; + unsigned long d_flags; + + dprintk("%s()\n", __FUNCTION__); + CRYPTO_DRIVER_LOCK(); + + if (crypto_drivers == NULL) { + err = EINVAL; + goto done; + } + + /* Determine two IDs. */ + hid = CRYPTO_SESID2HID(sid); + + if (hid >= crypto_drivers_num) { + dprintk("%s - INVALID DRIVER NUM %d\n", __FUNCTION__, hid); + err = ENOENT; + goto done; + } + cap = &crypto_drivers[hid]; + + if (cap->cc_dev) { + CRYPTO_DRIVER_UNLOCK(); + /* Call the driver cleanup routine, if available, unlocked. */ + err = CRYPTODEV_FREESESSION(cap->cc_dev, sid); + CRYPTO_DRIVER_LOCK(); + } + + if (cap->cc_sessions) + cap->cc_sessions--; + + if (cap->cc_flags & CRYPTOCAP_F_CLEANUP) + crypto_remove(cap); + +done: + CRYPTO_DRIVER_UNLOCK(); + return err; +} + +/* + * Return an unused driver id. Used by drivers prior to registering + * support for the algorithms they handle. + */ +int32_t +crypto_get_driverid(device_t dev, int flags) +{ + struct cryptocap *newdrv; + int i; + unsigned long d_flags; + + if ((flags & (CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE)) == 0) { + printf("%s: no flags specified when registering driver\n", + device_get_nameunit(dev)); + return -1; + } + + CRYPTO_DRIVER_LOCK(); + + for (i = 0; i < crypto_drivers_num; i++) { + if (crypto_drivers[i].cc_dev == NULL && + (crypto_drivers[i].cc_flags & CRYPTOCAP_F_CLEANUP) == 0) { + break; + } + } + + /* Out of entries, allocate some more. */ + if (i == crypto_drivers_num) { + /* Be careful about wrap-around. */ + if (2 * crypto_drivers_num <= crypto_drivers_num) { + CRYPTO_DRIVER_UNLOCK(); + printk("crypto: driver count wraparound!\n"); + return -1; + } + + newdrv = kmalloc(2 * crypto_drivers_num * sizeof(struct cryptocap), + GFP_KERNEL); + if (newdrv == NULL) { + CRYPTO_DRIVER_UNLOCK(); + printk("crypto: no space to expand driver table!\n"); + return -1; + } + + memcpy(newdrv, crypto_drivers, + crypto_drivers_num * sizeof(struct cryptocap)); + memset(&newdrv[crypto_drivers_num], 0, + crypto_drivers_num * sizeof(struct cryptocap)); + + crypto_drivers_num *= 2; + + kfree(crypto_drivers); + crypto_drivers = newdrv; + } + + /* NB: state is zero'd on free */ + crypto_drivers[i].cc_sessions = 1; /* Mark */ + crypto_drivers[i].cc_dev = dev; + crypto_drivers[i].cc_flags = flags; + if (bootverbose) + printf("crypto: assign %s driver id %u, flags %u\n", + device_get_nameunit(dev), i, flags); + + CRYPTO_DRIVER_UNLOCK(); + + return i; +} + +/* + * Lookup a driver by name. We match against the full device + * name and unit, and against just the name. The latter gives + * us a simple widlcarding by device name. On success return the + * driver/hardware identifier; otherwise return -1. + */ +int +crypto_find_driver(const char *match) +{ + int i, len = strlen(match); + unsigned long d_flags; + + CRYPTO_DRIVER_LOCK(); + for (i = 0; i < crypto_drivers_num; i++) { + device_t dev = crypto_drivers[i].cc_dev; + if (dev == NULL || + (crypto_drivers[i].cc_flags & CRYPTOCAP_F_CLEANUP)) + continue; + if (strncmp(match, device_get_nameunit(dev), len) == 0 || + strncmp(match, device_get_name(dev), len) == 0) + break; + } + CRYPTO_DRIVER_UNLOCK(); + return i < crypto_drivers_num ? i : -1; +} + +/* + * Return the device_t for the specified driver or NULL + * if the driver identifier is invalid. + */ +device_t +crypto_find_device_byhid(int hid) +{ + struct cryptocap *cap = crypto_checkdriver(hid); + return cap != NULL ? cap->cc_dev : NULL; +} + +/* + * Return the device/driver capabilities. + */ +int +crypto_getcaps(int hid) +{ + struct cryptocap *cap = crypto_checkdriver(hid); + return cap != NULL ? cap->cc_flags : 0; +} + +/* + * Register support for a key-related algorithm. This routine + * is called once for each algorithm supported a driver. + */ +int +crypto_kregister(u_int32_t driverid, int kalg, u_int32_t flags) +{ + struct cryptocap *cap; + int err; + unsigned long d_flags; + + dprintk("%s()\n", __FUNCTION__); + CRYPTO_DRIVER_LOCK(); + + cap = crypto_checkdriver(driverid); + if (cap != NULL && + (CRK_ALGORITM_MIN <= kalg && kalg <= CRK_ALGORITHM_MAX)) { + /* + * XXX Do some performance testing to determine placing. + * XXX We probably need an auxiliary data structure that + * XXX describes relative performances. + */ + + cap->cc_kalg[kalg] = flags | CRYPTO_ALG_FLAG_SUPPORTED; + if (bootverbose) + printf("crypto: %s registers key alg %u flags %u\n" + , device_get_nameunit(cap->cc_dev) + , kalg + , flags + ); + err = 0; + } else + err = EINVAL; + + CRYPTO_DRIVER_UNLOCK(); + return err; +} + +/* + * Register support for a non-key-related algorithm. This routine + * is called once for each such algorithm supported by a driver. + */ +int +crypto_register(u_int32_t driverid, int alg, u_int16_t maxoplen, + u_int32_t flags) +{ + struct cryptocap *cap; + int err; + unsigned long d_flags; + + dprintk("%s(id=0x%x, alg=%d, maxoplen=%d, flags=0x%x)\n", __FUNCTION__, + driverid, alg, maxoplen, flags); + + CRYPTO_DRIVER_LOCK(); + + cap = crypto_checkdriver(driverid); + /* NB: algorithms are in the range [1..max] */ + if (cap != NULL && + (CRYPTO_ALGORITHM_MIN <= alg && alg <= CRYPTO_ALGORITHM_MAX)) { + /* + * XXX Do some performance testing to determine placing. + * XXX We probably need an auxiliary data structure that + * XXX describes relative performances. + */ + + cap->cc_alg[alg] = flags | CRYPTO_ALG_FLAG_SUPPORTED; + cap->cc_max_op_len[alg] = maxoplen; + if (bootverbose) + printf("crypto: %s registers alg %u flags %u maxoplen %u\n" + , device_get_nameunit(cap->cc_dev) + , alg + , flags + , maxoplen + ); + cap->cc_sessions = 0; /* Unmark */ + err = 0; + } else + err = EINVAL; + + CRYPTO_DRIVER_UNLOCK(); + return err; +} + +static void +driver_finis(struct cryptocap *cap) +{ + u_int32_t ses, kops; + + CRYPTO_DRIVER_ASSERT(); + + ses = cap->cc_sessions; + kops = cap->cc_koperations; + bzero(cap, sizeof(*cap)); + if (ses != 0 || kops != 0) { + /* + * If there are pending sessions, + * just mark as invalid. + */ + cap->cc_flags |= CRYPTOCAP_F_CLEANUP; + cap->cc_sessions = ses; + cap->cc_koperations = kops; + } +} + +/* + * Unregister a crypto driver. If there are pending sessions using it, + * leave enough information around so that subsequent calls using those + * sessions will correctly detect the driver has been unregistered and + * reroute requests. + */ +int +crypto_unregister(u_int32_t driverid, int alg) +{ + struct cryptocap *cap; + int i, err; + unsigned long d_flags; + + dprintk("%s()\n", __FUNCTION__); + CRYPTO_DRIVER_LOCK(); + + cap = crypto_checkdriver(driverid); + if (cap != NULL && + (CRYPTO_ALGORITHM_MIN <= alg && alg <= CRYPTO_ALGORITHM_MAX) && + cap->cc_alg[alg] != 0) { + cap->cc_alg[alg] = 0; + cap->cc_max_op_len[alg] = 0; + + /* Was this the last algorithm ? */ + for (i = 1; i <= CRYPTO_ALGORITHM_MAX; i++) + if (cap->cc_alg[i] != 0) + break; + + if (i == CRYPTO_ALGORITHM_MAX + 1) + driver_finis(cap); + err = 0; + } else + err = EINVAL; + CRYPTO_DRIVER_UNLOCK(); + return err; +} + +/* + * Unregister all algorithms associated with a crypto driver. + * If there are pending sessions using it, leave enough information + * around so that subsequent calls using those sessions will + * correctly detect the driver has been unregistered and reroute + * requests. + */ +int +crypto_unregister_all(u_int32_t driverid) +{ + struct cryptocap *cap; + int err; + unsigned long d_flags; + + dprintk("%s()\n", __FUNCTION__); + CRYPTO_DRIVER_LOCK(); + cap = crypto_checkdriver(driverid); + if (cap != NULL) { + driver_finis(cap); + err = 0; + } else + err = EINVAL; + CRYPTO_DRIVER_UNLOCK(); + + return err; +} + +/* + * Clear blockage on a driver. The what parameter indicates whether + * the driver is now ready for cryptop's and/or cryptokop's. + */ +int +crypto_unblock(u_int32_t driverid, int what) +{ + struct cryptocap *cap; + int err; + unsigned long q_flags; + + CRYPTO_Q_LOCK(); + cap = crypto_checkdriver(driverid); + if (cap != NULL) { + if (what & CRYPTO_SYMQ) { + cap->cc_qblocked = 0; + cap->cc_unqblocked = 0; + crypto_all_qblocked = 0; + } + if (what & CRYPTO_ASYMQ) { + cap->cc_kqblocked = 0; + cap->cc_unkqblocked = 0; + crypto_all_kqblocked = 0; + } + wake_up_interruptible(&cryptoproc_wait); + err = 0; + } else + err = EINVAL; + CRYPTO_Q_UNLOCK(); //DAVIDM should this be a driver lock + + return err; +} + +/* + * Add a crypto request to a queue, to be processed by the kernel thread. + */ +int +crypto_dispatch(struct cryptop *crp) +{ + struct cryptocap *cap; + int result = -1; + unsigned long q_flags; + + dprintk("%s()\n", __FUNCTION__); + + cryptostats.cs_ops++; + + CRYPTO_Q_LOCK(); + if (crypto_q_cnt >= crypto_q_max) { + cryptostats.cs_drops++; + CRYPTO_Q_UNLOCK(); + return ENOMEM; + } + crypto_q_cnt++; + + /* make sure we are starting a fresh run on this crp. */ + crp->crp_flags &= ~CRYPTO_F_DONE; + crp->crp_etype = 0; + + /* + * Caller marked the request to be processed immediately; dispatch + * it directly to the driver unless the driver is currently blocked. + */ + if ((crp->crp_flags & CRYPTO_F_BATCH) == 0) { + int hid = CRYPTO_SESID2HID(crp->crp_sid); + cap = crypto_checkdriver(hid); + /* Driver cannot disappear when there is an active session. */ + KASSERT(cap != NULL, ("%s: Driver disappeared.", __func__)); + if (!cap->cc_qblocked) { + crypto_all_qblocked = 0; + crypto_drivers[hid].cc_unqblocked = 1; + CRYPTO_Q_UNLOCK(); + result = crypto_invoke(cap, crp, 0); + CRYPTO_Q_LOCK(); + if (result == ERESTART) + if (crypto_drivers[hid].cc_unqblocked) + crypto_drivers[hid].cc_qblocked = 1; + crypto_drivers[hid].cc_unqblocked = 0; + } + } + if (result == ERESTART) { + /* + * The driver ran out of resources, mark the + * driver ``blocked'' for cryptop's and put + * the request back in the queue. It would + * best to put the request back where we got + * it but that's hard so for now we put it + * at the front. This should be ok; putting + * it at the end does not work. + */ + list_add(&crp->crp_next, &crp_q); + cryptostats.cs_blocks++; + result = 0; + } else if (result == -1) { + TAILQ_INSERT_TAIL(&crp_q, crp, crp_next); + result = 0; + } + wake_up_interruptible(&cryptoproc_wait); + CRYPTO_Q_UNLOCK(); + return result; +} + +/* + * Add an asymetric crypto request to a queue, + * to be processed by the kernel thread. + */ +int +crypto_kdispatch(struct cryptkop *krp) +{ + int error; + unsigned long q_flags; + + cryptostats.cs_kops++; + + error = crypto_kinvoke(krp, krp->krp_crid); + if (error == ERESTART) { + CRYPTO_Q_LOCK(); + TAILQ_INSERT_TAIL(&crp_kq, krp, krp_next); + wake_up_interruptible(&cryptoproc_wait); + CRYPTO_Q_UNLOCK(); + error = 0; + } + return error; +} + +/* + * Verify a driver is suitable for the specified operation. + */ +static __inline int +kdriver_suitable(const struct cryptocap *cap, const struct cryptkop *krp) +{ + return (cap->cc_kalg[krp->krp_op] & CRYPTO_ALG_FLAG_SUPPORTED) != 0; +} + +/* + * Select a driver for an asym operation. The driver must + * support the necessary algorithm. The caller can constrain + * which device is selected with the flags parameter. The + * algorithm we use here is pretty stupid; just use the first + * driver that supports the algorithms we need. If there are + * multiple suitable drivers we choose the driver with the + * fewest active operations. We prefer hardware-backed + * drivers to software ones when either may be used. + */ +static struct cryptocap * +crypto_select_kdriver(const struct cryptkop *krp, int flags) +{ + struct cryptocap *cap, *best, *blocked; + int match, hid; + + CRYPTO_DRIVER_ASSERT(); + + /* + * Look first for hardware crypto devices if permitted. + */ + if (flags & CRYPTOCAP_F_HARDWARE) + match = CRYPTOCAP_F_HARDWARE; + else + match = CRYPTOCAP_F_SOFTWARE; + best = NULL; + blocked = NULL; +again: + for (hid = 0; hid < crypto_drivers_num; hid++) { + cap = &crypto_drivers[hid]; + /* + * If it's not initialized, is in the process of + * going away, or is not appropriate (hardware + * or software based on match), then skip. + */ + if (cap->cc_dev == NULL || + (cap->cc_flags & CRYPTOCAP_F_CLEANUP) || + (cap->cc_flags & match) == 0) + continue; + + /* verify all the algorithms are supported. */ + if (kdriver_suitable(cap, krp)) { + if (best == NULL || + cap->cc_koperations < best->cc_koperations) + best = cap; + } + } + if (best != NULL) + return best; + if (match == CRYPTOCAP_F_HARDWARE && (flags & CRYPTOCAP_F_SOFTWARE)) { + /* sort of an Algol 68-style for loop */ + match = CRYPTOCAP_F_SOFTWARE; + goto again; + } + return best; +} + +/* + * Dispatch an assymetric crypto request. + */ +static int +crypto_kinvoke(struct cryptkop *krp, int crid) +{ + struct cryptocap *cap = NULL; + int error; + unsigned long d_flags; + + KASSERT(krp != NULL, ("%s: krp == NULL", __func__)); + KASSERT(krp->krp_callback != NULL, + ("%s: krp->crp_callback == NULL", __func__)); + + CRYPTO_DRIVER_LOCK(); + if ((crid & (CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE)) == 0) { + cap = crypto_checkdriver(crid); + if (cap != NULL) { + /* + * Driver present, it must support the necessary + * algorithm and, if s/w drivers are excluded, + * it must be registered as hardware-backed. + */ + if (!kdriver_suitable(cap, krp) || + (!crypto_devallowsoft && + (cap->cc_flags & CRYPTOCAP_F_HARDWARE) == 0)) + cap = NULL; + } + } else { + /* + * No requested driver; select based on crid flags. + */ + if (!crypto_devallowsoft) /* NB: disallow s/w drivers */ + crid &= ~CRYPTOCAP_F_SOFTWARE; + cap = crypto_select_kdriver(krp, crid); + } + if (cap != NULL && !cap->cc_kqblocked) { + krp->krp_hid = cap - crypto_drivers; + cap->cc_koperations++; + CRYPTO_DRIVER_UNLOCK(); + error = CRYPTODEV_KPROCESS(cap->cc_dev, krp, 0); + CRYPTO_DRIVER_LOCK(); + if (error == ERESTART) { + cap->cc_koperations--; + CRYPTO_DRIVER_UNLOCK(); + return (error); + } + /* return the actual device used */ + krp->krp_crid = krp->krp_hid; + } else { + /* + * NB: cap is !NULL if device is blocked; in + * that case return ERESTART so the operation + * is resubmitted if possible. + */ + error = (cap == NULL) ? ENODEV : ERESTART; + } + CRYPTO_DRIVER_UNLOCK(); + + if (error) { + krp->krp_status = error; + crypto_kdone(krp); + } + return 0; +} + + +/* + * Dispatch a crypto request to the appropriate crypto devices. + */ +static int +crypto_invoke(struct cryptocap *cap, struct cryptop *crp, int hint) +{ + KASSERT(crp != NULL, ("%s: crp == NULL", __func__)); + KASSERT(crp->crp_callback != NULL, + ("%s: crp->crp_callback == NULL", __func__)); + KASSERT(crp->crp_desc != NULL, ("%s: crp->crp_desc == NULL", __func__)); + + dprintk("%s()\n", __FUNCTION__); + +#ifdef CRYPTO_TIMING + if (crypto_timing) + crypto_tstat(&cryptostats.cs_invoke, &crp->crp_tstamp); +#endif + if (cap->cc_flags & CRYPTOCAP_F_CLEANUP) { + struct cryptodesc *crd; + u_int64_t nid; + + /* + * Driver has unregistered; migrate the session and return + * an error to the caller so they'll resubmit the op. + * + * XXX: What if there are more already queued requests for this + * session? + */ + crypto_freesession(crp->crp_sid); + + for (crd = crp->crp_desc; crd->crd_next; crd = crd->crd_next) + crd->CRD_INI.cri_next = &(crd->crd_next->CRD_INI); + + /* XXX propagate flags from initial session? */ + if (crypto_newsession(&nid, &(crp->crp_desc->CRD_INI), + CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE) == 0) + crp->crp_sid = nid; + + crp->crp_etype = EAGAIN; + crypto_done(crp); + return 0; + } else { + /* + * Invoke the driver to process the request. + */ + return CRYPTODEV_PROCESS(cap->cc_dev, crp, hint); + } +} + +/* + * Release a set of crypto descriptors. + */ +void +crypto_freereq(struct cryptop *crp) +{ + struct cryptodesc *crd; + + if (crp == NULL) + return; + +#ifdef DIAGNOSTIC + { + struct cryptop *crp2; + unsigned long q_flags; + + CRYPTO_Q_LOCK(); + TAILQ_FOREACH(crp2, &crp_q, crp_next) { + KASSERT(crp2 != crp, + ("Freeing cryptop from the crypto queue (%p).", + crp)); + } + CRYPTO_Q_UNLOCK(); + CRYPTO_RETQ_LOCK(); + TAILQ_FOREACH(crp2, &crp_ret_q, crp_next) { + KASSERT(crp2 != crp, + ("Freeing cryptop from the return queue (%p).", + crp)); + } + CRYPTO_RETQ_UNLOCK(); + } +#endif + + while ((crd = crp->crp_desc) != NULL) { + crp->crp_desc = crd->crd_next; + kmem_cache_free(cryptodesc_zone, crd); + } + kmem_cache_free(cryptop_zone, crp); +} + +/* + * Acquire a set of crypto descriptors. + */ +struct cryptop * +crypto_getreq(int num) +{ + struct cryptodesc *crd; + struct cryptop *crp; + + crp = kmem_cache_alloc(cryptop_zone, SLAB_ATOMIC); + if (crp != NULL) { + memset(crp, 0, sizeof(*crp)); + INIT_LIST_HEAD(&crp->crp_next); + init_waitqueue_head(&crp->crp_waitq); + while (num--) { + crd = kmem_cache_alloc(cryptodesc_zone, SLAB_ATOMIC); + if (crd == NULL) { + crypto_freereq(crp); + return NULL; + } + memset(crd, 0, sizeof(*crd)); + crd->crd_next = crp->crp_desc; + crp->crp_desc = crd; + } + } + return crp; +} + +/* + * Invoke the callback on behalf of the driver. + */ +void +crypto_done(struct cryptop *crp) +{ + unsigned long q_flags; + + dprintk("%s()\n", __FUNCTION__); + if ((crp->crp_flags & CRYPTO_F_DONE) == 0) { + crp->crp_flags |= CRYPTO_F_DONE; + CRYPTO_Q_LOCK(); + crypto_q_cnt--; + CRYPTO_Q_UNLOCK(); + } else + printk("crypto: crypto_done op already done, flags 0x%x", + crp->crp_flags); + if (crp->crp_etype != 0) + cryptostats.cs_errs++; + /* + * CBIMM means unconditionally do the callback immediately; + * CBIFSYNC means do the callback immediately only if the + * operation was done synchronously. Both are used to avoid + * doing extraneous context switches; the latter is mostly + * used with the software crypto driver. + */ + if ((crp->crp_flags & CRYPTO_F_CBIMM) || + ((crp->crp_flags & CRYPTO_F_CBIFSYNC) && + (CRYPTO_SESID2CAPS(crp->crp_sid) & CRYPTOCAP_F_SYNC))) { + /* + * Do the callback directly. This is ok when the + * callback routine does very little (e.g. the + * /dev/crypto callback method just does a wakeup). + */ + crp->crp_callback(crp); + } else { + unsigned long r_flags; + /* + * Normal case; queue the callback for the thread. + */ + CRYPTO_RETQ_LOCK(); + wake_up_interruptible(&cryptoretproc_wait);/* shared wait channel */ + TAILQ_INSERT_TAIL(&crp_ret_q, crp, crp_next); + CRYPTO_RETQ_UNLOCK(); + } +} + +/* + * Invoke the callback on behalf of the driver. + */ +void +crypto_kdone(struct cryptkop *krp) +{ + struct cryptocap *cap; + unsigned long d_flags; + + if ((krp->krp_flags & CRYPTO_KF_DONE) != 0) + printk("crypto: crypto_kdone op already done, flags 0x%x", + krp->krp_flags); + krp->krp_flags |= CRYPTO_KF_DONE; + if (krp->krp_status != 0) + cryptostats.cs_kerrs++; + + CRYPTO_DRIVER_LOCK(); + /* XXX: What if driver is loaded in the meantime? */ + if (krp->krp_hid < crypto_drivers_num) { + cap = &crypto_drivers[krp->krp_hid]; + cap->cc_koperations--; + KASSERT(cap->cc_koperations >= 0, ("cc_koperations < 0")); + if (cap->cc_flags & CRYPTOCAP_F_CLEANUP) + crypto_remove(cap); + } + CRYPTO_DRIVER_UNLOCK(); + + /* + * CBIMM means unconditionally do the callback immediately; + * This is used to avoid doing extraneous context switches + */ + if ((krp->krp_flags & CRYPTO_KF_CBIMM)) { + /* + * Do the callback directly. This is ok when the + * callback routine does very little (e.g. the + * /dev/crypto callback method just does a wakeup). + */ + krp->krp_callback(krp); + } else { + unsigned long r_flags; + /* + * Normal case; queue the callback for the thread. + */ + CRYPTO_RETQ_LOCK(); + wake_up_interruptible(&cryptoretproc_wait);/* shared wait channel */ + TAILQ_INSERT_TAIL(&crp_ret_kq, krp, krp_next); + CRYPTO_RETQ_UNLOCK(); + } +} + +int +crypto_getfeat(int *featp) +{ + int hid, kalg, feat = 0; + unsigned long d_flags; + + CRYPTO_DRIVER_LOCK(); + for (hid = 0; hid < crypto_drivers_num; hid++) { + const struct cryptocap *cap = &crypto_drivers[hid]; + + if ((cap->cc_flags & CRYPTOCAP_F_SOFTWARE) && + !crypto_devallowsoft) { + continue; + } + for (kalg = 0; kalg < CRK_ALGORITHM_MAX; kalg++) + if (cap->cc_kalg[kalg] & CRYPTO_ALG_FLAG_SUPPORTED) + feat |= 1 << kalg; + } + CRYPTO_DRIVER_UNLOCK(); + *featp = feat; + return (0); +} + +/* + * Crypto thread, dispatches crypto requests. + */ +static int +crypto_proc(void *arg) +{ + struct cryptop *crp, *submit; + struct cryptkop *krp, *krpp; + struct cryptocap *cap; + u_int32_t hid; + int result, hint; + unsigned long q_flags; + int loopcount = 0; + + set_current_state(TASK_INTERRUPTIBLE); + + CRYPTO_Q_LOCK(); + for (;;) { + /* + * we need to make sure we don't get into a busy loop with nothing + * to do, the two crypto_all_*blocked vars help us find out when + * we are all full and can do nothing on any driver or Q. If so we + * wait for an unblock. + */ + crypto_all_qblocked = !list_empty(&crp_q); + + /* + * Find the first element in the queue that can be + * processed and look-ahead to see if multiple ops + * are ready for the same driver. + */ + submit = NULL; + hint = 0; + list_for_each_entry(crp, &crp_q, crp_next) { + hid = CRYPTO_SESID2HID(crp->crp_sid); + cap = crypto_checkdriver(hid); + /* + * Driver cannot disappear when there is an active + * session. + */ + KASSERT(cap != NULL, ("%s:%u Driver disappeared.", + __func__, __LINE__)); + if (cap == NULL || cap->cc_dev == NULL) { + /* Op needs to be migrated, process it. */ + if (submit == NULL) + submit = crp; + break; + } + if (!cap->cc_qblocked) { + if (submit != NULL) { + /* + * We stop on finding another op, + * regardless whether its for the same + * driver or not. We could keep + * searching the queue but it might be + * better to just use a per-driver + * queue instead. + */ + if (CRYPTO_SESID2HID(submit->crp_sid) == hid) + hint = CRYPTO_HINT_MORE; + break; + } else { + submit = crp; + if ((submit->crp_flags & CRYPTO_F_BATCH) == 0) + break; + /* keep scanning for more are q'd */ + } + } + } + if (submit != NULL) { + hid = CRYPTO_SESID2HID(submit->crp_sid); + crypto_all_qblocked = 0; + list_del(&submit->crp_next); + crypto_drivers[hid].cc_unqblocked = 1; + cap = crypto_checkdriver(hid); + CRYPTO_Q_UNLOCK(); + KASSERT(cap != NULL, ("%s:%u Driver disappeared.", + __func__, __LINE__)); + result = crypto_invoke(cap, submit, hint); + CRYPTO_Q_LOCK(); + if (result == ERESTART) { + /* + * The driver ran out of resources, mark the + * driver ``blocked'' for cryptop's and put + * the request back in the queue. It would + * best to put the request back where we got + * it but that's hard so for now we put it + * at the front. This should be ok; putting + * it at the end does not work. + */ + /* XXX validate sid again? */ + list_add(&submit->crp_next, &crp_q); + cryptostats.cs_blocks++; + if (crypto_drivers[hid].cc_unqblocked) + crypto_drivers[hid].cc_qblocked=0; + crypto_drivers[hid].cc_unqblocked=0; + } + crypto_drivers[hid].cc_unqblocked = 0; + } + + crypto_all_kqblocked = !list_empty(&crp_kq); + + /* As above, but for key ops */ + krp = NULL; + list_for_each_entry(krpp, &crp_kq, krp_next) { + cap = crypto_checkdriver(krpp->krp_hid); + if (cap == NULL || cap->cc_dev == NULL) { + /* + * Operation needs to be migrated, invalidate + * the assigned device so it will reselect a + * new one below. Propagate the original + * crid selection flags if supplied. + */ + krp->krp_hid = krp->krp_crid & + (CRYPTOCAP_F_SOFTWARE|CRYPTOCAP_F_HARDWARE); + if (krp->krp_hid == 0) + krp->krp_hid = + CRYPTOCAP_F_SOFTWARE|CRYPTOCAP_F_HARDWARE; + break; + } + if (!cap->cc_kqblocked) { + krp = krpp; + break; + } + } + if (krp != NULL) { + crypto_all_kqblocked = 0; + list_del(&krp->krp_next); + crypto_drivers[krp->krp_hid].cc_kqblocked = 1; + CRYPTO_Q_UNLOCK(); + result = crypto_kinvoke(krp, krp->krp_hid); + CRYPTO_Q_LOCK(); + if (result == ERESTART) { + /* + * The driver ran out of resources, mark the + * driver ``blocked'' for cryptkop's and put + * the request back in the queue. It would + * best to put the request back where we got + * it but that's hard so for now we put it + * at the front. This should be ok; putting + * it at the end does not work. + */ + /* XXX validate sid again? */ + list_add(&krp->krp_next, &crp_kq); + cryptostats.cs_kblocks++; + } else + crypto_drivers[krp->krp_hid].cc_kqblocked = 0; + } + + if (submit == NULL && krp == NULL) { + /* + * Nothing more to be processed. Sleep until we're + * woken because there are more ops to process. + * This happens either by submission or by a driver + * becoming unblocked and notifying us through + * crypto_unblock. Note that when we wakeup we + * start processing each queue again from the + * front. It's not clear that it's important to + * preserve this ordering since ops may finish + * out of order if dispatched to different devices + * and some become blocked while others do not. + */ + dprintk("%s - sleeping (qe=%d qb=%d kqe=%d kqb=%d)\n", + __FUNCTION__, + list_empty(&crp_q), crypto_all_qblocked, + list_empty(&crp_kq), crypto_all_kqblocked); + loopcount = 0; + CRYPTO_Q_UNLOCK(); + wait_event_interruptible(cryptoproc_wait, + !(list_empty(&crp_q) || crypto_all_qblocked) || + !(list_empty(&crp_kq) || crypto_all_kqblocked) || + kthread_should_stop()); + if (signal_pending (current)) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) + spin_lock_irq(¤t->sigmask_lock); +#endif + flush_signals(current); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) + spin_unlock_irq(¤t->sigmask_lock); +#endif + } + CRYPTO_Q_LOCK(); + dprintk("%s - awake\n", __FUNCTION__); + if (kthread_should_stop()) + break; + cryptostats.cs_intrs++; + } else if (loopcount > crypto_max_loopcount) { + /* + * Give other processes a chance to run if we've + * been using the CPU exclusively for a while. + */ + loopcount = 0; + CRYPTO_Q_UNLOCK(); + schedule(); + CRYPTO_Q_LOCK(); + } + loopcount++; + } + CRYPTO_Q_UNLOCK(); + return 0; +} + +/* + * Crypto returns thread, does callbacks for processed crypto requests. + * Callbacks are done here, rather than in the crypto drivers, because + * callbacks typically are expensive and would slow interrupt handling. + */ +static int +crypto_ret_proc(void *arg) +{ + struct cryptop *crpt; + struct cryptkop *krpt; + unsigned long r_flags; + + set_current_state(TASK_INTERRUPTIBLE); + + CRYPTO_RETQ_LOCK(); + for (;;) { + /* Harvest return q's for completed ops */ + crpt = NULL; + if (!list_empty(&crp_ret_q)) + crpt = list_entry(crp_ret_q.next, typeof(*crpt), crp_next); + if (crpt != NULL) + list_del(&crpt->crp_next); + + krpt = NULL; + if (!list_empty(&crp_ret_kq)) + krpt = list_entry(crp_ret_kq.next, typeof(*krpt), krp_next); + if (krpt != NULL) + list_del(&krpt->krp_next); + + if (crpt != NULL || krpt != NULL) { + CRYPTO_RETQ_UNLOCK(); + /* + * Run callbacks unlocked. + */ + if (crpt != NULL) + crpt->crp_callback(crpt); + if (krpt != NULL) + krpt->krp_callback(krpt); + CRYPTO_RETQ_LOCK(); + } else { + /* + * Nothing more to be processed. Sleep until we're + * woken because there are more returns to process. + */ + dprintk("%s - sleeping\n", __FUNCTION__); + CRYPTO_RETQ_UNLOCK(); + wait_event_interruptible(cryptoretproc_wait, + !list_empty(&crp_ret_q) || + !list_empty(&crp_ret_kq) || + kthread_should_stop()); + if (signal_pending (current)) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) + spin_lock_irq(¤t->sigmask_lock); +#endif + flush_signals(current); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) + spin_unlock_irq(¤t->sigmask_lock); +#endif + } + CRYPTO_RETQ_LOCK(); + dprintk("%s - awake\n", __FUNCTION__); + if (kthread_should_stop()) { + dprintk("%s - EXITING!\n", __FUNCTION__); + break; + } + cryptostats.cs_rets++; + } + } + CRYPTO_RETQ_UNLOCK(); + return 0; +} + + +#if 0 /* should put this into /proc or something */ +static void +db_show_drivers(void) +{ + int hid; + + db_printf("%12s %4s %4s %8s %2s %2s\n" + , "Device" + , "Ses" + , "Kops" + , "Flags" + , "QB" + , "KB" + ); + for (hid = 0; hid < crypto_drivers_num; hid++) { + const struct cryptocap *cap = &crypto_drivers[hid]; + if (cap->cc_dev == NULL) + continue; + db_printf("%-12s %4u %4u %08x %2u %2u\n" + , device_get_nameunit(cap->cc_dev) + , cap->cc_sessions + , cap->cc_koperations + , cap->cc_flags + , cap->cc_qblocked + , cap->cc_kqblocked + ); + } +} + +DB_SHOW_COMMAND(crypto, db_show_crypto) +{ + struct cryptop *crp; + + db_show_drivers(); + db_printf("\n"); + + db_printf("%4s %8s %4s %4s %4s %4s %8s %8s\n", + "HID", "Caps", "Ilen", "Olen", "Etype", "Flags", + "Desc", "Callback"); + TAILQ_FOREACH(crp, &crp_q, crp_next) { + db_printf("%4u %08x %4u %4u %4u %04x %8p %8p\n" + , (int) CRYPTO_SESID2HID(crp->crp_sid) + , (int) CRYPTO_SESID2CAPS(crp->crp_sid) + , crp->crp_ilen, crp->crp_olen + , crp->crp_etype + , crp->crp_flags + , crp->crp_desc + , crp->crp_callback + ); + } + if (!TAILQ_EMPTY(&crp_ret_q)) { + db_printf("\n%4s %4s %4s %8s\n", + "HID", "Etype", "Flags", "Callback"); + TAILQ_FOREACH(crp, &crp_ret_q, crp_next) { + db_printf("%4u %4u %04x %8p\n" + , (int) CRYPTO_SESID2HID(crp->crp_sid) + , crp->crp_etype + , crp->crp_flags + , crp->crp_callback + ); + } + } +} + +DB_SHOW_COMMAND(kcrypto, db_show_kcrypto) +{ + struct cryptkop *krp; + + db_show_drivers(); + db_printf("\n"); + + db_printf("%4s %5s %4s %4s %8s %4s %8s\n", + "Op", "Status", "#IP", "#OP", "CRID", "HID", "Callback"); + TAILQ_FOREACH(krp, &crp_kq, krp_next) { + db_printf("%4u %5u %4u %4u %08x %4u %8p\n" + , krp->krp_op + , krp->krp_status + , krp->krp_iparams, krp->krp_oparams + , krp->krp_crid, krp->krp_hid + , krp->krp_callback + ); + } + if (!TAILQ_EMPTY(&crp_ret_q)) { + db_printf("%4s %5s %8s %4s %8s\n", + "Op", "Status", "CRID", "HID", "Callback"); + TAILQ_FOREACH(krp, &crp_ret_kq, krp_next) { + db_printf("%4u %5u %08x %4u %8p\n" + , krp->krp_op + , krp->krp_status + , krp->krp_crid, krp->krp_hid + , krp->krp_callback + ); + } + } +} +#endif + + +static int +crypto_init(void) +{ + int error; + unsigned long cpu; + + dprintk("%s(%p)\n", __FUNCTION__, (void *) crypto_init); + + if (crypto_initted) + return 0; + crypto_initted = 1; + + spin_lock_init(&crypto_drivers_lock); + spin_lock_init(&crypto_q_lock); + spin_lock_init(&crypto_ret_q_lock); + + cryptop_zone = kmem_cache_create("cryptop", sizeof(struct cryptop), + 0, SLAB_HWCACHE_ALIGN, NULL +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23) + , NULL +#endif + ); + + cryptodesc_zone = kmem_cache_create("cryptodesc", sizeof(struct cryptodesc), + 0, SLAB_HWCACHE_ALIGN, NULL +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23) + , NULL +#endif + ); + + if (cryptodesc_zone == NULL || cryptop_zone == NULL) { + printk("crypto: crypto_init cannot setup crypto zones\n"); + error = ENOMEM; + goto bad; + } + + crypto_drivers_num = CRYPTO_DRIVERS_INITIAL; + crypto_drivers = kmalloc(crypto_drivers_num * sizeof(struct cryptocap), + GFP_KERNEL); + if (crypto_drivers == NULL) { + printk("crypto: crypto_init cannot setup crypto drivers\n"); + error = ENOMEM; + goto bad; + } + + memset(crypto_drivers, 0, crypto_drivers_num * sizeof(struct cryptocap)); + + ocf_for_each_cpu(cpu) { + cryptoproc[cpu] = kthread_create(crypto_proc, (void *) cpu, + "ocf_%d", (int) cpu); + if (IS_ERR(cryptoproc[cpu])) { + error = PTR_ERR(cryptoproc[cpu]); + printk("crypto: crypto_init cannot start crypto thread; error %d", + error); + goto bad; + } + kthread_bind(cryptoproc[cpu], cpu); + wake_up_process(cryptoproc[cpu]); + + cryptoretproc[cpu] = kthread_create(crypto_ret_proc, (void *) cpu, + "ocf_ret_%d", (int) cpu); + if (IS_ERR(cryptoretproc[cpu])) { + error = PTR_ERR(cryptoretproc[cpu]); + printk("crypto: crypto_init cannot start cryptoret thread; error %d", + error); + goto bad; + } + kthread_bind(cryptoretproc[cpu], cpu); + wake_up_process(cryptoretproc[cpu]); + } + + return 0; +bad: + crypto_exit(); + return error; +} + + +static void +crypto_exit(void) +{ + int cpu; + + dprintk("%s()\n", __FUNCTION__); + + /* + * Terminate any crypto threads. + */ + ocf_for_each_cpu(cpu) { + kthread_stop(cryptoproc[cpu]); + kthread_stop(cryptoretproc[cpu]); + } + + /* + * Reclaim dynamically allocated resources. + */ + if (crypto_drivers != NULL) + kfree(crypto_drivers); + + if (cryptodesc_zone != NULL) + kmem_cache_destroy(cryptodesc_zone); + if (cryptop_zone != NULL) + kmem_cache_destroy(cryptop_zone); +} + + +EXPORT_SYMBOL(crypto_newsession); +EXPORT_SYMBOL(crypto_freesession); +EXPORT_SYMBOL(crypto_get_driverid); +EXPORT_SYMBOL(crypto_kregister); +EXPORT_SYMBOL(crypto_register); +EXPORT_SYMBOL(crypto_unregister); +EXPORT_SYMBOL(crypto_unregister_all); +EXPORT_SYMBOL(crypto_unblock); +EXPORT_SYMBOL(crypto_dispatch); +EXPORT_SYMBOL(crypto_kdispatch); +EXPORT_SYMBOL(crypto_freereq); +EXPORT_SYMBOL(crypto_getreq); +EXPORT_SYMBOL(crypto_done); +EXPORT_SYMBOL(crypto_kdone); +EXPORT_SYMBOL(crypto_getfeat); +EXPORT_SYMBOL(crypto_userasymcrypto); +EXPORT_SYMBOL(crypto_getcaps); +EXPORT_SYMBOL(crypto_find_driver); +EXPORT_SYMBOL(crypto_find_device_byhid); + +module_init(crypto_init); +module_exit(crypto_exit); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_AUTHOR("David McCullough "); +MODULE_DESCRIPTION("OCF (OpenBSD Cryptographic Framework)"); diff --git a/target/linux/generic/files/crypto/ocf/cryptocteon/Makefile b/target/linux/generic/files/crypto/ocf/cryptocteon/Makefile new file mode 100644 index 0000000..eeed0d6 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/cryptocteon/Makefile @@ -0,0 +1,17 @@ +# for SGlinux builds +-include $(ROOTDIR)/modules/.config + +obj-$(CONFIG_OCF_CRYPTOCTEON) += cryptocteon.o + +obj ?= . +EXTRA_CFLAGS += -I$(obj)/.. -I$(obj)/ + +ifdef CONFIG_OCF_CRYPTOCTEON +# you need the cavium crypto component installed +EXTRA_CFLAGS += -I$(ROOTDIR)/prop/include +endif + +ifdef TOPDIR +-include $(TOPDIR)/Rules.make +endif + diff --git a/target/linux/generic/files/crypto/ocf/cryptocteon/README.txt b/target/linux/generic/files/crypto/ocf/cryptocteon/README.txt new file mode 100644 index 0000000..807b2e5 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/cryptocteon/README.txt @@ -0,0 +1,11 @@ + +You will need the CRYPTO package installed to build this driver, and +potentially the ADK. + +cavium_crypto sourced from: + + adk/components/source/cavium_ipsec_kame/cavium_ipsec.c + +and significantly modified to suit use with OCF. All original +copyright/ownership headers retained. + diff --git a/target/linux/generic/files/crypto/ocf/cryptocteon/cavium_crypto.c b/target/linux/generic/files/crypto/ocf/cryptocteon/cavium_crypto.c new file mode 100644 index 0000000..ceaf77c --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/cryptocteon/cavium_crypto.c @@ -0,0 +1,2283 @@ +/* + * Copyright (c) 2009 David McCullough + * + * Copyright (c) 2003-2007 Cavium Networks (support@cavium.com). All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Cavium Networks + * 4. Cavium Networks' name may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * This Software, including technical data, may be subject to U.S. export + * control laws, including the U.S. Export Administration Act and its + * associated regulations, and may be subject to export or import regulations + * in other countries. You warrant that You will comply strictly in all + * respects with all such regulations and acknowledge that you have the + * responsibility to obtain licenses to export, re-export or import the + * Software. + * + * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" AND + * WITH ALL FAULTS AND CAVIUM MAKES NO PROMISES, REPRESENTATIONS OR WARRANTIES, + * EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO THE + * SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR + * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM + * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE, + * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF + * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR + * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT OF USE OR + * PERFORMANCE OF THE SOFTWARE LIES WITH YOU. +*/ +/****************************************************************************/ + +#include +#include +#include "octeon-asm.h" + +/****************************************************************************/ + +extern unsigned long octeon_crypto_enable(struct octeon_cop2_state *); +extern void octeon_crypto_disable(struct octeon_cop2_state *, unsigned long); + +#define SG_INIT(s, p, i, l) \ + { \ + (i) = 0; \ + (l) = (s)[0].length; \ + (p) = (typeof(p)) sg_virt((s)); \ + CVMX_PREFETCH0((p)); \ + } + +#define SG_CONSUME(s, p, i, l) \ + { \ + (p)++; \ + (l) -= sizeof(*(p)); \ + if ((l) < 0) { \ + dprintk("%s, %d: l = %d\n", __FILE__, __LINE__, l); \ + } else if ((l) == 0) { \ + (i)++; \ + (l) = (s)[0].length; \ + (p) = (typeof(p)) sg_virt(s); \ + CVMX_PREFETCH0((p)); \ + } \ + } + +#define ESP_HEADER_LENGTH 8 +#define DES_CBC_IV_LENGTH 8 +#define AES_CBC_IV_LENGTH 16 +#define ESP_HMAC_LEN 12 + +#define ESP_HEADER_LENGTH 8 +#define DES_CBC_IV_LENGTH 8 + +/****************************************************************************/ + +#define CVM_LOAD_SHA_UNIT(dat, next) { \ + if (next == 0) { \ + next = 1; \ + CVMX_MT_HSH_DAT (dat, 0); \ + } else if (next == 1) { \ + next = 2; \ + CVMX_MT_HSH_DAT (dat, 1); \ + } else if (next == 2) { \ + next = 3; \ + CVMX_MT_HSH_DAT (dat, 2); \ + } else if (next == 3) { \ + next = 4; \ + CVMX_MT_HSH_DAT (dat, 3); \ + } else if (next == 4) { \ + next = 5; \ + CVMX_MT_HSH_DAT (dat, 4); \ + } else if (next == 5) { \ + next = 6; \ + CVMX_MT_HSH_DAT (dat, 5); \ + } else if (next == 6) { \ + next = 7; \ + CVMX_MT_HSH_DAT (dat, 6); \ + } else { \ + CVMX_MT_HSH_STARTSHA (dat); \ + next = 0; \ + } \ +} + +#define CVM_LOAD2_SHA_UNIT(dat1, dat2, next) { \ + if (next == 0) { \ + CVMX_MT_HSH_DAT (dat1, 0); \ + CVMX_MT_HSH_DAT (dat2, 1); \ + next = 2; \ + } else if (next == 1) { \ + CVMX_MT_HSH_DAT (dat1, 1); \ + CVMX_MT_HSH_DAT (dat2, 2); \ + next = 3; \ + } else if (next == 2) { \ + CVMX_MT_HSH_DAT (dat1, 2); \ + CVMX_MT_HSH_DAT (dat2, 3); \ + next = 4; \ + } else if (next == 3) { \ + CVMX_MT_HSH_DAT (dat1, 3); \ + CVMX_MT_HSH_DAT (dat2, 4); \ + next = 5; \ + } else if (next == 4) { \ + CVMX_MT_HSH_DAT (dat1, 4); \ + CVMX_MT_HSH_DAT (dat2, 5); \ + next = 6; \ + } else if (next == 5) { \ + CVMX_MT_HSH_DAT (dat1, 5); \ + CVMX_MT_HSH_DAT (dat2, 6); \ + next = 7; \ + } else if (next == 6) { \ + CVMX_MT_HSH_DAT (dat1, 6); \ + CVMX_MT_HSH_STARTSHA (dat2); \ + next = 0; \ + } else { \ + CVMX_MT_HSH_STARTSHA (dat1); \ + CVMX_MT_HSH_DAT (dat2, 0); \ + next = 1; \ + } \ +} + +/****************************************************************************/ + +#define CVM_LOAD_MD5_UNIT(dat, next) { \ + if (next == 0) { \ + next = 1; \ + CVMX_MT_HSH_DAT (dat, 0); \ + } else if (next == 1) { \ + next = 2; \ + CVMX_MT_HSH_DAT (dat, 1); \ + } else if (next == 2) { \ + next = 3; \ + CVMX_MT_HSH_DAT (dat, 2); \ + } else if (next == 3) { \ + next = 4; \ + CVMX_MT_HSH_DAT (dat, 3); \ + } else if (next == 4) { \ + next = 5; \ + CVMX_MT_HSH_DAT (dat, 4); \ + } else if (next == 5) { \ + next = 6; \ + CVMX_MT_HSH_DAT (dat, 5); \ + } else if (next == 6) { \ + next = 7; \ + CVMX_MT_HSH_DAT (dat, 6); \ + } else { \ + CVMX_MT_HSH_STARTMD5 (dat); \ + next = 0; \ + } \ +} + +#define CVM_LOAD2_MD5_UNIT(dat1, dat2, next) { \ + if (next == 0) { \ + CVMX_MT_HSH_DAT (dat1, 0); \ + CVMX_MT_HSH_DAT (dat2, 1); \ + next = 2; \ + } else if (next == 1) { \ + CVMX_MT_HSH_DAT (dat1, 1); \ + CVMX_MT_HSH_DAT (dat2, 2); \ + next = 3; \ + } else if (next == 2) { \ + CVMX_MT_HSH_DAT (dat1, 2); \ + CVMX_MT_HSH_DAT (dat2, 3); \ + next = 4; \ + } else if (next == 3) { \ + CVMX_MT_HSH_DAT (dat1, 3); \ + CVMX_MT_HSH_DAT (dat2, 4); \ + next = 5; \ + } else if (next == 4) { \ + CVMX_MT_HSH_DAT (dat1, 4); \ + CVMX_MT_HSH_DAT (dat2, 5); \ + next = 6; \ + } else if (next == 5) { \ + CVMX_MT_HSH_DAT (dat1, 5); \ + CVMX_MT_HSH_DAT (dat2, 6); \ + next = 7; \ + } else if (next == 6) { \ + CVMX_MT_HSH_DAT (dat1, 6); \ + CVMX_MT_HSH_STARTMD5 (dat2); \ + next = 0; \ + } else { \ + CVMX_MT_HSH_STARTMD5 (dat1); \ + CVMX_MT_HSH_DAT (dat2, 0); \ + next = 1; \ + } \ +} + +/****************************************************************************/ + +static inline uint64_t +swap64(uint64_t a) +{ + return ((a >> 56) | + (((a >> 48) & 0xfful) << 8) | + (((a >> 40) & 0xfful) << 16) | + (((a >> 32) & 0xfful) << 24) | + (((a >> 24) & 0xfful) << 32) | + (((a >> 16) & 0xfful) << 40) | + (((a >> 8) & 0xfful) << 48) | (((a >> 0) & 0xfful) << 56)); +} + +/****************************************************************************/ + +void +octo_calc_hash(__u8 auth, unsigned char *key, uint64_t *inner, uint64_t *outer) +{ + uint8_t hash_key[64]; + uint64_t *key1; + register uint64_t xor1 = 0x3636363636363636ULL; + register uint64_t xor2 = 0x5c5c5c5c5c5c5c5cULL; + struct octeon_cop2_state state; + unsigned long flags; + + dprintk("%s()\n", __FUNCTION__); + + memset(hash_key, 0, sizeof(hash_key)); + memcpy(hash_key, (uint8_t *) key, (auth ? 20 : 16)); + key1 = (uint64_t *) hash_key; + flags = octeon_crypto_enable(&state); + if (auth) { + CVMX_MT_HSH_IV(0x67452301EFCDAB89ULL, 0); + CVMX_MT_HSH_IV(0x98BADCFE10325476ULL, 1); + CVMX_MT_HSH_IV(0xC3D2E1F000000000ULL, 2); + } else { + CVMX_MT_HSH_IV(0x0123456789ABCDEFULL, 0); + CVMX_MT_HSH_IV(0xFEDCBA9876543210ULL, 1); + } + + CVMX_MT_HSH_DAT((*key1 ^ xor1), 0); + key1++; + CVMX_MT_HSH_DAT((*key1 ^ xor1), 1); + key1++; + CVMX_MT_HSH_DAT((*key1 ^ xor1), 2); + key1++; + CVMX_MT_HSH_DAT((*key1 ^ xor1), 3); + key1++; + CVMX_MT_HSH_DAT((*key1 ^ xor1), 4); + key1++; + CVMX_MT_HSH_DAT((*key1 ^ xor1), 5); + key1++; + CVMX_MT_HSH_DAT((*key1 ^ xor1), 6); + key1++; + if (auth) + CVMX_MT_HSH_STARTSHA((*key1 ^ xor1)); + else + CVMX_MT_HSH_STARTMD5((*key1 ^ xor1)); + + CVMX_MF_HSH_IV(inner[0], 0); + CVMX_MF_HSH_IV(inner[1], 1); + if (auth) { + inner[2] = 0; + CVMX_MF_HSH_IV(((uint64_t *) inner)[2], 2); + } + + memset(hash_key, 0, sizeof(hash_key)); + memcpy(hash_key, (uint8_t *) key, (auth ? 20 : 16)); + key1 = (uint64_t *) hash_key; + if (auth) { + CVMX_MT_HSH_IV(0x67452301EFCDAB89ULL, 0); + CVMX_MT_HSH_IV(0x98BADCFE10325476ULL, 1); + CVMX_MT_HSH_IV(0xC3D2E1F000000000ULL, 2); + } else { + CVMX_MT_HSH_IV(0x0123456789ABCDEFULL, 0); + CVMX_MT_HSH_IV(0xFEDCBA9876543210ULL, 1); + } + + CVMX_MT_HSH_DAT((*key1 ^ xor2), 0); + key1++; + CVMX_MT_HSH_DAT((*key1 ^ xor2), 1); + key1++; + CVMX_MT_HSH_DAT((*key1 ^ xor2), 2); + key1++; + CVMX_MT_HSH_DAT((*key1 ^ xor2), 3); + key1++; + CVMX_MT_HSH_DAT((*key1 ^ xor2), 4); + key1++; + CVMX_MT_HSH_DAT((*key1 ^ xor2), 5); + key1++; + CVMX_MT_HSH_DAT((*key1 ^ xor2), 6); + key1++; + if (auth) + CVMX_MT_HSH_STARTSHA((*key1 ^ xor2)); + else + CVMX_MT_HSH_STARTMD5((*key1 ^ xor2)); + + CVMX_MF_HSH_IV(outer[0], 0); + CVMX_MF_HSH_IV(outer[1], 1); + if (auth) { + outer[2] = 0; + CVMX_MF_HSH_IV(outer[2], 2); + } + octeon_crypto_disable(&state, flags); + return; +} + +/****************************************************************************/ +/* DES functions */ + +int +octo_des_cbc_encrypt( + struct octo_sess *od, + struct scatterlist *sg, int sg_len, + int auth_off, int auth_len, + int crypt_off, int crypt_len, + int icv_off, uint8_t *ivp) +{ + uint64_t *data; + int data_i, data_l; + struct octeon_cop2_state state; + unsigned long flags; + + dprintk("%s()\n", __FUNCTION__); + + if (unlikely(od == NULL || sg==NULL || sg_len==0 || ivp==NULL || + (crypt_off & 0x7) || (crypt_off + crypt_len > sg_len))) { + dprintk("%s: Bad parameters od=%p sg=%p sg_len=%d " + "auth_off=%d auth_len=%d crypt_off=%d crypt_len=%d " + "icv_off=%d ivp=%p\n", __FUNCTION__, od, sg, sg_len, + auth_off, auth_len, crypt_off, crypt_len, icv_off, ivp); + return -EINVAL; + } + + SG_INIT(sg, data, data_i, data_l); + + CVMX_PREFETCH0(ivp); + CVMX_PREFETCH0(od->octo_enckey); + + flags = octeon_crypto_enable(&state); + + /* load 3DES Key */ + CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 0); + if (od->octo_encklen == 24) { + CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[1], 1); + CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[2], 2); + } else if (od->octo_encklen == 8) { + CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 1); + CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 2); + } else { + octeon_crypto_disable(&state, flags); + dprintk("%s: Bad key length %d\n", __FUNCTION__, od->octo_encklen); + return -EINVAL; + } + + CVMX_MT_3DES_IV(* (uint64_t *) ivp); + + while (crypt_off > 0) { + SG_CONSUME(sg, data, data_i, data_l); + crypt_off -= 8; + } + + while (crypt_len > 0) { + CVMX_MT_3DES_ENC_CBC(*data); + CVMX_MF_3DES_RESULT(*data); + SG_CONSUME(sg, data, data_i, data_l); + crypt_len -= 8; + } + + octeon_crypto_disable(&state, flags); + return 0; +} + + +int +octo_des_cbc_decrypt( + struct octo_sess *od, + struct scatterlist *sg, int sg_len, + int auth_off, int auth_len, + int crypt_off, int crypt_len, + int icv_off, uint8_t *ivp) +{ + uint64_t *data; + int data_i, data_l; + struct octeon_cop2_state state; + unsigned long flags; + + dprintk("%s()\n", __FUNCTION__); + + if (unlikely(od == NULL || sg==NULL || sg_len==0 || ivp==NULL || + (crypt_off & 0x7) || (crypt_off + crypt_len > sg_len))) { + dprintk("%s: Bad parameters od=%p sg=%p sg_len=%d " + "auth_off=%d auth_len=%d crypt_off=%d crypt_len=%d " + "icv_off=%d ivp=%p\n", __FUNCTION__, od, sg, sg_len, + auth_off, auth_len, crypt_off, crypt_len, icv_off, ivp); + return -EINVAL; + } + + SG_INIT(sg, data, data_i, data_l); + + CVMX_PREFETCH0(ivp); + CVMX_PREFETCH0(od->octo_enckey); + + flags = octeon_crypto_enable(&state); + + /* load 3DES Key */ + CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 0); + if (od->octo_encklen == 24) { + CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[1], 1); + CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[2], 2); + } else if (od->octo_encklen == 8) { + CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 1); + CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 2); + } else { + octeon_crypto_disable(&state, flags); + dprintk("%s: Bad key length %d\n", __FUNCTION__, od->octo_encklen); + return -EINVAL; + } + + CVMX_MT_3DES_IV(* (uint64_t *) ivp); + + while (crypt_off > 0) { + SG_CONSUME(sg, data, data_i, data_l); + crypt_off -= 8; + } + + while (crypt_len > 0) { + CVMX_MT_3DES_DEC_CBC(*data); + CVMX_MF_3DES_RESULT(*data); + SG_CONSUME(sg, data, data_i, data_l); + crypt_len -= 8; + } + + octeon_crypto_disable(&state, flags); + return 0; +} + +/****************************************************************************/ +/* AES functions */ + +int +octo_aes_cbc_encrypt( + struct octo_sess *od, + struct scatterlist *sg, int sg_len, + int auth_off, int auth_len, + int crypt_off, int crypt_len, + int icv_off, uint8_t *ivp) +{ + uint64_t *data, *pdata; + int data_i, data_l; + struct octeon_cop2_state state; + unsigned long flags; + + dprintk("%s()\n", __FUNCTION__); + + if (unlikely(od == NULL || sg==NULL || sg_len==0 || ivp==NULL || + (crypt_off & 0x7) || (crypt_off + crypt_len > sg_len))) { + dprintk("%s: Bad parameters od=%p sg=%p sg_len=%d " + "auth_off=%d auth_len=%d crypt_off=%d crypt_len=%d " + "icv_off=%d ivp=%p\n", __FUNCTION__, od, sg, sg_len, + auth_off, auth_len, crypt_off, crypt_len, icv_off, ivp); + return -EINVAL; + } + + SG_INIT(sg, data, data_i, data_l); + + CVMX_PREFETCH0(ivp); + CVMX_PREFETCH0(od->octo_enckey); + + flags = octeon_crypto_enable(&state); + + /* load AES Key */ + CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[0], 0); + CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[1], 1); + + if (od->octo_encklen == 16) { + CVMX_MT_AES_KEY(0x0, 2); + CVMX_MT_AES_KEY(0x0, 3); + } else if (od->octo_encklen == 24) { + CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[2], 2); + CVMX_MT_AES_KEY(0x0, 3); + } else if (od->octo_encklen == 32) { + CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[2], 2); + CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[3], 3); + } else { + octeon_crypto_disable(&state, flags); + dprintk("%s: Bad key length %d\n", __FUNCTION__, od->octo_encklen); + return -EINVAL; + } + CVMX_MT_AES_KEYLENGTH(od->octo_encklen / 8 - 1); + + CVMX_MT_AES_IV(((uint64_t *) ivp)[0], 0); + CVMX_MT_AES_IV(((uint64_t *) ivp)[1], 1); + + while (crypt_off > 0) { + SG_CONSUME(sg, data, data_i, data_l); + crypt_off -= 8; + } + + while (crypt_len > 0) { + pdata = data; + CVMX_MT_AES_ENC_CBC0(*data); + SG_CONSUME(sg, data, data_i, data_l); + CVMX_MT_AES_ENC_CBC1(*data); + CVMX_MF_AES_RESULT(*pdata, 0); + CVMX_MF_AES_RESULT(*data, 1); + SG_CONSUME(sg, data, data_i, data_l); + crypt_len -= 16; + } + + octeon_crypto_disable(&state, flags); + return 0; +} + + +int +octo_aes_cbc_decrypt( + struct octo_sess *od, + struct scatterlist *sg, int sg_len, + int auth_off, int auth_len, + int crypt_off, int crypt_len, + int icv_off, uint8_t *ivp) +{ + uint64_t *data, *pdata; + int data_i, data_l; + struct octeon_cop2_state state; + unsigned long flags; + + dprintk("%s()\n", __FUNCTION__); + + if (unlikely(od == NULL || sg==NULL || sg_len==0 || ivp==NULL || + (crypt_off & 0x7) || (crypt_off + crypt_len > sg_len))) { + dprintk("%s: Bad parameters od=%p sg=%p sg_len=%d " + "auth_off=%d auth_len=%d crypt_off=%d crypt_len=%d " + "icv_off=%d ivp=%p\n", __FUNCTION__, od, sg, sg_len, + auth_off, auth_len, crypt_off, crypt_len, icv_off, ivp); + return -EINVAL; + } + + SG_INIT(sg, data, data_i, data_l); + + CVMX_PREFETCH0(ivp); + CVMX_PREFETCH0(od->octo_enckey); + + flags = octeon_crypto_enable(&state); + + /* load AES Key */ + CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[0], 0); + CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[1], 1); + + if (od->octo_encklen == 16) { + CVMX_MT_AES_KEY(0x0, 2); + CVMX_MT_AES_KEY(0x0, 3); + } else if (od->octo_encklen == 24) { + CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[2], 2); + CVMX_MT_AES_KEY(0x0, 3); + } else if (od->octo_encklen == 32) { + CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[2], 2); + CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[3], 3); + } else { + octeon_crypto_disable(&state, flags); + dprintk("%s: Bad key length %d\n", __FUNCTION__, od->octo_encklen); + return -EINVAL; + } + CVMX_MT_AES_KEYLENGTH(od->octo_encklen / 8 - 1); + + CVMX_MT_AES_IV(((uint64_t *) ivp)[0], 0); + CVMX_MT_AES_IV(((uint64_t *) ivp)[1], 1); + + while (crypt_off > 0) { + SG_CONSUME(sg, data, data_i, data_l); + crypt_off -= 8; + } + + while (crypt_len > 0) { + pdata = data; + CVMX_MT_AES_DEC_CBC0(*data); + SG_CONSUME(sg, data, data_i, data_l); + CVMX_MT_AES_DEC_CBC1(*data); + CVMX_MF_AES_RESULT(*pdata, 0); + CVMX_MF_AES_RESULT(*data, 1); + SG_CONSUME(sg, data, data_i, data_l); + crypt_len -= 16; + } + + octeon_crypto_disable(&state, flags); + return 0; +} + +/****************************************************************************/ +/* MD5 */ + +int +octo_null_md5_encrypt( + struct octo_sess *od, + struct scatterlist *sg, int sg_len, + int auth_off, int auth_len, + int crypt_off, int crypt_len, + int icv_off, uint8_t *ivp) +{ + register int next = 0; + uint64_t *data; + uint64_t tmp1, tmp2; + int data_i, data_l, alen = auth_len; + struct octeon_cop2_state state; + unsigned long flags; + + dprintk("%s()\n", __FUNCTION__); + + if (unlikely(od == NULL || sg==NULL || sg_len==0 || + (auth_off & 0x7) || (auth_off + auth_len > sg_len))) { + dprintk("%s: Bad parameters od=%p sg=%p sg_len=%d " + "auth_off=%d auth_len=%d crypt_off=%d crypt_len=%d " + "icv_off=%d ivp=%p\n", __FUNCTION__, od, sg, sg_len, + auth_off, auth_len, crypt_off, crypt_len, icv_off, ivp); + return -EINVAL; + } + + SG_INIT(sg, data, data_i, data_l); + + flags = octeon_crypto_enable(&state); + + /* Load MD5 IV */ + CVMX_MT_HSH_IV(od->octo_hminner[0], 0); + CVMX_MT_HSH_IV(od->octo_hminner[1], 1); + + while (auth_off > 0) { + SG_CONSUME(sg, data, data_i, data_l); + auth_off -= 8; + } + + while (auth_len > 0) { + CVM_LOAD_MD5_UNIT(*data, next); + auth_len -= 8; + SG_CONSUME(sg, data, data_i, data_l); + } + + /* finish the hash */ + CVMX_PREFETCH0(od->octo_hmouter); +#if 0 + if (unlikely(inplen)) { + uint64_t tmp = 0; + uint8_t *p = (uint8_t *) & tmp; + p[inplen] = 0x80; + do { + inplen--; + p[inplen] = ((uint8_t *) data)[inplen]; + } while (inplen); + CVM_LOAD_MD5_UNIT(tmp, next); + } else { + CVM_LOAD_MD5_UNIT(0x8000000000000000ULL, next); + } +#else + CVM_LOAD_MD5_UNIT(0x8000000000000000ULL, next); +#endif + + /* Finish Inner hash */ + while (next != 7) { + CVM_LOAD_MD5_UNIT(((uint64_t) 0x0ULL), next); + } + CVMX_ES64(tmp1, ((alen + 64) << 3)); + CVM_LOAD_MD5_UNIT(tmp1, next); + + /* Get the inner hash of HMAC */ + CVMX_MF_HSH_IV(tmp1, 0); + CVMX_MF_HSH_IV(tmp2, 1); + + /* Initialize hash unit */ + CVMX_MT_HSH_IV(od->octo_hmouter[0], 0); + CVMX_MT_HSH_IV(od->octo_hmouter[1], 1); + + CVMX_MT_HSH_DAT(tmp1, 0); + CVMX_MT_HSH_DAT(tmp2, 1); + CVMX_MT_HSH_DAT(0x8000000000000000ULL, 2); + CVMX_MT_HSH_DATZ(3); + CVMX_MT_HSH_DATZ(4); + CVMX_MT_HSH_DATZ(5); + CVMX_MT_HSH_DATZ(6); + CVMX_ES64(tmp1, ((64 + 16) << 3)); + CVMX_MT_HSH_STARTMD5(tmp1); + + /* save the HMAC */ + SG_INIT(sg, data, data_i, data_l); + while (icv_off > 0) { + SG_CONSUME(sg, data, data_i, data_l); + icv_off -= 8; + } + CVMX_MF_HSH_IV(*data, 0); + SG_CONSUME(sg, data, data_i, data_l); + CVMX_MF_HSH_IV(tmp1, 1); + *(uint32_t *)data = (uint32_t) (tmp1 >> 32); + + octeon_crypto_disable(&state, flags); + return 0; +} + +/****************************************************************************/ +/* SHA1 */ + +int +octo_null_sha1_encrypt( + struct octo_sess *od, + struct scatterlist *sg, int sg_len, + int auth_off, int auth_len, + int crypt_off, int crypt_len, + int icv_off, uint8_t *ivp) +{ + register int next = 0; + uint64_t *data; + uint64_t tmp1, tmp2, tmp3; + int data_i, data_l, alen = auth_len; + struct octeon_cop2_state state; + unsigned long flags; + + dprintk("%s()\n", __FUNCTION__); + + if (unlikely(od == NULL || sg==NULL || sg_len==0 || + (auth_off & 0x7) || (auth_off + auth_len > sg_len))) { + dprintk("%s: Bad parameters od=%p sg=%p sg_len=%d " + "auth_off=%d auth_len=%d crypt_off=%d crypt_len=%d " + "icv_off=%d ivp=%p\n", __FUNCTION__, od, sg, sg_len, + auth_off, auth_len, crypt_off, crypt_len, icv_off, ivp); + return -EINVAL; + } + + SG_INIT(sg, data, data_i, data_l); + + flags = octeon_crypto_enable(&state); + + /* Load SHA1 IV */ + CVMX_MT_HSH_IV(od->octo_hminner[0], 0); + CVMX_MT_HSH_IV(od->octo_hminner[1], 1); + CVMX_MT_HSH_IV(od->octo_hminner[2], 2); + + while (auth_off > 0) { + SG_CONSUME(sg, data, data_i, data_l); + auth_off -= 8; + } + + while (auth_len > 0) { + CVM_LOAD_SHA_UNIT(*data, next); + auth_len -= 8; + SG_CONSUME(sg, data, data_i, data_l); + } + + /* finish the hash */ + CVMX_PREFETCH0(od->octo_hmouter); +#if 0 + if (unlikely(inplen)) { + uint64_t tmp = 0; + uint8_t *p = (uint8_t *) & tmp; + p[inplen] = 0x80; + do { + inplen--; + p[inplen] = ((uint8_t *) data)[inplen]; + } while (inplen); + CVM_LOAD_MD5_UNIT(tmp, next); + } else { + CVM_LOAD_MD5_UNIT(0x8000000000000000ULL, next); + } +#else + CVM_LOAD_SHA_UNIT(0x8000000000000000ULL, next); +#endif + + /* Finish Inner hash */ + while (next != 7) { + CVM_LOAD_SHA_UNIT(((uint64_t) 0x0ULL), next); + } + CVM_LOAD_SHA_UNIT((uint64_t) ((alen + 64) << 3), next); + + /* Get the inner hash of HMAC */ + CVMX_MF_HSH_IV(tmp1, 0); + CVMX_MF_HSH_IV(tmp2, 1); + tmp3 = 0; + CVMX_MF_HSH_IV(tmp3, 2); + + /* Initialize hash unit */ + CVMX_MT_HSH_IV(od->octo_hmouter[0], 0); + CVMX_MT_HSH_IV(od->octo_hmouter[1], 1); + CVMX_MT_HSH_IV(od->octo_hmouter[2], 2); + + CVMX_MT_HSH_DAT(tmp1, 0); + CVMX_MT_HSH_DAT(tmp2, 1); + tmp3 |= 0x0000000080000000; + CVMX_MT_HSH_DAT(tmp3, 2); + CVMX_MT_HSH_DATZ(3); + CVMX_MT_HSH_DATZ(4); + CVMX_MT_HSH_DATZ(5); + CVMX_MT_HSH_DATZ(6); + CVMX_MT_HSH_STARTSHA((uint64_t) ((64 + 20) << 3)); + + /* save the HMAC */ + SG_INIT(sg, data, data_i, data_l); + while (icv_off > 0) { + SG_CONSUME(sg, data, data_i, data_l); + icv_off -= 8; + } + CVMX_MF_HSH_IV(*data, 0); + SG_CONSUME(sg, data, data_i, data_l); + CVMX_MF_HSH_IV(tmp1, 1); + *(uint32_t *)data = (uint32_t) (tmp1 >> 32); + + octeon_crypto_disable(&state, flags); + return 0; +} + +/****************************************************************************/ +/* DES MD5 */ + +int +octo_des_cbc_md5_encrypt( + struct octo_sess *od, + struct scatterlist *sg, int sg_len, + int auth_off, int auth_len, + int crypt_off, int crypt_len, + int icv_off, uint8_t *ivp) +{ + register int next = 0; + union { + uint32_t data32[2]; + uint64_t data64[1]; + } mydata; + uint64_t *data = &mydata.data64[0]; + uint32_t *data32; + uint64_t tmp1, tmp2; + int data_i, data_l, alen = auth_len; + struct octeon_cop2_state state; + unsigned long flags; + + dprintk("%s()\n", __FUNCTION__); + + if (unlikely(od == NULL || sg==NULL || sg_len==0 || ivp==NULL || + (crypt_off & 0x3) || (crypt_off + crypt_len > sg_len) || + (crypt_len & 0x7) || + (auth_len & 0x7) || + (auth_off & 0x3) || (auth_off + auth_len > sg_len))) { + dprintk("%s: Bad parameters od=%p sg=%p sg_len=%d " + "auth_off=%d auth_len=%d crypt_off=%d crypt_len=%d " + "icv_off=%d ivp=%p\n", __FUNCTION__, od, sg, sg_len, + auth_off, auth_len, crypt_off, crypt_len, icv_off, ivp); + return -EINVAL; + } + + SG_INIT(sg, data32, data_i, data_l); + + CVMX_PREFETCH0(ivp); + CVMX_PREFETCH0(od->octo_enckey); + + flags = octeon_crypto_enable(&state); + + /* load 3DES Key */ + CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 0); + if (od->octo_encklen == 24) { + CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[1], 1); + CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[2], 2); + } else if (od->octo_encklen == 8) { + CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 1); + CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 2); + } else { + octeon_crypto_disable(&state, flags); + dprintk("%s: Bad key length %d\n", __FUNCTION__, od->octo_encklen); + return -EINVAL; + } + + CVMX_MT_3DES_IV(* (uint64_t *) ivp); + + /* Load MD5 IV */ + CVMX_MT_HSH_IV(od->octo_hminner[0], 0); + CVMX_MT_HSH_IV(od->octo_hminner[1], 1); + + while (crypt_off > 0 && auth_off > 0) { + SG_CONSUME(sg, data32, data_i, data_l); + crypt_off -= 4; + auth_off -= 4; + } + + while (crypt_len > 0 || auth_len > 0) { + uint32_t *first = data32; + mydata.data32[0] = *first; + SG_CONSUME(sg, data32, data_i, data_l); + mydata.data32[1] = *data32; + if (crypt_off <= 0) { + if (crypt_len > 0) { + CVMX_MT_3DES_ENC_CBC(*data); + CVMX_MF_3DES_RESULT(*data); + crypt_len -= 8; + } + } else + crypt_off -= 8; + if (auth_off <= 0) { + if (auth_len > 0) { + CVM_LOAD_MD5_UNIT(*data, next); + auth_len -= 8; + } + } else + auth_off -= 8; + *first = mydata.data32[0]; + *data32 = mydata.data32[1]; + SG_CONSUME(sg, data32, data_i, data_l); + } + + /* finish the hash */ + CVMX_PREFETCH0(od->octo_hmouter); +#if 0 + if (unlikely(inplen)) { + uint64_t tmp = 0; + uint8_t *p = (uint8_t *) & tmp; + p[inplen] = 0x80; + do { + inplen--; + p[inplen] = ((uint8_t *) data)[inplen]; + } while (inplen); + CVM_LOAD_MD5_UNIT(tmp, next); + } else { + CVM_LOAD_MD5_UNIT(0x8000000000000000ULL, next); + } +#else + CVM_LOAD_MD5_UNIT(0x8000000000000000ULL, next); +#endif + + /* Finish Inner hash */ + while (next != 7) { + CVM_LOAD_MD5_UNIT(((uint64_t) 0x0ULL), next); + } + CVMX_ES64(tmp1, ((alen + 64) << 3)); + CVM_LOAD_MD5_UNIT(tmp1, next); + + /* Get the inner hash of HMAC */ + CVMX_MF_HSH_IV(tmp1, 0); + CVMX_MF_HSH_IV(tmp2, 1); + + /* Initialize hash unit */ + CVMX_MT_HSH_IV(od->octo_hmouter[0], 0); + CVMX_MT_HSH_IV(od->octo_hmouter[1], 1); + + CVMX_MT_HSH_DAT(tmp1, 0); + CVMX_MT_HSH_DAT(tmp2, 1); + CVMX_MT_HSH_DAT(0x8000000000000000ULL, 2); + CVMX_MT_HSH_DATZ(3); + CVMX_MT_HSH_DATZ(4); + CVMX_MT_HSH_DATZ(5); + CVMX_MT_HSH_DATZ(6); + CVMX_ES64(tmp1, ((64 + 16) << 3)); + CVMX_MT_HSH_STARTMD5(tmp1); + + /* save the HMAC */ + SG_INIT(sg, data32, data_i, data_l); + while (icv_off > 0) { + SG_CONSUME(sg, data32, data_i, data_l); + icv_off -= 4; + } + CVMX_MF_HSH_IV(tmp1, 0); + *data32 = (uint32_t) (tmp1 >> 32); + SG_CONSUME(sg, data32, data_i, data_l); + *data32 = (uint32_t) tmp1; + SG_CONSUME(sg, data32, data_i, data_l); + CVMX_MF_HSH_IV(tmp1, 1); + *data32 = (uint32_t) (tmp1 >> 32); + + octeon_crypto_disable(&state, flags); + return 0; +} + +int +octo_des_cbc_md5_decrypt( + struct octo_sess *od, + struct scatterlist *sg, int sg_len, + int auth_off, int auth_len, + int crypt_off, int crypt_len, + int icv_off, uint8_t *ivp) +{ + register int next = 0; + union { + uint32_t data32[2]; + uint64_t data64[1]; + } mydata; + uint64_t *data = &mydata.data64[0]; + uint32_t *data32; + uint64_t tmp1, tmp2; + int data_i, data_l, alen = auth_len; + struct octeon_cop2_state state; + unsigned long flags; + + dprintk("%s()\n", __FUNCTION__); + + if (unlikely(od == NULL || sg==NULL || sg_len==0 || ivp==NULL || + (crypt_off & 0x3) || (crypt_off + crypt_len > sg_len) || + (crypt_len & 0x7) || + (auth_len & 0x7) || + (auth_off & 0x3) || (auth_off + auth_len > sg_len))) { + dprintk("%s: Bad parameters od=%p sg=%p sg_len=%d " + "auth_off=%d auth_len=%d crypt_off=%d crypt_len=%d " + "icv_off=%d ivp=%p\n", __FUNCTION__, od, sg, sg_len, + auth_off, auth_len, crypt_off, crypt_len, icv_off, ivp); + return -EINVAL; + } + + SG_INIT(sg, data32, data_i, data_l); + + CVMX_PREFETCH0(ivp); + CVMX_PREFETCH0(od->octo_enckey); + + flags = octeon_crypto_enable(&state); + + /* load 3DES Key */ + CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 0); + if (od->octo_encklen == 24) { + CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[1], 1); + CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[2], 2); + } else if (od->octo_encklen == 8) { + CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 1); + CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 2); + } else { + octeon_crypto_disable(&state, flags); + dprintk("%s: Bad key length %d\n", __FUNCTION__, od->octo_encklen); + return -EINVAL; + } + + CVMX_MT_3DES_IV(* (uint64_t *) ivp); + + /* Load MD5 IV */ + CVMX_MT_HSH_IV(od->octo_hminner[0], 0); + CVMX_MT_HSH_IV(od->octo_hminner[1], 1); + + while (crypt_off > 0 && auth_off > 0) { + SG_CONSUME(sg, data32, data_i, data_l); + crypt_off -= 4; + auth_off -= 4; + } + + while (crypt_len > 0 || auth_len > 0) { + uint32_t *first = data32; + mydata.data32[0] = *first; + SG_CONSUME(sg, data32, data_i, data_l); + mydata.data32[1] = *data32; + if (auth_off <= 0) { + if (auth_len > 0) { + CVM_LOAD_MD5_UNIT(*data, next); + auth_len -= 8; + } + } else + auth_off -= 8; + if (crypt_off <= 0) { + if (crypt_len > 0) { + CVMX_MT_3DES_DEC_CBC(*data); + CVMX_MF_3DES_RESULT(*data); + crypt_len -= 8; + } + } else + crypt_off -= 8; + *first = mydata.data32[0]; + *data32 = mydata.data32[1]; + SG_CONSUME(sg, data32, data_i, data_l); + } + + /* finish the hash */ + CVMX_PREFETCH0(od->octo_hmouter); +#if 0 + if (unlikely(inplen)) { + uint64_t tmp = 0; + uint8_t *p = (uint8_t *) & tmp; + p[inplen] = 0x80; + do { + inplen--; + p[inplen] = ((uint8_t *) data)[inplen]; + } while (inplen); + CVM_LOAD_MD5_UNIT(tmp, next); + } else { + CVM_LOAD_MD5_UNIT(0x8000000000000000ULL, next); + } +#else + CVM_LOAD_MD5_UNIT(0x8000000000000000ULL, next); +#endif + + /* Finish Inner hash */ + while (next != 7) { + CVM_LOAD_MD5_UNIT(((uint64_t) 0x0ULL), next); + } + CVMX_ES64(tmp1, ((alen + 64) << 3)); + CVM_LOAD_MD5_UNIT(tmp1, next); + + /* Get the inner hash of HMAC */ + CVMX_MF_HSH_IV(tmp1, 0); + CVMX_MF_HSH_IV(tmp2, 1); + + /* Initialize hash unit */ + CVMX_MT_HSH_IV(od->octo_hmouter[0], 0); + CVMX_MT_HSH_IV(od->octo_hmouter[1], 1); + + CVMX_MT_HSH_DAT(tmp1, 0); + CVMX_MT_HSH_DAT(tmp2, 1); + CVMX_MT_HSH_DAT(0x8000000000000000ULL, 2); + CVMX_MT_HSH_DATZ(3); + CVMX_MT_HSH_DATZ(4); + CVMX_MT_HSH_DATZ(5); + CVMX_MT_HSH_DATZ(6); + CVMX_ES64(tmp1, ((64 + 16) << 3)); + CVMX_MT_HSH_STARTMD5(tmp1); + + /* save the HMAC */ + SG_INIT(sg, data32, data_i, data_l); + while (icv_off > 0) { + SG_CONSUME(sg, data32, data_i, data_l); + icv_off -= 4; + } + CVMX_MF_HSH_IV(tmp1, 0); + *data32 = (uint32_t) (tmp1 >> 32); + SG_CONSUME(sg, data32, data_i, data_l); + *data32 = (uint32_t) tmp1; + SG_CONSUME(sg, data32, data_i, data_l); + CVMX_MF_HSH_IV(tmp1, 1); + *data32 = (uint32_t) (tmp1 >> 32); + + octeon_crypto_disable(&state, flags); + return 0; +} + +/****************************************************************************/ +/* DES SHA */ + +int +octo_des_cbc_sha1_encrypt( + struct octo_sess *od, + struct scatterlist *sg, int sg_len, + int auth_off, int auth_len, + int crypt_off, int crypt_len, + int icv_off, uint8_t *ivp) +{ + register int next = 0; + union { + uint32_t data32[2]; + uint64_t data64[1]; + } mydata; + uint64_t *data = &mydata.data64[0]; + uint32_t *data32; + uint64_t tmp1, tmp2, tmp3; + int data_i, data_l, alen = auth_len; + struct octeon_cop2_state state; + unsigned long flags; + + dprintk("%s()\n", __FUNCTION__); + + if (unlikely(od == NULL || sg==NULL || sg_len==0 || ivp==NULL || + (crypt_off & 0x3) || (crypt_off + crypt_len > sg_len) || + (crypt_len & 0x7) || + (auth_len & 0x7) || + (auth_off & 0x3) || (auth_off + auth_len > sg_len))) { + dprintk("%s: Bad parameters od=%p sg=%p sg_len=%d " + "auth_off=%d auth_len=%d crypt_off=%d crypt_len=%d " + "icv_off=%d ivp=%p\n", __FUNCTION__, od, sg, sg_len, + auth_off, auth_len, crypt_off, crypt_len, icv_off, ivp); + return -EINVAL; + } + + SG_INIT(sg, data32, data_i, data_l); + + CVMX_PREFETCH0(ivp); + CVMX_PREFETCH0(od->octo_enckey); + + flags = octeon_crypto_enable(&state); + + /* load 3DES Key */ + CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 0); + if (od->octo_encklen == 24) { + CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[1], 1); + CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[2], 2); + } else if (od->octo_encklen == 8) { + CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 1); + CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 2); + } else { + octeon_crypto_disable(&state, flags); + dprintk("%s: Bad key length %d\n", __FUNCTION__, od->octo_encklen); + return -EINVAL; + } + + CVMX_MT_3DES_IV(* (uint64_t *) ivp); + + /* Load SHA1 IV */ + CVMX_MT_HSH_IV(od->octo_hminner[0], 0); + CVMX_MT_HSH_IV(od->octo_hminner[1], 1); + CVMX_MT_HSH_IV(od->octo_hminner[2], 2); + + while (crypt_off > 0 && auth_off > 0) { + SG_CONSUME(sg, data32, data_i, data_l); + crypt_off -= 4; + auth_off -= 4; + } + + while (crypt_len > 0 || auth_len > 0) { + uint32_t *first = data32; + mydata.data32[0] = *first; + SG_CONSUME(sg, data32, data_i, data_l); + mydata.data32[1] = *data32; + if (crypt_off <= 0) { + if (crypt_len > 0) { + CVMX_MT_3DES_ENC_CBC(*data); + CVMX_MF_3DES_RESULT(*data); + crypt_len -= 8; + } + } else + crypt_off -= 8; + if (auth_off <= 0) { + if (auth_len > 0) { + CVM_LOAD_SHA_UNIT(*data, next); + auth_len -= 8; + } + } else + auth_off -= 8; + *first = mydata.data32[0]; + *data32 = mydata.data32[1]; + SG_CONSUME(sg, data32, data_i, data_l); + } + + /* finish the hash */ + CVMX_PREFETCH0(od->octo_hmouter); +#if 0 + if (unlikely(inplen)) { + uint64_t tmp = 0; + uint8_t *p = (uint8_t *) & tmp; + p[inplen] = 0x80; + do { + inplen--; + p[inplen] = ((uint8_t *) data)[inplen]; + } while (inplen); + CVM_LOAD_SHA_UNIT(tmp, next); + } else { + CVM_LOAD_SHA_UNIT(0x8000000000000000ULL, next); + } +#else + CVM_LOAD_SHA_UNIT(0x8000000000000000ULL, next); +#endif + + /* Finish Inner hash */ + while (next != 7) { + CVM_LOAD_SHA_UNIT(((uint64_t) 0x0ULL), next); + } + CVM_LOAD_SHA_UNIT((uint64_t) ((alen + 64) << 3), next); + + /* Get the inner hash of HMAC */ + CVMX_MF_HSH_IV(tmp1, 0); + CVMX_MF_HSH_IV(tmp2, 1); + tmp3 = 0; + CVMX_MF_HSH_IV(tmp3, 2); + + /* Initialize hash unit */ + CVMX_MT_HSH_IV(od->octo_hmouter[0], 0); + CVMX_MT_HSH_IV(od->octo_hmouter[1], 1); + CVMX_MT_HSH_IV(od->octo_hmouter[2], 2); + + CVMX_MT_HSH_DAT(tmp1, 0); + CVMX_MT_HSH_DAT(tmp2, 1); + tmp3 |= 0x0000000080000000; + CVMX_MT_HSH_DAT(tmp3, 2); + CVMX_MT_HSH_DATZ(3); + CVMX_MT_HSH_DATZ(4); + CVMX_MT_HSH_DATZ(5); + CVMX_MT_HSH_DATZ(6); + CVMX_MT_HSH_STARTSHA((uint64_t) ((64 + 20) << 3)); + + /* save the HMAC */ + SG_INIT(sg, data32, data_i, data_l); + while (icv_off > 0) { + SG_CONSUME(sg, data32, data_i, data_l); + icv_off -= 4; + } + CVMX_MF_HSH_IV(tmp1, 0); + *data32 = (uint32_t) (tmp1 >> 32); + SG_CONSUME(sg, data32, data_i, data_l); + *data32 = (uint32_t) tmp1; + SG_CONSUME(sg, data32, data_i, data_l); + CVMX_MF_HSH_IV(tmp1, 1); + *data32 = (uint32_t) (tmp1 >> 32); + + octeon_crypto_disable(&state, flags); + return 0; +} + +int +octo_des_cbc_sha1_decrypt( + struct octo_sess *od, + struct scatterlist *sg, int sg_len, + int auth_off, int auth_len, + int crypt_off, int crypt_len, + int icv_off, uint8_t *ivp) +{ + register int next = 0; + union { + uint32_t data32[2]; + uint64_t data64[1]; + } mydata; + uint64_t *data = &mydata.data64[0]; + uint32_t *data32; + uint64_t tmp1, tmp2, tmp3; + int data_i, data_l, alen = auth_len; + struct octeon_cop2_state state; + unsigned long flags; + + dprintk("%s()\n", __FUNCTION__); + + if (unlikely(od == NULL || sg==NULL || sg_len==0 || ivp==NULL || + (crypt_off & 0x3) || (crypt_off + crypt_len > sg_len) || + (crypt_len & 0x7) || + (auth_len & 0x7) || + (auth_off & 0x3) || (auth_off + auth_len > sg_len))) { + dprintk("%s: Bad parameters od=%p sg=%p sg_len=%d " + "auth_off=%d auth_len=%d crypt_off=%d crypt_len=%d " + "icv_off=%d ivp=%p\n", __FUNCTION__, od, sg, sg_len, + auth_off, auth_len, crypt_off, crypt_len, icv_off, ivp); + return -EINVAL; + } + + SG_INIT(sg, data32, data_i, data_l); + + CVMX_PREFETCH0(ivp); + CVMX_PREFETCH0(od->octo_enckey); + + flags = octeon_crypto_enable(&state); + + /* load 3DES Key */ + CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 0); + if (od->octo_encklen == 24) { + CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[1], 1); + CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[2], 2); + } else if (od->octo_encklen == 8) { + CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 1); + CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 2); + } else { + octeon_crypto_disable(&state, flags); + dprintk("%s: Bad key length %d\n", __FUNCTION__, od->octo_encklen); + return -EINVAL; + } + + CVMX_MT_3DES_IV(* (uint64_t *) ivp); + + /* Load SHA1 IV */ + CVMX_MT_HSH_IV(od->octo_hminner[0], 0); + CVMX_MT_HSH_IV(od->octo_hminner[1], 1); + CVMX_MT_HSH_IV(od->octo_hminner[2], 2); + + while (crypt_off > 0 && auth_off > 0) { + SG_CONSUME(sg, data32, data_i, data_l); + crypt_off -= 4; + auth_off -= 4; + } + + while (crypt_len > 0 || auth_len > 0) { + uint32_t *first = data32; + mydata.data32[0] = *first; + SG_CONSUME(sg, data32, data_i, data_l); + mydata.data32[1] = *data32; + if (auth_off <= 0) { + if (auth_len > 0) { + CVM_LOAD_SHA_UNIT(*data, next); + auth_len -= 8; + } + } else + auth_off -= 8; + if (crypt_off <= 0) { + if (crypt_len > 0) { + CVMX_MT_3DES_DEC_CBC(*data); + CVMX_MF_3DES_RESULT(*data); + crypt_len -= 8; + } + } else + crypt_off -= 8; + *first = mydata.data32[0]; + *data32 = mydata.data32[1]; + SG_CONSUME(sg, data32, data_i, data_l); + } + + /* finish the hash */ + CVMX_PREFETCH0(od->octo_hmouter); +#if 0 + if (unlikely(inplen)) { + uint64_t tmp = 0; + uint8_t *p = (uint8_t *) & tmp; + p[inplen] = 0x80; + do { + inplen--; + p[inplen] = ((uint8_t *) data)[inplen]; + } while (inplen); + CVM_LOAD_SHA_UNIT(tmp, next); + } else { + CVM_LOAD_SHA_UNIT(0x8000000000000000ULL, next); + } +#else + CVM_LOAD_SHA_UNIT(0x8000000000000000ULL, next); +#endif + + /* Finish Inner hash */ + while (next != 7) { + CVM_LOAD_SHA_UNIT(((uint64_t) 0x0ULL), next); + } + CVM_LOAD_SHA_UNIT((uint64_t) ((alen + 64) << 3), next); + + /* Get the inner hash of HMAC */ + CVMX_MF_HSH_IV(tmp1, 0); + CVMX_MF_HSH_IV(tmp2, 1); + tmp3 = 0; + CVMX_MF_HSH_IV(tmp3, 2); + + /* Initialize hash unit */ + CVMX_MT_HSH_IV(od->octo_hmouter[0], 0); + CVMX_MT_HSH_IV(od->octo_hmouter[1], 1); + CVMX_MT_HSH_IV(od->octo_hmouter[2], 2); + + CVMX_MT_HSH_DAT(tmp1, 0); + CVMX_MT_HSH_DAT(tmp2, 1); + tmp3 |= 0x0000000080000000; + CVMX_MT_HSH_DAT(tmp3, 2); + CVMX_MT_HSH_DATZ(3); + CVMX_MT_HSH_DATZ(4); + CVMX_MT_HSH_DATZ(5); + CVMX_MT_HSH_DATZ(6); + CVMX_MT_HSH_STARTSHA((uint64_t) ((64 + 20) << 3)); + /* save the HMAC */ + SG_INIT(sg, data32, data_i, data_l); + while (icv_off > 0) { + SG_CONSUME(sg, data32, data_i, data_l); + icv_off -= 4; + } + CVMX_MF_HSH_IV(tmp1, 0); + *data32 = (uint32_t) (tmp1 >> 32); + SG_CONSUME(sg, data32, data_i, data_l); + *data32 = (uint32_t) tmp1; + SG_CONSUME(sg, data32, data_i, data_l); + CVMX_MF_HSH_IV(tmp1, 1); + *data32 = (uint32_t) (tmp1 >> 32); + + octeon_crypto_disable(&state, flags); + return 0; +} + +/****************************************************************************/ +/* AES MD5 */ + +int +octo_aes_cbc_md5_encrypt( + struct octo_sess *od, + struct scatterlist *sg, int sg_len, + int auth_off, int auth_len, + int crypt_off, int crypt_len, + int icv_off, uint8_t *ivp) +{ + register int next = 0; + union { + uint32_t data32[2]; + uint64_t data64[1]; + } mydata[2]; + uint64_t *pdata = &mydata[0].data64[0]; + uint64_t *data = &mydata[1].data64[0]; + uint32_t *data32; + uint64_t tmp1, tmp2; + int data_i, data_l, alen = auth_len; + struct octeon_cop2_state state; + unsigned long flags; + + dprintk("%s()\n", __FUNCTION__); + + if (unlikely(od == NULL || sg==NULL || sg_len==0 || ivp==NULL || + (crypt_off & 0x3) || (crypt_off + crypt_len > sg_len) || + (crypt_len & 0x7) || + (auth_len & 0x7) || + (auth_off & 0x3) || (auth_off + auth_len > sg_len))) { + dprintk("%s: Bad parameters od=%p sg=%p sg_len=%d " + "auth_off=%d auth_len=%d crypt_off=%d crypt_len=%d " + "icv_off=%d ivp=%p\n", __FUNCTION__, od, sg, sg_len, + auth_off, auth_len, crypt_off, crypt_len, icv_off, ivp); + return -EINVAL; + } + + SG_INIT(sg, data32, data_i, data_l); + + CVMX_PREFETCH0(ivp); + CVMX_PREFETCH0(od->octo_enckey); + + flags = octeon_crypto_enable(&state); + + /* load AES Key */ + CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[0], 0); + CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[1], 1); + + if (od->octo_encklen == 16) { + CVMX_MT_AES_KEY(0x0, 2); + CVMX_MT_AES_KEY(0x0, 3); + } else if (od->octo_encklen == 24) { + CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[2], 2); + CVMX_MT_AES_KEY(0x0, 3); + } else if (od->octo_encklen == 32) { + CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[2], 2); + CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[3], 3); + } else { + octeon_crypto_disable(&state, flags); + dprintk("%s: Bad key length %d\n", __FUNCTION__, od->octo_encklen); + return -EINVAL; + } + CVMX_MT_AES_KEYLENGTH(od->octo_encklen / 8 - 1); + + CVMX_MT_AES_IV(((uint64_t *) ivp)[0], 0); + CVMX_MT_AES_IV(((uint64_t *) ivp)[1], 1); + + /* Load MD5 IV */ + CVMX_MT_HSH_IV(od->octo_hminner[0], 0); + CVMX_MT_HSH_IV(od->octo_hminner[1], 1); + + while (crypt_off > 0 && auth_off > 0) { + SG_CONSUME(sg, data32, data_i, data_l); + crypt_off -= 4; + auth_off -= 4; + } + + /* align auth and crypt */ + while (crypt_off > 0 && auth_len > 0) { + mydata[0].data32[0] = *data32; + SG_CONSUME(sg, data32, data_i, data_l); + mydata[0].data32[1] = *data32; + SG_CONSUME(sg, data32, data_i, data_l); + CVM_LOAD_MD5_UNIT(*pdata, next); + crypt_off -= 8; + auth_len -= 8; + } + + while (crypt_len > 0) { + uint32_t *pdata32[3]; + + pdata32[0] = data32; + mydata[0].data32[0] = *data32; + SG_CONSUME(sg, data32, data_i, data_l); + + pdata32[1] = data32; + mydata[0].data32[1] = *data32; + SG_CONSUME(sg, data32, data_i, data_l); + + pdata32[2] = data32; + mydata[1].data32[0] = *data32; + SG_CONSUME(sg, data32, data_i, data_l); + + mydata[1].data32[1] = *data32; + + CVMX_MT_AES_ENC_CBC0(*pdata); + CVMX_MT_AES_ENC_CBC1(*data); + CVMX_MF_AES_RESULT(*pdata, 0); + CVMX_MF_AES_RESULT(*data, 1); + crypt_len -= 16; + + if (auth_len > 0) { + CVM_LOAD_MD5_UNIT(*pdata, next); + auth_len -= 8; + } + if (auth_len > 0) { + CVM_LOAD_MD5_UNIT(*data, next); + auth_len -= 8; + } + + *pdata32[0] = mydata[0].data32[0]; + *pdata32[1] = mydata[0].data32[1]; + *pdata32[2] = mydata[1].data32[0]; + *data32 = mydata[1].data32[1]; + + SG_CONSUME(sg, data32, data_i, data_l); + } + + /* finish any left over hashing */ + while (auth_len > 0) { + mydata[0].data32[0] = *data32; + SG_CONSUME(sg, data32, data_i, data_l); + mydata[0].data32[1] = *data32; + SG_CONSUME(sg, data32, data_i, data_l); + CVM_LOAD_MD5_UNIT(*pdata, next); + auth_len -= 8; + } + + /* finish the hash */ + CVMX_PREFETCH0(od->octo_hmouter); +#if 0 + if (unlikely(inplen)) { + uint64_t tmp = 0; + uint8_t *p = (uint8_t *) & tmp; + p[inplen] = 0x80; + do { + inplen--; + p[inplen] = ((uint8_t *) data)[inplen]; + } while (inplen); + CVM_LOAD_MD5_UNIT(tmp, next); + } else { + CVM_LOAD_MD5_UNIT(0x8000000000000000ULL, next); + } +#else + CVM_LOAD_MD5_UNIT(0x8000000000000000ULL, next); +#endif + + /* Finish Inner hash */ + while (next != 7) { + CVM_LOAD_MD5_UNIT(((uint64_t) 0x0ULL), next); + } + CVMX_ES64(tmp1, ((alen + 64) << 3)); + CVM_LOAD_MD5_UNIT(tmp1, next); + + /* Get the inner hash of HMAC */ + CVMX_MF_HSH_IV(tmp1, 0); + CVMX_MF_HSH_IV(tmp2, 1); + + /* Initialize hash unit */ + CVMX_MT_HSH_IV(od->octo_hmouter[0], 0); + CVMX_MT_HSH_IV(od->octo_hmouter[1], 1); + + CVMX_MT_HSH_DAT(tmp1, 0); + CVMX_MT_HSH_DAT(tmp2, 1); + CVMX_MT_HSH_DAT(0x8000000000000000ULL, 2); + CVMX_MT_HSH_DATZ(3); + CVMX_MT_HSH_DATZ(4); + CVMX_MT_HSH_DATZ(5); + CVMX_MT_HSH_DATZ(6); + CVMX_ES64(tmp1, ((64 + 16) << 3)); + CVMX_MT_HSH_STARTMD5(tmp1); + + /* save the HMAC */ + SG_INIT(sg, data32, data_i, data_l); + while (icv_off > 0) { + SG_CONSUME(sg, data32, data_i, data_l); + icv_off -= 4; + } + CVMX_MF_HSH_IV(tmp1, 0); + *data32 = (uint32_t) (tmp1 >> 32); + SG_CONSUME(sg, data32, data_i, data_l); + *data32 = (uint32_t) tmp1; + SG_CONSUME(sg, data32, data_i, data_l); + CVMX_MF_HSH_IV(tmp1, 1); + *data32 = (uint32_t) (tmp1 >> 32); + + octeon_crypto_disable(&state, flags); + return 0; +} + +int +octo_aes_cbc_md5_decrypt( + struct octo_sess *od, + struct scatterlist *sg, int sg_len, + int auth_off, int auth_len, + int crypt_off, int crypt_len, + int icv_off, uint8_t *ivp) +{ + register int next = 0; + union { + uint32_t data32[2]; + uint64_t data64[1]; + } mydata[2]; + uint64_t *pdata = &mydata[0].data64[0]; + uint64_t *data = &mydata[1].data64[0]; + uint32_t *data32; + uint64_t tmp1, tmp2; + int data_i, data_l, alen = auth_len; + struct octeon_cop2_state state; + unsigned long flags; + + dprintk("%s()\n", __FUNCTION__); + + if (unlikely(od == NULL || sg==NULL || sg_len==0 || ivp==NULL || + (crypt_off & 0x3) || (crypt_off + crypt_len > sg_len) || + (crypt_len & 0x7) || + (auth_len & 0x7) || + (auth_off & 0x3) || (auth_off + auth_len > sg_len))) { + dprintk("%s: Bad parameters od=%p sg=%p sg_len=%d " + "auth_off=%d auth_len=%d crypt_off=%d crypt_len=%d " + "icv_off=%d ivp=%p\n", __FUNCTION__, od, sg, sg_len, + auth_off, auth_len, crypt_off, crypt_len, icv_off, ivp); + return -EINVAL; + } + + SG_INIT(sg, data32, data_i, data_l); + + CVMX_PREFETCH0(ivp); + CVMX_PREFETCH0(od->octo_enckey); + + flags = octeon_crypto_enable(&state); + + /* load AES Key */ + CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[0], 0); + CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[1], 1); + + if (od->octo_encklen == 16) { + CVMX_MT_AES_KEY(0x0, 2); + CVMX_MT_AES_KEY(0x0, 3); + } else if (od->octo_encklen == 24) { + CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[2], 2); + CVMX_MT_AES_KEY(0x0, 3); + } else if (od->octo_encklen == 32) { + CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[2], 2); + CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[3], 3); + } else { + octeon_crypto_disable(&state, flags); + dprintk("%s: Bad key length %d\n", __FUNCTION__, od->octo_encklen); + return -EINVAL; + } + CVMX_MT_AES_KEYLENGTH(od->octo_encklen / 8 - 1); + + CVMX_MT_AES_IV(((uint64_t *) ivp)[0], 0); + CVMX_MT_AES_IV(((uint64_t *) ivp)[1], 1); + + /* Load MD5 IV */ + CVMX_MT_HSH_IV(od->octo_hminner[0], 0); + CVMX_MT_HSH_IV(od->octo_hminner[1], 1); + + while (crypt_off > 0 && auth_off > 0) { + SG_CONSUME(sg, data32, data_i, data_l); + crypt_off -= 4; + auth_off -= 4; + } + + /* align auth and crypt */ + while (crypt_off > 0 && auth_len > 0) { + mydata[0].data32[0] = *data32; + SG_CONSUME(sg, data32, data_i, data_l); + mydata[0].data32[1] = *data32; + SG_CONSUME(sg, data32, data_i, data_l); + CVM_LOAD_MD5_UNIT(*pdata, next); + crypt_off -= 8; + auth_len -= 8; + } + + while (crypt_len > 0) { + uint32_t *pdata32[3]; + + pdata32[0] = data32; + mydata[0].data32[0] = *data32; + SG_CONSUME(sg, data32, data_i, data_l); + pdata32[1] = data32; + mydata[0].data32[1] = *data32; + SG_CONSUME(sg, data32, data_i, data_l); + pdata32[2] = data32; + mydata[1].data32[0] = *data32; + SG_CONSUME(sg, data32, data_i, data_l); + mydata[1].data32[1] = *data32; + + if (auth_len > 0) { + CVM_LOAD_MD5_UNIT(*pdata, next); + auth_len -= 8; + } + + if (auth_len > 0) { + CVM_LOAD_MD5_UNIT(*data, next); + auth_len -= 8; + } + + CVMX_MT_AES_DEC_CBC0(*pdata); + CVMX_MT_AES_DEC_CBC1(*data); + CVMX_MF_AES_RESULT(*pdata, 0); + CVMX_MF_AES_RESULT(*data, 1); + crypt_len -= 16; + + *pdata32[0] = mydata[0].data32[0]; + *pdata32[1] = mydata[0].data32[1]; + *pdata32[2] = mydata[1].data32[0]; + *data32 = mydata[1].data32[1]; + + SG_CONSUME(sg, data32, data_i, data_l); + } + + /* finish left over hash if any */ + while (auth_len > 0) { + mydata[0].data32[0] = *data32; + SG_CONSUME(sg, data32, data_i, data_l); + mydata[0].data32[1] = *data32; + SG_CONSUME(sg, data32, data_i, data_l); + CVM_LOAD_MD5_UNIT(*pdata, next); + auth_len -= 8; + } + + + /* finish the hash */ + CVMX_PREFETCH0(od->octo_hmouter); +#if 0 + if (unlikely(inplen)) { + uint64_t tmp = 0; + uint8_t *p = (uint8_t *) & tmp; + p[inplen] = 0x80; + do { + inplen--; + p[inplen] = ((uint8_t *) data)[inplen]; + } while (inplen); + CVM_LOAD_MD5_UNIT(tmp, next); + } else { + CVM_LOAD_MD5_UNIT(0x8000000000000000ULL, next); + } +#else + CVM_LOAD_MD5_UNIT(0x8000000000000000ULL, next); +#endif + + /* Finish Inner hash */ + while (next != 7) { + CVM_LOAD_MD5_UNIT(((uint64_t) 0x0ULL), next); + } + CVMX_ES64(tmp1, ((alen + 64) << 3)); + CVM_LOAD_MD5_UNIT(tmp1, next); + + /* Get the inner hash of HMAC */ + CVMX_MF_HSH_IV(tmp1, 0); + CVMX_MF_HSH_IV(tmp2, 1); + + /* Initialize hash unit */ + CVMX_MT_HSH_IV(od->octo_hmouter[0], 0); + CVMX_MT_HSH_IV(od->octo_hmouter[1], 1); + + CVMX_MT_HSH_DAT(tmp1, 0); + CVMX_MT_HSH_DAT(tmp2, 1); + CVMX_MT_HSH_DAT(0x8000000000000000ULL, 2); + CVMX_MT_HSH_DATZ(3); + CVMX_MT_HSH_DATZ(4); + CVMX_MT_HSH_DATZ(5); + CVMX_MT_HSH_DATZ(6); + CVMX_ES64(tmp1, ((64 + 16) << 3)); + CVMX_MT_HSH_STARTMD5(tmp1); + + /* save the HMAC */ + SG_INIT(sg, data32, data_i, data_l); + while (icv_off > 0) { + SG_CONSUME(sg, data32, data_i, data_l); + icv_off -= 4; + } + CVMX_MF_HSH_IV(tmp1, 0); + *data32 = (uint32_t) (tmp1 >> 32); + SG_CONSUME(sg, data32, data_i, data_l); + *data32 = (uint32_t) tmp1; + SG_CONSUME(sg, data32, data_i, data_l); + CVMX_MF_HSH_IV(tmp1, 1); + *data32 = (uint32_t) (tmp1 >> 32); + + octeon_crypto_disable(&state, flags); + return 0; +} + +/****************************************************************************/ +/* AES SHA1 */ + +int +octo_aes_cbc_sha1_encrypt( + struct octo_sess *od, + struct scatterlist *sg, int sg_len, + int auth_off, int auth_len, + int crypt_off, int crypt_len, + int icv_off, uint8_t *ivp) +{ + register int next = 0; + union { + uint32_t data32[2]; + uint64_t data64[1]; + } mydata[2]; + uint64_t *pdata = &mydata[0].data64[0]; + uint64_t *data = &mydata[1].data64[0]; + uint32_t *data32; + uint64_t tmp1, tmp2, tmp3; + int data_i, data_l, alen = auth_len; + struct octeon_cop2_state state; + unsigned long flags; + + dprintk("%s(a_off=%d a_len=%d c_off=%d c_len=%d icv_off=%d)\n", + __FUNCTION__, auth_off, auth_len, crypt_off, crypt_len, icv_off); + + if (unlikely(od == NULL || sg==NULL || sg_len==0 || ivp==NULL || + (crypt_off & 0x3) || (crypt_off + crypt_len > sg_len) || + (crypt_len & 0x7) || + (auth_len & 0x7) || + (auth_off & 0x3) || (auth_off + auth_len > sg_len))) { + dprintk("%s: Bad parameters od=%p sg=%p sg_len=%d " + "auth_off=%d auth_len=%d crypt_off=%d crypt_len=%d " + "icv_off=%d ivp=%p\n", __FUNCTION__, od, sg, sg_len, + auth_off, auth_len, crypt_off, crypt_len, icv_off, ivp); + return -EINVAL; + } + + SG_INIT(sg, data32, data_i, data_l); + + CVMX_PREFETCH0(ivp); + CVMX_PREFETCH0(od->octo_enckey); + + flags = octeon_crypto_enable(&state); + + /* load AES Key */ + CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[0], 0); + CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[1], 1); + + if (od->octo_encklen == 16) { + CVMX_MT_AES_KEY(0x0, 2); + CVMX_MT_AES_KEY(0x0, 3); + } else if (od->octo_encklen == 24) { + CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[2], 2); + CVMX_MT_AES_KEY(0x0, 3); + } else if (od->octo_encklen == 32) { + CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[2], 2); + CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[3], 3); + } else { + octeon_crypto_disable(&state, flags); + dprintk("%s: Bad key length %d\n", __FUNCTION__, od->octo_encklen); + return -EINVAL; + } + CVMX_MT_AES_KEYLENGTH(od->octo_encklen / 8 - 1); + + CVMX_MT_AES_IV(((uint64_t *) ivp)[0], 0); + CVMX_MT_AES_IV(((uint64_t *) ivp)[1], 1); + + /* Load SHA IV */ + CVMX_MT_HSH_IV(od->octo_hminner[0], 0); + CVMX_MT_HSH_IV(od->octo_hminner[1], 1); + CVMX_MT_HSH_IV(od->octo_hminner[2], 2); + + while (crypt_off > 0 && auth_off > 0) { + SG_CONSUME(sg, data32, data_i, data_l); + crypt_off -= 4; + auth_off -= 4; + } + + /* align auth and crypt */ + while (crypt_off > 0 && auth_len > 0) { + mydata[0].data32[0] = *data32; + SG_CONSUME(sg, data32, data_i, data_l); + mydata[0].data32[1] = *data32; + SG_CONSUME(sg, data32, data_i, data_l); + CVM_LOAD_SHA_UNIT(*pdata, next); + crypt_off -= 8; + auth_len -= 8; + } + + while (crypt_len > 0) { + uint32_t *pdata32[3]; + + pdata32[0] = data32; + mydata[0].data32[0] = *data32; + SG_CONSUME(sg, data32, data_i, data_l); + pdata32[1] = data32; + mydata[0].data32[1] = *data32; + SG_CONSUME(sg, data32, data_i, data_l); + pdata32[2] = data32; + mydata[1].data32[0] = *data32; + SG_CONSUME(sg, data32, data_i, data_l); + mydata[1].data32[1] = *data32; + + CVMX_MT_AES_ENC_CBC0(*pdata); + CVMX_MT_AES_ENC_CBC1(*data); + CVMX_MF_AES_RESULT(*pdata, 0); + CVMX_MF_AES_RESULT(*data, 1); + crypt_len -= 16; + + if (auth_len > 0) { + CVM_LOAD_SHA_UNIT(*pdata, next); + auth_len -= 8; + } + if (auth_len > 0) { + CVM_LOAD_SHA_UNIT(*data, next); + auth_len -= 8; + } + + *pdata32[0] = mydata[0].data32[0]; + *pdata32[1] = mydata[0].data32[1]; + *pdata32[2] = mydata[1].data32[0]; + *data32 = mydata[1].data32[1]; + + SG_CONSUME(sg, data32, data_i, data_l); + } + + /* finish and hashing */ + while (auth_len > 0) { + mydata[0].data32[0] = *data32; + SG_CONSUME(sg, data32, data_i, data_l); + mydata[0].data32[1] = *data32; + SG_CONSUME(sg, data32, data_i, data_l); + CVM_LOAD_SHA_UNIT(*pdata, next); + auth_len -= 8; + } + + /* finish the hash */ + CVMX_PREFETCH0(od->octo_hmouter); +#if 0 + if (unlikely(inplen)) { + uint64_t tmp = 0; + uint8_t *p = (uint8_t *) & tmp; + p[inplen] = 0x80; + do { + inplen--; + p[inplen] = ((uint8_t *) data)[inplen]; + } while (inplen); + CVM_LOAD_SHA_UNIT(tmp, next); + } else { + CVM_LOAD_SHA_UNIT(0x8000000000000000ULL, next); + } +#else + CVM_LOAD_SHA_UNIT(0x8000000000000000ULL, next); +#endif + + /* Finish Inner hash */ + while (next != 7) { + CVM_LOAD_SHA_UNIT(((uint64_t) 0x0ULL), next); + } + CVM_LOAD_SHA_UNIT((uint64_t) ((alen + 64) << 3), next); + + /* Get the inner hash of HMAC */ + CVMX_MF_HSH_IV(tmp1, 0); + CVMX_MF_HSH_IV(tmp2, 1); + tmp3 = 0; + CVMX_MF_HSH_IV(tmp3, 2); + + /* Initialize hash unit */ + CVMX_MT_HSH_IV(od->octo_hmouter[0], 0); + CVMX_MT_HSH_IV(od->octo_hmouter[1], 1); + CVMX_MT_HSH_IV(od->octo_hmouter[2], 2); + + CVMX_MT_HSH_DAT(tmp1, 0); + CVMX_MT_HSH_DAT(tmp2, 1); + tmp3 |= 0x0000000080000000; + CVMX_MT_HSH_DAT(tmp3, 2); + CVMX_MT_HSH_DATZ(3); + CVMX_MT_HSH_DATZ(4); + CVMX_MT_HSH_DATZ(5); + CVMX_MT_HSH_DATZ(6); + CVMX_MT_HSH_STARTSHA((uint64_t) ((64 + 20) << 3)); + + /* finish the hash */ + CVMX_PREFETCH0(od->octo_hmouter); +#if 0 + if (unlikely(inplen)) { + uint64_t tmp = 0; + uint8_t *p = (uint8_t *) & tmp; + p[inplen] = 0x80; + do { + inplen--; + p[inplen] = ((uint8_t *) data)[inplen]; + } while (inplen); + CVM_LOAD_MD5_UNIT(tmp, next); + } else { + CVM_LOAD_MD5_UNIT(0x8000000000000000ULL, next); + } +#else + CVM_LOAD_MD5_UNIT(0x8000000000000000ULL, next); +#endif + + /* save the HMAC */ + SG_INIT(sg, data32, data_i, data_l); + while (icv_off > 0) { + SG_CONSUME(sg, data32, data_i, data_l); + icv_off -= 4; + } + CVMX_MF_HSH_IV(tmp1, 0); + *data32 = (uint32_t) (tmp1 >> 32); + SG_CONSUME(sg, data32, data_i, data_l); + *data32 = (uint32_t) tmp1; + SG_CONSUME(sg, data32, data_i, data_l); + CVMX_MF_HSH_IV(tmp1, 1); + *data32 = (uint32_t) (tmp1 >> 32); + + octeon_crypto_disable(&state, flags); + return 0; +} + +int +octo_aes_cbc_sha1_decrypt( + struct octo_sess *od, + struct scatterlist *sg, int sg_len, + int auth_off, int auth_len, + int crypt_off, int crypt_len, + int icv_off, uint8_t *ivp) +{ + register int next = 0; + union { + uint32_t data32[2]; + uint64_t data64[1]; + } mydata[2]; + uint64_t *pdata = &mydata[0].data64[0]; + uint64_t *data = &mydata[1].data64[0]; + uint32_t *data32; + uint64_t tmp1, tmp2, tmp3; + int data_i, data_l, alen = auth_len; + struct octeon_cop2_state state; + unsigned long flags; + + dprintk("%s(a_off=%d a_len=%d c_off=%d c_len=%d icv_off=%d)\n", + __FUNCTION__, auth_off, auth_len, crypt_off, crypt_len, icv_off); + + if (unlikely(od == NULL || sg==NULL || sg_len==0 || ivp==NULL || + (crypt_off & 0x3) || (crypt_off + crypt_len > sg_len) || + (crypt_len & 0x7) || + (auth_len & 0x7) || + (auth_off & 0x3) || (auth_off + auth_len > sg_len))) { + dprintk("%s: Bad parameters od=%p sg=%p sg_len=%d " + "auth_off=%d auth_len=%d crypt_off=%d crypt_len=%d " + "icv_off=%d ivp=%p\n", __FUNCTION__, od, sg, sg_len, + auth_off, auth_len, crypt_off, crypt_len, icv_off, ivp); + return -EINVAL; + } + + SG_INIT(sg, data32, data_i, data_l); + + CVMX_PREFETCH0(ivp); + CVMX_PREFETCH0(od->octo_enckey); + + flags = octeon_crypto_enable(&state); + + /* load AES Key */ + CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[0], 0); + CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[1], 1); + + if (od->octo_encklen == 16) { + CVMX_MT_AES_KEY(0x0, 2); + CVMX_MT_AES_KEY(0x0, 3); + } else if (od->octo_encklen == 24) { + CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[2], 2); + CVMX_MT_AES_KEY(0x0, 3); + } else if (od->octo_encklen == 32) { + CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[2], 2); + CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[3], 3); + } else { + octeon_crypto_disable(&state, flags); + dprintk("%s: Bad key length %d\n", __FUNCTION__, od->octo_encklen); + return -EINVAL; + } + CVMX_MT_AES_KEYLENGTH(od->octo_encklen / 8 - 1); + + CVMX_MT_AES_IV(((uint64_t *) ivp)[0], 0); + CVMX_MT_AES_IV(((uint64_t *) ivp)[1], 1); + + /* Load SHA1 IV */ + CVMX_MT_HSH_IV(od->octo_hminner[0], 0); + CVMX_MT_HSH_IV(od->octo_hminner[1], 1); + CVMX_MT_HSH_IV(od->octo_hminner[2], 2); + + while (crypt_off > 0 && auth_off > 0) { + SG_CONSUME(sg, data32, data_i, data_l); + crypt_off -= 4; + auth_off -= 4; + } + + /* align auth and crypt */ + while (crypt_off > 0 && auth_len > 0) { + mydata[0].data32[0] = *data32; + SG_CONSUME(sg, data32, data_i, data_l); + mydata[0].data32[1] = *data32; + SG_CONSUME(sg, data32, data_i, data_l); + CVM_LOAD_SHA_UNIT(*pdata, next); + crypt_off -= 8; + auth_len -= 8; + } + + while (crypt_len > 0) { + uint32_t *pdata32[3]; + + pdata32[0] = data32; + mydata[0].data32[0] = *data32; + SG_CONSUME(sg, data32, data_i, data_l); + pdata32[1] = data32; + mydata[0].data32[1] = *data32; + SG_CONSUME(sg, data32, data_i, data_l); + pdata32[2] = data32; + mydata[1].data32[0] = *data32; + SG_CONSUME(sg, data32, data_i, data_l); + mydata[1].data32[1] = *data32; + + if (auth_len > 0) { + CVM_LOAD_SHA_UNIT(*pdata, next); + auth_len -= 8; + } + if (auth_len > 0) { + CVM_LOAD_SHA_UNIT(*data, next); + auth_len -= 8; + } + + CVMX_MT_AES_DEC_CBC0(*pdata); + CVMX_MT_AES_DEC_CBC1(*data); + CVMX_MF_AES_RESULT(*pdata, 0); + CVMX_MF_AES_RESULT(*data, 1); + crypt_len -= 16; + + *pdata32[0] = mydata[0].data32[0]; + *pdata32[1] = mydata[0].data32[1]; + *pdata32[2] = mydata[1].data32[0]; + *data32 = mydata[1].data32[1]; + + SG_CONSUME(sg, data32, data_i, data_l); + } + + /* finish and leftover hashing */ + while (auth_len > 0) { + mydata[0].data32[0] = *data32; + SG_CONSUME(sg, data32, data_i, data_l); + mydata[0].data32[1] = *data32; + SG_CONSUME(sg, data32, data_i, data_l); + CVM_LOAD_SHA_UNIT(*pdata, next); + auth_len -= 8; + } + + /* finish the hash */ + CVMX_PREFETCH0(od->octo_hmouter); +#if 0 + if (unlikely(inplen)) { + uint64_t tmp = 0; + uint8_t *p = (uint8_t *) & tmp; + p[inplen] = 0x80; + do { + inplen--; + p[inplen] = ((uint8_t *) data)[inplen]; + } while (inplen); + CVM_LOAD_SHA_UNIT(tmp, next); + } else { + CVM_LOAD_SHA_UNIT(0x8000000000000000ULL, next); + } +#else + CVM_LOAD_SHA_UNIT(0x8000000000000000ULL, next); +#endif + + /* Finish Inner hash */ + while (next != 7) { + CVM_LOAD_SHA_UNIT(((uint64_t) 0x0ULL), next); + } + CVM_LOAD_SHA_UNIT((uint64_t) ((alen + 64) << 3), next); + + /* Get the inner hash of HMAC */ + CVMX_MF_HSH_IV(tmp1, 0); + CVMX_MF_HSH_IV(tmp2, 1); + tmp3 = 0; + CVMX_MF_HSH_IV(tmp3, 2); + + /* Initialize hash unit */ + CVMX_MT_HSH_IV(od->octo_hmouter[0], 0); + CVMX_MT_HSH_IV(od->octo_hmouter[1], 1); + CVMX_MT_HSH_IV(od->octo_hmouter[2], 2); + + CVMX_MT_HSH_DAT(tmp1, 0); + CVMX_MT_HSH_DAT(tmp2, 1); + tmp3 |= 0x0000000080000000; + CVMX_MT_HSH_DAT(tmp3, 2); + CVMX_MT_HSH_DATZ(3); + CVMX_MT_HSH_DATZ(4); + CVMX_MT_HSH_DATZ(5); + CVMX_MT_HSH_DATZ(6); + CVMX_MT_HSH_STARTSHA((uint64_t) ((64 + 20) << 3)); + + /* finish the hash */ + CVMX_PREFETCH0(od->octo_hmouter); +#if 0 + if (unlikely(inplen)) { + uint64_t tmp = 0; + uint8_t *p = (uint8_t *) & tmp; + p[inplen] = 0x80; + do { + inplen--; + p[inplen] = ((uint8_t *) data)[inplen]; + } while (inplen); + CVM_LOAD_MD5_UNIT(tmp, next); + } else { + CVM_LOAD_MD5_UNIT(0x8000000000000000ULL, next); + } +#else + CVM_LOAD_MD5_UNIT(0x8000000000000000ULL, next); +#endif + + /* save the HMAC */ + SG_INIT(sg, data32, data_i, data_l); + while (icv_off > 0) { + SG_CONSUME(sg, data32, data_i, data_l); + icv_off -= 4; + } + CVMX_MF_HSH_IV(tmp1, 0); + *data32 = (uint32_t) (tmp1 >> 32); + SG_CONSUME(sg, data32, data_i, data_l); + *data32 = (uint32_t) tmp1; + SG_CONSUME(sg, data32, data_i, data_l); + CVMX_MF_HSH_IV(tmp1, 1); + *data32 = (uint32_t) (tmp1 >> 32); + + octeon_crypto_disable(&state, flags); + return 0; +} + +/****************************************************************************/ diff --git a/target/linux/generic/files/crypto/ocf/cryptocteon/cryptocteon.c b/target/linux/generic/files/crypto/ocf/cryptocteon/cryptocteon.c new file mode 100644 index 0000000..e084c6b --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/cryptocteon/cryptocteon.c @@ -0,0 +1,576 @@ +/* + * Octeon Crypto for OCF + * + * Written by David McCullough + * Copyright (C) 2009-2010 David McCullough + * + * LICENSE TERMS + * + * The free distribution and use of this software in both source and binary + * form is allowed (with or without changes) provided that: + * + * 1. distributions of this source code include the above copyright + * notice, this list of conditions and the following disclaimer; + * + * 2. distributions in binary form include the above copyright + * notice, this list of conditions and the following disclaimer + * in the documentation and/or other associated materials; + * + * 3. the copyright holder's name is not used to endorse products + * built using this software without specific written permission. + * + * DISCLAIMER + * + * This software is provided 'as is' with no explicit or implied warranties + * in respect of its properties, including, but not limited to, correctness + * and/or fitness for purpose. + * --------------------------------------------------------------------------- + */ + +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) && !defined(AUTOCONF_INCLUDED) +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +struct { + softc_device_decl sc_dev; +} octo_softc; + +#define offset_in_page(p) ((unsigned long)(p) & ~PAGE_MASK) + +struct octo_sess { + int octo_encalg; + #define MAX_CIPHER_KEYLEN 64 + char octo_enckey[MAX_CIPHER_KEYLEN]; + int octo_encklen; + + int octo_macalg; + #define MAX_HASH_KEYLEN 64 + char octo_mackey[MAX_HASH_KEYLEN]; + int octo_macklen; + int octo_mackey_set; + + int octo_mlen; + int octo_ivsize; + + int (*octo_encrypt)(struct octo_sess *od, + struct scatterlist *sg, int sg_len, + int auth_off, int auth_len, + int crypt_off, int crypt_len, + int icv_off, uint8_t *ivp); + int (*octo_decrypt)(struct octo_sess *od, + struct scatterlist *sg, int sg_len, + int auth_off, int auth_len, + int crypt_off, int crypt_len, + int icv_off, uint8_t *ivp); + + uint64_t octo_hminner[3]; + uint64_t octo_hmouter[3]; +}; + +int32_t octo_id = -1; +module_param(octo_id, int, 0444); +MODULE_PARM_DESC(octo_id, "Read-Only OCF ID for cryptocteon driver"); + +static struct octo_sess **octo_sessions = NULL; +static u_int32_t octo_sesnum = 0; + +static int octo_process(device_t, struct cryptop *, int); +static int octo_newsession(device_t, u_int32_t *, struct cryptoini *); +static int octo_freesession(device_t, u_int64_t); + +static device_method_t octo_methods = { + /* crypto device methods */ + DEVMETHOD(cryptodev_newsession, octo_newsession), + DEVMETHOD(cryptodev_freesession,octo_freesession), + DEVMETHOD(cryptodev_process, octo_process), +}; + +#define debug octo_debug +int octo_debug = 0; +module_param(octo_debug, int, 0644); +MODULE_PARM_DESC(octo_debug, "Enable debug"); + + +#include "cavium_crypto.c" + + +/* + * Generate a new octo session. We artifically limit it to a single + * hash/cipher or hash-cipher combo just to make it easier, most callers + * do not expect more than this anyway. + */ +static int +octo_newsession(device_t dev, u_int32_t *sid, struct cryptoini *cri) +{ + struct cryptoini *c, *encini = NULL, *macini = NULL; + struct octo_sess **ocd; + int i; + + dprintk("%s()\n", __FUNCTION__); + if (sid == NULL || cri == NULL) { + dprintk("%s,%d - EINVAL\n", __FILE__, __LINE__); + return EINVAL; + } + + /* + * To keep it simple, we only handle hash, cipher or hash/cipher in a + * session, you cannot currently do multiple ciphers/hashes in one + * session even though it would be possibel to code this driver to + * handle it. + */ + for (i = 0, c = cri; c && i < 2; i++) { + if (c->cri_alg == CRYPTO_MD5_HMAC || + c->cri_alg == CRYPTO_SHA1_HMAC || + c->cri_alg == CRYPTO_NULL_HMAC) { + if (macini) { + break; + } + macini = c; + } + if (c->cri_alg == CRYPTO_DES_CBC || + c->cri_alg == CRYPTO_3DES_CBC || + c->cri_alg == CRYPTO_AES_CBC || + c->cri_alg == CRYPTO_NULL_CBC) { + if (encini) { + break; + } + encini = c; + } + c = c->cri_next; + } + if (!macini && !encini) { + dprintk("%s,%d - EINVAL bad cipher/hash or combination\n", + __FILE__, __LINE__); + return EINVAL; + } + if (c) { + dprintk("%s,%d - EINVAL cannot handle chained cipher/hash combos\n", + __FILE__, __LINE__); + return EINVAL; + } + + /* + * So we have something we can do, lets setup the session + */ + + if (octo_sessions) { + for (i = 1; i < octo_sesnum; i++) + if (octo_sessions[i] == NULL) + break; + } else + i = 1; /* NB: to silence compiler warning */ + + if (octo_sessions == NULL || i == octo_sesnum) { + if (octo_sessions == NULL) { + i = 1; /* We leave octo_sessions[0] empty */ + octo_sesnum = CRYPTO_SW_SESSIONS; + } else + octo_sesnum *= 2; + + ocd = kmalloc(octo_sesnum * sizeof(struct octo_sess *), SLAB_ATOMIC); + if (ocd == NULL) { + /* Reset session number */ + if (octo_sesnum == CRYPTO_SW_SESSIONS) + octo_sesnum = 0; + else + octo_sesnum /= 2; + dprintk("%s,%d: ENOBUFS\n", __FILE__, __LINE__); + return ENOBUFS; + } + memset(ocd, 0, octo_sesnum * sizeof(struct octo_sess *)); + + /* Copy existing sessions */ + if (octo_sessions) { + memcpy(ocd, octo_sessions, + (octo_sesnum / 2) * sizeof(struct octo_sess *)); + kfree(octo_sessions); + } + + octo_sessions = ocd; + } + + ocd = &octo_sessions[i]; + *sid = i; + + + *ocd = (struct octo_sess *) kmalloc(sizeof(struct octo_sess), SLAB_ATOMIC); + if (*ocd == NULL) { + octo_freesession(NULL, i); + dprintk("%s,%d: ENOBUFS\n", __FILE__, __LINE__); + return ENOBUFS; + } + memset(*ocd, 0, sizeof(struct octo_sess)); + + if (encini && encini->cri_key) { + (*ocd)->octo_encklen = (encini->cri_klen + 7) / 8; + memcpy((*ocd)->octo_enckey, encini->cri_key, (*ocd)->octo_encklen); + } + + if (macini && macini->cri_key) { + (*ocd)->octo_macklen = (macini->cri_klen + 7) / 8; + memcpy((*ocd)->octo_mackey, macini->cri_key, (*ocd)->octo_macklen); + } + + (*ocd)->octo_mlen = 0; + if (encini && encini->cri_mlen) + (*ocd)->octo_mlen = encini->cri_mlen; + else if (macini && macini->cri_mlen) + (*ocd)->octo_mlen = macini->cri_mlen; + else + (*ocd)->octo_mlen = 12; + + /* + * point c at the enc if it exists, otherwise the mac + */ + c = encini ? encini : macini; + + switch (c->cri_alg) { + case CRYPTO_DES_CBC: + case CRYPTO_3DES_CBC: + (*ocd)->octo_ivsize = 8; + switch (macini ? macini->cri_alg : -1) { + case CRYPTO_MD5_HMAC: + (*ocd)->octo_encrypt = octo_des_cbc_md5_encrypt; + (*ocd)->octo_decrypt = octo_des_cbc_md5_decrypt; + octo_calc_hash(0, macini->cri_key, (*ocd)->octo_hminner, + (*ocd)->octo_hmouter); + break; + case CRYPTO_SHA1_HMAC: + (*ocd)->octo_encrypt = octo_des_cbc_sha1_encrypt; + (*ocd)->octo_decrypt = octo_des_cbc_sha1_decrypt; + octo_calc_hash(1, macini->cri_key, (*ocd)->octo_hminner, + (*ocd)->octo_hmouter); + break; + case -1: + (*ocd)->octo_encrypt = octo_des_cbc_encrypt; + (*ocd)->octo_decrypt = octo_des_cbc_decrypt; + break; + default: + octo_freesession(NULL, i); + dprintk("%s,%d: EINVALn", __FILE__, __LINE__); + return EINVAL; + } + break; + case CRYPTO_AES_CBC: + (*ocd)->octo_ivsize = 16; + switch (macini ? macini->cri_alg : -1) { + case CRYPTO_MD5_HMAC: + (*ocd)->octo_encrypt = octo_aes_cbc_md5_encrypt; + (*ocd)->octo_decrypt = octo_aes_cbc_md5_decrypt; + octo_calc_hash(0, macini->cri_key, (*ocd)->octo_hminner, + (*ocd)->octo_hmouter); + break; + case CRYPTO_SHA1_HMAC: + (*ocd)->octo_encrypt = octo_aes_cbc_sha1_encrypt; + (*ocd)->octo_decrypt = octo_aes_cbc_sha1_decrypt; + octo_calc_hash(1, macini->cri_key, (*ocd)->octo_hminner, + (*ocd)->octo_hmouter); + break; + case -1: + (*ocd)->octo_encrypt = octo_aes_cbc_encrypt; + (*ocd)->octo_decrypt = octo_aes_cbc_decrypt; + break; + default: + octo_freesession(NULL, i); + dprintk("%s,%d: EINVALn", __FILE__, __LINE__); + return EINVAL; + } + break; + case CRYPTO_MD5_HMAC: + (*ocd)->octo_encrypt = octo_null_md5_encrypt; + (*ocd)->octo_decrypt = octo_null_md5_encrypt; /* encrypt == decrypt */ + octo_calc_hash(0, macini->cri_key, (*ocd)->octo_hminner, + (*ocd)->octo_hmouter); + break; + case CRYPTO_SHA1_HMAC: + (*ocd)->octo_encrypt = octo_null_sha1_encrypt; + (*ocd)->octo_decrypt = octo_null_sha1_encrypt; /* encrypt == decrypt */ + octo_calc_hash(1, macini->cri_key, (*ocd)->octo_hminner, + (*ocd)->octo_hmouter); + break; + default: + octo_freesession(NULL, i); + dprintk("%s,%d: EINVALn", __FILE__, __LINE__); + return EINVAL; + } + + (*ocd)->octo_encalg = encini ? encini->cri_alg : -1; + (*ocd)->octo_macalg = macini ? macini->cri_alg : -1; + + return 0; +} + +/* + * Free a session. + */ +static int +octo_freesession(device_t dev, u_int64_t tid) +{ + u_int32_t sid = CRYPTO_SESID2LID(tid); + + dprintk("%s()\n", __FUNCTION__); + if (sid > octo_sesnum || octo_sessions == NULL || + octo_sessions[sid] == NULL) { + dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__); + return(EINVAL); + } + + /* Silently accept and return */ + if (sid == 0) + return(0); + + if (octo_sessions[sid]) + kfree(octo_sessions[sid]); + octo_sessions[sid] = NULL; + return 0; +} + +/* + * Process a request. + */ +static int +octo_process(device_t dev, struct cryptop *crp, int hint) +{ + struct cryptodesc *crd; + struct octo_sess *od; + u_int32_t lid; +#define SCATTERLIST_MAX 16 + struct scatterlist sg[SCATTERLIST_MAX]; + int sg_num, sg_len; + struct sk_buff *skb = NULL; + struct uio *uiop = NULL; + struct cryptodesc *enccrd = NULL, *maccrd = NULL; + unsigned char *ivp = NULL; + unsigned char iv_data[HASH_MAX_LEN]; + int auth_off = 0, auth_len = 0, crypt_off = 0, crypt_len = 0, icv_off = 0; + + dprintk("%s()\n", __FUNCTION__); + /* Sanity check */ + if (crp == NULL) { + dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__); + return EINVAL; + } + + crp->crp_etype = 0; + + if (crp->crp_desc == NULL || crp->crp_buf == NULL) { + dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__); + crp->crp_etype = EINVAL; + goto done; + } + + lid = crp->crp_sid & 0xffffffff; + if (lid >= octo_sesnum || lid == 0 || octo_sessions == NULL || + octo_sessions[lid] == NULL) { + crp->crp_etype = ENOENT; + dprintk("%s,%d: ENOENT\n", __FILE__, __LINE__); + goto done; + } + od = octo_sessions[lid]; + + /* + * do some error checking outside of the loop for SKB and IOV processing + * this leaves us with valid skb or uiop pointers for later + */ + if (crp->crp_flags & CRYPTO_F_SKBUF) { + skb = (struct sk_buff *) crp->crp_buf; + if (skb_shinfo(skb)->nr_frags >= SCATTERLIST_MAX) { + printk("%s,%d: %d nr_frags > SCATTERLIST_MAX", __FILE__, __LINE__, + skb_shinfo(skb)->nr_frags); + goto done; + } + } else if (crp->crp_flags & CRYPTO_F_IOV) { + uiop = (struct uio *) crp->crp_buf; + if (uiop->uio_iovcnt > SCATTERLIST_MAX) { + printk("%s,%d: %d uio_iovcnt > SCATTERLIST_MAX", __FILE__, __LINE__, + uiop->uio_iovcnt); + goto done; + } + } + + /* point our enccrd and maccrd appropriately */ + crd = crp->crp_desc; + if (crd->crd_alg == od->octo_encalg) enccrd = crd; + if (crd->crd_alg == od->octo_macalg) maccrd = crd; + crd = crd->crd_next; + if (crd) { + if (crd->crd_alg == od->octo_encalg) enccrd = crd; + if (crd->crd_alg == od->octo_macalg) maccrd = crd; + crd = crd->crd_next; + } + if (crd) { + crp->crp_etype = EINVAL; + dprintk("%s,%d: ENOENT - descriptors do not match session\n", + __FILE__, __LINE__); + goto done; + } + + if (enccrd) { + if (enccrd->crd_flags & CRD_F_ENCRYPT) { + if (enccrd->crd_flags & CRD_F_IV_EXPLICIT) + ivp = enccrd->crd_iv; + else + read_random((ivp = iv_data), od->octo_ivsize); + if ((enccrd->crd_flags & CRD_F_IV_PRESENT) == 0) + crypto_copyback(crp->crp_flags, crp->crp_buf, + enccrd->crd_inject, od->octo_ivsize, ivp); + } else { + if (enccrd->crd_flags & CRD_F_IV_EXPLICIT) { + ivp = enccrd->crd_iv; + } else { + ivp = iv_data; + crypto_copydata(crp->crp_flags, crp->crp_buf, + enccrd->crd_inject, od->octo_ivsize, (caddr_t) ivp); + } + } + + if (maccrd) { + auth_off = maccrd->crd_skip; + auth_len = maccrd->crd_len; + icv_off = maccrd->crd_inject; + } + + crypt_off = enccrd->crd_skip; + crypt_len = enccrd->crd_len; + } else { /* if (maccrd) */ + auth_off = maccrd->crd_skip; + auth_len = maccrd->crd_len; + icv_off = maccrd->crd_inject; + } + + + /* + * setup the SG list to cover the buffer + */ + memset(sg, 0, sizeof(sg)); + if (crp->crp_flags & CRYPTO_F_SKBUF) { + int i, len; + + sg_num = 0; + sg_len = 0; + + len = skb_headlen(skb); + sg_set_page(&sg[sg_num], virt_to_page(skb->data), len, + offset_in_page(skb->data)); + sg_len += len; + sg_num++; + + for (i = 0; i < skb_shinfo(skb)->nr_frags && sg_num < SCATTERLIST_MAX; + i++) { + len = skb_shinfo(skb)->frags[i].size; + sg_set_page(&sg[sg_num], skb_frag_page(&skb_shinfo(skb)->frags[i]), + len, skb_shinfo(skb)->frags[i].page_offset); + sg_len += len; + sg_num++; + } + } else if (crp->crp_flags & CRYPTO_F_IOV) { + int len; + + sg_len = 0; + for (sg_num = 0; sg_len < crp->crp_ilen && + sg_num < uiop->uio_iovcnt && + sg_num < SCATTERLIST_MAX; sg_num++) { + len = uiop->uio_iov[sg_num].iov_len; + sg_set_page(&sg[sg_num], + virt_to_page(uiop->uio_iov[sg_num].iov_base), len, + offset_in_page(uiop->uio_iov[sg_num].iov_base)); + sg_len += len; + } + } else { + sg_len = crp->crp_ilen; + sg_set_page(&sg[0], virt_to_page(crp->crp_buf), sg_len, + offset_in_page(crp->crp_buf)); + sg_num = 1; + } + if (sg_num > 0) + sg_mark_end(&sg[sg_num-1]); + + /* + * setup a new explicit key + */ + if (enccrd) { + if (enccrd->crd_flags & CRD_F_KEY_EXPLICIT) { + od->octo_encklen = (enccrd->crd_klen + 7) / 8; + memcpy(od->octo_enckey, enccrd->crd_key, od->octo_encklen); + } + } + if (maccrd) { + if (maccrd->crd_flags & CRD_F_KEY_EXPLICIT) { + od->octo_macklen = (maccrd->crd_klen + 7) / 8; + memcpy(od->octo_mackey, maccrd->crd_key, od->octo_macklen); + od->octo_mackey_set = 0; + } + if (!od->octo_mackey_set) { + octo_calc_hash(maccrd->crd_alg == CRYPTO_MD5_HMAC ? 0 : 1, + maccrd->crd_key, od->octo_hminner, od->octo_hmouter); + od->octo_mackey_set = 1; + } + } + + + if (!enccrd || (enccrd->crd_flags & CRD_F_ENCRYPT)) + (*od->octo_encrypt)(od, sg, sg_len, + auth_off, auth_len, crypt_off, crypt_len, icv_off, ivp); + else + (*od->octo_decrypt)(od, sg, sg_len, + auth_off, auth_len, crypt_off, crypt_len, icv_off, ivp); + +done: + crypto_done(crp); + return 0; +} + +static int +cryptocteon_init(void) +{ + dprintk("%s(%p)\n", __FUNCTION__, cryptocteon_init); + + softc_device_init(&octo_softc, "cryptocteon", 0, octo_methods); + + octo_id = crypto_get_driverid(softc_get_device(&octo_softc), + CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SYNC); + if (octo_id < 0) { + printk("Cryptocteon device cannot initialize!"); + return -ENODEV; + } + + crypto_register(octo_id, CRYPTO_MD5_HMAC, 0,0); + crypto_register(octo_id, CRYPTO_SHA1_HMAC, 0,0); + //crypto_register(octo_id, CRYPTO_MD5, 0,0); + //crypto_register(octo_id, CRYPTO_SHA1, 0,0); + crypto_register(octo_id, CRYPTO_DES_CBC, 0,0); + crypto_register(octo_id, CRYPTO_3DES_CBC, 0,0); + crypto_register(octo_id, CRYPTO_AES_CBC, 0,0); + + return(0); +} + +static void +cryptocteon_exit(void) +{ + dprintk("%s()\n", __FUNCTION__); + crypto_unregister_all(octo_id); + octo_id = -1; +} + +module_init(cryptocteon_init); +module_exit(cryptocteon_exit); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_AUTHOR("David McCullough "); +MODULE_DESCRIPTION("Cryptocteon (OCF module for Cavium OCTEON crypto)"); diff --git a/target/linux/generic/files/crypto/ocf/cryptodev.c b/target/linux/generic/files/crypto/ocf/cryptodev.c new file mode 100644 index 0000000..9a23f05 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/cryptodev.c @@ -0,0 +1,1069 @@ +/* $OpenBSD: cryptodev.c,v 1.52 2002/06/19 07:22:46 deraadt Exp $ */ + +/*- + * Linux port done by David McCullough + * Copyright (C) 2006-2010 David McCullough + * Copyright (C) 2004-2005 Intel Corporation. + * The license and original author are listed below. + * + * Copyright (c) 2001 Theo de Raadt + * Copyright (c) 2002-2006 Sam Leffler, Errno Consulting + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Effort sponsored in part by the Defense Advanced Research Projects + * Agency (DARPA) and Air Force Research Laboratory, Air Force + * Materiel Command, USAF, under agreement number F30602-01-2-0537. + * +__FBSDID("$FreeBSD: src/sys/opencrypto/cryptodev.c,v 1.34 2007/05/09 19:37:02 gnn Exp $"); + */ + +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) && !defined(AUTOCONF_INCLUDED) +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +extern asmlinkage long sys_dup(unsigned int fildes); + +#define debug cryptodev_debug +int cryptodev_debug = 0; +module_param(cryptodev_debug, int, 0644); +MODULE_PARM_DESC(cryptodev_debug, "Enable cryptodev debug"); + +struct csession_info { + u_int16_t blocksize; + u_int16_t minkey, maxkey; + + u_int16_t keysize; + /* u_int16_t hashsize; */ + u_int16_t authsize; + u_int16_t authkey; + /* u_int16_t ctxsize; */ +}; + +struct csession { + struct list_head list; + u_int64_t sid; + u_int32_t ses; + + wait_queue_head_t waitq; + + u_int32_t cipher; + + u_int32_t mac; + + caddr_t key; + int keylen; + u_char tmp_iv[EALG_MAX_BLOCK_LEN]; + + caddr_t mackey; + int mackeylen; + + struct csession_info info; + + struct iovec iovec; + struct uio uio; + int error; +}; + +struct fcrypt { + struct list_head csessions; + int sesn; +}; + +static struct csession *csefind(struct fcrypt *, u_int); +static int csedelete(struct fcrypt *, struct csession *); +static struct csession *cseadd(struct fcrypt *, struct csession *); +static struct csession *csecreate(struct fcrypt *, u_int64_t, + struct cryptoini *crie, struct cryptoini *cria, struct csession_info *); +static int csefree(struct csession *); + +static int cryptodev_op(struct csession *, struct crypt_op *); +static int cryptodev_key(struct crypt_kop *); +static int cryptodev_find(struct crypt_find_op *); + +static int cryptodev_cb(void *); +static int cryptodev_open(struct inode *inode, struct file *filp); + +/* + * Check a crypto identifier to see if it requested + * a valid crid and it's capabilities match. + */ +static int +checkcrid(int crid) +{ + int hid = crid & ~(CRYPTOCAP_F_SOFTWARE | CRYPTOCAP_F_HARDWARE); + int typ = crid & (CRYPTOCAP_F_SOFTWARE | CRYPTOCAP_F_HARDWARE); + int caps = 0; + + /* if the user hasn't selected a driver, then just call newsession */ + if (hid == 0 && typ != 0) + return 0; + + caps = crypto_getcaps(hid); + + /* didn't find anything with capabilities */ + if (caps == 0) { + dprintk("%s: hid=%x typ=%x not matched\n", __FUNCTION__, hid, typ); + return EINVAL; + } + + /* the user didn't specify SW or HW, so the driver is ok */ + if (typ == 0) + return 0; + + /* if the type specified didn't match */ + if (typ != (caps & (CRYPTOCAP_F_SOFTWARE | CRYPTOCAP_F_HARDWARE))) { + dprintk("%s: hid=%x typ=%x caps=%x not matched\n", __FUNCTION__, + hid, typ, caps); + return EINVAL; + } + + return 0; +} + +static int +cryptodev_op(struct csession *cse, struct crypt_op *cop) +{ + struct cryptop *crp = NULL; + struct cryptodesc *crde = NULL, *crda = NULL; + int error = 0; + + dprintk("%s()\n", __FUNCTION__); + if (cop->len > CRYPTO_MAX_DATA_LEN) { + dprintk("%s: %d > %d\n", __FUNCTION__, cop->len, CRYPTO_MAX_DATA_LEN); + return (E2BIG); + } + + if (cse->info.blocksize && (cop->len % cse->info.blocksize) != 0) { + dprintk("%s: blocksize=%d len=%d\n", __FUNCTION__, cse->info.blocksize, + cop->len); + return (EINVAL); + } + + cse->uio.uio_iov = &cse->iovec; + cse->uio.uio_iovcnt = 1; + cse->uio.uio_offset = 0; +#if 0 + cse->uio.uio_resid = cop->len; + cse->uio.uio_segflg = UIO_SYSSPACE; + cse->uio.uio_rw = UIO_WRITE; + cse->uio.uio_td = td; +#endif + cse->uio.uio_iov[0].iov_len = cop->len; + if (cse->info.authsize) + cse->uio.uio_iov[0].iov_len += cse->info.authsize; + cse->uio.uio_iov[0].iov_base = kmalloc(cse->uio.uio_iov[0].iov_len, + GFP_KERNEL); + + if (cse->uio.uio_iov[0].iov_base == NULL) { + dprintk("%s: iov_base kmalloc(%d) failed\n", __FUNCTION__, + (int)cse->uio.uio_iov[0].iov_len); + return (ENOMEM); + } + + crp = crypto_getreq((cse->info.blocksize != 0) + (cse->info.authsize != 0)); + if (crp == NULL) { + dprintk("%s: ENOMEM\n", __FUNCTION__); + error = ENOMEM; + goto bail; + } + + if (cse->info.authsize && cse->info.blocksize) { + if (cop->op == COP_ENCRYPT) { + crde = crp->crp_desc; + crda = crde->crd_next; + } else { + crda = crp->crp_desc; + crde = crda->crd_next; + } + } else if (cse->info.authsize) { + crda = crp->crp_desc; + } else if (cse->info.blocksize) { + crde = crp->crp_desc; + } else { + dprintk("%s: bad request\n", __FUNCTION__); + error = EINVAL; + goto bail; + } + + if ((error = copy_from_user(cse->uio.uio_iov[0].iov_base, cop->src, + cop->len))) { + dprintk("%s: bad copy\n", __FUNCTION__); + goto bail; + } + + if (crda) { + crda->crd_skip = 0; + crda->crd_len = cop->len; + crda->crd_inject = cop->len; + + crda->crd_alg = cse->mac; + crda->crd_key = cse->mackey; + crda->crd_klen = cse->mackeylen * 8; + } + + if (crde) { + if (cop->op == COP_ENCRYPT) + crde->crd_flags |= CRD_F_ENCRYPT; + else + crde->crd_flags &= ~CRD_F_ENCRYPT; + crde->crd_len = cop->len; + crde->crd_inject = 0; + + crde->crd_alg = cse->cipher; + crde->crd_key = cse->key; + crde->crd_klen = cse->keylen * 8; + } + + crp->crp_ilen = cse->uio.uio_iov[0].iov_len; + crp->crp_flags = CRYPTO_F_IOV | CRYPTO_F_CBIMM + | (cop->flags & COP_F_BATCH); + crp->crp_buf = (caddr_t)&cse->uio; + crp->crp_callback = (int (*) (struct cryptop *)) cryptodev_cb; + crp->crp_sid = cse->sid; + crp->crp_opaque = (void *)cse; + + if (cop->iv) { + if (crde == NULL) { + error = EINVAL; + dprintk("%s no crde\n", __FUNCTION__); + goto bail; + } + if (cse->cipher == CRYPTO_ARC4) { /* XXX use flag? */ + error = EINVAL; + dprintk("%s arc4 with IV\n", __FUNCTION__); + goto bail; + } + if ((error = copy_from_user(cse->tmp_iv, cop->iv, + cse->info.blocksize))) { + dprintk("%s bad iv copy\n", __FUNCTION__); + goto bail; + } + memcpy(crde->crd_iv, cse->tmp_iv, cse->info.blocksize); + crde->crd_flags |= CRD_F_IV_EXPLICIT | CRD_F_IV_PRESENT; + crde->crd_skip = 0; + } else if (cse->cipher == CRYPTO_ARC4) { /* XXX use flag? */ + crde->crd_skip = 0; + } else if (crde) { + crde->crd_flags |= CRD_F_IV_PRESENT; + crde->crd_skip = cse->info.blocksize; + crde->crd_len -= cse->info.blocksize; + } + + if (cop->mac && crda == NULL) { + error = EINVAL; + dprintk("%s no crda\n", __FUNCTION__); + goto bail; + } + + /* + * Let the dispatch run unlocked, then, interlock against the + * callback before checking if the operation completed and going + * to sleep. This insures drivers don't inherit our lock which + * results in a lock order reversal between crypto_dispatch forced + * entry and the crypto_done callback into us. + */ + error = crypto_dispatch(crp); + if (error) { + dprintk("%s error in crypto_dispatch\n", __FUNCTION__); + goto bail; + } + + dprintk("%s about to WAIT\n", __FUNCTION__); + /* + * we really need to wait for driver to complete to maintain + * state, luckily interrupts will be remembered + */ + do { + error = wait_event_interruptible(crp->crp_waitq, + ((crp->crp_flags & CRYPTO_F_DONE) != 0)); + /* + * we can't break out of this loop or we will leave behind + * a huge mess, however, staying here means if your driver + * is broken user applications can hang and not be killed. + * The solution, fix your driver :-) + */ + if (error) { + schedule(); + error = 0; + } + } while ((crp->crp_flags & CRYPTO_F_DONE) == 0); + dprintk("%s finished WAITING error=%d\n", __FUNCTION__, error); + + if (crp->crp_etype != 0) { + error = crp->crp_etype; + dprintk("%s error in crp processing\n", __FUNCTION__); + goto bail; + } + + if (cse->error) { + error = cse->error; + dprintk("%s error in cse processing\n", __FUNCTION__); + goto bail; + } + + if (cop->dst && (error = copy_to_user(cop->dst, + cse->uio.uio_iov[0].iov_base, cop->len))) { + dprintk("%s bad dst copy\n", __FUNCTION__); + goto bail; + } + + if (cop->mac && + (error=copy_to_user(cop->mac, + (caddr_t)cse->uio.uio_iov[0].iov_base + cop->len, + cse->info.authsize))) { + dprintk("%s bad mac copy\n", __FUNCTION__); + goto bail; + } + +bail: + if (crp) + crypto_freereq(crp); + if (cse->uio.uio_iov[0].iov_base) + kfree(cse->uio.uio_iov[0].iov_base); + + return (error); +} + +static int +cryptodev_cb(void *op) +{ + struct cryptop *crp = (struct cryptop *) op; + struct csession *cse = (struct csession *)crp->crp_opaque; + int error; + + dprintk("%s()\n", __FUNCTION__); + error = crp->crp_etype; + if (error == EAGAIN) { + crp->crp_flags &= ~CRYPTO_F_DONE; +#ifdef NOTYET + /* + * DAVIDM I am fairly sure that we should turn this into a batch + * request to stop bad karma/lockup, revisit + */ + crp->crp_flags |= CRYPTO_F_BATCH; +#endif + return crypto_dispatch(crp); + } + if (error != 0 || (crp->crp_flags & CRYPTO_F_DONE)) { + cse->error = error; + wake_up_interruptible(&crp->crp_waitq); + } + return (0); +} + +static int +cryptodevkey_cb(void *op) +{ + struct cryptkop *krp = (struct cryptkop *) op; + dprintk("%s()\n", __FUNCTION__); + wake_up_interruptible(&krp->krp_waitq); + return (0); +} + +static int +cryptodev_key(struct crypt_kop *kop) +{ + struct cryptkop *krp = NULL; + int error = EINVAL; + int in, out, size, i; + + dprintk("%s()\n", __FUNCTION__); + if (kop->crk_iparams + kop->crk_oparams > CRK_MAXPARAM) { + dprintk("%s params too big\n", __FUNCTION__); + return (EFBIG); + } + + in = kop->crk_iparams; + out = kop->crk_oparams; + switch (kop->crk_op) { + case CRK_MOD_EXP: + if (in == 3 && out == 1) + break; + return (EINVAL); + case CRK_MOD_EXP_CRT: + if (in == 6 && out == 1) + break; + return (EINVAL); + case CRK_DSA_SIGN: + if (in == 5 && out == 2) + break; + return (EINVAL); + case CRK_DSA_VERIFY: + if (in == 7 && out == 0) + break; + return (EINVAL); + case CRK_DH_COMPUTE_KEY: + if (in == 3 && out == 1) + break; + return (EINVAL); + default: + return (EINVAL); + } + + krp = (struct cryptkop *)kmalloc(sizeof *krp, GFP_KERNEL); + if (!krp) + return (ENOMEM); + bzero(krp, sizeof *krp); + krp->krp_op = kop->crk_op; + krp->krp_status = kop->crk_status; + krp->krp_iparams = kop->crk_iparams; + krp->krp_oparams = kop->crk_oparams; + krp->krp_crid = kop->crk_crid; + krp->krp_status = 0; + krp->krp_flags = CRYPTO_KF_CBIMM; + krp->krp_callback = (int (*) (struct cryptkop *)) cryptodevkey_cb; + init_waitqueue_head(&krp->krp_waitq); + + for (i = 0; i < CRK_MAXPARAM; i++) + krp->krp_param[i].crp_nbits = kop->crk_param[i].crp_nbits; + for (i = 0; i < krp->krp_iparams + krp->krp_oparams; i++) { + size = (krp->krp_param[i].crp_nbits + 7) / 8; + if (size == 0) + continue; + krp->krp_param[i].crp_p = (caddr_t) kmalloc(size, GFP_KERNEL); + if (i >= krp->krp_iparams) + continue; + error = copy_from_user(krp->krp_param[i].crp_p, + kop->crk_param[i].crp_p, size); + if (error) + goto fail; + } + + error = crypto_kdispatch(krp); + if (error) + goto fail; + + do { + error = wait_event_interruptible(krp->krp_waitq, + ((krp->krp_flags & CRYPTO_KF_DONE) != 0)); + /* + * we can't break out of this loop or we will leave behind + * a huge mess, however, staying here means if your driver + * is broken user applications can hang and not be killed. + * The solution, fix your driver :-) + */ + if (error) { + schedule(); + error = 0; + } + } while ((krp->krp_flags & CRYPTO_KF_DONE) == 0); + + dprintk("%s finished WAITING error=%d\n", __FUNCTION__, error); + + kop->crk_crid = krp->krp_crid; /* device that did the work */ + if (krp->krp_status != 0) { + error = krp->krp_status; + goto fail; + } + + for (i = krp->krp_iparams; i < krp->krp_iparams + krp->krp_oparams; i++) { + size = (krp->krp_param[i].crp_nbits + 7) / 8; + if (size == 0) + continue; + error = copy_to_user(kop->crk_param[i].crp_p, krp->krp_param[i].crp_p, + size); + if (error) + goto fail; + } + +fail: + if (krp) { + kop->crk_status = krp->krp_status; + for (i = 0; i < CRK_MAXPARAM; i++) { + if (krp->krp_param[i].crp_p) + kfree(krp->krp_param[i].crp_p); + } + kfree(krp); + } + return (error); +} + +static int +cryptodev_find(struct crypt_find_op *find) +{ + device_t dev; + + if (find->crid != -1) { + dev = crypto_find_device_byhid(find->crid); + if (dev == NULL) + return (ENOENT); + strlcpy(find->name, device_get_nameunit(dev), + sizeof(find->name)); + } else { + find->crid = crypto_find_driver(find->name); + if (find->crid == -1) + return (ENOENT); + } + return (0); +} + +static struct csession * +csefind(struct fcrypt *fcr, u_int ses) +{ + struct csession *cse; + + dprintk("%s()\n", __FUNCTION__); + list_for_each_entry(cse, &fcr->csessions, list) + if (cse->ses == ses) + return (cse); + return (NULL); +} + +static int +csedelete(struct fcrypt *fcr, struct csession *cse_del) +{ + struct csession *cse; + + dprintk("%s()\n", __FUNCTION__); + list_for_each_entry(cse, &fcr->csessions, list) { + if (cse == cse_del) { + list_del(&cse->list); + return (1); + } + } + return (0); +} + +static struct csession * +cseadd(struct fcrypt *fcr, struct csession *cse) +{ + dprintk("%s()\n", __FUNCTION__); + list_add_tail(&cse->list, &fcr->csessions); + cse->ses = fcr->sesn++; + return (cse); +} + +static struct csession * +csecreate(struct fcrypt *fcr, u_int64_t sid, struct cryptoini *crie, + struct cryptoini *cria, struct csession_info *info) +{ + struct csession *cse; + + dprintk("%s()\n", __FUNCTION__); + cse = (struct csession *) kmalloc(sizeof(struct csession), GFP_KERNEL); + if (cse == NULL) + return NULL; + memset(cse, 0, sizeof(struct csession)); + + INIT_LIST_HEAD(&cse->list); + init_waitqueue_head(&cse->waitq); + + cse->key = crie->cri_key; + cse->keylen = crie->cri_klen/8; + cse->mackey = cria->cri_key; + cse->mackeylen = cria->cri_klen/8; + cse->sid = sid; + cse->cipher = crie->cri_alg; + cse->mac = cria->cri_alg; + cse->info = *info; + cseadd(fcr, cse); + return (cse); +} + +static int +csefree(struct csession *cse) +{ + int error; + + dprintk("%s()\n", __FUNCTION__); + error = crypto_freesession(cse->sid); + if (cse->key) + kfree(cse->key); + if (cse->mackey) + kfree(cse->mackey); + kfree(cse); + return(error); +} + +static int +cryptodev_ioctl( + struct inode *inode, + struct file *filp, + unsigned int cmd, + unsigned long arg) +{ + struct cryptoini cria, crie; + struct fcrypt *fcr = filp->private_data; + struct csession *cse; + struct csession_info info; + struct session2_op sop; + struct crypt_op cop; + struct crypt_kop kop; + struct crypt_find_op fop; + u_int64_t sid; + u_int32_t ses = 0; + int feat, fd, error = 0, crid; + mm_segment_t fs; + + dprintk("%s(cmd=%x arg=%lx)\n", __FUNCTION__, cmd, arg); + + switch (cmd) { + + case CRIOGET: { + dprintk("%s(CRIOGET)\n", __FUNCTION__); + fs = get_fs(); + set_fs(get_ds()); + for (fd = 0; fd < files_fdtable(current->files)->max_fds; fd++) + if (files_fdtable(current->files)->fd[fd] == filp) + break; + fd = sys_dup(fd); + set_fs(fs); + put_user(fd, (int *) arg); + return IS_ERR_VALUE(fd) ? fd : 0; + } + +#define CIOCGSESSSTR (cmd == CIOCGSESSION ? "CIOCGSESSION" : "CIOCGSESSION2") + case CIOCGSESSION: + case CIOCGSESSION2: + dprintk("%s(%s)\n", __FUNCTION__, CIOCGSESSSTR); + memset(&crie, 0, sizeof(crie)); + memset(&cria, 0, sizeof(cria)); + memset(&info, 0, sizeof(info)); + memset(&sop, 0, sizeof(sop)); + + if (copy_from_user(&sop, (void*)arg, (cmd == CIOCGSESSION) ? + sizeof(struct session_op) : sizeof(sop))) { + dprintk("%s(%s) - bad copy\n", __FUNCTION__, CIOCGSESSSTR); + error = EFAULT; + goto bail; + } + + switch (sop.cipher) { + case 0: + dprintk("%s(%s) - no cipher\n", __FUNCTION__, CIOCGSESSSTR); + break; + case CRYPTO_NULL_CBC: + info.blocksize = NULL_BLOCK_LEN; + info.minkey = NULL_MIN_KEY_LEN; + info.maxkey = NULL_MAX_KEY_LEN; + break; + case CRYPTO_DES_CBC: + info.blocksize = DES_BLOCK_LEN; + info.minkey = DES_MIN_KEY_LEN; + info.maxkey = DES_MAX_KEY_LEN; + break; + case CRYPTO_3DES_CBC: + info.blocksize = DES3_BLOCK_LEN; + info.minkey = DES3_MIN_KEY_LEN; + info.maxkey = DES3_MAX_KEY_LEN; + break; + case CRYPTO_BLF_CBC: + info.blocksize = BLOWFISH_BLOCK_LEN; + info.minkey = BLOWFISH_MIN_KEY_LEN; + info.maxkey = BLOWFISH_MAX_KEY_LEN; + break; + case CRYPTO_CAST_CBC: + info.blocksize = CAST128_BLOCK_LEN; + info.minkey = CAST128_MIN_KEY_LEN; + info.maxkey = CAST128_MAX_KEY_LEN; + break; + case CRYPTO_SKIPJACK_CBC: + info.blocksize = SKIPJACK_BLOCK_LEN; + info.minkey = SKIPJACK_MIN_KEY_LEN; + info.maxkey = SKIPJACK_MAX_KEY_LEN; + break; + case CRYPTO_AES_CBC: + info.blocksize = AES_BLOCK_LEN; + info.minkey = AES_MIN_KEY_LEN; + info.maxkey = AES_MAX_KEY_LEN; + break; + case CRYPTO_ARC4: + info.blocksize = ARC4_BLOCK_LEN; + info.minkey = ARC4_MIN_KEY_LEN; + info.maxkey = ARC4_MAX_KEY_LEN; + break; + case CRYPTO_CAMELLIA_CBC: + info.blocksize = CAMELLIA_BLOCK_LEN; + info.minkey = CAMELLIA_MIN_KEY_LEN; + info.maxkey = CAMELLIA_MAX_KEY_LEN; + break; + default: + dprintk("%s(%s) - bad cipher\n", __FUNCTION__, CIOCGSESSSTR); + error = EINVAL; + goto bail; + } + + switch (sop.mac) { + case 0: + dprintk("%s(%s) - no mac\n", __FUNCTION__, CIOCGSESSSTR); + break; + case CRYPTO_NULL_HMAC: + info.authsize = NULL_HASH_LEN; + break; + case CRYPTO_MD5: + info.authsize = MD5_HASH_LEN; + break; + case CRYPTO_SHA1: + info.authsize = SHA1_HASH_LEN; + break; + case CRYPTO_SHA2_256: + info.authsize = SHA2_256_HASH_LEN; + break; + case CRYPTO_SHA2_384: + info.authsize = SHA2_384_HASH_LEN; + break; + case CRYPTO_SHA2_512: + info.authsize = SHA2_512_HASH_LEN; + break; + case CRYPTO_RIPEMD160: + info.authsize = RIPEMD160_HASH_LEN; + break; + case CRYPTO_MD5_HMAC: + info.authsize = MD5_HASH_LEN; + info.authkey = 16; + break; + case CRYPTO_SHA1_HMAC: + info.authsize = SHA1_HASH_LEN; + info.authkey = 20; + break; + case CRYPTO_SHA2_256_HMAC: + info.authsize = SHA2_256_HASH_LEN; + info.authkey = 32; + break; + case CRYPTO_SHA2_384_HMAC: + info.authsize = SHA2_384_HASH_LEN; + info.authkey = 48; + break; + case CRYPTO_SHA2_512_HMAC: + info.authsize = SHA2_512_HASH_LEN; + info.authkey = 64; + break; + case CRYPTO_RIPEMD160_HMAC: + info.authsize = RIPEMD160_HASH_LEN; + info.authkey = 20; + break; + default: + dprintk("%s(%s) - bad mac\n", __FUNCTION__, CIOCGSESSSTR); + error = EINVAL; + goto bail; + } + + if (info.blocksize) { + crie.cri_alg = sop.cipher; + crie.cri_klen = sop.keylen * 8; + if ((info.maxkey && sop.keylen > info.maxkey) || + sop.keylen < info.minkey) { + dprintk("%s(%s) - bad key\n", __FUNCTION__, CIOCGSESSSTR); + error = EINVAL; + goto bail; + } + + crie.cri_key = (u_int8_t *) kmalloc(crie.cri_klen/8+1, GFP_KERNEL); + if (copy_from_user(crie.cri_key, sop.key, + crie.cri_klen/8)) { + dprintk("%s(%s) - bad copy\n", __FUNCTION__, CIOCGSESSSTR); + error = EFAULT; + goto bail; + } + if (info.authsize) + crie.cri_next = &cria; + } + + if (info.authsize) { + cria.cri_alg = sop.mac; + cria.cri_klen = sop.mackeylen * 8; + if (info.authkey && sop.mackeylen != info.authkey) { + dprintk("%s(%s) - mackeylen %d != %d\n", __FUNCTION__, + CIOCGSESSSTR, sop.mackeylen, info.authkey); + error = EINVAL; + goto bail; + } + + if (cria.cri_klen) { + cria.cri_key = (u_int8_t *) kmalloc(cria.cri_klen/8,GFP_KERNEL); + if (copy_from_user(cria.cri_key, sop.mackey, + cria.cri_klen / 8)) { + dprintk("%s(%s) - bad copy\n", __FUNCTION__, CIOCGSESSSTR); + error = EFAULT; + goto bail; + } + } + } + + /* NB: CIOGSESSION2 has the crid */ + if (cmd == CIOCGSESSION2) { + crid = sop.crid; + error = checkcrid(crid); + if (error) { + dprintk("%s(%s) - checkcrid %x\n", __FUNCTION__, + CIOCGSESSSTR, error); + goto bail; + } + } else { + /* allow either HW or SW to be used */ + crid = CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE; + } + error = crypto_newsession(&sid, (info.blocksize ? &crie : &cria), crid); + if (error) { + dprintk("%s(%s) - newsession %d\n",__FUNCTION__,CIOCGSESSSTR,error); + goto bail; + } + + cse = csecreate(fcr, sid, &crie, &cria, &info); + if (cse == NULL) { + crypto_freesession(sid); + error = EINVAL; + dprintk("%s(%s) - csecreate failed\n", __FUNCTION__, CIOCGSESSSTR); + goto bail; + } + sop.ses = cse->ses; + + if (cmd == CIOCGSESSION2) { + /* return hardware/driver id */ + sop.crid = CRYPTO_SESID2HID(cse->sid); + } + + if (copy_to_user((void*)arg, &sop, (cmd == CIOCGSESSION) ? + sizeof(struct session_op) : sizeof(sop))) { + dprintk("%s(%s) - bad copy\n", __FUNCTION__, CIOCGSESSSTR); + error = EFAULT; + } +bail: + if (error) { + dprintk("%s(%s) - bail %d\n", __FUNCTION__, CIOCGSESSSTR, error); + if (crie.cri_key) + kfree(crie.cri_key); + if (cria.cri_key) + kfree(cria.cri_key); + } + break; + case CIOCFSESSION: + dprintk("%s(CIOCFSESSION)\n", __FUNCTION__); + get_user(ses, (uint32_t*)arg); + cse = csefind(fcr, ses); + if (cse == NULL) { + error = EINVAL; + dprintk("%s(CIOCFSESSION) - Fail %d\n", __FUNCTION__, error); + break; + } + csedelete(fcr, cse); + error = csefree(cse); + break; + case CIOCCRYPT: + dprintk("%s(CIOCCRYPT)\n", __FUNCTION__); + if(copy_from_user(&cop, (void*)arg, sizeof(cop))) { + dprintk("%s(CIOCCRYPT) - bad copy\n", __FUNCTION__); + error = EFAULT; + goto bail; + } + cse = csefind(fcr, cop.ses); + if (cse == NULL) { + error = EINVAL; + dprintk("%s(CIOCCRYPT) - Fail %d\n", __FUNCTION__, error); + break; + } + error = cryptodev_op(cse, &cop); + if(copy_to_user((void*)arg, &cop, sizeof(cop))) { + dprintk("%s(CIOCCRYPT) - bad return copy\n", __FUNCTION__); + error = EFAULT; + goto bail; + } + break; + case CIOCKEY: + case CIOCKEY2: + dprintk("%s(CIOCKEY)\n", __FUNCTION__); + if (!crypto_userasymcrypto) + return (EPERM); /* XXX compat? */ + if(copy_from_user(&kop, (void*)arg, sizeof(kop))) { + dprintk("%s(CIOCKEY) - bad copy\n", __FUNCTION__); + error = EFAULT; + goto bail; + } + if (cmd == CIOCKEY) { + /* NB: crypto core enforces s/w driver use */ + kop.crk_crid = + CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE; + } + error = cryptodev_key(&kop); + if(copy_to_user((void*)arg, &kop, sizeof(kop))) { + dprintk("%s(CIOCGKEY) - bad return copy\n", __FUNCTION__); + error = EFAULT; + goto bail; + } + break; + case CIOCASYMFEAT: + dprintk("%s(CIOCASYMFEAT)\n", __FUNCTION__); + if (!crypto_userasymcrypto) { + /* + * NB: if user asym crypto operations are + * not permitted return "no algorithms" + * so well-behaved applications will just + * fallback to doing them in software. + */ + feat = 0; + } else + error = crypto_getfeat(&feat); + if (!error) { + error = copy_to_user((void*)arg, &feat, sizeof(feat)); + } + break; + case CIOCFINDDEV: + if (copy_from_user(&fop, (void*)arg, sizeof(fop))) { + dprintk("%s(CIOCFINDDEV) - bad copy\n", __FUNCTION__); + error = EFAULT; + goto bail; + } + error = cryptodev_find(&fop); + if (copy_to_user((void*)arg, &fop, sizeof(fop))) { + dprintk("%s(CIOCFINDDEV) - bad return copy\n", __FUNCTION__); + error = EFAULT; + goto bail; + } + break; + default: + dprintk("%s(unknown ioctl 0x%x)\n", __FUNCTION__, cmd); + error = EINVAL; + break; + } + return(-error); +} + +#ifdef HAVE_UNLOCKED_IOCTL +static long +cryptodev_unlocked_ioctl( + struct file *filp, + unsigned int cmd, + unsigned long arg) +{ + return cryptodev_ioctl(NULL, filp, cmd, arg); +} +#endif + +static int +cryptodev_open(struct inode *inode, struct file *filp) +{ + struct fcrypt *fcr; + + dprintk("%s()\n", __FUNCTION__); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) + /* + * on 2.6.35 private_data points to a miscdevice structure, we override + * it, which is currently safe to do. + */ + if (filp->private_data) { + printk("cryptodev: Private data already exists - %p!\n", filp->private_data); + return(-ENODEV); + } +#endif + + fcr = kmalloc(sizeof(*fcr), GFP_KERNEL); + if (!fcr) { + dprintk("%s() - malloc failed\n", __FUNCTION__); + return(-ENOMEM); + } + memset(fcr, 0, sizeof(*fcr)); + + INIT_LIST_HEAD(&fcr->csessions); + filp->private_data = fcr; + return(0); +} + +static int +cryptodev_release(struct inode *inode, struct file *filp) +{ + struct fcrypt *fcr = filp->private_data; + struct csession *cse, *tmp; + + dprintk("%s()\n", __FUNCTION__); + if (!filp) { + printk("cryptodev: No private data on release\n"); + return(0); + } + + list_for_each_entry_safe(cse, tmp, &fcr->csessions, list) { + list_del(&cse->list); + (void)csefree(cse); + } + filp->private_data = NULL; + kfree(fcr); + return(0); +} + +static struct file_operations cryptodev_fops = { + .owner = THIS_MODULE, + .open = cryptodev_open, + .release = cryptodev_release, +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) + .ioctl = cryptodev_ioctl, +#endif +#ifdef HAVE_UNLOCKED_IOCTL + .unlocked_ioctl = cryptodev_unlocked_ioctl, +#endif +}; + +static struct miscdevice cryptodev = { + .minor = CRYPTODEV_MINOR, + .name = "crypto", + .fops = &cryptodev_fops, +}; + +static int __init +cryptodev_init(void) +{ + int rc; + + dprintk("%s(%p)\n", __FUNCTION__, cryptodev_init); + rc = misc_register(&cryptodev); + if (rc) { + printk(KERN_ERR "cryptodev: registration of /dev/crypto failed\n"); + return(rc); + } + + return(0); +} + +static void __exit +cryptodev_exit(void) +{ + dprintk("%s()\n", __FUNCTION__); + misc_deregister(&cryptodev); +} + +module_init(cryptodev_init); +module_exit(cryptodev_exit); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_AUTHOR("David McCullough "); +MODULE_DESCRIPTION("Cryptodev (user interface to OCF)"); diff --git a/target/linux/generic/files/crypto/ocf/cryptodev.h b/target/linux/generic/files/crypto/ocf/cryptodev.h new file mode 100644 index 0000000..cca0ec8 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/cryptodev.h @@ -0,0 +1,480 @@ +/* $FreeBSD: src/sys/opencrypto/cryptodev.h,v 1.25 2007/05/09 19:37:02 gnn Exp $ */ +/* $OpenBSD: cryptodev.h,v 1.31 2002/06/11 11:14:29 beck Exp $ */ + +/*- + * Linux port done by David McCullough + * Copyright (C) 2006-2010 David McCullough + * Copyright (C) 2004-2005 Intel Corporation. + * The license and original author are listed below. + * + * The author of this code is Angelos D. Keromytis (angelos@cis.upenn.edu) + * Copyright (c) 2002-2006 Sam Leffler, Errno Consulting + * + * This code was written by Angelos D. Keromytis in Athens, Greece, in + * February 2000. Network Security Technologies Inc. (NSTI) kindly + * supported the development of this code. + * + * Copyright (c) 2000 Angelos D. Keromytis + * + * Permission to use, copy, and modify this software with or without fee + * is hereby granted, provided that this entire notice is included in + * all source code copies of any software which is or includes a copy or + * modification of this software. + * + * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY + * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE + * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR + * PURPOSE. + * + * Copyright (c) 2001 Theo de Raadt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Effort sponsored in part by the Defense Advanced Research Projects + * Agency (DARPA) and Air Force Research Laboratory, Air Force + * Materiel Command, USAF, under agreement number F30602-01-2-0537. + * + */ + +#ifndef _CRYPTO_CRYPTO_H_ +#define _CRYPTO_CRYPTO_H_ + +/* Some initial values */ +#define CRYPTO_DRIVERS_INITIAL 4 +#define CRYPTO_SW_SESSIONS 32 + +/* Hash values */ +#define NULL_HASH_LEN 0 +#define MD5_HASH_LEN 16 +#define SHA1_HASH_LEN 20 +#define RIPEMD160_HASH_LEN 20 +#define SHA2_256_HASH_LEN 32 +#define SHA2_384_HASH_LEN 48 +#define SHA2_512_HASH_LEN 64 +#define MD5_KPDK_HASH_LEN 16 +#define SHA1_KPDK_HASH_LEN 20 +/* Maximum hash algorithm result length */ +#define HASH_MAX_LEN SHA2_512_HASH_LEN /* Keep this updated */ + +/* HMAC values */ +#define NULL_HMAC_BLOCK_LEN 1 +#define MD5_HMAC_BLOCK_LEN 64 +#define SHA1_HMAC_BLOCK_LEN 64 +#define RIPEMD160_HMAC_BLOCK_LEN 64 +#define SHA2_256_HMAC_BLOCK_LEN 64 +#define SHA2_384_HMAC_BLOCK_LEN 128 +#define SHA2_512_HMAC_BLOCK_LEN 128 +/* Maximum HMAC block length */ +#define HMAC_MAX_BLOCK_LEN SHA2_512_HMAC_BLOCK_LEN /* Keep this updated */ +#define HMAC_IPAD_VAL 0x36 +#define HMAC_OPAD_VAL 0x5C + +/* Encryption algorithm block sizes */ +#define NULL_BLOCK_LEN 1 +#define DES_BLOCK_LEN 8 +#define DES3_BLOCK_LEN 8 +#define BLOWFISH_BLOCK_LEN 8 +#define SKIPJACK_BLOCK_LEN 8 +#define CAST128_BLOCK_LEN 8 +#define RIJNDAEL128_BLOCK_LEN 16 +#define AES_BLOCK_LEN RIJNDAEL128_BLOCK_LEN +#define CAMELLIA_BLOCK_LEN 16 +#define ARC4_BLOCK_LEN 1 +#define EALG_MAX_BLOCK_LEN AES_BLOCK_LEN /* Keep this updated */ + +/* Encryption algorithm min and max key sizes */ +#define NULL_MIN_KEY_LEN 0 +#define NULL_MAX_KEY_LEN 0 +#define DES_MIN_KEY_LEN 8 +#define DES_MAX_KEY_LEN 8 +#define DES3_MIN_KEY_LEN 24 +#define DES3_MAX_KEY_LEN 24 +#define BLOWFISH_MIN_KEY_LEN 4 +#define BLOWFISH_MAX_KEY_LEN 56 +#define SKIPJACK_MIN_KEY_LEN 10 +#define SKIPJACK_MAX_KEY_LEN 10 +#define CAST128_MIN_KEY_LEN 5 +#define CAST128_MAX_KEY_LEN 16 +#define RIJNDAEL128_MIN_KEY_LEN 16 +#define RIJNDAEL128_MAX_KEY_LEN 32 +#define AES_MIN_KEY_LEN RIJNDAEL128_MIN_KEY_LEN +#define AES_MAX_KEY_LEN RIJNDAEL128_MAX_KEY_LEN +#define CAMELLIA_MIN_KEY_LEN 16 +#define CAMELLIA_MAX_KEY_LEN 32 +#define ARC4_MIN_KEY_LEN 1 +#define ARC4_MAX_KEY_LEN 256 + +/* Max size of data that can be processed */ +#define CRYPTO_MAX_DATA_LEN 64*1024 - 1 + +#define CRYPTO_ALGORITHM_MIN 1 +#define CRYPTO_DES_CBC 1 +#define CRYPTO_3DES_CBC 2 +#define CRYPTO_BLF_CBC 3 +#define CRYPTO_CAST_CBC 4 +#define CRYPTO_SKIPJACK_CBC 5 +#define CRYPTO_MD5_HMAC 6 +#define CRYPTO_SHA1_HMAC 7 +#define CRYPTO_RIPEMD160_HMAC 8 +#define CRYPTO_MD5_KPDK 9 +#define CRYPTO_SHA1_KPDK 10 +#define CRYPTO_RIJNDAEL128_CBC 11 /* 128 bit blocksize */ +#define CRYPTO_AES_CBC 11 /* 128 bit blocksize -- the same as above */ +#define CRYPTO_ARC4 12 +#define CRYPTO_MD5 13 +#define CRYPTO_SHA1 14 +#define CRYPTO_NULL_HMAC 15 +#define CRYPTO_NULL_CBC 16 +#define CRYPTO_DEFLATE_COMP 17 /* Deflate compression algorithm */ +#define CRYPTO_SHA2_256_HMAC 18 +#define CRYPTO_SHA2_384_HMAC 19 +#define CRYPTO_SHA2_512_HMAC 20 +#define CRYPTO_CAMELLIA_CBC 21 +#define CRYPTO_SHA2_256 22 +#define CRYPTO_SHA2_384 23 +#define CRYPTO_SHA2_512 24 +#define CRYPTO_RIPEMD160 25 +#define CRYPTO_LZS_COMP 26 +#define CRYPTO_ALGORITHM_MAX 26 /* Keep updated - see above */ + +/* Algorithm flags */ +#define CRYPTO_ALG_FLAG_SUPPORTED 0x01 /* Algorithm is supported */ +#define CRYPTO_ALG_FLAG_RNG_ENABLE 0x02 /* Has HW RNG for DH/DSA */ +#define CRYPTO_ALG_FLAG_DSA_SHA 0x04 /* Can do SHA on msg */ + +/* + * Crypto driver/device flags. They can set in the crid + * parameter when creating a session or submitting a key + * op to affect the device/driver assigned. If neither + * of these are specified then the crid is assumed to hold + * the driver id of an existing (and suitable) device that + * must be used to satisfy the request. + */ +#define CRYPTO_FLAG_HARDWARE 0x01000000 /* hardware accelerated */ +#define CRYPTO_FLAG_SOFTWARE 0x02000000 /* software implementation */ + +/* NB: deprecated */ +struct session_op { + u_int32_t cipher; /* ie. CRYPTO_DES_CBC */ + u_int32_t mac; /* ie. CRYPTO_MD5_HMAC */ + + u_int32_t keylen; /* cipher key */ + caddr_t key; + int mackeylen; /* mac key */ + caddr_t mackey; + + u_int32_t ses; /* returns: session # */ +}; + +struct session2_op { + u_int32_t cipher; /* ie. CRYPTO_DES_CBC */ + u_int32_t mac; /* ie. CRYPTO_MD5_HMAC */ + + u_int32_t keylen; /* cipher key */ + caddr_t key; + int mackeylen; /* mac key */ + caddr_t mackey; + + u_int32_t ses; /* returns: session # */ + int crid; /* driver id + flags (rw) */ + int pad[4]; /* for future expansion */ +}; + +struct crypt_op { + u_int32_t ses; + u_int16_t op; /* i.e. COP_ENCRYPT */ +#define COP_NONE 0 +#define COP_ENCRYPT 1 +#define COP_DECRYPT 2 + u_int16_t flags; +#define COP_F_BATCH 0x0008 /* Batch op if possible */ + u_int len; + caddr_t src, dst; /* become iov[] inside kernel */ + caddr_t mac; /* must be big enough for chosen MAC */ + caddr_t iv; +}; + +/* + * Parameters for looking up a crypto driver/device by + * device name or by id. The latter are returned for + * created sessions (crid) and completed key operations. + */ +struct crypt_find_op { + int crid; /* driver id + flags */ + char name[32]; /* device/driver name */ +}; + +/* bignum parameter, in packed bytes, ... */ +struct crparam { + caddr_t crp_p; + u_int crp_nbits; +}; + +#define CRK_MAXPARAM 8 + +struct crypt_kop { + u_int crk_op; /* ie. CRK_MOD_EXP or other */ + u_int crk_status; /* return status */ + u_short crk_iparams; /* # of input parameters */ + u_short crk_oparams; /* # of output parameters */ + u_int crk_crid; /* NB: only used by CIOCKEY2 (rw) */ + struct crparam crk_param[CRK_MAXPARAM]; +}; +#define CRK_ALGORITM_MIN 0 +#define CRK_MOD_EXP 0 +#define CRK_MOD_EXP_CRT 1 +#define CRK_DSA_SIGN 2 +#define CRK_DSA_VERIFY 3 +#define CRK_DH_COMPUTE_KEY 4 +#define CRK_ALGORITHM_MAX 4 /* Keep updated - see below */ + +#define CRF_MOD_EXP (1 << CRK_MOD_EXP) +#define CRF_MOD_EXP_CRT (1 << CRK_MOD_EXP_CRT) +#define CRF_DSA_SIGN (1 << CRK_DSA_SIGN) +#define CRF_DSA_VERIFY (1 << CRK_DSA_VERIFY) +#define CRF_DH_COMPUTE_KEY (1 << CRK_DH_COMPUTE_KEY) + +/* + * done against open of /dev/crypto, to get a cloned descriptor. + * Please use F_SETFD against the cloned descriptor. + */ +#define CRIOGET _IOWR('c', 100, u_int32_t) +#define CRIOASYMFEAT CIOCASYMFEAT +#define CRIOFINDDEV CIOCFINDDEV + +/* the following are done against the cloned descriptor */ +#define CIOCGSESSION _IOWR('c', 101, struct session_op) +#define CIOCFSESSION _IOW('c', 102, u_int32_t) +#define CIOCCRYPT _IOWR('c', 103, struct crypt_op) +#define CIOCKEY _IOWR('c', 104, struct crypt_kop) +#define CIOCASYMFEAT _IOR('c', 105, u_int32_t) +#define CIOCGSESSION2 _IOWR('c', 106, struct session2_op) +#define CIOCKEY2 _IOWR('c', 107, struct crypt_kop) +#define CIOCFINDDEV _IOWR('c', 108, struct crypt_find_op) + +struct cryptotstat { + struct timespec acc; /* total accumulated time */ + struct timespec min; /* min time */ + struct timespec max; /* max time */ + u_int32_t count; /* number of observations */ +}; + +struct cryptostats { + u_int32_t cs_ops; /* symmetric crypto ops submitted */ + u_int32_t cs_errs; /* symmetric crypto ops that failed */ + u_int32_t cs_kops; /* asymetric/key ops submitted */ + u_int32_t cs_kerrs; /* asymetric/key ops that failed */ + u_int32_t cs_intrs; /* crypto swi thread activations */ + u_int32_t cs_rets; /* crypto return thread activations */ + u_int32_t cs_blocks; /* symmetric op driver block */ + u_int32_t cs_kblocks; /* symmetric op driver block */ + /* + * When CRYPTO_TIMING is defined at compile time and the + * sysctl debug.crypto is set to 1, the crypto system will + * accumulate statistics about how long it takes to process + * crypto requests at various points during processing. + */ + struct cryptotstat cs_invoke; /* crypto_dipsatch -> crypto_invoke */ + struct cryptotstat cs_done; /* crypto_invoke -> crypto_done */ + struct cryptotstat cs_cb; /* crypto_done -> callback */ + struct cryptotstat cs_finis; /* callback -> callback return */ + + u_int32_t cs_drops; /* crypto ops dropped due to congestion */ +}; + +#ifdef __KERNEL__ + +/* Standard initialization structure beginning */ +struct cryptoini { + int cri_alg; /* Algorithm to use */ + int cri_klen; /* Key length, in bits */ + int cri_mlen; /* Number of bytes we want from the + entire hash. 0 means all. */ + caddr_t cri_key; /* key to use */ + u_int8_t cri_iv[EALG_MAX_BLOCK_LEN]; /* IV to use */ + struct cryptoini *cri_next; +}; + +/* Describe boundaries of a single crypto operation */ +struct cryptodesc { + int crd_skip; /* How many bytes to ignore from start */ + int crd_len; /* How many bytes to process */ + int crd_inject; /* Where to inject results, if applicable */ + int crd_flags; + +#define CRD_F_ENCRYPT 0x01 /* Set when doing encryption */ +#define CRD_F_IV_PRESENT 0x02 /* When encrypting, IV is already in + place, so don't copy. */ +#define CRD_F_IV_EXPLICIT 0x04 /* IV explicitly provided */ +#define CRD_F_DSA_SHA_NEEDED 0x08 /* Compute SHA-1 of buffer for DSA */ +#define CRD_F_KEY_EXPLICIT 0x10 /* Key explicitly provided */ +#define CRD_F_COMP 0x0f /* Set when doing compression */ + + struct cryptoini CRD_INI; /* Initialization/context data */ +#define crd_iv CRD_INI.cri_iv +#define crd_key CRD_INI.cri_key +#define crd_alg CRD_INI.cri_alg +#define crd_klen CRD_INI.cri_klen +#define crd_mlen CRD_INI.cri_mlen + + struct cryptodesc *crd_next; +}; + +/* Structure describing complete operation */ +struct cryptop { + struct list_head crp_next; + wait_queue_head_t crp_waitq; + + u_int64_t crp_sid; /* Session ID */ + int crp_ilen; /* Input data total length */ + int crp_olen; /* Result total length */ + + int crp_etype; /* + * Error type (zero means no error). + * All error codes except EAGAIN + * indicate possible data corruption (as in, + * the data have been touched). On all + * errors, the crp_sid may have changed + * (reset to a new one), so the caller + * should always check and use the new + * value on future requests. + */ + int crp_flags; + +#define CRYPTO_F_SKBUF 0x0001 /* Input/output are skbuf chains */ +#define CRYPTO_F_IOV 0x0002 /* Input/output are uio */ +#define CRYPTO_F_REL 0x0004 /* Must return data in same place */ +#define CRYPTO_F_BATCH 0x0008 /* Batch op if possible */ +#define CRYPTO_F_CBIMM 0x0010 /* Do callback immediately */ +#define CRYPTO_F_DONE 0x0020 /* Operation completed */ +#define CRYPTO_F_CBIFSYNC 0x0040 /* Do CBIMM if op is synchronous */ + + caddr_t crp_buf; /* Data to be processed */ + caddr_t crp_opaque; /* Opaque pointer, passed along */ + struct cryptodesc *crp_desc; /* Linked list of processing descriptors */ + + int (*crp_callback)(struct cryptop *); /* Callback function */ +}; + +#define CRYPTO_BUF_CONTIG 0x0 +#define CRYPTO_BUF_IOV 0x1 +#define CRYPTO_BUF_SKBUF 0x2 + +#define CRYPTO_OP_DECRYPT 0x0 +#define CRYPTO_OP_ENCRYPT 0x1 + +/* + * Hints passed to process methods. + */ +#define CRYPTO_HINT_MORE 0x1 /* more ops coming shortly */ + +struct cryptkop { + struct list_head krp_next; + wait_queue_head_t krp_waitq; + + int krp_flags; +#define CRYPTO_KF_DONE 0x0001 /* Operation completed */ +#define CRYPTO_KF_CBIMM 0x0002 /* Do callback immediately */ + + u_int krp_op; /* ie. CRK_MOD_EXP or other */ + u_int krp_status; /* return status */ + u_short krp_iparams; /* # of input parameters */ + u_short krp_oparams; /* # of output parameters */ + u_int krp_crid; /* desired device, etc. */ + u_int32_t krp_hid; + struct crparam krp_param[CRK_MAXPARAM]; /* kvm */ + int (*krp_callback)(struct cryptkop *); +}; + +#include + +/* + * Session ids are 64 bits. The lower 32 bits contain a "local id" which + * is a driver-private session identifier. The upper 32 bits contain a + * "hardware id" used by the core crypto code to identify the driver and + * a copy of the driver's capabilities that can be used by client code to + * optimize operation. + */ +#define CRYPTO_SESID2HID(_sid) (((_sid) >> 32) & 0x00ffffff) +#define CRYPTO_SESID2CAPS(_sid) (((_sid) >> 32) & 0xff000000) +#define CRYPTO_SESID2LID(_sid) (((u_int32_t) (_sid)) & 0xffffffff) + +extern int crypto_newsession(u_int64_t *sid, struct cryptoini *cri, int hard); +extern int crypto_freesession(u_int64_t sid); +#define CRYPTOCAP_F_HARDWARE CRYPTO_FLAG_HARDWARE +#define CRYPTOCAP_F_SOFTWARE CRYPTO_FLAG_SOFTWARE +#define CRYPTOCAP_F_SYNC 0x04000000 /* operates synchronously */ +extern int32_t crypto_get_driverid(device_t dev, int flags); +extern int crypto_find_driver(const char *); +extern device_t crypto_find_device_byhid(int hid); +extern int crypto_getcaps(int hid); +extern int crypto_register(u_int32_t driverid, int alg, u_int16_t maxoplen, + u_int32_t flags); +extern int crypto_kregister(u_int32_t, int, u_int32_t); +extern int crypto_unregister(u_int32_t driverid, int alg); +extern int crypto_unregister_all(u_int32_t driverid); +extern int crypto_dispatch(struct cryptop *crp); +extern int crypto_kdispatch(struct cryptkop *); +#define CRYPTO_SYMQ 0x1 +#define CRYPTO_ASYMQ 0x2 +extern int crypto_unblock(u_int32_t, int); +extern void crypto_done(struct cryptop *crp); +extern void crypto_kdone(struct cryptkop *); +extern int crypto_getfeat(int *); + +extern void crypto_freereq(struct cryptop *crp); +extern struct cryptop *crypto_getreq(int num); + +extern int crypto_usercrypto; /* userland may do crypto requests */ +extern int crypto_userasymcrypto; /* userland may do asym crypto reqs */ +extern int crypto_devallowsoft; /* only use hardware crypto */ + +/* + * random number support, crypto_unregister_all will unregister + */ +extern int crypto_rregister(u_int32_t driverid, + int (*read_random)(void *arg, u_int32_t *buf, int len), void *arg); +extern int crypto_runregister_all(u_int32_t driverid); + +/* + * Crypto-related utility routines used mainly by drivers. + * + * XXX these don't really belong here; but for now they're + * kept apart from the rest of the system. + */ +struct uio; +extern void cuio_copydata(struct uio* uio, int off, int len, caddr_t cp); +extern void cuio_copyback(struct uio* uio, int off, int len, caddr_t cp); +extern struct iovec *cuio_getptr(struct uio *uio, int loc, int *off); + +extern void crypto_copyback(int flags, caddr_t buf, int off, int size, + caddr_t in); +extern void crypto_copydata(int flags, caddr_t buf, int off, int size, + caddr_t out); +extern int crypto_apply(int flags, caddr_t buf, int off, int len, + int (*f)(void *, void *, u_int), void *arg); + +#endif /* __KERNEL__ */ +#endif /* _CRYPTO_CRYPTO_H_ */ diff --git a/target/linux/generic/files/crypto/ocf/cryptosoft.c b/target/linux/generic/files/crypto/ocf/cryptosoft.c new file mode 100644 index 0000000..aa2383d --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/cryptosoft.c @@ -0,0 +1,1322 @@ +/* + * An OCF module that uses the linux kernel cryptoapi, based on the + * original cryptosoft for BSD by Angelos D. Keromytis (angelos@cis.upenn.edu) + * but is mostly unrecognisable, + * + * Written by David McCullough + * Copyright (C) 2004-2011 David McCullough + * Copyright (C) 2004-2005 Intel Corporation. + * + * LICENSE TERMS + * + * The free distribution and use of this software in both source and binary + * form is allowed (with or without changes) provided that: + * + * 1. distributions of this source code include the above copyright + * notice, this list of conditions and the following disclaimer; + * + * 2. distributions in binary form include the above copyright + * notice, this list of conditions and the following disclaimer + * in the documentation and/or other associated materials; + * + * 3. the copyright holder's name is not used to endorse products + * built using this software without specific written permission. + * + * ALTERNATIVELY, provided that this notice is retained in full, this product + * may be distributed under the terms of the GNU General Public License (GPL), + * in which case the provisions of the GPL apply INSTEAD OF those given above. + * + * DISCLAIMER + * + * This software is provided 'as is' with no explicit or implied warranties + * in respect of its properties, including, but not limited to, correctness + * and/or fitness for purpose. + * --------------------------------------------------------------------------- + */ + +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) && !defined(AUTOCONF_INCLUDED) +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10) +#include +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29) +#include +#endif + +#include +#include + +struct { + softc_device_decl sc_dev; +} swcr_softc; + +#define offset_in_page(p) ((unsigned long)(p) & ~PAGE_MASK) + +#define SW_TYPE_CIPHER 0x01 +#define SW_TYPE_HMAC 0x02 +#define SW_TYPE_HASH 0x04 +#define SW_TYPE_COMP 0x08 +#define SW_TYPE_BLKCIPHER 0x10 +#define SW_TYPE_ALG_MASK 0x1f + +#define SW_TYPE_ASYNC 0x8000 + +#define SW_TYPE_INUSE 0x10000000 + +/* We change some of the above if we have an async interface */ + +#define SW_TYPE_ALG_AMASK (SW_TYPE_ALG_MASK | SW_TYPE_ASYNC) + +#define SW_TYPE_ABLKCIPHER (SW_TYPE_BLKCIPHER | SW_TYPE_ASYNC) +#define SW_TYPE_AHASH (SW_TYPE_HASH | SW_TYPE_ASYNC) +#define SW_TYPE_AHMAC (SW_TYPE_HMAC | SW_TYPE_ASYNC) + +#define SCATTERLIST_MAX 16 + +struct swcr_data { + struct work_struct workq; + int sw_type; + int sw_alg; + struct crypto_tfm *sw_tfm; + spinlock_t sw_tfm_lock; + union { + struct { + char *sw_key; + int sw_klen; + int sw_mlen; + } hmac; + void *sw_comp_buf; + } u; + struct swcr_data *sw_next; +}; + +struct swcr_req { + struct swcr_data *sw_head; + struct swcr_data *sw; + struct cryptop *crp; + struct cryptodesc *crd; + struct scatterlist sg[SCATTERLIST_MAX]; + unsigned char iv[EALG_MAX_BLOCK_LEN]; + char result[HASH_MAX_LEN]; + void *crypto_req; +}; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) +static kmem_cache_t *swcr_req_cache; +#else +static struct kmem_cache *swcr_req_cache; +#endif + +#ifndef CRYPTO_TFM_MODE_CBC +/* + * As of linux-2.6.21 this is no longer defined, and presumably no longer + * needed to be passed into the crypto core code. + */ +#define CRYPTO_TFM_MODE_CBC 0 +#define CRYPTO_TFM_MODE_ECB 0 +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) + /* + * Linux 2.6.19 introduced a new Crypto API, setup macro's to convert new + * API into old API. + */ + + /* Symmetric/Block Cipher */ + struct blkcipher_desc + { + struct crypto_tfm *tfm; + void *info; + }; + #define ecb(X) #X , CRYPTO_TFM_MODE_ECB + #define cbc(X) #X , CRYPTO_TFM_MODE_CBC + #define crypto_has_blkcipher(X, Y, Z) crypto_alg_available(X, 0) + #define crypto_blkcipher_cast(X) X + #define crypto_blkcipher_tfm(X) X + #define crypto_alloc_blkcipher(X, Y, Z) crypto_alloc_tfm(X, mode) + #define crypto_blkcipher_ivsize(X) crypto_tfm_alg_ivsize(X) + #define crypto_blkcipher_blocksize(X) crypto_tfm_alg_blocksize(X) + #define crypto_blkcipher_setkey(X, Y, Z) crypto_cipher_setkey(X, Y, Z) + #define crypto_blkcipher_encrypt_iv(W, X, Y, Z) \ + crypto_cipher_encrypt_iv((W)->tfm, X, Y, Z, (u8 *)((W)->info)) + #define crypto_blkcipher_decrypt_iv(W, X, Y, Z) \ + crypto_cipher_decrypt_iv((W)->tfm, X, Y, Z, (u8 *)((W)->info)) + #define crypto_blkcipher_set_flags(x, y) /* nop */ + #define crypto_free_blkcipher(x) crypto_free_tfm(x) + #define crypto_free_comp crypto_free_tfm + #define crypto_free_hash crypto_free_tfm + + /* Hash/HMAC/Digest */ + struct hash_desc + { + struct crypto_tfm *tfm; + }; + #define hmac(X) #X , 0 + #define crypto_has_hash(X, Y, Z) crypto_alg_available(X, 0) + #define crypto_hash_cast(X) X + #define crypto_hash_tfm(X) X + #define crypto_alloc_hash(X, Y, Z) crypto_alloc_tfm(X, mode) + #define crypto_hash_digestsize(X) crypto_tfm_alg_digestsize(X) + #define crypto_hash_digest(W, X, Y, Z) \ + crypto_digest_digest((W)->tfm, X, sg_num, Z) + + /* Asymmetric Cipher */ + #define crypto_has_cipher(X, Y, Z) crypto_alg_available(X, 0) + + /* Compression */ + #define crypto_has_comp(X, Y, Z) crypto_alg_available(X, 0) + #define crypto_comp_tfm(X) X + #define crypto_comp_cast(X) X + #define crypto_alloc_comp(X, Y, Z) crypto_alloc_tfm(X, mode) + #define plain(X) #X , 0 +#else + #define ecb(X) "ecb(" #X ")" , 0 + #define cbc(X) "cbc(" #X ")" , 0 + #define hmac(X) "hmac(" #X ")" , 0 + #define plain(X) #X , 0 +#endif /* if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) */ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) +/* no ablkcipher in older kernels */ +#define crypto_alloc_ablkcipher(a,b,c) (NULL) +#define crypto_ablkcipher_tfm(x) ((struct crypto_tfm *)(x)) +#define crypto_ablkcipher_set_flags(a, b) /* nop */ +#define crypto_ablkcipher_setkey(x, y, z) (-EINVAL) +#define crypto_has_ablkcipher(a,b,c) (0) +#else +#define HAVE_ABLKCIPHER +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32) +/* no ahash in older kernels */ +#define crypto_ahash_tfm(x) ((struct crypto_tfm *)(x)) +#define crypto_alloc_ahash(a,b,c) (NULL) +#define crypto_ahash_digestsize(x) 0 +#else +#define HAVE_AHASH +#endif + +struct crypto_details { + char *alg_name; + int mode; + int sw_type; +}; + +static struct crypto_details crypto_details[] = { + [CRYPTO_DES_CBC] = { cbc(des), SW_TYPE_BLKCIPHER, }, + [CRYPTO_3DES_CBC] = { cbc(des3_ede), SW_TYPE_BLKCIPHER, }, + [CRYPTO_BLF_CBC] = { cbc(blowfish), SW_TYPE_BLKCIPHER, }, + [CRYPTO_CAST_CBC] = { cbc(cast5), SW_TYPE_BLKCIPHER, }, + [CRYPTO_SKIPJACK_CBC] = { cbc(skipjack), SW_TYPE_BLKCIPHER, }, + [CRYPTO_MD5_HMAC] = { hmac(md5), SW_TYPE_HMAC, }, + [CRYPTO_SHA1_HMAC] = { hmac(sha1), SW_TYPE_HMAC, }, + [CRYPTO_RIPEMD160_HMAC] = { hmac(ripemd160), SW_TYPE_HMAC, }, + [CRYPTO_MD5_KPDK] = { plain(md5-kpdk), SW_TYPE_HASH, }, + [CRYPTO_SHA1_KPDK] = { plain(sha1-kpdk), SW_TYPE_HASH, }, + [CRYPTO_AES_CBC] = { cbc(aes), SW_TYPE_BLKCIPHER, }, + [CRYPTO_ARC4] = { ecb(arc4), SW_TYPE_BLKCIPHER, }, + [CRYPTO_MD5] = { plain(md5), SW_TYPE_HASH, }, + [CRYPTO_SHA1] = { plain(sha1), SW_TYPE_HASH, }, + [CRYPTO_NULL_HMAC] = { hmac(digest_null), SW_TYPE_HMAC, }, + [CRYPTO_NULL_CBC] = { cbc(cipher_null), SW_TYPE_BLKCIPHER, }, + [CRYPTO_DEFLATE_COMP] = { plain(deflate), SW_TYPE_COMP, }, + [CRYPTO_SHA2_256_HMAC] = { hmac(sha256), SW_TYPE_HMAC, }, + [CRYPTO_SHA2_384_HMAC] = { hmac(sha384), SW_TYPE_HMAC, }, + [CRYPTO_SHA2_512_HMAC] = { hmac(sha512), SW_TYPE_HMAC, }, + [CRYPTO_CAMELLIA_CBC] = { cbc(camellia), SW_TYPE_BLKCIPHER, }, + [CRYPTO_SHA2_256] = { plain(sha256), SW_TYPE_HASH, }, + [CRYPTO_SHA2_384] = { plain(sha384), SW_TYPE_HASH, }, + [CRYPTO_SHA2_512] = { plain(sha512), SW_TYPE_HASH, }, + [CRYPTO_RIPEMD160] = { plain(ripemd160), SW_TYPE_HASH, }, +}; + +int32_t swcr_id = -1; +module_param(swcr_id, int, 0444); +MODULE_PARM_DESC(swcr_id, "Read-Only OCF ID for cryptosoft driver"); + +int swcr_fail_if_compression_grows = 1; +module_param(swcr_fail_if_compression_grows, int, 0644); +MODULE_PARM_DESC(swcr_fail_if_compression_grows, + "Treat compression that results in more data as a failure"); + +int swcr_no_ahash = 0; +module_param(swcr_no_ahash, int, 0644); +MODULE_PARM_DESC(swcr_no_ahash, + "Do not use async hash/hmac even if available"); + +int swcr_no_ablk = 0; +module_param(swcr_no_ablk, int, 0644); +MODULE_PARM_DESC(swcr_no_ablk, + "Do not use async blk ciphers even if available"); + +static struct swcr_data **swcr_sessions = NULL; +static u_int32_t swcr_sesnum = 0; + +static int swcr_process(device_t, struct cryptop *, int); +static int swcr_newsession(device_t, u_int32_t *, struct cryptoini *); +static int swcr_freesession(device_t, u_int64_t); + +static device_method_t swcr_methods = { + /* crypto device methods */ + DEVMETHOD(cryptodev_newsession, swcr_newsession), + DEVMETHOD(cryptodev_freesession,swcr_freesession), + DEVMETHOD(cryptodev_process, swcr_process), +}; + +#define debug swcr_debug +int swcr_debug = 0; +module_param(swcr_debug, int, 0644); +MODULE_PARM_DESC(swcr_debug, "Enable debug"); + +static void swcr_process_req(struct swcr_req *req); + +/* + * somethings just need to be run with user context no matter whether + * the kernel compression libs use vmalloc/vfree for example. + */ + +typedef struct { + struct work_struct wq; + void (*func)(void *arg); + void *arg; +} execute_later_t; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) +static void +doing_it_now(struct work_struct *wq) +{ + execute_later_t *w = container_of(wq, execute_later_t, wq); + (w->func)(w->arg); + kfree(w); +} +#else +static void +doing_it_now(void *arg) +{ + execute_later_t *w = (execute_later_t *) arg; + (w->func)(w->arg); + kfree(w); +} +#endif + +static void +execute_later(void (fn)(void *), void *arg) +{ + execute_later_t *w; + + w = (execute_later_t *) kmalloc(sizeof(execute_later_t), SLAB_ATOMIC); + if (w) { + memset(w, '\0', sizeof(w)); + w->func = fn; + w->arg = arg; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + INIT_WORK(&w->wq, doing_it_now); +#else + INIT_WORK(&w->wq, doing_it_now, w); +#endif + schedule_work(&w->wq); + } +} + +/* + * Generate a new software session. + */ +static int +swcr_newsession(device_t dev, u_int32_t *sid, struct cryptoini *cri) +{ + struct swcr_data **swd; + u_int32_t i; + int error; + char *algo; + int mode; + + dprintk("%s()\n", __FUNCTION__); + if (sid == NULL || cri == NULL) { + dprintk("%s,%d - EINVAL\n", __FILE__, __LINE__); + return EINVAL; + } + + if (swcr_sessions) { + for (i = 1; i < swcr_sesnum; i++) + if (swcr_sessions[i] == NULL) + break; + } else + i = 1; /* NB: to silence compiler warning */ + + if (swcr_sessions == NULL || i == swcr_sesnum) { + if (swcr_sessions == NULL) { + i = 1; /* We leave swcr_sessions[0] empty */ + swcr_sesnum = CRYPTO_SW_SESSIONS; + } else + swcr_sesnum *= 2; + + swd = kmalloc(swcr_sesnum * sizeof(struct swcr_data *), SLAB_ATOMIC); + if (swd == NULL) { + /* Reset session number */ + if (swcr_sesnum == CRYPTO_SW_SESSIONS) + swcr_sesnum = 0; + else + swcr_sesnum /= 2; + dprintk("%s,%d: ENOBUFS\n", __FILE__, __LINE__); + return ENOBUFS; + } + memset(swd, 0, swcr_sesnum * sizeof(struct swcr_data *)); + + /* Copy existing sessions */ + if (swcr_sessions) { + memcpy(swd, swcr_sessions, + (swcr_sesnum / 2) * sizeof(struct swcr_data *)); + kfree(swcr_sessions); + } + + swcr_sessions = swd; + } + + swd = &swcr_sessions[i]; + *sid = i; + + while (cri) { + *swd = (struct swcr_data *) kmalloc(sizeof(struct swcr_data), + SLAB_ATOMIC); + if (*swd == NULL) { + swcr_freesession(NULL, i); + dprintk("%s,%d: ENOBUFS\n", __FILE__, __LINE__); + return ENOBUFS; + } + memset(*swd, 0, sizeof(struct swcr_data)); + + if (cri->cri_alg < 0 || + cri->cri_alg>=sizeof(crypto_details)/sizeof(crypto_details[0])){ + printk("cryptosoft: Unknown algorithm 0x%x\n", cri->cri_alg); + swcr_freesession(NULL, i); + return EINVAL; + } + + algo = crypto_details[cri->cri_alg].alg_name; + if (!algo || !*algo) { + printk("cryptosoft: Unsupported algorithm 0x%x\n", cri->cri_alg); + swcr_freesession(NULL, i); + return EINVAL; + } + + mode = crypto_details[cri->cri_alg].mode; + (*swd)->sw_type = crypto_details[cri->cri_alg].sw_type; + (*swd)->sw_alg = cri->cri_alg; + + spin_lock_init(&(*swd)->sw_tfm_lock); + + /* Algorithm specific configuration */ + switch (cri->cri_alg) { + case CRYPTO_NULL_CBC: + cri->cri_klen = 0; /* make it work with crypto API */ + break; + default: + break; + } + + if ((*swd)->sw_type & SW_TYPE_BLKCIPHER) { + dprintk("%s crypto_alloc_*blkcipher(%s, 0x%x)\n", __FUNCTION__, + algo, mode); + + /* try async first */ + (*swd)->sw_tfm = swcr_no_ablk ? NULL : + crypto_ablkcipher_tfm(crypto_alloc_ablkcipher(algo, 0, 0)); + if ((*swd)->sw_tfm && !IS_ERR((*swd)->sw_tfm)) { + dprintk("%s %s cipher is async\n", __FUNCTION__, algo); + (*swd)->sw_type |= SW_TYPE_ASYNC; + } else { + (*swd)->sw_tfm = crypto_blkcipher_tfm( + crypto_alloc_blkcipher(algo, 0, CRYPTO_ALG_ASYNC)); + if ((*swd)->sw_tfm && !IS_ERR((*swd)->sw_tfm)) + dprintk("%s %s cipher is sync\n", __FUNCTION__, algo); + } + if (!(*swd)->sw_tfm || IS_ERR((*swd)->sw_tfm)) { + int err; + dprintk("cryptosoft: crypto_alloc_blkcipher failed(%s, 0x%x)\n", + algo,mode); + err = IS_ERR((*swd)->sw_tfm) ? -(PTR_ERR((*swd)->sw_tfm)) : EINVAL; + (*swd)->sw_tfm = NULL; /* ensure NULL */ + swcr_freesession(NULL, i); + return err; + } + + if (debug) { + dprintk("%s key:cri->cri_klen=%d,(cri->cri_klen + 7)/8=%d", + __FUNCTION__, cri->cri_klen, (cri->cri_klen + 7) / 8); + for (i = 0; i < (cri->cri_klen + 7) / 8; i++) + dprintk("%s0x%x", (i % 8) ? " " : "\n ", + cri->cri_key[i] & 0xff); + dprintk("\n"); + } + if ((*swd)->sw_type & SW_TYPE_ASYNC) { + /* OCF doesn't enforce keys */ + crypto_ablkcipher_set_flags( + __crypto_ablkcipher_cast((*swd)->sw_tfm), + CRYPTO_TFM_REQ_WEAK_KEY); + error = crypto_ablkcipher_setkey( + __crypto_ablkcipher_cast((*swd)->sw_tfm), + cri->cri_key, (cri->cri_klen + 7) / 8); + } else { + /* OCF doesn't enforce keys */ + crypto_blkcipher_set_flags( + crypto_blkcipher_cast((*swd)->sw_tfm), + CRYPTO_TFM_REQ_WEAK_KEY); + error = crypto_blkcipher_setkey( + crypto_blkcipher_cast((*swd)->sw_tfm), + cri->cri_key, (cri->cri_klen + 7) / 8); + } + if (error) { + printk("cryptosoft: setkey failed %d (crt_flags=0x%x)\n", error, + (*swd)->sw_tfm->crt_flags); + swcr_freesession(NULL, i); + return error; + } + } else if ((*swd)->sw_type & (SW_TYPE_HMAC | SW_TYPE_HASH)) { + dprintk("%s crypto_alloc_*hash(%s, 0x%x)\n", __FUNCTION__, + algo, mode); + + /* try async first */ + (*swd)->sw_tfm = swcr_no_ahash ? NULL : + crypto_ahash_tfm(crypto_alloc_ahash(algo, 0, 0)); + if ((*swd)->sw_tfm) { + dprintk("%s %s hash is async\n", __FUNCTION__, algo); + (*swd)->sw_type |= SW_TYPE_ASYNC; + } else { + dprintk("%s %s hash is sync\n", __FUNCTION__, algo); + (*swd)->sw_tfm = crypto_hash_tfm( + crypto_alloc_hash(algo, 0, CRYPTO_ALG_ASYNC)); + } + + if (!(*swd)->sw_tfm) { + dprintk("cryptosoft: crypto_alloc_hash failed(%s,0x%x)\n", + algo, mode); + swcr_freesession(NULL, i); + return EINVAL; + } + + (*swd)->u.hmac.sw_klen = (cri->cri_klen + 7) / 8; + (*swd)->u.hmac.sw_key = (char *)kmalloc((*swd)->u.hmac.sw_klen, + SLAB_ATOMIC); + if ((*swd)->u.hmac.sw_key == NULL) { + swcr_freesession(NULL, i); + dprintk("%s,%d: ENOBUFS\n", __FILE__, __LINE__); + return ENOBUFS; + } + memcpy((*swd)->u.hmac.sw_key, cri->cri_key, (*swd)->u.hmac.sw_klen); + if (cri->cri_mlen) { + (*swd)->u.hmac.sw_mlen = cri->cri_mlen; + } else if ((*swd)->sw_type & SW_TYPE_ASYNC) { + (*swd)->u.hmac.sw_mlen = crypto_ahash_digestsize( + __crypto_ahash_cast((*swd)->sw_tfm)); + } else { + (*swd)->u.hmac.sw_mlen = crypto_hash_digestsize( + crypto_hash_cast((*swd)->sw_tfm)); + } + } else if ((*swd)->sw_type & SW_TYPE_COMP) { + (*swd)->sw_tfm = crypto_comp_tfm( + crypto_alloc_comp(algo, 0, CRYPTO_ALG_ASYNC)); + if (!(*swd)->sw_tfm) { + dprintk("cryptosoft: crypto_alloc_comp failed(%s,0x%x)\n", + algo, mode); + swcr_freesession(NULL, i); + return EINVAL; + } + (*swd)->u.sw_comp_buf = kmalloc(CRYPTO_MAX_DATA_LEN, SLAB_ATOMIC); + if ((*swd)->u.sw_comp_buf == NULL) { + swcr_freesession(NULL, i); + dprintk("%s,%d: ENOBUFS\n", __FILE__, __LINE__); + return ENOBUFS; + } + } else { + printk("cryptosoft: Unhandled sw_type %d\n", (*swd)->sw_type); + swcr_freesession(NULL, i); + return EINVAL; + } + + cri = cri->cri_next; + swd = &((*swd)->sw_next); + } + return 0; +} + +/* + * Free a session. + */ +static int +swcr_freesession(device_t dev, u_int64_t tid) +{ + struct swcr_data *swd; + u_int32_t sid = CRYPTO_SESID2LID(tid); + + dprintk("%s()\n", __FUNCTION__); + if (sid > swcr_sesnum || swcr_sessions == NULL || + swcr_sessions[sid] == NULL) { + dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__); + return(EINVAL); + } + + /* Silently accept and return */ + if (sid == 0) + return(0); + + while ((swd = swcr_sessions[sid]) != NULL) { + swcr_sessions[sid] = swd->sw_next; + if (swd->sw_tfm) { + switch (swd->sw_type & SW_TYPE_ALG_AMASK) { +#ifdef HAVE_AHASH + case SW_TYPE_AHMAC: + case SW_TYPE_AHASH: + crypto_free_ahash(__crypto_ahash_cast(swd->sw_tfm)); + break; +#endif +#ifdef HAVE_ABLKCIPHER + case SW_TYPE_ABLKCIPHER: + crypto_free_ablkcipher(__crypto_ablkcipher_cast(swd->sw_tfm)); + break; +#endif + case SW_TYPE_BLKCIPHER: + crypto_free_blkcipher(crypto_blkcipher_cast(swd->sw_tfm)); + break; + case SW_TYPE_HMAC: + case SW_TYPE_HASH: + crypto_free_hash(crypto_hash_cast(swd->sw_tfm)); + break; + case SW_TYPE_COMP: + if (in_interrupt()) + execute_later((void (*)(void *))crypto_free_comp, (void *)crypto_comp_cast(swd->sw_tfm)); + else + crypto_free_comp(crypto_comp_cast(swd->sw_tfm)); + break; + default: + crypto_free_tfm(swd->sw_tfm); + break; + } + swd->sw_tfm = NULL; + } + if (swd->sw_type & SW_TYPE_COMP) { + if (swd->u.sw_comp_buf) + kfree(swd->u.sw_comp_buf); + } else { + if (swd->u.hmac.sw_key) + kfree(swd->u.hmac.sw_key); + } + kfree(swd); + } + return 0; +} + +static void swcr_process_req_complete(struct swcr_req *req) +{ + dprintk("%s()\n", __FUNCTION__); + + if (req->sw->sw_type & SW_TYPE_INUSE) { + unsigned long flags; + spin_lock_irqsave(&req->sw->sw_tfm_lock, flags); + req->sw->sw_type &= ~SW_TYPE_INUSE; + spin_unlock_irqrestore(&req->sw->sw_tfm_lock, flags); + } + + if (req->crp->crp_etype) + goto done; + + switch (req->sw->sw_type & SW_TYPE_ALG_AMASK) { +#if defined(HAVE_AHASH) + case SW_TYPE_AHMAC: + case SW_TYPE_AHASH: + crypto_copyback(req->crp->crp_flags, req->crp->crp_buf, + req->crd->crd_inject, req->sw->u.hmac.sw_mlen, req->result); + ahash_request_free(req->crypto_req); + break; +#endif +#if defined(HAVE_ABLKCIPHER) + case SW_TYPE_ABLKCIPHER: + ablkcipher_request_free(req->crypto_req); + break; +#endif + case SW_TYPE_CIPHER: + case SW_TYPE_HMAC: + case SW_TYPE_HASH: + case SW_TYPE_COMP: + case SW_TYPE_BLKCIPHER: + break; + default: + req->crp->crp_etype = EINVAL; + goto done; + } + + req->crd = req->crd->crd_next; + if (req->crd) { + swcr_process_req(req); + return; + } + +done: + dprintk("%s crypto_done %p\n", __FUNCTION__, req); + crypto_done(req->crp); + kmem_cache_free(swcr_req_cache, req); +} + +#if defined(HAVE_ABLKCIPHER) || defined(HAVE_AHASH) +static void swcr_process_callback(struct crypto_async_request *creq, int err) +{ + struct swcr_req *req = creq->data; + + dprintk("%s()\n", __FUNCTION__); + if (err) { + if (err == -EINPROGRESS) + return; + dprintk("%s() fail %d\n", __FUNCTION__, -err); + req->crp->crp_etype = -err; + } + + swcr_process_req_complete(req); +} +#endif /* defined(HAVE_ABLKCIPHER) || defined(HAVE_AHASH) */ + + +static void swcr_process_req(struct swcr_req *req) +{ + struct swcr_data *sw; + struct cryptop *crp = req->crp; + struct cryptodesc *crd = req->crd; + struct sk_buff *skb = (struct sk_buff *) crp->crp_buf; + struct uio *uiop = (struct uio *) crp->crp_buf; + int sg_num, sg_len, skip; + + dprintk("%s()\n", __FUNCTION__); + + /* + * Find the crypto context. + * + * XXX Note that the logic here prevents us from having + * XXX the same algorithm multiple times in a session + * XXX (or rather, we can but it won't give us the right + * XXX results). To do that, we'd need some way of differentiating + * XXX between the various instances of an algorithm (so we can + * XXX locate the correct crypto context). + */ + for (sw = req->sw_head; sw && sw->sw_alg != crd->crd_alg; sw = sw->sw_next) + ; + + /* No such context ? */ + if (sw == NULL) { + crp->crp_etype = EINVAL; + dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__); + goto done; + } + + /* + * for some types we need to ensure only one user as info is stored in + * the tfm during an operation that can get corrupted + */ + switch (sw->sw_type & SW_TYPE_ALG_AMASK) { +#ifdef HAVE_AHASH + case SW_TYPE_AHMAC: + case SW_TYPE_AHASH: +#endif + case SW_TYPE_HMAC: + case SW_TYPE_HASH: { + unsigned long flags; + spin_lock_irqsave(&sw->sw_tfm_lock, flags); + if (sw->sw_type & SW_TYPE_INUSE) { + spin_unlock_irqrestore(&sw->sw_tfm_lock, flags); + execute_later((void (*)(void *))swcr_process_req, (void *)req); + return; + } + sw->sw_type |= SW_TYPE_INUSE; + spin_unlock_irqrestore(&sw->sw_tfm_lock, flags); + } break; + } + + req->sw = sw; + skip = crd->crd_skip; + + /* + * setup the SG list skip from the start of the buffer + */ + memset(req->sg, 0, sizeof(req->sg)); + sg_init_table(req->sg, SCATTERLIST_MAX); + if (crp->crp_flags & CRYPTO_F_SKBUF) { + int i, len; + + sg_num = 0; + sg_len = 0; + + if (skip < skb_headlen(skb)) { + len = skb_headlen(skb) - skip; + if (len + sg_len > crd->crd_len) + len = crd->crd_len - sg_len; + sg_set_page(&req->sg[sg_num], + virt_to_page(skb->data + skip), len, + offset_in_page(skb->data + skip)); + sg_len += len; + sg_num++; + skip = 0; + } else + skip -= skb_headlen(skb); + + for (i = 0; sg_len < crd->crd_len && + i < skb_shinfo(skb)->nr_frags && + sg_num < SCATTERLIST_MAX; i++) { + if (skip < skb_shinfo(skb)->frags[i].size) { + len = skb_shinfo(skb)->frags[i].size - skip; + if (len + sg_len > crd->crd_len) + len = crd->crd_len - sg_len; + sg_set_page(&req->sg[sg_num], + skb_frag_page(&skb_shinfo(skb)->frags[i]), + len, + skb_shinfo(skb)->frags[i].page_offset + skip); + sg_len += len; + sg_num++; + skip = 0; + } else + skip -= skb_shinfo(skb)->frags[i].size; + } + } else if (crp->crp_flags & CRYPTO_F_IOV) { + int len; + + sg_len = 0; + for (sg_num = 0; sg_len < crd->crd_len && + sg_num < uiop->uio_iovcnt && + sg_num < SCATTERLIST_MAX; sg_num++) { + if (skip <= uiop->uio_iov[sg_num].iov_len) { + len = uiop->uio_iov[sg_num].iov_len - skip; + if (len + sg_len > crd->crd_len) + len = crd->crd_len - sg_len; + sg_set_page(&req->sg[sg_num], + virt_to_page(uiop->uio_iov[sg_num].iov_base+skip), + len, + offset_in_page(uiop->uio_iov[sg_num].iov_base+skip)); + sg_len += len; + skip = 0; + } else + skip -= uiop->uio_iov[sg_num].iov_len; + } + } else { + sg_len = (crp->crp_ilen - skip); + if (sg_len > crd->crd_len) + sg_len = crd->crd_len; + sg_set_page(&req->sg[0], virt_to_page(crp->crp_buf + skip), + sg_len, offset_in_page(crp->crp_buf + skip)); + sg_num = 1; + } + if (sg_num > 0) + sg_mark_end(&req->sg[sg_num-1]); + + switch (sw->sw_type & SW_TYPE_ALG_AMASK) { + +#ifdef HAVE_AHASH + case SW_TYPE_AHMAC: + case SW_TYPE_AHASH: + { + int ret; + + /* check we have room for the result */ + if (crp->crp_ilen - crd->crd_inject < sw->u.hmac.sw_mlen) { + dprintk("cryptosoft: EINVAL crp_ilen=%d, len=%d, inject=%d " + "digestsize=%d\n", crp->crp_ilen, crd->crd_skip + sg_len, + crd->crd_inject, sw->u.hmac.sw_mlen); + crp->crp_etype = EINVAL; + goto done; + } + + req->crypto_req = + ahash_request_alloc(__crypto_ahash_cast(sw->sw_tfm),GFP_ATOMIC); + if (!req->crypto_req) { + crp->crp_etype = ENOMEM; + dprintk("%s,%d: ENOMEM ahash_request_alloc", __FILE__, __LINE__); + goto done; + } + + ahash_request_set_callback(req->crypto_req, + CRYPTO_TFM_REQ_MAY_BACKLOG, swcr_process_callback, req); + + memset(req->result, 0, sizeof(req->result)); + + if (sw->sw_type & SW_TYPE_AHMAC) + crypto_ahash_setkey(__crypto_ahash_cast(sw->sw_tfm), + sw->u.hmac.sw_key, sw->u.hmac.sw_klen); + ahash_request_set_crypt(req->crypto_req, req->sg, req->result, sg_len); + ret = crypto_ahash_digest(req->crypto_req); + switch (ret) { + case -EINPROGRESS: + case -EBUSY: + return; + default: + case 0: + dprintk("hash OP %s %d\n", ret ? "failed" : "success", ret); + crp->crp_etype = ret; + goto done; + } + } break; +#endif /* HAVE_AHASH */ + +#ifdef HAVE_ABLKCIPHER + case SW_TYPE_ABLKCIPHER: { + int ret; + unsigned char *ivp = req->iv; + int ivsize = + crypto_ablkcipher_ivsize(__crypto_ablkcipher_cast(sw->sw_tfm)); + + if (sg_len < crypto_ablkcipher_blocksize( + __crypto_ablkcipher_cast(sw->sw_tfm))) { + crp->crp_etype = EINVAL; + dprintk("%s,%d: EINVAL len %d < %d\n", __FILE__, __LINE__, + sg_len, crypto_ablkcipher_blocksize( + __crypto_ablkcipher_cast(sw->sw_tfm))); + goto done; + } + + if (ivsize > sizeof(req->iv)) { + crp->crp_etype = EINVAL; + dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__); + goto done; + } + + req->crypto_req = ablkcipher_request_alloc( + __crypto_ablkcipher_cast(sw->sw_tfm), GFP_ATOMIC); + if (!req->crypto_req) { + crp->crp_etype = ENOMEM; + dprintk("%s,%d: ENOMEM ablkcipher_request_alloc", + __FILE__, __LINE__); + goto done; + } + + ablkcipher_request_set_callback(req->crypto_req, + CRYPTO_TFM_REQ_MAY_BACKLOG, swcr_process_callback, req); + + if (crd->crd_flags & CRD_F_KEY_EXPLICIT) { + int i, error; + + if (debug) { + dprintk("%s key:", __FUNCTION__); + for (i = 0; i < (crd->crd_klen + 7) / 8; i++) + dprintk("%s0x%x", (i % 8) ? " " : "\n ", + crd->crd_key[i] & 0xff); + dprintk("\n"); + } + /* OCF doesn't enforce keys */ + crypto_ablkcipher_set_flags(__crypto_ablkcipher_cast(sw->sw_tfm), + CRYPTO_TFM_REQ_WEAK_KEY); + error = crypto_ablkcipher_setkey( + __crypto_ablkcipher_cast(sw->sw_tfm), crd->crd_key, + (crd->crd_klen + 7) / 8); + if (error) { + dprintk("cryptosoft: setkey failed %d (crt_flags=0x%x)\n", + error, sw->sw_tfm->crt_flags); + crp->crp_etype = -error; + } + } + + if (crd->crd_flags & CRD_F_ENCRYPT) { /* encrypt */ + + if (crd->crd_flags & CRD_F_IV_EXPLICIT) + ivp = crd->crd_iv; + else + get_random_bytes(ivp, ivsize); + /* + * do we have to copy the IV back to the buffer ? + */ + if ((crd->crd_flags & CRD_F_IV_PRESENT) == 0) { + crypto_copyback(crp->crp_flags, crp->crp_buf, + crd->crd_inject, ivsize, (caddr_t)ivp); + } + ablkcipher_request_set_crypt(req->crypto_req, req->sg, req->sg, + sg_len, ivp); + ret = crypto_ablkcipher_encrypt(req->crypto_req); + + } else { /*decrypt */ + + if (crd->crd_flags & CRD_F_IV_EXPLICIT) + ivp = crd->crd_iv; + else + crypto_copydata(crp->crp_flags, crp->crp_buf, + crd->crd_inject, ivsize, (caddr_t)ivp); + ablkcipher_request_set_crypt(req->crypto_req, req->sg, req->sg, + sg_len, ivp); + ret = crypto_ablkcipher_decrypt(req->crypto_req); + } + + switch (ret) { + case -EINPROGRESS: + case -EBUSY: + return; + default: + case 0: + dprintk("crypto OP %s %d\n", ret ? "failed" : "success", ret); + crp->crp_etype = ret; + goto done; + } + } break; +#endif /* HAVE_ABLKCIPHER */ + + case SW_TYPE_BLKCIPHER: { + unsigned char iv[EALG_MAX_BLOCK_LEN]; + unsigned char *ivp = iv; + struct blkcipher_desc desc; + int ivsize = crypto_blkcipher_ivsize(crypto_blkcipher_cast(sw->sw_tfm)); + + if (sg_len < crypto_blkcipher_blocksize( + crypto_blkcipher_cast(sw->sw_tfm))) { + crp->crp_etype = EINVAL; + dprintk("%s,%d: EINVAL len %d < %d\n", __FILE__, __LINE__, + sg_len, crypto_blkcipher_blocksize( + crypto_blkcipher_cast(sw->sw_tfm))); + goto done; + } + + if (ivsize > sizeof(iv)) { + crp->crp_etype = EINVAL; + dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__); + goto done; + } + + if (crd->crd_flags & CRD_F_KEY_EXPLICIT) { + int i, error; + + if (debug) { + dprintk("%s key:", __FUNCTION__); + for (i = 0; i < (crd->crd_klen + 7) / 8; i++) + dprintk("%s0x%x", (i % 8) ? " " : "\n ", + crd->crd_key[i] & 0xff); + dprintk("\n"); + } + /* OCF doesn't enforce keys */ + crypto_blkcipher_set_flags(crypto_blkcipher_cast(sw->sw_tfm), + CRYPTO_TFM_REQ_WEAK_KEY); + error = crypto_blkcipher_setkey( + crypto_blkcipher_cast(sw->sw_tfm), crd->crd_key, + (crd->crd_klen + 7) / 8); + if (error) { + dprintk("cryptosoft: setkey failed %d (crt_flags=0x%x)\n", + error, sw->sw_tfm->crt_flags); + crp->crp_etype = -error; + } + } + + memset(&desc, 0, sizeof(desc)); + desc.tfm = crypto_blkcipher_cast(sw->sw_tfm); + + if (crd->crd_flags & CRD_F_ENCRYPT) { /* encrypt */ + + if (crd->crd_flags & CRD_F_IV_EXPLICIT) { + ivp = crd->crd_iv; + } else { + get_random_bytes(ivp, ivsize); + } + /* + * do we have to copy the IV back to the buffer ? + */ + if ((crd->crd_flags & CRD_F_IV_PRESENT) == 0) { + crypto_copyback(crp->crp_flags, crp->crp_buf, + crd->crd_inject, ivsize, (caddr_t)ivp); + } + desc.info = ivp; + crypto_blkcipher_encrypt_iv(&desc, req->sg, req->sg, sg_len); + + } else { /*decrypt */ + + if (crd->crd_flags & CRD_F_IV_EXPLICIT) { + ivp = crd->crd_iv; + } else { + crypto_copydata(crp->crp_flags, crp->crp_buf, + crd->crd_inject, ivsize, (caddr_t)ivp); + } + desc.info = ivp; + crypto_blkcipher_decrypt_iv(&desc, req->sg, req->sg, sg_len); + } + } break; + + case SW_TYPE_HMAC: + case SW_TYPE_HASH: + { + char result[HASH_MAX_LEN]; + struct hash_desc desc; + + /* check we have room for the result */ + if (crp->crp_ilen - crd->crd_inject < sw->u.hmac.sw_mlen) { + dprintk("cryptosoft: EINVAL crp_ilen=%d, len=%d, inject=%d " + "digestsize=%d\n", crp->crp_ilen, crd->crd_skip + sg_len, + crd->crd_inject, sw->u.hmac.sw_mlen); + crp->crp_etype = EINVAL; + goto done; + } + + memset(&desc, 0, sizeof(desc)); + desc.tfm = crypto_hash_cast(sw->sw_tfm); + + memset(result, 0, sizeof(result)); + + if (sw->sw_type & SW_TYPE_HMAC) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) + crypto_hmac(sw->sw_tfm, sw->u.hmac.sw_key, &sw->u.hmac.sw_klen, + req->sg, sg_num, result); +#else + crypto_hash_setkey(desc.tfm, sw->u.hmac.sw_key, + sw->u.hmac.sw_klen); + crypto_hash_digest(&desc, req->sg, sg_len, result); +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) */ + + } else { /* SW_TYPE_HASH */ + crypto_hash_digest(&desc, req->sg, sg_len, result); + } + + crypto_copyback(crp->crp_flags, crp->crp_buf, + crd->crd_inject, sw->u.hmac.sw_mlen, result); + } + break; + + case SW_TYPE_COMP: { + void *ibuf = NULL; + void *obuf = sw->u.sw_comp_buf; + int ilen = sg_len, olen = CRYPTO_MAX_DATA_LEN; + int ret = 0; + + /* + * we need to use an additional copy if there is more than one + * input chunk since the kernel comp routines do not handle + * SG yet. Otherwise we just use the input buffer as is. + * Rather than allocate another buffer we just split the tmp + * buffer we already have. + * Perhaps we should just use zlib directly ? + */ + if (sg_num > 1) { + int blk; + + ibuf = obuf; + for (blk = 0; blk < sg_num; blk++) { + memcpy(obuf, sg_virt(&req->sg[blk]), + req->sg[blk].length); + obuf += req->sg[blk].length; + } + olen -= sg_len; + } else + ibuf = sg_virt(&req->sg[0]); + + if (crd->crd_flags & CRD_F_ENCRYPT) { /* compress */ + ret = crypto_comp_compress(crypto_comp_cast(sw->sw_tfm), + ibuf, ilen, obuf, &olen); + if (!ret && olen > crd->crd_len) { + dprintk("cryptosoft: ERANGE compress %d into %d\n", + crd->crd_len, olen); + if (swcr_fail_if_compression_grows) + ret = ERANGE; + } + } else { /* decompress */ + ret = crypto_comp_decompress(crypto_comp_cast(sw->sw_tfm), + ibuf, ilen, obuf, &olen); + if (!ret && (olen + crd->crd_inject) > crp->crp_olen) { + dprintk("cryptosoft: ETOOSMALL decompress %d into %d, " + "space for %d,at offset %d\n", + crd->crd_len, olen, crp->crp_olen, crd->crd_inject); + ret = ETOOSMALL; + } + } + if (ret) + dprintk("%s,%d: ret = %d\n", __FILE__, __LINE__, ret); + + /* + * on success copy result back, + * linux crpyto API returns -errno, we need to fix that + */ + crp->crp_etype = ret < 0 ? -ret : ret; + if (ret == 0) { + /* copy back the result and return it's size */ + crypto_copyback(crp->crp_flags, crp->crp_buf, + crd->crd_inject, olen, obuf); + crp->crp_olen = olen; + } + } break; + + default: + /* Unknown/unsupported algorithm */ + dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__); + crp->crp_etype = EINVAL; + goto done; + } + +done: + swcr_process_req_complete(req); +} + + +/* + * Process a crypto request. + */ +static int +swcr_process(device_t dev, struct cryptop *crp, int hint) +{ + struct swcr_req *req = NULL; + u_int32_t lid; + + dprintk("%s()\n", __FUNCTION__); + /* Sanity check */ + if (crp == NULL) { + dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__); + return EINVAL; + } + + crp->crp_etype = 0; + + if (crp->crp_desc == NULL || crp->crp_buf == NULL) { + dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__); + crp->crp_etype = EINVAL; + goto done; + } + + lid = crp->crp_sid & 0xffffffff; + if (lid >= swcr_sesnum || lid == 0 || swcr_sessions == NULL || + swcr_sessions[lid] == NULL) { + crp->crp_etype = ENOENT; + dprintk("%s,%d: ENOENT\n", __FILE__, __LINE__); + goto done; + } + + /* + * do some error checking outside of the loop for SKB and IOV processing + * this leaves us with valid skb or uiop pointers for later + */ + if (crp->crp_flags & CRYPTO_F_SKBUF) { + struct sk_buff *skb = (struct sk_buff *) crp->crp_buf; + if (skb_shinfo(skb)->nr_frags >= SCATTERLIST_MAX) { + printk("%s,%d: %d nr_frags > SCATTERLIST_MAX", __FILE__, __LINE__, + skb_shinfo(skb)->nr_frags); + goto done; + } + } else if (crp->crp_flags & CRYPTO_F_IOV) { + struct uio *uiop = (struct uio *) crp->crp_buf; + if (uiop->uio_iovcnt > SCATTERLIST_MAX) { + printk("%s,%d: %d uio_iovcnt > SCATTERLIST_MAX", __FILE__, __LINE__, + uiop->uio_iovcnt); + goto done; + } + } + + /* + * setup a new request ready for queuing + */ + req = kmem_cache_alloc(swcr_req_cache, SLAB_ATOMIC); + if (req == NULL) { + dprintk("%s,%d: ENOMEM\n", __FILE__, __LINE__); + crp->crp_etype = ENOMEM; + goto done; + } + memset(req, 0, sizeof(*req)); + + req->sw_head = swcr_sessions[lid]; + req->crp = crp; + req->crd = crp->crp_desc; + + swcr_process_req(req); + return 0; + +done: + crypto_done(crp); + if (req) + kmem_cache_free(swcr_req_cache, req); + return 0; +} + + +static int +cryptosoft_init(void) +{ + int i, sw_type, mode; + char *algo; + + dprintk("%s(%p)\n", __FUNCTION__, cryptosoft_init); + + swcr_req_cache = kmem_cache_create("cryptosoft_req", + sizeof(struct swcr_req), 0, SLAB_HWCACHE_ALIGN, NULL +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23) + , NULL +#endif + ); + if (!swcr_req_cache) { + printk("cryptosoft: failed to create request cache\n"); + return -ENOENT; + } + + softc_device_init(&swcr_softc, "cryptosoft", 0, swcr_methods); + + swcr_id = crypto_get_driverid(softc_get_device(&swcr_softc), + CRYPTOCAP_F_SOFTWARE | CRYPTOCAP_F_SYNC); + if (swcr_id < 0) { + printk("cryptosoft: Software crypto device cannot initialize!"); + return -ENODEV; + } + +#define REGISTER(alg) \ + crypto_register(swcr_id, alg, 0,0) + + for (i = 0; i < sizeof(crypto_details)/sizeof(crypto_details[0]); i++) { + int found; + + algo = crypto_details[i].alg_name; + if (!algo || !*algo) { + dprintk("%s:Algorithm %d not supported\n", __FUNCTION__, i); + continue; + } + + mode = crypto_details[i].mode; + sw_type = crypto_details[i].sw_type; + + found = 0; + switch (sw_type & SW_TYPE_ALG_MASK) { + case SW_TYPE_CIPHER: + found = crypto_has_cipher(algo, 0, CRYPTO_ALG_ASYNC); + break; + case SW_TYPE_HMAC: + found = crypto_has_hash(algo, 0, swcr_no_ahash?CRYPTO_ALG_ASYNC:0); + break; + case SW_TYPE_HASH: + found = crypto_has_hash(algo, 0, swcr_no_ahash?CRYPTO_ALG_ASYNC:0); + break; + case SW_TYPE_COMP: + found = crypto_has_comp(algo, 0, CRYPTO_ALG_ASYNC); + break; + case SW_TYPE_BLKCIPHER: + found = crypto_has_blkcipher(algo, 0, CRYPTO_ALG_ASYNC); + if (!found && !swcr_no_ablk) + found = crypto_has_ablkcipher(algo, 0, 0); + break; + } + if (found) { + REGISTER(i); + } else { + dprintk("%s:Algorithm Type %d not supported (algorithm %d:'%s')\n", + __FUNCTION__, sw_type, i, algo); + } + } + return 0; +} + +static void +cryptosoft_exit(void) +{ + dprintk("%s()\n", __FUNCTION__); + crypto_unregister_all(swcr_id); + swcr_id = -1; + kmem_cache_destroy(swcr_req_cache); +} + +late_initcall(cryptosoft_init); +module_exit(cryptosoft_exit); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_AUTHOR("David McCullough "); +MODULE_DESCRIPTION("Cryptosoft (OCF module for kernel crypto)"); diff --git a/target/linux/generic/files/crypto/ocf/ep80579/Makefile b/target/linux/generic/files/crypto/ocf/ep80579/Makefile new file mode 100644 index 0000000..9aab295 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/ep80579/Makefile @@ -0,0 +1,119 @@ +######################################################################### +# +# Targets supported +# all - builds everything and installs +# install - identical to all +# depend - build dependencies +# clean - clears derived objects except the .depend files +# distclean- clears all derived objects and the .depend file +# +# @par +# This file is provided under a dual BSD/GPLv2 license. When using or +# redistributing this file, you may do so under either license. +# +# GPL LICENSE SUMMARY +# +# Copyright(c) 2007,2008,2009 Intel Corporation. All rights reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of version 2 of the GNU General Public License 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. +# The full GNU General Public License is included in this distribution +# in the file called LICENSE.GPL. +# +# Contact Information: +# Intel Corporation +# +# BSD LICENSE +# +# Copyright(c) 2007,2008,2009 Intel Corporation. All rights reserved. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# +# version: Security.L.1.0.2-229 +############################################################################ + + +####################Common variables and definitions######################## + +ifndef ICP_ROOT +$(warning ICP_ROOT is undefined. Please set the path to EP80579 release package directory \ + "-> setenv ICP_ROOT ") +all fastdep: + : +else + +ifndef KERNEL_SOURCE_ROOT +$(error KERNEL_SOURCE_ROOT is undefined. Please set the path to the kernel source directory \ + "-> setenv KERNEL_SOURCE_ROOT ") +endif + +# Ensure The ENV_DIR environmental var is defined. +ifndef ICP_ENV_DIR +$(error ICP_ENV_DIR is undefined. Please set the path to EP80579 driver environment.mk file \ + "-> setenv ICP_ENV_DIR ") +endif + +#Add your project environment Makefile +include ${ICP_ENV_DIR}/environment.mk + +#include the makefile with all the default and common Make variable definitions +include ${ICP_BUILDSYSTEM_PATH}/build_files/common.mk + +#Add the name for the executable, Library or Module output definitions +OUTPUT_NAME= icp_ocf + +# List of Source Files to be compiled +SOURCES= icp_common.c icp_sym.c icp_asym.c icp_ocf_linux.c + +#common includes between all supported OSes +INCLUDES= -I ${ICP_API_DIR} -I${ICP_LAC_API} \ +-I${ICP_OCF_SRC_DIR} + +# The location of the os level makefile needs to be changed. +include ${ICP_ENV_DIR}/${ICP_OS}_${ICP_OS_LEVEL}.mk + +# On the line directly below list the outputs you wish to build for, +# e.g "lib_static lib_shared exe module" as shown below +install: module + +###################Include rules makefiles######################## +include ${ICP_BUILDSYSTEM_PATH}/build_files/rules.mk +###################End of Rules inclusion######################### + +endif diff --git a/target/linux/generic/files/crypto/ocf/ep80579/environment.mk b/target/linux/generic/files/crypto/ocf/ep80579/environment.mk new file mode 100644 index 0000000..1a663e5 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/ep80579/environment.mk @@ -0,0 +1,78 @@ + ########################################################################### + # +# This file is provided under a dual BSD/GPLv2 license. When using or +# redistributing this file, you may do so under either license. +# +# GPL LICENSE SUMMARY +# +# Copyright(c) 2007,2008 Intel Corporation. All rights reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of version 2 of the GNU General Public License 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. +# The full GNU General Public License is included in this distribution +# in the file called LICENSE.GPL. +# +# Contact Information: +# Intel Corporation +# +# BSD LICENSE +# +# Copyright(c) 2007,2008 Intel Corporation. All rights reserved. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# +# version: Security.L.1.0.130 + # + ########################################################################### + + +ICP_LAC_API=$(ICP_ROOT)/Acceleration/include/lac +ICP_BTR_API=$(ICP_ROOT)/Acceleration/include/btr +ICP_API_DIR=$(ICP_ROOT)/Acceleration/include +ICP_OCF_SHIM_DIR?=$(KERNEL_SOURCE_ROOT)/crypto/ocf/ +ifeq ($(wildcard $(ICP_OCF_SHIM_DIR)),) +ICP_OCF_SHIM_DIR?=$(ROOTDIR)/modules/ocf/ +endif + +ICP_OS_LEVEL?=kernel_space + +ICP_OS?=linux_2.6 + +ICP_CORE?=ia + diff --git a/target/linux/generic/files/crypto/ocf/ep80579/icp_asym.c b/target/linux/generic/files/crypto/ocf/ep80579/icp_asym.c new file mode 100644 index 0000000..d2641c5 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/ep80579/icp_asym.c @@ -0,0 +1,1334 @@ +/*************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2007,2008,2009 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License 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. + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * Contact Information: + * Intel Corporation + * + * BSD LICENSE + * + * Copyright(c) 2007,2008,2009 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * version: Security.L.1.0.2-229 + * + ***************************************************************************/ + +#include "icp_ocf.h" + +/*The following define values (containing the word 'INDEX') are used to find +the index of each input buffer of the crypto_kop struct (see OCF cryptodev.h). +These values were found through analysis of the OCF OpenSSL patch. If the +calling program uses different input buffer positions, these defines will have +to be changed.*/ + +/*DIFFIE HELLMAN buffer index values*/ +#define ICP_DH_KRP_PARAM_PRIME_INDEX (0) +#define ICP_DH_KRP_PARAM_BASE_INDEX (1) +#define ICP_DH_KRP_PARAM_PRIVATE_VALUE_INDEX (2) +#define ICP_DH_KRP_PARAM_RESULT_INDEX (3) + +/*MOD EXP buffer index values*/ +#define ICP_MOD_EXP_KRP_PARAM_BASE_INDEX (0) +#define ICP_MOD_EXP_KRP_PARAM_EXPONENT_INDEX (1) +#define ICP_MOD_EXP_KRP_PARAM_MODULUS_INDEX (2) +#define ICP_MOD_EXP_KRP_PARAM_RESULT_INDEX (3) + +/*MOD EXP CRT buffer index values*/ +#define ICP_MOD_EXP_CRT_KRP_PARAM_PRIME_P_INDEX (0) +#define ICP_MOD_EXP_CRT_KRP_PARAM_PRIME_Q_INDEX (1) +#define ICP_MOD_EXP_CRT_KRP_PARAM_I_INDEX (2) +#define ICP_MOD_EXP_CRT_KRP_PARAM_EXPONENT_DP_INDEX (3) +#define ICP_MOD_EXP_CRT_KRP_PARAM_EXPONENT_DQ_INDEX (4) +#define ICP_MOD_EXP_CRT_KRP_PARAM_COEFF_QINV_INDEX (5) +#define ICP_MOD_EXP_CRT_KRP_PARAM_RESULT_INDEX (6) + +/*DSA sign buffer index values*/ +#define ICP_DSA_SIGN_KRP_PARAM_DGST_INDEX (0) +#define ICP_DSA_SIGN_KRP_PARAM_PRIME_P_INDEX (1) +#define ICP_DSA_SIGN_KRP_PARAM_PRIME_Q_INDEX (2) +#define ICP_DSA_SIGN_KRP_PARAM_G_INDEX (3) +#define ICP_DSA_SIGN_KRP_PARAM_X_INDEX (4) +#define ICP_DSA_SIGN_KRP_PARAM_R_RESULT_INDEX (5) +#define ICP_DSA_SIGN_KRP_PARAM_S_RESULT_INDEX (6) + +/*DSA verify buffer index values*/ +#define ICP_DSA_VERIFY_KRP_PARAM_DGST_INDEX (0) +#define ICP_DSA_VERIFY_KRP_PARAM_PRIME_P_INDEX (1) +#define ICP_DSA_VERIFY_KRP_PARAM_PRIME_Q_INDEX (2) +#define ICP_DSA_VERIFY_KRP_PARAM_G_INDEX (3) +#define ICP_DSA_VERIFY_KRP_PARAM_PUBKEY_INDEX (4) +#define ICP_DSA_VERIFY_KRP_PARAM_SIG_R_INDEX (5) +#define ICP_DSA_VERIFY_KRP_PARAM_SIG_S_INDEX (6) + +/*DSA sign prime Q vs random number K size check values*/ +#define DONT_RUN_LESS_THAN_CHECK (0) +#define FAIL_A_IS_GREATER_THAN_B (1) +#define FAIL_A_IS_EQUAL_TO_B (1) +#define SUCCESS_A_IS_LESS_THAN_B (0) +#define DSA_SIGN_RAND_GEN_VAL_CHECK_MAX_ITERATIONS (500) + +/* We need to set a cryptokp success value just in case it is set or allocated + and not set to zero outside of this module */ +#define CRYPTO_OP_SUCCESS (0) + +/*Function to compute Diffie Hellman (DH) phase 1 or phase 2 key values*/ +static int icp_ocfDrvDHComputeKey(struct cryptkop *krp); + +/*Function to compute a Modular Exponentiation (Mod Exp)*/ +static int icp_ocfDrvModExp(struct cryptkop *krp); + +/*Function to compute a Mod Exp using the Chinease Remainder Theorem*/ +static int icp_ocfDrvModExpCRT(struct cryptkop *krp); + +/*Helper function to compute whether the first big number argument is less than + the second big number argument */ +static int +icp_ocfDrvCheckALessThanB(CpaFlatBuffer * pK, CpaFlatBuffer * pQ, int *doCheck); + +/*Function to sign an input with DSA R and S keys*/ +static int icp_ocfDrvDsaSign(struct cryptkop *krp); + +/*Function to Verify a DSA buffer signature*/ +static int icp_ocfDrvDsaVerify(struct cryptkop *krp); + +/*Callback function for DH operation*/ +static void +icp_ocfDrvDhP1CallBack(void *callbackTag, + CpaStatus status, + void *pOpData, CpaFlatBuffer * pLocalOctetStringPV); + +/*Callback function for ME operation*/ +static void +icp_ocfDrvModExpCallBack(void *callbackTag, + CpaStatus status, + void *pOpData, CpaFlatBuffer * pResult); + +/*Callback function for ME CRT operation*/ +static void +icp_ocfDrvModExpCRTCallBack(void *callbackTag, + CpaStatus status, + void *pOpData, CpaFlatBuffer * pOutputData); + +/*Callback function for DSA sign operation*/ +static void +icp_ocfDrvDsaRSSignCallBack(void *callbackTag, + CpaStatus status, + void *pOpData, + CpaBoolean protocolStatus, + CpaFlatBuffer * pR, CpaFlatBuffer * pS); + +/*Callback function for DSA Verify operation*/ +static void +icp_ocfDrvDsaVerifyCallBack(void *callbackTag, + CpaStatus status, + void *pOpData, CpaBoolean verifyStatus); + +/* Name : icp_ocfDrvPkeProcess + * + * Description : This function will choose which PKE process to follow + * based on the input arguments + */ +int icp_ocfDrvPkeProcess(icp_device_t dev, struct cryptkop *krp, int hint) +{ + CpaStatus lacStatus = CPA_STATUS_SUCCESS; + + if (NULL == krp) { + DPRINTK("%s(): Invalid input parameters, cryptkop = %p\n", + __FUNCTION__, krp); + return EINVAL; + } + + if (CPA_TRUE == icp_atomic_read(&icp_ocfDrvIsExiting)) { + krp->krp_status = ECANCELED; + return ECANCELED; + } + + switch (krp->krp_op) { + case CRK_DH_COMPUTE_KEY: + DPRINTK("%s() doing DH_COMPUTE_KEY\n", __FUNCTION__); + lacStatus = icp_ocfDrvDHComputeKey(krp); + if (CPA_STATUS_SUCCESS != lacStatus) { + EPRINTK("%s(): icp_ocfDrvDHComputeKey failed " + "(%d).\n", __FUNCTION__, lacStatus); + krp->krp_status = ECANCELED; + return ECANCELED; + } + + break; + + case CRK_MOD_EXP: + DPRINTK("%s() doing MOD_EXP \n", __FUNCTION__); + lacStatus = icp_ocfDrvModExp(krp); + if (CPA_STATUS_SUCCESS != lacStatus) { + EPRINTK("%s(): icp_ocfDrvModExp failed (%d).\n", + __FUNCTION__, lacStatus); + krp->krp_status = ECANCELED; + return ECANCELED; + } + + break; + + case CRK_MOD_EXP_CRT: + DPRINTK("%s() doing MOD_EXP_CRT \n", __FUNCTION__); + lacStatus = icp_ocfDrvModExpCRT(krp); + if (CPA_STATUS_SUCCESS != lacStatus) { + EPRINTK("%s(): icp_ocfDrvModExpCRT " + "failed (%d).\n", __FUNCTION__, lacStatus); + krp->krp_status = ECANCELED; + return ECANCELED; + } + + break; + + case CRK_DSA_SIGN: + DPRINTK("%s() doing DSA_SIGN \n", __FUNCTION__); + lacStatus = icp_ocfDrvDsaSign(krp); + if (CPA_STATUS_SUCCESS != lacStatus) { + EPRINTK("%s(): icp_ocfDrvDsaSign " + "failed (%d).\n", __FUNCTION__, lacStatus); + krp->krp_status = ECANCELED; + return ECANCELED; + } + + break; + + case CRK_DSA_VERIFY: + DPRINTK("%s() doing DSA_VERIFY \n", __FUNCTION__); + lacStatus = icp_ocfDrvDsaVerify(krp); + if (CPA_STATUS_SUCCESS != lacStatus) { + EPRINTK("%s(): icp_ocfDrvDsaVerify " + "failed (%d).\n", __FUNCTION__, lacStatus); + krp->krp_status = ECANCELED; + return ECANCELED; + } + + break; + + default: + EPRINTK("%s(): Asymettric function not " + "supported (%d).\n", __FUNCTION__, krp->krp_op); + krp->krp_status = EOPNOTSUPP; + return EOPNOTSUPP; + } + + return ICP_OCF_DRV_STATUS_SUCCESS; +} + +/* Name : icp_ocfDrvSwapBytes + * + * Description : This function is used to swap the byte order of a buffer. + * It has been seen that in general we are passed little endian byte order + * buffers, but LAC only accepts big endian byte order buffers. + */ +static void inline icp_ocfDrvSwapBytes(u_int8_t * num, u_int32_t buff_len_bytes) +{ + + int i; + u_int8_t *end_ptr; + u_int8_t hold_val; + + end_ptr = num + (buff_len_bytes - 1); + buff_len_bytes = buff_len_bytes >> 1; + for (i = 0; i < buff_len_bytes; i++) { + hold_val = *num; + *num = *end_ptr; + num++; + *end_ptr = hold_val; + end_ptr--; + } +} + +/* Name : icp_ocfDrvDHComputeKey + * + * Description : This function will map Diffie Hellman calls from OCF + * to the LAC API. OCF uses this function for Diffie Hellman Phase1 and + * Phase2. LAC has a separate Diffie Hellman Phase2 call, however both phases + * break down to a modular exponentiation. + */ +static int icp_ocfDrvDHComputeKey(struct cryptkop *krp) +{ + CpaStatus lacStatus = CPA_STATUS_SUCCESS; + void *callbackTag = NULL; + CpaCyDhPhase1KeyGenOpData *pPhase1OpData = NULL; + CpaFlatBuffer *pLocalOctetStringPV = NULL; + uint32_t dh_prime_len_bytes = 0, dh_prime_len_bits = 0; + + /* Input checks - check prime is a multiple of 8 bits to allow for + allocation later */ + dh_prime_len_bits = + (krp->krp_param[ICP_DH_KRP_PARAM_PRIME_INDEX].crp_nbits); + + /* LAC can reject prime lengths based on prime key sizes, we just + need to make sure we can allocate space for the base and + exponent buffers correctly */ + if ((dh_prime_len_bits % NUM_BITS_IN_BYTE) != 0) { + APRINTK("%s(): Warning Prime number buffer size is not a " + "multiple of 8 bits\n", __FUNCTION__); + } + + /* Result storage space should be the same size as the prime as this + value can take up the same amount of storage space */ + if (dh_prime_len_bits != + krp->krp_param[ICP_DH_KRP_PARAM_RESULT_INDEX].crp_nbits) { + DPRINTK("%s(): Return Buffer must be the same size " + "as the Prime buffer\n", __FUNCTION__); + krp->krp_status = EINVAL; + return EINVAL; + } + /* Switch to size in bytes */ + BITS_TO_BYTES(dh_prime_len_bytes, dh_prime_len_bits); + + callbackTag = krp; + +/*All allocations are set to ICP_M_NOWAIT due to the possibility of getting +called in interrupt context*/ + pPhase1OpData = icp_kmem_cache_zalloc(drvDH_zone, ICP_M_NOWAIT); + if (NULL == pPhase1OpData) { + APRINTK("%s():Failed to get memory for key gen data\n", + __FUNCTION__); + krp->krp_status = ENOMEM; + return ENOMEM; + } + + pLocalOctetStringPV = + icp_kmem_cache_zalloc(drvFlatBuffer_zone, ICP_M_NOWAIT); + if (NULL == pLocalOctetStringPV) { + APRINTK("%s():Failed to get memory for pLocalOctetStringPV\n", + __FUNCTION__); + ICP_CACHE_FREE(drvDH_zone, pPhase1OpData); + krp->krp_status = ENOMEM; + return ENOMEM; + } + + /* Link parameters */ + pPhase1OpData->primeP.pData = + krp->krp_param[ICP_DH_KRP_PARAM_PRIME_INDEX].crp_p; + + pPhase1OpData->primeP.dataLenInBytes = dh_prime_len_bytes; + + icp_ocfDrvSwapBytes(pPhase1OpData->primeP.pData, dh_prime_len_bytes); + + pPhase1OpData->baseG.pData = + krp->krp_param[ICP_DH_KRP_PARAM_BASE_INDEX].crp_p; + + BITS_TO_BYTES(pPhase1OpData->baseG.dataLenInBytes, + krp->krp_param[ICP_DH_KRP_PARAM_BASE_INDEX].crp_nbits); + + icp_ocfDrvSwapBytes(pPhase1OpData->baseG.pData, + pPhase1OpData->baseG.dataLenInBytes); + + pPhase1OpData->privateValueX.pData = + krp->krp_param[ICP_DH_KRP_PARAM_PRIVATE_VALUE_INDEX].crp_p; + + BITS_TO_BYTES(pPhase1OpData->privateValueX.dataLenInBytes, + krp->krp_param[ICP_DH_KRP_PARAM_PRIVATE_VALUE_INDEX]. + crp_nbits); + + icp_ocfDrvSwapBytes(pPhase1OpData->privateValueX.pData, + pPhase1OpData->privateValueX.dataLenInBytes); + + /* Output parameters */ + pLocalOctetStringPV->pData = + krp->krp_param[ICP_DH_KRP_PARAM_RESULT_INDEX].crp_p; + + BITS_TO_BYTES(pLocalOctetStringPV->dataLenInBytes, + krp->krp_param[ICP_DH_KRP_PARAM_RESULT_INDEX].crp_nbits); + + lacStatus = cpaCyDhKeyGenPhase1(CPA_INSTANCE_HANDLE_SINGLE, + icp_ocfDrvDhP1CallBack, + callbackTag, pPhase1OpData, + pLocalOctetStringPV); + + if (CPA_STATUS_SUCCESS != lacStatus) { + EPRINTK("%s(): DH Phase 1 Key Gen failed (%d).\n", + __FUNCTION__, lacStatus); + icp_ocfDrvFreeFlatBuffer(pLocalOctetStringPV); + ICP_CACHE_FREE(drvDH_zone, pPhase1OpData); + } + + return lacStatus; +} + +/* Name : icp_ocfDrvModExp + * + * Description : This function will map ordinary Modular Exponentiation calls + * from OCF to the LAC API. + * + */ +static int icp_ocfDrvModExp(struct cryptkop *krp) +{ + CpaStatus lacStatus = CPA_STATUS_SUCCESS; + void *callbackTag = NULL; + CpaCyLnModExpOpData *pModExpOpData = NULL; + CpaFlatBuffer *pResult = NULL; + + if ((krp->krp_param[ICP_MOD_EXP_KRP_PARAM_MODULUS_INDEX].crp_nbits % + NUM_BITS_IN_BYTE) != 0) { + DPRINTK("%s(): Warning - modulus buffer size (%d) is not a " + "multiple of 8 bits\n", __FUNCTION__, + krp->krp_param[ICP_MOD_EXP_KRP_PARAM_MODULUS_INDEX]. + crp_nbits); + } + + /* Result storage space should be the same size as the prime as this + value can take up the same amount of storage space */ + if (krp->krp_param[ICP_MOD_EXP_KRP_PARAM_MODULUS_INDEX].crp_nbits > + krp->krp_param[ICP_MOD_EXP_KRP_PARAM_RESULT_INDEX].crp_nbits) { + APRINTK("%s(): Return Buffer size must be the same or" + " greater than the Modulus buffer\n", __FUNCTION__); + krp->krp_status = EINVAL; + return EINVAL; + } + + callbackTag = krp; + + pModExpOpData = icp_kmem_cache_zalloc(drvLnModExp_zone, ICP_M_NOWAIT); + if (NULL == pModExpOpData) { + APRINTK("%s():Failed to get memory for key gen data\n", + __FUNCTION__); + krp->krp_status = ENOMEM; + return ENOMEM; + } + + pResult = icp_kmem_cache_zalloc(drvFlatBuffer_zone, ICP_M_NOWAIT); + if (NULL == pResult) { + APRINTK("%s():Failed to get memory for ModExp result\n", + __FUNCTION__); + ICP_CACHE_FREE(drvLnModExp_zone, pModExpOpData); + krp->krp_status = ENOMEM; + return ENOMEM; + } + + /* Link parameters */ + pModExpOpData->modulus.pData = + krp->krp_param[ICP_MOD_EXP_KRP_PARAM_MODULUS_INDEX].crp_p; + BITS_TO_BYTES(pModExpOpData->modulus.dataLenInBytes, + krp->krp_param[ICP_MOD_EXP_KRP_PARAM_MODULUS_INDEX]. + crp_nbits); + + icp_ocfDrvSwapBytes(pModExpOpData->modulus.pData, + pModExpOpData->modulus.dataLenInBytes); + + DPRINTK("%s : base (%d)\n", __FUNCTION__, krp-> + krp_param[ICP_MOD_EXP_KRP_PARAM_BASE_INDEX].crp_nbits); + pModExpOpData->base.pData = + krp->krp_param[ICP_MOD_EXP_KRP_PARAM_BASE_INDEX].crp_p; + BITS_TO_BYTES(pModExpOpData->base.dataLenInBytes, + krp->krp_param[ICP_MOD_EXP_KRP_PARAM_BASE_INDEX]. + crp_nbits); + icp_ocfDrvSwapBytes(pModExpOpData->base.pData, + pModExpOpData->base.dataLenInBytes); + + pModExpOpData->exponent.pData = + krp->krp_param[ICP_MOD_EXP_KRP_PARAM_EXPONENT_INDEX].crp_p; + BITS_TO_BYTES(pModExpOpData->exponent.dataLenInBytes, + krp->krp_param[ICP_MOD_EXP_KRP_PARAM_EXPONENT_INDEX]. + crp_nbits); + + icp_ocfDrvSwapBytes(pModExpOpData->exponent.pData, + pModExpOpData->exponent.dataLenInBytes); + /* Output parameters */ + pResult->pData = + krp->krp_param[ICP_MOD_EXP_KRP_PARAM_RESULT_INDEX].crp_p, + BITS_TO_BYTES(pResult->dataLenInBytes, + krp->krp_param[ICP_MOD_EXP_KRP_PARAM_RESULT_INDEX]. + crp_nbits); + + lacStatus = cpaCyLnModExp(CPA_INSTANCE_HANDLE_SINGLE, + icp_ocfDrvModExpCallBack, + callbackTag, pModExpOpData, pResult); + + if (CPA_STATUS_SUCCESS != lacStatus) { + EPRINTK("%s(): Mod Exp Operation failed (%d).\n", + __FUNCTION__, lacStatus); + krp->krp_status = ECANCELED; + icp_ocfDrvFreeFlatBuffer(pResult); + ICP_CACHE_FREE(drvLnModExp_zone, pModExpOpData); + } + + return lacStatus; +} + +/* Name : icp_ocfDrvModExpCRT + * + * Description : This function will map ordinary Modular Exponentiation Chinese + * Remainder Theorem implementaion calls from OCF to the LAC API. + * + * Note : Mod Exp CRT for this driver is accelerated through LAC RSA type 2 + * decrypt operation. Therefore P and Q input values must always be prime + * numbers. Although basic primality checks are done in LAC, it is up to the + * user to do any correct prime number checking before passing the inputs. + */ +static int icp_ocfDrvModExpCRT(struct cryptkop *krp) +{ + CpaStatus lacStatus = CPA_STATUS_SUCCESS; + CpaCyRsaDecryptOpData *rsaDecryptOpData = NULL; + void *callbackTag = NULL; + CpaFlatBuffer *pOutputData = NULL; + + /*Parameter input checks are all done by LAC, no need to repeat + them here. */ + callbackTag = krp; + + rsaDecryptOpData = + icp_kmem_cache_zalloc(drvRSADecrypt_zone, ICP_M_NOWAIT); + if (NULL == rsaDecryptOpData) { + APRINTK("%s():Failed to get memory" + " for MOD EXP CRT Op data struct\n", __FUNCTION__); + krp->krp_status = ENOMEM; + return ENOMEM; + } + + rsaDecryptOpData->pRecipientPrivateKey + = icp_kmem_cache_zalloc(drvRSAPrivateKey_zone, ICP_M_NOWAIT); + if (NULL == rsaDecryptOpData->pRecipientPrivateKey) { + APRINTK("%s():Failed to get memory for MOD EXP CRT" + " private key values struct\n", __FUNCTION__); + ICP_CACHE_FREE(drvRSADecrypt_zone, rsaDecryptOpData); + krp->krp_status = ENOMEM; + return ENOMEM; + } + + rsaDecryptOpData->pRecipientPrivateKey-> + version = CPA_CY_RSA_VERSION_TWO_PRIME; + rsaDecryptOpData->pRecipientPrivateKey-> + privateKeyRepType = CPA_CY_RSA_PRIVATE_KEY_REP_TYPE_2; + + pOutputData = icp_kmem_cache_zalloc(drvFlatBuffer_zone, ICP_M_NOWAIT); + if (NULL == pOutputData) { + APRINTK("%s():Failed to get memory" + " for MOD EXP CRT output data\n", __FUNCTION__); + ICP_CACHE_FREE(drvRSAPrivateKey_zone, + rsaDecryptOpData->pRecipientPrivateKey); + ICP_CACHE_FREE(drvRSADecrypt_zone, rsaDecryptOpData); + krp->krp_status = ENOMEM; + return ENOMEM; + } + + rsaDecryptOpData->pRecipientPrivateKey-> + version = CPA_CY_RSA_VERSION_TWO_PRIME; + rsaDecryptOpData->pRecipientPrivateKey-> + privateKeyRepType = CPA_CY_RSA_PRIVATE_KEY_REP_TYPE_2; + + /* Link parameters */ + rsaDecryptOpData->inputData.pData = + krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_I_INDEX].crp_p; + BITS_TO_BYTES(rsaDecryptOpData->inputData.dataLenInBytes, + krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_I_INDEX]. + crp_nbits); + + icp_ocfDrvSwapBytes(rsaDecryptOpData->inputData.pData, + rsaDecryptOpData->inputData.dataLenInBytes); + + rsaDecryptOpData->pRecipientPrivateKey->privateKeyRep2.prime1P.pData = + krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_PRIME_P_INDEX].crp_p; + BITS_TO_BYTES(rsaDecryptOpData->pRecipientPrivateKey->privateKeyRep2. + prime1P.dataLenInBytes, + krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_PRIME_P_INDEX]. + crp_nbits); + + icp_ocfDrvSwapBytes(rsaDecryptOpData->pRecipientPrivateKey-> + privateKeyRep2.prime1P.pData, + rsaDecryptOpData->pRecipientPrivateKey-> + privateKeyRep2.prime1P.dataLenInBytes); + + rsaDecryptOpData->pRecipientPrivateKey->privateKeyRep2.prime2Q.pData = + krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_PRIME_Q_INDEX].crp_p; + BITS_TO_BYTES(rsaDecryptOpData->pRecipientPrivateKey->privateKeyRep2. + prime2Q.dataLenInBytes, + krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_PRIME_Q_INDEX]. + crp_nbits); + + icp_ocfDrvSwapBytes(rsaDecryptOpData->pRecipientPrivateKey-> + privateKeyRep2.prime2Q.pData, + rsaDecryptOpData->pRecipientPrivateKey-> + privateKeyRep2.prime2Q.dataLenInBytes); + + rsaDecryptOpData->pRecipientPrivateKey-> + privateKeyRep2.exponent1Dp.pData = + krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_EXPONENT_DP_INDEX].crp_p; + BITS_TO_BYTES(rsaDecryptOpData->pRecipientPrivateKey->privateKeyRep2. + exponent1Dp.dataLenInBytes, + krp-> + krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_EXPONENT_DP_INDEX]. + crp_nbits); + + icp_ocfDrvSwapBytes(rsaDecryptOpData->pRecipientPrivateKey-> + privateKeyRep2.exponent1Dp.pData, + rsaDecryptOpData->pRecipientPrivateKey-> + privateKeyRep2.exponent1Dp.dataLenInBytes); + + rsaDecryptOpData->pRecipientPrivateKey-> + privateKeyRep2.exponent2Dq.pData = + krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_EXPONENT_DQ_INDEX].crp_p; + BITS_TO_BYTES(rsaDecryptOpData->pRecipientPrivateKey-> + privateKeyRep2.exponent2Dq.dataLenInBytes, + krp-> + krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_EXPONENT_DQ_INDEX]. + crp_nbits); + + icp_ocfDrvSwapBytes(rsaDecryptOpData->pRecipientPrivateKey-> + privateKeyRep2.exponent2Dq.pData, + rsaDecryptOpData->pRecipientPrivateKey-> + privateKeyRep2.exponent2Dq.dataLenInBytes); + + rsaDecryptOpData->pRecipientPrivateKey-> + privateKeyRep2.coefficientQInv.pData = + krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_COEFF_QINV_INDEX].crp_p; + BITS_TO_BYTES(rsaDecryptOpData->pRecipientPrivateKey-> + privateKeyRep2.coefficientQInv.dataLenInBytes, + krp-> + krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_COEFF_QINV_INDEX]. + crp_nbits); + + icp_ocfDrvSwapBytes(rsaDecryptOpData->pRecipientPrivateKey-> + privateKeyRep2.coefficientQInv.pData, + rsaDecryptOpData->pRecipientPrivateKey-> + privateKeyRep2.coefficientQInv.dataLenInBytes); + + /* Output Parameter */ + pOutputData->pData = + krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_RESULT_INDEX].crp_p; + BITS_TO_BYTES(pOutputData->dataLenInBytes, + krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_RESULT_INDEX]. + crp_nbits); + + lacStatus = cpaCyRsaDecrypt(CPA_INSTANCE_HANDLE_SINGLE, + icp_ocfDrvModExpCRTCallBack, + callbackTag, rsaDecryptOpData, pOutputData); + + if (CPA_STATUS_SUCCESS != lacStatus) { + EPRINTK("%s(): Mod Exp CRT Operation failed (%d).\n", + __FUNCTION__, lacStatus); + krp->krp_status = ECANCELED; + icp_ocfDrvFreeFlatBuffer(pOutputData); + ICP_CACHE_FREE(drvRSAPrivateKey_zone, + rsaDecryptOpData->pRecipientPrivateKey); + ICP_CACHE_FREE(drvRSADecrypt_zone, rsaDecryptOpData); + } + + return lacStatus; +} + +/* Name : icp_ocfDrvCheckALessThanB + * + * Description : This function will check whether the first argument is less + * than the second. It is used to check whether the DSA RS sign Random K + * value is less than the Prime Q value (as defined in the specification) + * + */ +static int +icp_ocfDrvCheckALessThanB(CpaFlatBuffer * pK, CpaFlatBuffer * pQ, int *doCheck) +{ + + uint8_t *MSB_K = pK->pData; + uint8_t *MSB_Q = pQ->pData; + uint32_t buffer_lengths_in_bytes = pQ->dataLenInBytes; + + if (DONT_RUN_LESS_THAN_CHECK == *doCheck) { + return FAIL_A_IS_GREATER_THAN_B; + } + +/*Check MSBs +if A == B, check next MSB +if A > B, return A_IS_GREATER_THAN_B +if A < B, return A_IS_LESS_THAN_B (success) +*/ + while (*MSB_K == *MSB_Q) { + MSB_K++; + MSB_Q++; + + buffer_lengths_in_bytes--; + if (0 == buffer_lengths_in_bytes) { + DPRINTK("%s() Buffers have equal value!!\n", + __FUNCTION__); + return FAIL_A_IS_EQUAL_TO_B; + } + + } + + if (*MSB_K < *MSB_Q) { + return SUCCESS_A_IS_LESS_THAN_B; + } else { + return FAIL_A_IS_GREATER_THAN_B; + } + +} + +/* Name : icp_ocfDrvDsaSign + * + * Description : This function will map DSA RS Sign from OCF to the LAC API. + * + * NOTE: From looking at OCF patch to OpenSSL and even the number of input + * parameters, OCF expects us to generate the random seed value. This value + * is generated and passed to LAC, however the number is discared in the + * callback and not returned to the user. + */ +static int icp_ocfDrvDsaSign(struct cryptkop *krp) +{ + CpaStatus lacStatus = CPA_STATUS_SUCCESS; + CpaCyDsaRSSignOpData *dsaRsSignOpData = NULL; + void *callbackTag = NULL; + CpaCyRandGenOpData randGenOpData; + int primeQSizeInBytes = 0; + int doCheck = 0; + CpaFlatBuffer randData; + CpaBoolean protocolStatus = CPA_FALSE; + CpaFlatBuffer *pR = NULL; + CpaFlatBuffer *pS = NULL; + + callbackTag = krp; + + BITS_TO_BYTES(primeQSizeInBytes, + krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_PRIME_Q_INDEX]. + crp_nbits); + + if (DSA_RS_SIGN_PRIMEQ_SIZE_IN_BYTES != primeQSizeInBytes) { + APRINTK("%s(): DSA PRIME Q size not equal to the " + "FIPS defined 20bytes, = %d\n", + __FUNCTION__, primeQSizeInBytes); + krp->krp_status = EDOM; + return EDOM; + } + + dsaRsSignOpData = + icp_kmem_cache_zalloc(drvDSARSSign_zone, ICP_M_NOWAIT); + if (NULL == dsaRsSignOpData) { + APRINTK("%s():Failed to get memory" + " for DSA RS Sign Op data struct\n", __FUNCTION__); + krp->krp_status = ENOMEM; + return ENOMEM; + } + + dsaRsSignOpData->K.pData = + icp_kmem_cache_alloc(drvDSARSSignKValue_zone, ICP_M_NOWAIT); + + if (NULL == dsaRsSignOpData->K.pData) { + APRINTK("%s():Failed to get memory" + " for DSA RS Sign Op Random value\n", __FUNCTION__); + ICP_CACHE_FREE(drvDSARSSign_zone, dsaRsSignOpData); + krp->krp_status = ENOMEM; + return ENOMEM; + } + + pR = icp_kmem_cache_zalloc(drvFlatBuffer_zone, ICP_M_NOWAIT); + if (NULL == pR) { + APRINTK("%s():Failed to get memory" + " for DSA signature R\n", __FUNCTION__); + ICP_CACHE_FREE(drvDSARSSignKValue_zone, + dsaRsSignOpData->K.pData); + ICP_CACHE_FREE(drvDSARSSign_zone, dsaRsSignOpData); + krp->krp_status = ENOMEM; + return ENOMEM; + } + + pS = icp_kmem_cache_zalloc(drvFlatBuffer_zone, ICP_M_NOWAIT); + if (NULL == pS) { + APRINTK("%s():Failed to get memory" + " for DSA signature S\n", __FUNCTION__); + icp_ocfDrvFreeFlatBuffer(pR); + ICP_CACHE_FREE(drvDSARSSignKValue_zone, + dsaRsSignOpData->K.pData); + ICP_CACHE_FREE(drvDSARSSign_zone, dsaRsSignOpData); + krp->krp_status = ENOMEM; + return ENOMEM; + } + + /*link prime number parameter for ease of processing */ + dsaRsSignOpData->P.pData = + krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_PRIME_P_INDEX].crp_p; + BITS_TO_BYTES(dsaRsSignOpData->P.dataLenInBytes, + krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_PRIME_P_INDEX]. + crp_nbits); + + icp_ocfDrvSwapBytes(dsaRsSignOpData->P.pData, + dsaRsSignOpData->P.dataLenInBytes); + + dsaRsSignOpData->Q.pData = + krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_PRIME_Q_INDEX].crp_p; + BITS_TO_BYTES(dsaRsSignOpData->Q.dataLenInBytes, + krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_PRIME_Q_INDEX]. + crp_nbits); + + icp_ocfDrvSwapBytes(dsaRsSignOpData->Q.pData, + dsaRsSignOpData->Q.dataLenInBytes); + + /*generate random number with equal buffer size to Prime value Q, + but value less than Q */ + dsaRsSignOpData->K.dataLenInBytes = dsaRsSignOpData->Q.dataLenInBytes; + + randGenOpData.generateBits = CPA_TRUE; + randGenOpData.lenInBytes = dsaRsSignOpData->K.dataLenInBytes; + + icp_ocfDrvPtrAndLenToFlatBuffer(dsaRsSignOpData->K.pData, + dsaRsSignOpData->K.dataLenInBytes, + &randData); + + doCheck = 0; + while (icp_ocfDrvCheckALessThanB(&(dsaRsSignOpData->K), + &(dsaRsSignOpData->Q), &doCheck)) { + + if (CPA_STATUS_SUCCESS + != cpaCyRandGen(CPA_INSTANCE_HANDLE_SINGLE, + NULL, NULL, &randGenOpData, &randData)) { + APRINTK("%s(): ERROR - Failed to generate DSA RS Sign K" + "value\n", __FUNCTION__); + icp_ocfDrvFreeFlatBuffer(pS); + icp_ocfDrvFreeFlatBuffer(pR); + ICP_CACHE_FREE(drvDSARSSignKValue_zone, + dsaRsSignOpData->K.pData); + ICP_CACHE_FREE(drvDSARSSign_zone, dsaRsSignOpData); + krp->krp_status = EAGAIN; + return EAGAIN; + } + + doCheck++; + if (DSA_SIGN_RAND_GEN_VAL_CHECK_MAX_ITERATIONS == doCheck) { + APRINTK("%s(): ERROR - Failed to find DSA RS Sign K " + "value less than Q value\n", __FUNCTION__); + icp_ocfDrvFreeFlatBuffer(pS); + icp_ocfDrvFreeFlatBuffer(pR); + ICP_CACHE_FREE(drvDSARSSignKValue_zone, + dsaRsSignOpData->K.pData); + ICP_CACHE_FREE(drvDSARSSign_zone, dsaRsSignOpData); + krp->krp_status = EAGAIN; + return EAGAIN; + } + + } + /*Rand Data - no need to swap bytes for pK */ + + /* Link parameters */ + dsaRsSignOpData->G.pData = + krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_G_INDEX].crp_p; + BITS_TO_BYTES(dsaRsSignOpData->G.dataLenInBytes, + krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_G_INDEX].crp_nbits); + + icp_ocfDrvSwapBytes(dsaRsSignOpData->G.pData, + dsaRsSignOpData->G.dataLenInBytes); + + dsaRsSignOpData->X.pData = + krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_X_INDEX].crp_p; + BITS_TO_BYTES(dsaRsSignOpData->X.dataLenInBytes, + krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_X_INDEX].crp_nbits); + icp_ocfDrvSwapBytes(dsaRsSignOpData->X.pData, + dsaRsSignOpData->X.dataLenInBytes); + + /*OpenSSL dgst parameter is left in big endian byte order, + therefore no byte swap is required */ + dsaRsSignOpData->M.pData = + krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_DGST_INDEX].crp_p; + BITS_TO_BYTES(dsaRsSignOpData->M.dataLenInBytes, + krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_DGST_INDEX]. + crp_nbits); + + /* Output Parameters */ + pS->pData = krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_S_RESULT_INDEX].crp_p; + BITS_TO_BYTES(pS->dataLenInBytes, + krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_S_RESULT_INDEX]. + crp_nbits); + + pR->pData = krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_R_RESULT_INDEX].crp_p; + BITS_TO_BYTES(pR->dataLenInBytes, + krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_R_RESULT_INDEX]. + crp_nbits); + + lacStatus = cpaCyDsaSignRS(CPA_INSTANCE_HANDLE_SINGLE, + icp_ocfDrvDsaRSSignCallBack, + callbackTag, dsaRsSignOpData, + &protocolStatus, pR, pS); + + if (CPA_STATUS_SUCCESS != lacStatus) { + EPRINTK("%s(): DSA RS Sign Operation failed (%d).\n", + __FUNCTION__, lacStatus); + krp->krp_status = ECANCELED; + icp_ocfDrvFreeFlatBuffer(pS); + icp_ocfDrvFreeFlatBuffer(pR); + ICP_CACHE_FREE(drvDSARSSignKValue_zone, + dsaRsSignOpData->K.pData); + ICP_CACHE_FREE(drvDSARSSign_zone, dsaRsSignOpData); + } + + return lacStatus; +} + +/* Name : icp_ocfDrvDsaVerify + * + * Description : This function will map DSA RS Verify from OCF to the LAC API. + * + */ +static int icp_ocfDrvDsaVerify(struct cryptkop *krp) +{ + CpaStatus lacStatus = CPA_STATUS_SUCCESS; + CpaCyDsaVerifyOpData *dsaVerifyOpData = NULL; + void *callbackTag = NULL; + CpaBoolean verifyStatus = CPA_FALSE; + + callbackTag = krp; + + dsaVerifyOpData = + icp_kmem_cache_zalloc(drvDSAVerify_zone, ICP_M_NOWAIT); + if (NULL == dsaVerifyOpData) { + APRINTK("%s():Failed to get memory" + " for DSA Verify Op data struct\n", __FUNCTION__); + krp->krp_status = ENOMEM; + return ENOMEM; + } + + /* Link parameters */ + dsaVerifyOpData->P.pData = + krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_PRIME_P_INDEX].crp_p; + BITS_TO_BYTES(dsaVerifyOpData->P.dataLenInBytes, + krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_PRIME_P_INDEX]. + crp_nbits); + icp_ocfDrvSwapBytes(dsaVerifyOpData->P.pData, + dsaVerifyOpData->P.dataLenInBytes); + + dsaVerifyOpData->Q.pData = + krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_PRIME_Q_INDEX].crp_p; + BITS_TO_BYTES(dsaVerifyOpData->Q.dataLenInBytes, + krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_PRIME_Q_INDEX]. + crp_nbits); + icp_ocfDrvSwapBytes(dsaVerifyOpData->Q.pData, + dsaVerifyOpData->Q.dataLenInBytes); + + dsaVerifyOpData->G.pData = + krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_G_INDEX].crp_p; + BITS_TO_BYTES(dsaVerifyOpData->G.dataLenInBytes, + krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_G_INDEX]. + crp_nbits); + icp_ocfDrvSwapBytes(dsaVerifyOpData->G.pData, + dsaVerifyOpData->G.dataLenInBytes); + + dsaVerifyOpData->Y.pData = + krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_PUBKEY_INDEX].crp_p; + BITS_TO_BYTES(dsaVerifyOpData->Y.dataLenInBytes, + krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_PUBKEY_INDEX]. + crp_nbits); + icp_ocfDrvSwapBytes(dsaVerifyOpData->Y.pData, + dsaVerifyOpData->Y.dataLenInBytes); + + /*OpenSSL dgst parameter is left in big endian byte order, + therefore no byte swap is required */ + dsaVerifyOpData->M.pData = + krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_DGST_INDEX].crp_p; + BITS_TO_BYTES(dsaVerifyOpData->M.dataLenInBytes, + krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_DGST_INDEX]. + crp_nbits); + + dsaVerifyOpData->R.pData = + krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_SIG_R_INDEX].crp_p; + BITS_TO_BYTES(dsaVerifyOpData->R.dataLenInBytes, + krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_SIG_R_INDEX]. + crp_nbits); + icp_ocfDrvSwapBytes(dsaVerifyOpData->R.pData, + dsaVerifyOpData->R.dataLenInBytes); + + dsaVerifyOpData->S.pData = + krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_SIG_S_INDEX].crp_p; + BITS_TO_BYTES(dsaVerifyOpData->S.dataLenInBytes, + krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_SIG_S_INDEX]. + crp_nbits); + icp_ocfDrvSwapBytes(dsaVerifyOpData->S.pData, + dsaVerifyOpData->S.dataLenInBytes); + + lacStatus = cpaCyDsaVerify(CPA_INSTANCE_HANDLE_SINGLE, + icp_ocfDrvDsaVerifyCallBack, + callbackTag, dsaVerifyOpData, &verifyStatus); + + if (CPA_STATUS_SUCCESS != lacStatus) { + EPRINTK("%s(): DSA Verify Operation failed (%d).\n", + __FUNCTION__, lacStatus); + ICP_CACHE_FREE(drvDSAVerify_zone, dsaVerifyOpData); + krp->krp_status = ECANCELED; + } + + return lacStatus; +} + +/* Name : icp_ocfDrvDhP1Callback + * + * Description : When this function returns it signifies that the LAC + * component has completed the DH operation. + */ +static void +icp_ocfDrvDhP1CallBack(void *callbackTag, + CpaStatus status, + void *pOpData, CpaFlatBuffer * pLocalOctetStringPV) +{ + struct cryptkop *krp = NULL; + CpaCyDhPhase1KeyGenOpData *pPhase1OpData = NULL; + + if (NULL == callbackTag) { + DPRINTK("%s(): Invalid input parameters - " + "callbackTag data is NULL\n", __FUNCTION__); + return; + } + krp = (struct cryptkop *)callbackTag; + + if (NULL == pOpData) { + DPRINTK("%s(): Invalid input parameters - " + "Operation Data is NULL\n", __FUNCTION__); + krp->krp_status = ECANCELED; + crypto_kdone(krp); + return; + } + pPhase1OpData = (CpaCyDhPhase1KeyGenOpData *) pOpData; + + if (NULL == pLocalOctetStringPV) { + DPRINTK("%s(): Invalid input parameters - " + "pLocalOctetStringPV Data is NULL\n", __FUNCTION__); + memset(pPhase1OpData, 0, sizeof(CpaCyDhPhase1KeyGenOpData)); + ICP_CACHE_FREE(drvDH_zone, pPhase1OpData); + krp->krp_status = ECANCELED; + crypto_kdone(krp); + return; + } + + if (CPA_STATUS_SUCCESS == status) { + krp->krp_status = CRYPTO_OP_SUCCESS; + } else { + APRINTK("%s(): Diffie Hellman Phase1 Key Gen failed - " + "Operation Status = %d\n", __FUNCTION__, status); + krp->krp_status = ECANCELED; + } + + icp_ocfDrvSwapBytes(pLocalOctetStringPV->pData, + pLocalOctetStringPV->dataLenInBytes); + + icp_ocfDrvFreeFlatBuffer(pLocalOctetStringPV); + memset(pPhase1OpData, 0, sizeof(CpaCyDhPhase1KeyGenOpData)); + ICP_CACHE_FREE(drvDH_zone, pPhase1OpData); + + crypto_kdone(krp); + + return; +} + +/* Name : icp_ocfDrvModExpCallBack + * + * Description : When this function returns it signifies that the LAC + * component has completed the Mod Exp operation. + */ +static void +icp_ocfDrvModExpCallBack(void *callbackTag, + CpaStatus status, + void *pOpdata, CpaFlatBuffer * pResult) +{ + struct cryptkop *krp = NULL; + CpaCyLnModExpOpData *pLnModExpOpData = NULL; + + if (NULL == callbackTag) { + DPRINTK("%s(): Invalid input parameters - " + "callbackTag data is NULL\n", __FUNCTION__); + return; + } + krp = (struct cryptkop *)callbackTag; + + if (NULL == pOpdata) { + DPRINTK("%s(): Invalid Mod Exp input parameters - " + "Operation Data is NULL\n", __FUNCTION__); + krp->krp_status = ECANCELED; + crypto_kdone(krp); + return; + } + pLnModExpOpData = (CpaCyLnModExpOpData *) pOpdata; + + if (NULL == pResult) { + DPRINTK("%s(): Invalid input parameters - " + "pResult data is NULL\n", __FUNCTION__); + krp->krp_status = ECANCELED; + memset(pLnModExpOpData, 0, sizeof(CpaCyLnModExpOpData)); + ICP_CACHE_FREE(drvLnModExp_zone, pLnModExpOpData); + crypto_kdone(krp); + return; + } + + if (CPA_STATUS_SUCCESS == status) { + krp->krp_status = CRYPTO_OP_SUCCESS; + } else { + APRINTK("%s(): LAC Mod Exp Operation failed - " + "Operation Status = %d\n", __FUNCTION__, status); + krp->krp_status = ECANCELED; + } + + icp_ocfDrvSwapBytes(pResult->pData, pResult->dataLenInBytes); + + /*switch base size value back to original */ + if (pLnModExpOpData->base.pData == + (uint8_t *) & (krp-> + krp_param[ICP_MOD_EXP_KRP_PARAM_BASE_INDEX]. + crp_nbits)) { + *((uint32_t *) pLnModExpOpData->base.pData) = + ntohl(*((uint32_t *) pLnModExpOpData->base.pData)); + } + icp_ocfDrvFreeFlatBuffer(pResult); + memset(pLnModExpOpData, 0, sizeof(CpaCyLnModExpOpData)); + ICP_CACHE_FREE(drvLnModExp_zone, pLnModExpOpData); + + crypto_kdone(krp); + + return; + +} + +/* Name : icp_ocfDrvModExpCRTCallBack + * + * Description : When this function returns it signifies that the LAC + * component has completed the Mod Exp CRT operation. + */ +static void +icp_ocfDrvModExpCRTCallBack(void *callbackTag, + CpaStatus status, + void *pOpData, CpaFlatBuffer * pOutputData) +{ + struct cryptkop *krp = NULL; + CpaCyRsaDecryptOpData *pDecryptData = NULL; + + if (NULL == callbackTag) { + DPRINTK("%s(): Invalid input parameters - " + "callbackTag data is NULL\n", __FUNCTION__); + return; + } + + krp = (struct cryptkop *)callbackTag; + + if (NULL == pOpData) { + DPRINTK("%s(): Invalid input parameters - " + "Operation Data is NULL\n", __FUNCTION__); + krp->krp_status = ECANCELED; + crypto_kdone(krp); + return; + } + pDecryptData = (CpaCyRsaDecryptOpData *) pOpData; + + if (NULL == pOutputData) { + DPRINTK("%s(): Invalid input parameter - " + "pOutputData is NULL\n", __FUNCTION__); + memset(pDecryptData->pRecipientPrivateKey, 0, + sizeof(CpaCyRsaPrivateKey)); + ICP_CACHE_FREE(drvRSAPrivateKey_zone, + pDecryptData->pRecipientPrivateKey); + memset(pDecryptData, 0, sizeof(CpaCyRsaDecryptOpData)); + ICP_CACHE_FREE(drvRSADecrypt_zone, pDecryptData); + krp->krp_status = ECANCELED; + crypto_kdone(krp); + return; + } + + if (CPA_STATUS_SUCCESS == status) { + krp->krp_status = CRYPTO_OP_SUCCESS; + } else { + APRINTK("%s(): LAC Mod Exp CRT operation failed - " + "Operation Status = %d\n", __FUNCTION__, status); + krp->krp_status = ECANCELED; + } + + icp_ocfDrvSwapBytes(pOutputData->pData, pOutputData->dataLenInBytes); + + icp_ocfDrvFreeFlatBuffer(pOutputData); + memset(pDecryptData->pRecipientPrivateKey, 0, + sizeof(CpaCyRsaPrivateKey)); + ICP_CACHE_FREE(drvRSAPrivateKey_zone, + pDecryptData->pRecipientPrivateKey); + memset(pDecryptData, 0, sizeof(CpaCyRsaDecryptOpData)); + ICP_CACHE_FREE(drvRSADecrypt_zone, pDecryptData); + + crypto_kdone(krp); + + return; +} + +/* Name : icp_ocfDrvDsaRSSignCallBack + * + * Description : When this function returns it signifies that the LAC + * component has completed the DSA RS sign operation. + */ +static void +icp_ocfDrvDsaRSSignCallBack(void *callbackTag, + CpaStatus status, + void *pOpData, + CpaBoolean protocolStatus, + CpaFlatBuffer * pR, CpaFlatBuffer * pS) +{ + struct cryptkop *krp = NULL; + CpaCyDsaRSSignOpData *pSignData = NULL; + + if (NULL == callbackTag) { + DPRINTK("%s(): Invalid input parameters - " + "callbackTag data is NULL\n", __FUNCTION__); + return; + } + + krp = (struct cryptkop *)callbackTag; + + if (NULL == pOpData) { + DPRINTK("%s(): Invalid input parameters - " + "Operation Data is NULL\n", __FUNCTION__); + krp->krp_status = ECANCELED; + crypto_kdone(krp); + return; + } + pSignData = (CpaCyDsaRSSignOpData *) pOpData; + + if (NULL == pR) { + DPRINTK("%s(): Invalid input parameter - " + "pR sign is NULL\n", __FUNCTION__); + icp_ocfDrvFreeFlatBuffer(pS); + ICP_CACHE_FREE(drvDSARSSign_zone, pSignData); + krp->krp_status = ECANCELED; + crypto_kdone(krp); + return; + } + + if (NULL == pS) { + DPRINTK("%s(): Invalid input parameter - " + "pS sign is NULL\n", __FUNCTION__); + icp_ocfDrvFreeFlatBuffer(pR); + ICP_CACHE_FREE(drvDSARSSign_zone, pSignData); + krp->krp_status = ECANCELED; + crypto_kdone(krp); + return; + } + + if (CPA_STATUS_SUCCESS != status) { + APRINTK("%s(): LAC DSA RS Sign operation failed - " + "Operation Status = %d\n", __FUNCTION__, status); + krp->krp_status = ECANCELED; + } else { + krp->krp_status = CRYPTO_OP_SUCCESS; + + if (CPA_TRUE != protocolStatus) { + DPRINTK("%s(): LAC DSA RS Sign operation failed due " + "to protocol error\n", __FUNCTION__); + krp->krp_status = EIO; + } + } + + /* Swap bytes only when the callback status is successful and + protocolStatus is set to true */ + if (CPA_STATUS_SUCCESS == status && CPA_TRUE == protocolStatus) { + icp_ocfDrvSwapBytes(pR->pData, pR->dataLenInBytes); + icp_ocfDrvSwapBytes(pS->pData, pS->dataLenInBytes); + } + + icp_ocfDrvFreeFlatBuffer(pR); + icp_ocfDrvFreeFlatBuffer(pS); + memset(pSignData->K.pData, 0, pSignData->K.dataLenInBytes); + ICP_CACHE_FREE(drvDSARSSignKValue_zone, pSignData->K.pData); + memset(pSignData, 0, sizeof(CpaCyDsaRSSignOpData)); + ICP_CACHE_FREE(drvDSARSSign_zone, pSignData); + crypto_kdone(krp); + + return; +} + +/* Name : icp_ocfDrvDsaVerifyCallback + * + * Description : When this function returns it signifies that the LAC + * component has completed the DSA Verify operation. + */ +static void +icp_ocfDrvDsaVerifyCallBack(void *callbackTag, + CpaStatus status, + void *pOpData, CpaBoolean verifyStatus) +{ + + struct cryptkop *krp = NULL; + CpaCyDsaVerifyOpData *pVerData = NULL; + + if (NULL == callbackTag) { + DPRINTK("%s(): Invalid input parameters - " + "callbackTag data is NULL\n", __FUNCTION__); + return; + } + + krp = (struct cryptkop *)callbackTag; + + if (NULL == pOpData) { + DPRINTK("%s(): Invalid input parameters - " + "Operation Data is NULL\n", __FUNCTION__); + krp->krp_status = ECANCELED; + crypto_kdone(krp); + return; + } + pVerData = (CpaCyDsaVerifyOpData *) pOpData; + + if (CPA_STATUS_SUCCESS != status) { + APRINTK("%s(): LAC DSA Verify operation failed - " + "Operation Status = %d\n", __FUNCTION__, status); + krp->krp_status = ECANCELED; + } else { + krp->krp_status = CRYPTO_OP_SUCCESS; + + if (CPA_TRUE != verifyStatus) { + DPRINTK("%s(): DSA signature invalid\n", __FUNCTION__); + krp->krp_status = EIO; + } + } + + /* Swap bytes only when the callback status is successful and + verifyStatus is set to true */ + /*Just swapping back the key values for now. Possibly all + swapped buffers need to be reverted */ + if (CPA_STATUS_SUCCESS == status && CPA_TRUE == verifyStatus) { + icp_ocfDrvSwapBytes(pVerData->R.pData, + pVerData->R.dataLenInBytes); + icp_ocfDrvSwapBytes(pVerData->S.pData, + pVerData->S.dataLenInBytes); + } + + memset(pVerData, 0, sizeof(CpaCyDsaVerifyOpData)); + ICP_CACHE_FREE(drvDSAVerify_zone, pVerData); + crypto_kdone(krp); + + return; +} diff --git a/target/linux/generic/files/crypto/ocf/ep80579/icp_common.c b/target/linux/generic/files/crypto/ocf/ep80579/icp_common.c new file mode 100644 index 0000000..5d46c0a --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/ep80579/icp_common.c @@ -0,0 +1,773 @@ +/************************************************************************* + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2007,2008,2009 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License 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. + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * Contact Information: + * Intel Corporation + * + * BSD LICENSE + * + * Copyright(c) 2007,2008,2009 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * version: Security.L.1.0.2-229 + * + ***************************************************************************/ + +/* + * An OCF module that uses Intel® QuickAssist Integrated Accelerator to do the + * crypto. + * + * This driver requires the ICP Access Library that is available from Intel in + * order to operate. + */ + +#include "icp_ocf.h" + +#define ICP_OCF_COMP_NAME "ICP_OCF" +#define ICP_OCF_VER_MAIN (2) +#define ICP_OCF_VER_MJR (1) +#define ICP_OCF_VER_MNR (0) + +#define MAX_DEREG_RETRIES (100) +#define DEFAULT_DEREG_RETRIES (10) +#define DEFAULT_DEREG_DELAY_IN_JIFFIES (10) + +/* This defines the maximum number of sessions possible between OCF + and the OCF EP80579 Driver. If set to zero, there is no limit. */ +#define DEFAULT_OCF_TO_DRV_MAX_SESSION_COUNT (0) +#define NUM_SUPPORTED_CAPABILITIES (21) + +/*Slab zone names*/ +#define ICP_SESSION_DATA_NAME "icp_ocf.SesDat" +#define ICP_OP_DATA_NAME "icp_ocf.OpDat" +#define ICP_DH_NAME "icp_ocf.DH" +#define ICP_MODEXP_NAME "icp_ocf.ModExp" +#define ICP_RSA_DECRYPT_NAME "icp_ocf.RSAdec" +#define ICP_RSA_PKEY_NAME "icp_ocf.RSApk" +#define ICP_DSA_SIGN_NAME "icp_ocf.DSAsg" +#define ICP_DSA_VER_NAME "icp_ocf.DSAver" +#define ICP_RAND_VAL_NAME "icp_ocf.DSArnd" +#define ICP_FLAT_BUFF_NAME "icp_ocf.FB" + +/*Slabs zones*/ +icp_kmem_cache drvSessionData_zone = NULL; +icp_kmem_cache drvOpData_zone = NULL; +icp_kmem_cache drvDH_zone = NULL; +icp_kmem_cache drvLnModExp_zone = NULL; +icp_kmem_cache drvRSADecrypt_zone = NULL; +icp_kmem_cache drvRSAPrivateKey_zone = NULL; +icp_kmem_cache drvDSARSSign_zone = NULL; +icp_kmem_cache drvDSARSSignKValue_zone = NULL; +icp_kmem_cache drvDSAVerify_zone = NULL; + +/*Slab zones for flatbuffers and bufferlist*/ +icp_kmem_cache drvFlatBuffer_zone = NULL; + +static inline int icp_cache_null_check(void) +{ + return (drvSessionData_zone && drvOpData_zone + && drvDH_zone && drvLnModExp_zone && drvRSADecrypt_zone + && drvRSAPrivateKey_zone && drvDSARSSign_zone + && drvDSARSSign_zone && drvDSARSSignKValue_zone + && drvDSAVerify_zone && drvFlatBuffer_zone); +} + +/*Function to free all allocated slab caches before exiting the module*/ +static void icp_ocfDrvFreeCaches(void); + +int32_t icp_ocfDrvDriverId = INVALID_DRIVER_ID; + +/* Module parameter - gives the number of times LAC deregistration shall be + re-tried */ +int num_dereg_retries = DEFAULT_DEREG_RETRIES; + +/* Module parameter - gives the delay time in jiffies before a LAC session + shall be attempted to be deregistered again */ +int dereg_retry_delay_in_jiffies = DEFAULT_DEREG_DELAY_IN_JIFFIES; + +/* Module parameter - gives the maximum number of sessions possible between + OCF and the OCF EP80579 Driver. If set to zero, there is no limit.*/ +int max_sessions = DEFAULT_OCF_TO_DRV_MAX_SESSION_COUNT; + +/* This is set when the module is removed from the system, no further + processing can take place if this is set */ +icp_atomic_t icp_ocfDrvIsExiting = ICP_ATOMIC_INIT(0); + +/* This is used to show how many lac sessions were not deregistered*/ +icp_atomic_t lac_session_failed_dereg_count = ICP_ATOMIC_INIT(0); + +/* This is used to track the number of registered sessions between OCF and + * and the OCF EP80579 driver, when max_session is set to value other than + * zero. This ensures that the max_session set for the OCF and the driver + * is equal to the LAC registered sessions */ +icp_atomic_t num_ocf_to_drv_registered_sessions = ICP_ATOMIC_INIT(0); + +/* Head of linked list used to store session data */ +icp_drvSessionListHead_t icp_ocfDrvGlobalSymListHead; +icp_drvSessionListHead_t icp_ocfDrvGlobalSymListHead_FreeMemList; + +icp_spinlock_t icp_ocfDrvSymSessInfoListSpinlock; + +/*Below pointer is only used in linux, FreeBSD uses the name to +create its own variable name*/ +icp_workqueue *icp_ocfDrvFreeLacSessionWorkQ = NULL; +ICP_WORKQUEUE_DEFINE_THREAD(icp_ocfDrvFreeLacSessionWorkQ); + +struct icp_drvBuffListInfo defBuffListInfo; + +/* Name : icp_ocfDrvInit + * + * Description : This function will register all the symmetric and asymmetric + * functionality that will be accelerated by the hardware. It will also + * get a unique driver ID from the OCF and initialise all slab caches + */ +ICP_MODULE_INIT_FUNC(icp_ocfDrvInit) +{ + int ocfStatus = 0; + + IPRINTK("=== %s ver %d.%d.%d ===\n", ICP_OCF_COMP_NAME, + ICP_OCF_VER_MAIN, ICP_OCF_VER_MJR, ICP_OCF_VER_MNR); + + if (MAX_DEREG_RETRIES < num_dereg_retries) { + EPRINTK("Session deregistration retry count set to greater " + "than %d", MAX_DEREG_RETRIES); + icp_module_return_code(EINVAL); + } + + /* Initialize and Start the Cryptographic component */ + if (CPA_STATUS_SUCCESS != + cpaCyStartInstance(CPA_INSTANCE_HANDLE_SINGLE)) { + EPRINTK("Failed to initialize and start the instance " + "of the Cryptographic component.\n"); + return icp_module_return_code(EINVAL); + } + + icp_spin_lock_init(&icp_ocfDrvSymSessInfoListSpinlock); + + /* Set the default size of BufferList to allocate */ + memset(&defBuffListInfo, 0, sizeof(struct icp_drvBuffListInfo)); + if (ICP_OCF_DRV_STATUS_SUCCESS != + icp_ocfDrvBufferListMemInfo(ICP_OCF_DRV_DEFAULT_BUFFLIST_ARRAYS, + &defBuffListInfo)) { + EPRINTK("Failed to get bufferlist memory info.\n"); + return icp_module_return_code(ENOMEM); + } + + /*Register OCF EP80579 Driver with OCF */ + icp_ocfDrvDriverId = ICP_CRYPTO_GET_DRIVERID(); + + if (icp_ocfDrvDriverId < 0) { + EPRINTK("%s : ICP driver failed to register with OCF!\n", + __FUNCTION__); + return icp_module_return_code(ENODEV); + } + + /*Create all the slab caches used by the OCF EP80579 Driver */ + drvSessionData_zone = + ICP_CACHE_CREATE(ICP_SESSION_DATA_NAME, struct icp_drvSessionData); + + /* + * Allocation of the OpData includes the allocation space for meta data. + * The memory after the opData structure is reserved for this meta data. + */ + drvOpData_zone = + icp_kmem_cache_create(ICP_OP_DATA_NAME, + sizeof(struct icp_drvOpData) + + defBuffListInfo.metaSize, + ICP_KERNEL_CACHE_ALIGN, + ICP_KERNEL_CACHE_NOINIT); + + drvDH_zone = ICP_CACHE_CREATE(ICP_DH_NAME, CpaCyDhPhase1KeyGenOpData); + + drvLnModExp_zone = + ICP_CACHE_CREATE(ICP_MODEXP_NAME, CpaCyLnModExpOpData); + + drvRSADecrypt_zone = + ICP_CACHE_CREATE(ICP_RSA_DECRYPT_NAME, CpaCyRsaDecryptOpData); + + drvRSAPrivateKey_zone = + ICP_CACHE_CREATE(ICP_RSA_PKEY_NAME, CpaCyRsaPrivateKey); + + drvDSARSSign_zone = + ICP_CACHE_CREATE(ICP_DSA_SIGN_NAME, CpaCyDsaRSSignOpData); + + /*too awkward to use a macro here */ + drvDSARSSignKValue_zone = + ICP_CACHE_CREATE(ICP_RAND_VAL_NAME, + DSA_RS_SIGN_PRIMEQ_SIZE_IN_BYTES); + + drvDSAVerify_zone = + ICP_CACHE_CREATE(ICP_DSA_VER_NAME, CpaCyDsaVerifyOpData); + + drvFlatBuffer_zone = + ICP_CACHE_CREATE(ICP_FLAT_BUFF_NAME, CpaFlatBuffer); + + if (0 == icp_cache_null_check()) { + icp_ocfDrvFreeCaches(); + EPRINTK("%s() line %d: Not enough memory!\n", + __FUNCTION__, __LINE__); + return ENOMEM; + } + + /* Register the ICP symmetric crypto support. */ + ICP_REG_SYM_WITH_OCF(icp_ocfDrvDriverId, CRYPTO_NULL_CBC, ocfStatus); + ICP_REG_SYM_WITH_OCF(icp_ocfDrvDriverId, CRYPTO_DES_CBC, ocfStatus); + ICP_REG_SYM_WITH_OCF(icp_ocfDrvDriverId, CRYPTO_3DES_CBC, ocfStatus); + ICP_REG_SYM_WITH_OCF(icp_ocfDrvDriverId, CRYPTO_AES_CBC, ocfStatus); + ICP_REG_SYM_WITH_OCF(icp_ocfDrvDriverId, CRYPTO_ARC4, ocfStatus); + ICP_REG_SYM_WITH_OCF(icp_ocfDrvDriverId, CRYPTO_MD5, ocfStatus); + ICP_REG_SYM_WITH_OCF(icp_ocfDrvDriverId, CRYPTO_MD5_HMAC, ocfStatus); + ICP_REG_SYM_WITH_OCF(icp_ocfDrvDriverId, CRYPTO_SHA1, ocfStatus); + ICP_REG_SYM_WITH_OCF(icp_ocfDrvDriverId, CRYPTO_SHA1_HMAC, ocfStatus); + ICP_REG_SYM_WITH_OCF(icp_ocfDrvDriverId, CRYPTO_SHA2_256, ocfStatus); + ICP_REG_SYM_WITH_OCF(icp_ocfDrvDriverId, CRYPTO_SHA2_256_HMAC, + ocfStatus); + ICP_REG_SYM_WITH_OCF(icp_ocfDrvDriverId, CRYPTO_SHA2_384, ocfStatus); + ICP_REG_SYM_WITH_OCF(icp_ocfDrvDriverId, CRYPTO_SHA2_384_HMAC, + ocfStatus); + ICP_REG_SYM_WITH_OCF(icp_ocfDrvDriverId, CRYPTO_SHA2_512, ocfStatus); + ICP_REG_SYM_WITH_OCF(icp_ocfDrvDriverId, CRYPTO_SHA2_512_HMAC, + ocfStatus); + + /* Register the ICP asymmetric algorithm support */ + ICP_REG_ASYM_WITH_OCF(icp_ocfDrvDriverId, CRK_DH_COMPUTE_KEY, + ocfStatus); + ICP_REG_ASYM_WITH_OCF(icp_ocfDrvDriverId, CRK_MOD_EXP, ocfStatus); + ICP_REG_ASYM_WITH_OCF(icp_ocfDrvDriverId, CRK_MOD_EXP_CRT, ocfStatus); + ICP_REG_ASYM_WITH_OCF(icp_ocfDrvDriverId, CRK_DSA_SIGN, ocfStatus); + ICP_REG_ASYM_WITH_OCF(icp_ocfDrvDriverId, CRK_DSA_VERIFY, ocfStatus); + + /* Register the ICP random number generator support */ + ICP_REG_RAND_WITH_OCF(icp_ocfDrvDriverId, + icp_ocfDrvReadRandom, NULL, ocfStatus); + + if (OCF_ZERO_FUNCTIONALITY_REGISTERED == ocfStatus) { + DPRINTK("%s: Failed to register any device capabilities\n", + __FUNCTION__); + icp_ocfDrvFreeCaches(); + icp_ocfDrvDriverId = INVALID_DRIVER_ID; + return icp_module_return_code(ECANCELED); + } + + DPRINTK("%s: Registered %d of %d device capabilities\n", + __FUNCTION__, ocfStatus, NUM_SUPPORTED_CAPABILITIES); + + /*Session data linked list used during module exit */ + ICP_INIT_LIST_HEAD(&icp_ocfDrvGlobalSymListHead); + ICP_INIT_LIST_HEAD(&icp_ocfDrvGlobalSymListHead_FreeMemList); + + ICP_WORKQUEUE_CREATE(icp_ocfDrvFreeLacSessionWorkQ, "icpwq"); + if (ICP_WORKQUEUE_NULL_CHECK(icp_ocfDrvFreeLacSessionWorkQ)) { + EPRINTK("%s: Failed to create single " + "thread workqueue\n", __FUNCTION__); + icp_ocfDrvFreeCaches(); + icp_ocfDrvDriverId = INVALID_DRIVER_ID; + return icp_module_return_code(ENOMEM); + } + + return icp_module_return_code(0); +} + +/* Name : icp_ocfDrvExit + * + * Description : This function will deregister all the symmetric sessions + * registered with the LAC component. It will also deregister all symmetric + * and asymmetric functionality that can be accelerated by the hardware via OCF + * and random number generation if it is enabled. + */ +ICP_MODULE_EXIT_FUNC(icp_ocfDrvExit) +{ + CpaStatus lacStatus = CPA_STATUS_SUCCESS; + struct icp_drvSessionData *sessionData = NULL; + struct icp_drvSessionData *tempSessionData = NULL; + int i, remaining_delay_time_in_jiffies = 0; + + /* For FreeBSD the invariant macro below makes function to return */ + /* with EBUSY value in the case of any session which has been regi- */ + /* stered with LAC not being deregistered. */ + /* The Linux implementation is empty since it is purely to compensate */ + /* for a limitation of the FreeBSD 7.1 Opencrypto framework. */ + + ICP_MODULE_EXIT_INV(); + + /* There is a possibility of a process or new session command being */ + /* sent before this variable is incremented. The aim of this variable */ + /* is to stop a loop of calls creating a deadlock situation which */ + /* would prevent the driver from exiting. */ + icp_atomic_set(&icp_ocfDrvIsExiting, 1); + + /*Existing sessions will be routed to another driver after these calls */ + crypto_unregister_all(icp_ocfDrvDriverId); + crypto_runregister_all(icp_ocfDrvDriverId); + + if (ICP_WORKQUEUE_NULL_CHECK(icp_ocfDrvFreeLacSessionWorkQ)) { + DPRINTK("%s: workqueue already " + "destroyed, therefore module exit " + " function already called. Exiting.\n", __FUNCTION__); + return ICP_MODULE_EXIT_FUNC_RETURN_VAL; + } + /*If any sessions are waiting to be deregistered, do that. This also + flushes the work queue */ + ICP_WORKQUEUE_DESTROY(icp_ocfDrvFreeLacSessionWorkQ); + + /*ENTER CRITICAL SECTION */ + icp_spin_lockbh_lock(&icp_ocfDrvSymSessInfoListSpinlock); + + ICP_LIST_FOR_EACH_ENTRY_SAFE(tempSessionData, sessionData, + &icp_ocfDrvGlobalSymListHead, listNode) { + for (i = 0; i < num_dereg_retries; i++) { + /*No harm if bad input - LAC will handle error cases */ + if (ICP_SESSION_RUNNING == tempSessionData->inUse) { + lacStatus = + cpaCySymRemoveSession + (CPA_INSTANCE_HANDLE_SINGLE, + tempSessionData->sessHandle); + if (CPA_STATUS_SUCCESS == lacStatus) { + /* Succesfully deregistered */ + break; + } else if (CPA_STATUS_RETRY != lacStatus) { + icp_atomic_inc + (&lac_session_failed_dereg_count); + break; + } + + /*schedule_timout returns the time left for completion if + * this task is set to TASK_INTERRUPTIBLE */ + remaining_delay_time_in_jiffies = + dereg_retry_delay_in_jiffies; + while (0 > remaining_delay_time_in_jiffies) { + remaining_delay_time_in_jiffies = + icp_schedule_timeout + (&icp_ocfDrvSymSessInfoListSpinlock, + remaining_delay_time_in_jiffies); + } + + DPRINTK + ("%s(): Retry %d to deregistrate the session\n", + __FUNCTION__, i); + } + } + + /*remove from current list */ + ICP_LIST_DEL(tempSessionData, listNode); + /*add to free mem linked list */ + ICP_LIST_ADD(tempSessionData, + &icp_ocfDrvGlobalSymListHead_FreeMemList, + listNode); + + } + + /*EXIT CRITICAL SECTION */ + icp_spin_lockbh_unlock(&icp_ocfDrvSymSessInfoListSpinlock); + + /*set back to initial values */ + sessionData = NULL; + /*still have a reference in our list! */ + tempSessionData = NULL; + /*free memory */ + + ICP_LIST_FOR_EACH_ENTRY_SAFE(tempSessionData, sessionData, + &icp_ocfDrvGlobalSymListHead_FreeMemList, + listNode) { + + ICP_LIST_DEL(tempSessionData, listNode); + /* Free allocated CpaCySymSessionCtx */ + if (NULL != tempSessionData->sessHandle) { + icp_kfree(tempSessionData->sessHandle); + } + memset(tempSessionData, 0, sizeof(struct icp_drvSessionData)); + ICP_CACHE_FREE(drvSessionData_zone, tempSessionData); + } + + if (0 != icp_atomic_read(&lac_session_failed_dereg_count)) { + DPRINTK("%s(): %d LAC sessions were not deregistered " + "correctly. This is not a clean exit! \n", + __FUNCTION__, + icp_atomic_read(&lac_session_failed_dereg_count)); + } + + icp_ocfDrvFreeCaches(); + icp_ocfDrvDriverId = INVALID_DRIVER_ID; + + icp_spin_lock_destroy(&icp_ocfDrvSymSessInfoListSpinlock); + + /* Shutdown the Cryptographic component */ + lacStatus = cpaCyStopInstance(CPA_INSTANCE_HANDLE_SINGLE); + if (CPA_STATUS_SUCCESS != lacStatus) { + DPRINTK("%s(): Failed to stop instance of the " + "Cryptographic component.(status == %d)\n", + __FUNCTION__, lacStatus); + } + + return ICP_MODULE_EXIT_FUNC_RETURN_VAL; +} + +/* Name : icp_ocfDrvFreeCaches + * + * Description : This function deregisters all slab caches + */ +static void icp_ocfDrvFreeCaches(void) +{ + icp_atomic_set(&icp_ocfDrvIsExiting, 1); + + /*Sym Zones */ + ICP_CACHE_DESTROY(drvSessionData_zone); + ICP_CACHE_DESTROY(drvOpData_zone); + + /*Asym zones */ + ICP_CACHE_DESTROY(drvDH_zone); + ICP_CACHE_DESTROY(drvLnModExp_zone); + ICP_CACHE_DESTROY(drvRSADecrypt_zone); + ICP_CACHE_DESTROY(drvRSAPrivateKey_zone); + ICP_CACHE_DESTROY(drvDSARSSignKValue_zone); + ICP_CACHE_DESTROY(drvDSARSSign_zone); + ICP_CACHE_DESTROY(drvDSAVerify_zone); + + /*FlatBuffer and BufferList Zones */ + ICP_CACHE_DESTROY(drvFlatBuffer_zone); + +} + +/* Name : icp_ocfDrvDeregRetry + * + * Description : This function will try to farm the session deregistration + * off to a work queue. If it fails, nothing more can be done and it + * returns an error + */ +int icp_ocfDrvDeregRetry(CpaCySymSessionCtx sessionToDeregister) +{ + struct icp_ocfDrvFreeLacSession *workstore = NULL; + + DPRINTK("%s(): Retry - Deregistering session (%p)\n", + __FUNCTION__, sessionToDeregister); + + /*make sure the session is not available to be allocated during this + process */ + icp_atomic_inc(&lac_session_failed_dereg_count); + + /*Farm off to work queue */ + workstore = + icp_kmalloc(sizeof(struct icp_ocfDrvFreeLacSession), ICP_M_NOWAIT); + if (NULL == workstore) { + DPRINTK("%s(): unable to free session - no memory available " + "for work queue\n", __FUNCTION__); + return ENOMEM; + } + + workstore->sessionToDeregister = sessionToDeregister; + + icp_init_work(&(workstore->work), + icp_ocfDrvDeferedFreeLacSessionTaskFn, workstore); + + ICP_WORKQUEUE_ENQUEUE(icp_ocfDrvFreeLacSessionWorkQ, + &(workstore->work)); + + return ICP_OCF_DRV_STATUS_SUCCESS; + +} + +/* Name : icp_ocfDrvDeferedFreeLacSessionProcess + * + * Description : This function will retry (module input parameter) + * 'num_dereg_retries' times to deregister any symmetric session that recieves a + * CPA_STATUS_RETRY message from the LAC component. This function is run in + * Thread context because it is called from a worker thread + */ +void icp_ocfDrvDeferedFreeLacSessionProcess(void *arg) +{ + struct icp_ocfDrvFreeLacSession *workstore = NULL; + CpaCySymSessionCtx sessionToDeregister = NULL; + int i = 0; + int remaining_delay_time_in_jiffies = 0; + CpaStatus lacStatus = CPA_STATUS_SUCCESS; + + workstore = (struct icp_ocfDrvFreeLacSession *)arg; + if (NULL == workstore) { + DPRINTK("%s() function called with null parameter \n", + __FUNCTION__); + return; + } + + sessionToDeregister = workstore->sessionToDeregister; + icp_kfree(workstore); + + /*if exiting, give deregistration one more blast only */ + if (icp_atomic_read(&icp_ocfDrvIsExiting) == CPA_TRUE) { + lacStatus = cpaCySymRemoveSession(CPA_INSTANCE_HANDLE_SINGLE, + sessionToDeregister); + + if (lacStatus != CPA_STATUS_SUCCESS) { + DPRINTK("%s() Failed to Dereg LAC session %p " + "during module exit\n", __FUNCTION__, + sessionToDeregister); + return; + } + + icp_atomic_dec(&lac_session_failed_dereg_count); + return; + } + + for (i = 0; i <= num_dereg_retries; i++) { + lacStatus = cpaCySymRemoveSession(CPA_INSTANCE_HANDLE_SINGLE, + sessionToDeregister); + + if (lacStatus == CPA_STATUS_SUCCESS) { + icp_atomic_dec(&lac_session_failed_dereg_count); + return; + } + if (lacStatus != CPA_STATUS_RETRY) { + DPRINTK("%s() Failed to deregister session - lacStatus " + " = %d", __FUNCTION__, lacStatus); + break; + } + + /*schedule_timout returns the time left for completion if this + task is set to TASK_INTERRUPTIBLE */ + remaining_delay_time_in_jiffies = dereg_retry_delay_in_jiffies; + while (0 < remaining_delay_time_in_jiffies) { + remaining_delay_time_in_jiffies = + icp_schedule_timeout(NULL, + remaining_delay_time_in_jiffies); + } + + } + + DPRINTK("%s(): Unable to deregister session\n", __FUNCTION__); + DPRINTK("%s(): Number of unavailable LAC sessions = %d\n", __FUNCTION__, + icp_atomic_read(&lac_session_failed_dereg_count)); +} + +/* Name : icp_ocfDrvPtrAndLenToFlatBuffer + * + * Description : This function converts a "pointer and length" buffer + * structure to Fredericksburg Flat Buffer (CpaFlatBuffer) format. + * + * This function assumes that the data passed in are valid. + */ +inline void +icp_ocfDrvPtrAndLenToFlatBuffer(void *pData, uint32_t len, + CpaFlatBuffer * pFlatBuffer) +{ + pFlatBuffer->pData = pData; + pFlatBuffer->dataLenInBytes = len; +} + +/* Name : icp_ocfDrvPtrAndLenToBufferList + * + * Description : This function converts a "pointer and length" buffer + * structure to Fredericksburg Scatter/Gather Buffer (CpaBufferList) format. + * + * This function assumes that the data passed in are valid. + */ +inline void +icp_ocfDrvPtrAndLenToBufferList(void *pDataIn, uint32_t length, + CpaBufferList * pBufferList) +{ + pBufferList->numBuffers = 1; + pBufferList->pBuffers->pData = pDataIn; + pBufferList->pBuffers->dataLenInBytes = length; +} + +/* Name : icp_ocfDrvBufferListToPtrAndLen + * + * Description : This function converts Fredericksburg Scatter/Gather Buffer + * (CpaBufferList) format to a "pointer and length" buffer structure. + * + * This function assumes that the data passed in are valid. + */ +inline void +icp_ocfDrvBufferListToPtrAndLen(CpaBufferList * pBufferList, + void **ppDataOut, uint32_t * pLength) +{ + *ppDataOut = pBufferList->pBuffers->pData; + *pLength = pBufferList->pBuffers->dataLenInBytes; +} + +/* Name : icp_ocfDrvBufferListMemInfo + * + * Description : This function will set the number of flat buffers in + * bufferlist, the size of memory to allocate for the pPrivateMetaData + * member of the CpaBufferList. + */ +int +icp_ocfDrvBufferListMemInfo(uint16_t numBuffers, + struct icp_drvBuffListInfo *buffListInfo) +{ + buffListInfo->numBuffers = numBuffers; + + if (CPA_STATUS_SUCCESS != + cpaCyBufferListGetMetaSize(CPA_INSTANCE_HANDLE_SINGLE, + buffListInfo->numBuffers, + &(buffListInfo->metaSize))) { + EPRINTK("%s() Failed to get buffer list meta size.\n", + __FUNCTION__); + return ICP_OCF_DRV_STATUS_FAIL; + } + + return ICP_OCF_DRV_STATUS_SUCCESS; +} + +/* Name : icp_ocfDrvFreeFlatBuffer + * + * Description : This function will deallocate flat buffer. + */ +inline void icp_ocfDrvFreeFlatBuffer(CpaFlatBuffer * pFlatBuffer) +{ + if (pFlatBuffer != NULL) { + memset(pFlatBuffer, 0, sizeof(CpaFlatBuffer)); + ICP_CACHE_FREE(drvFlatBuffer_zone, pFlatBuffer); + } +} + +/* Name : icp_ocfDrvAllocMetaData + * + * Description : This function will allocate memory for the + * pPrivateMetaData member of CpaBufferList. + */ +inline int +icp_ocfDrvAllocMetaData(CpaBufferList * pBufferList, + struct icp_drvOpData *pOpData) +{ + Cpa32U metaSize = 0; + + if (pBufferList->numBuffers <= ICP_OCF_DRV_DEFAULT_BUFFLIST_ARRAYS) { + uint8_t *pOpDataStartAddr = (uint8_t *) pOpData; + + if (0 == defBuffListInfo.metaSize) { + pBufferList->pPrivateMetaData = NULL; + return ICP_OCF_DRV_STATUS_SUCCESS; + } + /* + * The meta data allocation has been included as part of the + * op data. It has been pre-allocated in memory just after the + * icp_drvOpData structure. + */ + pBufferList->pPrivateMetaData = (void *)(pOpDataStartAddr + + sizeof(struct + icp_drvOpData)); + } else { + if (CPA_STATUS_SUCCESS != + cpaCyBufferListGetMetaSize(CPA_INSTANCE_HANDLE_SINGLE, + pBufferList->numBuffers, + &metaSize)) { + EPRINTK("%s() Failed to get buffer list meta size.\n", + __FUNCTION__); + return ICP_OCF_DRV_STATUS_FAIL; + } + + if (0 == metaSize) { + pBufferList->pPrivateMetaData = NULL; + return ICP_OCF_DRV_STATUS_SUCCESS; + } + + pBufferList->pPrivateMetaData = + icp_kmalloc(metaSize, ICP_M_NOWAIT); + } + if (NULL == pBufferList->pPrivateMetaData) { + EPRINTK("%s() Failed to allocate pPrivateMetaData.\n", + __FUNCTION__); + return ICP_OCF_DRV_STATUS_FAIL; + } + + return ICP_OCF_DRV_STATUS_SUCCESS; +} + +/* Name : icp_ocfDrvFreeMetaData + * + * Description : This function will deallocate pPrivateMetaData memory. + */ +inline void icp_ocfDrvFreeMetaData(CpaBufferList * pBufferList) +{ + if (NULL == pBufferList->pPrivateMetaData) { + return; + } + + /* + * Only free the meta data if the BufferList has more than + * ICP_OCF_DRV_DEFAULT_BUFFLIST_ARRAYS number of buffers. + * Otherwise, the meta data shall be freed when the icp_drvOpData is + * freed. + */ + if (ICP_OCF_DRV_DEFAULT_BUFFLIST_ARRAYS < pBufferList->numBuffers) { + icp_kfree(pBufferList->pPrivateMetaData); + } +} + +/* Module declaration, init and exit functions */ +ICP_DECLARE_MODULE(icp_ocf, icp_ocfDrvInit, icp_ocfDrvExit); +ICP_MODULE_DESCRIPTION("OCF Driver for Intel Quick Assist crypto acceleration"); +ICP_MODULE_VERSION(icp_ocf, ICP_OCF_VER_MJR); +ICP_MODULE_LICENSE("Dual BSD/GPL"); +ICP_MODULE_AUTHOR("Intel"); + +/* Module parameters */ +ICP_MODULE_PARAM_INT(icp_ocf, num_dereg_retries, + "Number of times to retry LAC Sym Session Deregistration. " + "Default 10, Max 100"); +ICP_MODULE_PARAM_INT(icp_ocf, dereg_retry_delay_in_jiffies, "Delay in jiffies " + "(added to a schedule() function call) before a LAC Sym " + "Session Dereg is retried. Default 10"); +ICP_MODULE_PARAM_INT(icp_ocf, max_sessions, + "This sets the maximum number of sessions " + "between OCF and this driver. If this value is set to zero," + "max session count checking is disabled. Default is zero(0)"); + +/* Module dependencies */ +#define MODULE_MIN_VER 1 +#define CRYPTO_MAX_VER 3 +#define LAC_MAX_VER 2 + +ICP_MODULE_DEPEND(icp_ocf, crypto, MODULE_MIN_VER, MODULE_MIN_VER, + CRYPTO_MAX_VER); +ICP_MODULE_DEPEND(icp_ocf, cryptodev, MODULE_MIN_VER, MODULE_MIN_VER, + CRYPTO_MAX_VER); +ICP_MODULE_DEPEND(icp_ocf, icp_crypto, MODULE_MIN_VER, MODULE_MIN_VER, + LAC_MAX_VER); diff --git a/target/linux/generic/files/crypto/ocf/ep80579/icp_ocf.h b/target/linux/generic/files/crypto/ocf/ep80579/icp_ocf.h new file mode 100644 index 0000000..d9dde87 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/ep80579/icp_ocf.h @@ -0,0 +1,376 @@ +/*************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2007,2008,2009 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License 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. + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * Contact Information: + * Intel Corporation + * + * BSD LICENSE + * + * Copyright(c) 2007,2008,2009 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * version: Security.L.1.0.2-229 + * + ***************************************************************************/ + +/* + * OCF driver header file for the Intel ICP processor. + */ + +#ifndef ICP_OCF_H_ +#define ICP_OCF_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "icp_os.h" + +#define NUM_BITS_IN_BYTE (8) +#define NUM_BITS_IN_BYTE_MINUS_ONE (NUM_BITS_IN_BYTE -1) +#define INVALID_DRIVER_ID (-1) +#define RETURN_RAND_NUM_GEN_FAILED (-1) + +/*This is the max block cipher initialisation vector*/ +#define MAX_IV_LEN_IN_BYTES (20) +/*This is used to check whether the OCF to this driver session limit has + been disabled*/ +#define NO_OCF_TO_DRV_MAX_SESSIONS (0) + +/*OCF values mapped here*/ +#define ICP_SHA1_DIGEST_SIZE_IN_BYTES (SHA1_HASH_LEN) +#define ICP_SHA256_DIGEST_SIZE_IN_BYTES (SHA2_256_HASH_LEN) +#define ICP_SHA384_DIGEST_SIZE_IN_BYTES (SHA2_384_HASH_LEN) +#define ICP_SHA512_DIGEST_SIZE_IN_BYTES (SHA2_512_HASH_LEN) +#define ICP_MD5_DIGEST_SIZE_IN_BYTES (MD5_HASH_LEN) +#define ARC4_COUNTER_LEN (ARC4_BLOCK_LEN) + +#define OCF_REGISTRATION_STATUS_SUCCESS (0) +#define OCF_ZERO_FUNCTIONALITY_REGISTERED (0) +#define ICP_OCF_DRV_NO_CRYPTO_PROCESS_ERROR (0) +#define ICP_OCF_DRV_STATUS_SUCCESS (0) +#define ICP_OCF_DRV_STATUS_FAIL (1) + +/*Turn on/off debug options*/ +#define ICP_OCF_PRINT_DEBUG_MESSAGES (0) +#define ICP_OCF_PRINT_KERN_ALERT (1) +#define ICP_OCF_PRINT_KERN_ERRS (1) + +#if ICP_OCF_PRINT_DEBUG_MESSAGES == 1 +#define DPRINTK(args...) \ +{ \ + ICP_IPRINTK(args); \ +} + +#else //ICP_OCF_PRINT_DEBUG_MESSAGES == 1 + +#define DPRINTK(args...) + +#endif //ICP_OCF_PRINT_DEBUG_MESSAGES == 1 + +#if ICP_OCF_PRINT_KERN_ALERT == 1 +#define APRINTK(args...) \ +{ \ + ICP_APRINTK(args); \ +} + +#else //ICP_OCF_PRINT_KERN_ALERT == 1 + +#define APRINTK(args...) + +#endif //ICP_OCF_PRINT_KERN_ALERT == 1 + +#if ICP_OCF_PRINT_KERN_ERRS == 1 +#define EPRINTK(args...) \ +{ \ + ICP_EPRINTK(args); \ +} + +#else //ICP_OCF_PRINT_KERN_ERRS == 1 + +#define EPRINTK(args...) + +#endif //ICP_OCF_PRINT_KERN_ERRS == 1 + +#define IPRINTK(args...) \ +{ \ + ICP_IPRINTK(args); \ +} + +/*DSA Prime Q size in bytes (as defined in the standard) */ +#define DSA_RS_SIGN_PRIMEQ_SIZE_IN_BYTES (20) + +#define BITS_TO_BYTES(bytes, bits) \ + bytes = (bits + NUM_BITS_IN_BYTE_MINUS_ONE) / NUM_BITS_IN_BYTE + +typedef enum { + ICP_OCF_DRV_ALG_CIPHER = 0, + ICP_OCF_DRV_ALG_HASH +} icp_ocf_drv_alg_type_t; + +typedef ICP_LIST_HEAD(icp_drvSessionListHead_s, + icp_drvSessionData) icp_drvSessionListHead_t; + +/*Values used to derisk chances of performs being called against +deregistered sessions (for which the slab page has been reclaimed) +This is not a fix - since page frames are reclaimed from a slab, one cannot +rely on that memory not being re-used by another app.*/ +typedef enum { + ICP_SESSION_INITIALISED = 0x5C5C5C, + ICP_SESSION_RUNNING = 0x005C00, + ICP_SESSION_DEREGISTERED = 0xC5C5C5 +} usage_derisk; + +/* This struct is required for deferred session + deregistration as a work queue function can + only have one argument*/ +struct icp_ocfDrvFreeLacSession { + CpaCySymSessionCtx sessionToDeregister; + icp_workstruct work; +}; + +/* +This is the OCF<->OCF_DRV session object: + +1.listNode + The first member is a listNode. These session objects are added to a linked + list in order to make it easier to remove them all at session exit time. + +2.inUse + The second member is used to give the session object state and derisk the + possibility of OCF batch calls executing against a deregistered session (as + described above). + +3.sessHandle + The third member is a LAC<->OCF_DRV session handle (initialised with the first + perform request for that session). + +4.lacSessCtx + The fourth is the LAC session context. All the parameters for this structure + are only known when the first perform request for this session occurs. That is + why the OCF EP80579 Driver only registers a new LAC session at perform time +*/ +struct icp_drvSessionData { + ICP_LIST_ENTRY(icp_drvSessionData) listNode; + usage_derisk inUse; + CpaCySymSessionCtx sessHandle; + CpaCySymSessionSetupData lacSessCtx; +}; + +/* These are all defined in icp_common.c */ +extern icp_atomic_t lac_session_failed_dereg_count; +extern icp_atomic_t icp_ocfDrvIsExiting; +extern icp_atomic_t num_ocf_to_drv_registered_sessions; + +extern int32_t icp_ocfDrvDriverId; + +extern icp_drvSessionListHead_t icp_ocfDrvGlobalSymListHead; +extern icp_drvSessionListHead_t icp_ocfDrvGlobalSymListHead_FreeMemList; +extern icp_workqueue *icp_ocfDrvFreeLacSessionWorkQ; +extern icp_spinlock_t icp_ocfDrvSymSessInfoListSpinlock; + +/*Slab zones for symettric functionality, instantiated in icp_common.c*/ +extern icp_kmem_cache drvSessionData_zone; +extern icp_kmem_cache drvOpData_zone; + +/*Slabs zones for asymettric functionality, instantiated in icp_common.c*/ +extern icp_kmem_cache drvDH_zone; +extern icp_kmem_cache drvLnModExp_zone; +extern icp_kmem_cache drvRSADecrypt_zone; +extern icp_kmem_cache drvRSAPrivateKey_zone; +extern icp_kmem_cache drvDSARSSign_zone; +extern icp_kmem_cache drvDSARSSignKValue_zone; +extern icp_kmem_cache drvDSAVerify_zone; + +/* Module parameters defined in icp_cpmmon.c*/ + +/* Module parameters - gives the number of times LAC deregistration shall be + re-tried */ +extern int num_dereg_retries; + +/* Module parameter - gives the delay time in jiffies before a LAC session + shall be attempted to be deregistered again */ +extern int dereg_retry_delay_in_jiffies; + +/* Module parameter - gives the maximum number of sessions possible between + OCF and the OCF EP80579 Driver. If set to zero, there is no limit.*/ +extern int max_sessions; + +/*Slab zones for flatbuffers and bufferlist*/ +extern icp_kmem_cache drvFlatBuffer_zone; + +#define ICP_OCF_DRV_DEFAULT_BUFFLIST_ARRAYS (16) + +struct icp_drvBuffListInfo { + Cpa16U numBuffers; + Cpa32U metaSize; + Cpa32U metaOffset; + Cpa32U buffListSize; +}; + +extern struct icp_drvBuffListInfo defBuffListInfo; + +/* This struct is used to keep a reference to the relevant node in the list + of sessionData structs, to the buffer type required by OCF and to the OCF + provided crp struct that needs to be returned. All this info is needed in + the callback function.*/ +struct icp_drvOpData { + CpaCySymOpData lacOpData; + uint32_t digestSizeInBytes; + struct cryptop *crp; + uint8_t bufferType; + uint8_t ivData[MAX_IV_LEN_IN_BYTES]; + uint16_t numBufferListArray; + CpaBufferList srcBuffer; + CpaFlatBuffer bufferListArray[ICP_OCF_DRV_DEFAULT_BUFFLIST_ARRAYS]; + CpaBoolean verifyResult; +}; + +/* Create a new session between OCF and this driver*/ +int icp_ocfDrvNewSession(icp_device_t dev, uint32_t * sild, + struct cryptoini *cri); + +/* Free a session between this driver and the Quick Assist Framework*/ +int icp_ocfDrvFreeLACSession(icp_device_t dev, uint64_t sid); + +/* Defer freeing a Quick Assist session*/ +void icp_ocfDrvDeferedFreeLacSessionProcess(void *arg); + +/* Process OCF cryptographic request for a symmetric algorithm*/ +int icp_ocfDrvSymProcess(icp_device_t dev, struct cryptop *crp, int hint); + +/* Process OCF cryptographic request for an asymmetric algorithm*/ +int icp_ocfDrvPkeProcess(icp_device_t dev, struct cryptkop *krp, int hint); + +/* Populate a buffer with random data*/ +int icp_ocfDrvReadRandom(void *arg, uint32_t * buf, int maxwords); + +/* Retry Quick Assist session deregistration*/ +int icp_ocfDrvDeregRetry(CpaCySymSessionCtx sessionToDeregister); + +/* Convert an OS scatter gather list to a CPA buffer list*/ +int icp_ocfDrvPacketBuffToBufferList(icp_packet_buffer_t * pPacketBuffer, + CpaBufferList * bufferList); + +/* Convert a CPA buffer list to an OS scatter gather list*/ +int icp_ocfDrvBufferListToPacketBuff(CpaBufferList * bufferList, + icp_packet_buffer_t ** pPacketBuffer); + +/* Get the number of buffers in an OS scatter gather list*/ +uint16_t icp_ocfDrvGetPacketBuffFrags(icp_packet_buffer_t * pPacketBuffer); + +/* Convert a single OS buffer to a CPA Flat Buffer*/ +void icp_ocfDrvSinglePacketBuffToFlatBuffer(icp_packet_buffer_t * pPacketBuffer, + CpaFlatBuffer * pFlatBuffer); + +/* Add pointer and length to a CPA Flat Buffer structure*/ +void icp_ocfDrvPtrAndLenToFlatBuffer(void *pData, uint32_t len, + CpaFlatBuffer * pFlatBuffer); + +/* Convert pointer and length values to a CPA buffer list*/ +void icp_ocfDrvPtrAndLenToBufferList(void *pDataIn, uint32_t length, + CpaBufferList * pBufferList); + +/* Convert a CPA buffer list to pointer and length values*/ +void icp_ocfDrvBufferListToPtrAndLen(CpaBufferList * pBufferList, + void **ppDataOut, uint32_t * pLength); + +/* Set the number of flat buffers in bufferlist and the size of memory + to allocate for the pPrivateMetaData member of the CpaBufferList.*/ +int icp_ocfDrvBufferListMemInfo(uint16_t numBuffers, + struct icp_drvBuffListInfo *buffListInfo); + +/* Find pointer position of the digest within an OS scatter gather list*/ +uint8_t *icp_ocfDrvPacketBufferDigestPointerFind(struct icp_drvOpData + *drvOpData, + int offsetInBytes, + uint32_t digestSizeInBytes); + +/*This top level function is used to find a pointer to where a digest is + stored/needs to be inserted. */ +uint8_t *icp_ocfDrvDigestPointerFind(struct icp_drvOpData *drvOpData, + struct cryptodesc *crp_desc); + +/* Free a CPA flat buffer*/ +void icp_ocfDrvFreeFlatBuffer(CpaFlatBuffer * pFlatBuffer); + +/* This function will allocate memory for the pPrivateMetaData + member of CpaBufferList. */ +int icp_ocfDrvAllocMetaData(CpaBufferList * pBufferList, + struct icp_drvOpData *pOpData); + +/* Free data allocated for the pPrivateMetaData + member of CpaBufferList.*/ +void icp_ocfDrvFreeMetaData(CpaBufferList * pBufferList); + +#define ICP_CACHE_CREATE(cache_ID, cache_name) \ + icp_kmem_cache_create(cache_ID, sizeof(cache_name),ICP_KERNEL_CACHE_ALIGN,\ + ICP_KERNEL_CACHE_NOINIT) + +#define ICP_CACHE_FREE(args...) \ + icp_kmem_cache_free (args) + +#define ICP_CACHE_DESTROY(slab_zone)\ +{\ + if(NULL != slab_zone){\ + icp_kmem_cache_destroy(slab_zone);\ + slab_zone = NULL;\ + }\ +} + +#endif +/* ICP_OCF_H_ */ diff --git a/target/linux/generic/files/crypto/ocf/ep80579/icp_sym.c b/target/linux/generic/files/crypto/ocf/ep80579/icp_sym.c new file mode 100644 index 0000000..e1c7148 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/ep80579/icp_sym.c @@ -0,0 +1,1153 @@ +/*************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2007,2008,2009 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License 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. + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * Contact Information: + * Intel Corporation + * + * BSD LICENSE + * + * Copyright(c) 2007,2008,2009 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * version: Security.L.1.0.2-229 + * + ***************************************************************************/ +/* + * An OCF module that uses the API for Intel® QuickAssist Technology to do the + * cryptography. + * + * This driver requires the ICP Access Library that is available from Intel in + * order to operate. + */ + +#include "icp_ocf.h" + +/*This is the call back function for all symmetric cryptographic processes. + Its main functionality is to free driver crypto operation structure and to + call back to OCF*/ +static void +icp_ocfDrvSymCallBack(void *callbackTag, + CpaStatus status, + const CpaCySymOp operationType, + void *pOpData, + CpaBufferList * pDstBuffer, CpaBoolean verifyResult); + +/*This function is used to extract crypto processing information from the OCF + inputs, so as that it may be passed onto LAC*/ +static int +icp_ocfDrvProcessDataSetup(struct icp_drvOpData *drvOpData, + struct cryptodesc *crp_desc); + +/*This function checks whether the crp_desc argument pertains to a digest or a + cipher operation*/ +static int icp_ocfDrvAlgCheck(struct cryptodesc *crp_desc); + +/*This function copies all the passed in session context information and stores + it in a LAC context structure*/ +static int +icp_ocfDrvAlgorithmSetup(struct cryptoini *cri, + CpaCySymSessionSetupData * lacSessCtx); + +/*This function is used to free an OCF->OCF_DRV session object*/ +static void icp_ocfDrvFreeOCFSession(struct icp_drvSessionData *sessionData); + +/*max IOV buffs supported in a UIO structure*/ +#define NUM_IOV_SUPPORTED (1) + +/* Name : icp_ocfDrvSymCallBack + * + * Description : When this function returns it signifies that the LAC + * component has completed the relevant symmetric operation. + * + * Notes : The callbackTag is a pointer to an icp_drvOpData. This memory + * object was passed to LAC for the cryptographic processing and contains all + * the relevant information for cleaning up buffer handles etc. so that the + * OCF EP80579 Driver portion of this crypto operation can be fully completed. + */ +static void +icp_ocfDrvSymCallBack(void *callbackTag, + CpaStatus status, + const CpaCySymOp operationType, + void *pOpData, + CpaBufferList * pDstBuffer, CpaBoolean verifyResult) +{ + struct cryptop *crp = NULL; + struct icp_drvOpData *temp_drvOpData = + (struct icp_drvOpData *)callbackTag; + uint64_t *tempBasePtr = NULL; + uint32_t tempLen = 0; + + if (NULL == temp_drvOpData) { + DPRINTK("%s(): The callback from the LAC component" + " has failed due to Null userOpaque data" + "(status == %d).\n", __FUNCTION__, status); + DPRINTK("%s(): Unable to call OCF back! \n", __FUNCTION__); + return; + } + + crp = temp_drvOpData->crp; + crp->crp_etype = ICP_OCF_DRV_NO_CRYPTO_PROCESS_ERROR; + + if (NULL == pOpData) { + DPRINTK("%s(): The callback from the LAC component" + " has failed due to Null Symmetric Op data" + "(status == %d).\n", __FUNCTION__, status); + crp->crp_etype = ECANCELED; + crypto_done(crp); + return; + } + + if (NULL == pDstBuffer) { + DPRINTK("%s(): The callback from the LAC component" + " has failed due to Null Dst Bufferlist data" + "(status == %d).\n", __FUNCTION__, status); + crp->crp_etype = ECANCELED; + crypto_done(crp); + return; + } + + if (CPA_STATUS_SUCCESS == status) { + + if (temp_drvOpData->bufferType == ICP_CRYPTO_F_PACKET_BUF) { + if (ICP_OCF_DRV_STATUS_SUCCESS != + icp_ocfDrvBufferListToPacketBuff(pDstBuffer, + (icp_packet_buffer_t + **) + & (crp->crp_buf))) { + EPRINTK("%s(): BufferList to SkBuff " + "conversion error.\n", __FUNCTION__); + crp->crp_etype = EPERM; + } + } else { + icp_ocfDrvBufferListToPtrAndLen(pDstBuffer, + (void **)&tempBasePtr, + &tempLen); + crp->crp_olen = (int)tempLen; + } + + } else { + DPRINTK("%s(): The callback from the LAC component has failed" + "(status == %d).\n", __FUNCTION__, status); + + crp->crp_etype = ECANCELED; + } + + if (temp_drvOpData->numBufferListArray > + ICP_OCF_DRV_DEFAULT_BUFFLIST_ARRAYS) { + icp_kfree(pDstBuffer->pBuffers); + } + icp_ocfDrvFreeMetaData(pDstBuffer); + ICP_CACHE_FREE(drvOpData_zone, temp_drvOpData); + + /* Invoke the OCF callback function */ + crypto_done(crp); + + return; +} + +/* Name : icp_ocfDrvNewSession + * + * Description : This function will create a new Driver<->OCF session + * + * Notes : LAC session registration happens during the first perform call. + * That is the first time we know all information about a given session. + */ +int icp_ocfDrvNewSession(icp_device_t dev, uint32_t * sid, + struct cryptoini *cri) +{ + struct icp_drvSessionData *sessionData = NULL; + uint32_t delete_session = 0; + + /* The SID passed in should be our driver ID. We can return the */ + /* local ID (LID) which is a unique identifier which we can use */ + /* to differentiate between the encrypt/decrypt LAC session handles */ + if (NULL == sid) { + EPRINTK("%s(): Invalid input parameters - NULL sid.\n", + __FUNCTION__); + return EINVAL; + } + + if (NULL == cri) { + EPRINTK("%s(): Invalid input parameters - NULL cryptoini.\n", + __FUNCTION__); + return EINVAL; + } + + if (icp_ocfDrvDriverId != *sid) { + EPRINTK("%s(): Invalid input parameters - bad driver ID\n", + __FUNCTION__); + EPRINTK("\t sid = 0x08%p \n \t cri = 0x08%p \n", sid, cri); + return EINVAL; + } + + sessionData = icp_kmem_cache_zalloc(drvSessionData_zone, ICP_M_NOWAIT); + if (NULL == sessionData) { + DPRINTK("%s():No memory for Session Data\n", __FUNCTION__); + return ENOMEM; + } + + /*ENTER CRITICAL SECTION */ + icp_spin_lockbh_lock(&icp_ocfDrvSymSessInfoListSpinlock); + /*put this check in the spinlock so no new sessions can be added to the + linked list when we are exiting */ + if (CPA_TRUE == icp_atomic_read(&icp_ocfDrvIsExiting)) { + delete_session++; + + } else if (NO_OCF_TO_DRV_MAX_SESSIONS != max_sessions) { + if (icp_atomic_read(&num_ocf_to_drv_registered_sessions) >= + (max_sessions - + icp_atomic_read(&lac_session_failed_dereg_count))) { + delete_session++; + } else { + icp_atomic_inc(&num_ocf_to_drv_registered_sessions); + /* Add to session data linked list */ + ICP_LIST_ADD(sessionData, &icp_ocfDrvGlobalSymListHead, + listNode); + } + + } else if (NO_OCF_TO_DRV_MAX_SESSIONS == max_sessions) { + ICP_LIST_ADD(sessionData, &icp_ocfDrvGlobalSymListHead, + listNode); + } + + sessionData->inUse = ICP_SESSION_INITIALISED; + + /*EXIT CRITICAL SECTION */ + icp_spin_lockbh_unlock(&icp_ocfDrvSymSessInfoListSpinlock); + + if (delete_session) { + DPRINTK("%s():No Session handles available\n", __FUNCTION__); + ICP_CACHE_FREE(drvSessionData_zone, sessionData); + return EPERM; + } + + if (ICP_OCF_DRV_STATUS_SUCCESS != + icp_ocfDrvAlgorithmSetup(cri, &(sessionData->lacSessCtx))) { + DPRINTK("%s():algorithm not supported\n", __FUNCTION__); + icp_ocfDrvFreeOCFSession(sessionData); + return EINVAL; + } + + if (cri->cri_next) { + if (cri->cri_next->cri_next != NULL) { + DPRINTK("%s():only two chained algorithms supported\n", + __FUNCTION__); + icp_ocfDrvFreeOCFSession(sessionData); + return EPERM; + } + + if (ICP_OCF_DRV_STATUS_SUCCESS != + icp_ocfDrvAlgorithmSetup(cri->cri_next, + &(sessionData->lacSessCtx))) { + DPRINTK("%s():second algorithm not supported\n", + __FUNCTION__); + icp_ocfDrvFreeOCFSession(sessionData); + return EINVAL; + } + + sessionData->lacSessCtx.symOperation = + CPA_CY_SYM_OP_ALGORITHM_CHAINING; + } + + *sid = (uint32_t) sessionData; + + return ICP_OCF_DRV_STATUS_SUCCESS; +} + +/* Name : icp_ocfDrvAlgorithmSetup + * + * Description : This function builds the session context data from the + * information supplied through OCF. Algorithm chain order and whether the + * session is Encrypt/Decrypt can only be found out at perform time however, so + * the session is registered with LAC at that time. + */ +static int +icp_ocfDrvAlgorithmSetup(struct cryptoini *cri, + CpaCySymSessionSetupData * lacSessCtx) +{ + + lacSessCtx->sessionPriority = CPA_CY_PRIORITY_NORMAL; + + switch (cri->cri_alg) { + + case CRYPTO_NULL_CBC: + DPRINTK("%s(): NULL CBC\n", __FUNCTION__); + lacSessCtx->symOperation = CPA_CY_SYM_OP_CIPHER; + lacSessCtx->cipherSetupData.cipherAlgorithm = + CPA_CY_SYM_CIPHER_NULL; + lacSessCtx->cipherSetupData.cipherKeyLenInBytes = + cri->cri_klen / NUM_BITS_IN_BYTE; + lacSessCtx->cipherSetupData.pCipherKey = cri->cri_key; + break; + + case CRYPTO_DES_CBC: + DPRINTK("%s(): DES CBC\n", __FUNCTION__); + lacSessCtx->symOperation = CPA_CY_SYM_OP_CIPHER; + lacSessCtx->cipherSetupData.cipherAlgorithm = + CPA_CY_SYM_CIPHER_DES_CBC; + lacSessCtx->cipherSetupData.cipherKeyLenInBytes = + cri->cri_klen / NUM_BITS_IN_BYTE; + lacSessCtx->cipherSetupData.pCipherKey = cri->cri_key; + break; + + case CRYPTO_3DES_CBC: + DPRINTK("%s(): 3DES CBC\n", __FUNCTION__); + lacSessCtx->symOperation = CPA_CY_SYM_OP_CIPHER; + lacSessCtx->cipherSetupData.cipherAlgorithm = + CPA_CY_SYM_CIPHER_3DES_CBC; + lacSessCtx->cipherSetupData.cipherKeyLenInBytes = + cri->cri_klen / NUM_BITS_IN_BYTE; + lacSessCtx->cipherSetupData.pCipherKey = cri->cri_key; + break; + + case CRYPTO_AES_CBC: + DPRINTK("%s(): AES CBC\n", __FUNCTION__); + lacSessCtx->symOperation = CPA_CY_SYM_OP_CIPHER; + lacSessCtx->cipherSetupData.cipherAlgorithm = + CPA_CY_SYM_CIPHER_AES_CBC; + lacSessCtx->cipherSetupData.cipherKeyLenInBytes = + cri->cri_klen / NUM_BITS_IN_BYTE; + lacSessCtx->cipherSetupData.pCipherKey = cri->cri_key; + break; + + case CRYPTO_ARC4: + DPRINTK("%s(): ARC4\n", __FUNCTION__); + lacSessCtx->symOperation = CPA_CY_SYM_OP_CIPHER; + lacSessCtx->cipherSetupData.cipherAlgorithm = + CPA_CY_SYM_CIPHER_ARC4; + lacSessCtx->cipherSetupData.cipherKeyLenInBytes = + cri->cri_klen / NUM_BITS_IN_BYTE; + lacSessCtx->cipherSetupData.pCipherKey = cri->cri_key; + break; + + case CRYPTO_SHA1: + DPRINTK("%s(): SHA1\n", __FUNCTION__); + lacSessCtx->symOperation = CPA_CY_SYM_OP_HASH; + lacSessCtx->hashSetupData.hashAlgorithm = CPA_CY_SYM_HASH_SHA1; + lacSessCtx->hashSetupData.hashMode = CPA_CY_SYM_HASH_MODE_PLAIN; + lacSessCtx->hashSetupData.digestResultLenInBytes = + (cri->cri_mlen ? + cri->cri_mlen : ICP_SHA1_DIGEST_SIZE_IN_BYTES); + + break; + + case CRYPTO_SHA1_HMAC: + DPRINTK("%s(): SHA1_HMAC\n", __FUNCTION__); + lacSessCtx->symOperation = CPA_CY_SYM_OP_HASH; + lacSessCtx->hashSetupData.hashAlgorithm = CPA_CY_SYM_HASH_SHA1; + lacSessCtx->hashSetupData.hashMode = CPA_CY_SYM_HASH_MODE_AUTH; + lacSessCtx->hashSetupData.digestResultLenInBytes = + (cri->cri_mlen ? + cri->cri_mlen : ICP_SHA1_DIGEST_SIZE_IN_BYTES); + lacSessCtx->hashSetupData.authModeSetupData.authKey = + cri->cri_key; + lacSessCtx->hashSetupData.authModeSetupData.authKeyLenInBytes = + cri->cri_klen / NUM_BITS_IN_BYTE; + lacSessCtx->hashSetupData.authModeSetupData.aadLenInBytes = 0; + + break; + + case CRYPTO_SHA2_256: + DPRINTK("%s(): SHA256\n", __FUNCTION__); + lacSessCtx->symOperation = CPA_CY_SYM_OP_HASH; + lacSessCtx->hashSetupData.hashAlgorithm = + CPA_CY_SYM_HASH_SHA256; + lacSessCtx->hashSetupData.hashMode = CPA_CY_SYM_HASH_MODE_PLAIN; + lacSessCtx->hashSetupData.digestResultLenInBytes = + (cri->cri_mlen ? + cri->cri_mlen : ICP_SHA256_DIGEST_SIZE_IN_BYTES); + + break; + + case CRYPTO_SHA2_256_HMAC: + DPRINTK("%s(): SHA256_HMAC\n", __FUNCTION__); + lacSessCtx->symOperation = CPA_CY_SYM_OP_HASH; + lacSessCtx->hashSetupData.hashAlgorithm = + CPA_CY_SYM_HASH_SHA256; + lacSessCtx->hashSetupData.hashMode = CPA_CY_SYM_HASH_MODE_AUTH; + lacSessCtx->hashSetupData.digestResultLenInBytes = + (cri->cri_mlen ? + cri->cri_mlen : ICP_SHA256_DIGEST_SIZE_IN_BYTES); + lacSessCtx->hashSetupData.authModeSetupData.authKey = + cri->cri_key; + lacSessCtx->hashSetupData.authModeSetupData.authKeyLenInBytes = + cri->cri_klen / NUM_BITS_IN_BYTE; + lacSessCtx->hashSetupData.authModeSetupData.aadLenInBytes = 0; + + break; + + case CRYPTO_SHA2_384: + DPRINTK("%s(): SHA384\n", __FUNCTION__); + lacSessCtx->symOperation = CPA_CY_SYM_OP_HASH; + lacSessCtx->hashSetupData.hashAlgorithm = + CPA_CY_SYM_HASH_SHA384; + lacSessCtx->hashSetupData.hashMode = CPA_CY_SYM_HASH_MODE_PLAIN; + lacSessCtx->hashSetupData.digestResultLenInBytes = + (cri->cri_mlen ? + cri->cri_mlen : ICP_SHA384_DIGEST_SIZE_IN_BYTES); + + break; + + case CRYPTO_SHA2_384_HMAC: + DPRINTK("%s(): SHA384_HMAC\n", __FUNCTION__); + lacSessCtx->symOperation = CPA_CY_SYM_OP_HASH; + lacSessCtx->hashSetupData.hashAlgorithm = + CPA_CY_SYM_HASH_SHA384; + lacSessCtx->hashSetupData.hashMode = CPA_CY_SYM_HASH_MODE_AUTH; + lacSessCtx->hashSetupData.digestResultLenInBytes = + (cri->cri_mlen ? + cri->cri_mlen : ICP_SHA384_DIGEST_SIZE_IN_BYTES); + lacSessCtx->hashSetupData.authModeSetupData.authKey = + cri->cri_key; + lacSessCtx->hashSetupData.authModeSetupData.authKeyLenInBytes = + cri->cri_klen / NUM_BITS_IN_BYTE; + lacSessCtx->hashSetupData.authModeSetupData.aadLenInBytes = 0; + + break; + + case CRYPTO_SHA2_512: + DPRINTK("%s(): SHA512\n", __FUNCTION__); + lacSessCtx->symOperation = CPA_CY_SYM_OP_HASH; + lacSessCtx->hashSetupData.hashAlgorithm = + CPA_CY_SYM_HASH_SHA512; + lacSessCtx->hashSetupData.hashMode = CPA_CY_SYM_HASH_MODE_PLAIN; + lacSessCtx->hashSetupData.digestResultLenInBytes = + (cri->cri_mlen ? + cri->cri_mlen : ICP_SHA512_DIGEST_SIZE_IN_BYTES); + + break; + + case CRYPTO_SHA2_512_HMAC: + DPRINTK("%s(): SHA512_HMAC\n", __FUNCTION__); + lacSessCtx->symOperation = CPA_CY_SYM_OP_HASH; + lacSessCtx->hashSetupData.hashAlgorithm = + CPA_CY_SYM_HASH_SHA512; + lacSessCtx->hashSetupData.hashMode = CPA_CY_SYM_HASH_MODE_AUTH; + lacSessCtx->hashSetupData.digestResultLenInBytes = + (cri->cri_mlen ? + cri->cri_mlen : ICP_SHA512_DIGEST_SIZE_IN_BYTES); + lacSessCtx->hashSetupData.authModeSetupData.authKey = + cri->cri_key; + lacSessCtx->hashSetupData.authModeSetupData.authKeyLenInBytes = + cri->cri_klen / NUM_BITS_IN_BYTE; + lacSessCtx->hashSetupData.authModeSetupData.aadLenInBytes = 0; + + break; + + case CRYPTO_MD5: + DPRINTK("%s(): MD5\n", __FUNCTION__); + lacSessCtx->symOperation = CPA_CY_SYM_OP_HASH; + lacSessCtx->hashSetupData.hashAlgorithm = CPA_CY_SYM_HASH_MD5; + lacSessCtx->hashSetupData.hashMode = CPA_CY_SYM_HASH_MODE_PLAIN; + lacSessCtx->hashSetupData.digestResultLenInBytes = + (cri->cri_mlen ? + cri->cri_mlen : ICP_MD5_DIGEST_SIZE_IN_BYTES); + + break; + + case CRYPTO_MD5_HMAC: + DPRINTK("%s(): MD5_HMAC\n", __FUNCTION__); + lacSessCtx->symOperation = CPA_CY_SYM_OP_HASH; + lacSessCtx->hashSetupData.hashAlgorithm = CPA_CY_SYM_HASH_MD5; + lacSessCtx->hashSetupData.hashMode = CPA_CY_SYM_HASH_MODE_AUTH; + lacSessCtx->hashSetupData.digestResultLenInBytes = + (cri->cri_mlen ? + cri->cri_mlen : ICP_MD5_DIGEST_SIZE_IN_BYTES); + lacSessCtx->hashSetupData.authModeSetupData.authKey = + cri->cri_key; + lacSessCtx->hashSetupData.authModeSetupData.authKeyLenInBytes = + cri->cri_klen / NUM_BITS_IN_BYTE; + lacSessCtx->hashSetupData.authModeSetupData.aadLenInBytes = 0; + + break; + + default: + DPRINTK("%s(): ALG Setup FAIL\n", __FUNCTION__); + return ICP_OCF_DRV_STATUS_FAIL; + } + + return ICP_OCF_DRV_STATUS_SUCCESS; +} + +/* Name : icp_ocfDrvFreeOCFSession + * + * Description : This function deletes all existing Session data representing + * the Cryptographic session established between OCF and this driver. This + * also includes freeing the memory allocated for the session context. The + * session object is also removed from the session linked list. + */ +static void icp_ocfDrvFreeOCFSession(struct icp_drvSessionData *sessionData) +{ + + sessionData->inUse = ICP_SESSION_DEREGISTERED; + + /*ENTER CRITICAL SECTION */ + icp_spin_lockbh_lock(&icp_ocfDrvSymSessInfoListSpinlock); + + if (CPA_TRUE == icp_atomic_read(&icp_ocfDrvIsExiting)) { + /*If the Driver is exiting, allow that process to + handle any deletions */ + /*EXIT CRITICAL SECTION */ + icp_spin_lockbh_unlock(&icp_ocfDrvSymSessInfoListSpinlock); + return; + } + + icp_atomic_dec(&num_ocf_to_drv_registered_sessions); + + ICP_LIST_DEL(sessionData, listNode); + + /*EXIT CRITICAL SECTION */ + icp_spin_lockbh_unlock(&icp_ocfDrvSymSessInfoListSpinlock); + + if (NULL != sessionData->sessHandle) { + icp_kfree(sessionData->sessHandle); + } + ICP_CACHE_FREE(drvSessionData_zone, sessionData); +} + +/* Name : icp_ocfDrvFreeLACSession + * + * Description : This attempts to deregister a LAC session. If it fails, the + * deregistation retry function is called. + */ +int icp_ocfDrvFreeLACSession(icp_device_t dev, uint64_t sid) +{ + CpaCySymSessionCtx sessionToDeregister = NULL; + struct icp_drvSessionData *sessionData = NULL; + CpaStatus lacStatus = CPA_STATUS_SUCCESS; + int retval = 0; + + sessionData = (struct icp_drvSessionData *)CRYPTO_SESID2LID(sid); + if (NULL == sessionData) { + EPRINTK("%s(): OCF Free session called with Null Session ID.\n", + __FUNCTION__); + return EINVAL; + } + + sessionToDeregister = sessionData->sessHandle; + + if ((ICP_SESSION_INITIALISED != sessionData->inUse) && + (ICP_SESSION_RUNNING != sessionData->inUse) && + (ICP_SESSION_DEREGISTERED != sessionData->inUse)) { + DPRINTK("%s() Session not initialised.\n", __FUNCTION__); + return EINVAL; + } + + if (ICP_SESSION_RUNNING == sessionData->inUse) { + lacStatus = cpaCySymRemoveSession(CPA_INSTANCE_HANDLE_SINGLE, + sessionToDeregister); + if (CPA_STATUS_RETRY == lacStatus) { + if (ICP_OCF_DRV_STATUS_SUCCESS != + icp_ocfDrvDeregRetry(&sessionToDeregister)) { + /* the retry function increments the + dereg failed count */ + DPRINTK("%s(): LAC failed to deregister the " + "session. (localSessionId= %p)\n", + __FUNCTION__, sessionToDeregister); + retval = EPERM; + } + + } else if (CPA_STATUS_SUCCESS != lacStatus) { + DPRINTK("%s(): LAC failed to deregister the session. " + "localSessionId= %p, lacStatus = %d\n", + __FUNCTION__, sessionToDeregister, lacStatus); + icp_atomic_inc(&lac_session_failed_dereg_count); + retval = EPERM; + } + } else { + DPRINTK("%s() Session not registered with LAC.\n", + __FUNCTION__); + } + + icp_ocfDrvFreeOCFSession(sessionData); + return retval; + +} + +/* Name : icp_ocfDrvAlgCheck + * + * Description : This function checks whether the cryptodesc argument pertains + * to a sym or hash function + */ +static int icp_ocfDrvAlgCheck(struct cryptodesc *crp_desc) +{ + + if (crp_desc->crd_alg == CRYPTO_3DES_CBC || + crp_desc->crd_alg == CRYPTO_AES_CBC || + crp_desc->crd_alg == CRYPTO_DES_CBC || + crp_desc->crd_alg == CRYPTO_NULL_CBC || + crp_desc->crd_alg == CRYPTO_ARC4) { + return ICP_OCF_DRV_ALG_CIPHER; + } + + return ICP_OCF_DRV_ALG_HASH; +} + +/* Name : icp_ocfDrvSymProcess + * + * Description : This function will map symmetric functionality calls from OCF + * to the LAC API. It will also allocate memory to store the session context. + * + * Notes: If it is the first perform call for a given session, then a LAC + * session is registered. After the session is registered, no checks as + * to whether session paramaters have changed (e.g. alg chain order) are + * done. + */ +int icp_ocfDrvSymProcess(icp_device_t dev, struct cryptop *crp, int hint) +{ + struct icp_drvSessionData *sessionData = NULL; + struct icp_drvOpData *drvOpData = NULL; + CpaStatus lacStatus = CPA_STATUS_SUCCESS; + Cpa32U sessionCtxSizeInBytes = 0; + + if (NULL == crp) { + DPRINTK("%s(): Invalid input parameters, cryptop is NULL\n", + __FUNCTION__); + return EINVAL; + } + + if (NULL == crp->crp_desc) { + DPRINTK("%s(): Invalid input parameters, no crp_desc attached " + "to crp\n", __FUNCTION__); + crp->crp_etype = EINVAL; + return EINVAL; + } + + if (NULL == crp->crp_buf) { + DPRINTK("%s(): Invalid input parameters, no buffer attached " + "to crp\n", __FUNCTION__); + crp->crp_etype = EINVAL; + return EINVAL; + } + + if (CPA_TRUE == icp_atomic_read(&icp_ocfDrvIsExiting)) { + crp->crp_etype = EFAULT; + return EFAULT; + } + + sessionData = (struct icp_drvSessionData *) + (CRYPTO_SESID2LID(crp->crp_sid)); + if (NULL == sessionData) { + DPRINTK("%s(): Invalid input parameters, Null Session ID \n", + __FUNCTION__); + crp->crp_etype = EINVAL; + return EINVAL; + } + +/*If we get a request against a deregisted session, cancel operation*/ + if (ICP_SESSION_DEREGISTERED == sessionData->inUse) { + DPRINTK("%s(): Session ID %d was deregistered \n", + __FUNCTION__, (int)(CRYPTO_SESID2LID(crp->crp_sid))); + crp->crp_etype = EFAULT; + return EFAULT; + } + +/*If none of the session states are set, then the session structure was either + not initialised properly or we are reading from a freed memory area (possible + due to OCF batch mode not removing queued requests against deregistered + sessions*/ + if (ICP_SESSION_INITIALISED != sessionData->inUse && + ICP_SESSION_RUNNING != sessionData->inUse) { + DPRINTK("%s(): Session - ID %d - not properly initialised or " + "memory freed back to the kernel \n", + __FUNCTION__, (int)(CRYPTO_SESID2LID(crp->crp_sid))); + crp->crp_etype = EINVAL; + return EINVAL; + } + + /*For the below checks, remember error checking is already done in LAC. + We're not validating inputs subsequent to registration */ + if (sessionData->inUse == ICP_SESSION_INITIALISED) { + DPRINTK("%s(): Initialising session\n", __FUNCTION__); + + if (NULL != crp->crp_desc->crd_next) { + if (ICP_OCF_DRV_ALG_CIPHER == + icp_ocfDrvAlgCheck(crp->crp_desc)) { + + sessionData->lacSessCtx.algChainOrder = + CPA_CY_SYM_ALG_CHAIN_ORDER_CIPHER_THEN_HASH; + + if (crp->crp_desc->crd_flags & CRD_F_ENCRYPT) { + sessionData->lacSessCtx.cipherSetupData. + cipherDirection = + CPA_CY_SYM_CIPHER_DIRECTION_ENCRYPT; + } else { + sessionData->lacSessCtx.cipherSetupData. + cipherDirection = + CPA_CY_SYM_CIPHER_DIRECTION_DECRYPT; + } + } else { + sessionData->lacSessCtx.algChainOrder = + CPA_CY_SYM_ALG_CHAIN_ORDER_HASH_THEN_CIPHER; + + if (crp->crp_desc->crd_next->crd_flags & + CRD_F_ENCRYPT) { + sessionData->lacSessCtx.cipherSetupData. + cipherDirection = + CPA_CY_SYM_CIPHER_DIRECTION_ENCRYPT; + } else { + sessionData->lacSessCtx.cipherSetupData. + cipherDirection = + CPA_CY_SYM_CIPHER_DIRECTION_DECRYPT; + } + + } + + } else if (ICP_OCF_DRV_ALG_CIPHER == + icp_ocfDrvAlgCheck(crp->crp_desc)) { + if (crp->crp_desc->crd_flags & CRD_F_ENCRYPT) { + sessionData->lacSessCtx.cipherSetupData. + cipherDirection = + CPA_CY_SYM_CIPHER_DIRECTION_ENCRYPT; + } else { + sessionData->lacSessCtx.cipherSetupData. + cipherDirection = + CPA_CY_SYM_CIPHER_DIRECTION_DECRYPT; + } + + } + + /*No action required for standalone Auth here */ + + /* Allocate memory for SymSessionCtx before the Session Registration */ + lacStatus = + cpaCySymSessionCtxGetSize(CPA_INSTANCE_HANDLE_SINGLE, + &(sessionData->lacSessCtx), + &sessionCtxSizeInBytes); + if (CPA_STATUS_SUCCESS != lacStatus) { + EPRINTK("%s(): cpaCySymSessionCtxGetSize failed - %d\n", + __FUNCTION__, lacStatus); + crp->crp_etype = EINVAL; + return EINVAL; + } + sessionData->sessHandle = + icp_kmalloc(sessionCtxSizeInBytes, ICP_M_NOWAIT); + if (NULL == sessionData->sessHandle) { + EPRINTK + ("%s(): Failed to get memory for SymSessionCtx\n", + __FUNCTION__); + crp->crp_etype = ENOMEM; + return ENOMEM; + } + + lacStatus = cpaCySymInitSession(CPA_INSTANCE_HANDLE_SINGLE, + icp_ocfDrvSymCallBack, + &(sessionData->lacSessCtx), + sessionData->sessHandle); + + if (CPA_STATUS_SUCCESS != lacStatus) { + EPRINTK("%s(): cpaCySymInitSession failed -%d \n", + __FUNCTION__, lacStatus); + crp->crp_etype = EFAULT; + return EFAULT; + } + + sessionData->inUse = ICP_SESSION_RUNNING; + } + + drvOpData = icp_kmem_cache_zalloc(drvOpData_zone, ICP_M_NOWAIT); + if (NULL == drvOpData) { + EPRINTK("%s():Failed to get memory for drvOpData\n", + __FUNCTION__); + crp->crp_etype = ENOMEM; + return ENOMEM; + } + + drvOpData->lacOpData.pSessionCtx = sessionData->sessHandle; + drvOpData->digestSizeInBytes = sessionData->lacSessCtx.hashSetupData. + digestResultLenInBytes; + drvOpData->crp = crp; + + /* Set the default buffer list array memory allocation */ + drvOpData->srcBuffer.pBuffers = drvOpData->bufferListArray; + drvOpData->numBufferListArray = ICP_OCF_DRV_DEFAULT_BUFFLIST_ARRAYS; + + if (ICP_OCF_DRV_STATUS_SUCCESS != + icp_ocfDrvProcessDataSetup(drvOpData, drvOpData->crp->crp_desc)) { + crp->crp_etype = EINVAL; + goto err; + } + + if (drvOpData->crp->crp_desc->crd_next != NULL) { + if (icp_ocfDrvProcessDataSetup(drvOpData, drvOpData->crp-> + crp_desc->crd_next)) { + crp->crp_etype = EINVAL; + goto err; + } + + } + + /* + * Allocate buffer list array memory if the data fragment is more than + * the default number (ICP_OCF_DRV_DEFAULT_BUFFLIST_ARRAYS) and not + * calculated already + */ + if (crp->crp_flags & ICP_CRYPTO_F_PACKET_BUF) { + if (NULL == drvOpData->lacOpData.pDigestResult) { + drvOpData->numBufferListArray = + icp_ocfDrvGetPacketBuffFrags((icp_packet_buffer_t *) + crp->crp_buf); + } + + if (ICP_OCF_DRV_DEFAULT_BUFFLIST_ARRAYS < + drvOpData->numBufferListArray) { + DPRINTK("%s() numBufferListArray more than default\n", + __FUNCTION__); + drvOpData->srcBuffer.pBuffers = NULL; + drvOpData->srcBuffer.pBuffers = + icp_kmalloc(drvOpData->numBufferListArray * + sizeof(CpaFlatBuffer), ICP_M_NOWAIT); + if (NULL == drvOpData->srcBuffer.pBuffers) { + EPRINTK("%s() Failed to get memory for " + "pBuffers\n", __FUNCTION__); + ICP_CACHE_FREE(drvOpData_zone, drvOpData); + crp->crp_etype = ENOMEM; + return ENOMEM; + } + } + } + + /* + * Check the type of buffer structure we got and convert it into + * CpaBufferList format. + */ + if (crp->crp_flags & ICP_CRYPTO_F_PACKET_BUF) { + if (ICP_OCF_DRV_STATUS_SUCCESS != + icp_ocfDrvPacketBuffToBufferList((icp_packet_buffer_t *) + crp->crp_buf, + &(drvOpData->srcBuffer))) { + EPRINTK("%s():Failed to translate from packet buffer " + "to bufferlist\n", __FUNCTION__); + crp->crp_etype = EINVAL; + goto err; + } + + drvOpData->bufferType = ICP_CRYPTO_F_PACKET_BUF; + } else if (crp->crp_flags & CRYPTO_F_IOV) { + /* OCF only supports IOV of one entry. */ + if (NUM_IOV_SUPPORTED == + ((struct uio *)(crp->crp_buf))->uio_iovcnt) { + + icp_ocfDrvPtrAndLenToBufferList(((struct uio *)(crp-> + crp_buf))-> + uio_iov[0].iov_base, + ((struct uio *)(crp-> + crp_buf))-> + uio_iov[0].iov_len, + &(drvOpData-> + srcBuffer)); + + drvOpData->bufferType = CRYPTO_F_IOV; + + } else { + DPRINTK("%s():Unable to handle IOVs with lengths of " + "greater than one!\n", __FUNCTION__); + crp->crp_etype = EINVAL; + goto err; + } + + } else { + icp_ocfDrvPtrAndLenToBufferList(crp->crp_buf, + crp->crp_ilen, + &(drvOpData->srcBuffer)); + + drvOpData->bufferType = CRYPTO_BUF_CONTIG; + } + + /* Allocate srcBuffer's private meta data */ + if (ICP_OCF_DRV_STATUS_SUCCESS != + icp_ocfDrvAllocMetaData(&(drvOpData->srcBuffer), drvOpData)) { + EPRINTK("%s() icp_ocfDrvAllocMetaData failed\n", __FUNCTION__); + memset(&(drvOpData->lacOpData), 0, sizeof(CpaCySymOpData)); + crp->crp_etype = EINVAL; + goto err; + } + + /* Perform "in-place" crypto operation */ + lacStatus = cpaCySymPerformOp(CPA_INSTANCE_HANDLE_SINGLE, + (void *)drvOpData, + &(drvOpData->lacOpData), + &(drvOpData->srcBuffer), + &(drvOpData->srcBuffer), + &(drvOpData->verifyResult)); + if (CPA_STATUS_RETRY == lacStatus) { + DPRINTK("%s(): cpaCySymPerformOp retry, lacStatus = %d\n", + __FUNCTION__, lacStatus); + memset(&(drvOpData->lacOpData), 0, sizeof(CpaCySymOpData)); + crp->crp_etype = ERESTART; + goto err; + } + if (CPA_STATUS_SUCCESS != lacStatus) { + EPRINTK("%s(): cpaCySymPerformOp failed, lacStatus = %d\n", + __FUNCTION__, lacStatus); + memset(&(drvOpData->lacOpData), 0, sizeof(CpaCySymOpData)); + crp->crp_etype = EINVAL; + goto err; + } + + return 0; //OCF success status value + + err: + if (drvOpData->numBufferListArray > ICP_OCF_DRV_DEFAULT_BUFFLIST_ARRAYS) { + icp_kfree(drvOpData->srcBuffer.pBuffers); + } + icp_ocfDrvFreeMetaData(&(drvOpData->srcBuffer)); + ICP_CACHE_FREE(drvOpData_zone, drvOpData); + + return crp->crp_etype; +} + +/* Name : icp_ocfDrvProcessDataSetup + * + * Description : This function will setup all the cryptographic operation data + * that is required by LAC to execute the operation. + */ +static int icp_ocfDrvProcessDataSetup(struct icp_drvOpData *drvOpData, + struct cryptodesc *crp_desc) +{ + CpaCyRandGenOpData randGenOpData; + CpaFlatBuffer randData; + + drvOpData->lacOpData.packetType = CPA_CY_SYM_PACKET_TYPE_FULL; + + /* Convert from the cryptop to the ICP LAC crypto parameters */ + switch (crp_desc->crd_alg) { + case CRYPTO_NULL_CBC: + drvOpData->lacOpData. + cryptoStartSrcOffsetInBytes = crp_desc->crd_skip; + drvOpData->lacOpData. + messageLenToCipherInBytes = crp_desc->crd_len; + drvOpData->verifyResult = CPA_FALSE; + drvOpData->lacOpData.ivLenInBytes = NULL_BLOCK_LEN; + break; + case CRYPTO_DES_CBC: + drvOpData->lacOpData. + cryptoStartSrcOffsetInBytes = crp_desc->crd_skip; + drvOpData->lacOpData. + messageLenToCipherInBytes = crp_desc->crd_len; + drvOpData->verifyResult = CPA_FALSE; + drvOpData->lacOpData.ivLenInBytes = DES_BLOCK_LEN; + break; + case CRYPTO_3DES_CBC: + drvOpData->lacOpData. + cryptoStartSrcOffsetInBytes = crp_desc->crd_skip; + drvOpData->lacOpData. + messageLenToCipherInBytes = crp_desc->crd_len; + drvOpData->verifyResult = CPA_FALSE; + drvOpData->lacOpData.ivLenInBytes = DES3_BLOCK_LEN; + break; + case CRYPTO_ARC4: + drvOpData->lacOpData. + cryptoStartSrcOffsetInBytes = crp_desc->crd_skip; + drvOpData->lacOpData. + messageLenToCipherInBytes = crp_desc->crd_len; + drvOpData->verifyResult = CPA_FALSE; + drvOpData->lacOpData.ivLenInBytes = ARC4_COUNTER_LEN; + break; + case CRYPTO_AES_CBC: + drvOpData->lacOpData. + cryptoStartSrcOffsetInBytes = crp_desc->crd_skip; + drvOpData->lacOpData. + messageLenToCipherInBytes = crp_desc->crd_len; + drvOpData->verifyResult = CPA_FALSE; + drvOpData->lacOpData.ivLenInBytes = RIJNDAEL128_BLOCK_LEN; + break; + case CRYPTO_SHA1: + case CRYPTO_SHA1_HMAC: + case CRYPTO_SHA2_256: + case CRYPTO_SHA2_256_HMAC: + case CRYPTO_SHA2_384: + case CRYPTO_SHA2_384_HMAC: + case CRYPTO_SHA2_512: + case CRYPTO_SHA2_512_HMAC: + case CRYPTO_MD5: + case CRYPTO_MD5_HMAC: + drvOpData->lacOpData. + hashStartSrcOffsetInBytes = crp_desc->crd_skip; + drvOpData->lacOpData. + messageLenToHashInBytes = crp_desc->crd_len; + drvOpData->lacOpData. + pDigestResult = + icp_ocfDrvDigestPointerFind(drvOpData, crp_desc); + + if (NULL == drvOpData->lacOpData.pDigestResult) { + DPRINTK("%s(): ERROR - could not calculate " + "Digest Result memory address\n", __FUNCTION__); + return ICP_OCF_DRV_STATUS_FAIL; + } + + drvOpData->lacOpData.digestVerify = CPA_FALSE; + break; + default: + DPRINTK("%s(): Crypto process error - algorithm not " + "found \n", __FUNCTION__); + return ICP_OCF_DRV_STATUS_FAIL; + } + + /* Figure out what the IV is supposed to be */ + if ((crp_desc->crd_alg == CRYPTO_DES_CBC) || + (crp_desc->crd_alg == CRYPTO_3DES_CBC) || + (crp_desc->crd_alg == CRYPTO_AES_CBC)) { + /*ARC4 doesn't use an IV */ + if (crp_desc->crd_flags & CRD_F_IV_EXPLICIT) { + /* Explicit IV provided to OCF */ + drvOpData->lacOpData.pIv = crp_desc->crd_iv; + } else { + /* IV is not explicitly provided to OCF */ + + /* Point the LAC OP Data IV pointer to our allocated + storage location for this session. */ + drvOpData->lacOpData.pIv = drvOpData->ivData; + + if ((crp_desc->crd_flags & CRD_F_ENCRYPT) && + ((crp_desc->crd_flags & CRD_F_IV_PRESENT) == 0)) { + + /* Encrypting - need to create IV */ + randGenOpData.generateBits = CPA_TRUE; + randGenOpData.lenInBytes = MAX_IV_LEN_IN_BYTES; + + icp_ocfDrvPtrAndLenToFlatBuffer((Cpa8U *) + drvOpData-> + ivData, + MAX_IV_LEN_IN_BYTES, + &randData); + + if (CPA_STATUS_SUCCESS != + cpaCyRandGen(CPA_INSTANCE_HANDLE_SINGLE, + NULL, NULL, + &randGenOpData, &randData)) { + DPRINTK("%s(): ERROR - Failed to" + " generate" + " Initialisation Vector\n", + __FUNCTION__); + return ICP_OCF_DRV_STATUS_FAIL; + } + + crypto_copyback(drvOpData->crp-> + crp_flags, + drvOpData->crp->crp_buf, + crp_desc->crd_inject, + drvOpData->lacOpData. + ivLenInBytes, + (caddr_t) (drvOpData->lacOpData. + pIv)); + } else { + /* Reading IV from buffer */ + crypto_copydata(drvOpData->crp-> + crp_flags, + drvOpData->crp->crp_buf, + crp_desc->crd_inject, + drvOpData->lacOpData. + ivLenInBytes, + (caddr_t) (drvOpData->lacOpData. + pIv)); + } + + } + + } + + return ICP_OCF_DRV_STATUS_SUCCESS; +} + +/* Name : icp_ocfDrvDigestPointerFind + * + * Description : This function is used to find the memory address of where the + * digest information shall be stored in. Input buffer types are an skbuff, iov + * or flat buffer. The address is found using the buffer data start address and + * an offset. + * + * Note: In the case of a linux skbuff, the digest address may exist within + * a memory space linked to from the start buffer. These linked memory spaces + * must be traversed by the data length offset in order to find the digest start + * address. Whether there is enough space for the digest must also be checked. + */ +uint8_t *icp_ocfDrvDigestPointerFind(struct icp_drvOpData * drvOpData, + struct cryptodesc * crp_desc) +{ + + int offsetInBytes = crp_desc->crd_inject; + uint32_t digestSizeInBytes = drvOpData->digestSizeInBytes; + uint8_t *flat_buffer_base = NULL; + int flat_buffer_length = 0; + + if (drvOpData->crp->crp_flags & ICP_CRYPTO_F_PACKET_BUF) { + + return icp_ocfDrvPacketBufferDigestPointerFind(drvOpData, + offsetInBytes, + digestSizeInBytes); + + } else { + /* IOV or flat buffer */ + if (drvOpData->crp->crp_flags & CRYPTO_F_IOV) { + /*single IOV check has already been done */ + flat_buffer_base = ((struct uio *) + (drvOpData->crp->crp_buf))-> + uio_iov[0].iov_base; + flat_buffer_length = ((struct uio *) + (drvOpData->crp->crp_buf))-> + uio_iov[0].iov_len; + } else { + flat_buffer_base = (uint8_t *) drvOpData->crp->crp_buf; + flat_buffer_length = drvOpData->crp->crp_ilen; + } + + if (flat_buffer_length < (offsetInBytes + digestSizeInBytes)) { + DPRINTK("%s() Not enough space for Digest " + "(IOV/Flat Buffer) \n", __FUNCTION__); + return NULL; + } else { + return (uint8_t *) (flat_buffer_base + offsetInBytes); + } + } + DPRINTK("%s() Should not reach this point\n", __FUNCTION__); + return NULL; +} diff --git a/target/linux/generic/files/crypto/ocf/ep80579/linux_2.6_kernel_space.mk b/target/linux/generic/files/crypto/ocf/ep80579/linux_2.6_kernel_space.mk new file mode 100644 index 0000000..96afa9a --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/ep80579/linux_2.6_kernel_space.mk @@ -0,0 +1,69 @@ +################### +# @par +# This file is provided under a dual BSD/GPLv2 license. When using or +# redistributing this file, you may do so under either license. +# +# GPL LICENSE SUMMARY +# +# Copyright(c) 2007,2008 Intel Corporation. All rights reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of version 2 of the GNU General Public License 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. +# The full GNU General Public License is included in this distribution +# in the file called LICENSE.GPL. +# +# Contact Information: +# Intel Corporation +# +# BSD LICENSE +# +# Copyright(c) 2007,2008 Intel Corporation. All rights reserved. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# +# version: Security.L.1.0.130 +################### + +#specific include directories in kernel space +INCLUDES+=#e.g. -I$(OSAL_DIR)/include \ + +#Extra Flags Specific in kernel space e.g. include path or debug flags etc. e.g to add an include path EXTRA_CFLAGS += -I$(src)/../include +EXTRA_CFLAGS += $(INCLUDES) -O2 -Wall +EXTRA_LDFLAGS +=-whole-archive + diff --git a/target/linux/generic/files/crypto/ocf/hifn/Makefile b/target/linux/generic/files/crypto/ocf/hifn/Makefile new file mode 100644 index 0000000..163fed0 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/hifn/Makefile @@ -0,0 +1,13 @@ +# for SGlinux builds +-include $(ROOTDIR)/modules/.config + +obj-$(CONFIG_OCF_HIFN) += hifn7751.o +obj-$(CONFIG_OCF_HIFNHIPP) += hifnHIPP.o + +obj ?= . +EXTRA_CFLAGS += -I$(obj)/.. -I$(obj)/ + +ifdef TOPDIR +-include $(TOPDIR)/Rules.make +endif + diff --git a/target/linux/generic/files/crypto/ocf/hifn/hifn7751.c b/target/linux/generic/files/crypto/ocf/hifn/hifn7751.c new file mode 100644 index 0000000..3e5cc9b --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/hifn/hifn7751.c @@ -0,0 +1,2954 @@ +/* $OpenBSD: hifn7751.c,v 1.120 2002/05/17 00:33:34 deraadt Exp $ */ + +/*- + * Invertex AEON / Hifn 7751 driver + * Copyright (c) 1999 Invertex Inc. All rights reserved. + * Copyright (c) 1999 Theo de Raadt + * Copyright (c) 2000-2001 Network Security Technologies, Inc. + * http://www.netsec.net + * Copyright (c) 2003 Hifn Inc. + * + * This driver is based on a previous driver by Invertex, for which they + * requested: Please send any comments, feedback, bug-fixes, or feature + * requests to software@invertex.com. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Effort sponsored in part by the Defense Advanced Research Projects + * Agency (DARPA) and Air Force Research Laboratory, Air Force + * Materiel Command, USAF, under agreement number F30602-01-2-0537. + * + * +__FBSDID("$FreeBSD: src/sys/dev/hifn/hifn7751.c,v 1.40 2007/03/21 03:42:49 sam Exp $"); + */ + +/* + * Driver for various Hifn encryption processors. + */ +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) && !defined(AUTOCONF_INCLUDED) +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#if 1 +#define DPRINTF(a...) if (hifn_debug) { \ + printk("%s: ", sc ? \ + device_get_nameunit(sc->sc_dev) : "hifn"); \ + printk(a); \ + } else +#else +#define DPRINTF(a...) +#endif + +static inline int +pci_get_revid(struct pci_dev *dev) +{ + u8 rid = 0; + pci_read_config_byte(dev, PCI_REVISION_ID, &rid); + return rid; +} + +static struct hifn_stats hifnstats; + +#define debug hifn_debug +int hifn_debug = 0; +module_param(hifn_debug, int, 0644); +MODULE_PARM_DESC(hifn_debug, "Enable debug"); + +int hifn_maxbatch = 1; +module_param(hifn_maxbatch, int, 0644); +MODULE_PARM_DESC(hifn_maxbatch, "max ops to batch w/o interrupt"); + +int hifn_cache_linesize = 0x10; +module_param(hifn_cache_linesize, int, 0444); +MODULE_PARM_DESC(hifn_cache_linesize, "PCI config cache line size"); + +#ifdef MODULE_PARM +char *hifn_pllconfig = NULL; +MODULE_PARM(hifn_pllconfig, "s"); +#else +char hifn_pllconfig[32]; /* This setting is RO after loading */ +module_param_string(hifn_pllconfig, hifn_pllconfig, 32, 0444); +#endif +MODULE_PARM_DESC(hifn_pllconfig, "PLL config, ie., pci66, ext33, ..."); + +#ifdef HIFN_VULCANDEV +#include +#include + +static struct cdevsw vulcanpk_cdevsw; /* forward declaration */ +#endif + +/* + * Prototypes and count for the pci_device structure + */ +static int hifn_probe(struct pci_dev *dev, const struct pci_device_id *ent); +static void hifn_remove(struct pci_dev *dev); + +static int hifn_newsession(device_t, u_int32_t *, struct cryptoini *); +static int hifn_freesession(device_t, u_int64_t); +static int hifn_process(device_t, struct cryptop *, int); + +static device_method_t hifn_methods = { + /* crypto device methods */ + DEVMETHOD(cryptodev_newsession, hifn_newsession), + DEVMETHOD(cryptodev_freesession,hifn_freesession), + DEVMETHOD(cryptodev_process, hifn_process), +}; + +static void hifn_reset_board(struct hifn_softc *, int); +static void hifn_reset_puc(struct hifn_softc *); +static void hifn_puc_wait(struct hifn_softc *); +static int hifn_enable_crypto(struct hifn_softc *); +static void hifn_set_retry(struct hifn_softc *sc); +static void hifn_init_dma(struct hifn_softc *); +static void hifn_init_pci_registers(struct hifn_softc *); +static int hifn_sramsize(struct hifn_softc *); +static int hifn_dramsize(struct hifn_softc *); +static int hifn_ramtype(struct hifn_softc *); +static void hifn_sessions(struct hifn_softc *); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19) +static irqreturn_t hifn_intr(int irq, void *arg); +#else +static irqreturn_t hifn_intr(int irq, void *arg, struct pt_regs *regs); +#endif +static u_int hifn_write_command(struct hifn_command *, u_int8_t *); +static u_int32_t hifn_next_signature(u_int32_t a, u_int cnt); +static void hifn_callback(struct hifn_softc *, struct hifn_command *, u_int8_t *); +static int hifn_crypto(struct hifn_softc *, struct hifn_command *, struct cryptop *, int); +static int hifn_readramaddr(struct hifn_softc *, int, u_int8_t *); +static int hifn_writeramaddr(struct hifn_softc *, int, u_int8_t *); +static int hifn_dmamap_load_src(struct hifn_softc *, struct hifn_command *); +static int hifn_dmamap_load_dst(struct hifn_softc *, struct hifn_command *); +static int hifn_init_pubrng(struct hifn_softc *); +static void hifn_tick(unsigned long arg); +static void hifn_abort(struct hifn_softc *); +static void hifn_alloc_slot(struct hifn_softc *, int *, int *, int *, int *); + +static void hifn_write_reg_0(struct hifn_softc *, bus_size_t, u_int32_t); +static void hifn_write_reg_1(struct hifn_softc *, bus_size_t, u_int32_t); + +#ifdef CONFIG_OCF_RANDOMHARVEST +static int hifn_read_random(void *arg, u_int32_t *buf, int len); +#endif + +#define HIFN_MAX_CHIPS 8 +static struct hifn_softc *hifn_chip_idx[HIFN_MAX_CHIPS]; + +static __inline u_int32_t +READ_REG_0(struct hifn_softc *sc, bus_size_t reg) +{ + u_int32_t v = readl(sc->sc_bar0 + reg); + sc->sc_bar0_lastreg = (bus_size_t) -1; + return (v); +} +#define WRITE_REG_0(sc, reg, val) hifn_write_reg_0(sc, reg, val) + +static __inline u_int32_t +READ_REG_1(struct hifn_softc *sc, bus_size_t reg) +{ + u_int32_t v = readl(sc->sc_bar1 + reg); + sc->sc_bar1_lastreg = (bus_size_t) -1; + return (v); +} +#define WRITE_REG_1(sc, reg, val) hifn_write_reg_1(sc, reg, val) + +/* + * map in a given buffer (great on some arches :-) + */ + +static int +pci_map_uio(struct hifn_softc *sc, struct hifn_operand *buf, struct uio *uio) +{ + struct iovec *iov = uio->uio_iov; + + DPRINTF("%s()\n", __FUNCTION__); + + buf->mapsize = 0; + for (buf->nsegs = 0; buf->nsegs < uio->uio_iovcnt; ) { + buf->segs[buf->nsegs].ds_addr = pci_map_single(sc->sc_pcidev, + iov->iov_base, iov->iov_len, + PCI_DMA_BIDIRECTIONAL); + buf->segs[buf->nsegs].ds_len = iov->iov_len; + buf->mapsize += iov->iov_len; + iov++; + buf->nsegs++; + } + /* identify this buffer by the first segment */ + buf->map = (void *) buf->segs[0].ds_addr; + return(0); +} + +/* + * map in a given sk_buff + */ + +static int +pci_map_skb(struct hifn_softc *sc,struct hifn_operand *buf,struct sk_buff *skb) +{ + int i; + + DPRINTF("%s()\n", __FUNCTION__); + + buf->mapsize = 0; + + buf->segs[0].ds_addr = pci_map_single(sc->sc_pcidev, + skb->data, skb_headlen(skb), PCI_DMA_BIDIRECTIONAL); + buf->segs[0].ds_len = skb_headlen(skb); + buf->mapsize += buf->segs[0].ds_len; + + buf->nsegs = 1; + + for (i = 0; i < skb_shinfo(skb)->nr_frags; ) { + buf->segs[buf->nsegs].ds_len = skb_shinfo(skb)->frags[i].size; + buf->segs[buf->nsegs].ds_addr = pci_map_single(sc->sc_pcidev, + page_address(skb_frag_page(&skb_shinfo(skb)->frags[i])) + + skb_shinfo(skb)->frags[i].page_offset, + buf->segs[buf->nsegs].ds_len, PCI_DMA_BIDIRECTIONAL); + buf->mapsize += buf->segs[buf->nsegs].ds_len; + buf->nsegs++; + } + + /* identify this buffer by the first segment */ + buf->map = (void *) buf->segs[0].ds_addr; + return(0); +} + +/* + * map in a given contiguous buffer + */ + +static int +pci_map_buf(struct hifn_softc *sc,struct hifn_operand *buf, void *b, int len) +{ + DPRINTF("%s()\n", __FUNCTION__); + + buf->mapsize = 0; + buf->segs[0].ds_addr = pci_map_single(sc->sc_pcidev, + b, len, PCI_DMA_BIDIRECTIONAL); + buf->segs[0].ds_len = len; + buf->mapsize += buf->segs[0].ds_len; + buf->nsegs = 1; + + /* identify this buffer by the first segment */ + buf->map = (void *) buf->segs[0].ds_addr; + return(0); +} + +#if 0 /* not needed at this time */ +static void +pci_sync_iov(struct hifn_softc *sc, struct hifn_operand *buf) +{ + int i; + + DPRINTF("%s()\n", __FUNCTION__); + for (i = 0; i < buf->nsegs; i++) + pci_dma_sync_single_for_cpu(sc->sc_pcidev, buf->segs[i].ds_addr, + buf->segs[i].ds_len, PCI_DMA_BIDIRECTIONAL); +} +#endif + +static void +pci_unmap_buf(struct hifn_softc *sc, struct hifn_operand *buf) +{ + int i; + DPRINTF("%s()\n", __FUNCTION__); + for (i = 0; i < buf->nsegs; i++) { + pci_unmap_single(sc->sc_pcidev, buf->segs[i].ds_addr, + buf->segs[i].ds_len, PCI_DMA_BIDIRECTIONAL); + buf->segs[i].ds_addr = 0; + buf->segs[i].ds_len = 0; + } + buf->nsegs = 0; + buf->mapsize = 0; + buf->map = 0; +} + +static const char* +hifn_partname(struct hifn_softc *sc) +{ + /* XXX sprintf numbers when not decoded */ + switch (pci_get_vendor(sc->sc_pcidev)) { + case PCI_VENDOR_HIFN: + switch (pci_get_device(sc->sc_pcidev)) { + case PCI_PRODUCT_HIFN_6500: return "Hifn 6500"; + case PCI_PRODUCT_HIFN_7751: return "Hifn 7751"; + case PCI_PRODUCT_HIFN_7811: return "Hifn 7811"; + case PCI_PRODUCT_HIFN_7951: return "Hifn 7951"; + case PCI_PRODUCT_HIFN_7955: return "Hifn 7955"; + case PCI_PRODUCT_HIFN_7956: return "Hifn 7956"; + } + return "Hifn unknown-part"; + case PCI_VENDOR_INVERTEX: + switch (pci_get_device(sc->sc_pcidev)) { + case PCI_PRODUCT_INVERTEX_AEON: return "Invertex AEON"; + } + return "Invertex unknown-part"; + case PCI_VENDOR_NETSEC: + switch (pci_get_device(sc->sc_pcidev)) { + case PCI_PRODUCT_NETSEC_7751: return "NetSec 7751"; + } + return "NetSec unknown-part"; + } + return "Unknown-vendor unknown-part"; +} + +static u_int +checkmaxmin(struct pci_dev *dev, const char *what, u_int v, u_int min, u_int max) +{ + struct hifn_softc *sc = pci_get_drvdata(dev); + if (v > max) { + device_printf(sc->sc_dev, "Warning, %s %u out of range, " + "using max %u\n", what, v, max); + v = max; + } else if (v < min) { + device_printf(sc->sc_dev, "Warning, %s %u out of range, " + "using min %u\n", what, v, min); + v = min; + } + return v; +} + +/* + * Select PLL configuration for 795x parts. This is complicated in + * that we cannot determine the optimal parameters without user input. + * The reference clock is derived from an external clock through a + * multiplier. The external clock is either the host bus (i.e. PCI) + * or an external clock generator. When using the PCI bus we assume + * the clock is either 33 or 66 MHz; for an external source we cannot + * tell the speed. + * + * PLL configuration is done with a string: "pci" for PCI bus, or "ext" + * for an external source, followed by the frequency. We calculate + * the appropriate multiplier and PLL register contents accordingly. + * When no configuration is given we default to "pci66" since that + * always will allow the card to work. If a card is using the PCI + * bus clock and in a 33MHz slot then it will be operating at half + * speed until the correct information is provided. + * + * We use a default setting of "ext66" because according to Mike Ham + * of HiFn, almost every board in existence has an external crystal + * populated at 66Mhz. Using PCI can be a problem on modern motherboards, + * because PCI33 can have clocks from 0 to 33Mhz, and some have + * non-PCI-compliant spread-spectrum clocks, which can confuse the pll. + */ +static void +hifn_getpllconfig(struct pci_dev *dev, u_int *pll) +{ + const char *pllspec = hifn_pllconfig; + u_int freq, mul, fl, fh; + u_int32_t pllconfig; + char *nxt; + + if (pllspec == NULL) + pllspec = "ext66"; + fl = 33, fh = 66; + pllconfig = 0; + if (strncmp(pllspec, "ext", 3) == 0) { + pllspec += 3; + pllconfig |= HIFN_PLL_REF_SEL; + switch (pci_get_device(dev)) { + case PCI_PRODUCT_HIFN_7955: + case PCI_PRODUCT_HIFN_7956: + fl = 20, fh = 100; + break; +#ifdef notyet + case PCI_PRODUCT_HIFN_7954: + fl = 20, fh = 66; + break; +#endif + } + } else if (strncmp(pllspec, "pci", 3) == 0) + pllspec += 3; + freq = strtoul(pllspec, &nxt, 10); + if (nxt == pllspec) + freq = 66; + else + freq = checkmaxmin(dev, "frequency", freq, fl, fh); + /* + * Calculate multiplier. We target a Fck of 266 MHz, + * allowing only even values, possibly rounded down. + * Multipliers > 8 must set the charge pump current. + */ + mul = checkmaxmin(dev, "PLL divisor", (266 / freq) &~ 1, 2, 12); + pllconfig |= (mul / 2 - 1) << HIFN_PLL_ND_SHIFT; + if (mul > 8) + pllconfig |= HIFN_PLL_IS; + *pll = pllconfig; +} + +/* + * Attach an interface that successfully probed. + */ +static int +hifn_probe(struct pci_dev *dev, const struct pci_device_id *ent) +{ + struct hifn_softc *sc = NULL; + char rbase; + u_int16_t ena, rev; + int rseg, rc; + unsigned long mem_start, mem_len; + static int num_chips = 0; + + DPRINTF("%s()\n", __FUNCTION__); + + if (pci_enable_device(dev) < 0) + return(-ENODEV); + + if (pci_set_mwi(dev)) + return(-ENODEV); + + if (!dev->irq) { + printk("hifn: found device with no IRQ assigned. check BIOS settings!"); + pci_disable_device(dev); + return(-ENODEV); + } + + sc = (struct hifn_softc *) kmalloc(sizeof(*sc), GFP_KERNEL); + if (!sc) + return(-ENOMEM); + memset(sc, 0, sizeof(*sc)); + + softc_device_init(sc, "hifn", num_chips, hifn_methods); + + sc->sc_pcidev = dev; + sc->sc_irq = -1; + sc->sc_cid = -1; + sc->sc_num = num_chips++; + if (sc->sc_num < HIFN_MAX_CHIPS) + hifn_chip_idx[sc->sc_num] = sc; + + pci_set_drvdata(sc->sc_pcidev, sc); + + spin_lock_init(&sc->sc_mtx); + + /* XXX handle power management */ + + /* + * The 7951 and 795x have a random number generator and + * public key support; note this. + */ + if (pci_get_vendor(dev) == PCI_VENDOR_HIFN && + (pci_get_device(dev) == PCI_PRODUCT_HIFN_7951 || + pci_get_device(dev) == PCI_PRODUCT_HIFN_7955 || + pci_get_device(dev) == PCI_PRODUCT_HIFN_7956)) + sc->sc_flags = HIFN_HAS_RNG | HIFN_HAS_PUBLIC; + /* + * The 7811 has a random number generator and + * we also note it's identity 'cuz of some quirks. + */ + if (pci_get_vendor(dev) == PCI_VENDOR_HIFN && + pci_get_device(dev) == PCI_PRODUCT_HIFN_7811) + sc->sc_flags |= HIFN_IS_7811 | HIFN_HAS_RNG; + + /* + * The 795x parts support AES. + */ + if (pci_get_vendor(dev) == PCI_VENDOR_HIFN && + (pci_get_device(dev) == PCI_PRODUCT_HIFN_7955 || + pci_get_device(dev) == PCI_PRODUCT_HIFN_7956)) { + sc->sc_flags |= HIFN_IS_7956 | HIFN_HAS_AES; + /* + * Select PLL configuration. This depends on the + * bus and board design and must be manually configured + * if the default setting is unacceptable. + */ + hifn_getpllconfig(dev, &sc->sc_pllconfig); + } + + /* + * Setup PCI resources. Note that we record the bus + * tag and handle for each register mapping, this is + * used by the READ_REG_0, WRITE_REG_0, READ_REG_1, + * and WRITE_REG_1 macros throughout the driver. + */ + mem_start = pci_resource_start(sc->sc_pcidev, 0); + mem_len = pci_resource_len(sc->sc_pcidev, 0); + sc->sc_bar0 = (ocf_iomem_t) ioremap(mem_start, mem_len); + if (!sc->sc_bar0) { + device_printf(sc->sc_dev, "cannot map bar%d register space\n", 0); + goto fail; + } + sc->sc_bar0_lastreg = (bus_size_t) -1; + + mem_start = pci_resource_start(sc->sc_pcidev, 1); + mem_len = pci_resource_len(sc->sc_pcidev, 1); + sc->sc_bar1 = (ocf_iomem_t) ioremap(mem_start, mem_len); + if (!sc->sc_bar1) { + device_printf(sc->sc_dev, "cannot map bar%d register space\n", 1); + goto fail; + } + sc->sc_bar1_lastreg = (bus_size_t) -1; + + /* fix up the bus size */ + if (pci_set_dma_mask(dev, DMA_32BIT_MASK)) { + device_printf(sc->sc_dev, "No usable DMA configuration, aborting.\n"); + goto fail; + } + if (pci_set_consistent_dma_mask(dev, DMA_32BIT_MASK)) { + device_printf(sc->sc_dev, + "No usable consistent DMA configuration, aborting.\n"); + goto fail; + } + + hifn_set_retry(sc); + + /* + * Setup the area where the Hifn DMA's descriptors + * and associated data structures. + */ + sc->sc_dma = (struct hifn_dma *) pci_alloc_consistent(dev, + sizeof(*sc->sc_dma), + &sc->sc_dma_physaddr); + if (!sc->sc_dma) { + device_printf(sc->sc_dev, "cannot alloc sc_dma\n"); + goto fail; + } + bzero(sc->sc_dma, sizeof(*sc->sc_dma)); + + /* + * Reset the board and do the ``secret handshake'' + * to enable the crypto support. Then complete the + * initialization procedure by setting up the interrupt + * and hooking in to the system crypto support so we'll + * get used for system services like the crypto device, + * IPsec, RNG device, etc. + */ + hifn_reset_board(sc, 0); + + if (hifn_enable_crypto(sc) != 0) { + device_printf(sc->sc_dev, "crypto enabling failed\n"); + goto fail; + } + hifn_reset_puc(sc); + + hifn_init_dma(sc); + hifn_init_pci_registers(sc); + + pci_set_master(sc->sc_pcidev); + + /* XXX can't dynamically determine ram type for 795x; force dram */ + if (sc->sc_flags & HIFN_IS_7956) + sc->sc_drammodel = 1; + else if (hifn_ramtype(sc)) + goto fail; + + if (sc->sc_drammodel == 0) + hifn_sramsize(sc); + else + hifn_dramsize(sc); + + /* + * Workaround for NetSec 7751 rev A: half ram size because two + * of the address lines were left floating + */ + if (pci_get_vendor(dev) == PCI_VENDOR_NETSEC && + pci_get_device(dev) == PCI_PRODUCT_NETSEC_7751 && + pci_get_revid(dev) == 0x61) /*XXX???*/ + sc->sc_ramsize >>= 1; + + /* + * Arrange the interrupt line. + */ + rc = request_irq(dev->irq, hifn_intr, IRQF_SHARED, "hifn", sc); + if (rc) { + device_printf(sc->sc_dev, "could not map interrupt: %d\n", rc); + goto fail; + } + sc->sc_irq = dev->irq; + + hifn_sessions(sc); + + /* + * NB: Keep only the low 16 bits; this masks the chip id + * from the 7951. + */ + rev = READ_REG_1(sc, HIFN_1_REVID) & 0xffff; + + rseg = sc->sc_ramsize / 1024; + rbase = 'K'; + if (sc->sc_ramsize >= (1024 * 1024)) { + rbase = 'M'; + rseg /= 1024; + } + device_printf(sc->sc_dev, "%s, rev %u, %d%cB %cram", + hifn_partname(sc), rev, + rseg, rbase, sc->sc_drammodel ? 'd' : 's'); + if (sc->sc_flags & HIFN_IS_7956) + printf(", pll=0x%x<%s clk, %ux mult>", + sc->sc_pllconfig, + sc->sc_pllconfig & HIFN_PLL_REF_SEL ? "ext" : "pci", + 2 + 2*((sc->sc_pllconfig & HIFN_PLL_ND) >> 11)); + printf("\n"); + + sc->sc_cid = crypto_get_driverid(softc_get_device(sc),CRYPTOCAP_F_HARDWARE); + if (sc->sc_cid < 0) { + device_printf(sc->sc_dev, "could not get crypto driver id\n"); + goto fail; + } + + WRITE_REG_0(sc, HIFN_0_PUCNFG, + READ_REG_0(sc, HIFN_0_PUCNFG) | HIFN_PUCNFG_CHIPID); + ena = READ_REG_0(sc, HIFN_0_PUSTAT) & HIFN_PUSTAT_CHIPENA; + + switch (ena) { + case HIFN_PUSTAT_ENA_2: + crypto_register(sc->sc_cid, CRYPTO_3DES_CBC, 0, 0); + crypto_register(sc->sc_cid, CRYPTO_ARC4, 0, 0); + if (sc->sc_flags & HIFN_HAS_AES) + crypto_register(sc->sc_cid, CRYPTO_AES_CBC, 0, 0); + /*FALLTHROUGH*/ + case HIFN_PUSTAT_ENA_1: + crypto_register(sc->sc_cid, CRYPTO_MD5, 0, 0); + crypto_register(sc->sc_cid, CRYPTO_SHA1, 0, 0); + crypto_register(sc->sc_cid, CRYPTO_MD5_HMAC, 0, 0); + crypto_register(sc->sc_cid, CRYPTO_SHA1_HMAC, 0, 0); + crypto_register(sc->sc_cid, CRYPTO_DES_CBC, 0, 0); + break; + } + + if (sc->sc_flags & (HIFN_HAS_PUBLIC | HIFN_HAS_RNG)) + hifn_init_pubrng(sc); + + init_timer(&sc->sc_tickto); + sc->sc_tickto.function = hifn_tick; + sc->sc_tickto.data = (unsigned long) sc->sc_num; + mod_timer(&sc->sc_tickto, jiffies + HZ); + + return (0); + +fail: + if (sc->sc_cid >= 0) + crypto_unregister_all(sc->sc_cid); + if (sc->sc_irq != -1) + free_irq(sc->sc_irq, sc); + if (sc->sc_dma) { + /* Turn off DMA polling */ + WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET | + HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE); + + pci_free_consistent(sc->sc_pcidev, + sizeof(*sc->sc_dma), + sc->sc_dma, sc->sc_dma_physaddr); + } + kfree(sc); + return (-ENXIO); +} + +/* + * Detach an interface that successfully probed. + */ +static void +hifn_remove(struct pci_dev *dev) +{ + struct hifn_softc *sc = pci_get_drvdata(dev); + unsigned long l_flags; + + DPRINTF("%s()\n", __FUNCTION__); + + KASSERT(sc != NULL, ("hifn_detach: null software carrier!")); + + /* disable interrupts */ + HIFN_LOCK(sc); + WRITE_REG_1(sc, HIFN_1_DMA_IER, 0); + HIFN_UNLOCK(sc); + + /*XXX other resources */ + del_timer_sync(&sc->sc_tickto); + + /* Turn off DMA polling */ + WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET | + HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE); + + crypto_unregister_all(sc->sc_cid); + + free_irq(sc->sc_irq, sc); + + pci_free_consistent(sc->sc_pcidev, sizeof(*sc->sc_dma), + sc->sc_dma, sc->sc_dma_physaddr); +} + + +static int +hifn_init_pubrng(struct hifn_softc *sc) +{ + int i; + + DPRINTF("%s()\n", __FUNCTION__); + + if ((sc->sc_flags & HIFN_IS_7811) == 0) { + /* Reset 7951 public key/rng engine */ + WRITE_REG_1(sc, HIFN_1_PUB_RESET, + READ_REG_1(sc, HIFN_1_PUB_RESET) | HIFN_PUBRST_RESET); + + for (i = 0; i < 100; i++) { + DELAY(1000); + if ((READ_REG_1(sc, HIFN_1_PUB_RESET) & + HIFN_PUBRST_RESET) == 0) + break; + } + + if (i == 100) { + device_printf(sc->sc_dev, "public key init failed\n"); + return (1); + } + } + + /* Enable the rng, if available */ +#ifdef CONFIG_OCF_RANDOMHARVEST + if (sc->sc_flags & HIFN_HAS_RNG) { + if (sc->sc_flags & HIFN_IS_7811) { + u_int32_t r; + r = READ_REG_1(sc, HIFN_1_7811_RNGENA); + if (r & HIFN_7811_RNGENA_ENA) { + r &= ~HIFN_7811_RNGENA_ENA; + WRITE_REG_1(sc, HIFN_1_7811_RNGENA, r); + } + WRITE_REG_1(sc, HIFN_1_7811_RNGCFG, + HIFN_7811_RNGCFG_DEFL); + r |= HIFN_7811_RNGENA_ENA; + WRITE_REG_1(sc, HIFN_1_7811_RNGENA, r); + } else + WRITE_REG_1(sc, HIFN_1_RNG_CONFIG, + READ_REG_1(sc, HIFN_1_RNG_CONFIG) | + HIFN_RNGCFG_ENA); + + sc->sc_rngfirst = 1; + crypto_rregister(sc->sc_cid, hifn_read_random, sc); + } +#endif + + /* Enable public key engine, if available */ + if (sc->sc_flags & HIFN_HAS_PUBLIC) { + WRITE_REG_1(sc, HIFN_1_PUB_IEN, HIFN_PUBIEN_DONE); + sc->sc_dmaier |= HIFN_DMAIER_PUBDONE; + WRITE_REG_1(sc, HIFN_1_DMA_IER, sc->sc_dmaier); +#ifdef HIFN_VULCANDEV + sc->sc_pkdev = make_dev(&vulcanpk_cdevsw, 0, + UID_ROOT, GID_WHEEL, 0666, + "vulcanpk"); + sc->sc_pkdev->si_drv1 = sc; +#endif + } + + return (0); +} + +#ifdef CONFIG_OCF_RANDOMHARVEST +static int +hifn_read_random(void *arg, u_int32_t *buf, int len) +{ + struct hifn_softc *sc = (struct hifn_softc *) arg; + u_int32_t sts; + int i, rc = 0; + + if (len <= 0) + return rc; + + if (sc->sc_flags & HIFN_IS_7811) { + /* ONLY VALID ON 7811!!!! */ + for (i = 0; i < 5; i++) { + sts = READ_REG_1(sc, HIFN_1_7811_RNGSTS); + if (sts & HIFN_7811_RNGSTS_UFL) { + device_printf(sc->sc_dev, + "RNG underflow: disabling\n"); + /* DAVIDM perhaps return -1 */ + break; + } + if ((sts & HIFN_7811_RNGSTS_RDY) == 0) + break; + + /* + * There are at least two words in the RNG FIFO + * at this point. + */ + if (rc < len) + buf[rc++] = READ_REG_1(sc, HIFN_1_7811_RNGDAT); + if (rc < len) + buf[rc++] = READ_REG_1(sc, HIFN_1_7811_RNGDAT); + } + } else + buf[rc++] = READ_REG_1(sc, HIFN_1_RNG_DATA); + + /* NB: discard first data read */ + if (sc->sc_rngfirst) { + sc->sc_rngfirst = 0; + rc = 0; + } + + return(rc); +} +#endif /* CONFIG_OCF_RANDOMHARVEST */ + +static void +hifn_puc_wait(struct hifn_softc *sc) +{ + int i; + int reg = HIFN_0_PUCTRL; + + if (sc->sc_flags & HIFN_IS_7956) { + reg = HIFN_0_PUCTRL2; + } + + for (i = 5000; i > 0; i--) { + DELAY(1); + if (!(READ_REG_0(sc, reg) & HIFN_PUCTRL_RESET)) + break; + } + if (!i) + device_printf(sc->sc_dev, "proc unit did not reset(0x%x)\n", + READ_REG_0(sc, HIFN_0_PUCTRL)); +} + +/* + * Reset the processing unit. + */ +static void +hifn_reset_puc(struct hifn_softc *sc) +{ + /* Reset processing unit */ + int reg = HIFN_0_PUCTRL; + + if (sc->sc_flags & HIFN_IS_7956) { + reg = HIFN_0_PUCTRL2; + } + WRITE_REG_0(sc, reg, HIFN_PUCTRL_DMAENA); + + hifn_puc_wait(sc); +} + +/* + * Set the Retry and TRDY registers; note that we set them to + * zero because the 7811 locks up when forced to retry (section + * 3.6 of "Specification Update SU-0014-04". Not clear if we + * should do this for all Hifn parts, but it doesn't seem to hurt. + */ +static void +hifn_set_retry(struct hifn_softc *sc) +{ + DPRINTF("%s()\n", __FUNCTION__); + /* NB: RETRY only responds to 8-bit reads/writes */ + pci_write_config_byte(sc->sc_pcidev, HIFN_RETRY_TIMEOUT, 0); + pci_write_config_byte(sc->sc_pcidev, HIFN_TRDY_TIMEOUT, 0); + /* piggy back the cache line setting here */ + pci_write_config_byte(sc->sc_pcidev, PCI_CACHE_LINE_SIZE, hifn_cache_linesize); +} + +/* + * Resets the board. Values in the regesters are left as is + * from the reset (i.e. initial values are assigned elsewhere). + */ +static void +hifn_reset_board(struct hifn_softc *sc, int full) +{ + u_int32_t reg; + + DPRINTF("%s()\n", __FUNCTION__); + /* + * Set polling in the DMA configuration register to zero. 0x7 avoids + * resetting the board and zeros out the other fields. + */ + WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET | + HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE); + + /* + * Now that polling has been disabled, we have to wait 1 ms + * before resetting the board. + */ + DELAY(1000); + + /* Reset the DMA unit */ + if (full) { + WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MODE); + DELAY(1000); + } else { + WRITE_REG_1(sc, HIFN_1_DMA_CNFG, + HIFN_DMACNFG_MODE | HIFN_DMACNFG_MSTRESET); + hifn_reset_puc(sc); + } + + KASSERT(sc->sc_dma != NULL, ("hifn_reset_board: null DMA tag!")); + bzero(sc->sc_dma, sizeof(*sc->sc_dma)); + + /* Bring dma unit out of reset */ + WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET | + HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE); + + hifn_puc_wait(sc); + hifn_set_retry(sc); + + if (sc->sc_flags & HIFN_IS_7811) { + for (reg = 0; reg < 1000; reg++) { + if (READ_REG_1(sc, HIFN_1_7811_MIPSRST) & + HIFN_MIPSRST_CRAMINIT) + break; + DELAY(1000); + } + if (reg == 1000) + device_printf(sc->sc_dev, ": cram init timeout\n"); + } else { + /* set up DMA configuration register #2 */ + /* turn off all PK and BAR0 swaps */ + WRITE_REG_1(sc, HIFN_1_DMA_CNFG2, + (3 << HIFN_DMACNFG2_INIT_WRITE_BURST_SHIFT)| + (3 << HIFN_DMACNFG2_INIT_READ_BURST_SHIFT)| + (2 << HIFN_DMACNFG2_TGT_WRITE_BURST_SHIFT)| + (2 << HIFN_DMACNFG2_TGT_READ_BURST_SHIFT)); + } +} + +static u_int32_t +hifn_next_signature(u_int32_t a, u_int cnt) +{ + int i; + u_int32_t v; + + for (i = 0; i < cnt; i++) { + + /* get the parity */ + v = a & 0x80080125; + v ^= v >> 16; + v ^= v >> 8; + v ^= v >> 4; + v ^= v >> 2; + v ^= v >> 1; + + a = (v & 1) ^ (a << 1); + } + + return a; +} + + +/* + * Checks to see if crypto is already enabled. If crypto isn't enable, + * "hifn_enable_crypto" is called to enable it. The check is important, + * as enabling crypto twice will lock the board. + */ +static int +hifn_enable_crypto(struct hifn_softc *sc) +{ + u_int32_t dmacfg, ramcfg, encl, addr, i; + char offtbl[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 }; + + DPRINTF("%s()\n", __FUNCTION__); + + ramcfg = READ_REG_0(sc, HIFN_0_PUCNFG); + dmacfg = READ_REG_1(sc, HIFN_1_DMA_CNFG); + + /* + * The RAM config register's encrypt level bit needs to be set before + * every read performed on the encryption level register. + */ + WRITE_REG_0(sc, HIFN_0_PUCNFG, ramcfg | HIFN_PUCNFG_CHIPID); + + encl = READ_REG_0(sc, HIFN_0_PUSTAT) & HIFN_PUSTAT_CHIPENA; + + /* + * Make sure we don't re-unlock. Two unlocks kills chip until the + * next reboot. + */ + if (encl == HIFN_PUSTAT_ENA_1 || encl == HIFN_PUSTAT_ENA_2) { +#ifdef HIFN_DEBUG + if (hifn_debug) + device_printf(sc->sc_dev, + "Strong crypto already enabled!\n"); +#endif + goto report; + } + + if (encl != 0 && encl != HIFN_PUSTAT_ENA_0) { +#ifdef HIFN_DEBUG + if (hifn_debug) + device_printf(sc->sc_dev, + "Unknown encryption level 0x%x\n", encl); +#endif + return 1; + } + + WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_UNLOCK | + HIFN_DMACNFG_MSTRESET | HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE); + DELAY(1000); + addr = READ_REG_1(sc, HIFN_UNLOCK_SECRET1); + DELAY(1000); + WRITE_REG_1(sc, HIFN_UNLOCK_SECRET2, 0); + DELAY(1000); + + for (i = 0; i <= 12; i++) { + addr = hifn_next_signature(addr, offtbl[i] + 0x101); + WRITE_REG_1(sc, HIFN_UNLOCK_SECRET2, addr); + + DELAY(1000); + } + + WRITE_REG_0(sc, HIFN_0_PUCNFG, ramcfg | HIFN_PUCNFG_CHIPID); + encl = READ_REG_0(sc, HIFN_0_PUSTAT) & HIFN_PUSTAT_CHIPENA; + +#ifdef HIFN_DEBUG + if (hifn_debug) { + if (encl != HIFN_PUSTAT_ENA_1 && encl != HIFN_PUSTAT_ENA_2) + device_printf(sc->sc_dev, "Engine is permanently " + "locked until next system reset!\n"); + else + device_printf(sc->sc_dev, "Engine enabled " + "successfully!\n"); + } +#endif + +report: + WRITE_REG_0(sc, HIFN_0_PUCNFG, ramcfg); + WRITE_REG_1(sc, HIFN_1_DMA_CNFG, dmacfg); + + switch (encl) { + case HIFN_PUSTAT_ENA_1: + case HIFN_PUSTAT_ENA_2: + break; + case HIFN_PUSTAT_ENA_0: + default: + device_printf(sc->sc_dev, "disabled\n"); + break; + } + + return 0; +} + +/* + * Give initial values to the registers listed in the "Register Space" + * section of the HIFN Software Development reference manual. + */ +static void +hifn_init_pci_registers(struct hifn_softc *sc) +{ + DPRINTF("%s()\n", __FUNCTION__); + + /* write fixed values needed by the Initialization registers */ + WRITE_REG_0(sc, HIFN_0_PUCTRL, HIFN_PUCTRL_DMAENA); + WRITE_REG_0(sc, HIFN_0_FIFOCNFG, HIFN_FIFOCNFG_THRESHOLD); + WRITE_REG_0(sc, HIFN_0_PUIER, HIFN_PUIER_DSTOVER); + + /* write all 4 ring address registers */ + WRITE_REG_1(sc, HIFN_1_DMA_CRAR, sc->sc_dma_physaddr + + offsetof(struct hifn_dma, cmdr[0])); + WRITE_REG_1(sc, HIFN_1_DMA_SRAR, sc->sc_dma_physaddr + + offsetof(struct hifn_dma, srcr[0])); + WRITE_REG_1(sc, HIFN_1_DMA_DRAR, sc->sc_dma_physaddr + + offsetof(struct hifn_dma, dstr[0])); + WRITE_REG_1(sc, HIFN_1_DMA_RRAR, sc->sc_dma_physaddr + + offsetof(struct hifn_dma, resr[0])); + + DELAY(2000); + + /* write status register */ + WRITE_REG_1(sc, HIFN_1_DMA_CSR, + HIFN_DMACSR_D_CTRL_DIS | HIFN_DMACSR_R_CTRL_DIS | + HIFN_DMACSR_S_CTRL_DIS | HIFN_DMACSR_C_CTRL_DIS | + HIFN_DMACSR_D_ABORT | HIFN_DMACSR_D_DONE | HIFN_DMACSR_D_LAST | + HIFN_DMACSR_D_WAIT | HIFN_DMACSR_D_OVER | + HIFN_DMACSR_R_ABORT | HIFN_DMACSR_R_DONE | HIFN_DMACSR_R_LAST | + HIFN_DMACSR_R_WAIT | HIFN_DMACSR_R_OVER | + HIFN_DMACSR_S_ABORT | HIFN_DMACSR_S_DONE | HIFN_DMACSR_S_LAST | + HIFN_DMACSR_S_WAIT | + HIFN_DMACSR_C_ABORT | HIFN_DMACSR_C_DONE | HIFN_DMACSR_C_LAST | + HIFN_DMACSR_C_WAIT | + HIFN_DMACSR_ENGINE | + ((sc->sc_flags & HIFN_HAS_PUBLIC) ? + HIFN_DMACSR_PUBDONE : 0) | + ((sc->sc_flags & HIFN_IS_7811) ? + HIFN_DMACSR_ILLW | HIFN_DMACSR_ILLR : 0)); + + sc->sc_d_busy = sc->sc_r_busy = sc->sc_s_busy = sc->sc_c_busy = 0; + sc->sc_dmaier |= HIFN_DMAIER_R_DONE | HIFN_DMAIER_C_ABORT | + HIFN_DMAIER_D_OVER | HIFN_DMAIER_R_OVER | + HIFN_DMAIER_S_ABORT | HIFN_DMAIER_D_ABORT | HIFN_DMAIER_R_ABORT | + ((sc->sc_flags & HIFN_IS_7811) ? + HIFN_DMAIER_ILLW | HIFN_DMAIER_ILLR : 0); + sc->sc_dmaier &= ~HIFN_DMAIER_C_WAIT; + WRITE_REG_1(sc, HIFN_1_DMA_IER, sc->sc_dmaier); + + + if (sc->sc_flags & HIFN_IS_7956) { + u_int32_t pll; + + WRITE_REG_0(sc, HIFN_0_PUCNFG, HIFN_PUCNFG_COMPSING | + HIFN_PUCNFG_TCALLPHASES | + HIFN_PUCNFG_TCDRVTOTEM | HIFN_PUCNFG_BUS32); + + /* turn off the clocks and insure bypass is set */ + pll = READ_REG_1(sc, HIFN_1_PLL); + pll = (pll &~ (HIFN_PLL_PK_CLK_SEL | HIFN_PLL_PE_CLK_SEL)) + | HIFN_PLL_BP | HIFN_PLL_MBSET; + WRITE_REG_1(sc, HIFN_1_PLL, pll); + DELAY(10*1000); /* 10ms */ + + /* change configuration */ + pll = (pll &~ HIFN_PLL_CONFIG) | sc->sc_pllconfig; + WRITE_REG_1(sc, HIFN_1_PLL, pll); + DELAY(10*1000); /* 10ms */ + + /* disable bypass */ + pll &= ~HIFN_PLL_BP; + WRITE_REG_1(sc, HIFN_1_PLL, pll); + /* enable clocks with new configuration */ + pll |= HIFN_PLL_PK_CLK_SEL | HIFN_PLL_PE_CLK_SEL; + WRITE_REG_1(sc, HIFN_1_PLL, pll); + } else { + WRITE_REG_0(sc, HIFN_0_PUCNFG, HIFN_PUCNFG_COMPSING | + HIFN_PUCNFG_DRFR_128 | HIFN_PUCNFG_TCALLPHASES | + HIFN_PUCNFG_TCDRVTOTEM | HIFN_PUCNFG_BUS32 | + (sc->sc_drammodel ? HIFN_PUCNFG_DRAM : HIFN_PUCNFG_SRAM)); + } + + WRITE_REG_0(sc, HIFN_0_PUISR, HIFN_PUISR_DSTOVER); + WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET | + HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE | HIFN_DMACNFG_LAST | + ((HIFN_POLL_FREQUENCY << 16 ) & HIFN_DMACNFG_POLLFREQ) | + ((HIFN_POLL_SCALAR << 8) & HIFN_DMACNFG_POLLINVAL)); +} + +/* + * The maximum number of sessions supported by the card + * is dependent on the amount of context ram, which + * encryption algorithms are enabled, and how compression + * is configured. This should be configured before this + * routine is called. + */ +static void +hifn_sessions(struct hifn_softc *sc) +{ + u_int32_t pucnfg; + int ctxsize; + + DPRINTF("%s()\n", __FUNCTION__); + + pucnfg = READ_REG_0(sc, HIFN_0_PUCNFG); + + if (pucnfg & HIFN_PUCNFG_COMPSING) { + if (pucnfg & HIFN_PUCNFG_ENCCNFG) + ctxsize = 128; + else + ctxsize = 512; + /* + * 7955/7956 has internal context memory of 32K + */ + if (sc->sc_flags & HIFN_IS_7956) + sc->sc_maxses = 32768 / ctxsize; + else + sc->sc_maxses = 1 + + ((sc->sc_ramsize - 32768) / ctxsize); + } else + sc->sc_maxses = sc->sc_ramsize / 16384; + + if (sc->sc_maxses > 2048) + sc->sc_maxses = 2048; +} + +/* + * Determine ram type (sram or dram). Board should be just out of a reset + * state when this is called. + */ +static int +hifn_ramtype(struct hifn_softc *sc) +{ + u_int8_t data[8], dataexpect[8]; + int i; + + for (i = 0; i < sizeof(data); i++) + data[i] = dataexpect[i] = 0x55; + if (hifn_writeramaddr(sc, 0, data)) + return (-1); + if (hifn_readramaddr(sc, 0, data)) + return (-1); + if (bcmp(data, dataexpect, sizeof(data)) != 0) { + sc->sc_drammodel = 1; + return (0); + } + + for (i = 0; i < sizeof(data); i++) + data[i] = dataexpect[i] = 0xaa; + if (hifn_writeramaddr(sc, 0, data)) + return (-1); + if (hifn_readramaddr(sc, 0, data)) + return (-1); + if (bcmp(data, dataexpect, sizeof(data)) != 0) { + sc->sc_drammodel = 1; + return (0); + } + + return (0); +} + +#define HIFN_SRAM_MAX (32 << 20) +#define HIFN_SRAM_STEP_SIZE 16384 +#define HIFN_SRAM_GRANULARITY (HIFN_SRAM_MAX / HIFN_SRAM_STEP_SIZE) + +static int +hifn_sramsize(struct hifn_softc *sc) +{ + u_int32_t a; + u_int8_t data[8]; + u_int8_t dataexpect[sizeof(data)]; + int32_t i; + + for (i = 0; i < sizeof(data); i++) + data[i] = dataexpect[i] = i ^ 0x5a; + + for (i = HIFN_SRAM_GRANULARITY - 1; i >= 0; i--) { + a = i * HIFN_SRAM_STEP_SIZE; + bcopy(&i, data, sizeof(i)); + hifn_writeramaddr(sc, a, data); + } + + for (i = 0; i < HIFN_SRAM_GRANULARITY; i++) { + a = i * HIFN_SRAM_STEP_SIZE; + bcopy(&i, dataexpect, sizeof(i)); + if (hifn_readramaddr(sc, a, data) < 0) + return (0); + if (bcmp(data, dataexpect, sizeof(data)) != 0) + return (0); + sc->sc_ramsize = a + HIFN_SRAM_STEP_SIZE; + } + + return (0); +} + +/* + * XXX For dram boards, one should really try all of the + * HIFN_PUCNFG_DSZ_*'s. This just assumes that PUCNFG + * is already set up correctly. + */ +static int +hifn_dramsize(struct hifn_softc *sc) +{ + u_int32_t cnfg; + + if (sc->sc_flags & HIFN_IS_7956) { + /* + * 7955/7956 have a fixed internal ram of only 32K. + */ + sc->sc_ramsize = 32768; + } else { + cnfg = READ_REG_0(sc, HIFN_0_PUCNFG) & + HIFN_PUCNFG_DRAMMASK; + sc->sc_ramsize = 1 << ((cnfg >> 13) + 18); + } + return (0); +} + +static void +hifn_alloc_slot(struct hifn_softc *sc, int *cmdp, int *srcp, int *dstp, int *resp) +{ + struct hifn_dma *dma = sc->sc_dma; + + DPRINTF("%s()\n", __FUNCTION__); + + if (dma->cmdi == HIFN_D_CMD_RSIZE) { + dma->cmdi = 0; + dma->cmdr[HIFN_D_CMD_RSIZE].l = htole32(HIFN_D_JUMP|HIFN_D_MASKDONEIRQ); + wmb(); + dma->cmdr[HIFN_D_CMD_RSIZE].l |= htole32(HIFN_D_VALID); + HIFN_CMDR_SYNC(sc, HIFN_D_CMD_RSIZE, + BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); + } + *cmdp = dma->cmdi++; + dma->cmdk = dma->cmdi; + + if (dma->srci == HIFN_D_SRC_RSIZE) { + dma->srci = 0; + dma->srcr[HIFN_D_SRC_RSIZE].l = htole32(HIFN_D_JUMP|HIFN_D_MASKDONEIRQ); + wmb(); + dma->srcr[HIFN_D_SRC_RSIZE].l |= htole32(HIFN_D_VALID); + HIFN_SRCR_SYNC(sc, HIFN_D_SRC_RSIZE, + BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); + } + *srcp = dma->srci++; + dma->srck = dma->srci; + + if (dma->dsti == HIFN_D_DST_RSIZE) { + dma->dsti = 0; + dma->dstr[HIFN_D_DST_RSIZE].l = htole32(HIFN_D_JUMP|HIFN_D_MASKDONEIRQ); + wmb(); + dma->dstr[HIFN_D_DST_RSIZE].l |= htole32(HIFN_D_VALID); + HIFN_DSTR_SYNC(sc, HIFN_D_DST_RSIZE, + BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); + } + *dstp = dma->dsti++; + dma->dstk = dma->dsti; + + if (dma->resi == HIFN_D_RES_RSIZE) { + dma->resi = 0; + dma->resr[HIFN_D_RES_RSIZE].l = htole32(HIFN_D_JUMP|HIFN_D_MASKDONEIRQ); + wmb(); + dma->resr[HIFN_D_RES_RSIZE].l |= htole32(HIFN_D_VALID); + HIFN_RESR_SYNC(sc, HIFN_D_RES_RSIZE, + BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); + } + *resp = dma->resi++; + dma->resk = dma->resi; +} + +static int +hifn_writeramaddr(struct hifn_softc *sc, int addr, u_int8_t *data) +{ + struct hifn_dma *dma = sc->sc_dma; + hifn_base_command_t wc; + const u_int32_t masks = HIFN_D_VALID | HIFN_D_LAST | HIFN_D_MASKDONEIRQ; + int r, cmdi, resi, srci, dsti; + + DPRINTF("%s()\n", __FUNCTION__); + + wc.masks = htole16(3 << 13); + wc.session_num = htole16(addr >> 14); + wc.total_source_count = htole16(8); + wc.total_dest_count = htole16(addr & 0x3fff); + + hifn_alloc_slot(sc, &cmdi, &srci, &dsti, &resi); + + WRITE_REG_1(sc, HIFN_1_DMA_CSR, + HIFN_DMACSR_C_CTRL_ENA | HIFN_DMACSR_S_CTRL_ENA | + HIFN_DMACSR_D_CTRL_ENA | HIFN_DMACSR_R_CTRL_ENA); + + /* build write command */ + bzero(dma->command_bufs[cmdi], HIFN_MAX_COMMAND); + *(hifn_base_command_t *)dma->command_bufs[cmdi] = wc; + bcopy(data, &dma->test_src, sizeof(dma->test_src)); + + dma->srcr[srci].p = htole32(sc->sc_dma_physaddr + + offsetof(struct hifn_dma, test_src)); + dma->dstr[dsti].p = htole32(sc->sc_dma_physaddr + + offsetof(struct hifn_dma, test_dst)); + + dma->cmdr[cmdi].l = htole32(16 | masks); + dma->srcr[srci].l = htole32(8 | masks); + dma->dstr[dsti].l = htole32(4 | masks); + dma->resr[resi].l = htole32(4 | masks); + + for (r = 10000; r >= 0; r--) { + DELAY(10); + if ((dma->resr[resi].l & htole32(HIFN_D_VALID)) == 0) + break; + } + if (r == 0) { + device_printf(sc->sc_dev, "writeramaddr -- " + "result[%d](addr %d) still valid\n", resi, addr); + r = -1; + return (-1); + } else + r = 0; + + WRITE_REG_1(sc, HIFN_1_DMA_CSR, + HIFN_DMACSR_C_CTRL_DIS | HIFN_DMACSR_S_CTRL_DIS | + HIFN_DMACSR_D_CTRL_DIS | HIFN_DMACSR_R_CTRL_DIS); + + return (r); +} + +static int +hifn_readramaddr(struct hifn_softc *sc, int addr, u_int8_t *data) +{ + struct hifn_dma *dma = sc->sc_dma; + hifn_base_command_t rc; + const u_int32_t masks = HIFN_D_VALID | HIFN_D_LAST | HIFN_D_MASKDONEIRQ; + int r, cmdi, srci, dsti, resi; + + DPRINTF("%s()\n", __FUNCTION__); + + rc.masks = htole16(2 << 13); + rc.session_num = htole16(addr >> 14); + rc.total_source_count = htole16(addr & 0x3fff); + rc.total_dest_count = htole16(8); + + hifn_alloc_slot(sc, &cmdi, &srci, &dsti, &resi); + + WRITE_REG_1(sc, HIFN_1_DMA_CSR, + HIFN_DMACSR_C_CTRL_ENA | HIFN_DMACSR_S_CTRL_ENA | + HIFN_DMACSR_D_CTRL_ENA | HIFN_DMACSR_R_CTRL_ENA); + + bzero(dma->command_bufs[cmdi], HIFN_MAX_COMMAND); + *(hifn_base_command_t *)dma->command_bufs[cmdi] = rc; + + dma->srcr[srci].p = htole32(sc->sc_dma_physaddr + + offsetof(struct hifn_dma, test_src)); + dma->test_src = 0; + dma->dstr[dsti].p = htole32(sc->sc_dma_physaddr + + offsetof(struct hifn_dma, test_dst)); + dma->test_dst = 0; + dma->cmdr[cmdi].l = htole32(8 | masks); + dma->srcr[srci].l = htole32(8 | masks); + dma->dstr[dsti].l = htole32(8 | masks); + dma->resr[resi].l = htole32(HIFN_MAX_RESULT | masks); + + for (r = 10000; r >= 0; r--) { + DELAY(10); + if ((dma->resr[resi].l & htole32(HIFN_D_VALID)) == 0) + break; + } + if (r == 0) { + device_printf(sc->sc_dev, "readramaddr -- " + "result[%d](addr %d) still valid\n", resi, addr); + r = -1; + } else { + r = 0; + bcopy(&dma->test_dst, data, sizeof(dma->test_dst)); + } + + WRITE_REG_1(sc, HIFN_1_DMA_CSR, + HIFN_DMACSR_C_CTRL_DIS | HIFN_DMACSR_S_CTRL_DIS | + HIFN_DMACSR_D_CTRL_DIS | HIFN_DMACSR_R_CTRL_DIS); + + return (r); +} + +/* + * Initialize the descriptor rings. + */ +static void +hifn_init_dma(struct hifn_softc *sc) +{ + struct hifn_dma *dma = sc->sc_dma; + int i; + + DPRINTF("%s()\n", __FUNCTION__); + + hifn_set_retry(sc); + + /* initialize static pointer values */ + for (i = 0; i < HIFN_D_CMD_RSIZE; i++) + dma->cmdr[i].p = htole32(sc->sc_dma_physaddr + + offsetof(struct hifn_dma, command_bufs[i][0])); + for (i = 0; i < HIFN_D_RES_RSIZE; i++) + dma->resr[i].p = htole32(sc->sc_dma_physaddr + + offsetof(struct hifn_dma, result_bufs[i][0])); + + dma->cmdr[HIFN_D_CMD_RSIZE].p = + htole32(sc->sc_dma_physaddr + offsetof(struct hifn_dma, cmdr[0])); + dma->srcr[HIFN_D_SRC_RSIZE].p = + htole32(sc->sc_dma_physaddr + offsetof(struct hifn_dma, srcr[0])); + dma->dstr[HIFN_D_DST_RSIZE].p = + htole32(sc->sc_dma_physaddr + offsetof(struct hifn_dma, dstr[0])); + dma->resr[HIFN_D_RES_RSIZE].p = + htole32(sc->sc_dma_physaddr + offsetof(struct hifn_dma, resr[0])); + + dma->cmdu = dma->srcu = dma->dstu = dma->resu = 0; + dma->cmdi = dma->srci = dma->dsti = dma->resi = 0; + dma->cmdk = dma->srck = dma->dstk = dma->resk = 0; +} + +/* + * Writes out the raw command buffer space. Returns the + * command buffer size. + */ +static u_int +hifn_write_command(struct hifn_command *cmd, u_int8_t *buf) +{ + struct hifn_softc *sc = NULL; + u_int8_t *buf_pos; + hifn_base_command_t *base_cmd; + hifn_mac_command_t *mac_cmd; + hifn_crypt_command_t *cry_cmd; + int using_mac, using_crypt, len, ivlen; + u_int32_t dlen, slen; + + DPRINTF("%s()\n", __FUNCTION__); + + buf_pos = buf; + using_mac = cmd->base_masks & HIFN_BASE_CMD_MAC; + using_crypt = cmd->base_masks & HIFN_BASE_CMD_CRYPT; + + base_cmd = (hifn_base_command_t *)buf_pos; + base_cmd->masks = htole16(cmd->base_masks); + slen = cmd->src_mapsize; + if (cmd->sloplen) + dlen = cmd->dst_mapsize - cmd->sloplen + sizeof(u_int32_t); + else + dlen = cmd->dst_mapsize; + base_cmd->total_source_count = htole16(slen & HIFN_BASE_CMD_LENMASK_LO); + base_cmd->total_dest_count = htole16(dlen & HIFN_BASE_CMD_LENMASK_LO); + dlen >>= 16; + slen >>= 16; + base_cmd->session_num = htole16( + ((slen << HIFN_BASE_CMD_SRCLEN_S) & HIFN_BASE_CMD_SRCLEN_M) | + ((dlen << HIFN_BASE_CMD_DSTLEN_S) & HIFN_BASE_CMD_DSTLEN_M)); + buf_pos += sizeof(hifn_base_command_t); + + if (using_mac) { + mac_cmd = (hifn_mac_command_t *)buf_pos; + dlen = cmd->maccrd->crd_len; + mac_cmd->source_count = htole16(dlen & 0xffff); + dlen >>= 16; + mac_cmd->masks = htole16(cmd->mac_masks | + ((dlen << HIFN_MAC_CMD_SRCLEN_S) & HIFN_MAC_CMD_SRCLEN_M)); + mac_cmd->header_skip = htole16(cmd->maccrd->crd_skip); + mac_cmd->reserved = 0; + buf_pos += sizeof(hifn_mac_command_t); + } + + if (using_crypt) { + cry_cmd = (hifn_crypt_command_t *)buf_pos; + dlen = cmd->enccrd->crd_len; + cry_cmd->source_count = htole16(dlen & 0xffff); + dlen >>= 16; + cry_cmd->masks = htole16(cmd->cry_masks | + ((dlen << HIFN_CRYPT_CMD_SRCLEN_S) & HIFN_CRYPT_CMD_SRCLEN_M)); + cry_cmd->header_skip = htole16(cmd->enccrd->crd_skip); + cry_cmd->reserved = 0; + buf_pos += sizeof(hifn_crypt_command_t); + } + + if (using_mac && cmd->mac_masks & HIFN_MAC_CMD_NEW_KEY) { + bcopy(cmd->mac, buf_pos, HIFN_MAC_KEY_LENGTH); + buf_pos += HIFN_MAC_KEY_LENGTH; + } + + if (using_crypt && cmd->cry_masks & HIFN_CRYPT_CMD_NEW_KEY) { + switch (cmd->cry_masks & HIFN_CRYPT_CMD_ALG_MASK) { + case HIFN_CRYPT_CMD_ALG_3DES: + bcopy(cmd->ck, buf_pos, HIFN_3DES_KEY_LENGTH); + buf_pos += HIFN_3DES_KEY_LENGTH; + break; + case HIFN_CRYPT_CMD_ALG_DES: + bcopy(cmd->ck, buf_pos, HIFN_DES_KEY_LENGTH); + buf_pos += HIFN_DES_KEY_LENGTH; + break; + case HIFN_CRYPT_CMD_ALG_RC4: + len = 256; + do { + int clen; + + clen = MIN(cmd->cklen, len); + bcopy(cmd->ck, buf_pos, clen); + len -= clen; + buf_pos += clen; + } while (len > 0); + bzero(buf_pos, 4); + buf_pos += 4; + break; + case HIFN_CRYPT_CMD_ALG_AES: + /* + * AES keys are variable 128, 192 and + * 256 bits (16, 24 and 32 bytes). + */ + bcopy(cmd->ck, buf_pos, cmd->cklen); + buf_pos += cmd->cklen; + break; + } + } + + if (using_crypt && cmd->cry_masks & HIFN_CRYPT_CMD_NEW_IV) { + switch (cmd->cry_masks & HIFN_CRYPT_CMD_ALG_MASK) { + case HIFN_CRYPT_CMD_ALG_AES: + ivlen = HIFN_AES_IV_LENGTH; + break; + default: + ivlen = HIFN_IV_LENGTH; + break; + } + bcopy(cmd->iv, buf_pos, ivlen); + buf_pos += ivlen; + } + + if ((cmd->base_masks & (HIFN_BASE_CMD_MAC|HIFN_BASE_CMD_CRYPT)) == 0) { + bzero(buf_pos, 8); + buf_pos += 8; + } + + return (buf_pos - buf); +} + +static int +hifn_dmamap_aligned(struct hifn_operand *op) +{ + struct hifn_softc *sc = NULL; + int i; + + DPRINTF("%s()\n", __FUNCTION__); + + for (i = 0; i < op->nsegs; i++) { + if (op->segs[i].ds_addr & 3) + return (0); + if ((i != (op->nsegs - 1)) && (op->segs[i].ds_len & 3)) + return (0); + } + return (1); +} + +static __inline int +hifn_dmamap_dstwrap(struct hifn_softc *sc, int idx) +{ + struct hifn_dma *dma = sc->sc_dma; + + if (++idx == HIFN_D_DST_RSIZE) { + dma->dstr[idx].l = htole32(HIFN_D_VALID | HIFN_D_JUMP | + HIFN_D_MASKDONEIRQ); + HIFN_DSTR_SYNC(sc, idx, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + idx = 0; + } + return (idx); +} + +static int +hifn_dmamap_load_dst(struct hifn_softc *sc, struct hifn_command *cmd) +{ + struct hifn_dma *dma = sc->sc_dma; + struct hifn_operand *dst = &cmd->dst; + u_int32_t p, l; + int idx, used = 0, i; + + DPRINTF("%s()\n", __FUNCTION__); + + idx = dma->dsti; + for (i = 0; i < dst->nsegs - 1; i++) { + dma->dstr[idx].p = htole32(dst->segs[i].ds_addr); + dma->dstr[idx].l = htole32(HIFN_D_MASKDONEIRQ | dst->segs[i].ds_len); + wmb(); + dma->dstr[idx].l |= htole32(HIFN_D_VALID); + HIFN_DSTR_SYNC(sc, idx, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + used++; + + idx = hifn_dmamap_dstwrap(sc, idx); + } + + if (cmd->sloplen == 0) { + p = dst->segs[i].ds_addr; + l = HIFN_D_MASKDONEIRQ | HIFN_D_LAST | + dst->segs[i].ds_len; + } else { + p = sc->sc_dma_physaddr + + offsetof(struct hifn_dma, slop[cmd->slopidx]); + l = HIFN_D_MASKDONEIRQ | HIFN_D_LAST | + sizeof(u_int32_t); + + if ((dst->segs[i].ds_len - cmd->sloplen) != 0) { + dma->dstr[idx].p = htole32(dst->segs[i].ds_addr); + dma->dstr[idx].l = htole32(HIFN_D_MASKDONEIRQ | + (dst->segs[i].ds_len - cmd->sloplen)); + wmb(); + dma->dstr[idx].l |= htole32(HIFN_D_VALID); + HIFN_DSTR_SYNC(sc, idx, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + used++; + + idx = hifn_dmamap_dstwrap(sc, idx); + } + } + dma->dstr[idx].p = htole32(p); + dma->dstr[idx].l = htole32(l); + wmb(); + dma->dstr[idx].l |= htole32(HIFN_D_VALID); + HIFN_DSTR_SYNC(sc, idx, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + used++; + + idx = hifn_dmamap_dstwrap(sc, idx); + + dma->dsti = idx; + dma->dstu += used; + return (idx); +} + +static __inline int +hifn_dmamap_srcwrap(struct hifn_softc *sc, int idx) +{ + struct hifn_dma *dma = sc->sc_dma; + + if (++idx == HIFN_D_SRC_RSIZE) { + dma->srcr[idx].l = htole32(HIFN_D_VALID | + HIFN_D_JUMP | HIFN_D_MASKDONEIRQ); + HIFN_SRCR_SYNC(sc, HIFN_D_SRC_RSIZE, + BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); + idx = 0; + } + return (idx); +} + +static int +hifn_dmamap_load_src(struct hifn_softc *sc, struct hifn_command *cmd) +{ + struct hifn_dma *dma = sc->sc_dma; + struct hifn_operand *src = &cmd->src; + int idx, i; + u_int32_t last = 0; + + DPRINTF("%s()\n", __FUNCTION__); + + idx = dma->srci; + for (i = 0; i < src->nsegs; i++) { + if (i == src->nsegs - 1) + last = HIFN_D_LAST; + + dma->srcr[idx].p = htole32(src->segs[i].ds_addr); + dma->srcr[idx].l = htole32(src->segs[i].ds_len | + HIFN_D_MASKDONEIRQ | last); + wmb(); + dma->srcr[idx].l |= htole32(HIFN_D_VALID); + HIFN_SRCR_SYNC(sc, idx, + BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); + + idx = hifn_dmamap_srcwrap(sc, idx); + } + dma->srci = idx; + dma->srcu += src->nsegs; + return (idx); +} + + +static int +hifn_crypto( + struct hifn_softc *sc, + struct hifn_command *cmd, + struct cryptop *crp, + int hint) +{ + struct hifn_dma *dma = sc->sc_dma; + u_int32_t cmdlen, csr; + int cmdi, resi, err = 0; + unsigned long l_flags; + + DPRINTF("%s()\n", __FUNCTION__); + + /* + * need 1 cmd, and 1 res + * + * NB: check this first since it's easy. + */ + HIFN_LOCK(sc); + if ((dma->cmdu + 1) > HIFN_D_CMD_RSIZE || + (dma->resu + 1) > HIFN_D_RES_RSIZE) { +#ifdef HIFN_DEBUG + if (hifn_debug) { + device_printf(sc->sc_dev, + "cmd/result exhaustion, cmdu %u resu %u\n", + dma->cmdu, dma->resu); + } +#endif + hifnstats.hst_nomem_cr++; + sc->sc_needwakeup |= CRYPTO_SYMQ; + HIFN_UNLOCK(sc); + return (ERESTART); + } + + if (crp->crp_flags & CRYPTO_F_SKBUF) { + if (pci_map_skb(sc, &cmd->src, cmd->src_skb)) { + hifnstats.hst_nomem_load++; + err = ENOMEM; + goto err_srcmap1; + } + } else if (crp->crp_flags & CRYPTO_F_IOV) { + if (pci_map_uio(sc, &cmd->src, cmd->src_io)) { + hifnstats.hst_nomem_load++; + err = ENOMEM; + goto err_srcmap1; + } + } else { + if (pci_map_buf(sc, &cmd->src, cmd->src_buf, crp->crp_ilen)) { + hifnstats.hst_nomem_load++; + err = ENOMEM; + goto err_srcmap1; + } + } + + if (hifn_dmamap_aligned(&cmd->src)) { + cmd->sloplen = cmd->src_mapsize & 3; + cmd->dst = cmd->src; + } else { + if (crp->crp_flags & CRYPTO_F_IOV) { + DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__); + err = EINVAL; + goto err_srcmap; + } else if (crp->crp_flags & CRYPTO_F_SKBUF) { +#ifdef NOTYET + int totlen, len; + struct mbuf *m, *m0, *mlast; + + KASSERT(cmd->dst_m == cmd->src_m, + ("hifn_crypto: dst_m initialized improperly")); + hifnstats.hst_unaligned++; + /* + * Source is not aligned on a longword boundary. + * Copy the data to insure alignment. If we fail + * to allocate mbufs or clusters while doing this + * we return ERESTART so the operation is requeued + * at the crypto later, but only if there are + * ops already posted to the hardware; otherwise we + * have no guarantee that we'll be re-entered. + */ + totlen = cmd->src_mapsize; + if (cmd->src_m->m_flags & M_PKTHDR) { + len = MHLEN; + MGETHDR(m0, M_DONTWAIT, MT_DATA); + if (m0 && !m_dup_pkthdr(m0, cmd->src_m, M_DONTWAIT)) { + m_free(m0); + m0 = NULL; + } + } else { + len = MLEN; + MGET(m0, M_DONTWAIT, MT_DATA); + } + if (m0 == NULL) { + hifnstats.hst_nomem_mbuf++; + err = dma->cmdu ? ERESTART : ENOMEM; + goto err_srcmap; + } + if (totlen >= MINCLSIZE) { + MCLGET(m0, M_DONTWAIT); + if ((m0->m_flags & M_EXT) == 0) { + hifnstats.hst_nomem_mcl++; + err = dma->cmdu ? ERESTART : ENOMEM; + m_freem(m0); + goto err_srcmap; + } + len = MCLBYTES; + } + totlen -= len; + m0->m_pkthdr.len = m0->m_len = len; + mlast = m0; + + while (totlen > 0) { + MGET(m, M_DONTWAIT, MT_DATA); + if (m == NULL) { + hifnstats.hst_nomem_mbuf++; + err = dma->cmdu ? ERESTART : ENOMEM; + m_freem(m0); + goto err_srcmap; + } + len = MLEN; + if (totlen >= MINCLSIZE) { + MCLGET(m, M_DONTWAIT); + if ((m->m_flags & M_EXT) == 0) { + hifnstats.hst_nomem_mcl++; + err = dma->cmdu ? ERESTART : ENOMEM; + mlast->m_next = m; + m_freem(m0); + goto err_srcmap; + } + len = MCLBYTES; + } + + m->m_len = len; + m0->m_pkthdr.len += len; + totlen -= len; + + mlast->m_next = m; + mlast = m; + } + cmd->dst_m = m0; +#else + device_printf(sc->sc_dev, + "%s,%d: CRYPTO_F_SKBUF unaligned not implemented\n", + __FILE__, __LINE__); + err = EINVAL; + goto err_srcmap; +#endif + } else { + device_printf(sc->sc_dev, + "%s,%d: unaligned contig buffers not implemented\n", + __FILE__, __LINE__); + err = EINVAL; + goto err_srcmap; + } + } + + if (cmd->dst_map == NULL) { + if (crp->crp_flags & CRYPTO_F_SKBUF) { + if (pci_map_skb(sc, &cmd->dst, cmd->dst_skb)) { + hifnstats.hst_nomem_map++; + err = ENOMEM; + goto err_dstmap1; + } + } else if (crp->crp_flags & CRYPTO_F_IOV) { + if (pci_map_uio(sc, &cmd->dst, cmd->dst_io)) { + hifnstats.hst_nomem_load++; + err = ENOMEM; + goto err_dstmap1; + } + } else { + if (pci_map_buf(sc, &cmd->dst, cmd->dst_buf, crp->crp_ilen)) { + hifnstats.hst_nomem_load++; + err = ENOMEM; + goto err_dstmap1; + } + } + } + +#ifdef HIFN_DEBUG + if (hifn_debug) { + device_printf(sc->sc_dev, + "Entering cmd: stat %8x ien %8x u %d/%d/%d/%d n %d/%d\n", + READ_REG_1(sc, HIFN_1_DMA_CSR), + READ_REG_1(sc, HIFN_1_DMA_IER), + dma->cmdu, dma->srcu, dma->dstu, dma->resu, + cmd->src_nsegs, cmd->dst_nsegs); + } +#endif + +#if 0 + if (cmd->src_map == cmd->dst_map) { + bus_dmamap_sync(sc->sc_dmat, cmd->src_map, + BUS_DMASYNC_PREWRITE|BUS_DMASYNC_PREREAD); + } else { + bus_dmamap_sync(sc->sc_dmat, cmd->src_map, + BUS_DMASYNC_PREWRITE); + bus_dmamap_sync(sc->sc_dmat, cmd->dst_map, + BUS_DMASYNC_PREREAD); + } +#endif + + /* + * need N src, and N dst + */ + if ((dma->srcu + cmd->src_nsegs) > HIFN_D_SRC_RSIZE || + (dma->dstu + cmd->dst_nsegs + 1) > HIFN_D_DST_RSIZE) { +#ifdef HIFN_DEBUG + if (hifn_debug) { + device_printf(sc->sc_dev, + "src/dst exhaustion, srcu %u+%u dstu %u+%u\n", + dma->srcu, cmd->src_nsegs, + dma->dstu, cmd->dst_nsegs); + } +#endif + hifnstats.hst_nomem_sd++; + err = ERESTART; + goto err_dstmap; + } + + if (dma->cmdi == HIFN_D_CMD_RSIZE) { + dma->cmdi = 0; + dma->cmdr[HIFN_D_CMD_RSIZE].l = htole32(HIFN_D_JUMP|HIFN_D_MASKDONEIRQ); + wmb(); + dma->cmdr[HIFN_D_CMD_RSIZE].l |= htole32(HIFN_D_VALID); + HIFN_CMDR_SYNC(sc, HIFN_D_CMD_RSIZE, + BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); + } + cmdi = dma->cmdi++; + cmdlen = hifn_write_command(cmd, dma->command_bufs[cmdi]); + HIFN_CMD_SYNC(sc, cmdi, BUS_DMASYNC_PREWRITE); + + /* .p for command/result already set */ + dma->cmdr[cmdi].l = htole32(cmdlen | HIFN_D_LAST | + HIFN_D_MASKDONEIRQ); + wmb(); + dma->cmdr[cmdi].l |= htole32(HIFN_D_VALID); + HIFN_CMDR_SYNC(sc, cmdi, + BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); + dma->cmdu++; + + /* + * We don't worry about missing an interrupt (which a "command wait" + * interrupt salvages us from), unless there is more than one command + * in the queue. + */ + if (dma->cmdu > 1) { + sc->sc_dmaier |= HIFN_DMAIER_C_WAIT; + WRITE_REG_1(sc, HIFN_1_DMA_IER, sc->sc_dmaier); + } + + hifnstats.hst_ipackets++; + hifnstats.hst_ibytes += cmd->src_mapsize; + + hifn_dmamap_load_src(sc, cmd); + + /* + * Unlike other descriptors, we don't mask done interrupt from + * result descriptor. + */ +#ifdef HIFN_DEBUG + if (hifn_debug) + device_printf(sc->sc_dev, "load res\n"); +#endif + if (dma->resi == HIFN_D_RES_RSIZE) { + dma->resi = 0; + dma->resr[HIFN_D_RES_RSIZE].l = htole32(HIFN_D_JUMP|HIFN_D_MASKDONEIRQ); + wmb(); + dma->resr[HIFN_D_RES_RSIZE].l |= htole32(HIFN_D_VALID); + HIFN_RESR_SYNC(sc, HIFN_D_RES_RSIZE, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + } + resi = dma->resi++; + KASSERT(dma->hifn_commands[resi] == NULL, + ("hifn_crypto: command slot %u busy", resi)); + dma->hifn_commands[resi] = cmd; + HIFN_RES_SYNC(sc, resi, BUS_DMASYNC_PREREAD); + if ((hint & CRYPTO_HINT_MORE) && sc->sc_curbatch < hifn_maxbatch) { + dma->resr[resi].l = htole32(HIFN_MAX_RESULT | + HIFN_D_LAST | HIFN_D_MASKDONEIRQ); + wmb(); + dma->resr[resi].l |= htole32(HIFN_D_VALID); + sc->sc_curbatch++; + if (sc->sc_curbatch > hifnstats.hst_maxbatch) + hifnstats.hst_maxbatch = sc->sc_curbatch; + hifnstats.hst_totbatch++; + } else { + dma->resr[resi].l = htole32(HIFN_MAX_RESULT | HIFN_D_LAST); + wmb(); + dma->resr[resi].l |= htole32(HIFN_D_VALID); + sc->sc_curbatch = 0; + } + HIFN_RESR_SYNC(sc, resi, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + dma->resu++; + + if (cmd->sloplen) + cmd->slopidx = resi; + + hifn_dmamap_load_dst(sc, cmd); + + csr = 0; + if (sc->sc_c_busy == 0) { + csr |= HIFN_DMACSR_C_CTRL_ENA; + sc->sc_c_busy = 1; + } + if (sc->sc_s_busy == 0) { + csr |= HIFN_DMACSR_S_CTRL_ENA; + sc->sc_s_busy = 1; + } + if (sc->sc_r_busy == 0) { + csr |= HIFN_DMACSR_R_CTRL_ENA; + sc->sc_r_busy = 1; + } + if (sc->sc_d_busy == 0) { + csr |= HIFN_DMACSR_D_CTRL_ENA; + sc->sc_d_busy = 1; + } + if (csr) + WRITE_REG_1(sc, HIFN_1_DMA_CSR, csr); + +#ifdef HIFN_DEBUG + if (hifn_debug) { + device_printf(sc->sc_dev, "command: stat %8x ier %8x\n", + READ_REG_1(sc, HIFN_1_DMA_CSR), + READ_REG_1(sc, HIFN_1_DMA_IER)); + } +#endif + + sc->sc_active = 5; + HIFN_UNLOCK(sc); + KASSERT(err == 0, ("hifn_crypto: success with error %u", err)); + return (err); /* success */ + +err_dstmap: + if (cmd->src_map != cmd->dst_map) + pci_unmap_buf(sc, &cmd->dst); +err_dstmap1: +err_srcmap: + if (crp->crp_flags & CRYPTO_F_SKBUF) { + if (cmd->src_skb != cmd->dst_skb) +#ifdef NOTYET + m_freem(cmd->dst_m); +#else + device_printf(sc->sc_dev, + "%s,%d: CRYPTO_F_SKBUF src != dst not implemented\n", + __FILE__, __LINE__); +#endif + } + pci_unmap_buf(sc, &cmd->src); +err_srcmap1: + HIFN_UNLOCK(sc); + return (err); +} + +static void +hifn_tick(unsigned long arg) +{ + struct hifn_softc *sc; + unsigned long l_flags; + + if (arg >= HIFN_MAX_CHIPS) + return; + sc = hifn_chip_idx[arg]; + if (!sc) + return; + + HIFN_LOCK(sc); + if (sc->sc_active == 0) { + struct hifn_dma *dma = sc->sc_dma; + u_int32_t r = 0; + + if (dma->cmdu == 0 && sc->sc_c_busy) { + sc->sc_c_busy = 0; + r |= HIFN_DMACSR_C_CTRL_DIS; + } + if (dma->srcu == 0 && sc->sc_s_busy) { + sc->sc_s_busy = 0; + r |= HIFN_DMACSR_S_CTRL_DIS; + } + if (dma->dstu == 0 && sc->sc_d_busy) { + sc->sc_d_busy = 0; + r |= HIFN_DMACSR_D_CTRL_DIS; + } + if (dma->resu == 0 && sc->sc_r_busy) { + sc->sc_r_busy = 0; + r |= HIFN_DMACSR_R_CTRL_DIS; + } + if (r) + WRITE_REG_1(sc, HIFN_1_DMA_CSR, r); + } else + sc->sc_active--; + HIFN_UNLOCK(sc); + mod_timer(&sc->sc_tickto, jiffies + HZ); +} + +static irqreturn_t +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19) +hifn_intr(int irq, void *arg) +#else +hifn_intr(int irq, void *arg, struct pt_regs *regs) +#endif +{ + struct hifn_softc *sc = arg; + struct hifn_dma *dma; + u_int32_t dmacsr, restart; + int i, u; + unsigned long l_flags; + + dmacsr = READ_REG_1(sc, HIFN_1_DMA_CSR); + + /* Nothing in the DMA unit interrupted */ + if ((dmacsr & sc->sc_dmaier) == 0) + return IRQ_NONE; + + HIFN_LOCK(sc); + + dma = sc->sc_dma; + +#ifdef HIFN_DEBUG + if (hifn_debug) { + device_printf(sc->sc_dev, + "irq: stat %08x ien %08x damier %08x i %d/%d/%d/%d k %d/%d/%d/%d u %d/%d/%d/%d\n", + dmacsr, READ_REG_1(sc, HIFN_1_DMA_IER), sc->sc_dmaier, + dma->cmdi, dma->srci, dma->dsti, dma->resi, + dma->cmdk, dma->srck, dma->dstk, dma->resk, + dma->cmdu, dma->srcu, dma->dstu, dma->resu); + } +#endif + + WRITE_REG_1(sc, HIFN_1_DMA_CSR, dmacsr & sc->sc_dmaier); + + if ((sc->sc_flags & HIFN_HAS_PUBLIC) && + (dmacsr & HIFN_DMACSR_PUBDONE)) + WRITE_REG_1(sc, HIFN_1_PUB_STATUS, + READ_REG_1(sc, HIFN_1_PUB_STATUS) | HIFN_PUBSTS_DONE); + + restart = dmacsr & (HIFN_DMACSR_D_OVER | HIFN_DMACSR_R_OVER); + if (restart) + device_printf(sc->sc_dev, "overrun %x\n", dmacsr); + + if (sc->sc_flags & HIFN_IS_7811) { + if (dmacsr & HIFN_DMACSR_ILLR) + device_printf(sc->sc_dev, "illegal read\n"); + if (dmacsr & HIFN_DMACSR_ILLW) + device_printf(sc->sc_dev, "illegal write\n"); + } + + restart = dmacsr & (HIFN_DMACSR_C_ABORT | HIFN_DMACSR_S_ABORT | + HIFN_DMACSR_D_ABORT | HIFN_DMACSR_R_ABORT); + if (restart) { + device_printf(sc->sc_dev, "abort, resetting.\n"); + hifnstats.hst_abort++; + hifn_abort(sc); + HIFN_UNLOCK(sc); + return IRQ_HANDLED; + } + + if ((dmacsr & HIFN_DMACSR_C_WAIT) && (dma->cmdu == 0)) { + /* + * If no slots to process and we receive a "waiting on + * command" interrupt, we disable the "waiting on command" + * (by clearing it). + */ + sc->sc_dmaier &= ~HIFN_DMAIER_C_WAIT; + WRITE_REG_1(sc, HIFN_1_DMA_IER, sc->sc_dmaier); + } + + /* clear the rings */ + i = dma->resk; u = dma->resu; + while (u != 0) { + HIFN_RESR_SYNC(sc, i, + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); + if (dma->resr[i].l & htole32(HIFN_D_VALID)) { + HIFN_RESR_SYNC(sc, i, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + break; + } + + if (i != HIFN_D_RES_RSIZE) { + struct hifn_command *cmd; + u_int8_t *macbuf = NULL; + + HIFN_RES_SYNC(sc, i, BUS_DMASYNC_POSTREAD); + cmd = dma->hifn_commands[i]; + KASSERT(cmd != NULL, + ("hifn_intr: null command slot %u", i)); + dma->hifn_commands[i] = NULL; + + if (cmd->base_masks & HIFN_BASE_CMD_MAC) { + macbuf = dma->result_bufs[i]; + macbuf += 12; + } + + hifn_callback(sc, cmd, macbuf); + hifnstats.hst_opackets++; + u--; + } + + if (++i == (HIFN_D_RES_RSIZE + 1)) + i = 0; + } + dma->resk = i; dma->resu = u; + + i = dma->srck; u = dma->srcu; + while (u != 0) { + if (i == HIFN_D_SRC_RSIZE) + i = 0; + HIFN_SRCR_SYNC(sc, i, + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); + if (dma->srcr[i].l & htole32(HIFN_D_VALID)) { + HIFN_SRCR_SYNC(sc, i, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + break; + } + i++, u--; + } + dma->srck = i; dma->srcu = u; + + i = dma->cmdk; u = dma->cmdu; + while (u != 0) { + HIFN_CMDR_SYNC(sc, i, + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); + if (dma->cmdr[i].l & htole32(HIFN_D_VALID)) { + HIFN_CMDR_SYNC(sc, i, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + break; + } + if (i != HIFN_D_CMD_RSIZE) { + u--; + HIFN_CMD_SYNC(sc, i, BUS_DMASYNC_POSTWRITE); + } + if (++i == (HIFN_D_CMD_RSIZE + 1)) + i = 0; + } + dma->cmdk = i; dma->cmdu = u; + + HIFN_UNLOCK(sc); + + if (sc->sc_needwakeup) { /* XXX check high watermark */ + int wakeup = sc->sc_needwakeup & (CRYPTO_SYMQ|CRYPTO_ASYMQ); +#ifdef HIFN_DEBUG + if (hifn_debug) + device_printf(sc->sc_dev, + "wakeup crypto (%x) u %d/%d/%d/%d\n", + sc->sc_needwakeup, + dma->cmdu, dma->srcu, dma->dstu, dma->resu); +#endif + sc->sc_needwakeup &= ~wakeup; + crypto_unblock(sc->sc_cid, wakeup); + } + + return IRQ_HANDLED; +} + +/* + * Allocate a new 'session' and return an encoded session id. 'sidp' + * contains our registration id, and should contain an encoded session + * id on successful allocation. + */ +static int +hifn_newsession(device_t dev, u_int32_t *sidp, struct cryptoini *cri) +{ + struct hifn_softc *sc = device_get_softc(dev); + struct cryptoini *c; + int mac = 0, cry = 0, sesn; + struct hifn_session *ses = NULL; + unsigned long l_flags; + + DPRINTF("%s()\n", __FUNCTION__); + + KASSERT(sc != NULL, ("hifn_newsession: null softc")); + if (sidp == NULL || cri == NULL || sc == NULL) { + DPRINTF("%s,%d: %s - EINVAL\n", __FILE__, __LINE__, __FUNCTION__); + return (EINVAL); + } + + HIFN_LOCK(sc); + if (sc->sc_sessions == NULL) { + ses = sc->sc_sessions = (struct hifn_session *)kmalloc(sizeof(*ses), + SLAB_ATOMIC); + if (ses == NULL) { + HIFN_UNLOCK(sc); + return (ENOMEM); + } + sesn = 0; + sc->sc_nsessions = 1; + } else { + for (sesn = 0; sesn < sc->sc_nsessions; sesn++) { + if (!sc->sc_sessions[sesn].hs_used) { + ses = &sc->sc_sessions[sesn]; + break; + } + } + + if (ses == NULL) { + sesn = sc->sc_nsessions; + ses = (struct hifn_session *)kmalloc((sesn + 1) * sizeof(*ses), + SLAB_ATOMIC); + if (ses == NULL) { + HIFN_UNLOCK(sc); + return (ENOMEM); + } + bcopy(sc->sc_sessions, ses, sesn * sizeof(*ses)); + bzero(sc->sc_sessions, sesn * sizeof(*ses)); + kfree(sc->sc_sessions); + sc->sc_sessions = ses; + ses = &sc->sc_sessions[sesn]; + sc->sc_nsessions++; + } + } + HIFN_UNLOCK(sc); + + bzero(ses, sizeof(*ses)); + ses->hs_used = 1; + + for (c = cri; c != NULL; c = c->cri_next) { + switch (c->cri_alg) { + case CRYPTO_MD5: + case CRYPTO_SHA1: + case CRYPTO_MD5_HMAC: + case CRYPTO_SHA1_HMAC: + if (mac) { + DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__); + return (EINVAL); + } + mac = 1; + ses->hs_mlen = c->cri_mlen; + if (ses->hs_mlen == 0) { + switch (c->cri_alg) { + case CRYPTO_MD5: + case CRYPTO_MD5_HMAC: + ses->hs_mlen = 16; + break; + case CRYPTO_SHA1: + case CRYPTO_SHA1_HMAC: + ses->hs_mlen = 20; + break; + } + } + break; + case CRYPTO_DES_CBC: + case CRYPTO_3DES_CBC: + case CRYPTO_AES_CBC: + case CRYPTO_ARC4: + if (cry) { + DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__); + return (EINVAL); + } + cry = 1; + break; + default: + DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__); + return (EINVAL); + } + } + if (mac == 0 && cry == 0) { + DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__); + return (EINVAL); + } + + *sidp = HIFN_SID(device_get_unit(sc->sc_dev), sesn); + + return (0); +} + +/* + * Deallocate a session. + * XXX this routine should run a zero'd mac/encrypt key into context ram. + * XXX to blow away any keys already stored there. + */ +static int +hifn_freesession(device_t dev, u_int64_t tid) +{ + struct hifn_softc *sc = device_get_softc(dev); + int session, error; + u_int32_t sid = CRYPTO_SESID2LID(tid); + unsigned long l_flags; + + DPRINTF("%s()\n", __FUNCTION__); + + KASSERT(sc != NULL, ("hifn_freesession: null softc")); + if (sc == NULL) { + DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__); + return (EINVAL); + } + + HIFN_LOCK(sc); + session = HIFN_SESSION(sid); + if (session < sc->sc_nsessions) { + bzero(&sc->sc_sessions[session], sizeof(struct hifn_session)); + error = 0; + } else { + DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__); + error = EINVAL; + } + HIFN_UNLOCK(sc); + + return (error); +} + +static int +hifn_process(device_t dev, struct cryptop *crp, int hint) +{ + struct hifn_softc *sc = device_get_softc(dev); + struct hifn_command *cmd = NULL; + int session, err, ivlen; + struct cryptodesc *crd1, *crd2, *maccrd, *enccrd; + + DPRINTF("%s()\n", __FUNCTION__); + + if (crp == NULL || crp->crp_callback == NULL) { + hifnstats.hst_invalid++; + DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__); + return (EINVAL); + } + session = HIFN_SESSION(crp->crp_sid); + + if (sc == NULL || session >= sc->sc_nsessions) { + DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__); + err = EINVAL; + goto errout; + } + + cmd = kmalloc(sizeof(struct hifn_command), SLAB_ATOMIC); + if (cmd == NULL) { + hifnstats.hst_nomem++; + err = ENOMEM; + goto errout; + } + memset(cmd, 0, sizeof(*cmd)); + + if (crp->crp_flags & CRYPTO_F_SKBUF) { + cmd->src_skb = (struct sk_buff *)crp->crp_buf; + cmd->dst_skb = (struct sk_buff *)crp->crp_buf; + } else if (crp->crp_flags & CRYPTO_F_IOV) { + cmd->src_io = (struct uio *)crp->crp_buf; + cmd->dst_io = (struct uio *)crp->crp_buf; + } else { + cmd->src_buf = crp->crp_buf; + cmd->dst_buf = crp->crp_buf; + } + + crd1 = crp->crp_desc; + if (crd1 == NULL) { + DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__); + err = EINVAL; + goto errout; + } + crd2 = crd1->crd_next; + + if (crd2 == NULL) { + if (crd1->crd_alg == CRYPTO_MD5_HMAC || + crd1->crd_alg == CRYPTO_SHA1_HMAC || + crd1->crd_alg == CRYPTO_SHA1 || + crd1->crd_alg == CRYPTO_MD5) { + maccrd = crd1; + enccrd = NULL; + } else if (crd1->crd_alg == CRYPTO_DES_CBC || + crd1->crd_alg == CRYPTO_3DES_CBC || + crd1->crd_alg == CRYPTO_AES_CBC || + crd1->crd_alg == CRYPTO_ARC4) { + if ((crd1->crd_flags & CRD_F_ENCRYPT) == 0) + cmd->base_masks |= HIFN_BASE_CMD_DECODE; + maccrd = NULL; + enccrd = crd1; + } else { + DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__); + err = EINVAL; + goto errout; + } + } else { + if ((crd1->crd_alg == CRYPTO_MD5_HMAC || + crd1->crd_alg == CRYPTO_SHA1_HMAC || + crd1->crd_alg == CRYPTO_MD5 || + crd1->crd_alg == CRYPTO_SHA1) && + (crd2->crd_alg == CRYPTO_DES_CBC || + crd2->crd_alg == CRYPTO_3DES_CBC || + crd2->crd_alg == CRYPTO_AES_CBC || + crd2->crd_alg == CRYPTO_ARC4) && + ((crd2->crd_flags & CRD_F_ENCRYPT) == 0)) { + cmd->base_masks = HIFN_BASE_CMD_DECODE; + maccrd = crd1; + enccrd = crd2; + } else if ((crd1->crd_alg == CRYPTO_DES_CBC || + crd1->crd_alg == CRYPTO_ARC4 || + crd1->crd_alg == CRYPTO_3DES_CBC || + crd1->crd_alg == CRYPTO_AES_CBC) && + (crd2->crd_alg == CRYPTO_MD5_HMAC || + crd2->crd_alg == CRYPTO_SHA1_HMAC || + crd2->crd_alg == CRYPTO_MD5 || + crd2->crd_alg == CRYPTO_SHA1) && + (crd1->crd_flags & CRD_F_ENCRYPT)) { + enccrd = crd1; + maccrd = crd2; + } else { + /* + * We cannot order the 7751 as requested + */ + DPRINTF("%s,%d: %s %d,%d,%d - EINVAL\n",__FILE__,__LINE__,__FUNCTION__, crd1->crd_alg, crd2->crd_alg, crd1->crd_flags & CRD_F_ENCRYPT); + err = EINVAL; + goto errout; + } + } + + if (enccrd) { + cmd->enccrd = enccrd; + cmd->base_masks |= HIFN_BASE_CMD_CRYPT; + switch (enccrd->crd_alg) { + case CRYPTO_ARC4: + cmd->cry_masks |= HIFN_CRYPT_CMD_ALG_RC4; + break; + case CRYPTO_DES_CBC: + cmd->cry_masks |= HIFN_CRYPT_CMD_ALG_DES | + HIFN_CRYPT_CMD_MODE_CBC | + HIFN_CRYPT_CMD_NEW_IV; + break; + case CRYPTO_3DES_CBC: + cmd->cry_masks |= HIFN_CRYPT_CMD_ALG_3DES | + HIFN_CRYPT_CMD_MODE_CBC | + HIFN_CRYPT_CMD_NEW_IV; + break; + case CRYPTO_AES_CBC: + cmd->cry_masks |= HIFN_CRYPT_CMD_ALG_AES | + HIFN_CRYPT_CMD_MODE_CBC | + HIFN_CRYPT_CMD_NEW_IV; + break; + default: + DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__); + err = EINVAL; + goto errout; + } + if (enccrd->crd_alg != CRYPTO_ARC4) { + ivlen = ((enccrd->crd_alg == CRYPTO_AES_CBC) ? + HIFN_AES_IV_LENGTH : HIFN_IV_LENGTH); + if (enccrd->crd_flags & CRD_F_ENCRYPT) { + if (enccrd->crd_flags & CRD_F_IV_EXPLICIT) + bcopy(enccrd->crd_iv, cmd->iv, ivlen); + else + read_random(cmd->iv, ivlen); + + if ((enccrd->crd_flags & CRD_F_IV_PRESENT) + == 0) { + crypto_copyback(crp->crp_flags, + crp->crp_buf, enccrd->crd_inject, + ivlen, cmd->iv); + } + } else { + if (enccrd->crd_flags & CRD_F_IV_EXPLICIT) + bcopy(enccrd->crd_iv, cmd->iv, ivlen); + else { + crypto_copydata(crp->crp_flags, + crp->crp_buf, enccrd->crd_inject, + ivlen, cmd->iv); + } + } + } + + if (enccrd->crd_flags & CRD_F_KEY_EXPLICIT) + cmd->cry_masks |= HIFN_CRYPT_CMD_NEW_KEY; + cmd->ck = enccrd->crd_key; + cmd->cklen = enccrd->crd_klen >> 3; + cmd->cry_masks |= HIFN_CRYPT_CMD_NEW_KEY; + + /* + * Need to specify the size for the AES key in the masks. + */ + if ((cmd->cry_masks & HIFN_CRYPT_CMD_ALG_MASK) == + HIFN_CRYPT_CMD_ALG_AES) { + switch (cmd->cklen) { + case 16: + cmd->cry_masks |= HIFN_CRYPT_CMD_KSZ_128; + break; + case 24: + cmd->cry_masks |= HIFN_CRYPT_CMD_KSZ_192; + break; + case 32: + cmd->cry_masks |= HIFN_CRYPT_CMD_KSZ_256; + break; + default: + DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__); + err = EINVAL; + goto errout; + } + } + } + + if (maccrd) { + cmd->maccrd = maccrd; + cmd->base_masks |= HIFN_BASE_CMD_MAC; + + switch (maccrd->crd_alg) { + case CRYPTO_MD5: + cmd->mac_masks |= HIFN_MAC_CMD_ALG_MD5 | + HIFN_MAC_CMD_RESULT | HIFN_MAC_CMD_MODE_HASH | + HIFN_MAC_CMD_POS_IPSEC; + break; + case CRYPTO_MD5_HMAC: + cmd->mac_masks |= HIFN_MAC_CMD_ALG_MD5 | + HIFN_MAC_CMD_RESULT | HIFN_MAC_CMD_MODE_HMAC | + HIFN_MAC_CMD_POS_IPSEC | HIFN_MAC_CMD_TRUNC; + break; + case CRYPTO_SHA1: + cmd->mac_masks |= HIFN_MAC_CMD_ALG_SHA1 | + HIFN_MAC_CMD_RESULT | HIFN_MAC_CMD_MODE_HASH | + HIFN_MAC_CMD_POS_IPSEC; + break; + case CRYPTO_SHA1_HMAC: + cmd->mac_masks |= HIFN_MAC_CMD_ALG_SHA1 | + HIFN_MAC_CMD_RESULT | HIFN_MAC_CMD_MODE_HMAC | + HIFN_MAC_CMD_POS_IPSEC | HIFN_MAC_CMD_TRUNC; + break; + } + + if (maccrd->crd_alg == CRYPTO_SHA1_HMAC || + maccrd->crd_alg == CRYPTO_MD5_HMAC) { + cmd->mac_masks |= HIFN_MAC_CMD_NEW_KEY; + bcopy(maccrd->crd_key, cmd->mac, maccrd->crd_klen >> 3); + bzero(cmd->mac + (maccrd->crd_klen >> 3), + HIFN_MAC_KEY_LENGTH - (maccrd->crd_klen >> 3)); + } + } + + cmd->crp = crp; + cmd->session_num = session; + cmd->softc = sc; + + err = hifn_crypto(sc, cmd, crp, hint); + if (!err) { + return 0; + } else if (err == ERESTART) { + /* + * There weren't enough resources to dispatch the request + * to the part. Notify the caller so they'll requeue this + * request and resubmit it again soon. + */ +#ifdef HIFN_DEBUG + if (hifn_debug) + device_printf(sc->sc_dev, "requeue request\n"); +#endif + kfree(cmd); + sc->sc_needwakeup |= CRYPTO_SYMQ; + return (err); + } + +errout: + if (cmd != NULL) + kfree(cmd); + if (err == EINVAL) + hifnstats.hst_invalid++; + else + hifnstats.hst_nomem++; + crp->crp_etype = err; + crypto_done(crp); + return (err); +} + +static void +hifn_abort(struct hifn_softc *sc) +{ + struct hifn_dma *dma = sc->sc_dma; + struct hifn_command *cmd; + struct cryptop *crp; + int i, u; + + DPRINTF("%s()\n", __FUNCTION__); + + i = dma->resk; u = dma->resu; + while (u != 0) { + cmd = dma->hifn_commands[i]; + KASSERT(cmd != NULL, ("hifn_abort: null command slot %u", i)); + dma->hifn_commands[i] = NULL; + crp = cmd->crp; + + if ((dma->resr[i].l & htole32(HIFN_D_VALID)) == 0) { + /* Salvage what we can. */ + u_int8_t *macbuf; + + if (cmd->base_masks & HIFN_BASE_CMD_MAC) { + macbuf = dma->result_bufs[i]; + macbuf += 12; + } else + macbuf = NULL; + hifnstats.hst_opackets++; + hifn_callback(sc, cmd, macbuf); + } else { +#if 0 + if (cmd->src_map == cmd->dst_map) { + bus_dmamap_sync(sc->sc_dmat, cmd->src_map, + BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); + } else { + bus_dmamap_sync(sc->sc_dmat, cmd->src_map, + BUS_DMASYNC_POSTWRITE); + bus_dmamap_sync(sc->sc_dmat, cmd->dst_map, + BUS_DMASYNC_POSTREAD); + } +#endif + + if (cmd->src_skb != cmd->dst_skb) { +#ifdef NOTYET + m_freem(cmd->src_m); + crp->crp_buf = (caddr_t)cmd->dst_m; +#else + device_printf(sc->sc_dev, + "%s,%d: CRYPTO_F_SKBUF src != dst not implemented\n", + __FILE__, __LINE__); +#endif + } + + /* non-shared buffers cannot be restarted */ + if (cmd->src_map != cmd->dst_map) { + /* + * XXX should be EAGAIN, delayed until + * after the reset. + */ + crp->crp_etype = ENOMEM; + pci_unmap_buf(sc, &cmd->dst); + } else + crp->crp_etype = ENOMEM; + + pci_unmap_buf(sc, &cmd->src); + + kfree(cmd); + if (crp->crp_etype != EAGAIN) + crypto_done(crp); + } + + if (++i == HIFN_D_RES_RSIZE) + i = 0; + u--; + } + dma->resk = i; dma->resu = u; + + hifn_reset_board(sc, 1); + hifn_init_dma(sc); + hifn_init_pci_registers(sc); +} + +static void +hifn_callback(struct hifn_softc *sc, struct hifn_command *cmd, u_int8_t *macbuf) +{ + struct hifn_dma *dma = sc->sc_dma; + struct cryptop *crp = cmd->crp; + struct cryptodesc *crd; + int i, u; + + DPRINTF("%s()\n", __FUNCTION__); + +#if 0 + if (cmd->src_map == cmd->dst_map) { + bus_dmamap_sync(sc->sc_dmat, cmd->src_map, + BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); + } else { + bus_dmamap_sync(sc->sc_dmat, cmd->src_map, + BUS_DMASYNC_POSTWRITE); + bus_dmamap_sync(sc->sc_dmat, cmd->dst_map, + BUS_DMASYNC_POSTREAD); + } +#endif + + if (crp->crp_flags & CRYPTO_F_SKBUF) { + if (cmd->src_skb != cmd->dst_skb) { +#ifdef NOTYET + crp->crp_buf = (caddr_t)cmd->dst_m; + totlen = cmd->src_mapsize; + for (m = cmd->dst_m; m != NULL; m = m->m_next) { + if (totlen < m->m_len) { + m->m_len = totlen; + totlen = 0; + } else + totlen -= m->m_len; + } + cmd->dst_m->m_pkthdr.len = cmd->src_m->m_pkthdr.len; + m_freem(cmd->src_m); +#else + device_printf(sc->sc_dev, + "%s,%d: CRYPTO_F_SKBUF src != dst not implemented\n", + __FILE__, __LINE__); +#endif + } + } + + if (cmd->sloplen != 0) { + crypto_copyback(crp->crp_flags, crp->crp_buf, + cmd->src_mapsize - cmd->sloplen, cmd->sloplen, + (caddr_t)&dma->slop[cmd->slopidx]); + } + + i = dma->dstk; u = dma->dstu; + while (u != 0) { + if (i == HIFN_D_DST_RSIZE) + i = 0; +#if 0 + bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); +#endif + if (dma->dstr[i].l & htole32(HIFN_D_VALID)) { +#if 0 + bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); +#endif + break; + } + i++, u--; + } + dma->dstk = i; dma->dstu = u; + + hifnstats.hst_obytes += cmd->dst_mapsize; + + if (macbuf != NULL) { + for (crd = crp->crp_desc; crd; crd = crd->crd_next) { + int len; + + if (crd->crd_alg != CRYPTO_MD5 && + crd->crd_alg != CRYPTO_SHA1 && + crd->crd_alg != CRYPTO_MD5_HMAC && + crd->crd_alg != CRYPTO_SHA1_HMAC) { + continue; + } + len = cmd->softc->sc_sessions[cmd->session_num].hs_mlen; + crypto_copyback(crp->crp_flags, crp->crp_buf, + crd->crd_inject, len, macbuf); + break; + } + } + + if (cmd->src_map != cmd->dst_map) + pci_unmap_buf(sc, &cmd->dst); + pci_unmap_buf(sc, &cmd->src); + kfree(cmd); + crypto_done(crp); +} + +/* + * 7811 PB3 rev/2 parts lock-up on burst writes to Group 0 + * and Group 1 registers; avoid conditions that could create + * burst writes by doing a read in between the writes. + * + * NB: The read we interpose is always to the same register; + * we do this because reading from an arbitrary (e.g. last) + * register may not always work. + */ +static void +hifn_write_reg_0(struct hifn_softc *sc, bus_size_t reg, u_int32_t val) +{ + if (sc->sc_flags & HIFN_IS_7811) { + if (sc->sc_bar0_lastreg == reg - 4) + readl(sc->sc_bar0 + HIFN_0_PUCNFG); + sc->sc_bar0_lastreg = reg; + } + writel(val, sc->sc_bar0 + reg); +} + +static void +hifn_write_reg_1(struct hifn_softc *sc, bus_size_t reg, u_int32_t val) +{ + if (sc->sc_flags & HIFN_IS_7811) { + if (sc->sc_bar1_lastreg == reg - 4) + readl(sc->sc_bar1 + HIFN_1_REVID); + sc->sc_bar1_lastreg = reg; + } + writel(val, sc->sc_bar1 + reg); +} + + +static struct pci_device_id hifn_pci_tbl[] = { + { PCI_VENDOR_HIFN, PCI_PRODUCT_HIFN_7951, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, + { PCI_VENDOR_HIFN, PCI_PRODUCT_HIFN_7955, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, + { PCI_VENDOR_HIFN, PCI_PRODUCT_HIFN_7956, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, + { PCI_VENDOR_NETSEC, PCI_PRODUCT_NETSEC_7751, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, + { PCI_VENDOR_INVERTEX, PCI_PRODUCT_INVERTEX_AEON, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, + { PCI_VENDOR_HIFN, PCI_PRODUCT_HIFN_7811, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, + /* + * Other vendors share this PCI ID as well, such as + * http://www.powercrypt.com, and obviously they also + * use the same key. + */ + { PCI_VENDOR_HIFN, PCI_PRODUCT_HIFN_7751, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, + { 0, 0, 0, 0, 0, 0, } +}; +MODULE_DEVICE_TABLE(pci, hifn_pci_tbl); + +static struct pci_driver hifn_driver = { + .name = "hifn", + .id_table = hifn_pci_tbl, + .probe = hifn_probe, + .remove = hifn_remove, + /* add PM stuff here one day */ +}; + +static int __init hifn_init (void) +{ + struct hifn_softc *sc = NULL; + int rc; + + DPRINTF("%s(%p)\n", __FUNCTION__, hifn_init); + + rc = pci_register_driver(&hifn_driver); + pci_register_driver_compat(&hifn_driver, rc); + + return rc; +} + +static void __exit hifn_exit (void) +{ + pci_unregister_driver(&hifn_driver); +} + +module_init(hifn_init); +module_exit(hifn_exit); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_AUTHOR("David McCullough "); +MODULE_DESCRIPTION("OCF driver for hifn PCI crypto devices"); diff --git a/target/linux/generic/files/crypto/ocf/hifn/hifn7751reg.h b/target/linux/generic/files/crypto/ocf/hifn/hifn7751reg.h new file mode 100644 index 0000000..ccf54f9 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/hifn/hifn7751reg.h @@ -0,0 +1,540 @@ +/* $FreeBSD: src/sys/dev/hifn/hifn7751reg.h,v 1.7 2007/03/21 03:42:49 sam Exp $ */ +/* $OpenBSD: hifn7751reg.h,v 1.35 2002/04/08 17:49:42 jason Exp $ */ + +/*- + * Invertex AEON / Hifn 7751 driver + * Copyright (c) 1999 Invertex Inc. All rights reserved. + * Copyright (c) 1999 Theo de Raadt + * Copyright (c) 2000-2001 Network Security Technologies, Inc. + * http://www.netsec.net + * + * Please send any comments, feedback, bug-fixes, or feature requests to + * software@invertex.com. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Effort sponsored in part by the Defense Advanced Research Projects + * Agency (DARPA) and Air Force Research Laboratory, Air Force + * Materiel Command, USAF, under agreement number F30602-01-2-0537. + * + */ +#ifndef __HIFN_H__ +#define __HIFN_H__ + +/* + * Some PCI configuration space offset defines. The names were made + * identical to the names used by the Linux kernel. + */ +#define HIFN_BAR0 PCIR_BAR(0) /* PUC register map */ +#define HIFN_BAR1 PCIR_BAR(1) /* DMA register map */ +#define HIFN_TRDY_TIMEOUT 0x40 +#define HIFN_RETRY_TIMEOUT 0x41 + +/* + * PCI vendor and device identifiers + * (the names are preserved from their OpenBSD source). + */ +#define PCI_VENDOR_HIFN 0x13a3 /* Hifn */ +#define PCI_PRODUCT_HIFN_7751 0x0005 /* 7751 */ +#define PCI_PRODUCT_HIFN_6500 0x0006 /* 6500 */ +#define PCI_PRODUCT_HIFN_7811 0x0007 /* 7811 */ +#define PCI_PRODUCT_HIFN_7855 0x001f /* 7855 */ +#define PCI_PRODUCT_HIFN_7951 0x0012 /* 7951 */ +#define PCI_PRODUCT_HIFN_7955 0x0020 /* 7954/7955 */ +#define PCI_PRODUCT_HIFN_7956 0x001d /* 7956 */ + +#define PCI_VENDOR_INVERTEX 0x14e1 /* Invertex */ +#define PCI_PRODUCT_INVERTEX_AEON 0x0005 /* AEON */ + +#define PCI_VENDOR_NETSEC 0x1660 /* NetSec */ +#define PCI_PRODUCT_NETSEC_7751 0x7751 /* 7751 */ + +/* + * The values below should multiple of 4 -- and be large enough to handle + * any command the driver implements. + * + * MAX_COMMAND = base command + mac command + encrypt command + + * mac-key + rc4-key + * MAX_RESULT = base result + mac result + mac + encrypt result + * + * + */ +#define HIFN_MAX_COMMAND (8 + 8 + 8 + 64 + 260) +#define HIFN_MAX_RESULT (8 + 4 + 20 + 4) + +/* + * hifn_desc_t + * + * Holds an individual descriptor for any of the rings. + */ +typedef struct hifn_desc { + volatile u_int32_t l; /* length and status bits */ + volatile u_int32_t p; +} hifn_desc_t; + +/* + * Masks for the "length" field of struct hifn_desc. + */ +#define HIFN_D_LENGTH 0x0000ffff /* length bit mask */ +#define HIFN_D_MASKDONEIRQ 0x02000000 /* mask the done interrupt */ +#define HIFN_D_DESTOVER 0x04000000 /* destination overflow */ +#define HIFN_D_OVER 0x08000000 /* overflow */ +#define HIFN_D_LAST 0x20000000 /* last descriptor in chain */ +#define HIFN_D_JUMP 0x40000000 /* jump descriptor */ +#define HIFN_D_VALID 0x80000000 /* valid bit */ + + +/* + * Processing Unit Registers (offset from BASEREG0) + */ +#define HIFN_0_PUDATA 0x00 /* Processing Unit Data */ +#define HIFN_0_PUCTRL 0x04 /* Processing Unit Control */ +#define HIFN_0_PUISR 0x08 /* Processing Unit Interrupt Status */ +#define HIFN_0_PUCNFG 0x0c /* Processing Unit Configuration */ +#define HIFN_0_PUIER 0x10 /* Processing Unit Interrupt Enable */ +#define HIFN_0_PUSTAT 0x14 /* Processing Unit Status/Chip ID */ +#define HIFN_0_FIFOSTAT 0x18 /* FIFO Status */ +#define HIFN_0_FIFOCNFG 0x1c /* FIFO Configuration */ +#define HIFN_0_PUCTRL2 0x28 /* Processing Unit Control (2nd map) */ +#define HIFN_0_MUTE1 0x80 +#define HIFN_0_MUTE2 0x90 +#define HIFN_0_SPACESIZE 0x100 /* Register space size */ + +/* Processing Unit Control Register (HIFN_0_PUCTRL) */ +#define HIFN_PUCTRL_CLRSRCFIFO 0x0010 /* clear source fifo */ +#define HIFN_PUCTRL_STOP 0x0008 /* stop pu */ +#define HIFN_PUCTRL_LOCKRAM 0x0004 /* lock ram */ +#define HIFN_PUCTRL_DMAENA 0x0002 /* enable dma */ +#define HIFN_PUCTRL_RESET 0x0001 /* Reset processing unit */ + +/* Processing Unit Interrupt Status Register (HIFN_0_PUISR) */ +#define HIFN_PUISR_CMDINVAL 0x8000 /* Invalid command interrupt */ +#define HIFN_PUISR_DATAERR 0x4000 /* Data error interrupt */ +#define HIFN_PUISR_SRCFIFO 0x2000 /* Source FIFO ready interrupt */ +#define HIFN_PUISR_DSTFIFO 0x1000 /* Destination FIFO ready interrupt */ +#define HIFN_PUISR_DSTOVER 0x0200 /* Destination overrun interrupt */ +#define HIFN_PUISR_SRCCMD 0x0080 /* Source command interrupt */ +#define HIFN_PUISR_SRCCTX 0x0040 /* Source context interrupt */ +#define HIFN_PUISR_SRCDATA 0x0020 /* Source data interrupt */ +#define HIFN_PUISR_DSTDATA 0x0010 /* Destination data interrupt */ +#define HIFN_PUISR_DSTRESULT 0x0004 /* Destination result interrupt */ + +/* Processing Unit Configuration Register (HIFN_0_PUCNFG) */ +#define HIFN_PUCNFG_DRAMMASK 0xe000 /* DRAM size mask */ +#define HIFN_PUCNFG_DSZ_256K 0x0000 /* 256k dram */ +#define HIFN_PUCNFG_DSZ_512K 0x2000 /* 512k dram */ +#define HIFN_PUCNFG_DSZ_1M 0x4000 /* 1m dram */ +#define HIFN_PUCNFG_DSZ_2M 0x6000 /* 2m dram */ +#define HIFN_PUCNFG_DSZ_4M 0x8000 /* 4m dram */ +#define HIFN_PUCNFG_DSZ_8M 0xa000 /* 8m dram */ +#define HIFN_PUNCFG_DSZ_16M 0xc000 /* 16m dram */ +#define HIFN_PUCNFG_DSZ_32M 0xe000 /* 32m dram */ +#define HIFN_PUCNFG_DRAMREFRESH 0x1800 /* DRAM refresh rate mask */ +#define HIFN_PUCNFG_DRFR_512 0x0000 /* 512 divisor of ECLK */ +#define HIFN_PUCNFG_DRFR_256 0x0800 /* 256 divisor of ECLK */ +#define HIFN_PUCNFG_DRFR_128 0x1000 /* 128 divisor of ECLK */ +#define HIFN_PUCNFG_TCALLPHASES 0x0200 /* your guess is as good as mine... */ +#define HIFN_PUCNFG_TCDRVTOTEM 0x0100 /* your guess is as good as mine... */ +#define HIFN_PUCNFG_BIGENDIAN 0x0080 /* DMA big endian mode */ +#define HIFN_PUCNFG_BUS32 0x0040 /* Bus width 32bits */ +#define HIFN_PUCNFG_BUS16 0x0000 /* Bus width 16 bits */ +#define HIFN_PUCNFG_CHIPID 0x0020 /* Allow chipid from PUSTAT */ +#define HIFN_PUCNFG_DRAM 0x0010 /* Context RAM is DRAM */ +#define HIFN_PUCNFG_SRAM 0x0000 /* Context RAM is SRAM */ +#define HIFN_PUCNFG_COMPSING 0x0004 /* Enable single compression context */ +#define HIFN_PUCNFG_ENCCNFG 0x0002 /* Encryption configuration */ + +/* Processing Unit Interrupt Enable Register (HIFN_0_PUIER) */ +#define HIFN_PUIER_CMDINVAL 0x8000 /* Invalid command interrupt */ +#define HIFN_PUIER_DATAERR 0x4000 /* Data error interrupt */ +#define HIFN_PUIER_SRCFIFO 0x2000 /* Source FIFO ready interrupt */ +#define HIFN_PUIER_DSTFIFO 0x1000 /* Destination FIFO ready interrupt */ +#define HIFN_PUIER_DSTOVER 0x0200 /* Destination overrun interrupt */ +#define HIFN_PUIER_SRCCMD 0x0080 /* Source command interrupt */ +#define HIFN_PUIER_SRCCTX 0x0040 /* Source context interrupt */ +#define HIFN_PUIER_SRCDATA 0x0020 /* Source data interrupt */ +#define HIFN_PUIER_DSTDATA 0x0010 /* Destination data interrupt */ +#define HIFN_PUIER_DSTRESULT 0x0004 /* Destination result interrupt */ + +/* Processing Unit Status Register/Chip ID (HIFN_0_PUSTAT) */ +#define HIFN_PUSTAT_CMDINVAL 0x8000 /* Invalid command interrupt */ +#define HIFN_PUSTAT_DATAERR 0x4000 /* Data error interrupt */ +#define HIFN_PUSTAT_SRCFIFO 0x2000 /* Source FIFO ready interrupt */ +#define HIFN_PUSTAT_DSTFIFO 0x1000 /* Destination FIFO ready interrupt */ +#define HIFN_PUSTAT_DSTOVER 0x0200 /* Destination overrun interrupt */ +#define HIFN_PUSTAT_SRCCMD 0x0080 /* Source command interrupt */ +#define HIFN_PUSTAT_SRCCTX 0x0040 /* Source context interrupt */ +#define HIFN_PUSTAT_SRCDATA 0x0020 /* Source data interrupt */ +#define HIFN_PUSTAT_DSTDATA 0x0010 /* Destination data interrupt */ +#define HIFN_PUSTAT_DSTRESULT 0x0004 /* Destination result interrupt */ +#define HIFN_PUSTAT_CHIPREV 0x00ff /* Chip revision mask */ +#define HIFN_PUSTAT_CHIPENA 0xff00 /* Chip enabled mask */ +#define HIFN_PUSTAT_ENA_2 0x1100 /* Level 2 enabled */ +#define HIFN_PUSTAT_ENA_1 0x1000 /* Level 1 enabled */ +#define HIFN_PUSTAT_ENA_0 0x3000 /* Level 0 enabled */ +#define HIFN_PUSTAT_REV_2 0x0020 /* 7751 PT6/2 */ +#define HIFN_PUSTAT_REV_3 0x0030 /* 7751 PT6/3 */ + +/* FIFO Status Register (HIFN_0_FIFOSTAT) */ +#define HIFN_FIFOSTAT_SRC 0x7f00 /* Source FIFO available */ +#define HIFN_FIFOSTAT_DST 0x007f /* Destination FIFO available */ + +/* FIFO Configuration Register (HIFN_0_FIFOCNFG) */ +#define HIFN_FIFOCNFG_THRESHOLD 0x0400 /* must be written as this value */ + +/* + * DMA Interface Registers (offset from BASEREG1) + */ +#define HIFN_1_DMA_CRAR 0x0c /* DMA Command Ring Address */ +#define HIFN_1_DMA_SRAR 0x1c /* DMA Source Ring Address */ +#define HIFN_1_DMA_RRAR 0x2c /* DMA Result Ring Address */ +#define HIFN_1_DMA_DRAR 0x3c /* DMA Destination Ring Address */ +#define HIFN_1_DMA_CSR 0x40 /* DMA Status and Control */ +#define HIFN_1_DMA_IER 0x44 /* DMA Interrupt Enable */ +#define HIFN_1_DMA_CNFG 0x48 /* DMA Configuration */ +#define HIFN_1_PLL 0x4c /* 7955/7956: PLL config */ +#define HIFN_1_7811_RNGENA 0x60 /* 7811: rng enable */ +#define HIFN_1_7811_RNGCFG 0x64 /* 7811: rng config */ +#define HIFN_1_7811_RNGDAT 0x68 /* 7811: rng data */ +#define HIFN_1_7811_RNGSTS 0x6c /* 7811: rng status */ +#define HIFN_1_DMA_CNFG2 0x6c /* 7955/7956: dma config #2 */ +#define HIFN_1_7811_MIPSRST 0x94 /* 7811: MIPS reset */ +#define HIFN_1_REVID 0x98 /* Revision ID */ + +#define HIFN_1_PUB_RESET 0x204 /* Public/RNG Reset */ +#define HIFN_1_PUB_BASE 0x300 /* Public Base Address */ +#define HIFN_1_PUB_OPLEN 0x304 /* 7951-compat Public Operand Length */ +#define HIFN_1_PUB_OP 0x308 /* 7951-compat Public Operand */ +#define HIFN_1_PUB_STATUS 0x30c /* 7951-compat Public Status */ +#define HIFN_1_PUB_IEN 0x310 /* Public Interrupt enable */ +#define HIFN_1_RNG_CONFIG 0x314 /* RNG config */ +#define HIFN_1_RNG_DATA 0x318 /* RNG data */ +#define HIFN_1_PUB_MODE 0x320 /* PK mode */ +#define HIFN_1_PUB_FIFO_OPLEN 0x380 /* first element of oplen fifo */ +#define HIFN_1_PUB_FIFO_OP 0x384 /* first element of op fifo */ +#define HIFN_1_PUB_MEM 0x400 /* start of Public key memory */ +#define HIFN_1_PUB_MEMEND 0xbff /* end of Public key memory */ + +/* DMA Status and Control Register (HIFN_1_DMA_CSR) */ +#define HIFN_DMACSR_D_CTRLMASK 0xc0000000 /* Destinition Ring Control */ +#define HIFN_DMACSR_D_CTRL_NOP 0x00000000 /* Dest. Control: no-op */ +#define HIFN_DMACSR_D_CTRL_DIS 0x40000000 /* Dest. Control: disable */ +#define HIFN_DMACSR_D_CTRL_ENA 0x80000000 /* Dest. Control: enable */ +#define HIFN_DMACSR_D_ABORT 0x20000000 /* Destinition Ring PCIAbort */ +#define HIFN_DMACSR_D_DONE 0x10000000 /* Destinition Ring Done */ +#define HIFN_DMACSR_D_LAST 0x08000000 /* Destinition Ring Last */ +#define HIFN_DMACSR_D_WAIT 0x04000000 /* Destinition Ring Waiting */ +#define HIFN_DMACSR_D_OVER 0x02000000 /* Destinition Ring Overflow */ +#define HIFN_DMACSR_R_CTRL 0x00c00000 /* Result Ring Control */ +#define HIFN_DMACSR_R_CTRL_NOP 0x00000000 /* Result Control: no-op */ +#define HIFN_DMACSR_R_CTRL_DIS 0x00400000 /* Result Control: disable */ +#define HIFN_DMACSR_R_CTRL_ENA 0x00800000 /* Result Control: enable */ +#define HIFN_DMACSR_R_ABORT 0x00200000 /* Result Ring PCI Abort */ +#define HIFN_DMACSR_R_DONE 0x00100000 /* Result Ring Done */ +#define HIFN_DMACSR_R_LAST 0x00080000 /* Result Ring Last */ +#define HIFN_DMACSR_R_WAIT 0x00040000 /* Result Ring Waiting */ +#define HIFN_DMACSR_R_OVER 0x00020000 /* Result Ring Overflow */ +#define HIFN_DMACSR_S_CTRL 0x0000c000 /* Source Ring Control */ +#define HIFN_DMACSR_S_CTRL_NOP 0x00000000 /* Source Control: no-op */ +#define HIFN_DMACSR_S_CTRL_DIS 0x00004000 /* Source Control: disable */ +#define HIFN_DMACSR_S_CTRL_ENA 0x00008000 /* Source Control: enable */ +#define HIFN_DMACSR_S_ABORT 0x00002000 /* Source Ring PCI Abort */ +#define HIFN_DMACSR_S_DONE 0x00001000 /* Source Ring Done */ +#define HIFN_DMACSR_S_LAST 0x00000800 /* Source Ring Last */ +#define HIFN_DMACSR_S_WAIT 0x00000400 /* Source Ring Waiting */ +#define HIFN_DMACSR_ILLW 0x00000200 /* Illegal write (7811 only) */ +#define HIFN_DMACSR_ILLR 0x00000100 /* Illegal read (7811 only) */ +#define HIFN_DMACSR_C_CTRL 0x000000c0 /* Command Ring Control */ +#define HIFN_DMACSR_C_CTRL_NOP 0x00000000 /* Command Control: no-op */ +#define HIFN_DMACSR_C_CTRL_DIS 0x00000040 /* Command Control: disable */ +#define HIFN_DMACSR_C_CTRL_ENA 0x00000080 /* Command Control: enable */ +#define HIFN_DMACSR_C_ABORT 0x00000020 /* Command Ring PCI Abort */ +#define HIFN_DMACSR_C_DONE 0x00000010 /* Command Ring Done */ +#define HIFN_DMACSR_C_LAST 0x00000008 /* Command Ring Last */ +#define HIFN_DMACSR_C_WAIT 0x00000004 /* Command Ring Waiting */ +#define HIFN_DMACSR_PUBDONE 0x00000002 /* Public op done (7951 only) */ +#define HIFN_DMACSR_ENGINE 0x00000001 /* Command Ring Engine IRQ */ + +/* DMA Interrupt Enable Register (HIFN_1_DMA_IER) */ +#define HIFN_DMAIER_D_ABORT 0x20000000 /* Destination Ring PCIAbort */ +#define HIFN_DMAIER_D_DONE 0x10000000 /* Destination Ring Done */ +#define HIFN_DMAIER_D_LAST 0x08000000 /* Destination Ring Last */ +#define HIFN_DMAIER_D_WAIT 0x04000000 /* Destination Ring Waiting */ +#define HIFN_DMAIER_D_OVER 0x02000000 /* Destination Ring Overflow */ +#define HIFN_DMAIER_R_ABORT 0x00200000 /* Result Ring PCI Abort */ +#define HIFN_DMAIER_R_DONE 0x00100000 /* Result Ring Done */ +#define HIFN_DMAIER_R_LAST 0x00080000 /* Result Ring Last */ +#define HIFN_DMAIER_R_WAIT 0x00040000 /* Result Ring Waiting */ +#define HIFN_DMAIER_R_OVER 0x00020000 /* Result Ring Overflow */ +#define HIFN_DMAIER_S_ABORT 0x00002000 /* Source Ring PCI Abort */ +#define HIFN_DMAIER_S_DONE 0x00001000 /* Source Ring Done */ +#define HIFN_DMAIER_S_LAST 0x00000800 /* Source Ring Last */ +#define HIFN_DMAIER_S_WAIT 0x00000400 /* Source Ring Waiting */ +#define HIFN_DMAIER_ILLW 0x00000200 /* Illegal write (7811 only) */ +#define HIFN_DMAIER_ILLR 0x00000100 /* Illegal read (7811 only) */ +#define HIFN_DMAIER_C_ABORT 0x00000020 /* Command Ring PCI Abort */ +#define HIFN_DMAIER_C_DONE 0x00000010 /* Command Ring Done */ +#define HIFN_DMAIER_C_LAST 0x00000008 /* Command Ring Last */ +#define HIFN_DMAIER_C_WAIT 0x00000004 /* Command Ring Waiting */ +#define HIFN_DMAIER_PUBDONE 0x00000002 /* public op done (7951 only) */ +#define HIFN_DMAIER_ENGINE 0x00000001 /* Engine IRQ */ + +/* DMA Configuration Register (HIFN_1_DMA_CNFG) */ +#define HIFN_DMACNFG_BIGENDIAN 0x10000000 /* big endian mode */ +#define HIFN_DMACNFG_POLLFREQ 0x00ff0000 /* Poll frequency mask */ +#define HIFN_DMACNFG_UNLOCK 0x00000800 +#define HIFN_DMACNFG_POLLINVAL 0x00000700 /* Invalid Poll Scalar */ +#define HIFN_DMACNFG_LAST 0x00000010 /* Host control LAST bit */ +#define HIFN_DMACNFG_MODE 0x00000004 /* DMA mode */ +#define HIFN_DMACNFG_DMARESET 0x00000002 /* DMA Reset # */ +#define HIFN_DMACNFG_MSTRESET 0x00000001 /* Master Reset # */ + +/* DMA Configuration Register (HIFN_1_DMA_CNFG2) */ +#define HIFN_DMACNFG2_PKSWAP32 (1 << 19) /* swap the OPLEN/OP reg */ +#define HIFN_DMACNFG2_PKSWAP8 (1 << 18) /* swap the bits of OPLEN/OP */ +#define HIFN_DMACNFG2_BAR0_SWAP32 (1<<17) /* swap the bytes of BAR0 */ +#define HIFN_DMACNFG2_BAR1_SWAP8 (1<<16) /* swap the bits of BAR0 */ +#define HIFN_DMACNFG2_INIT_WRITE_BURST_SHIFT 12 +#define HIFN_DMACNFG2_INIT_READ_BURST_SHIFT 8 +#define HIFN_DMACNFG2_TGT_WRITE_BURST_SHIFT 4 +#define HIFN_DMACNFG2_TGT_READ_BURST_SHIFT 0 + +/* 7811 RNG Enable Register (HIFN_1_7811_RNGENA) */ +#define HIFN_7811_RNGENA_ENA 0x00000001 /* enable RNG */ + +/* 7811 RNG Config Register (HIFN_1_7811_RNGCFG) */ +#define HIFN_7811_RNGCFG_PRE1 0x00000f00 /* first prescalar */ +#define HIFN_7811_RNGCFG_OPRE 0x00000080 /* output prescalar */ +#define HIFN_7811_RNGCFG_DEFL 0x00000f80 /* 2 words/ 1/100 sec */ + +/* 7811 RNG Status Register (HIFN_1_7811_RNGSTS) */ +#define HIFN_7811_RNGSTS_RDY 0x00004000 /* two numbers in FIFO */ +#define HIFN_7811_RNGSTS_UFL 0x00001000 /* rng underflow */ + +/* 7811 MIPS Reset Register (HIFN_1_7811_MIPSRST) */ +#define HIFN_MIPSRST_BAR2SIZE 0xffff0000 /* sdram size */ +#define HIFN_MIPSRST_GPRAMINIT 0x00008000 /* gpram can be accessed */ +#define HIFN_MIPSRST_CRAMINIT 0x00004000 /* ctxram can be accessed */ +#define HIFN_MIPSRST_LED2 0x00000400 /* external LED2 */ +#define HIFN_MIPSRST_LED1 0x00000200 /* external LED1 */ +#define HIFN_MIPSRST_LED0 0x00000100 /* external LED0 */ +#define HIFN_MIPSRST_MIPSDIS 0x00000004 /* disable MIPS */ +#define HIFN_MIPSRST_MIPSRST 0x00000002 /* warm reset MIPS */ +#define HIFN_MIPSRST_MIPSCOLD 0x00000001 /* cold reset MIPS */ + +/* Public key reset register (HIFN_1_PUB_RESET) */ +#define HIFN_PUBRST_RESET 0x00000001 /* reset public/rng unit */ + +/* Public operation register (HIFN_1_PUB_OP) */ +#define HIFN_PUBOP_AOFFSET 0x0000003e /* A offset */ +#define HIFN_PUBOP_BOFFSET 0x00000fc0 /* B offset */ +#define HIFN_PUBOP_MOFFSET 0x0003f000 /* M offset */ +#define HIFN_PUBOP_OP_MASK 0x003c0000 /* Opcode: */ +#define HIFN_PUBOP_OP_NOP 0x00000000 /* NOP */ +#define HIFN_PUBOP_OP_ADD 0x00040000 /* ADD */ +#define HIFN_PUBOP_OP_ADDC 0x00080000 /* ADD w/carry */ +#define HIFN_PUBOP_OP_SUB 0x000c0000 /* SUB */ +#define HIFN_PUBOP_OP_SUBC 0x00100000 /* SUB w/carry */ +#define HIFN_PUBOP_OP_MODADD 0x00140000 /* Modular ADD */ +#define HIFN_PUBOP_OP_MODSUB 0x00180000 /* Modular SUB */ +#define HIFN_PUBOP_OP_INCA 0x001c0000 /* INC A */ +#define HIFN_PUBOP_OP_DECA 0x00200000 /* DEC A */ +#define HIFN_PUBOP_OP_MULT 0x00240000 /* MULT */ +#define HIFN_PUBOP_OP_MODMULT 0x00280000 /* Modular MULT */ +#define HIFN_PUBOP_OP_MODRED 0x002c0000 /* Modular Red */ +#define HIFN_PUBOP_OP_MODEXP 0x00300000 /* Modular Exp */ + +/* Public operand length register (HIFN_1_PUB_OPLEN) */ +#define HIFN_PUBOPLEN_MODLEN 0x0000007f +#define HIFN_PUBOPLEN_EXPLEN 0x0003ff80 +#define HIFN_PUBOPLEN_REDLEN 0x003c0000 + +/* Public status register (HIFN_1_PUB_STATUS) */ +#define HIFN_PUBSTS_DONE 0x00000001 /* operation done */ +#define HIFN_PUBSTS_CARRY 0x00000002 /* carry */ +#define HIFN_PUBSTS_FIFO_EMPTY 0x00000100 /* fifo empty */ +#define HIFN_PUBSTS_FIFO_FULL 0x00000200 /* fifo full */ +#define HIFN_PUBSTS_FIFO_OVFL 0x00000400 /* fifo overflow */ +#define HIFN_PUBSTS_FIFO_WRITE 0x000f0000 /* fifo write */ +#define HIFN_PUBSTS_FIFO_READ 0x0f000000 /* fifo read */ + +/* Public interrupt enable register (HIFN_1_PUB_IEN) */ +#define HIFN_PUBIEN_DONE 0x00000001 /* operation done interrupt */ + +/* Random number generator config register (HIFN_1_RNG_CONFIG) */ +#define HIFN_RNGCFG_ENA 0x00000001 /* enable rng */ + +/* + * Register offsets in register set 1 + */ + +#define HIFN_UNLOCK_SECRET1 0xf4 +#define HIFN_UNLOCK_SECRET2 0xfc + +/* + * PLL config register + * + * This register is present only on 7954/7955/7956 parts. It must be + * programmed according to the bus interface method used by the h/w. + * Note that the parts require a stable clock. Since the PCI clock + * may vary the reference clock must usually be used. To avoid + * overclocking the core logic, setup must be done carefully, refer + * to the driver for details. The exact multiplier required varies + * by part and system configuration; refer to the Hifn documentation. + */ +#define HIFN_PLL_REF_SEL 0x00000001 /* REF/HBI clk selection */ +#define HIFN_PLL_BP 0x00000002 /* bypass (used during setup) */ +/* bit 2 reserved */ +#define HIFN_PLL_PK_CLK_SEL 0x00000008 /* public key clk select */ +#define HIFN_PLL_PE_CLK_SEL 0x00000010 /* packet engine clk select */ +/* bits 5-9 reserved */ +#define HIFN_PLL_MBSET 0x00000400 /* must be set to 1 */ +#define HIFN_PLL_ND 0x00003800 /* Fpll_ref multiplier select */ +#define HIFN_PLL_ND_SHIFT 11 +#define HIFN_PLL_ND_2 0x00000000 /* 2x */ +#define HIFN_PLL_ND_4 0x00000800 /* 4x */ +#define HIFN_PLL_ND_6 0x00001000 /* 6x */ +#define HIFN_PLL_ND_8 0x00001800 /* 8x */ +#define HIFN_PLL_ND_10 0x00002000 /* 10x */ +#define HIFN_PLL_ND_12 0x00002800 /* 12x */ +/* bits 14-15 reserved */ +#define HIFN_PLL_IS 0x00010000 /* charge pump current select */ +/* bits 17-31 reserved */ + +/* + * Board configuration specifies only these bits. + */ +#define HIFN_PLL_CONFIG (HIFN_PLL_IS|HIFN_PLL_ND|HIFN_PLL_REF_SEL) + +/* + * Public Key Engine Mode Register + */ +#define HIFN_PKMODE_HOSTINVERT (1 << 0) /* HOST INVERT */ +#define HIFN_PKMODE_ENHANCED (1 << 1) /* Enable enhanced mode */ + + +/********************************************************************* + * Structs for board commands + * + *********************************************************************/ + +/* + * Structure to help build up the command data structure. + */ +typedef struct hifn_base_command { + volatile u_int16_t masks; + volatile u_int16_t session_num; + volatile u_int16_t total_source_count; + volatile u_int16_t total_dest_count; +} hifn_base_command_t; + +#define HIFN_BASE_CMD_MAC 0x0400 +#define HIFN_BASE_CMD_CRYPT 0x0800 +#define HIFN_BASE_CMD_DECODE 0x2000 +#define HIFN_BASE_CMD_SRCLEN_M 0xc000 +#define HIFN_BASE_CMD_SRCLEN_S 14 +#define HIFN_BASE_CMD_DSTLEN_M 0x3000 +#define HIFN_BASE_CMD_DSTLEN_S 12 +#define HIFN_BASE_CMD_LENMASK_HI 0x30000 +#define HIFN_BASE_CMD_LENMASK_LO 0x0ffff + +/* + * Structure to help build up the command data structure. + */ +typedef struct hifn_crypt_command { + volatile u_int16_t masks; + volatile u_int16_t header_skip; + volatile u_int16_t source_count; + volatile u_int16_t reserved; +} hifn_crypt_command_t; + +#define HIFN_CRYPT_CMD_ALG_MASK 0x0003 /* algorithm: */ +#define HIFN_CRYPT_CMD_ALG_DES 0x0000 /* DES */ +#define HIFN_CRYPT_CMD_ALG_3DES 0x0001 /* 3DES */ +#define HIFN_CRYPT_CMD_ALG_RC4 0x0002 /* RC4 */ +#define HIFN_CRYPT_CMD_ALG_AES 0x0003 /* AES */ +#define HIFN_CRYPT_CMD_MODE_MASK 0x0018 /* Encrypt mode: */ +#define HIFN_CRYPT_CMD_MODE_ECB 0x0000 /* ECB */ +#define HIFN_CRYPT_CMD_MODE_CBC 0x0008 /* CBC */ +#define HIFN_CRYPT_CMD_MODE_CFB 0x0010 /* CFB */ +#define HIFN_CRYPT_CMD_MODE_OFB 0x0018 /* OFB */ +#define HIFN_CRYPT_CMD_CLR_CTX 0x0040 /* clear context */ +#define HIFN_CRYPT_CMD_NEW_KEY 0x0800 /* expect new key */ +#define HIFN_CRYPT_CMD_NEW_IV 0x1000 /* expect new iv */ + +#define HIFN_CRYPT_CMD_SRCLEN_M 0xc000 +#define HIFN_CRYPT_CMD_SRCLEN_S 14 + +#define HIFN_CRYPT_CMD_KSZ_MASK 0x0600 /* AES key size: */ +#define HIFN_CRYPT_CMD_KSZ_128 0x0000 /* 128 bit */ +#define HIFN_CRYPT_CMD_KSZ_192 0x0200 /* 192 bit */ +#define HIFN_CRYPT_CMD_KSZ_256 0x0400 /* 256 bit */ + +/* + * Structure to help build up the command data structure. + */ +typedef struct hifn_mac_command { + volatile u_int16_t masks; + volatile u_int16_t header_skip; + volatile u_int16_t source_count; + volatile u_int16_t reserved; +} hifn_mac_command_t; + +#define HIFN_MAC_CMD_ALG_MASK 0x0001 +#define HIFN_MAC_CMD_ALG_SHA1 0x0000 +#define HIFN_MAC_CMD_ALG_MD5 0x0001 +#define HIFN_MAC_CMD_MODE_MASK 0x000c +#define HIFN_MAC_CMD_MODE_HMAC 0x0000 +#define HIFN_MAC_CMD_MODE_SSL_MAC 0x0004 +#define HIFN_MAC_CMD_MODE_HASH 0x0008 +#define HIFN_MAC_CMD_MODE_FULL 0x0004 +#define HIFN_MAC_CMD_TRUNC 0x0010 +#define HIFN_MAC_CMD_RESULT 0x0020 +#define HIFN_MAC_CMD_APPEND 0x0040 +#define HIFN_MAC_CMD_SRCLEN_M 0xc000 +#define HIFN_MAC_CMD_SRCLEN_S 14 + +/* + * MAC POS IPsec initiates authentication after encryption on encodes + * and before decryption on decodes. + */ +#define HIFN_MAC_CMD_POS_IPSEC 0x0200 +#define HIFN_MAC_CMD_NEW_KEY 0x0800 + +/* + * The poll frequency and poll scalar defines are unshifted values used + * to set fields in the DMA Configuration Register. + */ +#ifndef HIFN_POLL_FREQUENCY +#define HIFN_POLL_FREQUENCY 0x1 +#endif + +#ifndef HIFN_POLL_SCALAR +#define HIFN_POLL_SCALAR 0x0 +#endif + +#define HIFN_MAX_SEGLEN 0xffff /* maximum dma segment len */ +#define HIFN_MAX_DMALEN 0x3ffff /* maximum dma length */ +#endif /* __HIFN_H__ */ diff --git a/target/linux/generic/files/crypto/ocf/hifn/hifn7751var.h b/target/linux/generic/files/crypto/ocf/hifn/hifn7751var.h new file mode 100644 index 0000000..c5d30f9 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/hifn/hifn7751var.h @@ -0,0 +1,368 @@ +/* $FreeBSD: src/sys/dev/hifn/hifn7751var.h,v 1.9 2007/03/21 03:42:49 sam Exp $ */ +/* $OpenBSD: hifn7751var.h,v 1.42 2002/04/08 17:49:42 jason Exp $ */ + +/*- + * Invertex AEON / Hifn 7751 driver + * Copyright (c) 1999 Invertex Inc. All rights reserved. + * Copyright (c) 1999 Theo de Raadt + * Copyright (c) 2000-2001 Network Security Technologies, Inc. + * http://www.netsec.net + * + * Please send any comments, feedback, bug-fixes, or feature requests to + * software@invertex.com. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Effort sponsored in part by the Defense Advanced Research Projects + * Agency (DARPA) and Air Force Research Laboratory, Air Force + * Materiel Command, USAF, under agreement number F30602-01-2-0537. + * + */ + +#ifndef __HIFN7751VAR_H__ +#define __HIFN7751VAR_H__ + +#ifdef __KERNEL__ + +/* + * Some configurable values for the driver. By default command+result + * descriptor rings are the same size. The src+dst descriptor rings + * are sized at 3.5x the number of potential commands. Slower parts + * (e.g. 7951) tend to run out of src descriptors; faster parts (7811) + * src+cmd/result descriptors. It's not clear that increasing the size + * of the descriptor rings helps performance significantly as other + * factors tend to come into play (e.g. copying misaligned packets). + */ +#define HIFN_D_CMD_RSIZE 24 /* command descriptors */ +#define HIFN_D_SRC_RSIZE ((HIFN_D_CMD_RSIZE * 7) / 2) /* source descriptors */ +#define HIFN_D_RES_RSIZE HIFN_D_CMD_RSIZE /* result descriptors */ +#define HIFN_D_DST_RSIZE HIFN_D_SRC_RSIZE /* destination descriptors */ + +/* + * Length values for cryptography + */ +#define HIFN_DES_KEY_LENGTH 8 +#define HIFN_3DES_KEY_LENGTH 24 +#define HIFN_MAX_CRYPT_KEY_LENGTH HIFN_3DES_KEY_LENGTH +#define HIFN_IV_LENGTH 8 +#define HIFN_AES_IV_LENGTH 16 +#define HIFN_MAX_IV_LENGTH HIFN_AES_IV_LENGTH + +/* + * Length values for authentication + */ +#define HIFN_MAC_KEY_LENGTH 64 +#define HIFN_MD5_LENGTH 16 +#define HIFN_SHA1_LENGTH 20 +#define HIFN_MAC_TRUNC_LENGTH 12 + +#define MAX_SCATTER 64 + +/* + * Data structure to hold all 4 rings and any other ring related data. + */ +struct hifn_dma { + /* + * Descriptor rings. We add +1 to the size to accomidate the + * jump descriptor. + */ + struct hifn_desc cmdr[HIFN_D_CMD_RSIZE+1]; + struct hifn_desc srcr[HIFN_D_SRC_RSIZE+1]; + struct hifn_desc dstr[HIFN_D_DST_RSIZE+1]; + struct hifn_desc resr[HIFN_D_RES_RSIZE+1]; + + struct hifn_command *hifn_commands[HIFN_D_RES_RSIZE]; + + u_char command_bufs[HIFN_D_CMD_RSIZE][HIFN_MAX_COMMAND]; + u_char result_bufs[HIFN_D_CMD_RSIZE][HIFN_MAX_RESULT]; + u_int32_t slop[HIFN_D_CMD_RSIZE]; + + u_int64_t test_src, test_dst; + + /* + * Our current positions for insertion and removal from the desriptor + * rings. + */ + int cmdi, srci, dsti, resi; + volatile int cmdu, srcu, dstu, resu; + int cmdk, srck, dstk, resk; +}; + +struct hifn_session { + int hs_used; + int hs_mlen; +}; + +#define HIFN_RING_SYNC(sc, r, i, f) \ + /* DAVIDM bus_dmamap_sync((sc)->sc_dmat, (sc)->sc_dmamap, (f)) */ + +#define HIFN_CMDR_SYNC(sc, i, f) HIFN_RING_SYNC((sc), cmdr, (i), (f)) +#define HIFN_RESR_SYNC(sc, i, f) HIFN_RING_SYNC((sc), resr, (i), (f)) +#define HIFN_SRCR_SYNC(sc, i, f) HIFN_RING_SYNC((sc), srcr, (i), (f)) +#define HIFN_DSTR_SYNC(sc, i, f) HIFN_RING_SYNC((sc), dstr, (i), (f)) + +#define HIFN_CMD_SYNC(sc, i, f) \ + /* DAVIDM bus_dmamap_sync((sc)->sc_dmat, (sc)->sc_dmamap, (f)) */ + +#define HIFN_RES_SYNC(sc, i, f) \ + /* DAVIDM bus_dmamap_sync((sc)->sc_dmat, (sc)->sc_dmamap, (f)) */ + +typedef int bus_size_t; + +/* + * Holds data specific to a single HIFN board. + */ +struct hifn_softc { + softc_device_decl sc_dev; + + struct pci_dev *sc_pcidev; /* PCI device pointer */ + spinlock_t sc_mtx; /* per-instance lock */ + + int sc_num; /* for multiple devs */ + + ocf_iomem_t sc_bar0; + bus_size_t sc_bar0_lastreg;/* bar0 last reg written */ + ocf_iomem_t sc_bar1; + bus_size_t sc_bar1_lastreg;/* bar1 last reg written */ + + int sc_irq; + + u_int32_t sc_dmaier; + u_int32_t sc_drammodel; /* 1=dram, 0=sram */ + u_int32_t sc_pllconfig; /* 7954/7955/7956 PLL config */ + + struct hifn_dma *sc_dma; + dma_addr_t sc_dma_physaddr;/* physical address of sc_dma */ + + int sc_dmansegs; + int32_t sc_cid; + int sc_maxses; + int sc_nsessions; + struct hifn_session *sc_sessions; + int sc_ramsize; + int sc_flags; +#define HIFN_HAS_RNG 0x1 /* includes random number generator */ +#define HIFN_HAS_PUBLIC 0x2 /* includes public key support */ +#define HIFN_HAS_AES 0x4 /* includes AES support */ +#define HIFN_IS_7811 0x8 /* Hifn 7811 part */ +#define HIFN_IS_7956 0x10 /* Hifn 7956/7955 don't have SDRAM */ + + struct timer_list sc_tickto; /* for managing DMA */ + + int sc_rngfirst; + int sc_rnghz; /* RNG polling frequency */ + + int sc_c_busy; /* command ring busy */ + int sc_s_busy; /* source data ring busy */ + int sc_d_busy; /* destination data ring busy */ + int sc_r_busy; /* result ring busy */ + int sc_active; /* for initial countdown */ + int sc_needwakeup; /* ops q'd wating on resources */ + int sc_curbatch; /* # ops submitted w/o int */ + int sc_suspended; +#ifdef HIFN_VULCANDEV + struct cdev *sc_pkdev; +#endif +}; + +#define HIFN_LOCK(_sc) spin_lock_irqsave(&(_sc)->sc_mtx, l_flags) +#define HIFN_UNLOCK(_sc) spin_unlock_irqrestore(&(_sc)->sc_mtx, l_flags) + +/* + * hifn_command_t + * + * This is the control structure used to pass commands to hifn_encrypt(). + * + * flags + * ----- + * Flags is the bitwise "or" values for command configuration. A single + * encrypt direction needs to be set: + * + * HIFN_ENCODE or HIFN_DECODE + * + * To use cryptography, a single crypto algorithm must be included: + * + * HIFN_CRYPT_3DES or HIFN_CRYPT_DES + * + * To use authentication is used, a single MAC algorithm must be included: + * + * HIFN_MAC_MD5 or HIFN_MAC_SHA1 + * + * By default MD5 uses a 16 byte hash and SHA-1 uses a 20 byte hash. + * If the value below is set, hash values are truncated or assumed + * truncated to 12 bytes: + * + * HIFN_MAC_TRUNC + * + * Keys for encryption and authentication can be sent as part of a command, + * or the last key value used with a particular session can be retrieved + * and used again if either of these flags are not specified. + * + * HIFN_CRYPT_NEW_KEY, HIFN_MAC_NEW_KEY + * + * session_num + * ----------- + * A number between 0 and 2048 (for DRAM models) or a number between + * 0 and 768 (for SRAM models). Those who don't want to use session + * numbers should leave value at zero and send a new crypt key and/or + * new MAC key on every command. If you use session numbers and + * don't send a key with a command, the last key sent for that same + * session number will be used. + * + * Warning: Using session numbers and multiboard at the same time + * is currently broken. + * + * mbuf + * ---- + * Either fill in the mbuf pointer and npa=0 or + * fill packp[] and packl[] and set npa to > 0 + * + * mac_header_skip + * --------------- + * The number of bytes of the source_buf that are skipped over before + * authentication begins. This must be a number between 0 and 2^16-1 + * and can be used by IPsec implementers to skip over IP headers. + * *** Value ignored if authentication not used *** + * + * crypt_header_skip + * ----------------- + * The number of bytes of the source_buf that are skipped over before + * the cryptographic operation begins. This must be a number between 0 + * and 2^16-1. For IPsec, this number will always be 8 bytes larger + * than the auth_header_skip (to skip over the ESP header). + * *** Value ignored if cryptography not used *** + * + */ +struct hifn_operand { + union { + struct sk_buff *skb; + struct uio *io; + unsigned char *buf; + } u; + void *map; + bus_size_t mapsize; + int nsegs; + struct { + dma_addr_t ds_addr; + int ds_len; + } segs[MAX_SCATTER]; +}; + +struct hifn_command { + u_int16_t session_num; + u_int16_t base_masks, cry_masks, mac_masks; + u_int8_t iv[HIFN_MAX_IV_LENGTH], *ck, mac[HIFN_MAC_KEY_LENGTH]; + int cklen; + int sloplen, slopidx; + + struct hifn_operand src; + struct hifn_operand dst; + + struct hifn_softc *softc; + struct cryptop *crp; + struct cryptodesc *enccrd, *maccrd; +}; + +#define src_skb src.u.skb +#define src_io src.u.io +#define src_map src.map +#define src_mapsize src.mapsize +#define src_segs src.segs +#define src_nsegs src.nsegs +#define src_buf src.u.buf + +#define dst_skb dst.u.skb +#define dst_io dst.u.io +#define dst_map dst.map +#define dst_mapsize dst.mapsize +#define dst_segs dst.segs +#define dst_nsegs dst.nsegs +#define dst_buf dst.u.buf + +/* + * Return values for hifn_crypto() + */ +#define HIFN_CRYPTO_SUCCESS 0 +#define HIFN_CRYPTO_BAD_INPUT (-1) +#define HIFN_CRYPTO_RINGS_FULL (-2) + +/************************************************************************** + * + * Function: hifn_crypto + * + * Purpose: Called by external drivers to begin an encryption on the + * HIFN board. + * + * Blocking/Non-blocking Issues + * ============================ + * The driver cannot block in hifn_crypto (no calls to tsleep) currently. + * hifn_crypto() returns HIFN_CRYPTO_RINGS_FULL if there is not enough + * room in any of the rings for the request to proceed. + * + * Return Values + * ============= + * 0 for success, negative values on error + * + * Defines for negative error codes are: + * + * HIFN_CRYPTO_BAD_INPUT : The passed in command had invalid settings. + * HIFN_CRYPTO_RINGS_FULL : All DMA rings were full and non-blocking + * behaviour was requested. + * + *************************************************************************/ + +/* + * Convert back and forth from 'sid' to 'card' and 'session' + */ +#define HIFN_CARD(sid) (((sid) & 0xf0000000) >> 28) +#define HIFN_SESSION(sid) ((sid) & 0x000007ff) +#define HIFN_SID(crd,ses) (((crd) << 28) | ((ses) & 0x7ff)) + +#endif /* _KERNEL */ + +struct hifn_stats { + u_int64_t hst_ibytes; + u_int64_t hst_obytes; + u_int32_t hst_ipackets; + u_int32_t hst_opackets; + u_int32_t hst_invalid; + u_int32_t hst_nomem; /* malloc or one of hst_nomem_* */ + u_int32_t hst_abort; + u_int32_t hst_noirq; /* IRQ for no reason */ + u_int32_t hst_totbatch; /* ops submitted w/o interrupt */ + u_int32_t hst_maxbatch; /* max ops submitted together */ + u_int32_t hst_unaligned; /* unaligned src caused copy */ + /* + * The following divides hst_nomem into more specific buckets. + */ + u_int32_t hst_nomem_map; /* bus_dmamap_create failed */ + u_int32_t hst_nomem_load; /* bus_dmamap_load_* failed */ + u_int32_t hst_nomem_mbuf; /* MGET* failed */ + u_int32_t hst_nomem_mcl; /* MCLGET* failed */ + u_int32_t hst_nomem_cr; /* out of command/result descriptor */ + u_int32_t hst_nomem_sd; /* out of src/dst descriptors */ +}; + +#endif /* __HIFN7751VAR_H__ */ diff --git a/target/linux/generic/files/crypto/ocf/hifn/hifnHIPP.c b/target/linux/generic/files/crypto/ocf/hifn/hifnHIPP.c new file mode 100644 index 0000000..56b8a5c --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/hifn/hifnHIPP.c @@ -0,0 +1,421 @@ +/*- + * Driver for Hifn HIPP-I/II chipset + * Copyright (c) 2006 Michael Richardson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Effort sponsored by Hifn Inc. + * + */ + +/* + * Driver for various Hifn encryption processors. + */ +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) && !defined(AUTOCONF_INCLUDED) +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "hifnHIPPreg.h" +#include "hifnHIPPvar.h" + +#if 1 +#define DPRINTF(a...) if (hipp_debug) { \ + printk("%s: ", sc ? \ + device_get_nameunit(sc->sc_dev) : "hifn"); \ + printk(a); \ + } else +#else +#define DPRINTF(a...) +#endif + +typedef int bus_size_t; + +static inline int +pci_get_revid(struct pci_dev *dev) +{ + u8 rid = 0; + pci_read_config_byte(dev, PCI_REVISION_ID, &rid); + return rid; +} + +#define debug hipp_debug +int hipp_debug = 0; +module_param(hipp_debug, int, 0644); +MODULE_PARM_DESC(hipp_debug, "Enable debug"); + +int hipp_maxbatch = 1; +module_param(hipp_maxbatch, int, 0644); +MODULE_PARM_DESC(hipp_maxbatch, "max ops to batch w/o interrupt"); + +static int hipp_probe(struct pci_dev *dev, const struct pci_device_id *ent); +static void hipp_remove(struct pci_dev *dev); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19) +static irqreturn_t hipp_intr(int irq, void *arg); +#else +static irqreturn_t hipp_intr(int irq, void *arg, struct pt_regs *regs); +#endif + +static int hipp_num_chips = 0; +static struct hipp_softc *hipp_chip_idx[HIPP_MAX_CHIPS]; + +static int hipp_newsession(device_t, u_int32_t *, struct cryptoini *); +static int hipp_freesession(device_t, u_int64_t); +static int hipp_process(device_t, struct cryptop *, int); + +static device_method_t hipp_methods = { + /* crypto device methods */ + DEVMETHOD(cryptodev_newsession, hipp_newsession), + DEVMETHOD(cryptodev_freesession,hipp_freesession), + DEVMETHOD(cryptodev_process, hipp_process), +}; + +static __inline u_int32_t +READ_REG(struct hipp_softc *sc, unsigned int barno, bus_size_t reg) +{ + u_int32_t v = readl(sc->sc_bar[barno] + reg); + //sc->sc_bar0_lastreg = (bus_size_t) -1; + return (v); +} +static __inline void +WRITE_REG(struct hipp_softc *sc, unsigned int barno, bus_size_t reg, u_int32_t val) +{ + writel(val, sc->sc_bar[barno] + reg); +} + +#define READ_REG_0(sc, reg) READ_REG(sc, 0, reg) +#define WRITE_REG_0(sc, reg, val) WRITE_REG(sc,0, reg, val) +#define READ_REG_1(sc, reg) READ_REG(sc, 1, reg) +#define WRITE_REG_1(sc, reg, val) WRITE_REG(sc,1, reg, val) + +static int +hipp_newsession(device_t dev, u_int32_t *sidp, struct cryptoini *cri) +{ + return EINVAL; +} + +static int +hipp_freesession(device_t dev, u_int64_t tid) +{ + return EINVAL; +} + +static int +hipp_process(device_t dev, struct cryptop *crp, int hint) +{ + return EINVAL; +} + +static const char* +hipp_partname(struct hipp_softc *sc, char buf[128], size_t blen) +{ + char *n = NULL; + + switch (pci_get_vendor(sc->sc_pcidev)) { + case PCI_VENDOR_HIFN: + switch (pci_get_device(sc->sc_pcidev)) { + case PCI_PRODUCT_HIFN_7855: n = "Hifn 7855"; + case PCI_PRODUCT_HIFN_8155: n = "Hifn 8155"; + case PCI_PRODUCT_HIFN_6500: n = "Hifn 6500"; + } + } + + if(n==NULL) { + snprintf(buf, blen, "VID=%02x,PID=%02x", + pci_get_vendor(sc->sc_pcidev), + pci_get_device(sc->sc_pcidev)); + } else { + buf[0]='\0'; + strncat(buf, n, blen); + } + return buf; +} + +struct hipp_fs_entry { + struct attribute attr; + /* other stuff */ +}; + + +static ssize_t +cryptoid_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct hipp_softc *sc; + + sc = pci_get_drvdata(to_pci_dev (dev)); + return sprintf (buf, "%d\n", sc->sc_cid); +} + +struct device_attribute hipp_dev_cryptoid = __ATTR_RO(cryptoid); + +/* + * Attach an interface that successfully probed. + */ +static int +hipp_probe(struct pci_dev *dev, const struct pci_device_id *ent) +{ + struct hipp_softc *sc = NULL; + int i; + //char rbase; + //u_int16_t ena; + int rev; + //int rseg; + int rc; + + DPRINTF("%s()\n", __FUNCTION__); + + if (pci_enable_device(dev) < 0) + return(-ENODEV); + + if (pci_set_mwi(dev)) + return(-ENODEV); + + if (!dev->irq) { + printk("hifn: found device with no IRQ assigned. check BIOS settings!"); + pci_disable_device(dev); + return(-ENODEV); + } + + sc = (struct hipp_softc *) kmalloc(sizeof(*sc), GFP_KERNEL); + if (!sc) + return(-ENOMEM); + memset(sc, 0, sizeof(*sc)); + + softc_device_init(sc, "hifn-hipp", hipp_num_chips, hipp_methods); + + sc->sc_pcidev = dev; + sc->sc_irq = -1; + sc->sc_cid = -1; + sc->sc_num = hipp_num_chips++; + + if (sc->sc_num < HIPP_MAX_CHIPS) + hipp_chip_idx[sc->sc_num] = sc; + + pci_set_drvdata(sc->sc_pcidev, sc); + + spin_lock_init(&sc->sc_mtx); + + /* + * Setup PCI resources. + * The READ_REG_0, WRITE_REG_0, READ_REG_1, + * and WRITE_REG_1 macros throughout the driver are used + * to permit better debugging. + */ + for(i=0; i<4; i++) { + unsigned long mem_start, mem_len; + mem_start = pci_resource_start(sc->sc_pcidev, i); + mem_len = pci_resource_len(sc->sc_pcidev, i); + sc->sc_barphy[i] = (caddr_t)mem_start; + sc->sc_bar[i] = (ocf_iomem_t) ioremap(mem_start, mem_len); + if (!sc->sc_bar[i]) { + device_printf(sc->sc_dev, "cannot map bar%d register space\n", i); + goto fail; + } + } + + //hipp_reset_board(sc, 0); + pci_set_master(sc->sc_pcidev); + + /* + * Arrange the interrupt line. + */ + rc = request_irq(dev->irq, hipp_intr, IRQF_SHARED, "hifn", sc); + if (rc) { + device_printf(sc->sc_dev, "could not map interrupt: %d\n", rc); + goto fail; + } + sc->sc_irq = dev->irq; + + rev = READ_REG_1(sc, HIPP_1_REVID) & 0xffff; + + { + char b[32]; + device_printf(sc->sc_dev, "%s, rev %u", + hipp_partname(sc, b, sizeof(b)), rev); + } + +#if 0 + if (sc->sc_flags & HIFN_IS_7956) + printf(", pll=0x%x<%s clk, %ux mult>", + sc->sc_pllconfig, + sc->sc_pllconfig & HIFN_PLL_REF_SEL ? "ext" : "pci", + 2 + 2*((sc->sc_pllconfig & HIFN_PLL_ND) >> 11)); +#endif + printf("\n"); + + sc->sc_cid = crypto_get_driverid(softc_get_device(sc),CRYPTOCAP_F_HARDWARE); + if (sc->sc_cid < 0) { + device_printf(sc->sc_dev, "could not get crypto driver id\n"); + goto fail; + } + +#if 0 /* cannot work with a non-GPL module */ + /* make a sysfs entry to let the world know what entry we got */ + sysfs_create_file(&sc->sc_pcidev->dev.kobj, &hipp_dev_cryptoid.attr); +#endif + +#if 0 + init_timer(&sc->sc_tickto); + sc->sc_tickto.function = hifn_tick; + sc->sc_tickto.data = (unsigned long) sc->sc_num; + mod_timer(&sc->sc_tickto, jiffies + HZ); +#endif + +#if 0 /* no code here yet ?? */ + crypto_register(sc->sc_cid, CRYPTO_3DES_CBC, 0, 0); +#endif + + return (0); + +fail: + if (sc->sc_cid >= 0) + crypto_unregister_all(sc->sc_cid); + if (sc->sc_irq != -1) + free_irq(sc->sc_irq, sc); + +#if 0 + if (sc->sc_dma) { + /* Turn off DMA polling */ + WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET | + HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE); + + pci_free_consistent(sc->sc_pcidev, + sizeof(*sc->sc_dma), + sc->sc_dma, sc->sc_dma_physaddr); + } +#endif + kfree(sc); + return (-ENXIO); +} + +/* + * Detach an interface that successfully probed. + */ +static void +hipp_remove(struct pci_dev *dev) +{ + struct hipp_softc *sc = pci_get_drvdata(dev); + unsigned long l_flags; + + DPRINTF("%s()\n", __FUNCTION__); + + /* disable interrupts */ + HIPP_LOCK(sc); + +#if 0 + WRITE_REG_1(sc, HIFN_1_DMA_IER, 0); + HIFN_UNLOCK(sc); + + /*XXX other resources */ + del_timer_sync(&sc->sc_tickto); + + /* Turn off DMA polling */ + WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET | + HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE); +#endif + + crypto_unregister_all(sc->sc_cid); + + free_irq(sc->sc_irq, sc); + +#if 0 + pci_free_consistent(sc->sc_pcidev, sizeof(*sc->sc_dma), + sc->sc_dma, sc->sc_dma_physaddr); +#endif +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19) +static irqreturn_t hipp_intr(int irq, void *arg) +#else +static irqreturn_t hipp_intr(int irq, void *arg, struct pt_regs *regs) +#endif +{ + struct hipp_softc *sc = arg; + + sc = sc; /* shut up compiler */ + + return IRQ_HANDLED; +} + +static struct pci_device_id hipp_pci_tbl[] = { + { PCI_VENDOR_HIFN, PCI_PRODUCT_HIFN_7855, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, + { PCI_VENDOR_HIFN, PCI_PRODUCT_HIFN_8155, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, + { 0 }, /* terminating entry */ +}; +MODULE_DEVICE_TABLE(pci, hipp_pci_tbl); + +static struct pci_driver hipp_driver = { + .name = "hipp", + .id_table = hipp_pci_tbl, + .probe = hipp_probe, + .remove = hipp_remove, + /* add PM stuff here one day */ +}; + +static int __init hipp_init (void) +{ + struct hipp_softc *sc = NULL; + int rc; + + DPRINTF("%s(%p)\n", __FUNCTION__, hipp_init); + + rc = pci_register_driver(&hipp_driver); + pci_register_driver_compat(&hipp_driver, rc); + + return rc; +} + +static void __exit hipp_exit (void) +{ + pci_unregister_driver(&hipp_driver); +} + +module_init(hipp_init); +module_exit(hipp_exit); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_AUTHOR("Michael Richardson "); +MODULE_DESCRIPTION("OCF driver for hifn HIPP-I/II PCI crypto devices"); diff --git a/target/linux/generic/files/crypto/ocf/hifn/hifnHIPPreg.h b/target/linux/generic/files/crypto/ocf/hifn/hifnHIPPreg.h new file mode 100644 index 0000000..8c0e720 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/hifn/hifnHIPPreg.h @@ -0,0 +1,46 @@ +/*- + * Hifn HIPP-I/HIPP-II (7855/8155) driver. + * Copyright (c) 2006 Michael Richardson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Effort sponsored by Hifn inc. + * + */ + +#ifndef __HIFNHIPP_H__ +#define __HIFNHIPP_H__ + +/* + * PCI vendor and device identifiers + */ +#define PCI_VENDOR_HIFN 0x13a3 /* Hifn */ +#define PCI_PRODUCT_HIFN_6500 0x0006 /* 6500 */ +#define PCI_PRODUCT_HIFN_7855 0x001f /* 7855 */ +#define PCI_PRODUCT_HIFN_8155 0x999 /* XXX 8155 */ + +#define HIPP_1_REVID 0x01 /* BOGUS */ + +#endif /* __HIPP_H__ */ diff --git a/target/linux/generic/files/crypto/ocf/hifn/hifnHIPPvar.h b/target/linux/generic/files/crypto/ocf/hifn/hifnHIPPvar.h new file mode 100644 index 0000000..61d292f --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/hifn/hifnHIPPvar.h @@ -0,0 +1,93 @@ +/* + * Hifn HIPP-I/HIPP-II (7855/8155) driver. + * Copyright (c) 2006 Michael Richardson * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Effort sponsored by Hifn inc. + * + */ + +#ifndef __HIFNHIPPVAR_H__ +#define __HIFNHIPPVAR_H__ + +#define HIPP_MAX_CHIPS 8 + +/* + * Holds data specific to a single Hifn HIPP-I board. + */ +struct hipp_softc { + softc_device_decl sc_dev; + + struct pci_dev *sc_pcidev; /* device backpointer */ + ocf_iomem_t sc_bar[5]; + caddr_t sc_barphy[5]; /* physical address */ + int sc_num; /* for multiple devs */ + spinlock_t sc_mtx; /* per-instance lock */ + int32_t sc_cid; + int sc_irq; + +#if 0 + + u_int32_t sc_dmaier; + u_int32_t sc_drammodel; /* 1=dram, 0=sram */ + u_int32_t sc_pllconfig; /* 7954/7955/7956 PLL config */ + + struct hifn_dma *sc_dma; + dma_addr_t sc_dma_physaddr;/* physical address of sc_dma */ + + int sc_dmansegs; + int sc_maxses; + int sc_nsessions; + struct hifn_session *sc_sessions; + int sc_ramsize; + int sc_flags; +#define HIFN_HAS_RNG 0x1 /* includes random number generator */ +#define HIFN_HAS_PUBLIC 0x2 /* includes public key support */ +#define HIFN_HAS_AES 0x4 /* includes AES support */ +#define HIFN_IS_7811 0x8 /* Hifn 7811 part */ +#define HIFN_IS_7956 0x10 /* Hifn 7956/7955 don't have SDRAM */ + + struct timer_list sc_tickto; /* for managing DMA */ + + int sc_rngfirst; + int sc_rnghz; /* RNG polling frequency */ + + int sc_c_busy; /* command ring busy */ + int sc_s_busy; /* source data ring busy */ + int sc_d_busy; /* destination data ring busy */ + int sc_r_busy; /* result ring busy */ + int sc_active; /* for initial countdown */ + int sc_needwakeup; /* ops q'd wating on resources */ + int sc_curbatch; /* # ops submitted w/o int */ + int sc_suspended; + struct miscdevice sc_miscdev; +#endif +}; + +#define HIPP_LOCK(_sc) spin_lock_irqsave(&(_sc)->sc_mtx, l_flags) +#define HIPP_UNLOCK(_sc) spin_unlock_irqrestore(&(_sc)->sc_mtx, l_flags) + +#endif /* __HIFNHIPPVAR_H__ */ diff --git a/target/linux/generic/files/crypto/ocf/ixp4xx/Makefile b/target/linux/generic/files/crypto/ocf/ixp4xx/Makefile new file mode 100644 index 0000000..d94a3b7 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/ixp4xx/Makefile @@ -0,0 +1,104 @@ +# for SGlinux builds +-include $(ROOTDIR)/modules/.config + +# +# You will need to point this at your Intel ixp425 includes, this portion +# of the Makefile only really works under SGLinux with the appropriate libs +# installed. They can be downloaded from http://www.snapgear.org/ +# +ifeq ($(CONFIG_CPU_IXP46X),y) +IXPLATFORM = ixp46X +else +ifeq ($(CONFIG_CPU_IXP43X),y) +IXPLATFORM = ixp43X +else +IXPLATFORM = ixp42X +endif +endif + +ifdef CONFIG_IXP400_LIB_2_4 +IX_XSCALE_SW = $(ROOTDIR)/modules/ixp425/ixp400-2.4/ixp400_xscale_sw +OSAL_DIR = $(ROOTDIR)/modules/ixp425/ixp400-2.4/ixp_osal +endif +ifdef CONFIG_IXP400_LIB_2_1 +IX_XSCALE_SW = $(ROOTDIR)/modules/ixp425/ixp400-2.1/ixp400_xscale_sw +OSAL_DIR = $(ROOTDIR)/modules/ixp425/ixp400-2.1/ixp_osal +endif +ifdef CONFIG_IXP400_LIB_2_0 +IX_XSCALE_SW = $(ROOTDIR)/modules/ixp425/ixp400-2.0/ixp400_xscale_sw +OSAL_DIR = $(ROOTDIR)/modules/ixp425/ixp400-2.0/ixp_osal +endif +ifdef IX_XSCALE_SW +ifdef CONFIG_IXP400_LIB_2_4 +IXP_CFLAGS = \ + -I$(ROOTDIR)/. \ + -I$(IX_XSCALE_SW)/src/include \ + -I$(OSAL_DIR)/common/include/ \ + -I$(OSAL_DIR)/common/include/modules/ \ + -I$(OSAL_DIR)/common/include/modules/ddk/ \ + -I$(OSAL_DIR)/common/include/modules/bufferMgt/ \ + -I$(OSAL_DIR)/common/include/modules/ioMem/ \ + -I$(OSAL_DIR)/common/os/linux/include/ \ + -I$(OSAL_DIR)/common/os/linux/include/core/ \ + -I$(OSAL_DIR)/common/os/linux/include/modules/ \ + -I$(OSAL_DIR)/common/os/linux/include/modules/ddk/ \ + -I$(OSAL_DIR)/common/os/linux/include/modules/bufferMgt/ \ + -I$(OSAL_DIR)/common/os/linux/include/modules/ioMem/ \ + -I$(OSAL_DIR)/platforms/$(IXPLATFORM)/include/ \ + -I$(OSAL_DIR)/platforms/$(IXPLATFORM)/os/linux/include/ \ + -DENABLE_IOMEM -DENABLE_BUFFERMGT -DENABLE_DDK \ + -DUSE_IXP4XX_CRYPTO +else +IXP_CFLAGS = \ + -I$(ROOTDIR)/. \ + -I$(IX_XSCALE_SW)/src/include \ + -I$(OSAL_DIR)/ \ + -I$(OSAL_DIR)/os/linux/include/ \ + -I$(OSAL_DIR)/os/linux/include/modules/ \ + -I$(OSAL_DIR)/os/linux/include/modules/ioMem/ \ + -I$(OSAL_DIR)/os/linux/include/modules/bufferMgt/ \ + -I$(OSAL_DIR)/os/linux/include/core/ \ + -I$(OSAL_DIR)/os/linux/include/platforms/ \ + -I$(OSAL_DIR)/os/linux/include/platforms/ixp400/ \ + -I$(OSAL_DIR)/os/linux/include/platforms/ixp400/ixp425 \ + -I$(OSAL_DIR)/os/linux/include/platforms/ixp400/ixp465 \ + -I$(OSAL_DIR)/os/linux/include/core/ \ + -I$(OSAL_DIR)/include/ \ + -I$(OSAL_DIR)/include/modules/ \ + -I$(OSAL_DIR)/include/modules/bufferMgt/ \ + -I$(OSAL_DIR)/include/modules/ioMem/ \ + -I$(OSAL_DIR)/include/platforms/ \ + -I$(OSAL_DIR)/include/platforms/ixp400/ \ + -DUSE_IXP4XX_CRYPTO +endif +endif +ifdef CONFIG_IXP400_LIB_1_4 +IXP_CFLAGS = \ + -I$(ROOTDIR)/. \ + -I$(ROOTDIR)/modules/ixp425/ixp400-1.4/ixp400_xscale_sw/src/include \ + -I$(ROOTDIR)/modules/ixp425/ixp400-1.4/ixp400_xscale_sw/src/linux \ + -DUSE_IXP4XX_CRYPTO +endif +ifndef IXPDIR +IXPDIR = ixp-version-is-not-supported +endif + +ifeq ($(CONFIG_CPU_IXP46X),y) +IXP_CFLAGS += -D__ixp46X +else +ifeq ($(CONFIG_CPU_IXP43X),y) +IXP_CFLAGS += -D__ixp43X +else +IXP_CFLAGS += -D__ixp42X +endif +endif + +obj-$(CONFIG_OCF_IXP4XX) += ixp4xx.o + +obj ?= . +EXTRA_CFLAGS += $(IXP_CFLAGS) -I$(obj)/.. -I$(obj)/. + +ifdef TOPDIR +-include $(TOPDIR)/Rules.make +endif + diff --git a/target/linux/generic/files/crypto/ocf/ixp4xx/ixp4xx.c b/target/linux/generic/files/crypto/ocf/ixp4xx/ixp4xx.c new file mode 100644 index 0000000..ede598f --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/ixp4xx/ixp4xx.c @@ -0,0 +1,1339 @@ +/* + * An OCF module that uses Intels IXP CryptACC API to do the crypto. + * This driver requires the IXP400 Access Library that is available + * from Intel in order to operate (or compile). + * + * Written by David McCullough + * Copyright (C) 2006-2011 David McCullough + * Copyright (C) 2004-2005 Intel Corporation. + * + * LICENSE TERMS + * + * The free distribution and use of this software in both source and binary + * form is allowed (with or without changes) provided that: + * + * 1. distributions of this source code include the above copyright + * notice, this list of conditions and the following disclaimer; + * + * 2. distributions in binary form include the above copyright + * notice, this list of conditions and the following disclaimer + * in the documentation and/or other associated materials; + * + * 3. the copyright holder's name is not used to endorse products + * built using this software without specific written permission. + * + * ALTERNATIVELY, provided that this notice is retained in full, this product + * may be distributed under the terms of the GNU General Public License (GPL), + * in which case the provisions of the GPL apply INSTEAD OF those given above. + * + * DISCLAIMER + * + * This software is provided 'as is' with no explicit or implied warranties + * in respect of its properties, including, but not limited to, correctness + * and/or fitness for purpose. + */ + +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) && !defined(AUTOCONF_INCLUDED) +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifndef IX_MBUF_PRIV +#define IX_MBUF_PRIV(x) ((x)->priv) +#endif + +struct ixp_data; + +struct ixp_q { + struct list_head ixp_q_list; + struct ixp_data *ixp_q_data; + struct cryptop *ixp_q_crp; + struct cryptodesc *ixp_q_ccrd; + struct cryptodesc *ixp_q_acrd; + IX_MBUF ixp_q_mbuf; + UINT8 *ixp_hash_dest; /* Location for hash in client buffer */ + UINT8 *ixp_hash_src; /* Location of hash in internal buffer */ + unsigned char ixp_q_iv_data[IX_CRYPTO_ACC_MAX_CIPHER_IV_LENGTH]; + unsigned char *ixp_q_iv; +}; + +struct ixp_data { + int ixp_registered; /* is the context registered */ + int ixp_crd_flags; /* detect direction changes */ + + int ixp_cipher_alg; + int ixp_auth_alg; + + UINT32 ixp_ctx_id; + UINT32 ixp_hash_key_id; /* used when hashing */ + IxCryptoAccCtx ixp_ctx; + IX_MBUF ixp_pri_mbuf; + IX_MBUF ixp_sec_mbuf; + + struct work_struct ixp_pending_work; + struct work_struct ixp_registration_work; + struct list_head ixp_q; /* unprocessed requests */ +}; + +#ifdef __ixp46X + +#define MAX_IOP_SIZE 64 /* words */ +#define MAX_OOP_SIZE 128 + +#define MAX_PARAMS 3 + +struct ixp_pkq { + struct list_head pkq_list; + struct cryptkop *pkq_krp; + + IxCryptoAccPkeEauInOperands pkq_op; + IxCryptoAccPkeEauOpResult pkq_result; + + UINT32 pkq_ibuf0[MAX_IOP_SIZE]; + UINT32 pkq_ibuf1[MAX_IOP_SIZE]; + UINT32 pkq_ibuf2[MAX_IOP_SIZE]; + UINT32 pkq_obuf[MAX_OOP_SIZE]; +}; + +static LIST_HEAD(ixp_pkq); /* current PK wait list */ +static struct ixp_pkq *ixp_pk_cur; +static spinlock_t ixp_pkq_lock; + +#endif /* __ixp46X */ + +static int ixp_blocked = 0; + +static int32_t ixp_id = -1; +static struct ixp_data **ixp_sessions = NULL; +static u_int32_t ixp_sesnum = 0; + +static int ixp_process(device_t, struct cryptop *, int); +static int ixp_newsession(device_t, u_int32_t *, struct cryptoini *); +static int ixp_freesession(device_t, u_int64_t); +#ifdef __ixp46X +static int ixp_kprocess(device_t, struct cryptkop *krp, int hint); +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) +static kmem_cache_t *qcache; +#else +static struct kmem_cache *qcache; +#endif + +#define debug ixp_debug +static int ixp_debug = 0; +module_param(ixp_debug, int, 0644); +MODULE_PARM_DESC(ixp_debug, "Enable debug"); + +static int ixp_init_crypto = 1; +module_param(ixp_init_crypto, int, 0444); /* RO after load/boot */ +MODULE_PARM_DESC(ixp_init_crypto, "Call ixCryptoAccInit (default is 1)"); + +static void ixp_process_pending(void *arg); +static void ixp_registration(void *arg); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) +static void ixp_process_pending_wq(struct work_struct *work); +static void ixp_registration_wq(struct work_struct *work); +#endif + +/* + * dummy device structure + */ + +static struct { + softc_device_decl sc_dev; +} ixpdev; + +static device_method_t ixp_methods = { + /* crypto device methods */ + DEVMETHOD(cryptodev_newsession, ixp_newsession), + DEVMETHOD(cryptodev_freesession,ixp_freesession), + DEVMETHOD(cryptodev_process, ixp_process), +#ifdef __ixp46X + DEVMETHOD(cryptodev_kprocess, ixp_kprocess), +#endif +}; + +/* + * Generate a new software session. + */ +static int +ixp_newsession(device_t dev, u_int32_t *sid, struct cryptoini *cri) +{ + struct ixp_data *ixp; + u_int32_t i; +#define AUTH_LEN(cri, def) \ + (cri->cri_mlen ? cri->cri_mlen : (def)) + + dprintk("%s():alg %d\n", __FUNCTION__,cri->cri_alg); + if (sid == NULL || cri == NULL) { + dprintk("%s,%d - EINVAL\n", __FILE__, __LINE__); + return EINVAL; + } + + if (ixp_sessions) { + for (i = 1; i < ixp_sesnum; i++) + if (ixp_sessions[i] == NULL) + break; + } else + i = 1; /* NB: to silence compiler warning */ + + if (ixp_sessions == NULL || i == ixp_sesnum) { + struct ixp_data **ixpd; + + if (ixp_sessions == NULL) { + i = 1; /* We leave ixp_sessions[0] empty */ + ixp_sesnum = CRYPTO_SW_SESSIONS; + } else + ixp_sesnum *= 2; + + ixpd = kmalloc(ixp_sesnum * sizeof(struct ixp_data *), SLAB_ATOMIC); + if (ixpd == NULL) { + /* Reset session number */ + if (ixp_sesnum == CRYPTO_SW_SESSIONS) + ixp_sesnum = 0; + else + ixp_sesnum /= 2; + dprintk("%s,%d: ENOBUFS\n", __FILE__, __LINE__); + return ENOBUFS; + } + memset(ixpd, 0, ixp_sesnum * sizeof(struct ixp_data *)); + + /* Copy existing sessions */ + if (ixp_sessions) { + memcpy(ixpd, ixp_sessions, + (ixp_sesnum / 2) * sizeof(struct ixp_data *)); + kfree(ixp_sessions); + } + + ixp_sessions = ixpd; + } + + ixp_sessions[i] = (struct ixp_data *) kmalloc(sizeof(struct ixp_data), + SLAB_ATOMIC); + if (ixp_sessions[i] == NULL) { + ixp_freesession(NULL, i); + dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__); + return ENOBUFS; + } + + *sid = i; + + ixp = ixp_sessions[i]; + memset(ixp, 0, sizeof(*ixp)); + + ixp->ixp_cipher_alg = -1; + ixp->ixp_auth_alg = -1; + ixp->ixp_ctx_id = -1; + INIT_LIST_HEAD(&ixp->ixp_q); + + ixp->ixp_ctx.useDifferentSrcAndDestMbufs = 0; + + while (cri) { + switch (cri->cri_alg) { + case CRYPTO_DES_CBC: + ixp->ixp_cipher_alg = cri->cri_alg; + ixp->ixp_ctx.cipherCtx.cipherAlgo = IX_CRYPTO_ACC_CIPHER_DES; + ixp->ixp_ctx.cipherCtx.cipherMode = IX_CRYPTO_ACC_MODE_CBC; + ixp->ixp_ctx.cipherCtx.cipherKeyLen = (cri->cri_klen + 7) / 8; + ixp->ixp_ctx.cipherCtx.cipherBlockLen = IX_CRYPTO_ACC_DES_BLOCK_64; + ixp->ixp_ctx.cipherCtx.cipherInitialVectorLen = + IX_CRYPTO_ACC_DES_IV_64; + memcpy(ixp->ixp_ctx.cipherCtx.key.cipherKey, + cri->cri_key, (cri->cri_klen + 7) / 8); + break; + + case CRYPTO_3DES_CBC: + ixp->ixp_cipher_alg = cri->cri_alg; + ixp->ixp_ctx.cipherCtx.cipherAlgo = IX_CRYPTO_ACC_CIPHER_3DES; + ixp->ixp_ctx.cipherCtx.cipherMode = IX_CRYPTO_ACC_MODE_CBC; + ixp->ixp_ctx.cipherCtx.cipherKeyLen = (cri->cri_klen + 7) / 8; + ixp->ixp_ctx.cipherCtx.cipherBlockLen = IX_CRYPTO_ACC_DES_BLOCK_64; + ixp->ixp_ctx.cipherCtx.cipherInitialVectorLen = + IX_CRYPTO_ACC_DES_IV_64; + memcpy(ixp->ixp_ctx.cipherCtx.key.cipherKey, + cri->cri_key, (cri->cri_klen + 7) / 8); + break; + + case CRYPTO_RIJNDAEL128_CBC: + ixp->ixp_cipher_alg = cri->cri_alg; + ixp->ixp_ctx.cipherCtx.cipherAlgo = IX_CRYPTO_ACC_CIPHER_AES; + ixp->ixp_ctx.cipherCtx.cipherMode = IX_CRYPTO_ACC_MODE_CBC; + ixp->ixp_ctx.cipherCtx.cipherKeyLen = (cri->cri_klen + 7) / 8; + ixp->ixp_ctx.cipherCtx.cipherBlockLen = 16; + ixp->ixp_ctx.cipherCtx.cipherInitialVectorLen = 16; + memcpy(ixp->ixp_ctx.cipherCtx.key.cipherKey, + cri->cri_key, (cri->cri_klen + 7) / 8); + break; + + case CRYPTO_MD5: + case CRYPTO_MD5_HMAC: + ixp->ixp_auth_alg = cri->cri_alg; + ixp->ixp_ctx.authCtx.authAlgo = IX_CRYPTO_ACC_AUTH_MD5; + ixp->ixp_ctx.authCtx.authDigestLen = AUTH_LEN(cri, MD5_HASH_LEN); + ixp->ixp_ctx.authCtx.aadLen = 0; + /* Only MD5_HMAC needs a key */ + if (cri->cri_alg == CRYPTO_MD5_HMAC) { + ixp->ixp_ctx.authCtx.authKeyLen = (cri->cri_klen + 7) / 8; + if (ixp->ixp_ctx.authCtx.authKeyLen > + sizeof(ixp->ixp_ctx.authCtx.key.authKey)) { + printk( + "ixp4xx: Invalid key length for MD5_HMAC - %d bits\n", + cri->cri_klen); + ixp_freesession(NULL, i); + return EINVAL; + } + memcpy(ixp->ixp_ctx.authCtx.key.authKey, + cri->cri_key, (cri->cri_klen + 7) / 8); + } + break; + + case CRYPTO_SHA1: + case CRYPTO_SHA1_HMAC: + ixp->ixp_auth_alg = cri->cri_alg; + ixp->ixp_ctx.authCtx.authAlgo = IX_CRYPTO_ACC_AUTH_SHA1; + ixp->ixp_ctx.authCtx.authDigestLen = AUTH_LEN(cri, SHA1_HASH_LEN); + ixp->ixp_ctx.authCtx.aadLen = 0; + /* Only SHA1_HMAC needs a key */ + if (cri->cri_alg == CRYPTO_SHA1_HMAC) { + ixp->ixp_ctx.authCtx.authKeyLen = (cri->cri_klen + 7) / 8; + if (ixp->ixp_ctx.authCtx.authKeyLen > + sizeof(ixp->ixp_ctx.authCtx.key.authKey)) { + printk( + "ixp4xx: Invalid key length for SHA1_HMAC - %d bits\n", + cri->cri_klen); + ixp_freesession(NULL, i); + return EINVAL; + } + memcpy(ixp->ixp_ctx.authCtx.key.authKey, + cri->cri_key, (cri->cri_klen + 7) / 8); + } + break; + + default: + printk("ixp: unknown algo 0x%x\n", cri->cri_alg); + ixp_freesession(NULL, i); + return EINVAL; + } + cri = cri->cri_next; + } + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + INIT_WORK(&ixp->ixp_pending_work, ixp_process_pending_wq); + INIT_WORK(&ixp->ixp_registration_work, ixp_registration_wq); +#else + INIT_WORK(&ixp->ixp_pending_work, ixp_process_pending, ixp); + INIT_WORK(&ixp->ixp_registration_work, ixp_registration, ixp); +#endif + + return 0; +} + + +/* + * Free a session. + */ +static int +ixp_freesession(device_t dev, u_int64_t tid) +{ + u_int32_t sid = CRYPTO_SESID2LID(tid); + + dprintk("%s()\n", __FUNCTION__); + if (sid > ixp_sesnum || ixp_sessions == NULL || + ixp_sessions[sid] == NULL) { + dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__); + return EINVAL; + } + + /* Silently accept and return */ + if (sid == 0) + return 0; + + if (ixp_sessions[sid]) { + if (ixp_sessions[sid]->ixp_ctx_id != -1) { + ixCryptoAccCtxUnregister(ixp_sessions[sid]->ixp_ctx_id); + ixp_sessions[sid]->ixp_ctx_id = -1; + } + kfree(ixp_sessions[sid]); + } + ixp_sessions[sid] = NULL; + if (ixp_blocked) { + ixp_blocked = 0; + crypto_unblock(ixp_id, CRYPTO_SYMQ); + } + return 0; +} + + +/* + * callback for when hash processing is complete + */ + +static void +ixp_hash_perform_cb( + UINT32 hash_key_id, + IX_MBUF *bufp, + IxCryptoAccStatus status) +{ + struct ixp_q *q; + + dprintk("%s(%u, %p, 0x%x)\n", __FUNCTION__, hash_key_id, bufp, status); + + if (bufp == NULL) { + printk("ixp: NULL buf in %s\n", __FUNCTION__); + return; + } + + q = IX_MBUF_PRIV(bufp); + if (q == NULL) { + printk("ixp: NULL priv in %s\n", __FUNCTION__); + return; + } + + if (status == IX_CRYPTO_ACC_STATUS_SUCCESS) { + /* On success, need to copy hash back into original client buffer */ + memcpy(q->ixp_hash_dest, q->ixp_hash_src, + (q->ixp_q_data->ixp_auth_alg == CRYPTO_SHA1) ? + SHA1_HASH_LEN : MD5_HASH_LEN); + } + else { + printk("ixp: hash perform failed status=%d\n", status); + q->ixp_q_crp->crp_etype = EINVAL; + } + + /* Free internal buffer used for hashing */ + kfree(IX_MBUF_MDATA(&q->ixp_q_mbuf)); + + crypto_done(q->ixp_q_crp); + kmem_cache_free(qcache, q); +} + +/* + * setup a request and perform it + */ +static void +ixp_q_process(struct ixp_q *q) +{ + IxCryptoAccStatus status; + struct ixp_data *ixp = q->ixp_q_data; + int auth_off = 0; + int auth_len = 0; + int crypt_off = 0; + int crypt_len = 0; + int icv_off = 0; + char *crypt_func; + + dprintk("%s(%p)\n", __FUNCTION__, q); + + if (q->ixp_q_ccrd) { + if (q->ixp_q_ccrd->crd_flags & CRD_F_ENCRYPT) { + if (q->ixp_q_ccrd->crd_flags & CRD_F_IV_EXPLICIT) { + q->ixp_q_iv = q->ixp_q_ccrd->crd_iv; + } else { + q->ixp_q_iv = q->ixp_q_iv_data; + read_random(q->ixp_q_iv, ixp->ixp_ctx.cipherCtx.cipherInitialVectorLen); + } + if ((q->ixp_q_ccrd->crd_flags & CRD_F_IV_PRESENT) == 0) + crypto_copyback(q->ixp_q_crp->crp_flags, q->ixp_q_crp->crp_buf, + q->ixp_q_ccrd->crd_inject, + ixp->ixp_ctx.cipherCtx.cipherInitialVectorLen, + (caddr_t) q->ixp_q_iv); + } else { + if (q->ixp_q_ccrd->crd_flags & CRD_F_IV_EXPLICIT) + q->ixp_q_iv = q->ixp_q_ccrd->crd_iv; + else { + q->ixp_q_iv = q->ixp_q_iv_data; + crypto_copydata(q->ixp_q_crp->crp_flags, q->ixp_q_crp->crp_buf, + q->ixp_q_ccrd->crd_inject, + ixp->ixp_ctx.cipherCtx.cipherInitialVectorLen, + (caddr_t) q->ixp_q_iv); + } + } + + if (q->ixp_q_acrd) { + auth_off = q->ixp_q_acrd->crd_skip; + auth_len = q->ixp_q_acrd->crd_len; + icv_off = q->ixp_q_acrd->crd_inject; + } + + crypt_off = q->ixp_q_ccrd->crd_skip; + crypt_len = q->ixp_q_ccrd->crd_len; + } else { /* if (q->ixp_q_acrd) */ + auth_off = q->ixp_q_acrd->crd_skip; + auth_len = q->ixp_q_acrd->crd_len; + icv_off = q->ixp_q_acrd->crd_inject; + } + + if (q->ixp_q_crp->crp_flags & CRYPTO_F_SKBUF) { + struct sk_buff *skb = (struct sk_buff *) q->ixp_q_crp->crp_buf; + if (skb_shinfo(skb)->nr_frags) { + /* + * DAVIDM fix this limitation one day by using + * a buffer pool and chaining, it is not currently + * needed for current user/kernel space acceleration + */ + printk("ixp: Cannot handle fragmented skb's yet !\n"); + q->ixp_q_crp->crp_etype = ENOENT; + goto done; + } + IX_MBUF_MLEN(&q->ixp_q_mbuf) = + IX_MBUF_PKT_LEN(&q->ixp_q_mbuf) = skb->len; + IX_MBUF_MDATA(&q->ixp_q_mbuf) = skb->data; + } else if (q->ixp_q_crp->crp_flags & CRYPTO_F_IOV) { + struct uio *uiop = (struct uio *) q->ixp_q_crp->crp_buf; + if (uiop->uio_iovcnt != 1) { + /* + * DAVIDM fix this limitation one day by using + * a buffer pool and chaining, it is not currently + * needed for current user/kernel space acceleration + */ + printk("ixp: Cannot handle more than 1 iovec yet !\n"); + q->ixp_q_crp->crp_etype = ENOENT; + goto done; + } + IX_MBUF_MLEN(&q->ixp_q_mbuf) = + IX_MBUF_PKT_LEN(&q->ixp_q_mbuf) = uiop->uio_iov[0].iov_len; + IX_MBUF_MDATA(&q->ixp_q_mbuf) = uiop->uio_iov[0].iov_base; + } else /* contig buffer */ { + IX_MBUF_MLEN(&q->ixp_q_mbuf) = + IX_MBUF_PKT_LEN(&q->ixp_q_mbuf) = q->ixp_q_crp->crp_ilen; + IX_MBUF_MDATA(&q->ixp_q_mbuf) = q->ixp_q_crp->crp_buf; + } + + IX_MBUF_PRIV(&q->ixp_q_mbuf) = q; + + if (ixp->ixp_auth_alg == CRYPTO_SHA1 || ixp->ixp_auth_alg == CRYPTO_MD5) { + /* + * For SHA1 and MD5 hash, need to create an internal buffer that is big + * enough to hold the original data + the appropriate padding for the + * hash algorithm. + */ + UINT8 *tbuf = NULL; + + IX_MBUF_MLEN(&q->ixp_q_mbuf) = IX_MBUF_PKT_LEN(&q->ixp_q_mbuf) = + ((IX_MBUF_MLEN(&q->ixp_q_mbuf) * 8) + 72 + 511) / 8; + tbuf = kmalloc(IX_MBUF_MLEN(&q->ixp_q_mbuf), SLAB_ATOMIC); + + if (IX_MBUF_MDATA(&q->ixp_q_mbuf) == NULL) { + printk("ixp: kmalloc(%u, SLAB_ATOMIC) failed\n", + IX_MBUF_MLEN(&q->ixp_q_mbuf)); + q->ixp_q_crp->crp_etype = ENOMEM; + goto done; + } + memcpy(tbuf, &(IX_MBUF_MDATA(&q->ixp_q_mbuf))[auth_off], auth_len); + + /* Set location in client buffer to copy hash into */ + q->ixp_hash_dest = + &(IX_MBUF_MDATA(&q->ixp_q_mbuf))[auth_off + auth_len]; + + IX_MBUF_MDATA(&q->ixp_q_mbuf) = tbuf; + + /* Set location in internal buffer for where hash starts */ + q->ixp_hash_src = &(IX_MBUF_MDATA(&q->ixp_q_mbuf))[auth_len]; + + crypt_func = "ixCryptoAccHashPerform"; + status = ixCryptoAccHashPerform(ixp->ixp_ctx.authCtx.authAlgo, + &q->ixp_q_mbuf, ixp_hash_perform_cb, 0, auth_len, auth_len, + &ixp->ixp_hash_key_id); + } + else { + crypt_func = "ixCryptoAccAuthCryptPerform"; + status = ixCryptoAccAuthCryptPerform(ixp->ixp_ctx_id, &q->ixp_q_mbuf, + NULL, auth_off, auth_len, crypt_off, crypt_len, icv_off, + q->ixp_q_iv); + } + + if (IX_CRYPTO_ACC_STATUS_SUCCESS == status) + return; + + if (IX_CRYPTO_ACC_STATUS_QUEUE_FULL == status) { + q->ixp_q_crp->crp_etype = ENOMEM; + goto done; + } + + printk("ixp: %s failed %u\n", crypt_func, status); + q->ixp_q_crp->crp_etype = EINVAL; + +done: + crypto_done(q->ixp_q_crp); + kmem_cache_free(qcache, q); +} + + +/* + * because we cannot process the Q from the Register callback + * we do it here on a task Q. + */ + +static void +ixp_process_pending(void *arg) +{ + struct ixp_data *ixp = arg; + struct ixp_q *q = NULL; + + dprintk("%s(%p)\n", __FUNCTION__, arg); + + if (!ixp) + return; + + while (!list_empty(&ixp->ixp_q)) { + q = list_entry(ixp->ixp_q.next, struct ixp_q, ixp_q_list); + list_del(&q->ixp_q_list); + ixp_q_process(q); + } +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) +static void +ixp_process_pending_wq(struct work_struct *work) +{ + struct ixp_data *ixp = container_of(work, struct ixp_data, ixp_pending_work); + ixp_process_pending(ixp); +} +#endif + +/* + * callback for when context registration is complete + */ + +static void +ixp_register_cb(UINT32 ctx_id, IX_MBUF *bufp, IxCryptoAccStatus status) +{ + int i; + struct ixp_data *ixp; + struct ixp_q *q; + + dprintk("%s(%d, %p, %d)\n", __FUNCTION__, ctx_id, bufp, status); + + /* + * free any buffer passed in to this routine + */ + if (bufp) { + IX_MBUF_MLEN(bufp) = IX_MBUF_PKT_LEN(bufp) = 0; + kfree(IX_MBUF_MDATA(bufp)); + IX_MBUF_MDATA(bufp) = NULL; + } + + for (i = 0; i < ixp_sesnum; i++) { + ixp = ixp_sessions[i]; + if (ixp && ixp->ixp_ctx_id == ctx_id) + break; + } + if (i >= ixp_sesnum) { + printk("ixp: invalid context id %d\n", ctx_id); + return; + } + + if (IX_CRYPTO_ACC_STATUS_WAIT == status) { + /* this is normal to free the first of two buffers */ + dprintk("ixp: register not finished yet.\n"); + return; + } + + if (IX_CRYPTO_ACC_STATUS_SUCCESS != status) { + printk("ixp: register failed 0x%x\n", status); + while (!list_empty(&ixp->ixp_q)) { + q = list_entry(ixp->ixp_q.next, struct ixp_q, ixp_q_list); + list_del(&q->ixp_q_list); + q->ixp_q_crp->crp_etype = EINVAL; + crypto_done(q->ixp_q_crp); + kmem_cache_free(qcache, q); + } + return; + } + + /* + * we are now registered, we cannot start processing the Q here + * or we get strange errors with AES (DES/3DES seem to be ok). + */ + ixp->ixp_registered = 1; + schedule_work(&ixp->ixp_pending_work); +} + + +/* + * callback for when data processing is complete + */ + +static void +ixp_perform_cb( + UINT32 ctx_id, + IX_MBUF *sbufp, + IX_MBUF *dbufp, + IxCryptoAccStatus status) +{ + struct ixp_q *q; + + dprintk("%s(%d, %p, %p, 0x%x)\n", __FUNCTION__, ctx_id, sbufp, + dbufp, status); + + if (sbufp == NULL) { + printk("ixp: NULL sbuf in ixp_perform_cb\n"); + return; + } + + q = IX_MBUF_PRIV(sbufp); + if (q == NULL) { + printk("ixp: NULL priv in ixp_perform_cb\n"); + return; + } + + if (status != IX_CRYPTO_ACC_STATUS_SUCCESS) { + printk("ixp: perform failed status=%d\n", status); + q->ixp_q_crp->crp_etype = EINVAL; + } + + crypto_done(q->ixp_q_crp); + kmem_cache_free(qcache, q); +} + + +/* + * registration is not callable at IRQ time, so we defer + * to a task queue, this routines completes the registration for us + * when the task queue runs + * + * Unfortunately this means we cannot tell OCF that the driver is blocked, + * we do that on the next request. + */ + +static void +ixp_registration(void *arg) +{ + struct ixp_data *ixp = arg; + struct ixp_q *q = NULL; + IX_MBUF *pri = NULL, *sec = NULL; + int status = IX_CRYPTO_ACC_STATUS_SUCCESS; + + if (!ixp) { + printk("ixp: ixp_registration with no arg\n"); + return; + } + + if (ixp->ixp_ctx_id != -1) { + ixCryptoAccCtxUnregister(ixp->ixp_ctx_id); + ixp->ixp_ctx_id = -1; + } + + if (list_empty(&ixp->ixp_q)) { + printk("ixp: ixp_registration with no Q\n"); + return; + } + + /* + * setup the primary and secondary buffers + */ + q = list_entry(ixp->ixp_q.next, struct ixp_q, ixp_q_list); + if (q->ixp_q_acrd) { + pri = &ixp->ixp_pri_mbuf; + sec = &ixp->ixp_sec_mbuf; + IX_MBUF_MLEN(pri) = IX_MBUF_PKT_LEN(pri) = 128; + IX_MBUF_MDATA(pri) = (unsigned char *) kmalloc(128, SLAB_ATOMIC); + IX_MBUF_MLEN(sec) = IX_MBUF_PKT_LEN(sec) = 128; + IX_MBUF_MDATA(sec) = (unsigned char *) kmalloc(128, SLAB_ATOMIC); + } + + /* Only need to register if a crypt op or HMAC op */ + if (!(ixp->ixp_auth_alg == CRYPTO_SHA1 || + ixp->ixp_auth_alg == CRYPTO_MD5)) { + status = ixCryptoAccCtxRegister( + &ixp->ixp_ctx, + pri, sec, + ixp_register_cb, + ixp_perform_cb, + &ixp->ixp_ctx_id); + } + else { + /* Otherwise we start processing pending q */ + schedule_work(&ixp->ixp_pending_work); + } + + if (IX_CRYPTO_ACC_STATUS_SUCCESS == status) + return; + + if (IX_CRYPTO_ACC_STATUS_EXCEED_MAX_TUNNELS == status) { + printk("ixp: ixCryptoAccCtxRegister failed (out of tunnels)\n"); + ixp_blocked = 1; + /* perhaps we should return EGAIN on queued ops ? */ + return; + } + + printk("ixp: ixCryptoAccCtxRegister failed %d\n", status); + ixp->ixp_ctx_id = -1; + + /* + * everything waiting is toasted + */ + while (!list_empty(&ixp->ixp_q)) { + q = list_entry(ixp->ixp_q.next, struct ixp_q, ixp_q_list); + list_del(&q->ixp_q_list); + q->ixp_q_crp->crp_etype = ENOENT; + crypto_done(q->ixp_q_crp); + kmem_cache_free(qcache, q); + } +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) +static void +ixp_registration_wq(struct work_struct *work) +{ + struct ixp_data *ixp = container_of(work, struct ixp_data, + ixp_registration_work); + ixp_registration(ixp); +} +#endif + +/* + * Process a request. + */ +static int +ixp_process(device_t dev, struct cryptop *crp, int hint) +{ + struct ixp_data *ixp; + unsigned int lid; + struct ixp_q *q = NULL; + int status; + + dprintk("%s()\n", __FUNCTION__); + + /* Sanity check */ + if (crp == NULL) { + dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__); + return EINVAL; + } + + crp->crp_etype = 0; + + if (ixp_blocked) + return ERESTART; + + if (crp->crp_desc == NULL || crp->crp_buf == NULL) { + dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__); + crp->crp_etype = EINVAL; + goto done; + } + + /* + * find the session we are using + */ + + lid = crp->crp_sid & 0xffffffff; + if (lid >= ixp_sesnum || lid == 0 || ixp_sessions == NULL || + ixp_sessions[lid] == NULL) { + crp->crp_etype = ENOENT; + dprintk("%s,%d: ENOENT\n", __FILE__, __LINE__); + goto done; + } + ixp = ixp_sessions[lid]; + + /* + * setup a new request ready for queuing + */ + q = kmem_cache_alloc(qcache, SLAB_ATOMIC); + if (q == NULL) { + dprintk("%s,%d: ENOMEM\n", __FILE__, __LINE__); + crp->crp_etype = ENOMEM; + goto done; + } + /* + * save some cycles by only zeroing the important bits + */ + memset(&q->ixp_q_mbuf, 0, sizeof(q->ixp_q_mbuf)); + q->ixp_q_ccrd = NULL; + q->ixp_q_acrd = NULL; + q->ixp_q_crp = crp; + q->ixp_q_data = ixp; + + /* + * point the cipher and auth descriptors appropriately + * check that we have something to do + */ + if (crp->crp_desc->crd_alg == ixp->ixp_cipher_alg) + q->ixp_q_ccrd = crp->crp_desc; + else if (crp->crp_desc->crd_alg == ixp->ixp_auth_alg) + q->ixp_q_acrd = crp->crp_desc; + else { + crp->crp_etype = ENOENT; + dprintk("%s,%d: bad desc match: ENOENT\n", __FILE__, __LINE__); + goto done; + } + if (crp->crp_desc->crd_next) { + if (crp->crp_desc->crd_next->crd_alg == ixp->ixp_cipher_alg) + q->ixp_q_ccrd = crp->crp_desc->crd_next; + else if (crp->crp_desc->crd_next->crd_alg == ixp->ixp_auth_alg) + q->ixp_q_acrd = crp->crp_desc->crd_next; + else { + crp->crp_etype = ENOENT; + dprintk("%s,%d: bad desc match: ENOENT\n", __FILE__, __LINE__); + goto done; + } + } + + /* + * If there is a direction change for this context then we mark it as + * unregistered and re-register is for the new direction. This is not + * a very expensive operation and currently only tends to happen when + * user-space application are doing benchmarks + * + * DM - we should be checking for pending requests before unregistering. + */ + if (q->ixp_q_ccrd && ixp->ixp_registered && + ixp->ixp_crd_flags != (q->ixp_q_ccrd->crd_flags & CRD_F_ENCRYPT)) { + dprintk("%s - detected direction change on session\n", __FUNCTION__); + ixp->ixp_registered = 0; + } + + /* + * if we are registered, call straight into the perform code + */ + if (ixp->ixp_registered) { + ixp_q_process(q); + return 0; + } + + /* + * the only part of the context not set in newsession is the direction + * dependent parts + */ + if (q->ixp_q_ccrd) { + ixp->ixp_crd_flags = (q->ixp_q_ccrd->crd_flags & CRD_F_ENCRYPT); + if (q->ixp_q_ccrd->crd_flags & CRD_F_ENCRYPT) { + ixp->ixp_ctx.operation = q->ixp_q_acrd ? + IX_CRYPTO_ACC_OP_ENCRYPT_AUTH : IX_CRYPTO_ACC_OP_ENCRYPT; + } else { + ixp->ixp_ctx.operation = q->ixp_q_acrd ? + IX_CRYPTO_ACC_OP_AUTH_DECRYPT : IX_CRYPTO_ACC_OP_DECRYPT; + } + } else { + /* q->ixp_q_acrd must be set if we are here */ + ixp->ixp_ctx.operation = IX_CRYPTO_ACC_OP_AUTH_CALC; + } + + status = list_empty(&ixp->ixp_q); + list_add_tail(&q->ixp_q_list, &ixp->ixp_q); + if (status) + schedule_work(&ixp->ixp_registration_work); + return 0; + +done: + if (q) + kmem_cache_free(qcache, q); + crypto_done(crp); + return 0; +} + + +#ifdef __ixp46X +/* + * key processing support for the ixp465 + */ + + +/* + * copy a BN (LE) into a buffer (BE) an fill out the op appropriately + * assume zeroed and only copy bits that are significant + */ + +static int +ixp_copy_ibuf(struct crparam *p, IxCryptoAccPkeEauOperand *op, UINT32 *buf) +{ + unsigned char *src = (unsigned char *) p->crp_p; + unsigned char *dst; + int len, bits = p->crp_nbits; + + dprintk("%s()\n", __FUNCTION__); + + if (bits > MAX_IOP_SIZE * sizeof(UINT32) * 8) { + dprintk("%s - ibuf too big (%d > %d)\n", __FUNCTION__, + bits, MAX_IOP_SIZE * sizeof(UINT32) * 8); + return -1; + } + + len = (bits + 31) / 32; /* the number UINT32's needed */ + + dst = (unsigned char *) &buf[len]; + dst--; + + while (bits > 0) { + *dst-- = *src++; + bits -= 8; + } + +#if 0 /* no need to zero remaining bits as it is done during request alloc */ + while (dst > (unsigned char *) buf) + *dst-- = '\0'; +#endif + + op->pData = buf; + op->dataLen = len; + return 0; +} + +/* + * copy out the result, be as forgiving as we can about small output buffers + */ + +static int +ixp_copy_obuf(struct crparam *p, IxCryptoAccPkeEauOpResult *op, UINT32 *buf) +{ + unsigned char *dst = (unsigned char *) p->crp_p; + unsigned char *src = (unsigned char *) buf; + int len, z, bits = p->crp_nbits; + + dprintk("%s()\n", __FUNCTION__); + + len = op->dataLen * sizeof(UINT32); + + /* skip leading zeroes to be small buffer friendly */ + z = 0; + while (z < len && src[z] == '\0') + z++; + + src += len; + src--; + len -= z; + + while (len > 0 && bits > 0) { + *dst++ = *src--; + len--; + bits -= 8; + } + + while (bits > 0) { + *dst++ = '\0'; + bits -= 8; + } + + if (len > 0) { + dprintk("%s - obuf is %d (z=%d, ob=%d) bytes too small\n", + __FUNCTION__, len, z, p->crp_nbits / 8); + return -1; + } + + return 0; +} + + +/* + * the parameter offsets for exp_mod + */ + +#define IXP_PARAM_BASE 0 +#define IXP_PARAM_EXP 1 +#define IXP_PARAM_MOD 2 +#define IXP_PARAM_RES 3 + +/* + * key processing complete callback, is also used to start processing + * by passing a NULL for pResult + */ + +static void +ixp_kperform_cb( + IxCryptoAccPkeEauOperation operation, + IxCryptoAccPkeEauOpResult *pResult, + BOOL carryOrBorrow, + IxCryptoAccStatus status) +{ + struct ixp_pkq *q, *tmp; + unsigned long flags; + + dprintk("%s(0x%x, %p, %d, 0x%x)\n", __FUNCTION__, operation, pResult, + carryOrBorrow, status); + + /* handle a completed request */ + if (pResult) { + if (ixp_pk_cur && &ixp_pk_cur->pkq_result == pResult) { + q = ixp_pk_cur; + if (status != IX_CRYPTO_ACC_STATUS_SUCCESS) { + dprintk("%s() - op failed 0x%x\n", __FUNCTION__, status); + q->pkq_krp->krp_status = ERANGE; /* could do better */ + } else { + /* copy out the result */ + if (ixp_copy_obuf(&q->pkq_krp->krp_param[IXP_PARAM_RES], + &q->pkq_result, q->pkq_obuf)) + q->pkq_krp->krp_status = ERANGE; + } + crypto_kdone(q->pkq_krp); + kfree(q); + ixp_pk_cur = NULL; + } else + printk("%s - callback with invalid result pointer\n", __FUNCTION__); + } + + spin_lock_irqsave(&ixp_pkq_lock, flags); + if (ixp_pk_cur || list_empty(&ixp_pkq)) { + spin_unlock_irqrestore(&ixp_pkq_lock, flags); + return; + } + + list_for_each_entry_safe(q, tmp, &ixp_pkq, pkq_list) { + + list_del(&q->pkq_list); + ixp_pk_cur = q; + + spin_unlock_irqrestore(&ixp_pkq_lock, flags); + + status = ixCryptoAccPkeEauPerform( + IX_CRYPTO_ACC_OP_EAU_MOD_EXP, + &q->pkq_op, + ixp_kperform_cb, + &q->pkq_result); + + if (status == IX_CRYPTO_ACC_STATUS_SUCCESS) { + dprintk("%s() - ixCryptoAccPkeEauPerform SUCCESS\n", __FUNCTION__); + return; /* callback will return here for callback */ + } else if (status == IX_CRYPTO_ACC_STATUS_RETRY) { + printk("%s() - ixCryptoAccPkeEauPerform RETRY\n", __FUNCTION__); + } else { + printk("%s() - ixCryptoAccPkeEauPerform failed %d\n", + __FUNCTION__, status); + } + q->pkq_krp->krp_status = ERANGE; /* could do better */ + crypto_kdone(q->pkq_krp); + kfree(q); + spin_lock_irqsave(&ixp_pkq_lock, flags); + } + spin_unlock_irqrestore(&ixp_pkq_lock, flags); +} + + +static int +ixp_kprocess(device_t dev, struct cryptkop *krp, int hint) +{ + struct ixp_pkq *q; + int rc = 0; + unsigned long flags; + + dprintk("%s l1=%d l2=%d l3=%d l4=%d\n", __FUNCTION__, + krp->krp_param[IXP_PARAM_BASE].crp_nbits, + krp->krp_param[IXP_PARAM_EXP].crp_nbits, + krp->krp_param[IXP_PARAM_MOD].crp_nbits, + krp->krp_param[IXP_PARAM_RES].crp_nbits); + + + if (krp->krp_op != CRK_MOD_EXP) { + krp->krp_status = EOPNOTSUPP; + goto err; + } + + q = (struct ixp_pkq *) kmalloc(sizeof(*q), GFP_KERNEL); + if (q == NULL) { + krp->krp_status = ENOMEM; + goto err; + } + + /* + * The PKE engine does not appear to zero the output buffer + * appropriately, so we need to do it all here. + */ + memset(q, 0, sizeof(*q)); + + q->pkq_krp = krp; + INIT_LIST_HEAD(&q->pkq_list); + + if (ixp_copy_ibuf(&krp->krp_param[IXP_PARAM_BASE], &q->pkq_op.modExpOpr.M, + q->pkq_ibuf0)) + rc = 1; + if (!rc && ixp_copy_ibuf(&krp->krp_param[IXP_PARAM_EXP], + &q->pkq_op.modExpOpr.e, q->pkq_ibuf1)) + rc = 2; + if (!rc && ixp_copy_ibuf(&krp->krp_param[IXP_PARAM_MOD], + &q->pkq_op.modExpOpr.N, q->pkq_ibuf2)) + rc = 3; + + if (rc) { + kfree(q); + krp->krp_status = ERANGE; + goto err; + } + + q->pkq_result.pData = q->pkq_obuf; + q->pkq_result.dataLen = + (krp->krp_param[IXP_PARAM_RES].crp_nbits + 31) / 32; + + spin_lock_irqsave(&ixp_pkq_lock, flags); + list_add_tail(&q->pkq_list, &ixp_pkq); + spin_unlock_irqrestore(&ixp_pkq_lock, flags); + + if (!ixp_pk_cur) + ixp_kperform_cb(0, NULL, 0, 0); + return (0); + +err: + crypto_kdone(krp); + return (0); +} + + + +#ifdef CONFIG_OCF_RANDOMHARVEST +/* + * We run the random number generator output through SHA so that it + * is FIPS compliant. + */ + +static volatile int sha_done = 0; +static unsigned char sha_digest[20]; + +static void +ixp_hash_cb(UINT8 *digest, IxCryptoAccStatus status) +{ + dprintk("%s(%p, %d)\n", __FUNCTION__, digest, status); + if (sha_digest != digest) + printk("digest error\n"); + if (IX_CRYPTO_ACC_STATUS_SUCCESS == status) + sha_done = 1; + else + sha_done = -status; +} + +static int +ixp_read_random(void *arg, u_int32_t *buf, int maxwords) +{ + IxCryptoAccStatus status; + int i, n, rc; + + dprintk("%s(%p, %d)\n", __FUNCTION__, buf, maxwords); + memset(buf, 0, maxwords * sizeof(*buf)); + status = ixCryptoAccPkePseudoRandomNumberGet(maxwords, buf); + if (status != IX_CRYPTO_ACC_STATUS_SUCCESS) { + dprintk("%s: ixCryptoAccPkePseudoRandomNumberGet failed %d\n", + __FUNCTION__, status); + return 0; + } + + /* + * run the random data through SHA to make it look more random + */ + + n = sizeof(sha_digest); /* process digest bytes at a time */ + + rc = 0; + for (i = 0; i < maxwords; i += n / sizeof(*buf)) { + if ((maxwords - i) * sizeof(*buf) < n) + n = (maxwords - i) * sizeof(*buf); + sha_done = 0; + status = ixCryptoAccPkeHashPerform(IX_CRYPTO_ACC_AUTH_SHA1, + (UINT8 *) &buf[i], n, ixp_hash_cb, sha_digest); + if (status != IX_CRYPTO_ACC_STATUS_SUCCESS) { + dprintk("ixCryptoAccPkeHashPerform failed %d\n", status); + return -EIO; + } + while (!sha_done) + schedule(); + if (sha_done < 0) { + dprintk("ixCryptoAccPkeHashPerform failed CB %d\n", -sha_done); + return 0; + } + memcpy(&buf[i], sha_digest, n); + rc += n / sizeof(*buf);; + } + + return rc; +} +#endif /* CONFIG_OCF_RANDOMHARVEST */ + +#endif /* __ixp46X */ + + + +/* + * our driver startup and shutdown routines + */ + +static int +ixp_init(void) +{ + dprintk("%s(%p)\n", __FUNCTION__, ixp_init); + + if (ixp_init_crypto && ixCryptoAccInit() != IX_CRYPTO_ACC_STATUS_SUCCESS) + printk("ixCryptoAccInit failed, assuming already initialised!\n"); + + qcache = kmem_cache_create("ixp4xx_q", sizeof(struct ixp_q), 0, + SLAB_HWCACHE_ALIGN, NULL +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23) + , NULL +#endif + ); + if (!qcache) { + printk("failed to create Qcache\n"); + return -ENOENT; + } + + memset(&ixpdev, 0, sizeof(ixpdev)); + softc_device_init(&ixpdev, "ixp4xx", 0, ixp_methods); + + ixp_id = crypto_get_driverid(softc_get_device(&ixpdev), + CRYPTOCAP_F_HARDWARE); + if (ixp_id < 0) + panic("IXP/OCF crypto device cannot initialize!"); + +#define REGISTER(alg) \ + crypto_register(ixp_id,alg,0,0) + + REGISTER(CRYPTO_DES_CBC); + REGISTER(CRYPTO_3DES_CBC); + REGISTER(CRYPTO_RIJNDAEL128_CBC); +#ifdef CONFIG_OCF_IXP4XX_SHA1_MD5 + REGISTER(CRYPTO_MD5); + REGISTER(CRYPTO_SHA1); +#endif + REGISTER(CRYPTO_MD5_HMAC); + REGISTER(CRYPTO_SHA1_HMAC); +#undef REGISTER + +#ifdef __ixp46X + spin_lock_init(&ixp_pkq_lock); + /* + * we do not enable the go fast options here as they can potentially + * allow timing based attacks + * + * http://www.openssl.org/news/secadv_20030219.txt + */ + ixCryptoAccPkeEauExpConfig(0, 0); + crypto_kregister(ixp_id, CRK_MOD_EXP, 0); +#ifdef CONFIG_OCF_RANDOMHARVEST + crypto_rregister(ixp_id, ixp_read_random, NULL); +#endif +#endif + + return 0; +} + +static void +ixp_exit(void) +{ + dprintk("%s()\n", __FUNCTION__); + crypto_unregister_all(ixp_id); + ixp_id = -1; + kmem_cache_destroy(qcache); + qcache = NULL; +} + +module_init(ixp_init); +module_exit(ixp_exit); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_AUTHOR("David McCullough "); +MODULE_DESCRIPTION("ixp (OCF module for IXP4xx crypto)"); diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/Makefile b/target/linux/generic/files/crypto/ocf/kirkwood/Makefile new file mode 100644 index 0000000..6dafd00 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/Makefile @@ -0,0 +1,19 @@ +# for SGlinux builds +-include $(ROOTDIR)/modules/.config + +obj-$(CONFIG_OCF_KIRKWOOD) += mv_cesa.o + +mv_cesa-y := cesa/mvCesa.o cesa/mvLru.o cesa/mvMD5.o cesa/mvSHA1.o cesa/AES/mvAesAlg.o cesa/AES/mvAesApi.o cesa/mvCesaDebug.o cesa_ocf_drv.o + +# Extra objects required by the CESA driver +mv_cesa-y += mvHal/kw_family/ctrlEnv/mvCtrlEnvLib.o mvHal/kw_family/boardEnv/mvBoardEnvLib.o mvHal/mv_hal/twsi/mvTwsi.o mvHal/kw_family/ctrlEnv/sys/mvCpuIf.o mvHal/kw_family/ctrlEnv/sys/mvAhbToMbus.o mvHal/kw_family/ctrlEnv/sys/mvSysDram.o mvHal/linux_oss/mvOs.o mvHal/kw_family/ctrlEnv/mvCtrlEnvAddrDec.o mvHal/mv_hal/gpp/mvGpp.o mvHal/kw_family/ctrlEnv/sys/mvSysPex.o mvHal/mv_hal/pex/mvPex.o mvHal/kw_family/boardEnv/mvBoardEnvSpec.o mvHal/common/mvCommon.o mvHal/common/mvDebug.o mvHal/kw_family/ctrlEnv/sys/mvSysCesa.o + +ifdef src +EXTRA_CFLAGS += -I$(src)/.. -I$(src)/cesa -I$(src)/mvHal -I$(src)/mvHal/common -I$(src)/mvHal/kw_family -I$(src)/mvHal/mv_hal -I$(src)/mvHal/linux_oss -I$(src) +endif + +EXTRA_CFLAGS += -DMV_LINUX -DMV_CPU_LE -DMV_ARM -DMV_INCLUDE_CESA -DMV_INCLUDE_PEX -DMV_CACHE_COHERENCY=3 +ifdef TOPDIR +-include $(TOPDIR)/Rules.make +endif + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/cesa/AES/mvAes.h b/target/linux/generic/files/crypto/ocf/kirkwood/cesa/AES/mvAes.h new file mode 100644 index 0000000..07a8601 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/cesa/AES/mvAes.h @@ -0,0 +1,62 @@ +/* mvAes.h v2.0 August '99 + * Reference ANSI C code + */ + +/* AES Cipher header file for ANSI C Submissions + Lawrence E. Bassham III + Computer Security Division + National Institute of Standards and Technology + + April 15, 1998 + + This sample is to assist implementers developing to the Cryptographic +API Profile for AES Candidate Algorithm Submissions. Please consult this +document as a cross-reference. + + ANY CHANGES, WHERE APPROPRIATE, TO INFORMATION PROVIDED IN THIS FILE +MUST BE DOCUMENTED. CHANGES ARE ONLY APPROPRIATE WHERE SPECIFIED WITH +THE STRING "CHANGE POSSIBLE". FUNCTION CALLS AND THEIR PARAMETERS CANNOT +BE CHANGED. STRUCTURES CAN BE ALTERED TO ALLOW IMPLEMENTERS TO INCLUDE +IMPLEMENTATION SPECIFIC INFORMATION. +*/ + +/* Includes: + Standard include files +*/ + +#include "mvOs.h" + + +/* Error Codes - CHANGE POSSIBLE: inclusion of additional error codes */ + +/* Key direction is invalid, e.g., unknown value */ +#define AES_BAD_KEY_DIR -1 + +/* Key material not of correct length */ +#define AES_BAD_KEY_MAT -2 + +/* Key passed is not valid */ +#define AES_BAD_KEY_INSTANCE -3 + +/* Params struct passed to cipherInit invalid */ +#define AES_BAD_CIPHER_MODE -4 + +/* Cipher in wrong state (e.g., not initialized) */ +#define AES_BAD_CIPHER_STATE -5 + +#define AES_BAD_CIPHER_INSTANCE -7 + + +/* Function protoypes */ +/* CHANGED: makeKey(): parameter blockLen added + this parameter is absolutely necessary if you want to + setup the round keys in a variable block length setting + cipherInit(): parameter blockLen added (for obvious reasons) + */ +int aesMakeKey(MV_U8 *expandedKey, MV_U8 *keyMaterial, int keyLen, int blockLen); +int aesBlockEncrypt128(MV_U8 mode, MV_U8 *IV, MV_U8 *expandedKey, int keyLen, + MV_U32 *plain, int numBlocks, MV_U32 *cipher); +int aesBlockDecrypt128(MV_U8 mode, MV_U8 *IV, MV_U8 *expandedKey, int keyLen, + MV_U32 *plain, int numBlocks, MV_U32 *cipher); + + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/cesa/AES/mvAesAlg.c b/target/linux/generic/files/crypto/ocf/kirkwood/cesa/AES/mvAesAlg.c new file mode 100644 index 0000000..a65dc28 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/cesa/AES/mvAesAlg.c @@ -0,0 +1,317 @@ +/* rijndael-alg-ref.c v2.0 August '99 + * Reference ANSI C code + * authors: Paulo Barreto + * Vincent Rijmen, K.U.Leuven + * + * This code is placed in the public domain. + */ + +#include "mvOs.h" + +#include "mvAesAlg.h" + +#include "mvAesBoxes.dat" + + +MV_U8 mul1(MV_U8 aa, MV_U8 bb); +void KeyAddition(MV_U8 a[4][MAXBC], MV_U8 rk[4][MAXBC], MV_U8 BC); +void ShiftRow128Enc(MV_U8 a[4][MAXBC]); +void ShiftRow128Dec(MV_U8 a[4][MAXBC]); +void Substitution(MV_U8 a[4][MAXBC], MV_U8 box[256]); +void MixColumn(MV_U8 a[4][MAXBC], MV_U8 rk[4][MAXBC]); +void InvMixColumn(MV_U8 a[4][MAXBC]); + + +#define mul(aa, bb) (mask[bb] & Alogtable[aa + Logtable[bb]]) + +MV_U8 mul1(MV_U8 aa, MV_U8 bb) +{ + return mask[bb] & Alogtable[aa + Logtable[bb]]; +} + + +void KeyAddition(MV_U8 a[4][MAXBC], MV_U8 rk[4][MAXBC], MV_U8 BC) +{ + /* Exor corresponding text input and round key input bytes + */ + ((MV_U32*)(&(a[0][0])))[0] ^= ((MV_U32*)(&(rk[0][0])))[0]; + ((MV_U32*)(&(a[1][0])))[0] ^= ((MV_U32*)(&(rk[1][0])))[0]; + ((MV_U32*)(&(a[2][0])))[0] ^= ((MV_U32*)(&(rk[2][0])))[0]; + ((MV_U32*)(&(a[3][0])))[0] ^= ((MV_U32*)(&(rk[3][0])))[0]; + +} + +void ShiftRow128Enc(MV_U8 a[4][MAXBC]) { + /* Row 0 remains unchanged + * The other three rows are shifted a variable amount + */ + MV_U8 tmp[MAXBC]; + + tmp[0] = a[1][1]; + tmp[1] = a[1][2]; + tmp[2] = a[1][3]; + tmp[3] = a[1][0]; + + ((MV_U32*)(&(a[1][0])))[0] = ((MV_U32*)(&(tmp[0])))[0]; + /* + a[1][0] = tmp[0]; + a[1][1] = tmp[1]; + a[1][2] = tmp[2]; + a[1][3] = tmp[3]; + */ + tmp[0] = a[2][2]; + tmp[1] = a[2][3]; + tmp[2] = a[2][0]; + tmp[3] = a[2][1]; + + ((MV_U32*)(&(a[2][0])))[0] = ((MV_U32*)(&(tmp[0])))[0]; + /* + a[2][0] = tmp[0]; + a[2][1] = tmp[1]; + a[2][2] = tmp[2]; + a[2][3] = tmp[3]; + */ + tmp[0] = a[3][3]; + tmp[1] = a[3][0]; + tmp[2] = a[3][1]; + tmp[3] = a[3][2]; + + ((MV_U32*)(&(a[3][0])))[0] = ((MV_U32*)(&(tmp[0])))[0]; + /* + a[3][0] = tmp[0]; + a[3][1] = tmp[1]; + a[3][2] = tmp[2]; + a[3][3] = tmp[3]; + */ +} + +void ShiftRow128Dec(MV_U8 a[4][MAXBC]) { + /* Row 0 remains unchanged + * The other three rows are shifted a variable amount + */ + MV_U8 tmp[MAXBC]; + + tmp[0] = a[1][3]; + tmp[1] = a[1][0]; + tmp[2] = a[1][1]; + tmp[3] = a[1][2]; + + ((MV_U32*)(&(a[1][0])))[0] = ((MV_U32*)(&(tmp[0])))[0]; + /* + a[1][0] = tmp[0]; + a[1][1] = tmp[1]; + a[1][2] = tmp[2]; + a[1][3] = tmp[3]; + */ + + tmp[0] = a[2][2]; + tmp[1] = a[2][3]; + tmp[2] = a[2][0]; + tmp[3] = a[2][1]; + + ((MV_U32*)(&(a[2][0])))[0] = ((MV_U32*)(&(tmp[0])))[0]; + /* + a[2][0] = tmp[0]; + a[2][1] = tmp[1]; + a[2][2] = tmp[2]; + a[2][3] = tmp[3]; + */ + + tmp[0] = a[3][1]; + tmp[1] = a[3][2]; + tmp[2] = a[3][3]; + tmp[3] = a[3][0]; + + ((MV_U32*)(&(a[3][0])))[0] = ((MV_U32*)(&(tmp[0])))[0]; + /* + a[3][0] = tmp[0]; + a[3][1] = tmp[1]; + a[3][2] = tmp[2]; + a[3][3] = tmp[3]; + */ +} + +void Substitution(MV_U8 a[4][MAXBC], MV_U8 box[256]) { + /* Replace every byte of the input by the byte at that place + * in the nonlinear S-box + */ + int i, j; + + for(i = 0; i < 4; i++) + for(j = 0; j < 4; j++) a[i][j] = box[a[i][j]] ; +} + +void MixColumn(MV_U8 a[4][MAXBC], MV_U8 rk[4][MAXBC]) { + /* Mix the four bytes of every column in a linear way + */ + MV_U8 b[4][MAXBC]; + int i, j; + + for(j = 0; j < 4; j++){ + b[0][j] = mul(25,a[0][j]) ^ mul(1,a[1][j]) ^ a[2][j] ^ a[3][j]; + b[1][j] = mul(25,a[1][j]) ^ mul(1,a[2][j]) ^ a[3][j] ^ a[0][j]; + b[2][j] = mul(25,a[2][j]) ^ mul(1,a[3][j]) ^ a[0][j] ^ a[1][j]; + b[3][j] = mul(25,a[3][j]) ^ mul(1,a[0][j]) ^ a[1][j] ^ a[2][j]; + } + for(i = 0; i < 4; i++) + /*for(j = 0; j < BC; j++) a[i][j] = b[i][j];*/ + ((MV_U32*)(&(a[i][0])))[0] = ((MV_U32*)(&(b[i][0])))[0] ^ ((MV_U32*)(&(rk[i][0])))[0];; +} + +void InvMixColumn(MV_U8 a[4][MAXBC]) { + /* Mix the four bytes of every column in a linear way + * This is the opposite operation of Mixcolumn + */ + MV_U8 b[4][MAXBC]; + int i, j; + + for(j = 0; j < 4; j++){ + b[0][j] = mul(223,a[0][j]) ^ mul(104,a[1][j]) ^ mul(238,a[2][j]) ^ mul(199,a[3][j]); + b[1][j] = mul(223,a[1][j]) ^ mul(104,a[2][j]) ^ mul(238,a[3][j]) ^ mul(199,a[0][j]); + b[2][j] = mul(223,a[2][j]) ^ mul(104,a[3][j]) ^ mul(238,a[0][j]) ^ mul(199,a[1][j]); + b[3][j] = mul(223,a[3][j]) ^ mul(104,a[0][j]) ^ mul(238,a[1][j]) ^ mul(199,a[2][j]); + } + for(i = 0; i < 4; i++) + /*for(j = 0; j < BC; j++) a[i][j] = b[i][j];*/ + ((MV_U32*)(&(a[i][0])))[0] = ((MV_U32*)(&(b[i][0])))[0]; +} + +int rijndaelKeySched (MV_U8 k[4][MAXKC], int keyBits, int blockBits, MV_U8 W[MAXROUNDS+1][4][MAXBC]) +{ + /* Calculate the necessary round keys + * The number of calculations depends on keyBits and blockBits + */ + int KC, BC, ROUNDS; + int i, j, t, rconpointer = 0; + MV_U8 tk[4][MAXKC]; + + switch (keyBits) { + case 128: KC = 4; break; + case 192: KC = 6; break; + case 256: KC = 8; break; + default : return (-1); + } + + switch (blockBits) { + case 128: BC = 4; break; + case 192: BC = 6; break; + case 256: BC = 8; break; + default : return (-2); + } + + switch (keyBits >= blockBits ? keyBits : blockBits) { + case 128: ROUNDS = 10; break; + case 192: ROUNDS = 12; break; + case 256: ROUNDS = 14; break; + default : return (-3); /* this cannot happen */ + } + + + for(j = 0; j < KC; j++) + for(i = 0; i < 4; i++) + tk[i][j] = k[i][j]; + t = 0; + /* copy values into round key array */ + for(j = 0; (j < KC) && (t < (ROUNDS+1)*BC); j++, t++) + for(i = 0; i < 4; i++) W[t / BC][i][t % BC] = tk[i][j]; + + while (t < (ROUNDS+1)*BC) { /* while not enough round key material calculated */ + /* calculate new values */ + for(i = 0; i < 4; i++) + tk[i][0] ^= S[tk[(i+1)%4][KC-1]]; + tk[0][0] ^= rcon[rconpointer++]; + + if (KC != 8) + for(j = 1; j < KC; j++) + for(i = 0; i < 4; i++) tk[i][j] ^= tk[i][j-1]; + else { + for(j = 1; j < KC/2; j++) + for(i = 0; i < 4; i++) tk[i][j] ^= tk[i][j-1]; + for(i = 0; i < 4; i++) tk[i][KC/2] ^= S[tk[i][KC/2 - 1]]; + for(j = KC/2 + 1; j < KC; j++) + for(i = 0; i < 4; i++) tk[i][j] ^= tk[i][j-1]; + } + /* copy values into round key array */ + for(j = 0; (j < KC) && (t < (ROUNDS+1)*BC); j++, t++) + for(i = 0; i < 4; i++) W[t / BC][i][t % BC] = tk[i][j]; + } + + return 0; +} + + + +int rijndaelEncrypt128(MV_U8 a[4][MAXBC], MV_U8 rk[MAXROUNDS+1][4][MAXBC], int rounds) +{ + /* Encryption of one block. + */ + int r, BC, ROUNDS; + + BC = 4; + ROUNDS = rounds; + + /* begin with a key addition + */ + + KeyAddition(a,rk[0],BC); + + /* ROUNDS-1 ordinary rounds + */ + for(r = 1; r < ROUNDS; r++) { + Substitution(a,S); + ShiftRow128Enc(a); + MixColumn(a, rk[r]); + /*KeyAddition(a,rk[r],BC);*/ + } + + /* Last round is special: there is no MixColumn + */ + Substitution(a,S); + ShiftRow128Enc(a); + KeyAddition(a,rk[ROUNDS],BC); + + return 0; +} + + +int rijndaelDecrypt128(MV_U8 a[4][MAXBC], MV_U8 rk[MAXROUNDS+1][4][MAXBC], int rounds) +{ + int r, BC, ROUNDS; + + BC = 4; + ROUNDS = rounds; + + /* To decrypt: apply the inverse operations of the encrypt routine, + * in opposite order + * + * (KeyAddition is an involution: it 's equal to its inverse) + * (the inverse of Substitution with table S is Substitution with the inverse table of S) + * (the inverse of Shiftrow is Shiftrow over a suitable distance) + */ + + /* First the special round: + * without InvMixColumn + * with extra KeyAddition + */ + KeyAddition(a,rk[ROUNDS],BC); + ShiftRow128Dec(a); + Substitution(a,Si); + + /* ROUNDS-1 ordinary rounds + */ + for(r = ROUNDS-1; r > 0; r--) { + KeyAddition(a,rk[r],BC); + InvMixColumn(a); + ShiftRow128Dec(a); + Substitution(a,Si); + + } + + /* End with the extra key addition + */ + + KeyAddition(a,rk[0],BC); + + return 0; +} + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/cesa/AES/mvAesAlg.h b/target/linux/generic/files/crypto/ocf/kirkwood/cesa/AES/mvAesAlg.h new file mode 100644 index 0000000..ec81e40 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/cesa/AES/mvAesAlg.h @@ -0,0 +1,19 @@ +/* rijndael-alg-ref.h v2.0 August '99 + * Reference ANSI C code + * authors: Paulo Barreto + * Vincent Rijmen, K.U.Leuven + */ +#ifndef __RIJNDAEL_ALG_H +#define __RIJNDAEL_ALG_H + +#define MAXBC (128/32) +#define MAXKC (256/32) +#define MAXROUNDS 14 + + +int rijndaelKeySched (MV_U8 k[4][MAXKC], int keyBits, int blockBits, MV_U8 rk[MAXROUNDS+1][4][MAXBC]); + +int rijndaelEncrypt128(MV_U8 a[4][MAXBC], MV_U8 rk[MAXROUNDS+1][4][MAXBC], int rounds); +int rijndaelDecrypt128(MV_U8 a[4][MAXBC], MV_U8 rk[MAXROUNDS+1][4][MAXBC], int rounds); + +#endif /* __RIJNDAEL_ALG_H */ diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/cesa/AES/mvAesApi.c b/target/linux/generic/files/crypto/ocf/kirkwood/cesa/AES/mvAesApi.c new file mode 100644 index 0000000..b432dc6 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/cesa/AES/mvAesApi.c @@ -0,0 +1,312 @@ +/* rijndael-api-ref.c v2.1 April 2000 + * Reference ANSI C code + * authors: v2.0 Paulo Barreto + * Vincent Rijmen, K.U.Leuven + * v2.1 Vincent Rijmen, K.U.Leuven + * + * This code is placed in the public domain. + */ +#include "mvOs.h" + +#include "mvAes.h" +#include "mvAesAlg.h" + + +/* Defines: + Add any additional defines you need +*/ + +#define MODE_ECB 1 /* Are we ciphering in ECB mode? */ +#define MODE_CBC 2 /* Are we ciphering in CBC mode? */ +#define MODE_CFB1 3 /* Are we ciphering in 1-bit CFB mode? */ + + +int aesMakeKey(MV_U8 *expandedKey, MV_U8 *keyMaterial, int keyLen, int blockLen) +{ + MV_U8 W[MAXROUNDS+1][4][MAXBC]; + MV_U8 k[4][MAXKC]; + MV_U8 j; + int i, rounds, KC; + + if (expandedKey == NULL) + { + return AES_BAD_KEY_INSTANCE; + } + + if (!((keyLen == 128) || (keyLen == 192) || (keyLen == 256))) + { + return AES_BAD_KEY_MAT; + } + + if (keyMaterial == NULL) + { + return AES_BAD_KEY_MAT; + } + + /* initialize key schedule: */ + for(i=0; i= 3) +MV_U32 cesaChainLength = 0; +int chainReqNum = 0; +MV_U32 chainIndex = 0; +MV_CESA_REQ* pNextActiveChain = 0; +MV_CESA_REQ* pEndCurrChain = 0; +MV_BOOL isFirstReq = MV_TRUE; +#endif + +static INLINE MV_U8* mvCesaSramAddrGet(void) +{ +#ifdef MV_CESA_NO_SRAM + return (MV_U8*)cesaSramVirtPtr; +#else + return (MV_U8*)cesaCryptEngBase; +#endif /* MV_CESA_NO_SRAM */ +} + +static INLINE MV_ULONG mvCesaSramVirtToPhys(void* pDev, MV_U8* pSramVirt) +{ +#ifdef MV_CESA_NO_SRAM + return (MV_ULONG)mvOsIoVirtToPhy(NULL, pSramVirt); +#else + return (MV_ULONG)pSramVirt; +#endif /* MV_CESA_NO_SRAM */ +} + +/* Internal Function prototypes */ + +static INLINE void mvCesaSramDescrBuild(MV_U32 config, int frag, + int cryptoOffset, int ivOffset, int cryptoLength, + int macOffset, int digestOffset, int macLength, int macTotalLen, + MV_CESA_REQ *pCesaReq, MV_DMA_DESC* pDmaDesc); + +static INLINE void mvCesaSramSaUpdate(short sid, MV_DMA_DESC *pDmaDesc); + +static INLINE int mvCesaDmaCopyPrepare(MV_CESA_MBUF* pMbuf, MV_U8* pSramBuf, + MV_DMA_DESC* pDmaDesc, MV_BOOL isToMbuf, + int offset, int copySize, MV_BOOL skipFlush); + +static void mvCesaHmacIvGet(MV_CESA_MAC_MODE macMode, unsigned char key[], int keyLength, + unsigned char innerIV[], unsigned char outerIV[]); + +static MV_STATUS mvCesaFragAuthComplete(MV_CESA_REQ* pReq, MV_CESA_SA* pSA, + int macDataSize); + +static MV_CESA_COMMAND* mvCesaCtrModeInit(void); + +static MV_STATUS mvCesaCtrModePrepare(MV_CESA_COMMAND *pCtrModeCmd, MV_CESA_COMMAND *pCmd); +static MV_STATUS mvCesaCtrModeComplete(MV_CESA_COMMAND *pOrgCmd, MV_CESA_COMMAND *pCmd); +static void mvCesaCtrModeFinish(MV_CESA_COMMAND *pCmd); + +static INLINE MV_STATUS mvCesaReqProcess(MV_CESA_REQ* pReq); +static MV_STATUS mvCesaFragReqProcess(MV_CESA_REQ* pReq, MV_U8 frag); + +static INLINE MV_STATUS mvCesaParamCheck(MV_CESA_SA* pSA, MV_CESA_COMMAND *pCmd, MV_U8* pFixOffset); +static INLINE MV_STATUS mvCesaFragParamCheck(MV_CESA_SA* pSA, MV_CESA_COMMAND *pCmd); + +static INLINE void mvCesaFragSizeFind(MV_CESA_SA* pSA, MV_CESA_REQ* pReq, + int cryptoOffset, int macOffset, + int* pCopySize, int* pCryptoDataSize, int* pMacDataSize); +static MV_STATUS mvCesaMbufCacheUnmap(MV_CESA_MBUF* pMbuf, int offset, int size); + + +/* Go to the next request in the request queue */ +static INLINE MV_CESA_REQ* MV_CESA_REQ_NEXT_PTR(MV_CESA_REQ* pReq) +{ + if(pReq == pCesaReqLast) + return pCesaReqFirst; + + return pReq+1; +} + +#if (MV_CESA_VERSION >= 3) +/* Go to the previous request in the request queue */ +static INLINE MV_CESA_REQ* MV_CESA_REQ_PREV_PTR(MV_CESA_REQ* pReq) +{ + if(pReq == pCesaReqFirst) + return pCesaReqLast; + + return pReq-1; +} + +#endif + + +static INLINE void mvCesaReqProcessStart(MV_CESA_REQ* pReq) +{ + int frag; + +#if (MV_CESA_VERSION >= 3) + pReq->state = MV_CESA_CHAIN; +#else + pReq->state = MV_CESA_PROCESS; +#endif + cesaStats.startCount++; + + if(pReq->fragMode == MV_CESA_FRAG_NONE) + { + frag = 0; + } + else + { + frag = pReq->frags.nextFrag; + pReq->frags.nextFrag++; + } +#if (MV_CESA_VERSION >= 2) + /* Enable TDMA engine */ + MV_REG_WRITE(MV_CESA_TDMA_CURR_DESC_PTR_REG, 0); + MV_REG_WRITE(MV_CESA_TDMA_NEXT_DESC_PTR_REG, + (MV_U32)mvCesaVirtToPhys(&pReq->dmaDescBuf, pReq->dma[frag].pDmaFirst)); +#else + /* Enable IDMA engine */ + MV_REG_WRITE(IDMA_CURR_DESC_PTR_REG(0), 0); + MV_REG_WRITE(IDMA_NEXT_DESC_PTR_REG(0), + (MV_U32)mvCesaVirtToPhys(&pReq->dmaDescBuf, pReq->dma[frag].pDmaFirst)); +#endif /* MV_CESA_VERSION >= 2 */ + +#if defined(MV_BRIDGE_SYNC_REORDER) + mvOsBridgeReorderWA(); +#endif + + /* Start Accelerator */ + MV_REG_WRITE(MV_CESA_CMD_REG, MV_CESA_CMD_CHAN_ENABLE_MASK); +} + + +/******************************************************************************* +* mvCesaHalInit - Initialize the CESA driver +* +* DESCRIPTION: +* This function initialize the CESA driver. +* 1) Session database +* 2) Request queue +* 4) DMA descriptor lists - one list per request. Each list +* has MV_CESA_MAX_DMA_DESC descriptors. +* +* INPUT: +* numOfSession - maximum number of supported sessions +* queueDepth - number of elements in the request queue. +* pSramBase - virtual address of Sram +* osHandle - A handle used by the OS to allocate memory for the +* module (Passed to the OS Services layer) +* +* RETURN: +* MV_OK - Success +* MV_NO_RESOURCE - Fail, can't allocate resources: +* Session database, request queue, +* DMA descriptors list, LRU cache database. +* MV_NOT_ALIGNED - Sram base address is not 8 byte aligned. +* +*******************************************************************************/ +MV_STATUS mvCesaHalInit (int numOfSession, int queueDepth, char* pSramBase, MV_U32 cryptEngBase, + void *osHandle) +{ + int i, req; + MV_U32 descOffsetReg, configReg; + MV_CESA_SRAM_SA *pSramSA; + + + mvOsPrintf("mvCesaInit: sessions=%d, queue=%d, pSram=%p\n", + numOfSession, queueDepth, pSramBase); + + cesaOsHandle = osHandle; + /* Create Session database */ + pCesaSAD = mvOsMalloc(sizeof(MV_CESA_SA)*numOfSession); + if(pCesaSAD == NULL) + { + mvOsPrintf("mvCesaInit: Can't allocate %u bytes for %d SAs\n", + sizeof(MV_CESA_SA)*numOfSession, numOfSession); + mvCesaFinish(); + return MV_NO_RESOURCE; + } + memset(pCesaSAD, 0, sizeof(MV_CESA_SA)*numOfSession); + cesaMaxSA = numOfSession; + + /* Allocate imag of sramSA in the DRAM */ + cesaSramSaBuf.bufSize = sizeof(MV_CESA_SRAM_SA)*numOfSession + + CPU_D_CACHE_LINE_SIZE; + + cesaSramSaBuf.bufVirtPtr = mvOsIoCachedMalloc(osHandle,cesaSramSaBuf.bufSize, + &cesaSramSaBuf.bufPhysAddr, + &cesaSramSaBuf.memHandle); + + if(cesaSramSaBuf.bufVirtPtr == NULL) + { + mvOsPrintf("mvCesaInit: Can't allocate %d bytes for sramSA structures\n", + cesaSramSaBuf.bufSize); + mvCesaFinish(); + return MV_NO_RESOURCE; + } + memset(cesaSramSaBuf.bufVirtPtr, 0, cesaSramSaBuf.bufSize); + pSramSA = (MV_CESA_SRAM_SA*)MV_ALIGN_UP((MV_ULONG)cesaSramSaBuf.bufVirtPtr, + CPU_D_CACHE_LINE_SIZE); + for(i=0; i= 3) + cesaChainLength = MAX_CESA_CHAIN_LENGTH; +#endif + /* pSramBase must be 8 byte aligned */ + if( MV_IS_NOT_ALIGN((MV_ULONG)pSramBase, 8) ) + { + mvOsPrintf("mvCesaInit: pSramBase (%p) must be 8 byte aligned\n", + pSramBase); + mvCesaFinish(); + return MV_NOT_ALIGNED; + } + cesaSramVirtPtr = (MV_CESA_SRAM_MAP*)pSramBase; + + cesaCryptEngBase = cryptEngBase; + + /*memset(cesaSramVirtPtr, 0, sizeof(MV_CESA_SRAM_MAP));*/ + + /* Clear registers */ + MV_REG_WRITE( MV_CESA_CFG_REG, 0); + MV_REG_WRITE( MV_CESA_ISR_CAUSE_REG, 0); + MV_REG_WRITE( MV_CESA_ISR_MASK_REG, 0); + + /* Initialize DMA descriptor lists for all requests in Request queue */ + descOffsetReg = configReg = 0; + for(req=0; reqcesaDescBuf.bufSize = sizeof(MV_CESA_DESC)*MV_CESA_MAX_REQ_FRAGS + + CPU_D_CACHE_LINE_SIZE; + + pReq->cesaDescBuf.bufVirtPtr = + mvOsIoCachedMalloc(osHandle,pReq->cesaDescBuf.bufSize, + &pReq->cesaDescBuf.bufPhysAddr, + &pReq->cesaDescBuf.memHandle); + + if(pReq->cesaDescBuf.bufVirtPtr == NULL) + { + mvOsPrintf("mvCesaInit: req=%d, Can't allocate %d bytes for CESA descriptors\n", + req, pReq->cesaDescBuf.bufSize); + mvCesaFinish(); + return MV_NO_RESOURCE; + } + memset(pReq->cesaDescBuf.bufVirtPtr, 0, pReq->cesaDescBuf.bufSize); + pReq->pCesaDesc = (MV_CESA_DESC*)MV_ALIGN_UP((MV_ULONG)pReq->cesaDescBuf.bufVirtPtr, + CPU_D_CACHE_LINE_SIZE); + + pReq->dmaDescBuf.bufSize = sizeof(MV_DMA_DESC)*MV_CESA_MAX_DMA_DESC*MV_CESA_MAX_REQ_FRAGS + + CPU_D_CACHE_LINE_SIZE; + + pReq->dmaDescBuf.bufVirtPtr = + mvOsIoCachedMalloc(osHandle,pReq->dmaDescBuf.bufSize, + &pReq->dmaDescBuf.bufPhysAddr, + &pReq->dmaDescBuf.memHandle); + + if(pReq->dmaDescBuf.bufVirtPtr == NULL) + { + mvOsPrintf("mvCesaInit: req=%d, Can't allocate %d bytes for DMA descriptor list\n", + req, pReq->dmaDescBuf.bufSize); + mvCesaFinish(); + return MV_NO_RESOURCE; + } + memset(pReq->dmaDescBuf.bufVirtPtr, 0, pReq->dmaDescBuf.bufSize); + pDmaDesc = (MV_DMA_DESC*)MV_ALIGN_UP((MV_ULONG)pReq->dmaDescBuf.bufVirtPtr, + CPU_D_CACHE_LINE_SIZE); + + for(frag=0; fragdma[frag]; + + pDma->pDmaFirst = pDmaDesc; + pDma->pDmaLast = NULL; + + for(i=0; ipDmaFirst[i].phyNextDescPtr = + MV_32BIT_LE(mvCesaVirtToPhys(&pReq->dmaDescBuf, &pDmaDesc[i+1])); + } + pDma->pDmaFirst[i].phyNextDescPtr = 0; + mvOsCacheFlush(NULL, &pDma->pDmaFirst[0], MV_CESA_MAX_DMA_DESC*sizeof(MV_DMA_DESC)); + + pDmaDesc += MV_CESA_MAX_DMA_DESC; + } + } + /*mvCesaCryptoIvSet(NULL, MV_CESA_MAX_IV_LENGTH);*/ + descOffsetReg = (MV_U16)((MV_U8*)&cesaSramVirtPtr->desc - mvCesaSramAddrGet()); + MV_REG_WRITE(MV_CESA_CHAN_DESC_OFFSET_REG, descOffsetReg); + + configReg |= (MV_CESA_CFG_WAIT_DMA_MASK | MV_CESA_CFG_ACT_DMA_MASK); +#if (MV_CESA_VERSION >= 3) + configReg |= MV_CESA_CFG_CHAIN_MODE_MASK; +#endif + +#if (MV_CESA_VERSION >= 2) + /* Initialize TDMA engine */ + MV_REG_WRITE(MV_CESA_TDMA_CTRL_REG, MV_CESA_TDMA_CTRL_VALUE); + MV_REG_WRITE(MV_CESA_TDMA_BYTE_COUNT_REG, 0); + MV_REG_WRITE(MV_CESA_TDMA_CURR_DESC_PTR_REG, 0); +#else + /* Initialize IDMA #0 engine */ + MV_REG_WRITE(IDMA_CTRL_LOW_REG(0), 0); + MV_REG_WRITE(IDMA_BYTE_COUNT_REG(0), 0); + MV_REG_WRITE(IDMA_CURR_DESC_PTR_REG(0), 0); + MV_REG_WRITE(IDMA_CTRL_HIGH_REG(0), ICCHR_ENDIAN_LITTLE +#ifdef MV_CPU_LE + | ICCHR_DESC_BYTE_SWAP_EN +#endif + ); + /* Clear Cause Byte of IDMA channel to be used */ + MV_REG_WRITE( IDMA_CAUSE_REG, ~ICICR_CAUSE_MASK_ALL(0)); + MV_REG_WRITE(IDMA_CTRL_LOW_REG(0), MV_CESA_IDMA_CTRL_LOW_VALUE); +#endif /* (MV_CESA_VERSION >= 2) */ + + /* Set CESA configuration registers */ + MV_REG_WRITE( MV_CESA_CFG_REG, configReg); + mvCesaDebugStatsClear(); + + return MV_OK; +} + +/******************************************************************************* +* mvCesaFinish - Shutdown the CESA driver +* +* DESCRIPTION: +* This function shutdown the CESA driver and free all allocted resources. +* +* INPUT: None +* +* RETURN: +* MV_OK - Success +* Other - Fail +* +*******************************************************************************/ +MV_STATUS mvCesaFinish (void) +{ + int req; + MV_CESA_REQ* pReq; + + mvOsPrintf("mvCesaFinish: \n"); + + cesaSramVirtPtr = NULL; + + /* Free all resources: DMA list, etc. */ + for(req=0; reqdmaDescBuf.bufVirtPtr != NULL) + { + mvOsIoCachedFree(cesaOsHandle,pReq->dmaDescBuf.bufSize, + pReq->dmaDescBuf.bufPhysAddr, + pReq->dmaDescBuf.bufVirtPtr, + pReq->dmaDescBuf.memHandle); + } + if(pReq->cesaDescBuf.bufVirtPtr != NULL) + { + mvOsIoCachedFree(cesaOsHandle,pReq->cesaDescBuf.bufSize, + pReq->cesaDescBuf.bufPhysAddr, + pReq->cesaDescBuf.bufVirtPtr, + pReq->cesaDescBuf.memHandle); + } + } +#if (MV_CESA_VERSION < 2) + MV_REG_WRITE(IDMA_CTRL_LOW_REG(0), 0); +#endif /* (MV_CESA_VERSION < 2) */ + + /* Free request queue */ + if(pCesaReqFirst != NULL) + { + mvOsFree(pCesaReqFirst); + pCesaReqFirst = pCesaReqLast = NULL; + pCesaReqEmpty = pCesaReqProcess = NULL; + cesaQueueDepth = cesaReqResources = 0; + } + /* Free SA database */ + if(pCesaSAD != NULL) + { + mvOsFree(pCesaSAD); + pCesaSAD = NULL; + cesaMaxSA = 0; + } + MV_REG_WRITE( MV_CESA_CFG_REG, 0); + MV_REG_WRITE( MV_CESA_ISR_CAUSE_REG, 0); + MV_REG_WRITE( MV_CESA_ISR_MASK_REG, 0); + + return MV_OK; +} + +/******************************************************************************* +* mvCesaCryptoIvSet - Set IV value for Crypto algorithm working in CBC mode +* +* DESCRIPTION: +* This function set IV value using by Crypto algorithms in CBC mode. +* Each channel has its own IV value. +* This function gets IV value from the caller. If no IV value passed from +* the caller or only part of IV passed, the function will init the rest part +* of IV value (or the whole IV) by random value. +* +* INPUT: +* MV_U8* pIV - Pointer to IV value supplied by user. If pIV==NULL +* the function will generate random IV value. +* int ivSize - size (in bytes) of IV provided by user. If ivSize is +* smaller than maximum IV size, the function will complete +* IV by random value. +* +* RETURN: +* MV_OK - Success +* Other - Fail +* +*******************************************************************************/ +MV_STATUS mvCesaCryptoIvSet(MV_U8* pIV, int ivSize) +{ + MV_U8* pSramIV; +#if defined(MV646xx) + mvOsPrintf("mvCesaCryptoIvSet: ERR. shouldn't use this call on MV64660\n"); +#endif + pSramIV = cesaSramVirtPtr->cryptoIV; + if(ivSize > MV_CESA_MAX_IV_LENGTH) + { + mvOsPrintf("mvCesaCryptoIvSet: ivSize (%d) is too large\n", ivSize); + ivSize = MV_CESA_MAX_IV_LENGTH; + } + if(pIV != NULL) + { + memcpy(pSramIV, pIV, ivSize); + ivSize = MV_CESA_MAX_IV_LENGTH - ivSize; + pSramIV += ivSize; + } + + while(ivSize > 0) + { + int size, mv_random = mvOsRand(); + + size = MV_MIN(ivSize, sizeof(mv_random)); + memcpy(pSramIV, (void*)&mv_random, size); + + pSramIV += size; + ivSize -= size; + } +/* + mvOsCacheFlush(NULL, cesaSramVirtPtr->cryptoIV, + MV_CESA_MAX_IV_LENGTH); + mvOsCacheInvalidate(NULL, cesaSramVirtPtr->cryptoIV, + MV_CESA_MAX_IV_LENGTH); +*/ + return MV_OK; +} + +/******************************************************************************* +* mvCesaSessionOpen - Open new uni-directional crypto session +* +* DESCRIPTION: +* This function open new session. +* +* INPUT: +* MV_CESA_OPEN_SESSION *pSession - pointer to new session input parameters +* +* OUTPUT: +* short *pSid - session ID, should be used for all future +* requests over this session. +* +* RETURN: +* MV_OK - Session opend successfully. +* MV_FULL - All sessions are in use, no free place in +* SA database. +* MV_BAD_PARAM - One of session input parameters is invalid. +* +*******************************************************************************/ +MV_STATUS mvCesaSessionOpen(MV_CESA_OPEN_SESSION *pSession, short* pSid) +{ + short sid; + MV_U32 config = 0; + int digestSize; + + cesaStats.openedCount++; + + /* Find free entry in SAD */ + for(sid=0; sidoperation >= MV_CESA_MAX_OPERATION) + { + mvOsPrintf("mvCesaSessionOpen: Unexpected operation %d\n", + pSession->operation); + return MV_BAD_PARAM; + } + config |= (pSession->operation << MV_CESA_OPERATION_OFFSET); + + if( (pSession->direction != MV_CESA_DIR_ENCODE) && + (pSession->direction != MV_CESA_DIR_DECODE) ) + { + mvOsPrintf("mvCesaSessionOpen: Unexpected direction %d\n", + pSession->direction); + return MV_BAD_PARAM; + } + config |= (pSession->direction << MV_CESA_DIRECTION_BIT); + /* Clear SA entry */ + /* memset(&pCesaSAD[sid], 0, sizeof(pCesaSAD[sid])); */ + + /* Check AUTH parameters and update SA entry */ + if(pSession->operation != MV_CESA_CRYPTO_ONLY) + { + /* For HMAC (MD5 and SHA1) - Maximum Key size is 64 bytes */ + if( (pSession->macMode == MV_CESA_MAC_HMAC_MD5) || + (pSession->macMode == MV_CESA_MAC_HMAC_SHA1) ) + { + if(pSession->macKeyLength > MV_CESA_MAX_MAC_KEY_LENGTH) + { + mvOsPrintf("mvCesaSessionOpen: macKeyLength %d is too large\n", + pSession->macKeyLength); + return MV_BAD_PARAM; + } + mvCesaHmacIvGet(pSession->macMode, pSession->macKey, pSession->macKeyLength, + pCesaSAD[sid].pSramSA->macInnerIV, + pCesaSAD[sid].pSramSA->macOuterIV); + pCesaSAD[sid].macKeyLength = pSession->macKeyLength; + } + switch(pSession->macMode) + { + case MV_CESA_MAC_MD5: + case MV_CESA_MAC_HMAC_MD5: + digestSize = MV_CESA_MD5_DIGEST_SIZE; + break; + + case MV_CESA_MAC_SHA1: + case MV_CESA_MAC_HMAC_SHA1: + digestSize = MV_CESA_SHA1_DIGEST_SIZE; + break; + + default: + mvOsPrintf("mvCesaSessionOpen: Unexpected macMode %d\n", + pSession->macMode); + return MV_BAD_PARAM; + } + config |= (pSession->macMode << MV_CESA_MAC_MODE_OFFSET); + + /* Supported digest sizes: MD5 - 16 bytes (128 bits), */ + /* SHA1 - 20 bytes (160 bits) or 12 bytes (96 bits) for both */ + if( (pSession->digestSize != digestSize) && (pSession->digestSize != 12)) + { + mvOsPrintf("mvCesaSessionOpen: Unexpected digest size %d\n", + pSession->digestSize); + mvOsPrintf("\t Valid values [bytes]: MD5-16, SHA1-20, Both-12\n"); + return MV_BAD_PARAM; + } + pCesaSAD[sid].digestSize = pSession->digestSize; + + if(pCesaSAD[sid].digestSize == 12) + { + /* Set MV_CESA_MAC_DIGEST_SIZE_BIT if digest size is 96 bits */ + config |= (MV_CESA_MAC_DIGEST_96B << MV_CESA_MAC_DIGEST_SIZE_BIT); + } + } + + /* Check CRYPTO parameters and update SA entry */ + if(pSession->operation != MV_CESA_MAC_ONLY) + { + switch(pSession->cryptoAlgorithm) + { + case MV_CESA_CRYPTO_DES: + pCesaSAD[sid].cryptoKeyLength = MV_CESA_DES_KEY_LENGTH; + pCesaSAD[sid].cryptoBlockSize = MV_CESA_DES_BLOCK_SIZE; + break; + + case MV_CESA_CRYPTO_3DES: + pCesaSAD[sid].cryptoKeyLength = MV_CESA_3DES_KEY_LENGTH; + pCesaSAD[sid].cryptoBlockSize = MV_CESA_DES_BLOCK_SIZE; + /* Only EDE mode is supported */ + config |= (MV_CESA_CRYPTO_3DES_EDE << + MV_CESA_CRYPTO_3DES_MODE_BIT); + break; + + case MV_CESA_CRYPTO_AES: + switch(pSession->cryptoKeyLength) + { + case 16: + pCesaSAD[sid].cryptoKeyLength = MV_CESA_AES_128_KEY_LENGTH; + config |= (MV_CESA_CRYPTO_AES_KEY_128 << + MV_CESA_CRYPTO_AES_KEY_LEN_OFFSET); + break; + + case 24: + pCesaSAD[sid].cryptoKeyLength = MV_CESA_AES_192_KEY_LENGTH; + config |= (MV_CESA_CRYPTO_AES_KEY_192 << + MV_CESA_CRYPTO_AES_KEY_LEN_OFFSET); + break; + + case 32: + default: + pCesaSAD[sid].cryptoKeyLength = MV_CESA_AES_256_KEY_LENGTH; + config |= (MV_CESA_CRYPTO_AES_KEY_256 << + MV_CESA_CRYPTO_AES_KEY_LEN_OFFSET); + break; + } + pCesaSAD[sid].cryptoBlockSize = MV_CESA_AES_BLOCK_SIZE; + break; + + default: + mvOsPrintf("mvCesaSessionOpen: Unexpected cryptoAlgorithm %d\n", + pSession->cryptoAlgorithm); + return MV_BAD_PARAM; + } + config |= (pSession->cryptoAlgorithm << MV_CESA_CRYPTO_ALG_OFFSET); + + if(pSession->cryptoKeyLength != pCesaSAD[sid].cryptoKeyLength) + { + mvOsPrintf("cesaSessionOpen: Wrong CryptoKeySize %d != %d\n", + pSession->cryptoKeyLength, pCesaSAD[sid].cryptoKeyLength); + return MV_BAD_PARAM; + } + + /* Copy Crypto key */ + if( (pSession->cryptoAlgorithm == MV_CESA_CRYPTO_AES) && + (pSession->direction == MV_CESA_DIR_DECODE)) + { + /* Crypto Key for AES decode is computed from original key material */ + /* and depend on cryptoKeyLength (128/192/256 bits) */ + aesMakeKey(pCesaSAD[sid].pSramSA->cryptoKey, pSession->cryptoKey, + pSession->cryptoKeyLength*8, MV_CESA_AES_BLOCK_SIZE*8); + } + else + { + /*panic("mvCesaSessionOpen2");*/ + memcpy(pCesaSAD[sid].pSramSA->cryptoKey, pSession->cryptoKey, + pCesaSAD[sid].cryptoKeyLength); + + } + + switch(pSession->cryptoMode) + { + case MV_CESA_CRYPTO_ECB: + pCesaSAD[sid].cryptoIvSize = 0; + break; + + case MV_CESA_CRYPTO_CBC: + pCesaSAD[sid].cryptoIvSize = pCesaSAD[sid].cryptoBlockSize; + break; + + case MV_CESA_CRYPTO_CTR: + /* Supported only for AES algorithm */ + if(pSession->cryptoAlgorithm != MV_CESA_CRYPTO_AES) + { + mvOsPrintf("mvCesaSessionOpen: CRYPTO CTR mode supported for AES only\n"); + return MV_BAD_PARAM; + } + pCesaSAD[sid].cryptoIvSize = 0; + pCesaSAD[sid].ctrMode = 1; + /* Replace to ECB mode for HW */ + pSession->cryptoMode = MV_CESA_CRYPTO_ECB; + break; + + default: + mvOsPrintf("mvCesaSessionOpen: Unexpected cryptoMode %d\n", + pSession->cryptoMode); + return MV_BAD_PARAM; + } + + config |= (pSession->cryptoMode << MV_CESA_CRYPTO_MODE_BIT); + } + pCesaSAD[sid].config = config; + + mvOsCacheFlush(NULL, pCesaSAD[sid].pSramSA, sizeof(MV_CESA_SRAM_SA)); + if(pSid != NULL) + *pSid = sid; + + pCesaSAD[sid].valid = 1; + return MV_OK; +} + +/******************************************************************************* +* mvCesaSessionClose - Close active crypto session +* +* DESCRIPTION: +* This function closes existing session +* +* INPUT: +* short sid - Unique identifier of the session to be closed +* +* RETURN: +* MV_OK - Session closed successfully. +* MV_BAD_PARAM - Session identifier is out of valid range. +* MV_NOT_FOUND - There is no active session with such ID. +* +*******************************************************************************/ +MV_STATUS mvCesaSessionClose(short sid) +{ + cesaStats.closedCount++; + + if(sid >= cesaMaxSA) + { + mvOsPrintf("CESA Error: sid (%d) is too big\n", sid); + return MV_BAD_PARAM; + } + if(pCesaSAD[sid].valid == 0) + { + mvOsPrintf("CESA Warning: Session (sid=%d) is invalid\n", sid); + return MV_NOT_FOUND; + } + if(cesaLastSid == sid) + cesaLastSid = -1; + + pCesaSAD[sid].valid = 0; + return MV_OK; +} + +/******************************************************************************* +* mvCesaAction - Perform crypto operation +* +* DESCRIPTION: +* This function set new CESA request FIFO queue for further HW processing. +* The function checks request parameters before set new request to the queue. +* If one of the CESA channels is ready for processing the request will be +* passed to HW. When request processing is finished the CESA interrupt will +* be generated by HW. The caller should call mvCesaReadyGet() function to +* complete request processing and get result. +* +* INPUT: +* MV_CESA_COMMAND *pCmd - pointer to new CESA request. +* It includes pointers to Source and Destination +* buffers, session identifier get from +* mvCesaSessionOpen() function, pointer to caller +* private data and all needed crypto parameters. +* +* RETURN: +* MV_OK - request successfully added to request queue +* and will be processed. +* MV_NO_MORE - request successfully added to request queue and will +* be processed, but request queue became Full and next +* request will not be accepted. +* MV_NO_RESOURCE - request queue is FULL and the request can not +* be processed. +* MV_OUT_OF_CPU_MEM - memory allocation needed for request processing is +* failed. Request can not be processed. +* MV_NOT_ALLOWED - This mixed request (CRYPTO+MAC) can not be processed +* as one request and should be splitted for two requests: +* CRYPTO_ONLY and MAC_ONLY. +* MV_BAD_PARAM - One of the request parameters is out of valid range. +* The request can not be processed. +* +*******************************************************************************/ +MV_STATUS mvCesaAction (MV_CESA_COMMAND *pCmd) +{ + MV_STATUS status; + MV_CESA_REQ* pReq = pCesaReqEmpty; + int sid = pCmd->sessionId; + MV_CESA_SA* pSA = &pCesaSAD[sid]; +#if (MV_CESA_VERSION >= 3) + MV_CESA_REQ* pFromReq; + MV_CESA_REQ* pToReq; +#endif + cesaStats.reqCount++; + + /* Check that the request queue is not FULL */ + if(cesaReqResources == 0) + return MV_NO_RESOURCE; + + if( (sid >= cesaMaxSA) || (!pSA->valid) ) + { + mvOsPrintf("CESA Action Error: Session sid=%d is INVALID\n", sid); + return MV_BAD_PARAM; + } + pSA->count++; + + if(pSA->ctrMode) + { + /* AES in CTR mode can't be mixed with Authentication */ + if( (pSA->config & MV_CESA_OPERATION_MASK) != + (MV_CESA_CRYPTO_ONLY << MV_CESA_OPERATION_OFFSET) ) + { + mvOsPrintf("mvCesaAction : CRYPTO CTR mode can't be mixed with AUTH\n"); + return MV_NOT_ALLOWED; + } + /* All other request parameters should not be checked because key stream */ + /* (not user data) processed by AES HW engine */ + pReq->pOrgCmd = pCmd; + /* Allocate temporary pCmd structure for Key stream */ + pCmd = mvCesaCtrModeInit(); + if(pCmd == NULL) + return MV_OUT_OF_CPU_MEM; + + /* Prepare Key stream */ + mvCesaCtrModePrepare(pCmd, pReq->pOrgCmd); + pReq->fixOffset = 0; + } + else + { + /* Check request parameters and calculae fixOffset */ + status = mvCesaParamCheck(pSA, pCmd, &pReq->fixOffset); + if(status != MV_OK) + { + return status; + } + } + pReq->pCmd = pCmd; + + /* Check if the packet need fragmentation */ + if(pCmd->pSrc->mbufSize <= sizeof(cesaSramVirtPtr->buf) ) + { + /* request size is smaller than single buffer size */ + pReq->fragMode = MV_CESA_FRAG_NONE; + + /* Prepare NOT fragmented packets */ + status = mvCesaReqProcess(pReq); + if(status != MV_OK) + { + mvOsPrintf("CesaReady: ReqProcess error: pReq=%p, status=0x%x\n", + pReq, status); + } +#if (MV_CESA_VERSION >= 3) + pReq->frags.numFrag = 1; +#endif + } + else + { + MV_U8 frag = 0; + + /* request size is larger than buffer size - needs fragmentation */ + + /* Check restrictions for processing fragmented packets */ + status = mvCesaFragParamCheck(pSA, pCmd); + if(status != MV_OK) + return status; + + pReq->fragMode = MV_CESA_FRAG_FIRST; + pReq->frags.nextFrag = 0; + + /* Prepare Process Fragmented packets */ + while(pReq->fragMode != MV_CESA_FRAG_LAST) + { + if(frag >= MV_CESA_MAX_REQ_FRAGS) + { + mvOsPrintf("mvCesaAction Error: Too large request frag=%d\n", frag); + return MV_OUT_OF_CPU_MEM; + } + status = mvCesaFragReqProcess(pReq, frag); + if(status == MV_OK) { +#if (MV_CESA_VERSION >= 3) + if(frag) { + pReq->dma[frag-1].pDmaLast->phyNextDescPtr = + MV_32BIT_LE(mvCesaVirtToPhys(&pReq->dmaDescBuf, pReq->dma[frag].pDmaFirst)); + mvOsCacheFlush(NULL, pReq->dma[frag-1].pDmaLast, sizeof(MV_DMA_DESC)); + } +#endif + frag++; + } + } + pReq->frags.numFrag = frag; +#if (MV_CESA_VERSION >= 3) + if(chainReqNum) { + chainReqNum += pReq->frags.numFrag; + if(chainReqNum >= MAX_CESA_CHAIN_LENGTH) + chainReqNum = MAX_CESA_CHAIN_LENGTH; + } +#endif + } + + pReq->state = MV_CESA_PENDING; + + pCesaReqEmpty = MV_CESA_REQ_NEXT_PTR(pReq); + cesaReqResources -= 1; + +/* #ifdef CESA_DEBUG */ + if( (cesaQueueDepth - cesaReqResources) > cesaStats.maxReqCount) + cesaStats.maxReqCount = (cesaQueueDepth - cesaReqResources); +/* #endif CESA_DEBUG */ + + cesaLastSid = sid; + +#if (MV_CESA_VERSION >= 3) + /* Are we within chain bounderies and follows the first request ? */ + if((chainReqNum > 0) && (chainReqNum < MAX_CESA_CHAIN_LENGTH)) { + if(chainIndex) { + pFromReq = MV_CESA_REQ_PREV_PTR(pReq); + pToReq = pReq; + pReq->state = MV_CESA_CHAIN; + /* assume concatenating is possible */ + pFromReq->dma[pFromReq->frags.numFrag-1].pDmaLast->phyNextDescPtr = + MV_32BIT_LE(mvCesaVirtToPhys(&pToReq->dmaDescBuf, pToReq->dma[0].pDmaFirst)); + mvOsCacheFlush(NULL, pFromReq->dma[pFromReq->frags.numFrag-1].pDmaLast, sizeof(MV_DMA_DESC)); + + /* align active & next pointers */ + if(pNextActiveChain->state != MV_CESA_PENDING) + pEndCurrChain = pNextActiveChain = MV_CESA_REQ_NEXT_PTR(pReq); + } + else { /* we have only one chain, start new one */ + chainReqNum = 0; + chainIndex++; + /* align active & next pointers */ + if(pNextActiveChain->state != MV_CESA_PENDING) + pEndCurrChain = pNextActiveChain = pReq; + } + } + else { + /* In case we concatenate full chain */ + if(chainReqNum == MAX_CESA_CHAIN_LENGTH) { + chainIndex++; + if(pNextActiveChain->state != MV_CESA_PENDING) + pEndCurrChain = pNextActiveChain = pReq; + chainReqNum = 0; + } + + pReq = pCesaReqProcess; + if(pReq->state == MV_CESA_PENDING) { + pNextActiveChain = pReq; + pEndCurrChain = MV_CESA_REQ_NEXT_PTR(pReq); + /* Start Process new request */ + mvCesaReqProcessStart(pReq); + } + } + + chainReqNum++; + + if((chainIndex < MAX_CESA_CHAIN_LENGTH) && (chainReqNum > cesaStats.maxChainUsage)) + cesaStats.maxChainUsage = chainReqNum; + +#else + + /* Check status of CESA channels and process requests if possible */ + pReq = pCesaReqProcess; + if(pReq->state == MV_CESA_PENDING) + { + /* Start Process new request */ + mvCesaReqProcessStart(pReq); + } +#endif + /* If request queue became FULL - return MV_NO_MORE */ + if(cesaReqResources == 0) + return MV_NO_MORE; + + return MV_OK; + +} + +/******************************************************************************* +* mvCesaReadyGet - Get crypto request that processing is finished +* +* DESCRIPTION: +* This function complete request processing and return ready request to +* caller. To don't miss interrupts the caller must call this function +* while MV_OK or MV_TERMINATE values returned. +* +* INPUT: +* MV_U32 chanMap - map of CESA channels finished thier job +* accordingly with CESA Cause register. +* MV_CESA_RESULT* pResult - pointer to structure contains information +* about ready request. It includes pointer to +* user private structure "pReqPrv", session identifier +* for this request "sessionId" and return code. +* Return code set to MV_FAIL if calculated digest value +* on decode direction is different than digest value +* in the packet. +* +* RETURN: +* MV_OK - Success, ready request is returned. +* MV_NOT_READY - Next request is not ready yet. New interrupt will +* be generated for futher request processing. +* MV_EMPTY - There is no more request for processing. +* MV_BUSY - Fragmented request is not ready yet. +* MV_TERMINATE - Call this function once more to complete processing +* of fragmented request. +* +*******************************************************************************/ +MV_STATUS mvCesaReadyGet(MV_CESA_RESULT* pResult) +{ + MV_STATUS status, readyStatus = MV_NOT_READY; + MV_U32 statusReg; + MV_CESA_REQ* pReq; + MV_CESA_SA* pSA; + +#if (MV_CESA_VERSION >= 3) + if(isFirstReq == MV_TRUE) { + if(chainIndex == 0) + chainReqNum = 0; + + isFirstReq = MV_FALSE; + + if(pNextActiveChain->state == MV_CESA_PENDING) { + /* Start request Process */ + mvCesaReqProcessStart(pNextActiveChain); + pEndCurrChain = pNextActiveChain; + if(chainIndex > 0) + chainIndex--; + /* Update pNextActiveChain to next chain head */ + while(pNextActiveChain->state == MV_CESA_CHAIN) + pNextActiveChain = MV_CESA_REQ_NEXT_PTR(pNextActiveChain); + } + } + + /* Check if there are more processed requests - can we remove pEndCurrChain ??? */ + if(pCesaReqProcess == pEndCurrChain) { + isFirstReq = MV_TRUE; + pEndCurrChain = pNextActiveChain; +#else + if(pCesaReqProcess->state != MV_CESA_PROCESS) { +#endif + return MV_EMPTY; + } + +#ifdef CESA_DEBUG + statusReg = MV_REG_READ(MV_CESA_STATUS_REG); + if( statusReg & MV_CESA_STATUS_ACTIVE_MASK ) + { + mvOsPrintf("mvCesaReadyGet: Not Ready, Status = 0x%x\n", statusReg); + cesaStats.notReadyCount++; + return MV_NOT_READY; + } +#endif /* CESA_DEBUG */ + + cesaStats.readyCount++; + + pReq = pCesaReqProcess; + pSA = &pCesaSAD[pReq->pCmd->sessionId]; + + pResult->retCode = MV_OK; + if(pReq->fragMode != MV_CESA_FRAG_NONE) + { + MV_U8* pNewDigest; + int frag; +#if (MV_CESA_VERSION >= 3) + pReq->frags.nextFrag = 1; + while(pReq->frags.nextFrag <= pReq->frags.numFrag) { +#endif + frag = (pReq->frags.nextFrag - 1); + + /* Restore DMA descriptor list */ + pReq->dma[frag].pDmaLast->phyNextDescPtr = + MV_32BIT_LE(mvCesaVirtToPhys(&pReq->dmaDescBuf, &pReq->dma[frag].pDmaLast[1])); + pReq->dma[frag].pDmaLast = NULL; + + /* Special processing for finished fragmented request */ + if(pReq->frags.nextFrag >= pReq->frags.numFrag) + { + mvCesaMbufCacheUnmap(pReq->pCmd->pDst, 0, pReq->pCmd->pDst->mbufSize); + + /* Fragmented packet is ready */ + if( (pSA->config & MV_CESA_OPERATION_MASK) != + (MV_CESA_CRYPTO_ONLY << MV_CESA_OPERATION_OFFSET) ) + { + int macDataSize = pReq->pCmd->macLength - pReq->frags.macSize; + + if(macDataSize != 0) + { + /* Calculate all other blocks by SW */ + mvCesaFragAuthComplete(pReq, pSA, macDataSize); + } + + /* Copy new digest from SRAM to the Destination buffer */ + pNewDigest = cesaSramVirtPtr->buf + pReq->frags.newDigestOffset; + status = mvCesaCopyToMbuf(pNewDigest, pReq->pCmd->pDst, + pReq->pCmd->digestOffset, pSA->digestSize); + + /* For decryption: Compare new digest value with original one */ + if((pSA->config & MV_CESA_DIRECTION_MASK) == + (MV_CESA_DIR_DECODE << MV_CESA_DIRECTION_BIT)) + { + if( memcmp(pNewDigest, pReq->frags.orgDigest, pSA->digestSize) != 0) + { +/* + mvOsPrintf("Digest error: chan=%d, newDigest=%p, orgDigest=%p, status = 0x%x\n", + chan, pNewDigest, pReq->frags.orgDigest, MV_REG_READ(MV_CESA_STATUS_REG)); +*/ + /* Signiture verification is failed */ + pResult->retCode = MV_FAIL; + } + } + } + readyStatus = MV_OK; + } +#if (MV_CESA_VERSION >= 3) + pReq->frags.nextFrag++; + } +#endif + } + else + { + mvCesaMbufCacheUnmap(pReq->pCmd->pDst, 0, pReq->pCmd->pDst->mbufSize); + + /* Restore DMA descriptor list */ + pReq->dma[0].pDmaLast->phyNextDescPtr = + MV_32BIT_LE(mvCesaVirtToPhys(&pReq->dmaDescBuf, &pReq->dma[0].pDmaLast[1])); + pReq->dma[0].pDmaLast = NULL; + if( ((pSA->config & MV_CESA_OPERATION_MASK) != + (MV_CESA_CRYPTO_ONLY << MV_CESA_OPERATION_OFFSET) ) && + ((pSA->config & MV_CESA_DIRECTION_MASK) == + (MV_CESA_DIR_DECODE << MV_CESA_DIRECTION_BIT)) ) + { + /* For AUTH on decode : Check Digest result in Status register */ + statusReg = MV_REG_READ(MV_CESA_STATUS_REG); + if(statusReg & MV_CESA_STATUS_DIGEST_ERR_MASK) + { +/* + mvOsPrintf("Digest error: chan=%d, status = 0x%x\n", + chan, statusReg); +*/ + /* Signiture verification is failed */ + pResult->retCode = MV_FAIL; + } + } + readyStatus = MV_OK; + } + + if(readyStatus == MV_OK) + { + /* If Request is ready - Prepare pResult structure */ + pResult->pReqPrv = pReq->pCmd->pReqPrv; + pResult->sessionId = pReq->pCmd->sessionId; + + pReq->state = MV_CESA_IDLE; + pCesaReqProcess = MV_CESA_REQ_NEXT_PTR(pReq); + cesaReqResources++; + + if(pSA->ctrMode) + { + /* For AES CTR mode - complete processing and free allocated resources */ + mvCesaCtrModeComplete(pReq->pOrgCmd, pReq->pCmd); + mvCesaCtrModeFinish(pReq->pCmd); + pReq->pOrgCmd = NULL; + } + } + +#if (MV_CESA_VERSION < 3) + if(pCesaReqProcess->state == MV_CESA_PROCESS) + { + /* Start request Process */ + mvCesaReqProcessStart(pCesaReqProcess); + if(readyStatus == MV_NOT_READY) + readyStatus = MV_BUSY; + } + else if(pCesaReqProcess != pCesaReqEmpty) + { + /* Start process new request from the queue */ + mvCesaReqProcessStart(pCesaReqProcess); + } +#endif + return readyStatus; +} + +/***************** Functions to work with CESA_MBUF structure ******************/ + +/******************************************************************************* +* mvCesaMbufOffset - Locate offset in the Mbuf structure +* +* DESCRIPTION: +* This function locates offset inside Multi-Bufeer structure. +* It get fragment number and place in the fragment where the offset +* is located. +* +* +* INPUT: +* MV_CESA_MBUF* pMbuf - Pointer to multi-buffer structure +* int offset - Offset from the beginning of the data presented by +* the Mbuf structure. +* +* OUTPUT: +* int* pBufOffset - Offset from the beginning of the fragment where +* the offset is located. +* +* RETURN: +* int - Number of fragment, where the offset is located\ +* +*******************************************************************************/ +int mvCesaMbufOffset(MV_CESA_MBUF* pMbuf, int offset, int* pBufOffset) +{ + int frag = 0; + + while(offset > 0) + { + if(frag >= pMbuf->numFrags) + { + mvOsPrintf("mvCesaMbufOffset: Error: frag (%d) > numFrags (%d)\n", + frag, pMbuf->numFrags); + return MV_INVALID; + } + if(offset < pMbuf->pFrags[frag].bufSize) + { + break; + } + offset -= pMbuf->pFrags[frag].bufSize; + frag++; + } + if(pBufOffset != NULL) + *pBufOffset = offset; + + return frag; +} + +/******************************************************************************* +* mvCesaCopyFromMbuf - Copy data from the Mbuf structure to continuous buffer +* +* DESCRIPTION: +* +* +* INPUT: +* MV_U8* pDstBuf - Pointer to continuous buffer, where data is +* copied to. +* MV_CESA_MBUF* pSrcMbuf - Pointer to multi-buffer structure where data is +* copied from. +* int offset - Offset in the Mbuf structure where located first +* byte of data should be copied. +* int size - Size of data should be copied +* +* RETURN: +* MV_OK - Success, all data is copied successfully. +* MV_OUT_OF_RANGE - Failed, offset is out of Multi-buffer data range. +* No data is copied. +* MV_EMPTY - Multi-buffer structure has not enough data to copy +* Data from the offset to end of Mbuf data is copied. +* +*******************************************************************************/ +MV_STATUS mvCesaCopyFromMbuf(MV_U8* pDstBuf, MV_CESA_MBUF* pSrcMbuf, + int offset, int size) +{ + int frag, fragOffset, bufSize; + MV_U8* pBuf; + + if(size == 0) + return MV_OK; + + frag = mvCesaMbufOffset(pSrcMbuf, offset, &fragOffset); + if(frag == MV_INVALID) + { + mvOsPrintf("CESA Mbuf Error: offset (%d) out of range\n", offset); + return MV_OUT_OF_RANGE; + } + + bufSize = pSrcMbuf->pFrags[frag].bufSize - fragOffset; + pBuf = pSrcMbuf->pFrags[frag].bufVirtPtr + fragOffset; + while(MV_TRUE) + { + if(size <= bufSize) + { + memcpy(pDstBuf, pBuf, size); + return MV_OK; + } + memcpy(pDstBuf, pBuf, bufSize); + size -= bufSize; + frag++; + pDstBuf += bufSize; + if(frag >= pSrcMbuf->numFrags) + break; + + bufSize = pSrcMbuf->pFrags[frag].bufSize; + pBuf = pSrcMbuf->pFrags[frag].bufVirtPtr; + } + mvOsPrintf("mvCesaCopyFromMbuf: Mbuf is EMPTY - %d bytes isn't copied\n", + size); + return MV_EMPTY; +} + +/******************************************************************************* +* mvCesaCopyToMbuf - Copy data from continuous buffer to the Mbuf structure +* +* DESCRIPTION: +* +* +* INPUT: +* MV_U8* pSrcBuf - Pointer to continuous buffer, where data is +* copied from. +* MV_CESA_MBUF* pDstMbuf - Pointer to multi-buffer structure where data is +* copied to. +* int offset - Offset in the Mbuf structure where located first +* byte of data should be copied. +* int size - Size of data should be copied +* +* RETURN: +* MV_OK - Success, all data is copied successfully. +* MV_OUT_OF_RANGE - Failed, offset is out of Multi-buffer data range. +* No data is copied. +* MV_FULL - Multi-buffer structure has not enough place to copy +* all data. Data from the offset to end of Mbuf data +* is copied. +* +*******************************************************************************/ +MV_STATUS mvCesaCopyToMbuf(MV_U8* pSrcBuf, MV_CESA_MBUF* pDstMbuf, + int offset, int size) +{ + int frag, fragOffset, bufSize; + MV_U8* pBuf; + + if(size == 0) + return MV_OK; + + frag = mvCesaMbufOffset(pDstMbuf, offset, &fragOffset); + if(frag == MV_INVALID) + { + mvOsPrintf("CESA Mbuf Error: offset (%d) out of range\n", offset); + return MV_OUT_OF_RANGE; + } + + bufSize = pDstMbuf->pFrags[frag].bufSize - fragOffset; + pBuf = pDstMbuf->pFrags[frag].bufVirtPtr + fragOffset; + while(MV_TRUE) + { + if(size <= bufSize) + { + memcpy(pBuf, pSrcBuf, size); + return MV_OK; + } + memcpy(pBuf, pSrcBuf, bufSize); + size -= bufSize; + frag++; + pSrcBuf += bufSize; + if(frag >= pDstMbuf->numFrags) + break; + + bufSize = pDstMbuf->pFrags[frag].bufSize; + pBuf = pDstMbuf->pFrags[frag].bufVirtPtr; + } + mvOsPrintf("mvCesaCopyToMbuf: Mbuf is FULL - %d bytes isn't copied\n", + size); + return MV_FULL; +} + +/******************************************************************************* +* mvCesaMbufCopy - Copy data from one Mbuf structure to the other Mbuf structure +* +* DESCRIPTION: +* +* +* INPUT: +* +* MV_CESA_MBUF* pDstMbuf - Pointer to multi-buffer structure where data is +* copied to. +* int dstMbufOffset - Offset in the dstMbuf structure where first byte +* of data should be copied to. +* MV_CESA_MBUF* pSrcMbuf - Pointer to multi-buffer structure where data is +* copied from. +* int srcMbufOffset - Offset in the srcMbuf structure where first byte +* of data should be copied from. +* int size - Size of data should be copied +* +* RETURN: +* MV_OK - Success, all data is copied successfully. +* MV_OUT_OF_RANGE - Failed, srcMbufOffset or dstMbufOffset is out of +* srcMbuf or dstMbuf structure correspondently. +* No data is copied. +* MV_BAD_SIZE - srcMbuf or dstMbuf structure is too small to copy +* all data. Partial data is copied +* +*******************************************************************************/ +MV_STATUS mvCesaMbufCopy(MV_CESA_MBUF* pMbufDst, int dstMbufOffset, + MV_CESA_MBUF* pMbufSrc, int srcMbufOffset, int size) +{ + int srcFrag, dstFrag, srcSize, dstSize, srcOffset, dstOffset; + int copySize; + MV_U8 *pSrc, *pDst; + + if(size == 0) + return MV_OK; + + srcFrag = mvCesaMbufOffset(pMbufSrc, srcMbufOffset, &srcOffset); + if(srcFrag == MV_INVALID) + { + mvOsPrintf("CESA srcMbuf Error: offset (%d) out of range\n", srcMbufOffset); + return MV_OUT_OF_RANGE; + } + pSrc = pMbufSrc->pFrags[srcFrag].bufVirtPtr + srcOffset; + srcSize = pMbufSrc->pFrags[srcFrag].bufSize - srcOffset; + + dstFrag = mvCesaMbufOffset(pMbufDst, dstMbufOffset, &dstOffset); + if(dstFrag == MV_INVALID) + { + mvOsPrintf("CESA dstMbuf Error: offset (%d) out of range\n", dstMbufOffset); + return MV_OUT_OF_RANGE; + } + pDst = pMbufDst->pFrags[dstFrag].bufVirtPtr + dstOffset; + dstSize = pMbufDst->pFrags[dstFrag].bufSize - dstOffset; + + while(size > 0) + { + copySize = MV_MIN(srcSize, dstSize); + if(size <= copySize) + { + memcpy(pDst, pSrc, size); + return MV_OK; + } + memcpy(pDst, pSrc, copySize); + size -= copySize; + srcSize -= copySize; + dstSize -= copySize; + + if(srcSize == 0) + { + srcFrag++; + if(srcFrag >= pMbufSrc->numFrags) + break; + + pSrc = pMbufSrc->pFrags[srcFrag].bufVirtPtr; + srcSize = pMbufSrc->pFrags[srcFrag].bufSize; + } + + if(dstSize == 0) + { + dstFrag++; + if(dstFrag >= pMbufDst->numFrags) + break; + + pDst = pMbufDst->pFrags[dstFrag].bufVirtPtr; + dstSize = pMbufDst->pFrags[dstFrag].bufSize; + } + } + mvOsPrintf("mvCesaMbufCopy: BAD size - %d bytes isn't copied\n", + size); + + return MV_BAD_SIZE; +} + +static MV_STATUS mvCesaMbufCacheUnmap(MV_CESA_MBUF* pMbuf, int offset, int size) +{ + int frag, fragOffset, bufSize; + MV_U8* pBuf; + + if(size == 0) + return MV_OK; + + frag = mvCesaMbufOffset(pMbuf, offset, &fragOffset); + if(frag == MV_INVALID) + { + mvOsPrintf("CESA Mbuf Error: offset (%d) out of range\n", offset); + return MV_OUT_OF_RANGE; + } + + bufSize = pMbuf->pFrags[frag].bufSize - fragOffset; + pBuf = pMbuf->pFrags[frag].bufVirtPtr + fragOffset; + while(MV_TRUE) + { + if(size <= bufSize) + { + mvOsCacheUnmap(NULL, mvOsIoVirtToPhy(NULL, pBuf), size); + return MV_OK; + } + + mvOsCacheUnmap(NULL, mvOsIoVirtToPhy(NULL, pBuf), bufSize); + size -= bufSize; + frag++; + if(frag >= pMbuf->numFrags) + break; + + bufSize = pMbuf->pFrags[frag].bufSize; + pBuf = pMbuf->pFrags[frag].bufVirtPtr; + } + mvOsPrintf("%s: Mbuf is FULL - %d bytes isn't Unmapped\n", + __FUNCTION__, size); + return MV_FULL; +} + + +/*************************************** Local Functions ******************************/ + +/******************************************************************************* +* mvCesaFragReqProcess - Process fragmented request +* +* DESCRIPTION: +* This function processes a fragment of fragmented request (First, Middle or Last) +* +* +* INPUT: +* MV_CESA_REQ* pReq - Pointer to the request in the request queue. +* +* RETURN: +* MV_OK - The fragment is successfully passed to HW for processing. +* MV_TERMINATE - Means, that HW finished its work on this packet and no more +* interrupts will be generated for this request. +* Function mvCesaReadyGet() must be called to complete request +* processing and get request result. +* +*******************************************************************************/ +static MV_STATUS mvCesaFragReqProcess(MV_CESA_REQ* pReq, MV_U8 frag) +{ + int i, copySize, cryptoDataSize, macDataSize, sid; + int cryptoIvOffset, digestOffset; + MV_U32 config; + MV_CESA_COMMAND* pCmd = pReq->pCmd; + MV_CESA_SA* pSA; + MV_CESA_MBUF* pMbuf; + MV_DMA_DESC* pDmaDesc = pReq->dma[frag].pDmaFirst; + MV_U8* pSramBuf = cesaSramVirtPtr->buf; + int macTotalLen = 0; + int fixOffset, cryptoOffset, macOffset; + + cesaStats.fragCount++; + + sid = pReq->pCmd->sessionId; + + pSA = &pCesaSAD[sid]; + + cryptoIvOffset = digestOffset = 0; + i = macDataSize = 0; + cryptoDataSize = 0; + + /* First fragment processing */ + if(pReq->fragMode == MV_CESA_FRAG_FIRST) + { + /* pReq->frags monitors processing of fragmented request between fragments */ + pReq->frags.bufOffset = 0; + pReq->frags.cryptoSize = 0; + pReq->frags.macSize = 0; + + config = pSA->config | (MV_CESA_FRAG_FIRST << MV_CESA_FRAG_MODE_OFFSET); + + /* fixOffset can be not equal to zero only for FIRST fragment */ + fixOffset = pReq->fixOffset; + /* For FIRST fragment crypto and mac offsets are taken from pCmd */ + cryptoOffset = pCmd->cryptoOffset; + macOffset = pCmd->macOffset; + + copySize = sizeof(cesaSramVirtPtr->buf) - pReq->fixOffset; + + /* Find fragment size: Must meet all requirements for CRYPTO and MAC + * cryptoDataSize - size of data will be encrypted/decrypted in this fragment + * macDataSize - size of data will be signed/verified in this fragment + * copySize - size of data will be copied from srcMbuf to SRAM and + * back to dstMbuf for this fragment + */ + mvCesaFragSizeFind(pSA, pReq, cryptoOffset, macOffset, + ©Size, &cryptoDataSize, &macDataSize); + + if( (pSA->config & MV_CESA_OPERATION_MASK) != + (MV_CESA_MAC_ONLY << MV_CESA_OPERATION_OFFSET)) + { + /* CryptoIV special processing */ + if( (pSA->config & MV_CESA_CRYPTO_MODE_MASK) == + (MV_CESA_CRYPTO_CBC << MV_CESA_CRYPTO_MODE_BIT) ) + { + /* In CBC mode for encode direction when IV from user */ + if( (pCmd->ivFromUser) && + ((pSA->config & MV_CESA_DIRECTION_MASK) == + (MV_CESA_DIR_ENCODE << MV_CESA_DIRECTION_BIT)) ) + { + + /* For Crypto Encode in CBC mode HW always takes IV from SRAM IVPointer, + * (not from IVBufPointer). So when ivFromUser==1, we should copy IV from user place + * in the buffer to SRAM IVPointer + */ + i += mvCesaDmaCopyPrepare(pCmd->pSrc, cesaSramVirtPtr->cryptoIV, &pDmaDesc[i], + MV_FALSE, pCmd->ivOffset, pSA->cryptoIvSize, pCmd->skipFlush); + } + + /* Special processing when IV is not located in the first fragment */ + if(pCmd->ivOffset > (copySize - pSA->cryptoIvSize)) + { + /* Prepare dummy place for cryptoIV in SRAM */ + cryptoIvOffset = cesaSramVirtPtr->tempCryptoIV - mvCesaSramAddrGet(); + + /* For Decryption: Copy IV value from pCmd->ivOffset to Special SRAM place */ + if((pSA->config & MV_CESA_DIRECTION_MASK) == + (MV_CESA_DIR_DECODE << MV_CESA_DIRECTION_BIT)) + { + i += mvCesaDmaCopyPrepare(pCmd->pSrc, cesaSramVirtPtr->tempCryptoIV, &pDmaDesc[i], + MV_FALSE, pCmd->ivOffset, pSA->cryptoIvSize, pCmd->skipFlush); + } + else + { + /* For Encryption when IV is NOT from User: */ + /* Copy IV from SRAM to buffer (pCmd->ivOffset) */ + if(pCmd->ivFromUser == 0) + { + /* copy IV value from cryptoIV to Buffer (pCmd->ivOffset) */ + i += mvCesaDmaCopyPrepare(pCmd->pSrc, cesaSramVirtPtr->cryptoIV, &pDmaDesc[i], + MV_TRUE, pCmd->ivOffset, pSA->cryptoIvSize, pCmd->skipFlush); + } + } + } + else + { + cryptoIvOffset = pCmd->ivOffset; + } + } + } + + if( (pSA->config & MV_CESA_OPERATION_MASK) != + (MV_CESA_CRYPTO_ONLY << MV_CESA_OPERATION_OFFSET) ) + { + /* MAC digest special processing on Decode direction */ + if((pSA->config & MV_CESA_DIRECTION_MASK) == + (MV_CESA_DIR_DECODE << MV_CESA_DIRECTION_BIT)) + { + /* Save digest from pCmd->digestOffset */ + mvCesaCopyFromMbuf(pReq->frags.orgDigest, + pCmd->pSrc, pCmd->digestOffset, pSA->digestSize); + + /* If pCmd->digestOffset is not located on the first */ + if(pCmd->digestOffset > (copySize - pSA->digestSize)) + { + MV_U8 digestZero[MV_CESA_MAX_DIGEST_SIZE]; + + /* Set zeros to pCmd->digestOffset (DRAM) */ + memset(digestZero, 0, MV_CESA_MAX_DIGEST_SIZE); + mvCesaCopyToMbuf(digestZero, pCmd->pSrc, pCmd->digestOffset, pSA->digestSize); + + /* Prepare dummy place for digest in SRAM */ + digestOffset = cesaSramVirtPtr->tempDigest - mvCesaSramAddrGet(); + } + else + { + digestOffset = pCmd->digestOffset; + } + } + } + /* Update SA in SRAM */ + if(cesaLastSid != sid) + { + mvCesaSramSaUpdate(sid, &pDmaDesc[i]); + i++; + } + + pReq->fragMode = MV_CESA_FRAG_MIDDLE; + } + else + { + /* Continue fragment */ + fixOffset = 0; + cryptoOffset = 0; + macOffset = 0; + if( (pCmd->pSrc->mbufSize - pReq->frags.bufOffset) <= sizeof(cesaSramVirtPtr->buf)) + { + /* Last fragment */ + config = pSA->config | (MV_CESA_FRAG_LAST << MV_CESA_FRAG_MODE_OFFSET); + pReq->fragMode = MV_CESA_FRAG_LAST; + copySize = pCmd->pSrc->mbufSize - pReq->frags.bufOffset; + + if( (pSA->config & MV_CESA_OPERATION_MASK) != + (MV_CESA_CRYPTO_ONLY << MV_CESA_OPERATION_OFFSET) ) + { + macDataSize = pCmd->macLength - pReq->frags.macSize; + + /* If pCmd->digestOffset is not located on last fragment */ + if(pCmd->digestOffset < pReq->frags.bufOffset) + { + /* Prepare dummy place for digest in SRAM */ + digestOffset = cesaSramVirtPtr->tempDigest - mvCesaSramAddrGet(); + } + else + { + digestOffset = pCmd->digestOffset - pReq->frags.bufOffset; + } + pReq->frags.newDigestOffset = digestOffset; + macTotalLen = pCmd->macLength; + + /* HW can't calculate the Digest correctly for fragmented packets + * in the following cases: + * - MV88F5182 || + * - MV88F5181L when total macLength more that 16 Kbytes || + * - total macLength more that 64 Kbytes + */ + if( (mvCtrlModelGet() == MV_5182_DEV_ID) || + ( (mvCtrlModelGet() == MV_5181_DEV_ID) && + (mvCtrlRevGet() >= MV_5181L_A0_REV) && + (pCmd->macLength >= (1 << 14)) ) ) + { + return MV_TERMINATE; + } + } + if( (pSA->config & MV_CESA_OPERATION_MASK) != + (MV_CESA_MAC_ONLY << MV_CESA_OPERATION_OFFSET) ) + { + cryptoDataSize = pCmd->cryptoLength - pReq->frags.cryptoSize; + } + + /* cryptoIvOffset - don't care */ + } + else + { + /* WA for MV88F5182 SHA1 and MD5 fragmentation mode */ + if( (mvCtrlModelGet() == MV_5182_DEV_ID) && + (((pSA->config & MV_CESA_MAC_MODE_MASK) == + (MV_CESA_MAC_MD5 << MV_CESA_MAC_MODE_OFFSET)) || + ((pSA->config & MV_CESA_MAC_MODE_MASK) == + (MV_CESA_MAC_SHA1 << MV_CESA_MAC_MODE_OFFSET))) ) + { + pReq->frags.newDigestOffset = cesaSramVirtPtr->tempDigest - mvCesaSramAddrGet(); + pReq->fragMode = MV_CESA_FRAG_LAST; + + return MV_TERMINATE; + } + /* Middle fragment */ + config = pSA->config | (MV_CESA_FRAG_MIDDLE << MV_CESA_FRAG_MODE_OFFSET); + copySize = sizeof(cesaSramVirtPtr->buf); + /* digestOffset and cryptoIvOffset - don't care */ + + /* Find fragment size */ + mvCesaFragSizeFind(pSA, pReq, cryptoOffset, macOffset, + ©Size, &cryptoDataSize, &macDataSize); + } + } + /********* Prepare DMA descriptors to copy from pSrc to SRAM *********/ + pMbuf = pCmd->pSrc; + i += mvCesaDmaCopyPrepare(pMbuf, pSramBuf + fixOffset, &pDmaDesc[i], + MV_FALSE, pReq->frags.bufOffset, copySize, pCmd->skipFlush); + + /* Prepare CESA descriptor to copy from DRAM to SRAM by DMA */ + mvCesaSramDescrBuild(config, frag, + cryptoOffset + fixOffset, cryptoIvOffset + fixOffset, + cryptoDataSize, macOffset + fixOffset, + digestOffset + fixOffset, macDataSize, macTotalLen, + pReq, &pDmaDesc[i]); + i++; + + /* Add special descriptor Ownership for CPU */ + pDmaDesc[i].byteCnt = 0; + pDmaDesc[i].phySrcAdd = 0; + pDmaDesc[i].phyDestAdd = 0; + i++; + + /********* Prepare DMA descriptors to copy from SRAM to pDst *********/ + pMbuf = pCmd->pDst; + i += mvCesaDmaCopyPrepare(pMbuf, pSramBuf + fixOffset, &pDmaDesc[i], + MV_TRUE, pReq->frags.bufOffset, copySize, pCmd->skipFlush); + + /* Next field of Last DMA descriptor must be NULL */ + pDmaDesc[i-1].phyNextDescPtr = 0; + pReq->dma[frag].pDmaLast = &pDmaDesc[i-1]; + mvOsCacheFlush(NULL, pReq->dma[frag].pDmaFirst, + i*sizeof(MV_DMA_DESC)); + + /*mvCesaDebugDescriptor(&cesaSramVirtPtr->desc[frag]);*/ + + pReq->frags.bufOffset += copySize; + pReq->frags.cryptoSize += cryptoDataSize; + pReq->frags.macSize += macDataSize; + + return MV_OK; +} + + +/******************************************************************************* +* mvCesaReqProcess - Process regular (Non-fragmented) request +* +* DESCRIPTION: +* This function processes the whole (not fragmented) request +* +* INPUT: +* MV_CESA_REQ* pReq - Pointer to the request in the request queue. +* +* RETURN: +* MV_OK - The request is successfully passed to HW for processing. +* Other - Failure. The request will not be processed +* +*******************************************************************************/ +static MV_STATUS mvCesaReqProcess(MV_CESA_REQ* pReq) +{ + MV_CESA_MBUF *pMbuf; + MV_DMA_DESC *pDmaDesc; + MV_U8 *pSramBuf; + int sid, i, fixOffset; + MV_CESA_SA *pSA; + MV_CESA_COMMAND *pCmd = pReq->pCmd; + + cesaStats.procCount++; + + sid = pCmd->sessionId; + pSA = &pCesaSAD[sid]; + pDmaDesc = pReq->dma[0].pDmaFirst; + pSramBuf = cesaSramVirtPtr->buf; + fixOffset = pReq->fixOffset; + +/* + mvOsPrintf("mvCesaReqProcess: sid=%d, pSA=%p, pDmaDesc=%p, pSramBuf=%p\n", + sid, pSA, pDmaDesc, pSramBuf); +*/ + i = 0; + + /* Crypto IV Special processing in CBC mode for Encryption direction */ + if( ((pSA->config & MV_CESA_OPERATION_MASK) != (MV_CESA_MAC_ONLY << MV_CESA_OPERATION_OFFSET)) && + ((pSA->config & MV_CESA_CRYPTO_MODE_MASK) == (MV_CESA_CRYPTO_CBC << MV_CESA_CRYPTO_MODE_BIT)) && + ((pSA->config & MV_CESA_DIRECTION_MASK) == (MV_CESA_DIR_ENCODE << MV_CESA_DIRECTION_BIT)) && + (pCmd->ivFromUser) ) + { + /* For Crypto Encode in CBC mode HW always takes IV from SRAM IVPointer, + * (not from IVBufPointer). So when ivFromUser==1, we should copy IV from user place + * in the buffer to SRAM IVPointer + */ + i += mvCesaDmaCopyPrepare(pCmd->pSrc, cesaSramVirtPtr->cryptoIV, &pDmaDesc[i], + MV_FALSE, pCmd->ivOffset, pSA->cryptoIvSize, pCmd->skipFlush); + } + + /* Update SA in SRAM */ + if(cesaLastSid != sid) + { + mvCesaSramSaUpdate(sid, &pDmaDesc[i]); + i++; + } + + /********* Prepare DMA descriptors to copy from pSrc to SRAM *********/ + pMbuf = pCmd->pSrc; + i += mvCesaDmaCopyPrepare(pMbuf, pSramBuf + fixOffset, &pDmaDesc[i], + MV_FALSE, 0, pMbuf->mbufSize, pCmd->skipFlush); + + /* Prepare Security Accelerator descriptor to SRAM words 0 - 7 */ + mvCesaSramDescrBuild(pSA->config, 0, pCmd->cryptoOffset + fixOffset, + pCmd->ivOffset + fixOffset, pCmd->cryptoLength, + pCmd->macOffset + fixOffset, pCmd->digestOffset + fixOffset, + pCmd->macLength, pCmd->macLength, pReq, &pDmaDesc[i]); + i++; + + /* Add special descriptor Ownership for CPU */ + pDmaDesc[i].byteCnt = 0; + pDmaDesc[i].phySrcAdd = 0; + pDmaDesc[i].phyDestAdd = 0; + i++; + + /********* Prepare DMA descriptors to copy from SRAM to pDst *********/ + pMbuf = pCmd->pDst; + i += mvCesaDmaCopyPrepare(pMbuf, pSramBuf + fixOffset, &pDmaDesc[i], + MV_TRUE, 0, pMbuf->mbufSize, pCmd->skipFlush); + + /* Next field of Last DMA descriptor must be NULL */ + pDmaDesc[i-1].phyNextDescPtr = 0; + pReq->dma[0].pDmaLast = &pDmaDesc[i-1]; + mvOsCacheFlush(NULL, pReq->dma[0].pDmaFirst, i*sizeof(MV_DMA_DESC)); + + return MV_OK; +} + + +/******************************************************************************* +* mvCesaSramDescrBuild - Set CESA descriptor in SRAM +* +* DESCRIPTION: +* This function builds CESA descriptor in SRAM from all Command parameters +* +* +* INPUT: +* int chan - CESA channel uses the descriptor +* MV_U32 config - 32 bits of WORD_0 in CESA descriptor structure +* int cryptoOffset - Offset from the beginning of SRAM buffer where +* data for encryption/decription is started. +* int ivOffset - Offset of crypto IV from the SRAM base. Valid only +* for first fragment. +* int cryptoLength - Size (in bytes) of data for encryption/descryption +* operation on this fragment. +* int macOffset - Offset from the beginning of SRAM buffer where +* data for Authentication is started +* int digestOffset - Offset from the beginning of SRAM buffer where +* digest is located. Valid for first and last fragments. +* int macLength - Size (in bytes) of data for Authentication +* operation on this fragment. +* int macTotalLen - Toatl size (in bytes) of data for Authentication +* operation on the whole request (packet). Valid for +* last fragment only. +* +* RETURN: None +* +*******************************************************************************/ +static void mvCesaSramDescrBuild(MV_U32 config, int frag, + int cryptoOffset, int ivOffset, int cryptoLength, + int macOffset, int digestOffset, int macLength, + int macTotalLen, MV_CESA_REQ* pReq, MV_DMA_DESC* pDmaDesc) +{ + MV_CESA_DESC* pCesaDesc = &pReq->pCesaDesc[frag]; + MV_CESA_DESC* pSramDesc = pSramDesc = &cesaSramVirtPtr->desc; + MV_U16 sramBufOffset = (MV_U16)((MV_U8*)cesaSramVirtPtr->buf - mvCesaSramAddrGet()); + + pCesaDesc->config = MV_32BIT_LE(config); + + if( (config & MV_CESA_OPERATION_MASK) != + (MV_CESA_MAC_ONLY << MV_CESA_OPERATION_OFFSET) ) + { + /* word 1 */ + pCesaDesc->cryptoSrcOffset = MV_16BIT_LE(sramBufOffset + cryptoOffset); + pCesaDesc->cryptoDstOffset = MV_16BIT_LE(sramBufOffset + cryptoOffset); + /* word 2 */ + pCesaDesc->cryptoDataLen = MV_16BIT_LE(cryptoLength); + /* word 3 */ + pCesaDesc->cryptoKeyOffset = MV_16BIT_LE((MV_U16)(cesaSramVirtPtr->sramSA.cryptoKey - + mvCesaSramAddrGet())); + /* word 4 */ + pCesaDesc->cryptoIvOffset = MV_16BIT_LE((MV_U16)(cesaSramVirtPtr->cryptoIV - + mvCesaSramAddrGet())); + pCesaDesc->cryptoIvBufOffset = MV_16BIT_LE(sramBufOffset + ivOffset); + } + + if( (config & MV_CESA_OPERATION_MASK) != + (MV_CESA_CRYPTO_ONLY << MV_CESA_OPERATION_OFFSET) ) + { + /* word 5 */ + pCesaDesc->macSrcOffset = MV_16BIT_LE(sramBufOffset + macOffset); + pCesaDesc->macTotalLen = MV_16BIT_LE(macTotalLen); + + /* word 6 */ + pCesaDesc->macDigestOffset = MV_16BIT_LE(sramBufOffset + digestOffset); + pCesaDesc->macDataLen = MV_16BIT_LE(macLength); + + /* word 7 */ + pCesaDesc->macInnerIvOffset = MV_16BIT_LE((MV_U16)(cesaSramVirtPtr->sramSA.macInnerIV - + mvCesaSramAddrGet())); + pCesaDesc->macOuterIvOffset = MV_16BIT_LE((MV_U16)(cesaSramVirtPtr->sramSA.macOuterIV - + mvCesaSramAddrGet())); + } + /* Prepare DMA descriptor to CESA descriptor from DRAM to SRAM */ + pDmaDesc->phySrcAdd = MV_32BIT_LE(mvCesaVirtToPhys(&pReq->cesaDescBuf, pCesaDesc)); + pDmaDesc->phyDestAdd = MV_32BIT_LE(mvCesaSramVirtToPhys(NULL, (MV_U8*)pSramDesc)); + pDmaDesc->byteCnt = MV_32BIT_LE(sizeof(MV_CESA_DESC) | BIT31); + + /* flush Source buffer */ + mvOsCacheFlush(NULL, pCesaDesc, sizeof(MV_CESA_DESC)); +} + +/******************************************************************************* +* mvCesaSramSaUpdate - Move required SA information to SRAM if needed. +* +* DESCRIPTION: +* Copy to SRAM values of the required SA. +* +* +* INPUT: +* short sid - Session ID needs SRAM Cache update +* MV_DMA_DESC *pDmaDesc - Pointer to DMA descriptor used to +* copy SA values from DRAM to SRAM. +* +* RETURN: +* MV_OK - Cache entry for this SA copied to SRAM. +* MV_NO_CHANGE - Cache entry for this SA already exist in SRAM +* +*******************************************************************************/ +static INLINE void mvCesaSramSaUpdate(short sid, MV_DMA_DESC *pDmaDesc) +{ + MV_CESA_SA *pSA = &pCesaSAD[sid]; + + /* Prepare DMA descriptor to Copy CACHE_SA from SA database in DRAM to SRAM */ + pDmaDesc->byteCnt = MV_32BIT_LE(sizeof(MV_CESA_SRAM_SA) | BIT31); + pDmaDesc->phySrcAdd = MV_32BIT_LE(mvCesaVirtToPhys(&cesaSramSaBuf, pSA->pSramSA)); + pDmaDesc->phyDestAdd = + MV_32BIT_LE(mvCesaSramVirtToPhys(NULL, (MV_U8*)&cesaSramVirtPtr->sramSA)); + + /* Source buffer is already flushed during OpenSession*/ + /*mvOsCacheFlush(NULL, &pSA->sramSA, sizeof(MV_CESA_SRAM_SA));*/ +} + +/******************************************************************************* +* mvCesaDmaCopyPrepare - prepare DMA descriptor list to copy data presented by +* Mbuf structure from DRAM to SRAM +* +* DESCRIPTION: +* +* +* INPUT: +* MV_CESA_MBUF* pMbuf - pointer to Mbuf structure contains request +* data in DRAM +* MV_U8* pSramBuf - pointer to buffer in SRAM where data should +* be copied to. +* MV_DMA_DESC* pDmaDesc - pointer to first DMA descriptor for this copy. +* The function set number of DMA descriptors needed +* to copy the copySize bytes from Mbuf. +* MV_BOOL isToMbuf - Copy direction. +* MV_TRUE means copy from SRAM buffer to Mbuf in DRAM. +* MV_FALSE means copy from Mbuf in DRAM to SRAM buffer. +* int offset - Offset in the Mbuf structure that copy should be +* started from. +* int copySize - Size of data should be copied. +* +* RETURN: +* int - number of DMA descriptors used for the copy. +* +*******************************************************************************/ +#ifndef MV_NETBSD +static INLINE int mvCesaDmaCopyPrepare(MV_CESA_MBUF* pMbuf, MV_U8* pSramBuf, + MV_DMA_DESC* pDmaDesc, MV_BOOL isToMbuf, + int offset, int copySize, MV_BOOL skipFlush) +{ + int bufOffset, bufSize, size, frag, i; + MV_U8* pBuf; + + i = 0; + + /* Calculate start place for copy: fragment number and offset in the fragment */ + frag = mvCesaMbufOffset(pMbuf, offset, &bufOffset); + bufSize = pMbuf->pFrags[frag].bufSize - bufOffset; + pBuf = pMbuf->pFrags[frag].bufVirtPtr + bufOffset; + + /* Size accumulate total copy size */ + size = 0; + + /* Create DMA lists to copy mBuf from pSrc to SRAM */ + while(size < copySize) + { + /* Find copy size for each DMA descriptor */ + bufSize = MV_MIN(bufSize, (copySize - size)); + pDmaDesc[i].byteCnt = MV_32BIT_LE(bufSize | BIT31); + if(isToMbuf) + { + pDmaDesc[i].phyDestAdd = MV_32BIT_LE(mvOsIoVirtToPhy(NULL, pBuf)); + pDmaDesc[i].phySrcAdd = + MV_32BIT_LE(mvCesaSramVirtToPhys(NULL, (pSramBuf + size))); + /* invalidate the buffer */ + if(skipFlush == MV_FALSE) + mvOsCacheInvalidate(NULL, pBuf, bufSize); + } + else + { + pDmaDesc[i].phySrcAdd = MV_32BIT_LE(mvOsIoVirtToPhy(NULL, pBuf)); + pDmaDesc[i].phyDestAdd = + MV_32BIT_LE(mvCesaSramVirtToPhys(NULL, (pSramBuf + size))); + /* flush the buffer */ + if(skipFlush == MV_FALSE) + mvOsCacheFlush(NULL, pBuf, bufSize); + } + + /* Count number of used DMA descriptors */ + i++; + size += bufSize; + + /* go to next fragment in the Mbuf */ + frag++; + pBuf = pMbuf->pFrags[frag].bufVirtPtr; + bufSize = pMbuf->pFrags[frag].bufSize; + } + return i; +} +#else /* MV_NETBSD */ +static int mvCesaDmaCopyPrepare(MV_CESA_MBUF* pMbuf, MV_U8* pSramBuf, + MV_DMA_DESC* pDmaDesc, MV_BOOL isToMbuf, + int offset, int copySize, MV_BOOL skipFlush) +{ + int bufOffset, bufSize, thisSize, size, frag, i; + MV_ULONG bufPhys, sramPhys; + MV_U8* pBuf; + + /* + * Calculate start place for copy: fragment number and offset in + * the fragment + */ + frag = mvCesaMbufOffset(pMbuf, offset, &bufOffset); + + /* + * Get SRAM physical address only once. We can update it in-place + * as we build the descriptor chain. + */ + sramPhys = mvCesaSramVirtToPhys(NULL, pSramBuf); + + /* + * 'size' accumulates total copy size, 'i' counts desccriptors. + */ + size = i = 0; + + /* Create DMA lists to copy mBuf from pSrc to SRAM */ + while (size < copySize) { + /* + * Calculate # of bytes to copy from the current fragment, + * and the pointer to the start of data + */ + bufSize = pMbuf->pFrags[frag].bufSize - bufOffset; + pBuf = pMbuf->pFrags[frag].bufVirtPtr + bufOffset; + bufOffset = 0; /* First frag may be non-zero */ + frag++; + + /* + * As long as there is data in the current fragment... + */ + while (bufSize > 0) { + /* + * Ensure we don't cross an MMU page boundary. + * XXX: This is NetBSD-specific, but it is a + * quick and dirty way to fix the problem. + * A true HAL would rely on the OS-specific + * driver to do this... + */ + thisSize = PAGE_SIZE - + (((MV_ULONG)pBuf) & (PAGE_SIZE - 1)); + thisSize = MV_MIN(bufSize, thisSize); + /* + * Make sure we don't copy more than requested + */ + if (thisSize > (copySize - size)) { + thisSize = copySize - size; + bufSize = 0; + } + + /* + * Physicall address of this fragment + */ + bufPhys = MV_32BIT_LE(mvOsIoVirtToPhy(NULL, pBuf)); + + /* + * Set up the descriptor + */ + pDmaDesc[i].byteCnt = MV_32BIT_LE(thisSize | BIT31); + if(isToMbuf) { + pDmaDesc[i].phyDestAdd = bufPhys; + pDmaDesc[i].phySrcAdd = MV_32BIT_LE(sramPhys); + /* invalidate the buffer */ + if(skipFlush == MV_FALSE) + mvOsCacheInvalidate(NULL, pBuf, thisSize); + } else { + pDmaDesc[i].phySrcAdd = bufPhys; + pDmaDesc[i].phyDestAdd = MV_32BIT_LE(sramPhys); + /* flush the buffer */ + if(skipFlush == MV_FALSE) + mvOsCacheFlush(NULL, pBuf, thisSize); + } + + pDmaDesc[i].phyNextDescPtr = + MV_32BIT_LE(mvOsIoVirtToPhy(NULL,(&pDmaDesc[i+1]))); + + /* flush the DMA desc */ + mvOsCacheFlush(NULL, &pDmaDesc[i], sizeof(MV_DMA_DESC)); + + /* Update state */ + bufSize -= thisSize; + sramPhys += thisSize; + pBuf += thisSize; + size += thisSize; + i++; + } + } + + return i; +} +#endif /* MV_NETBSD */ +/******************************************************************************* +* mvCesaHmacIvGet - Calculate Inner and Outter values from HMAC key +* +* DESCRIPTION: +* This function calculate Inner and Outer values used for HMAC algorithm. +* This operation allows improve performance fro the whole HMAC processing. +* +* INPUT: +* MV_CESA_MAC_MODE macMode - Authentication mode: HMAC_MD5 or HMAC_SHA1. +* unsigned char key[] - Pointer to HMAC key. +* int keyLength - Size of HMAC key (maximum 64 bytes) +* +* OUTPUT: +* unsigned char innerIV[] - HASH(key^inner) +* unsigned char outerIV[] - HASH(key^outter) +* +* RETURN: None +* +*******************************************************************************/ +static void mvCesaHmacIvGet(MV_CESA_MAC_MODE macMode, unsigned char key[], int keyLength, + unsigned char innerIV[], unsigned char outerIV[]) +{ + unsigned char inner[MV_CESA_MAX_MAC_KEY_LENGTH]; + unsigned char outer[MV_CESA_MAX_MAC_KEY_LENGTH]; + int i, digestSize = 0; +#if defined(MV_CPU_LE) || defined(MV_PPC) + MV_U32 swapped32, val32, *pVal32; +#endif + for(i=0; ipFrags[frag].bufVirtPtr + fragOffset; + size = pMbuf->pFrags[frag].bufSize - fragOffset; + + /* Complete Inner part */ + while(macLeftSize > 0) + { + if(macLeftSize <= size) + { + mvSHA1Update(&ctx, pData, macLeftSize); + break; + } + mvSHA1Update(&ctx, pData, size); + macLeftSize -= size; + frag++; + pData = pMbuf->pFrags[frag].bufVirtPtr; + size = pMbuf->pFrags[frag].bufSize; + } + mvSHA1Final(pDigest, &ctx); +/* + mvOsPrintf("mvCesaFragSha1Complete: pOuterIV=%p, macLeftSize=%d, macTotalSize=%d\n", + pOuterIV, macLeftSize, macTotalSize); + mvDebugMemDump(pDigest, MV_CESA_SHA1_DIGEST_SIZE, 1); +*/ + + if(pOuterIV != NULL) + { + /* If HMAC - Complete Outer part */ + for(i=0; ipFrags[frag].bufVirtPtr + fragOffset; + size = pMbuf->pFrags[frag].bufSize - fragOffset; + + /* Complete Inner part */ + while(macLeftSize > 0) + { + if(macLeftSize <= size) + { + mvMD5Update(&ctx, pData, macLeftSize); + break; + } + mvMD5Update(&ctx, pData, size); + macLeftSize -= size; + frag++; + pData = pMbuf->pFrags[frag].bufVirtPtr; + size = pMbuf->pFrags[frag].bufSize; + } + mvMD5Final(pDigest, &ctx); + +/* + mvOsPrintf("mvCesaFragMd5Complete: pOuterIV=%p, macLeftSize=%d, macTotalSize=%d\n", + pOuterIV, macLeftSize, macTotalSize); + mvDebugMemDump(pDigest, MV_CESA_MD5_DIGEST_SIZE, 1); +*/ + if(pOuterIV != NULL) + { + /* Complete Outer part */ + for(i=0; ipCmd; + MV_U8* pDigest; + MV_CESA_MAC_MODE macMode; + MV_U8* pOuterIV = NULL; + + /* Copy data from Source fragment to Destination */ + if(pCmd->pSrc != pCmd->pDst) + { + mvCesaMbufCopy(pCmd->pDst, pReq->frags.bufOffset, + pCmd->pSrc, pReq->frags.bufOffset, macDataSize); + } + +/* + mvCesaCopyFromMbuf(cesaSramVirtPtr->buf[0], pCmd->pSrc, pReq->frags.bufOffset, macDataSize); + mvCesaCopyToMbuf(cesaSramVirtPtr->buf[0], pCmd->pDst, pReq->frags.bufOffset, macDataSize); +*/ + pDigest = (mvCesaSramAddrGet() + pReq->frags.newDigestOffset); + + macMode = (pSA->config & MV_CESA_MAC_MODE_MASK) >> MV_CESA_MAC_MODE_OFFSET; +/* + mvOsPrintf("macDataSize=%d, macLength=%d, digestOffset=%d, macMode=%d\n", + macDataSize, pCmd->macLength, pCmd->digestOffset, macMode); +*/ + switch(macMode) + { + case MV_CESA_MAC_HMAC_MD5: + pOuterIV = pSA->pSramSA->macOuterIV; + + case MV_CESA_MAC_MD5: + mvCesaFragMd5Complete(pCmd->pDst, pReq->frags.bufOffset, pOuterIV, + macDataSize, pCmd->macLength, pDigest); + break; + + case MV_CESA_MAC_HMAC_SHA1: + pOuterIV = pSA->pSramSA->macOuterIV; + + case MV_CESA_MAC_SHA1: + mvCesaFragSha1Complete(pCmd->pDst, pReq->frags.bufOffset, pOuterIV, + macDataSize, pCmd->macLength, pDigest); + break; + + default: + mvOsPrintf("mvCesaFragAuthComplete: Unexpected macMode %d\n", macMode); + return MV_BAD_PARAM; + } + return MV_OK; +} + +/******************************************************************************* +* mvCesaCtrModeInit - +* +* DESCRIPTION: +* +* +* INPUT: NONE +* +* +* RETURN: +* MV_CESA_COMMAND* +* +*******************************************************************************/ +static MV_CESA_COMMAND* mvCesaCtrModeInit(void) +{ + MV_CESA_MBUF *pMbuf; + MV_U8 *pBuf; + MV_CESA_COMMAND *pCmd; + + pBuf = mvOsMalloc(sizeof(MV_CESA_COMMAND) + + sizeof(MV_CESA_MBUF) + sizeof(MV_BUF_INFO) + 100); + if(pBuf == NULL) + { + mvOsPrintf("mvCesaSessionOpen: Can't allocate %u bytes for CTR Mode\n", + sizeof(MV_CESA_COMMAND) + sizeof(MV_CESA_MBUF) + sizeof(MV_BUF_INFO) ); + return NULL; + } + pCmd = (MV_CESA_COMMAND*)pBuf; + pBuf += sizeof(MV_CESA_COMMAND); + + pMbuf = (MV_CESA_MBUF*)pBuf; + pBuf += sizeof(MV_CESA_MBUF); + + pMbuf->pFrags = (MV_BUF_INFO*)pBuf; + + pMbuf->numFrags = 1; + pCmd->pSrc = pMbuf; + pCmd->pDst = pMbuf; +/* + mvOsPrintf("CtrModeInit: pCmd=%p, pSrc=%p, pDst=%p, pFrags=%p\n", + pCmd, pCmd->pSrc, pCmd->pDst, + pMbuf->pFrags); +*/ + return pCmd; +} + +/******************************************************************************* +* mvCesaCtrModePrepare - +* +* DESCRIPTION: +* +* +* INPUT: +* MV_CESA_COMMAND *pCtrModeCmd, MV_CESA_COMMAND *pCmd +* +* RETURN: +* MV_STATUS +* +*******************************************************************************/ +static MV_STATUS mvCesaCtrModePrepare(MV_CESA_COMMAND *pCtrModeCmd, MV_CESA_COMMAND *pCmd) +{ + MV_CESA_MBUF *pMbuf; + MV_U8 *pBuf, *pIV; + MV_U32 counter, *pCounter; + int cryptoSize = MV_ALIGN_UP(pCmd->cryptoLength, MV_CESA_AES_BLOCK_SIZE); +/* + mvOsPrintf("CtrModePrepare: pCmd=%p, pCtrSrc=%p, pCtrDst=%p, pOrgCmd=%p, pOrgSrc=%p, pOrgDst=%p\n", + pCmd, pCmd->pSrc, pCmd->pDst, + pCtrModeCmd, pCtrModeCmd->pSrc, pCtrModeCmd->pDst); +*/ + pMbuf = pCtrModeCmd->pSrc; + + /* Allocate buffer for Key stream */ + pBuf = mvOsIoCachedMalloc(cesaOsHandle,cryptoSize, + &pMbuf->pFrags[0].bufPhysAddr, + &pMbuf->pFrags[0].memHandle); + if(pBuf == NULL) + { + mvOsPrintf("mvCesaCtrModePrepare: Can't allocate %d bytes\n", cryptoSize); + return MV_OUT_OF_CPU_MEM; + } + memset(pBuf, 0, cryptoSize); + mvOsCacheFlush(NULL, pBuf, cryptoSize); + + pMbuf->pFrags[0].bufVirtPtr = pBuf; + pMbuf->mbufSize = cryptoSize; + pMbuf->pFrags[0].bufSize = cryptoSize; + + pCtrModeCmd->pReqPrv = pCmd->pReqPrv; + pCtrModeCmd->sessionId = pCmd->sessionId; + + /* ivFromUser and ivOffset are don't care */ + pCtrModeCmd->cryptoOffset = 0; + pCtrModeCmd->cryptoLength = cryptoSize; + + /* digestOffset, macOffset and macLength are don't care */ + + mvCesaCopyFromMbuf(pBuf, pCmd->pSrc, pCmd->ivOffset, MV_CESA_AES_BLOCK_SIZE); + pCounter = (MV_U32*)(pBuf + (MV_CESA_AES_BLOCK_SIZE - sizeof(counter))); + counter = *pCounter; + counter = MV_32BIT_BE(counter); + pIV = pBuf; + cryptoSize -= MV_CESA_AES_BLOCK_SIZE; + + /* fill key stream */ + while(cryptoSize > 0) + { + pBuf += MV_CESA_AES_BLOCK_SIZE; + memcpy(pBuf, pIV, MV_CESA_AES_BLOCK_SIZE - sizeof(counter)); + pCounter = (MV_U32*)(pBuf + (MV_CESA_AES_BLOCK_SIZE - sizeof(counter))); + counter++; + *pCounter = MV_32BIT_BE(counter); + cryptoSize -= MV_CESA_AES_BLOCK_SIZE; + } + + return MV_OK; +} + +/******************************************************************************* +* mvCesaCtrModeComplete - +* +* DESCRIPTION: +* +* +* INPUT: +* MV_CESA_COMMAND *pOrgCmd, MV_CESA_COMMAND *pCmd +* +* RETURN: +* MV_STATUS +* +*******************************************************************************/ +static MV_STATUS mvCesaCtrModeComplete(MV_CESA_COMMAND *pOrgCmd, MV_CESA_COMMAND *pCmd) +{ + int srcFrag, dstFrag, srcOffset, dstOffset, keyOffset, srcSize, dstSize; + int cryptoSize = pCmd->cryptoLength; + MV_U8 *pSrc, *pDst, *pKey; + MV_STATUS status = MV_OK; +/* + mvOsPrintf("CtrModeComplete: pCmd=%p, pCtrSrc=%p, pCtrDst=%p, pOrgCmd=%p, pOrgSrc=%p, pOrgDst=%p\n", + pCmd, pCmd->pSrc, pCmd->pDst, + pOrgCmd, pOrgCmd->pSrc, pOrgCmd->pDst); +*/ + /* XOR source data with key stream to destination data */ + pKey = pCmd->pDst->pFrags[0].bufVirtPtr; + keyOffset = 0; + + if( (pOrgCmd->pSrc != pOrgCmd->pDst) && + (pOrgCmd->cryptoOffset > 0) ) + { + /* Copy Prefix from source buffer to destination buffer */ + + status = mvCesaMbufCopy(pOrgCmd->pDst, 0, + pOrgCmd->pSrc, 0, pOrgCmd->cryptoOffset); +/* + status = mvCesaCopyFromMbuf(tempBuf, pOrgCmd->pSrc, + 0, pOrgCmd->cryptoOffset); + status = mvCesaCopyToMbuf(tempBuf, pOrgCmd->pDst, + 0, pOrgCmd->cryptoOffset); +*/ + } + + srcFrag = mvCesaMbufOffset(pOrgCmd->pSrc, pOrgCmd->cryptoOffset, &srcOffset); + pSrc = pOrgCmd->pSrc->pFrags[srcFrag].bufVirtPtr; + srcSize = pOrgCmd->pSrc->pFrags[srcFrag].bufSize; + + dstFrag = mvCesaMbufOffset(pOrgCmd->pDst, pOrgCmd->cryptoOffset, &dstOffset); + pDst = pOrgCmd->pDst->pFrags[dstFrag].bufVirtPtr; + dstSize = pOrgCmd->pDst->pFrags[dstFrag].bufSize; + + while(cryptoSize > 0) + { + pDst[dstOffset] = (pSrc[srcOffset] ^ pKey[keyOffset]); + + cryptoSize--; + dstOffset++; + srcOffset++; + keyOffset++; + + if(srcOffset >= srcSize) + { + srcFrag++; + srcOffset = 0; + pSrc = pOrgCmd->pSrc->pFrags[srcFrag].bufVirtPtr; + srcSize = pOrgCmd->pSrc->pFrags[srcFrag].bufSize; + } + + if(dstOffset >= dstSize) + { + dstFrag++; + dstOffset = 0; + pDst = pOrgCmd->pDst->pFrags[dstFrag].bufVirtPtr; + dstSize = pOrgCmd->pDst->pFrags[dstFrag].bufSize; + } + } + + if(pOrgCmd->pSrc != pOrgCmd->pDst) + { + /* Copy Suffix from source buffer to destination buffer */ + srcOffset = pOrgCmd->cryptoOffset + pOrgCmd->cryptoLength; + + if( (pOrgCmd->pDst->mbufSize - srcOffset) > 0) + { + status = mvCesaMbufCopy(pOrgCmd->pDst, srcOffset, + pOrgCmd->pSrc, srcOffset, + pOrgCmd->pDst->mbufSize - srcOffset); + } + +/* + status = mvCesaCopyFromMbuf(tempBuf, pOrgCmd->pSrc, + srcOffset, pOrgCmd->pSrc->mbufSize - srcOffset); + status = mvCesaCopyToMbuf(tempBuf, pOrgCmd->pDst, + srcOffset, pOrgCmd->pDst->mbufSize - srcOffset); +*/ + } + + /* Free buffer used for Key stream */ + mvOsIoCachedFree(cesaOsHandle,pCmd->pDst->pFrags[0].bufSize, + pCmd->pDst->pFrags[0].bufPhysAddr, + pCmd->pDst->pFrags[0].bufVirtPtr, + pCmd->pDst->pFrags[0].memHandle); + + return MV_OK; +} + +/******************************************************************************* +* mvCesaCtrModeFinish - +* +* DESCRIPTION: +* +* +* INPUT: +* MV_CESA_COMMAND* pCmd +* +* RETURN: +* MV_STATUS +* +*******************************************************************************/ +static void mvCesaCtrModeFinish(MV_CESA_COMMAND* pCmd) +{ + mvOsFree(pCmd); +} + +/******************************************************************************* +* mvCesaParamCheck - +* +* DESCRIPTION: +* +* +* INPUT: +* MV_CESA_SA* pSA, MV_CESA_COMMAND *pCmd, MV_U8* pFixOffset +* +* RETURN: +* MV_STATUS +* +*******************************************************************************/ +static MV_STATUS mvCesaParamCheck(MV_CESA_SA* pSA, MV_CESA_COMMAND *pCmd, + MV_U8* pFixOffset) +{ + MV_U8 fixOffset = 0xFF; + + /* Check AUTH operation parameters */ + if( ((pSA->config & MV_CESA_OPERATION_MASK) != + (MV_CESA_CRYPTO_ONLY << MV_CESA_OPERATION_OFFSET)) ) + { + /* MAC offset should be at least 4 byte aligned */ + if( MV_IS_NOT_ALIGN(pCmd->macOffset, 4) ) + { + mvOsPrintf("mvCesaAction: macOffset %d must be 4 byte aligned\n", + pCmd->macOffset); + return MV_BAD_PARAM; + } + /* Digest offset must be 4 byte aligned */ + if( MV_IS_NOT_ALIGN(pCmd->digestOffset, 4) ) + { + mvOsPrintf("mvCesaAction: digestOffset %d must be 4 byte aligned\n", + pCmd->digestOffset); + return MV_BAD_PARAM; + } + /* In addition all offsets should be the same alignment: 8 or 4 */ + if(fixOffset == 0xFF) + { + fixOffset = (pCmd->macOffset % 8); + } + else + { + if( (pCmd->macOffset % 8) != fixOffset) + { + mvOsPrintf("mvCesaAction: macOffset %d mod 8 must be equal %d\n", + pCmd->macOffset, fixOffset); + return MV_BAD_PARAM; + } + } + if( (pCmd->digestOffset % 8) != fixOffset) + { + mvOsPrintf("mvCesaAction: digestOffset %d mod 8 must be equal %d\n", + pCmd->digestOffset, fixOffset); + return MV_BAD_PARAM; + } + } + /* Check CRYPTO operation parameters */ + if( ((pSA->config & MV_CESA_OPERATION_MASK) != + (MV_CESA_MAC_ONLY << MV_CESA_OPERATION_OFFSET)) ) + { + /* CryptoOffset should be at least 4 byte aligned */ + if( MV_IS_NOT_ALIGN(pCmd->cryptoOffset, 4) ) + { + mvOsPrintf("CesaAction: cryptoOffset=%d must be 4 byte aligned\n", + pCmd->cryptoOffset); + return MV_BAD_PARAM; + } + /* cryptoLength should be the whole number of blocks */ + if( MV_IS_NOT_ALIGN(pCmd->cryptoLength, pSA->cryptoBlockSize) ) + { + mvOsPrintf("mvCesaAction: cryptoLength=%d must be %d byte aligned\n", + pCmd->cryptoLength, pSA->cryptoBlockSize); + return MV_BAD_PARAM; + } + if(fixOffset == 0xFF) + { + fixOffset = (pCmd->cryptoOffset % 8); + } + else + { + /* In addition all offsets should be the same alignment: 8 or 4 */ + if( (pCmd->cryptoOffset % 8) != fixOffset) + { + mvOsPrintf("mvCesaAction: cryptoOffset %d mod 8 must be equal %d \n", + pCmd->cryptoOffset, fixOffset); + return MV_BAD_PARAM; + } + } + + /* check for CBC mode */ + if(pSA->cryptoIvSize > 0) + { + /* cryptoIV must not be part of CryptoLength */ + if( ((pCmd->ivOffset + pSA->cryptoIvSize) > pCmd->cryptoOffset) && + (pCmd->ivOffset < (pCmd->cryptoOffset + pCmd->cryptoLength)) ) + { + mvOsPrintf("mvCesaFragParamCheck: cryptoIvOffset (%d) is part of cryptoLength (%d+%d)\n", + pCmd->ivOffset, pCmd->macOffset, pCmd->macLength); + return MV_BAD_PARAM; + } + + /* ivOffset must be 4 byte aligned */ + if( MV_IS_NOT_ALIGN(pCmd->ivOffset, 4) ) + { + mvOsPrintf("CesaAction: ivOffset=%d must be 4 byte aligned\n", + pCmd->ivOffset); + return MV_BAD_PARAM; + } + /* In addition all offsets should be the same alignment: 8 or 4 */ + if( (pCmd->ivOffset % 8) != fixOffset) + { + mvOsPrintf("mvCesaAction: ivOffset %d mod 8 must be %d\n", + pCmd->ivOffset, fixOffset); + return MV_BAD_PARAM; + } + } + } + return MV_OK; +} + +/******************************************************************************* +* mvCesaFragParamCheck - +* +* DESCRIPTION: +* +* +* INPUT: +* MV_CESA_SA* pSA, MV_CESA_COMMAND *pCmd +* +* RETURN: +* MV_STATUS +* +*******************************************************************************/ +static MV_STATUS mvCesaFragParamCheck(MV_CESA_SA* pSA, MV_CESA_COMMAND *pCmd) +{ + int offset; + + if( ((pSA->config & MV_CESA_OPERATION_MASK) != + (MV_CESA_CRYPTO_ONLY << MV_CESA_OPERATION_OFFSET)) ) + { + /* macOffset must be less that SRAM buffer size */ + if(pCmd->macOffset > (sizeof(cesaSramVirtPtr->buf) - MV_CESA_AUTH_BLOCK_SIZE)) + { + mvOsPrintf("mvCesaFragParamCheck: macOffset is too large (%d)\n", + pCmd->macOffset); + return MV_BAD_PARAM; + } + /* macOffset+macSize must be more than mbufSize - SRAM buffer size */ + if( ((pCmd->macOffset + pCmd->macLength) > pCmd->pSrc->mbufSize) || + ((pCmd->pSrc->mbufSize - (pCmd->macOffset + pCmd->macLength)) >= + sizeof(cesaSramVirtPtr->buf)) ) + { + mvOsPrintf("mvCesaFragParamCheck: macLength is too large (%d), mbufSize=%d\n", + pCmd->macLength, pCmd->pSrc->mbufSize); + return MV_BAD_PARAM; + } + } + + if( ((pSA->config & MV_CESA_OPERATION_MASK) != + (MV_CESA_MAC_ONLY << MV_CESA_OPERATION_OFFSET)) ) + { + /* cryptoOffset must be less that SRAM buffer size */ + /* 4 for possible fixOffset */ + if( (pCmd->cryptoOffset + 4) > (sizeof(cesaSramVirtPtr->buf) - pSA->cryptoBlockSize)) + { + mvOsPrintf("mvCesaFragParamCheck: cryptoOffset is too large (%d)\n", + pCmd->cryptoOffset); + return MV_BAD_PARAM; + } + + /* cryptoOffset+cryptoSize must be more than mbufSize - SRAM buffer size */ + if( ((pCmd->cryptoOffset + pCmd->cryptoLength) > pCmd->pSrc->mbufSize) || + ((pCmd->pSrc->mbufSize - (pCmd->cryptoOffset + pCmd->cryptoLength)) >= + (sizeof(cesaSramVirtPtr->buf) - pSA->cryptoBlockSize)) ) + { + mvOsPrintf("mvCesaFragParamCheck: cryptoLength is too large (%d), mbufSize=%d\n", + pCmd->cryptoLength, pCmd->pSrc->mbufSize); + return MV_BAD_PARAM; + } + } + + /* When MAC_THEN_CRYPTO or CRYPTO_THEN_MAC */ + if( ((pSA->config & MV_CESA_OPERATION_MASK) == + (MV_CESA_MAC_THEN_CRYPTO << MV_CESA_OPERATION_OFFSET)) || + ((pSA->config & MV_CESA_OPERATION_MASK) == + (MV_CESA_CRYPTO_THEN_MAC << MV_CESA_OPERATION_OFFSET)) ) + { + if( (mvCtrlModelGet() == MV_5182_DEV_ID) || + ( (mvCtrlModelGet() == MV_5181_DEV_ID) && + (mvCtrlRevGet() >= MV_5181L_A0_REV) && + (pCmd->macLength >= (1 << 14)) ) ) + { + return MV_NOT_ALLOWED; + } + + /* abs(cryptoOffset-macOffset) must be aligned cryptoBlockSize */ + if(pCmd->cryptoOffset > pCmd->macOffset) + { + offset = pCmd->cryptoOffset - pCmd->macOffset; + } + else + { + offset = pCmd->macOffset - pCmd->cryptoOffset; + } + + if( MV_IS_NOT_ALIGN(offset, pSA->cryptoBlockSize) ) + { +/* + mvOsPrintf("mvCesaFragParamCheck: (cryptoOffset - macOffset) must be %d byte aligned\n", + pSA->cryptoBlockSize); +*/ + return MV_NOT_ALLOWED; + } + /* Digest must not be part of CryptoLength */ + if( ((pCmd->digestOffset + pSA->digestSize) > pCmd->cryptoOffset) && + (pCmd->digestOffset < (pCmd->cryptoOffset + pCmd->cryptoLength)) ) + { +/* + mvOsPrintf("mvCesaFragParamCheck: digestOffset (%d) is part of cryptoLength (%d+%d)\n", + pCmd->digestOffset, pCmd->cryptoOffset, pCmd->cryptoLength); +*/ + return MV_NOT_ALLOWED; + } + } + return MV_OK; +} + +/******************************************************************************* +* mvCesaFragSizeFind - +* +* DESCRIPTION: +* +* +* INPUT: +* MV_CESA_SA* pSA, MV_CESA_COMMAND *pCmd, +* int cryptoOffset, int macOffset, +* +* OUTPUT: +* int* pCopySize, int* pCryptoDataSize, int* pMacDataSize +* +* RETURN: +* MV_STATUS +* +*******************************************************************************/ +static void mvCesaFragSizeFind(MV_CESA_SA* pSA, MV_CESA_REQ* pReq, + int cryptoOffset, int macOffset, + int* pCopySize, int* pCryptoDataSize, int* pMacDataSize) +{ + MV_CESA_COMMAND *pCmd = pReq->pCmd; + int cryptoDataSize, macDataSize, copySize; + + cryptoDataSize = macDataSize = 0; + copySize = *pCopySize; + + if( (pSA->config & MV_CESA_OPERATION_MASK) != + (MV_CESA_MAC_ONLY << MV_CESA_OPERATION_OFFSET) ) + { + cryptoDataSize = MV_MIN( (copySize - cryptoOffset), + (pCmd->cryptoLength - (pReq->frags.cryptoSize + 1)) ); + + /* cryptoSize for each fragment must be the whole number of blocksSize */ + if( MV_IS_NOT_ALIGN(cryptoDataSize, pSA->cryptoBlockSize) ) + { + cryptoDataSize = MV_ALIGN_DOWN(cryptoDataSize, pSA->cryptoBlockSize); + copySize = cryptoOffset + cryptoDataSize; + } + } + if( (pSA->config & MV_CESA_OPERATION_MASK) != + (MV_CESA_CRYPTO_ONLY << MV_CESA_OPERATION_OFFSET) ) + { + macDataSize = MV_MIN( (copySize - macOffset), + (pCmd->macLength - (pReq->frags.macSize + 1))); + + /* macSize for each fragment (except last) must be the whole number of blocksSize */ + if( MV_IS_NOT_ALIGN(macDataSize, MV_CESA_AUTH_BLOCK_SIZE) ) + { + macDataSize = MV_ALIGN_DOWN(macDataSize, MV_CESA_AUTH_BLOCK_SIZE); + copySize = macOffset + macDataSize; + } + cryptoDataSize = copySize - cryptoOffset; + } + *pCopySize = copySize; + + if(pCryptoDataSize != NULL) + *pCryptoDataSize = cryptoDataSize; + + if(pMacDataSize != NULL) + *pMacDataSize = macDataSize; +} diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/cesa/mvCesa.h b/target/linux/generic/files/crypto/ocf/kirkwood/cesa/mvCesa.h new file mode 100644 index 0000000..c0abc9b --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/cesa/mvCesa.h @@ -0,0 +1,412 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +/******************************************************************************* +* mvCesa.h - Header File for Cryptographic Engines and Security Accelerator +* +* DESCRIPTION: +* This header file contains macros typedefs and function declaration for +* the Marvell Cryptographic Engines and Security Accelerator. +* +*******************************************************************************/ + +#ifndef __mvCesa_h__ +#define __mvCesa_h__ + +#include "mvOs.h" +#include "mvCommon.h" +#include "mvDebug.h" + +#include "ctrlEnv/mvCtrlEnvSpec.h" + +#include "cesa/mvMD5.h" +#include "cesa/mvSHA1.h" + +#include "cesa/mvCesa.h" +#include "cesa/AES/mvAes.h" +#include "mvSysHwConfig.h" + +#ifdef MV_INCLUDE_IDMA +#include "idma/mvIdma.h" +#include "idma/mvIdmaRegs.h" +#else +/* Redefine MV_DMA_DESC structure */ +typedef struct _mvDmaDesc +{ + MV_U32 byteCnt; /* The total number of bytes to transfer */ + MV_U32 phySrcAdd; /* The physical source address */ + MV_U32 phyDestAdd; /* The physical destination address */ + MV_U32 phyNextDescPtr; /* If we are using chain mode DMA transfer, */ + /* then this pointer should point to the */ + /* physical address of the next descriptor, */ + /* otherwise it should be NULL. */ +}MV_DMA_DESC; +#endif /* MV_INCLUDE_IDMA */ + +#include "cesa/mvCesaRegs.h" + +#define MV_CESA_AUTH_BLOCK_SIZE 64 /* bytes */ + +#define MV_CESA_MD5_DIGEST_SIZE 16 /* bytes */ +#define MV_CESA_SHA1_DIGEST_SIZE 20 /* bytes */ + +#define MV_CESA_MAX_DIGEST_SIZE MV_CESA_SHA1_DIGEST_SIZE + +#define MV_CESA_DES_KEY_LENGTH 8 /* bytes = 64 bits */ +#define MV_CESA_3DES_KEY_LENGTH 24 /* bytes = 192 bits */ +#define MV_CESA_AES_128_KEY_LENGTH 16 /* bytes = 128 bits */ +#define MV_CESA_AES_192_KEY_LENGTH 24 /* bytes = 192 bits */ +#define MV_CESA_AES_256_KEY_LENGTH 32 /* bytes = 256 bits */ + +#define MV_CESA_MAX_CRYPTO_KEY_LENGTH MV_CESA_AES_256_KEY_LENGTH + +#define MV_CESA_DES_BLOCK_SIZE 8 /* bytes = 64 bits */ +#define MV_CESA_3DES_BLOCK_SIZE 8 /* bytes = 64 bits */ + +#define MV_CESA_AES_BLOCK_SIZE 16 /* bytes = 128 bits */ + +#define MV_CESA_MAX_IV_LENGTH MV_CESA_AES_BLOCK_SIZE + +#define MV_CESA_MAX_MAC_KEY_LENGTH 64 /* bytes */ + +typedef struct +{ + MV_U8 cryptoKey[MV_CESA_MAX_CRYPTO_KEY_LENGTH]; + MV_U8 macKey[MV_CESA_MAX_MAC_KEY_LENGTH]; + MV_CESA_OPERATION operation; + MV_CESA_DIRECTION direction; + MV_CESA_CRYPTO_ALG cryptoAlgorithm; + MV_CESA_CRYPTO_MODE cryptoMode; + MV_U8 cryptoKeyLength; + MV_CESA_MAC_MODE macMode; + MV_U8 macKeyLength; + MV_U8 digestSize; + +} MV_CESA_OPEN_SESSION; + +typedef struct +{ + MV_BUF_INFO *pFrags; + MV_U16 numFrags; + MV_U16 mbufSize; + +} MV_CESA_MBUF; + +typedef struct +{ + void* pReqPrv; /* instead of reqId */ + MV_U32 retCode; + MV_16 sessionId; + +} MV_CESA_RESULT; + +typedef void (*MV_CESA_CALLBACK) (MV_CESA_RESULT* pResult); + + +typedef struct +{ + void* pReqPrv; /* instead of reqId */ + MV_CESA_MBUF* pSrc; + MV_CESA_MBUF* pDst; + MV_CESA_CALLBACK* pFuncCB; + MV_16 sessionId; + MV_U16 ivFromUser; + MV_U16 ivOffset; + MV_U16 cryptoOffset; + MV_U16 cryptoLength; + MV_U16 digestOffset; + MV_U16 macOffset; + MV_U16 macLength; + MV_BOOL skipFlush; +} MV_CESA_COMMAND; + + + +MV_STATUS mvCesaHalInit (int numOfSession, int queueDepth, char* pSramBase, MV_U32 cryptEngBase, void *osHandle); +MV_STATUS mvCesaFinish (void); +MV_STATUS mvCesaSessionOpen(MV_CESA_OPEN_SESSION *pSession, short* pSid); +MV_STATUS mvCesaSessionClose(short sid); +MV_STATUS mvCesaCryptoIvSet(MV_U8* pIV, int ivSize); + +MV_STATUS mvCesaAction (MV_CESA_COMMAND* pCmd); + +MV_U32 mvCesaInProcessGet(void); +MV_STATUS mvCesaReadyDispatch(void); +MV_STATUS mvCesaReadyGet(MV_CESA_RESULT* pResult); +MV_BOOL mvCesaIsReady(void); + +int mvCesaMbufOffset(MV_CESA_MBUF* pMbuf, int offset, int* pBufOffset); +MV_STATUS mvCesaCopyFromMbuf(MV_U8* pDst, MV_CESA_MBUF* pSrcMbuf, + int offset, int size); +MV_STATUS mvCesaCopyToMbuf(MV_U8* pSrc, MV_CESA_MBUF* pDstMbuf, + int offset, int size); +MV_STATUS mvCesaMbufCopy(MV_CESA_MBUF* pMbufDst, int dstMbufOffset, + MV_CESA_MBUF* pMbufSrc, int srcMbufOffset, int size); + +/********** Debug functions ********/ + +void mvCesaDebugMbuf(const char* str, MV_CESA_MBUF *pMbuf, int offset, int size); +void mvCesaDebugSA(short sid, int mode); +void mvCesaDebugStats(void); +void mvCesaDebugStatsClear(void); +void mvCesaDebugRegs(void); +void mvCesaDebugStatus(void); +void mvCesaDebugQueue(int mode); +void mvCesaDebugSram(int mode); +void mvCesaDebugSAD(int mode); + + +/******** CESA Private definitions ********/ +#if (MV_CESA_VERSION >= 2) +#if (MV_CACHE_COHERENCY == MV_CACHE_COHER_SW) +#define MV_CESA_TDMA_CTRL_VALUE MV_CESA_TDMA_DST_BURST_MASK(MV_CESA_TDMA_BURST_128B) \ + | MV_CESA_TDMA_SRC_BURST_MASK(MV_CESA_TDMA_BURST_128B) \ + | MV_CESA_TDMA_OUTSTAND_READ_EN_MASK \ + | MV_CESA_TDMA_NO_BYTE_SWAP_MASK \ + | MV_CESA_TDMA_ENABLE_MASK +#else +#define MV_CESA_TDMA_CTRL_VALUE MV_CESA_TDMA_DST_BURST_MASK(MV_CESA_TDMA_BURST_32B) \ + | MV_CESA_TDMA_SRC_BURST_MASK(MV_CESA_TDMA_BURST_128B) \ + /*| MV_CESA_TDMA_OUTSTAND_READ_EN_MASK */\ + | MV_CESA_TDMA_ENABLE_MASK + +#endif +#else +#define MV_CESA_IDMA_CTRL_LOW_VALUE ICCLR_DST_BURST_LIM_128BYTE \ + | ICCLR_SRC_BURST_LIM_128BYTE \ + | ICCLR_INT_MODE_MASK \ + | ICCLR_BLOCK_MODE \ + | ICCLR_CHAN_ENABLE \ + | ICCLR_DESC_MODE_16M +#endif /* MV_CESA_VERSION >= 2 */ + +#define MV_CESA_MAX_PKT_SIZE (64 * 1024) +#define MV_CESA_MAX_MBUF_FRAGS 20 + +#define MV_CESA_MAX_REQ_FRAGS ( (MV_CESA_MAX_PKT_SIZE / MV_CESA_MAX_BUF_SIZE) + 1) + +#define MV_CESA_MAX_DMA_DESC (MV_CESA_MAX_MBUF_FRAGS*2 + 5) + +#define MAX_CESA_CHAIN_LENGTH 20 + +typedef enum +{ + MV_CESA_IDLE = 0, + MV_CESA_PENDING, + MV_CESA_PROCESS, + MV_CESA_READY, +#if (MV_CESA_VERSION >= 3) + MV_CESA_CHAIN, +#endif +} MV_CESA_STATE; + + +/* Session database */ + +/* Map of Key materials of the session in SRAM. + * Each field must be 8 byte aligned + * Total size: 32 + 24 + 24 = 80 bytes + */ +typedef struct +{ + MV_U8 cryptoKey[MV_CESA_MAX_CRYPTO_KEY_LENGTH]; + MV_U8 macInnerIV[MV_CESA_MAX_DIGEST_SIZE]; + MV_U8 reservedInner[4]; + MV_U8 macOuterIV[MV_CESA_MAX_DIGEST_SIZE]; + MV_U8 reservedOuter[4]; + +} MV_CESA_SRAM_SA; + +typedef struct +{ + MV_CESA_SRAM_SA* pSramSA; + MV_U32 config; + MV_U8 cryptoKeyLength; + MV_U8 cryptoIvSize; + MV_U8 cryptoBlockSize; + MV_U8 digestSize; + MV_U8 macKeyLength; + MV_U8 valid; + MV_U8 ctrMode; + MV_U32 count; + +} MV_CESA_SA; + +/* DMA list management */ +typedef struct +{ + MV_DMA_DESC* pDmaFirst; + MV_DMA_DESC* pDmaLast; + +} MV_CESA_DMA; + + +typedef struct +{ + MV_U8 numFrag; + MV_U8 nextFrag; + int bufOffset; + int cryptoSize; + int macSize; + int newDigestOffset; + MV_U8 orgDigest[MV_CESA_MAX_DIGEST_SIZE]; + +} MV_CESA_FRAGS; + +/* Request queue */ +typedef struct +{ + MV_U8 state; + MV_U8 fragMode; + MV_U8 fixOffset; + MV_CESA_COMMAND* pCmd; + MV_CESA_COMMAND* pOrgCmd; + MV_BUF_INFO dmaDescBuf; + MV_CESA_DMA dma[MV_CESA_MAX_REQ_FRAGS]; + MV_BUF_INFO cesaDescBuf; + MV_CESA_DESC* pCesaDesc; + MV_CESA_FRAGS frags; + + +} MV_CESA_REQ; + + +/* SRAM map */ +/* Total SRAM size calculation */ +/* SRAM size = + * MV_CESA_MAX_BUF_SIZE + + * sizeof(MV_CESA_DESC) + + * MV_CESA_MAX_IV_LENGTH + + * MV_CESA_MAX_IV_LENGTH + + * MV_CESA_MAX_DIGEST_SIZE + + * sizeof(MV_CESA_SRAM_SA) + * = 1600 + 32 + 16 + 16 + 24 + 80 + 280 (reserved) = 2048 bytes + * = 3200 + 32 + 16 + 16 + 24 + 80 + 728 (reserved) = 4096 bytes + */ +typedef struct +{ + MV_U8 buf[MV_CESA_MAX_BUF_SIZE]; + MV_CESA_DESC desc; + MV_U8 cryptoIV[MV_CESA_MAX_IV_LENGTH]; + MV_U8 tempCryptoIV[MV_CESA_MAX_IV_LENGTH]; + MV_U8 tempDigest[MV_CESA_MAX_DIGEST_SIZE+4]; + MV_CESA_SRAM_SA sramSA; + +} MV_CESA_SRAM_MAP; + + +typedef struct +{ + MV_U32 openedCount; + MV_U32 closedCount; + MV_U32 fragCount; + MV_U32 reqCount; + MV_U32 maxReqCount; + MV_U32 procCount; + MV_U32 readyCount; + MV_U32 notReadyCount; + MV_U32 startCount; +#if (MV_CESA_VERSION >= 3) + MV_U32 maxChainUsage; +#endif + +} MV_CESA_STATS; + + +/* External variables */ + +extern MV_CESA_STATS cesaStats; +extern MV_CESA_FRAGS cesaFrags; + +extern MV_BUF_INFO cesaSramSaBuf; + +extern MV_CESA_SA* pCesaSAD; +extern MV_U16 cesaMaxSA; + +extern MV_CESA_REQ* pCesaReqFirst; +extern MV_CESA_REQ* pCesaReqLast; +extern MV_CESA_REQ* pCesaReqEmpty; +extern MV_CESA_REQ* pCesaReqProcess; +extern int cesaQueueDepth; +extern int cesaReqResources; +#if (MV_CESA_VERSION>= 3) +extern MV_U32 cesaChainLength; +#endif + +extern MV_CESA_SRAM_MAP* cesaSramVirtPtr; +extern MV_U32 cesaSramPhysAddr; + +static INLINE MV_ULONG mvCesaVirtToPhys(MV_BUF_INFO* pBufInfo, void* pVirt) +{ + return (pBufInfo->bufPhysAddr + ((MV_U8*)pVirt - pBufInfo->bufVirtPtr)); +} + +/* Additional DEBUG functions */ +void mvCesaDebugSramSA(MV_CESA_SRAM_SA* pSramSA, int mode); +void mvCesaDebugCmd(MV_CESA_COMMAND* pCmd, int mode); +void mvCesaDebugDescriptor(MV_CESA_DESC* pDesc); + + + +#endif /* __mvCesa_h__ */ diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/cesa/mvCesaDebug.c b/target/linux/generic/files/crypto/ocf/kirkwood/cesa/mvCesaDebug.c new file mode 100644 index 0000000..31b78a8 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/cesa/mvCesaDebug.c @@ -0,0 +1,484 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#include "mvOs.h" +#include "mvDebug.h" + +#include "cesa/mvMD5.h" +#include "cesa/mvSHA1.h" + +#include "cesa/mvCesa.h" +#include "cesa/mvCesaRegs.h" +#include "cesa/AES/mvAes.h" + +static const char* mvCesaDebugStateStr(MV_CESA_STATE state) +{ + switch(state) + { + case MV_CESA_IDLE: + return "Idle"; + + case MV_CESA_PENDING: + return "Pend"; + + case MV_CESA_PROCESS: + return "Proc"; + + case MV_CESA_READY: + return "Ready"; + + default: + break; + } + return "Unknown"; +} + +static const char* mvCesaDebugOperStr(MV_CESA_OPERATION oper) +{ + switch(oper) + { + case MV_CESA_MAC_ONLY: + return "MacOnly"; + + case MV_CESA_CRYPTO_ONLY: + return "CryptoOnly"; + + case MV_CESA_MAC_THEN_CRYPTO: + return "MacCrypto"; + + case MV_CESA_CRYPTO_THEN_MAC: + return "CryptoMac"; + + default: + break; + } + return "Null"; +} + +static const char* mvCesaDebugCryptoAlgStr(MV_CESA_CRYPTO_ALG cryptoAlg) +{ + switch(cryptoAlg) + { + case MV_CESA_CRYPTO_DES: + return "DES"; + + case MV_CESA_CRYPTO_3DES: + return "3DES"; + + case MV_CESA_CRYPTO_AES: + return "AES"; + + default: + break; + } + return "Null"; +} + +static const char* mvCesaDebugMacModeStr(MV_CESA_MAC_MODE macMode) +{ + switch(macMode) + { + case MV_CESA_MAC_MD5: + return "MD5"; + + case MV_CESA_MAC_SHA1: + return "SHA1"; + + case MV_CESA_MAC_HMAC_MD5: + return "HMAC-MD5"; + + case MV_CESA_MAC_HMAC_SHA1: + return "HMAC_SHA1"; + + default: + break; + } + return "Null"; +} + +void mvCesaDebugCmd(MV_CESA_COMMAND* pCmd, int mode) +{ + mvOsPrintf("pCmd=%p, pReqPrv=%p, pSrc=%p, pDst=%p, pCB=%p, sid=%d\n", + pCmd, pCmd->pReqPrv, pCmd->pSrc, pCmd->pDst, + pCmd->pFuncCB, pCmd->sessionId); + mvOsPrintf("isUser=%d, ivOffs=%d, crOffs=%d, crLen=%d, digest=%d, macOffs=%d, macLen=%d\n", + pCmd->ivFromUser, pCmd->ivOffset, pCmd->cryptoOffset, pCmd->cryptoLength, + pCmd->digestOffset, pCmd->macOffset, pCmd->macLength); +} + +/* no need to use in tool */ +void mvCesaDebugMbuf(const char* str, MV_CESA_MBUF *pMbuf, int offset, int size) +{ + int frag, len, fragOffset; + + if(str != NULL) + mvOsPrintf("%s: pMbuf=%p, numFrags=%d, mbufSize=%d\n", + str, pMbuf, pMbuf->numFrags, pMbuf->mbufSize); + + frag = mvCesaMbufOffset(pMbuf, offset, &fragOffset); + if(frag == MV_INVALID) + { + mvOsPrintf("CESA Mbuf Error: offset (%d) out of range\n", offset); + return; + } + + for(; fragnumFrags; frag++) + { + mvOsPrintf("#%2d. bufVirt=%p, bufSize=%d\n", + frag, pMbuf->pFrags[frag].bufVirtPtr, + pMbuf->pFrags[frag].bufSize); + if(size > 0) + { + len = MV_MIN(pMbuf->pFrags[frag].bufSize, size); + mvDebugMemDump(pMbuf->pFrags[frag].bufVirtPtr+fragOffset, len, 1); + size -= len; + fragOffset = 0; + } + } +} + +void mvCesaDebugRegs(void) +{ + mvOsPrintf("\t CESA Registers:\n"); + + mvOsPrintf("MV_CESA_CMD_REG : 0x%X = 0x%08x\n", + MV_CESA_CMD_REG, + MV_REG_READ( MV_CESA_CMD_REG ) ); + + mvOsPrintf("MV_CESA_CHAN_DESC_OFFSET_REG : 0x%X = 0x%08x\n", + MV_CESA_CHAN_DESC_OFFSET_REG, + MV_REG_READ(MV_CESA_CHAN_DESC_OFFSET_REG) ); + + mvOsPrintf("MV_CESA_CFG_REG : 0x%X = 0x%08x\n", + MV_CESA_CFG_REG, + MV_REG_READ( MV_CESA_CFG_REG ) ); + + mvOsPrintf("MV_CESA_STATUS_REG : 0x%X = 0x%08x\n", + MV_CESA_STATUS_REG, + MV_REG_READ( MV_CESA_STATUS_REG ) ); + + mvOsPrintf("MV_CESA_ISR_CAUSE_REG : 0x%X = 0x%08x\n", + MV_CESA_ISR_CAUSE_REG, + MV_REG_READ( MV_CESA_ISR_CAUSE_REG ) ); + + mvOsPrintf("MV_CESA_ISR_MASK_REG : 0x%X = 0x%08x\n", + MV_CESA_ISR_MASK_REG, + MV_REG_READ( MV_CESA_ISR_MASK_REG ) ); +#if (MV_CESA_VERSION >= 2) + mvOsPrintf("MV_CESA_TDMA_CTRL_REG : 0x%X = 0x%08x\n", + MV_CESA_TDMA_CTRL_REG, + MV_REG_READ( MV_CESA_TDMA_CTRL_REG ) ); + + mvOsPrintf("MV_CESA_TDMA_BYTE_COUNT_REG : 0x%X = 0x%08x\n", + MV_CESA_TDMA_BYTE_COUNT_REG, + MV_REG_READ( MV_CESA_TDMA_BYTE_COUNT_REG ) ); + + mvOsPrintf("MV_CESA_TDMA_SRC_ADDR_REG : 0x%X = 0x%08x\n", + MV_CESA_TDMA_SRC_ADDR_REG, + MV_REG_READ( MV_CESA_TDMA_SRC_ADDR_REG ) ); + + mvOsPrintf("MV_CESA_TDMA_DST_ADDR_REG : 0x%X = 0x%08x\n", + MV_CESA_TDMA_DST_ADDR_REG, + MV_REG_READ( MV_CESA_TDMA_DST_ADDR_REG ) ); + + mvOsPrintf("MV_CESA_TDMA_NEXT_DESC_PTR_REG : 0x%X = 0x%08x\n", + MV_CESA_TDMA_NEXT_DESC_PTR_REG, + MV_REG_READ( MV_CESA_TDMA_NEXT_DESC_PTR_REG ) ); + + mvOsPrintf("MV_CESA_TDMA_CURR_DESC_PTR_REG : 0x%X = 0x%08x\n", + MV_CESA_TDMA_CURR_DESC_PTR_REG, + MV_REG_READ( MV_CESA_TDMA_CURR_DESC_PTR_REG ) ); + + mvOsPrintf("MV_CESA_TDMA_ERROR_CAUSE_REG : 0x%X = 0x%08x\n", + MV_CESA_TDMA_ERROR_CAUSE_REG, + MV_REG_READ( MV_CESA_TDMA_ERROR_CAUSE_REG ) ); + + mvOsPrintf("MV_CESA_TDMA_ERROR_MASK_REG : 0x%X = 0x%08x\n", + MV_CESA_TDMA_ERROR_MASK_REG, + MV_REG_READ( MV_CESA_TDMA_ERROR_CAUSE_REG ) ); + +#endif +} + +void mvCesaDebugStatus(void) +{ + mvOsPrintf("\n\t CESA Status\n\n"); + + mvOsPrintf("pReqQ=%p, qDepth=%d, reqSize=%ld bytes, qRes=%d, ", + pCesaReqFirst, cesaQueueDepth, sizeof(MV_CESA_REQ), + cesaReqResources); +#if (MV_CESA_VERSION >= 3) + mvOsPrintf("chainLength=%u\n",cesaChainLength); +#else + mvOsPrintf("\n"); +#endif + + mvOsPrintf("pSAD=%p, maxSA=%d, sizeSA=%ld bytes\n", + pCesaSAD, cesaMaxSA, sizeof(MV_CESA_SA)); + + mvOsPrintf("\n"); + + mvCesaDebugRegs(); + mvCesaDebugStats(); + mvCesaDebugStatsClear(); +} + +void mvCesaDebugDescriptor(MV_CESA_DESC* pDesc) +{ + mvOsPrintf("config=0x%08x, crSrcOffs=0x%04x, crDstOffs=0x%04x\n", + pDesc->config, pDesc->cryptoSrcOffset, pDesc->cryptoDstOffset); + + mvOsPrintf("crLen=0x%04x, crKeyOffs=0x%04x, ivOffs=0x%04x, ivBufOffs=0x%04x\n", + pDesc->cryptoDataLen, pDesc->cryptoKeyOffset, + pDesc->cryptoIvOffset, pDesc->cryptoIvBufOffset); + + mvOsPrintf("macSrc=0x%04x, digest=0x%04x, macLen=0x%04x, inIv=0x%04x, outIv=0x%04x\n", + pDesc->macSrcOffset, pDesc->macDigestOffset, pDesc->macDataLen, + pDesc->macInnerIvOffset, pDesc->macOuterIvOffset); +} + +void mvCesaDebugQueue(int mode) +{ + mvOsPrintf("\n\t CESA Request Queue:\n\n"); + + mvOsPrintf("pFirstReq=%p, pLastReq=%p, qDepth=%d, reqSize=%ld bytes\n", + pCesaReqFirst, pCesaReqLast, cesaQueueDepth, sizeof(MV_CESA_REQ)); + + mvOsPrintf("pEmpty=%p, pProcess=%p, qResources=%d\n", + pCesaReqEmpty, pCesaReqProcess, + cesaReqResources); + + if(mode != 0) + { + int count = 0; + MV_CESA_REQ* pReq = pCesaReqFirst; + + for(count=0; countstate), + pReq->fragMode, pReq->pCmd, pReq->dma[0].pDmaFirst, &pReq->pCesaDesc[0]); + if(pReq->fragMode != MV_CESA_FRAG_NONE) + { + int frag; + + mvOsPrintf("pFrags=%p, num=%d, next=%d, bufOffset=%d, cryptoSize=%d, macSize=%d\n", + &pReq->frags, pReq->frags.numFrag, pReq->frags.nextFrag, + pReq->frags.bufOffset, pReq->frags.cryptoSize, pReq->frags.macSize); + for(frag=0; fragfrags.numFrag; frag++) + { + mvOsPrintf("#%d: pDmaFirst=%p, pDesc=%p\n", frag, + pReq->dma[frag].pDmaFirst, &pReq->pCesaDesc[frag]); + } + } + if(mode > 1) + { + /* Print out Command */ + mvCesaDebugCmd(pReq->pCmd, mode); + + /* Print out Descriptor */ + mvCesaDebugDescriptor(&pReq->pCesaDesc[0]); + } + pReq++; + } + } +} + + +void mvCesaDebugSramSA(MV_CESA_SRAM_SA* pSramSA, int mode) +{ + if(pSramSA == NULL) + { + mvOsPrintf("cesaSramSA: Unexpected pSramSA=%p\n", pSramSA); + return; + } + mvOsPrintf("pSramSA=%p, sizeSramSA=%ld bytes\n", + pSramSA, sizeof(MV_CESA_SRAM_SA)); + + if(mode != 0) + { + mvOsPrintf("cryptoKey=%p, maxCryptoKey=%d bytes\n", + pSramSA->cryptoKey, MV_CESA_MAX_CRYPTO_KEY_LENGTH); + mvDebugMemDump(pSramSA->cryptoKey, MV_CESA_MAX_CRYPTO_KEY_LENGTH, 1); + + mvOsPrintf("macInnerIV=%p, maxInnerIV=%d bytes\n", + pSramSA->macInnerIV, MV_CESA_MAX_DIGEST_SIZE); + mvDebugMemDump(pSramSA->macInnerIV, MV_CESA_MAX_DIGEST_SIZE, 1); + + mvOsPrintf("macOuterIV=%p, maxOuterIV=%d bytes\n", + pSramSA->macOuterIV, MV_CESA_MAX_DIGEST_SIZE); + mvDebugMemDump(pSramSA->macOuterIV, MV_CESA_MAX_DIGEST_SIZE, 1); + } +} + +void mvCesaDebugSA(short sid, int mode) +{ + MV_CESA_OPERATION oper; + MV_CESA_DIRECTION dir; + MV_CESA_CRYPTO_ALG cryptoAlg; + MV_CESA_CRYPTO_MODE cryptoMode; + MV_CESA_MAC_MODE macMode; + MV_CESA_SA* pSA = &pCesaSAD[sid]; + + if( (pSA->valid) || ((pSA->count != 0) && (mode > 0)) || (mode >= 2) ) + { + mvOsPrintf("\n\nCESA SA Entry #%d (%p) - %s (count=%d)\n", + sid, pSA, + pSA->valid ? "Valid" : "Invalid", pSA->count); + + oper = (pSA->config & MV_CESA_OPERATION_MASK) >> MV_CESA_OPERATION_OFFSET; + dir = (pSA->config & MV_CESA_DIRECTION_MASK) >> MV_CESA_DIRECTION_BIT; + mvOsPrintf("%s - %s ", mvCesaDebugOperStr(oper), + (dir == MV_CESA_DIR_ENCODE) ? "Encode" : "Decode"); + if(oper != MV_CESA_MAC_ONLY) + { + cryptoAlg = (pSA->config & MV_CESA_CRYPTO_ALG_MASK) >> MV_CESA_CRYPTO_ALG_OFFSET; + cryptoMode = (pSA->config & MV_CESA_CRYPTO_MODE_MASK) >> MV_CESA_CRYPTO_MODE_BIT; + mvOsPrintf("- %s - %s ", mvCesaDebugCryptoAlgStr(cryptoAlg), + (cryptoMode == MV_CESA_CRYPTO_ECB) ? "ECB" : "CBC"); + } + if(oper != MV_CESA_CRYPTO_ONLY) + { + macMode = (pSA->config & MV_CESA_MAC_MODE_MASK) >> MV_CESA_MAC_MODE_OFFSET; + mvOsPrintf("- %s ", mvCesaDebugMacModeStr(macMode)); + } + mvOsPrintf("\n"); + + if(mode > 0) + { + mvOsPrintf("config=0x%08x, cryptoKeySize=%d, digestSize=%d\n", + pCesaSAD[sid].config, pCesaSAD[sid].cryptoKeyLength, + pCesaSAD[sid].digestSize); + + mvCesaDebugSramSA(pCesaSAD[sid].pSramSA, mode); + } + } +} + + +/**/ +void mvCesaDebugSram(int mode) +{ + mvOsPrintf("\n\t SRAM contents: size=%ld, pVirt=%p\n\n", + sizeof(MV_CESA_SRAM_MAP), cesaSramVirtPtr); + + mvOsPrintf("\n\t Sram buffer: size=%d, pVirt=%p\n", + MV_CESA_MAX_BUF_SIZE, cesaSramVirtPtr->buf); + if(mode != 0) + mvDebugMemDump(cesaSramVirtPtr->buf, 64, 1); + + mvOsPrintf("\n"); + mvOsPrintf("\n\t Sram descriptor: size=%ld, pVirt=%p\n", + sizeof(MV_CESA_DESC), &cesaSramVirtPtr->desc); + if(mode != 0) + { + mvOsPrintf("\n"); + mvCesaDebugDescriptor(&cesaSramVirtPtr->desc); + } + mvOsPrintf("\n\t Sram IV: size=%d, pVirt=%p\n", + MV_CESA_MAX_IV_LENGTH, &cesaSramVirtPtr->cryptoIV); + if(mode != 0) + { + mvOsPrintf("\n"); + mvDebugMemDump(cesaSramVirtPtr->cryptoIV, MV_CESA_MAX_IV_LENGTH, 1); + } + mvOsPrintf("\n"); + mvCesaDebugSramSA(&cesaSramVirtPtr->sramSA, 0); +} + +void mvCesaDebugSAD(int mode) +{ + int sid; + + mvOsPrintf("\n\t Cesa SAD status: pSAD=%p, maxSA=%d\n", + pCesaSAD, cesaMaxSA); + + for(sid=0; sid= 3) + mvOsPrintf("maxChainUsage=%u\n",cesaStats.maxChainUsage); +#endif + mvOsPrintf("\n"); + mvOsPrintf("proc=%u, ready=%u, notReady=%u\n", + cesaStats.procCount, cesaStats.readyCount, cesaStats.notReadyCount); +} + +void mvCesaDebugStatsClear(void) +{ + memset(&cesaStats, 0, sizeof(cesaStats)); +} diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/cesa/mvCesaRegs.h b/target/linux/generic/files/crypto/ocf/kirkwood/cesa/mvCesaRegs.h new file mode 100644 index 0000000..6b7ce12 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/cesa/mvCesaRegs.h @@ -0,0 +1,357 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#ifndef __mvCesaRegs_h__ +#define __mvCesaRegs_h__ + +#include "mvTypes.h" + +typedef struct +{ + /* word 0 */ + MV_U32 config; + /* word 1 */ + MV_U16 cryptoSrcOffset; + MV_U16 cryptoDstOffset; + /* word 2 */ + MV_U16 cryptoDataLen; + MV_U16 reserved1; + /* word 3 */ + MV_U16 cryptoKeyOffset; + MV_U16 reserved2; + /* word 4 */ + MV_U16 cryptoIvOffset; + MV_U16 cryptoIvBufOffset; + /* word 5 */ + MV_U16 macSrcOffset; + MV_U16 macTotalLen; + /* word 6 */ + MV_U16 macDigestOffset; + MV_U16 macDataLen; + /* word 7 */ + MV_U16 macInnerIvOffset; + MV_U16 macOuterIvOffset; + +} MV_CESA_DESC; + +/* operation */ +typedef enum +{ + MV_CESA_MAC_ONLY = 0, + MV_CESA_CRYPTO_ONLY = 1, + MV_CESA_MAC_THEN_CRYPTO = 2, + MV_CESA_CRYPTO_THEN_MAC = 3, + + MV_CESA_MAX_OPERATION + +} MV_CESA_OPERATION; + +#define MV_CESA_OPERATION_OFFSET 0 +#define MV_CESA_OPERATION_MASK (0x3 << MV_CESA_OPERATION_OFFSET) + +/* mac algorithm */ +typedef enum +{ + MV_CESA_MAC_NULL = 0, + MV_CESA_MAC_MD5 = 4, + MV_CESA_MAC_SHA1 = 5, + MV_CESA_MAC_HMAC_MD5 = 6, + MV_CESA_MAC_HMAC_SHA1 = 7, + +} MV_CESA_MAC_MODE; + +#define MV_CESA_MAC_MODE_OFFSET 4 +#define MV_CESA_MAC_MODE_MASK (0x7 << MV_CESA_MAC_MODE_OFFSET) + +typedef enum +{ + MV_CESA_MAC_DIGEST_FULL = 0, + MV_CESA_MAC_DIGEST_96B = 1, + +} MV_CESA_MAC_DIGEST_SIZE; + +#define MV_CESA_MAC_DIGEST_SIZE_BIT 7 +#define MV_CESA_MAC_DIGEST_SIZE_MASK (1 << MV_CESA_MAC_DIGEST_SIZE_BIT) + + +typedef enum +{ + MV_CESA_CRYPTO_NULL = 0, + MV_CESA_CRYPTO_DES = 1, + MV_CESA_CRYPTO_3DES = 2, + MV_CESA_CRYPTO_AES = 3, + +} MV_CESA_CRYPTO_ALG; + +#define MV_CESA_CRYPTO_ALG_OFFSET 8 +#define MV_CESA_CRYPTO_ALG_MASK (0x3 << MV_CESA_CRYPTO_ALG_OFFSET) + + +/* direction */ +typedef enum +{ + MV_CESA_DIR_ENCODE = 0, + MV_CESA_DIR_DECODE = 1, + +} MV_CESA_DIRECTION; + +#define MV_CESA_DIRECTION_BIT 12 +#define MV_CESA_DIRECTION_MASK (1 << MV_CESA_DIRECTION_BIT) + +/* crypto IV mode */ +typedef enum +{ + MV_CESA_CRYPTO_ECB = 0, + MV_CESA_CRYPTO_CBC = 1, + + /* NO HW Support */ + MV_CESA_CRYPTO_CTR = 10, + +} MV_CESA_CRYPTO_MODE; + +#define MV_CESA_CRYPTO_MODE_BIT 16 +#define MV_CESA_CRYPTO_MODE_MASK (1 << MV_CESA_CRYPTO_MODE_BIT) + +/* 3DES mode */ +typedef enum +{ + MV_CESA_CRYPTO_3DES_EEE = 0, + MV_CESA_CRYPTO_3DES_EDE = 1, + +} MV_CESA_CRYPTO_3DES_MODE; + +#define MV_CESA_CRYPTO_3DES_MODE_BIT 20 +#define MV_CESA_CRYPTO_3DES_MODE_MASK (1 << MV_CESA_CRYPTO_3DES_MODE_BIT) + + +/* AES Key Length */ +typedef enum +{ + MV_CESA_CRYPTO_AES_KEY_128 = 0, + MV_CESA_CRYPTO_AES_KEY_192 = 1, + MV_CESA_CRYPTO_AES_KEY_256 = 2, + +} MV_CESA_CRYPTO_AES_KEY_LEN; + +#define MV_CESA_CRYPTO_AES_KEY_LEN_OFFSET 24 +#define MV_CESA_CRYPTO_AES_KEY_LEN_MASK (0x3 << MV_CESA_CRYPTO_AES_KEY_LEN_OFFSET) + +/* Fragmentation mode */ +typedef enum +{ + MV_CESA_FRAG_NONE = 0, + MV_CESA_FRAG_FIRST = 1, + MV_CESA_FRAG_LAST = 2, + MV_CESA_FRAG_MIDDLE = 3, + +} MV_CESA_FRAG_MODE; + +#define MV_CESA_FRAG_MODE_OFFSET 30 +#define MV_CESA_FRAG_MODE_MASK (0x3 << MV_CESA_FRAG_MODE_OFFSET) +/*---------------------------------------------------------------------------*/ + +/********** Security Accelerator Command Register **************/ +#define MV_CESA_CMD_REG (MV_CESA_REG_BASE + 0xE00) + +#define MV_CESA_CMD_CHAN_ENABLE_BIT 0 +#define MV_CESA_CMD_CHAN_ENABLE_MASK (1 << MV_CESA_CMD_CHAN_ENABLE_BIT) + +#define MV_CESA_CMD_CHAN_DISABLE_BIT 2 +#define MV_CESA_CMD_CHAN_DISABLE_MASK (1 << MV_CESA_CMD_CHAN_DISABLE_BIT) + +/********** Security Accelerator Descriptor Pointers Register **********/ +#define MV_CESA_CHAN_DESC_OFFSET_REG (MV_CESA_REG_BASE + 0xE04) + +/********** Security Accelerator Configuration Register **********/ +#define MV_CESA_CFG_REG (MV_CESA_REG_BASE + 0xE08) + +#define MV_CESA_CFG_STOP_DIGEST_ERR_BIT 0 +#define MV_CESA_CFG_STOP_DIGEST_ERR_MASK (1 << MV_CESA_CFG_STOP_DIGEST_ERR_BIT) + +#define MV_CESA_CFG_WAIT_DMA_BIT 7 +#define MV_CESA_CFG_WAIT_DMA_MASK (1 << MV_CESA_CFG_WAIT_DMA_BIT) + +#define MV_CESA_CFG_ACT_DMA_BIT 9 +#define MV_CESA_CFG_ACT_DMA_MASK (1 << MV_CESA_CFG_ACT_DMA_BIT) + +#define MV_CESA_CFG_CHAIN_MODE_BIT 11 +#define MV_CESA_CFG_CHAIN_MODE_MASK (1 << MV_CESA_CFG_CHAIN_MODE_BIT) + +/********** Security Accelerator Status Register ***********/ +#define MV_CESA_STATUS_REG (MV_CESA_REG_BASE + 0xE0C) + +#define MV_CESA_STATUS_ACTIVE_BIT 0 +#define MV_CESA_STATUS_ACTIVE_MASK (1 << MV_CESA_STATUS_ACTIVE_BIT) + +#define MV_CESA_STATUS_DIGEST_ERR_BIT 8 +#define MV_CESA_STATUS_DIGEST_ERR_MASK (1 << MV_CESA_STATUS_DIGEST_ERR_BIT) + + +/* Cryptographic Engines and Security Accelerator Interrupt Cause Register */ +#define MV_CESA_ISR_CAUSE_REG (MV_CESA_REG_BASE + 0xE20) + +/* Cryptographic Engines and Security Accelerator Interrupt Mask Register */ +#define MV_CESA_ISR_MASK_REG (MV_CESA_REG_BASE + 0xE24) + +#define MV_CESA_CAUSE_AUTH_MASK (1 << 0) +#define MV_CESA_CAUSE_DES_MASK (1 << 1) +#define MV_CESA_CAUSE_AES_ENCR_MASK (1 << 2) +#define MV_CESA_CAUSE_AES_DECR_MASK (1 << 3) +#define MV_CESA_CAUSE_DES_ALL_MASK (1 << 4) + +#define MV_CESA_CAUSE_ACC_BIT 5 +#define MV_CESA_CAUSE_ACC_MASK (1 << MV_CESA_CAUSE_ACC_BIT) + +#define MV_CESA_CAUSE_ACC_DMA_BIT 7 +#define MV_CESA_CAUSE_ACC_DMA_MASK (1 << MV_CESA_CAUSE_ACC_DMA_BIT) +#define MV_CESA_CAUSE_ACC_DMA_ALL_MASK (3 << MV_CESA_CAUSE_ACC_DMA_BIT) + +#define MV_CESA_CAUSE_DMA_COMPL_BIT 9 +#define MV_CESA_CAUSE_DMA_COMPL_MASK (1 << MV_CESA_CAUSE_DMA_COMPL_BIT) + +#define MV_CESA_CAUSE_DMA_OWN_ERR_BIT 10 +#define MV_CESA_CAUSE_DMA_OWN_ERR_MASK (1 < MV_CESA_CAUSE_DMA_OWN_ERR_BIT) + +#define MV_CESA_CAUSE_DMA_CHAIN_PKT_BIT 11 +#define MV_CESA_CAUSE_DMA_CHAIN_PKT_MASK (1 < MV_CESA_CAUSE_DMA_CHAIN_PKT_BIT) + + +#define MV_CESA_AUTH_DATA_IN_REG (MV_CESA_REG_BASE + 0xd38) +#define MV_CESA_AUTH_BIT_COUNT_LOW_REG (MV_CESA_REG_BASE + 0xd20) +#define MV_CESA_AUTH_BIT_COUNT_HIGH_REG (MV_CESA_REG_BASE + 0xd24) + +#define MV_CESA_AUTH_INIT_VAL_DIGEST_REG(i) (MV_CESA_REG_BASE + 0xd00 + (i<<2)) + +#define MV_CESA_AUTH_INIT_VAL_DIGEST_A_REG (MV_CESA_REG_BASE + 0xd00) +#define MV_CESA_AUTH_INIT_VAL_DIGEST_B_REG (MV_CESA_REG_BASE + 0xd04) +#define MV_CESA_AUTH_INIT_VAL_DIGEST_C_REG (MV_CESA_REG_BASE + 0xd08) +#define MV_CESA_AUTH_INIT_VAL_DIGEST_D_REG (MV_CESA_REG_BASE + 0xd0c) +#define MV_CESA_AUTH_INIT_VAL_DIGEST_E_REG (MV_CESA_REG_BASE + 0xd10) +#define MV_CESA_AUTH_COMMAND_REG (MV_CESA_REG_BASE + 0xd18) + +#define MV_CESA_AUTH_ALGORITHM_BIT 0 +#define MV_CESA_AUTH_ALGORITHM_MD5 (0< +wait_queue_head_t cesaTest_waitq; +spinlock_t cesaLock; + +#define CESA_TEST_LOCK(flags) spin_lock_irqsave( &cesaLock, flags) +#define CESA_TEST_UNLOCK(flags) spin_unlock_irqrestore( &cesaLock, flags); + +#define CESA_TEST_WAIT_INIT() init_waitqueue_head(&cesaTest_waitq) +#define CESA_TEST_WAKE_UP() wake_up(&cesaTest_waitq) +#define CESA_TEST_WAIT(cond, ms) wait_event_timeout(cesaTest_waitq, (cond), msecs_to_jiffies(ms)) + +#define CESA_TEST_TICK_GET() jiffies +#define CESA_TEST_TICK_TO_MS(tick) jiffies_to_msecs(tick) + +#elif defined(MV_NETBSD) + +#include +#include +static int cesaLock; + +#define CESA_TEST_LOCK(flags) flags = splnet() +#define CESA_TEST_UNLOCK(flags) splx(flags) + +#define CESA_TEST_WAIT_INIT() /* nothing */ +#define CESA_TEST_WAKE_UP() wakeup(&cesaLock) +#define CESA_TEST_WAIT(cond, ms) \ +do { \ + while (!(cond)) \ + tsleep(&cesaLock, PWAIT, "cesatest",mstohz(ms)); \ +} while (/*CONSTCOND*/0) + +#define CESA_TEST_TICK_GET() hardclock_ticks +#define CESA_TEST_TICK_TO_MS(tick) ((1000/hz)*(tick)) + +#define request_irq(i,h,t,n,a) \ + !mv_intr_establish((i),IPL_NET,(int(*)(void *))(h),(a)) + +#else +#error "Only Linux, VxWorks, or NetBSD OS are supported" +#endif + +#include "mvDebug.h" + +#include "mvSysHwConfig.h" +#include "boardEnv/mvBoardEnvLib.h" +#include "ctrlEnv/sys/mvCpuIf.h" +#include "cntmr/mvCntmr.h" +#include "cesa/mvCesa.h" +#include "cesa/mvCesaRegs.h" +#include "cesa/mvMD5.h" +#include "cesa/mvSHA1.h" + +#if defined(CONFIG_MV646xx) +#include "marvell_pic.h" +#endif + +#define MV_CESA_USE_TIMER_ID 0 +#define CESA_DEF_BUF_SIZE 1500 +#define CESA_DEF_BUF_NUM 1 +#define CESA_DEF_SESSION_NUM 32 + +#define CESA_DEF_ITER_NUM 100 + +#define CESA_DEF_REQ_SIZE 256 + + +/* CESA Tests Debug */ +#undef CESA_TEST_DEBUG + +#ifdef CESA_TEST_DEBUG + +# define CESA_TEST_DEBUG_PRINT(msg) mvOsPrintf msg +# define CESA_TEST_DEBUG_CODE(code) code + +typedef struct +{ + int type; /* 0 - isrEmpty, 1 - cesaReadyGet, 2 - cesaAction */ + MV_U32 timeStamp; + MV_U32 cause; + MV_U32 realCause; + MV_U32 dmaCause; + int resources; + MV_CESA_REQ* pReqReady; + MV_CESA_REQ* pReqEmpty; + MV_CESA_REQ* pReqProcess; +} MV_CESA_TEST_TRACE; + +#define MV_CESA_TEST_TRACE_SIZE 25 + +static int cesaTestTraceIdx = 0; +static MV_CESA_TEST_TRACE cesaTestTrace[MV_CESA_TEST_TRACE_SIZE]; + +static void cesaTestTraceAdd(int type, MV_U32 cause) +{ + cesaTestTrace[cesaTestTraceIdx].type = type; + cesaTestTrace[cesaTestTraceIdx].cause = cause; + cesaTestTrace[cesaTestTraceIdx].realCause = MV_REG_READ(MV_CESA_ISR_CAUSE_REG); + cesaTestTrace[cesaTestTraceIdx].dmaCause = MV_REG_READ(IDMA_CAUSE_REG); + cesaTestTrace[cesaTestTraceIdx].resources = cesaReqResources; + cesaTestTrace[cesaTestTraceIdx].pReqReady = pCesaReqReady; + cesaTestTrace[cesaTestTraceIdx].pReqEmpty = pCesaReqEmpty; + cesaTestTrace[cesaTestTraceIdx].pReqProcess = pCesaReqProcess; + cesaTestTrace[cesaTestTraceIdx].timeStamp = mvCntmrRead(MV_CESA_USE_TIMER_ID); + cesaTestTraceIdx++; + if(cesaTestTraceIdx == MV_CESA_TEST_TRACE_SIZE) + cesaTestTraceIdx = 0; +} + +#else + +# define CESA_TEST_DEBUG_PRINT(msg) +# define CESA_TEST_DEBUG_CODE(code) + +#endif /* CESA_TEST_DEBUG */ + +int cesaExpReqId=0; +int cesaCbIter=0; + +int cesaIdx; +int cesaIteration; +int cesaRateSize; +int cesaReqSize; +unsigned long cesaTaskId; +int cesaBufNum; +int cesaBufSize; +int cesaCheckOffset; +int cesaCheckSize; +int cesaCheckMode; +int cesaTestIdx; +int cesaCaseIdx; + + +MV_U32 cesaTestIsrCount = 0; +MV_U32 cesaTestIsrMissCount = 0; + +MV_U32 cesaCryptoError = 0; +MV_U32 cesaReqIdError = 0; +MV_U32 cesaError = 0; + +char* cesaHexBuffer = NULL; + +char* cesaBinBuffer = NULL; +char* cesaExpBinBuffer = NULL; + +char* cesaInputHexStr = NULL; +char* cesaOutputHexStr = NULL; + +MV_BUF_INFO cesaReqBufs[CESA_DEF_REQ_SIZE]; + +MV_CESA_COMMAND* cesaCmdRing; +MV_CESA_RESULT cesaResult; + +int cesaTestFull = 0; + +MV_BOOL cesaIsReady = MV_FALSE; +MV_U32 cesaCycles = 0; +MV_U32 cesaBeginTicks = 0; +MV_U32 cesaEndTicks = 0; +MV_U32 cesaRate = 0; +MV_U32 cesaRateAfterDot = 0; + +void *cesaTestOSHandle = NULL; + +enum +{ + CESA_FAST_CHECK_MODE = 0, + CESA_FULL_CHECK_MODE, + CESA_NULL_CHECK_MODE, + CESA_SHOW_CHECK_MODE, + CESA_SW_SHOW_CHECK_MODE, + CESA_SW_NULL_CHECK_MODE, + + CESA_MAX_CHECK_MODE +}; + +enum +{ + DES_TEST_TYPE = 0, + TRIPLE_DES_TEST_TYPE = 1, + AES_TEST_TYPE = 2, + MD5_TEST_TYPE = 3, + SHA_TEST_TYPE = 4, + COMBINED_TEST_TYPE = 5, + + MAX_TEST_TYPE +}; + +/* Tests data base */ +typedef struct +{ + short sid; + char cryptoAlgorithm; /* DES/3DES/AES */ + char cryptoMode; /* ECB or CBC */ + char macAlgorithm; /* MD5 / SHA1 */ + char operation; /* CRYPTO/HMAC/CRYPTO+HMAC/HMAC+CRYPTO */ + char direction; /* ENCODE(SIGN)/DECODE(VERIFY) */ + unsigned char* pCryptoKey; + int cryptoKeySize; + unsigned char* pMacKey; + int macKeySize; + const char* name; + +} MV_CESA_TEST_SESSION; + +typedef struct +{ + MV_CESA_TEST_SESSION* pSessions; + int numSessions; + +} MV_CESA_TEST_DB_ENTRY; + +typedef struct +{ + char* plainHexStr; + char* cipherHexStr; + unsigned char* pCryptoIV; + int cryptoLength; + int macLength; + int digestOffset; + +} MV_CESA_TEST_CASE; + +typedef struct +{ + int size; + const char* outputHexStr; + +} MV_CESA_SIZE_TEST; + +static unsigned char cryptoKey1[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}; + +static unsigned char cryptoKey7[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}; +static unsigned char iv1[] = {0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef}; + + +static unsigned char cryptoKey2[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F}; + +static unsigned char cryptoKey3[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17}; + +static unsigned char cryptoKey4[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f}; + +static unsigned char cryptoKey5[] = {0x56, 0xe4, 0x7a, 0x38, 0xc5, 0x59, 0x89, 0x74, + 0xbc, 0x46, 0x90, 0x3d, 0xba, 0x29, 0x03, 0x49}; + + +static unsigned char key3des1[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, + 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, + 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23}; + +/* Input ASCII string: The quick brown fox jump */ +static char plain3des1[] = "54686520717566636B2062726F776E20666F78206A756D70"; +static char cipher3des1[] = "A826FD8CE53B855FCCE21C8112256FE668D5C05DD9B6B900"; + +static unsigned char key3des2[] = {0x62, 0x7f, 0x46, 0x0e, 0x08, 0x10, 0x4a, 0x10, + 0x43, 0xcd, 0x26, 0x5d, 0x58, 0x40, 0xea, 0xf1, + 0x31, 0x3e, 0xdf, 0x97, 0xdf, 0x2a, 0x8a, 0x8c}; + +static unsigned char iv3des2[] = {0x8e, 0x29, 0xf7, 0x5e, 0xa7, 0x7e, 0x54, 0x75}; + +static char plain3des2[] = "326a494cd33fe756"; + +static char cipher3desCbc2[] = "8e29f75ea77e5475" + "b22b8d66de970692"; + +static unsigned char key3des3[] = {0x37, 0xae, 0x5e, 0xbf, 0x46, 0xdf, 0xf2, 0xdc, + 0x07, 0x54, 0xb9, 0x4f, 0x31, 0xcb, 0xb3, 0x85, + 0x5e, 0x7f, 0xd3, 0x6d, 0xc8, 0x70, 0xbf, 0xae}; + +static unsigned char iv3des3[] = {0x3d, 0x1d, 0xe3, 0xcc, 0x13, 0x2e, 0x3b, 0x65}; + +static char plain3des3[] = "84401f78fe6c10876d8ea23094ea5309"; + +static char cipher3desCbc3[] = "3d1de3cc132e3b65" + "7b1f7c7e3b1c948ebd04a75ffba7d2f5"; + +static unsigned char iv5[] = {0x8c, 0xe8, 0x2e, 0xef, 0xbe, 0xa0, 0xda, 0x3c, + 0x44, 0x69, 0x9e, 0xd7, 0xdb, 0x51, 0xb7, 0xd9}; + +static unsigned char aesCtrKey[] = {0x76, 0x91, 0xBE, 0x03, 0x5E, 0x50, 0x20, 0xA8, + 0xAC, 0x6E, 0x61, 0x85, 0x29, 0xF9, 0xA0, 0xDC}; + +static unsigned char mdKey1[] = {0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b}; + +static unsigned char mdKey2[] = {0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa}; + +static unsigned char shaKey1[] = {0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b}; + +static unsigned char shaKey2[] = {0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa}; + +static unsigned char mdKey4[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10}; + +static unsigned char shaKey4[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, + 0x11, 0x12, 0x13, 0x14}; + + +static MV_CESA_TEST_SESSION desTestSessions[] = +{ +/*000*/ {-1, MV_CESA_CRYPTO_DES, MV_CESA_CRYPTO_ECB, + MV_CESA_MAC_NULL, MV_CESA_CRYPTO_ONLY, + MV_CESA_DIR_ENCODE, + cryptoKey7, sizeof(cryptoKey7)/sizeof(cryptoKey7[0]), + NULL, 0, + "DES ECB encode", + }, +/*001*/ {-1, MV_CESA_CRYPTO_DES, MV_CESA_CRYPTO_ECB, + MV_CESA_MAC_NULL, MV_CESA_CRYPTO_ONLY, + MV_CESA_DIR_DECODE, + cryptoKey7, sizeof(cryptoKey7)/sizeof(cryptoKey7[0]), + NULL, 0, + "DES ECB decode", + }, +/*002*/ {-1, MV_CESA_CRYPTO_DES, MV_CESA_CRYPTO_CBC, + MV_CESA_MAC_NULL, MV_CESA_CRYPTO_ONLY, + MV_CESA_DIR_ENCODE, + cryptoKey7, sizeof(cryptoKey7)/sizeof(cryptoKey7[0]), + NULL, 0, + "DES CBC encode" + }, +/*003*/ {-1, MV_CESA_CRYPTO_DES, MV_CESA_CRYPTO_CBC, + MV_CESA_MAC_NULL, MV_CESA_CRYPTO_ONLY, + MV_CESA_DIR_DECODE, + cryptoKey7, sizeof(cryptoKey7)/sizeof(cryptoKey7[0]), + NULL, 0, + "DES CBC decode" + }, +/*004*/ {-1, MV_CESA_CRYPTO_NULL, MV_CESA_CRYPTO_ECB, + MV_CESA_MAC_NULL, MV_CESA_CRYPTO_ONLY, + MV_CESA_DIR_ENCODE, + NULL, 0, NULL, 0, + "NULL Crypto Algorithm encode" + }, +}; + + +static MV_CESA_TEST_SESSION tripleDesTestSessions[] = +{ +/*100*/ {-1, MV_CESA_CRYPTO_3DES, MV_CESA_CRYPTO_ECB, + MV_CESA_MAC_NULL, MV_CESA_CRYPTO_ONLY, + MV_CESA_DIR_ENCODE, + cryptoKey1, sizeof(cryptoKey1)/sizeof(cryptoKey1[0]), + NULL, 0, + "3DES ECB encode", + }, +/*101*/ {-1, MV_CESA_CRYPTO_3DES, MV_CESA_CRYPTO_ECB, + MV_CESA_MAC_NULL, MV_CESA_CRYPTO_ONLY, + MV_CESA_DIR_DECODE, + cryptoKey1, sizeof(cryptoKey1)/sizeof(cryptoKey1[0]), + NULL, 0, + "3DES ECB decode", + }, +/*102*/ {-1, MV_CESA_CRYPTO_3DES, MV_CESA_CRYPTO_CBC, + MV_CESA_MAC_NULL, MV_CESA_CRYPTO_ONLY, + MV_CESA_DIR_ENCODE, + cryptoKey1, sizeof(cryptoKey1)/sizeof(cryptoKey1[0]), + NULL, 0, + "3DES CBC encode" + }, +/*103*/ {-1, MV_CESA_CRYPTO_3DES, MV_CESA_CRYPTO_CBC, + MV_CESA_MAC_NULL, MV_CESA_CRYPTO_ONLY, + MV_CESA_DIR_DECODE, + cryptoKey1, sizeof(cryptoKey1)/sizeof(cryptoKey1[0]), + NULL, 0, + "3DES CBC decode" + }, +/*104*/ {-1, MV_CESA_CRYPTO_3DES, MV_CESA_CRYPTO_ECB, + MV_CESA_MAC_NULL, MV_CESA_CRYPTO_ONLY, + MV_CESA_DIR_ENCODE, + key3des1, sizeof(key3des1), + NULL, 0, + "3DES ECB encode" + }, +/*105*/ {-1, MV_CESA_CRYPTO_3DES, MV_CESA_CRYPTO_CBC, + MV_CESA_MAC_NULL, MV_CESA_CRYPTO_ONLY, + MV_CESA_DIR_ENCODE, + key3des2, sizeof(key3des2), + NULL, 0, + "3DES ECB encode" + }, +/*106*/ {-1, MV_CESA_CRYPTO_3DES, MV_CESA_CRYPTO_CBC, + MV_CESA_MAC_NULL, MV_CESA_CRYPTO_ONLY, + MV_CESA_DIR_ENCODE, + key3des3, sizeof(key3des3), + NULL, 0, + "3DES ECB encode" + }, +}; + + +static MV_CESA_TEST_SESSION aesTestSessions[] = +{ +/*200*/ {-1, MV_CESA_CRYPTO_AES, MV_CESA_CRYPTO_ECB, + MV_CESA_MAC_NULL, MV_CESA_CRYPTO_ONLY, + MV_CESA_DIR_ENCODE, + cryptoKey2, sizeof(cryptoKey2)/sizeof(cryptoKey2[0]), + NULL, 0, + "AES-128 ECB encode" + }, +/*201*/ {-1, MV_CESA_CRYPTO_AES, MV_CESA_CRYPTO_ECB, + MV_CESA_MAC_NULL, MV_CESA_CRYPTO_ONLY, + MV_CESA_DIR_DECODE, + cryptoKey2, sizeof(cryptoKey2)/sizeof(cryptoKey2[0]), + NULL, 0, + "AES-128 ECB decode" + }, +/*202*/ {-1, MV_CESA_CRYPTO_AES, MV_CESA_CRYPTO_CBC, + MV_CESA_MAC_NULL, MV_CESA_CRYPTO_ONLY, + MV_CESA_DIR_ENCODE, + cryptoKey5, sizeof(cryptoKey5)/sizeof(cryptoKey5[0]), + NULL, 0, + "AES-128 CBC encode" + }, +/*203*/ {-1, MV_CESA_CRYPTO_AES, MV_CESA_CRYPTO_CBC, + MV_CESA_MAC_NULL, MV_CESA_CRYPTO_ONLY, + MV_CESA_DIR_DECODE, + cryptoKey5, sizeof(cryptoKey5)/sizeof(cryptoKey5[0]), + NULL, 0, + "AES-128 CBC decode" + }, +/*204*/ {-1, MV_CESA_CRYPTO_AES, MV_CESA_CRYPTO_ECB, + MV_CESA_MAC_NULL, MV_CESA_CRYPTO_ONLY, + MV_CESA_DIR_ENCODE, + cryptoKey3, sizeof(cryptoKey3)/sizeof(cryptoKey3[0]), + NULL, 0, + "AES-192 ECB encode" + }, +/*205*/ {-1, MV_CESA_CRYPTO_AES, MV_CESA_CRYPTO_ECB, + MV_CESA_MAC_NULL, MV_CESA_CRYPTO_ONLY, + MV_CESA_DIR_DECODE, + cryptoKey3, sizeof(cryptoKey3)/sizeof(cryptoKey3[0]), + NULL, 0, + "AES-192 ECB decode" + }, +/*206*/ {-1, MV_CESA_CRYPTO_AES, MV_CESA_CRYPTO_ECB, + MV_CESA_MAC_NULL, MV_CESA_CRYPTO_ONLY, + MV_CESA_DIR_ENCODE, + cryptoKey4, sizeof(cryptoKey4)/sizeof(cryptoKey4[0]), + NULL, 0, + "AES-256 ECB encode" + }, +/*207*/ {-1, MV_CESA_CRYPTO_AES, MV_CESA_CRYPTO_ECB, + MV_CESA_MAC_NULL, MV_CESA_CRYPTO_ONLY, + MV_CESA_DIR_DECODE, + cryptoKey4, sizeof(cryptoKey4)/sizeof(cryptoKey4[0]), + NULL, 0, + "AES-256 ECB decode" + }, +/*208*/ {-1, MV_CESA_CRYPTO_AES, MV_CESA_CRYPTO_CTR, + MV_CESA_MAC_NULL, MV_CESA_CRYPTO_ONLY, + MV_CESA_DIR_ENCODE, + aesCtrKey, sizeof(aesCtrKey)/sizeof(aesCtrKey[0]), + NULL, 0, + "AES-128 CTR encode" + }, +}; + + +static MV_CESA_TEST_SESSION md5TestSessions[] = +{ +/*300*/ {-1, MV_CESA_CRYPTO_NULL, MV_CESA_CRYPTO_ECB, + MV_CESA_MAC_HMAC_MD5, MV_CESA_MAC_ONLY, + MV_CESA_DIR_ENCODE, + NULL, 0, + mdKey1, sizeof(mdKey1), + "HMAC-MD5 Generate Signature" + }, +/*301*/ {-1, MV_CESA_CRYPTO_NULL, MV_CESA_CRYPTO_ECB, + MV_CESA_MAC_HMAC_MD5, MV_CESA_MAC_ONLY, + MV_CESA_DIR_DECODE, + NULL, 0, + mdKey1, sizeof(mdKey1), + "HMAC-MD5 Verify Signature" + }, +/*302*/ {-1, MV_CESA_CRYPTO_NULL, MV_CESA_CRYPTO_ECB, + MV_CESA_MAC_HMAC_MD5, MV_CESA_MAC_ONLY, + MV_CESA_DIR_ENCODE, + NULL, 0, + mdKey2, sizeof(mdKey2), + "HMAC-MD5 Generate Signature" + }, +/*303*/ {-1, MV_CESA_CRYPTO_NULL, MV_CESA_CRYPTO_ECB, + MV_CESA_MAC_HMAC_MD5, MV_CESA_MAC_ONLY, + MV_CESA_DIR_DECODE, + NULL, 0, + mdKey2, sizeof(mdKey2), + "HMAC-MD5 Verify Signature" + }, +/*304*/ {-1, MV_CESA_CRYPTO_NULL, MV_CESA_CRYPTO_ECB, + MV_CESA_MAC_HMAC_MD5, MV_CESA_MAC_ONLY, + MV_CESA_DIR_ENCODE, + NULL, 0, + mdKey4, sizeof(mdKey4), + "HMAC-MD5 Generate Signature" + }, +/*305*/ {-1, MV_CESA_CRYPTO_NULL, MV_CESA_CRYPTO_ECB, + MV_CESA_MAC_MD5, MV_CESA_MAC_ONLY, + MV_CESA_DIR_ENCODE, + NULL, 0, + NULL, 0, + "HASH-MD5 Generate Signature" + }, +}; + + +static MV_CESA_TEST_SESSION shaTestSessions[] = +{ +/*400*/ {-1, MV_CESA_CRYPTO_NULL, MV_CESA_CRYPTO_ECB, + MV_CESA_MAC_HMAC_SHA1, MV_CESA_MAC_ONLY, + MV_CESA_DIR_ENCODE, + NULL, 0, + shaKey1, sizeof(shaKey1), + "HMAC-SHA1 Generate Signature" + }, +/*401*/ {-1, MV_CESA_CRYPTO_NULL, MV_CESA_CRYPTO_ECB, + MV_CESA_MAC_HMAC_SHA1, MV_CESA_MAC_ONLY, + MV_CESA_DIR_DECODE, + NULL, 0, + shaKey1, sizeof(shaKey1), + "HMAC-SHA1 Verify Signature" + }, +/*402*/ {-1, MV_CESA_CRYPTO_NULL, MV_CESA_CRYPTO_ECB, + MV_CESA_MAC_HMAC_SHA1, MV_CESA_MAC_ONLY, + MV_CESA_DIR_ENCODE, + NULL, 0, + shaKey2, sizeof(shaKey2), + "HMAC-SHA1 Generate Signature" + }, +/*403*/ {-1, MV_CESA_CRYPTO_NULL, MV_CESA_CRYPTO_ECB, + MV_CESA_MAC_HMAC_SHA1, MV_CESA_MAC_ONLY, + MV_CESA_DIR_DECODE, + NULL, 0, + shaKey2, sizeof(shaKey2), + "HMAC-SHA1 Verify Signature" + }, +/*404*/ {-1, MV_CESA_CRYPTO_NULL, MV_CESA_CRYPTO_ECB, + MV_CESA_MAC_HMAC_SHA1, MV_CESA_MAC_ONLY, + MV_CESA_DIR_ENCODE, + NULL, 0, + shaKey4, sizeof(shaKey4), + "HMAC-SHA1 Generate Signature" + }, +/*405*/ {-1, MV_CESA_CRYPTO_NULL, MV_CESA_CRYPTO_ECB, + MV_CESA_MAC_SHA1, MV_CESA_MAC_ONLY, + MV_CESA_DIR_ENCODE, + NULL, 0, + NULL, 0, + "HASH-SHA1 Generate Signature" + }, +}; + +static MV_CESA_TEST_SESSION combinedTestSessions[] = +{ +/*500*/ {-1, MV_CESA_CRYPTO_DES, MV_CESA_CRYPTO_ECB, + MV_CESA_MAC_HMAC_MD5, MV_CESA_CRYPTO_THEN_MAC, + MV_CESA_DIR_ENCODE, + cryptoKey1, MV_CESA_DES_KEY_LENGTH, + mdKey4, sizeof(mdKey4), + "DES + MD5 encode" + }, +/*501*/ {-1, MV_CESA_CRYPTO_DES, MV_CESA_CRYPTO_ECB, + MV_CESA_MAC_HMAC_SHA1, MV_CESA_CRYPTO_THEN_MAC, + MV_CESA_DIR_ENCODE, + cryptoKey1, MV_CESA_DES_KEY_LENGTH, + shaKey4, sizeof(shaKey4), + "DES + SHA1 encode" + }, +/*502*/ {-1, MV_CESA_CRYPTO_3DES, MV_CESA_CRYPTO_ECB, + MV_CESA_MAC_HMAC_MD5, MV_CESA_CRYPTO_THEN_MAC, + MV_CESA_DIR_ENCODE, + cryptoKey1, sizeof(cryptoKey1)/sizeof(cryptoKey1[0]), + mdKey4, sizeof(mdKey4), + "3DES + MD5 encode" + }, +/*503*/ {-1, MV_CESA_CRYPTO_3DES, MV_CESA_CRYPTO_ECB, + MV_CESA_MAC_HMAC_SHA1, MV_CESA_CRYPTO_THEN_MAC, + MV_CESA_DIR_ENCODE, + cryptoKey1, sizeof(cryptoKey1)/sizeof(cryptoKey1[0]), + shaKey4, sizeof(shaKey4), + "3DES + SHA1 encode" + }, +/*504*/ {-1, MV_CESA_CRYPTO_3DES, MV_CESA_CRYPTO_CBC, + MV_CESA_MAC_HMAC_MD5, MV_CESA_CRYPTO_THEN_MAC, + MV_CESA_DIR_ENCODE, + cryptoKey1, sizeof(cryptoKey1)/sizeof(cryptoKey1[0]), + mdKey4, sizeof(mdKey4), + "3DES CBC + MD5 encode" + }, +/*505*/ {-1, MV_CESA_CRYPTO_3DES, MV_CESA_CRYPTO_CBC, + MV_CESA_MAC_HMAC_SHA1, MV_CESA_CRYPTO_THEN_MAC, + MV_CESA_DIR_ENCODE, + cryptoKey1, sizeof(cryptoKey1)/sizeof(cryptoKey1[0]), + shaKey4, sizeof(shaKey4), + "3DES CBC + SHA1 encode" + }, +/*506*/ {-1, MV_CESA_CRYPTO_AES, MV_CESA_CRYPTO_CBC, + MV_CESA_MAC_HMAC_MD5, MV_CESA_CRYPTO_THEN_MAC, + MV_CESA_DIR_ENCODE, + cryptoKey5, sizeof(cryptoKey5)/sizeof(cryptoKey5[0]), + mdKey4, sizeof(mdKey4), + "AES-128 CBC + MD5 encode" + }, +/*507*/ {-1, MV_CESA_CRYPTO_AES, MV_CESA_CRYPTO_CBC, + MV_CESA_MAC_HMAC_SHA1, MV_CESA_CRYPTO_THEN_MAC, + MV_CESA_DIR_ENCODE, + cryptoKey5, sizeof(cryptoKey5)/sizeof(cryptoKey5[0]), + shaKey4, sizeof(shaKey4), + "AES-128 CBC + SHA1 encode" + }, +/*508*/ {-1, MV_CESA_CRYPTO_3DES, MV_CESA_CRYPTO_ECB, + MV_CESA_MAC_HMAC_MD5, MV_CESA_MAC_THEN_CRYPTO, + MV_CESA_DIR_DECODE, + cryptoKey1, sizeof(cryptoKey1)/sizeof(cryptoKey1[0]), + mdKey4, sizeof(mdKey4), + "HMAC-MD5 + 3DES decode" + }, +}; + + +static MV_CESA_TEST_DB_ENTRY cesaTestsDB[MAX_TEST_TYPE+1] = +{ + { desTestSessions, sizeof(desTestSessions)/sizeof(desTestSessions[0]) }, + { tripleDesTestSessions, sizeof(tripleDesTestSessions)/sizeof(tripleDesTestSessions[0]) }, + { aesTestSessions, sizeof(aesTestSessions)/sizeof(aesTestSessions[0]) }, + { md5TestSessions, sizeof(md5TestSessions)/sizeof(md5TestSessions[0]) }, + { shaTestSessions, sizeof(shaTestSessions)/sizeof(shaTestSessions[0]) }, + { combinedTestSessions, sizeof(combinedTestSessions)/sizeof(combinedTestSessions[0]) }, + { NULL, 0 } +}; + + +char cesaNullPlainHexText[] = "000000000000000000000000000000000000000000000000"; + +char cesaPlainAsciiText[] = "Now is the time for all "; +char cesaPlainHexEbc[] = "4e6f77206973207468652074696d6520666f7220616c6c20"; +char cesaCipherHexEcb[] = "3fa40e8a984d48156a271787ab8883f9893d51ec4b563b53"; +char cesaPlainHexCbc[] = "1234567890abcdef4e6f77206973207468652074696d6520666f7220616c6c20"; +char cesaCipherHexCbc[] = "1234567890abcdefe5c7cdde872bf27c43e934008c389c0f683788499a7c05f6"; + +char cesaAesPlainHexEcb[] = "000102030405060708090a0b0c0d0e0f"; +char cesaAes128cipherHexEcb[] = "0a940bb5416ef045f1c39458c653ea5a"; +char cesaAes192cipherHexEcb[] = "0060bffe46834bb8da5cf9a61ff220ae"; +char cesaAes256cipherHexEcb[] = "5a6e045708fb7196f02e553d02c3a692"; + +char cesaAsciiStr1[] = "Hi There"; +char cesaDataHexStr1[] = "4869205468657265"; +char cesaHmacMd5digestHex1[] = "9294727a3638bb1c13f48ef8158bfc9d"; +char cesaHmacSha1digestHex1[] = "b617318655057264e28bc0b6fb378c8ef146be00"; +char cesaDataAndMd5digest1[] = "48692054686572659294727a3638bb1c13f48ef8158bfc9d"; +char cesaDataAndSha1digest1[] = "4869205468657265b617318655057264e28bc0b6fb378c8ef146be00"; + +char cesaAesPlainText[] = "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf" + "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf" + "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf" + "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf"; + +char cesaAes128CipherCbc[] = "c30e32ffedc0774e6aff6af0869f71aa" + "0f3af07a9a31a9c684db207eb0ef8e4e" + "35907aa632c3ffdf868bb7b29d3d46ad" + "83ce9f9a102ee99d49a53e87f4c3da55"; + +char cesaAesIvPlainText[] = "8ce82eefbea0da3c44699ed7db51b7d9" + "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf" + "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf" + "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf" + "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf"; + +char cesaAes128IvCipherCbc[] = "8ce82eefbea0da3c44699ed7db51b7d9" + "c30e32ffedc0774e6aff6af0869f71aa" + "0f3af07a9a31a9c684db207eb0ef8e4e" + "35907aa632c3ffdf868bb7b29d3d46ad" + "83ce9f9a102ee99d49a53e87f4c3da55"; + +char cesaAesCtrPlain[] = "00E0017B27777F3F4A1786F000000001" + "000102030405060708090A0B0C0D0E0F" + "101112131415161718191A1B1C1D1E1F" + "20212223"; + +char cesaAesCtrCipher[] = "00E0017B27777F3F4A1786F000000001" + "C1CF48A89F2FFDD9CF4652E9EFDB72D7" + "4540A42BDE6D7836D59A5CEAAEF31053" + "25B2072F"; + + + +/* Input cesaHmacHex3 is '0xdd' repeated 50 times */ +char cesaHmacMd5digestHex3[] = "56be34521d144c88dbb8c733f0e8b3f6"; +char cesaHmacSha1digestHex3[] = "125d7342b9ac11cd91a39af48aa17b4f63f175d3"; +char cesaDataHexStr3[50*2+1] = ""; +char cesaDataAndMd5digest3[sizeof(cesaDataHexStr3)+sizeof(cesaHmacMd5digestHex3)+8*2+1] = ""; +char cesaDataAndSha1digest3[sizeof(cesaDataHexStr3)+sizeof(cesaHmacSha1digestHex3)+8*2+1] = ""; + +/* Ascii string is "abc" */ +char hashHexStr3[] = "616263"; +char hashMd5digest3[] = "900150983cd24fb0d6963f7d28e17f72"; +char hashSha1digest3[] = "a9993e364706816aba3e25717850c26c9cd0d89d"; + +char hashHexStr80[] = "31323334353637383930" + "31323334353637383930" + "31323334353637383930" + "31323334353637383930" + "31323334353637383930" + "31323334353637383930" + "31323334353637383930" + "31323334353637383930"; + +char hashMd5digest80[] = "57edf4a22be3c955ac49da2e2107b67a"; + +char tripleDesThenMd5digest80[] = "b7726a03aad490bd6c5a452a89a1b271"; +char tripleDesThenSha1digest80[] = "b2ddeaca91030eab5b95a234ef2c0f6e738ff883"; + +char cbc3desThenMd5digest80[] = "6f463057e1a90e0e91ae505b527bcec0"; +char cbc3desThenSha1digest80[] = "1b002ed050be743aa98860cf35659646bb8efcc0"; + +char cbcAes128ThenMd5digest80[] = "6b6e863ac5a71d15e3e9b1c86c9ba05f"; +char cbcAes128ThenSha1digest80[] = "13558472d1fc1c90dffec6e5136c7203452d509b"; + + +static MV_CESA_TEST_CASE cesaTestCases[] = +{ + /* plainHexStr cipherHexStr IV crypto mac digest */ + /* Length Length Offset */ + /*0*/ { NULL, NULL, NULL, 0, 0, -1 }, + /*1*/ { cesaPlainHexEbc, cesaCipherHexEcb, NULL, 24, 0, -1 }, + /*2*/ { cesaPlainHexCbc, cesaCipherHexCbc, NULL, 24, 0, -1 }, + /*3*/ { cesaAesPlainHexEcb, cesaAes128cipherHexEcb, NULL, 16, 0, -1 }, + /*4*/ { cesaAesPlainHexEcb, cesaAes192cipherHexEcb, NULL, 16, 0, -1 }, + /*5*/ { cesaAesPlainHexEcb, cesaAes256cipherHexEcb, NULL, 16, 0, -1 }, + /*6*/ { cesaDataHexStr1, cesaHmacMd5digestHex1, NULL, 0, 8, -1 }, + /*7*/ { NULL, cesaDataAndMd5digest1, NULL, 0, 8, -1 }, + /*8*/ { cesaDataHexStr3, cesaHmacMd5digestHex3, NULL, 0, 50, -1 }, + /*9*/ { NULL, cesaDataAndMd5digest3, NULL, 0, 50, -1 }, +/*10*/ { cesaAesPlainText, cesaAes128IvCipherCbc, iv5, 64, 0, -1 }, +/*11*/ { cesaDataHexStr1, cesaHmacSha1digestHex1, NULL, 0, 8, -1 }, +/*12*/ { NULL, cesaDataAndSha1digest1, NULL, 0, 8, -1 }, +/*13*/ { cesaDataHexStr3, cesaHmacSha1digestHex3, NULL, 0, 50, -1 }, +/*14*/ { NULL, cesaDataAndSha1digest3, NULL, 0, 50, -1 }, +/*15*/ { hashHexStr3, hashMd5digest3, NULL, 0, 3, -1 }, +/*16*/ { hashHexStr3, hashSha1digest3, NULL, 0, 3, -1 }, +/*17*/ { hashHexStr80, tripleDesThenMd5digest80, NULL, 80, 80, -1 }, +/*18*/ { hashHexStr80, tripleDesThenSha1digest80, NULL, 80, 80, -1 }, +/*19*/ { hashHexStr80, cbc3desThenMd5digest80, iv1, 80, 80, -1 }, +/*20*/ { hashHexStr80, cbc3desThenSha1digest80, iv1, 80, 80, -1 }, +/*21*/ { hashHexStr80, cbcAes128ThenMd5digest80, iv5, 80, 80, -1 }, +/*22*/ { hashHexStr80, cbcAes128ThenSha1digest80, iv5, 80, 80, -1 }, +/*23*/ { cesaAesCtrPlain, cesaAesCtrCipher, NULL, 36, 0, -1 }, +/*24*/ { cesaAesIvPlainText, cesaAes128IvCipherCbc, NULL, 64, 0, -1 }, +/*25*/ { plain3des1, cipher3des1, NULL, 0, 0, -1 }, +/*26*/ { plain3des2, cipher3desCbc2, iv3des2,0, 0, -1 }, +/*27*/ { plain3des3, cipher3desCbc3, iv3des3,0, 0, -1 }, +}; + + +/* Key = 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + * 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa + * Input 0xdd repeated "size" times + */ +static MV_CESA_SIZE_TEST mdMultiSizeTest302[] = +{ + { 80, "7a031a640c14a4872814930b1ef3a5b2" }, + { 512, "5488e6c5a14dc72a79f28312ca5b939b" }, + { 1000, "d00814f586a8b78a05724239d2531821" }, + { 1001, "bf07df7b7f49d3f5b5ecacd4e9e63281" }, + { 1002, "1ed4a1a802e87817a819d4e37bb4d0f7" }, + { 1003, "5972ab64a4f265ee371dac2f2f137f90" }, + { 1004, "71f95e7ec3aa7df2548e90898abdb28e" }, + { 1005, "e082790b4857fcfc266e92e59e608814" }, + { 1006, "9500f02fd8ac7fde8b10e4fece9a920d" }, + { 1336, "e42edcce57d0b75b01aa09d71427948b" }, + { 1344, "bb5454ada0deb49ba0a97ffd60f57071" }, + { 1399, "0f44d793e744b24d53f44f295082ee8c" }, + { 1400, "359de8a03a9b707928c6c60e0e8d79f1" }, + { 1401, "e913858b484cbe2b384099ea88d8855b" }, + { 1402, "d9848a164af53620e0540c1d7d87629e" }, + { 1403, "0c9ee1c2c9ef45e9b625c26cbaf3e822" }, + { 1404, "12edd4f609416e3c936170360561b064" }, + { 1405, "7fc912718a05446395345009132bf562" }, + { 1406, "882f17425e579ff0d85a91a59f308aa0" }, + { 1407, "005cae408630a2fb5db82ad9db7e59da" }, + { 1408, "64655f8b404b3fea7a3e3e609bc5088f" }, + { 1409, "4a145284a7f74e01b6bb1a0ec6a0dd80" }, + { 2048, "67caf64475650732def374ebb8bde3fd" }, + { 2049, "6c84f11f472825f7e6cd125c2981884b" }, + { 2050, "8999586754a73a99efbe4dbad2816d41" }, + { 2051, "ba6946b610e098d286bc81091659dfff" }, + { 2052, "d0afa01c92d4d13def2b024f36faed83" }, + { 3072, "61d8beac61806afa2585d74a9a0e6974" }, + { 3074, "f6501a28dcc24d1e4770505c51a87ed3" }, + { 3075, "ea4a6929be67e33e61ff475369248b73" }, + { 4048, "aa8c4d68f282a07e7385acdfa69f4bed" }, + { 4052, "afb5ed2c0e1d430ea59e59ed5ed6b18a" }, + { 4058, "9e8553f9bdd43aebe0bd729f0e600c99" }, + { 6144, "f628f3e5d183fe5cdd3a5abee39cf872" }, + { 6150, "89a3efcea9a2f25f919168ad4a1fd292" }, + { 6400, "cdd176b7fb747873efa4da5e32bdf88f" }, + { 6528, "b1d707b027354aca152c45ee559ccd3f" }, + { 8192, "c600ea4429ac47f9941f09182166e51a" }, + {16384, "16e8754bfbeb4c649218422792267a37" }, + {18432, "0fd0607521b0aa8b52219cfbe215f63e" }, + { 0, NULL }, +}; + +/* Key = 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + * 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10 + * InputHexStr = "31323334353637383930" (ASCII = "1234567890") + */ +static MV_CESA_SIZE_TEST mdMultiSizeTest304[] = +{ + { 80, "a456c4723fee6068530af5a2afa71627" }, + { 512, "f85c2a2344f5de68b432208ad13e5794" }, + { 1000, "35464d6821fd4a293a41eb84e274c8c5" }, + { 1001, "c08eedbdce60cceb54bc2d732bb32c8b" }, + { 1002, "5664f71800c011cc311cb6943339c1b8" }, + { 1003, "779c723b044c585dc7802b13e8501bdc" }, + { 1004, "55e500766a2c307bc5c5fdd15e4cacd4" }, + { 1005, "d5f978954f5c38529d1679d2b714f068" }, + { 1006, "cd3efc827ce628b7281b72172693abf9" }, + { 1336, "6f04479910785878ae6335b8d1e87edf" }, + { 1344, "b6d27b50c2bce1ba2a8e1b5cc4324368" }, + { 1399, "65f70a1d4c86e5eaeb0704c8a7816795" }, + { 1400, "3394b5adc4cb3ff98843ca260a44a88a" }, + { 1401, "3a06f3582033a66a4e57e0603ce94e74" }, + { 1402, "e4d97f5ed51edc48abfa46eeb5c31752" }, + { 1403, "3d05e40b080ee3bedf293cb87b7140e7" }, + { 1404, "8cf294fc3cd153ab18dccb2a52cbf244" }, + { 1405, "d1487bd42f6edd9b4dab316631159221" }, + { 1406, "0527123b6bf6936cf5d369dc18c6c70f" }, + { 1407, "3224a06639db70212a0cd1ae1fcc570a" }, + { 1408, "a9e13335612c0356f5e2c27086e86c43" }, + { 1409, "a86d1f37d1ed8a3552e9a4f04dceea98" }, + { 2048, "396905c9b961cd0f6152abfb69c4449c" }, + { 2049, "49f39bff85d9dcf059fadb89efc4a70f" }, + { 2050, "3a2b4823bc4d0415656550226a63e34a" }, + { 2051, "dec60580d406c782540f398ad0bcc7e0" }, + { 2052, "32f76610a14310309eb748fe025081bf" }, + { 3072, "45edc1a42bf9d708a621076b63b774da" }, + { 3074, "9be1b333fe7c0c9f835fb369dc45f778" }, + { 3075, "8c06fcac7bd0e7b7a17fd6508c09a549" }, + { 4048, "0ddaef848184bf0ad98507a10f1e90e4" }, + { 4052, "81976bcaeb274223983996c137875cb8" }, + { 4058, "0b0a7a1c82bc7cbc64d8b7cd2dc2bb22" }, + { 6144, "1c24056f52725ede2dff0d7f9fc9855f" }, + { 6150, "b7f4b65681c4e43ee68ca466ca9ca4ec" }, + { 6400, "443bbaab9f7331ddd4bf11b659cd43c8" }, + { 6528, "216f44f23047cfee03a7a64f88f9a995" }, + { 8192, "ac7a993b2cad54879dba1bde63e39097" }, + { 8320, "55ed7be9682d6c0025b3221a62088d08" }, + {16384, "c6c722087653b62007aea668277175e5" }, + {18432, "f1faca8e907872c809e14ffbd85792d6" }, + { 0, NULL }, +}; + +/* HASH-MD5 + * InputHexStr = "31323334353637383930" (ASCII = "1234567890") + * repeated "size" times + */ +static MV_CESA_SIZE_TEST mdMultiSizeTest305[] = +{ + { 80, "57edf4a22be3c955ac49da2e2107b67a" }, + { 512, "c729ae8f0736cc377a9767a660eaa04e" }, + { 1000, "f1257a8659eb92d36fe14c6bf3852a6a" }, + { 1001, "f8a46fe8ea04fdc8c7de0e84042d3878" }, + { 1002, "da188dd67bff87d58aa3c02af2d0cc0f" }, + { 1003, "961753017feee04c9b93a8e51658a829" }, + { 1004, "dd68c4338608dcc87807a711636bf2af" }, + { 1005, "e338d567d3ce66bf69ada29658a8759b" }, + { 1006, "443c9811e8b92599b0b149e8d7ec700a" }, + { 1336, "89a98511706008ba4cbd0b4a24fa5646" }, + { 1344, "335a919805f370b9e402a62c6fe01739" }, + { 1399, "5d18d0eddcd84212fe28d812b5e80e3b" }, + { 1400, "6b695c240d2dffd0dffc99459ca76db6" }, + { 1401, "49590f61298a76719bc93a57a30136f5" }, + { 1402, "94c2999fa3ef1910a683d69b2b8476f2" }, + { 1403, "37073a02ab00ecba2645c57c228860db" }, + { 1404, "1bcd06994fce28b624f0c5fdc2dcdd2b" }, + { 1405, "11b93671a64c95079e8cf9e7cddc8b3d" }, + { 1406, "4b6695772a4c66313fa4871017d05f36" }, + { 1407, "d1539b97fbfda1c075624e958de19c5b" }, + { 1408, "b801b9b69920907cd018e8063092ede9" }, + { 1409, "b765f1406cfe78e238273ed01bbcaf7e" }, + { 2048, "1d7e2c64ac29e2b3fb4c272844ed31f5" }, + { 2049, "71d38fac49c6b1f4478d8d88447bcdd0" }, + { 2050, "141c34a5592b1bebfa731e0b23d0cdba" }, + { 2051, "c5e1853f21c59f5d6039bd13d4b380d8" }, + { 2052, "dd44a0d128b63d4b5cccd967906472d7" }, + { 3072, "37d158e33b21390822739d13db7b87fe" }, + { 3074, "aef3b209d01d39d0597fe03634bbf441" }, + { 3075, "335ffb428eabf210bada96d74d5a4012" }, + { 4048, "2434c2b43d798d2819487a886261fc64" }, + { 4052, "ac2fa84a8a33065b2e92e36432e861f8" }, + { 4058, "856781f85616c341c3533d090c1e1e84" }, + { 6144, "e5d134c652c18bf19833e115f7a82e9b" }, + { 6150, "a09a353be7795fac2401dac5601872e6" }, + { 6400, "08b9033ac6a1821398f50af75a2dbc83" }, + { 6528, "3d47aa193a8540c091e7e02f779e6751" }, + { 8192, "d3164e710c0626f6f395b38f20141cb7" }, + { 8320, "b727589d9183ff4e8491dd24466974a3" }, + {16384, "3f54d970793d2274d5b20d10a69938ac" }, + {18432, "f558511dcf81985b7a1bb57fad970531" }, + { 0, NULL }, +}; + + +/* Key = 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + * 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa + * 0xaa, 0xaa, 0xaa, 0xaa + * InputHexStr = "31323334353637383930" (ASCII = "1234567890") + */ +static MV_CESA_SIZE_TEST shaMultiSizeTest402[] = +{ + { 80, "e812f370e659705a1649940d1f78cd7af18affd3" }, + { 512, "e547f886b2c15d995ed76a8a924cb408c8080f66" }, + { 1000, "239443194409f1a5342ecde1a092c8f3a3ed790a" }, + { 1001, "f278ab9a102850a9f48dc4e9e6822afe2d0c52b5" }, + { 1002, "8bcc667df5ab6ece988b3af361d09747c77f4e72" }, + { 1003, "0fae6046c7dc1d3e356b25af836f6077a363f338" }, + { 1004, "0ea48401cc92ae6bc92ae76685269cb0167fbe1a" }, + { 1005, "ecbcd7c879b295bafcd8766cbeac58cc371e31d1" }, + { 1006, "eb4a4a3d07d1e9a15e6f1ab8a9c47f243e27324c" }, + { 1336, "f5950ee1d77c10e9011d2149699c9366fe52529c" }, + { 1344, "b04263604a63c351b0b3b9cf1785b4bdba6c8838" }, + { 1399, "8cb1cff61d5b784045974a2fc69386e3b8d24218" }, + { 1400, "9bb2f3fcbeddb2b90f0be797cd647334a2816d51" }, + { 1401, "23ae462a7a0cb440f7445791079a5d75a535dd33" }, + { 1402, "832974b524a4d3f9cc2f45a3cabf5ccef65cd2aa" }, + { 1403, "d1c683742fe404c3c20d5704a5430e7832a7ec95" }, + { 1404, "867c79042e64f310628e219d8b85594cd0c7adc3" }, + { 1405, "c9d81d49d13d94358f56ccfd61af02b36c69f7c3" }, + { 1406, "0df43daab2786172f9b8d07d61f14a070cf1287a" }, + { 1407, "0fd8f3ad7f169534b274d4c66bbddd89f759e391" }, + { 1408, "3987511182b18473a564436003139b808fa46343" }, + { 1409, "ef667e063c9e9f539a8987a8d0bd3066ee85d901" }, + { 2048, "921109c99f3fedaca21727156d5f2b4460175327" }, + { 2049, "47188600dd165eb45f27c27196d3c46f4f042c1b" }, + { 2050, "8831939904009338de10e7fa670847041387807d" }, + { 2051, "2f8ebb5db2997d614e767be1050366f3641e7520" }, + { 2052, "669e51cd730dae158d3bef8adba075bd95a0d011" }, + { 3072, "cfee66cfd83abc8451af3c96c6b35a41cc6c55f5" }, + { 3074, "216ea26f02976a261b7d21a4dd3085157bedfabd" }, + { 3075, "bd612ebba021fd8e012b14c3bd60c8c5161fabc0" }, + { 4048, "c2564c1fdf2d5e9d7dde7aace2643428e90662e8" }, + { 4052, "91ce61fe924b445dfe7b5a1dcd10a27caec16df6" }, + { 4058, "db2a9be5ee8124f091c7ebd699266c5de223c164" }, + { 6144, "855109903feae2ba3a7a05a326b8a171116eb368" }, + { 6150, "37520bb3a668294d9c7b073e7e3daf8fee248a78" }, + { 6400, "60a353c841b6d2b1a05890349dad2fa33c7536b7" }, + { 6528, "9e53a43a69bb42d7c8522ca8bd632e421d5edb36" }, + { 8192, "a918cb0da862eaea0a33ee0efea50243e6b4927c" }, + { 8320, "29a5dcf55d1db29cd113fcf0572ae414f1c71329" }, + {16384, "6fb27966138e0c8d5a0d65ace817ebd53633cee1" }, + {18432, "ca09900d891c7c9ae2a559b10f63a217003341c1" }, + { 0, NULL }, +}; + +/* Key = 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + * 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10 + * 0x11, 0x12, 0x13, 0x14 + * InputHexStr = "31323334353637383930" (ASCII = "1234567890") + */ +static MV_CESA_SIZE_TEST shaMultiSizeTest404[] = +{ + { 80, "beaf20a34b06a87558d156c0949bc3957d40222e" }, + { 512, "3353955358d886bc2940a3c7f337ff7dafb59c7b" }, + { 1000, "8737a542c5e9b2b6244b757ebb69d5bd602a829f" }, + { 1001, "fd9e7582d8a5d3c9fe3b923e4e6a41b07a1eb4d4" }, + { 1002, "a146d14a6fc3c274ff600568f4d75b977989e00d" }, + { 1003, "be22601bbc027ddef2dec97d30b3dc424fd803c5" }, + { 1004, "3e71fe99b2fe2b7bfdf4dbf0c7f3da25d7ea35e7" }, + { 1005, "2c422735d7295408fddd76f5e8a83a2a8da13df3" }, + { 1006, "6d875319049314b61855101a647b9ba3313428e6" }, + { 1336, "c1631ea80bad9dc43a180712461b65a0598c711c" }, + { 1344, "816069bf91d34581005746e2e0283d0f9c7b7605" }, + { 1399, "4e139866dc61cfcb8b67ca2ebd637b3a538593af" }, + { 1400, "ff2a0f8dd2b02c5417910f6f55d33a78e081a723" }, + { 1401, "ab00c12be62336964cbce31ae97fe2a0002984d5" }, + { 1402, "61349e7f999f3a1acc56c3e9a5060a9c4a7b05b6" }, + { 1403, "3edbc0f61e435bc1317fa27d840076093fb79353" }, + { 1404, "d052c6dfdbe63d45dab23ef9893e2aa4636aca1e" }, + { 1405, "0cc16b7388d67bf0add15a31e6e6c753cfae4987" }, + { 1406, "c96ba7eaad74253c38c22101b558d2850b1d1b90" }, + { 1407, "3445428a40d2c6556e7c55797ad8d323b61a48d9" }, + { 1408, "8d6444f937a09317c89834187b8ea9b8d3a8c56b" }, + { 1409, "c700acd3ecd19014ea2bdb4d42510c467e088475" }, + { 2048, "ee27d2a0cb77470c2f496212dfd68b5bb7b04e4b" }, + { 2049, "683762d7a02983b26a6d046e6451d9cd82c25932" }, + { 2050, "0fd20f1d55a9ee18363c2a6fd54aa13aee69992f" }, + { 2051, "86c267d8cc4bc8d59090e4f8b303da960fd228b7" }, + { 2052, "452395ae05b3ec503eea34f86fc0832485ad97c1" }, + { 3072, "75198e3cfd0b9bcff2dabdf8e38e6fdaa33ca49a" }, + { 3074, "4e24785ef080141ce4aab4675986d9acea624d7c" }, + { 3075, "3a20c5978dd637ec0e809bf84f0d9ccf30bc65bf" }, + { 4048, "3c32da256be7a7554922bf5fed51b0d2d09e59ad" }, + { 4052, "fff898426ea16e54325ae391a32c6c9bce4c23c0" }, + { 4058, "c800b9e562e1c91e1310116341a3c91d37f848ec" }, + { 6144, "d91d509d0cc4376c2d05bf9a5097717a373530e6" }, + { 6150, "d957030e0f13c5df07d9eec298542d8f94a07f12" }, + { 6400, "bb745313c3d7dc17b3f955e5534ad500a1082613" }, + { 6528, "77905f80d9ca82080bbb3e5654896dabfcfd1bdb" }, + { 8192, "5237fd9a81830c974396f99f32047586612ff3c0" }, + { 8320, "57668e28d5f2dba0839518a11db0f6af3d7e08bf" }, + {16384, "62e093fde467f0748087beea32e9af97d5c61241" }, + {18432, "845fb33130c7d6ea554fd5aacb9c50cf7ccb5929" }, + { 0, NULL }, +}; + +/* HASH-SHA1 + * InputHexStr = "31323334353637383930" (ASCII = "1234567890") + * repeated "size" times + */ +static MV_CESA_SIZE_TEST shaMultiSizeTest405[] = +{ + { 80, "50abf5706a150990a08b2c5ea40fa0e585554732" }, + { 512, "f14516a08948fa27917a974d219741a697ba0087" }, + { 1000, "0bd18c378d5788817eb4f1e5dc07d867efa5cbf4" }, + { 1001, "ca29b85c35db1b8aef83c977893a11159d1b7aa2" }, + { 1002, "d83bc973eaaedb8a31437994dabbb3304b0be086" }, + { 1003, "2cf7bbef0acd6c00536b5c58ca470df9a3a90b6c" }, + { 1004, "e4375d09b1223385a8a393066f8209acfd936a80" }, + { 1005, "1029b38043e027745d019ce1d2d68e3d8b9d8f99" }, + { 1006, "deea16dcebbd8ac137e2b984deb639b9fb5e9680" }, + { 1336, "ea031b065fff63dcfb6a41956e4777520cdbc55d" }, + { 1344, "b52096c6445e6c0a8355995c70dc36ae186c863c" }, + { 1399, "cde2f6f8379870db4b32cf17471dc828a8dbff2b" }, + { 1400, "e53ff664064bc09fe5054c650806bd42d8179518" }, + { 1401, "d1156db5ddafcace64cdb510ff0d4af9b9a8ad64" }, + { 1402, "34ede0e9a909dd84a2ae291539105c0507b958e1" }, + { 1403, "a772ca3536da77e6ad3251e4f9e1234a4d7b87c0" }, + { 1404, "29740fd2b04e7a8bfd32242db6233156ad699948" }, + { 1405, "65b17397495b70ce4865dad93bf991b74c97cce1" }, + { 1406, "a7ee89cd0754061fdb91af7ea6abad2c69d542e3" }, + { 1407, "3eebf82f7420188e23d328b7ce93580b279a5715" }, + { 1408, "e08d3363a8b9a490dfb3a4c453452b8f114deeec" }, + { 1409, "95d74df739181a4ff30b8c39e28793a36598e924" }, + { 2048, "aa40262509c2abf84aab0197f83187fc90056d91" }, + { 2049, "7dec28ef105bc313bade8d9a7cdeac58b99de5ea" }, + { 2050, "d2e30f77ec81197de20f56588a156094ecb88450" }, + { 2051, "6b22ccc874833e96551a39da0c0edcaa0d969d92" }, + { 2052, "f843141e57875cd669af58744bc60aa9ea59549c" }, + { 3072, "09c5fedeaa62c132e673cc3c608a00142273d086" }, + { 3074, "b09e95eea9c7b1b007a58accec488301901a7f3d" }, + { 3075, "e6226b77b4ada287a8c9bbcf4ed71eec5ce632dc" }, + { 4048, "e99394894f855821951ddddf5bfc628547435f5c" }, + { 4052, "32d2f1af38be9cfba6cd03d55a254d0b3e1eb382" }, + { 4058, "d906552a4f2aca3a22e1fecccbcd183d7289d0ef" }, + { 6144, "2e7f62d35a860988e1224dc0543204af19316041" }, + { 6150, "d6b89698ee133df46fec9d552fadc328aa5a1b51" }, + { 6400, "dff50e90c46853988fa3a4b4ce5dda6945aae976" }, + { 6528, "9e63ec0430b96db02d38bc78357a2f63de2ab7f8" }, + { 8192, "971eb71ed60394d5ab5abb12e88420bdd41b5992" }, + { 8320, "91606a31b46afeaac965cecf87297e791b211013" }, + {16384, "547f830a5ec1f5f170ce818f156b1002cabc7569" }, + {18432, "f16f272787f3b8d539652e4dc315af6ab4fda0ef" }, + { 0, NULL }, +}; + +/* CryptoKey = 0x01234567, 0x89abcdef, + * 0x01234567, 0x89abcdef, + * 0x01234567, 0x89abcdef; + * MacKey = 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + * 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10 + * InputHexStr = "31323334353637383930" (ASCII = "1234567890") + * Note: only sizes aligned to 3DES block size (8 bytes) allowed + */ +static MV_CESA_SIZE_TEST tripleDesMdMultiSizeTest502[] = +{ + { 64, "9586962a2aaaef28803dec2e17807a7f" }, + { 80, "b7726a03aad490bd6c5a452a89a1b271" }, + { 352, "f1ed9563aecc3c0d2766eb2bed3b4e4c" }, + { 512, "0f9decb11ab40fe86f4d4d9397bc020e" }, + { 1000, "3ba69deac12cab8ff9dff7dbd9669927" }, + { 1336, "6cf47bf1e80e03e2c1d0945bc50d37d2" }, + { 1344, "4be388dab21ceb3fa1b8d302e9b821f7" }, + { 1400, "a58b79fb21dd9bfc6ec93e3b99fb0ef1" }, + { 1408, "8bc97379fc2ac3237effcdd4f7a86528" }, + { 2048, "1339f03ab3076f25a20bc4cba16eb5bf" }, + { 3072, "731204d2d90c4b36ae41f5e1fb874288" }, + { 4048, "c028d998cfda5642547b7e1ed5ea16e4" }, + { 6144, "b1b19cd910cc51bd22992f1e59f1e068" }, + { 6400, "44e4613496ba622deb0e7cb768135a2f" }, + { 6528, "3b06b0a86f8db9cd67f9448dfcf10549" }, + { 8192, "d581780b7163138a0f412be681457d82" }, + {16384, "03b8ac05527faaf1bed03df149c65ccf" }, + {18432, "677c8a86a41dab6c5d81b85b8fb10ff6" }, + { 0, NULL }, +}; + + +/* CryptoKey = 0x01234567, 0x89abcdef, + * 0x01234567, 0x89abcdef, + * 0x01234567, 0x89abcdef; + * MacKey = 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + * 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10 + * 0x11, 0x12, 0x13, 0x14 + * InputHexStr = "31323334353637383930" (ASCII = "1234567890") + * Note: only sizes aligned to 3DES block size (8 bytes) allowed + */ +static MV_CESA_SIZE_TEST tripleDesShaMultiSizeTest503[] = +{ + { 64, "44a1e9bcbfc1429630d9ea68b7a48b0427a684f2" }, + { 80, "b2ddeaca91030eab5b95a234ef2c0f6e738ff883" }, + { 352, "4b91864c7ff629bdff75d9726421f76705452aaf" }, + { 512, "6dd37faceeb2aa98ba74f4242ed6734a4d546af5" }, + { 1000, "463661c30300be512a9df40904f0757cde5f1141" }, + { 1336, "b931f831d9034fe59c65176400b039fe9c1f44a5" }, + { 1344, "af8866b1cd4a4887d6185bfe72470ffdfb3648e1" }, + { 1400, "49c6caf07296d5e31d2504d088bc5b20c3ee7cdb" }, + { 1408, "fcae8deedbc6ebf0763575dc7e9de075b448a0f4" }, + { 2048, "edece5012146c1faa0dd10f50b183ba5d2af58ac" }, + { 3072, "5b83625adb43a488b8d64fecf39bb766818547b7" }, + { 4048, "d2c533678d26c970293af60f14c8279dc708bfc9" }, + { 6144, "b8f67af4f991b08b725f969b049ebf813bfacc5c" }, + { 6400, "d9a6c7f746ac7a60ef2edbed2841cf851c25cfb0" }, + { 6528, "376792b8c8d18161d15579fb7829e6e3a27e9946" }, + { 8192, "d890eabdca195b34ef8724b28360cffa92ae5655" }, + {16384, "a167ee52639ec7bf19aee9c6e8f76667c14134b9" }, + {18432, "e4396ab56f67296b220985a12078f4a0e365d2cc" }, + { 0, NULL }, +}; + +/* CryptoKey = 0x01234567, 0x89abcdef, + * 0x01234567, 0x89abcdef, + * 0x01234567, 0x89abcdef + * IV = 0x12345678, 0x90abcdef + * MacKey = 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + * 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10 + * InputHexStr = "31323334353637383930" (ASCII = "1234567890") + * Note: only sizes aligned to 3DES block size (8 bytes) allowed + */ +static MV_CESA_SIZE_TEST cbc3desMdMultiSizeTest504[] = +{ + { 64, "8d10e00802460ede0058c139ba48bd2d" }, + { 80, "6f463057e1a90e0e91ae505b527bcec0" }, + { 352, "4938d48bdf86aece2c6851e7c6079788" }, + { 512, "516705d59f3cf810ebf2a13a23a7d42e" }, + { 1000, "a5a000ee5c830e67ddc6a2d2e5644b31" }, + { 1336, "44af60087b74ed07950088efbe3b126a" }, + { 1344, "1f5b39e0577920af731dabbfcf6dfc2a" }, + { 1400, "6804ea640e29b9cd39e08bc37dbce734" }, + { 1408, "4fb436624b02516fc9d1535466574bf9" }, + { 2048, "c909b0985c423d8d86719f701e9e83db" }, + { 3072, "cfe0bc34ef97213ee3d3f8b10122db21" }, + { 4048, "03ea10b5ae4ddeb20aed6af373082ed1" }, + { 6144, "b9a0ff4f87fc14b3c2dc6f0ed0998fdf" }, + { 6400, "6995f85d9d4985dd99e974ec7dda9dd6" }, + { 6528, "bbbb548ce2fa3d58467f6a6a5168a0e6" }, + { 8192, "afe101fbe745bb449ae4f50d10801456" }, + {16384, "9741706d0b1c923340c4660ff97cacdf" }, + {18432, "b0217becb73cb8f61fd79c7ce9d023fb" }, + { 0, NULL }, +}; + + +/* CryptoKey = 0x01234567, 0x89abcdef, + * 0x01234567, 0x89abcdef, + * 0x01234567, 0x89abcdef; + * IV = 0x12345678, 0x90abcdef + * MacKey = 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + * 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10 + * 0x11, 0x12, 0x13, 0x14 + * InputHexStr = "31323334353637383930" (ASCII = "1234567890") + * Note: only sizes aligned to 3DES block size (8 bytes) allowed + */ +static MV_CESA_SIZE_TEST cbc3desShaMultiSizeTest505[] = +{ + { 64, "409187e5bdb0be4a7754ca3747f7433dc4f01b98" }, + { 80, "1b002ed050be743aa98860cf35659646bb8efcc0" }, + { 352, "6cbf7ebe50fa4fa6eecc19eca23f9eae553ccfff" }, + { 512, "cfb5253fb4bf72b743320c30c7e48c54965853b0" }, + { 1000, "95e04e1ca2937e7c5a9aba9e42d2bcdb8a7af21f" }, + { 1336, "3b5c1f5eee5837ebf67b83ae01405542d77a6627" }, + { 1344, "2b3d42ab25615437f98a1ee310b81d07a02badc2" }, + { 1400, "7f8687df7c1af44e4baf3c934b6cca5ab6bc993e" }, + { 1408, "473a581c5f04f7527d50793c845471ac87e86430" }, + { 2048, "e41d20cae7ebe34e6e828ed62b1e5734019037bb" }, + { 3072, "275664afd7a561d804e6b0d204e53939cde653ae" }, + { 4048, "0d220cc5b34aeeb46bbbd637dde6290b5a8285a3" }, + { 6144, "cb393ddcc8b1c206060625b7d822ef9839e67bc5" }, + { 6400, "dd3317e2a627fc04800f74a4b05bfda00fab0347" }, + { 6528, "8a74c3b2441ab3f5a7e08895cc432566219a7c41" }, + { 8192, "b8e6ef3a549ed0e005bd5b8b1a5fe6689e9711a7" }, + {16384, "55f59404008276cdac0e2ba0d193af2d40eac5ce" }, + {18432, "86ae6c4fc72369a54cce39938e2d0296cd9c6ec5" }, + { 0, NULL }, +}; + + +/* CryptoKey = 0x01234567, 0x89abcdef, + * 0x01234567, 0x89abcdef, + * 0x01234567, 0x89abcdef + * IV = 0x12345678, 0x90abcdef + * MacKey = 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + * 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10 + * InputHexStr = "31323334353637383930" (ASCII = "1234567890") + * Note: only sizes aligned to AES block size (16 bytes) allowed + */ +static MV_CESA_SIZE_TEST cbcAes128md5multiSizeTest506[] = +{ + { 16, "7ca4c2ba866751598720c5c4aa0d6786" }, + { 64, "7dba7fb988e80da609b1fea7254bced8" }, + { 80, "6b6e863ac5a71d15e3e9b1c86c9ba05f" }, + { 352, "a1ceb9c2e3021002400d525187a9f38c" }, + { 512, "596c055c1c55db748379223164075641" }, + { 1008, "f920989c02f3b3603f53c99d89492377" }, + { 1344, "2e496b73759d77ed32ea222dbd2e7b41" }, + { 1408, "7178c046b3a8d772efdb6a71c4991ea4" }, + { 2048, "a917f0099c69eb94079a8421714b6aad" }, + { 3072, "693cd5033d7f5391d3c958519fa9e934" }, + { 4048, "139dca91bcff65b3c40771749052906b" }, + { 6144, "428d9cef6df4fb70a6e9b6bbe4819e55" }, + { 6400, "9c0b909e76daa811e12b1fc17000a0c4" }, + { 6528, "ad876f6297186a7be1f1b907ed860eda" }, + { 8192, "479cbbaca37dd3191ea1f3e8134a0ef4" }, + {16384, "60fda559c74f91df538100c9842f2f15" }, + {18432, "4a3eb1cba1fa45f3981270953f720c42" }, + { 0, NULL }, +}; + + +/* CryptoKey = 0x01234567, 0x89abcdef, + * 0x01234567, 0x89abcdef, + * 0x01234567, 0x89abcdef; + * IV = 0x12345678, 0x90abcdef + * MacKey = 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + * 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10 + * 0x11, 0x12, 0x13, 0x14 + * InputHexStr = "31323334353637383930" (ASCII = "1234567890") + * Note: only sizes aligned to AES block size (16 bytes) allowed + */ +static MV_CESA_SIZE_TEST cbcAes128sha1multiSizeTest507[] = +{ + { 16, "9aa8dc1c45f0946daf78057fa978759c625c1fee" }, + { 64, "9f588fc1ede851e5f8b20256abc9979465ae2189" }, + { 80, "13558472d1fc1c90dffec6e5136c7203452d509b" }, + { 352, "6b93518e006cfaa1f7adb24615e7291fb0a27e06" }, + { 512, "096874951a77fbbf333e49d80c096ee2016e09bd" }, + { 1008, "696fc203c2e4b5ae0ec5d1db3f623c490bc6dbac" }, + { 1344, "79bf77509935ccd3528caaac6a5eb6481f74029b" }, + { 1408, "627f9462b95fc188e8cfa7eec15119bdc5d4fcf1" }, + { 2048, "3d50d0c005feba92fe41502d609fced9c882b4d1" }, + { 3072, "758807e5b983e3a91c06fb218fe0f73f77111e94" }, + { 4048, "ca90e85242e33f005da3504416a52098d0d31fb2" }, + { 6144, "8044c1d4fd06642dfc46990b4f18b61ef1e972cf" }, + { 6400, "166f1f4ea57409f04feba9fb1e39af0e00bd6f43" }, + { 6528, "0389016a39485d6e330f8b4215ddf718b404f7e9" }, + { 8192, "6df7ee2a8b61d6f7f860ce8dbf778f0c2a5b508b" }, + {16384, "a70a6d8dfa1f91ded621c3dbaed34162bc48783f" }, + {18432, "8dfad627922ce15df1eed10bdbed49244efa57db" }, + { 0, NULL }, +}; + + +void cesaTestPrintStatus(void); + + +/*------------------------- LOCAL FUNCTIONs ---------------------------------*/ +MV_STATUS testCmd(int sid, int iter, MV_CESA_COMMAND* pCmd, + MV_CESA_TEST_SESSION* pTestSession, MV_U8* pIV, int ivSize); +MV_STATUS testClose(int idx); +MV_STATUS testOpen(int idx); +void close_session(int sid); +void cesaTestCheckReady(const MV_CESA_RESULT *r); +void cesaCheckReady(MV_CESA_RESULT* r); +void printTestResults(int idx, MV_STATUS status, int checkMode); +void cesaLastResult(void); +void cesaTestPrintReq(int req, int offset, int size); + +void cesaTestPrintStatus(void); +void cesaTestPrintSession(int idx); +void sizeTest(int testIdx, int iter, int checkMode); +void multiTest(int iter, int reqSize, int checkMode); +void oneTest(int testIdx, int caseIdx,int iter, int reqSize, int checkMode); +void multiSizeTest(int idx, int iter, int checkMode, char* inputData); +void cesaTest(int iter, int reqSize, int checkMode); +void cesaOneTest(int testIdx, int caseIdx,int iter, int reqSize, int checkMode); +void combiTest(int iter, int reqSize, int checkMode); +void shaTest(int iter, int reqSize, int checkMode); +void mdTest(int iter, int reqSize, int checkMode); +void aesTest(int iter, int reqSize, int checkMode); +void tripleDesTest(int iter, int reqSize, int checkMode); +void desTest(int iter, int reqSize, int checkMode); +void cesaTestStop(void); +MV_STATUS testRun(int idx, int caseIdx, int iter,int reqSize, int checkMode); +void cesaTestStart(int bufNum, int bufSize); + + +static MV_U32 getRate(MV_U32* remainder) +{ + MV_U32 kBits, milliSec, rate; + + milliSec = 0; + if( (cesaEndTicks - cesaBeginTicks) > 0) + { + milliSec = CESA_TEST_TICK_TO_MS(cesaEndTicks - cesaBeginTicks); + } + if(milliSec == 0) + { + if(remainder != NULL) + *remainder = 0; + return 0; + } + + kBits = (cesaIteration*cesaRateSize*8)/1000; + rate = kBits/milliSec; + if(remainder != NULL) + *remainder = ((kBits % milliSec)*10)/milliSec; + + return rate; +} + +static char* extractMbuf(MV_CESA_MBUF *pMbuf, + int offset, int size, char* hexStr) +{ + mvCesaCopyFromMbuf((MV_U8*)cesaBinBuffer, pMbuf, offset, size); + mvBinToHex((const MV_U8*)cesaBinBuffer, hexStr, size); + + return hexStr; +} + +static MV_BOOL cesaCheckMbuf(MV_CESA_MBUF *pMbuf, + const char* hexString, int offset, + int checkSize) +{ + MV_BOOL isFailed = MV_FALSE; + MV_STATUS status; + int size = strlen(hexString)/2; + int checkedSize = 0; +/* + mvOsPrintf("cesaCheckMbuf: pMbuf=%p, offset=%d, checkSize=%d, mBufSize=%d\n", + pMbuf, offset, checkSize, pMbuf->mbufSize); +*/ + if(pMbuf->mbufSize < (checkSize + offset)) + { + mvOsPrintf("checkSize (%d) is too large: offset=%d, mbufSize=%d\n", + checkSize, offset, pMbuf->mbufSize); + return MV_TRUE; + } + status = mvCesaCopyFromMbuf((MV_U8*)cesaBinBuffer, pMbuf, offset, checkSize); + if(status != MV_OK) + { + mvOsPrintf("CesaTest: Can't copy %d bytes from Mbuf=%p to checkBuf=%p\n", + checkSize, pMbuf, cesaBinBuffer); + return MV_TRUE; + } +/* + mvDebugMemDump(cesaBinBuffer, size, 1); +*/ + mvHexToBin(hexString, (MV_U8*)cesaExpBinBuffer, size); + + /* Compare buffers */ + while(checkSize > checkedSize) + { + size = MV_MIN(size, (checkSize - checkedSize)); + if(memcmp(cesaExpBinBuffer, &cesaBinBuffer[checkedSize], size) != 0) + { + mvOsPrintf("CheckMbuf failed: checkSize=%d, size=%d, checkedSize=%d\n", + checkSize, size, checkedSize); + mvDebugMemDump(&cesaBinBuffer[checkedSize], size, 1); + mvDebugMemDump(cesaExpBinBuffer, size, 1); + + isFailed = MV_TRUE; + break; + } + checkedSize += size; + } + + return isFailed; +} + +static MV_STATUS cesaSetMbuf(MV_CESA_MBUF *pMbuf, + const char* hexString, + int offset, int reqSize) +{ + MV_STATUS status = MV_OK; + int copySize, size = strlen(hexString)/2; + + mvHexToBin(hexString, (MV_U8*)cesaBinBuffer, size); + + copySize = 0; + while(reqSize > copySize) + { + size = MV_MIN(size, (reqSize - copySize)); + + status = mvCesaCopyToMbuf((MV_U8*)cesaBinBuffer, pMbuf, offset+copySize, size); + if(status != MV_OK) + { + mvOsPrintf("cesaSetMbuf Error: Copy %d of %d bytes to MBuf\n", + copySize, reqSize); + break; + } + copySize += size; + } + pMbuf->mbufSize = offset+copySize; + return status; +} + +static MV_CESA_TEST_SESSION* getTestSessionDb(int idx, int* pTestIdx) +{ + int testIdx, dbIdx = idx/100; + + if(dbIdx > MAX_TEST_TYPE) + { + mvOsPrintf("Wrong index %d - No such test type\n", idx); + return NULL; + } + testIdx = idx % 100; + + if(testIdx >= cesaTestsDB[dbIdx].numSessions) + { + mvOsPrintf("Wrong index %d - No such test\n", idx); + return NULL; + } + if(pTestIdx != NULL) + *pTestIdx = testIdx; + + return cesaTestsDB[dbIdx].pSessions; +} + +/* Debug */ +void cesaTestPrintReq(int req, int offset, int size) +{ + MV_CESA_MBUF* pMbuf; + + mvOsPrintf("cesaTestPrintReq: req=%d, offset=%d, size=%d\n", + req, offset, size); + mvDebugMemDump(cesaCmdRing, 128, 4); + + pMbuf = cesaCmdRing[req].pSrc; + mvCesaDebugMbuf("src", pMbuf, offset,size); + pMbuf = cesaCmdRing[req].pDst; + mvCesaDebugMbuf("dst", pMbuf, offset, size); + + cesaTestPrintStatus(); +} + +void cesaLastResult(void) +{ + mvOsPrintf("Last Result: ReqId = %d, SessionId = %d, rc = (%d)\n", + (MV_U32)cesaResult.pReqPrv, cesaResult.sessionId, + cesaResult.retCode); +} + +void printTestResults(int idx, MV_STATUS status, int checkMode) +{ + int testIdx; + MV_CESA_TEST_SESSION* pTestSessions = getTestSessionDb(idx, &testIdx); + + if(pTestSessions == NULL) + return; + + mvOsPrintf("%-35s %4dx%-4d : ", pTestSessions[testIdx].name, + cesaIteration, cesaReqSize); + if( (status == MV_OK) && + (cesaCryptoError == 0) && + (cesaError == 0) && + (cesaReqIdError == 0) ) + { + mvOsPrintf("Passed, Rate=%3u.%u Mbps (%5u cpp)\n", + cesaRate, cesaRateAfterDot, cesaEndTicks - cesaBeginTicks); + } + else + { + mvOsPrintf("Failed, Status = 0x%x\n", status); + if(cesaCryptoError > 0) + mvOsPrintf("cryptoError : %d\n", cesaCryptoError); + if(cesaReqIdError > 0) + mvOsPrintf("reqIdError : %d\n", cesaReqIdError); + if(cesaError > 0) + mvOsPrintf("cesaError : %d\n", cesaError); + } + if(cesaTestIsrMissCount > 0) + mvOsPrintf("cesaIsrMissed : %d\n", cesaTestIsrMissCount); +} + +void cesaCheckReady(MV_CESA_RESULT* r) +{ + int reqId; + MV_CESA_MBUF *pMbuf; + MV_BOOL isFailed; + + cesaResult = *r; + reqId = (int)cesaResult.pReqPrv; + pMbuf = cesaCmdRing[reqId].pDst; + +/* + mvOsPrintf("cesaCheckReady: reqId=%d, checkOffset=%d, checkSize=%d\n", + reqId, cesaCheckOffset, cesaCheckSize); +*/ + /* Check expected reqId */ + if(reqId != cesaExpReqId) + { + cesaReqIdError++; +/* + mvOsPrintf("CESA reqId Error: cbIter=%d (%d), reqId=%d, expReqId=%d\n", + cesaCbIter, cesaIteration, reqId, cesaExpReqId); +*/ + } + else + { + if( (cesaCheckMode == CESA_FULL_CHECK_MODE) || + (cesaCheckMode == CESA_FAST_CHECK_MODE) ) + { + if(cesaResult.retCode != MV_OK) + { + cesaError++; + + mvOsPrintf("CESA Error: cbIter=%d (%d), reqId=%d, rc=%d\n", + cesaCbIter, cesaIteration, reqId, cesaResult.retCode); + } + else + { + if( (cesaCheckSize > 0) && (cesaOutputHexStr != NULL) ) + { + /* Check expected output */ + + isFailed = cesaCheckMbuf(pMbuf, cesaOutputHexStr, cesaCheckOffset, cesaCheckSize); + if(isFailed) + { + mvOsPrintf("CESA Crypto Error: cbIter=%d (%d), reqId=%d\n", + cesaCbIter, cesaIteration, reqId); + + CESA_TEST_DEBUG_PRINT(("Error: reqId=%d, reqSize=%d, checkOffset=%d, checkSize=%d\n", + reqId, cesaReqSize, cesaCheckOffset, cesaCheckSize)); + + CESA_TEST_DEBUG_PRINT(("Output str: %s\n", cesaOutputHexStr)); + + CESA_TEST_DEBUG_CODE( mvCesaDebugMbuf("error", pMbuf, 0, cesaCheckOffset+cesaCheckSize) ); + + cesaCryptoError++; + } + } + } + } + } + if(cesaCheckMode == CESA_SHOW_CHECK_MODE) + { + extractMbuf(pMbuf, cesaCheckOffset, cesaCheckSize, cesaHexBuffer); + mvOsPrintf("%4d, %s\n", cesaCheckOffset, cesaHexBuffer); + } + + cesaCbIter++; + if(cesaCbIter >= cesaIteration) + { + cesaCbIter = 0; + cesaExpReqId = 0; + cesaIsReady = MV_TRUE; + + cesaEndTicks = CESA_TEST_TICK_GET(); + cesaRate = getRate(&cesaRateAfterDot); + } + else + { + cesaExpReqId = reqId + 1; + if(cesaExpReqId == CESA_DEF_REQ_SIZE) + cesaExpReqId = 0; + } +} + + +#ifdef MV_NETBSD +static int cesaTestReadyIsr(void *arg) +#else +#ifdef __KERNEL__ +static irqreturn_t cesaTestReadyIsr( int irq , void *dev_id) +#endif +#ifdef MV_VXWORKS +void cesaTestReadyIsr(void) +#endif +#endif +{ + MV_U32 cause; + MV_STATUS status; + MV_CESA_RESULT result; + + cesaTestIsrCount++; + /* Clear cause register */ + cause = MV_REG_READ(MV_CESA_ISR_CAUSE_REG); + if( (cause & MV_CESA_CAUSE_ACC_DMA_ALL_MASK) == 0) + { + mvOsPrintf("cesaTestReadyIsr: cause=0x%x\n", cause); +#ifdef MV_NETBSD + return 0; +#else +#ifdef __KERNEL__ + return 1; +#else + return; +#endif +#endif + } + + MV_REG_WRITE(MV_CESA_ISR_CAUSE_REG, 0); + + while(MV_TRUE) + { + /* Get Ready requests */ + status = mvCesaReadyGet(&result); + if(status == MV_OK) + cesaCheckReady(&result); + + break; + } + if( (cesaTestFull == 1) && (status != MV_BUSY) ) + { + cesaTestFull = 0; + CESA_TEST_WAKE_UP(); + } + +#ifdef __KERNEL__ + return 1; +#endif +} + +void +cesaTestCheckReady(const MV_CESA_RESULT *r) +{ + MV_CESA_RESULT result = *r; + + cesaCheckReady(&result); + + if (cesaTestFull == 1) { + cesaTestFull = 0; + CESA_TEST_WAKE_UP(); + } +} + +static INLINE int open_session(MV_CESA_OPEN_SESSION* pOs) +{ + MV_U16 sid; + MV_STATUS status; + + status = mvCesaSessionOpen(pOs, (short*)&sid); + if(status != MV_OK) + { + mvOsPrintf("CesaTest: Can't open new session - status = 0x%x\n", + status); + return -1; + } + + return (int)sid; +} + +void close_session(int sid) +{ + MV_STATUS status; + + status = mvCesaSessionClose(sid); + if(status != MV_OK) + { + mvOsPrintf("CesaTest: Can't close session %d - status = 0x%x\n", + sid, status); + } +} + +MV_STATUS testOpen(int idx) +{ + MV_CESA_OPEN_SESSION os; + int sid, i, testIdx; + MV_CESA_TEST_SESSION* pTestSession; + MV_U16 digestSize = 0; + + pTestSession = getTestSessionDb(idx, &testIdx); + if(pTestSession == NULL) + { + mvOsPrintf("Test %d is not exist\n", idx); + return MV_BAD_PARAM; + } + pTestSession = &pTestSession[testIdx]; + + if(pTestSession->sid != -1) + { + mvOsPrintf("Session for test %d already created: sid=%d\n", + idx, pTestSession->sid); + return MV_OK; + } + + os.cryptoAlgorithm = pTestSession->cryptoAlgorithm; + os.macMode = pTestSession->macAlgorithm; + switch(os.macMode) + { + case MV_CESA_MAC_MD5: + case MV_CESA_MAC_HMAC_MD5: + digestSize = MV_CESA_MD5_DIGEST_SIZE; + break; + + case MV_CESA_MAC_SHA1: + case MV_CESA_MAC_HMAC_SHA1: + digestSize = MV_CESA_SHA1_DIGEST_SIZE; + break; + + case MV_CESA_MAC_NULL: + digestSize = 0; + } + os.cryptoMode = pTestSession->cryptoMode; + os.direction = pTestSession->direction; + os.operation = pTestSession->operation; + + for(i=0; icryptoKeySize; i++) + os.cryptoKey[i] = pTestSession->pCryptoKey[i]; + + os.cryptoKeyLength = pTestSession->cryptoKeySize; + + for(i=0; imacKeySize; i++) + os.macKey[i] = pTestSession->pMacKey[i]; + + os.macKeyLength = pTestSession->macKeySize; + os.digestSize = digestSize; + + sid = open_session(&os); + if(sid == -1) + { + mvOsPrintf("Can't open session for test %d: rc=0x%x\n", + idx, cesaResult.retCode); + return cesaResult.retCode; + } + CESA_TEST_DEBUG_PRINT(("Opened session: sid = %d\n", sid)); + pTestSession->sid = sid; + return MV_OK; +} + +MV_STATUS testClose(int idx) +{ + int testIdx; + MV_CESA_TEST_SESSION* pTestSession; + + pTestSession = getTestSessionDb(idx, &testIdx); + if(pTestSession == NULL) + { + mvOsPrintf("Test %d is not exist\n", idx); + return MV_BAD_PARAM; + } + pTestSession = &pTestSession[testIdx]; + + if(pTestSession->sid == -1) + { + mvOsPrintf("Test session %d is not opened\n", idx); + return MV_NO_SUCH; + } + + close_session(pTestSession->sid); + pTestSession->sid = -1; + + return MV_OK; +} + +MV_STATUS testCmd(int sid, int iter, MV_CESA_COMMAND* pCmd, + MV_CESA_TEST_SESSION* pTestSession, MV_U8* pIV, int ivSize) +{ + int cmdReqId = 0; + int i; + MV_STATUS rc = MV_OK; + char ivZeroHex[] = "0000"; + + if(iter == 0) + iter = CESA_DEF_ITER_NUM; + + if(pCmd == NULL) + { + mvOsPrintf("testCmd failed: pCmd=NULL\n"); + return MV_BAD_PARAM; + } + pCmd->sessionId = sid; + + cesaCryptoError = 0; + cesaReqIdError = 0; + cesaError = 0; + cesaTestIsrMissCount = 0; + cesaIsReady = MV_FALSE; + cesaIteration = iter; + + if(cesaInputHexStr == NULL) + cesaInputHexStr = cesaPlainHexEbc; + + for(i=0; ipSrc = (MV_CESA_MBUF*)(cesaCmdRing[i].pSrc); + if(pIV != NULL) + { + /* If IV from SA - set IV in Source buffer to zeros */ + cesaSetMbuf(pCmd->pSrc, ivZeroHex, 0, pCmd->cryptoOffset); + cesaSetMbuf(pCmd->pSrc, cesaInputHexStr, pCmd->cryptoOffset, + (cesaReqSize - pCmd->cryptoOffset)); + } + else + { + cesaSetMbuf(pCmd->pSrc, cesaInputHexStr, 0, cesaReqSize); + } + pCmd->pDst = (MV_CESA_MBUF*)(cesaCmdRing[i].pDst); + cesaSetMbuf(pCmd->pDst, cesaNullPlainHexText, 0, cesaReqSize); + + memcpy(&cesaCmdRing[i], pCmd, sizeof(*pCmd)); + } + + if(cesaCheckMode == CESA_SW_SHOW_CHECK_MODE) + { + MV_U8 pDigest[MV_CESA_MAX_DIGEST_SIZE]; + + if(pTestSession->macAlgorithm == MV_CESA_MAC_MD5) + { + mvMD5(pCmd->pSrc->pFrags[0].bufVirtPtr, pCmd->macLength, pDigest); + mvOsPrintf("SW HASH_MD5: reqSize=%d, macLength=%d\n", + cesaReqSize, pCmd->macLength); + mvDebugMemDump(pDigest, MV_CESA_MD5_DIGEST_SIZE, 1); + return MV_OK; + } + if(pTestSession->macAlgorithm == MV_CESA_MAC_SHA1) + { + mvSHA1(pCmd->pSrc->pFrags[0].bufVirtPtr, pCmd->macLength, pDigest); + mvOsPrintf("SW HASH_SHA1: reqSize=%d, macLength=%d\n", + cesaReqSize, pCmd->macLength); + mvDebugMemDump(pDigest, MV_CESA_SHA1_DIGEST_SIZE, 1); + return MV_OK; + } + } + + cesaBeginTicks = CESA_TEST_TICK_GET(); + CESA_TEST_DEBUG_CODE( memset(cesaTestTrace, 0, sizeof(cesaTestTrace)); + cesaTestTraceIdx = 0; + ); + + if(cesaCheckMode == CESA_SW_NULL_CHECK_MODE) + { + volatile MV_U8 pDigest[MV_CESA_MAX_DIGEST_SIZE]; + + for(i=0; imacAlgorithm == MV_CESA_MAC_MD5) + { + mvMD5(pCmd->pSrc->pFrags[0].bufVirtPtr, pCmd->macLength, (unsigned char*)pDigest); + } + if(pTestSession->macAlgorithm == MV_CESA_MAC_SHA1) + { + mvSHA1(pCmd->pSrc->pFrags[0].bufVirtPtr, pCmd->macLength, (MV_U8 *)pDigest); + } + } + cesaEndTicks = CESA_TEST_TICK_GET(); + cesaRate = getRate(&cesaRateAfterDot); + cesaIsReady = MV_TRUE; + + return MV_OK; + } + + /*cesaTestIsrCount = 0;*/ + /*mvCesaDebugStatsClear();*/ + +#ifndef MV_NETBSD + MV_REG_WRITE(MV_CESA_ISR_CAUSE_REG, 0); +#endif + + for(i=0; ipReqPrv = (void*)cmdReqId; + + CESA_TEST_LOCK(flags); + + rc = mvCesaAction(pCmd); + if(rc == MV_NO_RESOURCE) + cesaTestFull = 1; + + CESA_TEST_UNLOCK(flags); + + if(rc == MV_NO_RESOURCE) + { + CESA_TEST_LOCK(flags); + CESA_TEST_WAIT( (cesaTestFull == 0), 100); + CESA_TEST_UNLOCK(flags); + if(cesaTestFull == 1) + { + mvOsPrintf("CESA Test timeout: i=%d, iter=%d, cesaTestFull=%d\n", + i, iter, cesaTestFull); + cesaTestFull = 0; + return MV_TIMEOUT; + } + + CESA_TEST_LOCK(flags); + + rc = mvCesaAction(pCmd); + + CESA_TEST_UNLOCK(flags); + } + if( (rc != MV_OK) && (rc != MV_NO_MORE) ) + { + mvOsPrintf("mvCesaAction failed: rc=%d\n", rc); + return rc; + } + + cmdReqId++; + if(cmdReqId >= CESA_DEF_REQ_SIZE) + cmdReqId = 0; + +#ifdef MV_LINUX + /* Reschedule each 16 requests */ + if( (i & 0xF) == 0) + schedule(); +#endif + } + return MV_OK; +} + +void cesaTestStart(int bufNum, int bufSize) +{ + int i, j, idx; + MV_CESA_MBUF *pMbufSrc, *pMbufDst; + MV_BUF_INFO *pFragsSrc, *pFragsDst; + char *pBuf; +#ifndef MV_NETBSD + int numOfSessions, queueDepth; + char *pSram; + MV_STATUS status; + MV_CPU_DEC_WIN addrDecWin; +#endif + + cesaCmdRing = mvOsMalloc(sizeof(MV_CESA_COMMAND) * CESA_DEF_REQ_SIZE); + if(cesaCmdRing == NULL) + { + mvOsPrintf("testStart: Can't allocate %ld bytes of memory\n", + sizeof(MV_CESA_COMMAND) * CESA_DEF_REQ_SIZE); + return; + } + memset(cesaCmdRing, 0, sizeof(MV_CESA_COMMAND) * CESA_DEF_REQ_SIZE); + + if(bufNum == 0) + bufNum = CESA_DEF_BUF_NUM; + + if(bufSize == 0) + bufSize = CESA_DEF_BUF_SIZE; + + cesaBufNum = bufNum; + cesaBufSize = bufSize; + mvOsPrintf("CESA test started: bufNum = %d, bufSize = %d\n", + bufNum, bufSize); + + cesaHexBuffer = mvOsMalloc(2*bufNum*bufSize); + if(cesaHexBuffer == NULL) + { + mvOsPrintf("testStart: Can't malloc %d bytes for cesaHexBuffer.\n", + 2*bufNum*bufSize); + return; + } + memset(cesaHexBuffer, 0, (2*bufNum*bufSize)); + + cesaBinBuffer = mvOsMalloc(bufNum*bufSize); + if(cesaBinBuffer == NULL) + { + mvOsPrintf("testStart: Can't malloc %d bytes for cesaBinBuffer\n", + bufNum*bufSize); + return; + } + memset(cesaBinBuffer, 0, (bufNum*bufSize)); + + cesaExpBinBuffer = mvOsMalloc(bufNum*bufSize); + if(cesaExpBinBuffer == NULL) + { + mvOsPrintf("testStart: Can't malloc %d bytes for cesaExpBinBuffer\n", + bufNum*bufSize); + return; + } + memset(cesaExpBinBuffer, 0, (bufNum*bufSize)); + + CESA_TEST_WAIT_INIT(); + + pMbufSrc = mvOsMalloc(sizeof(MV_CESA_MBUF) * CESA_DEF_REQ_SIZE); + pFragsSrc = mvOsMalloc(sizeof(MV_BUF_INFO) * bufNum * CESA_DEF_REQ_SIZE); + + pMbufDst = mvOsMalloc(sizeof(MV_CESA_MBUF) * CESA_DEF_REQ_SIZE); + pFragsDst = mvOsMalloc(sizeof(MV_BUF_INFO) * bufNum * CESA_DEF_REQ_SIZE); + + if( (pMbufSrc == NULL) || (pFragsSrc == NULL) || + (pMbufDst == NULL) || (pFragsDst == NULL) ) + { + mvOsPrintf("testStart: Can't malloc Src and Dst pMbuf and pFrags structures.\n"); + /* !!!! Dima cesaTestCleanup();*/ + return; + } + + memset(pMbufSrc, 0, sizeof(MV_CESA_MBUF) * CESA_DEF_REQ_SIZE); + memset(pFragsSrc, 0, sizeof(MV_BUF_INFO) * bufNum * CESA_DEF_REQ_SIZE); + + memset(pMbufDst, 0, sizeof(MV_CESA_MBUF) * CESA_DEF_REQ_SIZE); + memset(pFragsDst, 0, sizeof(MV_BUF_INFO) * bufNum * CESA_DEF_REQ_SIZE); + + mvOsPrintf("Cesa Test Start: pMbufSrc=%p, pFragsSrc=%p, pMbufDst=%p, pFragsDst=%p\n", + pMbufSrc, pFragsSrc, pMbufDst, pFragsDst); + + idx = 0; + for(i=0; ipFrags = &pFragsSrc[idx]; + cesaCmdRing[i].pSrc->numFrags = bufNum; + cesaCmdRing[i].pSrc->mbufSize = 0; + + cesaCmdRing[i].pDst = &pMbufDst[i]; + cesaCmdRing[i].pDst->pFrags = &pFragsDst[idx]; + cesaCmdRing[i].pDst->numFrags = bufNum; + cesaCmdRing[i].pDst->mbufSize = 0; + + for(j=0; jpFrags[j].bufVirtPtr = (MV_U8*)pBuf; + cesaCmdRing[i].pSrc->pFrags[j].bufSize = bufSize; + pBuf += bufSize; + cesaCmdRing[i].pDst->pFrags[j].bufVirtPtr = (MV_U8*)pBuf; + cesaCmdRing[i].pDst->pFrags[j].bufSize = bufSize; + pBuf += bufSize; + } + idx += bufNum; + } + +#ifndef MV_NETBSD + if (mvCpuIfTargetWinGet(CRYPT_ENG, &addrDecWin) == MV_OK) + pSram = (char*)addrDecWin.addrWin.baseLow; + else + { + mvOsPrintf("mvCesaInit: ERR. mvCpuIfTargetWinGet failed\n"); + return; + } + +#ifdef MV_CESA_NO_SRAM + pSram = mvOsMalloc(4*1024+8); + if(pSram == NULL) + { + mvOsPrintf("CesaTest: can't allocate %d bytes for SRAM simulation\n", + 4*1024+8); + /* !!!! Dima cesaTestCleanup();*/ + return; + } + pSram = (MV_U8*)MV_ALIGN_UP((MV_U32)pSram, 8); +#endif /* MV_CESA_NO_SRAM */ + + numOfSessions = CESA_DEF_SESSION_NUM; + queueDepth = CESA_DEF_REQ_SIZE - MV_CESA_MAX_CHAN; + + status = mvCesaInit(numOfSessions, queueDepth, pSram, NULL); + if(status != MV_OK) + { + mvOsPrintf("mvCesaInit is Failed: status = 0x%x\n", status); + /* !!!! Dima cesaTestCleanup();*/ + return; + } +#endif /* !MV_NETBSD */ + + /* Prepare data for tests */ + for(i=0; i<50; i++) + strcat((char*)cesaDataHexStr3, "dd"); + + strcpy((char*)cesaDataAndMd5digest3, cesaDataHexStr3); + strcpy((char*)cesaDataAndSha1digest3, cesaDataHexStr3); + + /* Digest must be 8 byte aligned */ + for(; i<56; i++) + { + strcat((char*)cesaDataAndMd5digest3, "00"); + strcat((char*)cesaDataAndSha1digest3, "00"); + } + strcat((char*)cesaDataAndMd5digest3, cesaHmacMd5digestHex3); + strcat((char*)cesaDataAndSha1digest3, cesaHmacSha1digestHex3); + +#ifndef MV_NETBSD + MV_REG_WRITE( MV_CESA_ISR_CAUSE_REG, 0); + MV_REG_WRITE( MV_CESA_ISR_MASK_REG, MV_CESA_CAUSE_ACC_DMA_MASK); +#endif + +#ifdef MV_VXWORKS + { + MV_STATUS status; + + status = intConnect((VOIDFUNCPTR *)INT_LVL_CESA, cesaTestReadyIsr, (int)NULL); + if (status != OK) + { + mvOsPrintf("CESA: Can't connect CESA (%d) interrupt, status=0x%x \n", + INT_LVL_CESA, status); + /* !!!! Dima cesaTestCleanup();*/ + return; + } + cesaSemId = semMCreate(SEM_Q_PRIORITY | SEM_INVERSION_SAFE | SEM_DELETE_SAFE); + if(cesaSemId == NULL) + { + mvOsPrintf("cesaTestStart: Can't create semaphore\n"); + return; + } + intEnable(INT_LVL_CESA); + } +#endif /* MV_VXWORKS */ + +#if !defined(MV_NETBSD) && defined(__KERNEL__) + if( request_irq(CESA_IRQ, cesaTestReadyIsr, (SA_INTERRUPT) , "cesa_test", NULL ) ) + { + mvOsPrintf( "cannot assign irq\n" ); + /* !!!! Dima cesaTestCleanup();*/ + return; + } + spin_lock_init( &cesaLock ); +#endif +} + +MV_STATUS testRun(int idx, int caseIdx, int iter, + int reqSize, int checkMode) +{ + int testIdx, count, sid, digestSize; + int blockSize; + MV_CESA_TEST_SESSION* pTestSession; + MV_CESA_COMMAND cmd; + MV_STATUS status; + + memset(&cmd, 0, sizeof(cmd)); + + pTestSession = getTestSessionDb(idx, &testIdx); + if(pTestSession == NULL) + { + mvOsPrintf("Test %d is not exist\n", idx); + return MV_BAD_PARAM; + } + pTestSession = &pTestSession[testIdx]; + + sid = pTestSession->sid; + if(sid == -1) + { + mvOsPrintf("Test %d is not opened\n", idx); + return MV_BAD_STATE; + } + switch(pTestSession->cryptoAlgorithm) + { + case MV_CESA_CRYPTO_DES: + case MV_CESA_CRYPTO_3DES: + blockSize = MV_CESA_DES_BLOCK_SIZE; + break; + + case MV_CESA_CRYPTO_AES: + blockSize = MV_CESA_AES_BLOCK_SIZE; + break; + + case MV_CESA_CRYPTO_NULL: + blockSize = 0; + break; + + default: + mvOsPrintf("cesaTestRun: Bad CryptoAlgorithm=%d\n", + pTestSession->cryptoAlgorithm); + return MV_BAD_PARAM; + } + switch(pTestSession->macAlgorithm) + { + case MV_CESA_MAC_MD5: + case MV_CESA_MAC_HMAC_MD5: + digestSize = MV_CESA_MD5_DIGEST_SIZE; + break; + + case MV_CESA_MAC_SHA1: + case MV_CESA_MAC_HMAC_SHA1: + digestSize = MV_CESA_SHA1_DIGEST_SIZE; + break; + default: + digestSize = 0; + } + + if(iter == 0) + iter = CESA_DEF_ITER_NUM; + + if(pTestSession->direction == MV_CESA_DIR_ENCODE) + { + cesaOutputHexStr = cesaTestCases[caseIdx].cipherHexStr; + cesaInputHexStr = cesaTestCases[caseIdx].plainHexStr; + } + else + { + cesaOutputHexStr = cesaTestCases[caseIdx].plainHexStr; + cesaInputHexStr = cesaTestCases[caseIdx].cipherHexStr; + } + + cmd.sessionId = sid; + if(checkMode == CESA_FAST_CHECK_MODE) + { + cmd.cryptoLength = cesaTestCases[caseIdx].cryptoLength; + cmd.macLength = cesaTestCases[caseIdx].macLength; + } + else + { + cmd.cryptoLength = reqSize; + cmd.macLength = reqSize; + } + cesaRateSize = cmd.cryptoLength; + cesaReqSize = cmd.cryptoLength; + cmd.cryptoOffset = 0; + if(pTestSession->operation != MV_CESA_MAC_ONLY) + { + if( (pTestSession->cryptoMode == MV_CESA_CRYPTO_CBC) || + (pTestSession->cryptoMode == MV_CESA_CRYPTO_CTR) ) + { + cmd.ivOffset = 0; + cmd.cryptoOffset = blockSize; + if(cesaTestCases[caseIdx].pCryptoIV == NULL) + { + cmd.ivFromUser = 1; + } + else + { + cmd.ivFromUser = 0; + mvCesaCryptoIvSet(cesaTestCases[caseIdx].pCryptoIV, blockSize); + } + cesaReqSize = cmd.cryptoOffset + cmd.cryptoLength; + } + } + +/* + mvOsPrintf("ivFromUser=%d, cryptoLength=%d, cesaReqSize=%d, cryptoOffset=%d\n", + cmd.ivFromUser, cmd.cryptoLength, cesaReqSize, cmd.cryptoOffset); +*/ + if(pTestSession->operation != MV_CESA_CRYPTO_ONLY) + { + cmd.macOffset = cmd.cryptoOffset; + + if(cesaTestCases[caseIdx].digestOffset == -1) + { + cmd.digestOffset = cmd.macOffset + cmd.macLength; + cmd.digestOffset = MV_ALIGN_UP(cmd.digestOffset, 8); + } + else + { + cmd.digestOffset = cesaTestCases[caseIdx].digestOffset; + } + if( (cmd.digestOffset + digestSize) > cesaReqSize) + cesaReqSize = cmd.digestOffset + digestSize; + } + + cesaCheckMode = checkMode; + + if(checkMode == CESA_NULL_CHECK_MODE) + { + cesaCheckSize = 0; + cesaCheckOffset = 0; + } + else + { + if(pTestSession->operation == MV_CESA_CRYPTO_ONLY) + { + cesaCheckOffset = 0; + cesaCheckSize = cmd.cryptoLength; + } + else + { + cesaCheckSize = digestSize; + cesaCheckOffset = cmd.digestOffset; + } + } +/* + mvOsPrintf("reqSize=%d, checkSize=%d, checkOffset=%d, checkMode=%d\n", + cesaReqSize, cesaCheckSize, cesaCheckOffset, cesaCheckMode); + + mvOsPrintf("blockSize=%d, ivOffset=%d, ivFromUser=%d, crOffset=%d, crLength=%d\n", + blockSize, cmd.ivOffset, cmd.ivFromUser, + cmd.cryptoOffset, cmd.cryptoLength); + + mvOsPrintf("macOffset=%d, digestOffset=%d, macLength=%d\n", + cmd.macOffset, cmd.digestOffset, cmd.macLength); +*/ + status = testCmd(sid, iter, &cmd, pTestSession, + cesaTestCases[caseIdx].pCryptoIV, blockSize); + + if(status != MV_OK) + return status; + + /* Wait when all callbacks is received */ + count = 0; + while(cesaIsReady == MV_FALSE) + { + mvOsSleep(10); + count++; + if(count > 100) + { + mvOsPrintf("testRun: Timeout occured\n"); + return MV_TIMEOUT; + } + } + + return MV_OK; +} + + +void cesaTestStop(void) +{ + MV_CESA_MBUF *pMbufSrc, *pMbufDst; + MV_BUF_INFO *pFragsSrc, *pFragsDst; + int i; + + /* Release all allocated memories */ + pMbufSrc = (MV_CESA_MBUF*)(cesaCmdRing[0].pSrc); + pFragsSrc = cesaCmdRing[0].pSrc->pFrags; + + pMbufDst = (MV_CESA_MBUF*)(cesaCmdRing[0].pDst); + pFragsDst = cesaCmdRing[0].pDst->pFrags; + + mvOsFree(pMbufSrc); + mvOsFree(pMbufDst); + mvOsFree(pFragsSrc); + mvOsFree(pFragsDst); + + for(i=0; i 0) + cryptoError++; + if(cesaReqIdError > 0) + reqIdError++; + + testClose(idx); + } + } + if(cryptoError > 0) + mvOsPrintf("cryptoError : %d\n", cryptoError); + if(reqIdError > 0) + mvOsPrintf("reqIdError : %d\n", reqIdError); + + if(openErrors > 0) + { + mvOsPrintf("Open Errors = %d\n", openErrors); + for(i=0; i<100; i++) + { + if(openErrDisp[i] != 0) + mvOsPrintf("Error %d - occurs %d times\n", i, openErrDisp[i]); + } + } +} + + +void loopback_test(int idx, int iter, int size, char* pPlainData) +{ +} + + +#if defined(MV_VXWORKS) +int testMode = 0; +unsigned __TASKCONV cesaTask(void* args) +{ + int reqSize = cesaReqSize; + + if(testMode == 0) + { + cesaOneTest(cesaTestIdx, cesaCaseIdx, cesaIteration, + reqSize, cesaCheckMode); + } + else + { + if(testMode == 1) + { + cesaTest(cesaIteration, reqSize, cesaCheckMode); + combiTest(cesaIteration, reqSize, cesaCheckMode); + } + else + { + multiSizeTest(cesaIdx, cesaIteration, cesaCheckMode, NULL); + } + } + return 0; +} + +void oneTest(int testIdx, int caseIdx, + int iter, int reqSize, int checkMode) +{ + long rc; + + cesaIteration = iter; + cesaReqSize = cesaRateSize = reqSize; + cesaCheckMode = checkMode; + testMode = 0; + cesaTestIdx = testIdx; + cesaCaseIdx = caseIdx; + rc = mvOsTaskCreate("CESA_T", 100, 4*1024, cesaTask, NULL, &cesaTaskId); + if (rc != MV_OK) + { + mvOsPrintf("hMW: Can't create CESA multiCmd test task, rc = %ld\n", rc); + } +} + +void multiTest(int iter, int reqSize, int checkMode) +{ + long rc; + + cesaIteration = iter; + cesaCheckMode = checkMode; + cesaReqSize = reqSize; + testMode = 1; + rc = mvOsTaskCreate("CESA_T", 100, 4*1024, cesaTask, NULL, &cesaTaskId); + if (rc != MV_OK) + { + mvOsPrintf("hMW: Can't create CESA multiCmd test task, rc = %ld\n", rc); + } +} + +void sizeTest(int testIdx, int iter, int checkMode) +{ + long rc; + + cesaIteration = iter; + cesaCheckMode = checkMode; + testMode = 2; + cesaIdx = testIdx; + rc = mvOsTaskCreate("CESA_T", 100, 4*1024, cesaTask, NULL, &cesaTaskId); + if (rc != MV_OK) + { + mvOsPrintf("hMW: Can't create CESA test task, rc = %ld\n", rc); + } +} + +#endif /* MV_VXWORKS */ + +extern void mvCesaDebugSA(short sid, int mode); +void cesaTestPrintSession(int idx) +{ + int testIdx; + MV_CESA_TEST_SESSION* pTestSession; + + pTestSession = getTestSessionDb(idx, &testIdx); + if(pTestSession == NULL) + { + mvOsPrintf("Test %d is not exist\n", idx); + return; + } + pTestSession = &pTestSession[testIdx]; + + if(pTestSession->sid == -1) + { + mvOsPrintf("Test session %d is not opened\n", idx); + return; + } + + mvCesaDebugSA(pTestSession->sid, 1); +} + +void cesaTestPrintStatus(void) +{ + mvOsPrintf("\n\t Cesa Test Status\n\n"); + + mvOsPrintf("isrCount=%d\n", + cesaTestIsrCount); + +#ifdef CESA_TEST_DEBUG + { + int i, j; + j = cesaTestTraceIdx; + mvOsPrintf("No Type Cause rCause iCause Res Time pReady pProc pEmpty\n"); + for(i=0; itable = mvOsMalloc(numOfEntries*sizeof(MV_LRU_ENTRY)); + if(pLruCache->table == NULL) + { + mvOsFree(pLruCache); + return NULL; + } + memset(pLruCache->table, 0, numOfEntries*sizeof(MV_LRU_ENTRY)); + pLruCache->tableSize = numOfEntries; + + for(i=0; itable[i].next = i+1; + pLruCache->table[i].prev = i-1; + } + pLruCache->least = 0; + pLruCache->most = numOfEntries-1; + + return pLruCache; +} + +void mvLruCacheFinish(MV_LRU_CACHE* pLruCache) +{ + mvOsFree(pLruCache->table); + mvOsFree(pLruCache); +} + +/* Update LRU cache database after using cache Index */ +void mvLruCacheIdxUpdate(MV_LRU_CACHE* pLruHndl, int cacheIdx) +{ + int prev, next; + + if(cacheIdx == pLruHndl->most) + return; + + next = pLruHndl->table[cacheIdx].next; + if(cacheIdx == pLruHndl->least) + { + pLruHndl->least = next; + } + else + { + prev = pLruHndl->table[cacheIdx].prev; + + pLruHndl->table[next].prev = prev; + pLruHndl->table[prev].next = next; + } + + pLruHndl->table[pLruHndl->most].next = cacheIdx; + pLruHndl->table[cacheIdx].prev = pLruHndl->most; + pLruHndl->most = cacheIdx; +} + +/* Delete LRU cache entry */ +void mvLruCacheIdxDelete(MV_LRU_CACHE* pLruHndl, int cacheIdx) +{ + int prev, next; + + if(cacheIdx == pLruHndl->least) + return; + + prev = pLruHndl->table[cacheIdx].prev; + if(cacheIdx == pLruHndl->most) + { + pLruHndl->most = prev; + } + else + { + next = pLruHndl->table[cacheIdx].next; + + pLruHndl->table[next].prev = prev; + pLruHndl->table[prev].next = next; + } + pLruHndl->table[pLruHndl->least].prev = cacheIdx; + pLruHndl->table[cacheIdx].next = pLruHndl->least; + pLruHndl->least = cacheIdx; +} diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/cesa/mvLru.h b/target/linux/generic/files/crypto/ocf/kirkwood/cesa/mvLru.h new file mode 100644 index 0000000..896e7f8 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/cesa/mvLru.h @@ -0,0 +1,112 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ +/******************************************************************************* +* mvLru.h - Header File for Least Recently Used Cache algorithm +* +* DESCRIPTION: +* This header file contains macros typedefs and function declaration for +* the Least Recently Used Cache algorithm. +* +*******************************************************************************/ + +#ifndef __mvLru_h__ +#define __mvLru_h__ + + +typedef struct +{ + int next; + int prev; +} MV_LRU_ENTRY; + +typedef struct +{ + int least; + int most; + MV_LRU_ENTRY* table; + int tableSize; + +}MV_LRU_CACHE; + + +/* Find Cache index for replacement LRU */ +static INLINE int mvLruCacheIdxFind(MV_LRU_CACHE* pLruHndl) +{ + return pLruHndl->least; +} + +/* Init LRU cache module */ +MV_LRU_CACHE* mvLruCacheInit(int numOfEntries); + +/* Finish LRU cache module */ +void mvLruCacheFinish(MV_LRU_CACHE* pLruHndl); + +/* Update LRU cache database after using cache Index */ +void mvLruCacheIdxUpdate(MV_LRU_CACHE* pLruHndl, int cacheIdx); + +/* Delete LRU cache entry */ +void mvLruCacheIdxDelete(MV_LRU_CACHE* pLruHndl, int cacheIdx); + + +#endif /* __mvLru_h__ */ diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/cesa/mvMD5.c b/target/linux/generic/files/crypto/ocf/kirkwood/cesa/mvMD5.c new file mode 100644 index 0000000..189f629 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/cesa/mvMD5.c @@ -0,0 +1,349 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#include "mvOs.h" +#include "mvMD5.h" + +static void mvMD5Transform(MV_U32 buf[4], MV_U32 const in[MV_MD5_MAC_LEN]); + +#ifdef MV_CPU_LE +#define mvByteReverse(buf, len) /* Nothing */ +#else +static void mvByteReverse(unsigned char *buf, unsigned longs); + +/* + * Note: this code is harmless on little-endian machines. + */ +static void mvByteReverse(unsigned char *buf, unsigned longs) +{ + MV_U32 t; + + do + { + t = (MV_U32) ((unsigned) buf[3] << 8 | buf[2]) << 16 | + ((unsigned) buf[1] << 8 | buf[0]); + *(MV_U32 *) buf = t; + buf += 4; + } while (--longs); +} +#endif + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +void mvMD5Init(MV_MD5_CONTEXT *ctx) +{ + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + + ctx->bits[0] = 0; + ctx->bits[1] = 0; +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +void mvMD5Update(MV_MD5_CONTEXT *ctx, unsigned char const *buf, unsigned len) +{ + MV_U32 t; + + /* Update bitcount */ + + t = ctx->bits[0]; + if ((ctx->bits[0] = t + ((MV_U32) len << 3)) < t) + ctx->bits[1]++; /* Carry from low to high */ + ctx->bits[1] += len >> 29; + + t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ + + /* Handle any leading odd-sized chunks */ + + if (t) + { + unsigned char *p = (unsigned char *) ctx->in + t; + + t = 64 - t; + if (len < t) + { + memcpy(p, buf, len); + return; + } + memcpy(p, buf, t); + mvByteReverse(ctx->in, MV_MD5_MAC_LEN); + mvMD5Transform(ctx->buf, (MV_U32 *) ctx->in); + buf += t; + len -= t; + } + /* Process data in 64-byte chunks */ + + while (len >= 64) + { + memcpy(ctx->in, buf, 64); + mvByteReverse(ctx->in, MV_MD5_MAC_LEN); + mvMD5Transform(ctx->buf, (MV_U32 *) ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + + memcpy(ctx->in, buf, len); +} + +/* + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +void mvMD5Final(unsigned char digest[MV_MD5_MAC_LEN], MV_MD5_CONTEXT *ctx) +{ + unsigned count; + unsigned char *p; + + /* Compute number of bytes mod 64 */ + count = (ctx->bits[0] >> 3) & 0x3F; + + /* Set the first char of padding to 0x80. This is safe since there is + always at least one byte free */ + p = ctx->in + count; + *p++ = 0x80; + + /* Bytes of padding needed to make 64 bytes */ + count = 64 - 1 - count; + + /* Pad out to 56 mod 64 */ + if (count < 8) + { + /* Two lots of padding: Pad the first block to 64 bytes */ + memset(p, 0, count); + mvByteReverse(ctx->in, MV_MD5_MAC_LEN); + mvMD5Transform(ctx->buf, (MV_U32 *) ctx->in); + + /* Now fill the next block with 56 bytes */ + memset(ctx->in, 0, 56); + } + else + { + /* Pad block to 56 bytes */ + memset(p, 0, count - 8); + } + mvByteReverse(ctx->in, 14); + + /* Append length in bits and transform */ + ((MV_U32 *) ctx->in)[14] = ctx->bits[0]; + ((MV_U32 *) ctx->in)[15] = ctx->bits[1]; + + mvMD5Transform(ctx->buf, (MV_U32 *) ctx->in); + mvByteReverse((unsigned char *) ctx->buf, 4); + memcpy(digest, ctx->buf, MV_MD5_MAC_LEN); + memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */ +} + +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f, w, x, y, z, data, s) \ + ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +static void mvMD5Transform(MV_U32 buf[4], MV_U32 const in[MV_MD5_MAC_LEN]) +{ + register MV_U32 a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +void mvMD5(unsigned char const *buf, unsigned len, unsigned char* digest) +{ + MV_MD5_CONTEXT ctx; + + mvMD5Init(&ctx); + mvMD5Update(&ctx, buf, len); + mvMD5Final(digest, &ctx); +} + + +void mvHmacMd5(unsigned char const* text, int text_len, + unsigned char const* key, int key_len, + unsigned char* digest) +{ + int i; + MV_MD5_CONTEXT ctx; + unsigned char k_ipad[64+1]; /* inner padding - key XORd with ipad */ + unsigned char k_opad[64+1]; /* outer padding - key XORd with opad */ + + /* start out by storing key in pads */ + memset(k_ipad, 0, 64); + memcpy(k_ipad, key, key_len); + memset(k_opad, 0, 64); + memcpy(k_opad, key, key_len); + + /* XOR key with ipad and opad values */ + for (i=0; i<64; i++) + { + k_ipad[i] ^= 0x36; + k_opad[i] ^= 0x5c; + } + + /* perform inner MD5 */ + mvMD5Init(&ctx); /* init ctx for 1st pass */ + mvMD5Update(&ctx, k_ipad, 64); /* start with inner pad */ + mvMD5Update(&ctx, text, text_len); /* then text of datagram */ + mvMD5Final(digest, &ctx); /* finish up 1st pass */ + + /* perform outer MD5 */ + mvMD5Init(&ctx); /* init ctx for 2nd pass */ + mvMD5Update(&ctx, k_opad, 64); /* start with outer pad */ + mvMD5Update(&ctx, digest, 16); /* then results of 1st hash */ + mvMD5Final(digest, &ctx); /* finish up 2nd pass */ +} diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/cesa/mvMD5.h b/target/linux/generic/files/crypto/ocf/kirkwood/cesa/mvMD5.h new file mode 100644 index 0000000..d05c6b6 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/cesa/mvMD5.h @@ -0,0 +1,93 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#ifndef __mvMD5_h__ +#define __mvMD5_h__ + +#include "mvMD5.h" + +#define MV_MD5_MAC_LEN 16 + + +typedef struct +{ + MV_U32 buf[4]; + MV_U32 bits[2]; + MV_U8 in[64]; + +} MV_MD5_CONTEXT; + +void mvMD5Init(MV_MD5_CONTEXT *context); +void mvMD5Update(MV_MD5_CONTEXT *context, unsigned char const *buf, + unsigned len); +void mvMD5Final(unsigned char digest[16], MV_MD5_CONTEXT *context); + +void mvMD5(unsigned char const *buf, unsigned len, unsigned char* digest); + +void mvHmacMd5(unsigned char const* text, int text_len, + unsigned char const* key, int key_len, + unsigned char* digest); + + +#endif /* __mvMD5_h__ */ diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/cesa/mvSHA1.c b/target/linux/generic/files/crypto/ocf/kirkwood/cesa/mvSHA1.c new file mode 100644 index 0000000..0e0786b --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/cesa/mvSHA1.c @@ -0,0 +1,239 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#include "mvOs.h" +#include "mvSHA1.h" + +#define SHA1HANDSOFF + +typedef union +{ + MV_U8 c[64]; + MV_U32 l[16]; + +} CHAR64LONG16; + +static void mvSHA1Transform(MV_U32 state[5], const MV_U8 *buffer); + +#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) + + +#ifdef MV_CPU_LE +#define blk0(i) (block->l[i] = (rol(block->l[i], 24) & 0xFF00FF00) | \ + (rol(block->l[i], 8) & 0x00FF00FF)) +#else +#define blk0(i) block->l[i] +#endif +#define blk(i) (block->l[i & 15] = rol(block->l[(i + 13) & 15] ^ \ + block->l[(i + 8) & 15] ^ block->l[(i + 2) & 15] ^ block->l[i & 15], 1)) + +/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ +#define R0(v,w,x,y,z,i) \ + z += ((w & (x ^ y)) ^ y) + blk0(i) + 0x5A827999 + rol(v, 5); \ + w = rol(w, 30); +#define R1(v,w,x,y,z,i) \ + z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); \ + w = rol(w, 30); +#define R2(v,w,x,y,z,i) \ + z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); w = rol(w, 30); +#define R3(v,w,x,y,z,i) \ + z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); \ + w = rol(w, 30); +#define R4(v,w,x,y,z,i) \ + z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); \ + w=rol(w, 30); + +/* Hash a single 512-bit block. This is the core of the algorithm. */ +static void mvSHA1Transform(MV_U32 state[5], const MV_U8 *buffer) +{ + MV_U32 a, b, c, d, e; + CHAR64LONG16* block; + +#ifdef SHA1HANDSOFF + static MV_U32 workspace[16]; + + block = (CHAR64LONG16 *) workspace; + memcpy(block, buffer, 64); +#else + block = (CHAR64LONG16 *) buffer; +#endif + /* Copy context->state[] to working vars */ + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + /* 4 rounds of 20 operations each. Loop unrolled. */ + R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); + R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); + R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); + R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); + R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); + R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); + R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); + R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); + R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); + R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); + R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); + R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); + R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); + R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); + R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); + R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); + R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); + R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); + R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); + R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); + /* Add the working vars back into context.state[] */ + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + /* Wipe variables */ + a = b = c = d = e = 0; +} + +void mvSHA1Init(MV_SHA1_CTX* context) +{ + /* SHA1 initialization constants */ + context->state[0] = 0x67452301; + context->state[1] = 0xEFCDAB89; + context->state[2] = 0x98BADCFE; + context->state[3] = 0x10325476; + context->state[4] = 0xC3D2E1F0; + context->count[0] = context->count[1] = 0; +} + + +/* Run your data through this. */ +void mvSHA1Update(MV_SHA1_CTX *context, MV_U8 const *data, + unsigned int len) +{ + MV_U32 i, j; + + j = (context->count[0] >> 3) & 63; + if ((context->count[0] += len << 3) < (len << 3)) + context->count[1]++; + context->count[1] += (len >> 29); + if ((j + len) > 63) + { + memcpy(&context->buffer[j], data, (i = 64-j)); + mvSHA1Transform(context->state, context->buffer); + for ( ; i + 63 < len; i += 64) + { + mvSHA1Transform(context->state, &data[i]); + } + j = 0; + } + else + { + i = 0; + } + memcpy(&context->buffer[j], &data[i], len - i); +} + +void mvSHA1Final(MV_U8* digest, MV_SHA1_CTX* context) +{ + MV_U32 i; + MV_U8 finalcount[8]; + + for (i = 0; i < 8; i++) + { + finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)] >> + ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ + } + mvSHA1Update(context, (const unsigned char *) "\200", 1); + while ((context->count[0] & 504) != 448) + { + mvSHA1Update(context, (const unsigned char *) "\0", 1); + } + mvSHA1Update(context, finalcount, 8); /* Should cause a mvSHA1Transform() + */ + for (i = 0; i < 20; i++) + { + digest[i] = (unsigned char) + ((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255); + } + /* Wipe variables */ + i = 0; + memset(context->buffer, 0, 64); + memset(context->state, 0, 20); + memset(context->count, 0, 8); + memset(finalcount, 0, 8); + +#ifdef SHA1HANDSOFF /* make SHA1Transform overwrite it's own static vars */ + mvSHA1Transform(context->state, context->buffer); +#endif +} + + +void mvSHA1(MV_U8 const *buf, unsigned int len, MV_U8* digest) +{ + MV_SHA1_CTX ctx; + + mvSHA1Init(&ctx); + mvSHA1Update(&ctx, buf, len); + mvSHA1Final(digest, &ctx); +} diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/cesa/mvSHA1.h b/target/linux/generic/files/crypto/ocf/kirkwood/cesa/mvSHA1.h new file mode 100644 index 0000000..17df9fc --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/cesa/mvSHA1.h @@ -0,0 +1,88 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#ifndef __mvSHA1_h__ +#define __mvSHA1_h__ + +#include "mvSHA1.h" + +#define MV_SHA1_MAC_LEN 20 + + +typedef struct +{ + MV_U32 state[5]; + MV_U32 count[2]; + MV_U8 buffer[64]; + +} MV_SHA1_CTX; + +void mvSHA1Init(MV_SHA1_CTX *context); +void mvSHA1Update(MV_SHA1_CTX *context, MV_U8 const *buf, unsigned int len); +void mvSHA1Final(MV_U8* digest, MV_SHA1_CTX *context); + +void mvSHA1(MV_U8 const *buf, unsigned int len, MV_U8* digest); + + +#endif /* __mvSHA1_h__ */ diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/cesa_ocf_drv.c b/target/linux/generic/files/crypto/ocf/kirkwood/cesa_ocf_drv.c new file mode 100644 index 0000000..6fb9e09 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/cesa_ocf_drv.c @@ -0,0 +1,1302 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +*******************************************************************************/ + +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) && !defined(AUTOCONF_INCLUDED) +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ctrlEnv/sys/mvSysCesa.h" +#include "cesa/mvCesa.h" /* moved here before cryptodev.h due to include dependencies */ +#include +#include +#include +#include +#include "mvDebug.h" + +#include "cesa/mvMD5.h" +#include "cesa/mvSHA1.h" + +#include "cesa/mvCesaRegs.h" +#include "cesa/AES/mvAes.h" +#include "cesa/mvLru.h" + +#undef RT_DEBUG +#ifdef RT_DEBUG +static int debug = 1; +module_param(debug, int, 1); +MODULE_PARM_DESC(debug, "Enable debug"); +#undef dprintk +#define dprintk(a...) if (debug) { printk(a); } else +#else +static int debug = 0; +#undef dprintk +#define dprintk(a...) +#endif + + +/* TDMA Regs */ +#define WINDOW_BASE(i) 0xA00 + (i << 3) +#define WINDOW_CTRL(i) 0xA04 + (i << 3) + +/* interrupt handling */ +#undef CESA_OCF_POLLING +#undef CESA_OCF_TASKLET + +#if defined(CESA_OCF_POLLING) && defined(CESA_OCF_TASKLET) +#error "don't use both tasklet and polling mode" +#endif + +extern int cesaReqResources; +/* support for spliting action into 2 actions */ +#define CESA_OCF_SPLIT + +/* general defines */ +#define CESA_OCF_MAX_SES 128 +#define CESA_Q_SIZE 64 + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0) +#define FRAG_PAGE(f) (f).p +#else +#define FRAG_PAGE(f) (f) +#endif + +/* data structures */ +struct cesa_ocf_data { + int cipher_alg; + int auth_alg; + int encrypt_tn_auth; +#define auth_tn_decrypt encrypt_tn_auth + int ivlen; + int digestlen; + short sid_encrypt; + short sid_decrypt; + /* fragment workaround sessions */ + short frag_wa_encrypt; + short frag_wa_decrypt; + short frag_wa_auth; +}; + +/* CESA device data */ +struct cesa_dev { + void __iomem *sram; + void __iomem *reg; + struct mv_cesa_platform_data *plat_data; + int irq; +}; + +#define DIGEST_BUF_SIZE 32 +struct cesa_ocf_process { + MV_CESA_COMMAND cesa_cmd; + MV_CESA_MBUF cesa_mbuf; + MV_BUF_INFO cesa_bufs[MV_CESA_MAX_MBUF_FRAGS]; + char digest[DIGEST_BUF_SIZE]; + int digest_len; + struct cryptop *crp; + int need_cb; +}; + +/* global variables */ +static int32_t cesa_ocf_id = -1; +static struct cesa_ocf_data *cesa_ocf_sessions[CESA_OCF_MAX_SES]; +static spinlock_t cesa_lock; +static struct cesa_dev cesa_device; + +/* static APIs */ +static int cesa_ocf_process (device_t, struct cryptop *, int); +static int cesa_ocf_newsession (device_t, u_int32_t *, struct cryptoini *); +static int cesa_ocf_freesession (device_t, u_int64_t); +static void cesa_callback (unsigned long); +static irqreturn_t cesa_interrupt_handler (int, void *); +#ifdef CESA_OCF_POLLING +static void cesa_interrupt_polling(void); +#endif +#ifdef CESA_OCF_TASKLET +static struct tasklet_struct cesa_ocf_tasklet; +#endif + +static struct timeval tt_start; +static struct timeval tt_end; + +/* + * dummy device structure + */ + +static struct { + softc_device_decl sc_dev; +} mv_cesa_dev; + +static device_method_t mv_cesa_methods = { + /* crypto device methods */ + DEVMETHOD(cryptodev_newsession, cesa_ocf_newsession), + DEVMETHOD(cryptodev_freesession,cesa_ocf_freesession), + DEVMETHOD(cryptodev_process, cesa_ocf_process), + DEVMETHOD(cryptodev_kprocess, NULL), +}; + + + +/* Add debug Trace */ +#undef CESA_OCF_TRACE_DEBUG +#ifdef CESA_OCF_TRACE_DEBUG + +#define MV_CESA_USE_TIMER_ID 0 + +typedef struct +{ + int type; /* 0 - isrEmpty, 1 - cesaReadyGet, 2 - cesaAction */ + MV_U32 timeStamp; + MV_U32 cause; + MV_U32 realCause; + MV_U32 dmaCause; + int resources; + MV_CESA_REQ* pReqReady; + MV_CESA_REQ* pReqEmpty; + MV_CESA_REQ* pReqProcess; +} MV_CESA_TEST_TRACE; + +#define MV_CESA_TEST_TRACE_SIZE 50 + +static int cesaTestTraceIdx = 0; +static MV_CESA_TEST_TRACE cesaTestTrace[MV_CESA_TEST_TRACE_SIZE]; + +static void cesaTestTraceAdd(int type) +{ + cesaTestTrace[cesaTestTraceIdx].type = type; + cesaTestTrace[cesaTestTraceIdx].realCause = MV_REG_READ(MV_CESA_ISR_CAUSE_REG); + //cesaTestTrace[cesaTestTraceIdx].idmaCause = MV_REG_READ(IDMA_CAUSE_REG); + cesaTestTrace[cesaTestTraceIdx].resources = cesaReqResources; + cesaTestTrace[cesaTestTraceIdx].pReqReady = pCesaReqReady; + cesaTestTrace[cesaTestTraceIdx].pReqEmpty = pCesaReqEmpty; + cesaTestTrace[cesaTestTraceIdx].pReqProcess = pCesaReqProcess; + cesaTestTrace[cesaTestTraceIdx].timeStamp = mvCntmrRead(MV_CESA_USE_TIMER_ID); + cesaTestTraceIdx++; + if(cesaTestTraceIdx == MV_CESA_TEST_TRACE_SIZE) + cesaTestTraceIdx = 0; +} + +#else /* CESA_OCF_TRACE_DEBUG */ + +#define cesaTestTraceAdd(x) + +#endif /* CESA_OCF_TRACE_DEBUG */ + +unsigned int +get_usec(unsigned int start) +{ + if(start) { + do_gettimeofday (&tt_start); + return 0; + } + else { + do_gettimeofday (&tt_end); + tt_end.tv_sec -= tt_start.tv_sec; + tt_end.tv_usec -= tt_start.tv_usec; + if (tt_end.tv_usec < 0) { + tt_end.tv_usec += 1000 * 1000; + tt_end.tv_sec -= 1; + } + } + printk("time taken is %d\n", (unsigned int)(tt_end.tv_usec + tt_end.tv_sec * 1000000)); + return (tt_end.tv_usec + tt_end.tv_sec * 1000000); +} + +#ifdef RT_DEBUG +/* + * check that the crp action match the current session + */ +static int +ocf_check_action(struct cryptop *crp, struct cesa_ocf_data *cesa_ocf_cur_ses) { + int count = 0; + int encrypt = 0, decrypt = 0, auth = 0; + struct cryptodesc *crd; + + /* Go through crypto descriptors, processing as we go */ + for (crd = crp->crp_desc; crd; crd = crd->crd_next, count++) { + if(count > 2) { + printk("%s,%d: session mode is not supported.\n", __FILE__, __LINE__); + return 1; + } + + /* Encryption /Decryption */ + if(crd->crd_alg == cesa_ocf_cur_ses->cipher_alg) { + /* check that the action is compatible with session */ + if(encrypt || decrypt) { + printk("%s,%d: session mode is not supported.\n", __FILE__, __LINE__); + return 1; + } + + if(crd->crd_flags & CRD_F_ENCRYPT) { /* encrypt */ + if( (count == 2) && (cesa_ocf_cur_ses->encrypt_tn_auth) ) { + printk("%s,%d: sequence isn't supported by this session.\n", __FILE__, __LINE__); + return 1; + } + encrypt++; + } + else { /* decrypt */ + if( (count == 2) && !(cesa_ocf_cur_ses->auth_tn_decrypt) ) { + printk("%s,%d: sequence isn't supported by this session.\n", __FILE__, __LINE__); + return 1; + } + decrypt++; + } + + } + /* Authentication */ + else if(crd->crd_alg == cesa_ocf_cur_ses->auth_alg) { + /* check that the action is compatible with session */ + if(auth) { + printk("%s,%d: session mode is not supported.\n", __FILE__, __LINE__); + return 1; + } + if( (count == 2) && (decrypt) && (cesa_ocf_cur_ses->auth_tn_decrypt)) { + printk("%s,%d: sequence isn't supported by this session.\n", __FILE__, __LINE__); + return 1; + } + if( (count == 2) && (encrypt) && !(cesa_ocf_cur_ses->encrypt_tn_auth)) { + printk("%s,%d: sequence isn't supported by this session.\n", __FILE__, __LINE__); + return 1; + } + auth++; + } + else { + printk("%s,%d: Alg isn't supported by this session.\n", __FILE__, __LINE__); + return 1; + } + } + return 0; + +} +#endif + +/* + * Process a request. + */ +static int +cesa_ocf_process(device_t dev, struct cryptop *crp, int hint) +{ + struct cesa_ocf_process *cesa_ocf_cmd = NULL; + struct cesa_ocf_process *cesa_ocf_cmd_wa = NULL; + MV_CESA_COMMAND *cesa_cmd; + struct cryptodesc *crd; + struct cesa_ocf_data *cesa_ocf_cur_ses; + int sid = 0, temp_len = 0, i; + int encrypt = 0, decrypt = 0, auth = 0; + int status; + struct sk_buff *skb = NULL; + struct uio *uiop = NULL; + unsigned char *ivp; + MV_BUF_INFO *p_buf_info; + MV_CESA_MBUF *p_mbuf_info; + unsigned long flags; + + dprintk("%s()\n", __FUNCTION__); + + if( cesaReqResources <= 1 ) { + dprintk("%s,%d: ERESTART\n", __FILE__, __LINE__); + return ERESTART; + } + +#ifdef RT_DEBUG + /* Sanity check */ + if (crp == NULL) { + printk("%s,%d: EINVAL\n", __FILE__, __LINE__); + return EINVAL; + } + + if (crp->crp_desc == NULL || crp->crp_buf == NULL ) { + printk("%s,%d: EINVAL\n", __FILE__, __LINE__); + crp->crp_etype = EINVAL; + return EINVAL; + } + + sid = crp->crp_sid & 0xffffffff; + if ((sid >= CESA_OCF_MAX_SES) || (cesa_ocf_sessions[sid] == NULL)) { + crp->crp_etype = ENOENT; + printk("%s,%d: ENOENT session %d \n", __FILE__, __LINE__, sid); + return EINVAL; + } +#endif + + sid = crp->crp_sid & 0xffffffff; + crp->crp_etype = 0; + cesa_ocf_cur_ses = cesa_ocf_sessions[sid]; + +#ifdef RT_DEBUG + if(ocf_check_action(crp, cesa_ocf_cur_ses)){ + goto p_error; + } +#endif + + /* malloc a new cesa process */ + cesa_ocf_cmd = kmalloc(sizeof(struct cesa_ocf_process), GFP_ATOMIC); + + if (cesa_ocf_cmd == NULL) { + printk("%s,%d: ENOBUFS \n", __FILE__, __LINE__); + goto p_error; + } + memset(cesa_ocf_cmd, 0, sizeof(struct cesa_ocf_process)); + + /* init cesa_process */ + cesa_ocf_cmd->crp = crp; + /* always call callback */ + cesa_ocf_cmd->need_cb = 1; + + /* init cesa_cmd for usage of the HALs */ + cesa_cmd = &cesa_ocf_cmd->cesa_cmd; + cesa_cmd->pReqPrv = (void *)cesa_ocf_cmd; + cesa_cmd->sessionId = cesa_ocf_cur_ses->sid_encrypt; /* defualt use encrypt */ + + /* prepare src buffer */ + /* we send the entire buffer to the HAL, even if only part of it should be encrypt/auth. */ + /* if not using seesions for both encrypt and auth, then it will be wiser to to copy only */ + /* from skip to crd_len. */ + p_buf_info = cesa_ocf_cmd->cesa_bufs; + p_mbuf_info = &cesa_ocf_cmd->cesa_mbuf; + + p_buf_info += 2; /* save 2 first buffers for IV and digest - + we won't append them to the end since, they + might be places in an unaligned addresses. */ + + p_mbuf_info->pFrags = p_buf_info; + temp_len = 0; + + /* handle SKB */ + if (crp->crp_flags & CRYPTO_F_SKBUF) { + + dprintk("%s,%d: handle SKB.\n", __FILE__, __LINE__); + skb = (struct sk_buff *) crp->crp_buf; + + if (skb_shinfo(skb)->nr_frags >= (MV_CESA_MAX_MBUF_FRAGS - 1)) { + printk("%s,%d: %d nr_frags > MV_CESA_MAX_MBUF_FRAGS", __FILE__, __LINE__, skb_shinfo(skb)->nr_frags); + goto p_error; + } + + p_mbuf_info->mbufSize = skb->len; + temp_len = skb->len; + /* first skb fragment */ + p_buf_info->bufSize = skb_headlen(skb); + p_buf_info->bufVirtPtr = skb->data; + p_buf_info++; + + /* now handle all other skb fragments */ + for ( i = 0; i < skb_shinfo(skb)->nr_frags; i++ ) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + p_buf_info->bufSize = frag->size; + p_buf_info->bufVirtPtr = page_address(FRAG_PAGE(frag->page)) + frag->page_offset; + p_buf_info++; + } + p_mbuf_info->numFrags = skb_shinfo(skb)->nr_frags + 1; + } + /* handle UIO */ + else if(crp->crp_flags & CRYPTO_F_IOV) { + + dprintk("%s,%d: handle UIO.\n", __FILE__, __LINE__); + uiop = (struct uio *) crp->crp_buf; + + if (uiop->uio_iovcnt > (MV_CESA_MAX_MBUF_FRAGS - 1)) { + printk("%s,%d: %d uio_iovcnt > MV_CESA_MAX_MBUF_FRAGS \n", __FILE__, __LINE__, uiop->uio_iovcnt); + goto p_error; + } + + p_mbuf_info->mbufSize = crp->crp_ilen; + p_mbuf_info->numFrags = uiop->uio_iovcnt; + for(i = 0; i < uiop->uio_iovcnt; i++) { + p_buf_info->bufVirtPtr = uiop->uio_iov[i].iov_base; + p_buf_info->bufSize = uiop->uio_iov[i].iov_len; + temp_len += p_buf_info->bufSize; + dprintk("%s,%d: buf %x-> addr %x, size %x \n" + , __FILE__, __LINE__, i, (unsigned int)p_buf_info->bufVirtPtr, p_buf_info->bufSize); + p_buf_info++; + } + + } + /* handle CONTIG */ + else { + dprintk("%s,%d: handle CONTIG.\n", __FILE__, __LINE__); + p_mbuf_info->numFrags = 1; + p_mbuf_info->mbufSize = crp->crp_ilen; + p_buf_info->bufVirtPtr = crp->crp_buf; + p_buf_info->bufSize = crp->crp_ilen; + temp_len = crp->crp_ilen; + p_buf_info++; + } + + /* Support up to 64K why? cause! */ + if(crp->crp_ilen > 64*1024) { + printk("%s,%d: buf too big %x \n", __FILE__, __LINE__, crp->crp_ilen); + goto p_error; + } + + if( temp_len != crp->crp_ilen ) { + printk("%s,%d: warning size don't match.(%x %x) \n", __FILE__, __LINE__, temp_len, crp->crp_ilen); + } + + cesa_cmd->pSrc = p_mbuf_info; + cesa_cmd->pDst = p_mbuf_info; + + /* restore p_buf_info to point to first available buf */ + p_buf_info = cesa_ocf_cmd->cesa_bufs; + p_buf_info += 1; + + + /* Go through crypto descriptors, processing as we go */ + for (crd = crp->crp_desc; crd; crd = crd->crd_next) { + + /* Encryption /Decryption */ + if(crd->crd_alg == cesa_ocf_cur_ses->cipher_alg) { + + dprintk("%s,%d: cipher", __FILE__, __LINE__); + + cesa_cmd->cryptoOffset = crd->crd_skip; + cesa_cmd->cryptoLength = crd->crd_len; + + if(crd->crd_flags & CRD_F_ENCRYPT) { /* encrypt */ + dprintk(" encrypt \n"); + encrypt++; + + /* handle IV */ + if (crd->crd_flags & CRD_F_IV_EXPLICIT) { /* IV from USER */ + dprintk("%s,%d: IV from USER (offset %x) \n", __FILE__, __LINE__, crd->crd_inject); + cesa_cmd->ivFromUser = 1; + ivp = crd->crd_iv; + + /* + * do we have to copy the IV back to the buffer ? + */ + if ((crd->crd_flags & CRD_F_IV_PRESENT) == 0) { + dprintk("%s,%d: copy the IV back to the buffer\n", __FILE__, __LINE__); + cesa_cmd->ivOffset = crd->crd_inject; + crypto_copyback(crp->crp_flags, crp->crp_buf, crd->crd_inject, cesa_ocf_cur_ses->ivlen, ivp); + } + else { + dprintk("%s,%d: don't copy the IV back to the buffer \n", __FILE__, __LINE__); + p_mbuf_info->numFrags++; + p_mbuf_info->mbufSize += cesa_ocf_cur_ses->ivlen; + p_mbuf_info->pFrags = p_buf_info; + + p_buf_info->bufVirtPtr = ivp; + p_buf_info->bufSize = cesa_ocf_cur_ses->ivlen; + p_buf_info--; + + /* offsets */ + cesa_cmd->ivOffset = 0; + cesa_cmd->cryptoOffset += cesa_ocf_cur_ses->ivlen; + if(auth) { + cesa_cmd->macOffset += cesa_ocf_cur_ses->ivlen; + cesa_cmd->digestOffset += cesa_ocf_cur_ses->ivlen; + } + } + } + else { /* random IV */ + dprintk("%s,%d: random IV \n", __FILE__, __LINE__); + cesa_cmd->ivFromUser = 0; + + /* + * do we have to copy the IV back to the buffer ? + */ + /* in this mode the HAL will always copy the IV */ + /* given by the session to the ivOffset */ + if ((crd->crd_flags & CRD_F_IV_PRESENT) == 0) { + cesa_cmd->ivOffset = crd->crd_inject; + } + else { + /* if IV isn't copy, then how will the user know which IV did we use??? */ + printk("%s,%d: EINVAL\n", __FILE__, __LINE__); + goto p_error; + } + } + } + else { /* decrypt */ + dprintk(" decrypt \n"); + decrypt++; + cesa_cmd->sessionId = cesa_ocf_cur_ses->sid_decrypt; + + /* handle IV */ + if (crd->crd_flags & CRD_F_IV_EXPLICIT) { + dprintk("%s,%d: IV from USER \n", __FILE__, __LINE__); + /* append the IV buf to the mbuf */ + cesa_cmd->ivFromUser = 1; + p_mbuf_info->numFrags++; + p_mbuf_info->mbufSize += cesa_ocf_cur_ses->ivlen; + p_mbuf_info->pFrags = p_buf_info; + + p_buf_info->bufVirtPtr = crd->crd_iv; + p_buf_info->bufSize = cesa_ocf_cur_ses->ivlen; + p_buf_info--; + + /* offsets */ + cesa_cmd->ivOffset = 0; + cesa_cmd->cryptoOffset += cesa_ocf_cur_ses->ivlen; + if(auth) { + cesa_cmd->macOffset += cesa_ocf_cur_ses->ivlen; + cesa_cmd->digestOffset += cesa_ocf_cur_ses->ivlen; + } + } + else { + dprintk("%s,%d: IV inside the buffer \n", __FILE__, __LINE__); + cesa_cmd->ivFromUser = 0; + cesa_cmd->ivOffset = crd->crd_inject; + } + } + + } + /* Authentication */ + else if(crd->crd_alg == cesa_ocf_cur_ses->auth_alg) { + dprintk("%s,%d: Authentication \n", __FILE__, __LINE__); + auth++; + cesa_cmd->macOffset = crd->crd_skip; + cesa_cmd->macLength = crd->crd_len; + + /* digest + mac */ + cesa_cmd->digestOffset = crd->crd_inject; + } + else { + printk("%s,%d: Alg isn't supported by this session.\n", __FILE__, __LINE__); + goto p_error; + } + } + + dprintk("\n"); + dprintk("%s,%d: Sending Action: \n", __FILE__, __LINE__); + dprintk("%s,%d: IV from user: %d. IV offset %x \n", __FILE__, __LINE__, cesa_cmd->ivFromUser, cesa_cmd->ivOffset); + dprintk("%s,%d: crypt offset %x len %x \n", __FILE__, __LINE__, cesa_cmd->cryptoOffset, cesa_cmd->cryptoLength); + dprintk("%s,%d: Auth offset %x len %x \n", __FILE__, __LINE__, cesa_cmd->macOffset, cesa_cmd->macLength); + dprintk("%s,%d: set digest in offset %x . \n", __FILE__, __LINE__, cesa_cmd->digestOffset); + if(debug) { + mvCesaDebugMbuf("SRC BUFFER", cesa_cmd->pSrc, 0, cesa_cmd->pSrc->mbufSize); + } + + + /* send action to HAL */ + spin_lock_irqsave(&cesa_lock, flags); + status = mvCesaAction(cesa_cmd); + spin_unlock_irqrestore(&cesa_lock, flags); + + /* action not allowed */ + if(status == MV_NOT_ALLOWED) { +#ifdef CESA_OCF_SPLIT + /* if both encrypt and auth try to split */ + if(auth && (encrypt || decrypt)) { + MV_CESA_COMMAND *cesa_cmd_wa; + + /* malloc a new cesa process and init it */ + cesa_ocf_cmd_wa = kmalloc(sizeof(struct cesa_ocf_process), GFP_ATOMIC); + + if (cesa_ocf_cmd_wa == NULL) { + printk("%s,%d: ENOBUFS \n", __FILE__, __LINE__); + goto p_error; + } + memcpy(cesa_ocf_cmd_wa, cesa_ocf_cmd, sizeof(struct cesa_ocf_process)); + cesa_cmd_wa = &cesa_ocf_cmd_wa->cesa_cmd; + cesa_cmd_wa->pReqPrv = (void *)cesa_ocf_cmd_wa; + cesa_ocf_cmd_wa->need_cb = 0; + + /* break requests to two operation, first operation completion won't call callback */ + if((decrypt) && (cesa_ocf_cur_ses->auth_tn_decrypt)) { + cesa_cmd_wa->sessionId = cesa_ocf_cur_ses->frag_wa_auth; + cesa_cmd->sessionId = cesa_ocf_cur_ses->frag_wa_decrypt; + } + else if((decrypt) && !(cesa_ocf_cur_ses->auth_tn_decrypt)) { + cesa_cmd_wa->sessionId = cesa_ocf_cur_ses->frag_wa_decrypt; + cesa_cmd->sessionId = cesa_ocf_cur_ses->frag_wa_auth; + } + else if((encrypt) && (cesa_ocf_cur_ses->encrypt_tn_auth)) { + cesa_cmd_wa->sessionId = cesa_ocf_cur_ses->frag_wa_encrypt; + cesa_cmd->sessionId = cesa_ocf_cur_ses->frag_wa_auth; + } + else if((encrypt) && !(cesa_ocf_cur_ses->encrypt_tn_auth)){ + cesa_cmd_wa->sessionId = cesa_ocf_cur_ses->frag_wa_auth; + cesa_cmd->sessionId = cesa_ocf_cur_ses->frag_wa_encrypt; + } + else { + printk("%s,%d: Unsupporterd fragment wa mode \n", __FILE__, __LINE__); + goto p_error; + } + + /* send the 2 actions to the HAL */ + spin_lock_irqsave(&cesa_lock, flags); + status = mvCesaAction(cesa_cmd_wa); + spin_unlock_irqrestore(&cesa_lock, flags); + + if((status != MV_NO_MORE) && (status != MV_OK)) { + printk("%s,%d: cesa action failed, status = 0x%x\n", __FILE__, __LINE__, status); + goto p_error; + } + spin_lock_irqsave(&cesa_lock, flags); + status = mvCesaAction(cesa_cmd); + spin_unlock_irqrestore(&cesa_lock, flags); + + } + /* action not allowed and can't split */ + else +#endif + { + goto p_error; + } + } + + /* Hal Q is full, send again. This should never happen */ + if(status == MV_NO_RESOURCE) { + printk("%s,%d: cesa no more resources \n", __FILE__, __LINE__); + if(cesa_ocf_cmd) + kfree(cesa_ocf_cmd); + if(cesa_ocf_cmd_wa) + kfree(cesa_ocf_cmd_wa); + return ERESTART; + } + else if((status != MV_NO_MORE) && (status != MV_OK)) { + printk("%s,%d: cesa action failed, status = 0x%x\n", __FILE__, __LINE__, status); + goto p_error; + } + + +#ifdef CESA_OCF_POLLING + cesa_interrupt_polling(); +#endif + cesaTestTraceAdd(5); + + return 0; +p_error: + crp->crp_etype = EINVAL; + if(cesa_ocf_cmd) + kfree(cesa_ocf_cmd); + if(cesa_ocf_cmd_wa) + kfree(cesa_ocf_cmd_wa); + return EINVAL; +} + +/* + * cesa callback. + */ +static void +cesa_callback(unsigned long dummy) +{ + struct cesa_ocf_process *cesa_ocf_cmd = NULL; + struct cryptop *crp = NULL; + MV_CESA_RESULT result[MV_CESA_MAX_CHAN]; + int res_idx = 0,i; + MV_STATUS status; + + dprintk("%s()\n", __FUNCTION__); + +#ifdef CESA_OCF_TASKLET + disable_irq(cesa_device.irq); +#endif + while(MV_TRUE) { + + /* Get Ready requests */ + spin_lock(&cesa_lock); + status = mvCesaReadyGet(&result[res_idx]); + spin_unlock(&cesa_lock); + + cesaTestTraceAdd(2); + + if(status != MV_OK) { +#ifdef CESA_OCF_POLLING + if(status == MV_BUSY) { /* Fragment */ + cesa_interrupt_polling(); + return; + } +#endif + break; + } + res_idx++; + break; + } + + for(i = 0; i < res_idx; i++) { + + if(!result[i].pReqPrv) { + printk("%s,%d: warning private is NULL\n", __FILE__, __LINE__); + break; + } + + cesa_ocf_cmd = result[i].pReqPrv; + crp = cesa_ocf_cmd->crp; + + // ignore HMAC error. + //if(result->retCode) + // crp->crp_etype = EIO; + +#if defined(CESA_OCF_POLLING) + if(!cesa_ocf_cmd->need_cb){ + cesa_interrupt_polling(); + } +#endif + if(cesa_ocf_cmd->need_cb) { + if(debug) { + mvCesaDebugMbuf("DST BUFFER", cesa_ocf_cmd->cesa_cmd.pDst, 0, cesa_ocf_cmd->cesa_cmd.pDst->mbufSize); + } + crypto_done(crp); + } + kfree(cesa_ocf_cmd); + } +#ifdef CESA_OCF_TASKLET + enable_irq(cesa_device.irq); +#endif + + cesaTestTraceAdd(3); + + return; +} + +#ifdef CESA_OCF_POLLING +static void +cesa_interrupt_polling(void) +{ + u32 cause; + + dprintk("%s()\n", __FUNCTION__); + + /* Read cause register */ + do { + cause = MV_REG_READ(MV_CESA_ISR_CAUSE_REG); + cause &= MV_CESA_CAUSE_ACC_DMA_ALL_MASK; + + } while (cause == 0); + + /* clear interrupts */ + MV_REG_WRITE(MV_CESA_ISR_CAUSE_REG, 0); + + cesa_callback(0); + + return; +} + +#endif + +/* + * cesa Interrupt polling routine. + */ +static irqreturn_t +cesa_interrupt_handler(int irq, void *arg) +{ + u32 cause; + + dprintk("%s()\n", __FUNCTION__); + + cesaTestTraceAdd(0); + + /* Read cause register */ + cause = MV_REG_READ(MV_CESA_ISR_CAUSE_REG); + + if( (cause & MV_CESA_CAUSE_ACC_DMA_ALL_MASK) == 0) + { + /* Empty interrupt */ + dprintk("%s,%d: cesaTestReadyIsr: cause=0x%x\n", __FILE__, __LINE__, cause); + return IRQ_HANDLED; + } + + /* clear interrupts */ + MV_REG_WRITE(MV_CESA_ISR_CAUSE_REG, 0); + + cesaTestTraceAdd(1); +#ifdef CESA_OCF_TASKLET + tasklet_hi_schedule(&cesa_ocf_tasklet); +#else + cesa_callback(0); +#endif + return IRQ_HANDLED; +} + +/* + * Open a session. + */ +static int +/*cesa_ocf_newsession(void *arg, u_int32_t *sid, struct cryptoini *cri)*/ +cesa_ocf_newsession(device_t dev, u_int32_t *sid, struct cryptoini *cri) +{ + u32 status = 0, i; + u32 count = 0, auth = 0, encrypt =0; + struct cesa_ocf_data *cesa_ocf_cur_ses; + MV_CESA_OPEN_SESSION cesa_session; + MV_CESA_OPEN_SESSION *cesa_ses = &cesa_session; + + + dprintk("%s()\n", __FUNCTION__); + if (sid == NULL || cri == NULL) { + printk("%s,%d: EINVAL\n", __FILE__, __LINE__); + return EINVAL; + } + + /* leave first empty like in other implementations */ + for (i = 1; i < CESA_OCF_MAX_SES; i++) { + if (cesa_ocf_sessions[i] == NULL) + break; + } + + if(i >= CESA_OCF_MAX_SES) { + printk("%s,%d: no more sessions \n", __FILE__, __LINE__); + return EINVAL; + } + + cesa_ocf_sessions[i] = (struct cesa_ocf_data *) kmalloc(sizeof(struct cesa_ocf_data), GFP_ATOMIC); + if (cesa_ocf_sessions[i] == NULL) { + cesa_ocf_freesession(NULL, i); + printk("%s,%d: ENOBUFS \n", __FILE__, __LINE__); + return ENOBUFS; + } + dprintk("%s,%d: new session %d \n", __FILE__, __LINE__, i); + + *sid = i; + cesa_ocf_cur_ses = cesa_ocf_sessions[i]; + memset(cesa_ocf_cur_ses, 0, sizeof(struct cesa_ocf_data)); + cesa_ocf_cur_ses->sid_encrypt = -1; + cesa_ocf_cur_ses->sid_decrypt = -1; + cesa_ocf_cur_ses->frag_wa_encrypt = -1; + cesa_ocf_cur_ses->frag_wa_decrypt = -1; + cesa_ocf_cur_ses->frag_wa_auth = -1; + + /* init the session */ + memset(cesa_ses, 0, sizeof(MV_CESA_OPEN_SESSION)); + count = 1; + while (cri) { + if(count > 2) { + printk("%s,%d: don't support more then 2 operations\n", __FILE__, __LINE__); + goto error; + } + switch (cri->cri_alg) { + case CRYPTO_AES_CBC: + dprintk("%s,%d: (%d) AES CBC \n", __FILE__, __LINE__, count); + cesa_ocf_cur_ses->cipher_alg = cri->cri_alg; + cesa_ocf_cur_ses->ivlen = MV_CESA_AES_BLOCK_SIZE; + cesa_ses->cryptoAlgorithm = MV_CESA_CRYPTO_AES; + cesa_ses->cryptoMode = MV_CESA_CRYPTO_CBC; + if(cri->cri_klen/8 > MV_CESA_MAX_CRYPTO_KEY_LENGTH) { + printk("%s,%d: CRYPTO key too long.\n", __FILE__, __LINE__); + goto error; + } + memcpy(cesa_ses->cryptoKey, cri->cri_key, cri->cri_klen/8); + dprintk("%s,%d: key length %d \n", __FILE__, __LINE__, cri->cri_klen/8); + cesa_ses->cryptoKeyLength = cri->cri_klen/8; + encrypt += count; + break; + case CRYPTO_3DES_CBC: + dprintk("%s,%d: (%d) 3DES CBC \n", __FILE__, __LINE__, count); + cesa_ocf_cur_ses->cipher_alg = cri->cri_alg; + cesa_ocf_cur_ses->ivlen = MV_CESA_3DES_BLOCK_SIZE; + cesa_ses->cryptoAlgorithm = MV_CESA_CRYPTO_3DES; + cesa_ses->cryptoMode = MV_CESA_CRYPTO_CBC; + if(cri->cri_klen/8 > MV_CESA_MAX_CRYPTO_KEY_LENGTH) { + printk("%s,%d: CRYPTO key too long.\n", __FILE__, __LINE__); + goto error; + } + memcpy(cesa_ses->cryptoKey, cri->cri_key, cri->cri_klen/8); + cesa_ses->cryptoKeyLength = cri->cri_klen/8; + encrypt += count; + break; + case CRYPTO_DES_CBC: + dprintk("%s,%d: (%d) DES CBC \n", __FILE__, __LINE__, count); + cesa_ocf_cur_ses->cipher_alg = cri->cri_alg; + cesa_ocf_cur_ses->ivlen = MV_CESA_DES_BLOCK_SIZE; + cesa_ses->cryptoAlgorithm = MV_CESA_CRYPTO_DES; + cesa_ses->cryptoMode = MV_CESA_CRYPTO_CBC; + if(cri->cri_klen/8 > MV_CESA_MAX_CRYPTO_KEY_LENGTH) { + printk("%s,%d: CRYPTO key too long.\n", __FILE__, __LINE__); + goto error; + } + memcpy(cesa_ses->cryptoKey, cri->cri_key, cri->cri_klen/8); + cesa_ses->cryptoKeyLength = cri->cri_klen/8; + encrypt += count; + break; + case CRYPTO_MD5: + case CRYPTO_MD5_HMAC: + dprintk("%s,%d: (%d) %sMD5 CBC \n", __FILE__, __LINE__, count, (cri->cri_alg != CRYPTO_MD5)? "H-":" "); + cesa_ocf_cur_ses->auth_alg = cri->cri_alg; + cesa_ocf_cur_ses->digestlen = (cri->cri_alg == CRYPTO_MD5)? MV_CESA_MD5_DIGEST_SIZE : 12; + cesa_ses->macMode = (cri->cri_alg == CRYPTO_MD5)? MV_CESA_MAC_MD5 : MV_CESA_MAC_HMAC_MD5; + if(cri->cri_klen/8 > MV_CESA_MAX_CRYPTO_KEY_LENGTH) { + printk("%s,%d: MAC key too long. \n", __FILE__, __LINE__); + goto error; + } + cesa_ses->macKeyLength = cri->cri_klen/8; + memcpy(cesa_ses->macKey, cri->cri_key, cri->cri_klen/8); + cesa_ses->digestSize = cesa_ocf_cur_ses->digestlen; + auth += count; + break; + case CRYPTO_SHA1: + case CRYPTO_SHA1_HMAC: + dprintk("%s,%d: (%d) %sSHA1 CBC \n", __FILE__, __LINE__, count, (cri->cri_alg != CRYPTO_SHA1)? "H-":" "); + cesa_ocf_cur_ses->auth_alg = cri->cri_alg; + cesa_ocf_cur_ses->digestlen = (cri->cri_alg == CRYPTO_SHA1)? MV_CESA_SHA1_DIGEST_SIZE : 12; + cesa_ses->macMode = (cri->cri_alg == CRYPTO_SHA1)? MV_CESA_MAC_SHA1 : MV_CESA_MAC_HMAC_SHA1; + if(cri->cri_klen/8 > MV_CESA_MAX_CRYPTO_KEY_LENGTH) { + printk("%s,%d: MAC key too long. \n", __FILE__, __LINE__); + goto error; + } + cesa_ses->macKeyLength = cri->cri_klen/8; + memcpy(cesa_ses->macKey, cri->cri_key, cri->cri_klen/8); + cesa_ses->digestSize = cesa_ocf_cur_ses->digestlen; + auth += count; + break; + default: + printk("%s,%d: unknown algo 0x%x\n", __FILE__, __LINE__, cri->cri_alg); + goto error; + } + cri = cri->cri_next; + count++; + } + + if((encrypt > 2) || (auth > 2)) { + printk("%s,%d: session mode is not supported.\n", __FILE__, __LINE__); + goto error; + } + /* create new sessions in HAL */ + if(encrypt) { + cesa_ses->operation = MV_CESA_CRYPTO_ONLY; + /* encrypt session */ + if(auth == 1) { + cesa_ses->operation = MV_CESA_MAC_THEN_CRYPTO; + } + else if(auth == 2) { + cesa_ses->operation = MV_CESA_CRYPTO_THEN_MAC; + cesa_ocf_cur_ses->encrypt_tn_auth = 1; + } + else { + cesa_ses->operation = MV_CESA_CRYPTO_ONLY; + } + cesa_ses->direction = MV_CESA_DIR_ENCODE; + status = mvCesaSessionOpen(cesa_ses, &cesa_ocf_cur_ses->sid_encrypt); + if(status != MV_OK) { + printk("%s,%d: Can't open new session - status = 0x%x\n", __FILE__, __LINE__, status); + goto error; + } + /* decrypt session */ + if( cesa_ses->operation == MV_CESA_MAC_THEN_CRYPTO ) { + cesa_ses->operation = MV_CESA_CRYPTO_THEN_MAC; + } + else if( cesa_ses->operation == MV_CESA_CRYPTO_THEN_MAC ) { + cesa_ses->operation = MV_CESA_MAC_THEN_CRYPTO; + } + cesa_ses->direction = MV_CESA_DIR_DECODE; + status = mvCesaSessionOpen(cesa_ses, &cesa_ocf_cur_ses->sid_decrypt); + if(status != MV_OK) { + printk("%s,%d: Can't open new session - status = 0x%x\n", __FILE__, __LINE__, status); + goto error; + } + + /* preapre one action sessions for case we will need to split an action */ +#ifdef CESA_OCF_SPLIT + if(( cesa_ses->operation == MV_CESA_MAC_THEN_CRYPTO ) || + ( cesa_ses->operation == MV_CESA_CRYPTO_THEN_MAC )) { + /* open one session for encode and one for decode */ + cesa_ses->operation = MV_CESA_CRYPTO_ONLY; + cesa_ses->direction = MV_CESA_DIR_ENCODE; + status = mvCesaSessionOpen(cesa_ses, &cesa_ocf_cur_ses->frag_wa_encrypt); + if(status != MV_OK) { + printk("%s,%d: Can't open new session - status = 0x%x\n", __FILE__, __LINE__, status); + goto error; + } + + cesa_ses->direction = MV_CESA_DIR_DECODE; + status = mvCesaSessionOpen(cesa_ses, &cesa_ocf_cur_ses->frag_wa_decrypt); + if(status != MV_OK) { + printk("%s,%d: Can't open new session - status = 0x%x\n", __FILE__, __LINE__, status); + goto error; + } + /* open one session for auth */ + cesa_ses->operation = MV_CESA_MAC_ONLY; + cesa_ses->direction = MV_CESA_DIR_ENCODE; + status = mvCesaSessionOpen(cesa_ses, &cesa_ocf_cur_ses->frag_wa_auth); + if(status != MV_OK) { + printk("%s,%d: Can't open new session - status = 0x%x\n", __FILE__, __LINE__, status); + goto error; + } + } +#endif + } + else { /* only auth */ + cesa_ses->operation = MV_CESA_MAC_ONLY; + cesa_ses->direction = MV_CESA_DIR_ENCODE; + status = mvCesaSessionOpen(cesa_ses, &cesa_ocf_cur_ses->sid_encrypt); + if(status != MV_OK) { + printk("%s,%d: Can't open new session - status = 0x%x\n", __FILE__, __LINE__, status); + goto error; + } + } + + return 0; +error: + cesa_ocf_freesession(NULL, *sid); + return EINVAL; + +} + + +/* + * Free a session. + */ +static int +cesa_ocf_freesession(device_t dev, u_int64_t tid) +{ + struct cesa_ocf_data *cesa_ocf_cur_ses; + u_int32_t sid = CRYPTO_SESID2LID(tid); + //unsigned long flags; + + dprintk("%s() %d \n", __FUNCTION__, sid); + if ( (sid >= CESA_OCF_MAX_SES) || (cesa_ocf_sessions[sid] == NULL) ) { + printk("%s,%d: EINVAL can't free session %d \n", __FILE__, __LINE__, sid); + return(EINVAL); + } + + /* Silently accept and return */ + if (sid == 0) + return(0); + + /* release session from HAL */ + cesa_ocf_cur_ses = cesa_ocf_sessions[sid]; + if (cesa_ocf_cur_ses->sid_encrypt != -1) { + mvCesaSessionClose(cesa_ocf_cur_ses->sid_encrypt); + } + if (cesa_ocf_cur_ses->sid_decrypt != -1) { + mvCesaSessionClose(cesa_ocf_cur_ses->sid_decrypt); + } + if (cesa_ocf_cur_ses->frag_wa_encrypt != -1) { + mvCesaSessionClose(cesa_ocf_cur_ses->frag_wa_encrypt); + } + if (cesa_ocf_cur_ses->frag_wa_decrypt != -1) { + mvCesaSessionClose(cesa_ocf_cur_ses->frag_wa_decrypt); + } + if (cesa_ocf_cur_ses->frag_wa_auth != -1) { + mvCesaSessionClose(cesa_ocf_cur_ses->frag_wa_auth); + } + + kfree(cesa_ocf_cur_ses); + cesa_ocf_sessions[sid] = NULL; + + return 0; +} + + +/* TDMA Window setup */ + +static void __init +setup_tdma_mbus_windows(struct cesa_dev *dev) +{ + int i; + + for (i = 0; i < 4; i++) { + writel(0, dev->reg + WINDOW_BASE(i)); + writel(0, dev->reg + WINDOW_CTRL(i)); + } + + for (i = 0; i < dev->plat_data->dram->num_cs; i++) { + struct mbus_dram_window *cs = dev->plat_data->dram->cs + i; + writel( + ((cs->size - 1) & 0xffff0000) | + (cs->mbus_attr << 8) | + (dev->plat_data->dram->mbus_dram_target_id << 4) | 1, + dev->reg + WINDOW_CTRL(i) + ); + writel(cs->base, dev->reg + WINDOW_BASE(i)); + } +} + +/* + * our driver startup and shutdown routines + */ +static int +mv_cesa_ocf_init(struct platform_device *pdev) +{ +#if defined(CONFIG_MV78200) || defined(CONFIG_MV632X) + if (MV_FALSE == mvSocUnitIsMappedToThisCpu(CESA)) + { + dprintk("CESA is not mapped to this CPU\n"); + return -ENODEV; + } +#endif + + dprintk("%s\n", __FUNCTION__); + memset(&mv_cesa_dev, 0, sizeof(mv_cesa_dev)); + softc_device_init(&mv_cesa_dev, "MV CESA", 0, mv_cesa_methods); + cesa_ocf_id = crypto_get_driverid(softc_get_device(&mv_cesa_dev),CRYPTOCAP_F_HARDWARE); + + if (cesa_ocf_id < 0) + panic("MV CESA crypto device cannot initialize!"); + + dprintk("%s,%d: cesa ocf device id is %d \n", __FILE__, __LINE__, cesa_ocf_id); + + /* CESA unit is auto power on off */ +#if 0 + if (MV_FALSE == mvCtrlPwrClckGet(CESA_UNIT_ID,0)) + { + printk("\nWarning CESA %d is Powered Off\n",0); + return EINVAL; + } +#endif + + memset(&cesa_device, 0, sizeof(struct cesa_dev)); + /* Get the IRQ, and crypto memory regions */ + { + struct resource *res; + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sram"); + + if (!res) + return -ENXIO; + + cesa_device.sram = ioremap(res->start, res->end - res->start + 1); + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs"); + + if (!res) { + iounmap(cesa_device.sram); + return -ENXIO; + } + cesa_device.reg = ioremap(res->start, res->end - res->start + 1); + cesa_device.irq = platform_get_irq(pdev, 0); + cesa_device.plat_data = pdev->dev.platform_data; + setup_tdma_mbus_windows(&cesa_device); + + } + + + if( MV_OK != mvCesaInit(CESA_OCF_MAX_SES*5, CESA_Q_SIZE, cesa_device.reg, + NULL) ) { + printk("%s,%d: mvCesaInit Failed. \n", __FILE__, __LINE__); + return EINVAL; + } + + /* clear and unmask Int */ + MV_REG_WRITE( MV_CESA_ISR_CAUSE_REG, 0); +#ifndef CESA_OCF_POLLING + MV_REG_WRITE( MV_CESA_ISR_MASK_REG, MV_CESA_CAUSE_ACC_DMA_MASK); +#endif +#ifdef CESA_OCF_TASKLET + tasklet_init(&cesa_ocf_tasklet, cesa_callback, (unsigned int) 0); +#endif + /* register interrupt */ + if( request_irq( cesa_device.irq, cesa_interrupt_handler, + 0, "cesa", &cesa_ocf_id) < 0) { + printk("%s,%d: cannot assign irq %x\n", __FILE__, __LINE__, cesa_device.reg); + return EINVAL; + } + + + memset(cesa_ocf_sessions, 0, sizeof(struct cesa_ocf_data *) * CESA_OCF_MAX_SES); + +#define REGISTER(alg) \ + crypto_register(cesa_ocf_id, alg, 0,0) + REGISTER(CRYPTO_AES_CBC); + REGISTER(CRYPTO_DES_CBC); + REGISTER(CRYPTO_3DES_CBC); + REGISTER(CRYPTO_MD5); + REGISTER(CRYPTO_MD5_HMAC); + REGISTER(CRYPTO_SHA1); + REGISTER(CRYPTO_SHA1_HMAC); +#undef REGISTER + + return 0; +} + +static void +mv_cesa_ocf_exit(struct platform_device *pdev) +{ + dprintk("%s()\n", __FUNCTION__); + + crypto_unregister_all(cesa_ocf_id); + cesa_ocf_id = -1; + iounmap(cesa_device.reg); + iounmap(cesa_device.sram); + free_irq(cesa_device.irq, NULL); + + /* mask and clear Int */ + MV_REG_WRITE( MV_CESA_ISR_MASK_REG, 0); + MV_REG_WRITE( MV_CESA_ISR_CAUSE_REG, 0); + + + if( MV_OK != mvCesaFinish() ) { + printk("%s,%d: mvCesaFinish Failed. \n", __FILE__, __LINE__); + return; + } +} + + +void cesa_ocf_debug(void) +{ + +#ifdef CESA_OCF_TRACE_DEBUG + { + int i, j; + j = cesaTestTraceIdx; + mvOsPrintf("No Type rCause iCause Proc Isr Res Time pReady pProc pEmpty\n"); + for(i=0; i= _1G) + { + mvOsOutput("%3dGB ", size / _1G); + size %= _1G; + if(size) + mvOsOutput("+"); + } + if(size >= _1M ) + { + mvOsOutput("%3dMB ", size / _1M); + size %= _1M; + if(size) + mvOsOutput("+"); + } + if(size >= _1K) + { + mvOsOutput("%3dKB ", size / _1K); + size %= _1K; + if(size) + mvOsOutput("+"); + } + if(size > 0) + { + mvOsOutput("%3dB ", size); + } +} + +/******************************************************************************* +* mvHexToBin - Convert hex to binary +* +* DESCRIPTION: +* This function Convert hex to binary. +* +* INPUT: +* pHexStr - hex buffer pointer. +* size - Size to convert. +* +* OUTPUT: +* pBin - Binary buffer pointer. +* +* RETURN: +* None. +* +*******************************************************************************/ +MV_VOID mvHexToBin(const char* pHexStr, MV_U8* pBin, int size) +{ + int j, i; + char tmp[3]; + MV_U8 byte; + + for(j=0, i=0; j> 1; + result++; + } + return result; +} + + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/common/mvCommon.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/common/mvCommon.h new file mode 100644 index 0000000..c8e9ce1 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/common/mvCommon.h @@ -0,0 +1,308 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + + + +#ifndef __INCmvCommonh +#define __INCmvCommonh + +#include "mvTypes.h" + +/* Swap tool */ + +/* 16bit nibble swap. For example 0x1234 -> 0x2143 */ +#define MV_NIBBLE_SWAP_16BIT(X) (((X&0xf) << 4) | \ + ((X&0xf0) >> 4) | \ + ((X&0xf00) << 4) | \ + ((X&0xf000) >> 4)) + +/* 32bit nibble swap. For example 0x12345678 -> 0x21436587 */ +#define MV_NIBBLE_SWAP_32BIT(X) (((X&0xf) << 4) | \ + ((X&0xf0) >> 4) | \ + ((X&0xf00) << 4) | \ + ((X&0xf000) >> 4) | \ + ((X&0xf0000) << 4) | \ + ((X&0xf00000) >> 4) | \ + ((X&0xf000000) << 4) | \ + ((X&0xf0000000) >> 4)) + +/* 16bit byte swap. For example 0x1122 -> 0x2211 */ +#define MV_BYTE_SWAP_16BIT(X) ((((X)&0xff)<<8) | (((X)&0xff00)>>8)) + +/* 32bit byte swap. For example 0x11223344 -> 0x44332211 */ +#define MV_BYTE_SWAP_32BIT(X) ((((X)&0xff)<<24) | \ + (((X)&0xff00)<<8) | \ + (((X)&0xff0000)>>8) | \ + (((X)&0xff000000)>>24)) + +/* 64bit byte swap. For example 0x11223344.55667788 -> 0x88776655.44332211 */ +#define MV_BYTE_SWAP_64BIT(X) ((l64) ((((X)&0xffULL)<<56) | \ + (((X)&0xff00ULL)<<40) | \ + (((X)&0xff0000ULL)<<24) | \ + (((X)&0xff000000ULL)<<8) | \ + (((X)&0xff00000000ULL)>>8) | \ + (((X)&0xff0000000000ULL)>>24) | \ + (((X)&0xff000000000000ULL)>>40) | \ + (((X)&0xff00000000000000ULL)>>56))) + +/* Endianess macros. */ +#if defined(MV_CPU_LE) + #define MV_16BIT_LE(X) (X) + #define MV_32BIT_LE(X) (X) + #define MV_64BIT_LE(X) (X) + #define MV_16BIT_BE(X) MV_BYTE_SWAP_16BIT(X) + #define MV_32BIT_BE(X) MV_BYTE_SWAP_32BIT(X) + #define MV_64BIT_BE(X) MV_BYTE_SWAP_64BIT(X) +#elif defined(MV_CPU_BE) + #define MV_16BIT_LE(X) MV_BYTE_SWAP_16BIT(X) + #define MV_32BIT_LE(X) MV_BYTE_SWAP_32BIT(X) + #define MV_64BIT_LE(X) MV_BYTE_SWAP_64BIT(X) + #define MV_16BIT_BE(X) (X) + #define MV_32BIT_BE(X) (X) + #define MV_64BIT_BE(X) (X) +#else + #error "CPU endianess isn't defined!\n" +#endif + + +/* Bit field definitions */ +#define NO_BIT 0x00000000 +#define BIT0 0x00000001 +#define BIT1 0x00000002 +#define BIT2 0x00000004 +#define BIT3 0x00000008 +#define BIT4 0x00000010 +#define BIT5 0x00000020 +#define BIT6 0x00000040 +#define BIT7 0x00000080 +#define BIT8 0x00000100 +#define BIT9 0x00000200 +#define BIT10 0x00000400 +#define BIT11 0x00000800 +#define BIT12 0x00001000 +#define BIT13 0x00002000 +#define BIT14 0x00004000 +#define BIT15 0x00008000 +#define BIT16 0x00010000 +#define BIT17 0x00020000 +#define BIT18 0x00040000 +#define BIT19 0x00080000 +#define BIT20 0x00100000 +#define BIT21 0x00200000 +#define BIT22 0x00400000 +#define BIT23 0x00800000 +#define BIT24 0x01000000 +#define BIT25 0x02000000 +#define BIT26 0x04000000 +#define BIT27 0x08000000 +#define BIT28 0x10000000 +#define BIT29 0x20000000 +#define BIT30 0x40000000 +#define BIT31 0x80000000 + +/* Handy sizes */ +#define _1K 0x00000400 +#define _2K 0x00000800 +#define _4K 0x00001000 +#define _8K 0x00002000 +#define _16K 0x00004000 +#define _32K 0x00008000 +#define _64K 0x00010000 +#define _128K 0x00020000 +#define _256K 0x00040000 +#define _512K 0x00080000 + +#define _1M 0x00100000 +#define _2M 0x00200000 +#define _4M 0x00400000 +#define _8M 0x00800000 +#define _16M 0x01000000 +#define _32M 0x02000000 +#define _64M 0x04000000 +#define _128M 0x08000000 +#define _256M 0x10000000 +#define _512M 0x20000000 + +#define _1G 0x40000000 +#define _2G 0x80000000 + +/* Tclock and Sys clock define */ +#define _100MHz 100000000 +#define _125MHz 125000000 +#define _133MHz 133333334 +#define _150MHz 150000000 +#define _160MHz 160000000 +#define _166MHz 166666667 +#define _175MHz 175000000 +#define _178MHz 178000000 +#define _183MHz 183333334 +#define _187MHz 187000000 +#define _192MHz 192000000 +#define _194MHz 194000000 +#define _200MHz 200000000 +#define _233MHz 233333334 +#define _250MHz 250000000 +#define _266MHz 266666667 +#define _300MHz 300000000 + +/* For better address window table readability */ +#define EN MV_TRUE +#define DIS MV_FALSE +#define N_A -1 /* Not applicable */ + +/* Cache configuration options for memory (DRAM, SRAM, ... ) */ + +/* Memory uncached, HW or SW cache coherency is not needed */ +#define MV_UNCACHED 0 +/* Memory cached, HW cache coherency supported in WriteThrough mode */ +#define MV_CACHE_COHER_HW_WT 1 +/* Memory cached, HW cache coherency supported in WriteBack mode */ +#define MV_CACHE_COHER_HW_WB 2 +/* Memory cached, No HW cache coherency, Cache coherency must be in SW */ +#define MV_CACHE_COHER_SW 3 + + +/* Macro for testing aligment. Positive if number is NOT aligned */ +#define MV_IS_NOT_ALIGN(number, align) ((number) & ((align) - 1)) + +/* Macro for alignment up. For example, MV_ALIGN_UP(0x0330, 0x20) = 0x0340 */ +#define MV_ALIGN_UP(number, align) \ +(((number) & ((align) - 1)) ? (((number) + (align)) & ~((align)-1)) : (number)) + +/* Macro for alignment down. For example, MV_ALIGN_UP(0x0330, 0x20) = 0x0320 */ +#define MV_ALIGN_DOWN(number, align) ((number) & ~((align)-1)) + +/* This macro returns absolute value */ +#define MV_ABS(number) (((int)(number) < 0) ? -(int)(number) : (int)(number)) + + +/* Bit fields manipulation macros */ + +/* An integer word which its 'x' bit is set */ +#define MV_BIT_MASK(bitNum) (1 << (bitNum) ) + +/* Checks wheter bit 'x' in integer word is set */ +#define MV_BIT_CHECK(word, bitNum) ( (word) & MV_BIT_MASK(bitNum) ) + +/* Clear (reset) bit 'x' in integer word (RMW - Read-Modify-Write) */ +#define MV_BIT_CLEAR(word, bitNum) ( (word) &= ~(MV_BIT_MASK(bitNum)) ) + +/* Set bit 'x' in integer word (RMW) */ +#define MV_BIT_SET(word, bitNum) ( (word) |= MV_BIT_MASK(bitNum) ) + +/* Invert bit 'x' in integer word (RMW) */ +#define MV_BIT_INV(word, bitNum) ( (word) ^= MV_BIT_MASK(bitNum) ) + +/* Get the min between 'a' or 'b' */ +#define MV_MIN(a,b) (((a) < (b)) ? (a) : (b)) + +/* Get the max between 'a' or 'b' */ +#define MV_MAX(a,b) (((a) < (b)) ? (b) : (a)) + +/* Temporary */ +#define mvOsDivide(num, div) \ +({ \ + int i=0, rem=(num); \ + \ + while(rem >= (div)) \ + { \ + rem -= (div); \ + i++; \ + } \ + (i); \ +}) + +/* Temporary */ +#define mvOsReminder(num, div) \ +({ \ + int rem = (num); \ + \ + while(rem >= (div)) \ + rem -= (div); \ + (rem); \ +}) + +#define MV_IP_QUAD(ipAddr) ((ipAddr >> 24) & 0xFF), ((ipAddr >> 16) & 0xFF), \ + ((ipAddr >> 8) & 0xFF), ((ipAddr >> 0) & 0xFF) + +#define MV_IS_POWER_OF_2(num) ((num != 0) && ((num & (num - 1)) == 0)) + +#ifndef MV_ASMLANGUAGE +/* mvCommon API list */ + +MV_VOID mvHexToBin(const char* pHexStr, MV_U8* pBin, int size); +void mvAsciiToHex(const char* asciiStr, char* hexStr); +void mvBinToHex(const MV_U8* bin, char* hexStr, int size); +void mvBinToAscii(const MV_U8* bin, char* asciiStr, int size); + +MV_STATUS mvMacStrToHex(const char* macStr, MV_U8* macHex); +MV_STATUS mvMacHexToStr(MV_U8* macHex, char* macStr); +void mvSizePrint(MV_U32); + +MV_U32 mvLog2(MV_U32 num); + +#endif /* MV_ASMLANGUAGE */ + + +#endif /* __INCmvCommonh */ diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/common/mvCompVer.txt b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/common/mvCompVer.txt new file mode 100644 index 0000000..38a9264 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/common/mvCompVer.txt @@ -0,0 +1,4 @@ +Global HAL Version: FEROCEON_HAL_3_1_7 +Unit HAL Version: 3.1.4 +Description: This component includes an implementation of the unit HAL drivers + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/common/mvDebug.c b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/common/mvDebug.c new file mode 100644 index 0000000..087f36d --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/common/mvDebug.c @@ -0,0 +1,326 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + + + +/* includes */ +#include "mvOs.h" +#include "mv802_3.h" +#include "mvCommon.h" +#include "mvDebug.h" + +/* Global variables effect on behave MV_DEBUG_PRINT and MV_DEBUG_CODE macros + * mvDebug - map of bits (one for each module) bit=1 means enable + * debug code and messages for this module + * mvModuleDebug - array of 32 bits varables one for each module + */ +MV_U32 mvDebug = 0; +MV_U32 mvDebugModules[MV_MODULE_MAX]; + +/* Init mvModuleDebug array to default values */ +void mvDebugInit(void) +{ + int bit; + + mvDebug = 0; + for(bit=0; bit 0) + { + mvOsPrintf("%08x: ", memAddr); + i = 0; + /* 32 bytes in the line */ + while(i < 32) + { + if(memAddr >= (MV_U32)addr) + { + switch(access) + { + case 1: + if( memAddr == CPU_PHY_MEM(memAddr) ) + { + mvOsPrintf("%02x ", MV_MEMIO8_READ(memAddr)); + } + else + { + mvOsPrintf("%02x ", *((MV_U8*)memAddr)); + } + break; + + case 2: + if( memAddr == CPU_PHY_MEM(memAddr) ) + { + mvOsPrintf("%04x ", MV_MEMIO16_READ(memAddr)); + } + else + { + mvOsPrintf("%04x ", *((MV_U16*)memAddr)); + } + break; + + case 4: + if( memAddr == CPU_PHY_MEM(memAddr) ) + { + mvOsPrintf("%08x ", MV_MEMIO32_READ(memAddr)); + } + else + { + mvOsPrintf("%08x ", *((MV_U32*)memAddr)); + } + break; + } + } + else + { + for(j=0; j<(access*2+1); j++) + mvOsPrintf(" "); + } + i += access; + memAddr += access; + size -= access; + if(size <= 0) + break; + } + mvOsPrintf("\n"); + } +} + +void mvDebugPrintBufInfo(BUF_INFO* pBufInfo, int size, int access) +{ + if(pBufInfo == NULL) + { + mvOsPrintf("\n!!! pBufInfo = NULL\n"); + return; + } + mvOsPrintf("\n*** pBufInfo=0x%x, cmdSts=0x%08x, pBuf=0x%x, bufSize=%d\n", + (unsigned int)pBufInfo, + (unsigned int)pBufInfo->cmdSts, + (unsigned int)pBufInfo->pBuff, + (unsigned int)pBufInfo->bufSize); + mvOsPrintf("pData=0x%x, byteCnt=%d, pNext=0x%x, uInfo1=0x%x, uInfo2=0x%x\n", + (unsigned int)pBufInfo->pData, + (unsigned int)pBufInfo->byteCnt, + (unsigned int)pBufInfo->pNextBufInfo, + (unsigned int)pBufInfo->userInfo1, + (unsigned int)pBufInfo->userInfo2); + if(pBufInfo->pData != NULL) + { + if(size > pBufInfo->byteCnt) + size = pBufInfo->byteCnt; + mvDebugMemDump(pBufInfo->pData, size, access); + } +} + +void mvDebugPrintPktInfo(MV_PKT_INFO* pPktInfo, int size, int access) +{ + int frag, len; + + if(pPktInfo == NULL) + { + mvOsPrintf("\n!!! pPktInfo = NULL\n"); + return; + } + mvOsPrintf("\npPkt=%p, stat=0x%08x, numFr=%d, size=%d, pFr=%p, osInfo=0x%lx\n", + pPktInfo, pPktInfo->status, pPktInfo->numFrags, pPktInfo->pktSize, + pPktInfo->pFrags, pPktInfo->osInfo); + + for(frag=0; fragnumFrags; frag++) + { + mvOsPrintf("#%2d. bufVirt=%p, bufSize=%d\n", + frag, pPktInfo->pFrags[frag].bufVirtPtr, + pPktInfo->pFrags[frag].bufSize); + if(size > 0) + { + len = MV_MIN((int)pPktInfo->pFrags[frag].bufSize, size); + mvDebugMemDump(pPktInfo->pFrags[frag].bufVirtPtr, len, access); + size -= len; + } + } + +} + +void mvDebugPrintIpAddr(MV_U32 ipAddr) +{ + mvOsPrintf("%d.%d.%d.%d", ((ipAddr >> 24) & 0xFF), ((ipAddr >> 16) & 0xFF), + ((ipAddr >> 8) & 0xFF), ((ipAddr >> 0) & 0xFF)); +} + +void mvDebugPrintMacAddr(const MV_U8* pMacAddr) +{ + int i; + + mvOsPrintf("%02x", (unsigned int)pMacAddr[0]); + for(i=1; ibegin = 0; + pTimeEntry->count = count; + pTimeEntry->end = 0; + pTimeEntry->left = pTimeEntry->count; + pTimeEntry->total = 0; + pTimeEntry->min = 0xFFFFFFFF; + pTimeEntry->max = 0x0; + strncpy(pTimeEntry->name, pName, sizeof(pTimeEntry->name)-1); + pTimeEntry->name[sizeof(pTimeEntry->name)-1] = '\0'; +} + +/* Print out MV_DEBUG_TIMES entry */ +void mvDebugPrintTimeEntry(MV_DEBUG_TIMES* pTimeEntry, MV_BOOL isTitle) +{ + int num; + + if(isTitle == MV_TRUE) + mvOsPrintf("Event NumOfEvents TotalTime Average Min Max\n"); + + num = pTimeEntry->count-pTimeEntry->left; + if(num > 0) + { + mvOsPrintf("%-11s %6u 0x%08lx %6lu %6lu %6lu\n", + pTimeEntry->name, num, pTimeEntry->total, pTimeEntry->total/num, + pTimeEntry->min, pTimeEntry->max); + } +} + +/* Update MV_DEBUG_TIMES entry */ +void mvDebugUpdateTimeEntry(MV_DEBUG_TIMES* pTimeEntry) +{ + MV_U32 delta; + + if(pTimeEntry->left > 0) + { + if(pTimeEntry->end <= pTimeEntry->begin) + { + delta = pTimeEntry->begin - pTimeEntry->end; + } + else + { + delta = ((MV_U32)0x10000 - pTimeEntry->end) + pTimeEntry->begin; + } + pTimeEntry->total += delta; + + if(delta < pTimeEntry->min) + pTimeEntry->min = delta; + + if(delta > pTimeEntry->max) + pTimeEntry->max = delta; + + pTimeEntry->left--; + } +} + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/common/mvDebug.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/common/mvDebug.h new file mode 100644 index 0000000..e4975be --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/common/mvDebug.h @@ -0,0 +1,178 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + + + +#ifndef __INCmvDebugh +#define __INCmvDebugh + +/* includes */ +#include "mvTypes.h" + +typedef enum +{ + MV_MODULE_INVALID = -1, + MV_MODULE_ETH = 0, + MV_MODULE_IDMA, + MV_MODULE_XOR, + MV_MODULE_TWASI, + MV_MODULE_MGI, + MV_MODULE_USB, + MV_MODULE_CESA, + + MV_MODULE_MAX +}MV_MODULE_ID; + +/* Define generic flags useful for most of modules */ +#define MV_DEBUG_FLAG_ALL (0) +#define MV_DEBUG_FLAG_INIT (1 << 0) +#define MV_DEBUG_FLAG_RX (1 << 1) +#define MV_DEBUG_FLAG_TX (1 << 2) +#define MV_DEBUG_FLAG_ERR (1 << 3) +#define MV_DEBUG_FLAG_TRACE (1 << 4) +#define MV_DEBUG_FLAG_DUMP (1 << 5) +#define MV_DEBUG_FLAG_CACHE (1 << 6) +#define MV_DEBUG_FLAG_IOCTL (1 << 7) +#define MV_DEBUG_FLAG_STATS (1 << 8) + +extern MV_U32 mvDebug; +extern MV_U32 mvDebugModules[MV_MODULE_MAX]; + +#ifdef MV_DEBUG +# define MV_DEBUG_PRINT(module, flags, msg) mvOsPrintf msg +# define MV_DEBUG_CODE(module, flags, code) code +#elif defined(MV_RT_DEBUG) +# define MV_DEBUG_PRINT(module, flags, msg) \ + if( (mvDebug & (1<<(module))) && \ + ((mvDebugModules[(module)] & (flags)) == (flags)) ) \ + mvOsPrintf msg +# define MV_DEBUG_CODE(module, flags, code) \ + if( (mvDebug & (1<<(module))) && \ + ((mvDebugModules[(module)] & (flags)) == (flags)) ) \ + code +#else +# define MV_DEBUG_PRINT(module, flags, msg) +# define MV_DEBUG_CODE(module, flags, code) +#endif + + + +/* typedefs */ + +/* time measurement structure used to check how much time pass between + * two points + */ +typedef struct { + char name[20]; /* name of the entry */ + unsigned long begin; /* time measured on begin point */ + unsigned long end; /* time measured on end point */ + unsigned long total; /* Accumulated time */ + unsigned long left; /* The rest measurement actions */ + unsigned long count; /* Maximum measurement actions */ + unsigned long min; /* Minimum time from begin to end */ + unsigned long max; /* Maximum time from begin to end */ +} MV_DEBUG_TIMES; + + +/* mvDebug.h API list */ + +/****** Error Recording ******/ + +/* Dump memory in specific format: + * address: X1X1X1X1 X2X2X2X2 ... X8X8X8X8 + */ +void mvDebugMemDump(void* addr, int size, int access); + +void mvDebugPrintBufInfo(BUF_INFO* pBufInfo, int size, int access); + +void mvDebugPrintPktInfo(MV_PKT_INFO* pPktInfo, int size, int access); + +void mvDebugPrintIpAddr(MV_U32 ipAddr); + +void mvDebugPrintMacAddr(const MV_U8* pMacAddr); + +/**** There are three functions deals with MV_DEBUG_TIMES structure ****/ + +/* Reset MV_DEBUG_TIMES entry */ +void mvDebugResetTimeEntry(MV_DEBUG_TIMES* pTimeEntry, int count, char* name); + +/* Update MV_DEBUG_TIMES entry */ +void mvDebugUpdateTimeEntry(MV_DEBUG_TIMES* pTimeEntry); + +/* Print out MV_DEBUG_TIMES entry */ +void mvDebugPrintTimeEntry(MV_DEBUG_TIMES* pTimeEntry, MV_BOOL isTitle); + + +/******** General ***********/ + +/* Change value of mvDebugPrint global variable */ + +void mvDebugInit(void); +void mvDebugModuleEnable(MV_MODULE_ID module, MV_BOOL isEnable); +void mvDebugModuleSetFlags(MV_MODULE_ID module, MV_U32 flags); +void mvDebugModuleClearFlags(MV_MODULE_ID module, MV_U32 flags); + + +#endif /* __INCmvDebug.h */ + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/common/mvDeviceId.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/common/mvDeviceId.h new file mode 100644 index 0000000..4782094 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/common/mvDeviceId.h @@ -0,0 +1,225 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#ifndef __INCmvDeviceIdh +#define __INCmvDeviceIdh + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* defines */ +#define MARVELL_VEN_ID 0x11ab + +/* Disco-3 */ +#define MV64460_DEV_ID 0x6480 +#define MV64460B_DEV_ID 0x6485 +#define MV64430_DEV_ID 0x6420 + +/* Disco-5 */ +#define MV64560_DEV_ID 0x6450 + +/* Disco-6 */ +#define MV64660_DEV_ID 0x6460 + +/* Orion */ +#define MV_1181_DEV_ID 0x1181 +#define MV_5181_DEV_ID 0x5181 +#define MV_5281_DEV_ID 0x5281 +#define MV_5182_DEV_ID 0x5182 +#define MV_8660_DEV_ID 0x8660 +#define MV_5180_DEV_ID 0x5180 +#define MV_5082_DEV_ID 0x5082 +#define MV_1281_DEV_ID 0x1281 +#define MV_6082_DEV_ID 0x6082 +#define MV_6183_DEV_ID 0x6183 +#define MV_6183L_DEV_ID 0x6083 + +#define MV_5281_D0_REV 0x4 +#define MV_5281_D0_ID ((MV_5281_DEV_ID << 16) | MV_5281_D0_REV) +#define MV_5281_D0_NAME "88F5281 D0" + +#define MV_5281_D1_REV 0x5 +#define MV_5281_D1_ID ((MV_5281_DEV_ID << 16) | MV_5281_D1_REV) +#define MV_5281_D1_NAME "88F5281 D1" + +#define MV_5281_D2_REV 0x6 +#define MV_5281_D2_ID ((MV_5281_DEV_ID << 16) | MV_5281_D2_REV) +#define MV_5281_D2_NAME "88F5281 D2" + + +#define MV_5181L_A0_REV 0x8 /* need for PCIE Er */ +#define MV_5181_A1_REV 0x1 /* for USB Er ..*/ +#define MV_5181_B0_REV 0x2 +#define MV_5181_B1_REV 0x3 +#define MV_5182_A1_REV 0x1 +#define MV_5180N_B1_REV 0x3 +#define MV_5181L_A0_ID ((MV_5181_DEV_ID << 16) | MV_5181L_A0_REV) + + + +/* kw */ +#define MV_6281_DEV_ID 0x6281 +#define MV_6192_DEV_ID 0x6192 +#define MV_6190_DEV_ID 0x6190 +#define MV_6180_DEV_ID 0x6180 + +#define MV_6281_A0_REV 0x2 +#define MV_6281_A0_ID ((MV_6281_DEV_ID << 16) | MV_6281_A0_REV) +#define MV_6281_A0_NAME "88F6281 A0" + +#define MV_6192_A0_REV 0x2 +#define MV_6192_A0_ID ((MV_6192_DEV_ID << 16) | MV_6192_A0_REV) +#define MV_6192_A0_NAME "88F6192 A0" + +#define MV_6190_A0_REV 0x2 +#define MV_6190_A0_ID ((MV_6190_DEV_ID << 16) | MV_6190_A0_REV) +#define MV_6190_A0_NAME "88F6190 A0" + +#define MV_6180_A0_REV 0x2 +#define MV_6180_A0_ID ((MV_6180_DEV_ID << 16) | MV_6180_A0_REV) +#define MV_6180_A0_NAME "88F6180 A0" + +#define MV_6281_A1_REV 0x3 +#define MV_6281_A1_ID ((MV_6281_DEV_ID << 16) | MV_6281_A1_REV) +#define MV_6281_A1_NAME "88F6281 A1" + +#define MV_6192_A1_REV 0x3 +#define MV_6192_A1_ID ((MV_6192_DEV_ID << 16) | MV_6192_A1_REV) +#define MV_6192_A1_NAME "88F6192 A1" + +#define MV_6190_A1_REV 0x3 +#define MV_6190_A1_ID ((MV_6190_DEV_ID << 16) | MV_6190_A1_REV) +#define MV_6190_A1_NAME "88F6190 A1" + +#define MV_6180_A1_REV 0x3 +#define MV_6180_A1_ID ((MV_6180_DEV_ID << 16) | MV_6180_A1_REV) +#define MV_6180_A1_NAME "88F6180 A1" + +#define MV_88F6XXX_A0_REV 0x2 +#define MV_88F6XXX_A1_REV 0x3 +/* Disco-Duo */ +#define MV_78XX0_ZY_DEV_ID 0x6381 +#define MV_78XX0_ZY_NAME "MV78X00" + +#define MV_78XX0_Z0_REV 0x1 +#define MV_78XX0_Z0_ID ((MV_78XX0_ZY_DEV_ID << 16) | MV_78XX0_Z0_REV) +#define MV_78XX0_Z0_NAME "78X00 Z0" + +#define MV_78XX0_Y0_REV 0x2 +#define MV_78XX0_Y0_ID ((MV_78XX0_ZY_DEV_ID << 16) | MV_78XX0_Y0_REV) +#define MV_78XX0_Y0_NAME "78X00 Y0" + +#define MV_78XX0_DEV_ID 0x7800 +#define MV_78XX0_NAME "MV78X00" + +#define MV_76100_DEV_ID 0x7610 +#define MV_78200_DEV_ID 0x7820 +#define MV_78100_DEV_ID 0x7810 +#define MV_78XX0_A0_REV 0x1 +#define MV_78XX0_A1_REV 0x2 + +#define MV_76100_NAME "MV76100" +#define MV_78100_NAME "MV78100" +#define MV_78200_NAME "MV78200" + +#define MV_76100_A0_ID ((MV_76100_DEV_ID << 16) | MV_78XX0_A0_REV) +#define MV_78100_A0_ID ((MV_78100_DEV_ID << 16) | MV_78XX0_A0_REV) +#define MV_78200_A0_ID ((MV_78200_DEV_ID << 16) | MV_78XX0_A0_REV) + +#define MV_76100_A1_ID ((MV_76100_DEV_ID << 16) | MV_78XX0_A1_REV) +#define MV_78100_A1_ID ((MV_78100_DEV_ID << 16) | MV_78XX0_A1_REV) +#define MV_78200_A1_ID ((MV_78200_DEV_ID << 16) | MV_78XX0_A1_REV) + +#define MV_76100_A0_NAME "MV76100 A0" +#define MV_78100_A0_NAME "MV78100 A0" +#define MV_78200_A0_NAME "MV78200 A0" +#define MV_78XX0_A0_NAME "MV78XX0 A0" + +#define MV_76100_A1_NAME "MV76100 A1" +#define MV_78100_A1_NAME "MV78100 A1" +#define MV_78200_A1_NAME "MV78200 A1" +#define MV_78XX0_A1_NAME "MV78XX0 A1" + +/*MV88F632X family*/ +#define MV_6321_DEV_ID 0x6321 +#define MV_6322_DEV_ID 0x6322 +#define MV_6323_DEV_ID 0x6323 + +#define MV_6321_NAME "88F6321" +#define MV_6322_NAME "88F6322" +#define MV_6323_NAME "88F6323" + +#define MV_632X_A1_REV 0x2 + +#define MV_6321_A1_ID ((MV_6321_DEV_ID << 16) | MV_632X_A1_REV) +#define MV_6322_A1_ID ((MV_6322_DEV_ID << 16) | MV_632X_A1_REV) +#define MV_6323_A1_ID ((MV_6323_DEV_ID << 16) | MV_632X_A1_REV) + +#define MV_6321_A1_NAME "88F6321 A1" +#define MV_6322_A1_NAME "88F6322 A1" +#define MV_6323_A1_NAME "88F6323 A1" + + +#endif /* __INCmvDeviceIdh */ diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/common/mvHalVer.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/common/mvHalVer.h new file mode 100644 index 0000000..3bfcfe1 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/common/mvHalVer.h @@ -0,0 +1,73 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + + +#ifndef __INCmvHalVerh +#define __INCmvHalVerh + +/* Defines */ +#define MV_HAL_VERSION "FEROCEON_HAL_3_1_7" +#define MV_RELEASE_BASELINE "SoCandControllers_FEROCEON_RELEASE_7_9_2009_KW_4_3_4_DD_2_1_4_6183_1_1_4" + +#endif /* __INCmvHalVerh */ \ No newline at end of file diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/common/mvStack.c b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/common/mvStack.c new file mode 100644 index 0000000..41ca7ce --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/common/mvStack.c @@ -0,0 +1,100 @@ +/******************************************************************************* +* Copyright 2003, Marvell Semiconductor Israel LTD. * +* THIS CODE CONTAINS CONFIDENTIAL INFORMATION OF MARVELL. * +* NO RIGHTS ARE GRANTED HEREIN UNDER ANY PATENT, MASK WORK RIGHT OR COPYRIGHT * +* OF MARVELL OR ANY THIRD PARTY. MARVELL RESERVES THE RIGHT AT ITS SOLE * +* DISCRETION TO REQUEST THAT THIS CODE BE IMMEDIATELY RETURNED TO MARVELL. * +* THIS CODE IS PROVIDED "AS IS". MARVELL MAKES NO WARRANTIES, EXPRESSED, * +* IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, COMPLETENESS OR PERFORMANCE. * +* * +* MARVELL COMPRISES MARVELL TECHNOLOGY GROUP LTD. (MTGL) AND ITS SUBSIDIARIES, * +* MARVELL INTERNATIONAL LTD. (MIL), MARVELL TECHNOLOGY, INC. (MTI), MARVELL * +* SEMICONDUCTOR, INC. (MSI), MARVELL ASIA PTE LTD. (MAPL), MARVELL JAPAN K.K. * +* (MJKK), MARVELL SEMICONDUCTOR ISRAEL LTD (MSIL). * +******************************************************************************** +* mvQueue.c +* +* FILENAME: $Workfile: mvStack.c $ +* REVISION: $Revision: 1.1 $ +* LAST UPDATE: $Modtime: $ +* +* DESCRIPTION: +* This file implements simple Stack LIFO functionality. +*******************************************************************************/ + +/* includes */ +#include "mvOs.h" +#include "mvTypes.h" +#include "mvDebug.h" +#include "mvStack.h" + +/* defines */ + + +/* Public functions */ + + +/* Purpose: Create new stack + * Inputs: + * - MV_U32 noOfElements - maximum number of elements in the stack. + * Each element 4 bytes size + * Return: void* - pointer to created stack. + */ +void* mvStackCreate(int numOfElements) +{ + MV_STACK* pStack; + MV_U32* pStackElements; + + pStack = (MV_STACK*)mvOsMalloc(sizeof(MV_STACK)); + pStackElements = (MV_U32*)mvOsMalloc(numOfElements*sizeof(MV_U32)); + if( (pStack == NULL) || (pStackElements == NULL) ) + { + mvOsPrintf("mvStack: Can't create new stack\n"); + return NULL; + } + memset(pStackElements, 0, numOfElements*sizeof(MV_U32)); + pStack->numOfElements = numOfElements; + pStack->stackIdx = 0; + pStack->stackElements = pStackElements; + + return pStack; +} + +/* Purpose: Delete existing stack + * Inputs: + * - void* stackHndl - Stack handle as returned by "mvStackCreate()" function + * + * Return: MV_STATUS MV_NOT_FOUND - Failure. StackHandle is not valid. + * MV_OK - Success. + */ +MV_STATUS mvStackDelete(void* stackHndl) +{ + MV_STACK* pStack = (MV_STACK*)stackHndl; + + if( (pStack == NULL) || (pStack->stackElements == NULL) ) + return MV_NOT_FOUND; + + mvOsFree(pStack->stackElements); + mvOsFree(pStack); + + return MV_OK; +} + + +/* PrintOut status of the stack */ +void mvStackStatus(void* stackHndl, MV_BOOL isPrintElements) +{ + int i; + MV_STACK* pStack = (MV_STACK*)stackHndl; + + mvOsPrintf("StackHandle=%p, pElements=%p, numElements=%d, stackIdx=%d\n", + stackHndl, pStack->stackElements, pStack->numOfElements, + pStack->stackIdx); + if(isPrintElements == MV_TRUE) + { + for(i=0; istackIdx; i++) + { + mvOsPrintf("%3d. Value=0x%x\n", i, pStack->stackElements[i]); + } + } +} diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/common/mvStack.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/common/mvStack.h new file mode 100644 index 0000000..e247e61 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/common/mvStack.h @@ -0,0 +1,140 @@ +/******************************************************************************* +* Copyright 2003, Marvell Semiconductor Israel LTD. * +* THIS CODE CONTAINS CONFIDENTIAL INFORMATION OF MARVELL. * +* NO RIGHTS ARE GRANTED HEREIN UNDER ANY PATENT, MASK WORK RIGHT OR COPYRIGHT * +* OF MARVELL OR ANY THIRD PARTY. MARVELL RESERVES THE RIGHT AT ITS SOLE * +* DISCRETION TO REQUEST THAT THIS CODE BE IMMEDIATELY RETURNED TO MARVELL. * +* THIS CODE IS PROVIDED "AS IS". MARVELL MAKES NO WARRANTIES, EXPRESSED, * +* IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, COMPLETENESS OR PERFORMANCE. * +* * +* MARVELL COMPRISES MARVELL TECHNOLOGY GROUP LTD. (MTGL) AND ITS SUBSIDIARIES, * +* MARVELL INTERNATIONAL LTD. (MIL), MARVELL TECHNOLOGY, INC. (MTI), MARVELL * +* SEMICONDUCTOR, INC. (MSI), MARVELL ASIA PTE LTD. (MAPL), MARVELL JAPAN K.K. * +* (MJKK), MARVELL SEMICONDUCTOR ISRAEL LTD (MSIL). * +******************************************************************************** +* mvStack.h - Header File for : +* +* FILENAME: $Workfile: mvStack.h $ +* REVISION: $Revision: 1.1 $ +* LAST UPDATE: $Modtime: $ +* +* DESCRIPTION: +* This file defines simple Stack (LIFO) functionality. +* +*******************************************************************************/ + +#ifndef __mvStack_h__ +#define __mvStack_h__ + + +/* includes */ +#include "mvTypes.h" + + +/* defines */ + + +/* typedefs */ +/* Data structure describes general purpose Stack */ +typedef struct +{ + int stackIdx; + int numOfElements; + MV_U32* stackElements; +} MV_STACK; + +static INLINE MV_BOOL mvStackIsFull(void* stackHndl) +{ + MV_STACK* pStack = (MV_STACK*)stackHndl; + + if(pStack->stackIdx == pStack->numOfElements) + return MV_TRUE; + + return MV_FALSE; +} + +static INLINE MV_BOOL mvStackIsEmpty(void* stackHndl) +{ + MV_STACK* pStack = (MV_STACK*)stackHndl; + + if(pStack->stackIdx == 0) + return MV_TRUE; + + return MV_FALSE; +} +/* Purpose: Push new element to stack + * Inputs: + * - void* stackHndl - Stack handle as returned by "mvStackCreate()" function. + * - MV_U32 value - New element. + * + * Return: MV_STATUS MV_FULL - Failure. Stack is full. + * MV_OK - Success. Element is put to stack. + */ +static INLINE void mvStackPush(void* stackHndl, MV_U32 value) +{ + MV_STACK* pStack = (MV_STACK*)stackHndl; + +#ifdef MV_RT_DEBUG + if(pStack->stackIdx == pStack->numOfElements) + { + mvOsPrintf("mvStackPush: Stack is FULL\n"); + return; + } +#endif /* MV_RT_DEBUG */ + + pStack->stackElements[pStack->stackIdx] = value; + pStack->stackIdx++; +} + +/* Purpose: Pop element from the top of stack and copy it to "pValue" + * Inputs: + * - void* stackHndl - Stack handle as returned by "mvStackCreate()" function. + * - MV_U32 value - Element in the top of stack. + * + * Return: MV_STATUS MV_EMPTY - Failure. Stack is empty. + * MV_OK - Success. Element is removed from the stack and + * copied to pValue argument + */ +static INLINE MV_U32 mvStackPop(void* stackHndl) +{ + MV_STACK* pStack = (MV_STACK*)stackHndl; + +#ifdef MV_RT_DEBUG + if(pStack->stackIdx == 0) + { + mvOsPrintf("mvStackPop: Stack is EMPTY\n"); + return 0; + } +#endif /* MV_RT_DEBUG */ + + pStack->stackIdx--; + return pStack->stackElements[pStack->stackIdx]; +} + +static INLINE int mvStackIndex(void* stackHndl) +{ + MV_STACK* pStack = (MV_STACK*)stackHndl; + + return pStack->stackIdx; +} + +static INLINE int mvStackFreeElements(void* stackHndl) +{ + MV_STACK* pStack = (MV_STACK*)stackHndl; + + return (pStack->numOfElements - pStack->stackIdx); +} + +/* mvStack.h API list */ + +/* Create new Stack */ +void* mvStackCreate(int numOfElements); + +/* Delete existing stack */ +MV_STATUS mvStackDelete(void* stackHndl); + +/* Print status of the stack */ +void mvStackStatus(void* stackHndl, MV_BOOL isPrintElements); + +#endif /* __mvStack_h__ */ + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/common/mvTypes.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/common/mvTypes.h new file mode 100644 index 0000000..de212a1 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/common/mvTypes.h @@ -0,0 +1,245 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + + +#ifndef __INCmvTypesh +#define __INCmvTypesh + +/* Defines */ + +/* The following is a list of Marvell status */ +#define MV_ERROR (-1) +#define MV_OK (0x00) /* Operation succeeded */ +#define MV_FAIL (0x01) /* Operation failed */ +#define MV_BAD_VALUE (0x02) /* Illegal value (general) */ +#define MV_OUT_OF_RANGE (0x03) /* The value is out of range */ +#define MV_BAD_PARAM (0x04) /* Illegal parameter in function called */ +#define MV_BAD_PTR (0x05) /* Illegal pointer value */ +#define MV_BAD_SIZE (0x06) /* Illegal size */ +#define MV_BAD_STATE (0x07) /* Illegal state of state machine */ +#define MV_SET_ERROR (0x08) /* Set operation failed */ +#define MV_GET_ERROR (0x09) /* Get operation failed */ +#define MV_CREATE_ERROR (0x0A) /* Fail while creating an item */ +#define MV_NOT_FOUND (0x0B) /* Item not found */ +#define MV_NO_MORE (0x0C) /* No more items found */ +#define MV_NO_SUCH (0x0D) /* No such item */ +#define MV_TIMEOUT (0x0E) /* Time Out */ +#define MV_NO_CHANGE (0x0F) /* Parameter(s) is already in this value */ +#define MV_NOT_SUPPORTED (0x10) /* This request is not support */ +#define MV_NOT_IMPLEMENTED (0x11) /* Request supported but not implemented */ +#define MV_NOT_INITIALIZED (0x12) /* The item is not initialized */ +#define MV_NO_RESOURCE (0x13) /* Resource not available (memory ...) */ +#define MV_FULL (0x14) /* Item is full (Queue or table etc...) */ +#define MV_EMPTY (0x15) /* Item is empty (Queue or table etc...) */ +#define MV_INIT_ERROR (0x16) /* Error occured while INIT process */ +#define MV_HW_ERROR (0x17) /* Hardware error */ +#define MV_TX_ERROR (0x18) /* Transmit operation not succeeded */ +#define MV_RX_ERROR (0x19) /* Recieve operation not succeeded */ +#define MV_NOT_READY (0x1A) /* The other side is not ready yet */ +#define MV_ALREADY_EXIST (0x1B) /* Tried to create existing item */ +#define MV_OUT_OF_CPU_MEM (0x1C) /* Cpu memory allocation failed. */ +#define MV_NOT_STARTED (0x1D) /* Not started yet */ +#define MV_BUSY (0x1E) /* Item is busy. */ +#define MV_TERMINATE (0x1F) /* Item terminates it's work. */ +#define MV_NOT_ALIGNED (0x20) /* Wrong alignment */ +#define MV_NOT_ALLOWED (0x21) /* Operation NOT allowed */ +#define MV_WRITE_PROTECT (0x22) /* Write protected */ + + +#define MV_INVALID (int)(-1) + +#define MV_FALSE 0 +#define MV_TRUE (!(MV_FALSE)) + + +#ifndef NULL +#define NULL ((void*)0) +#endif + + +#ifndef MV_ASMLANGUAGE +/* typedefs */ + +typedef char MV_8; +typedef unsigned char MV_U8; + +typedef int MV_32; +typedef unsigned int MV_U32; + +typedef short MV_16; +typedef unsigned short MV_U16; + +#ifdef MV_PPC64 +typedef long MV_64; +typedef unsigned long MV_U64; +#else +typedef long long MV_64; +typedef unsigned long long MV_U64; +#endif + +typedef long MV_LONG; /* 32/64 */ +typedef unsigned long MV_ULONG; /* 32/64 */ + +typedef int MV_STATUS; +typedef int MV_BOOL; +typedef void MV_VOID; +typedef float MV_FLOAT; + +typedef int (*MV_FUNCPTR) (void); /* ptr to function returning int */ +typedef void (*MV_VOIDFUNCPTR) (void); /* ptr to function returning void */ +typedef double (*MV_DBLFUNCPTR) (void); /* ptr to function returning double*/ +typedef float (*MV_FLTFUNCPTR) (void); /* ptr to function returning float */ + +typedef MV_U32 MV_KHZ; +typedef MV_U32 MV_MHZ; +typedef MV_U32 MV_HZ; + + +/* This enumerator describes the set of commands that can be applied on */ +/* an engine (e.g. IDMA, XOR). Appling a comman depends on the current */ +/* status (see MV_STATE enumerator) */ +/* Start can be applied only when status is IDLE */ +/* Stop can be applied only when status is IDLE, ACTIVE or PAUSED */ +/* Pause can be applied only when status is ACTIVE */ +/* Restart can be applied only when status is PAUSED */ +typedef enum _mvCommand +{ + MV_START, /* Start */ + MV_STOP, /* Stop */ + MV_PAUSE, /* Pause */ + MV_RESTART /* Restart */ +} MV_COMMAND; + +/* This enumerator describes the set of state conditions. */ +/* Moving from one state to other is stricted. */ +typedef enum _mvState +{ + MV_IDLE, + MV_ACTIVE, + MV_PAUSED, + MV_UNDEFINED_STATE +} MV_STATE; + + +/* This structure describes address space window. Window base can be */ +/* 64 bit, window size up to 4GB */ +typedef struct _mvAddrWin +{ + MV_U32 baseLow; /* 32bit base low */ + MV_U32 baseHigh; /* 32bit base high */ + MV_U32 size; /* 32bit size */ +}MV_ADDR_WIN; + +/* This binary enumerator describes protection attribute status */ +typedef enum _mvProtRight +{ + ALLOWED, /* Protection attribute allowed */ + FORBIDDEN /* Protection attribute forbidden */ +}MV_PROT_RIGHT; + +/* Unified struct for Rx and Tx packet operations. The user is required to */ +/* be familier only with Tx/Rx descriptor command status. */ +typedef struct _bufInfo +{ + MV_U32 cmdSts; /* Tx/Rx command status */ + MV_U16 byteCnt; /* Size of valid data in the buffer */ + MV_U16 bufSize; /* Total size of the buffer */ + MV_U8 *pBuff; /* Pointer to Buffer */ + MV_U8 *pData; /* Pointer to data in the Buffer */ + MV_U32 userInfo1; /* Tx/Rx attached user information 1 */ + MV_U32 userInfo2; /* Tx/Rx attached user information 2 */ + struct _bufInfo *pNextBufInfo; /* Next buffer in packet */ +} BUF_INFO; + +/* This structure contains information describing one of buffers + * (fragments) they are built Ethernet packet. + */ +typedef struct +{ + MV_U8* bufVirtPtr; + MV_ULONG bufPhysAddr; + MV_U32 bufSize; + MV_U32 dataSize; + MV_U32 memHandle; + MV_32 bufAddrShift; +} MV_BUF_INFO; + +/* This structure contains information describing Ethernet packet. + * The packet can be divided for few buffers (fragments) + */ +typedef struct +{ + MV_ULONG osInfo; + MV_BUF_INFO *pFrags; + MV_U32 status; + MV_U16 pktSize; + MV_U16 numFrags; + MV_U32 ownerId; + MV_U32 fragIP; +} MV_PKT_INFO; + +#endif /* MV_ASMLANGUAGE */ + +#endif /* __INCmvTypesh */ + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/dbg-trace.c b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/dbg-trace.c new file mode 100644 index 0000000..644fd02 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/dbg-trace.c @@ -0,0 +1,110 @@ +#include +#include +#include +#include "dbg-trace.h" + +#define TRACE_ARR_LEN 800 +#define STR_LEN 128 +struct trace { + struct timeval tv; + char str[STR_LEN]; + unsigned int callback_val1; + unsigned int callback_val2; + char valid; +}; +static unsigned int (*trc_callback1) (unsigned char) = NULL; +static unsigned int (*trc_callback2) (unsigned char) = NULL; +static unsigned char trc_param1 = 0; +static unsigned char trc_param2 = 0; +struct trace *trc_arr; +static int trc_index; +static int trc_active = 0; + +void TRC_START() +{ + trc_active = 1; +} + +void TRC_STOP() +{ + trc_active = 0; +} + +void TRC_INIT(void *callback1, void *callback2, unsigned char callback1_param, unsigned char callback2_param) +{ + printk("Marvell debug tracing is on\n"); + trc_arr = (struct trace *)kmalloc(TRACE_ARR_LEN*sizeof(struct trace),GFP_KERNEL); + if(trc_arr == NULL) + { + printk("Can't allocate Debug Trace buffer\n"); + return; + } + memset(trc_arr,0,TRACE_ARR_LEN*sizeof(struct trace)); + trc_index = 0; + trc_callback1 = callback1; + trc_callback2 = callback2; + trc_param1 = callback1_param; + trc_param2 = callback2_param; +} +void TRC_REC(char *fmt,...) +{ + va_list args; + struct trace *trc = &trc_arr[trc_index]; + + if(trc_active == 0) + return; + + do_gettimeofday(&trc->tv); + if(trc_callback1) + trc->callback_val1 = trc_callback1(trc_param1); + if(trc_callback2) + trc->callback_val2 = trc_callback2(trc_param2); + va_start(args, fmt); + vsprintf(trc->str,fmt,args); + va_end(args); + trc->valid = 1; + if((++trc_index) == TRACE_ARR_LEN) { + trc_index = 0; + } +} +void TRC_OUTPUT(void) +{ + int i,j; + struct trace *p; + printk("\n\nTrace %d items\n",TRACE_ARR_LEN); + for(i=0,j=trc_index; ivalid) { + unsigned long uoffs; + struct trace *plast; + if(p == &trc_arr[0]) + plast = &trc_arr[TRACE_ARR_LEN-1]; + else + plast = p-1; + if(p->tv.tv_sec == ((plast)->tv.tv_sec)) + uoffs = (p->tv.tv_usec - ((plast)->tv.tv_usec)); + else + uoffs = (1000000 - ((plast)->tv.tv_usec)) + + ((p->tv.tv_sec - ((plast)->tv.tv_sec) - 1) * 1000000) + + p->tv.tv_usec; + printk("%03d: [+%ld usec]", j, (unsigned long)uoffs); + if(trc_callback1) + printk("[%u]",p->callback_val1); + if(trc_callback2) + printk("[%u]",p->callback_val2); + printk(": %s",p->str); + } + p->valid = 0; + } + memset(trc_arr,0,TRACE_ARR_LEN*sizeof(struct trace)); + trc_index = 0; +} +void TRC_RELEASE(void) +{ + kfree(trc_arr); + trc_index = 0; +} + + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/dbg-trace.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/dbg-trace.h new file mode 100644 index 0000000..a5aac26 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/dbg-trace.h @@ -0,0 +1,24 @@ + +#ifndef _MV_DBG_TRCE_H_ +#define _MV_DBG_TRCE_H_ + +#ifdef CONFIG_MV_DBG_TRACE +void TRC_INIT(void *callback1, void *callback2, + unsigned char callback1_param, unsigned char callback2_param); +void TRC_REC(char *fmt,...); +void TRC_OUTPUT(void); +void TRC_RELEASE(void); +void TRC_START(void); +void TRC_STOP(void); + +#else +#define TRC_INIT(x1,x2,x3,x4) +#define TRC_REC(X...) +#define TRC_OUTPUT() +#define TRC_RELEASE() +#define TRC_START() +#define TRC_STOP() +#endif + + +#endif diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/boardEnv/mvBoardEnvLib.c b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/boardEnv/mvBoardEnvLib.c new file mode 100644 index 0000000..5f62784 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/boardEnv/mvBoardEnvLib.c @@ -0,0 +1,2513 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#include "boardEnv/mvBoardEnvLib.h" +#include "ctrlEnv/mvCtrlEnvLib.h" +#include "ctrlEnv/sys/mvCpuIf.h" +#include "cpu/mvCpu.h" +#include "cntmr/mvCntmr.h" +#include "gpp/mvGpp.h" +#include "twsi/mvTwsi.h" +#include "pex/mvPex.h" +#include "device/mvDevice.h" +#include "eth/gbe/mvEthRegs.h" + +/* defines */ +/* #define MV_DEBUG */ +#ifdef MV_DEBUG + #define DB(x) x +#else + #define DB(x) +#endif + +extern MV_CPU_ARM_CLK _cpuARMDDRCLK[]; + +#define CODE_IN_ROM MV_FALSE +#define CODE_IN_RAM MV_TRUE + +extern MV_BOARD_INFO* boardInfoTbl[]; +#define BOARD_INFO(boardId) boardInfoTbl[boardId - BOARD_ID_BASE] + +/* Locals */ +static MV_DEV_CS_INFO* boardGetDevEntry(MV_32 devNum, MV_BOARD_DEV_CLASS devClass); + +MV_U32 tClkRate = -1; + + +/******************************************************************************* +* mvBoardEnvInit - Init board +* +* DESCRIPTION: +* In this function the board environment take care of device bank +* initialization. +* +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* None. +* +*******************************************************************************/ +MV_VOID mvBoardEnvInit(MV_VOID) +{ + MV_U32 boardId= mvBoardIdGet(); + + if (!((boardId >= BOARD_ID_BASE)&&(boardId < MV_MAX_BOARD_ID))) + { + mvOsPrintf("mvBoardEnvInit:Board unknown.\n"); + return; + + } + + /* Set GPP Out value */ + MV_REG_WRITE(GPP_DATA_OUT_REG(0), BOARD_INFO(boardId)->gppOutValLow); + MV_REG_WRITE(GPP_DATA_OUT_REG(1), BOARD_INFO(boardId)->gppOutValHigh); + + /* set GPP polarity */ + mvGppPolaritySet(0, 0xFFFFFFFF, BOARD_INFO(boardId)->gppPolarityValLow); + mvGppPolaritySet(1, 0xFFFFFFFF, BOARD_INFO(boardId)->gppPolarityValHigh); + + /* Workaround for Erratum FE-MISC-70*/ + if(mvCtrlRevGet()==MV_88F6XXX_A0_REV) + { + BOARD_INFO(boardId)->gppOutEnValLow &= 0xfffffffd; + BOARD_INFO(boardId)->gppOutEnValLow |= (BOARD_INFO(boardId)->gppOutEnValHigh) & 0x00000002; + } /*End of WA*/ + + /* Set GPP Out Enable*/ + mvGppTypeSet(0, 0xFFFFFFFF, BOARD_INFO(boardId)->gppOutEnValLow); + mvGppTypeSet(1, 0xFFFFFFFF, BOARD_INFO(boardId)->gppOutEnValHigh); + + /* Nand CE */ + MV_REG_BIT_SET(NAND_CTRL_REG, NAND_ACTCEBOOT_BIT); +} + +/******************************************************************************* +* mvBoardModelGet - Get Board model +* +* DESCRIPTION: +* This function returns 16bit describing board model. +* Board model is constructed of one byte major and minor numbers in the +* following manner: +* +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* String describing board model. +* +*******************************************************************************/ +MV_U16 mvBoardModelGet(MV_VOID) +{ + return (mvBoardIdGet() >> 16); +} + +/******************************************************************************* +* mbBoardRevlGet - Get Board revision +* +* DESCRIPTION: +* This function returns a 32bit describing the board revision. +* Board revision is constructed of 4bytes. 2bytes describes major number +* and the other 2bytes describes minor munber. +* For example for board revision 3.4 the function will return +* 0x00030004. +* +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* String describing board model. +* +*******************************************************************************/ +MV_U16 mvBoardRevGet(MV_VOID) +{ + return (mvBoardIdGet() & 0xFFFF); +} + +/******************************************************************************* +* mvBoardNameGet - Get Board name +* +* DESCRIPTION: +* This function returns a string describing the board model and revision. +* String is extracted from board I2C EEPROM. +* +* INPUT: +* None. +* +* OUTPUT: +* pNameBuff - Buffer to contain board name string. Minimum size 32 chars. +* +* RETURN: +* +* MV_ERROR if informantion can not be read. +*******************************************************************************/ +MV_STATUS mvBoardNameGet(char *pNameBuff) +{ + MV_U32 boardId= mvBoardIdGet(); + + if (!((boardId >= BOARD_ID_BASE)&&(boardId < MV_MAX_BOARD_ID))) + { + mvOsSPrintf (pNameBuff, "Board unknown.\n"); + return MV_ERROR; + + } + + mvOsSPrintf (pNameBuff, "%s",BOARD_INFO(boardId)->boardName); + + return MV_OK; +} + +/******************************************************************************* +* mvBoardIsPortInSgmii - +* +* DESCRIPTION: +* This routine returns MV_TRUE for port number works in SGMII or MV_FALSE +* For all other options. +* +* INPUT: +* ethPortNum - Ethernet port number. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_TRUE - port in SGMII. +* MV_FALSE - other. +* +*******************************************************************************/ +MV_BOOL mvBoardIsPortInSgmii(MV_U32 ethPortNum) +{ + MV_BOOL ethPortSgmiiSupport[BOARD_ETH_PORT_NUM] = MV_ETH_PORT_SGMII; + + if(ethPortNum >= BOARD_ETH_PORT_NUM) + { + mvOsPrintf ("Invalid portNo=%d\n", ethPortNum); + return MV_FALSE; + } + return ethPortSgmiiSupport[ethPortNum]; +} + +/******************************************************************************* +* mvBoardIsPortInGmii - +* +* DESCRIPTION: +* This routine returns MV_TRUE for port number works in GMII or MV_FALSE +* For all other options. +* +* INPUT: +* +* OUTPUT: +* None. +* +* RETURN: +* MV_TRUE - port in GMII. +* MV_FALSE - other. +* +*******************************************************************************/ +MV_BOOL mvBoardIsPortInGmii(MV_VOID) +{ + MV_U32 devClassId, devClass = 0; + if (mvBoardMppGroupTypeGet(devClass) == MV_BOARD_AUTO) + { + /* Get MPP module ID */ + devClassId = mvBoarModuleTypeGet(devClass); + if (MV_BOARD_MODULE_GMII_ID == devClassId) + return MV_TRUE; + } + else if (mvBoardMppGroupTypeGet(devClass) == MV_BOARD_GMII) + return MV_TRUE; + + return MV_FALSE; +} +/******************************************************************************* +* mvBoardPhyAddrGet - Get the phy address +* +* DESCRIPTION: +* This routine returns the Phy address of a given ethernet port. +* +* INPUT: +* ethPortNum - Ethernet port number. +* +* OUTPUT: +* None. +* +* RETURN: +* 32bit describing Phy address, -1 if the port number is wrong. +* +*******************************************************************************/ +MV_32 mvBoardPhyAddrGet(MV_U32 ethPortNum) +{ + MV_U32 boardId= mvBoardIdGet(); + + if (!((boardId >= BOARD_ID_BASE)&&(boardId < MV_MAX_BOARD_ID))) + { + mvOsPrintf("mvBoardPhyAddrGet: Board unknown.\n"); + return MV_ERROR; + } + + return BOARD_INFO(boardId)->pBoardMacInfo[ethPortNum].boardEthSmiAddr; +} + +/******************************************************************************* +* mvBoardMacSpeedGet - Get the Mac speed +* +* DESCRIPTION: +* This routine returns the Mac speed if pre define of a given ethernet port. +* +* INPUT: +* ethPortNum - Ethernet port number. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_BOARD_MAC_SPEED, -1 if the port number is wrong. +* +*******************************************************************************/ +MV_BOARD_MAC_SPEED mvBoardMacSpeedGet(MV_U32 ethPortNum) +{ + MV_U32 boardId= mvBoardIdGet(); + + if (!((boardId >= BOARD_ID_BASE)&&(boardId < MV_MAX_BOARD_ID))) + { + mvOsPrintf("mvBoardMacSpeedGet: Board unknown.\n"); + return MV_ERROR; + } + + return BOARD_INFO(boardId)->pBoardMacInfo[ethPortNum].boardMacSpeed; +} + +/******************************************************************************* +* mvBoardLinkStatusIrqGet - Get the IRQ number for the link status indication +* +* DESCRIPTION: +* This routine returns the IRQ number for the link status indication. +* +* INPUT: +* ethPortNum - Ethernet port number. +* +* OUTPUT: +* None. +* +* RETURN: +* the number of the IRQ for the link status indication, -1 if the port +* number is wrong or if not relevant. +* +*******************************************************************************/ +MV_32 mvBoardLinkStatusIrqGet(MV_U32 ethPortNum) +{ + MV_U32 boardId = mvBoardIdGet(); + + if (!((boardId >= BOARD_ID_BASE)&&(boardId < MV_MAX_BOARD_ID))) + { + mvOsPrintf("mvBoardLinkStatusIrqGet: Board unknown.\n"); + return MV_ERROR; + } + + return BOARD_INFO(boardId)->pSwitchInfo[ethPortNum].linkStatusIrq; +} + +/******************************************************************************* +* mvBoardSwitchPortGet - Get the mapping between the board connector and the +* Ethernet Switch port +* +* DESCRIPTION: +* This routine returns the matching Switch port. +* +* INPUT: +* ethPortNum - Ethernet port number. +* boardPortNum - logical number of the connector on the board +* +* OUTPUT: +* None. +* +* RETURN: +* the matching Switch port, -1 if the port number is wrong or if not relevant. +* +*******************************************************************************/ +MV_32 mvBoardSwitchPortGet(MV_U32 ethPortNum, MV_U8 boardPortNum) +{ + MV_U32 boardId = mvBoardIdGet(); + + if (!((boardId >= BOARD_ID_BASE)&&(boardId < MV_MAX_BOARD_ID))) + { + mvOsPrintf("mvBoardSwitchPortGet: Board unknown.\n"); + return MV_ERROR; + } + if (boardPortNum >= BOARD_ETH_SWITCH_PORT_NUM) + { + mvOsPrintf("mvBoardSwitchPortGet: Illegal board port number.\n"); + return MV_ERROR; + } + + return BOARD_INFO(boardId)->pSwitchInfo[ethPortNum].qdPort[boardPortNum]; +} + +/******************************************************************************* +* mvBoardSwitchCpuPortGet - Get the the Ethernet Switch CPU port +* +* DESCRIPTION: +* This routine returns the Switch CPU port. +* +* INPUT: +* ethPortNum - Ethernet port number. +* +* OUTPUT: +* None. +* +* RETURN: +* the Switch CPU port, -1 if the port number is wrong or if not relevant. +* +*******************************************************************************/ +MV_32 mvBoardSwitchCpuPortGet(MV_U32 ethPortNum) +{ + MV_U32 boardId = mvBoardIdGet(); + + if (!((boardId >= BOARD_ID_BASE)&&(boardId < MV_MAX_BOARD_ID))) + { + mvOsPrintf("mvBoardSwitchCpuPortGet: Board unknown.\n"); + return MV_ERROR; + } + + return BOARD_INFO(boardId)->pSwitchInfo[ethPortNum].qdCpuPort; +} + +/******************************************************************************* +* mvBoardIsSwitchConnected - Get switch connection status +* DESCRIPTION: +* This routine returns port's connection status +* +* INPUT: +* ethPortNum - Ethernet port number. +* +* OUTPUT: +* None. +* +* RETURN: +* 1 - if ethPortNum is connected to switch, 0 otherwise +* +*******************************************************************************/ +MV_32 mvBoardIsSwitchConnected(MV_U32 ethPortNum) +{ + MV_U32 boardId = mvBoardIdGet(); + + if (!((boardId >= BOARD_ID_BASE)&&(boardId < MV_MAX_BOARD_ID))) + { + mvOsPrintf("mvBoardIsSwitchConnected: Board unknown.\n"); + return MV_ERROR; + } + + if(ethPortNum >= BOARD_INFO(boardId)->numBoardMacInfo) + { + mvOsPrintf("mvBoardIsSwitchConnected: Illegal port number(%u)\n", ethPortNum); + return MV_ERROR; + } + + if((MV_32)(BOARD_INFO(boardId)->pSwitchInfo)) + return (MV_32)(BOARD_INFO(boardId)->pSwitchInfo[ethPortNum].switchOnPort == ethPortNum); + else + return 0; +} +/******************************************************************************* +* mvBoardSmiScanModeGet - Get Switch SMI scan mode +* +* DESCRIPTION: +* This routine returns Switch SMI scan mode. +* +* INPUT: +* ethPortNum - Ethernet port number. +* +* OUTPUT: +* None. +* +* RETURN: +* 1 for SMI_MANUAL_MODE, -1 if the port number is wrong or if not relevant. +* +*******************************************************************************/ +MV_32 mvBoardSmiScanModeGet(MV_U32 ethPortNum) +{ + MV_U32 boardId = mvBoardIdGet(); + + if (!((boardId >= BOARD_ID_BASE)&&(boardId < MV_MAX_BOARD_ID))) + { + mvOsPrintf("mvBoardSmiScanModeGet: Board unknown.\n"); + return MV_ERROR; + } + + return BOARD_INFO(boardId)->pSwitchInfo[ethPortNum].smiScanMode; +} +/******************************************************************************* +* mvBoardSpecInitGet - +* +* DESCRIPTION: +* +* INPUT: +* +* OUTPUT: +* None. +* +* RETURN: Return MV_TRUE and parameters in case board need spesific phy init, +* otherwise return MV_FALSE. +* +* +*******************************************************************************/ + +MV_BOOL mvBoardSpecInitGet(MV_U32* regOff, MV_U32* data) +{ + return MV_FALSE; +} + +/******************************************************************************* +* mvBoardTclkGet - Get the board Tclk (Controller clock) +* +* DESCRIPTION: +* This routine extract the controller core clock. +* This function uses the controller counters to make identification. +* Note: In order to avoid interference, make sure task context switch +* and interrupts will not occure during this function operation +* +* INPUT: +* countNum - Counter number. +* +* OUTPUT: +* None. +* +* RETURN: +* 32bit clock cycles in Hertz. +* +*******************************************************************************/ +MV_U32 mvBoardTclkGet(MV_VOID) +{ + if(mvCtrlModelGet()==MV_6281_DEV_ID) + { +#if defined(TCLK_AUTO_DETECT) + MV_U32 tmpTClkRate = MV_BOARD_TCLK_166MHZ; + + tmpTClkRate = MV_REG_READ(MPP_SAMPLE_AT_RESET); + tmpTClkRate &= MSAR_TCLCK_MASK; + + switch (tmpTClkRate) + { + case MSAR_TCLCK_166: + return MV_BOARD_TCLK_166MHZ; + break; + case MSAR_TCLCK_200: + return MV_BOARD_TCLK_200MHZ; + break; + } +#else + return MV_BOARD_TCLK_200MHZ; +#endif + } + + return MV_BOARD_TCLK_166MHZ; + +} +/******************************************************************************* +* mvBoardSysClkGet - Get the board SysClk (CPU bus clock) +* +* DESCRIPTION: +* This routine extract the CPU bus clock. +* +* INPUT: +* countNum - Counter number. +* +* OUTPUT: +* None. +* +* RETURN: +* 32bit clock cycles in Hertz. +* +*******************************************************************************/ +static MV_U32 mvBoard6180SysClkGet(MV_VOID) +{ + MV_U32 sysClkRate=0; + MV_CPU_ARM_CLK _cpu6180_ddr_l2_CLK[] = MV_CPU6180_DDR_L2_CLCK_TBL; + + sysClkRate = MV_REG_READ(MPP_SAMPLE_AT_RESET); + sysClkRate = sysClkRate & MSAR_CPUCLCK_MASK_6180; + sysClkRate = sysClkRate >> MSAR_CPUCLCK_OFFS_6180; + + sysClkRate = _cpu6180_ddr_l2_CLK[sysClkRate].ddrClk; + + return sysClkRate; + +} + +MV_U32 mvBoardSysClkGet(MV_VOID) +{ +#ifdef SYSCLK_AUTO_DETECT + MV_U32 sysClkRate, tmp, pClkRate, indexDdrRtio; + MV_U32 cpuCLK[] = MV_CPU_CLCK_TBL; + MV_U32 ddrRtio[][2] = MV_DDR_CLCK_RTIO_TBL; + + if(mvCtrlModelGet() == MV_6180_DEV_ID) + return mvBoard6180SysClkGet(); + + tmp = MV_REG_READ(MPP_SAMPLE_AT_RESET); + pClkRate = MSAR_CPUCLCK_EXTRACT(tmp); + pClkRate = cpuCLK[pClkRate]; + + indexDdrRtio = tmp & MSAR_DDRCLCK_RTIO_MASK; + indexDdrRtio = indexDdrRtio >> MSAR_DDRCLCK_RTIO_OFFS; + if(ddrRtio[indexDdrRtio][0] != 0) + sysClkRate = ((pClkRate * ddrRtio[indexDdrRtio][1]) / ddrRtio[indexDdrRtio][0]); + else + sysClkRate = 0; + return sysClkRate; +#else + return MV_BOARD_DEFAULT_SYSCLK; +#endif +} + + +/******************************************************************************* +* mvBoardPexBridgeIntPinGet - Get PEX to PCI bridge interrupt pin number +* +* DESCRIPTION: +* Multi-ported PCI Express bridges that is implemented on the board +* collapse interrupts across multiple conventional PCI/PCI-X buses. +* A dual-headed PCI Express bridge would map (or "swizzle") the +* interrupts per the following table (in accordance with the respective +* logical PCI/PCI-X bridge's Device Number), collapse the INTA#-INTD# +* signals from its two logical PCI/PCI-X bridges, collapse the +* INTA#-INTD# signals from any internal sources, and convert the +* signals to in-band PCI Express messages. 10 +* This function returns the upstream interrupt as it was converted by +* the bridge, according to board configuration and the following table: +* PCI dev num +* Interrupt pin 7, 8, 9 +* A -> A D C +* B -> B A D +* C -> C B A +* D -> D C B +* +* +* INPUT: +* devNum - PCI/PCIX device number. +* intPin - PCI Int pin +* +* OUTPUT: +* None. +* +* RETURN: +* Int pin connected to the Interrupt controller +* +*******************************************************************************/ +MV_U32 mvBoardPexBridgeIntPinGet(MV_U32 devNum, MV_U32 intPin) +{ + MV_U32 realIntPin = ((intPin + (3 - (devNum % 4))) %4 ); + + if (realIntPin == 0) return 4; + else return realIntPin; + +} + +/******************************************************************************* +* mvBoardDebugLedNumGet - Get number of debug Leds +* +* DESCRIPTION: +* INPUT: +* boardId +* +* OUTPUT: +* None. +* +* RETURN: +* None. +* +*******************************************************************************/ +MV_U32 mvBoardDebugLedNumGet(MV_U32 boardId) +{ + return BOARD_INFO(boardId)->activeLedsNumber; +} + +/******************************************************************************* +* mvBoardDebugLeg - Set the board debug Leds +* +* DESCRIPTION: turn on/off status leds. +* Note: assume MPP leds are part of group 0 only. +* +* INPUT: +* hexNum - Number to be displied in hex by Leds. +* +* OUTPUT: +* None. +* +* RETURN: +* None. +* +*******************************************************************************/ +MV_VOID mvBoardDebugLed(MV_U32 hexNum) +{ + MV_U32 val = 0,totalMask, currentBitMask = 1,i; + MV_U32 boardId= mvBoardIdGet(); + + if (BOARD_INFO(boardId)->pLedGppPin == NULL) + return; + + totalMask = (1 << BOARD_INFO(boardId)->activeLedsNumber) -1; + hexNum &= totalMask; + totalMask = 0; + + for (i = 0 ; i < BOARD_INFO(boardId)->activeLedsNumber ; i++) + { + if (hexNum & currentBitMask) + { + val |= (1 << BOARD_INFO(boardId)->pLedGppPin[i]); + } + + totalMask |= (1 << BOARD_INFO(boardId)->pLedGppPin[i]); + + currentBitMask = (currentBitMask << 1); + } + + if (BOARD_INFO(boardId)->ledsPolarity) + { + mvGppValueSet(0, totalMask, val); + } + else + { + mvGppValueSet(0, totalMask, ~val); + } +} + + +/******************************************************************************* +* mvBoarGpioPinGet - mvBoarGpioPinGet +* +* DESCRIPTION: +* +* INPUT: +* class - MV_BOARD_GPP_CLASS enum. +* +* OUTPUT: +* None. +* +* RETURN: +* GPIO pin number. The function return -1 for bad parameters. +* +*******************************************************************************/ +MV_32 mvBoarGpioPinNumGet(MV_BOARD_GPP_CLASS class, MV_U32 index) +{ + MV_U32 boardId, i; + MV_U32 indexFound = 0; + + boardId = mvBoardIdGet(); + + if (!((boardId >= BOARD_ID_BASE)&&(boardId < MV_MAX_BOARD_ID))) + { + mvOsPrintf("mvBoardRTCGpioPinGet:Board unknown.\n"); + return MV_ERROR; + + } + + for (i = 0; i < BOARD_INFO(boardId)->numBoardGppInfo; i++) + if (BOARD_INFO(boardId)->pBoardGppInfo[i].devClass == class) { + if (indexFound == index) + return (MV_U32)BOARD_INFO(boardId)->pBoardGppInfo[i].gppPinNum; + else + indexFound++; + + } + + return MV_ERROR; +} + + +/******************************************************************************* +* mvBoardRTCGpioPinGet - mvBoardRTCGpioPinGet +* +* DESCRIPTION: +* +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* GPIO pin number. The function return -1 for bad parameters. +* +*******************************************************************************/ +MV_32 mvBoardRTCGpioPinGet(MV_VOID) +{ + return mvBoarGpioPinNumGet(BOARD_GPP_RTC, 0); +} + + +/******************************************************************************* +* mvBoardReset - mvBoardReset +* +* DESCRIPTION: +* Reset the board +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* None +* +*******************************************************************************/ +MV_VOID mvBoardReset(MV_VOID) +{ + MV_32 resetPin; + + /* Get gpp reset pin if define */ + resetPin = mvBoardResetGpioPinGet(); + if (resetPin != MV_ERROR) + { + MV_REG_BIT_RESET( GPP_DATA_OUT_REG(0) ,(1 << resetPin)); + MV_REG_BIT_RESET( GPP_DATA_OUT_EN_REG(0) ,(1 << resetPin)); + + } + else + { + /* No gpp reset pin was found, try to reset ussing + system reset out */ + MV_REG_BIT_SET( CPU_RSTOUTN_MASK_REG , BIT2); + MV_REG_BIT_SET( CPU_SYS_SOFT_RST_REG , BIT0); + } +} + +/******************************************************************************* +* mvBoardResetGpioPinGet - mvBoardResetGpioPinGet +* +* DESCRIPTION: +* +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* GPIO pin number. The function return -1 for bad parameters. +* +*******************************************************************************/ +MV_32 mvBoardResetGpioPinGet(MV_VOID) +{ + return mvBoarGpioPinNumGet(BOARD_GPP_RESET, 0); +} +/******************************************************************************* +* mvBoardSDIOGpioPinGet - mvBoardSDIOGpioPinGet +* +* DESCRIPTION: +* used for hotswap detection +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* GPIO pin number. The function return -1 for bad parameters. +* +*******************************************************************************/ +MV_32 mvBoardSDIOGpioPinGet(MV_VOID) +{ + return mvBoarGpioPinNumGet(BOARD_GPP_SDIO_DETECT, 0); +} + +/******************************************************************************* +* mvBoardUSBVbusGpioPinGet - return Vbus input GPP +* +* DESCRIPTION: +* +* INPUT: +* int devNo. +* +* OUTPUT: +* None. +* +* RETURN: +* GPIO pin number. The function return -1 for bad parameters. +* +*******************************************************************************/ +MV_32 mvBoardUSBVbusGpioPinGet(MV_32 devId) +{ + return mvBoarGpioPinNumGet(BOARD_GPP_USB_VBUS, devId); +} + +/******************************************************************************* +* mvBoardUSBVbusEnGpioPinGet - return Vbus Enable output GPP +* +* DESCRIPTION: +* +* INPUT: +* int devNo. +* +* OUTPUT: +* None. +* +* RETURN: +* GPIO pin number. The function return -1 for bad parameters. +* +*******************************************************************************/ +MV_32 mvBoardUSBVbusEnGpioPinGet(MV_32 devId) +{ + return mvBoarGpioPinNumGet(BOARD_GPP_USB_VBUS_EN, devId); +} + + +/******************************************************************************* +* mvBoardGpioIntMaskGet - Get GPIO mask for interrupt pins +* +* DESCRIPTION: +* This function returns a 32-bit mask of GPP pins that connected to +* interrupt generating sources on board. +* For example if UART channel A is hardwired to GPP pin 8 and +* UART channel B is hardwired to GPP pin 4 the fuinction will return +* the value 0x000000110 +* +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* See description. The function return -1 if board is not identified. +* +*******************************************************************************/ +MV_32 mvBoardGpioIntMaskLowGet(MV_VOID) +{ + MV_U32 boardId; + + boardId = mvBoardIdGet(); + + if (!((boardId >= BOARD_ID_BASE)&&(boardId < MV_MAX_BOARD_ID))) + { + mvOsPrintf("mvBoardGpioIntMaskGet:Board unknown.\n"); + return MV_ERROR; + + } + + return BOARD_INFO(boardId)->intsGppMaskLow; +} +MV_32 mvBoardGpioIntMaskHighGet(MV_VOID) +{ + MV_U32 boardId; + + boardId = mvBoardIdGet(); + + if (!((boardId >= BOARD_ID_BASE)&&(boardId < MV_MAX_BOARD_ID))) + { + mvOsPrintf("mvBoardGpioIntMaskGet:Board unknown.\n"); + return MV_ERROR; + + } + + return BOARD_INFO(boardId)->intsGppMaskHigh; +} + + +/******************************************************************************* +* mvBoardMppGet - Get board dependent MPP register value +* +* DESCRIPTION: +* MPP settings are derived from board design. +* MPP group consist of 8 MPPs. An MPP group represent MPP +* control register. +* This function retrieves board dependend MPP register value. +* +* INPUT: +* mppGroupNum - MPP group number. +* +* OUTPUT: +* None. +* +* RETURN: +* 32bit value describing MPP control register value. +* +*******************************************************************************/ +MV_32 mvBoardMppGet(MV_U32 mppGroupNum) +{ + MV_U32 boardId; + + boardId = mvBoardIdGet(); + + if (!((boardId >= BOARD_ID_BASE)&&(boardId < MV_MAX_BOARD_ID))) + { + mvOsPrintf("mvBoardMppGet:Board unknown.\n"); + return MV_ERROR; + + } + + return BOARD_INFO(boardId)->pBoardMppConfigValue[0].mppGroup[mppGroupNum]; +} + + +/******************************************************************************* +* mvBoardMppGroupId - If MPP group type is AUTO then identify it using twsi +* +* DESCRIPTION: +* +* INPUT: +* +* OUTPUT: +* None. +* +* RETURN: +* +*******************************************************************************/ +MV_VOID mvBoardMppGroupIdUpdate(MV_VOID) +{ + + MV_BOARD_MPP_GROUP_CLASS devClass; + MV_BOARD_MODULE_ID_CLASS devClassId; + MV_BOARD_MPP_TYPE_CLASS mppGroupType; + MV_U32 devId; + MV_U32 maxMppGrp = 1; + + devId = mvCtrlModelGet(); + + switch(devId){ + case MV_6281_DEV_ID: + maxMppGrp = MV_6281_MPP_MAX_MODULE; + break; + case MV_6192_DEV_ID: + maxMppGrp = MV_6192_MPP_MAX_MODULE; + break; + case MV_6190_DEV_ID: + maxMppGrp = MV_6190_MPP_MAX_MODULE; + break; + case MV_6180_DEV_ID: + maxMppGrp = MV_6180_MPP_MAX_MODULE; + break; + } + + for (devClass = 0; devClass < maxMppGrp; devClass++) + { + /* If MPP group can be defined by the module connected to it */ + if (mvBoardMppGroupTypeGet(devClass) == MV_BOARD_AUTO) + { + /* Get MPP module ID */ + devClassId = mvBoarModuleTypeGet(devClass); + if (MV_ERROR != devClassId) + { + switch(devClassId) + { + case MV_BOARD_MODULE_TDM_ID: + case MV_BOARD_MODULE_TDM_5CHAN_ID: + mppGroupType = MV_BOARD_TDM; + break; + case MV_BOARD_MODULE_AUDIO_ID: + mppGroupType = MV_BOARD_AUDIO; + break; + case MV_BOARD_MODULE_RGMII_ID: + mppGroupType = MV_BOARD_RGMII; + break; + case MV_BOARD_MODULE_GMII_ID: + mppGroupType = MV_BOARD_GMII; + break; + case MV_BOARD_MODULE_TS_ID: + mppGroupType = MV_BOARD_TS; + break; + case MV_BOARD_MODULE_MII_ID: + mppGroupType = MV_BOARD_MII; + break; + default: + mppGroupType = MV_BOARD_OTHER; + break; + } + } + else + /* The module bay is empty */ + mppGroupType = MV_BOARD_OTHER; + + /* Update MPP group type */ + mvBoardMppGroupTypeSet(devClass, mppGroupType); + } + + /* Update MPP output voltage for RGMII 1.8V. Set port to GMII for GMII module */ + if ((mvBoardMppGroupTypeGet(devClass) == MV_BOARD_RGMII)) + MV_REG_BIT_SET(MPP_OUTPUT_DRIVE_REG,MPP_1_8_RGMII1_OUTPUT_DRIVE | MPP_1_8_RGMII0_OUTPUT_DRIVE); + else + { + if ((mvBoardMppGroupTypeGet(devClass) == MV_BOARD_GMII)) + { + MV_REG_BIT_RESET(MPP_OUTPUT_DRIVE_REG, BIT7 | BIT15); + MV_REG_BIT_RESET(ETH_PORT_SERIAL_CTRL_1_REG(0),BIT3); + MV_REG_BIT_RESET(ETH_PORT_SERIAL_CTRL_1_REG(1),BIT3); + } + else if ((mvBoardMppGroupTypeGet(devClass) == MV_BOARD_MII)) + { + /* Assumption that the MDC & MDIO should be 3.3V */ + MV_REG_BIT_RESET(MPP_OUTPUT_DRIVE_REG, BIT7 | BIT15); + /* Assumption that only ETH1 can be MII when using modules on DB */ + MV_REG_BIT_RESET(ETH_PORT_SERIAL_CTRL_1_REG(1),BIT3); + } + } + } +} + +/******************************************************************************* +* mvBoardMppGroupTypeGet +* +* DESCRIPTION: +* +* INPUT: +* mppGroupClass - MPP group number 0 for MPP[35:20] or 1 for MPP[49:36]. +* +* OUTPUT: +* None. +* +* RETURN: +* +*******************************************************************************/ +MV_BOARD_MPP_TYPE_CLASS mvBoardMppGroupTypeGet(MV_BOARD_MPP_GROUP_CLASS mppGroupClass) +{ + MV_U32 boardId; + + boardId = mvBoardIdGet(); + + if (!((boardId >= BOARD_ID_BASE)&&(boardId < MV_MAX_BOARD_ID))) + { + mvOsPrintf("mvBoardMppGet:Board unknown.\n"); + return MV_ERROR; + + } + + if (mppGroupClass == MV_BOARD_MPP_GROUP_1) + return BOARD_INFO(boardId)->pBoardMppTypeValue[0].boardMppGroup1; + else + return BOARD_INFO(boardId)->pBoardMppTypeValue[0].boardMppGroup2; +} + +/******************************************************************************* +* mvBoardMppGroupTypeSet +* +* DESCRIPTION: +* +* INPUT: +* mppGroupClass - MPP group number 0 for MPP[35:20] or 1 for MPP[49:36]. +* mppGroupType - MPP group type for MPP[35:20] or for MPP[49:36]. +* +* OUTPUT: +* None. +* +* RETURN: +* +*******************************************************************************/ +MV_VOID mvBoardMppGroupTypeSet(MV_BOARD_MPP_GROUP_CLASS mppGroupClass, + MV_BOARD_MPP_TYPE_CLASS mppGroupType) +{ + MV_U32 boardId; + + boardId = mvBoardIdGet(); + + if (!((boardId >= BOARD_ID_BASE)&&(boardId < MV_MAX_BOARD_ID))) + { + mvOsPrintf("mvBoardMppGet:Board unknown.\n"); + } + + if (mppGroupClass == MV_BOARD_MPP_GROUP_1) + BOARD_INFO(boardId)->pBoardMppTypeValue[0].boardMppGroup1 = mppGroupType; + else + BOARD_INFO(boardId)->pBoardMppTypeValue[0].boardMppGroup2 = mppGroupType; + +} + +/******************************************************************************* +* mvBoardMppMuxSet - Update MPP mux +* +* DESCRIPTION: +* +* INPUT: +* +* OUTPUT: +* None. +* +* RETURN: +* +*******************************************************************************/ +MV_VOID mvBoardMppMuxSet(MV_VOID) +{ + + MV_BOARD_MPP_GROUP_CLASS devClass; + MV_BOARD_MPP_TYPE_CLASS mppGroupType; + MV_U32 devId; + MV_U8 muxVal = 0xf; + MV_U32 maxMppGrp = 1; + MV_TWSI_SLAVE twsiSlave; + MV_TWSI_ADDR slave; + + devId = mvCtrlModelGet(); + + switch(devId){ + case MV_6281_DEV_ID: + maxMppGrp = MV_6281_MPP_MAX_MODULE; + break; + case MV_6192_DEV_ID: + maxMppGrp = MV_6192_MPP_MAX_MODULE; + break; + case MV_6190_DEV_ID: + maxMppGrp = MV_6190_MPP_MAX_MODULE; + break; + case MV_6180_DEV_ID: + maxMppGrp = MV_6180_MPP_MAX_MODULE; + break; + } + + for (devClass = 0; devClass < maxMppGrp; devClass++) + { + mppGroupType = mvBoardMppGroupTypeGet(devClass); + + switch(mppGroupType) + { + case MV_BOARD_TDM: + muxVal &= ~(devClass ? (0x2 << (devClass * 2)):0x0); + break; + case MV_BOARD_AUDIO: + muxVal &= ~(devClass ? 0x7 : 0x0); /*old Z0 value 0xd:0x0*/ + break; + case MV_BOARD_TS: + muxVal &= ~(devClass ? (0x2 << (devClass * 2)):0x0); + break; + default: + muxVal |= (devClass ? 0xf : 0); + break; + } + } + + /* TWSI init */ + slave.type = ADDR7_BIT; + slave.address = 0; + mvTwsiInit(0, TWSI_SPEED, mvBoardTclkGet(), &slave, 0); + + /* Read MPP module ID */ + DB(mvOsPrintf("Board: twsi exp set\n")); + twsiSlave.slaveAddr.address = mvBoardTwsiExpAddrGet(MV_BOARD_MUX_I2C_ADDR_ENTRY); + twsiSlave.slaveAddr.type = mvBoardTwsiExpAddrTypeGet(MV_BOARD_MUX_I2C_ADDR_ENTRY); + twsiSlave.validOffset = MV_TRUE; + /* Offset is the first command after the address which indicate the register number to be read + in next operation */ + twsiSlave.offset = 2; + twsiSlave.moreThen256 = MV_FALSE; + + + + if( MV_OK != mvTwsiWrite (0, &twsiSlave, &muxVal, 1) ) + { + DB(mvOsPrintf("Board: twsi exp out val fail\n")); + return; + } + DB(mvOsPrintf("Board: twsi exp out val succeded\n")); + + /* Change twsi exp to output */ + twsiSlave.offset = 6; + muxVal = 0; + if( MV_OK != mvTwsiWrite (0, &twsiSlave, &muxVal, 1) ) + { + DB(mvOsPrintf("Board: twsi exp change to out fail\n")); + return; + } + DB(mvOsPrintf("Board: twsi exp change to out succeded\n")); + +} + +/******************************************************************************* +* mvBoardTdmMppSet - set MPPs in TDM module +* +* DESCRIPTION: +* +* INPUT: type of second telephony device +* +* OUTPUT: +* None. +* +* RETURN: +* +*******************************************************************************/ +MV_VOID mvBoardTdmMppSet(MV_32 chType) +{ + + MV_BOARD_MPP_GROUP_CLASS devClass; + MV_BOARD_MPP_TYPE_CLASS mppGroupType; + MV_U32 devId; + MV_U8 muxVal = 1; + MV_U8 muxValMask = 1; + MV_U8 twsiVal; + MV_U32 maxMppGrp = 1; + MV_TWSI_SLAVE twsiSlave; + MV_TWSI_ADDR slave; + + devId = mvCtrlModelGet(); + + switch(devId){ + case MV_6281_DEV_ID: + maxMppGrp = MV_6281_MPP_MAX_MODULE; + break; + case MV_6192_DEV_ID: + maxMppGrp = MV_6192_MPP_MAX_MODULE; + break; + case MV_6190_DEV_ID: + maxMppGrp = MV_6190_MPP_MAX_MODULE; + break; + case MV_6180_DEV_ID: + maxMppGrp = MV_6180_MPP_MAX_MODULE; + break; + } + + for (devClass = 0; devClass < maxMppGrp; devClass++) + { + mppGroupType = mvBoardMppGroupTypeGet(devClass); + if(mppGroupType == MV_BOARD_TDM) + break; + } + + if(devClass == maxMppGrp) + return; /* TDM module not found */ + + /* TWSI init */ + slave.type = ADDR7_BIT; + slave.address = 0; + mvTwsiInit(0, TWSI_SPEED, mvBoardTclkGet(), &slave, 0); + + /* Read MPP module ID */ + DB(mvOsPrintf("Board: twsi exp set\n")); + twsiSlave.slaveAddr.address = mvBoardTwsiExpAddrGet(devClass); + twsiSlave.slaveAddr.type = ADDR7_BIT; + twsiSlave.validOffset = MV_TRUE; + /* Offset is the first command after the address which indicate the register number to be read + in next operation */ + twsiSlave.offset = 3; + twsiSlave.moreThen256 = MV_FALSE; + + if(mvBoardIdGet() == RD_88F6281A_ID) + { + muxVal = 0xc; + muxValMask = 0xf3; + } + + mvTwsiRead(0, &twsiSlave, &twsiVal, 1); + muxVal = (twsiVal & muxValMask) | muxVal; + + if( MV_OK != mvTwsiWrite (0, &twsiSlave, &muxVal, 1) ) + { + mvOsPrintf("Board: twsi exp out val fail\n"); + return; + } + DB(mvOsPrintf("Board: twsi exp out val succeded\n")); + + /* Change twsi exp to output */ + twsiSlave.offset = 7; + muxVal = 0xfe; + if(mvBoardIdGet() == RD_88F6281A_ID) + muxVal = 0xf3; + + mvTwsiRead(0, &twsiSlave, &twsiVal, 1); + muxVal = (twsiVal & muxVal); + + if( MV_OK != mvTwsiWrite (0, &twsiSlave, &muxVal, 1) ) + { + mvOsPrintf("Board: twsi exp change to out fail\n"); + return; + } + DB(mvOsPrintf("Board: twsi exp change to out succeded\n")); + /* reset the line to 0 */ + twsiSlave.offset = 3; + muxVal = 0; + muxValMask = 1; + + if(mvBoardIdGet() == RD_88F6281A_ID) { + muxVal = 0x0; + muxValMask = 0xf3; + } + + mvTwsiRead(0, &twsiSlave, &twsiVal, 1); + muxVal = (twsiVal & muxValMask) | muxVal; + + if( MV_OK != mvTwsiWrite (0, &twsiSlave, &muxVal, 1) ) + { + mvOsPrintf("Board: twsi exp out val fail\n"); + return; + } + DB(mvOsPrintf("Board: twsi exp out val succeded\n")); + + mvOsDelay(20); + + /* set the line to 1 */ + twsiSlave.offset = 3; + muxVal = 1; + muxValMask = 1; + + if(mvBoardIdGet() == RD_88F6281A_ID) + { + muxVal = 0xc; + muxValMask = 0xf3; + if(chType) /* FXS - issue reset properly */ + { + MV_REG_BIT_SET(GPP_DATA_OUT_REG(1), MV_GPP12); + mvOsDelay(50); + MV_REG_BIT_RESET(GPP_DATA_OUT_REG(1), MV_GPP12); + } + else /* FXO - issue reset via TDM_CODEC_RST*/ + { + /* change MPP44 type to TDM_CODEC_RST(0x2) */ + MV_REG_WRITE(MPP_CONTROL_REG5, ((MV_REG_READ(MPP_CONTROL_REG5) & 0xFFF0FFFF) | BIT17)); + } + } + + mvTwsiRead(0, &twsiSlave, &twsiVal, 1); + muxVal = (twsiVal & muxValMask) | muxVal; + + if( MV_OK != mvTwsiWrite (0, &twsiSlave, &muxVal, 1) ) + { + mvOsPrintf("Board: twsi exp out val fail\n"); + return; + } + + /* TBD - 5 channels */ +#if defined(MV_TDM_5CHANNELS) + /* change MPP38 type to GPIO(0x0) & polarity for TDM_STROBE */ + MV_REG_WRITE(MPP_CONTROL_REG4, (MV_REG_READ(MPP_CONTROL_REG4) & 0xF0FFFFFF)); + mvGppPolaritySet(1, MV_GPP6, 0); + + twsiSlave.offset = 6; + twsiSlave.slaveAddr.address = mvBoardTwsiExpAddrGet(2); + + mvTwsiRead(0, &twsiSlave, &twsiVal, 1); + muxVal = (twsiVal & ~BIT2); + + if( MV_OK != mvTwsiWrite (0, &twsiSlave, &muxVal, 1) ) + { + mvOsPrintf("Board: twsi exp change to out fail\n"); + return; + } + + + twsiSlave.offset = 2; + + mvTwsiRead(0, &twsiSlave, &twsiVal, 1); + muxVal = (twsiVal & ~BIT2); + + if( MV_OK != mvTwsiWrite (0, &twsiSlave, &muxVal, 1) ) + { + mvOsPrintf("Board: twsi exp change to out fail\n"); + return; + } +#endif + DB(mvOsPrintf("Board: twsi exp out val succeded\n")); + + +} +/******************************************************************************* +* mvBoardVoiceConnModeGet - return SLIC/DAA connection & interrupt modes +* +* DESCRIPTION: +* +* INPUT: +* +* OUTPUT: +* None. +* +* RETURN: +* +*******************************************************************************/ + +MV_VOID mvBoardVoiceConnModeGet(MV_32* connMode, MV_32* irqMode) +{ + switch(mvBoardIdGet()) + { + case RD_88F6281A_ID: + *connMode = DAISY_CHAIN_MODE; + *irqMode = INTERRUPT_TO_TDM; + break; + case DB_88F6281A_BP_ID: + *connMode = DUAL_CHIP_SELECT_MODE; + *irqMode = INTERRUPT_TO_TDM; + break; + case RD_88F6192A_ID: + *connMode = DUAL_CHIP_SELECT_MODE; + *irqMode = INTERRUPT_TO_TDM; + break; + case DB_88F6192A_BP_ID: + *connMode = DUAL_CHIP_SELECT_MODE; + *irqMode = INTERRUPT_TO_TDM; + break; + default: + *connMode = *irqMode = -1; + mvOsPrintf("mvBoardVoiceAssembleModeGet: TDM not supported(boardId=0x%x)\n",mvBoardIdGet()); + } + return; + +} + +/******************************************************************************* +* mvBoardMppModuleTypePrint - print module detect +* +* DESCRIPTION: +* +* INPUT: +* +* OUTPUT: +* None. +* +* RETURN: +* +*******************************************************************************/ +MV_VOID mvBoardMppModuleTypePrint(MV_VOID) +{ + + MV_BOARD_MPP_GROUP_CLASS devClass; + MV_BOARD_MPP_TYPE_CLASS mppGroupType; + MV_U32 devId; + MV_U32 maxMppGrp = 1; + + devId = mvCtrlModelGet(); + + switch(devId){ + case MV_6281_DEV_ID: + maxMppGrp = MV_6281_MPP_MAX_MODULE; + break; + case MV_6192_DEV_ID: + maxMppGrp = MV_6192_MPP_MAX_MODULE; + break; + case MV_6190_DEV_ID: + maxMppGrp = MV_6190_MPP_MAX_MODULE; + break; + case MV_6180_DEV_ID: + maxMppGrp = MV_6180_MPP_MAX_MODULE; + break; + } + + for (devClass = 0; devClass < maxMppGrp; devClass++) + { + mppGroupType = mvBoardMppGroupTypeGet(devClass); + + switch(mppGroupType) + { + case MV_BOARD_TDM: + if(devId != MV_6190_DEV_ID) + mvOsPrintf("Module %d is TDM\n", devClass); + break; + case MV_BOARD_AUDIO: + if(devId != MV_6190_DEV_ID) + mvOsPrintf("Module %d is AUDIO\n", devClass); + break; + case MV_BOARD_RGMII: + if(devId != MV_6190_DEV_ID) + mvOsPrintf("Module %d is RGMII\n", devClass); + break; + case MV_BOARD_GMII: + if(devId != MV_6190_DEV_ID) + mvOsPrintf("Module %d is GMII\n", devClass); + break; + case MV_BOARD_TS: + if(devId != MV_6190_DEV_ID) + mvOsPrintf("Module %d is TS\n", devClass); + break; + default: + break; + } + } +} + +/* Board devices API managments */ + +/******************************************************************************* +* mvBoardGetDeviceNumber - Get number of device of some type on the board +* +* DESCRIPTION: +* +* INPUT: +* devType - The device type ( Flash,RTC , etc .. ) +* +* OUTPUT: +* None. +* +* RETURN: +* If the device is found on the board the then the functions returns the +* number of those devices else the function returns 0 +* +* +*******************************************************************************/ +MV_32 mvBoardGetDevicesNumber(MV_BOARD_DEV_CLASS devClass) +{ + MV_U32 foundIndex=0,devNum; + MV_U32 boardId= mvBoardIdGet(); + + if (!((boardId >= BOARD_ID_BASE)&&(boardId < MV_MAX_BOARD_ID))) + { + mvOsPrintf("mvBoardGetDeviceNumber:Board unknown.\n"); + return 0xFFFFFFFF; + + } + + for (devNum = START_DEV_CS; devNum < BOARD_INFO(boardId)->numBoardDeviceIf; devNum++) + { + if (BOARD_INFO(boardId)->pDevCsInfo[devNum].devClass == devClass) + { + foundIndex++; + } + } + + return foundIndex; + +} + +/******************************************************************************* +* mvBoardGetDeviceBaseAddr - Get base address of a device existing on the board +* +* DESCRIPTION: +* +* INPUT: +* devIndex - The device sequential number on the board +* devType - The device type ( Flash,RTC , etc .. ) +* +* OUTPUT: +* None. +* +* RETURN: +* If the device is found on the board the then the functions returns the +* Base address else the function returns 0xffffffff +* +* +*******************************************************************************/ +MV_32 mvBoardGetDeviceBaseAddr(MV_32 devNum, MV_BOARD_DEV_CLASS devClass) +{ + MV_DEV_CS_INFO* devEntry; + devEntry = boardGetDevEntry(devNum,devClass); + if (devEntry != NULL) + { + return mvCpuIfTargetWinBaseLowGet(DEV_TO_TARGET(devEntry->deviceCS)); + + } + + return 0xFFFFFFFF; +} + +/******************************************************************************* +* mvBoardGetDeviceBusWidth - Get Bus width of a device existing on the board +* +* DESCRIPTION: +* +* INPUT: +* devIndex - The device sequential number on the board +* devType - The device type ( Flash,RTC , etc .. ) +* +* OUTPUT: +* None. +* +* RETURN: +* If the device is found on the board the then the functions returns the +* Bus width else the function returns 0xffffffff +* +* +*******************************************************************************/ +MV_32 mvBoardGetDeviceBusWidth(MV_32 devNum, MV_BOARD_DEV_CLASS devClass) +{ + MV_DEV_CS_INFO* devEntry; + + devEntry = boardGetDevEntry(devNum,devClass); + if (devEntry != NULL) + { + return 8; + } + + return 0xFFFFFFFF; + +} + +/******************************************************************************* +* mvBoardGetDeviceWidth - Get dev width of a device existing on the board +* +* DESCRIPTION: +* +* INPUT: +* devIndex - The device sequential number on the board +* devType - The device type ( Flash,RTC , etc .. ) +* +* OUTPUT: +* None. +* +* RETURN: +* If the device is found on the board the then the functions returns the +* dev width else the function returns 0xffffffff +* +* +*******************************************************************************/ +MV_32 mvBoardGetDeviceWidth(MV_32 devNum, MV_BOARD_DEV_CLASS devClass) +{ + MV_DEV_CS_INFO* devEntry; + MV_U32 boardId= mvBoardIdGet(); + + if (!((boardId >= BOARD_ID_BASE)&&(boardId < MV_MAX_BOARD_ID))) + { + mvOsPrintf("Board unknown.\n"); + return 0xFFFFFFFF; + } + + devEntry = boardGetDevEntry(devNum,devClass); + if (devEntry != NULL) + return devEntry->devWidth; + + return MV_ERROR; + +} + +/******************************************************************************* +* mvBoardGetDeviceWinSize - Get the window size of a device existing on the board +* +* DESCRIPTION: +* +* INPUT: +* devIndex - The device sequential number on the board +* devType - The device type ( Flash,RTC , etc .. ) +* +* OUTPUT: +* None. +* +* RETURN: +* If the device is found on the board the then the functions returns the +* window size else the function returns 0xffffffff +* +* +*******************************************************************************/ +MV_32 mvBoardGetDeviceWinSize(MV_32 devNum, MV_BOARD_DEV_CLASS devClass) +{ + MV_DEV_CS_INFO* devEntry; + MV_U32 boardId = mvBoardIdGet(); + + if (!((boardId >= BOARD_ID_BASE)&&(boardId < MV_MAX_BOARD_ID))) + { + mvOsPrintf("Board unknown.\n"); + return 0xFFFFFFFF; + } + + devEntry = boardGetDevEntry(devNum,devClass); + if (devEntry != NULL) + { + return mvCpuIfTargetWinSizeGet(DEV_TO_TARGET(devEntry->deviceCS)); + } + + return 0xFFFFFFFF; +} + + +/******************************************************************************* +* boardGetDevEntry - returns the entry pointer of a device on the board +* +* DESCRIPTION: +* +* INPUT: +* devIndex - The device sequential number on the board +* devType - The device type ( Flash,RTC , etc .. ) +* +* OUTPUT: +* None. +* +* RETURN: +* If the device is found on the board the then the functions returns the +* dev number else the function returns 0x0 +* +* +*******************************************************************************/ +static MV_DEV_CS_INFO* boardGetDevEntry(MV_32 devNum, MV_BOARD_DEV_CLASS devClass) +{ + MV_U32 foundIndex=0,devIndex; + MV_U32 boardId= mvBoardIdGet(); + + if (!((boardId >= BOARD_ID_BASE)&&(boardId < MV_MAX_BOARD_ID))) + { + mvOsPrintf("boardGetDevEntry: Board unknown.\n"); + return NULL; + + } + + for (devIndex = START_DEV_CS; devIndex < BOARD_INFO(boardId)->numBoardDeviceIf; devIndex++) + { + /* TBR */ + /*if (BOARD_INFO(boardId)->pDevCsInfo[devIndex].deviceCS == MV_BOOTDEVICE_INDEX) + continue;*/ + + if (BOARD_INFO(boardId)->pDevCsInfo[devIndex].devClass == devClass) + { + if (foundIndex == devNum) + { + return &(BOARD_INFO(boardId)->pDevCsInfo[devIndex]); + } + foundIndex++; + } + } + + /* device not found */ + return NULL; +} + +/* Get device CS number */ + +MV_U32 boardGetDevCSNum(MV_32 devNum, MV_BOARD_DEV_CLASS devClass) +{ + MV_DEV_CS_INFO* devEntry; + MV_U32 boardId= mvBoardIdGet(); + + if (!((boardId >= BOARD_ID_BASE)&&(boardId < MV_MAX_BOARD_ID))) + { + mvOsPrintf("Board unknown.\n"); + return 0xFFFFFFFF; + + } + + + devEntry = boardGetDevEntry(devNum,devClass); + if (devEntry != NULL) + return devEntry->deviceCS; + + return 0xFFFFFFFF; + +} + +/******************************************************************************* +* mvBoardRtcTwsiAddrTypeGet - +* +* DESCRIPTION: +* +* INPUT: +* +* OUTPUT: +* None. +* +* RETURN: +* +* +*******************************************************************************/ +MV_U8 mvBoardRtcTwsiAddrTypeGet() +{ + int i; + MV_U32 boardId= mvBoardIdGet(); + + for (i = 0; i < BOARD_INFO(boardId)->numBoardTwsiDev; i++) + if (BOARD_INFO(boardId)->pBoardTwsiDev[i].devClass == BOARD_TWSI_RTC) + return BOARD_INFO(boardId)->pBoardTwsiDev[i].twsiDevAddrType; + return (MV_ERROR); +} + +/******************************************************************************* +* mvBoardRtcTwsiAddrGet - +* +* DESCRIPTION: +* +* INPUT: +* +* OUTPUT: +* None. +* +* RETURN: +* +* +*******************************************************************************/ +MV_U8 mvBoardRtcTwsiAddrGet() +{ + int i; + MV_U32 boardId= mvBoardIdGet(); + + for (i = 0; i < BOARD_INFO(boardId)->numBoardTwsiDev; i++) + if (BOARD_INFO(boardId)->pBoardTwsiDev[i].devClass == BOARD_TWSI_RTC) + return BOARD_INFO(boardId)->pBoardTwsiDev[i].twsiDevAddr; + return (0xFF); +} + +/******************************************************************************* +* mvBoardA2DTwsiAddrTypeGet - +* +* DESCRIPTION: +* +* INPUT: +* +* OUTPUT: +* None. +* +* RETURN: +* +* +*******************************************************************************/ +MV_U8 mvBoardA2DTwsiAddrTypeGet() +{ + int i; + MV_U32 boardId= mvBoardIdGet(); + + for (i = 0; i < BOARD_INFO(boardId)->numBoardTwsiDev; i++) + if (BOARD_INFO(boardId)->pBoardTwsiDev[i].devClass == BOARD_TWSI_AUDIO_DEC) + return BOARD_INFO(boardId)->pBoardTwsiDev[i].twsiDevAddrType; + return (MV_ERROR); +} + +/******************************************************************************* +* mvBoardA2DTwsiAddrGet - +* +* DESCRIPTION: +* +* INPUT: +* +* OUTPUT: +* None. +* +* RETURN: +* +* +*******************************************************************************/ +MV_U8 mvBoardA2DTwsiAddrGet() +{ + int i; + MV_U32 boardId= mvBoardIdGet(); + + for (i = 0; i < BOARD_INFO(boardId)->numBoardTwsiDev; i++) + if (BOARD_INFO(boardId)->pBoardTwsiDev[i].devClass == BOARD_TWSI_AUDIO_DEC) + return BOARD_INFO(boardId)->pBoardTwsiDev[i].twsiDevAddr; + return (0xFF); +} + +/******************************************************************************* +* mvBoardTwsiExpAddrTypeGet - +* +* DESCRIPTION: +* +* INPUT: +* +* OUTPUT: +* None. +* +* RETURN: +* +* +*******************************************************************************/ +MV_U8 mvBoardTwsiExpAddrTypeGet(MV_U32 index) +{ + int i; + MV_U32 indexFound = 0; + MV_U32 boardId= mvBoardIdGet(); + + for (i = 0; i < BOARD_INFO(boardId)->numBoardTwsiDev; i++) + if (BOARD_INFO(boardId)->pBoardTwsiDev[i].devClass == BOARD_DEV_TWSI_EXP) + { + if (indexFound == index) + return BOARD_INFO(boardId)->pBoardTwsiDev[i].twsiDevAddrType; + else + indexFound++; + } + + return (MV_ERROR); +} + +/******************************************************************************* +* mvBoardTwsiExpAddrGet - +* +* DESCRIPTION: +* +* INPUT: +* +* OUTPUT: +* None. +* +* RETURN: +* +* +*******************************************************************************/ +MV_U8 mvBoardTwsiExpAddrGet(MV_U32 index) +{ + int i; + MV_U32 indexFound = 0; + MV_U32 boardId= mvBoardIdGet(); + + for (i = 0; i < BOARD_INFO(boardId)->numBoardTwsiDev; i++) + if (BOARD_INFO(boardId)->pBoardTwsiDev[i].devClass == BOARD_DEV_TWSI_EXP) + { + if (indexFound == index) + return BOARD_INFO(boardId)->pBoardTwsiDev[i].twsiDevAddr; + else + indexFound++; + } + + return (0xFF); +} + + +/******************************************************************************* +* mvBoardTwsiSatRAddrTypeGet - +* +* DESCRIPTION: +* +* INPUT: +* +* OUTPUT: +* None. +* +* RETURN: +* +* +*******************************************************************************/ +MV_U8 mvBoardTwsiSatRAddrTypeGet(MV_U32 index) +{ + int i; + MV_U32 indexFound = 0; + MV_U32 boardId= mvBoardIdGet(); + + for (i = 0; i < BOARD_INFO(boardId)->numBoardTwsiDev; i++) + if (BOARD_INFO(boardId)->pBoardTwsiDev[i].devClass == BOARD_DEV_TWSI_SATR) + { + if (indexFound == index) + return BOARD_INFO(boardId)->pBoardTwsiDev[i].twsiDevAddrType; + else + indexFound++; + } + + return (MV_ERROR); +} + +/******************************************************************************* +* mvBoardTwsiSatRAddrGet - +* +* DESCRIPTION: +* +* INPUT: +* +* OUTPUT: +* None. +* +* RETURN: +* +* +*******************************************************************************/ +MV_U8 mvBoardTwsiSatRAddrGet(MV_U32 index) +{ + int i; + MV_U32 indexFound = 0; + MV_U32 boardId= mvBoardIdGet(); + + for (i = 0; i < BOARD_INFO(boardId)->numBoardTwsiDev; i++) + if (BOARD_INFO(boardId)->pBoardTwsiDev[i].devClass == BOARD_DEV_TWSI_SATR) + { + if (indexFound == index) + return BOARD_INFO(boardId)->pBoardTwsiDev[i].twsiDevAddr; + else + indexFound++; + } + + return (0xFF); +} + +/******************************************************************************* +* mvBoardNandWidthGet - +* +* DESCRIPTION: Get the width of the first NAND device in byte. +* +* INPUT: +* +* OUTPUT: +* None. +* +* RETURN: 1, 2, 4 or MV_ERROR +* +* +*******************************************************************************/ +/* */ +MV_32 mvBoardNandWidthGet(void) +{ + MV_U32 devNum; + MV_U32 devWidth; + MV_U32 boardId= mvBoardIdGet(); + + for (devNum = START_DEV_CS; devNum < BOARD_INFO(boardId)->numBoardDeviceIf; devNum++) + { + devWidth = mvBoardGetDeviceWidth(devNum, BOARD_DEV_NAND_FLASH); + if (devWidth != MV_ERROR) + return (devWidth / 8); + } + + /* NAND wasn't found */ + return MV_ERROR; +} + +MV_U32 gBoardId = -1; + +/******************************************************************************* +* mvBoardIdGet - Get Board model +* +* DESCRIPTION: +* This function returns board ID. +* Board ID is 32bit word constructed of board model (16bit) and +* board revision (16bit) in the following way: 0xMMMMRRRR. +* +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* 32bit board ID number, '-1' if board is undefined. +* +*******************************************************************************/ +MV_U32 mvBoardIdGet(MV_VOID) +{ + MV_U32 tmpBoardId = -1; + + if(gBoardId == -1) + { + #if defined(DB_88F6281A) + tmpBoardId = DB_88F6281A_BP_ID; + #elif defined(RD_88F6281A) + tmpBoardId = RD_88F6281A_ID; + #elif defined(DB_88F6192A) + tmpBoardId = DB_88F6192A_BP_ID; + #elif defined(DB_88F6190A) + tmpBoardId = DB_88F6190A_BP_ID; + #elif defined(RD_88F6192A) + tmpBoardId = RD_88F6192A_ID; + #elif defined(RD_88F6190A) + tmpBoardId = RD_88F6190A_ID; + #elif defined(DB_88F6180A) + tmpBoardId = DB_88F6180A_BP_ID; + #elif defined(RD_88F6281A_PCAC) + tmpBoardId = RD_88F6281A_PCAC_ID; + #elif defined(RD_88F6281A_SHEEVA_PLUG) + tmpBoardId = SHEEVA_PLUG_ID; + #elif defined(DB_CUSTOMER) + tmpBoardId = DB_CUSTOMER_ID; + #endif + gBoardId = tmpBoardId; + } + + return gBoardId; +} + + +/******************************************************************************* +* mvBoarModuleTypeGet - mvBoarModuleTypeGet +* +* DESCRIPTION: +* +* INPUT: +* group num - MV_BOARD_MPP_GROUP_CLASS enum +* +* OUTPUT: +* None. +* +* RETURN: +* module num - MV_BOARD_MODULE_CLASS enum +* +*******************************************************************************/ +MV_BOARD_MODULE_ID_CLASS mvBoarModuleTypeGet(MV_BOARD_MPP_GROUP_CLASS devClass) +{ + MV_TWSI_SLAVE twsiSlave; + MV_TWSI_ADDR slave; + MV_U8 data; + + /* TWSI init */ + slave.type = ADDR7_BIT; + slave.address = 0; + mvTwsiInit(0, TWSI_SPEED, mvBoardTclkGet(), &slave, 0); + + /* Read MPP module ID */ + DB(mvOsPrintf("Board: Read MPP module ID\n")); + twsiSlave.slaveAddr.address = mvBoardTwsiExpAddrGet(devClass); + twsiSlave.slaveAddr.type = mvBoardTwsiExpAddrTypeGet(devClass); + twsiSlave.validOffset = MV_TRUE; + /* Offset is the first command after the address which indicate the register number to be read + in next operation */ + twsiSlave.offset = 0; + twsiSlave.moreThen256 = MV_FALSE; + + + + if( MV_OK != mvTwsiRead (0, &twsiSlave, &data, 1) ) + { + DB(mvOsPrintf("Board: Read MPP module ID fail\n")); + return MV_ERROR; + } + DB(mvOsPrintf("Board: Read MPP module ID succeded\n")); + + return data; +} + +/******************************************************************************* +* mvBoarTwsiSatRGet - +* +* DESCRIPTION: +* +* INPUT: +* device num - one of three devices +* reg num - 0 or 1 +* +* OUTPUT: +* None. +* +* RETURN: +* reg value +* +*******************************************************************************/ +MV_U8 mvBoarTwsiSatRGet(MV_U8 devNum, MV_U8 regNum) +{ + MV_TWSI_SLAVE twsiSlave; + MV_TWSI_ADDR slave; + MV_U8 data; + + /* TWSI init */ + slave.type = ADDR7_BIT; + slave.address = 0; + mvTwsiInit(0, TWSI_SPEED, mvBoardTclkGet(), &slave, 0); + + /* Read MPP module ID */ + DB(mvOsPrintf("Board: Read S@R device read\n")); + twsiSlave.slaveAddr.address = mvBoardTwsiSatRAddrGet(devNum); + twsiSlave.slaveAddr.type = mvBoardTwsiSatRAddrTypeGet(devNum); + twsiSlave.validOffset = MV_TRUE; + /* Use offset as command */ + twsiSlave.offset = regNum; + twsiSlave.moreThen256 = MV_FALSE; + + if( MV_OK != mvTwsiRead (0, &twsiSlave, &data, 1) ) + { + DB(mvOsPrintf("Board: Read S@R fail\n")); + return MV_ERROR; + } + DB(mvOsPrintf("Board: Read S@R succeded\n")); + + return data; +} + +/******************************************************************************* +* mvBoarTwsiSatRSet - +* +* DESCRIPTION: +* +* INPUT: +* devNum - one of three devices +* regNum - 0 or 1 +* regVal - value +* +* +* OUTPUT: +* None. +* +* RETURN: +* reg value +* +*******************************************************************************/ +MV_STATUS mvBoarTwsiSatRSet(MV_U8 devNum, MV_U8 regNum, MV_U8 regVal) +{ + MV_TWSI_SLAVE twsiSlave; + MV_TWSI_ADDR slave; + + /* TWSI init */ + slave.type = ADDR7_BIT; + slave.address = 0; + mvTwsiInit(0, TWSI_SPEED, mvBoardTclkGet(), &slave, 0); + + /* Read MPP module ID */ + twsiSlave.slaveAddr.address = mvBoardTwsiSatRAddrGet(devNum); + twsiSlave.slaveAddr.type = mvBoardTwsiSatRAddrTypeGet(devNum); + twsiSlave.validOffset = MV_TRUE; + DB(mvOsPrintf("Board: Write S@R device addr %x, type %x, data %x\n", twsiSlave.slaveAddr.address,\ + twsiSlave.slaveAddr.type, regVal)); + /* Use offset as command */ + twsiSlave.offset = regNum; + twsiSlave.moreThen256 = MV_FALSE; + if( MV_OK != mvTwsiWrite (0, &twsiSlave, ®Val, 1) ) + { + DB(mvOsPrintf("Board: Write S@R fail\n")); + return MV_ERROR; + } + DB(mvOsPrintf("Board: Write S@R succeded\n")); + + return MV_OK; +} + +/******************************************************************************* +* mvBoardSlicGpioPinGet - +* +* DESCRIPTION: +* +* INPUT: +* +* OUTPUT: +* None. +* +* RETURN: +* +* +*******************************************************************************/ +MV_32 mvBoardSlicGpioPinGet(MV_U32 slicNum) +{ + MV_U32 boardId; + boardId = mvBoardIdGet(); + + switch (boardId) + { + case DB_88F6281A_BP_ID: + case RD_88F6281A_ID: + default: + return MV_ERROR; + break; + + } +} + +/******************************************************************************* +* mvBoardFanPowerControl - Turn on/off the fan power control on the RD-6281A +* +* DESCRIPTION: +* +* INPUT: +* mode - MV_TRUE = on ; MV_FALSE = off +* +* OUTPUT: +* MV_STATUS - MV_OK , MV_ERROR. +* +* RETURN: +* +*******************************************************************************/ +MV_STATUS mvBoardFanPowerControl(MV_BOOL mode) +{ + + MV_U8 val = 1, twsiVal; + MV_TWSI_SLAVE twsiSlave; + MV_TWSI_ADDR slave; + + if(mvBoardIdGet() != RD_88F6281A_ID) + return MV_ERROR; + + /* TWSI init */ + slave.type = ADDR7_BIT; + slave.address = 0; + mvTwsiInit(0, TWSI_SPEED, mvBoardTclkGet(), &slave, 0); + + /* Read MPP module ID */ + DB(mvOsPrintf("Board: twsi exp set\n")); + twsiSlave.slaveAddr.address = mvBoardTwsiExpAddrGet(1); + twsiSlave.slaveAddr.type = ADDR7_BIT; + twsiSlave.validOffset = MV_TRUE; + /* Offset is the first command after the address which indicate the register number to be read + in next operation */ + twsiSlave.offset = 3; + twsiSlave.moreThen256 = MV_FALSE; + if(mode == MV_TRUE) + val = 0x1; + else + val = 0; + mvTwsiRead(0, &twsiSlave, &twsiVal, 1); + val = (twsiVal & 0xfe) | val; + + if( MV_OK != mvTwsiWrite (0, &twsiSlave, &val, 1) ) + { + DB(mvOsPrintf("Board: twsi exp out val fail\n")); + return MV_ERROR; + } + DB(mvOsPrintf("Board: twsi exp out val succeded\n")); + + /* Change twsi exp to output */ + twsiSlave.offset = 7; + mvTwsiRead(0, &twsiSlave, &twsiVal, 1); + val = (twsiVal & 0xfe); + if( MV_OK != mvTwsiWrite (0, &twsiSlave, &val, 1) ) + { + DB(mvOsPrintf("Board: twsi exp change to out fail\n")); + return MV_ERROR; + } + DB(mvOsPrintf("Board: twsi exp change to out succeded\n")); + return MV_OK; +} + +/******************************************************************************* +* mvBoardHDDPowerControl - Turn on/off the HDD power control on the RD-6281A +* +* DESCRIPTION: +* +* INPUT: +* mode - MV_TRUE = on ; MV_FALSE = off +* +* OUTPUT: +* MV_STATUS - MV_OK , MV_ERROR. +* +* RETURN: +* +*******************************************************************************/ +MV_STATUS mvBoardHDDPowerControl(MV_BOOL mode) +{ + + MV_U8 val = 1, twsiVal; + MV_TWSI_SLAVE twsiSlave; + MV_TWSI_ADDR slave; + + if(mvBoardIdGet() != RD_88F6281A_ID) + return MV_ERROR; + + /* TWSI init */ + slave.type = ADDR7_BIT; + slave.address = 0; + mvTwsiInit(0, TWSI_SPEED, mvBoardTclkGet(), &slave, 0); + + /* Read MPP module ID */ + DB(mvOsPrintf("Board: twsi exp set\n")); + twsiSlave.slaveAddr.address = mvBoardTwsiExpAddrGet(1); + twsiSlave.slaveAddr.type = ADDR7_BIT; + twsiSlave.validOffset = MV_TRUE; + /* Offset is the first command after the address which indicate the register number to be read + in next operation */ + twsiSlave.offset = 3; + twsiSlave.moreThen256 = MV_FALSE; + if(mode == MV_TRUE) + val = 0x2; + else + val = 0; + mvTwsiRead(0, &twsiSlave, &twsiVal, 1); + val = (twsiVal & 0xfd) | val; + if( MV_OK != mvTwsiWrite (0, &twsiSlave, &val, 1) ) + { + DB(mvOsPrintf("Board: twsi exp out val fail\n")); + return MV_ERROR; + } + DB(mvOsPrintf("Board: twsi exp out val succeded\n")); + + /* Change twsi exp to output */ + twsiSlave.offset = 7; + mvTwsiRead(0, &twsiSlave, &twsiVal, 1); + val = (twsiVal & 0xfd); + if( MV_OK != mvTwsiWrite (0, &twsiSlave, &val, 1) ) + { + DB(mvOsPrintf("Board: twsi exp change to out fail\n")); + return MV_ERROR; + } + DB(mvOsPrintf("Board: twsi exp change to out succeded\n")); + return MV_OK; +} + +/******************************************************************************* +* mvBoardSDioWPControl - Turn on/off the SDIO WP on the RD-6281A +* +* DESCRIPTION: +* +* INPUT: +* mode - MV_TRUE = on ; MV_FALSE = off +* +* OUTPUT: +* MV_STATUS - MV_OK , MV_ERROR. +* +* RETURN: +* +*******************************************************************************/ +MV_STATUS mvBoardSDioWPControl(MV_BOOL mode) +{ + + MV_U8 val = 1, twsiVal; + MV_TWSI_SLAVE twsiSlave; + MV_TWSI_ADDR slave; + + if(mvBoardIdGet() != RD_88F6281A_ID) + return MV_ERROR; + + /* TWSI init */ + slave.type = ADDR7_BIT; + slave.address = 0; + mvTwsiInit(0, TWSI_SPEED, mvBoardTclkGet(), &slave, 0); + + /* Read MPP module ID */ + DB(mvOsPrintf("Board: twsi exp set\n")); + twsiSlave.slaveAddr.address = mvBoardTwsiExpAddrGet(0); + twsiSlave.slaveAddr.type = ADDR7_BIT; + twsiSlave.validOffset = MV_TRUE; + /* Offset is the first command after the address which indicate the register number to be read + in next operation */ + twsiSlave.offset = 3; + twsiSlave.moreThen256 = MV_FALSE; + if(mode == MV_TRUE) + val = 0x10; + else + val = 0; + mvTwsiRead(0, &twsiSlave, &twsiVal, 1); + val = (twsiVal & 0xef) | val; + if( MV_OK != mvTwsiWrite (0, &twsiSlave, &val, 1) ) + { + DB(mvOsPrintf("Board: twsi exp out val fail\n")); + return MV_ERROR; + } + DB(mvOsPrintf("Board: twsi exp out val succeded\n")); + + /* Change twsi exp to output */ + twsiSlave.offset = 7; + mvTwsiRead(0, &twsiSlave, &twsiVal, 1); + val = (twsiVal & 0xef); + if( MV_OK != mvTwsiWrite (0, &twsiSlave, &val, 1) ) + { + DB(mvOsPrintf("Board: twsi exp change to out fail\n")); + return MV_ERROR; + } + DB(mvOsPrintf("Board: twsi exp change to out succeded\n")); + return MV_OK; +} + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/boardEnv/mvBoardEnvLib.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/boardEnv/mvBoardEnvLib.h new file mode 100644 index 0000000..dead633 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/boardEnv/mvBoardEnvLib.h @@ -0,0 +1,376 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ +#ifndef __INCmvBoardEnvLibh +#define __INCmvBoardEnvLibh + +/* defines */ +/* The below constant macros defines the board I2C EEPROM data offsets */ + + + +#include "ctrlEnv/mvCtrlEnvLib.h" +#include "mvSysHwConfig.h" +#include "boardEnv/mvBoardEnvSpec.h" + + +/* DUART stuff for Tclk detection only */ +#define DUART_BAUD_RATE 115200 +#define MAX_CLOCK_MARGINE 5000000 /* Maximum detected clock margine */ + +/* Voice devices assembly modes */ +#define DAISY_CHAIN_MODE 1 +#define DUAL_CHIP_SELECT_MODE 0 +#define INTERRUPT_TO_MPP 1 +#define INTERRUPT_TO_TDM 0 + + +#define BOARD_ETH_PORT_NUM MV_ETH_MAX_PORTS +#define BOARD_ETH_SWITCH_PORT_NUM 5 + +#define MV_BOARD_MAX_USB_IF 1 +#define MV_BOARD_MAX_MPP 7 +#define MV_BOARD_NAME_LEN 0x20 + +typedef struct _boardData +{ + MV_U32 magic; + MV_U16 boardId; + MV_U8 boardVer; + MV_U8 boardRev; + MV_U32 reserved1; + MV_U32 reserved2; + +}BOARD_DATA; + +typedef enum _devBoardMppGroupClass +{ + MV_BOARD_MPP_GROUP_1, + MV_BOARD_MPP_GROUP_2, + MV_BOARD_MAX_MPP_GROUP +}MV_BOARD_MPP_GROUP_CLASS; + +typedef enum _devBoardMppTypeClass +{ + MV_BOARD_AUTO, + MV_BOARD_TDM, + MV_BOARD_AUDIO, + MV_BOARD_RGMII, + MV_BOARD_GMII, + MV_BOARD_TS, + MV_BOARD_MII, + MV_BOARD_OTHER +}MV_BOARD_MPP_TYPE_CLASS; + +typedef enum _devBoardModuleIdClass +{ + MV_BOARD_MODULE_TDM_ID = 1, + MV_BOARD_MODULE_AUDIO_ID, + MV_BOARD_MODULE_RGMII_ID, + MV_BOARD_MODULE_GMII_ID, + MV_BOARD_MODULE_TS_ID, + MV_BOARD_MODULE_MII_ID, + MV_BOARD_MODULE_TDM_5CHAN_ID, + MV_BOARD_MODULE_OTHER_ID +}MV_BOARD_MODULE_ID_CLASS; + +typedef struct _boardMppTypeInfo +{ + MV_BOARD_MPP_TYPE_CLASS boardMppGroup1; + MV_BOARD_MPP_TYPE_CLASS boardMppGroup2; + +}MV_BOARD_MPP_TYPE_INFO; + + +typedef enum _devBoardClass +{ + BOARD_DEV_NOR_FLASH, + BOARD_DEV_NAND_FLASH, + BOARD_DEV_SEVEN_SEG, + BOARD_DEV_FPGA, + BOARD_DEV_SRAM, + BOARD_DEV_SPI_FLASH, + BOARD_DEV_OTHER, +}MV_BOARD_DEV_CLASS; + +typedef enum _devTwsiBoardClass +{ + BOARD_TWSI_RTC, + BOARD_DEV_TWSI_EXP, + BOARD_DEV_TWSI_SATR, + BOARD_TWSI_AUDIO_DEC, + BOARD_TWSI_OTHER +}MV_BOARD_TWSI_CLASS; + +typedef enum _devGppBoardClass +{ + BOARD_GPP_RTC, + BOARD_GPP_MV_SWITCH, + BOARD_GPP_USB_VBUS, + BOARD_GPP_USB_VBUS_EN, + BOARD_GPP_USB_OC, + BOARD_GPP_USB_HOST_DEVICE, + BOARD_GPP_REF_CLCK, + BOARD_GPP_VOIP_SLIC, + BOARD_GPP_LIFELINE, + BOARD_GPP_BUTTON, + BOARD_GPP_TS_BUTTON_C, + BOARD_GPP_TS_BUTTON_U, + BOARD_GPP_TS_BUTTON_D, + BOARD_GPP_TS_BUTTON_L, + BOARD_GPP_TS_BUTTON_R, + BOARD_GPP_POWER_BUTTON, + BOARD_GPP_RESTOR_BUTTON, + BOARD_GPP_WPS_BUTTON, + BOARD_GPP_HDD0_POWER, + BOARD_GPP_HDD1_POWER, + BOARD_GPP_FAN_POWER, + BOARD_GPP_RESET, + BOARD_GPP_POWER_ON_LED, + BOARD_GPP_HDD_POWER, + BOARD_GPP_SDIO_POWER, + BOARD_GPP_SDIO_DETECT, + BOARD_GPP_SDIO_WP, + BOARD_GPP_SWITCH_PHY_INT, + BOARD_GPP_TSU_DIRCTION, + BOARD_GPP_OTHER +}MV_BOARD_GPP_CLASS; + + +typedef struct _devCsInfo +{ + MV_U8 deviceCS; + MV_U32 params; + MV_U32 devClass; /* MV_BOARD_DEV_CLASS */ + MV_U8 devWidth; + +}MV_DEV_CS_INFO; + + +#define MV_BOARD_PHY_FORCE_10MB 0x0 +#define MV_BOARD_PHY_FORCE_100MB 0x1 +#define MV_BOARD_PHY_FORCE_1000MB 0x2 +#define MV_BOARD_PHY_SPEED_AUTO 0x3 + +typedef struct _boardSwitchInfo +{ + MV_32 linkStatusIrq; + MV_32 qdPort[BOARD_ETH_SWITCH_PORT_NUM]; + MV_32 qdCpuPort; + MV_32 smiScanMode; /* 1 for SMI_MANUAL_MODE, 0 otherwise */ + MV_32 switchOnPort; + +}MV_BOARD_SWITCH_INFO; + +typedef struct _boardLedInfo +{ + MV_U8 activeLedsNumber; + MV_U8 ledsPolarity; /* '0' or '1' to turn on led */ + MV_U8* gppPinNum; /* Pointer to GPP values */ + +}MV_BOARD_LED_INFO; + +typedef struct _boardGppInfo +{ + MV_BOARD_GPP_CLASS devClass; + MV_U8 gppPinNum; + +}MV_BOARD_GPP_INFO; + + +typedef struct _boardTwsiInfo +{ + MV_BOARD_TWSI_CLASS devClass; + MV_U8 twsiDevAddr; + MV_U8 twsiDevAddrType; + +}MV_BOARD_TWSI_INFO; + + +typedef enum _boardMacSpeed +{ + BOARD_MAC_SPEED_10M, + BOARD_MAC_SPEED_100M, + BOARD_MAC_SPEED_1000M, + BOARD_MAC_SPEED_AUTO, + +}MV_BOARD_MAC_SPEED; + +typedef struct _boardMacInfo +{ + MV_BOARD_MAC_SPEED boardMacSpeed; + MV_U8 boardEthSmiAddr; + +}MV_BOARD_MAC_INFO; + +typedef struct _boardMppInfo +{ + MV_U32 mppGroup[MV_BOARD_MAX_MPP]; + +}MV_BOARD_MPP_INFO; + +typedef struct _boardInfo +{ + char boardName[MV_BOARD_NAME_LEN]; + MV_U8 numBoardMppTypeValue; + MV_BOARD_MPP_TYPE_INFO* pBoardMppTypeValue; + MV_U8 numBoardMppConfigValue; + MV_BOARD_MPP_INFO* pBoardMppConfigValue; + MV_U32 intsGppMaskLow; + MV_U32 intsGppMaskHigh; + MV_U8 numBoardDeviceIf; + MV_DEV_CS_INFO* pDevCsInfo; + MV_U8 numBoardTwsiDev; + MV_BOARD_TWSI_INFO* pBoardTwsiDev; + MV_U8 numBoardMacInfo; + MV_BOARD_MAC_INFO* pBoardMacInfo; + MV_U8 numBoardGppInfo; + MV_BOARD_GPP_INFO* pBoardGppInfo; + MV_U8 activeLedsNumber; + MV_U8* pLedGppPin; + MV_U8 ledsPolarity; /* '0' or '1' to turn on led */ + /* GPP values */ + MV_U32 gppOutEnValLow; + MV_U32 gppOutEnValHigh; + MV_U32 gppOutValLow; + MV_U32 gppOutValHigh; + MV_U32 gppPolarityValLow; + MV_U32 gppPolarityValHigh; + + /* Switch Configuration */ + MV_BOARD_SWITCH_INFO* pSwitchInfo; +}MV_BOARD_INFO; + + + +MV_VOID mvBoardEnvInit(MV_VOID); +MV_U32 mvBoardIdGet(MV_VOID); +MV_U16 mvBoardModelGet(MV_VOID); +MV_U16 mvBoardRevGet(MV_VOID); +MV_STATUS mvBoardNameGet(char *pNameBuff); +MV_32 mvBoardPhyAddrGet(MV_U32 ethPortNum); +MV_BOARD_MAC_SPEED mvBoardMacSpeedGet(MV_U32 ethPortNum); +MV_32 mvBoardLinkStatusIrqGet(MV_U32 ethPortNum); +MV_32 mvBoardSwitchPortGet(MV_U32 ethPortNum, MV_U8 boardPortNum); +MV_32 mvBoardSwitchCpuPortGet(MV_U32 ethPortNum); +MV_32 mvBoardIsSwitchConnected(MV_U32 ethPortNum); +MV_32 mvBoardSmiScanModeGet(MV_U32 ethPortNum); +MV_BOOL mvBoardIsPortInSgmii(MV_U32 ethPortNum); +MV_BOOL mvBoardIsPortInGmii(MV_VOID); +MV_U32 mvBoardTclkGet(MV_VOID); +MV_U32 mvBoardSysClkGet(MV_VOID); +MV_U32 mvBoardDebugLedNumGet(MV_U32 boardId); +MV_VOID mvBoardDebugLed(MV_U32 hexNum); +MV_32 mvBoardMppGet(MV_U32 mppGroupNum); + +MV_U8 mvBoardRtcTwsiAddrTypeGet(MV_VOID); +MV_U8 mvBoardRtcTwsiAddrGet(MV_VOID); + +MV_U8 mvBoardA2DTwsiAddrTypeGet(MV_VOID); +MV_U8 mvBoardA2DTwsiAddrGet(MV_VOID); + +MV_U8 mvBoardTwsiExpAddrGet(MV_U32 index); +MV_U8 mvBoardTwsiSatRAddrTypeGet(MV_U32 index); +MV_U8 mvBoardTwsiSatRAddrGet(MV_U32 index); +MV_U8 mvBoardTwsiExpAddrTypeGet(MV_U32 index); +MV_BOARD_MODULE_ID_CLASS mvBoarModuleTypeGet(MV_BOARD_MPP_GROUP_CLASS devClass); +MV_BOARD_MPP_TYPE_CLASS mvBoardMppGroupTypeGet(MV_BOARD_MPP_GROUP_CLASS mppGroupClass); +MV_VOID mvBoardMppGroupTypeSet(MV_BOARD_MPP_GROUP_CLASS mppGroupClass, + MV_BOARD_MPP_TYPE_CLASS mppGroupType); +MV_VOID mvBoardMppGroupIdUpdate(MV_VOID); +MV_VOID mvBoardMppMuxSet(MV_VOID); +MV_VOID mvBoardTdmMppSet(MV_32 chType); +MV_VOID mvBoardVoiceConnModeGet(MV_32* connMode, MV_32* irqMode); + +MV_VOID mvBoardMppModuleTypePrint(MV_VOID); +MV_VOID mvBoardReset(MV_VOID); +MV_U8 mvBoarTwsiSatRGet(MV_U8 devNum, MV_U8 regNum); +MV_STATUS mvBoarTwsiSatRSet(MV_U8 devNum, MV_U8 regNum, MV_U8 regVal); +MV_BOOL mvBoardSpecInitGet(MV_U32* regOff, MV_U32* data); +/* Board devices API managments */ +MV_32 mvBoardGetDevicesNumber(MV_BOARD_DEV_CLASS devClass); +MV_32 mvBoardGetDeviceBaseAddr(MV_32 devNum, MV_BOARD_DEV_CLASS devClass); +MV_32 mvBoardGetDeviceBusWidth(MV_32 devNum, MV_BOARD_DEV_CLASS devClass); +MV_32 mvBoardGetDeviceWidth(MV_32 devNum, MV_BOARD_DEV_CLASS devClass); +MV_32 mvBoardGetDeviceWinSize(MV_32 devNum, MV_BOARD_DEV_CLASS devClass); +MV_U32 boardGetDevCSNum(MV_32 devNum, MV_BOARD_DEV_CLASS devClass); + +/* Gpio Pin Connections API */ +MV_32 mvBoardUSBVbusGpioPinGet(int devId); +MV_32 mvBoardUSBVbusEnGpioPinGet(int devId); +MV_U32 mvBoardPexBridgeIntPinGet(MV_U32 devNum, MV_U32 intPin); + +MV_32 mvBoardResetGpioPinGet(MV_VOID); +MV_32 mvBoardRTCGpioPinGet(MV_VOID); +MV_32 mvBoardGpioIntMaskLowGet(MV_VOID); +MV_32 mvBoardGpioIntMaskHighGet(MV_VOID); +MV_32 mvBoardSlicGpioPinGet(MV_U32 slicNum); + +MV_32 mvBoardSDIOGpioPinGet(MV_VOID); +MV_STATUS mvBoardSDioWPControl(MV_BOOL mode); +MV_32 mvBoarGpioPinNumGet(MV_BOARD_GPP_CLASS class, MV_U32 index); + +MV_32 mvBoardNandWidthGet(void); +MV_STATUS mvBoardFanPowerControl(MV_BOOL mode); +MV_STATUS mvBoardHDDPowerControl(MV_BOOL mode); +#endif /* __INCmvBoardEnvLibh */ diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/boardEnv/mvBoardEnvSpec.c b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/boardEnv/mvBoardEnvSpec.c new file mode 100644 index 0000000..e256c4f --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/boardEnv/mvBoardEnvSpec.c @@ -0,0 +1,848 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ +#include "mvCommon.h" +#include "mvBoardEnvLib.h" +#include "mvBoardEnvSpec.h" +#include "twsi/mvTwsi.h" + +#define DB_88F6281A_BOARD_PCI_IF_NUM 0x0 +#define DB_88F6281A_BOARD_TWSI_DEF_NUM 0x7 +#define DB_88F6281A_BOARD_MAC_INFO_NUM 0x2 +#define DB_88F6281A_BOARD_GPP_INFO_NUM 0x3 +#define DB_88F6281A_BOARD_MPP_CONFIG_NUM 0x1 +#define DB_88F6281A_BOARD_MPP_GROUP_TYPE_NUM 0x1 +#if defined(MV_NAND) && defined(MV_NAND_BOOT) + #define DB_88F6281A_BOARD_DEVICE_CONFIG_NUM 0x1 +#elif defined(MV_NAND) && defined(MV_SPI_BOOT) + #define DB_88F6281A_BOARD_DEVICE_CONFIG_NUM 0x2 +#else + #define DB_88F6281A_BOARD_DEVICE_CONFIG_NUM 0x1 +#endif +#define DB_88F6281A_BOARD_DEBUG_LED_NUM 0x0 + + +MV_BOARD_TWSI_INFO db88f6281AInfoBoardTwsiDev[] = + /* {{MV_BOARD_DEV_CLASS devClass, MV_U8 twsiDevAddr, MV_U8 twsiDevAddrType}} */ + { + {BOARD_DEV_TWSI_EXP, 0x20, ADDR7_BIT}, + {BOARD_DEV_TWSI_EXP, 0x21, ADDR7_BIT}, + {BOARD_DEV_TWSI_EXP, 0x27, ADDR7_BIT}, + {BOARD_DEV_TWSI_SATR, 0x4C, ADDR7_BIT}, + {BOARD_DEV_TWSI_SATR, 0x4D, ADDR7_BIT}, + {BOARD_DEV_TWSI_SATR, 0x4E, ADDR7_BIT}, + {BOARD_TWSI_AUDIO_DEC, 0x4A, ADDR7_BIT} + }; + +MV_BOARD_MAC_INFO db88f6281AInfoBoardMacInfo[] = + /* {{MV_BOARD_MAC_SPEED boardMacSpeed, MV_U8 boardEthSmiAddr}} */ + { + {BOARD_MAC_SPEED_AUTO, 0x8}, + {BOARD_MAC_SPEED_AUTO, 0x9} + }; + +MV_BOARD_MPP_TYPE_INFO db88f6281AInfoBoardMppTypeInfo[] = + /* {{MV_BOARD_MPP_TYPE_CLASS boardMppGroup1, + MV_BOARD_MPP_TYPE_CLASS boardMppGroup2}} */ + {{MV_BOARD_AUTO, MV_BOARD_AUTO} + }; + +MV_BOARD_GPP_INFO db88f6281AInfoBoardGppInfo[] = + /* {{MV_BOARD_GPP_CLASS devClass, MV_U8 gppPinNum}} */ + { + {BOARD_GPP_TSU_DIRCTION, 33} + /*muxed with TDM/Audio module via IOexpender + {BOARD_GPP_SDIO_DETECT, 38}, + {BOARD_GPP_USB_VBUS, 49}*/ + }; + +MV_DEV_CS_INFO db88f6281AInfoBoardDeCsInfo[] = + /*{deviceCS, params, devType, devWidth}*/ +#if defined(MV_NAND) && defined(MV_NAND_BOOT) + {{0, N_A, BOARD_DEV_NAND_FLASH, 8}}; /* NAND DEV */ +#elif defined(MV_NAND) && defined(MV_SPI_BOOT) + { + {0, N_A, BOARD_DEV_NAND_FLASH, 8}, /* NAND DEV */ + {1, N_A, BOARD_DEV_SPI_FLASH, 8}, /* SPI DEV */ + }; +#else + {{1, N_A, BOARD_DEV_SPI_FLASH, 8}}; /* SPI DEV */ +#endif + +MV_BOARD_MPP_INFO db88f6281AInfoBoardMppConfigValue[] = + {{{ + DB_88F6281A_MPP0_7, + DB_88F6281A_MPP8_15, + DB_88F6281A_MPP16_23, + DB_88F6281A_MPP24_31, + DB_88F6281A_MPP32_39, + DB_88F6281A_MPP40_47, + DB_88F6281A_MPP48_55 + }}}; + + +MV_BOARD_INFO db88f6281AInfo = { + "DB-88F6281A-BP", /* boardName[MAX_BOARD_NAME_LEN] */ + DB_88F6281A_BOARD_MPP_GROUP_TYPE_NUM, /* numBoardMppGroupType */ + db88f6281AInfoBoardMppTypeInfo, + DB_88F6281A_BOARD_MPP_CONFIG_NUM, /* numBoardMppConfig */ + db88f6281AInfoBoardMppConfigValue, + 0, /* intsGppMaskLow */ + 0, /* intsGppMaskHigh */ + DB_88F6281A_BOARD_DEVICE_CONFIG_NUM, /* numBoardDevIf */ + db88f6281AInfoBoardDeCsInfo, + DB_88F6281A_BOARD_TWSI_DEF_NUM, /* numBoardTwsiDev */ + db88f6281AInfoBoardTwsiDev, + DB_88F6281A_BOARD_MAC_INFO_NUM, /* numBoardMacInfo */ + db88f6281AInfoBoardMacInfo, + DB_88F6281A_BOARD_GPP_INFO_NUM, /* numBoardGppInfo */ + db88f6281AInfoBoardGppInfo, + DB_88F6281A_BOARD_DEBUG_LED_NUM, /* activeLedsNumber */ + NULL, + 0, /* ledsPolarity */ + DB_88F6281A_OE_LOW, /* gppOutEnLow */ + DB_88F6281A_OE_HIGH, /* gppOutEnHigh */ + DB_88F6281A_OE_VAL_LOW, /* gppOutValLow */ + DB_88F6281A_OE_VAL_HIGH, /* gppOutValHigh */ + 0, /* gppPolarityValLow */ + BIT6, /* gppPolarityValHigh */ + NULL /* pSwitchInfo */ +}; + + +#define RD_88F6281A_BOARD_PCI_IF_NUM 0x0 +#define RD_88F6281A_BOARD_TWSI_DEF_NUM 0x2 +#define RD_88F6281A_BOARD_MAC_INFO_NUM 0x2 +#define RD_88F6281A_BOARD_GPP_INFO_NUM 0x5 +#define RD_88F6281A_BOARD_MPP_GROUP_TYPE_NUM 0x1 +#define RD_88F6281A_BOARD_MPP_CONFIG_NUM 0x1 +#if defined(MV_NAND) && defined(MV_NAND_BOOT) + #define RD_88F6281A_BOARD_DEVICE_CONFIG_NUM 0x1 +#elif defined(MV_NAND) && defined(MV_SPI_BOOT) + #define RD_88F6281A_BOARD_DEVICE_CONFIG_NUM 0x2 +#else + #define RD_88F6281A_BOARD_DEVICE_CONFIG_NUM 0x1 +#endif +#define RD_88F6281A_BOARD_DEBUG_LED_NUM 0x0 + +MV_BOARD_MAC_INFO rd88f6281AInfoBoardMacInfo[] = + /* {{MV_BOARD_MAC_SPEED boardMacSpeed, MV_U8 boardEthSmiAddr}} */ + {{BOARD_MAC_SPEED_1000M, 0xa}, + {BOARD_MAC_SPEED_AUTO, 0xb} + }; + +MV_BOARD_SWITCH_INFO rd88f6281AInfoBoardSwitchInfo[] = + /* MV_32 linkStatusIrq, {MV_32 qdPort0, MV_32 qdPort1, MV_32 qdPort2, MV_32 qdPort3, MV_32 qdPort4}, + MV_32 qdCpuPort, MV_32 smiScanMode, MV_32 switchOnPort} */ + {{38, {0, 1, 2, 3, -1}, 5, 2, 0}, + {-1, {-1}, -1, -1, -1}}; + +MV_BOARD_TWSI_INFO rd88f6281AInfoBoardTwsiDev[] = + /* {{MV_BOARD_DEV_CLASS devClass, MV_U8 twsiDevAddr, MV_U8 twsiDevAddrType}} */ + { + {BOARD_DEV_TWSI_EXP, 0xFF, ADDR7_BIT}, /* dummy entry to align with modules indexes */ + {BOARD_DEV_TWSI_EXP, 0x27, ADDR7_BIT} + }; + +MV_BOARD_MPP_TYPE_INFO rd88f6281AInfoBoardMppTypeInfo[] = + {{MV_BOARD_RGMII, MV_BOARD_TDM} + }; + +MV_DEV_CS_INFO rd88f6281AInfoBoardDeCsInfo[] = + /*{deviceCS, params, devType, devWidth}*/ +#if defined(MV_NAND) && defined(MV_NAND_BOOT) + {{0, N_A, BOARD_DEV_NAND_FLASH, 8}}; /* NAND DEV */ +#elif defined(MV_NAND) && defined(MV_SPI_BOOT) + { + {0, N_A, BOARD_DEV_NAND_FLASH, 8}, /* NAND DEV */ + {1, N_A, BOARD_DEV_SPI_FLASH, 8}, /* SPI DEV */ + }; +#else + {{1, N_A, BOARD_DEV_SPI_FLASH, 8}}; /* SPI DEV */ +#endif + +MV_BOARD_GPP_INFO rd88f6281AInfoBoardGppInfo[] = + /* {{MV_BOARD_GPP_CLASS devClass, MV_U8 gppPinNum}} */ + {{BOARD_GPP_SDIO_DETECT, 28}, + {BOARD_GPP_USB_OC, 29}, + {BOARD_GPP_WPS_BUTTON, 35}, + {BOARD_GPP_MV_SWITCH, 38}, + {BOARD_GPP_USB_VBUS, 49} + }; + +MV_BOARD_MPP_INFO rd88f6281AInfoBoardMppConfigValue[] = + {{{ + RD_88F6281A_MPP0_7, + RD_88F6281A_MPP8_15, + RD_88F6281A_MPP16_23, + RD_88F6281A_MPP24_31, + RD_88F6281A_MPP32_39, + RD_88F6281A_MPP40_47, + RD_88F6281A_MPP48_55 + }}}; + +MV_BOARD_INFO rd88f6281AInfo = { + "RD-88F6281A", /* boardName[MAX_BOARD_NAME_LEN] */ + RD_88F6281A_BOARD_MPP_GROUP_TYPE_NUM, /* numBoardMppGroupType */ + rd88f6281AInfoBoardMppTypeInfo, + RD_88F6281A_BOARD_MPP_CONFIG_NUM, /* numBoardMppConfig */ + rd88f6281AInfoBoardMppConfigValue, + 0, /* intsGppMaskLow */ + (1 << 3), /* intsGppMaskHigh */ + RD_88F6281A_BOARD_DEVICE_CONFIG_NUM, /* numBoardDevIf */ + rd88f6281AInfoBoardDeCsInfo, + RD_88F6281A_BOARD_TWSI_DEF_NUM, /* numBoardTwsiDev */ + rd88f6281AInfoBoardTwsiDev, + RD_88F6281A_BOARD_MAC_INFO_NUM, /* numBoardMacInfo */ + rd88f6281AInfoBoardMacInfo, + RD_88F6281A_BOARD_GPP_INFO_NUM, /* numBoardGppInfo */ + rd88f6281AInfoBoardGppInfo, + RD_88F6281A_BOARD_DEBUG_LED_NUM, /* activeLedsNumber */ + NULL, + 0, /* ledsPolarity */ + RD_88F6281A_OE_LOW, /* gppOutEnLow */ + RD_88F6281A_OE_HIGH, /* gppOutEnHigh */ + RD_88F6281A_OE_VAL_LOW, /* gppOutValLow */ + RD_88F6281A_OE_VAL_HIGH, /* gppOutValHigh */ + 0, /* gppPolarityValLow */ + BIT6, /* gppPolarityValHigh */ + rd88f6281AInfoBoardSwitchInfo /* pSwitchInfo */ +}; + + +#define DB_88F6192A_BOARD_PCI_IF_NUM 0x0 +#define DB_88F6192A_BOARD_TWSI_DEF_NUM 0x7 +#define DB_88F6192A_BOARD_MAC_INFO_NUM 0x2 +#define DB_88F6192A_BOARD_GPP_INFO_NUM 0x3 +#define DB_88F6192A_BOARD_MPP_GROUP_TYPE_NUM 0x1 +#define DB_88F6192A_BOARD_MPP_CONFIG_NUM 0x1 +#if defined(MV_NAND) && defined(MV_NAND_BOOT) + #define DB_88F6192A_BOARD_DEVICE_CONFIG_NUM 0x1 +#elif defined(MV_NAND) && defined(MV_SPI_BOOT) + #define DB_88F6192A_BOARD_DEVICE_CONFIG_NUM 0x2 +#else + #define DB_88F6192A_BOARD_DEVICE_CONFIG_NUM 0x1 +#endif +#define DB_88F6192A_BOARD_DEBUG_LED_NUM 0x0 + +MV_BOARD_TWSI_INFO db88f6192AInfoBoardTwsiDev[] = + /* {{MV_BOARD_DEV_CLASS devClass, MV_U8 twsiDevAddr, MV_U8 twsiDevAddrType}} */ + { + {BOARD_DEV_TWSI_EXP, 0x20, ADDR7_BIT}, + {BOARD_DEV_TWSI_EXP, 0x21, ADDR7_BIT}, + {BOARD_DEV_TWSI_EXP, 0x27, ADDR7_BIT}, + {BOARD_DEV_TWSI_SATR, 0x4C, ADDR7_BIT}, + {BOARD_DEV_TWSI_SATR, 0x4D, ADDR7_BIT}, + {BOARD_DEV_TWSI_SATR, 0x4E, ADDR7_BIT}, + {BOARD_TWSI_AUDIO_DEC, 0x4A, ADDR7_BIT} + }; + +MV_BOARD_MAC_INFO db88f6192AInfoBoardMacInfo[] = + /* {{MV_BOARD_MAC_SPEED boardMacSpeed, MV_U8 boardEthSmiAddr}} */ + { + {BOARD_MAC_SPEED_AUTO, 0x8}, + {BOARD_MAC_SPEED_AUTO, 0x9} + }; + +MV_BOARD_MPP_TYPE_INFO db88f6192AInfoBoardMppTypeInfo[] = + /* {{MV_BOARD_MPP_TYPE_CLASS boardMppGroup1, + MV_BOARD_MPP_TYPE_CLASS boardMppGroup2}} */ + {{MV_BOARD_AUTO, MV_BOARD_OTHER} + }; + +MV_DEV_CS_INFO db88f6192AInfoBoardDeCsInfo[] = + /*{deviceCS, params, devType, devWidth}*/ +#if defined(MV_NAND) && defined(MV_NAND_BOOT) + {{0, N_A, BOARD_DEV_NAND_FLASH, 8}}; /* NAND DEV */ +#elif defined(MV_NAND) && defined(MV_SPI_BOOT) + { + {0, N_A, BOARD_DEV_NAND_FLASH, 8}, /* NAND DEV */ + {1, N_A, BOARD_DEV_SPI_FLASH, 8}, /* SPI DEV */ + }; +#else + {{1, N_A, BOARD_DEV_SPI_FLASH, 8}}; /* SPI DEV */ +#endif + +MV_BOARD_GPP_INFO db88f6192AInfoBoardGppInfo[] = + /* {{MV_BOARD_GPP_CLASS devClass, MV_U8 gppPinNum}} */ + { + {BOARD_GPP_SDIO_WP, 20}, + {BOARD_GPP_USB_VBUS, 22}, + {BOARD_GPP_SDIO_DETECT, 23}, + }; + +MV_BOARD_MPP_INFO db88f6192AInfoBoardMppConfigValue[] = + {{{ + DB_88F6192A_MPP0_7, + DB_88F6192A_MPP8_15, + DB_88F6192A_MPP16_23, + DB_88F6192A_MPP24_31, + DB_88F6192A_MPP32_35 + }}}; + +MV_BOARD_INFO db88f6192AInfo = { + "DB-88F6192A-BP", /* boardName[MAX_BOARD_NAME_LEN] */ + DB_88F6192A_BOARD_MPP_GROUP_TYPE_NUM, /* numBoardMppGroupType */ + db88f6192AInfoBoardMppTypeInfo, + DB_88F6192A_BOARD_MPP_CONFIG_NUM, /* numBoardMppConfig */ + db88f6192AInfoBoardMppConfigValue, + 0, /* intsGppMaskLow */ + (1 << 3), /* intsGppMaskHigh */ + DB_88F6192A_BOARD_DEVICE_CONFIG_NUM, /* numBoardDevIf */ + db88f6192AInfoBoardDeCsInfo, + DB_88F6192A_BOARD_TWSI_DEF_NUM, /* numBoardTwsiDev */ + db88f6192AInfoBoardTwsiDev, + DB_88F6192A_BOARD_MAC_INFO_NUM, /* numBoardMacInfo */ + db88f6192AInfoBoardMacInfo, + DB_88F6192A_BOARD_GPP_INFO_NUM, /* numBoardGppInfo */ + db88f6192AInfoBoardGppInfo, + DB_88F6192A_BOARD_DEBUG_LED_NUM, /* activeLedsNumber */ + NULL, + 0, /* ledsPolarity */ + DB_88F6192A_OE_LOW, /* gppOutEnLow */ + DB_88F6192A_OE_HIGH, /* gppOutEnHigh */ + DB_88F6192A_OE_VAL_LOW, /* gppOutValLow */ + DB_88F6192A_OE_VAL_HIGH, /* gppOutValHigh */ + 0, /* gppPolarityValLow */ + 0, /* gppPolarityValHigh */ + NULL /* pSwitchInfo */ +}; + +#define DB_88F6190A_BOARD_MAC_INFO_NUM 0x1 + +MV_BOARD_INFO db88f6190AInfo = { + "DB-88F6190A-BP", /* boardName[MAX_BOARD_NAME_LEN] */ + DB_88F6192A_BOARD_MPP_GROUP_TYPE_NUM, /* numBoardMppGroupType */ + db88f6192AInfoBoardMppTypeInfo, + DB_88F6192A_BOARD_MPP_CONFIG_NUM, /* numBoardMppConfig */ + db88f6192AInfoBoardMppConfigValue, + 0, /* intsGppMaskLow */ + (1 << 3), /* intsGppMaskHigh */ + DB_88F6192A_BOARD_DEVICE_CONFIG_NUM, /* numBoardDevIf */ + db88f6192AInfoBoardDeCsInfo, + DB_88F6192A_BOARD_TWSI_DEF_NUM, /* numBoardTwsiDev */ + db88f6192AInfoBoardTwsiDev, + DB_88F6190A_BOARD_MAC_INFO_NUM, /* numBoardMacInfo */ + db88f6192AInfoBoardMacInfo, + DB_88F6192A_BOARD_GPP_INFO_NUM, /* numBoardGppInfo */ + db88f6192AInfoBoardGppInfo, + DB_88F6192A_BOARD_DEBUG_LED_NUM, /* activeLedsNumber */ + NULL, + 0, /* ledsPolarity */ + DB_88F6192A_OE_LOW, /* gppOutEnLow */ + DB_88F6192A_OE_HIGH, /* gppOutEnHigh */ + DB_88F6192A_OE_VAL_LOW, /* gppOutValLow */ + DB_88F6192A_OE_VAL_HIGH, /* gppOutValHigh */ + 0, /* gppPolarityValLow */ + 0, /* gppPolarityValHigh */ + NULL /* pSwitchInfo */ +}; + +#define RD_88F6192A_BOARD_PCI_IF_NUM 0x0 +#define RD_88F6192A_BOARD_TWSI_DEF_NUM 0x0 +#define RD_88F6192A_BOARD_MAC_INFO_NUM 0x1 +#define RD_88F6192A_BOARD_GPP_INFO_NUM 0xE +#define RD_88F6192A_BOARD_MPP_GROUP_TYPE_NUM 0x1 +#define RD_88F6192A_BOARD_MPP_CONFIG_NUM 0x1 +#define RD_88F6192A_BOARD_DEVICE_CONFIG_NUM 0x1 +#define RD_88F6192A_BOARD_DEBUG_LED_NUM 0x3 + +MV_U8 rd88f6192AInfoBoardDebugLedIf[] = + {17, 28, 29}; + +MV_BOARD_MAC_INFO rd88f6192AInfoBoardMacInfo[] = + /* {{MV_BOARD_MAC_SPEED boardMacSpeed, MV_U8 boardEthSmiAddr}} */ + {{BOARD_MAC_SPEED_AUTO, 0x8} + }; + +MV_BOARD_MPP_TYPE_INFO rd88f6192AInfoBoardMppTypeInfo[] = + /* {{MV_BOARD_MPP_TYPE_CLASS boardMppGroup1, + MV_BOARD_MPP_TYPE_CLASS boardMppGroup2}} */ + {{MV_BOARD_OTHER, MV_BOARD_OTHER} + }; + +MV_DEV_CS_INFO rd88f6192AInfoBoardDeCsInfo[] = + /*{deviceCS, params, devType, devWidth}*/ + {{1, N_A, BOARD_DEV_SPI_FLASH, 8}}; /* SPI DEV */ + +MV_BOARD_GPP_INFO rd88f6192AInfoBoardGppInfo[] = + /* {{MV_BOARD_GPP_CLASS devClass, MV_U8 gppPinNum}} */ + { + {BOARD_GPP_USB_VBUS_EN, 10}, + {BOARD_GPP_USB_HOST_DEVICE, 11}, + {BOARD_GPP_RESET, 14}, + {BOARD_GPP_POWER_ON_LED, 15}, + {BOARD_GPP_HDD_POWER, 16}, + {BOARD_GPP_WPS_BUTTON, 24}, + {BOARD_GPP_TS_BUTTON_C, 25}, + {BOARD_GPP_USB_VBUS, 26}, + {BOARD_GPP_USB_OC, 27}, + {BOARD_GPP_TS_BUTTON_U, 30}, + {BOARD_GPP_TS_BUTTON_R, 31}, + {BOARD_GPP_TS_BUTTON_L, 32}, + {BOARD_GPP_TS_BUTTON_D, 34}, + {BOARD_GPP_FAN_POWER, 35} + }; + +MV_BOARD_MPP_INFO rd88f6192AInfoBoardMppConfigValue[] = + {{{ + RD_88F6192A_MPP0_7, + RD_88F6192A_MPP8_15, + RD_88F6192A_MPP16_23, + RD_88F6192A_MPP24_31, + RD_88F6192A_MPP32_35 + }}}; + +MV_BOARD_INFO rd88f6192AInfo = { + "RD-88F6192A-NAS", /* boardName[MAX_BOARD_NAME_LEN] */ + RD_88F6192A_BOARD_MPP_GROUP_TYPE_NUM, /* numBoardMppGroupType */ + rd88f6192AInfoBoardMppTypeInfo, + RD_88F6192A_BOARD_MPP_CONFIG_NUM, /* numBoardMppConfig */ + rd88f6192AInfoBoardMppConfigValue, + 0, /* intsGppMaskLow */ + (1 << 3), /* intsGppMaskHigh */ + RD_88F6192A_BOARD_DEVICE_CONFIG_NUM, /* numBoardDevIf */ + rd88f6192AInfoBoardDeCsInfo, + RD_88F6192A_BOARD_TWSI_DEF_NUM, /* numBoardTwsiDev */ + NULL, + RD_88F6192A_BOARD_MAC_INFO_NUM, /* numBoardMacInfo */ + rd88f6192AInfoBoardMacInfo, + RD_88F6192A_BOARD_GPP_INFO_NUM, /* numBoardGppInfo */ + rd88f6192AInfoBoardGppInfo, + RD_88F6192A_BOARD_DEBUG_LED_NUM, /* activeLedsNumber */ + rd88f6192AInfoBoardDebugLedIf, + 0, /* ledsPolarity */ + RD_88F6192A_OE_LOW, /* gppOutEnLow */ + RD_88F6192A_OE_HIGH, /* gppOutEnHigh */ + RD_88F6192A_OE_VAL_LOW, /* gppOutValLow */ + RD_88F6192A_OE_VAL_HIGH, /* gppOutValHigh */ + 0, /* gppPolarityValLow */ + 0, /* gppPolarityValHigh */ + NULL /* pSwitchInfo */ +}; + +MV_BOARD_INFO rd88f6190AInfo = { + "RD-88F6190A-NAS", /* boardName[MAX_BOARD_NAME_LEN] */ + RD_88F6192A_BOARD_MPP_GROUP_TYPE_NUM, /* numBoardMppGroupType */ + rd88f6192AInfoBoardMppTypeInfo, + RD_88F6192A_BOARD_MPP_CONFIG_NUM, /* numBoardMppConfig */ + rd88f6192AInfoBoardMppConfigValue, + 0, /* intsGppMaskLow */ + (1 << 3), /* intsGppMaskHigh */ + RD_88F6192A_BOARD_DEVICE_CONFIG_NUM, /* numBoardDevIf */ + rd88f6192AInfoBoardDeCsInfo, + RD_88F6192A_BOARD_TWSI_DEF_NUM, /* numBoardTwsiDev */ + NULL, + RD_88F6192A_BOARD_MAC_INFO_NUM, /* numBoardMacInfo */ + rd88f6192AInfoBoardMacInfo, + RD_88F6192A_BOARD_GPP_INFO_NUM, /* numBoardGppInfo */ + rd88f6192AInfoBoardGppInfo, + RD_88F6192A_BOARD_DEBUG_LED_NUM, /* activeLedsNumber */ + rd88f6192AInfoBoardDebugLedIf, + 0, /* ledsPolarity */ + RD_88F6192A_OE_LOW, /* gppOutEnLow */ + RD_88F6192A_OE_HIGH, /* gppOutEnHigh */ + RD_88F6192A_OE_VAL_LOW, /* gppOutValLow */ + RD_88F6192A_OE_VAL_HIGH, /* gppOutValHigh */ + 0, /* gppPolarityValLow */ + 0, /* gppPolarityValHigh */ + NULL /* pSwitchInfo */ +}; + +#define DB_88F6180A_BOARD_PCI_IF_NUM 0x0 +#define DB_88F6180A_BOARD_TWSI_DEF_NUM 0x5 +#define DB_88F6180A_BOARD_MAC_INFO_NUM 0x1 +#define DB_88F6180A_BOARD_GPP_INFO_NUM 0x0 +#define DB_88F6180A_BOARD_MPP_GROUP_TYPE_NUM 0x2 +#define DB_88F6180A_BOARD_MPP_CONFIG_NUM 0x1 +#define DB_88F6180A_BOARD_DEVICE_CONFIG_NUM 0x1 +#define DB_88F6180A_BOARD_DEBUG_LED_NUM 0x0 + +MV_BOARD_TWSI_INFO db88f6180AInfoBoardTwsiDev[] = + /* {{MV_BOARD_DEV_CLASS devClass, MV_U8 twsiDevAddr, MV_U8 twsiDevAddrType}} */ + { + {BOARD_DEV_TWSI_EXP, 0x20, ADDR7_BIT}, + {BOARD_DEV_TWSI_EXP, 0x21, ADDR7_BIT}, + {BOARD_DEV_TWSI_EXP, 0x27, ADDR7_BIT}, + {BOARD_DEV_TWSI_SATR, 0x4C, ADDR7_BIT}, + {BOARD_TWSI_AUDIO_DEC, 0x4A, ADDR7_BIT} + }; + +MV_BOARD_MAC_INFO db88f6180AInfoBoardMacInfo[] = + /* {{MV_BOARD_MAC_SPEED boardMacSpeed, MV_U8 boardEthSmiAddr}} */ + {{BOARD_MAC_SPEED_AUTO, 0x8} + }; + +MV_BOARD_GPP_INFO db88f6180AInfoBoardGppInfo[] = + /* {{MV_BOARD_GPP_CLASS devClass, MV_U8 gppPinNum}} */ + { + /* Muxed with TDM/Audio module via IOexpender + {BOARD_GPP_USB_VBUS, 6} */ + }; + +MV_BOARD_MPP_TYPE_INFO db88f6180AInfoBoardMppTypeInfo[] = + /* {{MV_BOARD_MPP_TYPE_CLASS boardMppGroup1, + MV_BOARD_MPP_TYPE_CLASS boardMppGroup2}} */ + {{MV_BOARD_OTHER, MV_BOARD_AUTO} + }; + +MV_DEV_CS_INFO db88f6180AInfoBoardDeCsInfo[] = + /*{deviceCS, params, devType, devWidth}*/ +#if defined(MV_NAND_BOOT) + {{0, N_A, BOARD_DEV_NAND_FLASH, 8}}; /* NAND DEV */ +#else + {{1, N_A, BOARD_DEV_SPI_FLASH, 8}}; /* SPI DEV */ +#endif + +MV_BOARD_MPP_INFO db88f6180AInfoBoardMppConfigValue[] = + {{{ + DB_88F6180A_MPP0_7, + DB_88F6180A_MPP8_15, + DB_88F6180A_MPP16_23, + DB_88F6180A_MPP24_31, + DB_88F6180A_MPP32_39, + DB_88F6180A_MPP40_44 + }}}; + +MV_BOARD_INFO db88f6180AInfo = { + "DB-88F6180A-BP", /* boardName[MAX_BOARD_NAME_LEN] */ + DB_88F6180A_BOARD_MPP_GROUP_TYPE_NUM, /* numBoardMppGroupType */ + db88f6180AInfoBoardMppTypeInfo, + DB_88F6180A_BOARD_MPP_CONFIG_NUM, /* numBoardMppConfig */ + db88f6180AInfoBoardMppConfigValue, + 0, /* intsGppMaskLow */ + 0, /* intsGppMaskHigh */ + DB_88F6180A_BOARD_DEVICE_CONFIG_NUM, /* numBoardDevIf */ + db88f6180AInfoBoardDeCsInfo, + DB_88F6180A_BOARD_TWSI_DEF_NUM, /* numBoardTwsiDev */ + db88f6180AInfoBoardTwsiDev, + DB_88F6180A_BOARD_MAC_INFO_NUM, /* numBoardMacInfo */ + db88f6180AInfoBoardMacInfo, + DB_88F6180A_BOARD_GPP_INFO_NUM, /* numBoardGppInfo */ + NULL, + DB_88F6180A_BOARD_DEBUG_LED_NUM, /* activeLedsNumber */ + NULL, + 0, /* ledsPolarity */ + DB_88F6180A_OE_LOW, /* gppOutEnLow */ + DB_88F6180A_OE_HIGH, /* gppOutEnHigh */ + DB_88F6180A_OE_VAL_LOW, /* gppOutValLow */ + DB_88F6180A_OE_VAL_HIGH, /* gppOutValHigh */ + 0, /* gppPolarityValLow */ + 0, /* gppPolarityValHigh */ + NULL /* pSwitchInfo */ +}; + + +#define RD_88F6281A_PCAC_BOARD_PCI_IF_NUM 0x0 +#define RD_88F6281A_PCAC_BOARD_TWSI_DEF_NUM 0x1 +#define RD_88F6281A_PCAC_BOARD_MAC_INFO_NUM 0x1 +#define RD_88F6281A_PCAC_BOARD_GPP_INFO_NUM 0x0 +#define RD_88F6281A_PCAC_BOARD_MPP_GROUP_TYPE_NUM 0x1 +#define RD_88F6281A_PCAC_BOARD_MPP_CONFIG_NUM 0x1 +#if defined(MV_NAND) && defined(MV_NAND_BOOT) + #define RD_88F6281A_PCAC_BOARD_DEVICE_CONFIG_NUM 0x1 +#elif defined(MV_NAND) && defined(MV_SPI_BOOT) + #define RD_88F6281A_PCAC_BOARD_DEVICE_CONFIG_NUM 0x2 +#else + #define RD_88F6281A_PCAC_BOARD_DEVICE_CONFIG_NUM 0x1 +#endif +#define RD_88F6281A_PCAC_BOARD_DEBUG_LED_NUM 0x4 + +MV_U8 rd88f6281APcacInfoBoardDebugLedIf[] = + {38, 39, 40, 41}; + +MV_BOARD_MAC_INFO rd88f6281APcacInfoBoardMacInfo[] = + /* {{MV_BOARD_MAC_SPEED boardMacSpeed, MV_U8 boardEthSmiAddr}} */ + {{BOARD_MAC_SPEED_AUTO, 0x8} + }; + +MV_BOARD_TWSI_INFO rd88f6281APcacInfoBoardTwsiDev[] = + /* {{MV_BOARD_DEV_CLASS devClass, MV_U8 twsiDevAddr, MV_U8 twsiDevAddrType}} */ + { + {BOARD_TWSI_OTHER, 0xa7, ADDR7_BIT} + }; + +MV_BOARD_MPP_TYPE_INFO rd88f6281APcacInfoBoardMppTypeInfo[] = + {{MV_BOARD_OTHER, MV_BOARD_OTHER} + }; + +MV_DEV_CS_INFO rd88f6281APcacInfoBoardDeCsInfo[] = + /*{deviceCS, params, devType, devWidth}*/ +#if defined(MV_NAND) && defined(MV_NAND_BOOT) + {{0, N_A, BOARD_DEV_NAND_FLASH, 8}}; /* NAND DEV */ +#elif defined(MV_NAND) && defined(MV_SPI_BOOT) + { + {0, N_A, BOARD_DEV_NAND_FLASH, 8}, /* NAND DEV */ + {1, N_A, BOARD_DEV_SPI_FLASH, 8}, /* SPI DEV */ + }; +#else + {{1, N_A, BOARD_DEV_SPI_FLASH, 8}}; /* SPI DEV */ +#endif + +MV_BOARD_MPP_INFO rd88f6281APcacInfoBoardMppConfigValue[] = + {{{ + RD_88F6281A_PCAC_MPP0_7, + RD_88F6281A_PCAC_MPP8_15, + RD_88F6281A_PCAC_MPP16_23, + RD_88F6281A_PCAC_MPP24_31, + RD_88F6281A_PCAC_MPP32_39, + RD_88F6281A_PCAC_MPP40_47, + RD_88F6281A_PCAC_MPP48_55 + }}}; + +MV_BOARD_INFO rd88f6281APcacInfo = { + "RD-88F6281A-PCAC", /* boardName[MAX_BOARD_NAME_LEN] */ + RD_88F6281A_PCAC_BOARD_MPP_GROUP_TYPE_NUM, /* numBoardMppGroupType */ + rd88f6281APcacInfoBoardMppTypeInfo, + RD_88F6281A_PCAC_BOARD_MPP_CONFIG_NUM, /* numBoardMppConfig */ + rd88f6281APcacInfoBoardMppConfigValue, + 0, /* intsGppMaskLow */ + (1 << 3), /* intsGppMaskHigh */ + RD_88F6281A_PCAC_BOARD_DEVICE_CONFIG_NUM, /* numBoardDevIf */ + rd88f6281APcacInfoBoardDeCsInfo, + RD_88F6281A_PCAC_BOARD_TWSI_DEF_NUM, /* numBoardTwsiDev */ + rd88f6281APcacInfoBoardTwsiDev, + RD_88F6281A_PCAC_BOARD_MAC_INFO_NUM, /* numBoardMacInfo */ + rd88f6281APcacInfoBoardMacInfo, + RD_88F6281A_PCAC_BOARD_GPP_INFO_NUM, /* numBoardGppInfo */ + 0, + RD_88F6281A_PCAC_BOARD_DEBUG_LED_NUM, /* activeLedsNumber */ + NULL, + 0, /* ledsPolarity */ + RD_88F6281A_PCAC_OE_LOW, /* gppOutEnLow */ + RD_88F6281A_PCAC_OE_HIGH, /* gppOutEnHigh */ + RD_88F6281A_PCAC_OE_VAL_LOW, /* gppOutValLow */ + RD_88F6281A_PCAC_OE_VAL_HIGH, /* gppOutValHigh */ + 0, /* gppPolarityValLow */ + 0, /* gppPolarityValHigh */ + NULL /* pSwitchInfo */ +}; + + +/* 6281 Sheeva Plug*/ + +#define SHEEVA_PLUG_BOARD_PCI_IF_NUM 0x0 +#define SHEEVA_PLUG_BOARD_TWSI_DEF_NUM 0x0 +#define SHEEVA_PLUG_BOARD_MAC_INFO_NUM 0x1 +#define SHEEVA_PLUG_BOARD_GPP_INFO_NUM 0x0 +#define SHEEVA_PLUG_BOARD_MPP_GROUP_TYPE_NUN 0x1 +#define SHEEVA_PLUG_BOARD_MPP_CONFIG_NUM 0x1 +#define SHEEVA_PLUG_BOARD_DEVICE_CONFIG_NUM 0x1 +#define SHEEVA_PLUG_BOARD_DEBUG_LED_NUM 0x1 + +MV_U8 sheevaPlugInfoBoardDebugLedIf[] = + {49}; + +MV_BOARD_MAC_INFO sheevaPlugInfoBoardMacInfo[] = + /* {{MV_BOARD_MAC_SPEED boardMacSpeed, MV_U8 boardEthSmiAddr}} */ + {{BOARD_MAC_SPEED_AUTO, 0x0}}; + +MV_BOARD_TWSI_INFO sheevaPlugInfoBoardTwsiDev[] = + /* {{MV_BOARD_DEV_CLASS devClass, MV_U8 twsiDevAddr, MV_U8 twsiDevAddrType}} */ + {{BOARD_TWSI_OTHER, 0x0, ADDR7_BIT}}; + +MV_BOARD_MPP_TYPE_INFO sheevaPlugInfoBoardMppTypeInfo[] = + {{MV_BOARD_OTHER, MV_BOARD_OTHER} + }; + +MV_DEV_CS_INFO sheevaPlugInfoBoardDeCsInfo[] = + /*{deviceCS, params, devType, devWidth}*/ + {{0, N_A, BOARD_DEV_NAND_FLASH, 8}}; /* NAND DEV */ + +MV_BOARD_MPP_INFO sheevaPlugInfoBoardMppConfigValue[] = + {{{ + RD_SHEEVA_PLUG_MPP0_7, + RD_SHEEVA_PLUG_MPP8_15, + RD_SHEEVA_PLUG_MPP16_23, + RD_SHEEVA_PLUG_MPP24_31, + RD_SHEEVA_PLUG_MPP32_39, + RD_SHEEVA_PLUG_MPP40_47, + RD_SHEEVA_PLUG_MPP48_55 + }}}; + +MV_BOARD_INFO sheevaPlugInfo = { + "SHEEVA PLUG", /* boardName[MAX_BOARD_NAME_LEN] */ + SHEEVA_PLUG_BOARD_MPP_GROUP_TYPE_NUN, /* numBoardMppGroupType */ + sheevaPlugInfoBoardMppTypeInfo, + SHEEVA_PLUG_BOARD_MPP_CONFIG_NUM, /* numBoardMppConfig */ + sheevaPlugInfoBoardMppConfigValue, + 0, /* intsGppMaskLow */ + 0, /* intsGppMaskHigh */ + SHEEVA_PLUG_BOARD_DEVICE_CONFIG_NUM, /* numBoardDevIf */ + sheevaPlugInfoBoardDeCsInfo, + SHEEVA_PLUG_BOARD_TWSI_DEF_NUM, /* numBoardTwsiDev */ + sheevaPlugInfoBoardTwsiDev, + SHEEVA_PLUG_BOARD_MAC_INFO_NUM, /* numBoardMacInfo */ + sheevaPlugInfoBoardMacInfo, + SHEEVA_PLUG_BOARD_GPP_INFO_NUM, /* numBoardGppInfo */ + 0, + SHEEVA_PLUG_BOARD_DEBUG_LED_NUM, /* activeLedsNumber */ + sheevaPlugInfoBoardDebugLedIf, + 0, /* ledsPolarity */ + RD_SHEEVA_PLUG_OE_LOW, /* gppOutEnLow */ + RD_SHEEVA_PLUG_OE_HIGH, /* gppOutEnHigh */ + RD_SHEEVA_PLUG_OE_VAL_LOW, /* gppOutValLow */ + RD_SHEEVA_PLUG_OE_VAL_HIGH, /* gppOutValHigh */ + 0, /* gppPolarityValLow */ + 0, /* gppPolarityValHigh */ + NULL /* pSwitchInfo */ +}; + +/* Customer specific board place holder*/ + +#define DB_CUSTOMER_BOARD_PCI_IF_NUM 0x0 +#define DB_CUSTOMER_BOARD_TWSI_DEF_NUM 0x0 +#define DB_CUSTOMER_BOARD_MAC_INFO_NUM 0x0 +#define DB_CUSTOMER_BOARD_GPP_INFO_NUM 0x0 +#define DB_CUSTOMER_BOARD_MPP_GROUP_TYPE_NUN 0x0 +#define DB_CUSTOMER_BOARD_MPP_CONFIG_NUM 0x0 +#if defined(MV_NAND) && defined(MV_NAND_BOOT) + #define DB_CUSTOMER_BOARD_DEVICE_CONFIG_NUM 0x0 +#elif defined(MV_NAND) && defined(MV_SPI_BOOT) + #define DB_CUSTOMER_BOARD_DEVICE_CONFIG_NUM 0x0 +#else + #define DB_CUSTOMER_BOARD_DEVICE_CONFIG_NUM 0x0 +#endif +#define DB_CUSTOMER_BOARD_DEBUG_LED_NUM 0x0 + +MV_U8 dbCustomerInfoBoardDebugLedIf[] = + {0}; + +MV_BOARD_MAC_INFO dbCustomerInfoBoardMacInfo[] = + /* {{MV_BOARD_MAC_SPEED boardMacSpeed, MV_U8 boardEthSmiAddr}} */ + {{BOARD_MAC_SPEED_AUTO, 0x0}}; + +MV_BOARD_TWSI_INFO dbCustomerInfoBoardTwsiDev[] = + /* {{MV_BOARD_DEV_CLASS devClass, MV_U8 twsiDevAddr, MV_U8 twsiDevAddrType}} */ + {{BOARD_TWSI_OTHER, 0x0, ADDR7_BIT}}; + +MV_BOARD_MPP_TYPE_INFO dbCustomerInfoBoardMppTypeInfo[] = + {{MV_BOARD_OTHER, MV_BOARD_OTHER} + }; + +MV_DEV_CS_INFO dbCustomerInfoBoardDeCsInfo[] = + /*{deviceCS, params, devType, devWidth}*/ +#if defined(MV_NAND) && defined(MV_NAND_BOOT) + {{0, N_A, BOARD_DEV_NAND_FLASH, 8}}; /* NAND DEV */ +#elif defined(MV_NAND) && defined(MV_SPI_BOOT) + { + {0, N_A, BOARD_DEV_NAND_FLASH, 8}, /* NAND DEV */ + {2, N_A, BOARD_DEV_SPI_FLASH, 8}, /* SPI DEV */ + }; +#else + {{2, N_A, BOARD_DEV_SPI_FLASH, 8}}; /* SPI DEV */ +#endif + +MV_BOARD_MPP_INFO dbCustomerInfoBoardMppConfigValue[] = + {{{ + DB_CUSTOMER_MPP0_7, + DB_CUSTOMER_MPP8_15, + DB_CUSTOMER_MPP16_23, + DB_CUSTOMER_MPP24_31, + DB_CUSTOMER_MPP32_39, + DB_CUSTOMER_MPP40_47, + DB_CUSTOMER_MPP48_55 + }}}; + +MV_BOARD_INFO dbCustomerInfo = { + "DB-CUSTOMER", /* boardName[MAX_BOARD_NAME_LEN] */ + DB_CUSTOMER_BOARD_MPP_GROUP_TYPE_NUN, /* numBoardMppGroupType */ + dbCustomerInfoBoardMppTypeInfo, + DB_CUSTOMER_BOARD_MPP_CONFIG_NUM, /* numBoardMppConfig */ + dbCustomerInfoBoardMppConfigValue, + 0, /* intsGppMaskLow */ + 0, /* intsGppMaskHigh */ + DB_CUSTOMER_BOARD_DEVICE_CONFIG_NUM, /* numBoardDevIf */ + dbCustomerInfoBoardDeCsInfo, + DB_CUSTOMER_BOARD_TWSI_DEF_NUM, /* numBoardTwsiDev */ + dbCustomerInfoBoardTwsiDev, + DB_CUSTOMER_BOARD_MAC_INFO_NUM, /* numBoardMacInfo */ + dbCustomerInfoBoardMacInfo, + DB_CUSTOMER_BOARD_GPP_INFO_NUM, /* numBoardGppInfo */ + 0, + DB_CUSTOMER_BOARD_DEBUG_LED_NUM, /* activeLedsNumber */ + NULL, + 0, /* ledsPolarity */ + DB_CUSTOMER_OE_LOW, /* gppOutEnLow */ + DB_CUSTOMER_OE_HIGH, /* gppOutEnHigh */ + DB_CUSTOMER_OE_VAL_LOW, /* gppOutValLow */ + DB_CUSTOMER_OE_VAL_HIGH, /* gppOutValHigh */ + 0, /* gppPolarityValLow */ + 0, /* gppPolarityValHigh */ + NULL /* pSwitchInfo */ +}; + +MV_BOARD_INFO* boardInfoTbl[] = { + &db88f6281AInfo, + &rd88f6281AInfo, + &db88f6192AInfo, + &rd88f6192AInfo, + &db88f6180AInfo, + &db88f6190AInfo, + &rd88f6190AInfo, + &rd88f6281APcacInfo, + &dbCustomerInfo, + &sheevaPlugInfo + }; + + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/boardEnv/mvBoardEnvSpec.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/boardEnv/mvBoardEnvSpec.h new file mode 100644 index 0000000..0372eee --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/boardEnv/mvBoardEnvSpec.h @@ -0,0 +1,262 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + + +#ifndef __INCmvBoardEnvSpech +#define __INCmvBoardEnvSpech + +#include "mvSysHwConfig.h" + + +/* For future use */ +#define BD_ID_DATA_START_OFFS 0x0 +#define BD_DETECT_SEQ_OFFS 0x0 +#define BD_SYS_NUM_OFFS 0x4 +#define BD_NAME_OFFS 0x8 + +/* I2C bus addresses */ +#define MV_BOARD_CTRL_I2C_ADDR 0x0 /* Controller slave addr */ +#define MV_BOARD_CTRL_I2C_ADDR_TYPE ADDR7_BIT +#define MV_BOARD_DIMM0_I2C_ADDR 0x56 +#define MV_BOARD_DIMM0_I2C_ADDR_TYPE ADDR7_BIT +#define MV_BOARD_DIMM1_I2C_ADDR 0x54 +#define MV_BOARD_DIMM1_I2C_ADDR_TYPE ADDR7_BIT +#define MV_BOARD_EEPROM_I2C_ADDR 0x51 +#define MV_BOARD_EEPROM_I2C_ADDR_TYPE ADDR7_BIT +#define MV_BOARD_MAIN_EEPROM_I2C_ADDR 0x50 +#define MV_BOARD_MAIN_EEPROM_I2C_ADDR_TYPE ADDR7_BIT +#define MV_BOARD_MUX_I2C_ADDR_ENTRY 0x2 +#define MV_BOARD_DIMM_I2C_CHANNEL 0x0 + +#define BOOT_FLASH_INDEX 0 +#define MAIN_FLASH_INDEX 1 + +#define BOARD_ETH_START_PORT_NUM 0 + +/* Supported clocks */ +#define MV_BOARD_TCLK_100MHZ 100000000 +#define MV_BOARD_TCLK_125MHZ 125000000 +#define MV_BOARD_TCLK_133MHZ 133333333 +#define MV_BOARD_TCLK_150MHZ 150000000 +#define MV_BOARD_TCLK_166MHZ 166666667 +#define MV_BOARD_TCLK_200MHZ 200000000 + +#define MV_BOARD_SYSCLK_100MHZ 100000000 +#define MV_BOARD_SYSCLK_125MHZ 125000000 +#define MV_BOARD_SYSCLK_133MHZ 133333333 +#define MV_BOARD_SYSCLK_150MHZ 150000000 +#define MV_BOARD_SYSCLK_166MHZ 166666667 +#define MV_BOARD_SYSCLK_200MHZ 200000000 +#define MV_BOARD_SYSCLK_233MHZ 233333333 +#define MV_BOARD_SYSCLK_250MHZ 250000000 +#define MV_BOARD_SYSCLK_267MHZ 266666667 +#define MV_BOARD_SYSCLK_300MHZ 300000000 +#define MV_BOARD_SYSCLK_333MHZ 333333334 +#define MV_BOARD_SYSCLK_400MHZ 400000000 + +#define MV_BOARD_REFCLK_25MHZ 25000000 + +/* Board specific */ +/* =============================== */ + +/* boards ID numbers */ + +#define BOARD_ID_BASE 0x0 + +/* New board ID numbers */ +#define DB_88F6281A_BP_ID (BOARD_ID_BASE) +#define DB_88F6281_BP_MLL_ID 1680 +#define RD_88F6281A_ID (BOARD_ID_BASE+0x1) +#define RD_88F6281_MLL_ID 1682 +#define DB_88F6192A_BP_ID (BOARD_ID_BASE+0x2) +#define RD_88F6192A_ID (BOARD_ID_BASE+0x3) +#define RD_88F6192_MLL_ID 1681 +#define DB_88F6180A_BP_ID (BOARD_ID_BASE+0x4) +#define DB_88F6190A_BP_ID (BOARD_ID_BASE+0x5) +#define RD_88F6190A_ID (BOARD_ID_BASE+0x6) +#define RD_88F6281A_PCAC_ID (BOARD_ID_BASE+0x7) +#define DB_CUSTOMER_ID (BOARD_ID_BASE+0x8) +#define SHEEVA_PLUG_ID (BOARD_ID_BASE+0x9) +#define MV_MAX_BOARD_ID (SHEEVA_PLUG_ID + 1) + +/* DB-88F6281A-BP */ +#if defined(MV_NAND) + #define DB_88F6281A_MPP0_7 0x21111111 +#else + #define DB_88F6281A_MPP0_7 0x21112220 +#endif +#define DB_88F6281A_MPP8_15 0x11113311 +#define DB_88F6281A_MPP16_23 0x00551111 +#define DB_88F6281A_MPP24_31 0x00000000 +#define DB_88F6281A_MPP32_39 0x00000000 +#define DB_88F6281A_MPP40_47 0x00000000 +#define DB_88F6281A_MPP48_55 0x00000000 +#define DB_88F6281A_OE_LOW 0x0 +#if defined(MV_TDM_5CHANNELS) + #define DB_88F6281A_OE_HIGH (BIT6) +#else +#define DB_88F6281A_OE_HIGH 0x0 +#endif +#define DB_88F6281A_OE_VAL_LOW 0x0 +#define DB_88F6281A_OE_VAL_HIGH 0x0 + +/* RD-88F6281A */ +#if defined(MV_NAND) + #define RD_88F6281A_MPP0_7 0x21111111 +#else + #define RD_88F6281A_MPP0_7 0x21112220 +#endif +#define RD_88F6281A_MPP8_15 0x11113311 +#define RD_88F6281A_MPP16_23 0x33331111 +#define RD_88F6281A_MPP24_31 0x33003333 +#define RD_88F6281A_MPP32_39 0x20440533 +#define RD_88F6281A_MPP40_47 0x22202222 +#define RD_88F6281A_MPP48_55 0x00000002 +#define RD_88F6281A_OE_LOW (BIT28 | BIT29) +#define RD_88F6281A_OE_HIGH (BIT3 | BIT6 | BIT17) +#define RD_88F6281A_OE_VAL_LOW 0x0 +#define RD_88F6281A_OE_VAL_HIGH 0x0 + +/* DB-88F6192A-BP */ +#if defined(MV_NAND) + #define DB_88F6192A_MPP0_7 0x21111111 +#else + #define DB_88F6192A_MPP0_7 0x21112220 +#endif +#define DB_88F6192A_MPP8_15 0x11113311 +#define DB_88F6192A_MPP16_23 0x00501111 +#define DB_88F6192A_MPP24_31 0x00000000 +#define DB_88F6192A_MPP32_35 0x00000000 +#define DB_88F6192A_OE_LOW (BIT22 | BIT23) +#define DB_88F6192A_OE_HIGH 0x0 +#define DB_88F6192A_OE_VAL_LOW 0x0 +#define DB_88F6192A_OE_VAL_HIGH 0x0 + +/* RD-88F6192A */ +#define RD_88F6192A_MPP0_7 0x01222222 +#define RD_88F6192A_MPP8_15 0x00000011 +#define RD_88F6192A_MPP16_23 0x05550000 +#define RD_88F6192A_MPP24_31 0x0 +#define RD_88F6192A_MPP32_35 0x0 +#define RD_88F6192A_OE_LOW (BIT11 | BIT14 | BIT24 | BIT25 | BIT26 | BIT27 | BIT30 | BIT31) +#define RD_88F6192A_OE_HIGH (BIT0 | BIT2) +#define RD_88F6192A_OE_VAL_LOW 0x18400 +#define RD_88F6192A_OE_VAL_HIGH 0x8 + +/* DB-88F6180A-BP */ +#if defined(MV_NAND) + #define DB_88F6180A_MPP0_7 0x21111111 +#else + #define DB_88F6180A_MPP0_7 0x01112222 +#endif +#define DB_88F6180A_MPP8_15 0x11113311 +#define DB_88F6180A_MPP16_23 0x00001111 +#define DB_88F6180A_MPP24_31 0x0 +#define DB_88F6180A_MPP32_39 0x4444c000 +#define DB_88F6180A_MPP40_44 0x00044444 +#define DB_88F6180A_OE_LOW 0x0 +#define DB_88F6180A_OE_HIGH 0x0 +#define DB_88F6180A_OE_VAL_LOW 0x0 +#define DB_88F6180A_OE_VAL_HIGH 0x0 + +/* RD-88F6281A_PCAC */ +#define RD_88F6281A_PCAC_MPP0_7 0x21111111 +#define RD_88F6281A_PCAC_MPP8_15 0x00003311 +#define RD_88F6281A_PCAC_MPP16_23 0x00001100 +#define RD_88F6281A_PCAC_MPP24_31 0x00000000 +#define RD_88F6281A_PCAC_MPP32_39 0x00000000 +#define RD_88F6281A_PCAC_MPP40_47 0x00000000 +#define RD_88F6281A_PCAC_MPP48_55 0x00000000 +#define RD_88F6281A_PCAC_OE_LOW 0x0 +#define RD_88F6281A_PCAC_OE_HIGH 0x0 +#define RD_88F6281A_PCAC_OE_VAL_LOW 0x0 +#define RD_88F6281A_PCAC_OE_VAL_HIGH 0x0 + +/* SHEEVA PLUG */ +#define RD_SHEEVA_PLUG_MPP0_7 0x01111111 +#define RD_SHEEVA_PLUG_MPP8_15 0x11113322 +#define RD_SHEEVA_PLUG_MPP16_23 0x00001111 +#define RD_SHEEVA_PLUG_MPP24_31 0x00100000 +#define RD_SHEEVA_PLUG_MPP32_39 0x00000000 +#define RD_SHEEVA_PLUG_MPP40_47 0x00000000 +#define RD_SHEEVA_PLUG_MPP48_55 0x00000000 +#define RD_SHEEVA_PLUG_OE_LOW 0x0 +#define RD_SHEEVA_PLUG_OE_HIGH 0x0 +#define RD_SHEEVA_PLUG_OE_VAL_LOW (BIT29) +#define RD_SHEEVA_PLUG_OE_VAL_HIGH ((~(BIT17 | BIT16 | BIT15)) | BIT14) + +/* DB-CUSTOMER */ +#define DB_CUSTOMER_MPP0_7 0x21111111 +#define DB_CUSTOMER_MPP8_15 0x00003311 +#define DB_CUSTOMER_MPP16_23 0x00001100 +#define DB_CUSTOMER_MPP24_31 0x00000000 +#define DB_CUSTOMER_MPP32_39 0x00000000 +#define DB_CUSTOMER_MPP40_47 0x00000000 +#define DB_CUSTOMER_MPP48_55 0x00000000 +#define DB_CUSTOMER_OE_LOW 0x0 +#define DB_CUSTOMER_OE_HIGH (~((BIT6) | (BIT7) | (BIT8) | (BIT9))) +#define DB_CUSTOMER_OE_VAL_LOW 0x0 +#define DB_CUSTOMER_OE_VAL_HIGH 0x0 + +#endif /* __INCmvBoardEnvSpech */ diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/cpu/mvCpu.c b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/cpu/mvCpu.c new file mode 100644 index 0000000..fed0fa1 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/cpu/mvCpu.c @@ -0,0 +1,320 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + + +#include "cpu/mvCpu.h" +#include "ctrlEnv/mvCtrlEnvLib.h" +#include "ctrlEnv/mvCtrlEnvRegs.h" +#include "ctrlEnv/sys/mvCpuIfRegs.h" + +/* defines */ +#ifdef MV_DEBUG + #define DB(x) x +#else + #define DB(x) +#endif + +/* locals */ + +/******************************************************************************* +* mvCpuPclkGet - Get the CPU pClk (pipe clock) +* +* DESCRIPTION: +* This routine extract the CPU core clock. +* +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* 32bit clock cycles in MHertz. +* +*******************************************************************************/ +/* 6180 have different clk reset sampling */ + +static MV_U32 mvCpu6180PclkGet(MV_VOID) +{ + MV_U32 tmpPClkRate=0; + MV_CPU_ARM_CLK cpu6180_ddr_l2_CLK[] = MV_CPU6180_DDR_L2_CLCK_TBL; + + tmpPClkRate = MV_REG_READ(MPP_SAMPLE_AT_RESET); + tmpPClkRate = tmpPClkRate & MSAR_CPUCLCK_MASK_6180; + tmpPClkRate = tmpPClkRate >> MSAR_CPUCLCK_OFFS_6180; + + tmpPClkRate = cpu6180_ddr_l2_CLK[tmpPClkRate].cpuClk; + + return tmpPClkRate; +} + + +MV_U32 mvCpuPclkGet(MV_VOID) +{ +#if defined(PCLCK_AUTO_DETECT) + MV_U32 tmpPClkRate=0; + MV_U32 cpuCLK[] = MV_CPU_CLCK_TBL; + + if(mvCtrlModelGet() == MV_6180_DEV_ID) + return mvCpu6180PclkGet(); + + tmpPClkRate = MV_REG_READ(MPP_SAMPLE_AT_RESET); + tmpPClkRate = MSAR_CPUCLCK_EXTRACT(tmpPClkRate); + tmpPClkRate = cpuCLK[tmpPClkRate]; + + return tmpPClkRate; +#else + return MV_DEFAULT_PCLK +#endif +} + +/******************************************************************************* +* mvCpuL2ClkGet - Get the CPU L2 (CPU bus clock) +* +* DESCRIPTION: +* This routine extract the CPU L2 clock. +* +* RETURN: +* 32bit clock cycles in Hertz. +* +*******************************************************************************/ +static MV_U32 mvCpu6180L2ClkGet(MV_VOID) +{ + MV_U32 L2ClkRate=0; + MV_CPU_ARM_CLK _cpu6180_ddr_l2_CLK[] = MV_CPU6180_DDR_L2_CLCK_TBL; + + L2ClkRate = MV_REG_READ(MPP_SAMPLE_AT_RESET); + L2ClkRate = L2ClkRate & MSAR_CPUCLCK_MASK_6180; + L2ClkRate = L2ClkRate >> MSAR_CPUCLCK_OFFS_6180; + + L2ClkRate = _cpu6180_ddr_l2_CLK[L2ClkRate].l2Clk; + + return L2ClkRate; + +} + +MV_U32 mvCpuL2ClkGet(MV_VOID) +{ +#ifdef L2CLK_AUTO_DETECT + MV_U32 L2ClkRate, tmp, pClkRate, indexL2Rtio; + MV_U32 L2Rtio[][2] = MV_L2_CLCK_RTIO_TBL; + + if(mvCtrlModelGet() == MV_6180_DEV_ID) + return mvCpu6180L2ClkGet(); + + pClkRate = mvCpuPclkGet(); + + tmp = MV_REG_READ(MPP_SAMPLE_AT_RESET); + indexL2Rtio = MSAR_L2CLCK_EXTRACT(tmp); + + L2ClkRate = ((pClkRate * L2Rtio[indexL2Rtio][1]) / L2Rtio[indexL2Rtio][0]); + + return L2ClkRate; +#else + return MV_BOARD_DEFAULT_L2CLK; +#endif +} + + +/******************************************************************************* +* mvCpuNameGet - Get CPU name +* +* DESCRIPTION: +* This function returns a string describing the CPU model and revision. +* +* INPUT: +* None. +* +* OUTPUT: +* pNameBuff - Buffer to contain board name string. Minimum size 32 chars. +* +* RETURN: +* None. +*******************************************************************************/ +MV_VOID mvCpuNameGet(char *pNameBuff) +{ + MV_U32 cpuModel; + + cpuModel = mvOsCpuPartGet(); + + /* The CPU module is indicated in the Processor Version Register (PVR) */ + switch(cpuModel) + { + case CPU_PART_MRVL131: + mvOsSPrintf(pNameBuff, "%s (Rev %d)", "Marvell Feroceon",mvOsCpuRevGet()); + break; + case CPU_PART_ARM926: + mvOsSPrintf(pNameBuff, "%s (Rev %d)", "ARM926",mvOsCpuRevGet()); + break; + case CPU_PART_ARM946: + mvOsSPrintf(pNameBuff, "%s (Rev %d)", "ARM946",mvOsCpuRevGet()); + break; + default: + mvOsSPrintf(pNameBuff,"??? (0x%04x) (Rev %d)",cpuModel,mvOsCpuRevGet()); + break; + } /* switch */ + + return; +} + + +#define MV_PROC_STR_SIZE 50 + +static void mvCpuIfGetL2EccMode(MV_8 *buf) +{ + MV_U32 regVal = MV_REG_READ(CPU_L2_CONFIG_REG); + if (regVal & BIT2) + mvOsSPrintf(buf, "L2 ECC Enabled"); + else + mvOsSPrintf(buf, "L2 ECC Disabled"); +} + +static void mvCpuIfGetL2Mode(MV_8 *buf) +{ + MV_U32 regVal = 0; + __asm volatile ("mrc p15, 1, %0, c15, c1, 0" : "=r" (regVal)); /* Read Marvell extra features register */ + if (regVal & BIT22) + mvOsSPrintf(buf, "L2 Enabled"); + else + mvOsSPrintf(buf, "L2 Disabled"); +} + +static void mvCpuIfGetL2PrefetchMode(MV_8 *buf) +{ + MV_U32 regVal = 0; + __asm volatile ("mrc p15, 1, %0, c15, c1, 0" : "=r" (regVal)); /* Read Marvell extra features register */ + if (regVal & BIT24) + mvOsSPrintf(buf, "L2 Prefetch Disabled"); + else + mvOsSPrintf(buf, "L2 Prefetch Enabled"); +} + +static void mvCpuIfGetWriteAllocMode(MV_8 *buf) +{ + MV_U32 regVal = 0; + __asm volatile ("mrc p15, 1, %0, c15, c1, 0" : "=r" (regVal)); /* Read Marvell extra features register */ + if (regVal & BIT28) + mvOsSPrintf(buf, "Write Allocate Enabled"); + else + mvOsSPrintf(buf, "Write Allocate Disabled"); +} + +static void mvCpuIfGetCpuStreamMode(MV_8 *buf) +{ + MV_U32 regVal = 0; + __asm volatile ("mrc p15, 1, %0, c15, c1, 0" : "=r" (regVal)); /* Read Marvell extra features register */ + if (regVal & BIT29) + mvOsSPrintf(buf, "CPU Streaming Enabled"); + else + mvOsSPrintf(buf, "CPU Streaming Disabled"); +} + +static void mvCpuIfPrintCpuRegs(void) +{ + MV_U32 regVal = 0; + + __asm volatile ("mrc p15, 1, %0, c15, c1, 0" : "=r" (regVal)); /* Read Marvell extra features register */ + mvOsPrintf("Extra Feature Reg = 0x%x\n",regVal); + + __asm volatile ("mrc p15, 0, %0, c1, c0, 0" : "=r" (regVal)); /* Read Control register */ + mvOsPrintf("Control Reg = 0x%x\n",regVal); + + __asm volatile ("mrc p15, 0, %0, c0, c0, 0" : "=r" (regVal)); /* Read ID Code register */ + mvOsPrintf("ID Code Reg = 0x%x\n",regVal); + + __asm volatile ("mrc p15, 0, %0, c0, c0, 1" : "=r" (regVal)); /* Read Cache Type register */ + mvOsPrintf("Cache Type Reg = 0x%x\n",regVal); + +} + +MV_U32 mvCpuIfPrintSystemConfig(MV_8 *buffer, MV_U32 index) +{ + MV_U32 count = 0; + + MV_8 L2_ECC_str[MV_PROC_STR_SIZE]; + MV_8 L2_En_str[MV_PROC_STR_SIZE]; + MV_8 L2_Prefetch_str[MV_PROC_STR_SIZE]; + MV_8 Write_Alloc_str[MV_PROC_STR_SIZE]; + MV_8 Cpu_Stream_str[MV_PROC_STR_SIZE]; + + mvCpuIfGetL2Mode(L2_En_str); + mvCpuIfGetL2EccMode(L2_ECC_str); + mvCpuIfGetL2PrefetchMode(L2_Prefetch_str); + mvCpuIfGetWriteAllocMode(Write_Alloc_str); + mvCpuIfGetCpuStreamMode(Cpu_Stream_str); + mvCpuIfPrintCpuRegs(); + + count += mvOsSPrintf(buffer + count + index, "%s\n", L2_En_str); + count += mvOsSPrintf(buffer + count + index, "%s\n", L2_ECC_str); + count += mvOsSPrintf(buffer + count + index, "%s\n", L2_Prefetch_str); + count += mvOsSPrintf(buffer + count + index, "%s\n", Write_Alloc_str); + count += mvOsSPrintf(buffer + count + index, "%s\n", Cpu_Stream_str); + return count; +} + +MV_U32 whoAmI(MV_VOID) +{ + return 0; +} + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/cpu/mvCpu.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/cpu/mvCpu.h new file mode 100644 index 0000000..7f58b03 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/cpu/mvCpu.h @@ -0,0 +1,99 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + + +#ifndef __INCmvCpuh +#define __INCmvCpuh + +#include "mvCommon.h" +#include "mvOs.h" +#include "ctrlEnv/mvCtrlEnvSpec.h" + +/* defines */ +#define CPU_PART_MRVL131 0x131 +#define CPU_PART_ARM926 0x926 +#define CPU_PART_ARM946 0x946 +#define MV_CPU_ARM_CLK_ELM_SIZE 12 +#define MV_CPU_ARM_CLK_RATIO_OFF 8 +#define MV_CPU_ARM_CLK_DDR_OFF 4 + +#ifndef MV_ASMLANGUAGE +typedef struct _mvCpuArmClk +{ + MV_U32 cpuClk; /* CPU clock in MHz */ + MV_U32 ddrClk; /* DDR clock in MHz */ + MV_U32 l2Clk; /* CPU DDR clock ratio */ + +}MV_CPU_ARM_CLK; + +MV_U32 mvCpuPclkGet(MV_VOID); +MV_VOID mvCpuNameGet(char *pNameBuff); +MV_U32 mvCpuL2ClkGet(MV_VOID); +MV_U32 mvCpuIfPrintSystemConfig(MV_8 *buffer, MV_U32 index); +MV_U32 whoAmI(MV_VOID); + +#endif /* MV_ASMLANGUAGE */ + + +#endif /* __INCmvCpuh */ diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/mvCtrlEnvAddrDec.c b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/mvCtrlEnvAddrDec.c new file mode 100644 index 0000000..fbe7c56 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/mvCtrlEnvAddrDec.c @@ -0,0 +1,296 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +/******************************************************************************* +* mvCtrlEnvAddrDec.h - Marvell controller address decode library +* +* DESCRIPTION: +* +* DEPENDENCIES: +* None. +* +*******************************************************************************/ + +/* includes */ +#include "ctrlEnv/mvCtrlEnvAddrDec.h" +#include "ctrlEnv/sys/mvAhbToMbusRegs.h" +#include "ddr2/mvDramIfRegs.h" +#include "pex/mvPexRegs.h" + +#define MV_DEBUG + +/* defines */ +#ifdef MV_DEBUG + #define DB(x) x +#else + #define DB(x) +#endif + +/* Default Attributes array */ +MV_TARGET_ATTRIB mvTargetDefaultsArray[] = TARGETS_DEF_ARRAY; +extern MV_TARGET *sampleAtResetTargetArray; +/* Dram\AHBToMbus\PEX share regsiter */ + +#define CTRL_DEC_BASE_OFFS 16 +#define CTRL_DEC_BASE_MASK (0xffff << CTRL_DEC_BASE_OFFS) +#define CTRL_DEC_BASE_ALIGNMENT 0x10000 + +#define CTRL_DEC_SIZE_OFFS 16 +#define CTRL_DEC_SIZE_MASK (0xffff << CTRL_DEC_SIZE_OFFS) +#define CTRL_DEC_SIZE_ALIGNMENT 0x10000 + +#define CTRL_DEC_WIN_EN BIT0 + + + +/******************************************************************************* +* mvCtrlAddrDecToReg - Get address decode register format values +* +* DESCRIPTION: +* +* INPUT: +* +* OUTPUT: +* +* RETURN: +* +*******************************************************************************/ +MV_STATUS mvCtrlAddrDecToReg(MV_ADDR_WIN *pAddrDecWin, MV_DEC_REGS *pAddrDecRegs) +{ + + MV_U32 baseToReg=0 , sizeToReg=0; + + /* BaseLow[31:16] => base register [31:16] */ + baseToReg = pAddrDecWin->baseLow & CTRL_DEC_BASE_MASK; + + /* Write to address decode Base Address Register */ + pAddrDecRegs->baseReg &= ~CTRL_DEC_BASE_MASK; + pAddrDecRegs->baseReg |= baseToReg; + + /* Get size register value according to window size */ + sizeToReg = ctrlSizeToReg(pAddrDecWin->size, CTRL_DEC_SIZE_ALIGNMENT); + + /* Size parameter validity check. */ + if (-1 == sizeToReg) + { + return MV_BAD_PARAM; + } + + /* set size */ + pAddrDecRegs->sizeReg &= ~CTRL_DEC_SIZE_MASK; + pAddrDecRegs->sizeReg |= (sizeToReg << CTRL_DEC_SIZE_OFFS); + + + return MV_OK; + +} + +/******************************************************************************* +* mvCtrlRegToAddrDec - Extract address decode struct from registers. +* +* DESCRIPTION: +* This function extract address decode struct from address decode +* registers given as parameters. +* +* INPUT: +* pAddrDecRegs - Address decode register struct. +* +* OUTPUT: +* pAddrDecWin - Target window data structure. +* +* RETURN: +* MV_BAD_PARAM if address decode registers data is invalid. +* +*******************************************************************************/ +MV_STATUS mvCtrlRegToAddrDec(MV_DEC_REGS *pAddrDecRegs, MV_ADDR_WIN *pAddrDecWin) +{ + MV_U32 sizeRegVal; + + sizeRegVal = (pAddrDecRegs->sizeReg & CTRL_DEC_SIZE_MASK) >> + CTRL_DEC_SIZE_OFFS; + + pAddrDecWin->size = ctrlRegToSize(sizeRegVal, CTRL_DEC_SIZE_ALIGNMENT); + + + /* Extract base address */ + /* Base register [31:16] ==> baseLow[31:16] */ + pAddrDecWin->baseLow = pAddrDecRegs->baseReg & CTRL_DEC_BASE_MASK; + + pAddrDecWin->baseHigh = 0; + + return MV_OK; + +} + +/******************************************************************************* +* mvCtrlAttribGet - +* +* DESCRIPTION: +* +* INPUT: +* +* OUTPUT: +* +* RETURN: +* +*******************************************************************************/ + +MV_STATUS mvCtrlAttribGet(MV_TARGET target, + MV_TARGET_ATTRIB *targetAttrib) +{ + + targetAttrib->attrib = mvTargetDefaultsArray[MV_CHANGE_BOOT_CS(target)].attrib; + targetAttrib->targetId = mvTargetDefaultsArray[MV_CHANGE_BOOT_CS(target)].targetId; + + return MV_OK; + +} + +/******************************************************************************* +* mvCtrlGetAttrib - +* +* DESCRIPTION: +* +* INPUT: +* +* OUTPUT: +* +* RETURN: +* +*******************************************************************************/ +MV_TARGET mvCtrlTargetGet(MV_TARGET_ATTRIB *targetAttrib) +{ + MV_TARGET target; + MV_TARGET x; + for (target = SDRAM_CS0; target < MAX_TARGETS ; target ++) + { + x = MV_CHANGE_BOOT_CS(target); + if ((mvTargetDefaultsArray[x].attrib == targetAttrib->attrib) && + (mvTargetDefaultsArray[MV_CHANGE_BOOT_CS(target)].targetId == targetAttrib->targetId)) + { + /* found it */ + break; + } + } + + return target; +} + +MV_STATUS mvCtrlAddrDecToParams(MV_DEC_WIN *pAddrDecWin, + MV_DEC_WIN_PARAMS *pWinParam) +{ + MV_U32 baseToReg=0, sizeToReg=0; + + /* BaseLow[31:16] => base register [31:16] */ + baseToReg = pAddrDecWin->addrWin.baseLow & CTRL_DEC_BASE_MASK; + + /* Write to address decode Base Address Register */ + pWinParam->baseAddr &= ~CTRL_DEC_BASE_MASK; + pWinParam->baseAddr |= baseToReg; + + /* Get size register value according to window size */ + sizeToReg = ctrlSizeToReg(pAddrDecWin->addrWin.size, CTRL_DEC_SIZE_ALIGNMENT); + + /* Size parameter validity check. */ + if (-1 == sizeToReg) + { + mvOsPrintf("mvCtrlAddrDecToParams: ERR. ctrlSizeToReg failed.\n"); + return MV_BAD_PARAM; + } + pWinParam->size = sizeToReg; + + pWinParam->attrib = mvTargetDefaultsArray[MV_CHANGE_BOOT_CS(pAddrDecWin->target)].attrib; + pWinParam->targetId = mvTargetDefaultsArray[MV_CHANGE_BOOT_CS(pAddrDecWin->target)].targetId; + + return MV_OK; +} + +MV_STATUS mvCtrlParamsToAddrDec(MV_DEC_WIN_PARAMS *pWinParam, + MV_DEC_WIN *pAddrDecWin) +{ + MV_TARGET_ATTRIB targetAttrib; + + pAddrDecWin->addrWin.baseLow = pWinParam->baseAddr; + + /* Upper 32bit address base is supported under PCI High Address remap */ + pAddrDecWin->addrWin.baseHigh = 0; + + /* Prepare sizeReg to ctrlRegToSize function */ + pAddrDecWin->addrWin.size = ctrlRegToSize(pWinParam->size, CTRL_DEC_SIZE_ALIGNMENT); + + if (-1 == pAddrDecWin->addrWin.size) + { + DB(mvOsPrintf("mvCtrlParamsToAddrDec: ERR. ctrlRegToSize failed.\n")); + return MV_BAD_PARAM; + } + targetAttrib.targetId = pWinParam->targetId; + targetAttrib.attrib = pWinParam->attrib; + + pAddrDecWin->target = mvCtrlTargetGet(&targetAttrib); + + return MV_OK; +} + + + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/mvCtrlEnvAddrDec.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/mvCtrlEnvAddrDec.h new file mode 100644 index 0000000..946737f --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/mvCtrlEnvAddrDec.h @@ -0,0 +1,203 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + + +#ifndef __INCmvCtrlEnvAddrDech +#define __INCmvCtrlEnvAddrDech + +/* includes */ +#include "ctrlEnv/mvCtrlEnvLib.h" +#include "ctrlEnv/mvCtrlEnvRegs.h" + + +/* defines */ +/* DUnit attributes */ +#define ATMWCR_WIN_DUNIT_CS0_OFFS 0 +#define ATMWCR_WIN_DUNIT_CS0_MASK BIT0 +#define ATMWCR_WIN_DUNIT_CS0_REQ (0 << ATMWCR_WIN_DUNIT_CS0_OFFS) + +#define ATMWCR_WIN_DUNIT_CS1_OFFS 1 +#define ATMWCR_WIN_DUNIT_CS1_MASK BIT1 +#define ATMWCR_WIN_DUNIT_CS1_REQ (0 << ATMWCR_WIN_DUNIT_CS1_OFFS) + +#define ATMWCR_WIN_DUNIT_CS2_OFFS 2 +#define ATMWCR_WIN_DUNIT_CS2_MASK BIT2 +#define ATMWCR_WIN_DUNIT_CS2_REQ (0 << ATMWCR_WIN_DUNIT_CS2_OFFS) + +#define ATMWCR_WIN_DUNIT_CS3_OFFS 3 +#define ATMWCR_WIN_DUNIT_CS3_MASK BIT3 +#define ATMWCR_WIN_DUNIT_CS3_REQ (0 << ATMWCR_WIN_DUNIT_CS3_OFFS) + +/* RUnit (Device) attributes */ +#define ATMWCR_WIN_RUNIT_DEVCS0_OFFS 0 +#define ATMWCR_WIN_RUNIT_DEVCS0_MASK BIT0 +#define ATMWCR_WIN_RUNIT_DEVCS0_REQ (0 << ATMWCR_WIN_RUNIT_DEVCS0_OFFS) + +#define ATMWCR_WIN_RUNIT_DEVCS1_OFFS 1 +#define ATMWCR_WIN_RUNIT_DEVCS1_MASK BIT1 +#define ATMWCR_WIN_RUNIT_DEVCS1_REQ (0 << ATMWCR_WIN_RUNIT_DEVCS1_OFFS) + +#define ATMWCR_WIN_RUNIT_DEVCS2_OFFS 2 +#define ATMWCR_WIN_RUNIT_DEVCS2_MASK BIT2 +#define ATMWCR_WIN_RUNIT_DEVCS2_REQ (0 << ATMWCR_WIN_RUNIT_DEVCS2_OFFS) + +#define ATMWCR_WIN_RUNIT_BOOTCS_OFFS 4 +#define ATMWCR_WIN_RUNIT_BOOTCS_MASK BIT4 +#define ATMWCR_WIN_RUNIT_BOOTCS_REQ (0 << ATMWCR_WIN_RUNIT_BOOTCS_OFFS) + +/* LMaster (PCI) attributes */ +#define ATMWCR_WIN_LUNIT_BYTE_SWP_OFFS 0 +#define ATMWCR_WIN_LUNIT_BYTE_SWP_MASK BIT0 +#define ATMWCR_WIN_LUNIT_BYTE_SWP (0 << ATMWCR_WIN_LUNIT_BYTE_SWP_OFFS) +#define ATMWCR_WIN_LUNIT_BYTE_NO_SWP (1 << ATMWCR_WIN_LUNIT_BYTE_SWP_OFFS) + + +#define ATMWCR_WIN_LUNIT_WORD_SWP_OFFS 1 +#define ATMWCR_WIN_LUNIT_WORD_SWP_MASK BIT1 +#define ATMWCR_WIN_LUNIT_WORD_SWP (0 << ATMWCR_WIN_LUNIT_WORD_SWP_OFFS) +#define ATMWCR_WIN_LUNIT_WORD_NO_SWP (1 << ATMWCR_WIN_LUNIT_WORD_SWP_OFFS) + +#define ATMWCR_WIN_LUNIT_NO_SNOOP BIT2 + +#define ATMWCR_WIN_LUNIT_TYPE_OFFS 3 +#define ATMWCR_WIN_LUNIT_TYPE_MASK BIT3 +#define ATMWCR_WIN_LUNIT_TYPE_IO (0 << ATMWCR_WIN_LUNIT_TYPE_OFFS) +#define ATMWCR_WIN_LUNIT_TYPE_MEM (1 << ATMWCR_WIN_LUNIT_TYPE_OFFS) + +#define ATMWCR_WIN_LUNIT_FORCE64_OFFS 4 +#define ATMWCR_WIN_LUNIT_FORCE64_MASK BIT4 +#define ATMWCR_WIN_LUNIT_FORCE64 (0 << ATMWCR_WIN_LUNIT_FORCE64_OFFS) + +#define ATMWCR_WIN_LUNIT_ORDERING_OFFS 6 +#define ATMWCR_WIN_LUNIT_ORDERING_MASK BIT6 +#define ATMWCR_WIN_LUNIT_ORDERING (1 << ATMWCR_WIN_LUNIT_FORCE64_OFFS) + +/* PEX Attributes */ +#define ATMWCR_WIN_PEX_TYPE_OFFS 3 +#define ATMWCR_WIN_PEX_TYPE_MASK BIT3 +#define ATMWCR_WIN_PEX_TYPE_IO (0 << ATMWCR_WIN_PEX_TYPE_OFFS) +#define ATMWCR_WIN_PEX_TYPE_MEM (1 << ATMWCR_WIN_PEX_TYPE_OFFS) + +/* typedefs */ + +/* Unsupported attributes for address decode: */ +/* 2) PCI0/1_REQ64n control */ + +typedef struct _mvDecRegs +{ + MV_U32 baseReg; + MV_U32 baseRegHigh; + MV_U32 sizeReg; + +}MV_DEC_REGS; + +typedef struct _mvTargetAttrib +{ + MV_U8 attrib; /* chip select attributes */ + MV_TARGET_ID targetId; /* Target Id of this MV_TARGET */ + +}MV_TARGET_ATTRIB; + + +/* This structure describes address decode window */ +typedef struct _mvDecWin +{ + MV_TARGET target; /* Target for addr decode window */ + MV_ADDR_WIN addrWin; /* Address window of target */ + MV_BOOL enable; /* Window enable/disable */ +}MV_DEC_WIN; + +typedef struct _mvDecWinParams +{ + MV_TARGET_ID targetId; /* Target ID field */ + MV_U8 attrib; /* Attribute field */ + MV_U32 baseAddr; /* Base address in register format */ + MV_U32 size; /* Size in register format */ +}MV_DEC_WIN_PARAMS; + + +/* mvCtrlEnvAddrDec API list */ + +MV_STATUS mvCtrlAddrDecToReg(MV_ADDR_WIN *pAddrDecWin, + MV_DEC_REGS *pAddrDecRegs); + +MV_STATUS mvCtrlRegToAddrDec(MV_DEC_REGS *pAddrDecRegs, + MV_ADDR_WIN *pAddrDecWin); + +MV_STATUS mvCtrlAttribGet(MV_TARGET target, + MV_TARGET_ATTRIB *targetAttrib); + +MV_TARGET mvCtrlTargetGet(MV_TARGET_ATTRIB *targetAttrib); + + +MV_STATUS mvCtrlAddrDecToParams(MV_DEC_WIN *pAddrDecWin, + MV_DEC_WIN_PARAMS *pWinParam); + +MV_STATUS mvCtrlParamsToAddrDec(MV_DEC_WIN_PARAMS *pWinParam, + MV_DEC_WIN *pAddrDecWin); + + + + +#endif /* __INCmvCtrlEnvAddrDech */ diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/mvCtrlEnvAsm.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/mvCtrlEnvAsm.h new file mode 100644 index 0000000..6f6367a --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/mvCtrlEnvAsm.h @@ -0,0 +1,98 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + + +#ifndef __INCmvCtrlEnvAsmh +#define __INCmvCtrlEnvAsmh +#include "pex/mvPexRegs.h" + +#define CHIP_BOND_REG 0x10034 +#define PCKG_OPT_MASK_AS #3 +#define PXCCARI_REVID_MASK_AS #PXCCARI_REVID_MASK + +/* Read device ID into toReg bits 15:0 from 0xd0000000 */ +/* defines */ +#define MV_DV_CTRL_MODEL_GET_ASM(toReg, tmpReg) \ + MV_DV_REG_READ_ASM(toReg, tmpReg, CHIP_BOND_REG);\ + and toReg, toReg, PCKG_OPT_MASK_AS /* Mask for package ID */ + +/* Read device ID into toReg bits 15:0 from 0xf1000000*/ +#define MV_CTRL_MODEL_GET_ASM(toReg, tmpReg) \ + MV_REG_READ_ASM(toReg, tmpReg, CHIP_BOND_REG);\ + and toReg, toReg, PCKG_OPT_MASK_AS /* Mask for package ID */ + +/* Read Revision into toReg bits 7:0 0xd0000000*/ +#define MV_DV_CTRL_REV_GET_ASM(toReg, tmpReg) \ + /* Read device revision */ \ + MV_DV_REG_READ_ASM(toReg, tmpReg, PEX_CFG_DIRECT_ACCESS(0,PEX_CLASS_CODE_AND_REVISION_ID));\ + and toReg, toReg, PXCCARI_REVID_MASK_AS /* Mask for calss ID */ + +/* Read Revision into toReg bits 7:0 0xf1000000*/ +#define MV_CTRL_REV_GET_ASM(toReg, tmpReg) \ + /* Read device revision */ \ + MV_REG_READ_ASM(toReg, tmpReg, PEX_CFG_DIRECT_ACCESS(0,PEX_CLASS_CODE_AND_REVISION_ID));\ + and toReg, toReg, PXCCARI_REVID_MASK_AS /* Mask for calss ID */ + + +#endif /* __INCmvCtrlEnvAsmh */ diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/mvCtrlEnvLib.c b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/mvCtrlEnvLib.c new file mode 100644 index 0000000..adf451d --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/mvCtrlEnvLib.c @@ -0,0 +1,1825 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + + +/* includes */ +#include "mvCommon.h" +#include "mvCtrlEnvLib.h" +#include "ctrlEnv/sys/mvCpuIf.h" + +#if defined(MV_INCLUDE_PEX) +#include "pex/mvPex.h" +#include "ctrlEnv/sys/mvSysPex.h" +#endif + +#if defined(MV_INCLUDE_GIG_ETH) +#include "ctrlEnv/sys/mvSysGbe.h" +#endif + +#if defined(MV_INCLUDE_XOR) +#include "ctrlEnv/sys/mvSysXor.h" +#endif + +#if defined(MV_INCLUDE_SATA) +#include "ctrlEnv/sys/mvSysSata.h" +#endif + +#if defined(MV_INCLUDE_USB) +#include "ctrlEnv/sys/mvSysUsb.h" +#endif + +#if defined(MV_INCLUDE_AUDIO) +#include "ctrlEnv/sys/mvSysAudio.h" +#endif + +#if defined(MV_INCLUDE_CESA) +#include "ctrlEnv/sys/mvSysCesa.h" +#endif + +#if defined(MV_INCLUDE_TS) +#include "ctrlEnv/sys/mvSysTs.h" +#endif + +/* defines */ +#ifdef MV_DEBUG + #define DB(x) x +#else + #define DB(x) +#endif + +/******************************************************************************* +* mvCtrlEnvInit - Initialize Marvell controller environment. +* +* DESCRIPTION: +* This function get environment information and initialize controller +* internal/external environment. For example +* 1) MPP settings according to board MPP macros. +* NOTE: It is the user responsibility to shut down all DMA channels +* in device and disable controller sub units interrupts during +* boot process. +* +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* None. +* +*******************************************************************************/ +MV_STATUS mvCtrlEnvInit(MV_VOID) +{ + MV_U32 mppGroup; + MV_U32 devId; + MV_U32 boardId; + MV_U32 i; + MV_U32 maxMppGrp = 1; + MV_U32 mppVal = 0; + MV_U32 bootVal = 0; + MV_U32 mppGroupType = 0; + MV_U32 mppGroup1[][3] = MPP_GROUP_1_TYPE; + MV_U32 mppGroup2[][3] = MPP_GROUP_2_TYPE; + + devId = mvCtrlModelGet(); + boardId= mvBoardIdGet(); + + switch(devId){ + case MV_6281_DEV_ID: + maxMppGrp = MV_6281_MPP_MAX_GROUP; + break; + case MV_6192_DEV_ID: + maxMppGrp = MV_6192_MPP_MAX_GROUP; + break; + case MV_6190_DEV_ID: + maxMppGrp = MV_6190_MPP_MAX_GROUP; + break; + case MV_6180_DEV_ID: + maxMppGrp = MV_6180_MPP_MAX_GROUP; + break; + } + + /* MPP Init */ + /* We split mpp init to 3 phases: + * 1. We init mpp[19:0] from the board info. mpp[23:20] will be over write + * in phase 2. + * 2. We detect the mpp group type and according the mpp values [35:20]. + * 3. We detect the mpp group type and according the mpp values [49:36]. + */ + /* Mpp phase 1 mpp[19:0] */ + /* Read MPP group from board level and assign to MPP register */ + for (mppGroup = 0; mppGroup < 3; mppGroup++) + { + mppVal = mvBoardMppGet(mppGroup); + if (mppGroup == 0) + { + bootVal = MV_REG_READ(mvCtrlMppRegGet(mppGroup)); + if (mvCtrlIsBootFromSPI()) + { + mppVal &= ~0xffff; + bootVal &= 0xffff; + mppVal |= bootVal; + } + else if (mvCtrlIsBootFromSPIUseNAND()) + { + mppVal &= ~0xf0000000; + bootVal &= 0xf0000000; + mppVal |= bootVal; + } + else if (mvCtrlIsBootFromNAND()) + { + mppVal &= ~0xffffff; + bootVal &= 0xffffff; + mppVal |= bootVal; + } + } + + if (mppGroup == 2) + { + bootVal = MV_REG_READ(mvCtrlMppRegGet(mppGroup)); + if (mvCtrlIsBootFromNAND()) + { + mppVal &= ~0xff00; + bootVal &= 0xff00; + mppVal |= bootVal; + } + } + + MV_REG_WRITE(mvCtrlMppRegGet(mppGroup), mppVal); + } + + /* Identify MPPs group */ + mvBoardMppGroupIdUpdate(); + + /* Update MPPs mux relevent only on Marvell DB */ + if ((boardId == DB_88F6281A_BP_ID) || + (boardId == DB_88F6180A_BP_ID)) + mvBoardMppMuxSet(); + + mppGroupType = mvBoardMppGroupTypeGet(MV_BOARD_MPP_GROUP_1); + + /* Mpp phase 2 */ + /* Read MPP group from board level and assign to MPP register */ + if (devId != MV_6180_DEV_ID) + { + i = 0; + for (mppGroup = 2; mppGroup < 5; mppGroup++) + { + if ((mppGroupType == MV_BOARD_OTHER) || + (boardId == RD_88F6281A_ID) || + (boardId == RD_88F6192A_ID) || + (boardId == RD_88F6190A_ID) || + (boardId == RD_88F6281A_PCAC_ID) || + (boardId == SHEEVA_PLUG_ID)) + mppVal = mvBoardMppGet(mppGroup); + else + { + mppVal = mppGroup1[mppGroupType][i]; + i++; + } + + /* Group 2 is shared mpp[23:16] */ + if (mppGroup == 2) + { + bootVal = MV_REG_READ(mvCtrlMppRegGet(mppGroup)); + mppVal &= ~0xffff; + bootVal &= 0xffff; + mppVal |= bootVal; + } + + MV_REG_WRITE(mvCtrlMppRegGet(mppGroup), mppVal); + } + } + + if ((devId == MV_6192_DEV_ID) || (devId == MV_6190_DEV_ID)) + return MV_OK; + + /* Mpp phase 3 */ + mppGroupType = mvBoardMppGroupTypeGet(MV_BOARD_MPP_GROUP_2); + /* Read MPP group from board level and assign to MPP register */ + i = 0; + for (mppGroup = 4; mppGroup < 7; mppGroup++) + { + if ((mppGroupType == MV_BOARD_OTHER) || + (boardId == RD_88F6281A_ID) || + (boardId == RD_88F6281A_PCAC_ID) || + (boardId == SHEEVA_PLUG_ID)) + mppVal = mvBoardMppGet(mppGroup); + else + { + mppVal = mppGroup2[mppGroupType][i]; + i++; + } + + /* Group 4 is shared mpp[35:32] */ + if (mppGroup == 4) + { + bootVal = MV_REG_READ(mvCtrlMppRegGet(mppGroup)); + mppVal &= ~0xffff; + bootVal &= 0xffff; + mppVal |= bootVal; + } + + MV_REG_WRITE(mvCtrlMppRegGet(mppGroup), mppVal); + } + /* Update SSCG configuration register*/ + if(mvBoardIdGet() == DB_88F6281A_BP_ID || mvBoardIdGet() == DB_88F6192A_BP_ID || + mvBoardIdGet() == DB_88F6190A_BP_ID || mvBoardIdGet() == DB_88F6180A_BP_ID) + MV_REG_WRITE(0x100d8, 0x53); + + return MV_OK; +} + +/******************************************************************************* +* mvCtrlMppRegGet - return reg address of mpp group +* +* DESCRIPTION: +* +* INPUT: +* mppGroup - MPP group. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_U32 - Register address. +* +*******************************************************************************/ +MV_U32 mvCtrlMppRegGet(MV_U32 mppGroup) +{ + MV_U32 ret; + + switch(mppGroup){ + case (0): ret = MPP_CONTROL_REG0; + break; + case (1): ret = MPP_CONTROL_REG1; + break; + case (2): ret = MPP_CONTROL_REG2; + break; + case (3): ret = MPP_CONTROL_REG3; + break; + case (4): ret = MPP_CONTROL_REG4; + break; + case (5): ret = MPP_CONTROL_REG5; + break; + case (6): ret = MPP_CONTROL_REG6; + break; + default: ret = MPP_CONTROL_REG0; + break; + } + return ret; +} +#if defined(MV_INCLUDE_PEX) +/******************************************************************************* +* mvCtrlPexMaxIfGet - Get Marvell controller number of PEX interfaces. +* +* DESCRIPTION: +* This function returns Marvell controller number of PEX interfaces. +* +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* Marvell controller number of PEX interfaces. If controller +* ID is undefined the function returns '0'. +* +*******************************************************************************/ +MV_U32 mvCtrlPexMaxIfGet(MV_VOID) +{ + + return MV_PEX_MAX_IF; +} +#endif + +#if defined(MV_INCLUDE_GIG_ETH) +/******************************************************************************* +* mvCtrlEthMaxPortGet - Get Marvell controller number of etherent ports. +* +* DESCRIPTION: +* This function returns Marvell controller number of etherent port. +* +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* Marvell controller number of etherent port. +* +*******************************************************************************/ +MV_U32 mvCtrlEthMaxPortGet(MV_VOID) +{ + MV_U32 devId; + + devId = mvCtrlModelGet(); + + switch(devId){ + case MV_6281_DEV_ID: + return MV_6281_ETH_MAX_PORTS; + break; + case MV_6192_DEV_ID: + return MV_6192_ETH_MAX_PORTS; + break; + case MV_6190_DEV_ID: + return MV_6190_ETH_MAX_PORTS; + break; + case MV_6180_DEV_ID: + return MV_6180_ETH_MAX_PORTS; + break; + } + return 0; + +} +#endif + +#if defined(MV_INCLUDE_XOR) +/******************************************************************************* +* mvCtrlXorMaxChanGet - Get Marvell controller number of XOR channels. +* +* DESCRIPTION: +* This function returns Marvell controller number of XOR channels. +* +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* Marvell controller number of XOR channels. +* +*******************************************************************************/ +MV_U32 mvCtrlXorMaxChanGet(MV_VOID) +{ + return MV_XOR_MAX_CHAN; +} +#endif + +#if defined(MV_INCLUDE_USB) +/******************************************************************************* +* mvCtrlUsbHostMaxGet - Get number of Marvell Usb controllers +* +* DESCRIPTION: +* +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* returns number of Marvell USB controllers. +* +*******************************************************************************/ +MV_U32 mvCtrlUsbMaxGet(void) +{ + return MV_USB_MAX_PORTS; +} +#endif + + +#if defined(MV_INCLUDE_NAND) +/******************************************************************************* +* mvCtrlNandSupport - Return if this controller has integrated NAND flash support +* +* DESCRIPTION: +* +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_TRUE if NAND is supported and MV_FALSE otherwise +* +*******************************************************************************/ +MV_U32 mvCtrlNandSupport(MV_VOID) +{ + MV_U32 devId; + + devId = mvCtrlModelGet(); + + switch(devId){ + case MV_6281_DEV_ID: + return MV_6281_NAND; + break; + case MV_6192_DEV_ID: + return MV_6192_NAND; + break; + case MV_6190_DEV_ID: + return MV_6190_NAND; + break; + case MV_6180_DEV_ID: + return MV_6180_NAND; + break; + } + return 0; + +} +#endif + +#if defined(MV_INCLUDE_SDIO) +/******************************************************************************* +* mvCtrlSdioSupport - Return if this controller has integrated SDIO flash support +* +* DESCRIPTION: +* +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_TRUE if SDIO is supported and MV_FALSE otherwise +* +*******************************************************************************/ +MV_U32 mvCtrlSdioSupport(MV_VOID) +{ + MV_U32 devId; + + devId = mvCtrlModelGet(); + + switch(devId){ + case MV_6281_DEV_ID: + return MV_6281_SDIO; + break; + case MV_6192_DEV_ID: + return MV_6192_SDIO; + break; + case MV_6190_DEV_ID: + return MV_6190_SDIO; + break; + case MV_6180_DEV_ID: + return MV_6180_SDIO; + break; + } + return 0; + +} +#endif + +#if defined(MV_INCLUDE_TS) +/******************************************************************************* +* mvCtrlTsSupport - Return if this controller has integrated TS flash support +* +* DESCRIPTION: +* +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_TRUE if TS is supported and MV_FALSE otherwise +* +*******************************************************************************/ +MV_U32 mvCtrlTsSupport(MV_VOID) +{ + MV_U32 devId; + + devId = mvCtrlModelGet(); + + switch(devId){ + case MV_6281_DEV_ID: + return MV_6281_TS; + break; + case MV_6192_DEV_ID: + return MV_6192_TS; + break; + case MV_6190_DEV_ID: + return MV_6190_TS; + break; + case MV_6180_DEV_ID: + return MV_6180_TS; + break; + } + return 0; +} +#endif + +#if defined(MV_INCLUDE_AUDIO) +/******************************************************************************* +* mvCtrlAudioSupport - Return if this controller has integrated AUDIO flash support +* +* DESCRIPTION: +* +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_TRUE if AUDIO is supported and MV_FALSE otherwise +* +*******************************************************************************/ +MV_U32 mvCtrlAudioSupport(MV_VOID) +{ + MV_U32 devId; + + devId = mvCtrlModelGet(); + + switch(devId){ + case MV_6281_DEV_ID: + return MV_6281_AUDIO; + break; + case MV_6192_DEV_ID: + return MV_6192_AUDIO; + break; + case MV_6190_DEV_ID: + return MV_6190_AUDIO; + break; + case MV_6180_DEV_ID: + return MV_6180_AUDIO; + break; + } + return 0; + +} +#endif + +#if defined(MV_INCLUDE_TDM) +/******************************************************************************* +* mvCtrlTdmSupport - Return if this controller has integrated TDM flash support +* +* DESCRIPTION: +* +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_TRUE if TDM is supported and MV_FALSE otherwise +* +*******************************************************************************/ +MV_U32 mvCtrlTdmSupport(MV_VOID) +{ + MV_U32 devId; + + devId = mvCtrlModelGet(); + + switch(devId){ + case MV_6281_DEV_ID: + return MV_6281_TDM; + break; + case MV_6192_DEV_ID: + return MV_6192_TDM; + break; + case MV_6190_DEV_ID: + return MV_6190_TDM; + break; + case MV_6180_DEV_ID: + return MV_6180_TDM; + break; + } + return 0; + +} +#endif + +/******************************************************************************* +* mvCtrlModelGet - Get Marvell controller device model (Id) +* +* DESCRIPTION: +* This function returns 16bit describing the device model (ID) as defined +* in PCI Device and Vendor ID configuration register offset 0x0. +* +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* 16bit desscribing Marvell controller ID +* +*******************************************************************************/ +MV_U16 mvCtrlModelGet(MV_VOID) +{ + MV_U32 devId; + + devId = MV_REG_READ(CHIP_BOND_REG); + devId &= PCKG_OPT_MASK; + + switch(devId){ + case 2: + return MV_6281_DEV_ID; + break; + case 1: + if (((MV_REG_READ(PEX_CFG_DIRECT_ACCESS(0,PEX_DEVICE_AND_VENDOR_ID))& 0xffff0000) >> 16) + == MV_6190_DEV_ID) + return MV_6190_DEV_ID; + else + return MV_6192_DEV_ID; + break; + case 0: + return MV_6180_DEV_ID; + break; + } + + return 0; +} +/******************************************************************************* +* mvCtrlRevGet - Get Marvell controller device revision number +* +* DESCRIPTION: +* This function returns 8bit describing the device revision as defined +* in PCI Express Class Code and Revision ID Register. +* +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* 8bit desscribing Marvell controller revision number +* +*******************************************************************************/ +MV_U8 mvCtrlRevGet(MV_VOID) +{ + MV_U8 revNum; +#if defined(MV_INCLUDE_CLK_PWR_CNTRL) + /* Check pex power state */ + MV_U32 pexPower; + pexPower = mvCtrlPwrClckGet(PEX_UNIT_ID,0); + if (pexPower == MV_FALSE) + mvCtrlPwrClckSet(PEX_UNIT_ID, 0, MV_TRUE); +#endif + revNum = (MV_U8)MV_REG_READ(PEX_CFG_DIRECT_ACCESS(0,PCI_CLASS_CODE_AND_REVISION_ID)); +#if defined(MV_INCLUDE_CLK_PWR_CNTRL) + /* Return to power off state */ + if (pexPower == MV_FALSE) + mvCtrlPwrClckSet(PEX_UNIT_ID, 0, MV_FALSE); +#endif + return ((revNum & PCCRIR_REVID_MASK) >> PCCRIR_REVID_OFFS); +} + +/******************************************************************************* +* mvCtrlNameGet - Get Marvell controller name +* +* DESCRIPTION: +* This function returns a string describing the device model and revision. +* +* INPUT: +* None. +* +* OUTPUT: +* pNameBuff - Buffer to contain device name string. Minimum size 30 chars. +* +* RETURN: +* +* MV_ERROR if informantion can not be read. +*******************************************************************************/ +MV_STATUS mvCtrlNameGet(char *pNameBuff) +{ + mvOsSPrintf (pNameBuff, "%s%x Rev %d", SOC_NAME_PREFIX, + mvCtrlModelGet(), mvCtrlRevGet()); + + return MV_OK; +} + +/******************************************************************************* +* mvCtrlModelRevGet - Get Controller Model (Device ID) and Revision +* +* DESCRIPTION: +* This function returns 32bit value describing both Device ID and Revision +* as defined in PCI Express Device and Vendor ID Register and device revision +* as defined in PCI Express Class Code and Revision ID Register. + +* +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* 32bit describing both controller device ID and revision number +* +*******************************************************************************/ +MV_U32 mvCtrlModelRevGet(MV_VOID) +{ + return ((mvCtrlModelGet() << 16) | mvCtrlRevGet()); +} + +/******************************************************************************* +* mvCtrlModelRevNameGet - Get Marvell controller name +* +* DESCRIPTION: +* This function returns a string describing the device model and revision. +* +* INPUT: +* None. +* +* OUTPUT: +* pNameBuff - Buffer to contain device name string. Minimum size 30 chars. +* +* RETURN: +* +* MV_ERROR if informantion can not be read. +*******************************************************************************/ + +MV_STATUS mvCtrlModelRevNameGet(char *pNameBuff) +{ + + switch (mvCtrlModelRevGet()) + { + case MV_6281_A0_ID: + mvOsSPrintf (pNameBuff, "%s",MV_6281_A0_NAME); + break; + case MV_6192_A0_ID: + mvOsSPrintf (pNameBuff, "%s",MV_6192_A0_NAME); + break; + case MV_6180_A0_ID: + mvOsSPrintf (pNameBuff, "%s",MV_6180_A0_NAME); + break; + case MV_6190_A0_ID: + mvOsSPrintf (pNameBuff, "%s",MV_6190_A0_NAME); + break; + case MV_6281_A1_ID: + mvOsSPrintf (pNameBuff, "%s",MV_6281_A1_NAME); + break; + case MV_6192_A1_ID: + mvOsSPrintf (pNameBuff, "%s",MV_6192_A1_NAME); + break; + case MV_6180_A1_ID: + mvOsSPrintf (pNameBuff, "%s",MV_6180_A1_NAME); + break; + case MV_6190_A1_ID: + mvOsSPrintf (pNameBuff, "%s",MV_6190_A1_NAME); + break; + default: + mvCtrlNameGet(pNameBuff); + break; + } + + return MV_OK; +} + + +/******************************************************************************* +* ctrlWinOverlapTest - Test address windows for overlaping. +* +* DESCRIPTION: +* This function checks the given two address windows for overlaping. +* +* INPUT: +* pAddrWin1 - Address window 1. +* pAddrWin2 - Address window 2. +* +* OUTPUT: +* None. +* +* RETURN: +* +* MV_TRUE if address window overlaps, MV_FALSE otherwise. +*******************************************************************************/ +MV_STATUS ctrlWinOverlapTest(MV_ADDR_WIN *pAddrWin1, MV_ADDR_WIN *pAddrWin2) +{ + MV_U32 winBase1, winBase2; + MV_U32 winTop1, winTop2; + + /* check if we have overflow than 4G*/ + if (((0xffffffff - pAddrWin1->baseLow) < pAddrWin1->size-1)|| + ((0xffffffff - pAddrWin2->baseLow) < pAddrWin2->size-1)) + { + return MV_TRUE; + } + + winBase1 = pAddrWin1->baseLow; + winBase2 = pAddrWin2->baseLow; + winTop1 = winBase1 + pAddrWin1->size-1; + winTop2 = winBase2 + pAddrWin2->size-1; + + + if (((winBase1 <= winTop2 ) && ( winTop2 <= winTop1)) || + ((winBase1 <= winBase2) && (winBase2 <= winTop1))) + { + return MV_TRUE; + } + else + { + return MV_FALSE; + } +} + +/******************************************************************************* +* ctrlWinWithinWinTest - Test address windows for overlaping. +* +* DESCRIPTION: +* This function checks the given win1 boundries is within +* win2 boundries. +* +* INPUT: +* pAddrWin1 - Address window 1. +* pAddrWin2 - Address window 2. +* +* OUTPUT: +* None. +* +* RETURN: +* +* MV_TRUE if found win1 inside win2, MV_FALSE otherwise. +*******************************************************************************/ +MV_STATUS ctrlWinWithinWinTest(MV_ADDR_WIN *pAddrWin1, MV_ADDR_WIN *pAddrWin2) +{ + MV_U32 winBase1, winBase2; + MV_U32 winTop1, winTop2; + + winBase1 = pAddrWin1->baseLow; + winBase2 = pAddrWin2->baseLow; + winTop1 = winBase1 + pAddrWin1->size -1; + winTop2 = winBase2 + pAddrWin2->size -1; + + if (((winBase1 >= winBase2 ) && ( winBase1 <= winTop2)) || + ((winTop1 >= winBase2) && (winTop1 <= winTop2))) + { + return MV_TRUE; + } + else + { + return MV_FALSE; + } +} + +static const char* cntrlName[] = TARGETS_NAME_ARRAY; + +/******************************************************************************* +* mvCtrlTargetNameGet - Get Marvell controller target name +* +* DESCRIPTION: +* This function convert the trget enumeration to string. +* +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* Target name (const MV_8 *) +*******************************************************************************/ +const MV_8* mvCtrlTargetNameGet( MV_TARGET target ) +{ + + if (target >= MAX_TARGETS) + { + return "target unknown"; + } + + return cntrlName[target]; +} + +/******************************************************************************* +* mvCtrlAddrDecShow - Print the Controller units address decode map. +* +* DESCRIPTION: +* This function the Controller units address decode map. +* +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* None. +* +*******************************************************************************/ +MV_VOID mvCtrlAddrDecShow(MV_VOID) +{ + mvCpuIfAddDecShow(); + mvAhbToMbusAddDecShow(); +#if defined(MV_INCLUDE_PEX) + mvPexAddrDecShow(); +#endif +#if defined(MV_INCLUDE_USB) + mvUsbAddrDecShow(); +#endif +#if defined(MV_INCLUDE_GIG_ETH) + mvEthAddrDecShow(); +#endif +#if defined(MV_INCLUDE_XOR) + mvXorAddrDecShow(); +#endif +#if defined(MV_INCLUDE_SATA) + mvSataAddrDecShow(); +#endif +#if defined(MV_INCLUDE_AUDIO) + mvAudioAddrDecShow(); +#endif +#if defined(MV_INCLUDE_TS) + mvTsuAddrDecShow(); +#endif +} + +/******************************************************************************* +* ctrlSizeToReg - Extract size value for register assignment. +* +* DESCRIPTION: +* Address decode size parameter must be programed from LSB to MSB as +* sequence of 1's followed by sequence of 0's. The number of 1's +* specifies the size of the window in 64 KB granularity (e.g. a +* value of 0x00ff specifies 256x64k = 16 MB). +* This function extract the size value from the size parameter according +* to given aligment paramter. For example for size 0x1000000 (16MB) and +* aligment 0x10000 (64KB) the function will return 0x00FF. +* +* INPUT: +* size - Size. +* alignment - Size alignment. Note that alignment must be power of 2! +* +* OUTPUT: +* None. +* +* RETURN: +* 32bit describing size register value correspond to size parameter. +* If value is '-1' size parameter or aligment are invalid. +*******************************************************************************/ +MV_U32 ctrlSizeToReg(MV_U32 size, MV_U32 alignment) +{ + MV_U32 retVal; + + /* Check size parameter alignment */ + if ((0 == size) || (MV_IS_NOT_ALIGN(size, alignment))) + { + DB(mvOsPrintf("ctrlSizeToReg: ERR. Size is zero or not aligned.\n")); + return -1; + } + + /* Take out the "alignment" portion out of the size parameter */ + alignment--; /* Now the alignmet is a sequance of '1' (e.g. 0xffff) */ + /* and size is 0x1000000 (16MB) for example */ + while(alignment & 1) /* Check that alignmet LSB is set */ + { + size = (size >> 1); /* If LSB is set, move 'size' one bit to right */ + alignment = (alignment >> 1); + } + + /* If after the alignment first '0' was met we still have '1' in */ + /* it then aligment is invalid (not power of 2) */ + if (alignment) + { + DB(mvOsPrintf("ctrlSizeToReg: ERR. Alignment parameter 0x%x invalid.\n", + (MV_U32)alignment)); + return -1; + } + + /* Now the size is shifted right according to aligment: 0x0100 */ + size--; /* Now the size is a sequance of '1': 0x00ff */ + + retVal = size ; + + /* Check that LSB to MSB is sequence of 1's followed by sequence of 0's */ + while(size & 1) /* Check that LSB is set */ + { + size = (size >> 1); /* If LSB is set, move one bit to the right */ + } + + if (size) /* Sequance of 1's is over. Check that we have no other 1's */ + { + DB(mvOsPrintf("ctrlSizeToReg: ERR. Size parameter 0x%x invalid.\n", + size)); + return -1; + } + + return retVal; + +} + +/******************************************************************************* +* ctrlRegToSize - Extract size value from register value. +* +* DESCRIPTION: +* This function extract a size value from the register size parameter +* according to given aligment paramter. For example for register size +* value 0xff and aligment 0x10000 the function will return 0x01000000. +* +* INPUT: +* regSize - Size as in register format. See ctrlSizeToReg. +* alignment - Size alignment. Note that alignment must be power of 2! +* +* OUTPUT: +* None. +* +* RETURN: +* 32bit describing size. +* If value is '-1' size parameter or aligment are invalid. +*******************************************************************************/ +MV_U32 ctrlRegToSize(MV_U32 regSize, MV_U32 alignment) +{ + MV_U32 temp; + + /* Check that LSB to MSB is sequence of 1's followed by sequence of 0's */ + temp = regSize; /* Now the size is a sequance of '1': 0x00ff */ + + while(temp & 1) /* Check that LSB is set */ + { + temp = (temp >> 1); /* If LSB is set, move one bit to the right */ + } + + if (temp) /* Sequance of 1's is over. Check that we have no other 1's */ + { + DB(mvOsPrintf("ctrlRegToSize: ERR. Size parameter 0x%x invalid.\n", + regSize)); + return -1; + } + + + /* Check that aligment is a power of two */ + temp = alignment - 1;/* Now the alignmet is a sequance of '1' (0xffff) */ + + while(temp & 1) /* Check that alignmet LSB is set */ + { + temp = (temp >> 1); /* If LSB is set, move 'size' one bit to right */ + } + + /* If after the 'temp' first '0' was met we still have '1' in 'temp' */ + /* then 'temp' is invalid (not power of 2) */ + if (temp) + { + DB(mvOsPrintf("ctrlSizeToReg: ERR. Alignment parameter 0x%x invalid.\n", + alignment)); + return -1; + } + + regSize++; /* Now the size is 0x0100 */ + + /* Add in the "alignment" portion to the register size parameter */ + alignment--; /* Now the alignmet is a sequance of '1' (e.g. 0xffff) */ + + while(alignment & 1) /* Check that alignmet LSB is set */ + { + regSize = (regSize << 1); /* LSB is set, move 'size' one bit left */ + alignment = (alignment >> 1); + } + + return regSize; +} + + +/******************************************************************************* +* ctrlSizeRegRoundUp - Round up given size +* +* DESCRIPTION: +* This function round up a given size to a size that fits the +* restrictions of size format given an aligment parameter. +* to given aligment paramter. For example for size parameter 0xa1000 and +* aligment 0x1000 the function will return 0xFF000. +* +* INPUT: +* size - Size. +* alignment - Size alignment. Note that alignment must be power of 2! +* +* OUTPUT: +* None. +* +* RETURN: +* 32bit describing size value correspond to size in register. +*******************************************************************************/ +MV_U32 ctrlSizeRegRoundUp(MV_U32 size, MV_U32 alignment) +{ + MV_U32 msbBit = 0; + MV_U32 retSize; + + /* Check if size parameter is already comply with restriction */ + if (!(-1 == ctrlSizeToReg(size, alignment))) + { + return size; + } + + while(size) + { + size = (size >> 1); + msbBit++; + } + + retSize = (1 << msbBit); + + if (retSize < alignment) + { + return alignment; + } + else + { + return retSize; + } +} +/******************************************************************************* +* mvCtrlSysRstLengthCounterGet - Return number of milliseconds the reset button +* was pressed and clear counter +* +* DESCRIPTION: +* +* INPUT: +* +* OUTPUT: +* +* RETURN: number of milliseconds the reset button was pressed +*******************************************************************************/ +MV_U32 mvCtrlSysRstLengthCounterGet(MV_VOID) +{ + static volatile MV_U32 Count = 0; + + if(!Count) { + Count = (MV_REG_READ(SYSRST_LENGTH_COUNTER_REG) & SLCR_COUNT_MASK); + Count = (Count / (MV_BOARD_REFCLK_25MHZ / 1000)); + /* clear counter for next boot */ + MV_REG_BIT_SET(SYSRST_LENGTH_COUNTER_REG, SLCR_CLR_MASK); + } + + DB(mvOsPrintf("mvCtrlSysRstLengthCounterGet: Reset button was pressed for %u milliseconds\n", Count)); + + return Count; +} + +MV_BOOL mvCtrlIsBootFromSPI(MV_VOID) +{ + MV_U32 satr = 0; + satr = MV_REG_READ(MPP_SAMPLE_AT_RESET); + if(mvCtrlModelGet() == MV_6180_DEV_ID) + { + if (MSAR_BOOT_MODE_6180(satr) == MSAR_BOOT_SPI_WITH_BOOTROM_6180) + return MV_TRUE; + else + return MV_FALSE; + } + satr = satr & MSAR_BOOT_MODE_MASK; + if (satr == MSAR_BOOT_SPI_WITH_BOOTROM) + return MV_TRUE; + else + return MV_FALSE; +} + +MV_BOOL mvCtrlIsBootFromSPIUseNAND(MV_VOID) +{ + MV_U32 satr = 0; + if(mvCtrlModelGet() == MV_6180_DEV_ID) + return MV_FALSE; + satr = MV_REG_READ(MPP_SAMPLE_AT_RESET); + satr = satr & MSAR_BOOT_MODE_MASK; + + if (satr == MSAR_BOOT_SPI_USE_NAND_WITH_BOOTROM) + return MV_TRUE; + else + return MV_FALSE; +} + +MV_BOOL mvCtrlIsBootFromNAND(MV_VOID) +{ + MV_U32 satr = 0; + satr = MV_REG_READ(MPP_SAMPLE_AT_RESET); + if(mvCtrlModelGet() == MV_6180_DEV_ID) + { + if (MSAR_BOOT_MODE_6180(satr) == MSAR_BOOT_NAND_WITH_BOOTROM_6180) + return MV_TRUE; + else + return MV_FALSE; + } + satr = satr & MSAR_BOOT_MODE_MASK; + if ((satr == MSAR_BOOT_NAND_WITH_BOOTROM)) + return MV_TRUE; + else + return MV_FALSE; +} + +#if defined(MV_INCLUDE_CLK_PWR_CNTRL) +/******************************************************************************* +* mvCtrlPwrSaveOn - Set Power save mode +* +* DESCRIPTION: +* +* INPUT: +* +* OUTPUT: +* +* RETURN: +*******************************************************************************/ +MV_VOID mvCtrlPwrSaveOn(MV_VOID) +{ + unsigned long old,temp; + /* Disable int */ + __asm__ __volatile__("mrs %0, cpsr\n" + "orr %1, %0, #0xc0\n" + "msr cpsr_c, %1" + : "=r" (old), "=r" (temp) + : + : "memory"); + + /* Set SoC in power save */ + MV_REG_BIT_SET(POWER_MNG_CTRL_REG, BIT11); + /* Wait for int */ + __asm__ __volatile__("mcr p15, 0, r0, c7, c0, 4"); + + /* Enabled int */ + __asm__ __volatile__("msr cpsr_c, %0" + : + : "r" (old) + : "memory"); +} + + + +/******************************************************************************* +* mvCtrlPwrSaveOff - Go out of power save mode +* +* DESCRIPTION: +* +* INPUT: +* +* OUTPUT: +* +* RETURN: +*******************************************************************************/ +MV_VOID mvCtrlPwrSaveOff(MV_VOID) +{ + unsigned long old,temp; + /* Disable int */ + __asm__ __volatile__("mrs %0, cpsr\n" + "orr %1, %0, #0xc0\n" + "msr cpsr_c, %1" + : "=r" (old), "=r" (temp) + : + : "memory"); + + /* Set SoC in power save */ + MV_REG_BIT_RESET(POWER_MNG_CTRL_REG, BIT11); + /* Wait for int */ + __asm__ __volatile__("mcr p15, 0, r0, c7, c0, 4"); + + /* Enabled int */ + __asm__ __volatile__("msr cpsr_c, %0" + : + : "r" (old) + : "memory"); +} + +/******************************************************************************* +* mvCtrlPwrClckSet - Set Power State for specific Unit +* +* DESCRIPTION: +* +* INPUT: +* +* OUTPUT: +* +* RETURN: +*******************************************************************************/ +MV_VOID mvCtrlPwrClckSet(MV_UNIT_ID unitId, MV_U32 index, MV_BOOL enable) +{ + switch (unitId) + { +#if defined(MV_INCLUDE_PEX) + case PEX_UNIT_ID: + if (enable == MV_FALSE) + { + MV_REG_BIT_RESET(POWER_MNG_CTRL_REG, PMC_PEXSTOPCLOCK_MASK); + } + else + { + MV_REG_BIT_SET(POWER_MNG_CTRL_REG, PMC_PEXSTOPCLOCK_MASK); + } + break; +#endif +#if defined(MV_INCLUDE_GIG_ETH) + case ETH_GIG_UNIT_ID: + if (enable == MV_FALSE) + { + MV_REG_BIT_RESET(POWER_MNG_CTRL_REG, PMC_GESTOPCLOCK_MASK(index)); + } + else + { + MV_REG_BIT_SET(POWER_MNG_CTRL_REG, PMC_GESTOPCLOCK_MASK(index)); + } + break; +#endif +#if defined(MV_INCLUDE_INTEG_SATA) + case SATA_UNIT_ID: + if (enable == MV_FALSE) + { + MV_REG_BIT_RESET(POWER_MNG_CTRL_REG, PMC_SATASTOPCLOCK_MASK(index)); + } + else + { + MV_REG_BIT_SET(POWER_MNG_CTRL_REG, PMC_SATASTOPCLOCK_MASK(index)); + } + break; +#endif +#if defined(MV_INCLUDE_CESA) + case CESA_UNIT_ID: + if (enable == MV_FALSE) + { + MV_REG_BIT_RESET(POWER_MNG_CTRL_REG, PMC_SESTOPCLOCK_MASK); + } + else + { + MV_REG_BIT_SET(POWER_MNG_CTRL_REG, PMC_SESTOPCLOCK_MASK); + } + break; +#endif +#if defined(MV_INCLUDE_USB) + case USB_UNIT_ID: + if (enable == MV_FALSE) + { + MV_REG_BIT_RESET(POWER_MNG_CTRL_REG, PMC_USBSTOPCLOCK_MASK); + } + else + { + MV_REG_BIT_SET(POWER_MNG_CTRL_REG, PMC_USBSTOPCLOCK_MASK); + } + break; +#endif +#if defined(MV_INCLUDE_AUDIO) + case AUDIO_UNIT_ID: + if (enable == MV_FALSE) + { + MV_REG_BIT_RESET(POWER_MNG_CTRL_REG, PMC_AUDIOSTOPCLOCK_MASK); + } + else + { + MV_REG_BIT_SET(POWER_MNG_CTRL_REG, PMC_AUDIOSTOPCLOCK_MASK); + } + break; +#endif +#if defined(MV_INCLUDE_TS) + case TS_UNIT_ID: + if (enable == MV_FALSE) + { + MV_REG_BIT_RESET(POWER_MNG_CTRL_REG, PMC_TSSTOPCLOCK_MASK); + } + else + { + MV_REG_BIT_SET(POWER_MNG_CTRL_REG, PMC_TSSTOPCLOCK_MASK); + } + break; +#endif +#if defined(MV_INCLUDE_SDIO) + case SDIO_UNIT_ID: + if (enable == MV_FALSE) + { + MV_REG_BIT_RESET(POWER_MNG_CTRL_REG, PMC_SDIOSTOPCLOCK_MASK); + } + else + { + MV_REG_BIT_SET(POWER_MNG_CTRL_REG, PMC_SDIOSTOPCLOCK_MASK); + } + break; +#endif +#if defined(MV_INCLUDE_TDM) + case TDM_UNIT_ID: + if (enable == MV_FALSE) + { + MV_REG_BIT_RESET(POWER_MNG_CTRL_REG, PMC_TDMSTOPCLOCK_MASK); + } + else + { + MV_REG_BIT_SET(POWER_MNG_CTRL_REG, PMC_TDMSTOPCLOCK_MASK); + } + break; +#endif + + default: + + break; + + } +} + +/******************************************************************************* +* mvCtrlPwrClckGet - Get Power State of specific Unit +* +* DESCRIPTION: +* +* INPUT: +* +* OUTPUT: +* +* RETURN: +******************************************************************************/ +MV_BOOL mvCtrlPwrClckGet(MV_UNIT_ID unitId, MV_U32 index) +{ + MV_U32 reg = MV_REG_READ(POWER_MNG_CTRL_REG); + MV_BOOL state = MV_TRUE; + + switch (unitId) + { +#if defined(MV_INCLUDE_PEX) + case PEX_UNIT_ID: + if ((reg & PMC_PEXSTOPCLOCK_MASK) == PMC_PEXSTOPCLOCK_STOP) + { + state = MV_FALSE; + } + else state = MV_TRUE; + + break; +#endif +#if defined(MV_INCLUDE_GIG_ETH) + case ETH_GIG_UNIT_ID: + if ((reg & PMC_GESTOPCLOCK_MASK(index)) == PMC_GESTOPCLOCK_STOP(index)) + { + state = MV_FALSE; + } + else state = MV_TRUE; + break; +#endif +#if defined(MV_INCLUDE_SATA) + case SATA_UNIT_ID: + if ((reg & PMC_SATASTOPCLOCK_MASK(index)) == PMC_SATASTOPCLOCK_STOP(index)) + { + state = MV_FALSE; + } + else state = MV_TRUE; + break; +#endif +#if defined(MV_INCLUDE_CESA) + case CESA_UNIT_ID: + if ((reg & PMC_SESTOPCLOCK_MASK) == PMC_SESTOPCLOCK_STOP) + { + state = MV_FALSE; + } + else state = MV_TRUE; + break; +#endif +#if defined(MV_INCLUDE_USB) + case USB_UNIT_ID: + if ((reg & PMC_USBSTOPCLOCK_MASK) == PMC_USBSTOPCLOCK_STOP) + { + state = MV_FALSE; + } + else state = MV_TRUE; + break; +#endif +#if defined(MV_INCLUDE_AUDIO) + case AUDIO_UNIT_ID: + if ((reg & PMC_AUDIOSTOPCLOCK_MASK) == PMC_AUDIOSTOPCLOCK_STOP) + { + state = MV_FALSE; + } + else state = MV_TRUE; + break; +#endif +#if defined(MV_INCLUDE_TS) + case TS_UNIT_ID: + if ((reg & PMC_TSSTOPCLOCK_MASK) == PMC_TSSTOPCLOCK_STOP) + { + state = MV_FALSE; + } + else state = MV_TRUE; + break; +#endif +#if defined(MV_INCLUDE_SDIO) + case SDIO_UNIT_ID: + if ((reg & PMC_SDIOSTOPCLOCK_MASK)== PMC_SDIOSTOPCLOCK_STOP) + { + state = MV_FALSE; + } + else state = MV_TRUE; + break; +#endif +#if defined(MV_INCLUDE_TDM) + case TDM_UNIT_ID: + if ((reg & PMC_TDMSTOPCLOCK_MASK) == PMC_TDMSTOPCLOCK_STOP) + { + state = MV_FALSE; + } + else state = MV_TRUE; + break; +#endif + + default: + state = MV_TRUE; + break; + } + + + return state; +} +/******************************************************************************* +* mvCtrlPwrMemSet - Set Power State for memory on specific Unit +* +* DESCRIPTION: +* +* INPUT: +* +* OUTPUT: +* +* RETURN: +*******************************************************************************/ +MV_VOID mvCtrlPwrMemSet(MV_UNIT_ID unitId, MV_U32 index, MV_BOOL enable) +{ + switch (unitId) + { +#if defined(MV_INCLUDE_PEX) + case PEX_UNIT_ID: + if (enable == MV_FALSE) + { + MV_REG_BIT_SET(POWER_MNG_MEM_CTRL_REG, PMC_PEXSTOPMEM_MASK); + } + else + { + MV_REG_BIT_RESET(POWER_MNG_MEM_CTRL_REG, PMC_PEXSTOPMEM_MASK); + } + break; +#endif +#if defined(MV_INCLUDE_GIG_ETH) + case ETH_GIG_UNIT_ID: + if (enable == MV_FALSE) + { + MV_REG_BIT_SET(POWER_MNG_MEM_CTRL_REG, PMC_GESTOPMEM_MASK(index)); + } + else + { + MV_REG_BIT_RESET(POWER_MNG_MEM_CTRL_REG, PMC_GESTOPMEM_MASK(index)); + } + break; +#endif +#if defined(MV_INCLUDE_INTEG_SATA) + case SATA_UNIT_ID: + if (enable == MV_FALSE) + { + MV_REG_BIT_SET(POWER_MNG_MEM_CTRL_REG, PMC_SATASTOPMEM_MASK(index)); + } + else + { + MV_REG_BIT_RESET(POWER_MNG_MEM_CTRL_REG, PMC_SATASTOPMEM_MASK(index)); + } + break; +#endif +#if defined(MV_INCLUDE_CESA) + case CESA_UNIT_ID: + if (enable == MV_FALSE) + { + MV_REG_BIT_SET(POWER_MNG_MEM_CTRL_REG, PMC_SESTOPMEM_MASK); + } + else + { + MV_REG_BIT_RESET(POWER_MNG_MEM_CTRL_REG, PMC_SESTOPMEM_MASK); + } + break; +#endif +#if defined(MV_INCLUDE_USB) + case USB_UNIT_ID: + if (enable == MV_FALSE) + { + MV_REG_BIT_SET(POWER_MNG_MEM_CTRL_REG, PMC_USBSTOPMEM_MASK); + } + else + { + MV_REG_BIT_RESET(POWER_MNG_MEM_CTRL_REG, PMC_USBSTOPMEM_MASK); + } + break; +#endif +#if defined(MV_INCLUDE_AUDIO) + case AUDIO_UNIT_ID: + if (enable == MV_FALSE) + { + MV_REG_BIT_SET(POWER_MNG_MEM_CTRL_REG, PMC_AUDIOSTOPMEM_MASK); + } + else + { + MV_REG_BIT_RESET(POWER_MNG_MEM_CTRL_REG, PMC_AUDIOSTOPMEM_MASK); + } + break; +#endif +#if defined(MV_INCLUDE_XOR) + case XOR_UNIT_ID: + if (enable == MV_FALSE) + { + MV_REG_BIT_SET(POWER_MNG_MEM_CTRL_REG, PMC_XORSTOPMEM_MASK(index)); + } + else + { + MV_REG_BIT_RESET(POWER_MNG_MEM_CTRL_REG, PMC_XORSTOPMEM_MASK(index)); + } + break; +#endif + default: + + break; + + } +} + +/******************************************************************************* +* mvCtrlPwrMemGet - Get Power State of memory on specific Unit +* +* DESCRIPTION: +* +* INPUT: +* +* OUTPUT: +* +* RETURN: +******************************************************************************/ +MV_BOOL mvCtrlPwrMemGet(MV_UNIT_ID unitId, MV_U32 index) +{ + MV_U32 reg = MV_REG_READ(POWER_MNG_MEM_CTRL_REG); + MV_BOOL state = MV_TRUE; + + switch (unitId) + { +#if defined(MV_INCLUDE_PEX) + case PEX_UNIT_ID: + if ((reg & PMC_PEXSTOPMEM_MASK) == PMC_PEXSTOPMEM_STOP) + { + state = MV_FALSE; + } + else state = MV_TRUE; + + break; +#endif +#if defined(MV_INCLUDE_GIG_ETH) + case ETH_GIG_UNIT_ID: + if ((reg & PMC_GESTOPMEM_MASK(index)) == PMC_GESTOPMEM_STOP(index)) + { + state = MV_FALSE; + } + else state = MV_TRUE; + break; +#endif +#if defined(MV_INCLUDE_SATA) + case SATA_UNIT_ID: + if ((reg & PMC_SATASTOPMEM_MASK(index)) == PMC_SATASTOPMEM_STOP(index)) + { + state = MV_FALSE; + } + else state = MV_TRUE; + break; +#endif +#if defined(MV_INCLUDE_CESA) + case CESA_UNIT_ID: + if ((reg & PMC_SESTOPMEM_MASK) == PMC_SESTOPMEM_STOP) + { + state = MV_FALSE; + } + else state = MV_TRUE; + break; +#endif +#if defined(MV_INCLUDE_USB) + case USB_UNIT_ID: + if ((reg & PMC_USBSTOPMEM_MASK) == PMC_USBSTOPMEM_STOP) + { + state = MV_FALSE; + } + else state = MV_TRUE; + break; +#endif +#if defined(MV_INCLUDE_AUDIO) + case AUDIO_UNIT_ID: + if ((reg & PMC_AUDIOSTOPMEM_MASK) == PMC_AUDIOSTOPMEM_STOP) + { + state = MV_FALSE; + } + else state = MV_TRUE; + break; +#endif +#if defined(MV_INCLUDE_XOR) + case XOR_UNIT_ID: + if ((reg & PMC_XORSTOPMEM_MASK(index)) == PMC_XORSTOPMEM_STOP(index)) + { + state = MV_FALSE; + } + else state = MV_TRUE; + break; +#endif + + default: + state = MV_TRUE; + break; + } + + + return state; +} +#else +MV_VOID mvCtrlPwrClckSet(MV_UNIT_ID unitId, MV_U32 index, MV_BOOL enable) {return;} +MV_BOOL mvCtrlPwrClckGet(MV_UNIT_ID unitId, MV_U32 index) {return MV_TRUE;} +#endif /* #if defined(MV_INCLUDE_CLK_PWR_CNTRL) */ + + +/******************************************************************************* +* mvMPPConfigToSPI - Change MPP[3:0] configuration to SPI mode +* +* DESCRIPTION: +* +* INPUT: +* +* OUTPUT: +* +* RETURN: +******************************************************************************/ +MV_VOID mvMPPConfigToSPI(MV_VOID) +{ + MV_U32 mppVal = 0; + MV_U32 bootVal = 0; + + if(!mvCtrlIsBootFromSPIUseNAND()) + return; + mppVal = 0x00002220; /* Set MPP [3:1] to SPI mode */ + bootVal = MV_REG_READ(mvCtrlMppRegGet(0)); + bootVal &= 0xffff000f; + mppVal |= bootVal; + + MV_REG_WRITE(mvCtrlMppRegGet(0), mppVal); +} + + +/******************************************************************************* +* mvMPPConfigToDefault - Change MPP[7:0] configuration to default configuration +* +* DESCRIPTION: +* +* INPUT: +* +* OUTPUT: +* +* RETURN: +******************************************************************************/ +MV_VOID mvMPPConfigToDefault(MV_VOID) +{ + MV_U32 mppVal = 0; + MV_U32 bootVal = 0; + + if(!mvCtrlIsBootFromSPIUseNAND()) + return; + mppVal = mvBoardMppGet(0); + bootVal = MV_REG_READ(mvCtrlMppRegGet(0)); + mppVal &= ~0xffff000f; + bootVal &= 0xffff000f; + mppVal |= bootVal; + + MV_REG_WRITE(mvCtrlMppRegGet(0), mppVal); +} + + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/mvCtrlEnvLib.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/mvCtrlEnvLib.h new file mode 100644 index 0000000..6e2e813 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/mvCtrlEnvLib.h @@ -0,0 +1,185 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + + +#ifndef __INCmvCtrlEnvLibh +#define __INCmvCtrlEnvLibh + +/* includes */ +#include "mvSysHwConfig.h" +#include "mvCommon.h" +#include "mvTypes.h" +#include "mvOs.h" +#include "boardEnv/mvBoardEnvLib.h" +#include "ctrlEnv/mvCtrlEnvSpec.h" +#include "ctrlEnv/mvCtrlEnvRegs.h" +#include "ctrlEnv/mvCtrlEnvAddrDec.h" + + +/* typedefs */ + +/* This enumerator describes the possible HW cache coherency policies the */ +/* controllers supports. */ +typedef enum _mvCachePolicy +{ + NO_COHERENCY, /* No HW cache coherency support */ + WT_COHERENCY, /* HW cache coherency supported in Write Through policy */ + WB_COHERENCY /* HW cache coherency supported in Write Back policy */ +}MV_CACHE_POLICY; + + +/* The swapping is referred to a 64-bit words (as this is the controller */ +/* internal data path width). This enumerator describes the possible */ +/* data swap types. Below is an example of the data 0x0011223344556677 */ +typedef enum _mvSwapType +{ + MV_BYTE_SWAP, /* Byte Swap 77 66 55 44 33 22 11 00 */ + MV_NO_SWAP, /* No swapping 00 11 22 33 44 55 66 77 */ + MV_BYTE_WORD_SWAP, /* Both byte and word swap 33 22 11 00 77 66 55 44 */ + MV_WORD_SWAP, /* Word swap 44 55 66 77 00 11 22 33 */ + SWAP_TYPE_MAX /* Delimiter for this enumerator */ +}MV_SWAP_TYPE; + +/* This structure describes access rights for Access protection windows */ +/* that can be found in IDMA, XOR, Ethernet and MPSC units. */ +/* Note that the permission enumerator coresponds to its register format. */ +/* For example, Read only premission is presented as "1" in register field. */ +typedef enum _mvAccessRights +{ + NO_ACCESS_ALLOWED = 0, /* No access allowed */ + READ_ONLY = 1, /* Read only permission */ + ACC_RESERVED = 2, /* Reserved access right */ + FULL_ACCESS = 3, /* Read and Write permission */ + MAX_ACC_RIGHTS +}MV_ACCESS_RIGHTS; + + +/* mcspLib.h API list */ + +MV_STATUS mvCtrlEnvInit(MV_VOID); +MV_U32 mvCtrlMppRegGet(MV_U32 mppGroup); + +#if defined(MV_INCLUDE_PEX) +MV_U32 mvCtrlPexMaxIfGet(MV_VOID); +#else +#define mvCtrlPexMaxIfGet() (0) +#endif + +#define mvCtrlPciIfMaxIfGet() (0) + +#if defined(MV_INCLUDE_GIG_ETH) +MV_U32 mvCtrlEthMaxPortGet(MV_VOID); +#endif +#if defined(MV_INCLUDE_XOR) +MV_U32 mvCtrlXorMaxChanGet(MV_VOID); +#endif +#if defined(MV_INCLUDE_USB) +MV_U32 mvCtrlUsbMaxGet(MV_VOID); +#endif +#if defined(MV_INCLUDE_NAND) +MV_U32 mvCtrlNandSupport(MV_VOID); +#endif +#if defined(MV_INCLUDE_SDIO) +MV_U32 mvCtrlSdioSupport(MV_VOID); +#endif +#if defined(MV_INCLUDE_TS) +MV_U32 mvCtrlTsSupport(MV_VOID); +#endif +#if defined(MV_INCLUDE_AUDIO) +MV_U32 mvCtrlAudioSupport(MV_VOID); +#endif +#if defined(MV_INCLUDE_TDM) +MV_U32 mvCtrlTdmSupport(MV_VOID); +#endif + +MV_U16 mvCtrlModelGet(MV_VOID); +MV_U8 mvCtrlRevGet(MV_VOID); +MV_STATUS mvCtrlNameGet(char *pNameBuff); +MV_U32 mvCtrlModelRevGet(MV_VOID); +MV_STATUS mvCtrlModelRevNameGet(char *pNameBuff); +MV_VOID mvCtrlAddrDecShow(MV_VOID); +const MV_8* mvCtrlTargetNameGet(MV_TARGET target); +MV_U32 ctrlSizeToReg(MV_U32 size, MV_U32 alignment); +MV_U32 ctrlRegToSize(MV_U32 regSize, MV_U32 alignment); +MV_U32 ctrlSizeRegRoundUp(MV_U32 size, MV_U32 alignment); +MV_U32 mvCtrlSysRstLengthCounterGet(MV_VOID); +MV_STATUS ctrlWinOverlapTest(MV_ADDR_WIN *pAddrWin1, MV_ADDR_WIN *pAddrWin2); +MV_STATUS ctrlWinWithinWinTest(MV_ADDR_WIN *pAddrWin1, MV_ADDR_WIN *pAddrWin2); + +MV_VOID mvCtrlPwrClckSet(MV_UNIT_ID unitId, MV_U32 index, MV_BOOL enable); +MV_BOOL mvCtrlPwrClckGet(MV_UNIT_ID unitId, MV_U32 index); +MV_VOID mvCtrlPwrMemSet(MV_UNIT_ID unitId, MV_U32 index, MV_BOOL enable); +MV_BOOL mvCtrlIsBootFromSPI(MV_VOID); +MV_BOOL mvCtrlIsBootFromSPIUseNAND(MV_VOID); +MV_BOOL mvCtrlIsBootFromNAND(MV_VOID); +#if defined(MV_INCLUDE_CLK_PWR_CNTRL) +MV_VOID mvCtrlPwrSaveOn(MV_VOID); +MV_VOID mvCtrlPwrSaveOff(MV_VOID); +#endif +MV_BOOL mvCtrlPwrMemGet(MV_UNIT_ID unitId, MV_U32 index); +MV_VOID mvMPPConfigToSPI(MV_VOID); +MV_VOID mvMPPConfigToDefault(MV_VOID); + + +#endif /* __INCmvCtrlEnvLibh */ diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/mvCtrlEnvRegs.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/mvCtrlEnvRegs.h new file mode 100644 index 0000000..ae3f141 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/mvCtrlEnvRegs.h @@ -0,0 +1,419 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#ifndef __INCmvCtrlEnvRegsh +#define __INCmvCtrlEnvRegsh + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* CV Support */ +#define PEX0_MEM0 PEX0_MEM +#define PCI0_MEM0 PEX0_MEM + +/* Controller revision info */ +#define PCI_CLASS_CODE_AND_REVISION_ID 0x008 +#define PCCRIR_REVID_OFFS 0 /* Revision ID */ +#define PCCRIR_REVID_MASK (0xff << PCCRIR_REVID_OFFS) + +/* Controler environment registers offsets */ + +/* Power Managment Control */ +#define POWER_MNG_MEM_CTRL_REG 0x20118 + +#define PMC_GESTOPMEM_OFFS(port) ((port)? 13 : 0) +#define PMC_GESTOPMEM_MASK(port) (1 << PMC_GESTOPMEM_OFFS(port)) +#define PMC_GESTOPMEM_EN(port) (0 << PMC_GESTOPMEM_OFFS(port)) +#define PMC_GESTOPMEM_STOP(port) (1 << PMC_GESTOPMEM_OFFS(port)) + +#define PMC_PEXSTOPMEM_OFFS 1 +#define PMC_PEXSTOPMEM_MASK (1 << PMC_PEXSTOPMEM_OFFS) +#define PMC_PEXSTOPMEM_EN (0 << PMC_PEXSTOPMEM_OFFS) +#define PMC_PEXSTOPMEM_STOP (1 << PMC_PEXSTOPMEM_OFFS) + +#define PMC_USBSTOPMEM_OFFS 2 +#define PMC_USBSTOPMEM_MASK (1 << PMC_USBSTOPMEM_OFFS) +#define PMC_USBSTOPMEM_EN (0 << PMC_USBSTOPMEM_OFFS) +#define PMC_USBSTOPMEM_STOP (1 << PMC_USBSTOPMEM_OFFS) + +#define PMC_DUNITSTOPMEM_OFFS 3 +#define PMC_DUNITSTOPMEM_MASK (1 << PMC_DUNITSTOPMEM_OFFS) +#define PMC_DUNITSTOPMEM_EN (0 << PMC_DUNITSTOPMEM_OFFS) +#define PMC_DUNITSTOPMEM_STOP (1 << PMC_DUNITSTOPMEM_OFFS) + +#define PMC_RUNITSTOPMEM_OFFS 4 +#define PMC_RUNITSTOPMEM_MASK (1 << PMC_RUNITSTOPMEM_OFFS) +#define PMC_RUNITSTOPMEM_EN (0 << PMC_RUNITSTOPMEM_OFFS) +#define PMC_RUNITSTOPMEM_STOP (1 << PMC_RUNITSTOPMEM_OFFS) + +#define PMC_XORSTOPMEM_OFFS(port) (5+(port*2)) +#define PMC_XORSTOPMEM_MASK(port) (1 << PMC_XORSTOPMEM_OFFS(port)) +#define PMC_XORSTOPMEM_EN(port) (0 << PMC_XORSTOPMEM_OFFS(port)) +#define PMC_XORSTOPMEM_STOP(port) (1 << PMC_XORSTOPMEM_OFFS(port)) + +#define PMC_SATASTOPMEM_OFFS(port) (6+(port*5)) +#define PMC_SATASTOPMEM_MASK(port) (1 << PMC_SATASTOPMEM_OFFS(port)) +#define PMC_SATASTOPMEM_EN(port) (0 << PMC_SATASTOPMEM_OFFS(port)) +#define PMC_SATASTOPMEM_STOP(port) (1 << PMC_SATASTOPMEM_OFFS(port)) + +#define PMC_SESTOPMEM_OFFS 8 +#define PMC_SESTOPMEM_MASK (1 << PMC_SESTOPMEM_OFFS) +#define PMC_SESTOPMEM_EN (0 << PMC_SESTOPMEM_OFFS) +#define PMC_SESTOPMEM_STOP (1 << PMC_SESTOPMEM_OFFS) + +#define PMC_AUDIOSTOPMEM_OFFS 9 +#define PMC_AUDIOSTOPMEM_MASK (1 << PMC_AUDIOSTOPMEM_OFFS) +#define PMC_AUDIOSTOPMEM_EN (0 << PMC_AUDIOSTOPMEM_OFFS) +#define PMC_AUDIOSTOPMEM_STOP (1 << PMC_AUDIOSTOPMEM_OFFS) + +#define POWER_MNG_CTRL_REG 0x2011C + +#define PMC_GESTOPCLOCK_OFFS(port) ((port)? 19 : 0) +#define PMC_GESTOPCLOCK_MASK(port) (1 << PMC_GESTOPCLOCK_OFFS(port)) +#define PMC_GESTOPCLOCK_EN(port) (1 << PMC_GESTOPCLOCK_OFFS(port)) +#define PMC_GESTOPCLOCK_STOP(port) (0 << PMC_GESTOPCLOCK_OFFS(port)) + +#define PMC_PEXPHYSTOPCLOCK_OFFS 1 +#define PMC_PEXPHYSTOPCLOCK_MASK (1 << PMC_PEXPHYSTOPCLOCK_OFFS) +#define PMC_PEXPHYSTOPCLOCK_EN (1 << PMC_PEXPHYSTOPCLOCK_OFFS) +#define PMC_PEXPHYSTOPCLOCK_STOP (0 << PMC_PEXPHYSTOPCLOCK_OFFS) + +#define PMC_PEXSTOPCLOCK_OFFS 2 +#define PMC_PEXSTOPCLOCK_MASK (1 << PMC_PEXSTOPCLOCK_OFFS) +#define PMC_PEXSTOPCLOCK_EN (1 << PMC_PEXSTOPCLOCK_OFFS) +#define PMC_PEXSTOPCLOCK_STOP (0 << PMC_PEXSTOPCLOCK_OFFS) + +#define PMC_USBSTOPCLOCK_OFFS 3 +#define PMC_USBSTOPCLOCK_MASK (1 << PMC_USBSTOPCLOCK_OFFS) +#define PMC_USBSTOPCLOCK_EN (1 << PMC_USBSTOPCLOCK_OFFS) +#define PMC_USBSTOPCLOCK_STOP (0 << PMC_USBSTOPCLOCK_OFFS) + +#define PMC_SDIOSTOPCLOCK_OFFS 4 +#define PMC_SDIOSTOPCLOCK_MASK (1 << PMC_SDIOSTOPCLOCK_OFFS) +#define PMC_SDIOSTOPCLOCK_EN (1 << PMC_SDIOSTOPCLOCK_OFFS) +#define PMC_SDIOSTOPCLOCK_STOP (0 << PMC_SDIOSTOPCLOCK_OFFS) + +#define PMC_TSSTOPCLOCK_OFFS 5 +#define PMC_TSSTOPCLOCK_MASK (1 << PMC_TSSTOPCLOCK_OFFS) +#define PMC_TSSTOPCLOCK_EN (1 << PMC_TSSTOPCLOCK_OFFS) +#define PMC_TSSTOPCLOCK_STOP (0 << PMC_TSSTOPCLOCK_OFFS) + +#define PMC_AUDIOSTOPCLOCK_OFFS 9 +#define PMC_AUDIOSTOPCLOCK_MASK (1 << PMC_AUDIOSTOPCLOCK_OFFS) +#define PMC_AUDIOSTOPCLOCK_EN (1 << PMC_AUDIOSTOPCLOCK_OFFS) +#define PMC_AUDIOSTOPCLOCK_STOP (0 << PMC_AUDIOSTOPCLOCK_OFFS) + +#define PMC_POWERSAVE_OFFS 11 +#define PMC_POWERSAVE_MASK (1 << PMC_POWERSAVE_OFFS) +#define PMC_POWERSAVE_EN (1 << PMC_POWERSAVE_OFFS) +#define PMC_POWERSAVE_STOP (0 << PMC_POWERSAVE_OFFS) + + + + +#define PMC_SATASTOPCLOCK_OFFS(port) (14+(port)) +#define PMC_SATASTOPCLOCK_MASK(port) (1 << PMC_SATASTOPCLOCK_OFFS(port)) +#define PMC_SATASTOPCLOCK_EN(port) (1 << PMC_SATASTOPCLOCK_OFFS(port)) +#define PMC_SATASTOPCLOCK_STOP(port) (0 << PMC_SATASTOPCLOCK_OFFS(port)) + +#define PMC_SESTOPCLOCK_OFFS 17 +#define PMC_SESTOPCLOCK_MASK (1 << PMC_SESTOPCLOCK_OFFS) +#define PMC_SESTOPCLOCK_EN (1 << PMC_SESTOPCLOCK_OFFS) +#define PMC_SESTOPCLOCK_STOP (0 << PMC_SESTOPCLOCK_OFFS) + +#define PMC_TDMSTOPCLOCK_OFFS 20 +#define PMC_TDMSTOPCLOCK_MASK (1 << PMC_TDMSTOPCLOCK_OFFS) +#define PMC_TDMSTOPCLOCK_EN (1 << PMC_TDMSTOPCLOCK_OFFS) +#define PMC_TDMSTOPCLOCK_STOP (0 << PMC_TDMSTOPCLOCK_OFFS) + + +/* Controler environment registers offsets */ +#define MPP_CONTROL_REG0 0x10000 +#define MPP_CONTROL_REG1 0x10004 +#define MPP_CONTROL_REG2 0x10008 +#define MPP_CONTROL_REG3 0x1000C +#define MPP_CONTROL_REG4 0x10010 +#define MPP_CONTROL_REG5 0x10014 +#define MPP_CONTROL_REG6 0x10018 +#define MPP_SAMPLE_AT_RESET 0x10030 +#define CHIP_BOND_REG 0x10034 +#define SYSRST_LENGTH_COUNTER_REG 0x10050 +#define SLCR_COUNT_OFFS 0 +#define SLCR_COUNT_MASK (0x1FFFFFFF << SLCR_COUNT_OFFS) +#define SLCR_CLR_OFFS 31 +#define SLCR_CLR_MASK (1 << SLCR_CLR_OFFS) +#define PCKG_OPT_MASK 0x3 +#define MPP_OUTPUT_DRIVE_REG 0x100E0 +#define MPP_RGMII0_OUTPUT_DRIVE_OFFS 7 +#define MPP_3_3_RGMII0_OUTPUT_DRIVE (0x0 << MPP_RGMII0_OUTPUT_DRIVE_OFFS) +#define MPP_1_8_RGMII0_OUTPUT_DRIVE (0x1 << MPP_RGMII0_OUTPUT_DRIVE_OFFS) +#define MPP_RGMII1_OUTPUT_DRIVE_OFFS 15 +#define MPP_3_3_RGMII1_OUTPUT_DRIVE (0x0 << MPP_RGMII1_OUTPUT_DRIVE_OFFS) +#define MPP_1_8_RGMII1_OUTPUT_DRIVE (0x1 << MPP_RGMII1_OUTPUT_DRIVE_OFFS) + +#define MSAR_BOOT_MODE_OFFS 12 +#define MSAR_BOOT_MODE_MASK (0x7 << MSAR_BOOT_MODE_OFFS) +#define MSAR_BOOT_NAND_WITH_BOOTROM (0x5 << MSAR_BOOT_MODE_OFFS) +#define MSAR_BOOT_SPI_WITH_BOOTROM (0x4 << MSAR_BOOT_MODE_OFFS) +#define MSAR_BOOT_SPI_USE_NAND_WITH_BOOTROM (0x2 << MSAR_BOOT_MODE_OFFS) + +#define MSAR_BOOT_MODE_6180(X) (((X & 0x3000) >> 12) | \ + ((X & 0x2) << 1)) +#define MSAR_BOOT_SPI_WITH_BOOTROM_6180 0x1 +#define MSAR_BOOT_NAND_WITH_BOOTROM_6180 0x5 + +#define MSAR_TCLCK_OFFS 21 +#define MSAR_TCLCK_MASK (0x1 << MSAR_TCLCK_OFFS) +#define MSAR_TCLCK_166 (0x1 << MSAR_TCLCK_OFFS) +#define MSAR_TCLCK_200 (0x0 << MSAR_TCLCK_OFFS) + + +#define MSAR_CPUCLCK_EXTRACT(X) (((X & 0x2) >> 1) | ((X & 0x400000) >> 21) | \ + ((X & 0x18) >> 1)) + +#define MSAR_CPUCLCK_OFFS_6180 2 +#define MSAR_CPUCLCK_MASK_6180 (0x7 << MSAR_CPUCLCK_OFFS_6180) + +#define MSAR_DDRCLCK_RTIO_OFFS 5 +#define MSAR_DDRCLCK_RTIO_MASK (0xF << MSAR_DDRCLCK_RTIO_OFFS) + +#define MSAR_L2CLCK_EXTRACT(X) (((X & 0x600) >> 9) | ((X & 0x80000) >> 17)) + +#ifndef MV_ASMLANGUAGE +/* CPU clock for 6281,6192 0->Resereved */ +#define MV_CPU_CLCK_TBL { 0, 0, 0, 0, \ + 600000000, 0, 800000000, 1000000000, \ + 0, 1200000000, 0, 0, \ + 1500000000, 0, 0, 0} + +/* DDR clock RATIO for 6281,6192 {0,0}->Reserved */ +#define MV_DDR_CLCK_RTIO_TBL {\ + {0, 0}, {0, 0}, {2, 1}, {0, 0}, \ + {3, 1}, {0, 0}, {4, 1}, {9, 2}, \ + {5, 1}, {6, 1}, {0, 0}, {0, 0}, \ + {0, 0}, {0, 0}, {0, 0}, {0, 0} \ +} + +/* L2 clock RATIO for 6281,6192 {1,1}->Reserved */ +#define MV_L2_CLCK_RTIO_TBL {\ + {0, 0}, {2, 1}, {0, 0}, {3, 1}, \ + {0, 0}, {0, 0}, {0, 0}, {0, 0} \ +} + +/* 6180 have different clk reset sampling */ +/* ARM CPU, DDR, L2 clock for 6180 {0,0,0}->Reserved */ +#define MV_CPU6180_DDR_L2_CLCK_TBL { \ + {0, 0, 0 },\ + {0, 0, 0 },\ + {0, 0, 0 },\ + {0, 0, 0 },\ + {0, 0, 0 },\ + {600000000, 200000000, 300000000 },\ + {800000000, 200000000, 400000000 },\ + {0, 0, 0 }\ +} + + + +/* These macros help units to identify a target Mbus Arbiter group */ +#define MV_TARGET_IS_DRAM(target) \ + ((target >= SDRAM_CS0) && (target <= SDRAM_CS3)) + +#define MV_TARGET_IS_PEX0(target) \ + ((target >= PEX0_MEM) && (target <= PEX0_IO)) + +#define MV_TARGET_IS_PEX1(target) 0 + +#define MV_TARGET_IS_PEX(target) (MV_TARGET_IS_PEX0(target) || MV_TARGET_IS_PEX1(target)) + +#define MV_TARGET_IS_DEVICE(target) \ + ((target >= DEVICE_CS0) && (target <= DEVICE_CS3)) + +#define MV_PCI_DRAM_BAR_TO_DRAM_TARGET(bar) 0 + +#define MV_TARGET_IS_AS_BOOT(target) ((target) == (sampleAtResetTargetArray[ \ + (mvCtrlModelGet() == MV_6180_DEV_ID)? MSAR_BOOT_MODE_6180 \ + (MV_REG_READ(MPP_SAMPLE_AT_RESET)):((MV_REG_READ(MPP_SAMPLE_AT_RESET)\ + & MSAR_BOOT_MODE_MASK) >> MSAR_BOOT_MODE_OFFS)])) + + +#define MV_CHANGE_BOOT_CS(target) (((target) == DEV_BOOCS)?\ + sampleAtResetTargetArray[(mvCtrlModelGet() == MV_6180_DEV_ID)? \ + MSAR_BOOT_MODE_6180(MV_REG_READ(MPP_SAMPLE_AT_RESET)): \ + ((MV_REG_READ(MPP_SAMPLE_AT_RESET) & MSAR_BOOT_MODE_MASK)\ + >> MSAR_BOOT_MODE_OFFS)]:(target)) + +#define TCLK_TO_COUNTER_RATIO 1 /* counters running in Tclk */ + +#define BOOT_TARGETS_NAME_ARRAY { \ + TBL_TERM, \ + TBL_TERM, \ + BOOT_ROM_CS, \ + TBL_TERM, \ + BOOT_ROM_CS, \ + BOOT_ROM_CS, \ + TBL_TERM, \ + TBL_TERM \ +} + +#define BOOT_TARGETS_NAME_ARRAY_6180 { \ + TBL_TERM, \ + BOOT_ROM_CS, \ + TBL_TERM, \ + TBL_TERM, \ + TBL_TERM, \ + BOOT_ROM_CS, \ + TBL_TERM, \ + TBL_TERM \ +} + + +/* For old competability */ +#define DEVICE_CS0 NFLASH_CS +#define DEVICE_CS1 SPI_CS +#define DEVICE_CS2 BOOT_ROM_CS +#define DEVICE_CS3 DEV_BOOCS +#define MV_BOOTDEVICE_INDEX 0 + +#define START_DEV_CS DEV_CS0 +#define DEV_TO_TARGET(dev) ((dev) + DEVICE_CS0) + +#define PCI_IF0_MEM0 PEX0_MEM +#define PCI_IF0_IO PEX0_IO + + +/* This enumerator defines the Marvell controller target ID */ +typedef enum _mvTargetId +{ + DRAM_TARGET_ID = 0 , /* Port 0 -> DRAM interface */ + DEV_TARGET_ID = 1, /* Port 1 -> Nand/SPI */ + PEX0_TARGET_ID = 4 , /* Port 4 -> PCI Express0 */ + CRYPT_TARGET_ID = 3 , /* Port 3 --> Crypto Engine */ + SAGE_TARGET_ID = 12 , /* Port 12 -> SAGE Unit */ + MAX_TARGETS_ID +}MV_TARGET_ID; + + +/* This enumerator described the possible Controller paripheral targets. */ +/* Controller peripherals are designated memory/IO address spaces that the */ +/* controller can access. They are also refered as "targets" */ +typedef enum _mvTarget +{ + TBL_TERM = -1, /* none valid target, used as targets list terminator*/ + SDRAM_CS0, /* SDRAM chip select 0 */ + SDRAM_CS1, /* SDRAM chip select 1 */ + SDRAM_CS2, /* SDRAM chip select 2 */ + SDRAM_CS3, /* SDRAM chip select 3 */ + PEX0_MEM, /* PCI Express 0 Memory */ + PEX0_IO, /* PCI Express 0 IO */ + INTER_REGS, /* Internal registers */ + NFLASH_CS, /* NFLASH_CS */ + SPI_CS, /* SPI_CS */ + BOOT_ROM_CS, /* BOOT_ROM_CS */ + DEV_BOOCS, /* DEV_BOOCS */ + CRYPT_ENG, /* Crypto Engine */ +#ifdef MV_INCLUDE_SAGE + SAGE_UNIT, /* SAGE Unit */ +#endif + MAX_TARGETS + +}MV_TARGET; + +#define TARGETS_DEF_ARRAY { \ + {0x0E, DRAM_TARGET_ID }, /* SDRAM_CS0 */ \ + {0x0D, DRAM_TARGET_ID }, /* SDRAM_CS1 */ \ + {0x0B, DRAM_TARGET_ID }, /* SDRAM_CS0 */ \ + {0x07, DRAM_TARGET_ID }, /* SDRAM_CS1 */ \ + {0xE8, PEX0_TARGET_ID }, /* PEX0_MEM */ \ + {0xE0, PEX0_TARGET_ID }, /* PEX0_IO */ \ + {0xFF, 0xFF }, /* INTER_REGS */ \ + {0x2F, DEV_TARGET_ID }, /* NFLASH_CS */ \ + {0x1E, DEV_TARGET_ID }, /* SPI_CS */ \ + {0x1D, DEV_TARGET_ID }, /* BOOT_ROM_CS */ \ + {0x1E, DEV_TARGET_ID }, /* DEV_BOOCS */ \ + {0x01, CRYPT_TARGET_ID}, /* CRYPT_ENG */ \ + {0x00, SAGE_TARGET_ID } \ +} + + +#define TARGETS_NAME_ARRAY { \ + "SDRAM_CS0", /* SDRAM_CS0 */ \ + "SDRAM_CS1", /* SDRAM_CS1 */ \ + "SDRAM_CS2", /* SDRAM_CS2 */ \ + "SDRAM_CS3", /* SDRAM_CS3 */ \ + "PEX0_MEM", /* PEX0_MEM */ \ + "PEX0_IO", /* PEX0_IO */ \ + "INTER_REGS", /* INTER_REGS */ \ + "NFLASH_CS", /* NFLASH_CS */ \ + "SPI_CS", /* SPI_CS */ \ + "BOOT_ROM_CS", /* BOOT_ROM_CS */ \ + "DEV_BOOTCS", /* DEV_BOOCS */ \ + "CRYPT_ENG", /* CRYPT_ENG */ \ + "SAGE_UNIT" /* SAGE_UNIT */ \ +} +#endif /* MV_ASMLANGUAGE */ + + +#endif diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/mvCtrlEnvSpec.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/mvCtrlEnvSpec.h new file mode 100644 index 0000000..e41d80a --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/mvCtrlEnvSpec.h @@ -0,0 +1,257 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#ifndef __INCmvCtrlEnvSpech +#define __INCmvCtrlEnvSpech + +#include "mvDeviceId.h" +#include "mvSysHwConfig.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define MV_ARM_SOC +#define SOC_NAME_PREFIX "MV88F" + + +/* units base and port numbers */ +#ifdef MV_ASMLANGUAGE +#define XOR_UNIT_BASE(unit) 0x60800 +#else +#define MV_XOR_REG_BASE 0x60000 +#define XOR_UNIT_BASE(unit) ((unit)? 0x60900:0x60800) +#endif + +#define TDM_REG_BASE 0xD0000 +#define USB_REG_BASE(dev) 0x50000 +#define AUDIO_REG_BASE 0xA0000 +#define SATA_REG_BASE 0x80000 +#define MV_CESA_REG_BASE 0x3D000 +#define MV_CESA_TDMA_REG_BASE 0x30000 +#define MV_SDIO_REG_BASE 0x90000 +#define MV_ETH_REG_BASE(port) (((port) == 0) ? 0x72000 : 0x76000) +#define MV_UART_CHAN_BASE(chanNum) (0x12000 + (chanNum * 0x100)) +#define DRAM_BASE 0x0 +#define CNTMR_BASE 0x20300 +#define TWSI_SLAVE_BASE(chanNum) 0x11000 +#define PEX_IF_BASE(pexIf) 0x40000 +#define MPP_REG_BASE 0x10000 +#define TSU_GLOBAL_REG_BASE 0xB4000 +#define MAX_AHB_TO_MBUS_REG_BASE 0x20000 + +#define INTER_REGS_SIZE _1M +/* This define describes the TWSI interrupt bit and location */ +#define TWSI_CPU_MAIN_INT_CAUSE_REG 0x20200 +#define TWSI0_CPU_MAIN_INT_BIT (1<<29) +#define TWSI_SPEED 100000 + +#define MV_GPP_MAX_GROUP 2 +#define MV_CNTMR_MAX_COUNTER 2 +#define MV_UART_MAX_CHAN 2 +#define MV_XOR_MAX_UNIT 2 +#define MV_XOR_MAX_CHAN 4 /* total channels for all units together*/ +#define MV_XOR_MAX_CHAN_PER_UNIT 2 /* channels for units */ +#define MV_SATA_MAX_CHAN 2 + +#define MV_6281_MPP_MAX_MODULE 2 +#define MV_6192_MPP_MAX_MODULE 1 +#define MV_6190_MPP_MAX_MODULE 1 +#define MV_6180_MPP_MAX_MODULE 2 +#define MV_6281_MPP_MAX_GROUP 7 +#define MV_6192_MPP_MAX_GROUP 4 +#define MV_6190_MPP_MAX_GROUP 4 +#define MV_6180_MPP_MAX_GROUP 3 + +#define MV_DRAM_MAX_CS 4 + +/* This define describes the maximum number of supported PCI\PCIX Interfaces*/ +#define MV_PCI_MAX_IF 0 +#define MV_PCI_START_IF 0 + +/* This define describes the maximum number of supported PEX Interfaces */ +#define MV_INCLUDE_PEX0 +#define MV_DISABLE_PEX_DEVICE_BAR +#define MV_PEX_MAX_IF 1 +#define MV_PEX_START_IF MV_PCI_MAX_IF + +/* This define describes the maximum number of supported PCI Interfaces */ +#define MV_PCI_IF_MAX_IF (MV_PEX_MAX_IF+MV_PCI_MAX_IF) + +#define MV_ETH_MAX_PORTS 2 +#define MV_6281_ETH_MAX_PORTS 2 +#define MV_6192_ETH_MAX_PORTS 2 +#define MV_6190_ETH_MAX_PORTS 1 +#define MV_6180_ETH_MAX_PORTS 1 + +#define MV_IDMA_MAX_CHAN 0 + +#define MV_USB_MAX_PORTS 1 + +#define MV_USB_VERSION 1 + + +#define MV_6281_NAND 1 +#define MV_6192_NAND 1 +#define MV_6190_NAND 1 +#define MV_6180_NAND 0 + +#define MV_6281_SDIO 1 +#define MV_6192_SDIO 1 +#define MV_6190_SDIO 1 +#define MV_6180_SDIO 1 + +#define MV_6281_TS 1 +#define MV_6192_TS 1 +#define MV_6190_TS 0 +#define MV_6180_TS 0 + +#define MV_6281_AUDIO 1 +#define MV_6192_AUDIO 1 +#define MV_6190_AUDIO 0 +#define MV_6180_AUDIO 1 + +#define MV_6281_TDM 1 +#define MV_6192_TDM 1 +#define MV_6190_TDM 0 +#define MV_6180_TDM 0 + +#define MV_DEVICE_MAX_CS 4 + +/* Others */ +#define PEX_HOST_BUS_NUM(pciIf) (pciIf) +#define PEX_HOST_DEV_NUM(pciIf) 0 + +#define PCI_IO(pciIf) (PEX0_IO) +#define PCI_MEM(pciIf, memNum) (PEX0_MEM0) +/* CESA version #2: One channel, 2KB SRAM, TDMA */ +#if defined(MV_CESA_CHAIN_MODE_SUPPORT) + #define MV_CESA_VERSION 3 +#else +#define MV_CESA_VERSION 2 +#endif +#define MV_CESA_SRAM_SIZE 2*1024 +/* This define describes the maximum number of supported Ethernet ports */ +#define MV_ETH_VERSION 4 +#define MV_ETH_MAX_RXQ 8 +#define MV_ETH_MAX_TXQ 8 +#define MV_ETH_PORT_SGMII { MV_FALSE, MV_FALSE } +/* This define describes the the support of USB */ +#define MV_USB_VERSION 1 + +#define MV_INCLUDE_SDRAM_CS0 +#define MV_INCLUDE_SDRAM_CS1 +#define MV_INCLUDE_SDRAM_CS2 +#define MV_INCLUDE_SDRAM_CS3 + +#define MV_INCLUDE_DEVICE_CS0 +#define MV_INCLUDE_DEVICE_CS1 +#define MV_INCLUDE_DEVICE_CS2 +#define MV_INCLUDE_DEVICE_CS3 + +#define MPP_GROUP_1_TYPE {\ + {0, 0, 0}, /* Reserved for AUTO */ \ + {0x22220000, 0x22222222, 0x2222}, /* TDM */ \ + {0x44440000, 0x00044444, 0x0000}, /* AUDIO */ \ + {0x33330000, 0x33003333, 0x0033}, /* RGMII */ \ + {0x33330000, 0x03333333, 0x0033}, /* GMII */ \ + {0x11110000, 0x11111111, 0x0001}, /* TS */ \ + {0x33330000, 0x33333333, 0x3333} /* MII */ \ +} + +#define MPP_GROUP_2_TYPE {\ + {0, 0, 0}, /* Reserved for AUTO */ \ + {0x22220000, 0x22222222, 0x22}, /* TDM */ \ + {0x44440000, 0x00044444, 0x0}, /* AUDIO */ \ + {0, 0, 0}, /* N_A */ \ + {0, 0, 0}, /* N_A */ \ + {0x11110000, 0x11111111, 0x01} /* TS */ \ +} + +#ifndef MV_ASMLANGUAGE + +/* This enumerator defines the Marvell Units ID */ +typedef enum _mvUnitId +{ + DRAM_UNIT_ID, + PEX_UNIT_ID, + ETH_GIG_UNIT_ID, + USB_UNIT_ID, + IDMA_UNIT_ID, + XOR_UNIT_ID, + SATA_UNIT_ID, + TDM_UNIT_ID, + UART_UNIT_ID, + CESA_UNIT_ID, + SPI_UNIT_ID, + AUDIO_UNIT_ID, + SDIO_UNIT_ID, + TS_UNIT_ID, + MAX_UNITS_ID + +}MV_UNIT_ID; + +#endif + +#endif /* __INCmvCtrlEnvSpech */ diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvAhbToMbus.c b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvAhbToMbus.c new file mode 100644 index 0000000..d21bb07 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvAhbToMbus.c @@ -0,0 +1,1048 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + + +/* includes */ +#include "ctrlEnv/sys/mvAhbToMbus.h" +#include "ctrlEnv/mvCtrlEnvAddrDec.h" + +#undef MV_DEBUG +/* defines */ +#ifdef MV_DEBUG + #define DB(x) x +#else + #define DB(x) +#endif + +/* typedefs */ + + +/* CPU address remap registers offsets are inconsecutive. This struct */ +/* describes address remap register offsets */ +typedef struct _ahbToMbusRemapRegOffs +{ + MV_U32 lowRegOffs; /* Low 32-bit remap register offset */ + MV_U32 highRegOffs; /* High 32 bit remap register offset */ +}AHB_TO_MBUS_REMAP_REG_OFFS; + +/* locals */ +static MV_STATUS ahbToMbusRemapRegOffsGet (MV_U32 winNum, + AHB_TO_MBUS_REMAP_REG_OFFS *pRemapRegs); + +/******************************************************************************* +* mvAhbToMbusInit - Initialize Ahb To Mbus Address Map ! +* +* DESCRIPTION: +* +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_OK laways. +* +*******************************************************************************/ +MV_STATUS mvAhbToMbusInit(void) +{ + return MV_OK; + +} + +/******************************************************************************* +* mvAhbToMbusWinSet - Set CPU-to-peripheral winNum address window +* +* DESCRIPTION: +* This function sets +* address window, also known as address decode window. +* A new address decode window is set for specified winNum address window. +* If address decode window parameter structure enables the window, +* the routine will also enable the winNum window, allowing CPU to access +* the winNum window. +* +* INPUT: +* winNum - Windows number. +* pAddrDecWin - CPU winNum window data structure. +* +* OUTPUT: +* N/A +* +* RETURN: +* MV_OK if CPU winNum window was set correctly, MV_ERROR in case of +* address window overlapps with other active CPU winNum window or +* trying to assign 36bit base address while CPU does not support that. +* The function returns MV_NOT_SUPPORTED, if the winNum is unsupported. +* +*******************************************************************************/ +MV_STATUS mvAhbToMbusWinSet(MV_U32 winNum, MV_AHB_TO_MBUS_DEC_WIN *pAddrDecWin) +{ + MV_TARGET_ATTRIB targetAttribs; + MV_DEC_REGS decRegs; + + /* Parameter checking */ + if (winNum >= MAX_AHB_TO_MBUS_WINS) + { + mvOsPrintf("mvAhbToMbusWinSet: ERR. Invalid winNum %d\n", winNum); + return MV_NOT_SUPPORTED; + } + + + /* read base register*/ + if (winNum != MV_AHB_TO_MBUS_INTREG_WIN) + { + decRegs.baseReg = MV_REG_READ(AHB_TO_MBUS_WIN_BASE_REG(winNum)); + } + else + { + decRegs.baseReg = MV_REG_READ(AHB_TO_MBUS_WIN_INTEREG_REG); + } + + /* check if address is aligned to the size */ + if(MV_IS_NOT_ALIGN(pAddrDecWin->addrWin.baseLow, pAddrDecWin->addrWin.size)) + { + mvOsPrintf("mvAhbToMbusWinSet:Error setting AHB to MBUS window %d to "\ + "target %s.\nAddress 0x%08x is unaligned to size 0x%x.\n", + winNum, + mvCtrlTargetNameGet(pAddrDecWin->target), + pAddrDecWin->addrWin.baseLow, + pAddrDecWin->addrWin.size); + return MV_ERROR; + } + + /* read control register*/ + if (winNum != MV_AHB_TO_MBUS_INTREG_WIN) + { + decRegs.sizeReg = MV_REG_READ(AHB_TO_MBUS_WIN_CTRL_REG(winNum)); + } + + if (MV_OK != mvCtrlAddrDecToReg(&(pAddrDecWin->addrWin),&decRegs)) + { + mvOsPrintf("mvAhbToMbusWinSet:mvCtrlAddrDecToReg Failed\n"); + return MV_ERROR; + } + + /* enable\Disable */ + if (MV_TRUE == pAddrDecWin->enable) + { + decRegs.sizeReg |= ATMWCR_WIN_ENABLE; + } + else + { + decRegs.sizeReg &= ~ATMWCR_WIN_ENABLE; + } + + mvCtrlAttribGet(pAddrDecWin->target,&targetAttribs); + + /* set attributes */ + decRegs.sizeReg &= ~ATMWCR_WIN_ATTR_MASK; + decRegs.sizeReg |= targetAttribs.attrib << ATMWCR_WIN_ATTR_OFFS; + /* set target ID */ + decRegs.sizeReg &= ~ATMWCR_WIN_TARGET_MASK; + decRegs.sizeReg |= targetAttribs.targetId << ATMWCR_WIN_TARGET_OFFS; + +#if !defined(MV_RUN_FROM_FLASH) + /* To be on the safe side we disable the window before writing the */ + /* new values. */ + if (winNum != MV_AHB_TO_MBUS_INTREG_WIN) + { + mvAhbToMbusWinEnable(winNum,MV_FALSE); + } +#endif + + /* 3) Write to address decode Base Address Register */ + if (winNum != MV_AHB_TO_MBUS_INTREG_WIN) + { + MV_REG_WRITE(AHB_TO_MBUS_WIN_BASE_REG(winNum), decRegs.baseReg); + } + else + { + MV_REG_WRITE(AHB_TO_MBUS_WIN_INTEREG_REG, decRegs.baseReg); + } + + + /* Internal register space have no size */ + /* register. Do not perform size register assigment for those targets */ + if (winNum != MV_AHB_TO_MBUS_INTREG_WIN) + { + /* Write to address decode Size Register */ + MV_REG_WRITE(AHB_TO_MBUS_WIN_CTRL_REG(winNum), decRegs.sizeReg); + } + + return MV_OK; +} + +/******************************************************************************* +* mvAhbToMbusWinGet - Get CPU-to-peripheral winNum address window +* +* DESCRIPTION: +* Get the CPU peripheral winNum address window. +* +* INPUT: +* winNum - Peripheral winNum enumerator +* +* OUTPUT: +* pAddrDecWin - CPU winNum window information data structure. +* +* RETURN: +* MV_OK if winNum exist, MV_ERROR otherwise. +* +*******************************************************************************/ +MV_STATUS mvAhbToMbusWinGet(MV_U32 winNum, MV_AHB_TO_MBUS_DEC_WIN *pAddrDecWin) +{ + MV_DEC_REGS decRegs; + MV_TARGET_ATTRIB targetAttrib; + + + /* Parameter checking */ + if (winNum >= MAX_AHB_TO_MBUS_WINS) + { + mvOsPrintf("mvAhbToMbusWinGet: ERR. Invalid winNum %d\n", winNum); + return MV_NOT_SUPPORTED; + } + + + /* Internal register space size have no size register*/ + if (winNum != MV_AHB_TO_MBUS_INTREG_WIN) + { + decRegs.sizeReg = MV_REG_READ(AHB_TO_MBUS_WIN_CTRL_REG(winNum)); + } + else + { + decRegs.sizeReg = 0; + } + + + /* Read base and size */ + if (winNum != MV_AHB_TO_MBUS_INTREG_WIN) + { + decRegs.baseReg = MV_REG_READ(AHB_TO_MBUS_WIN_BASE_REG(winNum)); + } + else + { + decRegs.baseReg = MV_REG_READ(AHB_TO_MBUS_WIN_INTEREG_REG); + } + + + + if (MV_OK != mvCtrlRegToAddrDec(&decRegs,&(pAddrDecWin->addrWin))) + { + mvOsPrintf("mvAhbToMbusWinGet: mvCtrlRegToAddrDec Failed \n"); + return MV_ERROR; + } + + if (winNum == MV_AHB_TO_MBUS_INTREG_WIN) + { + pAddrDecWin->addrWin.size = INTER_REGS_SIZE; + pAddrDecWin->target = INTER_REGS; + pAddrDecWin->enable = MV_TRUE; + + return MV_OK; + } + + + if (decRegs.sizeReg & ATMWCR_WIN_ENABLE) + { + pAddrDecWin->enable = MV_TRUE; + } + else + { + pAddrDecWin->enable = MV_FALSE; + + } + + + + if (-1 == pAddrDecWin->addrWin.size) + { + return MV_ERROR; + } + + /* attrib and targetId */ + targetAttrib.attrib = (decRegs.sizeReg & ATMWCR_WIN_ATTR_MASK) >> + ATMWCR_WIN_ATTR_OFFS; + targetAttrib.targetId = (decRegs.sizeReg & ATMWCR_WIN_TARGET_MASK) >> + ATMWCR_WIN_TARGET_OFFS; + + pAddrDecWin->target = mvCtrlTargetGet(&targetAttrib); + + return MV_OK; +} + +/******************************************************************************* +* mvAhbToMbusWinTargetGet - Get Window number associated with target +* +* DESCRIPTION: +* +* INPUT: +* +* OUTPUT: +* +* RETURN: +* +*******************************************************************************/ +MV_U32 mvAhbToMbusWinTargetGet(MV_TARGET target) +{ + MV_AHB_TO_MBUS_DEC_WIN decWin; + MV_U32 winNum; + + /* Check parameters */ + if (target >= MAX_TARGETS) + { + mvOsPrintf("mvAhbToMbusWinTargetGet: target %d is Illigal\n", target); + return 0xffffffff; + } + + if (INTER_REGS == target) + { + return MV_AHB_TO_MBUS_INTREG_WIN; + } + + for (winNum = 0; winNum < MAX_AHB_TO_MBUS_WINS ; winNum++) + { + if (winNum == MV_AHB_TO_MBUS_INTREG_WIN) + continue; + + if (mvAhbToMbusWinGet(winNum,&decWin) != MV_OK) + { + mvOsPrintf("mvAhbToMbusWinTargetGet: mvAhbToMbusWinGet fail\n"); + return 0xffffffff; + + } + + if (decWin.enable == MV_TRUE) + { + if (decWin.target == target) + { + return winNum; + } + + } + + } + + return 0xFFFFFFFF; + + +} + +/******************************************************************************* +* mvAhbToMbusWinAvailGet - Get First Available window number. +* +* DESCRIPTION: +* +* INPUT: +* +* OUTPUT: +* +* RETURN: +* +*******************************************************************************/ +MV_U32 mvAhbToMbusWinAvailGet(MV_VOID) +{ + MV_AHB_TO_MBUS_DEC_WIN decWin; + MV_U32 winNum; + + for (winNum = 0; winNum < MAX_AHB_TO_MBUS_WINS ; winNum++) + { + if (winNum == MV_AHB_TO_MBUS_INTREG_WIN) + continue; + + if (mvAhbToMbusWinGet(winNum,&decWin) != MV_OK) + { + mvOsPrintf("mvAhbToMbusWinTargetGet: mvAhbToMbusWinGet fail\n"); + return 0xffffffff; + + } + + if (decWin.enable == MV_FALSE) + { + return winNum; + } + + } + + return 0xFFFFFFFF; +} + + +/******************************************************************************* +* mvAhbToMbusWinEnable - Enable/disable a CPU address decode window +* +* DESCRIPTION: +* This function enable/disable a CPU address decode window. +* if parameter 'enable' == MV_TRUE the routine will enable the +* window, thus enabling CPU accesses (before enabling the window it is +* tested for overlapping). Otherwise, the window will be disabled. +* +* INPUT: +* winNum - Peripheral winNum enumerator. +* enable - Enable/disable parameter. +* +* OUTPUT: +* N/A +* +* RETURN: +* MV_ERROR if protection window number was wrong, or the window +* overlapps other winNum window. +* +*******************************************************************************/ +MV_STATUS mvAhbToMbusWinEnable(MV_U32 winNum, MV_BOOL enable) +{ + + /* Parameter checking */ + if (winNum >= MAX_AHB_TO_MBUS_WINS) + { + mvOsPrintf("mvAhbToMbusWinEnable: ERR. Invalid winNum %d\n", winNum); + return MV_NOT_SUPPORTED; + } + + /* Internal registers bar can't be disable or enabled */ + if (winNum == MV_AHB_TO_MBUS_INTREG_WIN) + { + return (enable ? MV_OK : MV_ERROR); + } + + if (enable == MV_TRUE) + { + /* enable the window */ + MV_REG_BIT_SET(AHB_TO_MBUS_WIN_CTRL_REG(winNum), ATMWCR_WIN_ENABLE); + } + else + { /* Disable address decode winNum window */ + MV_REG_BIT_RESET(AHB_TO_MBUS_WIN_CTRL_REG(winNum), ATMWCR_WIN_ENABLE); + } + + return MV_OK; +} + + +/******************************************************************************* +* mvAhbToMbusWinRemap - Set CPU remap register for address windows. +* +* DESCRIPTION: +* After a CPU address hits one of PCI address decode windows there is an +* option to remap the address to a different one. For example, CPU +* executes a read from PCI winNum window address 0x1200.0000. This +* can be modified so the address on the PCI bus would be 0x1400.0000 +* Using the PCI address remap mechanism. +* +* INPUT: +* winNum - Peripheral winNum enumerator. Must be a PCI winNum. +* pAddrDecWin - CPU winNum window information data structure. +* Note that caller has to fill in the base field only. The +* size field is ignored. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_ERROR if winNum is not a PCI one, MV_OK otherwise. +* +*******************************************************************************/ +MV_U32 mvAhbToMbusWinRemap(MV_U32 winNum, MV_ADDR_WIN *pAddrWin) +{ + MV_U32 baseAddr; + AHB_TO_MBUS_REMAP_REG_OFFS remapRegOffs; + + MV_U32 effectiveBaseAddress=0, + baseAddrValue=0,windowSizeValue=0; + + + /* Get registers offsets of given winNum */ + if (MV_NO_SUCH == ahbToMbusRemapRegOffsGet(winNum, &remapRegOffs)) + { + return 0xffffffff; + } + + /* 1) Set address remap low */ + baseAddr = pAddrWin->baseLow; + + /* Check base address aligment */ + /* + if (MV_IS_NOT_ALIGN(baseAddr, ATMWRLR_REMAP_LOW_ALIGNMENT)) + { + mvOsPrintf("mvAhbToMbusPciRemap: Warning. Target base 0x%x unaligned\n", + baseAddr); + return MV_ERROR; + } + */ + + /* BaseLow[31:16] => base register [31:16] */ + baseAddr = baseAddr & ATMWRLR_REMAP_LOW_MASK; + + MV_REG_WRITE(remapRegOffs.lowRegOffs, baseAddr); + + MV_REG_WRITE(remapRegOffs.highRegOffs, pAddrWin->baseHigh); + + + baseAddrValue = MV_REG_READ(AHB_TO_MBUS_WIN_BASE_REG(winNum)); + windowSizeValue = MV_REG_READ(AHB_TO_MBUS_WIN_CTRL_REG(winNum)); + + baseAddrValue &= ATMWBR_BASE_MASK; + windowSizeValue &=ATMWCR_WIN_SIZE_MASK; + + /* Start calculating the effective Base Address */ + effectiveBaseAddress = baseAddrValue ; + + /* The effective base address will be combined from the chopped (if any) + remap value (according to the size value and remap mechanism) and the + window's base address */ + effectiveBaseAddress |= (((windowSizeValue) | 0xffff) & pAddrWin->baseLow); + /* If the effectiveBaseAddress exceed the window boundaries return an + invalid value. */ + + if (effectiveBaseAddress > (baseAddrValue + (windowSizeValue | 0xffff))) + { + mvOsPrintf("mvAhbToMbusPciRemap: Error\n"); + return 0xffffffff; + } + + return effectiveBaseAddress; + + +} +/******************************************************************************* +* mvAhbToMbusWinTargetSwap - Swap AhbToMbus windows between targets +* +* DESCRIPTION: +* +* INPUT: +* target1 - CPU Interface target 1 +* target2 - CPU Interface target 2 +* +* OUTPUT: +* None. +* +* RETURN: +* MV_ERROR if targets are illigal, or if one of the targets is not +* associated to a valid window . +* MV_OK otherwise. +* +*******************************************************************************/ + + +MV_STATUS mvAhbToMbusWinTargetSwap(MV_TARGET target1,MV_TARGET target2) +{ + MV_U32 winNum1,winNum2; + MV_AHB_TO_MBUS_DEC_WIN winDec1,winDec2,winDecTemp; + AHB_TO_MBUS_REMAP_REG_OFFS remapRegs1,remapRegs2; + MV_U32 remapBaseLow1=0,remapBaseLow2=0; + MV_U32 remapBaseHigh1=0,remapBaseHigh2=0; + + + /* Check parameters */ + if (target1 >= MAX_TARGETS) + { + mvOsPrintf("mvAhbToMbusWinTargetSwap: target %d is Illigal\n", target1); + return MV_ERROR; + } + + if (target2 >= MAX_TARGETS) + { + mvOsPrintf("mvAhbToMbusWinTargetSwap: target %d is Illigal\n", target1); + return MV_ERROR; + } + + + /* get window associated with this target */ + winNum1 = mvAhbToMbusWinTargetGet(target1); + + if (winNum1 == 0xffffffff) + { + mvOsPrintf("mvAhbToMbusWinTargetSwap: target %d has illigal win %d\n", + target1,winNum1); + return MV_ERROR; + + } + + /* get window associated with this target */ + winNum2 = mvAhbToMbusWinTargetGet(target2); + + if (winNum2 == 0xffffffff) + { + mvOsPrintf("mvAhbToMbusWinTargetSwap: target %d has illigal win %d\n", + target2,winNum2); + return MV_ERROR; + + } + + /* now Get original values of both Windows */ + if (MV_OK != mvAhbToMbusWinGet(winNum1,&winDec1)) + { + mvOsPrintf("mvAhbToMbusWinTargetSwap: mvAhbToMbusWinGet failed win %d\n", + winNum1); + return MV_ERROR; + + } + if (MV_OK != mvAhbToMbusWinGet(winNum2,&winDec2)) + { + mvOsPrintf("mvAhbToMbusWinTargetSwap: mvAhbToMbusWinGet failed win %d\n", + winNum2); + return MV_ERROR; + + } + + + /* disable both windows */ + if (MV_OK != mvAhbToMbusWinEnable(winNum1,MV_FALSE)) + { + mvOsPrintf("mvAhbToMbusWinTargetSwap: failed to enable window %d\n", + winNum1); + return MV_ERROR; + + } + if (MV_OK != mvAhbToMbusWinEnable(winNum2,MV_FALSE)) + { + mvOsPrintf("mvAhbToMbusWinTargetSwap: failed to enable windo %d\n", + winNum2); + return MV_ERROR; + + } + + + /* now swap targets */ + + /* first save winDec2 values */ + winDecTemp.addrWin.baseHigh = winDec2.addrWin.baseHigh; + winDecTemp.addrWin.baseLow = winDec2.addrWin.baseLow; + winDecTemp.addrWin.size = winDec2.addrWin.size; + winDecTemp.enable = winDec2.enable; + winDecTemp.target = winDec2.target; + + /* winDec2 = winDec1 */ + winDec2.addrWin.baseHigh = winDec1.addrWin.baseHigh; + winDec2.addrWin.baseLow = winDec1.addrWin.baseLow; + winDec2.addrWin.size = winDec1.addrWin.size; + winDec2.enable = winDec1.enable; + winDec2.target = winDec1.target; + + + /* winDec1 = winDecTemp */ + winDec1.addrWin.baseHigh = winDecTemp.addrWin.baseHigh; + winDec1.addrWin.baseLow = winDecTemp.addrWin.baseLow; + winDec1.addrWin.size = winDecTemp.addrWin.size; + winDec1.enable = winDecTemp.enable; + winDec1.target = winDecTemp.target; + + + /* now set the new values */ + + + mvAhbToMbusWinSet(winNum1,&winDec1); + mvAhbToMbusWinSet(winNum2,&winDec2); + + + + + + /* now we will treat the remap windows if exist */ + + + /* now check if one or both windows has a remap window + as well after the swap ! */ + + /* if a window had a remap value differnt than the base value + before the swap , then after the swap the remap value will be + equal to the base value unless both windows has a remap windows*/ + + /* first get old values */ + if (MV_NO_SUCH != ahbToMbusRemapRegOffsGet(winNum1,&remapRegs1)) + { + remapBaseLow1 = MV_REG_READ(remapRegs1.lowRegOffs); + remapBaseHigh1 = MV_REG_READ(remapRegs1.highRegOffs); + + } + if (MV_NO_SUCH != ahbToMbusRemapRegOffsGet(winNum2,&remapRegs2)) + { + remapBaseLow2 = MV_REG_READ(remapRegs2.lowRegOffs); + remapBaseHigh2 = MV_REG_READ(remapRegs2.highRegOffs); + + + } + + /* now do the swap */ + if (MV_NO_SUCH != ahbToMbusRemapRegOffsGet(winNum1,&remapRegs1)) + { + if (MV_NO_SUCH != ahbToMbusRemapRegOffsGet(winNum2,&remapRegs2)) + { + /* Two windows has a remap !!! so swap */ + + MV_REG_WRITE(remapRegs2.highRegOffs,remapBaseHigh1); + MV_REG_WRITE(remapRegs2.lowRegOffs,remapBaseLow1); + + MV_REG_WRITE(remapRegs1.highRegOffs,remapBaseHigh2); + MV_REG_WRITE(remapRegs1.lowRegOffs,remapBaseLow2); + + + + } + else + { + /* remap == base */ + MV_REG_WRITE(remapRegs1.highRegOffs,winDec1.addrWin.baseHigh); + MV_REG_WRITE(remapRegs1.lowRegOffs,winDec1.addrWin.baseLow); + + } + + } + else if (MV_NO_SUCH != ahbToMbusRemapRegOffsGet(winNum2,&remapRegs2)) + { + /* remap == base */ + MV_REG_WRITE(remapRegs2.highRegOffs,winDec2.addrWin.baseHigh); + MV_REG_WRITE(remapRegs2.lowRegOffs,winDec2.addrWin.baseLow); + + } + + + + return MV_OK; + + +} + + + +#if defined(MV_88F1181) + +/******************************************************************************* +* mvAhbToMbusXbarCtrlSet - Set The CPU master Xbar arbitration. +* +* DESCRIPTION: +* This function sets CPU Mbus Arbiter +* +* INPUT: +* pPizzaArbArray - A priority Structure describing 16 "pizza slices". At +* each clock cycle, the crossbar arbiter samples all +* requests and gives the bus to the next agent according +* to the "pizza". +* +* OUTPUT: +* N/A +* +* RETURN: +* MV_ERROR if paramers to function invalid. +* +*******************************************************************************/ +MV_STATUS mvMbusArbSet(MV_MBUS_ARB_TARGET *pPizzaArbArray) +{ + MV_U32 sliceNum; + MV_U32 xbarCtrl = 0; + MV_MBUS_ARB_TARGET xbarTarget; + + /* 1) Set crossbar control low register */ + for (sliceNum = 0; sliceNum < MRLR_SLICE_NUM; sliceNum++) + { + xbarTarget = pPizzaArbArray[sliceNum]; + + /* sliceNum parameter check */ + if (xbarTarget > MAX_MBUS_ARB_TARGETS) + { + mvOsPrintf("mvAhbToMbusXbarCtrlSet: ERR. Can't set Target %d\n", + xbarTarget); + return MV_ERROR; + } + xbarCtrl |= (xbarTarget << MRLR_LOW_ARB_OFFS(sliceNum)); + } + /* Write to crossbar control low register */ + MV_REG_WRITE(MBUS_ARBITER_LOW_REG, xbarCtrl); + + xbarCtrl = 0; + + /* 2) Set crossbar control high register */ + for (sliceNum = MRLR_SLICE_NUM; + sliceNum < MRLR_SLICE_NUM+MRHR_SLICE_NUM; + sliceNum++) + { + + xbarTarget = pPizzaArbArray[sliceNum]; + + /* sliceNum parameter check */ + if (xbarTarget > MAX_MBUS_ARB_TARGETS) + { + mvOsPrintf("mvAhbToMbusXbarCtrlSet: ERR. Can't set Target %d\n", + xbarTarget); + return MV_ERROR; + } + xbarCtrl |= (xbarTarget << MRHR_HIGH_ARB_OFFS(sliceNum)); + } + /* Write to crossbar control high register */ + MV_REG_WRITE(MBUS_ARBITER_HIGH_REG, xbarCtrl); + + return MV_OK; +} + +/******************************************************************************* +* mvMbusArbCtrlSet - Set MBus Arbiter control register +* +* DESCRIPTION: +* +* INPUT: +* ctrl - pointer to MV_MBUS_ARB_CTRL register +* +* OUTPUT: +* N/A +* +* RETURN: +* MV_ERROR if paramers to function invalid. +* +*******************************************************************************/ +MV_STATUS mvMbusArbCtrlSet(MV_MBUS_ARB_CTRL *ctrl) +{ + + if (ctrl->highPrio == MV_FALSE) + { + MV_REG_BIT_RESET(MBUS_ARBITER_CTRL_REG, MACR_ARB_ARM_TOP); + } + else + { + MV_REG_BIT_SET(MBUS_ARBITER_CTRL_REG, MACR_ARB_ARM_TOP); + } + + if (ctrl->fixedRoundRobin == MV_FALSE) + { + MV_REG_BIT_RESET(MBUS_ARBITER_CTRL_REG, MACR_ARB_TARGET_FIXED); + } + else + { + MV_REG_BIT_SET(MBUS_ARBITER_CTRL_REG, MACR_ARB_TARGET_FIXED); + } + + if (ctrl->starvEn == MV_FALSE) + { + MV_REG_BIT_RESET(MBUS_ARBITER_CTRL_REG, MACR_ARB_REQ_CTRL_EN); + } + else + { + MV_REG_BIT_SET(MBUS_ARBITER_CTRL_REG, MACR_ARB_REQ_CTRL_EN); + } + + return MV_OK; +} + +/******************************************************************************* +* mvMbusArbCtrlGet - Get MBus Arbiter control register +* +* DESCRIPTION: +* +* INPUT: +* ctrl - pointer to MV_MBUS_ARB_CTRL register +* +* OUTPUT: +* ctrl - pointer to MV_MBUS_ARB_CTRL register +* +* RETURN: +* MV_ERROR if paramers to function invalid. +* +*******************************************************************************/ +MV_STATUS mvMbusArbCtrlGet(MV_MBUS_ARB_CTRL *ctrl) +{ + + MV_U32 ctrlReg = MV_REG_READ(MBUS_ARBITER_CTRL_REG); + + if (ctrlReg & MACR_ARB_ARM_TOP) + { + ctrl->highPrio = MV_TRUE; + } + else + { + ctrl->highPrio = MV_FALSE; + } + + if (ctrlReg & MACR_ARB_TARGET_FIXED) + { + ctrl->fixedRoundRobin = MV_TRUE; + } + else + { + ctrl->fixedRoundRobin = MV_FALSE; + } + + if (ctrlReg & MACR_ARB_REQ_CTRL_EN) + { + ctrl->starvEn = MV_TRUE; + } + else + { + ctrl->starvEn = MV_FALSE; + } + + + return MV_OK; +} + +#endif /* #if defined(MV_88F1181) */ + + + +/******************************************************************************* +* ahbToMbusRemapRegOffsGet - Get CPU address remap register offsets +* +* DESCRIPTION: +* CPU to PCI address remap registers offsets are inconsecutive. +* This function returns PCI address remap registers offsets. +* +* INPUT: +* winNum - Address decode window number. See MV_U32 enumerator. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_ERROR if winNum is not a PCI one. +* +*******************************************************************************/ +static MV_STATUS ahbToMbusRemapRegOffsGet(MV_U32 winNum, + AHB_TO_MBUS_REMAP_REG_OFFS *pRemapRegs) +{ + switch (winNum) + { + case 0: + case 1: + pRemapRegs->lowRegOffs = AHB_TO_MBUS_WIN_REMAP_LOW_REG(winNum); + pRemapRegs->highRegOffs = AHB_TO_MBUS_WIN_REMAP_HIGH_REG(winNum); + break; + case 2: + case 3: + if((mvCtrlModelGet() == MV_5281_DEV_ID) || + (mvCtrlModelGet() == MV_1281_DEV_ID) || + (mvCtrlModelGet() == MV_6183_DEV_ID) || + (mvCtrlModelGet() == MV_6183L_DEV_ID)) + { + pRemapRegs->lowRegOffs = AHB_TO_MBUS_WIN_REMAP_LOW_REG(winNum); + pRemapRegs->highRegOffs = AHB_TO_MBUS_WIN_REMAP_HIGH_REG(winNum); + break; + } + else + { + pRemapRegs->lowRegOffs = 0; + pRemapRegs->highRegOffs = 0; + + DB(mvOsPrintf("ahbToMbusRemapRegOffsGet: ERR. Invalid winNum %d\n", + winNum)); + return MV_NO_SUCH; + } + default: + { + pRemapRegs->lowRegOffs = 0; + pRemapRegs->highRegOffs = 0; + + DB(mvOsPrintf("ahbToMbusRemapRegOffsGet: ERR. Invalid winNum %d\n", + winNum)); + return MV_NO_SUCH; + } + } + + return MV_OK; +} + +/******************************************************************************* +* mvAhbToMbusAddDecShow - Print the AHB to MBus bridge address decode map. +* +* DESCRIPTION: +* This function print the CPU address decode map. +* +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* None. +* +*******************************************************************************/ +MV_VOID mvAhbToMbusAddDecShow(MV_VOID) +{ + MV_AHB_TO_MBUS_DEC_WIN win; + MV_U32 winNum; + mvOsOutput( "\n" ); + mvOsOutput( "AHB To MBUS Bridge:\n" ); + mvOsOutput( "-------------------\n" ); + + for( winNum = 0; winNum < MAX_AHB_TO_MBUS_WINS; winNum++ ) + { + memset( &win, 0, sizeof(MV_AHB_TO_MBUS_DEC_WIN) ); + + mvOsOutput( "win%d - ", winNum ); + + if( mvAhbToMbusWinGet( winNum, &win ) == MV_OK ) + { + if( win.enable ) + { + mvOsOutput( "%s base %08x, ", + mvCtrlTargetNameGet(win.target), win.addrWin.baseLow ); + mvOsOutput( "...." ); + mvSizePrint( win.addrWin.size ); + + mvOsOutput( "\n" ); + + } + else + mvOsOutput( "disable\n" ); + } + } + +} + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvAhbToMbus.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvAhbToMbus.h new file mode 100644 index 0000000..1b352a1 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvAhbToMbus.h @@ -0,0 +1,130 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + + +#ifndef __INCmvAhbToMbush +#define __INCmvAhbToMbush + +/* includes */ +#include "ctrlEnv/mvCtrlEnvLib.h" +#include "ctrlEnv/sys/mvAhbToMbusRegs.h" +#include "ctrlEnv/mvCtrlEnvAddrDec.h" + +/* defines */ + +#if defined(MV_88F1181) +/* This enumerator defines the Marvell controller possible MBUS arbiter */ +/* target ports. It is used to define crossbar priority scheame (pizza) */ +typedef enum _mvMBusArbTargetId +{ + DRAM_MBUS_ARB_TARGET = 0, /* Port 0 -> DRAM interface */ + TWSI_MBUS_ARB_TARGET = 1, /* Port 1 -> TWSI */ + ARM_MBUS_ARB_TARGET = 2, /* Port 2 -> ARM */ + PEX1_MBUS_ARB_TARGET = 3, /* Port 3 -> PCI Express 1 */ + PEX0_MBUS_ARB_TARGET = 4, /* Port 4 -> PCI Express0 */ + MAX_MBUS_ARB_TARGETS +}MV_MBUS_ARB_TARGET; + +typedef struct _mvMBusArbCtrl +{ + MV_BOOL starvEn; + MV_BOOL highPrio; + MV_BOOL fixedRoundRobin; + +}MV_MBUS_ARB_CTRL; + +#endif /* #if defined(MV_88F1181) */ + +typedef struct _mvAhbtoMbusDecWin +{ + MV_TARGET target; + MV_ADDR_WIN addrWin; /* An address window*/ + MV_BOOL enable; /* Address decode window is enabled/disabled */ + +}MV_AHB_TO_MBUS_DEC_WIN; + +/* mvAhbToMbus.h API list */ + +MV_STATUS mvAhbToMbusInit(MV_VOID); +MV_STATUS mvAhbToMbusWinSet(MV_U32 winNum, MV_AHB_TO_MBUS_DEC_WIN *pAddrDecWin); +MV_STATUS mvAhbToMbusWinGet(MV_U32 winNum, MV_AHB_TO_MBUS_DEC_WIN *pAddrDecWin); +MV_STATUS mvAhbToMbusWinEnable(MV_U32 winNum,MV_BOOL enable); +MV_U32 mvAhbToMbusWinRemap(MV_U32 winNum, MV_ADDR_WIN *pAddrDecWin); +MV_U32 mvAhbToMbusWinTargetGet(MV_TARGET target); +MV_U32 mvAhbToMbusWinAvailGet(MV_VOID); +MV_STATUS mvAhbToMbusWinTargetSwap(MV_TARGET target1,MV_TARGET target2); + +#if defined(MV_88F1181) + +MV_STATUS mvMbusArbSet(MV_MBUS_ARB_TARGET *pPizzaArbArray); +MV_STATUS mvMbusArbCtrlSet(MV_MBUS_ARB_CTRL *ctrl); +MV_STATUS mvMbusArbCtrlGet(MV_MBUS_ARB_CTRL *ctrl); + +#endif /* #if defined(MV_88F1181) */ + + +MV_VOID mvAhbToMbusAddDecShow(MV_VOID); + + +#endif /* __INCmvAhbToMbush */ diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvAhbToMbusRegs.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvAhbToMbusRegs.h new file mode 100644 index 0000000..97dc631 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvAhbToMbusRegs.h @@ -0,0 +1,143 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + + +#ifndef __INCmvAhbToMbusRegsh +#define __INCmvAhbToMbusRegsh + +/******************************/ +/* ARM Address Map Registers */ +/******************************/ + +#define MAX_AHB_TO_MBUS_WINS 9 +#define MV_AHB_TO_MBUS_INTREG_WIN 8 + + +#define AHB_TO_MBUS_WIN_CTRL_REG(winNum) (0x20000 + (winNum)*0x10) +#define AHB_TO_MBUS_WIN_BASE_REG(winNum) (0x20004 + (winNum)*0x10) +#define AHB_TO_MBUS_WIN_REMAP_LOW_REG(winNum) (0x20008 + (winNum)*0x10) +#define AHB_TO_MBUS_WIN_REMAP_HIGH_REG(winNum) (0x2000C + (winNum)*0x10) +#define AHB_TO_MBUS_WIN_INTEREG_REG 0x20080 + +/* Window Control Register */ +/* AHB_TO_MBUS_WIN_CTRL_REG (ATMWCR)*/ +#define ATMWCR_WIN_ENABLE BIT0 /* Window Enable */ + +#define ATMWCR_WIN_TARGET_OFFS 4 /* The target interface associated + with this window*/ +#define ATMWCR_WIN_TARGET_MASK (0xf << ATMWCR_WIN_TARGET_OFFS) + +#define ATMWCR_WIN_ATTR_OFFS 8 /* The target interface attributes + Associated with this window */ +#define ATMWCR_WIN_ATTR_MASK (0xff << ATMWCR_WIN_ATTR_OFFS) + + +/* +Used with the Base register to set the address window size and location +Must be programed from LSB to MSB as sequence of 1’s followed +by sequence of 0’s. The number of 1’s specifies the size of the window +in 64 KB granularity (e.g. a value of 0x00FF specifies 256 = 16 MB). + +NOTE: A value of 0x0 specifies 64KB size. +*/ +#define ATMWCR_WIN_SIZE_OFFS 16 /* Window Size */ +#define ATMWCR_WIN_SIZE_MASK (0xffff << ATMWCR_WIN_SIZE_OFFS) +#define ATMWCR_WIN_SIZE_ALIGNMENT 0x10000 + +/* Window Base Register */ +/* AHB_TO_MBUS_WIN_BASE_REG (ATMWBR) */ + +/* +Used with the size field to set the address window size and location. +Corresponds to transaction address[31:16] +*/ +#define ATMWBR_BASE_OFFS 16 /* Base Address */ +#define ATMWBR_BASE_MASK (0xffff << ATMWBR_BASE_OFFS) +#define ATMWBR_BASE_ALIGNMENT 0x10000 + +/* Window Remap Low Register */ +/* AHB_TO_MBUS_WIN_REMAP_LOW_REG (ATMWRLR) */ + +/* +Used with the size field to specifies address bits[31:0] to be driven to +the target interface.: +target_addr[31:16] = (addr[31:16] & size[15:0]) | (remap[31:16] & ~size[15:0]) +*/ +#define ATMWRLR_REMAP_LOW_OFFS 16 /* Remap Address */ +#define ATMWRLR_REMAP_LOW_MASK (0xffff << ATMWRLR_REMAP_LOW_OFFS) +#define ATMWRLR_REMAP_LOW_ALIGNMENT 0x10000 + +/* Window Remap High Register */ +/* AHB_TO_MBUS_WIN_REMAP_HIGH_REG (ATMWRHR) */ + +/* +Specifies address bits[63:32] to be driven to the target interface. +target_addr[63:32] = (RemapHigh[31:0] +*/ +#define ATMWRHR_REMAP_HIGH_OFFS 0 /* Remap Address */ +#define ATMWRHR_REMAP_HIGH_MASK (0xffffffff << ATMWRHR_REMAP_HIGH_OFFS) + + +#endif /* __INCmvAhbToMbusRegsh */ + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvCpuIf.c b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvCpuIf.c new file mode 100644 index 0000000..872dc6e --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvCpuIf.c @@ -0,0 +1,1036 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + + +/* includes */ +#include "ctrlEnv/sys/mvCpuIf.h" +#include "ctrlEnv/sys/mvAhbToMbusRegs.h" +#include "cpu/mvCpu.h" +#include "ctrlEnv/mvCtrlEnvLib.h" +#include "mvSysHwConfig.h" +#include "mvSysDram.h" + +/*#define MV_DEBUG*/ +/* defines */ + +#ifdef MV_DEBUG + #define DB(x) x +#else + #define DB(x) +#endif + +/* locals */ +/* static functions */ +static MV_BOOL cpuTargetWinOverlap(MV_TARGET target, MV_ADDR_WIN *pAddrWin); + +MV_TARGET * sampleAtResetTargetArray; +MV_TARGET sampleAtResetTargetArrayP[] = BOOT_TARGETS_NAME_ARRAY; +MV_TARGET sampleAtResetTargetArray6180P[] = BOOT_TARGETS_NAME_ARRAY_6180; +/******************************************************************************* +* mvCpuIfInit - Initialize Controller CPU interface +* +* DESCRIPTION: +* This function initialize Controller CPU interface: +* 1. Set CPU interface configuration registers. +* 2. Set CPU master Pizza arbiter control according to static +* configuration described in configuration file. +* 3. Opens CPU address decode windows. DRAM windows are assumed to be +* already set (auto detection). +* +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* None. +* +*******************************************************************************/ +MV_STATUS mvCpuIfInit(MV_CPU_DEC_WIN *cpuAddrWinMap) +{ + MV_U32 regVal; + MV_TARGET target; + MV_ADDR_WIN addrWin; + + if (cpuAddrWinMap == NULL) + { + DB(mvOsPrintf("mvCpuIfInit:ERR. cpuAddrWinMap == NULL\n")); + return MV_ERROR; + } + + /*Initialize the boot target array according to device type*/ + if(mvCtrlModelGet() == MV_6180_DEV_ID) + sampleAtResetTargetArray = sampleAtResetTargetArray6180P; + else + sampleAtResetTargetArray = sampleAtResetTargetArrayP; + + /* Set ARM Configuration register */ + regVal = MV_REG_READ(CPU_CONFIG_REG); + regVal &= ~CPU_CONFIG_DEFAULT_MASK; + regVal |= CPU_CONFIG_DEFAULT; + MV_REG_WRITE(CPU_CONFIG_REG,regVal); + + /* First disable all CPU target windows */ + for (target = 0; cpuAddrWinMap[target].enable != TBL_TERM; target++) + { + if ((MV_TARGET_IS_DRAM(target))||(target == INTER_REGS)) + { + continue; + } + +#if defined(MV_MEM_OVER_PCI_WA) || defined(MV_UART_OVER_PCI_WA) + /* If the target PEX or PCI and memory is over PEX or PCI we don't touch this CPU windows */ + if (MV_TARGET_IS_PCI(target)) + { + continue; + } +#endif + +#if defined(MV_MEM_OVER_PEX_WA) || defined(MV_UART_OVER_PEX_WA) + /* If the target PEX or PCI and memory is over PEX or PCI we don't touch this CPU windows */ + if (MV_TARGET_IS_PEX(target)) + { + continue; + } +#endif +#if defined(MV_RUN_FROM_FLASH) + /* Don't disable the boot device. */ + if (target == DEV_BOOCS) + { + continue; + } +#endif /* MV_RUN_FROM_FLASH */ + mvCpuIfTargetWinEnable(MV_CHANGE_BOOT_CS(target),MV_FALSE); + } + +#if defined(MV_RUN_FROM_FLASH) + /* Resize the bootcs windows before other windows, because this */ + /* window is enabled and will cause an overlap if not resized. */ + target = DEV_BOOCS; + + if (MV_OK != mvCpuIfTargetWinSet(target, &cpuAddrWinMap[target])) + { + DB(mvOsPrintf("mvCpuIfInit:ERR. mvCpuIfTargetWinSet fail\n")); + return MV_ERROR; + } + + addrWin.baseLow = cpuAddrWinMap[target].addrWin.baseLow; + addrWin.baseHigh = cpuAddrWinMap[target].addrWin.baseHigh; + if (0xffffffff == mvAhbToMbusWinRemap(cpuAddrWinMap[target].winNum ,&addrWin)) + { + DB(mvOsPrintf("mvCpuIfInit:WARN. mvAhbToMbusWinRemap can't remap winNum=%d\n", + cpuAddrWinMap[target].winNum)); + } + +#endif /* MV_RUN_FROM_FLASH */ + + /* Go through all targets in user table until table terminator */ + for (target = 0; cpuAddrWinMap[target].enable != TBL_TERM; target++) + { + +#if defined(MV_RUN_FROM_FLASH) + if (target == DEV_BOOCS) + { + continue; + } +#endif /* MV_RUN_FROM_FLASH */ + + /* if DRAM auto sizing is used do not initialized DRAM target windows, */ + /* assuming this already has been done earlier. */ +#ifdef MV_DRAM_AUTO_SIZE + if (MV_TARGET_IS_DRAM(target)) + { + continue; + } +#endif + +#if defined(MV_MEM_OVER_PCI_WA) || defined(MV_UART_OVER_PCI_WA) + /* If the target PEX or PCI and memory is over PEX or PCI we don't touch this CPU windows */ + if (MV_TARGET_IS_PCI(target)) + { + continue; + } +#endif + +#if defined(MV_MEM_OVER_PEX_WA) || defined(MV_UART_OVER_PEX_WA) + /* If the target PEX or PCI and memory is over PEX or PCI we don't touch this CPU windows */ + if (MV_TARGET_IS_PEX(target)) + { + continue; + } +#endif + /* If the target attribute is the same as the boot device attribute */ + /* then it's stays disable */ + if (MV_TARGET_IS_AS_BOOT(target)) + { + continue; + } + + if((0 == cpuAddrWinMap[target].addrWin.size) || + (DIS == cpuAddrWinMap[target].enable)) + + { + if (MV_OK != mvCpuIfTargetWinEnable(target, MV_FALSE)) + { + DB(mvOsPrintf("mvCpuIfInit:ERR. mvCpuIfTargetWinEnable fail\n")); + return MV_ERROR; + } + + } + else + { + if (MV_OK != mvCpuIfTargetWinSet(target, &cpuAddrWinMap[target])) + { + DB(mvOsPrintf("mvCpuIfInit:ERR. mvCpuIfTargetWinSet fail\n")); + return MV_ERROR; + } + + addrWin.baseLow = cpuAddrWinMap[target].addrWin.baseLow; + addrWin.baseHigh = cpuAddrWinMap[target].addrWin.baseHigh; + if (0xffffffff == mvAhbToMbusWinRemap(cpuAddrWinMap[target].winNum ,&addrWin)) + { + DB(mvOsPrintf("mvCpuIfInit:WARN. mvAhbToMbusWinRemap can't remap winNum=%d\n", + cpuAddrWinMap[target].winNum)); + } + + + } + } + + return MV_OK; + + +} + + +/******************************************************************************* +* mvCpuIfTargetWinSet - Set CPU-to-peripheral target address window +* +* DESCRIPTION: +* This function sets a peripheral target (e.g. SDRAM bank0, PCI0_MEM0) +* address window, also known as address decode window. +* A new address decode window is set for specified target address window. +* If address decode window parameter structure enables the window, +* the routine will also enable the target window, allowing CPU to access +* the target window. +* +* INPUT: +* target - Peripheral target enumerator. +* pAddrDecWin - CPU target window data structure. +* +* OUTPUT: +* N/A +* +* RETURN: +* MV_OK if CPU target window was set correctly, MV_ERROR in case of +* address window overlapps with other active CPU target window or +* trying to assign 36bit base address while CPU does not support that. +* The function returns MV_NOT_SUPPORTED, if the target is unsupported. +* +*******************************************************************************/ +MV_STATUS mvCpuIfTargetWinSet(MV_TARGET target, MV_CPU_DEC_WIN *pAddrDecWin) +{ + MV_AHB_TO_MBUS_DEC_WIN decWin; + MV_U32 existingWinNum; + MV_DRAM_DEC_WIN addrDecWin; + + target = MV_CHANGE_BOOT_CS(target); + + /* Check parameters */ + if (target >= MAX_TARGETS) + { + mvOsPrintf("mvCpuIfTargetWinSet: target %d is Illigal\n", target); + return MV_ERROR; + } + + /* 2) Check if the requested window overlaps with current windows */ + if (MV_TRUE == cpuTargetWinOverlap(target, &pAddrDecWin->addrWin)) + { + mvOsPrintf("mvCpuIfTargetWinSet: ERR. Target %d overlap\n", target); + return MV_BAD_PARAM; + } + + if (MV_TARGET_IS_DRAM(target)) + { + /* copy relevant data to MV_DRAM_DEC_WIN structure */ + addrDecWin.addrWin.baseHigh = pAddrDecWin->addrWin.baseHigh; + addrDecWin.addrWin.baseLow = pAddrDecWin->addrWin.baseLow; + addrDecWin.addrWin.size = pAddrDecWin->addrWin.size; + addrDecWin.enable = pAddrDecWin->enable; + + + if (mvDramIfWinSet(target,&addrDecWin) != MV_OK); + { + mvOsPrintf("mvCpuIfTargetWinSet: mvDramIfWinSet Failed\n"); + return MV_ERROR; + } + + } + else + { + /* copy relevant data to MV_AHB_TO_MBUS_DEC_WIN structure */ + decWin.addrWin.baseLow = pAddrDecWin->addrWin.baseLow; + decWin.addrWin.baseHigh = pAddrDecWin->addrWin.baseHigh; + decWin.addrWin.size = pAddrDecWin->addrWin.size; + decWin.enable = pAddrDecWin->enable; + decWin.target = target; + + existingWinNum = mvAhbToMbusWinTargetGet(target); + + /* check if there is already another Window configured + for this target */ + if ((existingWinNum < MAX_AHB_TO_MBUS_WINS )&& + (existingWinNum != pAddrDecWin->winNum)) + { + /* if we want to enable the new winow number + passed by the user , then the old one should + be disabled */ + if (MV_TRUE == pAddrDecWin->enable) + { + /* be sure it is disabled */ + mvAhbToMbusWinEnable(existingWinNum , MV_FALSE); + } + } + + if (mvAhbToMbusWinSet(pAddrDecWin->winNum,&decWin) != MV_OK) + { + mvOsPrintf("mvCpuIfTargetWinSet: mvAhbToMbusWinSet Failed\n"); + return MV_ERROR; + } + + } + + return MV_OK; +} + +/******************************************************************************* +* mvCpuIfTargetWinGet - Get CPU-to-peripheral target address window +* +* DESCRIPTION: +* Get the CPU peripheral target address window. +* +* INPUT: +* target - Peripheral target enumerator +* +* OUTPUT: +* pAddrDecWin - CPU target window information data structure. +* +* RETURN: +* MV_OK if target exist, MV_ERROR otherwise. +* +*******************************************************************************/ +MV_STATUS mvCpuIfTargetWinGet(MV_TARGET target, MV_CPU_DEC_WIN *pAddrDecWin) +{ + + MV_U32 winNum=0xffffffff; + MV_AHB_TO_MBUS_DEC_WIN decWin; + MV_DRAM_DEC_WIN addrDecWin; + + target = MV_CHANGE_BOOT_CS(target); + + /* Check parameters */ + if (target >= MAX_TARGETS) + { + mvOsPrintf("mvCpuIfTargetWinGet: target %d is Illigal\n", target); + return MV_ERROR; + } + + if (MV_TARGET_IS_DRAM(target)) + { + if (mvDramIfWinGet(target,&addrDecWin) != MV_OK) + { + mvOsPrintf("mvCpuIfTargetWinGet: Failed to get window target %d\n", + target); + return MV_ERROR; + } + + /* copy relevant data to MV_CPU_DEC_WIN structure */ + pAddrDecWin->addrWin.baseLow = addrDecWin.addrWin.baseLow; + pAddrDecWin->addrWin.baseHigh = addrDecWin.addrWin.baseHigh; + pAddrDecWin->addrWin.size = addrDecWin.addrWin.size; + pAddrDecWin->enable = addrDecWin.enable; + pAddrDecWin->winNum = 0xffffffff; + + } + else + { + /* get the Window number associated with this target */ + + winNum = mvAhbToMbusWinTargetGet(target); + if (winNum >= MAX_AHB_TO_MBUS_WINS) + { + return MV_NO_SUCH; + + } + + if (mvAhbToMbusWinGet(winNum , &decWin) != MV_OK) + { + mvOsPrintf("%s: mvAhbToMbusWinGet Failed at winNum = %d\n", + __FUNCTION__, winNum); + return MV_ERROR; + + } + + /* copy relevant data to MV_CPU_DEC_WIN structure */ + pAddrDecWin->addrWin.baseLow = decWin.addrWin.baseLow; + pAddrDecWin->addrWin.baseHigh = decWin.addrWin.baseHigh; + pAddrDecWin->addrWin.size = decWin.addrWin.size; + pAddrDecWin->enable = decWin.enable; + pAddrDecWin->winNum = winNum; + + } + + + + + return MV_OK; +} + + +/******************************************************************************* +* mvCpuIfTargetWinEnable - Enable/disable a CPU address decode window +* +* DESCRIPTION: +* This function enable/disable a CPU address decode window. +* if parameter 'enable' == MV_TRUE the routine will enable the +* window, thus enabling CPU accesses (before enabling the window it is +* tested for overlapping). Otherwise, the window will be disabled. +* +* INPUT: +* target - Peripheral target enumerator. +* enable - Enable/disable parameter. +* +* OUTPUT: +* N/A +* +* RETURN: +* MV_ERROR if protection window number was wrong, or the window +* overlapps other target window. +* +*******************************************************************************/ +MV_STATUS mvCpuIfTargetWinEnable(MV_TARGET target,MV_BOOL enable) +{ + MV_U32 winNum, temp; + MV_CPU_DEC_WIN addrDecWin; + + target = MV_CHANGE_BOOT_CS(target); + + /* Check parameters */ + if (target >= MAX_TARGETS) + { + mvOsPrintf("mvCpuIfTargetWinEnable: target %d is Illigal\n", target); + return MV_ERROR; + } + + /* get the window and check if it exist */ + temp = mvCpuIfTargetWinGet(target, &addrDecWin); + if (MV_NO_SUCH == temp) + { + return (enable? MV_ERROR: MV_OK); + } + else if( MV_OK != temp) + { + mvOsPrintf("%s: ERR. Getting target %d failed.\n",__FUNCTION__, target); + return MV_ERROR; + } + + + /* check overlap */ + + if (MV_TRUE == enable) + { + if (MV_TRUE == cpuTargetWinOverlap(target, &addrDecWin.addrWin)) + { + DB(mvOsPrintf("%s: ERR. Target %d overlap\n",__FUNCTION__, target)); + return MV_ERROR; + } + + } + + + if (MV_TARGET_IS_DRAM(target)) + { + if (mvDramIfWinEnable(target , enable) != MV_OK) + { + mvOsPrintf("mvCpuIfTargetWinGet: mvDramIfWinEnable Failed at \n"); + return MV_ERROR; + + } + + } + else + { + /* get the Window number associated with this target */ + + winNum = mvAhbToMbusWinTargetGet(target); + + if (winNum >= MAX_AHB_TO_MBUS_WINS) + { + return (enable? MV_ERROR: MV_OK); + } + + if (mvAhbToMbusWinEnable(winNum , enable) != MV_OK) + { + mvOsPrintf("mvCpuIfTargetWinGet: Failed to enable window = %d\n", + winNum); + return MV_ERROR; + + } + + } + + return MV_OK; +} + + +/******************************************************************************* +* mvCpuIfTargetWinSizeGet - Get CPU target address window size +* +* DESCRIPTION: +* Get the size of CPU-to-peripheral target window. +* +* INPUT: +* target - Peripheral target enumerator +* +* OUTPUT: +* None. +* +* RETURN: +* 32bit size. Function also returns '0' if window is closed. +* Function returns 0xFFFFFFFF in case of an error. +* +*******************************************************************************/ +MV_U32 mvCpuIfTargetWinSizeGet(MV_TARGET target) +{ + MV_CPU_DEC_WIN addrDecWin; + + target = MV_CHANGE_BOOT_CS(target); + + /* Check parameters */ + if (target >= MAX_TARGETS) + { + mvOsPrintf("mvCpuIfTargetWinSizeGet: target %d is Illigal\n", target); + return 0; + } + + /* Get the winNum window */ + if (MV_OK != mvCpuIfTargetWinGet(target, &addrDecWin)) + { + mvOsPrintf("mvCpuIfTargetWinSizeGet:ERR. Getting target %d failed.\n", + target); + return 0; + } + + /* Check if window is enabled */ + if (addrDecWin.enable == MV_TRUE) + { + return (addrDecWin.addrWin.size); + } + else + { + return 0; /* Window disabled. return 0 */ + } +} + +/******************************************************************************* +* mvCpuIfTargetWinBaseLowGet - Get CPU target address window base low +* +* DESCRIPTION: +* CPU-to-peripheral target address window base is constructed of +* two parts: Low and high. +* This function gets the CPU peripheral target low base address. +* +* INPUT: +* target - Peripheral target enumerator +* +* OUTPUT: +* None. +* +* RETURN: +* 32bit low base address. +* +*******************************************************************************/ +MV_U32 mvCpuIfTargetWinBaseLowGet(MV_TARGET target) +{ + MV_CPU_DEC_WIN addrDecWin; + + target = MV_CHANGE_BOOT_CS(target); + + /* Check parameters */ + if (target >= MAX_TARGETS) + { + mvOsPrintf("mvCpuIfTargetWinBaseLowGet: target %d is Illigal\n", target); + return 0xffffffff; + } + + /* Get the target window */ + if (MV_OK != mvCpuIfTargetWinGet(target, &addrDecWin)) + { + mvOsPrintf("mvCpuIfTargetWinBaseLowGet:ERR. Getting target %d failed.\n", + target); + return 0xffffffff; + } + + if (MV_FALSE == addrDecWin.enable) + { + return 0xffffffff; + } + return (addrDecWin.addrWin.baseLow); +} + +/******************************************************************************* +* mvCpuIfTargetWinBaseHighGet - Get CPU target address window base high +* +* DESCRIPTION: +* CPU-to-peripheral target address window base is constructed of +* two parts: Low and high. +* This function gets the CPU peripheral target high base address. +* +* INPUT: +* target - Peripheral target enumerator +* +* OUTPUT: +* None. +* +* RETURN: +* 32bit high base address. +* +*******************************************************************************/ +MV_U32 mvCpuIfTargetWinBaseHighGet(MV_TARGET target) +{ + MV_CPU_DEC_WIN addrDecWin; + + target = MV_CHANGE_BOOT_CS(target); + + /* Check parameters */ + if (target >= MAX_TARGETS) + { + mvOsPrintf("mvCpuIfTargetWinBaseLowGet: target %d is Illigal\n", target); + return 0xffffffff; + } + + /* Get the target window */ + if (MV_OK != mvCpuIfTargetWinGet(target, &addrDecWin)) + { + mvOsPrintf("mvCpuIfTargetWinBaseHighGet:ERR. Getting target %d failed.\n", + target); + return 0xffffffff; + } + + if (MV_FALSE == addrDecWin.enable) + { + return 0; + } + + return (addrDecWin.addrWin.baseHigh); +} + +#if defined(MV_INCLUDE_PEX) +/******************************************************************************* +* mvCpuIfPexRemap - Set CPU remap register for address windows. +* +* DESCRIPTION: +* +* INPUT: +* pexTarget - Peripheral target enumerator. Must be a PEX target. +* pAddrDecWin - CPU target window information data structure. +* Note that caller has to fill in the base field only. The +* size field is ignored. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_ERROR if target is not a PEX one, MV_OK otherwise. +* +*******************************************************************************/ +MV_U32 mvCpuIfPexRemap(MV_TARGET pexTarget, MV_ADDR_WIN *pAddrDecWin) +{ + MV_U32 winNum; + + /* Check parameters */ + + if (mvCtrlPexMaxIfGet() > 1) + { + if ((!MV_TARGET_IS_PEX1(pexTarget))&&(!MV_TARGET_IS_PEX0(pexTarget))) + { + mvOsPrintf("mvCpuIfPexRemap: target %d is Illigal\n",pexTarget); + return 0xffffffff; + } + + } + else + { + if (!MV_TARGET_IS_PEX0(pexTarget)) + { + mvOsPrintf("mvCpuIfPexRemap: target %d is Illigal\n",pexTarget); + return 0xffffffff; + } + + } + + /* get the Window number associated with this target */ + winNum = mvAhbToMbusWinTargetGet(pexTarget); + + if (winNum >= MAX_AHB_TO_MBUS_WINS) + { + mvOsPrintf("mvCpuIfPexRemap: mvAhbToMbusWinTargetGet Failed\n"); + return 0xffffffff; + + } + + return mvAhbToMbusWinRemap(winNum , pAddrDecWin); +} + +#endif + +#if defined(MV_INCLUDE_PCI) +/******************************************************************************* +* mvCpuIfPciRemap - Set CPU remap register for address windows. +* +* DESCRIPTION: +* +* INPUT: +* pciTarget - Peripheral target enumerator. Must be a PCI target. +* pAddrDecWin - CPU target window information data structure. +* Note that caller has to fill in the base field only. The +* size field is ignored. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_ERROR if target is not a PCI one, MV_OK otherwise. +* +*******************************************************************************/ +MV_U32 mvCpuIfPciRemap(MV_TARGET pciTarget, MV_ADDR_WIN *pAddrDecWin) +{ + MV_U32 winNum; + + /* Check parameters */ + if (!MV_TARGET_IS_PCI(pciTarget)) + { + mvOsPrintf("mvCpuIfPciRemap: target %d is Illigal\n",pciTarget); + return 0xffffffff; + } + + /* get the Window number associated with this target */ + winNum = mvAhbToMbusWinTargetGet(pciTarget); + + if (winNum >= MAX_AHB_TO_MBUS_WINS) + { + mvOsPrintf("mvCpuIfPciRemap: mvAhbToMbusWinTargetGet Failed\n"); + return 0xffffffff; + + } + + return mvAhbToMbusWinRemap(winNum , pAddrDecWin); +} +#endif /* MV_INCLUDE_PCI */ + + +/******************************************************************************* +* mvCpuIfPciIfRemap - Set CPU remap register for address windows. +* +* DESCRIPTION: +* +* INPUT: +* pciTarget - Peripheral target enumerator. Must be a PCI target. +* pAddrDecWin - CPU target window information data structure. +* Note that caller has to fill in the base field only. The +* size field is ignored. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_ERROR if target is not a PCI one, MV_OK otherwise. +* +*******************************************************************************/ +MV_U32 mvCpuIfPciIfRemap(MV_TARGET pciIfTarget, MV_ADDR_WIN *pAddrDecWin) +{ +#if defined(MV_INCLUDE_PEX) + if (MV_TARGET_IS_PEX(pciIfTarget)) + { + return mvCpuIfPexRemap(pciIfTarget,pAddrDecWin); + } +#endif +#if defined(MV_INCLUDE_PCI) + + if (MV_TARGET_IS_PCI(pciIfTarget)) + { + return mvCpuIfPciRemap(pciIfTarget,pAddrDecWin); + } +#endif + return 0; +} + + + +/******************************************************************************* +* mvCpuIfTargetOfBaseAddressGet - Get the target according to base address +* +* DESCRIPTION: +* +* INPUT: +* baseAddress - base address to be checked +* +* OUTPUT: +* None. +* +* RETURN: +* the target number that baseAddress belongs to or MAX_TARGETS is not +* found +* +*******************************************************************************/ + +MV_TARGET mvCpuIfTargetOfBaseAddressGet(MV_U32 baseAddress) +{ + MV_CPU_DEC_WIN win; + MV_U32 target; + + for( target = 0; target < MAX_TARGETS; target++ ) + { + if( mvCpuIfTargetWinGet( target, &win ) == MV_OK ) + { + if( win.enable ) + { + if ((baseAddress >= win.addrWin.baseLow) && + (baseAddress < win.addrWin.baseLow + win.addrWin.size)) break; + } + } + else return MAX_TARGETS; + + } + + return target; +} +/******************************************************************************* +* cpuTargetWinOverlap - Detect CPU address decode windows overlapping +* +* DESCRIPTION: +* An unpredicted behaviur is expected in case CPU address decode +* windows overlapps. +* This function detects CPU address decode windows overlapping of a +* specified target. The function does not check the target itself for +* overlapping. The function also skipps disabled address decode windows. +* +* INPUT: +* target - Peripheral target enumerator. +* pAddrDecWin - An address decode window struct. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_TRUE if the given address window overlaps current address +* decode map, MV_FALSE otherwise. +* +*******************************************************************************/ +static MV_BOOL cpuTargetWinOverlap(MV_TARGET target, MV_ADDR_WIN *pAddrWin) +{ + MV_U32 targetNum; + MV_CPU_DEC_WIN addrDecWin; + MV_STATUS status; + + + for(targetNum = 0; targetNum < MAX_TARGETS; targetNum++) + { +#if defined(MV_RUN_FROM_FLASH) + if(MV_TARGET_IS_AS_BOOT(target)) + { + if (MV_CHANGE_BOOT_CS(targetNum) == target) + continue; + } +#endif /* MV_RUN_FROM_FLASH */ + + /* don't check our target or illegal targets */ + if (targetNum == target) + { + continue; + } + + /* Get window parameters */ + status = mvCpuIfTargetWinGet(targetNum, &addrDecWin); + if(MV_NO_SUCH == status) + { + continue; + } + if(MV_OK != status) + { + DB(mvOsPrintf("cpuTargetWinOverlap: ERR. TargetWinGet failed\n")); + return MV_TRUE; + } + + /* Do not check disabled windows */ + if (MV_FALSE == addrDecWin.enable) + { + continue; + } + + if(MV_TRUE == ctrlWinOverlapTest(pAddrWin, &addrDecWin.addrWin)) + { + DB(mvOsPrintf( + "cpuTargetWinOverlap: Required target %d overlap current %d\n", + target, targetNum)); + return MV_TRUE; + } + } + + return MV_FALSE; + +} + +/******************************************************************************* +* mvCpuIfAddDecShow - Print the CPU address decode map. +* +* DESCRIPTION: +* This function print the CPU address decode map. +* +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* None. +* +*******************************************************************************/ +MV_VOID mvCpuIfAddDecShow(MV_VOID) +{ + MV_CPU_DEC_WIN win; + MV_U32 target; + mvOsOutput( "\n" ); + mvOsOutput( "CPU Interface\n" ); + mvOsOutput( "-------------\n" ); + + for( target = 0; target < MAX_TARGETS; target++ ) + { + + memset( &win, 0, sizeof(MV_CPU_DEC_WIN) ); + + mvOsOutput( "%s ",mvCtrlTargetNameGet(target)); + mvOsOutput( "...." ); + + if( mvCpuIfTargetWinGet( target, &win ) == MV_OK ) + { + if( win.enable ) + { + mvOsOutput( "base %08x, ", win.addrWin.baseLow ); + mvSizePrint( win.addrWin.size ); + mvOsOutput( "\n" ); + + } + else + mvOsOutput( "disable\n" ); + } + else if( mvCpuIfTargetWinGet( target, &win ) == MV_NO_SUCH ) + { + mvOsOutput( "no such\n" ); + } + } +} + +/******************************************************************************* +* mvCpuIfEnablePex - Enable PCI Express. +* +* DESCRIPTION: +* This function Enable PCI Express. +* +* INPUT: +* pexIf - PEX interface number. +* pexType - MV_PEX_ROOT_COMPLEX - root complex device +* MV_PEX_END_POINT - end point device +* OUTPUT: +* None. +* +* RETURN: +* None. +* +*******************************************************************************/ +#if defined(MV_INCLUDE_PEX) +MV_VOID mvCpuIfEnablePex(MV_U32 pexIf, MV_PEX_TYPE pexType) +{ + /* Set pex mode incase S@R not exist */ + if( pexType == MV_PEX_END_POINT) + { + MV_REG_BIT_RESET(PEX_CTRL_REG(pexIf),PXCR_DEV_TYPE_CTRL_MASK); + /* Change pex mode in capability reg */ + MV_REG_BIT_RESET(PEX_CFG_DIRECT_ACCESS(pexIf,PEX_CAPABILITY_REG), BIT22); + MV_REG_BIT_SET(PEX_CFG_DIRECT_ACCESS(pexIf,PEX_CAPABILITY_REG), BIT20); + + } + else + { + MV_REG_BIT_SET(PEX_CTRL_REG(pexIf),PXCR_DEV_TYPE_CTRL_MASK); + } + + /* CPU config register Pex enable */ + MV_REG_BIT_SET(CPU_CTRL_STAT_REG,CCSR_PCI_ACCESS_MASK); +} +#endif + + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvCpuIf.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvCpuIf.h new file mode 100644 index 0000000..224ed07 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvCpuIf.h @@ -0,0 +1,120 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + + +#ifndef __INCmvCpuIfh +#define __INCmvCpuIfh + +/* includes */ +#include "ctrlEnv/mvCtrlEnvLib.h" +#include "ctrlEnv/sys/mvCpuIfRegs.h" +#include "ctrlEnv/sys/mvAhbToMbus.h" +#include "ddr2/mvDramIf.h" +#include "ctrlEnv/sys/mvSysDram.h" +#if defined(MV_INCLUDE_PEX) +#include "pex/mvPex.h" +#endif + +/* defines */ + +/* typedefs */ +/* This structure describes CPU interface address decode window */ +typedef struct _mvCpuIfDecWin +{ + MV_ADDR_WIN addrWin; /* An address window*/ + MV_U32 winNum; /* Window Number in the AHB To Mbus bridge */ + MV_BOOL enable; /* Address decode window is enabled/disabled */ + +}MV_CPU_DEC_WIN; + + + +/* mvCpuIfLib.h API list */ + +/* mvCpuIfLib.h API list */ + +MV_STATUS mvCpuIfInit(MV_CPU_DEC_WIN *cpuAddrWinMap); +MV_STATUS mvCpuIfTargetWinSet(MV_TARGET target, MV_CPU_DEC_WIN *pAddrDecWin); +MV_STATUS mvCpuIfTargetWinGet(MV_TARGET target, MV_CPU_DEC_WIN *pAddrDecWin); +MV_STATUS mvCpuIfTargetWinEnable(MV_TARGET target,MV_BOOL enable); +MV_U32 mvCpuIfTargetWinSizeGet(MV_TARGET target); +MV_U32 mvCpuIfTargetWinBaseLowGet(MV_TARGET target); +MV_U32 mvCpuIfTargetWinBaseHighGet(MV_TARGET target); +MV_TARGET mvCpuIfTargetOfBaseAddressGet(MV_U32 baseAddress); +#if defined(MV_INCLUDE_PEX) +MV_U32 mvCpuIfPexRemap(MV_TARGET pexTarget, MV_ADDR_WIN *pAddrDecWin); +MV_VOID mvCpuIfEnablePex(MV_U32 pexIf, MV_PEX_TYPE pexType); +#endif +#if defined(MV_INCLUDE_PCI) +MV_U32 mvCpuIfPciRemap(MV_TARGET pciTarget, MV_ADDR_WIN *pAddrDecWin); +#endif +MV_U32 mvCpuIfPciIfRemap(MV_TARGET pciTarget, MV_ADDR_WIN *pAddrDecWin); + +MV_VOID mvCpuIfAddDecShow(MV_VOID); + +#if defined(MV88F6281) +MV_STATUS mvCpuIfBridgeReorderWAInit(void); +#endif + +#endif /* __INCmvCpuIfh */ diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvCpuIfInit.S b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvCpuIfInit.S new file mode 100644 index 0000000..b7efda0 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvCpuIfInit.S @@ -0,0 +1,163 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#define MV_ASMLANGUAGE +#include "mvOsAsm.h" +#include "mvDeviceId.h" +#include "mvCtrlEnvRegs.h" +#include "mvCpuIfRegs.h" +#include "mvCtrlEnvAsm.h" + + +/******************************************************************************* +* mvCpuIfPreInit - Make early initialization of CPU interface. +* +* DESCRIPTION: +* The function will initialize the CPU interface parameters that must +* be initialize before any BUS activity towards the DDR interface, +* which means it must be executed from ROM. Because of that, the function +* is implemented in assembly code. +* The function configure the following CPU config register parameters: +* 1) CPU2MbusLTickDrv +* 2) CPU2MbusLTickSample. +* NOTE: This function must be called AFTER the internal register +* base is modified to INTER_REGS_BASE. +* +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* None. +* +* r11 holds return function address. +*******************************************************************************/ +#define MV88F6281_PCKG_OPT 2 +#define MV88F6192_PCKG_OPT 1 +#define MV88F6180_PCKG_OPT 0 + + .globl _mvCpuIfPreInit +_mvCpuIfPreInit: + + mov r11, LR /* Save link register */ + + /* Read device ID */ + MV_CTRL_MODEL_GET_ASM(r4, r5); + + /* goto calcConfigReg if device is 6281 */ + ldr r5, =MV88F6281_PCKG_OPT + cmp r4, r5 + beq calcConfigReg + + /* goto calcConfigReg if device is 6192/6190 */ + ldr r5, =MV88F6192_PCKG_OPT + cmp r4, r5 + beq calcConfigReg + + /* Else 6180 */ + /* Get the "sample on reset" register */ + MV_REG_READ_ASM (r4, r5, MPP_SAMPLE_AT_RESET) + ldr r5, =MSAR_CPUCLCK_MASK_6180 + and r5, r4, r5 + mov r5, r5, lsr #MSAR_CPUCLCK_OFFS_6180 + + ldr r4, =CPU_2_MBUSL_DDR_CLK_1x3 + cmp r5, #CPU_2_DDR_CLK_1x3_1 + beq setConfigReg + + ldr r4, =CPU_2_MBUSL_DDR_CLK_1x4 + cmp r5, #CPU_2_DDR_CLK_1x4_1 + beq setConfigReg + b setConfigReg + +calcConfigReg: + /* Get the "sample on reset" register */ + MV_REG_READ_ASM (r4, r5, MPP_SAMPLE_AT_RESET) + ldr r5, =MSAR_DDRCLCK_RTIO_MASK + and r5, r4, r5 + mov r5, r5, lsr #MSAR_DDRCLCK_RTIO_OFFS + + ldr r4, =CPU_2_MBUSL_DDR_CLK_1x3 + cmp r5, #CPU_2_DDR_CLK_1x3 + beq setConfigReg + + ldr r4, =CPU_2_MBUSL_DDR_CLK_1x4 + cmp r5, #CPU_2_DDR_CLK_1x4 + beq setConfigReg + + /* Else */ + ldr r4, =0 + +setConfigReg: + /* Read CPU Config register */ + MV_REG_READ_ASM (r7, r5, CPU_CONFIG_REG) + ldr r5, =~(CCR_CPU_2_MBUSL_TICK_DRV_MASK | CCR_CPU_2_MBUSL_TICK_SMPL_MASK) + and r7, r7, r5 /* Clear register fields */ + orr r7, r7, r4 /* Set the values according to the findings */ + MV_REG_WRITE_ASM (r7, r5, CPU_CONFIG_REG) + +done: + mov PC, r11 /* r11 is saved link register */ diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvCpuIfRegs.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvCpuIfRegs.h new file mode 100644 index 0000000..8cfeee2 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvCpuIfRegs.h @@ -0,0 +1,304 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + + +#ifndef __INCmvCpuIfRegsh +#define __INCmvCpuIfRegsh + +/****************************************/ +/* ARM Control and Status Registers Map */ +/****************************************/ + +#define CPU_CONFIG_REG 0x20100 +#define CPU_CTRL_STAT_REG 0x20104 +#define CPU_RSTOUTN_MASK_REG 0x20108 +#define CPU_SYS_SOFT_RST_REG 0x2010C +#define CPU_AHB_MBUS_CAUSE_INT_REG 0x20110 +#define CPU_AHB_MBUS_MASK_INT_REG 0x20114 +#define CPU_FTDLL_CONFIG_REG 0x20120 +#define CPU_L2_CONFIG_REG 0x20128 + + + +/* ARM Configuration register */ +/* CPU_CONFIG_REG (CCR) */ + + +/* Reset vector location */ +#define CCR_VEC_INIT_LOC_OFFS 1 +#define CCR_VEC_INIT_LOC_MASK BIT1 +/* reset at 0x00000000 */ +#define CCR_VEC_INIT_LOC_0000 (0 << CCR_VEC_INIT_LOC_OFFS) +/* reset at 0xFFFF0000 */ +#define CCR_VEC_INIT_LOC_FF00 (1 << CCR_VEC_INIT_LOC_OFFS) + + +#define CCR_AHB_ERROR_PROP_OFFS 2 +#define CCR_AHB_ERROR_PROP_MASK BIT2 +/* Erros are not propogated to AHB */ +#define CCR_AHB_ERROR_PROP_NO_INDICATE (0 << CCR_AHB_ERROR_PROP_OFFS) +/* Erros are propogated to AHB */ +#define CCR_AHB_ERROR_PROP_INDICATE (1 << CCR_AHB_ERROR_PROP_OFFS) + + +#define CCR_ENDIAN_INIT_OFFS 3 +#define CCR_ENDIAN_INIT_MASK BIT3 +#define CCR_ENDIAN_INIT_LITTLE (0 << CCR_ENDIAN_INIT_OFFS) +#define CCR_ENDIAN_INIT_BIG (1 << CCR_ENDIAN_INIT_OFFS) + + +#define CCR_INCR_EN_OFFS 4 +#define CCR_INCR_EN_MASK BIT4 +#define CCR_INCR_EN BIT4 + + +#define CCR_NCB_BLOCKING_OFFS 5 +#define CCR_NCB_BLOCKING_MASK (1 << CCR_NCB_BLOCKING_OFFS) +#define CCR_NCB_BLOCKING_NON (0 << CCR_NCB_BLOCKING_OFFS) +#define CCR_NCB_BLOCKING_EN (1 << CCR_NCB_BLOCKING_OFFS) + +#define CCR_CPU_2_MBUSL_TICK_DRV_OFFS 8 +#define CCR_CPU_2_MBUSL_TICK_DRV_MASK (0xF << CCR_CPU_2_MBUSL_TICK_DRV_OFFS) +#define CCR_CPU_2_MBUSL_TICK_SMPL_OFFS 12 +#define CCR_CPU_2_MBUSL_TICK_SMPL_MASK (0xF << CCR_CPU_2_MBUSL_TICK_SMPL_OFFS) +#define CCR_ICACH_PREF_BUF_ENABLE BIT16 +#define CCR_DCACH_PREF_BUF_ENABLE BIT17 + +/* Ratio options for CPU to DDR for 6281/6192/6190 */ +#define CPU_2_DDR_CLK_1x3 4 +#define CPU_2_DDR_CLK_1x4 6 + +/* Ratio options for CPU to DDR for 6281 only */ +#define CPU_2_DDR_CLK_2x9 7 +#define CPU_2_DDR_CLK_1x5 8 +#define CPU_2_DDR_CLK_1x6 9 + +/* Ratio options for CPU to DDR for 6180 only */ +#define CPU_2_DDR_CLK_1x3_1 0x5 +#define CPU_2_DDR_CLK_1x4_1 0x6 + +/* Default values for CPU to Mbus-L DDR Interface Tick Driver and */ +/* CPU to Mbus-L Tick Sample fields in CPU config register */ + +#define TICK_DRV_1x1 0 +#define TICK_DRV_1x2 0 +#define TICK_DRV_1x3 1 +#define TICK_DRV_1x4 2 +#define TICK_SMPL_1x1 0 +#define TICK_SMPL_1x2 1 +#define TICK_SMPL_1x3 0 +#define TICK_SMPL_1x4 0 + +#define CPU_2_MBUSL_DDR_CLK_1x2 \ + ((TICK_DRV_1x2 << CCR_CPU_2_MBUSL_TICK_DRV_OFFS) | \ + (TICK_SMPL_1x2 << CCR_CPU_2_MBUSL_TICK_SMPL_OFFS)) +#define CPU_2_MBUSL_DDR_CLK_1x3 \ + ((TICK_DRV_1x3 << CCR_CPU_2_MBUSL_TICK_DRV_OFFS) | \ + (TICK_SMPL_1x3 << CCR_CPU_2_MBUSL_TICK_SMPL_OFFS)) +#define CPU_2_MBUSL_DDR_CLK_1x4 \ + ((TICK_DRV_1x4 << CCR_CPU_2_MBUSL_TICK_DRV_OFFS) | \ + (TICK_SMPL_1x4 << CCR_CPU_2_MBUSL_TICK_SMPL_OFFS)) + +/* ARM Control and Status register */ +/* CPU_CTRL_STAT_REG (CCSR) */ + + +/* +This is used to block PCI express\PCI from access Socrates/Feroceon GP +while ARM boot is still in progress +*/ + +#define CCSR_PCI_ACCESS_OFFS 0 +#define CCSR_PCI_ACCESS_MASK BIT0 +#define CCSR_PCI_ACCESS_ENABLE (0 << CCSR_PCI_ACCESS_OFFS) +#define CCSR_PCI_ACCESS_DISBALE (1 << CCSR_PCI_ACCESS_OFFS) + +#define CCSR_ARM_RESET BIT1 +#define CCSR_SELF_INT BIT2 +#define CCSR_BIG_ENDIAN BIT15 + + +/* RSTOUTn Mask Register */ +/* CPU_RSTOUTN_MASK_REG (CRMR) */ + +#define CRMR_PEX_RST_OUT_OFFS 0 +#define CRMR_PEX_RST_OUT_MASK BIT0 +#define CRMR_PEX_RST_OUT_ENABLE (1 << CRMR_PEX_RST_OUT_OFFS) +#define CRMR_PEX_RST_OUT_DISABLE (0 << CRMR_PEX_RST_OUT_OFFS) + +#define CRMR_WD_RST_OUT_OFFS 1 +#define CRMR_WD_RST_OUT_MASK BIT1 +#define CRMR_WD_RST_OUT_ENABLE (1 << CRMR_WD_RST_OUT_OFFS) +#define CRMR_WD_RST_OUT_DISBALE (0 << CRMR_WD_RST_OUT_OFFS) + +#define CRMR_SOFT_RST_OUT_OFFS 2 +#define CRMR_SOFT_RST_OUT_MASK BIT2 +#define CRMR_SOFT_RST_OUT_ENABLE (1 << CRMR_SOFT_RST_OUT_OFFS) +#define CRMR_SOFT_RST_OUT_DISBALE (0 << CRMR_SOFT_RST_OUT_OFFS) + +/* System Software Reset Register */ +/* CPU_SYS_SOFT_RST_REG (CSSRR) */ + +#define CSSRR_SYSTEM_SOFT_RST BIT0 + +/* AHB to Mbus Bridge Interrupt Cause Register*/ +/* CPU_AHB_MBUS_CAUSE_INT_REG (CAMCIR) */ + +#define CAMCIR_ARM_SELF_INT BIT0 +#define CAMCIR_ARM_TIMER0_INT_REQ BIT1 +#define CAMCIR_ARM_TIMER1_INT_REQ BIT2 +#define CAMCIR_ARM_WD_TIMER_INT_REQ BIT3 + + +/* AHB to Mbus Bridge Interrupt Mask Register*/ +/* CPU_AHB_MBUS_MASK_INT_REG (CAMMIR) */ + +#define CAMCIR_ARM_SELF_INT_OFFS 0 +#define CAMCIR_ARM_SELF_INT_MASK BIT0 +#define CAMCIR_ARM_SELF_INT_EN (1 << CAMCIR_ARM_SELF_INT_OFFS) +#define CAMCIR_ARM_SELF_INT_DIS (0 << CAMCIR_ARM_SELF_INT_OFFS) + + +#define CAMCIR_ARM_TIMER0_INT_REQ_OFFS 1 +#define CAMCIR_ARM_TIMER0_INT_REQ_MASK BIT1 +#define CAMCIR_ARM_TIMER0_INT_REQ_EN (1 << CAMCIR_ARM_TIMER0_INT_REQ_OFFS) +#define CAMCIR_ARM_TIMER0_INT_REQ_DIS (0 << CAMCIR_ARM_TIMER0_INT_REQ_OFFS) + +#define CAMCIR_ARM_TIMER1_INT_REQ_OFFS 2 +#define CAMCIR_ARM_TIMER1_INT_REQ_MASK BIT2 +#define CAMCIR_ARM_TIMER1_INT_REQ_EN (1 << CAMCIR_ARM_TIMER1_INT_REQ_OFFS) +#define CAMCIR_ARM_TIMER1_INT_REQ_DIS (0 << CAMCIR_ARM_TIMER1_INT_REQ_OFFS) + +#define CAMCIR_ARM_WD_TIMER_INT_REQ_OFFS 3 +#define CAMCIR_ARM_WD_TIMER_INT_REQ_MASK BIT3 +#define CAMCIR_ARM_WD_TIMER_INT_REQ_EN (1 << CAMCIR_ARM_WD_TIMER_INT_REQ_OFFS) +#define CAMCIR_ARM_WD_TIMER_INT_REQ_DIS (0 << CAMCIR_ARM_WD_TIMER_INT_REQ_OFFS) + +/* CPU FTDLL Config register (CFCR) fields */ +#define CFCR_FTDLL_ICACHE_TAG_OFFS 0 +#define CFCR_FTDLL_ICACHE_TAG_MASK (0x7F << CFCR_FTDLL_ICACHE_TAG_OFFS) +#define CFCR_FTDLL_DCACHE_TAG_OFFS 8 +#define CFCR_FTDLL_DCACHE_TAG_MASK (0x7F << CFCR_FTDLL_DCACHE_TAG_OFFS) +#define CFCR_FTDLL_OVERWRITE_ENABLE (1 << 15) +/* For Orion 2 D2 only */ +#define CFCR_MRVL_CPU_ID_OFFS 16 +#define CFCR_MRVL_CPU_ID_MASK (0x1 << CFCR_MRVL_CPU_ID_OFFS) +#define CFCR_ARM_CPU_ID (0x0 << CFCR_MRVL_CPU_ID_OFFS) +#define CFCR_MRVL_CPU_ID (0x1 << CFCR_MRVL_CPU_ID_OFFS) +#define CFCR_VFP_SUB_ARC_NUM_OFFS 7 +#define CFCR_VFP_SUB_ARC_NUM_MASK (0x1 << CFCR_VFP_SUB_ARC_NUM_OFFS) +#define CFCR_VFP_SUB_ARC_NUM_1 (0x0 << CFCR_VFP_SUB_ARC_NUM_OFFS) +#define CFCR_VFP_SUB_ARC_NUM_2 (0x1 << CFCR_VFP_SUB_ARC_NUM_OFFS) + +/* CPU_L2_CONFIG_REG fields */ +#ifdef MV_CPU_LE +#define CL2CR_L2_ECC_EN_OFFS 2 +#define CL2CR_L2_WT_MODE_OFFS 4 +#else +#define CL2CR_L2_ECC_EN_OFFS 26 +#define CL2CR_L2_WT_MODE_OFFS 28 +#endif + +#define CL2CR_L2_ECC_EN_MASK (1 << CL2CR_L2_ECC_EN_OFFS) +#define CL2CR_L2_WT_MODE_MASK (1 << CL2CR_L2_WT_MODE_OFFS) + +/*******************************************/ +/* Main Interrupt Controller Registers Map */ +/*******************************************/ + +#define CPU_MAIN_INT_CAUSE_REG 0x20200 +#define CPU_MAIN_IRQ_MASK_REG 0x20204 +#define CPU_MAIN_FIQ_MASK_REG 0x20208 +#define CPU_ENPOINT_MASK_REG 0x2020C +#define CPU_MAIN_INT_CAUSE_HIGH_REG 0x20210 +#define CPU_MAIN_IRQ_MASK_HIGH_REG 0x20214 +#define CPU_MAIN_FIQ_MASK_HIGH_REG 0x20218 +#define CPU_ENPOINT_MASK_HIGH_REG 0x2021C + + +/*******************************************/ +/* ARM Doorbell Registers Map */ +/*******************************************/ + +#define CPU_HOST_TO_ARM_DRBL_REG 0x20400 +#define CPU_HOST_TO_ARM_MASK_REG 0x20404 +#define CPU_ARM_TO_HOST_DRBL_REG 0x20408 +#define CPU_ARM_TO_HOST_MASK_REG 0x2040C + + + +/* CPU control register map */ +/* Set bits means value is about to change according to new value */ +#define CPU_CONFIG_DEFAULT_MASK (CCR_VEC_INIT_LOC_MASK | CCR_AHB_ERROR_PROP_MASK) + +#define CPU_CONFIG_DEFAULT (CCR_VEC_INIT_LOC_FF00) + +/* CPU Control and status defaults */ +#define CPU_CTRL_STAT_DEFAULT_MASK (CCSR_PCI_ACCESS_MASK) + + +#define CPU_CTRL_STAT_DEFAULT (CCSR_PCI_ACCESS_ENABLE) + +#endif /* __INCmvCpuIfRegsh */ + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysAudio.c b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysAudio.c new file mode 100644 index 0000000..769475f --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysAudio.c @@ -0,0 +1,324 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ +#include "mvSysAudio.h" + +/******************************************************************************* +* mvAudioWinSet - Set AUDIO target address window +* +* DESCRIPTION: +* This function sets a peripheral target (e.g. SDRAM bank0, PCI_MEM0) +* address window, also known as address decode window. +* After setting this target window, the AUDIO will be able to access the +* target within the address window. +* +* INPUT: +* winNum - AUDIO target address decode window number. +* pAddrDecWin - AUDIO target window data structure. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_ERROR if address window overlapps with other address decode windows. +* MV_BAD_PARAM if base address is invalid parameter or target is +* unknown. +* +*******************************************************************************/ +MV_STATUS mvAudioWinSet(MV_U32 winNum, MV_AUDIO_DEC_WIN *pAddrDecWin) +{ + MV_TARGET_ATTRIB targetAttribs; + MV_DEC_REGS decRegs; + + /* Parameter checking */ + if (winNum >= MV_AUDIO_MAX_ADDR_DECODE_WIN) + { + mvOsPrintf("%s: ERR. Invalid win num %d\n",__FUNCTION__, winNum); + return MV_BAD_PARAM; + } + + /* check if address is aligned to the size */ + if(MV_IS_NOT_ALIGN(pAddrDecWin->addrWin.baseLow, pAddrDecWin->addrWin.size)) + { + mvOsPrintf("mvAudioWinSet:Error setting AUDIO window %d to "\ + "target %s.\nAddress 0x%08x is unaligned to size 0x%x.\n", + winNum, + mvCtrlTargetNameGet(pAddrDecWin->target), + pAddrDecWin->addrWin.baseLow, + pAddrDecWin->addrWin.size); + return MV_ERROR; + } + + decRegs.baseReg = 0; + decRegs.sizeReg = 0; + + if (MV_OK != mvCtrlAddrDecToReg(&(pAddrDecWin->addrWin),&decRegs)) + { + mvOsPrintf("%s: mvCtrlAddrDecToReg Failed\n", __FUNCTION__); + return MV_ERROR; + } + + mvCtrlAttribGet(pAddrDecWin->target, &targetAttribs); + + /* set attributes */ + decRegs.sizeReg &= ~MV_AUDIO_WIN_ATTR_MASK; + decRegs.sizeReg |= (targetAttribs.attrib << MV_AUDIO_WIN_ATTR_OFFSET); + + /* set target ID */ + decRegs.sizeReg &= ~MV_AUDIO_WIN_TARGET_MASK; + decRegs.sizeReg |= (targetAttribs.targetId << MV_AUDIO_WIN_TARGET_OFFSET); + + if (pAddrDecWin->enable == MV_TRUE) + { + decRegs.sizeReg |= MV_AUDIO_WIN_ENABLE_MASK; + } + else + { + decRegs.sizeReg &= ~MV_AUDIO_WIN_ENABLE_MASK; + } + + MV_REG_WRITE( MV_AUDIO_WIN_CTRL_REG(winNum), decRegs.sizeReg); + MV_REG_WRITE( MV_AUDIO_WIN_BASE_REG(winNum), decRegs.baseReg); + + return MV_OK; +} + +/******************************************************************************* +* mvAudioWinGet - Get AUDIO peripheral target address window. +* +* DESCRIPTION: +* Get AUDIO peripheral target address window. +* +* INPUT: +* winNum - AUDIO target address decode window number. +* +* OUTPUT: +* pAddrDecWin - AUDIO target window data structure. +* +* RETURN: +* MV_ERROR if register parameters are invalid. +* +*******************************************************************************/ +MV_STATUS mvAudioWinGet(MV_U32 winNum, MV_AUDIO_DEC_WIN *pAddrDecWin) +{ + MV_DEC_REGS decRegs; + MV_TARGET_ATTRIB targetAttrib; + + /* Parameter checking */ + if (winNum >= MV_AUDIO_MAX_ADDR_DECODE_WIN) + { + mvOsPrintf("%s : ERR. Invalid winNum %d\n", + __FUNCTION__, winNum); + return MV_NOT_SUPPORTED; + } + + decRegs.baseReg = MV_REG_READ( MV_AUDIO_WIN_BASE_REG(winNum) ); + decRegs.sizeReg = MV_REG_READ( MV_AUDIO_WIN_CTRL_REG(winNum) ); + + if (MV_OK != mvCtrlRegToAddrDec(&decRegs, &pAddrDecWin->addrWin) ) + { + mvOsPrintf("%s: mvCtrlRegToAddrDec Failed\n", __FUNCTION__); + return MV_ERROR; + } + + /* attrib and targetId */ + targetAttrib.attrib = (decRegs.sizeReg & MV_AUDIO_WIN_ATTR_MASK) >> + MV_AUDIO_WIN_ATTR_OFFSET; + targetAttrib.targetId = (decRegs.sizeReg & MV_AUDIO_WIN_TARGET_MASK) >> + MV_AUDIO_WIN_TARGET_OFFSET; + + pAddrDecWin->target = mvCtrlTargetGet(&targetAttrib); + + /* Check if window is enabled */ + if(decRegs.sizeReg & MV_AUDIO_WIN_ENABLE_MASK) + { + pAddrDecWin->enable = MV_TRUE; + } + else + { + pAddrDecWin->enable = MV_FALSE; + } + return MV_OK; +} +/******************************************************************************* +* mvAudioAddrDecShow - Print the AUDIO address decode map. +* +* DESCRIPTION: +* This function print the AUDIO address decode map. +* +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* None. +* +*******************************************************************************/ +MV_VOID mvAudioAddrDecShow(MV_VOID) +{ + + MV_AUDIO_DEC_WIN win; + int i; + + if (MV_FALSE == mvCtrlPwrClckGet(AUDIO_UNIT_ID, 0)) + return; + + + mvOsOutput( "\n" ); + mvOsOutput( "AUDIO:\n" ); + mvOsOutput( "----\n" ); + + for( i = 0; i < MV_AUDIO_MAX_ADDR_DECODE_WIN; i++ ) + { + memset( &win, 0, sizeof(MV_AUDIO_DEC_WIN) ); + + mvOsOutput( "win%d - ", i ); + + if( mvAudioWinGet( i, &win ) == MV_OK ) + { + if( win.enable ) + { + mvOsOutput( "%s base %08x, ", + mvCtrlTargetNameGet(win.target), win.addrWin.baseLow ); + mvOsOutput( "...." ); + + mvSizePrint( win.addrWin.size ); + + mvOsOutput( "\n" ); + } + else + mvOsOutput( "disable\n" ); + } + } +} + + +/******************************************************************************* +* mvAudioWinInit - Initialize the integrated AUDIO target address window. +* +* DESCRIPTION: +* Initialize the AUDIO peripheral target address window. +* +* INPUT: +* +* +* OUTPUT: +* +* +* RETURN: +* MV_ERROR if register parameters are invalid. +* +*******************************************************************************/ +MV_STATUS mvAudioInit(MV_VOID) +{ + int winNum; + MV_AUDIO_DEC_WIN audioWin; + MV_CPU_DEC_WIN cpuAddrDecWin; + MV_U32 status; + + mvAudioHalInit(); + + /* Initiate Audio address decode */ + + /* First disable all address decode windows */ + for(winNum = 0; winNum < MV_AUDIO_MAX_ADDR_DECODE_WIN; winNum++) + { + MV_U32 regVal = MV_REG_READ(MV_AUDIO_WIN_CTRL_REG(winNum)); + regVal &= ~MV_AUDIO_WIN_ENABLE_MASK; + MV_REG_WRITE(MV_AUDIO_WIN_CTRL_REG(winNum), regVal); + } + + for(winNum = 0; winNum < MV_AUDIO_MAX_ADDR_DECODE_WIN; winNum++) + { + + /* We will set the Window to DRAM_CS0 in default */ + /* first get attributes from CPU If */ + status = mvCpuIfTargetWinGet(SDRAM_CS0, + &cpuAddrDecWin); + + if (MV_OK != status) + { + mvOsPrintf("%s: ERR. mvCpuIfTargetWinGet failed\n", __FUNCTION__); + return MV_ERROR; + } + + if (cpuAddrDecWin.enable == MV_TRUE) + { + audioWin.addrWin.baseHigh = cpuAddrDecWin.addrWin.baseHigh; + audioWin.addrWin.baseLow = cpuAddrDecWin.addrWin.baseLow; + audioWin.addrWin.size = cpuAddrDecWin.addrWin.size; + audioWin.enable = MV_TRUE; + audioWin.target = SDRAM_CS0; + + if(MV_OK != mvAudioWinSet(winNum, &audioWin)) + { + return MV_ERROR; + } + } + } + + return MV_OK; +} + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysAudio.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysAudio.h new file mode 100644 index 0000000..f59eb9a --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysAudio.h @@ -0,0 +1,123 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ +#ifndef __INCMVSysAudioH +#define __INCMVSysAudioH + +#include "mvCommon.h" +#include "audio/mvAudio.h" +#include "ctrlEnv/mvCtrlEnvSpec.h" +#include "ctrlEnv/sys/mvCpuIf.h" + +/***********************************/ +/* Audio Address Decoding registers*/ +/***********************************/ + +#define MV_AUDIO_MAX_ADDR_DECODE_WIN 2 +#define MV_AUDIO_RECORD_WIN_NUM 0 +#define MV_AUDIO_PLAYBACK_WIN_NUM 1 + +#define MV_AUDIO_WIN_CTRL_REG(win) (AUDIO_REG_BASE + 0xA04 + ((win)<<3)) +#define MV_AUDIO_WIN_BASE_REG(win) (AUDIO_REG_BASE + 0xA00 + ((win)<<3)) + +#define MV_AUDIO_RECORD_WIN_CTRL_REG MV_AUDIO_WIN_CTRL_REG(MV_AUDIO_RECORD_WIN_NUM) +#define MV_AUDIO_RECORD_WIN_BASE_REG MV_AUDIO_WIN_BASE_REG(MV_AUDIO_RECORD_WIN_NUM) +#define MV_AUDIO_PLAYBACK_WIN_CTRL_REG MV_AUDIO_WIN_CTRL_REG(MV_AUDIO_PLAYBACK_WIN_NUM) +#define MV_AUDIO_PLAYBACK_WIN_BASE_REG MV_AUDIO_WIN_BASE_REG(MV_AUDIO_PLAYBACK_WIN_NUM) + + +/* BITs in Windows 0-3 Control and Base Registers */ +#define MV_AUDIO_WIN_ENABLE_BIT 0 +#define MV_AUDIO_WIN_ENABLE_MASK (1<= 2) +MV_TARGET tdmaAddrDecPrioTable[] = +{ +#if defined(MV_INCLUDE_SDRAM_CS0) + SDRAM_CS0, +#endif +#if defined(MV_INCLUDE_SDRAM_CS1) + SDRAM_CS1, +#endif +#if defined(MV_INCLUDE_SDRAM_CS2) + SDRAM_CS2, +#endif +#if defined(MV_INCLUDE_SDRAM_CS3) + SDRAM_CS3, +#endif +#if defined(MV_INCLUDE_PEX) + PEX0_MEM, +#endif + + TBL_TERM +}; + +/******************************************************************************* +* mvCesaWinGet - Get TDMA target address window. +* +* DESCRIPTION: +* Get TDMA target address window. +* +* INPUT: +* winNum - TDMA target address decode window number. +* +* OUTPUT: +* pDecWin - TDMA target window data structure. +* +* RETURN: +* MV_ERROR if register parameters are invalid. +* +*******************************************************************************/ +static MV_STATUS mvCesaWinGet(MV_U32 winNum, MV_DEC_WIN *pDecWin) +{ + MV_DEC_WIN_PARAMS winParam; + MV_U32 sizeReg, baseReg; + + /* Parameter checking */ + if (winNum >= MV_CESA_TDMA_ADDR_DEC_WIN) + { + mvOsPrintf("%s : ERR. Invalid winNum %d\n", + __FUNCTION__, winNum); + return MV_NOT_SUPPORTED; + } + + baseReg = MV_REG_READ( MV_CESA_TDMA_BASE_ADDR_REG(winNum) ); + sizeReg = MV_REG_READ( MV_CESA_TDMA_WIN_CTRL_REG(winNum) ); + + /* Check if window is enabled */ + if(sizeReg & MV_CESA_TDMA_WIN_ENABLE_MASK) + { + pDecWin->enable = MV_TRUE; + + /* Extract window parameters from registers */ + winParam.targetId = (sizeReg & MV_CESA_TDMA_WIN_TARGET_MASK) >> MV_CESA_TDMA_WIN_TARGET_OFFSET; + winParam.attrib = (sizeReg & MV_CESA_TDMA_WIN_ATTR_MASK) >> MV_CESA_TDMA_WIN_ATTR_OFFSET; + winParam.size = (sizeReg & MV_CESA_TDMA_WIN_SIZE_MASK) >> MV_CESA_TDMA_WIN_SIZE_OFFSET; + winParam.baseAddr = (baseReg & MV_CESA_TDMA_WIN_BASE_MASK); + + /* Translate the decode window parameters to address decode struct */ + if (MV_OK != mvCtrlParamsToAddrDec(&winParam, pDecWin)) + { + mvOsPrintf("Failed to translate register parameters to CESA address" \ + " decode window structure\n"); + return MV_ERROR; + } + } + else + { + pDecWin->enable = MV_FALSE; + } + return MV_OK; +} + +/******************************************************************************* +* cesaWinOverlapDetect - Detect CESA TDMA address windows overlapping +* +* DESCRIPTION: +* An unpredicted behaviur is expected in case TDMA address decode +* windows overlapps. +* This function detects TDMA address decode windows overlapping of a +* specified window. The function does not check the window itself for +* overlapping. The function also skipps disabled address decode windows. +* +* INPUT: +* winNum - address decode window number. +* pAddrDecWin - An address decode window struct. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_TRUE - if the given address window overlap current address +* decode map, +* MV_FALSE - otherwise, MV_ERROR if reading invalid data +* from registers. +* +*******************************************************************************/ +static MV_STATUS cesaWinOverlapDetect(MV_U32 winNum, MV_ADDR_WIN *pAddrWin) +{ + MV_U32 winNumIndex; + MV_DEC_WIN addrDecWin; + + for(winNumIndex=0; winNumIndex= MV_CESA_TDMA_ADDR_DEC_WIN) + { + mvOsPrintf("mvCesaTdmaWinSet: ERR. Invalid win num %d\n",winNum); + return MV_BAD_PARAM; + } + + /* Check if the requested window overlapps with current windows */ + if (MV_TRUE == cesaWinOverlapDetect(winNum, &pDecWin->addrWin)) + { + mvOsPrintf("%s: ERR. Window %d overlap\n", __FUNCTION__, winNum); + return MV_ERROR; + } + + /* check if address is aligned to the size */ + if(MV_IS_NOT_ALIGN(pDecWin->addrWin.baseLow, pDecWin->addrWin.size)) + { + mvOsPrintf("mvCesaTdmaWinSet: Error setting CESA TDMA window %d to "\ + "target %s.\nAddress 0x%08x is unaligned to size 0x%x.\n", + winNum, + mvCtrlTargetNameGet(pDecWin->target), + pDecWin->addrWin.baseLow, + pDecWin->addrWin.size); + return MV_ERROR; + } + + if(MV_OK != mvCtrlAddrDecToParams(pDecWin, &winParams)) + { + mvOsPrintf("%s: mvCtrlAddrDecToParams Failed\n", __FUNCTION__); + return MV_ERROR; + } + + /* set Size, Attributes and TargetID */ + sizeReg = (((winParams.targetId << MV_CESA_TDMA_WIN_TARGET_OFFSET) & MV_CESA_TDMA_WIN_TARGET_MASK) | + ((winParams.attrib << MV_CESA_TDMA_WIN_ATTR_OFFSET) & MV_CESA_TDMA_WIN_ATTR_MASK) | + ((winParams.size << MV_CESA_TDMA_WIN_SIZE_OFFSET) & MV_CESA_TDMA_WIN_SIZE_MASK)); + + if (pDecWin->enable == MV_TRUE) + { + sizeReg |= MV_CESA_TDMA_WIN_ENABLE_MASK; + } + else + { + sizeReg &= ~MV_CESA_TDMA_WIN_ENABLE_MASK; + } + + /* Update Base value */ + baseReg = (winParams.baseAddr & MV_CESA_TDMA_WIN_BASE_MASK); + + MV_REG_WRITE( MV_CESA_TDMA_WIN_CTRL_REG(winNum), sizeReg); + MV_REG_WRITE( MV_CESA_TDMA_BASE_ADDR_REG(winNum), baseReg); + + return MV_OK; +} + + +static MV_STATUS mvCesaTdmaAddrDecInit (void) +{ + MV_U32 winNum; + MV_STATUS status; + MV_CPU_DEC_WIN cpuAddrDecWin; + MV_DEC_WIN cesaWin; + MV_U32 winPrioIndex = 0; + + /* First disable all address decode windows */ + for(winNum=0; winNum= 2 */ + + + + +MV_STATUS mvCesaInit (int numOfSession, int queueDepth, char* pSramBase, void *osHandle) +{ + MV_U32 cesaCryptEngBase; + MV_CPU_DEC_WIN addrDecWin; + + if(sizeof(MV_CESA_SRAM_MAP) > MV_CESA_SRAM_SIZE) + { + mvOsPrintf("mvCesaInit: Wrong SRAM map - %ld > %d\n", + sizeof(MV_CESA_SRAM_MAP), MV_CESA_SRAM_SIZE); + return MV_FAIL; + } +#if 0 + if (mvCpuIfTargetWinGet(CRYPT_ENG, &addrDecWin) == MV_OK) + cesaCryptEngBase = addrDecWin.addrWin.baseLow; + else + { + mvOsPrintf("mvCesaInit: ERR. mvCpuIfTargetWinGet failed\n"); + return MV_ERROR; + } +#else + cesaCryptEngBase = (MV_U32)pSramBase; +#endif + +#if 0 /* Already done in the platform init */ +#if (MV_CESA_VERSION >= 2) + mvCesaTdmaAddrDecInit(); +#endif /* MV_CESA_VERSION >= 2 */ +#endif + return mvCesaHalInit(numOfSession, queueDepth, pSramBase, cesaCryptEngBase, + osHandle); + +} diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysCesa.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysCesa.h new file mode 100644 index 0000000..73bcdc5 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysCesa.h @@ -0,0 +1,100 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#ifndef __mvSysCesa_h__ +#define __mvSysCesa_h__ + + +#include "mvCommon.h" +#include "cesa/mvCesa.h" +#include "ctrlEnv/mvCtrlEnvSpec.h" +#include "ctrlEnv/sys/mvCpuIf.h" + +/***************************** TDMA Registers *************************************/ + +#define MV_CESA_TDMA_ADDR_DEC_WIN 4 + +#define MV_CESA_TDMA_BASE_ADDR_REG(win) (MV_CESA_TDMA_REG_BASE + 0xa00 + (win<<3)) + +#define MV_CESA_TDMA_WIN_CTRL_REG(win) (MV_CESA_TDMA_REG_BASE + 0xa04 + (win<<3)) + +#define MV_CESA_TDMA_WIN_ENABLE_BIT 0 +#define MV_CESA_TDMA_WIN_ENABLE_MASK (1 << MV_CESA_TDMA_WIN_ENABLE_BIT) + +#define MV_CESA_TDMA_WIN_TARGET_OFFSET 4 +#define MV_CESA_TDMA_WIN_TARGET_MASK (0xf << MV_CESA_TDMA_WIN_TARGET_OFFSET) + +#define MV_CESA_TDMA_WIN_ATTR_OFFSET 8 +#define MV_CESA_TDMA_WIN_ATTR_MASK (0xff << MV_CESA_TDMA_WIN_ATTR_OFFSET) + +#define MV_CESA_TDMA_WIN_SIZE_OFFSET 16 +#define MV_CESA_TDMA_WIN_SIZE_MASK (0xFFFF << MV_CESA_TDMA_WIN_SIZE_OFFSET) + +#define MV_CESA_TDMA_WIN_BASE_OFFSET 16 +#define MV_CESA_TDMA_WIN_BASE_MASK (0xFFFF << MV_CESA_TDMA_WIN_BASE_OFFSET) + + +MV_STATUS mvCesaInit (int numOfSession, int queueDepth, char* pSramBase, void *osHandle); + +#endif diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysDram.c b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysDram.c new file mode 100644 index 0000000..6f76c2c --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysDram.c @@ -0,0 +1,348 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + + +/* includes */ + +#include "ddr2/mvDramIf.h" +#include "ctrlEnv/sys/mvCpuIf.h" +#include "ctrlEnv/sys/mvSysDram.h" + +/* #define MV_DEBUG */ +#ifdef MV_DEBUG +#define DB(x) x +#else +#define DB(x) +#endif + +static MV_BOOL sdramIfWinOverlap(MV_TARGET target, MV_ADDR_WIN *pAddrWin); + +/******************************************************************************* +* mvDramIfWinSet - Set DRAM interface address decode window +* +* DESCRIPTION: +* This function sets DRAM interface address decode window. +* +* INPUT: +* target - System target. Use only SDRAM targets. +* pAddrDecWin - SDRAM address window structure. +* +* OUTPUT: +* None +* +* RETURN: +* MV_BAD_PARAM if parameters are invalid or window is invalid, MV_OK +* otherwise. +*******************************************************************************/ +MV_STATUS mvDramIfWinSet(MV_TARGET target, MV_DRAM_DEC_WIN *pAddrDecWin) +{ + MV_U32 baseReg=0,sizeReg=0; + MV_U32 baseToReg=0 , sizeToReg=0; + + /* Check parameters */ + if (!MV_TARGET_IS_DRAM(target)) + { + mvOsPrintf("mvDramIfWinSet: target %d is not SDRAM\n", target); + return MV_BAD_PARAM; + } + + /* Check if the requested window overlaps with current enabled windows */ + if (MV_TRUE == sdramIfWinOverlap(target, &pAddrDecWin->addrWin)) + { + mvOsPrintf("mvDramIfWinSet: ERR. Target %d overlaps\n", target); + return MV_BAD_PARAM; + } + + /* check if address is aligned to the size */ + if(MV_IS_NOT_ALIGN(pAddrDecWin->addrWin.baseLow, pAddrDecWin->addrWin.size)) + { + mvOsPrintf("mvDramIfWinSet:Error setting DRAM interface window %d."\ + "\nAddress 0x%08x is unaligned to size 0x%x.\n", + target, + pAddrDecWin->addrWin.baseLow, + pAddrDecWin->addrWin.size); + return MV_ERROR; + } + + /* read base register*/ + baseReg = MV_REG_READ(SDRAM_BASE_ADDR_REG(0,target)); + + /* read size register */ + sizeReg = MV_REG_READ(SDRAM_SIZE_REG(0,target)); + + /* BaseLow[31:16] => base register [31:16] */ + baseToReg = pAddrDecWin->addrWin.baseLow & SCBAR_BASE_MASK; + + /* Write to address decode Base Address Register */ + baseReg &= ~SCBAR_BASE_MASK; + baseReg |= baseToReg; + + /* Translate the given window size to register format */ + sizeToReg = ctrlSizeToReg(pAddrDecWin->addrWin.size, SCSR_SIZE_ALIGNMENT); + + /* Size parameter validity check. */ + if (-1 == sizeToReg) + { + mvOsPrintf("mvCtrlAddrDecToReg: ERR. Win %d size invalid.\n",target); + return MV_BAD_PARAM; + } + + /* set size */ + sizeReg &= ~SCSR_SIZE_MASK; + /* Size is located at upper 16 bits */ + sizeReg |= (sizeToReg << SCSR_SIZE_OFFS); + + /* enable/Disable */ + if (MV_TRUE == pAddrDecWin->enable) + { + sizeReg |= SCSR_WIN_EN; + } + else + { + sizeReg &= ~SCSR_WIN_EN; + } + + /* 3) Write to address decode Base Address Register */ + MV_REG_WRITE(SDRAM_BASE_ADDR_REG(0,target), baseReg); + + /* Write to address decode Size Register */ + MV_REG_WRITE(SDRAM_SIZE_REG(0,target), sizeReg); + + return MV_OK; +} +/******************************************************************************* +* mvDramIfWinGet - Get DRAM interface address decode window +* +* DESCRIPTION: +* This function gets DRAM interface address decode window. +* +* INPUT: +* target - System target. Use only SDRAM targets. +* +* OUTPUT: +* pAddrDecWin - SDRAM address window structure. +* +* RETURN: +* MV_BAD_PARAM if parameters are invalid or window is invalid, MV_OK +* otherwise. +*******************************************************************************/ +MV_STATUS mvDramIfWinGet(MV_TARGET target, MV_DRAM_DEC_WIN *pAddrDecWin) +{ + MV_U32 baseReg,sizeReg; + MV_U32 sizeRegVal; + /* Check parameters */ + if (!MV_TARGET_IS_DRAM(target)) + { + mvOsPrintf("mvDramIfWinGet: target %d is Illigal\n", target); + return MV_ERROR; + } + + /* Read base and size registers */ + sizeReg = MV_REG_READ(SDRAM_SIZE_REG(0,target)); + baseReg = MV_REG_READ(SDRAM_BASE_ADDR_REG(0,target)); + + sizeRegVal = (sizeReg & SCSR_SIZE_MASK) >> SCSR_SIZE_OFFS; + + pAddrDecWin->addrWin.size = ctrlRegToSize(sizeRegVal, + SCSR_SIZE_ALIGNMENT); + + /* Check if ctrlRegToSize returned OK */ + if (-1 == pAddrDecWin->addrWin.size) + { + mvOsPrintf("mvDramIfWinGet: size of target %d is Illigal\n", target); + return MV_ERROR; + } + + /* Extract base address */ + /* Base register [31:16] ==> baseLow[31:16] */ + pAddrDecWin->addrWin.baseLow = baseReg & SCBAR_BASE_MASK; + + pAddrDecWin->addrWin.baseHigh = 0; + + + if (sizeReg & SCSR_WIN_EN) + { + pAddrDecWin->enable = MV_TRUE; + } + else + { + pAddrDecWin->enable = MV_FALSE; + } + + return MV_OK; +} +/******************************************************************************* +* mvDramIfWinEnable - Enable/Disable SDRAM address decode window +* +* DESCRIPTION: +* This function enable/Disable SDRAM address decode window. +* +* INPUT: +* target - System target. Use only SDRAM targets. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_ERROR in case function parameter are invalid, MV_OK otherewise. +* +*******************************************************************************/ +MV_STATUS mvDramIfWinEnable(MV_TARGET target, MV_BOOL enable) +{ + MV_DRAM_DEC_WIN addrDecWin; + + /* Check parameters */ + if (!MV_TARGET_IS_DRAM(target)) + { + mvOsPrintf("mvDramIfWinEnable: target %d is Illigal\n", target); + return MV_ERROR; + } + + if (enable == MV_TRUE) + { /* First check for overlap with other enabled windows */ + if (MV_OK != mvDramIfWinGet(target, &addrDecWin)) + { + mvOsPrintf("mvDramIfWinEnable:ERR. Getting target %d failed.\n", + target); + return MV_ERROR; + } + /* Check for overlapping */ + if (MV_FALSE == sdramIfWinOverlap(target, &(addrDecWin.addrWin))) + { + /* No Overlap. Enable address decode winNum window */ + MV_REG_BIT_SET(SDRAM_SIZE_REG(0,target), SCSR_WIN_EN); + } + else + { /* Overlap detected */ + mvOsPrintf("mvDramIfWinEnable: ERR. Target %d overlap detect\n", + target); + return MV_ERROR; + } + } + else + { /* Disable address decode winNum window */ + MV_REG_BIT_RESET(SDRAM_SIZE_REG(0, target), SCSR_WIN_EN); + } + + return MV_OK; +} + +/******************************************************************************* +* sdramIfWinOverlap - Check if an address window overlap an SDRAM address window +* +* DESCRIPTION: +* This function scan each SDRAM address decode window to test if it +* overlapps the given address windoow +* +* INPUT: +* target - SDRAM target where the function skips checking. +* pAddrDecWin - The tested address window for overlapping with +* SDRAM windows. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_TRUE if the given address window overlaps any enabled address +* decode map, MV_FALSE otherwise. +* +*******************************************************************************/ +static MV_BOOL sdramIfWinOverlap(MV_TARGET target, MV_ADDR_WIN *pAddrWin) +{ + MV_TARGET targetNum; + MV_DRAM_DEC_WIN addrDecWin; + + for(targetNum = SDRAM_CS0; targetNum < MV_DRAM_MAX_CS ; targetNum++) + { + /* don't check our winNum or illegal targets */ + if (targetNum == target) + { + continue; + } + + /* Get window parameters */ + if (MV_OK != mvDramIfWinGet(targetNum, &addrDecWin)) + { + mvOsPrintf("sdramIfWinOverlap: ERR. TargetWinGet failed\n"); + return MV_ERROR; + } + + /* Do not check disabled windows */ + if (MV_FALSE == addrDecWin.enable) + { + continue; + } + + if(MV_TRUE == ctrlWinOverlapTest(pAddrWin, &addrDecWin.addrWin)) + { + mvOsPrintf( + "sdramIfWinOverlap: Required target %d overlap winNum %d\n", + target, targetNum); + return MV_TRUE; + } + } + + return MV_FALSE; +} + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysDram.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysDram.h new file mode 100644 index 0000000..7bd9c9d --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysDram.h @@ -0,0 +1,80 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + + +#ifndef __sysDram +#define __sysDram + +/* This structure describes CPU interface address decode window */ +typedef struct _mvDramIfDecWin +{ + MV_ADDR_WIN addrWin; /* An address window*/ + MV_BOOL enable; /* Address decode window is enabled/disabled */ +}MV_DRAM_DEC_WIN; + +MV_STATUS mvDramIfWinSet(MV_TARGET target, MV_DRAM_DEC_WIN *pAddrDecWin); +MV_STATUS mvDramIfWinGet(MV_TARGET target, MV_DRAM_DEC_WIN *pAddrDecWin); +MV_STATUS mvDramIfWinEnable(MV_TARGET target, MV_BOOL enable); + +#endif diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysGbe.c b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysGbe.c new file mode 100644 index 0000000..7f6e4a5 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysGbe.c @@ -0,0 +1,658 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + + +#include "ctrlEnv/sys/mvSysGbe.h" + + + +typedef struct _mvEthDecWin +{ + MV_TARGET target; + MV_ADDR_WIN addrWin; /* An address window*/ + MV_BOOL enable; /* Address decode window is enabled/disabled */ + +}MV_ETH_DEC_WIN; + +MV_TARGET ethAddrDecPrioTap[] = +{ +#if defined(MV_INCLUDE_SDRAM_CS0) + SDRAM_CS0, +#endif +#if defined(MV_INCLUDE_SDRAM_CS1) + SDRAM_CS1, +#endif +#if defined(MV_INCLUDE_SDRAM_CS2) + SDRAM_CS2, +#endif +#if defined(MV_INCLUDE_SDRAM_CS3) + SDRAM_CS3, +#endif +#if defined(MV_INCLUDE_DEVICE_CS0) + DEVICE_CS0, +#endif +#if defined(MV_INCLUDE_DEVICE_CS1) + DEVICE_CS1, +#endif +#if defined(MV_INCLUDE_DEVICE_CS2) + DEVICE_CS2, +#endif +#if defined(MV_INCLUDE_DEVICE_CS3) + DEVICE_CS3, +#endif +#if defined(MV_INCLUDE_PEX) + PEX0_IO, +#endif + TBL_TERM +}; + +static MV_STATUS ethWinOverlapDetect(int port, MV_U32 winNum, MV_ADDR_WIN *pAddrWin); +static MV_STATUS mvEthWinSet(int port, MV_U32 winNum, MV_ETH_DEC_WIN *pAddrDecWin); +static MV_STATUS mvEthWinGet(int port, MV_U32 winNum, MV_ETH_DEC_WIN *pAddrDecWin); + + +/******************************************************************************* +* mvEthWinInit - Initialize ETH address decode windows +* +* DESCRIPTION: +* This function initialize ETH window decode unit. It set the +* default address decode windows of the unit. +* +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_ERROR if setting fail. +*******************************************************************************/ +/* Configure EthDrv memory map registes. */ +MV_STATUS mvEthWinInit (int port) +{ + MV_U32 winNum, status, winPrioIndex=0, i, regVal=0; + MV_ETH_DEC_WIN ethWin; + MV_CPU_DEC_WIN cpuAddrDecWin; + static MV_U32 accessProtReg = 0; + +#if (MV_ETH_VERSION <= 1) + static MV_BOOL isFirst = MV_TRUE; + + if(isFirst == MV_FALSE) + { + MV_REG_WRITE(ETH_ACCESS_PROTECT_REG(port), accessProtReg); + return MV_OK; + } + isFirst = MV_FALSE; +#endif /* MV_GIGA_ETH_VERSION */ + + /* Initiate Ethernet address decode */ + + /* First disable all address decode windows */ + for(winNum=0; winNum= ETH_MAX_DECODE_WIN) + { + mvOsPrintf("mvEthWinSet: ERR. Invalid win num %d\n",winNum); + return MV_BAD_PARAM; + } + + /* Check if the requested window overlapps with current windows */ + if (MV_TRUE == ethWinOverlapDetect(port, winNum, &pAddrDecWin->addrWin)) + { + mvOsPrintf("mvEthWinSet: ERR. Window %d overlap\n", winNum); + return MV_ERROR; + } + + /* check if address is aligned to the size */ + if(MV_IS_NOT_ALIGN(pAddrDecWin->addrWin.baseLow, pAddrDecWin->addrWin.size)) + { + mvOsPrintf("mvEthWinSet: Error setting Ethernet window %d to "\ + "target %s.\nAddress 0x%08x is unaligned to size 0x%x.\n", + winNum, + mvCtrlTargetNameGet(pAddrDecWin->target), + pAddrDecWin->addrWin.baseLow, + pAddrDecWin->addrWin.size); + return MV_ERROR; + } + + + decRegs.baseReg = MV_REG_READ(ETH_WIN_BASE_REG(port, winNum)); + decRegs.sizeReg = MV_REG_READ(ETH_WIN_SIZE_REG(port, winNum)); + + if (MV_OK != mvCtrlAddrDecToReg(&(pAddrDecWin->addrWin),&decRegs)) + { + mvOsPrintf("mvEthWinSet:mvCtrlAddrDecToReg Failed\n"); + return MV_ERROR; + } + + mvCtrlAttribGet(pAddrDecWin->target,&targetAttribs); + + /* set attributes */ + decRegs.baseReg &= ~ETH_WIN_ATTR_MASK; + decRegs.baseReg |= targetAttribs.attrib << ETH_WIN_ATTR_OFFS; + /* set target ID */ + decRegs.baseReg &= ~ETH_WIN_TARGET_MASK; + decRegs.baseReg |= targetAttribs.targetId << ETH_WIN_TARGET_OFFS; + + /* for the safe side we disable the window before writing the new + values */ + mvEthWinEnable(port, winNum, MV_FALSE); + MV_REG_WRITE(ETH_WIN_BASE_REG(port, winNum), decRegs.baseReg); + + /* Write to address decode Size Register */ + MV_REG_WRITE(ETH_WIN_SIZE_REG(port, winNum), decRegs.sizeReg); + + /* Enable address decode target window */ + if (pAddrDecWin->enable == MV_TRUE) + { + mvEthWinEnable(port, winNum, MV_TRUE); + } + + return MV_OK; +} + +/******************************************************************************* +* mvETHWinGet - Get dma peripheral target address window. +* +* DESCRIPTION: +* Get ETH peripheral target address window. +* +* INPUT: +* winNum - ETH to target address decode window number. +* +* OUTPUT: +* pAddrDecWin - ETH target window data structure. +* +* RETURN: +* MV_ERROR if register parameters are invalid. +* +*******************************************************************************/ +MV_STATUS mvEthWinGet(int port, MV_U32 winNum, MV_ETH_DEC_WIN *pAddrDecWin) +{ + MV_DEC_REGS decRegs; + MV_TARGET_ATTRIB targetAttrib; + + /* Parameter checking */ + if (winNum >= ETH_MAX_DECODE_WIN) + { + mvOsPrintf("mvEthWinGet: ERR. Invalid winNum %d\n", winNum); + return MV_NOT_SUPPORTED; + } + + decRegs.baseReg = MV_REG_READ(ETH_WIN_BASE_REG(port, winNum)); + decRegs.sizeReg = MV_REG_READ(ETH_WIN_SIZE_REG(port, winNum)); + + if (MV_OK != mvCtrlRegToAddrDec(&decRegs,&(pAddrDecWin->addrWin))) + { + mvOsPrintf("mvAhbToMbusWinGet: mvCtrlRegToAddrDec Failed \n"); + return MV_ERROR; + } + + /* attrib and targetId */ + targetAttrib.attrib = + (decRegs.baseReg & ETH_WIN_ATTR_MASK) >> ETH_WIN_ATTR_OFFS; + targetAttrib.targetId = + (decRegs.baseReg & ETH_WIN_TARGET_MASK) >> ETH_WIN_TARGET_OFFS; + + pAddrDecWin->target = mvCtrlTargetGet(&targetAttrib); + + /* Check if window is enabled */ + if (~(MV_REG_READ(ETH_BASE_ADDR_ENABLE_REG(port))) & (1 << winNum) ) + { + pAddrDecWin->enable = MV_TRUE; + } + else + { + pAddrDecWin->enable = MV_FALSE; + } + + return MV_OK; +} + +/******************************************************************************* +* mvEthWinEnable - Enable/disable a ETH to target address window +* +* DESCRIPTION: +* This function enable/disable a ETH to target address window. +* According to parameter 'enable' the routine will enable the +* window, thus enabling ETH accesses (before enabling the window it is +* tested for overlapping). Otherwise, the window will be disabled. +* +* INPUT: +* winNum - ETH to target address decode window number. +* enable - Enable/disable parameter. +* +* OUTPUT: +* N/A +* +* RETURN: +* MV_ERROR if decode window number was wrong or enabled window overlapps. +* +*******************************************************************************/ +MV_STATUS mvEthWinEnable(int port, MV_U32 winNum,MV_BOOL enable) +{ + MV_ETH_DEC_WIN addrDecWin; + + /* Parameter checking */ + if (winNum >= ETH_MAX_DECODE_WIN) + { + mvOsPrintf("mvEthTargetWinEnable:ERR. Invalid winNum%d\n",winNum); + return MV_ERROR; + } + + if (enable == MV_TRUE) + { /* First check for overlap with other enabled windows */ + /* Get current window */ + if (MV_OK != mvEthWinGet(port, winNum, &addrDecWin)) + { + mvOsPrintf("mvEthTargetWinEnable:ERR. targetWinGet fail\n"); + return MV_ERROR; + } + /* Check for overlapping */ + if (MV_FALSE == ethWinOverlapDetect(port, winNum, &(addrDecWin.addrWin))) + { + /* No Overlap. Enable address decode target window */ + MV_REG_BIT_RESET(ETH_BASE_ADDR_ENABLE_REG(port), (1 << winNum)); + } + else + { /* Overlap detected */ + mvOsPrintf("mvEthTargetWinEnable:ERR. Overlap detected\n"); + return MV_ERROR; + } + } + else + { /* Disable address decode target window */ + MV_REG_BIT_SET(ETH_BASE_ADDR_ENABLE_REG(port), (1 << winNum)); + } + return MV_OK; +} + +/******************************************************************************* +* mvEthWinTargetGet - Get Window number associated with target +* +* DESCRIPTION: +* +* INPUT: +* +* OUTPUT: +* +* RETURN: +* window number +* +*******************************************************************************/ +MV_U32 mvEthWinTargetGet(int port, MV_TARGET target) +{ + MV_ETH_DEC_WIN decWin; + MV_U32 winNum; + + /* Check parameters */ + if (target >= MAX_TARGETS) + { + mvOsPrintf("mvAhbToMbusWinTargetGet: target %d is Illigal\n", target); + return 0xffffffff; + } + + for (winNum=0; winNum= mvCtrlEthMaxPortGet()) + { + mvOsPrintf("mvEthProtWinSet:ERR. Invalid port number %d\n", portNo); + return MV_ERROR; + } + + if (winNum >= ETH_MAX_DECODE_WIN) + { + mvOsPrintf("mvEthProtWinSet:ERR. Invalid winNum%d\n",winNum); + return MV_ERROR; + } + + if((access == ACC_RESERVED) || (access >= MAX_ACC_RIGHTS)) + { + mvOsPrintf("mvEthProtWinSet:ERR. Inv access param %d\n", access); + return MV_ERROR; + } + /* Read current protection register */ + protReg = MV_REG_READ(ETH_ACCESS_PROTECT_REG(portNo)); + + /* Clear protection window field */ + protReg &= ~(ETH_PROT_WIN_MASK(winNum)); + + /* Set new protection field value */ + protReg |= (access << (ETH_PROT_WIN_OFFS(winNum))); + + /* Write protection register back */ + MV_REG_WRITE(ETH_ACCESS_PROTECT_REG(portNo), protReg); + + return MV_OK; +} + +/******************************************************************************* +* ethWinOverlapDetect - Detect ETH address windows overlapping +* +* DESCRIPTION: +* An unpredicted behaviur is expected in case ETH address decode +* windows overlapps. +* This function detects ETH address decode windows overlapping of a +* specified window. The function does not check the window itself for +* overlapping. The function also skipps disabled address decode windows. +* +* INPUT: +* winNum - address decode window number. +* pAddrDecWin - An address decode window struct. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_TRUE if the given address window overlap current address +* decode map, MV_FALSE otherwise, MV_ERROR if reading invalid data +* from registers. +* +*******************************************************************************/ +static MV_STATUS ethWinOverlapDetect(int port, MV_U32 winNum, MV_ADDR_WIN *pAddrWin) +{ + MV_U32 baseAddrEnableReg; + MV_U32 winNumIndex; + MV_ETH_DEC_WIN addrDecWin; + + /* Read base address enable register. Do not check disabled windows */ + baseAddrEnableReg = MV_REG_READ(ETH_BASE_ADDR_ENABLE_REG(port)); + + for (winNumIndex=0; winNumIndex= mvCtrlPexMaxIfGet()) + { + mvOsPrintf("mvPexInit: ERR. Invalid PEX interface %d\n", pexIf); + return MV_BAD_PARAM; + } + + /* Enabled CPU access to PCI-Express */ + mvCpuIfEnablePex(pexIf, pexType); + + /* Start with bars */ + /* First disable all PEX bars*/ + for (bar = 0; bar < PEX_MAX_BARS; bar++) + { + if (PEX_INTER_REGS_BAR != bar) + { + if (MV_OK != mvPexBarEnable(pexIf, bar, MV_FALSE)) + { + mvOsPrintf("mvPexInit:mvPexBarEnable bar =%d failed \n",bar); + return MV_ERROR; + } + + } + + } + + /* and disable all PEX target windows */ + for (winNum = 0; winNum < PEX_MAX_TARGET_WIN - 2; winNum++) + { + if (MV_OK != mvPexTargetWinEnable(pexIf, winNum, MV_FALSE)) + { + mvOsPrintf("mvPexInit:mvPexTargetWinEnable winNum =%d failed \n", + winNum); + return MV_ERROR; + + } + } + + /* Now, go through all bars*/ + + + +/******************************************************************************/ +/* Internal registers bar */ +/******************************************************************************/ + bar = PEX_INTER_REGS_BAR; + + /* we only open the bar , no need to open windows for this bar */ + + /* first get the CS attribute from the CPU Interface */ + if (MV_OK !=mvCpuIfTargetWinGet(INTER_REGS,&addrDecWin)) + { + mvOsPrintf("mvPexInit: ERR. mvCpuIfTargetWinGet failed target =%d\n",INTER_REGS); + return MV_ERROR; + } + + pexBar.addrWin.baseHigh = addrDecWin.addrWin.baseHigh; + pexBar.addrWin.baseLow = addrDecWin.addrWin.baseLow; + pexBar.addrWin.size = addrDecWin.addrWin.size; + pexBar.enable = MV_TRUE; + + if (MV_OK != mvPexBarSet(pexIf, bar, &pexBar)) + { + mvOsPrintf("mvPexInit: ERR. mvPexBarSet %d failed\n", bar); + return MV_ERROR; + } + +/******************************************************************************/ +/* DRAM bar */ +/******************************************************************************/ + + bar = PEX_DRAM_BAR; + + pexBar.addrWin.size = 0; + + for (target = SDRAM_CS0;target < MV_DRAM_MAX_CS; target++ ) + { + + status = mvCpuIfTargetWinGet(target,&addrDecWin); + + if((MV_NO_SUCH == status)&&(target != SDRAM_CS0)) + { + continue; + } + + /* first get attributes from CPU If */ + if (MV_OK != status) + { + mvOsPrintf("mvPexInit: ERR. mvCpuIfTargetWinGet failed target =%d\n",target); + return MV_ERROR; + } + if (addrDecWin.enable == MV_TRUE) + { + /* the base is the base of DRAM CS0 always */ + if (SDRAM_CS0 == target ) + { + pexBar.addrWin.baseHigh = addrDecWin.addrWin.baseHigh; + pexBar.addrWin.baseLow = addrDecWin.addrWin.baseLow; + + } + + /* increment the bar size to be the sum of the size of all + DRAM chips selecs */ + pexBar.addrWin.size += addrDecWin.addrWin.size; + + /* set a Pex window for this target ! + DRAM CS always will have a Pex Window , and is not a + part of the priority table */ + pexWin.addrWin.baseHigh = addrDecWin.addrWin.baseHigh; + pexWin.addrWin.baseLow = addrDecWin.addrWin.baseLow; + pexWin.addrWin.size = addrDecWin.addrWin.size; + + /* we disable the windows at first because we are not + sure that it is witihin bar boundries */ + pexWin.enable =MV_FALSE; + pexWin.target = target; + pexWin.targetBar = bar; + + if (MV_OK != mvPexTargetWinSet(pexIf,pexCurrWin++,&pexWin)) + { + mvOsPrintf("mvPexInit: ERR. mvPexTargetWinSet failed\n"); + return MV_ERROR; + } + } + } + + /* check if the size of the bar is illeggal */ + if (-1 == ctrlSizeToReg(pexBar.addrWin.size, PXBCR_BAR_SIZE_ALIGNMENT)) + { + /* try to get a good size */ + pexBar.addrWin.size = ctrlSizeRegRoundUp(pexBar.addrWin.size, + PXBCR_BAR_SIZE_ALIGNMENT); + } + + /* check if the size and base are valid */ + if (MV_TRUE == pexBarOverlapDetect(pexIf,bar,&pexBar.addrWin)) + { + mvOsPrintf("mvPexInit:Warning :Bar %d size is illigal\n",bar); + mvOsPrintf("it will be disabled\n"); + mvOsPrintf("please check Pex and CPU windows configuration\n"); + } + else + { + pexBar.enable = MV_TRUE; + + /* configure the bar */ + if (MV_OK != mvPexBarSet(pexIf, bar, &pexBar)) + { + mvOsPrintf("mvPexInit: ERR. mvPexBarSet %d failed\n", bar); + return MV_ERROR; + } + + /* after the bar was configured then we enable the Pex windows*/ + for (winNum = 0;winNum < pexCurrWin ;winNum++) + { + if (MV_OK != mvPexTargetWinEnable(pexIf, winNum, MV_TRUE)) + { + mvOsPrintf("mvPexInit: Can't enable window =%d\n",winNum); + return MV_ERROR; + } + + } + } + +/******************************************************************************/ +/* DEVICE bar */ +/******************************************************************************/ + +/* Open the Device BAR for non linux only */ +#ifndef MV_DISABLE_PEX_DEVICE_BAR + + /* then device bar*/ + bar = PEX_DEVICE_BAR; + + /* save the starting window */ + pexStartWindow = pexCurrWin; + pexBar.addrWin.size = 0; + pexBar.addrWin.baseLow = 0xffffffff; + pexBar.addrWin.baseHigh = 0; + maxBase = 0; + + for (target = DEV_TO_TARGET(START_DEV_CS);target < DEV_TO_TARGET(MV_DEV_MAX_CS); target++ ) + { + status = mvCpuIfTargetWinGet(target,&addrDecWin); + + if (MV_NO_SUCH == status) + { + continue; + } + + if (MV_OK != status) + { + mvOsPrintf("mvPexInit: ERR. mvCpuIfTargetWinGet failed target =%d\n",target); + return MV_ERROR; + } + + if (addrDecWin.enable == MV_TRUE) + { + /* get the minimum base */ + if (addrDecWin.addrWin.baseLow < pexBar.addrWin.baseLow) + { + pexBar.addrWin.baseLow = addrDecWin.addrWin.baseLow; + } + + /* get the maximum base */ + if (addrDecWin.addrWin.baseLow > maxBase) + { + maxBase = addrDecWin.addrWin.baseLow; + sizeOfMaxBase = addrDecWin.addrWin.size; + } + + /* search in the priority table for this target */ + for (winIndex = 0; pexDevBarPrioTable[winIndex] != TBL_TERM; + winIndex++) + { + if (pexDevBarPrioTable[winIndex] != target) + { + continue; + } + else if (pexDevBarPrioTable[winIndex] == target) + { + /*found it */ + + /* if the index of this target in the prio table is valid + then we set the Pex window for this target, a valid index is + an index that is lower than the number of the windows that + was not configured yet */ + + /* we subtract 2 always because the default and expantion + rom windows are always configured */ + if ( pexCurrWin < PEX_MAX_TARGET_WIN - 2) + { + /* set a Pex window for this target ! */ + pexWin.addrWin.baseHigh = addrDecWin.addrWin.baseHigh; + pexWin.addrWin.baseLow = addrDecWin.addrWin.baseLow; + pexWin.addrWin.size = addrDecWin.addrWin.size; + + /* we disable the windows at first because we are not + sure that it is witihin bar boundries */ + pexWin.enable = MV_FALSE; + pexWin.target = target; + pexWin.targetBar = bar; + + if (MV_OK != mvPexTargetWinSet(pexIf,pexCurrWin++, + &pexWin)) + { + mvOsPrintf("mvPexInit: ERR. Window Set failed\n"); + return MV_ERROR; + } + } + } + } + } + } + + pexBar.addrWin.size = maxBase - pexBar.addrWin.baseLow + sizeOfMaxBase; + pexBar.enable = MV_TRUE; + + /* check if the size of the bar is illegal */ + if (-1 == ctrlSizeToReg(pexBar.addrWin.size, PXBCR_BAR_SIZE_ALIGNMENT)) + { + /* try to get a good size */ + pexBar.addrWin.size = ctrlSizeRegRoundUp(pexBar.addrWin.size, + PXBCR_BAR_SIZE_ALIGNMENT); + } + + /* check if the size and base are valid */ + if (MV_TRUE == pexBarOverlapDetect(pexIf,bar,&pexBar.addrWin)) + { + mvOsPrintf("mvPexInit:Warning :Bar %d size is illigal\n",bar); + mvOsPrintf("it will be disabled\n"); + mvOsPrintf("please check Pex and CPU windows configuration\n"); + } + else + { + if (MV_OK != mvPexBarSet(pexIf, bar, &pexBar)) + { + mvOsPrintf("mvPexInit: ERR. mvPexBarSet %d failed\n", bar); + return MV_ERROR; + } + + /* now enable the windows */ + for (winNum = pexStartWindow; winNum < pexCurrWin ; winNum++) + { + if (MV_OK != mvPexTargetWinEnable(pexIf, winNum, MV_TRUE)) + { + mvOsPrintf("mvPexInit:mvPexTargetWinEnable winNum =%d failed \n", + winNum); + return MV_ERROR; + } + } + } + +#endif + + return mvPexHalInit(pexIf, pexType); + +} + +/******************************************************************************* +* mvPexTargetWinSet - Set PEX to peripheral target address window BAR +* +* DESCRIPTION: +* +* INPUT: +* +* OUTPUT: +* N/A +* +* RETURN: +* MV_OK if PEX BAR target window was set correctly, +* MV_BAD_PARAM on bad params +* MV_ERROR otherwise +* (e.g. address window overlapps with other active PEX target window). +* +*******************************************************************************/ +MV_STATUS mvPexTargetWinSet(MV_U32 pexIf, MV_U32 winNum, + MV_PEX_DEC_WIN *pAddrDecWin) +{ + + MV_DEC_REGS decRegs; + PEX_WIN_REG_INFO winRegInfo; + MV_TARGET_ATTRIB targetAttribs; + + /* Parameter checking */ + if(pexIf >= mvCtrlPexMaxIfGet()) + { + mvOsPrintf("mvPexTargetWinSet: ERR. Invalid PEX interface %d\n", pexIf); + return MV_BAD_PARAM; + } + + if (winNum >= PEX_MAX_TARGET_WIN) + { + mvOsPrintf("mvPexTargetWinSet: ERR. Invalid PEX winNum %d\n", winNum); + return MV_BAD_PARAM; + + } + + /* get the pex Window registers offsets */ + pexWinRegInfoGet(pexIf,winNum,&winRegInfo); + + + if (MV_TRUE == pAddrDecWin->enable) + { + + /* 2) Check if the requested window overlaps with current windows */ + if (MV_TRUE == pexWinOverlapDetect(pexIf,winNum, &pAddrDecWin->addrWin)) + { + mvOsPrintf("mvPexTargetWinSet: ERR. Target %d overlap\n", winNum); + return MV_BAD_PARAM; + } + + /* 2) Check if the requested window overlaps with current windows */ + if (MV_FALSE == pexIsWinWithinBar(pexIf,&pAddrDecWin->addrWin)) + { + mvOsPrintf("mvPexTargetWinSet: Win %d should be in bar boundries\n", + winNum); + return MV_BAD_PARAM; + } + + } + + + + /* read base register*/ + + if (winRegInfo.baseLowRegOffs) + { + decRegs.baseReg = MV_REG_READ(winRegInfo.baseLowRegOffs); + } + else + { + decRegs.baseReg = 0; + } + + if (winRegInfo.sizeRegOffs) + { + decRegs.sizeReg = MV_REG_READ(winRegInfo.sizeRegOffs); + } + else + { + decRegs.sizeReg =0; + } + + if (MV_OK != mvCtrlAddrDecToReg(&(pAddrDecWin->addrWin),&decRegs)) + { + mvOsPrintf("mvPexTargetWinSet:mvCtrlAddrDecToReg Failed\n"); + return MV_ERROR; + } + + /* enable\Disable */ + if (MV_TRUE == pAddrDecWin->enable) + { + decRegs.sizeReg |= PXWCR_WIN_EN; + } + else + { + decRegs.sizeReg &= ~PXWCR_WIN_EN; + } + + + /* clear bit location */ + decRegs.sizeReg &= ~PXWCR_WIN_BAR_MAP_MASK; + + /* set bar Mapping */ + if (pAddrDecWin->targetBar == 1) + { + decRegs.sizeReg |= PXWCR_WIN_BAR_MAP_BAR1; + } + else if (pAddrDecWin->targetBar == 2) + { + decRegs.sizeReg |= PXWCR_WIN_BAR_MAP_BAR2; + } + + mvCtrlAttribGet(pAddrDecWin->target,&targetAttribs); + + /* set attributes */ + decRegs.sizeReg &= ~PXWCR_ATTRIB_MASK; + decRegs.sizeReg |= targetAttribs.attrib << PXWCR_ATTRIB_OFFS; + /* set target ID */ + decRegs.sizeReg &= ~PXWCR_TARGET_MASK; + decRegs.sizeReg |= targetAttribs.targetId << PXWCR_TARGET_OFFS; + + + /* 3) Write to address decode Base Address Register */ + + if (winRegInfo.baseLowRegOffs) + { + MV_REG_WRITE(winRegInfo.baseLowRegOffs, decRegs.baseReg); + } + + /* write size reg */ + if (winRegInfo.sizeRegOffs) + { + if ((MV_PEX_WIN_DEFAULT == winNum)|| + (MV_PEX_WIN_EXP_ROM == winNum)) + { + /* clear size because there is no size field*/ + decRegs.sizeReg &= ~PXWCR_SIZE_MASK; + + /* clear enable because there is no enable field*/ + decRegs.sizeReg &= ~PXWCR_WIN_EN; + + } + + MV_REG_WRITE(winRegInfo.sizeRegOffs, decRegs.sizeReg); + } + + + return MV_OK; + +} + +/******************************************************************************* +* mvPexTargetWinGet - Get PEX to peripheral target address window +* +* DESCRIPTION: +* Get the PEX to peripheral target address window BAR. +* +* INPUT: +* pexIf - PEX interface number. +* bar - BAR to be accessed by slave. +* +* OUTPUT: +* pAddrBarWin - PEX target window information data structure. +* +* RETURN: +* MV_BAD_PARAM for bad parameters ,MV_ERROR on error ! otherwise MV_OK +* +*******************************************************************************/ +MV_STATUS mvPexTargetWinGet(MV_U32 pexIf, MV_U32 winNum, + MV_PEX_DEC_WIN *pAddrDecWin) +{ + MV_TARGET_ATTRIB targetAttrib; + MV_DEC_REGS decRegs; + + PEX_WIN_REG_INFO winRegInfo; + + /* Parameter checking */ + if(pexIf >= mvCtrlPexMaxIfGet()) + { + mvOsPrintf("mvPexTargetWinGet: ERR. Invalid PEX interface %d\n", pexIf); + return MV_BAD_PARAM; + } + + if (winNum >= PEX_MAX_TARGET_WIN) + { + mvOsPrintf("mvPexTargetWinGet: ERR. Invalid PEX winNum %d\n", winNum); + return MV_BAD_PARAM; + + } + + /* get the pex Window registers offsets */ + pexWinRegInfoGet(pexIf,winNum,&winRegInfo); + + /* read base register*/ + if (winRegInfo.baseLowRegOffs) + { + decRegs.baseReg = MV_REG_READ(winRegInfo.baseLowRegOffs); + } + else + { + decRegs.baseReg = 0; + } + + /* read size reg */ + if (winRegInfo.sizeRegOffs) + { + decRegs.sizeReg = MV_REG_READ(winRegInfo.sizeRegOffs); + } + else + { + decRegs.sizeReg =0; + } + + if (MV_OK != mvCtrlRegToAddrDec(&decRegs,&(pAddrDecWin->addrWin))) + { + mvOsPrintf("mvPexTargetWinGet: mvCtrlRegToAddrDec Failed \n"); + return MV_ERROR; + + } + + if (decRegs.sizeReg & PXWCR_WIN_EN) + { + pAddrDecWin->enable = MV_TRUE; + } + else + { + pAddrDecWin->enable = MV_FALSE; + + } + + + #if 0 + if (-1 == pAddrDecWin->addrWin.size) + { + return MV_ERROR; + } + #endif + + + /* get target bar */ + if ((decRegs.sizeReg & PXWCR_WIN_BAR_MAP_MASK) == PXWCR_WIN_BAR_MAP_BAR1 ) + { + pAddrDecWin->targetBar = 1; + } + else if ((decRegs.sizeReg & PXWCR_WIN_BAR_MAP_MASK) == + PXWCR_WIN_BAR_MAP_BAR2 ) + { + pAddrDecWin->targetBar = 2; + } + + /* attrib and targetId */ + pAddrDecWin->attrib = (decRegs.sizeReg & PXWCR_ATTRIB_MASK) >> + PXWCR_ATTRIB_OFFS; + pAddrDecWin->targetId = (decRegs.sizeReg & PXWCR_TARGET_MASK) >> + PXWCR_TARGET_OFFS; + + targetAttrib.attrib = pAddrDecWin->attrib; + targetAttrib.targetId = pAddrDecWin->targetId; + + pAddrDecWin->target = mvCtrlTargetGet(&targetAttrib); + + return MV_OK; + +} + + +/******************************************************************************* +* mvPexTargetWinEnable - Enable/disable a PEX BAR window +* +* DESCRIPTION: +* This function enable/disable a PEX BAR window. +* if parameter 'enable' == MV_TRUE the routine will enable the +* window, thus enabling PEX accesses for that BAR (before enabling the +* window it is tested for overlapping). Otherwise, the window will +* be disabled. +* +* INPUT: +* pexIf - PEX interface number. +* bar - BAR to be accessed by slave. +* enable - Enable/disable parameter. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_BAD_PARAM for bad parameters ,MV_ERROR on error ! otherwise MV_OK +* +*******************************************************************************/ +MV_STATUS mvPexTargetWinEnable(MV_U32 pexIf,MV_U32 winNum, MV_BOOL enable) +{ + PEX_WIN_REG_INFO winRegInfo; + MV_PEX_DEC_WIN addrDecWin; + + /* Parameter checking */ + if(pexIf >= mvCtrlPexMaxIfGet()) + { + mvOsPrintf("mvPexTargetWinEnable: ERR. Invalid PEX If %d\n", pexIf); + return MV_BAD_PARAM; + } + + if (winNum >= PEX_MAX_TARGET_WIN) + { + mvOsPrintf("mvPexTargetWinEnable ERR. Invalid PEX winNum %d\n", winNum); + return MV_BAD_PARAM; + + } + + + /* get the pex Window registers offsets */ + pexWinRegInfoGet(pexIf,winNum,&winRegInfo); + + + /* if the address windows is disabled , we only disable the appropriare + pex window and ignore other settings */ + + if (MV_FALSE == enable) + { + + /* this is not relevant to default and expantion rom + windows */ + if (winRegInfo.sizeRegOffs) + { + if ((MV_PEX_WIN_DEFAULT != winNum)&& + (MV_PEX_WIN_EXP_ROM != winNum)) + { + MV_REG_BIT_RESET(winRegInfo.sizeRegOffs, PXWCR_WIN_EN); + } + } + + } + else + { + if (MV_OK != mvPexTargetWinGet(pexIf,winNum, &addrDecWin)) + { + mvOsPrintf("mvPexTargetWinEnable: mvPexTargetWinGet Failed\n"); + return MV_ERROR; + } + + /* Check if the requested window overlaps with current windows */ + if (MV_TRUE == pexWinOverlapDetect(pexIf,winNum, &addrDecWin.addrWin)) + { + mvOsPrintf("mvPexTargetWinEnable: ERR. Target %d overlap\n", winNum); + return MV_BAD_PARAM; + } + + if (MV_FALSE == pexIsWinWithinBar(pexIf,&addrDecWin.addrWin)) + { + mvOsPrintf("mvPexTargetWinEnable: Win %d should be in bar boundries\n", + winNum); + return MV_BAD_PARAM; + } + + + /* this is not relevant to default and expantion rom + windows */ + if (winRegInfo.sizeRegOffs) + { + if ((MV_PEX_WIN_DEFAULT != winNum)&& + (MV_PEX_WIN_EXP_ROM != winNum)) + { + MV_REG_BIT_SET(winRegInfo.sizeRegOffs, PXWCR_WIN_EN); + } + } + + + } + + return MV_OK; + +} + + + +/******************************************************************************* +* mvPexTargetWinRemap - Set PEX to target address window remap. +* +* DESCRIPTION: +* The PEX interface supports remap of the BAR original address window. +* For each BAR it is possible to define a remap address. For example +* an address 0x12345678 that hits BAR 0x10 (SDRAM CS[0]) will be modified +* according to remap register but will also be targeted to the +* SDRAM CS[0]. +* +* INPUT: +* pexIf - PEX interface number. +* bar - Peripheral target enumerator accessed by slave. +* pAddrWin - Address window to be checked. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_BAD_PARAM for bad parameters ,MV_ERROR on error ! otherwise MV_OK +* +*******************************************************************************/ +MV_STATUS mvPexTargetWinRemap(MV_U32 pexIf, MV_U32 winNum, + MV_PEX_REMAP_WIN *pAddrWin) +{ + + PEX_WIN_REG_INFO winRegInfo; + + /* Parameter checking */ + if (pexIf >= mvCtrlPexMaxIfGet()) + { + mvOsPrintf("mvPexTargetWinRemap: ERR. Invalid PEX interface num %d\n", + pexIf); + return MV_BAD_PARAM; + } + if (MV_PEX_WIN_DEFAULT == winNum) + { + mvOsPrintf("mvPexTargetWinRemap: ERR. Invalid PEX win num %d\n", + winNum); + return MV_BAD_PARAM; + + } + + if (MV_IS_NOT_ALIGN(pAddrWin->addrWin.baseLow, PXWRR_REMAP_ALIGNMENT)) + { + mvOsPrintf("mvPexTargetWinRemap: Error remap PEX interface %d win %d."\ + "\nAddress 0x%08x is unaligned to size 0x%x.\n", + pexIf, + winNum, + pAddrWin->addrWin.baseLow, + pAddrWin->addrWin.size); + + return MV_ERROR; + } + + pexWinRegInfoGet(pexIf, winNum, &winRegInfo); + + /* Set remap low register value */ + MV_REG_WRITE(winRegInfo.remapLowRegOffs, pAddrWin->addrWin.baseLow); + + /* Skip base high settings if the BAR has only base low (32-bit) */ + if (0 != winRegInfo.remapHighRegOffs) + { + MV_REG_WRITE(winRegInfo.remapHighRegOffs, pAddrWin->addrWin.baseHigh); + } + + + if (pAddrWin->enable == MV_TRUE) + { + MV_REG_BIT_SET(winRegInfo.remapLowRegOffs,PXWRR_REMAP_EN); + } + else + { + MV_REG_BIT_RESET(winRegInfo.remapLowRegOffs,PXWRR_REMAP_EN); + } + + return MV_OK; +} + +/******************************************************************************* +* mvPexTargetWinRemapEnable - +* +* DESCRIPTION: +* +* INPUT: +* +* OUTPUT: +* +* RETURN: +* MV_BAD_PARAM for bad parameters ,MV_ERROR on error ! otherwise MV_OK +* +*******************************************************************************/ + +MV_STATUS mvPexTargetWinRemapEnable(MV_U32 pexIf, MV_U32 winNum, + MV_BOOL enable) +{ + PEX_WIN_REG_INFO winRegInfo; + + /* Parameter checking */ + if (pexIf >= mvCtrlPexMaxIfGet()) + { + mvOsPrintf("mvPexTargetWinRemap: ERR. Invalid PEX interface num %d\n", + pexIf); + return MV_BAD_PARAM; + } + if (MV_PEX_WIN_DEFAULT == winNum) + { + mvOsPrintf("mvPexTargetWinRemap: ERR. Invalid PEX win num %d\n", + winNum); + return MV_BAD_PARAM; + + } + + + pexWinRegInfoGet(pexIf, winNum, &winRegInfo); + + if (enable == MV_TRUE) + { + MV_REG_BIT_SET(winRegInfo.remapLowRegOffs,PXWRR_REMAP_EN); + } + else + { + MV_REG_BIT_RESET(winRegInfo.remapLowRegOffs,PXWRR_REMAP_EN); + } + + return MV_OK; + +} + +/******************************************************************************* +* mvPexBarSet - Set PEX bar address and size +* +* DESCRIPTION: +* +* INPUT: +* +* OUTPUT: +* None. +* +* RETURN: +* MV_BAD_PARAM for bad parameters ,MV_ERROR on error ! otherwise MV_OK +* +*******************************************************************************/ +MV_STATUS mvPexBarSet(MV_U32 pexIf, + MV_U32 barNum, + MV_PEX_BAR *pAddrWin) +{ + MV_U32 regBaseLow; + MV_U32 regSize,sizeToReg; + + + /* check parameters */ + if(pexIf >= mvCtrlPexMaxIfGet()) + { + mvOsPrintf("mvPexBarSet: ERR. Invalid PEX interface %d\n", pexIf); + return MV_BAD_PARAM; + } + + if(barNum >= PEX_MAX_BARS) + { + mvOsPrintf("mvPexBarSet: ERR. Invalid bar number %d\n", barNum); + return MV_BAD_PARAM; + } + + + if (pAddrWin->addrWin.size == 0) + { + mvOsPrintf("mvPexBarSet: Size zero is Illigal\n" ); + return MV_BAD_PARAM; + } + + + /* Check if the window complies with PEX spec */ + if (MV_TRUE != pexBarIsValid(pAddrWin->addrWin.baseLow, + pAddrWin->addrWin.size)) + { + mvOsPrintf("mvPexBarSet: ERR. Target %d window invalid\n", barNum); + return MV_BAD_PARAM; + } + + /* 2) Check if the requested bar overlaps with current bars */ + if (MV_TRUE == pexBarOverlapDetect(pexIf,barNum, &pAddrWin->addrWin)) + { + mvOsPrintf("mvPexBarSet: ERR. Target %d overlap\n", barNum); + return MV_BAD_PARAM; + } + + /* Get size register value according to window size */ + sizeToReg = ctrlSizeToReg(pAddrWin->addrWin.size, PXBCR_BAR_SIZE_ALIGNMENT); + + /* Read bar size */ + if (PEX_INTER_REGS_BAR != barNum) /* internal registers have no size */ + { + regSize = MV_REG_READ(PEX_BAR_CTRL_REG(pexIf,barNum)); + + /* Size parameter validity check. */ + if (-1 == sizeToReg) + { + mvOsPrintf("mvPexBarSet: ERR. Target BAR %d size invalid.\n",barNum); + return MV_BAD_PARAM; + } + + regSize &= ~PXBCR_BAR_SIZE_MASK; + regSize |= (sizeToReg << PXBCR_BAR_SIZE_OFFS) ; + + MV_REG_WRITE(PEX_BAR_CTRL_REG(pexIf,barNum),regSize); + + } + + /* set size */ + + + + /* Read base address low */ + regBaseLow = MV_REG_READ(PEX_CFG_DIRECT_ACCESS(pexIf, + PEX_MV_BAR_BASE(barNum))); + + /* clear current base */ + if (PEX_INTER_REGS_BAR == barNum) + { + regBaseLow &= ~PXBIR_BASE_MASK; + regBaseLow |= (pAddrWin->addrWin.baseLow & PXBIR_BASE_MASK); + } + else + { + regBaseLow &= ~PXBR_BASE_MASK; + regBaseLow |= (pAddrWin->addrWin.baseLow & PXBR_BASE_MASK); + } + + /* if we had a previous value that contain the bar type (MeM\IO), we want to + restore it */ + regBaseLow |= PEX_BAR_DEFAULT_ATTRIB; + + + + /* write base low */ + MV_REG_WRITE(PEX_CFG_DIRECT_ACCESS(pexIf,PEX_MV_BAR_BASE(barNum)), + regBaseLow); + + if (pAddrWin->addrWin.baseHigh != 0) + { + /* Read base address high */ + MV_REG_WRITE(PEX_CFG_DIRECT_ACCESS(pexIf,PEX_MV_BAR_BASE_HIGH(barNum)), + pAddrWin->addrWin.baseHigh); + + } + + /* lastly enable the Bar */ + if (pAddrWin->enable == MV_TRUE) + { + if (PEX_INTER_REGS_BAR != barNum) /* internal registers + are enabled always */ + { + MV_REG_BIT_SET(PEX_BAR_CTRL_REG(pexIf,barNum),PXBCR_BAR_EN); + } + } + else if (MV_FALSE == pAddrWin->enable) + { + if (PEX_INTER_REGS_BAR != barNum) /* internal registers + are enabled always */ + { + MV_REG_BIT_RESET(PEX_BAR_CTRL_REG(pexIf,barNum),PXBCR_BAR_EN); + } + + } + + + + return MV_OK; +} + + +/******************************************************************************* +* mvPexBarGet - Get PEX bar address and size +* +* DESCRIPTION: +* +* INPUT: +* +* OUTPUT: +* None. +* +* RETURN: +* MV_BAD_PARAM for bad parameters ,MV_ERROR on error ! otherwise MV_OK +* +*******************************************************************************/ + +MV_STATUS mvPexBarGet(MV_U32 pexIf, + MV_U32 barNum, + MV_PEX_BAR *pAddrWin) +{ + /* check parameters */ + if(pexIf >= mvCtrlPexMaxIfGet()) + { + mvOsPrintf("mvPexBarGet: ERR. Invalid PEX interface %d\n", pexIf); + return MV_BAD_PARAM; + } + + if(barNum >= PEX_MAX_BARS) + { + mvOsPrintf("mvPexBarGet: ERR. Invalid bar number %d\n", barNum); + return MV_BAD_PARAM; + } + + /* read base low */ + pAddrWin->addrWin.baseLow = + MV_REG_READ(PEX_CFG_DIRECT_ACCESS(pexIf,PEX_MV_BAR_BASE(barNum))); + + + if (PEX_INTER_REGS_BAR == barNum) + { + pAddrWin->addrWin.baseLow &= PXBIR_BASE_MASK; + } + else + { + pAddrWin->addrWin.baseLow &= PXBR_BASE_MASK; + } + + + /* read base high */ + pAddrWin->addrWin.baseHigh = + MV_REG_READ(PEX_CFG_DIRECT_ACCESS(pexIf,PEX_MV_BAR_BASE_HIGH(barNum))); + + + /* Read bar size */ + if (PEX_INTER_REGS_BAR != barNum) /* internal registers have no size */ + { + pAddrWin->addrWin.size = MV_REG_READ(PEX_BAR_CTRL_REG(pexIf,barNum)); + + /* check if enable or not */ + if (pAddrWin->addrWin.size & PXBCR_BAR_EN) + { + pAddrWin->enable = MV_TRUE; + } + else + { + pAddrWin->enable = MV_FALSE; + } + + /* now get the size */ + pAddrWin->addrWin.size &= PXBCR_BAR_SIZE_MASK; + pAddrWin->addrWin.size >>= PXBCR_BAR_SIZE_OFFS; + + pAddrWin->addrWin.size = ctrlRegToSize(pAddrWin->addrWin.size, + PXBCR_BAR_SIZE_ALIGNMENT); + + } + else /* PEX_INTER_REGS_BAR */ + { + pAddrWin->addrWin.size = INTER_REGS_SIZE; + pAddrWin->enable = MV_TRUE; + } + + + return MV_OK; +} + +/******************************************************************************* +* mvPexBarEnable - +* +* DESCRIPTION: +* +* INPUT: +* +* OUTPUT: +* None. +* +* RETURN: +* MV_BAD_PARAM for bad parameters ,MV_ERROR on error ! otherwise MV_OK +* +*******************************************************************************/ + + +MV_STATUS mvPexBarEnable(MV_U32 pexIf, MV_U32 barNum, MV_BOOL enable) +{ + + MV_PEX_BAR pexBar; + + /* check parameters */ + if(pexIf >= mvCtrlPexMaxIfGet()) + { + mvOsPrintf("mvPexBarEnable: ERR. Invalid PEX interface %d\n", pexIf); + return MV_BAD_PARAM; + } + + + if(barNum >= PEX_MAX_BARS) + { + mvOsPrintf("mvPexBarEnable: ERR. Invalid bar number %d\n", barNum); + return MV_BAD_PARAM; + } + + if (PEX_INTER_REGS_BAR == barNum) + { + if (MV_TRUE == enable) + { + return MV_OK; + } + else + { + return MV_ERROR; + } + } + + + if (MV_FALSE == enable) + { + /* disable bar and quit */ + MV_REG_BIT_RESET(PEX_BAR_CTRL_REG(pexIf,barNum),PXBCR_BAR_EN); + return MV_OK; + } + + /* else */ + + if (mvPexBarGet(pexIf,barNum,&pexBar) != MV_OK) + { + mvOsPrintf("mvPexBarEnable: mvPexBarGet Failed\n"); + return MV_ERROR; + + } + + if (MV_TRUE == pexBar.enable) + { + /* it is already enabled !!! */ + return MV_OK; + } + + /* else enable the bar*/ + + pexBar.enable = MV_TRUE; + + if (mvPexBarSet(pexIf,barNum,&pexBar) != MV_OK) + { + mvOsPrintf("mvPexBarEnable: mvPexBarSet Failed\n"); + return MV_ERROR; + + } + + return MV_OK; +} + + +/******************************************************************************* +* pexWinOverlapDetect - Detect address windows overlapping +* +* DESCRIPTION: +* This function detects address window overlapping of a given address +* window in PEX BARs. +* +* INPUT: +* pAddrWin - Address window to be checked. +* bar - BAR to be accessed by slave. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_TRUE if the given address window overlap current address +* decode map, MV_FALSE otherwise. +* +*******************************************************************************/ +static MV_BOOL pexWinOverlapDetect(MV_U32 pexIf, + MV_U32 winNum, + MV_ADDR_WIN *pAddrWin) +{ + MV_U32 win; + MV_PEX_DEC_WIN addrDecWin; + + + for(win = 0; win < PEX_MAX_TARGET_WIN -2 ; win++) + { + /* don't check our target or illegal targets */ + if (winNum == win) + { + continue; + } + + /* Get window parameters */ + if (MV_OK != mvPexTargetWinGet(pexIf, win, &addrDecWin)) + { + mvOsPrintf("pexWinOverlapDetect: ERR. TargetWinGet failed win=%x\n", + win); + return MV_ERROR; + } + + /* Do not check disabled windows */ + if (MV_FALSE == addrDecWin.enable) + { + continue; + } + + + if(MV_TRUE == ctrlWinOverlapTest(pAddrWin, &addrDecWin.addrWin)) + { + mvOsPrintf("pexWinOverlapDetect: winNum %d overlap current %d\n", + winNum, win); + return MV_TRUE; + } + } + + return MV_FALSE; +} + +/******************************************************************************* +* pexIsWinWithinBar - Detect if address is within PEX bar boundries +* +* DESCRIPTION: +* +* INPUT: +* +* OUTPUT: +* None. +* +* RETURN: +* MV_TRUE if the given address window overlap current address +* decode map, MV_FALSE otherwise. +* +*******************************************************************************/ +static MV_BOOL pexIsWinWithinBar(MV_U32 pexIf, + MV_ADDR_WIN *pAddrWin) +{ + MV_U32 bar; + MV_PEX_BAR addrDecWin; + + for(bar = 0; bar < PEX_MAX_BARS; bar++) + { + + /* Get window parameters */ + if (MV_OK != mvPexBarGet(pexIf, bar, &addrDecWin)) + { + mvOsPrintf("pexIsWinWithinBar: ERR. mvPexBarGet failed\n"); + return MV_ERROR; + } + + /* Do not check disabled bars */ + if (MV_FALSE == addrDecWin.enable) + { + continue; + } + + + if(MV_TRUE == ctrlWinWithinWinTest(pAddrWin, &addrDecWin.addrWin)) + { + return MV_TRUE; + } + } + + return MV_FALSE; + +} + +/******************************************************************************* +* pexBarOverlapDetect - Detect address windows overlapping +* +* DESCRIPTION: +* This function detects address window overlapping of a given address +* window in PEX BARs. +* +* INPUT: +* pAddrWin - Address window to be checked. +* bar - BAR to be accessed by slave. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_TRUE if the given address window overlap current address +* decode map, MV_FALSE otherwise. +* +*******************************************************************************/ +static MV_BOOL pexBarOverlapDetect(MV_U32 pexIf, + MV_U32 barNum, + MV_ADDR_WIN *pAddrWin) +{ + MV_U32 bar; + MV_PEX_BAR barDecWin; + + + for(bar = 0; bar < PEX_MAX_BARS; bar++) + { + /* don't check our target or illegal targets */ + if (barNum == bar) + { + continue; + } + + /* Get window parameters */ + if (MV_OK != mvPexBarGet(pexIf, bar, &barDecWin)) + { + mvOsPrintf("pexBarOverlapDetect: ERR. TargetWinGet failed\n"); + return MV_ERROR; + } + + /* don'nt check disabled bars */ + if (barDecWin.enable == MV_FALSE) + { + continue; + } + + + if(MV_TRUE == ctrlWinOverlapTest(pAddrWin, &barDecWin.addrWin)) + { + mvOsPrintf("pexBarOverlapDetect: winNum %d overlap current %d\n", + barNum, bar); + return MV_TRUE; + } + } + + return MV_FALSE; +} + +/******************************************************************************* +* pexBarIsValid - Check if the given address window is valid +* +* DESCRIPTION: +* PEX spec restrict BAR base to be aligned to BAR size. +* This function checks if the given address window is valid. +* +* INPUT: +* baseLow - 32bit low base address. +* size - Window size. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_TRUE if the address window is valid, MV_FALSE otherwise. +* +*******************************************************************************/ +static MV_STATUS pexBarIsValid(MV_U32 baseLow, MV_U32 size) +{ + + /* PCI spec restrict BAR base to be aligned to BAR size */ + if(MV_IS_NOT_ALIGN(baseLow, size)) + { + return MV_ERROR; + } + else + { + return MV_TRUE; + } + + return MV_TRUE; +} + +/******************************************************************************* +* pexBarRegInfoGet - Get BAR register information +* +* DESCRIPTION: +* PEX BARs registers offsets are inconsecutive. +* This function gets a PEX BAR register information like register offsets +* and function location of the BAR. +* +* INPUT: +* pexIf - PEX interface number. +* bar - The PEX BAR in question. +* +* OUTPUT: +* pBarRegInfo - BAR register info struct. +* +* RETURN: +* MV_BAD_PARAM when bad parameters ,MV_ERROR on error ,othewise MV_OK +* +*******************************************************************************/ +static MV_STATUS pexWinRegInfoGet(MV_U32 pexIf, + MV_U32 winNum, + PEX_WIN_REG_INFO *pWinRegInfo) +{ + + if ((winNum >= 0)&&(winNum <=3)) + { + pWinRegInfo->baseLowRegOffs = PEX_WIN0_3_BASE_REG(pexIf,winNum); + pWinRegInfo->baseHighRegOffs = 0; + pWinRegInfo->sizeRegOffs = PEX_WIN0_3_CTRL_REG(pexIf,winNum); + pWinRegInfo->remapLowRegOffs = PEX_WIN0_3_REMAP_REG(pexIf,winNum); + pWinRegInfo->remapHighRegOffs = 0; + } + else if ((winNum >= 4)&&(winNum <=5)) + { + pWinRegInfo->baseLowRegOffs = PEX_WIN4_5_BASE_REG(pexIf,winNum); + pWinRegInfo->baseHighRegOffs = 0; + pWinRegInfo->sizeRegOffs = PEX_WIN4_5_CTRL_REG(pexIf,winNum); + pWinRegInfo->remapLowRegOffs = PEX_WIN4_5_REMAP_REG(pexIf,winNum); + pWinRegInfo->remapHighRegOffs = PEX_WIN4_5_REMAP_HIGH_REG(pexIf,winNum); + + } + else if (MV_PEX_WIN_DEFAULT == winNum) + { + pWinRegInfo->baseLowRegOffs = 0; + pWinRegInfo->baseHighRegOffs = 0; + pWinRegInfo->sizeRegOffs = PEX_WIN_DEFAULT_CTRL_REG(pexIf); + pWinRegInfo->remapLowRegOffs = 0; + pWinRegInfo->remapHighRegOffs = 0; + } + else if (MV_PEX_WIN_EXP_ROM == winNum) + { + pWinRegInfo->baseLowRegOffs = 0; + pWinRegInfo->baseHighRegOffs = 0; + pWinRegInfo->sizeRegOffs = PEX_WIN_EXP_ROM_CTRL_REG(pexIf); + pWinRegInfo->remapLowRegOffs = PEX_WIN_EXP_ROM_REMAP_REG(pexIf); + pWinRegInfo->remapHighRegOffs = 0; + + } + + return MV_OK; +} + +/******************************************************************************* +* pexBarNameGet - Get the string name of PEX BAR. +* +* DESCRIPTION: +* This function get the string name of PEX BAR. +* +* INPUT: +* bar - PEX bar number. +* +* OUTPUT: +* None. +* +* RETURN: +* pointer to the string name of PEX BAR. +* +*******************************************************************************/ +const MV_8* pexBarNameGet( MV_U32 bar ) +{ + switch( bar ) + { + case PEX_INTER_REGS_BAR: + return "Internal Regs Bar0...."; + case PEX_DRAM_BAR: + return "DRAM Bar1............."; + case PEX_DEVICE_BAR: + return "Devices Bar2.........."; + default: + return "Bar unknown"; + } +} +/******************************************************************************* +* mvPexAddrDecShow - Print the PEX address decode map (BARs and windows). +* +* DESCRIPTION: +* This function print the PEX address decode map (BARs and windows). +* +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* None. +* +*******************************************************************************/ +MV_VOID mvPexAddrDecShow(MV_VOID) +{ + MV_PEX_BAR pexBar; + MV_PEX_DEC_WIN win; + MV_U32 pexIf; + MV_U32 bar,winNum; + + for( pexIf = 0; pexIf < mvCtrlPexMaxIfGet(); pexIf++ ) + { + if (MV_FALSE == mvCtrlPwrClckGet(PEX_UNIT_ID, pexIf)) continue; + mvOsOutput( "\n" ); + mvOsOutput( "PEX%d:\n", pexIf ); + mvOsOutput( "-----\n" ); + + mvOsOutput( "\nPex Bars \n\n"); + + for( bar = 0; bar < PEX_MAX_BARS; bar++ ) + { + memset( &pexBar, 0, sizeof(MV_PEX_BAR) ); + + mvOsOutput( "%s ", pexBarNameGet(bar) ); + + if( mvPexBarGet( pexIf, bar, &pexBar ) == MV_OK ) + { + if( pexBar.enable ) + { + mvOsOutput( "base %08x, ", pexBar.addrWin.baseLow ); + mvSizePrint( pexBar.addrWin.size ); + mvOsOutput( "\n" ); + } + else + mvOsOutput( "disable\n" ); + } + } + mvOsOutput( "\nPex Decode Windows\n\n"); + + for( winNum = 0; winNum < PEX_MAX_TARGET_WIN - 2; winNum++) + { + memset( &win, 0,sizeof(MV_PEX_DEC_WIN) ); + + mvOsOutput( "win%d - ", winNum ); + + if ( mvPexTargetWinGet(pexIf,winNum,&win) == MV_OK) + { + if (win.enable) + { + mvOsOutput( "%s base %08x, ", + mvCtrlTargetNameGet(win.target), win.addrWin.baseLow ); + mvOsOutput( "...." ); + mvSizePrint( win.addrWin.size ); + + mvOsOutput( "\n" ); + } + else + mvOsOutput( "disable\n" ); + + + } + } + + memset( &win, 0,sizeof(MV_PEX_DEC_WIN) ); + + mvOsOutput( "default win - " ); + + if ( mvPexTargetWinGet(pexIf, MV_PEX_WIN_DEFAULT, &win) == MV_OK) + { + mvOsOutput( "%s ", + mvCtrlTargetNameGet(win.target) ); + mvOsOutput( "\n" ); + } + memset( &win, 0,sizeof(MV_PEX_DEC_WIN) ); + + mvOsOutput( "Expansion ROM - " ); + + if ( mvPexTargetWinGet(pexIf, MV_PEX_WIN_EXP_ROM, &win) == MV_OK) + { + mvOsOutput( "%s ", + mvCtrlTargetNameGet(win.target) ); + mvOsOutput( "\n" ); + } + + } +} + + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysPex.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysPex.h new file mode 100644 index 0000000..3505613 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysPex.h @@ -0,0 +1,348 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#ifndef __INCSysPEXH +#define __INCSysPEXH + +#include "mvCommon.h" +#include "ctrlEnv/sys/mvCpuIf.h" +#include "ctrlEnv/mvCtrlEnvLib.h" +#include "ctrlEnv/mvCtrlEnvAddrDec.h" + +/* 4KB granularity */ +#define MINIMUM_WINDOW_SIZE 0x1000 +#define MINIMUM_BAR_SIZE 0x1000 +#define MINIMUM_BAR_SIZE_MASK 0xFFFFF000 +#define BAR_SIZE_OFFS 12 +#define BAR_SIZE_MASK (0xFFFFF << BAR_SIZE_OFFS) + + + +#define MV_PEX_WIN_DEFAULT 6 +#define MV_PEX_WIN_EXP_ROM 7 +#define PEX_MAX_TARGET_WIN 8 + + +#define PEX_MAX_BARS 3 +#define PEX_INTER_REGS_BAR 0 +#define PEX_DRAM_BAR 1 +#define PEX_DEVICE_BAR 2 + +/*************************************/ +/* PCI Express BAR Control Registers */ +/*************************************/ +#define PEX_BAR_CTRL_REG(pexIf,bar) (0x41804 + (bar-1)*4- (pexIf)*0x10000) +#define PEX_EXP_ROM_BAR_CTRL_REG(pexIf) (0x4180C - (pexIf)*0x10000) + + +/* PCI Express BAR Control Register */ +/* PEX_BAR_CTRL_REG (PXBCR) */ + +#define PXBCR_BAR_EN BIT0 +#define PXBCR_BAR_SIZE_OFFS 16 +#define PXBCR_BAR_SIZE_MASK (0xffff << PXBCR_BAR_SIZE_OFFS) +#define PXBCR_BAR_SIZE_ALIGNMENT 0x10000 + + + +/* PCI Express Expansion ROM BAR Control Register */ +/* PEX_EXP_ROM_BAR_CTRL_REG (PXERBCR) */ + +#define PXERBCR_EXPROM_EN BIT0 +#define PXERBCR_EXPROMSZ_OFFS 19 +#define PXERBCR_EXPROMSZ_MASK (0xf << PXERBCR_EXPROMSZ_OFFS) +#define PXERBCR_EXPROMSZ_512KB (0x0 << PXERBCR_EXPROMSZ_OFFS) +#define PXERBCR_EXPROMSZ_1024KB (0x1 << PXERBCR_EXPROMSZ_OFFS) +#define PXERBCR_EXPROMSZ_2048KB (0x3 << PXERBCR_EXPROMSZ_OFFS) +#define PXERBCR_EXPROMSZ_4096KB (0x7 << PXERBCR_EXPROMSZ_OFFS) + +/************************************************/ +/* PCI Express Address Window Control Registers */ +/************************************************/ +#define PEX_WIN0_3_CTRL_REG(pexIf,winNum) \ + (0x41820 + (winNum) * 0x10 - (pexIf) * 0x10000) +#define PEX_WIN0_3_BASE_REG(pexIf,winNum) \ + (0x41824 + (winNum) * 0x10 - (pexIf) * 0x10000) +#define PEX_WIN0_3_REMAP_REG(pexIf,winNum) \ + (0x4182C + (winNum) * 0x10 - (pexIf) * 0x10000) +#define PEX_WIN4_5_CTRL_REG(pexIf,winNum) \ + (0x41860 + (winNum - 4) * 0x20 - (pexIf) * 0x10000) +#define PEX_WIN4_5_BASE_REG(pexIf,winNum) \ + (0x41864 + (winNum - 4) * 0x20 - (pexIf) * 0x10000) +#define PEX_WIN4_5_REMAP_REG(pexIf,winNum) \ + (0x4186C + (winNum - 4) * 0x20 - (pexIf) * 0x10000) +#define PEX_WIN4_5_REMAP_HIGH_REG(pexIf,winNum) \ + (0x41870 + (winNum - 4) * 0x20 - (pexIf) * 0x10000) + +#define PEX_WIN_DEFAULT_CTRL_REG(pexIf) (0x418B0 - (pexIf) * 0x10000) +#define PEX_WIN_EXP_ROM_CTRL_REG(pexIf) (0x418C0 - (pexIf) * 0x10000) +#define PEX_WIN_EXP_ROM_REMAP_REG(pexIf) (0x418C4 - (pexIf) * 0x10000) + +/* PCI Express Window Control Register */ +/* PEX_WIN_CTRL_REG (PXWCR) */ + +#define PXWCR_WIN_EN BIT0 /* Window Enable.*/ + +#define PXWCR_WIN_BAR_MAP_OFFS 1 /* Mapping to BAR.*/ +#define PXWCR_WIN_BAR_MAP_MASK BIT1 +#define PXWCR_WIN_BAR_MAP_BAR1 (0 << PXWCR_WIN_BAR_MAP_OFFS) +#define PXWCR_WIN_BAR_MAP_BAR2 (1 << PXWCR_WIN_BAR_MAP_OFFS) + +#define PXWCR_TARGET_OFFS 4 /*Unit ID */ +#define PXWCR_TARGET_MASK (0xf << PXWCR_TARGET_OFFS) + +#define PXWCR_ATTRIB_OFFS 8 /* target attributes */ +#define PXWCR_ATTRIB_MASK (0xff << PXWCR_ATTRIB_OFFS) + +#define PXWCR_SIZE_OFFS 16 /* size */ +#define PXWCR_SIZE_MASK (0xffff << PXWCR_SIZE_OFFS) +#define PXWCR_SIZE_ALIGNMENT 0x10000 + +/* PCI Express Window Base Register */ +/* PEX_WIN_BASE_REG (PXWBR)*/ + +#define PXWBR_BASE_OFFS 16 /* address[31:16] */ +#define PXWBR_BASE_MASK (0xffff << PXWBR_BASE_OFFS) +#define PXWBR_BASE_ALIGNMENT 0x10000 + +/* PCI Express Window Remap Register */ +/* PEX_WIN_REMAP_REG (PXWRR)*/ + +#define PXWRR_REMAP_EN BIT0 +#define PXWRR_REMAP_OFFS 16 +#define PXWRR_REMAP_MASK (0xffff << PXWRR_REMAP_OFFS) +#define PXWRR_REMAP_ALIGNMENT 0x10000 + +/* PCI Express Window Remap (High) Register */ +/* PEX_WIN_REMAP_HIGH_REG (PXWRHR)*/ + +#define PXWRHR_REMAP_HIGH_OFFS 0 +#define PXWRHR_REMAP_HIGH_MASK (0xffffffff << PXWRHR_REMAP_HIGH_OFFS) + +/* PCI Express Default Window Control Register */ +/* PEX_WIN_DEFAULT_CTRL_REG (PXWDCR) */ + +#define PXWDCR_TARGET_OFFS 4 /*Unit ID */ +#define PXWDCR_TARGET_MASK (0xf << PXWDCR_TARGET_OFFS) +#define PXWDCR_ATTRIB_OFFS 8 /* target attributes */ +#define PXWDCR_ATTRIB_MASK (0xff << PXWDCR_ATTRIB_OFFS) + +/* PCI Express Expansion ROM Window Control Register */ +/* PEX_WIN_EXP_ROM_CTRL_REG (PXWERCR)*/ + +#define PXWERCR_TARGET_OFFS 4 /*Unit ID */ +#define PXWERCR_TARGET_MASK (0xf << PXWERCR_TARGET_OFFS) +#define PXWERCR_ATTRIB_OFFS 8 /* target attributes */ +#define PXWERCR_ATTRIB_MASK (0xff << PXWERCR_ATTRIB_OFFS) + +/* PCI Express Expansion ROM Window Remap Register */ +/* PEX_WIN_EXP_ROM_REMAP_REG (PXWERRR)*/ + +#define PXWERRR_REMAP_EN BIT0 +#define PXWERRR_REMAP_OFFS 16 +#define PXWERRR_REMAP_MASK (0xffff << PXWERRR_REMAP_OFFS) +#define PXWERRR_REMAP_ALIGNMENT 0x10000 + + + +/*PEX_MEMORY_BAR_BASE_ADDR(barNum) (PXMBBA)*/ +/* PCI Express BAR0 Internal Register*/ +/*PEX BAR0_INTER_REG (PXBIR)*/ + +#define PXBIR_IOSPACE BIT0 /* Memory Space Indicator */ + +#define PXBIR_TYPE_OFFS 1 /* BAR Type/Init Val. */ +#define PXBIR_TYPE_MASK (0x3 << PXBIR_TYPE_OFFS) +#define PXBIR_TYPE_32BIT_ADDR (0x0 << PXBIR_TYPE_OFFS) +#define PXBIR_TYPE_64BIT_ADDR (0x2 << PXBIR_TYPE_OFFS) + +#define PXBIR_PREFETCH_EN BIT3 /* Prefetch Enable */ + +#define PXBIR_BASE_OFFS 20 /* Base address. Address bits [31:20] */ +#define PXBIR_BASE_MASK (0xfff << PXBIR_BASE_OFFS) +#define PXBIR_BASE_ALIGNMET (1 << PXBIR_BASE_OFFS) + + +/* PCI Express BAR0 Internal (High) Register*/ +/*PEX BAR0_INTER_REG_HIGH (PXBIRH)*/ + +#define PXBIRH_BASE_OFFS 0 /* Base address. Bits [63:32] */ +#define PXBIRH_BASE_MASK (0xffffffff << PBBHR_BASE_OFFS) + + +#define PEX_BAR_DEFAULT_ATTRIB 0xc /* Memory - Prefetch - 64 bit address */ +#define PEX_BAR0_DEFAULT_ATTRIB PEX_BAR_DEFAULT_ATTRIB +#define PEX_BAR1_DEFAULT_ATTRIB PEX_BAR_DEFAULT_ATTRIB +#define PEX_BAR2_DEFAULT_ATTRIB PEX_BAR_DEFAULT_ATTRIB + + +/* PCI Express BAR1 Register */ +/* PCI Express BAR2 Register*/ +/*PEX BAR1_REG (PXBR)*/ +/*PEX BAR2_REG (PXBR)*/ + +#define PXBR_IOSPACE BIT0 /* Memory Space Indicator */ + +#define PXBR_TYPE_OFFS 1 /* BAR Type/Init Val. */ +#define PXBR_TYPE_MASK (0x3 << PXBR_TYPE_OFFS) +#define PXBR_TYPE_32BIT_ADDR (0x0 << PXBR_TYPE_OFFS) +#define PXBR_TYPE_64BIT_ADDR (0x2 << PXBR_TYPE_OFFS) + +#define PXBR_PREFETCH_EN BIT3 /* Prefetch Enable */ + +#define PXBR_BASE_OFFS 16 /* Base address. Address bits [31:16] */ +#define PXBR_BASE_MASK (0xffff << PXBR_BASE_OFFS) +#define PXBR_BASE_ALIGNMET (1 << PXBR_BASE_OFFS) + + +/* PCI Express BAR1 (High) Register*/ +/* PCI Express BAR2 (High) Register*/ +/*PEX BAR1_REG_HIGH (PXBRH)*/ +/*PEX BAR2_REG_HIGH (PXBRH)*/ + +#define PXBRH_BASE_OFFS 0 /* Base address. Address bits [63:32] */ +#define PXBRH_BASE_MASK (0xffffffff << PXBRH_BASE_OFFS) + +/* PCI Express Expansion ROM BAR Register*/ +/*PEX_EXPANSION_ROM_BASE_ADDR_REG (PXERBAR)*/ + +#define PXERBAR_EXPROMEN BIT0 /* Expansion ROM Enable */ + +#define PXERBAR_BASE_512K_OFFS 19 /* Expansion ROM Base Address */ +#define PXERBAR_BASE_512K_MASK (0x1fff << PXERBAR_BASE_512K_OFFS) + +#define PXERBAR_BASE_1MB_OFFS 20 /* Expansion ROM Base Address */ +#define PXERBAR_BASE_1MB_MASK (0xfff << PXERBAR_BASE_1MB_OFFS) + +#define PXERBAR_BASE_2MB_OFFS 21 /* Expansion ROM Base Address */ +#define PXERBAR_BASE_2MB_MASK (0x7ff << PXERBAR_BASE_2MB_OFFS) + +#define PXERBAR_BASE_4MB_OFFS 22 /* Expansion ROM Base Address */ +#define PXERBAR_BASE_4MB_MASK (0x3ff << PXERBAR_BASE_4MB_OFFS) + +/* PEX Bar attributes */ +typedef struct _mvPexBar +{ + MV_ADDR_WIN addrWin; /* An address window*/ + MV_BOOL enable; /* Address decode window is enabled/disabled */ + +}MV_PEX_BAR; + +/* PEX Remap Window attributes */ +typedef struct _mvPexRemapWin +{ + MV_ADDR_WIN addrWin; /* An address window*/ + MV_BOOL enable; /* Address decode window is enabled/disabled */ + +}MV_PEX_REMAP_WIN; + +/* PEX Remap Window attributes */ +typedef struct _mvPexDecWin +{ + MV_TARGET target; + MV_ADDR_WIN addrWin; /* An address window*/ + MV_U32 targetBar; + MV_U8 attrib; /* chip select attributes */ + MV_TARGET_ID targetId; /* Target Id of this MV_TARGET */ + MV_BOOL enable; /* Address decode window is enabled/disabled */ + +}MV_PEX_DEC_WIN; + +/* Global Functions prototypes */ +/* mvPexHalInit - Initialize PEX interfaces*/ +MV_STATUS mvPexInit(MV_U32 pexIf, MV_PEX_TYPE pexType); + + +/* mvPexTargetWinSet - Set PEX to peripheral target address window BAR*/ +MV_STATUS mvPexTargetWinSet(MV_U32 pexIf, MV_U32 winNum, + MV_PEX_DEC_WIN *pAddrDecWin); + +/* mvPexTargetWinGet - Get PEX to peripheral target address window*/ +MV_STATUS mvPexTargetWinGet(MV_U32 pexIf, MV_U32 winNum, + MV_PEX_DEC_WIN *pAddrDecWin); + +/* mvPexTargetWinEnable - Enable/disable a PEX BAR window*/ +MV_STATUS mvPexTargetWinEnable(MV_U32 pexIf,MV_U32 winNum, MV_BOOL enable); + +/* mvPexTargetWinRemap - Set PEX to target address window remap.*/ +MV_STATUS mvPexTargetWinRemap(MV_U32 pexIf, MV_U32 winNum, + MV_PEX_REMAP_WIN *pAddrWin); + +/* mvPexTargetWinRemapEnable -enable\disable a PEX Window remap.*/ +MV_STATUS mvPexTargetWinRemapEnable(MV_U32 pexIf, MV_U32 winNum, + MV_BOOL enable); + +/* mvPexBarSet - Set PEX bar address and size */ +MV_STATUS mvPexBarSet(MV_U32 pexIf, MV_U32 barNum, MV_PEX_BAR *addrWin); + +/* mvPexBarGet - Get PEX bar address and size */ +MV_STATUS mvPexBarGet(MV_U32 pexIf, MV_U32 barNum, MV_PEX_BAR *addrWin); + +/* mvPexBarEnable - enable\disable a PEX bar*/ +MV_STATUS mvPexBarEnable(MV_U32 pexIf, MV_U32 barNum, MV_BOOL enable); + +/* mvPexAddrDecShow - Display address decode windows attributes */ +MV_VOID mvPexAddrDecShow(MV_VOID); + +#endif diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysSata.c b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysSata.c new file mode 100644 index 0000000..f100a12 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysSata.c @@ -0,0 +1,430 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + + +#include "mvTypes.h" +#include "mvCommon.h" +#include "mvOs.h" +#include "ctrlEnv/mvCtrlEnvLib.h" +#include "cpu/mvCpu.h" +#include "ctrlEnv/sys/mvCpuIf.h" +#include "sata/CoreDriver/mvRegs.h" +#include "ctrlEnv/sys/mvSysSata.h" + +MV_TARGET sataAddrDecPrioTab[] = +{ +#if defined(MV_INCLUDE_SDRAM_CS0) + SDRAM_CS0, +#endif +#if defined(MV_INCLUDE_SDRAM_CS1) + SDRAM_CS1, +#endif +#if defined(MV_INCLUDE_SDRAM_CS2) + SDRAM_CS2, +#endif +#if defined(MV_INCLUDE_SDRAM_CS3) + SDRAM_CS3, +#endif +#if defined(MV_INCLUDE_PEX) + PEX0_MEM, +#endif + TBL_TERM +}; + + +/******************************************************************************* +* sataWinOverlapDetect - Detect SATA address windows overlapping +* +* DESCRIPTION: +* An unpredicted behaviur is expected in case SATA address decode +* windows overlapps. +* This function detects SATA address decode windows overlapping of a +* specified window. The function does not check the window itself for +* overlapping. The function also skipps disabled address decode windows. +* +* INPUT: +* winNum - address decode window number. +* pAddrDecWin - An address decode window struct. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_TRUE if the given address window overlap current address +* decode map, MV_FALSE otherwise, MV_ERROR if reading invalid data +* from registers. +* +*******************************************************************************/ +static MV_STATUS sataWinOverlapDetect(int dev, MV_U32 winNum, + MV_ADDR_WIN *pAddrWin) +{ + MV_U32 winNumIndex; + MV_SATA_DEC_WIN addrDecWin; + + for(winNumIndex=0; winNumIndex= MV_SATA_MAX_ADDR_DECODE_WIN) + { + mvOsPrintf("%s: ERR. Invalid win num %d\n",__FUNCTION__, winNum); + return MV_BAD_PARAM; + } + + /* Check if the requested window overlapps with current windows */ + if (MV_TRUE == sataWinOverlapDetect(dev, winNum, &pAddrDecWin->addrWin)) + { + mvOsPrintf("%s: ERR. Window %d overlap\n", __FUNCTION__, winNum); + return MV_ERROR; + } + + /* check if address is aligned to the size */ + if(MV_IS_NOT_ALIGN(pAddrDecWin->addrWin.baseLow, pAddrDecWin->addrWin.size)) + { + mvOsPrintf("mvSataWinSet:Error setting SATA window %d to "\ + "target %s.\nAddress 0x%08x is unaligned to size 0x%x.\n", + winNum, + mvCtrlTargetNameGet(pAddrDecWin->target), + pAddrDecWin->addrWin.baseLow, + pAddrDecWin->addrWin.size); + return MV_ERROR; + } + + decRegs.baseReg = 0; + decRegs.sizeReg = 0; + + if (MV_OK != mvCtrlAddrDecToReg(&(pAddrDecWin->addrWin),&decRegs)) + { + mvOsPrintf("%s: mvCtrlAddrDecToReg Failed\n", __FUNCTION__); + return MV_ERROR; + } + + mvCtrlAttribGet(pAddrDecWin->target, &targetAttribs); + + /* set attributes */ + decRegs.sizeReg &= ~MV_SATA_WIN_ATTR_MASK; + decRegs.sizeReg |= (targetAttribs.attrib << MV_SATA_WIN_ATTR_OFFSET); + + /* set target ID */ + decRegs.sizeReg &= ~MV_SATA_WIN_TARGET_MASK; + decRegs.sizeReg |= (targetAttribs.targetId << MV_SATA_WIN_TARGET_OFFSET); + + if (pAddrDecWin->enable == MV_TRUE) + { + decRegs.sizeReg |= MV_SATA_WIN_ENABLE_MASK; + } + else + { + decRegs.sizeReg &= ~MV_SATA_WIN_ENABLE_MASK; + } + + MV_REG_WRITE( MV_SATA_WIN_CTRL_REG(dev, winNum), decRegs.sizeReg); + MV_REG_WRITE( MV_SATA_WIN_BASE_REG(dev, winNum), decRegs.baseReg); + + return MV_OK; +} + +/******************************************************************************* +* mvSataWinGet - Get SATA peripheral target address window. +* +* DESCRIPTION: +* Get SATA peripheral target address window. +* +* INPUT: +* winNum - SATA target address decode window number. +* +* OUTPUT: +* pAddrDecWin - SATA target window data structure. +* +* RETURN: +* MV_ERROR if register parameters are invalid. +* +*******************************************************************************/ +MV_STATUS mvSataWinGet(int dev, MV_U32 winNum, MV_SATA_DEC_WIN *pAddrDecWin) +{ + MV_DEC_REGS decRegs; + MV_TARGET_ATTRIB targetAttrib; + + /* Parameter checking */ + if (winNum >= MV_SATA_MAX_ADDR_DECODE_WIN) + { + mvOsPrintf("%s (dev=%d): ERR. Invalid winNum %d\n", + __FUNCTION__, dev, winNum); + return MV_NOT_SUPPORTED; + } + + decRegs.baseReg = MV_REG_READ( MV_SATA_WIN_BASE_REG(dev, winNum) ); + decRegs.sizeReg = MV_REG_READ( MV_SATA_WIN_CTRL_REG(dev, winNum) ); + + if (MV_OK != mvCtrlRegToAddrDec(&decRegs, &pAddrDecWin->addrWin) ) + { + mvOsPrintf("%s: mvCtrlRegToAddrDec Failed\n", __FUNCTION__); + return MV_ERROR; + } + + /* attrib and targetId */ + targetAttrib.attrib = (decRegs.sizeReg & MV_SATA_WIN_ATTR_MASK) >> + MV_SATA_WIN_ATTR_OFFSET; + targetAttrib.targetId = (decRegs.sizeReg & MV_SATA_WIN_TARGET_MASK) >> + MV_SATA_WIN_TARGET_OFFSET; + + pAddrDecWin->target = mvCtrlTargetGet(&targetAttrib); + + /* Check if window is enabled */ + if(decRegs.sizeReg & MV_SATA_WIN_ENABLE_MASK) + { + pAddrDecWin->enable = MV_TRUE; + } + else + { + pAddrDecWin->enable = MV_FALSE; + } + return MV_OK; +} +/******************************************************************************* +* mvSataAddrDecShow - Print the SATA address decode map. +* +* DESCRIPTION: +* This function print the SATA address decode map. +* +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* None. +* +*******************************************************************************/ +MV_VOID mvSataAddrDecShow(MV_VOID) +{ + + MV_SATA_DEC_WIN win; + int i,j; + + + + for( j = 0; j < MV_SATA_MAX_CHAN; j++ ) + { + if (MV_FALSE == mvCtrlPwrClckGet(SATA_UNIT_ID, j)) + return; + + mvOsOutput( "\n" ); + mvOsOutput( "SATA %d:\n", j ); + mvOsOutput( "----\n" ); + + for( i = 0; i < MV_SATA_MAX_ADDR_DECODE_WIN; i++ ) + { + memset( &win, 0, sizeof(MV_SATA_DEC_WIN) ); + + mvOsOutput( "win%d - ", i ); + + if( mvSataWinGet(j, i, &win ) == MV_OK ) + { + if( win.enable ) + { + mvOsOutput( "%s base %08x, ", + mvCtrlTargetNameGet(win.target), win.addrWin.baseLow ); + mvOsOutput( "...." ); + + mvSizePrint( win.addrWin.size ); + + mvOsOutput( "\n" ); + } + else + mvOsOutput( "disable\n" ); + } + } + } +} + + +/******************************************************************************* +* mvSataWinInit - Initialize the integrated SATA target address window. +* +* DESCRIPTION: +* Initialize the SATA peripheral target address window. +* +* INPUT: +* +* +* OUTPUT: +* +* +* RETURN: +* MV_ERROR if register parameters are invalid. +* +*******************************************************************************/ +MV_STATUS mvSataWinInit(MV_VOID) +{ + int winNum; + MV_SATA_DEC_WIN sataWin; + MV_CPU_DEC_WIN cpuAddrDecWin; + MV_U32 status, winPrioIndex = 0; + + /* Initiate Sata address decode */ + + /* First disable all address decode windows */ + for(winNum = 0; winNum < MV_SATA_MAX_ADDR_DECODE_WIN; winNum++) + { + MV_U32 regVal = MV_REG_READ(MV_SATA_WIN_CTRL_REG(0, winNum)); + regVal &= ~MV_SATA_WIN_ENABLE_MASK; + MV_REG_WRITE(MV_SATA_WIN_CTRL_REG(0, winNum), regVal); + } + + winNum = 0; + while( (sataAddrDecPrioTab[winPrioIndex] != TBL_TERM) && + (winNum < MV_SATA_MAX_ADDR_DECODE_WIN) ) + { + /* first get attributes from CPU If */ + status = mvCpuIfTargetWinGet(sataAddrDecPrioTab[winPrioIndex], + &cpuAddrDecWin); + + if(MV_NO_SUCH == status) + { + winPrioIndex++; + continue; + } + if (MV_OK != status) + { + mvOsPrintf("%s: ERR. mvCpuIfTargetWinGet failed\n", __FUNCTION__); + return MV_ERROR; + } + + if (cpuAddrDecWin.enable == MV_TRUE) + { + sataWin.addrWin.baseHigh = cpuAddrDecWin.addrWin.baseHigh; + sataWin.addrWin.baseLow = cpuAddrDecWin.addrWin.baseLow; + sataWin.addrWin.size = cpuAddrDecWin.addrWin.size; + sataWin.enable = MV_TRUE; + sataWin.target = sataAddrDecPrioTab[winPrioIndex]; + + if(MV_OK != mvSataWinSet(0/*dev*/, winNum, &sataWin)) + { + return MV_ERROR; + } + winNum++; + } + winPrioIndex++; + } + return MV_OK; +} + + + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysSata.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysSata.h new file mode 100644 index 0000000..325fb8d --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysSata.h @@ -0,0 +1,128 @@ + +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ +#ifndef __INCMVSysSataAddrDech +#define __INCMVSysSataAddrDech + +#include "mvCommon.h" +#include "ctrlEnv/mvCtrlEnvLib.h" +#include "ctrlEnv/sys/mvCpuIf.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _mvSataDecWin +{ + MV_TARGET target; + MV_ADDR_WIN addrWin; /* An address window*/ + MV_BOOL enable; /* Address decode window is enabled/disabled */ + +} MV_SATA_DEC_WIN; + + +#define MV_SATA_MAX_ADDR_DECODE_WIN 4 + +#define MV_SATA_WIN_CTRL_REG(dev, win) (SATA_REG_BASE + 0x30 + ((win)<<4)) +#define MV_SATA_WIN_BASE_REG(dev, win) (SATA_REG_BASE + 0x34 + ((win)<<4)) + +/* BITs in Bridge Interrupt Cause and Mask registers */ +#define MV_SATA_ADDR_DECODE_ERROR_BIT 0 +#define MV_SATA_ADDR_DECODE_ERROR_MASK (1<= MV_SDMMC_MAX_ADDR_DECODE_WIN) + { + mvOsPrintf("%s: ERR. Invalid win num %d\n",__FUNCTION__, winNum); + return MV_BAD_PARAM; + } + + /* Check if the requested window overlapps with current windows */ + if (MV_TRUE == sdmmcWinOverlapDetect(dev, winNum, &pAddrDecWin->addrWin)) + { + mvOsPrintf("%s: ERR. Window %d overlap\n", __FUNCTION__, winNum); + return MV_ERROR; + } + + /* check if address is aligned to the size */ + if(MV_IS_NOT_ALIGN(pAddrDecWin->addrWin.baseLow, pAddrDecWin->addrWin.size)) + { + mvOsPrintf("mvSdmmcWinSet:Error setting SDMMC window %d to "\ + "target %s.\nAddress 0x%08x is unaligned to size 0x%x.\n", + winNum, + mvCtrlTargetNameGet(pAddrDecWin->target), + pAddrDecWin->addrWin.baseLow, + pAddrDecWin->addrWin.size); + return MV_ERROR; + } + + decRegs.baseReg = 0; + decRegs.sizeReg = 0; + + if (MV_OK != mvCtrlAddrDecToReg(&(pAddrDecWin->addrWin),&decRegs)) + { + mvOsPrintf("%s: mvCtrlAddrDecToReg Failed\n", __FUNCTION__); + return MV_ERROR; + } + + mvCtrlAttribGet(pAddrDecWin->target, &targetAttribs); + + /* set attributes */ + decRegs.sizeReg &= ~MV_SDMMC_WIN_ATTR_MASK; + decRegs.sizeReg |= (targetAttribs.attrib << MV_SDMMC_WIN_ATTR_OFFSET); + + /* set target ID */ + decRegs.sizeReg &= ~MV_SDMMC_WIN_TARGET_MASK; + decRegs.sizeReg |= (targetAttribs.targetId << MV_SDMMC_WIN_TARGET_OFFSET); + + if (pAddrDecWin->enable == MV_TRUE) + { + decRegs.sizeReg |= MV_SDMMC_WIN_ENABLE_MASK; + } + else + { + decRegs.sizeReg &= ~MV_SDMMC_WIN_ENABLE_MASK; + } + + MV_REG_WRITE( MV_SDMMC_WIN_CTRL_REG(dev, winNum), decRegs.sizeReg); + MV_REG_WRITE( MV_SDMMC_WIN_BASE_REG(dev, winNum), decRegs.baseReg); + + return MV_OK; +} + +/******************************************************************************* +* mvSdmmcWinGet - Get SDMMC peripheral target address window. +* +* DESCRIPTION: +* Get SDMMC peripheral target address window. +* +* INPUT: +* winNum - SDMMC target address decode window number. +*d +* OUTPUT: +* pAddrDecWin - SDMMC target window data structure. +* +* RETURN: +* MV_ERROR if register parameters are invalid. +* +*******************************************************************************/ +MV_STATUS mvSdmmcWinGet(int dev, MV_U32 winNum, MV_SDMMC_DEC_WIN *pAddrDecWin) +{ + MV_DEC_REGS decRegs; + MV_TARGET_ATTRIB targetAttrib; + + /* Parameter checking */ + if (winNum >= MV_SDMMC_MAX_ADDR_DECODE_WIN) + { + mvOsPrintf("%s (dev=%d): ERR. Invalid winNum %d\n", + __FUNCTION__, dev, winNum); + return MV_NOT_SUPPORTED; + } + + decRegs.baseReg = MV_REG_READ( MV_SDMMC_WIN_BASE_REG(dev, winNum) ); + decRegs.sizeReg = MV_REG_READ( MV_SDMMC_WIN_CTRL_REG(dev, winNum) ); + + if (MV_OK != mvCtrlRegToAddrDec(&decRegs, &pAddrDecWin->addrWin) ) + { + mvOsPrintf("%s: mvCtrlRegToAddrDec Failed\n", __FUNCTION__); + return MV_ERROR; + } + + /* attrib and targetId */ + targetAttrib.attrib = (decRegs.sizeReg & MV_SDMMC_WIN_ATTR_MASK) >> + MV_SDMMC_WIN_ATTR_OFFSET; + targetAttrib.targetId = (decRegs.sizeReg & MV_SDMMC_WIN_TARGET_MASK) >> + MV_SDMMC_WIN_TARGET_OFFSET; + + pAddrDecWin->target = mvCtrlTargetGet(&targetAttrib); + + /* Check if window is enabled */ + if(decRegs.sizeReg & MV_SDMMC_WIN_ENABLE_MASK) + { + pAddrDecWin->enable = MV_TRUE; + } + else + { + pAddrDecWin->enable = MV_FALSE; + } + return MV_OK; +} +/******************************************************************************* +* mvSdmmcAddrDecShow - Print the SDMMC address decode map. +* +* DESCRIPTION: +* This function print the SDMMC address decode map. +* +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* None. +* +*******************************************************************************/ +MV_VOID mvSdmmcAddrDecShow(MV_VOID) +{ + + MV_SDMMC_DEC_WIN win; + int i,j=0; + + + + if (MV_FALSE == mvCtrlPwrClckGet(SDIO_UNIT_ID, 0)) + return; + + mvOsOutput( "\n" ); + mvOsOutput( "SDMMC %d:\n", j ); + mvOsOutput( "----\n" ); + + for( i = 0; i < MV_SDMMC_MAX_ADDR_DECODE_WIN; i++ ) + { + memset( &win, 0, sizeof(MV_SDMMC_DEC_WIN) ); + + mvOsOutput( "win%d - ", i ); + + if( mvSdmmcWinGet(j, i, &win ) == MV_OK ) + { + if( win.enable ) + { + mvOsOutput( "%s base %08x, ", + mvCtrlTargetNameGet(win.target), win.addrWin.baseLow ); + mvOsOutput( "...." ); + + mvSizePrint( win.addrWin.size ); + + mvOsOutput( "\n" ); + } + else + mvOsOutput( "disable\n" ); + } + } +} + + +/******************************************************************************* +* mvSdmmcWinInit - Initialize the integrated SDMMC target address window. +* +* DESCRIPTION: +* Initialize the SDMMC peripheral target address window. +* +* INPUT: +* +* +* OUTPUT: +* +* +* RETURN: +* MV_ERROR if register parameters are invalid. +* +*******************************************************************************/ +MV_STATUS mvSdmmcWinInit(MV_VOID) +{ + int winNum; + MV_SDMMC_DEC_WIN sdmmcWin; + MV_CPU_DEC_WIN cpuAddrDecWin; + MV_U32 status, winPrioIndex = 0; + + /* Initiate Sdmmc address decode */ + + /* First disable all address decode windows */ + for(winNum = 0; winNum < MV_SDMMC_MAX_ADDR_DECODE_WIN; winNum++) + { + MV_U32 regVal = MV_REG_READ(MV_SDMMC_WIN_CTRL_REG(0, winNum)); + regVal &= ~MV_SDMMC_WIN_ENABLE_MASK; + MV_REG_WRITE(MV_SDMMC_WIN_CTRL_REG(0, winNum), regVal); + } + + winNum = 0; + while( (sdmmcAddrDecPrioTab[winPrioIndex] != TBL_TERM) && + (winNum < MV_SDMMC_MAX_ADDR_DECODE_WIN) ) + { + /* first get attributes from CPU If */ + status = mvCpuIfTargetWinGet(sdmmcAddrDecPrioTab[winPrioIndex], + &cpuAddrDecWin); + + if(MV_NO_SUCH == status) + { + winPrioIndex++; + continue; + } + if (MV_OK != status) + { + mvOsPrintf("%s: ERR. mvCpuIfTargetWinGet failed\n", __FUNCTION__); + return MV_ERROR; + } + + if (cpuAddrDecWin.enable == MV_TRUE) + { + sdmmcWin.addrWin.baseHigh = cpuAddrDecWin.addrWin.baseHigh; + sdmmcWin.addrWin.baseLow = cpuAddrDecWin.addrWin.baseLow; + sdmmcWin.addrWin.size = cpuAddrDecWin.addrWin.size; + sdmmcWin.enable = MV_TRUE; + sdmmcWin.target = sdmmcAddrDecPrioTab[winPrioIndex]; + + if(MV_OK != mvSdmmcWinSet(0/*dev*/, winNum, &sdmmcWin)) + { + return MV_ERROR; + } + winNum++; + } + winPrioIndex++; + } + return MV_OK; +} + + + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysSdmmc.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysSdmmc.h new file mode 100644 index 0000000..4c50a2b --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysSdmmc.h @@ -0,0 +1,125 @@ + +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ +#ifndef __INCMVSysSdmmcAddrDech +#define __INCMVSysSdmmcAddrDech + +#include "mvCommon.h" +#include "ctrlEnv/mvCtrlEnvLib.h" +#include "ctrlEnv/sys/mvCpuIf.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _mvSdmmcDecWin +{ + MV_TARGET target; + MV_ADDR_WIN addrWin; /* An address window*/ + MV_BOOL enable; /* Address decode window is enabled/disabled */ + +} MV_SDMMC_DEC_WIN; + + +#define MV_SDMMC_MAX_ADDR_DECODE_WIN 4 + +#define MV_SDMMC_WIN_CTRL_REG(dev, win) (MV_SDIO_REG_BASE + 0x108 + ((win)<<3)) +#define MV_SDMMC_WIN_BASE_REG(dev, win) (MV_SDIO_REG_BASE + 0x10c + ((win)<<3)) + + +/* BITs in Windows 0-3 Control and Base Registers */ +#define MV_SDMMC_WIN_ENABLE_BIT 0 +#define MV_SDMMC_WIN_ENABLE_MASK (1<= TDM_MBUS_MAX_WIN) + { + mvOsPrintf("mvTdmWinSet: ERR. Invalid win num %d\n",winNum); + return MV_BAD_PARAM; + } + + /* Check if the requested window overlapps with current windows */ + if (MV_TRUE == tdmWinOverlapDetect(winNum, &pAddrDecWin->addrWin)) + { + mvOsPrintf("mvTdmWinSet: ERR. Window %d overlap\n", winNum); + return MV_ERROR; + } + + /* check if address is aligned to the size */ + if (MV_IS_NOT_ALIGN(pAddrDecWin->addrWin.baseLow, pAddrDecWin->addrWin.size)) + { + mvOsPrintf("mvTdmWinSet: Error setting TDM window %d to "\ + "target %s.\nAddress 0x%08x is unaligned to size 0x%x.\n", + winNum, + mvCtrlTargetNameGet(pAddrDecWin->target), + pAddrDecWin->addrWin.baseLow, + pAddrDecWin->addrWin.size); + return MV_ERROR; + } + + decRegs.baseReg = MV_REG_READ(TDM_WIN_BASE_REG(winNum)); + decRegs.sizeReg = (MV_REG_READ(TDM_WIN_CTRL_REG(winNum)) & TDM_WIN_SIZE_MASK) >> TDM_WIN_SIZE_OFFS; + + if (MV_OK != mvCtrlAddrDecToReg(&(pAddrDecWin->addrWin),&decRegs)) + { + mvOsPrintf("mvTdmWinSet: mvCtrlAddrDecToReg Failed\n"); + return MV_ERROR; + } + + mvCtrlAttribGet(pAddrDecWin->target, &targetAttribs); + + /* for the safe side we disable the window before writing the new + values */ + mvTdmWinEnable(winNum, MV_FALSE); + + ctrlReg |= (targetAttribs.attrib << TDM_WIN_ATTRIB_OFFS); + ctrlReg |= (targetAttribs.targetId << TDM_WIN_TARGET_OFFS); + ctrlReg |= (decRegs.sizeReg & TDM_WIN_SIZE_MASK); + + /* Write to address base and control registers */ + MV_REG_WRITE(TDM_WIN_BASE_REG(winNum), decRegs.baseReg); + MV_REG_WRITE(TDM_WIN_CTRL_REG(winNum), ctrlReg); + /* Enable address decode target window */ + if (pAddrDecWin->enable == MV_TRUE) + { + mvTdmWinEnable(winNum, MV_TRUE); + } + return MV_OK; +} + +/******************************************************************************* +* mvTdmWinGet - Get peripheral target address window. +* +* DESCRIPTION: +* Get TDM peripheral target address window. +* +* INPUT: +* winNum - TDM to target address decode window number. +* +* OUTPUT: +* pAddrDecWin - TDM target window data structure. +* +* RETURN: +* MV_ERROR if register parameters are invalid. +* +*******************************************************************************/ + +MV_STATUS mvTdmWinGet(MV_U32 winNum, MV_TDM_DEC_WIN *pAddrDecWin) +{ + + MV_DEC_REGS decRegs; + MV_TARGET_ATTRIB targetAttrib; + + /* Parameter checking */ + if (winNum >= TDM_MBUS_MAX_WIN) + { + mvOsPrintf("mvTdmWinGet: ERR. Invalid winNum %d\n", winNum); + return MV_NOT_SUPPORTED; + } + + decRegs.baseReg = MV_REG_READ(TDM_WIN_BASE_REG(winNum)); + decRegs.sizeReg = (MV_REG_READ(TDM_WIN_CTRL_REG(winNum)) & TDM_WIN_SIZE_MASK) >> TDM_WIN_SIZE_OFFS; + + if (MV_OK != mvCtrlRegToAddrDec(&decRegs,&(pAddrDecWin->addrWin))) + { + mvOsPrintf("mvTdmWinGet: mvCtrlRegToAddrDec Failed \n"); + return MV_ERROR; + } + + /* attrib and targetId */ + targetAttrib.attrib = + (MV_REG_READ(TDM_WIN_CTRL_REG(winNum)) & TDM_WIN_ATTRIB_MASK) >> TDM_WIN_ATTRIB_OFFS; + targetAttrib.targetId = + (MV_REG_READ(TDM_WIN_CTRL_REG(winNum)) & TDM_WIN_TARGET_MASK) >> TDM_WIN_TARGET_OFFS; + + pAddrDecWin->target = mvCtrlTargetGet(&targetAttrib); + + /* Check if window is enabled */ + if (MV_REG_READ(TDM_WIN_CTRL_REG(winNum)) & TDM_WIN_ENABLE_MASK) + { + pAddrDecWin->enable = MV_TRUE; + } + else + { + pAddrDecWin->enable = MV_FALSE; + } + + return MV_OK; +} + +/******************************************************************************* +* mvTdmWinEnable - Enable/disable a TDM to target address window +* +* DESCRIPTION: +* This function enable/disable a TDM to target address window. +* According to parameter 'enable' the routine will enable the +* window, thus enabling TDM accesses (before enabling the window it is +* tested for overlapping). Otherwise, the window will be disabled. +* +* INPUT: +* winNum - TDM to target address decode window number. +* enable - Enable/disable parameter. +* +* OUTPUT: +* N/A +* +* RETURN: +* MV_ERROR if decode window number was wrong or enabled window overlapps. +* +*******************************************************************************/ +MV_STATUS mvTdmWinEnable(int winNum, MV_BOOL enable) +{ + MV_TDM_DEC_WIN addrDecWin; + + if (MV_TRUE == enable) + { + if (winNum >= TDM_MBUS_MAX_WIN) + { + mvOsPrintf("mvTdmWinEnable:ERR. Invalid winNum%d\n",winNum); + return MV_ERROR; + } + + /* First check for overlap with other enabled windows */ + /* Get current window */ + if (MV_OK != mvTdmWinGet(winNum, &addrDecWin)) + { + mvOsPrintf("mvTdmWinEnable:ERR. targetWinGet fail\n"); + return MV_ERROR; + } + /* Check for overlapping */ + if (MV_FALSE == tdmWinOverlapDetect(winNum, &(addrDecWin.addrWin))) + { + /* No Overlap. Enable address decode target window */ + MV_REG_BIT_SET(TDM_WIN_CTRL_REG(winNum), TDM_WIN_ENABLE_MASK); + } + else + { /* Overlap detected */ + mvOsPrintf("mvTdmWinEnable:ERR. Overlap detected\n"); + return MV_ERROR; + } + } + else + { + MV_REG_BIT_RESET(TDM_WIN_CTRL_REG(winNum), TDM_WIN_ENABLE_MASK); + } + return MV_OK; +} + + +/******************************************************************************* +* tdmWinOverlapDetect - Detect TDM address windows overlapping +* +* DESCRIPTION: +* An unpredicted behaviour is expected in case TDM address decode +* windows overlapps. +* This function detects TDM address decode windows overlapping of a +* specified window. The function does not check the window itself for +* overlapping. The function also skipps disabled address decode windows. +* +* INPUT: +* winNum - address decode window number. +* pAddrDecWin - An address decode window struct. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_TRUE if the given address window overlap current address +* decode map, MV_FALSE otherwise, MV_ERROR if reading invalid data +* from registers. +* +*******************************************************************************/ +static MV_STATUS tdmWinOverlapDetect(MV_U32 winNum, MV_ADDR_WIN *pAddrWin) +{ + MV_U32 winNumIndex; + MV_TDM_DEC_WIN addrDecWin; + + for (winNumIndex = 0; winNumIndex < TDM_MBUS_MAX_WIN; winNumIndex++) + { + /* Do not check window itself */ + if (winNumIndex == winNum) + { + continue; + } + /* Do not check disabled windows */ + if (MV_REG_READ(TDM_WIN_CTRL_REG(winNum)) & TDM_WIN_ENABLE_MASK) + { + /* Get window parameters */ + if (MV_OK != mvTdmWinGet(winNumIndex, &addrDecWin)) + { + DB(mvOsPrintf("dmaWinOverlapDetect: ERR. TargetWinGet failed\n")); + return MV_ERROR; + } + + if (MV_TRUE == ctrlWinOverlapTest(pAddrWin, &(addrDecWin.addrWin))) + { + return MV_TRUE; + } + } + } + return MV_FALSE; +} + +/******************************************************************************* +* mvTdmAddrDecShow - Print the TDM address decode map. +* +* DESCRIPTION: +* This function print the TDM address decode map. +* +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* None. +* +*******************************************************************************/ +MV_VOID mvTdmAddrDecShow(MV_VOID) +{ + MV_TDM_DEC_WIN win; + int i; + + mvOsOutput( "\n" ); + mvOsOutput( "TDM:\n" ); + mvOsOutput( "----\n" ); + + for( i = 0; i < TDM_MBUS_MAX_WIN; i++ ) + { + memset( &win, 0, sizeof(MV_TDM_DEC_WIN) ); + + mvOsOutput( "win%d - ", i ); + + if (mvTdmWinGet(i, &win ) == MV_OK ) + { + if( win.enable ) + { + mvOsOutput( "%s base %08x, ", + mvCtrlTargetNameGet(win.target), win.addrWin.baseLow); + mvOsOutput( "...." ); + mvSizePrint( win.addrWin.size ); + mvOsOutput( "\n" ); + } + else + mvOsOutput( "disable\n" ); + } + } +} + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysTdm.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysTdm.h new file mode 100644 index 0000000..0d3140f --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysTdm.h @@ -0,0 +1,106 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#ifndef __INCmvSysTdmh +#define __INCmvSysTdmh + +#include "ctrlEnv/sys/mvCpuIf.h" +#include "ctrlEnv/mvCtrlEnvLib.h" +#include "ctrlEnv/mvCtrlEnvAddrDec.h" + +typedef struct _mvTdmDecWin +{ + MV_TARGET target; + MV_ADDR_WIN addrWin; /* An address window*/ + MV_BOOL enable; /* Address decode window is enabled/disabled */ +} MV_TDM_DEC_WIN; + +MV_STATUS mvTdmWinInit(MV_VOID); +MV_STATUS mvTdmWinSet(MV_U32 winNum, MV_TDM_DEC_WIN *pAddrDecWin); +MV_STATUS mvTdmWinGet(MV_U32 winNum, MV_TDM_DEC_WIN *pAddrDecWin); +MV_STATUS mvTdmWinEnable(int winNum, MV_BOOL enable); +MV_VOID mvTdmAddrDecShow(MV_VOID); + + +#define TDM_MBUS_MAX_WIN 4 +#define TDM_WIN_CTRL_REG(win) ((TDM_REG_BASE + 0x4030) + (win<<4)) +#define TDM_WIN_BASE_REG(win) ((TDM_REG_BASE +0x4034) + (win<<4)) + +/* TDM_WIN_CTRL_REG bits */ +#define TDM_WIN_ENABLE_OFFS 0 +#define TDM_WIN_ENABLE_MASK (1<= TSU_MAX_DECODE_WIN) + { + mvOsPrintf("mvTsuWinSet: ERR. Invalid win num %d\n",winNum); + return MV_BAD_PARAM; + } + + /* Check if the requested window overlapps with current windows */ + if(MV_TRUE == tsuWinOverlapDetect(winNum, &pAddrDecWin->addrWin)) + { + mvOsPrintf("mvTsuWinSet: ERR. Window %d overlap\n", winNum); + return MV_ERROR; + } + + /* check if address is aligned to the size */ + if(MV_IS_NOT_ALIGN(pAddrDecWin->addrWin.baseLow,pAddrDecWin->addrWin.size)) + { + mvOsPrintf("mvTsuWinSet: Error setting TSU window %d to target " + "%s.\nAddress 0x%08x is unaligned to size 0x%x.\n", + winNum, mvCtrlTargetNameGet(pAddrDecWin->target), + pAddrDecWin->addrWin.baseLow, + pAddrDecWin->addrWin.size); + return MV_ERROR; + } + + decRegs.baseReg = MV_REG_READ(MV_TSU_WIN_BASE_REG(winNum)); + decRegs.sizeReg = MV_REG_READ(MV_TSU_WIN_CTRL_REG(winNum)); + + if(MV_OK != mvCtrlAddrDecToReg(&(pAddrDecWin->addrWin),&decRegs)) + { + mvOsPrintf("mvTsuWinSet: mvCtrlAddrDecToReg Failed\n"); + return MV_ERROR; + } + + mvCtrlAttribGet(pAddrDecWin->target,&targetAttribs); + + /* set attributes */ + decRegs.sizeReg &= ~TSU_WIN_CTRL_ATTR_MASK; + decRegs.sizeReg |= targetAttribs.attrib << TSU_WIN_CTRL_ATTR_OFFS; + /* set target ID */ + decRegs.sizeReg &= ~TSU_WIN_CTRL_TARGET_MASK; + decRegs.sizeReg |= targetAttribs.targetId << TSU_WIN_CTRL_TARGET_OFFS; + + /* for the safe side we disable the window before writing the new */ + /* values */ + mvTsuWinEnable(winNum, MV_FALSE); + MV_REG_WRITE(MV_TSU_WIN_CTRL_REG(winNum),decRegs.sizeReg); + + /* Write to address decode Size Register */ + MV_REG_WRITE(MV_TSU_WIN_BASE_REG(winNum), decRegs.baseReg); + + /* Enable address decode target window */ + if(pAddrDecWin->enable == MV_TRUE) + { + mvTsuWinEnable(winNum,MV_TRUE); + } + + return MV_OK; +} + + +/******************************************************************************* +* mvTsuWinGet +* +* DESCRIPTION: +* Get TSU peripheral target address window. +* +* INPUT: +* winNum - TSU to target address decode window number. +* +* OUTPUT: +* pAddrDecWin - TSU target window data structure. +* +* RETURN: +* MV_ERROR if register parameters are invalid. +* +*******************************************************************************/ +MV_STATUS mvTsuWinGet(MV_U32 winNum, MV_TSU_DEC_WIN *pAddrDecWin) +{ + MV_DEC_REGS decRegs; + MV_TARGET_ATTRIB targetAttrib; + + /* Parameter checking */ + if(winNum >= TSU_MAX_DECODE_WIN) + { + mvOsPrintf("mvTsuWinGet: ERR. Invalid winNum %d\n", winNum); + return MV_NOT_SUPPORTED; + } + + decRegs.baseReg = MV_REG_READ(MV_TSU_WIN_BASE_REG(winNum)); + decRegs.sizeReg = MV_REG_READ(MV_TSU_WIN_CTRL_REG(winNum)); + + if(MV_OK != mvCtrlRegToAddrDec(&decRegs,&(pAddrDecWin->addrWin))) + { + mvOsPrintf("mvTsuWinGet: mvCtrlRegToAddrDec Failed \n"); + return MV_ERROR; + } + + /* attrib and targetId */ + targetAttrib.attrib = + (decRegs.sizeReg & TSU_WIN_CTRL_ATTR_MASK) >> TSU_WIN_CTRL_ATTR_OFFS; + targetAttrib.targetId = + (decRegs.sizeReg & TSU_WIN_CTRL_TARGET_MASK) >> TSU_WIN_CTRL_TARGET_OFFS; + + pAddrDecWin->target = mvCtrlTargetGet(&targetAttrib); + + /* Check if window is enabled */ + if((MV_REG_READ(MV_TSU_WIN_CTRL_REG(winNum)) & TSU_WIN_CTRL_EN_MASK)) + { + pAddrDecWin->enable = MV_TRUE; + } + else + { + pAddrDecWin->enable = MV_FALSE; + } + + return MV_OK; +} + + +/******************************************************************************* +* mvTsuWinEnable +* +* DESCRIPTION: +* This function enable/disable a TSU to target address window. +* According to parameter 'enable' the routine will enable the +* window, thus enabling TSU accesses (before enabling the window it is +* tested for overlapping). Otherwise, the window will be disabled. +* +* INPUT: +* winNum - TSU to target address decode window number. +* enable - Enable / disable parameter. +* +* OUTPUT: +* N/A +* +* RETURN: +* MV_ERROR if decode window number was wrong or enabled window overlapps. +* +*******************************************************************************/ +MV_STATUS mvTsuWinEnable(MV_U32 winNum,MV_BOOL enable) +{ + MV_TSU_DEC_WIN addrDecWin; + + /* Parameter checking */ + if(winNum >= TSU_MAX_DECODE_WIN) + { + mvOsPrintf("mvTsuWinEnable: ERR. Invalid winNum%d\n",winNum); + return MV_ERROR; + } + + if(enable == MV_TRUE) + { + /* First check for overlap with other enabled windows */ + /* Get current window. */ + if(MV_OK != mvTsuWinGet(winNum,&addrDecWin)) + { + mvOsPrintf("mvTsuWinEnable: ERR. targetWinGet fail\n"); + return MV_ERROR; + } + /* Check for overlapping. */ + if(MV_FALSE == tsuWinOverlapDetect(winNum,&(addrDecWin.addrWin))) + { + /* No Overlap. Enable address decode target window */ + MV_REG_BIT_SET(MV_TSU_WIN_CTRL_REG(winNum), + TSU_WIN_CTRL_EN_MASK); + } + else + { + /* Overlap detected */ + mvOsPrintf("mvTsuWinEnable: ERR. Overlap detected\n"); + return MV_ERROR; + } + } + else + { + /* Disable address decode target window */ + MV_REG_BIT_RESET(MV_TSU_WIN_CTRL_REG(winNum), + TSU_WIN_CTRL_EN_MASK); + } + return MV_OK; +} + +/******************************************************************************* +* mvTsuWinTargetGet +* +* DESCRIPTION: +* Get Window number associated with target +* +* INPUT: +* target - Target ID to get the window number for. +* OUTPUT: +* +* RETURN: +* window number or 0xFFFFFFFF on error. +* +*******************************************************************************/ +MV_U32 mvTsuWinTargetGet(MV_TARGET target) +{ + MV_TSU_DEC_WIN decWin; + MV_U32 winNum; + + /* Check parameters */ + if(target >= MAX_TARGETS) + { + mvOsPrintf("mvTsuWinTargetGet: target %d is Illigal\n", target); + return 0xffffffff; + } + + for(winNum = 0; winNum < TSU_MAX_DECODE_WIN; winNum++) + { + if(mvTsuWinGet(winNum,&decWin) != MV_OK) + { + mvOsPrintf("mvTsuWinGet: window returned error\n"); + return 0xffffffff; + } + + if (decWin.enable == MV_TRUE) + { + if(decWin.target == target) + { + return winNum; + } + } + } + return 0xFFFFFFFF; +} + + +/******************************************************************************* +* tsuWinOverlapDetect +* +* DESCRIPTION: +* Detect TSU address windows overlapping +* An unpredicted behaviur is expected in case TSU address decode +* windows overlapps. +* This function detects TSU address decode windows overlapping of a +* specified window. The function does not check the window itself for +* overlapping. The function also skipps disabled address decode windows. +* +* INPUT: +* winNum - address decode window number. +* pAddrDecWin - An address decode window struct. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_TRUE if the given address window overlap current address +* decode map, MV_FALSE otherwise, MV_ERROR if reading invalid data +* from registers. +* +*******************************************************************************/ +static MV_STATUS tsuWinOverlapDetect(MV_U32 winNum, MV_ADDR_WIN *pAddrWin) +{ + MV_U32 ctrlReg; + MV_U32 winNumIndex; + MV_TSU_DEC_WIN addrDecWin; + + for(winNumIndex = 0; winNumIndex < TSU_MAX_DECODE_WIN; winNumIndex++) + { + /* Do not check window itself */ + if(winNumIndex == winNum) + { + continue; + } + + /* Do not check disabled windows */ + ctrlReg = MV_REG_READ(MV_TSU_WIN_CTRL_REG(winNumIndex)); + if((ctrlReg & TSU_WIN_CTRL_EN_MASK) == 0) + { + continue; + } + + /* Get window parameters */ + if (MV_OK != mvTsuWinGet(winNumIndex, &addrDecWin)) + { + mvOsPrintf("tsuWinOverlapDetect: ERR. mvTsuWinGet failed\n"); + return MV_ERROR; + } + + if (MV_TRUE == ctrlWinOverlapTest(pAddrWin, &(addrDecWin.addrWin))) + { + return MV_TRUE; + } + } + return MV_FALSE; +} + + +/******************************************************************************* +* mvTsuAddrDecShow +* +* DESCRIPTION: +* Print the TSU address decode map. +* +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* None. +* +*******************************************************************************/ +void mvTsuAddrDecShow(void) +{ + MV_TSU_DEC_WIN win; + int i; + + if (MV_FALSE == mvCtrlPwrClckGet(TS_UNIT_ID, 0)) + return; + + mvOsOutput( "\n" ); + mvOsOutput( "TSU:\n"); + mvOsOutput( "----\n" ); + + for(i = 0; i < TSU_MAX_DECODE_WIN; i++) + { + memset(&win, 0, sizeof(TSU_MAX_DECODE_WIN)); + mvOsOutput( "win%d - ", i ); + + if(mvTsuWinGet(i, &win ) == MV_OK ) + { + if(win.enable == MV_TRUE) + { + mvOsOutput("%s base %08x, ", + mvCtrlTargetNameGet(win.target), + win.addrWin.baseLow); + mvOsOutput( "...." ); + mvSizePrint(win.addrWin.size ); + mvOsOutput( "\n" ); + } + else + { + mvOsOutput( "disable\n" ); + } + } + } + return; +} + + +/******************************************************************************* +* mvTsuInit +* +* DESCRIPTION: +* Initialize the TSU unit, and get unit out of reset. +* +* INPUT: +* coreClock - The core clock at which the TSU should operate. +* mode - The mode on configure the unit into (serial/parallel). +* memHandle - Memory handle used for memory allocations. +* OUTPUT: +* None. +* RETURN: +* MV_OK - on success, +* +*******************************************************************************/ +MV_STATUS mvTsuInit(MV_TSU_CORE_CLOCK coreClock, MV_TSU_PORTS_MODE mode, + void *osHandle) +{ + MV_STATUS status; + + status = mvTsuWinInit(); + if(status == MV_OK) + status = mvTsuHalInit(coreClock,mode,osHandle); + + return status; +} diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysTs.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysTs.h new file mode 100644 index 0000000..4282589 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysTs.h @@ -0,0 +1,110 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#ifndef __INCmvSysTsh +#define __INCmvSysTsh + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* includes */ +#include "ts/mvTsu.h" +#include "ctrlEnv/sys/mvCpuIf.h" +#include "ctrlEnv/mvCtrlEnvLib.h" +#include "ctrlEnv/mvCtrlEnvAddrDec.h" + +#define TSU_MAX_DECODE_WIN 4 + + +/*******************************************/ +/* TSU Windows Registers */ +/*******************************************/ +#define MV_TSU_WIN_CTRL_REG(win) (TSU_GLOBAL_REG_BASE +0x30 + 0x10 * win) +#define MV_TSU_WIN_BASE_REG(win) (TSU_GLOBAL_REG_BASE +0x34 + 0x10 * win) + +/* TSU windows control register. */ +#define TSU_WIN_CTRL_EN_MASK (0x1 << 0) +#define TSU_WIN_CTRL_TARGET_OFFS 4 +#define TSU_WIN_CTRL_TARGET_MASK (0xF << TSU_WIN_CTRL_TARGET_OFFS) +#define TSU_WIN_CTRL_ATTR_OFFS 8 +#define TSU_WIN_CTRL_ATTR_MASK (0xFF << TSU_WIN_CTRL_ATTR_OFFS) +#define TSU_WIN_CTRL_SIZE_OFFS 16 +#define TSU_WIN_CTRL_SIZE_MASK (0xFFFF << TSU_WIN_CTRL_SIZE_OFFS) + +/* TSU windows base register. */ +#define TSU_WIN_BASE_OFFS 16 +#define TSU_WIN_BASE_MASK (0xFFFF << TSU_WIN_BASE_OFFS) + +MV_STATUS mvTsuWinInit(void); + +void mvTsuAddrDecShow(void); +MV_STATUS mvTsuInit(MV_TSU_CORE_CLOCK coreClock, MV_TSU_PORTS_MODE mode, + void *osHandle); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __INCmvTsh */ diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysUsb.c b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysUsb.c new file mode 100644 index 0000000..195b5e1 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysUsb.c @@ -0,0 +1,497 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#include "ctrlEnv/sys/mvSysUsb.h" + +MV_TARGET usbAddrDecPrioTab[] = +{ +#if defined(MV_INCLUDE_SDRAM_CS0) + SDRAM_CS0, +#endif +#if defined(MV_INCLUDE_SDRAM_CS1) + SDRAM_CS1, +#endif +#if defined(MV_INCLUDE_SDRAM_CS2) + SDRAM_CS2, +#endif +#if defined(MV_INCLUDE_SDRAM_CS3) + SDRAM_CS3, +#endif +#if defined(MV_INCLUDE_CESA) && defined(USB_UNDERRUN_WA) + CRYPT_ENG, +#endif +#if defined(MV_INCLUDE_PEX) + PEX0_MEM, +#endif + TBL_TERM +}; + + + +MV_STATUS mvUsbInit(int dev, MV_BOOL isHost) +{ + MV_STATUS status; + + status = mvUsbWinInit(dev); + if(status != MV_OK) + return status; + + return mvUsbHalInit(dev, isHost); +} + + +/******************************************************************************* +* usbWinOverlapDetect - Detect USB address windows overlapping +* +* DESCRIPTION: +* An unpredicted behaviur is expected in case USB address decode +* windows overlapps. +* This function detects USB address decode windows overlapping of a +* specified window. The function does not check the window itself for +* overlapping. The function also skipps disabled address decode windows. +* +* INPUT: +* winNum - address decode window number. +* pAddrDecWin - An address decode window struct. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_TRUE if the given address window overlap current address +* decode map, MV_FALSE otherwise, MV_ERROR if reading invalid data +* from registers. +* +*******************************************************************************/ +static MV_STATUS usbWinOverlapDetect(int dev, MV_U32 winNum, + MV_ADDR_WIN *pAddrWin) +{ + MV_U32 winNumIndex; + MV_DEC_WIN addrDecWin; + + for(winNumIndex=0; winNumIndex= MV_USB_MAX_ADDR_DECODE_WIN) + { + mvOsPrintf("%s: ERR. Invalid win num %d\n",__FUNCTION__, winNum); + return MV_BAD_PARAM; + } + + /* Check if the requested window overlapps with current windows */ + if (MV_TRUE == usbWinOverlapDetect(dev, winNum, &pDecWin->addrWin)) + { + mvOsPrintf("%s: ERR. Window %d overlap\n", __FUNCTION__, winNum); + return MV_ERROR; + } + + /* check if address is aligned to the size */ + if(MV_IS_NOT_ALIGN(pDecWin->addrWin.baseLow, pDecWin->addrWin.size)) + { + mvOsPrintf("mvUsbWinSet:Error setting USB window %d to "\ + "target %s.\nAddress 0x%08x is unaligned to size 0x%x.\n", + winNum, + mvCtrlTargetNameGet(pDecWin->target), + pDecWin->addrWin.baseLow, + pDecWin->addrWin.size); + return MV_ERROR; + } + + if(MV_OK != mvCtrlAddrDecToParams(pDecWin, &winParams)) + { + mvOsPrintf("%s: mvCtrlAddrDecToParams Failed\n", __FUNCTION__); + return MV_ERROR; + } + + /* set Size, Attributes and TargetID */ + sizeReg = (((winParams.targetId << MV_USB_WIN_TARGET_OFFSET) & MV_USB_WIN_TARGET_MASK) | + ((winParams.attrib << MV_USB_WIN_ATTR_OFFSET) & MV_USB_WIN_ATTR_MASK) | + ((winParams.size << MV_USB_WIN_SIZE_OFFSET) & MV_USB_WIN_SIZE_MASK)); + +#if defined(MV645xx) || defined(MV646xx) + /* If window is DRAM with HW cache coherency, make sure bit2 is set */ + sizeReg &= ~MV_USB_WIN_BURST_WR_LIMIT_MASK; + + if((MV_TARGET_IS_DRAM(pDecWin->target)) && + (pDecWin->addrWinAttr.cachePolicy != NO_COHERENCY)) + { + sizeReg |= MV_USB_WIN_BURST_WR_32BIT_LIMIT; + } + else + { + sizeReg |= MV_USB_WIN_BURST_WR_NO_LIMIT; + } +#endif /* MV645xx || MV646xx */ + + if (pDecWin->enable == MV_TRUE) + { + sizeReg |= MV_USB_WIN_ENABLE_MASK; + } + else + { + sizeReg &= ~MV_USB_WIN_ENABLE_MASK; + } + + /* Update Base value */ + baseReg = (winParams.baseAddr & MV_USB_WIN_BASE_MASK); + + MV_REG_WRITE( MV_USB_WIN_CTRL_REG(dev, winNum), sizeReg); + MV_REG_WRITE( MV_USB_WIN_BASE_REG(dev, winNum), baseReg); + + return MV_OK; +} + +/******************************************************************************* +* mvUsbWinGet - Get USB peripheral target address window. +* +* DESCRIPTION: +* Get USB peripheral target address window. +* +* INPUT: +* winNum - USB target address decode window number. +* +* OUTPUT: +* pDecWin - USB target window data structure. +* +* RETURN: +* MV_ERROR if register parameters are invalid. +* +*******************************************************************************/ +MV_STATUS mvUsbWinGet(int dev, MV_U32 winNum, MV_DEC_WIN *pDecWin) +{ + MV_DEC_WIN_PARAMS winParam; + MV_U32 sizeReg, baseReg; + + /* Parameter checking */ + if (winNum >= MV_USB_MAX_ADDR_DECODE_WIN) + { + mvOsPrintf("%s (dev=%d): ERR. Invalid winNum %d\n", + __FUNCTION__, dev, winNum); + return MV_NOT_SUPPORTED; + } + + baseReg = MV_REG_READ( MV_USB_WIN_BASE_REG(dev, winNum) ); + sizeReg = MV_REG_READ( MV_USB_WIN_CTRL_REG(dev, winNum) ); + + /* Check if window is enabled */ + if(sizeReg & MV_USB_WIN_ENABLE_MASK) + { + pDecWin->enable = MV_TRUE; + + /* Extract window parameters from registers */ + winParam.targetId = (sizeReg & MV_USB_WIN_TARGET_MASK) >> MV_USB_WIN_TARGET_OFFSET; + winParam.attrib = (sizeReg & MV_USB_WIN_ATTR_MASK) >> MV_USB_WIN_ATTR_OFFSET; + winParam.size = (sizeReg & MV_USB_WIN_SIZE_MASK) >> MV_USB_WIN_SIZE_OFFSET; + winParam.baseAddr = (baseReg & MV_USB_WIN_BASE_MASK); + + /* Translate the decode window parameters to address decode struct */ + if (MV_OK != mvCtrlParamsToAddrDec(&winParam, pDecWin)) + { + mvOsPrintf("Failed to translate register parameters to USB address" \ + " decode window structure\n"); + return MV_ERROR; + } + } + else + { + pDecWin->enable = MV_FALSE; + } + return MV_OK; +} + +/******************************************************************************* +* mvUsbWinInit - +* +* INPUT: +* +* OUTPUT: +* +* RETURN: +* MV_ERROR if register parameters are invalid. +* +*******************************************************************************/ +MV_STATUS mvUsbWinInit(int dev) +{ + MV_STATUS status; + MV_DEC_WIN usbWin; + MV_CPU_DEC_WIN cpuAddrDecWin; + int winNum; + MV_U32 winPrioIndex = 0; + + /* First disable all address decode windows */ + for(winNum = 0; winNum < MV_USB_MAX_ADDR_DECODE_WIN; winNum++) + { + MV_REG_BIT_RESET(MV_USB_WIN_CTRL_REG(dev, winNum), MV_USB_WIN_ENABLE_MASK); + } + + /* Go through all windows in user table until table terminator */ + winNum = 0; + while( (usbAddrDecPrioTab[winPrioIndex] != TBL_TERM) && + (winNum < MV_USB_MAX_ADDR_DECODE_WIN) ) + { + /* first get attributes from CPU If */ + status = mvCpuIfTargetWinGet(usbAddrDecPrioTab[winPrioIndex], + &cpuAddrDecWin); + + if(MV_NO_SUCH == status) + { + winPrioIndex++; + continue; + } + if (MV_OK != status) + { + mvOsPrintf("%s: ERR. mvCpuIfTargetWinGet failed\n", __FUNCTION__); + return MV_ERROR; + } + + if (cpuAddrDecWin.enable == MV_TRUE) + { + usbWin.addrWin.baseHigh = cpuAddrDecWin.addrWin.baseHigh; + usbWin.addrWin.baseLow = cpuAddrDecWin.addrWin.baseLow; + usbWin.addrWin.size = cpuAddrDecWin.addrWin.size; + usbWin.enable = MV_TRUE; + usbWin.target = usbAddrDecPrioTab[winPrioIndex]; + +#if defined(MV645xx) || defined(MV646xx) + /* Get the default attributes for that target window */ + mvCtrlDefAttribGet(usbWin.target, &usbWin.addrWinAttr); +#endif /* MV645xx || MV646xx */ + + if(MV_OK != mvUsbWinSet(dev, winNum, &usbWin)) + { + return MV_ERROR; + } + winNum++; + } + winPrioIndex++; + } + return MV_OK; +} + +/******************************************************************************* +* mvUsbAddrDecShow - Print the USB address decode map. +* +* DESCRIPTION: +* This function print the USB address decode map. +* +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* None. +* +*******************************************************************************/ +MV_VOID mvUsbAddrDecShow(MV_VOID) +{ + MV_DEC_WIN addrDecWin; + int i, winNum; + + mvOsOutput( "\n" ); + mvOsOutput( "USB:\n" ); + mvOsOutput( "----\n" ); + + for(i=0; i= XOR_MAX_ADDR_DEC_WIN) + { + DB(mvOsPrintf("%s: ERR. Invalid win num %d\n",__FUNCTION__, winNum)); + return MV_BAD_PARAM; + } + if (pAddrDecWin == NULL) + { + DB(mvOsPrintf("%s: ERR. pAddrDecWin is NULL pointer\n", __FUNCTION__ )); + return MV_BAD_PTR; + } + /* Check if the requested window overlaps with current windows */ + if (MV_TRUE == xorWinOverlapDetect(unit, winNum, &pAddrDecWin->addrWin)) + { + DB(mvOsPrintf("%s: ERR. Window %d overlap\n",__FUNCTION__,winNum)); + return MV_ERROR; + } + + xorDecRegs.baseReg = MV_REG_READ(XOR_BASE_ADDR_REG(unit,winNum)); + xorDecRegs.sizeReg = MV_REG_READ(XOR_SIZE_MASK_REG(unit,winNum)); + + /* Get Base Address and size registers values */ + if(MV_OK != mvCtrlAddrDecToReg(&pAddrDecWin->addrWin, &xorDecRegs)) + { + DB(mvOsPrintf("%s: ERR. Invalid addr dec window\n",__FUNCTION__)); + return MV_BAD_PARAM; + } + + + mvCtrlAttribGet(pAddrDecWin->target,&targetAttribs); + + /* set attributes */ + xorDecRegs.baseReg &= ~XEBARX_ATTR_MASK; + xorDecRegs.baseReg |= targetAttribs.attrib << XEBARX_ATTR_OFFS; + /* set target ID */ + xorDecRegs.baseReg &= ~XEBARX_TARGET_MASK; + xorDecRegs.baseReg |= targetAttribs.targetId << XEBARX_TARGET_OFFS; + + + /* Write to address decode Base Address Register */ + MV_REG_WRITE(XOR_BASE_ADDR_REG(unit,winNum), xorDecRegs.baseReg); + + /* Write to Size Register */ + MV_REG_WRITE(XOR_SIZE_MASK_REG(unit,winNum), xorDecRegs.sizeReg); + + for (chan = 0; chan < MV_XOR_MAX_CHAN_PER_UNIT; chan++) + { + if (pAddrDecWin->enable) + { + MV_REG_BIT_SET(XOR_WINDOW_CTRL_REG(unit,chan), + XEXWCR_WIN_EN_MASK(winNum)); + } + else + { + MV_REG_BIT_RESET(XOR_WINDOW_CTRL_REG(unit,chan), + XEXWCR_WIN_EN_MASK(winNum)); + } + } + return MV_OK; +} + +/******************************************************************************* +* mvXorTargetWinGet - Get xor peripheral target address window. +* +* DESCRIPTION: +* Get xor peripheral target address window. +* +* INPUT: +* winNum - One of the possible XOR memory decode windows. +* +* OUTPUT: +* base - Window base address. +* size - Window size. +* enable - window enable/disable. +* +* RETURN: +* MV_BAD_PARAM if parameters to function invalid, MV_OK otherwise. +* +*******************************************************************************/ +MV_STATUS mvXorTargetWinGet(MV_U32 unit,MV_U32 winNum, MV_XOR_DEC_WIN *pAddrDecWin) +{ + MV_DEC_REGS xorDecRegs; + MV_TARGET_ATTRIB targetAttrib; + MV_U32 chan=0,chanWinEn; + + /* Parameter checking */ + if (winNum >= XOR_MAX_ADDR_DEC_WIN) + { + DB(mvOsPrintf("%s: ERR. Invalid win num %d\n",__FUNCTION__ , winNum)); + return MV_ERROR; + } + + if (NULL == pAddrDecWin) + { + DB(mvOsPrintf("%s: ERR. pAddrDecWin is NULL pointer\n", __FUNCTION__ )); + return MV_BAD_PTR; + } + + chanWinEn = MV_REG_READ(XOR_WINDOW_CTRL_REG(unit,0)) & XEXWCR_WIN_EN_MASK(winNum); + + for (chan = 0; chan < MV_XOR_MAX_CHAN_PER_UNIT; chan++) /* we should scan here all channels per unit */ + { + /* Check if enable bit is equal for all channels */ + if ((MV_REG_READ(XOR_WINDOW_CTRL_REG(unit,chan)) & + XEXWCR_WIN_EN_MASK(winNum)) != chanWinEn) + { + mvOsPrintf("%s: ERR. Window enable field must be equal in " + "all channels(chan=%d)\n",__FUNCTION__, chan); + return MV_ERROR; + } + } + + + + xorDecRegs.baseReg = MV_REG_READ(XOR_BASE_ADDR_REG(unit,winNum)); + xorDecRegs.sizeReg = MV_REG_READ(XOR_SIZE_MASK_REG(unit,winNum)); + + if (MV_OK != mvCtrlRegToAddrDec(&xorDecRegs, &pAddrDecWin->addrWin)) + { + mvOsPrintf("%s: ERR. mvCtrlRegToAddrDec failed\n", __FUNCTION__); + return MV_ERROR; + } + + /* attrib and targetId */ + targetAttrib.attrib = + (xorDecRegs.baseReg & XEBARX_ATTR_MASK) >> XEBARX_ATTR_OFFS; + targetAttrib.targetId = + (xorDecRegs.baseReg & XEBARX_TARGET_MASK) >> XEBARX_TARGET_OFFS; + + + pAddrDecWin->target = mvCtrlTargetGet(&targetAttrib); + + if(chanWinEn) + { + pAddrDecWin->enable = MV_TRUE; + } + else pAddrDecWin->enable = MV_FALSE; + + return MV_OK; +} + +/******************************************************************************* +* mvXorTargetWinEnable - Enable/disable a Xor address decode window +* +* DESCRIPTION: +* This function enable/disable a XOR address decode window. +* if parameter 'enable' == MV_TRUE the routine will enable the +* window, thus enabling XOR accesses (before enabling the window it is +* tested for overlapping). Otherwise, the window will be disabled. +* +* INPUT: +* winNum - Decode window number. +* enable - Enable/disable parameter. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_BAD_PARAM if parameters to function invalid, MV_OK otherwise. +* +*******************************************************************************/ +MV_STATUS mvXorTargetWinEnable(MV_U32 unit,MV_U32 winNum, MV_BOOL enable) +{ + MV_XOR_DEC_WIN addrDecWin; + MV_U32 chan; + + /* Parameter checking */ + if (winNum >= XOR_MAX_ADDR_DEC_WIN) + { + DB(mvOsPrintf("%s: ERR. Invalid winNum%d\n", __FUNCTION__, winNum)); + return MV_ERROR; + } + + if (enable == MV_TRUE) + { + /* Get current window */ + if (MV_OK != mvXorTargetWinGet(unit,winNum, &addrDecWin)) + { + DB(mvOsPrintf("%s: ERR. targetWinGet fail\n", __FUNCTION__)); + return MV_ERROR; + } + + /* Check for overlapping */ + if (MV_TRUE == xorWinOverlapDetect(unit,winNum, &(addrDecWin.addrWin))) + { + /* Overlap detected */ + DB(mvOsPrintf("%s: ERR. Overlap detected\n", __FUNCTION__)); + return MV_ERROR; + } + + /* No Overlap. Enable address decode target window */ + for (chan = 0; chan < MV_XOR_MAX_CHAN_PER_UNIT; chan++) + { + MV_REG_BIT_SET(XOR_WINDOW_CTRL_REG(unit,chan), + XEXWCR_WIN_EN_MASK(winNum)); + } + + } + else + { + /* Disable address decode target window */ + + for (chan = 0; chan < MV_XOR_MAX_CHAN_PER_UNIT; chan++) + { + MV_REG_BIT_RESET(XOR_WINDOW_CTRL_REG(unit,chan), + XEXWCR_WIN_EN_MASK(winNum)); + } + + } + + return MV_OK; +} + +/******************************************************************************* +* mvXorSetProtWinSet - Configure access attributes of a XOR engine +* to one of the XOR memory windows. +* +* DESCRIPTION: +* Each engine can be configured with access attributes for each of the +* memory spaces. This function sets access attributes +* to a given window for the given engine +* +* INPUTS: +* chan - One of the possible engines. +* winNum - One of the possible XOR memory spaces. +* access - Protection access rights. +* write - Write rights. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_BAD_PARAM if parameters to function invalid, MV_OK otherwise. +* +*******************************************************************************/ +MV_STATUS mvXorProtWinSet (MV_U32 unit,MV_U32 chan, MV_U32 winNum, MV_BOOL access, + MV_BOOL write) +{ + MV_U32 temp; + + /* Parameter checking */ + if (chan >= MV_XOR_MAX_CHAN_PER_UNIT) + { + DB(mvOsPrintf("%s: ERR. Invalid chan num %d\n", __FUNCTION__ , chan)); + return MV_BAD_PARAM; + } + if (winNum >= XOR_MAX_ADDR_DEC_WIN) + { + DB(mvOsPrintf("%s: ERR. Invalid win num %d\n", __FUNCTION__, winNum)); + return MV_BAD_PARAM; + } + + temp = MV_REG_READ(XOR_WINDOW_CTRL_REG(unit,chan)) & + (~XEXWCR_WIN_ACC_MASK(winNum)); + + /* if access is disable */ + if (!access) + { + /* disable access */ + temp |= XEXWCR_WIN_ACC_NO_ACC(winNum); + } + /* if access is enable */ + else + { + /* if write is enable */ + if (write) + { + /* enable write */ + temp |= XEXWCR_WIN_ACC_RW(winNum); + } + /* if write is disable */ + else + { + /* disable write */ + temp |= XEXWCR_WIN_ACC_RO(winNum); + } + } + MV_REG_WRITE(XOR_WINDOW_CTRL_REG(unit,chan),temp); + return MV_OK; +} + +/******************************************************************************* +* mvXorPciRemap - Set XOR remap register for PCI address windows. +* +* DESCRIPTION: +* only Windows 0-3 can be remapped. +* +* INPUT: +* winNum - window number +* pAddrDecWin - pointer to address space window structure +* OUTPUT: +* None. +* +* RETURN: +* MV_BAD_PARAM if parameters to function invalid, MV_OK otherwise. +* +*******************************************************************************/ +MV_STATUS mvXorPciRemap(MV_U32 unit,MV_U32 winNum, MV_U32 addrHigh) +{ + /* Parameter checking */ + if (winNum >= XOR_MAX_REMAP_WIN) + { + DB(mvOsPrintf("%s: ERR. Invalid win num %d\n", __FUNCTION__, winNum)); + return MV_BAD_PARAM; + } + + MV_REG_WRITE(XOR_HIGH_ADDR_REMAP_REG(unit,winNum), addrHigh); + + return MV_OK; +} + +/******************************************************************************* +* xorWinOverlapDetect - Detect XOR address windows overlaping +* +* DESCRIPTION: +* An unpredicted behaviour is expected in case XOR address decode +* windows overlaps. +* This function detects XOR address decode windows overlaping of a +* specified window. The function does not check the window itself for +* overlaping. The function also skipps disabled address decode windows. +* +* INPUT: +* winNum - address decode window number. +* pAddrDecWin - An address decode window struct. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_TRUE if the given address window overlap current address +* decode map, MV_FALSE otherwise, MV_ERROR if reading invalid data +* from registers. +* +*******************************************************************************/ +static MV_STATUS xorWinOverlapDetect(MV_U32 unit,MV_U32 winNum, MV_ADDR_WIN *pAddrWin) +{ + MV_U32 baseAddrEnableReg; + MV_U32 winNumIndex,chan; + MV_XOR_DEC_WIN addrDecWin; + + if (pAddrWin == NULL) + { + DB(mvOsPrintf("%s: ERR. pAddrWin is NULL pointer\n", __FUNCTION__ )); + return MV_BAD_PTR; + } + + for (chan = 0; chan < MV_XOR_MAX_CHAN_PER_UNIT; chan++) + { + /* Read base address enable register. Do not check disabled windows */ + baseAddrEnableReg = MV_REG_READ(XOR_WINDOW_CTRL_REG(unit,chan)); + + for (winNumIndex = 0; winNumIndex < XOR_MAX_ADDR_DEC_WIN; winNumIndex++) + { + /* Do not check window itself */ + if (winNumIndex == winNum) + { + continue; + } + + /* Do not check disabled windows */ + if ((baseAddrEnableReg & XEXWCR_WIN_EN_MASK(winNumIndex)) == 0) + { + continue; + } + + /* Get window parameters */ + if (MV_OK != mvXorTargetWinGet(unit,winNumIndex, &addrDecWin)) + { + DB(mvOsPrintf("%s: ERR. TargetWinGet failed\n", __FUNCTION__ )); + return MV_ERROR; + } + + if (MV_TRUE == ctrlWinOverlapTest(pAddrWin, &(addrDecWin.addrWin))) + { + return MV_TRUE; + } + } + } + + return MV_FALSE; +} + +static MV_VOID mvXorAddrDecShowUnit(MV_U32 unit) +{ + MV_XOR_DEC_WIN win; + int i; + + mvOsOutput( "\n" ); + mvOsOutput( "XOR %d:\n", unit ); + mvOsOutput( "----\n" ); + + for( i = 0; i < XOR_MAX_ADDR_DEC_WIN; i++ ) + { + memset( &win, 0, sizeof(MV_XOR_DEC_WIN) ); + + mvOsOutput( "win%d - ", i ); + + if( mvXorTargetWinGet(unit, i, &win ) == MV_OK ) + { + if( win.enable ) + { + mvOsOutput( "%s base %x, ", + mvCtrlTargetNameGet(win.target), win.addrWin.baseLow ); + + mvSizePrint( win.addrWin.size ); + + mvOsOutput( "\n" ); + } + else + mvOsOutput( "disable\n" ); + } + } +} + +/******************************************************************************* +* mvXorAddrDecShow - Print the XOR address decode map. +* +* DESCRIPTION: +* This function print the XOR address decode map. +* +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* None. +* +*******************************************************************************/ +MV_VOID mvXorAddrDecShow(MV_VOID) +{ + int i; + + for( i = 0; i < MV_XOR_MAX_UNIT; i++ ) + mvXorAddrDecShowUnit(i); + +} diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysXor.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysXor.h new file mode 100644 index 0000000..73b2d9e --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/ctrlEnv/sys/mvSysXor.h @@ -0,0 +1,140 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#ifndef __INCMVSysXorh +#define __INCMVSysXorh + + +#ifdef __cplusplus +extern "C" { +#endif + +#include "ctrlEnv/sys/mvCpuIf.h" + +#include "ctrlEnv/mvCtrlEnvLib.h" +#include "ctrlEnv/mvCtrlEnvAddrDec.h" + +#define XOR_MAX_ADDR_DEC_WIN 8 /* Maximum address decode windows */ +#define XOR_MAX_REMAP_WIN 4 /* Maximum address arbiter windows */ + +/* XOR Engine Address Decoding Register Map */ +#define XOR_WINDOW_CTRL_REG(unit,chan) (XOR_UNIT_BASE(unit)+(0x240 + ((chan) * 4))) +#define XOR_BASE_ADDR_REG(unit,winNum) (XOR_UNIT_BASE(unit)+(0x250 + ((winNum) * 4))) +#define XOR_SIZE_MASK_REG(unit,winNum) (XOR_UNIT_BASE(unit)+(0x270 + ((winNum) * 4))) +#define XOR_HIGH_ADDR_REMAP_REG(unit,winNum) (XOR_UNIT_BASE(unit)+(0x290 + ((winNum) * 4))) + +/* XOR Engine [0..1] Window Control Registers (XExWCR) */ +#define XEXWCR_WIN_EN_OFFS(winNum) (winNum) +#define XEXWCR_WIN_EN_MASK(winNum) (1 << (XEXWCR_WIN_EN_OFFS(winNum))) +#define XEXWCR_WIN_EN_ENABLE(winNum) (1 << (XEXWCR_WIN_EN_OFFS(winNum))) +#define XEXWCR_WIN_EN_DISABLE(winNum) (0 << (XEXWCR_WIN_EN_OFFS(winNum))) + +#define XEXWCR_WIN_ACC_OFFS(winNum) ((2 * winNum) + 16) +#define XEXWCR_WIN_ACC_MASK(winNum) (3 << (XEXWCR_WIN_ACC_OFFS(winNum))) +#define XEXWCR_WIN_ACC_NO_ACC(winNum) (0 << (XEXWCR_WIN_ACC_OFFS(winNum))) +#define XEXWCR_WIN_ACC_RO(winNum) (1 << (XEXWCR_WIN_ACC_OFFS(winNum))) +#define XEXWCR_WIN_ACC_RW(winNum) (3 << (XEXWCR_WIN_ACC_OFFS(winNum))) + +/* XOR Engine Base Address Registers (XEBARx) */ +#define XEBARX_TARGET_OFFS (0) +#define XEBARX_TARGET_MASK (0xF << XEBARX_TARGET_OFFS) +#define XEBARX_ATTR_OFFS (8) +#define XEBARX_ATTR_MASK (0xFF << XEBARX_ATTR_OFFS) +#define XEBARX_BASE_OFFS (16) +#define XEBARX_BASE_MASK (0xFFFF << XEBARX_BASE_OFFS) + +/* XOR Engine Size Mask Registers (XESMRx) */ +#define XESMRX_SIZE_MASK_OFFS (16) +#define XESMRX_SIZE_MASK_MASK (0xFFFF << XESMRX_SIZE_MASK_OFFS) + +/* XOR Engine High Address Remap Register (XEHARRx1) */ +#define XEHARRX_REMAP_OFFS (0) +#define XEHARRX_REMAP_MASK (0xFFFFFFFF << XEHARRX_REMAP_OFFS) + +typedef struct _mvXorDecWin +{ + MV_TARGET target; + MV_ADDR_WIN addrWin; /* An address window*/ + MV_BOOL enable; /* Address decode window is enabled/disabled */ + +}MV_XOR_DEC_WIN; + +MV_STATUS mvXorInit (MV_VOID); +MV_STATUS mvXorTargetWinSet(MV_U32 unit, MV_U32 winNum, + MV_XOR_DEC_WIN *pAddrDecWin); +MV_STATUS mvXorTargetWinGet(MV_U32 unit, MV_U32 winNum, + MV_XOR_DEC_WIN *pAddrDecWin); +MV_STATUS mvXorTargetWinEnable(MV_U32 unit, + MV_U32 winNum, MV_BOOL enable); +MV_STATUS mvXorProtWinSet (MV_U32 unit,MV_U32 chan, MV_U32 winNum, MV_BOOL access, + MV_BOOL write); +MV_STATUS mvXorPciRemap(MV_U32 unit, MV_U32 winNum, MV_U32 addrHigh); + +MV_VOID mvXorAddrDecShow(MV_VOID); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/device/mvDevice.c b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/device/mvDevice.c new file mode 100644 index 0000000..80325fc --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/device/mvDevice.c @@ -0,0 +1,75 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#include "device/mvDevice.h" + +/* defines */ +#ifdef MV_DEBUG + #define DB(x) x +#else + #define DB(x) +#endif + + + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/device/mvDevice.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/device/mvDevice.h new file mode 100644 index 0000000..9350779 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/device/mvDevice.h @@ -0,0 +1,74 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#ifndef __INCmvDeviceH +#define __INCmvDeviceH + +#include "mvCommon.h" +#include "mvOs.h" +#include "ctrlEnv/mvCtrlEnvSpec.h" +#include "device/mvDeviceRegs.h" + + +#endif /* #ifndef __INCmvDeviceH */ diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/device/mvDeviceRegs.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/device/mvDeviceRegs.h new file mode 100644 index 0000000..80778ad --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/device/mvDeviceRegs.h @@ -0,0 +1,101 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#ifndef __INCmvDeviceRegsH +#define __INCmvDeviceRegsH + +#ifndef MV_ASMLANGUAGE +#include "ctrlEnv/mvCtrlEnvLib.h" +/* This enumerator describes the Marvell controller possible devices that */ +/* can be connected to its device interface. */ +typedef enum _mvDevice +{ +#if defined(MV_INCLUDE_DEVICE_CS0) + DEV_CS0 = 0, /* Device connected to dev CS[0] */ +#endif +#if defined(MV_INCLUDE_DEVICE_CS1) + DEV_CS1 = 1, /* Device connected to dev CS[1] */ +#endif +#if defined(MV_INCLUDE_DEVICE_CS2) + DEV_CS2 = 2, /* Device connected to dev CS[2] */ +#endif +#if defined(MV_INCLUDE_DEVICE_CS3) + DEV_CS3 = 3, /* Device connected to dev CS[2] */ +#endif +#if defined(MV_INCLUDE_DEVICE_CS4) + DEV_CS4 = 4, /* Device connected to BOOT dev */ +#endif + MV_DEV_MAX_CS = MV_DEVICE_MAX_CS +}MV_DEVICE; + + +#endif /* MV_ASMLANGUAGE */ + + +#define NAND_CTRL_REG 0x10470 + +#define NAND_ACTCEBOOT_BIT BIT1 + + +#endif /* #ifndef __INCmvDeviceRegsH */ diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/mvCompVer.txt b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/mvCompVer.txt new file mode 100644 index 0000000..4053116 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/kw_family/mvCompVer.txt @@ -0,0 +1,4 @@ +Global HAL Version: FEROCEON_HAL_3_1_7 +Unit HAL Version: 3.1.5 +Description: This component includes an implementation of the unit HAL drivers + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/linux_oss/mvOs.c b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/linux_oss/mvOs.c new file mode 100644 index 0000000..75f7e88 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/linux_oss/mvOs.c @@ -0,0 +1,211 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +*******************************************************************************/ +/******************************************************************************* +* mvOsCpuArchLib.c - Marvell CPU architecture library +* +* DESCRIPTION: +* This library introduce Marvell API for OS dependent CPU architecture +* APIs. This library introduce single CPU architecture services APKI +* cross OS. +* +* DEPENDENCIES: +* None. +* +*******************************************************************************/ + +/* includes */ +#include +#include "mvOs.h" + +static MV_U32 read_p15_c0 (void); + +/* defines */ +#define ARM_ID_REVISION_OFFS 0 +#define ARM_ID_REVISION_MASK (0xf << ARM_ID_REVISION_OFFS) + +#define ARM_ID_PART_NUM_OFFS 4 +#define ARM_ID_PART_NUM_MASK (0xfff << ARM_ID_PART_NUM_OFFS) + +#define ARM_ID_ARCH_OFFS 16 +#define ARM_ID_ARCH_MASK (0xf << ARM_ID_ARCH_OFFS) + +#define ARM_ID_VAR_OFFS 20 +#define ARM_ID_VAR_MASK (0xf << ARM_ID_VAR_OFFS) + +#define ARM_ID_ASCII_OFFS 24 +#define ARM_ID_ASCII_MASK (0xff << ARM_ID_ASCII_OFFS) + + + +void* mvOsIoCachedMalloc( void* osHandle, MV_U32 size, MV_ULONG* pPhyAddr, + MV_U32 *memHandle) +{ + void *p = kmalloc( size, GFP_KERNEL ); + *pPhyAddr = pci_map_single( osHandle, p, 0, PCI_DMA_BIDIRECTIONAL ); + return p; +} +void* mvOsIoUncachedMalloc( void* osHandle, MV_U32 size, MV_ULONG* pPhyAddr, + MV_U32 *memHandle) +{ + return pci_alloc_consistent( osHandle, size, (dma_addr_t *)pPhyAddr ); +} + +void mvOsIoUncachedFree( void* osHandle, MV_U32 size, MV_ULONG phyAddr, void* pVirtAddr, + MV_U32 memHandle) +{ + return pci_free_consistent( osHandle, size, pVirtAddr, (dma_addr_t)phyAddr ); +} + +void mvOsIoCachedFree( void* osHandle, MV_U32 size, MV_ULONG phyAddr, void* pVirtAddr, + MV_U32 memHandle ) +{ + return kfree( pVirtAddr ); +} + +int mvOsRand(void) +{ + int rand; + get_random_bytes(&rand, sizeof(rand) ); + return rand; +} + +/******************************************************************************* +* mvOsCpuVerGet() - +* +* DESCRIPTION: +* +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* 32bit CPU Revision +* +*******************************************************************************/ +MV_U32 mvOsCpuRevGet( MV_VOID ) +{ + return ((read_p15_c0() & ARM_ID_REVISION_MASK ) >> ARM_ID_REVISION_OFFS); +} +/******************************************************************************* +* mvOsCpuPartGet() - +* +* DESCRIPTION: +* +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* 32bit CPU Part number +* +*******************************************************************************/ +MV_U32 mvOsCpuPartGet( MV_VOID ) +{ + return ((read_p15_c0() & ARM_ID_PART_NUM_MASK ) >> ARM_ID_PART_NUM_OFFS); +} +/******************************************************************************* +* mvOsCpuArchGet() - +* +* DESCRIPTION: +* +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* 32bit CPU Architicture number +* +*******************************************************************************/ +MV_U32 mvOsCpuArchGet( MV_VOID ) +{ + return ((read_p15_c0() & ARM_ID_ARCH_MASK ) >> ARM_ID_ARCH_OFFS); +} +/******************************************************************************* +* mvOsCpuVarGet() - +* +* DESCRIPTION: +* +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* 32bit CPU Variant number +* +*******************************************************************************/ +MV_U32 mvOsCpuVarGet( MV_VOID ) +{ + return ((read_p15_c0() & ARM_ID_VAR_MASK ) >> ARM_ID_VAR_OFFS); +} +/******************************************************************************* +* mvOsCpuAsciiGet() - +* +* DESCRIPTION: +* +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* 32bit CPU Variant number +* +*******************************************************************************/ +MV_U32 mvOsCpuAsciiGet( MV_VOID ) +{ + return ((read_p15_c0() & ARM_ID_ASCII_MASK ) >> ARM_ID_ASCII_OFFS); +} + + + +/* +static unsigned long read_p15_c0 (void) +*/ +/* read co-processor 15, register #0 (ID register) */ +static MV_U32 read_p15_c0 (void) +{ + MV_U32 value; + + __asm__ __volatile__( + "mrc p15, 0, %0, c0, c0, 0 @ read control reg\n" + : "=r" (value) + : + : "memory"); + + return value; +} + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/linux_oss/mvOs.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/linux_oss/mvOs.h new file mode 100644 index 0000000..8da562a --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/linux_oss/mvOs.h @@ -0,0 +1,423 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +*******************************************************************************/ +#ifndef _MV_OS_LNX_H_ +#define _MV_OS_LNX_H_ + + +#ifdef __KERNEL__ +/* for kernel space */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include "dbg-trace.h" + +extern void mv_early_printk(char *fmt,...); + +#define MV_ASM __asm__ __volatile__ +#define INLINE inline +#define MV_TRC_REC TRC_REC +#define mvOsPrintf printk +#define mvOsEarlyPrintf mv_early_printk +#define mvOsOutput printk +#define mvOsSPrintf sprintf +#define mvOsMalloc(_size_) kmalloc(_size_,GFP_ATOMIC) +#define mvOsFree kfree +#define mvOsMemcpy memcpy +#define mvOsSleep(_mils_) mdelay(_mils_) +#define mvOsTaskLock() +#define mvOsTaskUnlock() +#define strtol simple_strtoul +#define mvOsDelay(x) mdelay(x) +#define mvOsUDelay(x) udelay(x) +#define mvCopyFromOs copy_from_user +#define mvCopyToOs copy_to_user + + +#include "mvTypes.h" +#include "mvCommon.h" + +#ifdef MV_NDEBUG +#define mvOsAssert(cond) +#else +#define mvOsAssert(cond) { do { if(!(cond)) { BUG(); } }while(0); } +#endif /* MV_NDEBUG */ + +#else /* __KERNEL__ */ + +/* for user space applications */ +#include +#include +#include +#include + +#define INLINE inline +#define mvOsPrintf printf +#define mvOsOutput printf +#define mvOsMalloc(_size_) malloc(_size_) +#define mvOsFree free +#define mvOsAssert(cond) assert(cond) + +#endif /* __KERNEL__ */ +#define mvOsIoVirtToPhy(pDev, pVirtAddr) \ + pci_map_single( (pDev), (pVirtAddr), 0, PCI_DMA_BIDIRECTIONAL ) + +#define mvOsCacheClear(pDev, p, size ) \ + pci_map_single( (pDev), (p), (size), PCI_DMA_BIDIRECTIONAL) + +#define mvOsCacheFlush(pDev, p, size ) \ + pci_map_single( (pDev), (p), (size), PCI_DMA_TODEVICE) + +#define mvOsCacheInvalidate(pDev, p, size) \ + pci_map_single( (pDev), (p), (size), PCI_DMA_FROMDEVICE ) + +#define mvOsCacheUnmap(pDev, phys, size) \ + pci_unmap_single( (pDev), (dma_addr_t)(phys), (size), PCI_DMA_FROMDEVICE ) + + +#define CPU_PHY_MEM(x) (MV_U32)x +#define CPU_MEMIO_CACHED_ADDR(x) (void*)x +#define CPU_MEMIO_UNCACHED_ADDR(x) (void*)x + + +/* CPU architecture dependent 32, 16, 8 bit read/write IO addresses */ +#define MV_MEMIO32_WRITE(addr, data) \ + ((*((volatile unsigned int*)(addr))) = ((unsigned int)(data))) + +#define MV_MEMIO32_READ(addr) \ + ((*((volatile unsigned int*)(addr)))) + +#define MV_MEMIO16_WRITE(addr, data) \ + ((*((volatile unsigned short*)(addr))) = ((unsigned short)(data))) + +#define MV_MEMIO16_READ(addr) \ + ((*((volatile unsigned short*)(addr)))) + +#define MV_MEMIO8_WRITE(addr, data) \ + ((*((volatile unsigned char*)(addr))) = ((unsigned char)(data))) + +#define MV_MEMIO8_READ(addr) \ + ((*((volatile unsigned char*)(addr)))) + + +/* No Fast Swap implementation (in assembler) for ARM */ +#define MV_32BIT_LE_FAST(val) MV_32BIT_LE(val) +#define MV_16BIT_LE_FAST(val) MV_16BIT_LE(val) +#define MV_32BIT_BE_FAST(val) MV_32BIT_BE(val) +#define MV_16BIT_BE_FAST(val) MV_16BIT_BE(val) + +/* 32 and 16 bit read/write in big/little endian mode */ + +/* 16bit write in little endian mode */ +#define MV_MEMIO_LE16_WRITE(addr, data) \ + MV_MEMIO16_WRITE(addr, MV_16BIT_LE_FAST(data)) + +/* 16bit read in little endian mode */ +static __inline MV_U16 MV_MEMIO_LE16_READ(MV_U32 addr) +{ + MV_U16 data; + + data= (MV_U16)MV_MEMIO16_READ(addr); + + return (MV_U16)MV_16BIT_LE_FAST(data); +} + +/* 32bit write in little endian mode */ +#define MV_MEMIO_LE32_WRITE(addr, data) \ + MV_MEMIO32_WRITE(addr, MV_32BIT_LE_FAST(data)) + +/* 32bit read in little endian mode */ +static __inline MV_U32 MV_MEMIO_LE32_READ(MV_U32 addr) +{ + MV_U32 data; + + data= (MV_U32)MV_MEMIO32_READ(addr); + + return (MV_U32)MV_32BIT_LE_FAST(data); +} + +static __inline void mvOsBCopy(char* srcAddr, char* dstAddr, int byteCount) +{ + while(byteCount != 0) + { + *dstAddr = *srcAddr; + dstAddr++; + srcAddr++; + byteCount--; + } +} + +static INLINE MV_U64 mvOsDivMod64(MV_U64 divided, MV_U64 divisor, MV_U64* modulu) +{ + MV_U64 division = 0; + + if(divisor == 1) + return divided; + + while(divided >= divisor) + { + division++; + divided -= divisor; + } + if (modulu != NULL) + *modulu = divided; + + return division; +} + +#if defined(MV_BRIDGE_SYNC_REORDER) +extern MV_U32 *mvUncachedParam; + +static __inline void mvOsBridgeReorderWA(void) +{ + volatile MV_U32 val = 0; + + val = mvUncachedParam[0]; +} +#endif + + +/* Flash APIs */ +#define MV_FL_8_READ MV_MEMIO8_READ +#define MV_FL_16_READ MV_MEMIO_LE16_READ +#define MV_FL_32_READ MV_MEMIO_LE32_READ +#define MV_FL_8_DATA_READ MV_MEMIO8_READ +#define MV_FL_16_DATA_READ MV_MEMIO16_READ +#define MV_FL_32_DATA_READ MV_MEMIO32_READ +#define MV_FL_8_WRITE MV_MEMIO8_WRITE +#define MV_FL_16_WRITE MV_MEMIO_LE16_WRITE +#define MV_FL_32_WRITE MV_MEMIO_LE32_WRITE +#define MV_FL_8_DATA_WRITE MV_MEMIO8_WRITE +#define MV_FL_16_DATA_WRITE MV_MEMIO16_WRITE +#define MV_FL_32_DATA_WRITE MV_MEMIO32_WRITE + + +/* CPU cache information */ +#define CPU_I_CACHE_LINE_SIZE 32 /* 2do: replace 32 with linux core macro */ +#define CPU_D_CACHE_LINE_SIZE 32 /* 2do: replace 32 with linux core macro */ + +#ifdef CONFIG_L2_CACHE_ENABLE +/* Data cache flush one line */ +#define mvOsCacheLineFlushInv(handle, addr) \ +{ \ + __asm__ __volatile__ ("mcr p15, 0, %0, c7, c14, 1" : : "r" (addr));\ + __asm__ __volatile__ ("mcr p15, 1, %0, c15, c10, 1" : : "r" (addr));\ + __asm__ __volatile__ ("mcr p15, 0, r0, c7, c10, 4"); \ +} + +#else + +/* Data cache flush one line */ +#define mvOsCacheLineFlushInv(handle, addr) \ +{ \ + __asm__ __volatile__ ("mcr p15, 0, %0, c7, c14, 1" : : "r" (addr));\ + __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 4" : : "r" (addr)); \ +} +#endif + +#ifdef CONFIG_L2_CACHE_ENABLE +#define mvOsCacheLineInv(handle,addr) \ +{ \ + __asm__ __volatile__ ("mcr p15, 0, %0, c7, c6, 1" : : "r" (addr)); \ + __asm__ __volatile__ ("mcr p15, 1, %0, c15, c11, 1" : : "r" (addr)); \ +} +#else +#define mvOsCacheLineInv(handle,addr) \ +{ \ + __asm__ __volatile__ ("mcr p15, 0, %0, c7, c6, 1" : : "r" (addr)); \ +} +#endif + +#ifdef CONFIG_L2_CACHE_ENABLE +/* Data cache flush one line */ +#define mvOsCacheLineFlush(handle, addr) \ +{ \ + __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 1" : : "r" (addr));\ + __asm__ __volatile__ ("mcr p15, 1, %0, c15, c9, 1" : : "r" (addr));\ + __asm__ __volatile__ ("mcr p15, 0, r0, c7, c10, 4"); \ +} + +#else +/* Data cache flush one line */ +#define mvOsCacheLineFlush(handle, addr) \ +{ \ + __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 1" : : "r" (addr));\ + __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 4" : : "r" (addr)); \ +} +#endif + +static __inline void mvOsPrefetch(const void *ptr) +{ +#ifdef CONFIG_USE_DSP + __asm__ __volatile__( + "pld\t%0" + : + : "o" (*(char *)ptr) + : "cc"); +#else + return; +#endif +} + + +/* Flush CPU pipe */ +#define CPU_PIPE_FLUSH + + + + + +/* register manipulations */ + +/****************************************************************************** +* This debug function enable the write of each register that u-boot access to +* to an array in the DRAM, the function record only MV_REG_WRITE access. +* The function could not be operate when booting from flash. +* In order to print the array we use the printreg command. +******************************************************************************/ +/* #define REG_DEBUG */ +#if defined(REG_DEBUG) +extern int reg_arry[2048][2]; +extern int reg_arry_index; +#endif + +/* Marvell controller register read/write macros */ +#define MV_REG_VALUE(offset) \ + (MV_MEMIO32_READ((INTER_REGS_BASE | (offset)))) + +#define MV_REG_READ(offset) \ + (MV_MEMIO_LE32_READ(INTER_REGS_BASE | (offset))) + +#if defined(REG_DEBUG) +#define MV_REG_WRITE(offset, val) \ + MV_MEMIO_LE32_WRITE((INTER_REGS_BASE | (offset)), (val)); \ + { \ + reg_arry[reg_arry_index][0] = (INTER_REGS_BASE | (offset));\ + reg_arry[reg_arry_index][1] = (val);\ + reg_arry_index++;\ + } +#else +#define MV_REG_WRITE(offset, val) \ + MV_MEMIO_LE32_WRITE((INTER_REGS_BASE | (offset)), (val)); +#endif + +#define MV_REG_BYTE_READ(offset) \ + (MV_MEMIO8_READ((INTER_REGS_BASE | (offset)))) + +#if defined(REG_DEBUG) +#define MV_REG_BYTE_WRITE(offset, val) \ + MV_MEMIO8_WRITE((INTER_REGS_BASE | (offset)), (val)); \ + { \ + reg_arry[reg_arry_index][0] = (INTER_REGS_BASE | (offset));\ + reg_arry[reg_arry_index][1] = (val);\ + reg_arry_index++;\ + } +#else +#define MV_REG_BYTE_WRITE(offset, val) \ + MV_MEMIO8_WRITE((INTER_REGS_BASE | (offset)), (val)) +#endif + +#if defined(REG_DEBUG) +#define MV_REG_BIT_SET(offset, bitMask) \ + (MV_MEMIO32_WRITE((INTER_REGS_BASE | (offset)), \ + (MV_MEMIO32_READ(INTER_REGS_BASE | (offset)) | \ + MV_32BIT_LE_FAST(bitMask)))); \ + { \ + reg_arry[reg_arry_index][0] = (INTER_REGS_BASE | (offset));\ + reg_arry[reg_arry_index][1] = (MV_MEMIO32_READ(INTER_REGS_BASE | (offset)));\ + reg_arry_index++;\ + } +#else +#define MV_REG_BIT_SET(offset, bitMask) \ + (MV_MEMIO32_WRITE((INTER_REGS_BASE | (offset)), \ + (MV_MEMIO32_READ(INTER_REGS_BASE | (offset)) | \ + MV_32BIT_LE_FAST(bitMask)))) +#endif + +#if defined(REG_DEBUG) +#define MV_REG_BIT_RESET(offset,bitMask) \ + (MV_MEMIO32_WRITE((INTER_REGS_BASE | (offset)), \ + (MV_MEMIO32_READ(INTER_REGS_BASE | (offset)) & \ + MV_32BIT_LE_FAST(~bitMask)))); \ + { \ + reg_arry[reg_arry_index][0] = (INTER_REGS_BASE | (offset));\ + reg_arry[reg_arry_index][1] = (MV_MEMIO32_READ(INTER_REGS_BASE | (offset)));\ + reg_arry_index++;\ + } +#else +#define MV_REG_BIT_RESET(offset,bitMask) \ + (MV_MEMIO32_WRITE((INTER_REGS_BASE | (offset)), \ + (MV_MEMIO32_READ(INTER_REGS_BASE | (offset)) & \ + MV_32BIT_LE_FAST(~bitMask)))) +#endif + + + +/* ARM architecture APIs */ +MV_U32 mvOsCpuRevGet (MV_VOID); +MV_U32 mvOsCpuPartGet (MV_VOID); +MV_U32 mvOsCpuArchGet (MV_VOID); +MV_U32 mvOsCpuVarGet (MV_VOID); +MV_U32 mvOsCpuAsciiGet (MV_VOID); + +/* Other APIs */ +void* mvOsIoCachedMalloc( void* osHandle, MV_U32 size, MV_ULONG* pPhyAddr, MV_U32 *memHandle); +void* mvOsIoUncachedMalloc( void* osHandle, MV_U32 size, MV_ULONG* pPhyAddr, MV_U32 *memHandle ); +void mvOsIoUncachedFree( void* osHandle, MV_U32 size, MV_ULONG phyAddr, void* pVirtAddr, MV_U32 memHandle ); +void mvOsIoCachedFree( void* osHandle, MV_U32 size, MV_ULONG phyAddr, void* pVirtAddr, MV_U32 memHandle ); +int mvOsRand(void); + +#endif /* _MV_OS_LNX_H_ */ + + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/linux_oss/mvOsSata.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/linux_oss/mvOsSata.h new file mode 100644 index 0000000..c925a9e --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/linux_oss/mvOsSata.h @@ -0,0 +1,158 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +*******************************************************************************/ +/******************************************************************************* +* mvOsLinux.h - O.S. interface header file for Linux +* +* DESCRIPTION: +* This header file contains OS dependent definition under Linux +* +* DEPENDENCIES: +* Linux kernel header files. +* +* FILE REVISION NUMBER: +* $Revision: 1.1 $ +*******************************************************************************/ + +#ifndef __INCmvOsLinuxh +#define __INCmvOsLinuxh + +/* Includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include "mvOs.h" + + +/* Definitions */ +#define MV_DEFAULT_QUEUE_DEPTH 2 +#define MV_SATA_SUPPORT_EDMA_SINGLE_DATA_REGION +#define MV_SATA_SUPPORT_GEN2E_128_QUEUE_LEN + +#ifdef CONFIG_MV88F6082 + #define MV_SATA_OVERRIDE_SW_QUEUE_SIZE + #define MV_SATA_REQUESTED_SW_QUEUE_SIZE 2 + #undef MV_SATA_SUPPORT_GEN2E_128_QUEUE_LEN +#endif + +/* System dependent macro for flushing CPU write cache */ +#if defined (MV_BRIDGE_SYNC_REORDER) +#define MV_CPU_WRITE_BUFFER_FLUSH() do { \ + wmb(); \ + mvOsBridgeReorderWA(); \ + } while (0) +#else +#define MV_CPU_WRITE_BUFFER_FLUSH() wmb() +#endif /* CONFIG_MV78XX0 */ + +/* System dependent little endian from / to CPU conversions */ +#define MV_CPU_TO_LE16(x) cpu_to_le16(x) +#define MV_CPU_TO_LE32(x) cpu_to_le32(x) + +#define MV_LE16_TO_CPU(x) le16_to_cpu(x) +#define MV_LE32_TO_CPU(x) le32_to_cpu(x) + +#ifdef __BIG_ENDIAN_BITFIELD +#define MV_BIG_ENDIAN_BITFIELD +#endif + +/* System dependent register read / write in byte/word/dword variants */ +#define MV_REG_WRITE_BYTE(base, offset, val) writeb(val, base + offset) +#define MV_REG_WRITE_WORD(base, offset, val) writew(val, base + offset) +#define MV_REG_WRITE_DWORD(base, offset, val) writel(val, base + offset) +#define MV_REG_READ_BYTE(base, offset) readb(base + offset) +#define MV_REG_READ_WORD(base, offset) readw(base + offset) +#define MV_REG_READ_DWORD(base, offset) readl(base + offset) + + +/* Typedefs */ + +/* System dependant typedefs */ +typedef void *MV_VOID_PTR; +typedef u32 *MV_U32_PTR; +typedef u16 *MV_U16_PTR; +typedef u8 *MV_U8_PTR; +typedef char *MV_CHAR_PTR; +typedef void *MV_BUS_ADDR_T; +typedef unsigned long MV_CPU_FLAGS; + + +/* Structures */ +/* System dependent structure */ +typedef struct mvOsSemaphore +{ + int notUsed; +} MV_OS_SEMAPHORE; + + +/* Functions (User implemented)*/ + +/* Semaphore init, take and release */ +#define mvOsSemInit(x) MV_TRUE +#define mvOsSemTake(x) +#define mvOsSemRelease(x) + +/* Interrupt masking and unmasking functions */ +MV_CPU_FLAGS mvOsSaveFlagsAndMaskCPUInterrupts(MV_VOID); +MV_VOID mvOsRestoreFlags(MV_CPU_FLAGS); + +/* Delay function in micro seconds resolution */ +void mvMicroSecondsDelay(MV_VOID_PTR, MV_U32); + +/* Typedefs */ +typedef enum mvBoolean +{ + MV_SFALSE, MV_STRUE +} MV_BOOLEAN; + +/* System logging function */ +#include "mvLog.h" +/* Enable READ/WRITE Long SCSI command only when driver is compiled for debugging */ +#ifdef MV_LOGGER +#define MV_SATA_SUPPORT_READ_WRITE_LONG +#endif + +#define MV_IAL_LOG_ID 3 + +#endif /* __INCmvOsLinuxh */ diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mvSysHwConfig.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mvSysHwConfig.h new file mode 100644 index 0000000..d761060 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mvSysHwConfig.h @@ -0,0 +1,375 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. + +*******************************************************************************/ +/******************************************************************************* +* mvSysHwCfg.h - Marvell system HW configuration file +* +* DESCRIPTION: +* None. +* +* DEPENDENCIES: +* None. +* +*******************************************************************************/ + +#ifndef __INCmvSysHwConfigh +#define __INCmvSysHwConfigh + +#include "../../../../include/linux/autoconf.h" + +#define CONFIG_MARVELL 1 + +/* includes */ +#define _1K 0x00000400 +#define _4K 0x00001000 +#define _8K 0x00002000 +#define _16K 0x00004000 +#define _32K 0x00008000 +#define _64K 0x00010000 +#define _128K 0x00020000 +#define _256K 0x00040000 +#define _512K 0x00080000 + +#define _1M 0x00100000 +#define _2M 0x00200000 +#define _4M 0x00400000 +#define _8M 0x00800000 +#define _16M 0x01000000 +#define _32M 0x02000000 +#define _64M 0x04000000 +#define _128M 0x08000000 +#define _256M 0x10000000 +#define _512M 0x20000000 + +#define _1G 0x40000000 +#define _2G 0x80000000 + +/****************************************/ +/* Soc supporeted Units definitions */ +/****************************************/ + +#ifdef CONFIG_MV_INCLUDE_PEX +#define MV_INCLUDE_PEX +#endif +#ifdef CONFIG_MV_INCLUDE_TWSI +#define MV_INCLUDE_TWSI +#endif +#ifdef CONFIG_MV_INCLUDE_CESA +#define MV_INCLUDE_CESA +#endif +#ifdef CONFIG_MV_INCLUDE_GIG_ETH +#define MV_INCLUDE_GIG_ETH +#endif +#ifdef CONFIG_MV_INCLUDE_INTEG_SATA +#define MV_INCLUDE_INTEG_SATA +#define MV_INCLUDE_SATA +#endif +#ifdef CONFIG_MV_INCLUDE_USB +#define MV_INCLUDE_USB +#define MV_USB_VOLTAGE_FIX +#endif +#ifdef CONFIG_MV_INCLUDE_NAND +#define MV_INCLUDE_NAND +#endif +#ifdef CONFIG_MV_INCLUDE_TDM +#define MV_INCLUDE_TDM +#endif +#ifdef CONFIG_MV_INCLUDE_XOR +#define MV_INCLUDE_XOR +#endif +#ifdef CONFIG_MV_INCLUDE_TWSI +#define MV_INCLUDE_TWSI +#endif +#ifdef CONFIG_MV_INCLUDE_UART +#define MV_INCLUDE_UART +#endif +#ifdef CONFIG_MV_INCLUDE_SPI +#define MV_INCLUDE_SPI +#endif +#ifdef CONFIG_MV_INCLUDE_SFLASH_MTD +#define MV_INCLUDE_SFLASH_MTD +#endif +#ifdef CONFIG_MV_INCLUDE_AUDIO +#define MV_INCLUDE_AUDIO +#endif +#ifdef CONFIG_MV_INCLUDE_TS +#define MV_INCLUDE_TS +#endif +#ifdef CONFIG_MV_INCLUDE_SDIO +#define MV_INCLUDE_SDIO +#endif + + +/* NAND flash stuff */ +#ifdef CONFIG_MV_NAND_BOOT +#define MV_NAND_BOOT +#endif +#ifdef CONFIG_MV_NAND +#define MV_NAND +#endif + +/* SPI flash stuff */ +#ifdef CONFIG_MV_SPI_BOOT +#define MV_SPI_BOOT +#endif + + +/****************************************************************/ +/************* General configuration ********************/ +/****************************************************************/ + +/* Enable Clock Power Control */ +#define MV_INCLUDE_CLK_PWR_CNTRL + +/* Disable the DEVICE BAR in the PEX */ +#define MV_DISABLE_PEX_DEVICE_BAR + +/* Allow the usage of early printings during initialization */ +#define MV_INCLUDE_EARLY_PRINTK + +/****************************************************************/ +/************* NFP configuration ********************************/ +/****************************************************************/ +#define MV_NFP_SEC_Q_SIZE 64 +#define MV_NFP_SEC_REQ_Q_SIZE 1000 + + + +/****************************************************************/ +/************* CESA configuration ********************/ +/****************************************************************/ + +#ifdef MV_INCLUDE_CESA + +#define MV_CESA_MAX_CHAN 4 + +/* Use 2K of SRAM */ +#define MV_CESA_MAX_BUF_SIZE 1600 + +#endif /* MV_INCLUDE_CESA */ + +#if defined(CONFIG_MV_INCLUDE_GIG_ETH) + +#ifdef CONFIG_MV_NFP_STATS +#define MV_FP_STATISTICS +#else +#undef MV_FP_STATISTICS +#endif +/* Default configuration for SKB_REUSE: 0 - Disabled, 1 - Enabled */ +#define MV_ETH_SKB_REUSE_DEFAULT 1 +/* Default configuration for TX_EN workaround: 0 - Disabled, 1 - Enabled */ +#define MV_ETH_TX_EN_DEFAULT 0 + +/* un-comment if you want to perform tx_done from within the poll function */ +/* #define ETH_TX_DONE_ISR */ + +/* put descriptors in uncached memory */ +/* #define ETH_DESCR_UNCACHED */ + +/* Descriptors location: DRAM/internal-SRAM */ +#define ETH_DESCR_IN_SDRAM +#undef ETH_DESCR_IN_SRAM /* No integrated SRAM in 88Fxx81 devices */ + +#if defined(ETH_DESCR_IN_SRAM) +#if defined(ETH_DESCR_UNCACHED) + #define ETH_DESCR_CONFIG_STR "Uncached descriptors in integrated SRAM" +#else + #define ETH_DESCR_CONFIG_STR "Cached descriptors in integrated SRAM" +#endif +#elif defined(ETH_DESCR_IN_SDRAM) +#if defined(ETH_DESCR_UNCACHED) + #define ETH_DESCR_CONFIG_STR "Uncached descriptors in DRAM" +#else + #define ETH_DESCR_CONFIG_STR "Cached descriptors in DRAM" +#endif +#else + #error "Ethernet descriptors location undefined" +#endif /* ETH_DESCR_IN_SRAM or ETH_DESCR_IN_SDRAM*/ + +/* SW Sync-Barrier: not relevant for 88fxx81*/ +/* Reasnable to define this macro when descriptors in SRAM and buffers in DRAM */ +/* In RX the CPU theoretically might see himself as the descriptor owner, */ +/* although the buffer hadn't been written to DRAM yet. Performance cost. */ +/* #define INCLUDE_SYNC_BARR */ + +/* Buffers cache coherency method (buffers in DRAM) */ +#ifndef MV_CACHE_COHER_SW +/* Taken from mvCommon.h */ +/* Memory uncached, HW or SW cache coherency is not needed */ +#define MV_UNCACHED 0 +/* Memory cached, HW cache coherency supported in WriteThrough mode */ +#define MV_CACHE_COHER_HW_WT 1 +/* Memory cached, HW cache coherency supported in WriteBack mode */ +#define MV_CACHE_COHER_HW_WB 2 +/* Memory cached, No HW cache coherency, Cache coherency must be in SW */ +#define MV_CACHE_COHER_SW 3 + +#endif + +/* DRAM cache coherency configuration */ +#define MV_CACHE_COHERENCY MV_CACHE_COHER_SW + + +#define ETHER_DRAM_COHER MV_CACHE_COHER_SW /* No HW coherency in 88Fxx81 devices */ + +#if (ETHER_DRAM_COHER == MV_CACHE_COHER_HW_WB) + #define ETH_SDRAM_CONFIG_STR "DRAM HW cache coherency (write-back)" +#elif (ETHER_DRAM_COHER == MV_CACHE_COHER_HW_WT) + #define ETH_SDRAM_CONFIG_STR "DRAM HW cache coherency (write-through)" +#elif (ETHER_DRAM_COHER == MV_CACHE_COHER_SW) + #define ETH_SDRAM_CONFIG_STR "DRAM SW cache-coherency" +#elif (ETHER_DRAM_COHER == MV_UNCACHED) +# define ETH_SDRAM_CONFIG_STR "DRAM uncached" +#else + #error "Ethernet-DRAM undefined" +#endif /* ETHER_DRAM_COHER */ + + +/****************************************************************/ +/************* Ethernet driver configuration ********************/ +/****************************************************************/ + +/* port's default queueus */ +#define ETH_DEF_TXQ 0 +#define ETH_DEF_RXQ 0 + +#define MV_ETH_RX_Q_NUM CONFIG_MV_ETH_RX_Q_NUM +#define MV_ETH_TX_Q_NUM CONFIG_MV_ETH_TX_Q_NUM + +/* interrupt coalescing setting */ +#define ETH_TX_COAL 200 +#define ETH_RX_COAL 200 + +/* Checksum offloading */ +#define TX_CSUM_OFFLOAD +#define RX_CSUM_OFFLOAD + +#endif /* CONFIG_MV_INCLUDE_GIG_ETH */ + +/****************************************************************/ +/*************** Telephony configuration ************************/ +/****************************************************************/ +#if defined(CONFIG_MV_TDM_LINEAR_MODE) + #define MV_TDM_LINEAR_MODE +#elif defined(CONFIG_MV_TDM_ULAW_MODE) + #define MV_TDM_ULAW_MODE +#endif + +#if defined(CONFIG_MV_TDM_5CHANNELS) + #define MV_TDM_5CHANNELS +#endif + +#if defined(CONFIG_MV_TDM_USE_EXTERNAL_PCLK_SOURCE) + #define MV_TDM_USE_EXTERNAL_PCLK_SOURCE +#endif + +/* We use the following registers to store DRAM interface pre configuration */ +/* auto-detection results */ +/* IMPORTANT: We are using mask register for that purpose. Before writing */ +/* to units mask register, make sure main maks register is set to disable */ +/* all interrupts. */ +#define DRAM_BUF_REG0 0x30810 /* sdram bank 0 size */ +#define DRAM_BUF_REG1 0x30820 /* sdram config */ +#define DRAM_BUF_REG2 0x30830 /* sdram mode */ +#define DRAM_BUF_REG3 0x308c4 /* dunit control low */ +#define DRAM_BUF_REG4 0x60a90 /* sdram address control */ +#define DRAM_BUF_REG5 0x60a94 /* sdram timing control low */ +#define DRAM_BUF_REG6 0x60a98 /* sdram timing control high */ +#define DRAM_BUF_REG7 0x60a9c /* sdram ODT control low */ +#define DRAM_BUF_REG8 0x60b90 /* sdram ODT control high */ +#define DRAM_BUF_REG9 0x60b94 /* sdram Dunit ODT control */ +#define DRAM_BUF_REG10 0x60b98 /* sdram Extended Mode */ +#define DRAM_BUF_REG11 0x60b9c /* sdram Ddr2 Time Low Reg */ +#define DRAM_BUF_REG12 0x60a00 /* sdram Ddr2 Time High Reg */ +#define DRAM_BUF_REG13 0x60a04 /* dunit Ctrl High */ +#define DRAM_BUF_REG14 0x60b00 /* sdram second DIMM exist */ + +/* Following the pre-configuration registers default values restored after */ +/* auto-detection is done */ +#define DRAM_BUF_REG_DV 0 + +/* System Mapping */ +#define SDRAM_CS0_BASE 0x00000000 +#define SDRAM_CS0_SIZE _256M + +#define SDRAM_CS1_BASE 0x10000000 +#define SDRAM_CS1_SIZE _256M + +#define SDRAM_CS2_BASE 0x20000000 +#define SDRAM_CS2_SIZE _256M + +#define SDRAM_CS3_BASE 0x30000000 +#define SDRAM_CS3_SIZE _256M + +/* PEX */ +#define PEX0_MEM_BASE 0xe8000000 +#define PEX0_MEM_SIZE _128M + +#define PEX0_IO_BASE 0xf2000000 +#define PEX0_IO_SIZE _1M + +/* Device Chip Selects */ +#define NFLASH_CS_BASE 0xfa000000 +#define NFLASH_CS_SIZE _2M + +#define SPI_CS_BASE 0xf4000000 +#define SPI_CS_SIZE _16M + +#define CRYPT_ENG_BASE 0xf0000000 +#define CRYPT_ENG_SIZE _2M + +#define BOOTDEV_CS_BASE 0xff800000 +#define BOOTDEV_CS_SIZE _8M + +/* CS2 - BOOTROM */ +#define DEVICE_CS2_BASE 0xff900000 +#define DEVICE_CS2_SIZE _1M + +/* PEX Work arround */ +/* the target we will use for the workarround */ +#define PEX_CONFIG_RW_WA_TARGET PEX0_MEM +/*a flag that indicates if we are going to use the +size and base of the target we using for the workarround +window */ +#define PEX_CONFIG_RW_WA_USE_ORIGINAL_WIN_VALUES 1 +/* if the above flag is 0 then the following values +will be used for the workarround window base and size, +otherwise the following defines will be ignored */ +#define PEX_CONFIG_RW_WA_BASE 0xF3000000 +#define PEX_CONFIG_RW_WA_SIZE _16M + +/* Internal registers: size is defined in Controllerenvironment */ +#define INTER_REGS_BASE 0xFEE00000 + +/* DRAM detection stuff */ +#define MV_DRAM_AUTO_SIZE + +/* Board clock detection */ +#define TCLK_AUTO_DETECT /* Use Tclk auto detection */ +#define SYSCLK_AUTO_DETECT /* Use SysClk auto detection */ +#define PCLCK_AUTO_DETECT /* Use PClk auto detection */ +#define L2CLK_AUTO_DETECT /* Use L2Clk auto detection */ + +/* PEX-PCI\PCI-PCI Bridge*/ +#define PCI0_IF_PTP 0 /* Bridge exist on pciIf0*/ + + + +#endif /* __INCmvSysHwConfigh */ + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/cntmr/mvCntmr.c b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/cntmr/mvCntmr.c new file mode 100644 index 0000000..717c150 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/cntmr/mvCntmr.c @@ -0,0 +1,376 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#include "mvCntmr.h" +#include "cpu/mvCpu.h" + +/* defines */ +#ifdef MV_DEBUG + #define DB(x) x +#else + #define DB(x) +#endif + +extern unsigned int whoAmI(void); + +/******************************************************************************* +* mvCntmrLoad - +* +* DESCRIPTION: +* Load an init Value to a given counter/timer +* +* INPUT: +* countNum - counter number +* value - value to be loaded +* +* OUTPUT: +* None. +* +* RETURN: +* MV_BAD_PARAM on bad parameters , MV_ERROR on error ,MV_OK on sucess +*******************************************************************************/ +MV_STATUS mvCntmrLoad(MV_U32 countNum, MV_U32 value) +{ + if (countNum >= MV_CNTMR_MAX_COUNTER ) + { + + mvOsPrintf(("mvCntmrLoad: Err. Illigal counter number \n")); + return MV_BAD_PARAM;; + + } + + MV_REG_WRITE(CNTMR_RELOAD_REG(countNum),value); + MV_REG_WRITE(CNTMR_VAL_REG(countNum),value); + + return MV_OK; +} + +/******************************************************************************* +* mvCntmrRead - +* +* DESCRIPTION: +* Returns the value of the given Counter/Timer +* +* INPUT: +* countNum - counter number +* +* OUTPUT: +* None. +* +* RETURN: +* MV_U32 counter value +*******************************************************************************/ +MV_U32 mvCntmrRead(MV_U32 countNum) +{ + return MV_REG_READ(CNTMR_VAL_REG(countNum)); +} + +/******************************************************************************* +* mvCntmrWrite - +* +* DESCRIPTION: +* Returns the value of the given Counter/Timer +* +* INPUT: +* countNum - counter number +* countVal - value to write +* +* OUTPUT: +* None. +* +* RETURN: +* None +*******************************************************************************/ +void mvCntmrWrite(MV_U32 countNum,MV_U32 countVal) +{ + MV_REG_WRITE(CNTMR_VAL_REG(countNum),countVal); +} + +/******************************************************************************* +* mvCntmrCtrlSet - +* +* DESCRIPTION: +* Set the Control to a given counter/timer +* +* INPUT: +* countNum - counter number +* pCtrl - pointer to MV_CNTMR_CTRL structure +* +* OUTPUT: +* None. +* +* RETURN: +* MV_BAD_PARAM on bad parameters , MV_ERROR on error ,MV_OK on sucess +*******************************************************************************/ +MV_STATUS mvCntmrCtrlSet(MV_U32 countNum, MV_CNTMR_CTRL *pCtrl) +{ + MV_U32 cntmrCtrl; + + if (countNum >= MV_CNTMR_MAX_COUNTER ) + { + + DB(mvOsPrintf(("mvCntmrCtrlSet: Err. Illigal counter number \n"))); + return MV_BAD_PARAM;; + + } + + /* read control register */ + cntmrCtrl = MV_REG_READ(CNTMR_CTRL_REG); + + + if (pCtrl->enable) /* enable counter\timer */ + { + cntmrCtrl |= CTCR_ARM_TIMER_EN(countNum); + } + else /* disable counter\timer */ + { + cntmrCtrl &= ~CTCR_ARM_TIMER_EN(countNum); + } + + if ( pCtrl->autoEnable ) /* Auto mode */ + { + cntmrCtrl |= CTCR_ARM_TIMER_AUTO_EN(countNum); + + } + else /* no auto mode */ + { + cntmrCtrl &= ~CTCR_ARM_TIMER_AUTO_EN(countNum); + } + + MV_REG_WRITE(CNTMR_CTRL_REG,cntmrCtrl); + + return MV_OK; + +} + +/******************************************************************************* +* mvCntmrCtrlGet - +* +* DESCRIPTION: +* Get the Control value of a given counter/timer +* +* INPUT: +* countNum - counter number +* pCtrl - pointer to MV_CNTMR_CTRL structure +* +* OUTPUT: +* Counter\Timer control value +* +* RETURN: +* MV_BAD_PARAM on bad parameters , MV_ERROR on error ,MV_OK on sucess +*******************************************************************************/ +MV_STATUS mvCntmrCtrlGet(MV_U32 countNum, MV_CNTMR_CTRL *pCtrl) +{ + MV_U32 cntmrCtrl; + + if (countNum >= MV_CNTMR_MAX_COUNTER ) + { + DB(mvOsPrintf(("mvCntmrCtrlGet: Err. Illigal counter number \n"))); + return MV_BAD_PARAM;; + } + + /* read control register */ + cntmrCtrl = MV_REG_READ(CNTMR_CTRL_REG); + + /* enable counter\timer */ + if (cntmrCtrl & CTCR_ARM_TIMER_EN(countNum)) + { + pCtrl->enable = MV_TRUE; + } + else + { + pCtrl->enable = MV_FALSE; + } + + /* counter mode */ + if (cntmrCtrl & CTCR_ARM_TIMER_AUTO_EN(countNum)) + { + pCtrl->autoEnable = MV_TRUE; + } + else + { + pCtrl->autoEnable = MV_FALSE; + } + + return MV_OK; +} + +/******************************************************************************* +* mvCntmrEnable - +* +* DESCRIPTION: +* Set the Enable-Bit to logic '1' ==> starting the counter +* +* INPUT: +* countNum - counter number +* +* OUTPUT: +* None. +* +* RETURN: +* MV_BAD_PARAM on bad parameters , MV_ERROR on error ,MV_OK on sucess +*******************************************************************************/ +MV_STATUS mvCntmrEnable(MV_U32 countNum) +{ + MV_U32 cntmrCtrl; + + if (countNum >= MV_CNTMR_MAX_COUNTER ) + { + + DB(mvOsPrintf(("mvCntmrEnable: Err. Illigal counter number \n"))); + return MV_BAD_PARAM;; + + } + + /* read control register */ + cntmrCtrl = MV_REG_READ(CNTMR_CTRL_REG); + + /* enable counter\timer */ + cntmrCtrl |= CTCR_ARM_TIMER_EN(countNum); + + + MV_REG_WRITE(CNTMR_CTRL_REG,cntmrCtrl); + + return MV_OK; +} + +/******************************************************************************* +* mvCntmrDisable - +* +* DESCRIPTION: +* Stop the counter/timer running, and returns its Value +* +* INPUT: +* countNum - counter number +* +* OUTPUT: +* None. +* +* RETURN: +* MV_U32 counter\timer value +*******************************************************************************/ +MV_STATUS mvCntmrDisable(MV_U32 countNum) +{ + MV_U32 cntmrCtrl; + + if (countNum >= MV_CNTMR_MAX_COUNTER ) + { + + DB(mvOsPrintf(("mvCntmrDisable: Err. Illigal counter number \n"))); + return MV_BAD_PARAM;; + + } + + /* read control register */ + cntmrCtrl = MV_REG_READ(CNTMR_CTRL_REG); + + /* disable counter\timer */ + cntmrCtrl &= ~CTCR_ARM_TIMER_EN(countNum); + + MV_REG_WRITE(CNTMR_CTRL_REG,cntmrCtrl); + + return MV_OK; +} + +/******************************************************************************* +* mvCntmrStart - +* +* DESCRIPTION: +* Combined all the sub-operations above to one function: Load,setMode,Enable +* +* INPUT: +* countNum - counter number +* value - value of the counter\timer to be set +* pCtrl - pointer to MV_CNTMR_CTRL structure +* +* OUTPUT: +* None. +* +* RETURN: +* MV_BAD_PARAM on bad parameters , MV_ERROR on error ,MV_OK on sucess +*******************************************************************************/ +MV_STATUS mvCntmrStart(MV_U32 countNum, MV_U32 value, + MV_CNTMR_CTRL *pCtrl) +{ + + if (countNum >= MV_CNTMR_MAX_COUNTER ) + { + + mvOsPrintf(("mvCntmrDisable: Err. Illigal counter number \n")); + return MV_BAD_PARAM;; + + } + + /* load value onto counter\timer */ + mvCntmrLoad(countNum,value); + + /* set the counter to load in the first time */ + mvCntmrWrite(countNum,value); + + /* set control for timer \ cunter and enable */ + mvCntmrCtrlSet(countNum,pCtrl); + + return MV_OK; +} + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/cntmr/mvCntmr.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/cntmr/mvCntmr.h new file mode 100644 index 0000000..b911d0f --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/cntmr/mvCntmr.h @@ -0,0 +1,121 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#ifndef __INCmvTmrWtdgh +#define __INCmvTmrWtdgh + +/* includes */ +#include "mvCommon.h" +#include "mvOs.h" +#include "cntmr/mvCntmrRegs.h" +#include "ctrlEnv/mvCtrlEnvSpec.h" + + +/* This enumerator describe counters\watchdog numbers */ +typedef enum _mvCntmrID +{ + TIMER0 = 0, + TIMER1, + WATCHDOG, + TIMER2, + TIMER3, +}MV_CNTMR_ID; + + +/* Counter / Timer control structure */ +typedef struct _mvCntmrCtrl +{ + MV_BOOL enable; /* enable */ + MV_BOOL autoEnable; /* counter/Timer */ +}MV_CNTMR_CTRL; + + +/* Functions */ + +/* Load an init Value to a given counter/timer */ +MV_STATUS mvCntmrLoad(MV_U32 countNum, MV_U32 value); + +/* Returns the value of the given Counter/Timer */ +MV_U32 mvCntmrRead(MV_U32 countNum); + +/* Write a value of the given Counter/Timer */ +void mvCntmrWrite(MV_U32 countNum,MV_U32 countVal); + +/* Set the Control to a given counter/timer */ +MV_STATUS mvCntmrCtrlSet(MV_U32 countNum, MV_CNTMR_CTRL *pCtrl); + +/* Get the value of a given counter/timer */ +MV_STATUS mvCntmrCtrlGet(MV_U32 countNum, MV_CNTMR_CTRL *pCtrl); + +/* Set the Enable-Bit to logic '1' ==> starting the counter. */ +MV_STATUS mvCntmrEnable(MV_U32 countNum); + +/* Stop the counter/timer running, and returns its Value. */ +MV_STATUS mvCntmrDisable(MV_U32 countNum); + +/* Combined all the sub-operations above to one function: Load,setMode,Enable */ +MV_STATUS mvCntmrStart(MV_U32 countNum, MV_U32 value, + MV_CNTMR_CTRL *pCtrl); + +#endif /* __INCmvTmrWtdgh */ diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/cntmr/mvCntmrRegs.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/cntmr/mvCntmrRegs.h new file mode 100644 index 0000000..b69bc66 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/cntmr/mvCntmrRegs.h @@ -0,0 +1,121 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#ifndef __INCmvTmrwtdgRegsh +#define __INCmvTmrwtdgRegsh + +/*******************************************/ +/* ARM Timers Registers Map */ +/*******************************************/ + +#define CNTMR_RELOAD_REG(tmrNum) (CNTMR_BASE + 0x10 + (tmrNum)*8 + \ + (((tmrNum) <= 3)?0:8)) +#define CNTMR_VAL_REG(tmrNum) (CNTMR_BASE + 0x14 + (tmrNum)*8 + \ + (((tmrNum) <= 3)?0:8)) +#define CNTMR_CTRL_REG (CNTMR_BASE) + +/*For MV78XX0*/ +#define CNTMR_CAUSE_REG (CPU_AHB_MBUS_CAUSE_INT_REG(whoAmI())) +#define CNTMR_MASK_REG (CPU_AHB_MBUS_MASK_INT_REG(whoAmI())) + +/* ARM Timers Registers Map */ +/*******************************************/ + + +/* ARM Timers Control Register */ +/* CPU_TIMERS_CTRL_REG (CTCR) */ + +#define TIMER0_NUM 0 +#define TIMER1_NUM 1 +#define WATCHDOG_NUM 2 +#define TIMER2_NUM 3 +#define TIMER3_NUM 4 + +#define CTCR_ARM_TIMER_EN_OFFS(cntr) (cntr * 2) +#define CTCR_ARM_TIMER_EN_MASK(cntr) (1 << CTCR_ARM_TIMER_EN_OFFS) +#define CTCR_ARM_TIMER_EN(cntr) (1 << CTCR_ARM_TIMER_EN_OFFS(cntr)) +#define CTCR_ARM_TIMER_DIS(cntr) (0 << CTCR_ARM_TIMER_EN_OFFS(cntr)) + +#define CTCR_ARM_TIMER_AUTO_OFFS(cntr) ((cntr * 2) + 1) +#define CTCR_ARM_TIMER_AUTO_MASK(cntr) BIT1 +#define CTCR_ARM_TIMER_AUTO_EN(cntr) (1 << CTCR_ARM_TIMER_AUTO_OFFS(cntr)) +#define CTCR_ARM_TIMER_AUTO_DIS(cntr) (0 << CTCR_ARM_TIMER_AUTO_OFFS(cntr)) + + +/* ARM Timer\Watchdog Reload Register */ +/* CNTMR_RELOAD_REG (TRR) */ + +#define TRG_ARM_TIMER_REL_OFFS 0 +#define TRG_ARM_TIMER_REL_MASK 0xffffffff + +/* ARM Timer\Watchdog Register */ +/* CNTMR_VAL_REG (TVRG) */ + +#define TVR_ARM_TIMER_OFFS 0 +#define TVR_ARM_TIMER_MASK 0xffffffff +#define TVR_ARM_TIMER_MAX 0xffffffff + + + +#endif /* __INCmvTmrwtdgRegsh */ diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/cntmr/mvCompVer.txt b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/cntmr/mvCompVer.txt new file mode 100644 index 0000000..85bfa61 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/cntmr/mvCompVer.txt @@ -0,0 +1,4 @@ +Global HAL Version: FEROCEON_HAL_3_1_7 +Unit HAL Version: 3.1.3 +Description: This component includes an implementation of the unit HAL drivers + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/cpu/mvCpuCntrs.c b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/cpu/mvCpuCntrs.c new file mode 100644 index 0000000..609e674 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/cpu/mvCpuCntrs.c @@ -0,0 +1,207 @@ +/* + * 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 "mvOs.h" +#include "mvCpuCntrs.h" + + +const static MV_CPU_CNTRS_OPS mvCpuCntrsOpsTbl[MV_CPU_CNTRS_NUM][MV_CPU_CNTRS_OPS_NUM] = +{ + /*0*/ + { + MV_CPU_CNTRS_CYCLES, MV_CPU_CNTRS_DCACHE_READ_HIT, MV_CPU_CNTRS_DCACHE_READ_MISS, + MV_CPU_CNTRS_DCACHE_WRITE_HIT, MV_CPU_CNTRS_DCACHE_WRITE_MISS, MV_CPU_CNTRS_INSTRUCTIONS, + MV_CPU_CNTRS_INVALID, MV_CPU_CNTRS_INVALID, MV_CPU_CNTRS_INVALID, + MV_CPU_CNTRS_MMU_READ_LATENCY, MV_CPU_CNTRS_ICACHE_READ_LATENCY, MV_CPU_CNTRS_WB_WRITE_LATENCY, + MV_CPU_CNTRS_LDM_STM_HOLD, MV_CPU_CNTRS_INVALID, MV_CPU_CNTRS_INVALID, + MV_CPU_CNTRS_DATA_WRITE_ACCESS, MV_CPU_CNTRS_DATA_READ_ACCESS, MV_CPU_CNTRS_INVALID, + MV_CPU_CNTRS_BRANCH_PREDICT_COUNT, + }, + /*1*/ + { + MV_CPU_CNTRS_CYCLES, MV_CPU_CNTRS_ICACHE_READ_MISS, MV_CPU_CNTRS_DCACHE_READ_MISS, + MV_CPU_CNTRS_DCACHE_WRITE_MISS, MV_CPU_CNTRS_ITLB_MISS, MV_CPU_CNTRS_SINGLE_ISSUE, + MV_CPU_CNTRS_INVALID, MV_CPU_CNTRS_BRANCH_RETIRED, MV_CPU_CNTRS_INVALID, + MV_CPU_CNTRS_MMU_READ_BEAT, MV_CPU_CNTRS_ICACHE_READ_LATENCY, MV_CPU_CNTRS_WB_WRITE_BEAT, + MV_CPU_CNTRS_INVALID, MV_CPU_CNTRS_IS_HOLD, MV_CPU_CNTRS_DATA_READ_ACCESS, + MV_CPU_CNTRS_INVALID, MV_CPU_CNTRS_INVALID, MV_CPU_CNTRS_INVALID, + MV_CPU_CNTRS_INVALID, + }, + /*2*/ + { + MV_CPU_CNTRS_CYCLES, MV_CPU_CNTRS_INVALID, MV_CPU_CNTRS_DCACHE_ACCESS, + MV_CPU_CNTRS_DTLB_MISS, MV_CPU_CNTRS_INVALID, MV_CPU_CNTRS_INVALID, + MV_CPU_CNTRS_INVALID, MV_CPU_CNTRS_BRANCH_PREDICT_MISS, MV_CPU_CNTRS_WB_WRITE_BEAT, + MV_CPU_CNTRS_INVALID, MV_CPU_CNTRS_DCACHE_READ_LATENCY, MV_CPU_CNTRS_DCACHE_WRITE_LATENCY, + MV_CPU_CNTRS_INVALID, MV_CPU_CNTRS_INVALID, MV_CPU_CNTRS_BIU_SIMULT_ACCESS, + MV_CPU_CNTRS_INVALID, MV_CPU_CNTRS_INVALID, MV_CPU_CNTRS_INVALID, + MV_CPU_CNTRS_INVALID, + }, + /*3*/ + { + MV_CPU_CNTRS_CYCLES, MV_CPU_CNTRS_DCACHE_READ_MISS, MV_CPU_CNTRS_DCACHE_WRITE_MISS, + MV_CPU_CNTRS_TLB_MISS, MV_CPU_CNTRS_INVALID, MV_CPU_CNTRS_INVALID, + MV_CPU_CNTRS_INVALID, MV_CPU_CNTRS_BRANCH_TAKEN, MV_CPU_CNTRS_WB_FULL_CYCLES, + MV_CPU_CNTRS_INVALID, MV_CPU_CNTRS_DCACHE_READ_BEAT, MV_CPU_CNTRS_DCACHE_WRITE_BEAT, + MV_CPU_CNTRS_INVALID, MV_CPU_CNTRS_INVALID, MV_CPU_CNTRS_BIU_ANY_ACCESS, + MV_CPU_CNTRS_INVALID, MV_CPU_CNTRS_INVALID, MV_CPU_CNTRS_DATA_WRITE_ACCESS, + MV_CPU_CNTRS_INVALID, + } +}; + +MV_CPU_CNTRS_ENTRY mvCpuCntrsTbl[MV_CPU_CNTRS_NUM]; + +MV_CPU_CNTRS_EVENT* mvCpuCntrsEventTbl[128]; + +void mvCpuCntrsReset(void) +{ + MV_U32 reg = 0; + + MV_ASM ("mcr p15, 0, %0, c15, c13, 0" : : "r" (reg)); + MV_ASM ("mcr p15, 0, %0, c15, c13, 1" : : "r" (reg)); + MV_ASM ("mcr p15, 0, %0, c15, c13, 2" : : "r" (reg)); + MV_ASM ("mcr p15, 0, %0, c15, c13, 3" : : "r" (reg)); + MV_ASM ("mcr p15, 0, %0, c15, c13, 4" : : "r" (reg)); + MV_ASM ("mcr p15, 0, %0, c15, c13, 5" : : "r" (reg)); + MV_ASM ("mcr p15, 0, %0, c15, c13, 6" : : "r" (reg)); + MV_ASM ("mcr p15, 0, %0, c15, c13, 7" : : "r" (reg)); +} + +void program_counter(int counter, int op) +{ + MV_U32 reg = (1 << op) | 0x1; /*enable*/ + + switch(counter) + { + case 0: + __asm__ __volatile__ ("mcr p15, 0, %0, c15, c12, 0" : : "r" (reg)); + return; + + case 1: + __asm__ __volatile__ ("mcr p15, 0, %0, c15, c12, 1" : : "r" (reg)); + return; + + case 2: + __asm__ __volatile__ ("mcr p15, 0, %0, c15, c12, 2" : : "r" (reg)); + return; + + case 3: + __asm__ __volatile__ ("mcr p15, 0, %0, c15, c12, 3" : : "r" (reg)); + return; + + default: + mvOsPrintf("error in program_counter: bad counter number (%d)\n", counter); + } + return; +} + +void mvCpuCntrsEventClear(MV_CPU_CNTRS_EVENT* pEvent) +{ + int i; + + for(i=0; icounters_sum[i] = 0; + } + pEvent->num_of_measurements = 0; +} + + +MV_CPU_CNTRS_EVENT* mvCpuCntrsEventCreate(char* name, MV_U32 print_threshold) +{ + int i; + MV_CPU_CNTRS_EVENT* event = mvOsMalloc(sizeof(MV_CPU_CNTRS_EVENT)); + + if(event) + { + strncpy(event->name, name, sizeof(event->name)); + event->num_of_measurements = 0; + event->avg_sample_count = print_threshold; + for(i=0; icounters_before[i] = 0; + event->counters_after[i] = 0; + event->counters_sum[i] = 0; + } + } + return event; +} + +void mvCpuCntrsEventDelete(MV_CPU_CNTRS_EVENT* event) +{ + if(event != NULL) + mvOsFree(event); +} + + +MV_STATUS mvCpuCntrsProgram(int counter, MV_CPU_CNTRS_OPS op, + char* name, MV_U32 overhead) +{ + int i; + + /* Find required operations */ + for(i=0; inum_of_measurements < pEvent->avg_sample_count) + return; + + mvOsPrintf("%16s: ", pEvent->name); + for(i=0; icounters_sum[i], + pEvent->num_of_measurements, NULL); + if(counters_avg >= mvCpuCntrsTbl[i].overhead) + counters_avg -= mvCpuCntrsTbl[i].overhead; + else + counters_avg = 0; + + mvOsPrintf("%s=%5llu, ", mvCpuCntrsTbl[i].name, counters_avg); + } + mvOsPrintf("\n"); + mvCpuCntrsEventClear(pEvent); + mvCpuCntrsReset(); +} + +void mvCpuCntrsStatus(void) +{ + int i; + + for(i=0; icounters_before[i] = mvCpuCntrsRead(i); +#else + pEvent->counters_before[1] = mvCpuCntrsRead(1); + pEvent->counters_before[3] = mvCpuCntrsRead(3); + pEvent->counters_before[0] = mvCpuCntrsRead(0); + pEvent->counters_before[2] = mvCpuCntrsRead(2); +#endif +} + +static INLINE void mvCpuCntrsReadAfter(MV_CPU_CNTRS_EVENT* pEvent) +{ + int i; + +#if 0 + /* order is important - we want to measure the cycle count first here! */ + for(i=0; icounters_after[i] = mvCpuCntrsRead(i); +#else + pEvent->counters_after[2] = mvCpuCntrsRead(2); + pEvent->counters_after[0] = mvCpuCntrsRead(0); + pEvent->counters_after[3] = mvCpuCntrsRead(3); + pEvent->counters_after[1] = mvCpuCntrsRead(1); +#endif + + for(i=0; icounters_sum[i] += (pEvent->counters_after[i] - pEvent->counters_before[i]); + } + pEvent->num_of_measurements++; +} + + +#ifdef CONFIG_MV_CPU_PERF_CNTRS + +#define MV_CPU_CNTRS_READ(counter) mvCpuCntrsRead(counter) + +#define MV_CPU_CNTRS_START(event) mvCpuCntrsReadBefore(event) + +#define MV_CPU_CNTRS_STOP(event) mvCpuCntrsReadAfter(event) + +#define MV_CPU_CNTRS_SHOW(event) mvCpuCntrsShow(event) + +#else + +#define MV_CPU_CNTRS_READ(counter) +#define MV_CPU_CNTRS_START(event) +#define MV_CPU_CNTRS_STOP(event) +#define MV_CPU_CNTRS_SHOW(event) + +#endif /* CONFIG_MV_CPU_PERF_CNTRS */ + + +#endif /* __mvCpuCntrs_h__ */ + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/cpu/mvCpuL2Cntrs.c b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/cpu/mvCpuL2Cntrs.c new file mode 100644 index 0000000..0333862 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/cpu/mvCpuL2Cntrs.c @@ -0,0 +1,143 @@ +/* + * 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 "mvOs.h" +#include "mvCpuL2Cntrs.h" + + + +MV_CPU_L2_CNTRS_ENTRY mvCpuL2CntrsTbl[MV_CPU_L2_CNTRS_NUM]; + +MV_CPU_L2_CNTRS_EVENT* mvCpuL2CntrsEventTbl[128]; + +void mvCpuL2CntrsReset(void) +{ + MV_U32 reg = 0; + + MV_ASM ("mcr p15, 6, %0, c15, c13, 0" : : "r" (reg)); + MV_ASM ("mcr p15, 6, %0, c15, c13, 1" : : "r" (reg)); + MV_ASM ("mcr p15, 6, %0, c15, c13, 2" : : "r" (reg)); + MV_ASM ("mcr p15, 6, %0, c15, c13, 3" : : "r" (reg)); +} + +static void mvCpuL2CntrConfig(int counter, int op) +{ + MV_U32 reg = (1 << op) | 0x1; /*enable*/ + + switch(counter) + { + case 0: + MV_ASM ("mcr p15, 6, %0, c15, c12, 0" : : "r" (reg)); + return; + + case 1: + MV_ASM ("mcr p15, 6, %0, c15, c12, 1" : : "r" (reg)); + return; + + default: + mvOsPrintf("mvCpuL2CntrConfig: bad counter number (%d)\n", counter); + } + return; +} + +void mvCpuL2CntrsEventClear(MV_CPU_L2_CNTRS_EVENT* pEvent) +{ + int i; + + for(i=0; icounters_sum[i] = 0; + } + pEvent->num_of_measurements = 0; +} + + +MV_CPU_L2_CNTRS_EVENT* mvCpuL2CntrsEventCreate(char* name, MV_U32 print_threshold) +{ + int i; + MV_CPU_L2_CNTRS_EVENT* event = mvOsMalloc(sizeof(MV_CPU_L2_CNTRS_EVENT)); + + if(event) + { + strncpy(event->name, name, sizeof(event->name)); + event->num_of_measurements = 0; + event->avg_sample_count = print_threshold; + for(i=0; icounters_before[i] = 0; + event->counters_after[i] = 0; + event->counters_sum[i] = 0; + } + } + return event; +} + +void mvCpuL2CntrsEventDelete(MV_CPU_L2_CNTRS_EVENT* event) +{ + if(event != NULL) + mvOsFree(event); +} + + +MV_STATUS mvCpuL2CntrsProgram(int counter, MV_CPU_L2_CNTRS_OPS op, + char* name, MV_U32 overhead) +{ + strncpy(mvCpuL2CntrsTbl[counter].name, name, sizeof(mvCpuL2CntrsTbl[counter].name)); + mvCpuL2CntrsTbl[counter].operation = op; + mvCpuL2CntrsTbl[counter].opIdx = op; + mvCpuL2CntrsTbl[counter].overhead = overhead; + mvCpuL2CntrConfig(counter, op); + mvOsPrintf("CPU L2 Counter %d: operation=%d, overhead=%d\n", + counter, op, overhead); + return MV_OK; +} + +void mvCpuL2CntrsShow(MV_CPU_L2_CNTRS_EVENT* pEvent) +{ + int i; + MV_U64 counters_avg; + + if(pEvent->num_of_measurements < pEvent->avg_sample_count) + return; + + mvOsPrintf("%16s: ", pEvent->name); + for(i=0; icounters_sum[i], + pEvent->num_of_measurements, NULL); + + if(counters_avg >= mvCpuL2CntrsTbl[i].overhead) + counters_avg -= mvCpuL2CntrsTbl[i].overhead; + else + counters_avg = 0; + + mvOsPrintf("%s=%5llu, ", mvCpuL2CntrsTbl[i].name, counters_avg); + } + mvOsPrintf("\n"); + mvCpuL2CntrsEventClear(pEvent); + mvCpuL2CntrsReset(); +} + +void mvCpuL2CntrsStatus(void) +{ + int i; + + for(i=0; icounters_before[i] = mvCpuL2CntrsRead(i); +} + +static INLINE void mvCpuL2CntrsReadAfter(MV_CPU_L2_CNTRS_EVENT* pEvent) +{ + int i; + + for(i=0; icounters_after[i] = mvCpuL2CntrsRead(i); + pEvent->counters_sum[i] += (pEvent->counters_after[i] - pEvent->counters_before[i]); + } + pEvent->num_of_measurements++; +} + + +#ifdef CONFIG_MV_CPU_L2_PERF_CNTRS + +#define MV_CPU_L2_CNTRS_READ(counter) mvCpuL2CntrsRead(counter) + +#define MV_CPU_L2_CNTRS_START(event) mvCpuL2CntrsReadBefore(event) + +#define MV_CPU_L2_CNTRS_STOP(event) mvCpuL2CntrsReadAfter(event) + +#define MV_CPU_L2_CNTRS_SHOW(event) mvCpuL2CntrsShow(event) + +#else + +#define MV_CPU_L2_CNTRS_READ(counter) +#define MV_CPU_L2_CNTRS_START(event) +#define MV_CPU_L2_CNTRS_STOP(event) +#define MV_CPU_L2_CNTRS_SHOW(event) + +#endif /* CONFIG_MV_CPU_L2_PERF_CNTRS */ + + +#endif /* __mvCpuL2Cntrs_h__ */ + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvCompVer.txt b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvCompVer.txt new file mode 100644 index 0000000..85bfa61 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvCompVer.txt @@ -0,0 +1,4 @@ +Global HAL Version: FEROCEON_HAL_3_1_7 +Unit HAL Version: 3.1.3 +Description: This component includes an implementation of the unit HAL drivers + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvDram.c b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvDram.c new file mode 100644 index 0000000..d1b8a3d --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvDram.c @@ -0,0 +1,1479 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#include "ddr1_2/mvDram.h" +#include "boardEnv/mvBoardEnvLib.h" + +#undef MV_DEBUG +#ifdef MV_DEBUG +#define DB(x) x +#else +#define DB(x) +#endif + +static MV_VOID cpyDimm2BankInfo(MV_DIMM_INFO *pDimmInfo, + MV_DRAM_BANK_INFO *pBankInfo); +static MV_U32 cas2ps(MV_U8 spd_byte); +/******************************************************************************* +* mvDramBankGet - Get the DRAM bank paramters. +* +* DESCRIPTION: +* This function retrieves DRAM bank parameters as described in +* DRAM_BANK_INFO struct to the controller DRAM unit. In case the board +* has its DRAM on DIMMs it will use its EEPROM to extract SPD data +* from it. Otherwise, if the DRAM is soldered on board, the function +* should insert its bank information into MV_DRAM_BANK_INFO struct. +* +* INPUT: +* bankNum - Board DRAM bank number. +* +* OUTPUT: +* pBankInfo - DRAM bank information struct. +* +* RETURN: +* MV_FAIL - Bank parameters could not be read. +* +*******************************************************************************/ +MV_STATUS mvDramBankInfoGet(MV_U32 bankNum, MV_DRAM_BANK_INFO *pBankInfo) +{ + MV_DIMM_INFO dimmInfo; + + DB(mvOsPrintf("Dram: mvDramBankInfoGet bank %d\n", bankNum)); + /* zero pBankInfo structure */ + memset(pBankInfo, 0, sizeof(*pBankInfo)); + + if((NULL == pBankInfo) || (bankNum >= MV_DRAM_MAX_CS )) + { + DB(mvOsPrintf("Dram: mvDramBankInfoGet bad params \n")); + return MV_BAD_PARAM; + } + if( MV_OK != dimmSpdGet((MV_U32)(bankNum/2), &dimmInfo)) + { + DB(mvOsPrintf("Dram: ERR dimmSpdGet failed to get dimm info \n")); + return MV_FAIL; + } + if((dimmInfo.numOfModuleBanks == 1) && ((bankNum % 2) == 1)) + { + DB(mvOsPrintf("Dram: ERR dimmSpdGet. Can't find DIMM bank 2 \n")); + return MV_FAIL; + } + + /* convert Dimm info to Bank info */ + cpyDimm2BankInfo(&dimmInfo, pBankInfo); + + return MV_OK; +} + +/******************************************************************************* +* cpyDimm2BankInfo - Convert a Dimm info struct into a bank info struct. +* +* DESCRIPTION: +* Convert a Dimm info struct into a bank info struct. +* +* INPUT: +* pDimmInfo - DIMM information structure. +* +* OUTPUT: +* pBankInfo - DRAM bank information struct. +* +* RETURN: +* None. +* +*******************************************************************************/ +static MV_VOID cpyDimm2BankInfo(MV_DIMM_INFO *pDimmInfo, + MV_DRAM_BANK_INFO *pBankInfo) +{ + pBankInfo->memoryType = pDimmInfo->memoryType; + + /* DIMM dimensions */ + pBankInfo->numOfRowAddr = pDimmInfo->numOfRowAddr; + pBankInfo->numOfColAddr = pDimmInfo->numOfColAddr; + pBankInfo->dataWidth = pDimmInfo->dataWidth; + pBankInfo->errorCheckType = pDimmInfo->errorCheckType; + pBankInfo->sdramWidth = pDimmInfo->sdramWidth; + pBankInfo->errorCheckDataWidth = pDimmInfo->errorCheckDataWidth; + pBankInfo->numOfBanksOnEachDevice = pDimmInfo->numOfBanksOnEachDevice; + pBankInfo->suportedCasLatencies = pDimmInfo->suportedCasLatencies; + pBankInfo->refreshInterval = pDimmInfo->refreshInterval; + + /* DIMM timing parameters */ + pBankInfo->minCycleTimeAtMaxCasLatPs = pDimmInfo->minCycleTimeAtMaxCasLatPs; + pBankInfo->minCycleTimeAtMaxCasLatMinus1Ps = + pDimmInfo->minCycleTimeAtMaxCasLatMinus1Ps; + pBankInfo->minCycleTimeAtMaxCasLatMinus2Ps = + pDimmInfo->minCycleTimeAtMaxCasLatMinus2Ps; + + pBankInfo->minRowPrechargeTime = pDimmInfo->minRowPrechargeTime; + pBankInfo->minRowActiveToRowActive = pDimmInfo->minRowActiveToRowActive; + pBankInfo->minRasToCasDelay = pDimmInfo->minRasToCasDelay; + pBankInfo->minRasPulseWidth = pDimmInfo->minRasPulseWidth; + pBankInfo->minWriteRecoveryTime = pDimmInfo->minWriteRecoveryTime; + pBankInfo->minWriteToReadCmdDelay = pDimmInfo->minWriteToReadCmdDelay; + pBankInfo->minReadToPrechCmdDelay = pDimmInfo->minReadToPrechCmdDelay; + pBankInfo->minRefreshToActiveCmd = pDimmInfo->minRefreshToActiveCmd; + + /* Parameters calculated from the extracted DIMM information */ + pBankInfo->size = pDimmInfo->size/pDimmInfo->numOfModuleBanks; + pBankInfo->deviceDensity = pDimmInfo->deviceDensity; + pBankInfo->numberOfDevices = pDimmInfo->numberOfDevices / + pDimmInfo->numOfModuleBanks; + + /* DIMM attributes (MV_TRUE for yes) */ + + if ((pDimmInfo->memoryType == MEM_TYPE_SDRAM) || + (pDimmInfo->memoryType == MEM_TYPE_DDR1) ) + { + if (pDimmInfo->dimmAttributes & BIT1) + pBankInfo->registeredAddrAndControlInputs = MV_TRUE; + else + pBankInfo->registeredAddrAndControlInputs = MV_FALSE; + } + else /* pDimmInfo->memoryType == MEM_TYPE_DDR2 */ + { + if (pDimmInfo->dimmTypeInfo & (BIT0 | BIT4)) + pBankInfo->registeredAddrAndControlInputs = MV_TRUE; + else + pBankInfo->registeredAddrAndControlInputs = MV_FALSE; + } + + return; +} + +/******************************************************************************* +* dimmSpdCpy - Cpy SPD parameters from dimm 0 to dimm 1. +* +* DESCRIPTION: +* Read the DIMM SPD parameters from dimm 0 into dimm 1 SPD. +* +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_TRUE if function could read DIMM parameters, MV_FALSE otherwise. +* +*******************************************************************************/ +MV_STATUS dimmSpdCpy(MV_VOID) +{ + MV_U32 i; + MV_U32 spdChecksum; + + MV_TWSI_SLAVE twsiSlave; + MV_U8 data[SPD_SIZE]; + + /* zero dimmInfo structure */ + memset(data, 0, SPD_SIZE); + + /* read the dimm eeprom */ + DB(mvOsPrintf("DRAM: Read Dimm eeprom\n")); + twsiSlave.slaveAddr.address = MV_BOARD_DIMM0_I2C_ADDR; + twsiSlave.slaveAddr.type = ADDR7_BIT; + twsiSlave.validOffset = MV_TRUE; + twsiSlave.offset = 0; + twsiSlave.moreThen256 = MV_FALSE; + + if( MV_OK != mvTwsiRead (MV_BOARD_DIMM_I2C_CHANNEL, + &twsiSlave, data, SPD_SIZE) ) + { + DB(mvOsPrintf("DRAM: ERR. no DIMM in dimmNum 0\n")); + return MV_FAIL; + } + DB(puts("DRAM: Reading dimm info succeded.\n")); + + /* calculate SPD checksum */ + spdChecksum = 0; + + for(i = 0 ; i <= 62 ; i++) + { + spdChecksum += data[i]; + } + + if ((spdChecksum & 0xff) != data[63]) + { + DB(mvOsPrintf("DRAM: Warning. Wrong SPD Checksum %2x, expValue=%2x\n", + (MV_U32)(spdChecksum & 0xff), data[63])); + } + else + { + DB(mvOsPrintf("DRAM: SPD Checksum ok!\n")); + } + + /* copy the SPD content 1:1 into the DIMM 1 SPD */ + twsiSlave.slaveAddr.address = MV_BOARD_DIMM1_I2C_ADDR; + twsiSlave.slaveAddr.type = ADDR7_BIT; + twsiSlave.validOffset = MV_TRUE; + twsiSlave.offset = 0; + twsiSlave.moreThen256 = MV_FALSE; + + for(i = 0 ; i < SPD_SIZE ; i++) + { + twsiSlave.offset = i; + if( MV_OK != mvTwsiWrite (MV_BOARD_DIMM_I2C_CHANNEL, + &twsiSlave, &data[i], 1) ) + { + mvOsPrintf("DRAM: ERR. no DIMM in dimmNum 1 byte %d \n",i); + return MV_FAIL; + } + mvOsDelay(5); + } + + DB(puts("DRAM: Reading dimm info succeded.\n")); + return MV_OK; +} + +/******************************************************************************* +* dimmSpdGet - Get the SPD parameters. +* +* DESCRIPTION: +* Read the DIMM SPD parameters into given struct parameter. +* +* INPUT: +* dimmNum - DIMM number. See MV_BOARD_DIMM_NUM enumerator. +* +* OUTPUT: +* pDimmInfo - DIMM information structure. +* +* RETURN: +* MV_TRUE if function could read DIMM parameters, MV_FALSE otherwise. +* +*******************************************************************************/ +MV_STATUS dimmSpdGet(MV_U32 dimmNum, MV_DIMM_INFO *pDimmInfo) +{ + MV_U32 i; + MV_U32 density = 1; + MV_U32 spdChecksum; + + MV_TWSI_SLAVE twsiSlave; + MV_U8 data[SPD_SIZE]; + + if((NULL == pDimmInfo)|| (dimmNum >= MAX_DIMM_NUM)) + { + DB(mvOsPrintf("Dram: mvDramBankInfoGet bad params \n")); + return MV_BAD_PARAM; + } + + /* zero dimmInfo structure */ + memset(data, 0, SPD_SIZE); + + /* read the dimm eeprom */ + DB(mvOsPrintf("DRAM: Read Dimm eeprom\n")); + twsiSlave.slaveAddr.address = (dimmNum == 0) ? + MV_BOARD_DIMM0_I2C_ADDR : MV_BOARD_DIMM1_I2C_ADDR; + twsiSlave.slaveAddr.type = ADDR7_BIT; + twsiSlave.validOffset = MV_TRUE; + twsiSlave.offset = 0; + twsiSlave.moreThen256 = MV_FALSE; + + if( MV_OK != mvTwsiRead (MV_BOARD_DIMM_I2C_CHANNEL, + &twsiSlave, data, SPD_SIZE) ) + { + DB(mvOsPrintf("DRAM: ERR. no DIMM in dimmNum %d \n", dimmNum)); + return MV_FAIL; + } + DB(puts("DRAM: Reading dimm info succeded.\n")); + + /* calculate SPD checksum */ + spdChecksum = 0; + + for(i = 0 ; i <= 62 ; i++) + { + spdChecksum += data[i]; + } + + if ((spdChecksum & 0xff) != data[63]) + { + DB(mvOsPrintf("DRAM: Warning. Wrong SPD Checksum %2x, expValue=%2x\n", + (MV_U32)(spdChecksum & 0xff), data[63])); + } + else + { + DB(mvOsPrintf("DRAM: SPD Checksum ok!\n")); + } + + /* copy the SPD content 1:1 into the dimmInfo structure*/ + for(i = 0 ; i < SPD_SIZE ; i++) + { + pDimmInfo->spdRawData[i] = data[i]; + DB(mvOsPrintf("SPD-EEPROM Byte %3d = %3x (%3d)\n",i, data[i], data[i])); + } + + DB(mvOsPrintf("DRAM SPD Information:\n")); + + /* Memory type (DDR / SDRAM) */ + switch (data[DIMM_MEM_TYPE]) + { + case (DIMM_MEM_TYPE_SDRAM): + pDimmInfo->memoryType = MEM_TYPE_SDRAM; + DB(mvOsPrintf("DRAM Memeory type SDRAM\n")); + break; + case (DIMM_MEM_TYPE_DDR1): + pDimmInfo->memoryType = MEM_TYPE_DDR1; + DB(mvOsPrintf("DRAM Memeory type DDR1\n")); + break; + case (DIMM_MEM_TYPE_DDR2): + pDimmInfo->memoryType = MEM_TYPE_DDR2; + DB(mvOsPrintf("DRAM Memeory type DDR2\n")); + break; + default: + mvOsPrintf("ERROR: Undefined memory type!\n"); + return MV_ERROR; + } + + + /* Number Of Row Addresses */ + pDimmInfo->numOfRowAddr = data[DIMM_ROW_NUM]; + DB(mvOsPrintf("DRAM numOfRowAddr[3] %d\n",pDimmInfo->numOfRowAddr)); + + /* Number Of Column Addresses */ + pDimmInfo->numOfColAddr = data[DIMM_COL_NUM]; + DB(mvOsPrintf("DRAM numOfColAddr[4] %d\n",pDimmInfo->numOfColAddr)); + + /* Number Of Module Banks */ + pDimmInfo->numOfModuleBanks = data[DIMM_MODULE_BANK_NUM]; + DB(mvOsPrintf("DRAM numOfModuleBanks[5] 0x%x\n", + pDimmInfo->numOfModuleBanks)); + + /* Number of module banks encoded differently for DDR2 */ + if (pDimmInfo->memoryType == MEM_TYPE_DDR2) + pDimmInfo->numOfModuleBanks = (pDimmInfo->numOfModuleBanks & 0x7)+1; + + /* Data Width */ + pDimmInfo->dataWidth = data[DIMM_DATA_WIDTH]; + DB(mvOsPrintf("DRAM dataWidth[6] 0x%x\n", pDimmInfo->dataWidth)); + + /* Minimum Cycle Time At Max CasLatancy */ + pDimmInfo->minCycleTimeAtMaxCasLatPs = cas2ps(data[DIMM_MIN_CC_AT_MAX_CAS]); + + /* Error Check Type */ + pDimmInfo->errorCheckType = data[DIMM_ERR_CHECK_TYPE]; + DB(mvOsPrintf("DRAM errorCheckType[11] 0x%x\n", + pDimmInfo->errorCheckType)); + + /* Refresh Interval */ + pDimmInfo->refreshInterval = data[DIMM_REFRESH_INTERVAL]; + DB(mvOsPrintf("DRAM refreshInterval[12] 0x%x\n", + pDimmInfo->refreshInterval)); + + /* Sdram Width */ + pDimmInfo->sdramWidth = data[DIMM_SDRAM_WIDTH]; + DB(mvOsPrintf("DRAM sdramWidth[13] 0x%x\n",pDimmInfo->sdramWidth)); + + /* Error Check Data Width */ + pDimmInfo->errorCheckDataWidth = data[DIMM_ERR_CHECK_DATA_WIDTH]; + DB(mvOsPrintf("DRAM errorCheckDataWidth[14] 0x%x\n", + pDimmInfo->errorCheckDataWidth)); + + /* Burst Length Supported */ + /* SDRAM/DDR1: + *******-******-******-******-******-******-******-******* + * bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 * + *******-******-******-******-******-******-******-******* + burst length = * Page | TBD | TBD | TBD | 8 | 4 | 2 | 1 * + *********************************************************/ + /* DDR2: + *******-******-******-******-******-******-******-******* + * bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 * + *******-******-******-******-******-******-******-******* + burst length = * Page | TBD | TBD | TBD | 8 | 4 | TBD | TBD * + *********************************************************/ + + pDimmInfo->burstLengthSupported = data[DIMM_BURST_LEN_SUP]; + DB(mvOsPrintf("DRAM burstLengthSupported[16] 0x%x\n", + pDimmInfo->burstLengthSupported)); + + /* Number Of Banks On Each Device */ + pDimmInfo->numOfBanksOnEachDevice = data[DIMM_DEV_BANK_NUM]; + DB(mvOsPrintf("DRAM numOfBanksOnEachDevice[17] 0x%x\n", + pDimmInfo->numOfBanksOnEachDevice)); + + /* Suported Cas Latencies */ + + /* SDRAM: + *******-******-******-******-******-******-******-******* + * bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 * + *******-******-******-******-******-******-******-******* + CAS = * TBD | 7 | 6 | 5 | 4 | 3 | 2 | 1 * + ********************************************************/ + + /* DDR 1: + *******-******-******-******-******-******-******-******* + * bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 * + *******-******-******-******-******-******-******-******* + CAS = * TBD | 4 | 3.5 | 3 | 2.5 | 2 | 1.5 | 1 * + *********************************************************/ + + /* DDR 2: + *******-******-******-******-******-******-******-******* + * bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 * + *******-******-******-******-******-******-******-******* + CAS = * TBD | TBD | 5 | 4 | 3 | 2 | TBD | TBD * + *********************************************************/ + + pDimmInfo->suportedCasLatencies = data[DIMM_SUP_CAL]; + DB(mvOsPrintf("DRAM suportedCasLatencies[18] 0x%x\n", + pDimmInfo->suportedCasLatencies)); + + /* For DDR2 only, get the DIMM type information */ + if (pDimmInfo->memoryType == MEM_TYPE_DDR2) + { + pDimmInfo->dimmTypeInfo = data[DIMM_DDR2_TYPE_INFORMATION]; + DB(mvOsPrintf("DRAM dimmTypeInfo[20] (DDR2) 0x%x\n", + pDimmInfo->dimmTypeInfo)); + } + + /* SDRAM Modules Attributes */ + pDimmInfo->dimmAttributes = data[DIMM_BUF_ADDR_CONT_IN]; + DB(mvOsPrintf("DRAM dimmAttributes[21] 0x%x\n", + pDimmInfo->dimmAttributes)); + + /* Minimum Cycle Time At Max CasLatancy Minus 1*/ + pDimmInfo->minCycleTimeAtMaxCasLatMinus1Ps = + cas2ps(data[DIMM_MIN_CC_AT_MAX_CAS_MINUS1]); + + /* Minimum Cycle Time At Max CasLatancy Minus 2*/ + pDimmInfo->minCycleTimeAtMaxCasLatMinus2Ps = + cas2ps(data[DIMM_MIN_CC_AT_MAX_CAS_MINUS2]); + + pDimmInfo->minRowPrechargeTime = data[DIMM_MIN_ROW_PRECHARGE_TIME]; + DB(mvOsPrintf("DRAM minRowPrechargeTime[27] 0x%x\n", + pDimmInfo->minRowPrechargeTime)); + pDimmInfo->minRowActiveToRowActive = data[DIMM_MIN_ROW_ACTIVE_TO_ROW_ACTIVE]; + DB(mvOsPrintf("DRAM minRowActiveToRowActive[28] 0x%x\n", + pDimmInfo->minRowActiveToRowActive)); + pDimmInfo->minRasToCasDelay = data[DIMM_MIN_RAS_TO_CAS_DELAY]; + DB(mvOsPrintf("DRAM minRasToCasDelay[29] 0x%x\n", + pDimmInfo->minRasToCasDelay)); + pDimmInfo->minRasPulseWidth = data[DIMM_MIN_RAS_PULSE_WIDTH]; + DB(mvOsPrintf("DRAM minRasPulseWidth[30] 0x%x\n", + pDimmInfo->minRasPulseWidth)); + + /* DIMM Bank Density */ + pDimmInfo->dimmBankDensity = data[DIMM_BANK_DENSITY]; + DB(mvOsPrintf("DRAM dimmBankDensity[31] 0x%x\n", + pDimmInfo->dimmBankDensity)); + + /* Only DDR2 includes Write Recovery Time field. Other SDRAM ignore */ + pDimmInfo->minWriteRecoveryTime = data[DIMM_MIN_WRITE_RECOVERY_TIME]; + DB(mvOsPrintf("DRAM minWriteRecoveryTime[36] 0x%x\n", + pDimmInfo->minWriteRecoveryTime)); + + /* Only DDR2 includes Internal Write To Read Command Delay field. */ + pDimmInfo->minWriteToReadCmdDelay = data[DIMM_MIN_WRITE_TO_READ_CMD_DELAY]; + DB(mvOsPrintf("DRAM minWriteToReadCmdDelay[37] 0x%x\n", + pDimmInfo->minWriteToReadCmdDelay)); + + /* Only DDR2 includes Internal Read To Precharge Command Delay field. */ + pDimmInfo->minReadToPrechCmdDelay = data[DIMM_MIN_READ_TO_PRECH_CMD_DELAY]; + DB(mvOsPrintf("DRAM minReadToPrechCmdDelay[38] 0x%x\n", + pDimmInfo->minReadToPrechCmdDelay)); + + /* Only DDR2 includes Minimum Refresh to Activate/Refresh Command field */ + pDimmInfo->minRefreshToActiveCmd = data[DIMM_MIN_REFRESH_TO_ACTIVATE_CMD]; + DB(mvOsPrintf("DRAM minRefreshToActiveCmd[42] 0x%x\n", + pDimmInfo->minRefreshToActiveCmd)); + + /* calculating the sdram density. Representing device density from */ + /* bit 20 to allow representation of 4GB and above. */ + /* For example, if density is 512Mbit 0x20000000, will be represent in */ + /* deviceDensity by 0x20000000 >> 16 --> 0x00000200. Another example */ + /* is density 8GB 0x200000000 >> 16 --> 0x00002000. */ + density = (1 << ((pDimmInfo->numOfRowAddr + pDimmInfo->numOfColAddr) - 20)); + pDimmInfo->deviceDensity = density * + pDimmInfo->numOfBanksOnEachDevice * + pDimmInfo->sdramWidth; + DB(mvOsPrintf("DRAM deviceDensity %d\n",pDimmInfo->deviceDensity)); + + /* Number of devices includeing Error correction */ + pDimmInfo->numberOfDevices = (pDimmInfo->dataWidth/pDimmInfo->sdramWidth) * + pDimmInfo->numOfModuleBanks; + DB(mvOsPrintf("DRAM numberOfDevices %d\n", + pDimmInfo->numberOfDevices)); + + pDimmInfo->size = 0; + + /* Note that pDimmInfo->size is in MB units */ + if (pDimmInfo->memoryType == MEM_TYPE_SDRAM) + { + if (pDimmInfo->dimmBankDensity & BIT0) + pDimmInfo->size += 1024; /* Equal to 1GB */ + else if (pDimmInfo->dimmBankDensity & BIT1) + pDimmInfo->size += 8; /* Equal to 8MB */ + else if (pDimmInfo->dimmBankDensity & BIT2) + pDimmInfo->size += 16; /* Equal to 16MB */ + else if (pDimmInfo->dimmBankDensity & BIT3) + pDimmInfo->size += 32; /* Equal to 32MB */ + else if (pDimmInfo->dimmBankDensity & BIT4) + pDimmInfo->size += 64; /* Equal to 64MB */ + else if (pDimmInfo->dimmBankDensity & BIT5) + pDimmInfo->size += 128; /* Equal to 128MB */ + else if (pDimmInfo->dimmBankDensity & BIT6) + pDimmInfo->size += 256; /* Equal to 256MB */ + else if (pDimmInfo->dimmBankDensity & BIT7) + pDimmInfo->size += 512; /* Equal to 512MB */ + } + else if (pDimmInfo->memoryType == MEM_TYPE_DDR1) + { + if (pDimmInfo->dimmBankDensity & BIT0) + pDimmInfo->size += 1024; /* Equal to 1GB */ + else if (pDimmInfo->dimmBankDensity & BIT1) + pDimmInfo->size += 2048; /* Equal to 2GB */ + else if (pDimmInfo->dimmBankDensity & BIT2) + pDimmInfo->size += 16; /* Equal to 16MB */ + else if (pDimmInfo->dimmBankDensity & BIT3) + pDimmInfo->size += 32; /* Equal to 32MB */ + else if (pDimmInfo->dimmBankDensity & BIT4) + pDimmInfo->size += 64; /* Equal to 64MB */ + else if (pDimmInfo->dimmBankDensity & BIT5) + pDimmInfo->size += 128; /* Equal to 128MB */ + else if (pDimmInfo->dimmBankDensity & BIT6) + pDimmInfo->size += 256; /* Equal to 256MB */ + else if (pDimmInfo->dimmBankDensity & BIT7) + pDimmInfo->size += 512; /* Equal to 512MB */ + } + else /* if (dimmInfo.memoryType == MEM_TYPE_DDR2) */ + { + if (pDimmInfo->dimmBankDensity & BIT0) + pDimmInfo->size += 1024; /* Equal to 1GB */ + else if (pDimmInfo->dimmBankDensity & BIT1) + pDimmInfo->size += 2048; /* Equal to 2GB */ + else if (pDimmInfo->dimmBankDensity & BIT2) + pDimmInfo->size += 4096; /* Equal to 4GB */ + else if (pDimmInfo->dimmBankDensity & BIT3) + pDimmInfo->size += 8192; /* Equal to 8GB */ + else if (pDimmInfo->dimmBankDensity & BIT4) + pDimmInfo->size += 16384; /* Equal to 16GB */ + else if (pDimmInfo->dimmBankDensity & BIT5) + pDimmInfo->size += 128; /* Equal to 128MB */ + else if (pDimmInfo->dimmBankDensity & BIT6) + pDimmInfo->size += 256; /* Equal to 256MB */ + else if (pDimmInfo->dimmBankDensity & BIT7) + pDimmInfo->size += 512; /* Equal to 512MB */ + } + + pDimmInfo->size *= pDimmInfo->numOfModuleBanks; + + DB(mvOsPrintf("Dram: dimm size %dMB \n",pDimmInfo->size)); + + return MV_OK; +} + +/******************************************************************************* +* dimmSpdPrint - Print the SPD parameters. +* +* DESCRIPTION: +* Print the Dimm SPD parameters. +* +* INPUT: +* pDimmInfo - DIMM information structure. +* +* OUTPUT: +* None. +* +* RETURN: +* None. +* +*******************************************************************************/ +MV_VOID dimmSpdPrint(MV_U32 dimmNum) +{ + MV_DIMM_INFO dimmInfo; + MV_U32 i, temp = 0; + MV_U32 k, maskLeftOfPoint = 0, maskRightOfPoint = 0; + MV_U32 rightOfPoint = 0,leftOfPoint = 0, div, time_tmp, shift; + MV_U32 busClkPs; + MV_U8 trp_clocks=0, trcd_clocks, tras_clocks, trrd_clocks, + temp_buf[40], *spdRawData; + + busClkPs = 1000000000 / (mvBoardSysClkGet() / 100); /* in 10 ps units */ + + spdRawData = dimmInfo.spdRawData; + + if(MV_OK != dimmSpdGet(dimmNum, &dimmInfo)) + { + mvOsOutput("ERROR: Could not read SPD information!\n"); + return; + } + + /* find Manufactura of Dimm Module */ + mvOsOutput("\nManufacturer's JEDEC ID Code: "); + for(i = 0 ; i < DIMM_MODULE_MANU_SIZE ; i++) + { + mvOsOutput("%x",spdRawData[DIMM_MODULE_MANU_OFFS + i]); + } + mvOsOutput("\n"); + + /* Manufacturer's Specific Data */ + for(i = 0 ; i < DIMM_MODULE_ID_SIZE ; i++) + { + temp_buf[i] = spdRawData[DIMM_MODULE_ID_OFFS + i]; + } + mvOsOutput("Manufacturer's Specific Data: %s\n", temp_buf); + + /* Module Part Number */ + for(i = 0 ; i < DIMM_MODULE_VEN_SIZE ; i++) + { + temp_buf[i] = spdRawData[DIMM_MODULE_VEN_OFFS + i]; + } + mvOsOutput("Module Part Number: %s\n", temp_buf); + + /* Module Serial Number */ + for(i = 0; i < sizeof(MV_U32); i++) + { + temp |= spdRawData[95+i] << 8*i; + } + mvOsOutput("DIMM Serial No. %ld (%lx)\n", (long)temp, + (long)temp); + + /* find Manufac-Data of Dimm Module */ + mvOsOutput("Manufactoring Date: Year 20%d%d/ ww %d%d\n", + ((spdRawData[93] & 0xf0) >> 4), (spdRawData[93] & 0xf), + ((spdRawData[94] & 0xf0) >> 4), (spdRawData[94] & 0xf)); + /* find modul_revision of Dimm Module */ + mvOsOutput("Module Revision: %d.%d\n", + spdRawData[91], spdRawData[92]); + + /* find manufac_place of Dimm Module */ + mvOsOutput("manufac_place: %d\n", spdRawData[72]); + + /* go over the first 35 I2C data bytes */ + for(i = 2 ; i <= 35 ; i++) + switch(i) + { + case 2: /* Memory type (DDR1/2 / SDRAM) */ + if (dimmInfo.memoryType == MEM_TYPE_SDRAM) + mvOsOutput("Dram Type is: SDRAM\n"); + else if (dimmInfo.memoryType == MEM_TYPE_DDR1) + mvOsOutput("Dram Type is: SDRAM DDR1\n"); + else if (dimmInfo.memoryType == MEM_TYPE_DDR2) + mvOsOutput("Dram Type is: SDRAM DDR2\n"); + else + mvOsOutput("Dram Type unknown\n"); + break; +/*----------------------------------------------------------------------------*/ + + case 3: /* Number Of Row Addresses */ + mvOsOutput("Module Number of row addresses: %d\n", + dimmInfo.numOfRowAddr); + break; +/*----------------------------------------------------------------------------*/ + + case 4: /* Number Of Column Addresses */ + mvOsOutput("Module Number of col addresses: %d\n", + dimmInfo.numOfColAddr); + break; +/*----------------------------------------------------------------------------*/ + + case 5: /* Number Of Module Banks */ + mvOsOutput("Number of Banks on Mod.: %d\n", + dimmInfo.numOfModuleBanks); + break; +/*----------------------------------------------------------------------------*/ + + case 6: /* Data Width */ + mvOsOutput("Module Data Width: %d bit\n", + dimmInfo.dataWidth); + break; +/*----------------------------------------------------------------------------*/ + + case 8: /* Voltage Interface */ + switch(spdRawData[i]) + { + case 0x0: + mvOsOutput("Module is TTL_5V_TOLERANT\n"); + break; + case 0x1: + mvOsOutput("Module is LVTTL\n"); + break; + case 0x2: + mvOsOutput("Module is HSTL_1_5V\n"); + break; + case 0x3: + mvOsOutput("Module is SSTL_3_3V\n"); + break; + case 0x4: + mvOsOutput("Module is SSTL_2_5V\n"); + break; + case 0x5: + if (dimmInfo.memoryType != MEM_TYPE_SDRAM) + { + mvOsOutput("Module is SSTL_1_8V\n"); + break; + } + default: + mvOsOutput("Module is VOLTAGE_UNKNOWN\n"); + break; + } + break; +/*----------------------------------------------------------------------------*/ + + case 9: /* Minimum Cycle Time At Max CasLatancy */ + leftOfPoint = (spdRawData[i] & 0xf0) >> 4; + rightOfPoint = (spdRawData[i] & 0x0f) * 10; + + /* DDR2 addition of right of point */ + if ((spdRawData[i] & 0x0f) == 0xA) + { + rightOfPoint = 25; + } + if ((spdRawData[i] & 0x0f) == 0xB) + { + rightOfPoint = 33; + } + if ((spdRawData[i] & 0x0f) == 0xC) + { + rightOfPoint = 66; + } + if ((spdRawData[i] & 0x0f) == 0xD) + { + rightOfPoint = 75; + } + mvOsOutput("Minimum Cycle Time At Max CL: %d.%d [ns]\n", + leftOfPoint, rightOfPoint); + break; +/*----------------------------------------------------------------------------*/ + + case 10: /* Clock To Data Out */ + div = (dimmInfo.memoryType == MEM_TYPE_SDRAM)? 10:100; + time_tmp = (((spdRawData[i] & 0xf0) >> 4)*10) + + ((spdRawData[i] & 0x0f)); + leftOfPoint = time_tmp / div; + rightOfPoint = time_tmp % div; + mvOsOutput("Clock To Data Out: %d.%d [ns]\n", + leftOfPoint, rightOfPoint); + break; +/*----------------------------------------------------------------------------*/ + + case 11: /* Error Check Type */ + mvOsOutput("Error Check Type (0=NONE): %d\n", + dimmInfo.errorCheckType); + break; +/*----------------------------------------------------------------------------*/ + + case 12: /* Refresh Interval */ + mvOsOutput("Refresh Rate: %x\n", + dimmInfo.refreshInterval); + break; +/*----------------------------------------------------------------------------*/ + + case 13: /* Sdram Width */ + mvOsOutput("Sdram Width: %d bits\n", + dimmInfo.sdramWidth); + break; +/*----------------------------------------------------------------------------*/ + + case 14: /* Error Check Data Width */ + mvOsOutput("Error Check Data Width: %d bits\n", + dimmInfo.errorCheckDataWidth); + break; +/*----------------------------------------------------------------------------*/ + + case 15: /* Minimum Clock Delay is unsupported */ + if ((dimmInfo.memoryType == MEM_TYPE_SDRAM) || + (dimmInfo.memoryType == MEM_TYPE_DDR1)) + { + mvOsOutput("Minimum Clk Delay back to back: %d\n", + spdRawData[i]); + } + break; +/*----------------------------------------------------------------------------*/ + + case 16: /* Burst Length Supported */ + /* SDRAM/DDR1: + *******-******-******-******-******-******-******-******* + * bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 * + *******-******-******-******-******-******-******-******* + burst length = * Page | TBD | TBD | TBD | 8 | 4 | 2 | 1 * + *********************************************************/ + /* DDR2: + *******-******-******-******-******-******-******-******* + * bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 * + *******-******-******-******-******-******-******-******* + burst length = * Page | TBD | TBD | TBD | 8 | 4 | TBD | TBD * + *********************************************************/ + mvOsOutput("Burst Length Supported: "); + if ((dimmInfo.memoryType == MEM_TYPE_SDRAM) || + (dimmInfo.memoryType == MEM_TYPE_DDR1)) + { + if (dimmInfo.burstLengthSupported & BIT0) + mvOsOutput("1, "); + if (dimmInfo.burstLengthSupported & BIT1) + mvOsOutput("2, "); + } + if (dimmInfo.burstLengthSupported & BIT2) + mvOsOutput("4, "); + if (dimmInfo.burstLengthSupported & BIT3) + mvOsOutput("8, "); + + mvOsOutput(" Bit \n"); + break; +/*----------------------------------------------------------------------------*/ + + case 17: /* Number Of Banks On Each Device */ + mvOsOutput("Number Of Banks On Each Chip: %d\n", + dimmInfo.numOfBanksOnEachDevice); + break; +/*----------------------------------------------------------------------------*/ + + case 18: /* Suported Cas Latencies */ + + /* SDRAM: + *******-******-******-******-******-******-******-******* + * bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 * + *******-******-******-******-******-******-******-******* + CAS = * TBD | 7 | 6 | 5 | 4 | 3 | 2 | 1 * + ********************************************************/ + + /* DDR 1: + *******-******-******-******-******-******-******-******* + * bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 * + *******-******-******-******-******-******-******-******* + CAS = * TBD | 4 | 3.5 | 3 | 2.5 | 2 | 1.5 | 1 * + *********************************************************/ + + /* DDR 2: + *******-******-******-******-******-******-******-******* + * bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 * + *******-******-******-******-******-******-******-******* + CAS = * TBD | TBD | 5 | 4 | 3 | 2 | TBD | TBD * + *********************************************************/ + + mvOsOutput("Suported Cas Latencies: (CL) "); + if (dimmInfo.memoryType == MEM_TYPE_SDRAM) + { + for (k = 0; k <=7; k++) + { + if (dimmInfo.suportedCasLatencies & (1 << k)) + mvOsOutput("%d, ", k+1); + } + } + else if (dimmInfo.memoryType == MEM_TYPE_DDR1) + { + if (dimmInfo.suportedCasLatencies & BIT0) + mvOsOutput("1, "); + if (dimmInfo.suportedCasLatencies & BIT1) + mvOsOutput("1.5, "); + if (dimmInfo.suportedCasLatencies & BIT2) + mvOsOutput("2, "); + if (dimmInfo.suportedCasLatencies & BIT3) + mvOsOutput("2.5, "); + if (dimmInfo.suportedCasLatencies & BIT4) + mvOsOutput("3, "); + if (dimmInfo.suportedCasLatencies & BIT5) + mvOsOutput("3.5, "); + } + else if (dimmInfo.memoryType == MEM_TYPE_DDR2) + { + if (dimmInfo.suportedCasLatencies & BIT2) + mvOsOutput("2, "); + if (dimmInfo.suportedCasLatencies & BIT3) + mvOsOutput("3, "); + if (dimmInfo.suportedCasLatencies & BIT4) + mvOsOutput("4, "); + if (dimmInfo.suportedCasLatencies & BIT5) + mvOsOutput("5, "); + } + else + mvOsOutput("?.?, "); + mvOsOutput("\n"); + break; +/*----------------------------------------------------------------------------*/ + + case 20: /* DDR2 DIMM type info */ + if (dimmInfo.memoryType == MEM_TYPE_DDR2) + { + if (dimmInfo.dimmTypeInfo & (BIT0 | BIT4)) + mvOsOutput("Registered DIMM (RDIMM)\n"); + else if (dimmInfo.dimmTypeInfo & (BIT1 | BIT5)) + mvOsOutput("Unbuffered DIMM (UDIMM)\n"); + else + mvOsOutput("Unknown DIMM type.\n"); + } + + break; +/*----------------------------------------------------------------------------*/ + + case 21: /* SDRAM Modules Attributes */ + mvOsOutput("\nModule Attributes (SPD Byte 21): \n"); + + if (dimmInfo.memoryType == MEM_TYPE_SDRAM) + { + if (dimmInfo.dimmAttributes & BIT0) + mvOsOutput(" Buffered Addr/Control Input: Yes\n"); + else + mvOsOutput(" Buffered Addr/Control Input: No\n"); + + if (dimmInfo.dimmAttributes & BIT1) + mvOsOutput(" Registered Addr/Control Input: Yes\n"); + else + mvOsOutput(" Registered Addr/Control Input: No\n"); + + if (dimmInfo.dimmAttributes & BIT2) + mvOsOutput(" On-Card PLL (clock): Yes \n"); + else + mvOsOutput(" On-Card PLL (clock): No \n"); + + if (dimmInfo.dimmAttributes & BIT3) + mvOsOutput(" Bufferd DQMB Input: Yes \n"); + else + mvOsOutput(" Bufferd DQMB Inputs: No \n"); + + if (dimmInfo.dimmAttributes & BIT4) + mvOsOutput(" Registered DQMB Inputs: Yes \n"); + else + mvOsOutput(" Registered DQMB Inputs: No \n"); + + if (dimmInfo.dimmAttributes & BIT5) + mvOsOutput(" Differential Clock Input: Yes \n"); + else + mvOsOutput(" Differential Clock Input: No \n"); + + if (dimmInfo.dimmAttributes & BIT6) + mvOsOutput(" redundant Row Addressing: Yes \n"); + else + mvOsOutput(" redundant Row Addressing: No \n"); + } + else if (dimmInfo.memoryType == MEM_TYPE_DDR1) + { + if (dimmInfo.dimmAttributes & BIT0) + mvOsOutput(" Buffered Addr/Control Input: Yes\n"); + else + mvOsOutput(" Buffered Addr/Control Input: No\n"); + + if (dimmInfo.dimmAttributes & BIT1) + mvOsOutput(" Registered Addr/Control Input: Yes\n"); + else + mvOsOutput(" Registered Addr/Control Input: No\n"); + + if (dimmInfo.dimmAttributes & BIT2) + mvOsOutput(" On-Card PLL (clock): Yes \n"); + else + mvOsOutput(" On-Card PLL (clock): No \n"); + + if (dimmInfo.dimmAttributes & BIT3) + mvOsOutput(" FET Switch On-Card Enabled: Yes \n"); + else + mvOsOutput(" FET Switch On-Card Enabled: No \n"); + + if (dimmInfo.dimmAttributes & BIT4) + mvOsOutput(" FET Switch External Enabled: Yes \n"); + else + mvOsOutput(" FET Switch External Enabled: No \n"); + + if (dimmInfo.dimmAttributes & BIT5) + mvOsOutput(" Differential Clock Input: Yes \n"); + else + mvOsOutput(" Differential Clock Input: No \n"); + } + else /* if (dimmInfo.memoryType == MEM_TYPE_DDR2) */ + { + mvOsOutput(" Number of Active Registers on the DIMM: %d\n", + (dimmInfo.dimmAttributes & 0x3) + 1); + + mvOsOutput(" Number of PLLs on the DIMM: %d\n", + ((dimmInfo.dimmAttributes) >> 2) & 0x3); + + if (dimmInfo.dimmAttributes & BIT4) + mvOsOutput(" FET Switch External Enabled: Yes \n"); + else + mvOsOutput(" FET Switch External Enabled: No \n"); + + if (dimmInfo.dimmAttributes & BIT6) + mvOsOutput(" Analysis probe installed: Yes \n"); + else + mvOsOutput(" Analysis probe installed: No \n"); + } + + break; +/*----------------------------------------------------------------------------*/ + + case 22: /* Suported AutoPreCharge */ + mvOsOutput("\nModul Attributes (SPD Byte 22): \n"); + if (dimmInfo.memoryType == MEM_TYPE_SDRAM) + { + if ( spdRawData[i] & BIT0 ) + mvOsOutput(" Early Ras Precharge: Yes \n"); + else + mvOsOutput(" Early Ras Precharge: No \n"); + + if ( spdRawData[i] & BIT1 ) + mvOsOutput(" AutoPreCharge: Yes \n"); + else + mvOsOutput(" AutoPreCharge: No \n"); + + if ( spdRawData[i] & BIT2 ) + mvOsOutput(" Precharge All: Yes \n"); + else + mvOsOutput(" Precharge All: No \n"); + + if ( spdRawData[i] & BIT3 ) + mvOsOutput(" Write 1/ReadBurst: Yes \n"); + else + mvOsOutput(" Write 1/ReadBurst: No \n"); + + if ( spdRawData[i] & BIT4 ) + mvOsOutput(" lower VCC tolerance: 5%%\n"); + else + mvOsOutput(" lower VCC tolerance: 10%%\n"); + + if ( spdRawData[i] & BIT5 ) + mvOsOutput(" upper VCC tolerance: 5%%\n"); + else + mvOsOutput(" upper VCC tolerance: 10%%\n"); + } + else if (dimmInfo.memoryType == MEM_TYPE_DDR1) + { + if ( spdRawData[i] & BIT0 ) + mvOsOutput(" Supports Weak Driver: Yes \n"); + else + mvOsOutput(" Supports Weak Driver: No \n"); + + if ( !(spdRawData[i] & BIT4) ) + mvOsOutput(" lower VCC tolerance: 0.2V\n"); + + if ( !(spdRawData[i] & BIT5) ) + mvOsOutput(" upper VCC tolerance: 0.2V\n"); + + if ( spdRawData[i] & BIT6 ) + mvOsOutput(" Concurrent Auto Preharge: Yes \n"); + else + mvOsOutput(" Concurrent Auto Preharge: No \n"); + + if ( spdRawData[i] & BIT7 ) + mvOsOutput(" Supports Fast AP: Yes \n"); + else + mvOsOutput(" Supports Fast AP: No \n"); + } + else if (dimmInfo.memoryType == MEM_TYPE_DDR2) + { + if ( spdRawData[i] & BIT0 ) + mvOsOutput(" Supports Weak Driver: Yes \n"); + else + mvOsOutput(" Supports Weak Driver: No \n"); + } + break; +/*----------------------------------------------------------------------------*/ + + case 23: + /* Minimum Cycle Time At Maximum Cas Latancy Minus 1 (2nd highest CL) */ + leftOfPoint = (spdRawData[i] & 0xf0) >> 4; + rightOfPoint = (spdRawData[i] & 0x0f) * 10; + + /* DDR2 addition of right of point */ + if ((spdRawData[i] & 0x0f) == 0xA) + { + rightOfPoint = 25; + } + if ((spdRawData[i] & 0x0f) == 0xB) + { + rightOfPoint = 33; + } + if ((spdRawData[i] & 0x0f) == 0xC) + { + rightOfPoint = 66; + } + if ((spdRawData[i] & 0x0f) == 0xD) + { + rightOfPoint = 75; + } + + mvOsOutput("Minimum Cycle Time At 2nd highest CasLatancy" + "(0 = Not supported): %d.%d [ns]\n", + leftOfPoint, rightOfPoint ); + break; +/*----------------------------------------------------------------------------*/ + + case 24: /* Clock To Data Out 2nd highest Cas Latency Value*/ + div = (dimmInfo.memoryType == MEM_TYPE_SDRAM) ? 10:100; + time_tmp = (((spdRawData[i] & 0xf0) >> 4)*10) + + ((spdRawData[i] & 0x0f)); + leftOfPoint = time_tmp / div; + rightOfPoint = time_tmp % div; + mvOsOutput("Clock To Data Out (2nd CL value): %d.%d [ns]\n", + leftOfPoint, rightOfPoint); + break; +/*----------------------------------------------------------------------------*/ + + case 25: + /* Minimum Cycle Time At Maximum Cas Latancy Minus 2 (3rd highest CL) */ + if (dimmInfo.memoryType == MEM_TYPE_SDRAM) + { + leftOfPoint = (spdRawData[i] & 0xfc) >> 2; + rightOfPoint = (spdRawData[i] & 0x3) * 25; + } + else /* DDR1 or DDR2 */ + { + leftOfPoint = (spdRawData[i] & 0xf0) >> 4; + rightOfPoint = (spdRawData[i] & 0x0f) * 10; + + /* DDR2 addition of right of point */ + if ((spdRawData[i] & 0x0f) == 0xA) + { + rightOfPoint = 25; + } + if ((spdRawData[i] & 0x0f) == 0xB) + { + rightOfPoint = 33; + } + if ((spdRawData[i] & 0x0f) == 0xC) + { + rightOfPoint = 66; + } + if ((spdRawData[i] & 0x0f) == 0xD) + { + rightOfPoint = 75; + } + } + mvOsOutput("Minimum Cycle Time At 3rd highest CasLatancy" + "(0 = Not supported): %d.%d [ns]\n", + leftOfPoint, rightOfPoint ); + break; +/*----------------------------------------------------------------------------*/ + + case 26: /* Clock To Data Out 3rd highest Cas Latency Value*/ + if (dimmInfo.memoryType == MEM_TYPE_SDRAM) + { + leftOfPoint = (spdRawData[i] & 0xfc) >> 2; + rightOfPoint = (spdRawData[i] & 0x3) * 25; + } + else /* DDR1 or DDR2 */ + { + time_tmp = (((spdRawData[i] & 0xf0) >> 4)*10) + + ((spdRawData[i] & 0x0f)); + leftOfPoint = 0; + rightOfPoint = time_tmp; + } + mvOsOutput("Clock To Data Out (3rd CL value): %d.%2d[ns]\n", + leftOfPoint, rightOfPoint ); + break; +/*----------------------------------------------------------------------------*/ + + case 27: /* Minimum Row Precharge Time */ + shift = (dimmInfo.memoryType == MEM_TYPE_SDRAM)? 0:2; + maskLeftOfPoint = (dimmInfo.memoryType == MEM_TYPE_SDRAM) ? + 0xff : 0xfc; + maskRightOfPoint = (dimmInfo.memoryType == MEM_TYPE_SDRAM) ? + 0x00 : 0x03; + leftOfPoint = ((spdRawData[i] & maskLeftOfPoint) >> shift); + rightOfPoint = (spdRawData[i] & maskRightOfPoint)*25; + temp = ((leftOfPoint*100) + rightOfPoint);/* in 10ps Intervals*/ + trp_clocks = (temp + (busClkPs-1)) / busClkPs; + mvOsOutput("Minimum Row Precharge Time [ns]: %d.%d = " + "in Clk cycles %d\n", + leftOfPoint, rightOfPoint, trp_clocks); + break; +/*----------------------------------------------------------------------------*/ + + case 28: /* Minimum Row Active to Row Active Time */ + shift = (dimmInfo.memoryType == MEM_TYPE_SDRAM)? 0:2; + maskLeftOfPoint = (dimmInfo.memoryType == MEM_TYPE_SDRAM) ? + 0xff : 0xfc; + maskRightOfPoint = (dimmInfo.memoryType == MEM_TYPE_SDRAM) ? + 0x00 : 0x03; + leftOfPoint = ((spdRawData[i] & maskLeftOfPoint) >> shift); + rightOfPoint = (spdRawData[i] & maskRightOfPoint)*25; + temp = ((leftOfPoint*100) + rightOfPoint);/* in 100ns Interval*/ + trrd_clocks = (temp + (busClkPs-1)) / busClkPs; + mvOsOutput("Minimum Row Active -To- Row Active Delay [ns]: " + "%d.%d = in Clk cycles %d\n", + leftOfPoint, rightOfPoint, trp_clocks); + break; +/*----------------------------------------------------------------------------*/ + + case 29: /* Minimum Ras-To-Cas Delay */ + shift = (dimmInfo.memoryType == MEM_TYPE_SDRAM)? 0:2; + maskLeftOfPoint = (dimmInfo.memoryType == MEM_TYPE_SDRAM) ? + 0xff : 0xfc; + maskRightOfPoint = (dimmInfo.memoryType == MEM_TYPE_SDRAM) ? + 0x00 : 0x03; + leftOfPoint = ((spdRawData[i] & maskLeftOfPoint) >> shift); + rightOfPoint = (spdRawData[i] & maskRightOfPoint)*25; + temp = ((leftOfPoint*100) + rightOfPoint);/* in 100ns Interval*/ + trcd_clocks = (temp + (busClkPs-1) )/ busClkPs; + mvOsOutput("Minimum Ras-To-Cas Delay [ns]: %d.%d = " + "in Clk cycles %d\n", + leftOfPoint, rightOfPoint, trp_clocks); + break; +/*----------------------------------------------------------------------------*/ + + case 30: /* Minimum Ras Pulse Width */ + tras_clocks = (cas2ps(spdRawData[i])+(busClkPs-1)) / busClkPs; + mvOsOutput("Minimum Ras Pulse Width [ns]: %d = " + "in Clk cycles %d\n", spdRawData[i], tras_clocks); + break; +/*----------------------------------------------------------------------------*/ + + case 31: /* Module Bank Density */ + mvOsOutput("Module Bank Density (more than 1= Multisize-Module):"); + + if (dimmInfo.memoryType == MEM_TYPE_SDRAM) + { + if (dimmInfo.dimmBankDensity & BIT0) + mvOsOutput("1GB, "); + if (dimmInfo.dimmBankDensity & BIT1) + mvOsOutput("8MB, "); + if (dimmInfo.dimmBankDensity & BIT2) + mvOsOutput("16MB, "); + if (dimmInfo.dimmBankDensity & BIT3) + mvOsOutput("32MB, "); + if (dimmInfo.dimmBankDensity & BIT4) + mvOsOutput("64MB, "); + if (dimmInfo.dimmBankDensity & BIT5) + mvOsOutput("128MB, "); + if (dimmInfo.dimmBankDensity & BIT6) + mvOsOutput("256MB, "); + if (dimmInfo.dimmBankDensity & BIT7) + mvOsOutput("512MB, "); + } + else if (dimmInfo.memoryType == MEM_TYPE_DDR1) + { + if (dimmInfo.dimmBankDensity & BIT0) + mvOsOutput("1GB, "); + if (dimmInfo.dimmBankDensity & BIT1) + mvOsOutput("2GB, "); + if (dimmInfo.dimmBankDensity & BIT2) + mvOsOutput("16MB, "); + if (dimmInfo.dimmBankDensity & BIT3) + mvOsOutput("32MB, "); + if (dimmInfo.dimmBankDensity & BIT4) + mvOsOutput("64MB, "); + if (dimmInfo.dimmBankDensity & BIT5) + mvOsOutput("128MB, "); + if (dimmInfo.dimmBankDensity & BIT6) + mvOsOutput("256MB, "); + if (dimmInfo.dimmBankDensity & BIT7) + mvOsOutput("512MB, "); + } + else /* if (dimmInfo.memoryType == MEM_TYPE_DDR2) */ + { + if (dimmInfo.dimmBankDensity & BIT0) + mvOsOutput("1GB, "); + if (dimmInfo.dimmBankDensity & BIT1) + mvOsOutput("2GB, "); + if (dimmInfo.dimmBankDensity & BIT2) + mvOsOutput("4GB, "); + if (dimmInfo.dimmBankDensity & BIT3) + mvOsOutput("8GB, "); + if (dimmInfo.dimmBankDensity & BIT4) + mvOsOutput("16GB, "); + if (dimmInfo.dimmBankDensity & BIT5) + mvOsOutput("128MB, "); + if (dimmInfo.dimmBankDensity & BIT6) + mvOsOutput("256MB, "); + if (dimmInfo.dimmBankDensity & BIT7) + mvOsOutput("512MB, "); + } + mvOsOutput("\n"); + break; +/*----------------------------------------------------------------------------*/ + + case 32: /* Address And Command Setup Time (measured in ns/1000) */ + if (dimmInfo.memoryType == MEM_TYPE_SDRAM) + { + rightOfPoint = (spdRawData[i] & 0x0f); + leftOfPoint = (spdRawData[i] & 0xf0) >> 4; + if(leftOfPoint > 7) + { + leftOfPoint *= -1; + } + } + else /* DDR1 or DDR2 */ + { + time_tmp = (((spdRawData[i] & 0xf0) >> 4)*10) + + ((spdRawData[i] & 0x0f)); + leftOfPoint = time_tmp / 100; + rightOfPoint = time_tmp % 100; + } + mvOsOutput("Address And Command Setup Time [ns]: %d.%d\n", + leftOfPoint, rightOfPoint); + break; +/*----------------------------------------------------------------------------*/ + + case 33: /* Address And Command Hold Time */ + if (dimmInfo.memoryType == MEM_TYPE_SDRAM) + { + rightOfPoint = (spdRawData[i] & 0x0f); + leftOfPoint = (spdRawData[i] & 0xf0) >> 4; + if(leftOfPoint > 7) + { + leftOfPoint *= -1; + } + } + else /* DDR1 or DDR2 */ + { + time_tmp = (((spdRawData[i] & 0xf0) >> 4)*10) + + ((spdRawData[i] & 0x0f)); + leftOfPoint = time_tmp / 100; + rightOfPoint = time_tmp % 100; + } + mvOsOutput("Address And Command Hold Time [ns]: %d.%d\n", + leftOfPoint, rightOfPoint); + break; +/*----------------------------------------------------------------------------*/ + + case 34: /* Data Input Setup Time */ + if (dimmInfo.memoryType == MEM_TYPE_SDRAM) + { + rightOfPoint = (spdRawData[i] & 0x0f); + leftOfPoint = (spdRawData[i] & 0xf0) >> 4; + if(leftOfPoint > 7) + { + leftOfPoint *= -1; + } + } + else /* DDR1 or DDR2 */ + { + time_tmp = (((spdRawData[i] & 0xf0) >> 4)*10) + + ((spdRawData[i] & 0x0f)); + leftOfPoint = time_tmp / 100; + rightOfPoint = time_tmp % 100; + } + mvOsOutput("Data Input Setup Time [ns]: %d.%d\n", + leftOfPoint, rightOfPoint); + break; +/*----------------------------------------------------------------------------*/ + + case 35: /* Data Input Hold Time */ + if (dimmInfo.memoryType == MEM_TYPE_SDRAM) + { + rightOfPoint = (spdRawData[i] & 0x0f); + leftOfPoint = (spdRawData[i] & 0xf0) >> 4; + if(leftOfPoint > 7) + { + leftOfPoint *= -1; + } + } + else /* DDR1 or DDR2 */ + { + time_tmp = (((spdRawData[i] & 0xf0) >> 4)*10) + + ((spdRawData[i] & 0x0f)); + leftOfPoint = time_tmp / 100; + rightOfPoint = time_tmp % 100; + } + mvOsOutput("Data Input Hold Time [ns]: %d.%d\n\n", + leftOfPoint, rightOfPoint); + break; +/*----------------------------------------------------------------------------*/ + + case 36: /* Relevant for DDR2 only: Write Recovery Time */ + leftOfPoint = ((spdRawData[i] & maskLeftOfPoint) >> 2); + rightOfPoint = (spdRawData[i] & maskRightOfPoint) * 25; + mvOsOutput("Write Recovery Time [ns]: %d.%d\n", + leftOfPoint, rightOfPoint); + break; +/*----------------------------------------------------------------------------*/ + } + +} + + +/* + * translate ns.ns/10 coding of SPD timing values + * into ps unit values + */ +/******************************************************************************* +* cas2ps - Translate x.y ns parameter to pico-seconds values +* +* DESCRIPTION: +* This function translates x.y nano seconds to its value in pico seconds. +* For example 3.75ns will return 3750. +* +* INPUT: +* spd_byte - DIMM SPD byte. +* +* OUTPUT: +* None. +* +* RETURN: +* value in pico seconds. +* +*******************************************************************************/ +static MV_U32 cas2ps(MV_U8 spd_byte) +{ + MV_U32 ns, ns10; + + /* isolate upper nibble */ + ns = (spd_byte >> 4) & 0x0F; + /* isolate lower nibble */ + ns10 = (spd_byte & 0x0F); + + if( ns10 < 10 ) { + ns10 *= 10; + } + else if( ns10 == 10 ) + ns10 = 25; + else if( ns10 == 11 ) + ns10 = 33; + else if( ns10 == 12 ) + ns10 = 66; + else if( ns10 == 13 ) + ns10 = 75; + else + { + mvOsOutput("cas2ps Err. unsupported cycle time.\n"); + } + + return (ns*1000 + ns10*10); +} + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvDram.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvDram.h new file mode 100644 index 0000000..678e224 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvDram.h @@ -0,0 +1,191 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#ifndef __INCmvDram +#define __INCmvDram + +#include "ddr1_2/mvDramIf.h" +#include "twsi/mvTwsi.h" + +#define MAX_DIMM_NUM 2 +#define SPD_SIZE 128 + +/* Dimm spd offsets */ +#define DIMM_MEM_TYPE 2 +#define DIMM_ROW_NUM 3 +#define DIMM_COL_NUM 4 +#define DIMM_MODULE_BANK_NUM 5 +#define DIMM_DATA_WIDTH 6 +#define DIMM_VOLT_IF 8 +#define DIMM_MIN_CC_AT_MAX_CAS 9 +#define DIMM_ERR_CHECK_TYPE 11 +#define DIMM_REFRESH_INTERVAL 12 +#define DIMM_SDRAM_WIDTH 13 +#define DIMM_ERR_CHECK_DATA_WIDTH 14 +#define DIMM_MIN_CLK_DEL 15 +#define DIMM_BURST_LEN_SUP 16 +#define DIMM_DEV_BANK_NUM 17 +#define DIMM_SUP_CAL 18 +#define DIMM_DDR2_TYPE_INFORMATION 20 /* DDR2 only */ +#define DIMM_BUF_ADDR_CONT_IN 21 +#define DIMM_MIN_CC_AT_MAX_CAS_MINUS1 23 +#define DIMM_MIN_CC_AT_MAX_CAS_MINUS2 25 +#define DIMM_MIN_ROW_PRECHARGE_TIME 27 +#define DIMM_MIN_ROW_ACTIVE_TO_ROW_ACTIVE 28 +#define DIMM_MIN_RAS_TO_CAS_DELAY 29 +#define DIMM_MIN_RAS_PULSE_WIDTH 30 +#define DIMM_BANK_DENSITY 31 +#define DIMM_MIN_WRITE_RECOVERY_TIME 36 +#define DIMM_MIN_WRITE_TO_READ_CMD_DELAY 37 +#define DIMM_MIN_READ_TO_PRECH_CMD_DELAY 38 +#define DIMM_MIN_REFRESH_TO_ACTIVATE_CMD 42 + +/* Dimm Memory Type values */ +#define DIMM_MEM_TYPE_SDRAM 0x4 +#define DIMM_MEM_TYPE_DDR1 0x7 +#define DIMM_MEM_TYPE_DDR2 0x8 + +#define DIMM_MODULE_MANU_OFFS 64 +#define DIMM_MODULE_MANU_SIZE 8 +#define DIMM_MODULE_VEN_OFFS 73 +#define DIMM_MODULE_VEN_SIZE 25 +#define DIMM_MODULE_ID_OFFS 99 +#define DIMM_MODULE_ID_SIZE 18 + +/* enumeration for voltage levels. */ +typedef enum _mvDimmVoltageIf +{ + TTL_5V_TOLERANT, + LVTTL, + HSTL_1_5V, + SSTL_3_3V, + SSTL_2_5V, + VOLTAGE_UNKNOWN, +} MV_DIMM_VOLTAGE_IF; + + +/* enumaration for SDRAM CAS Latencies. */ +typedef enum _mvDimmSdramCas +{ + SD_CL_1 =1, + SD_CL_2, + SD_CL_3, + SD_CL_4, + SD_CL_5, + SD_CL_6, + SD_CL_7, + SD_FAULT +}MV_DIMM_SDRAM_CAS; + + +/* DIMM information structure */ +typedef struct _mvDimmInfo +{ + MV_MEMORY_TYPE memoryType; /* DDR or SDRAM */ + + MV_U8 spdRawData[SPD_SIZE]; /* Content of SPD-EEPROM copied 1:1 */ + + /* DIMM dimensions */ + MV_U32 numOfRowAddr; + MV_U32 numOfColAddr; + MV_U32 numOfModuleBanks; + MV_U32 dataWidth; + MV_U32 errorCheckType; /* ECC , PARITY..*/ + MV_U32 sdramWidth; /* 4,8,16 or 32 */ + MV_U32 errorCheckDataWidth; /* 0 - no, 1 - Yes */ + MV_U32 burstLengthSupported; + MV_U32 numOfBanksOnEachDevice; + MV_U32 suportedCasLatencies; + MV_U32 refreshInterval; + MV_U32 dimmBankDensity; + MV_U32 dimmTypeInfo; /* DDR2 only */ + MV_U32 dimmAttributes; + + /* DIMM timing parameters */ + MV_U32 minCycleTimeAtMaxCasLatPs; + MV_U32 minCycleTimeAtMaxCasLatMinus1Ps; + MV_U32 minCycleTimeAtMaxCasLatMinus2Ps; + MV_U32 minRowPrechargeTime; + MV_U32 minRowActiveToRowActive; + MV_U32 minRasToCasDelay; + MV_U32 minRasPulseWidth; + MV_U32 minWriteRecoveryTime; /* DDR2 only */ + MV_U32 minWriteToReadCmdDelay; /* DDR2 only */ + MV_U32 minReadToPrechCmdDelay; /* DDR2 only */ + MV_U32 minRefreshToActiveCmd; /* DDR2 only */ + + /* Parameters calculated from the extracted DIMM information */ + MV_U32 size; /* 16,64,128,256 or 512 MByte in MB units */ + MV_U32 deviceDensity; /* 16,64,128,256 or 512 Mbit in MB units */ + MV_U32 numberOfDevices; + +} MV_DIMM_INFO; + + +MV_STATUS mvDramBankInfoGet(MV_U32 bankNum, MV_DRAM_BANK_INFO *pBankInfo); +MV_STATUS dimmSpdGet(MV_U32 dimmNum, MV_DIMM_INFO *pDimmInfo); +MV_VOID dimmSpdPrint(MV_U32 dimmNum); +MV_STATUS dimmSpdCpy(MV_VOID); + +#endif /* __INCmvDram */ diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvDramIf.c b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvDramIf.c new file mode 100644 index 0000000..12fb26a --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvDramIf.c @@ -0,0 +1,1599 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + + +/* includes */ +#include "ddr1_2/mvDramIf.h" +#include "ctrlEnv/sys/mvCpuIf.h" + + + +#ifdef MV_DEBUG +#define DB(x) x +#else +#define DB(x) +#endif + +/* DRAM bank presence encoding */ +#define BANK_PRESENT_CS0 0x1 +#define BANK_PRESENT_CS0_CS1 0x3 +#define BANK_PRESENT_CS0_CS2 0x5 +#define BANK_PRESENT_CS0_CS1_CS2 0x7 +#define BANK_PRESENT_CS0_CS2_CS3 0xd +#define BANK_PRESENT_CS0_CS2_CS3_CS4 0xf + +/* locals */ +static MV_BOOL sdramIfWinOverlap(MV_TARGET target, MV_ADDR_WIN *pAddrWin); +#if defined(MV_INC_BOARD_DDIM) +static void sdramDDr2OdtConfig(MV_DRAM_BANK_INFO *pBankInfo); +static MV_U32 dunitCtrlLowRegCalc(MV_DRAM_BANK_INFO *pBankInfo, MV_U32 minCas); +static MV_U32 sdramModeRegCalc(MV_U32 minCas); +static MV_U32 sdramExtModeRegCalc(MV_DRAM_BANK_INFO *pBankInfo); +static MV_U32 sdramAddrCtrlRegCalc(MV_DRAM_BANK_INFO *pBankInfo); +static MV_U32 sdramConfigRegCalc(MV_DRAM_BANK_INFO *pBankInfo, MV_U32 busClk); +static MV_U32 minCasCalc(MV_DRAM_BANK_INFO *pBankInfo, MV_U32 busClk, + MV_U32 forcedCl); +static MV_U32 sdramTimeCtrlLowRegCalc(MV_DRAM_BANK_INFO *pBankInfo, + MV_U32 minCas, MV_U32 busClk); +static MV_U32 sdramTimeCtrlHighRegCalc(MV_DRAM_BANK_INFO *pBankInfo, + MV_U32 busClk); + +/******************************************************************************* +* mvDramIfDetect - Prepare DRAM interface configuration values. +* +* DESCRIPTION: +* This function implements the full DRAM detection and timing +* configuration for best system performance. +* Since this routine runs from a ROM device (Boot Flash), its stack +* resides on RAM, that might be the system DRAM. Changing DRAM +* configuration values while keeping vital data in DRAM is risky. That +* is why the function does not preform the configuration setting but +* prepare those in predefined 32bit registers (in this case IDMA +* registers are used) for other routine to perform the settings. +* The function will call for board DRAM SPD information for each DRAM +* chip select. The function will then analyze those SPD parameters of +* all DRAM banks in order to decide on DRAM configuration compatible +* for all DRAM banks. +* The function will set the CPU DRAM address decode registers. +* Note: This routine prepares values that will overide configuration of +* mvDramBasicAsmInit(). +* +* INPUT: +* forcedCl - Forced CAL Latency. If equal to zero, do not force. +* +* OUTPUT: +* None. +* +* RETURN: +* None. +* +*******************************************************************************/ +MV_STATUS mvDramIfDetect(MV_U32 forcedCl) +{ + MV_U32 retVal = MV_OK; /* return value */ + MV_DRAM_BANK_INFO bankInfo[MV_DRAM_MAX_CS]; + MV_U32 busClk, size, base = 0, i, temp, deviceW, dimmW; + MV_U8 minCas; + MV_DRAM_DEC_WIN dramDecWin; + + dramDecWin.addrWin.baseHigh = 0; + + busClk = mvBoardSysClkGet(); + + if (0 == busClk) + { + mvOsPrintf("Dram: ERR. Can't detect system clock! \n"); + return MV_ERROR; + } + + /* Close DRAM banks except bank 0 (in case code is excecuting from it...) */ +#if defined(MV_INCLUDE_SDRAM_CS1) + for(i= SDRAM_CS1; i < MV_DRAM_MAX_CS; i++) + mvCpuIfTargetWinEnable(i, MV_FALSE); +#endif + + /* we will use bank 0 as the representative of the all the DRAM banks, */ + /* since bank 0 must exist. */ + for(i = 0; i < MV_DRAM_MAX_CS; i++) + { + /* if Bank exist */ + if(MV_OK == mvDramBankInfoGet(i, &bankInfo[i])) + { + /* check it isn't SDRAM */ + if(bankInfo[i].memoryType == MEM_TYPE_SDRAM) + { + mvOsPrintf("Dram: ERR. SDRAM type not supported !!!\n"); + return MV_ERROR; + } + /* All banks must support registry in order to activate it */ + if(bankInfo[i].registeredAddrAndControlInputs != + bankInfo[0].registeredAddrAndControlInputs) + { + mvOsPrintf("Dram: ERR. different Registered settings !!!\n"); + return MV_ERROR; + } + + /* Init the CPU window decode */ + /* Note that the size in Bank info is in MB units */ + /* Note that the Dimm width might be different then the device DRAM width */ + temp = MV_REG_READ(SDRAM_CONFIG_REG); + + deviceW = ((temp & SDRAM_DWIDTH_MASK) == SDRAM_DWIDTH_16BIT )? 16 : 32; + dimmW = bankInfo[0].dataWidth - (bankInfo[0].dataWidth % 16); + size = ((bankInfo[i].size << 20) / (dimmW/deviceW)); + + /* We can not change DRAM window settings while excecuting */ + /* code from it. That is why we skip the DRAM CS[0], saving */ + /* it to the ROM configuration routine */ + if(i == SDRAM_CS0) + { + MV_U32 sizeToReg; + + /* Translate the given window size to register format */ + sizeToReg = ctrlSizeToReg(size, SCSR_SIZE_ALIGNMENT); + + /* Size parameter validity check. */ + if (-1 == sizeToReg) + { + mvOsPrintf("mvCtrlAddrDecToReg: ERR. Win %d size invalid.\n" + ,i); + return MV_BAD_PARAM; + } + + /* Size is located at upper 16 bits */ + sizeToReg <<= SCSR_SIZE_OFFS; + + /* enable it */ + sizeToReg |= SCSR_WIN_EN; + + MV_REG_WRITE(DRAM_BUF_REG0, sizeToReg); + } + else + { + dramDecWin.addrWin.baseLow = base; + dramDecWin.addrWin.size = size; + dramDecWin.enable = MV_TRUE; + + if (MV_OK != mvDramIfWinSet(SDRAM_CS0 + i, &dramDecWin)) + { + mvOsPrintf("Dram: ERR. Fail to set bank %d!!!\n", + SDRAM_CS0 + i); + return MV_ERROR; + } + } + + base += size; + + /* update the suportedCasLatencies mask */ + bankInfo[0].suportedCasLatencies &= bankInfo[i].suportedCasLatencies; + + } + else + { + if( i == 0 ) /* bank 0 doesn't exist */ + { + mvOsPrintf("Dram: ERR. Fail to detect bank 0 !!!\n"); + return MV_ERROR; + } + else + { + DB(mvOsPrintf("Dram: Could not find bank %d\n", i)); + bankInfo[i].size = 0; /* Mark this bank as non exist */ + } + } + } + + /* calculate minimum CAS */ + minCas = minCasCalc(&bankInfo[0], busClk, forcedCl); + if (0 == minCas) + { + mvOsOutput("Dram: Warn: Could not find CAS compatible to SysClk %dMhz\n", + (busClk / 1000000)); + + if (MV_REG_READ(SDRAM_CONFIG_REG) & SDRAM_DTYPE_DDR2) + { + minCas = DDR2_CL_4; /* Continue with this CAS */ + mvOsPrintf("Set default CAS latency 4\n"); + } + else + { + minCas = DDR1_CL_3; /* Continue with this CAS */ + mvOsPrintf("Set default CAS latency 3\n"); + } + } + + /* calc SDRAM_CONFIG_REG and save it to temp register */ + temp = sdramConfigRegCalc(&bankInfo[0], busClk); + if(-1 == temp) + { + mvOsPrintf("Dram: ERR. sdramConfigRegCalc failed !!!\n"); + return MV_ERROR; + } + MV_REG_WRITE(DRAM_BUF_REG1, temp); + + /* calc SDRAM_MODE_REG and save it to temp register */ + temp = sdramModeRegCalc(minCas); + if(-1 == temp) + { + mvOsPrintf("Dram: ERR. sdramModeRegCalc failed !!!\n"); + return MV_ERROR; + } + MV_REG_WRITE(DRAM_BUF_REG2, temp); + + /* calc SDRAM_EXTENDED_MODE_REG and save it to temp register */ + temp = sdramExtModeRegCalc(&bankInfo[0]); + if(-1 == temp) + { + mvOsPrintf("Dram: ERR. sdramModeRegCalc failed !!!\n"); + return MV_ERROR; + } + MV_REG_WRITE(DRAM_BUF_REG10, temp); + + /* calc D_UNIT_CONTROL_LOW and save it to temp register */ + temp = dunitCtrlLowRegCalc(&bankInfo[0], minCas); + if(-1 == temp) + { + mvOsPrintf("Dram: ERR. dunitCtrlLowRegCalc failed !!!\n"); + return MV_ERROR; + } + MV_REG_WRITE(DRAM_BUF_REG3, temp); + + /* calc SDRAM_ADDR_CTRL_REG and save it to temp register */ + temp = sdramAddrCtrlRegCalc(&bankInfo[0]); + if(-1 == temp) + { + mvOsPrintf("Dram: ERR. sdramAddrCtrlRegCalc failed !!!\n"); + return MV_ERROR; + } + MV_REG_WRITE(DRAM_BUF_REG4, temp); + + /* calc SDRAM_TIMING_CTRL_LOW_REG and save it to temp register */ + temp = sdramTimeCtrlLowRegCalc(&bankInfo[0], minCas, busClk); + if(-1 == temp) + { + mvOsPrintf("Dram: ERR. sdramTimeCtrlLowRegCalc failed !!!\n"); + return MV_ERROR; + } + MV_REG_WRITE(DRAM_BUF_REG5, temp); + + /* calc SDRAM_TIMING_CTRL_HIGH_REG and save it to temp register */ + temp = sdramTimeCtrlHighRegCalc(&bankInfo[0], busClk); + if(-1 == temp) + { + mvOsPrintf("Dram: ERR. sdramTimeCtrlHighRegCalc failed !!!\n"); + return MV_ERROR; + } + MV_REG_WRITE(DRAM_BUF_REG6, temp); + + /* Config DDR2 On Die Termination (ODT) registers */ + if (MV_REG_READ(SDRAM_CONFIG_REG) & SDRAM_DTYPE_DDR2) + { + sdramDDr2OdtConfig(bankInfo); + } + + /* Note that DDR SDRAM Address/Control and Data pad calibration */ + /* settings is done in mvSdramIfConfig.s */ + + return retVal; +} + +/******************************************************************************* +* minCasCalc - Calculate the Minimum CAS latency which can be used. +* +* DESCRIPTION: +* Calculate the minimum CAS latency that can be used, base on the DRAM +* parameters and the SDRAM bus Clock freq. +* +* INPUT: +* busClk - the DRAM bus Clock. +* pBankInfo - bank info parameters. +* +* OUTPUT: +* None +* +* RETURN: +* The minimum CAS Latency. The function returns 0 if max CAS latency +* supported by banks is incompatible with system bus clock frequancy. +* +*******************************************************************************/ +static MV_U32 minCasCalc(MV_DRAM_BANK_INFO *pBankInfo, MV_U32 busClk, + MV_U32 forcedCl) +{ + MV_U32 count = 1, j; + MV_U32 busClkPs = 1000000000 / (busClk / 1000); /* in ps units */ + MV_U32 startBit, stopBit; + + /* DDR 1: + *******-******-******-******-******-******-******-******* + * bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 * + *******-******-******-******-******-******-******-******* + CAS = * TBD | 4 | 3.5 | 3 | 2.5 | 2 | 1.5 | 1 * + *********************************************************/ + + /* DDR 2: + *******-******-******-******-******-******-******-******* + * bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 * + *******-******-******-******-******-******-******-******* + CAS = * TBD | TBD | 5 | 4 | 3 | 2 | TBD | TBD * + *********************************************************/ + + + /* If we are asked to use the forced CAL */ + if (forcedCl) + { + mvOsPrintf("DRAM: Using forced CL %d.%d\n", (forcedCl / 10), + (forcedCl % 10)); + + if (MV_REG_READ(SDRAM_CONFIG_REG) & SDRAM_DTYPE_DDR2) + { + if (forcedCl == 30) + pBankInfo->suportedCasLatencies = 0x08; + else if (forcedCl == 40) + pBankInfo->suportedCasLatencies = 0x10; + else + { + mvOsPrintf("Forced CL %d.%d not supported. Set default CL 4\n", + (forcedCl / 10), (forcedCl % 10)); + pBankInfo->suportedCasLatencies = 0x10; + } + } + else + { + if (forcedCl == 15) + pBankInfo->suportedCasLatencies = 0x02; + else if (forcedCl == 20) + pBankInfo->suportedCasLatencies = 0x04; + else if (forcedCl == 25) + pBankInfo->suportedCasLatencies = 0x08; + else if (forcedCl == 30) + pBankInfo->suportedCasLatencies = 0x10; + else if (forcedCl == 40) + pBankInfo->suportedCasLatencies = 0x40; + else + { + mvOsPrintf("Forced CL %d.%d not supported. Set default CL 3\n", + (forcedCl / 10), (forcedCl % 10)); + pBankInfo->suportedCasLatencies = 0x10; + } + } + + return pBankInfo->suportedCasLatencies; + } + + /* go over the supported cas mask from Max Cas down and check if the */ + /* SysClk stands in its time requirments. */ + + + DB(mvOsPrintf("Dram: minCasCalc supported mask = %x busClkPs = %x \n", + pBankInfo->suportedCasLatencies,busClkPs )); + for(j = 7; j > 0; j--) + { + if((pBankInfo->suportedCasLatencies >> j) & BIT0 ) + { + /* Reset the bits for CL incompatible for the sysClk */ + switch (count) + { + case 1: + if (pBankInfo->minCycleTimeAtMaxCasLatPs > busClkPs) + pBankInfo->suportedCasLatencies &= ~(BIT0 << j); + count++; + break; + case 2: + if (pBankInfo->minCycleTimeAtMaxCasLatMinus1Ps > busClkPs) + pBankInfo->suportedCasLatencies &= ~(BIT0 << j); + count++; + break; + case 3: + if (pBankInfo->minCycleTimeAtMaxCasLatMinus2Ps > busClkPs) + pBankInfo->suportedCasLatencies &= ~(BIT0 << j); + count++; + break; + default: + pBankInfo->suportedCasLatencies &= ~(BIT0 << j); + break; + } + } + } + + DB(mvOsPrintf("Dram: minCasCalc support = %x (after SysCC calc)\n", + pBankInfo->suportedCasLatencies )); + + /* SDRAM DDR1 controller supports CL 1.5 to 3.5 */ + /* SDRAM DDR2 controller supports CL 3 to 5 */ + if (MV_REG_READ(SDRAM_CONFIG_REG) & SDRAM_DTYPE_DDR2) + { + startBit = 3; /* DDR2 support CL start with CL3 (bit 3) */ + stopBit = 5; /* DDR2 support CL stops with CL5 (bit 5) */ + } + else + { + startBit = 1; /* DDR1 support CL start with CL1.5 (bit 3) */ + stopBit = 4; /* DDR1 support CL stops with CL3 (bit 4) */ + } + + for(j = startBit; j <= stopBit ; j++) + { + if((pBankInfo->suportedCasLatencies >> j) & BIT0 ) + { + DB(mvOsPrintf("Dram: minCasCalc choose CAS %x \n",(BIT0 << j))); + return (BIT0 << j); + } + } + + return 0; +} + +/******************************************************************************* +* sdramConfigRegCalc - Calculate sdram config register +* +* DESCRIPTION: Calculate sdram config register optimized value based +* on the bank info parameters. +* +* INPUT: +* pBankInfo - sdram bank parameters +* +* OUTPUT: +* None +* +* RETURN: +* sdram config reg value. +* +*******************************************************************************/ +static MV_U32 sdramConfigRegCalc(MV_DRAM_BANK_INFO *pBankInfo, MV_U32 busClk) +{ + MV_U32 sdramConfig = 0; + MV_U32 refreshPeriod; + + busClk /= 1000000; /* we work with busClk in MHz */ + + sdramConfig = MV_REG_READ(SDRAM_CONFIG_REG); + + /* figure out the memory refresh internal */ + switch (pBankInfo->refreshInterval & 0xf) + { + case 0x0: /* refresh period is 15.625 usec */ + refreshPeriod = 15625; + break; + case 0x1: /* refresh period is 3.9 usec */ + refreshPeriod = 3900; + break; + case 0x2: /* refresh period is 7.8 usec */ + refreshPeriod = 7800; + break; + case 0x3: /* refresh period is 31.3 usec */ + refreshPeriod = 31300; + break; + case 0x4: /* refresh period is 62.5 usec */ + refreshPeriod = 62500; + break; + case 0x5: /* refresh period is 125 usec */ + refreshPeriod = 125000; + break; + default: /* refresh period undefined */ + mvOsPrintf("Dram: ERR. DRAM refresh period is unknown!\n"); + return -1; + } + + /* Now the refreshPeriod is in register format value */ + refreshPeriod = (busClk * refreshPeriod) / 1000; + + DB(mvOsPrintf("Dram: sdramConfigRegCalc calculated refresh interval %0x\n", + refreshPeriod)); + + /* make sure the refresh value is only 14 bits */ + if(refreshPeriod > SDRAM_REFRESH_MAX) + { + refreshPeriod = SDRAM_REFRESH_MAX; + DB(mvOsPrintf("Dram: sdramConfigRegCalc adjusted refresh interval %0x\n", + refreshPeriod)); + } + + /* Clear the refresh field */ + sdramConfig &= ~SDRAM_REFRESH_MASK; + + /* Set new value to refresh field */ + sdramConfig |= (refreshPeriod & SDRAM_REFRESH_MASK); + + /* registered DRAM ? */ + if ( pBankInfo->registeredAddrAndControlInputs ) + { + /* it's registered DRAM, so set the reg. DRAM bit */ + sdramConfig |= SDRAM_REGISTERED; + mvOsPrintf("DRAM Attribute: Registered address and control inputs.\n"); + } + + /* set DDR SDRAM devices configuration */ + sdramConfig &= ~SDRAM_DCFG_MASK; /* Clear Dcfg field */ + + switch (pBankInfo->sdramWidth) + { + case 8: /* memory is x8 */ + sdramConfig |= SDRAM_DCFG_X8_DEV; + DB(mvOsPrintf("Dram: sdramConfigRegCalc SDRAM device width x8\n")); + break; + case 16: + sdramConfig |= SDRAM_DCFG_X16_DEV; + DB(mvOsPrintf("Dram: sdramConfigRegCalc SDRAM device width x16\n")); + break; + default: /* memory width unsupported */ + mvOsPrintf("Dram: ERR. DRAM chip width is unknown!\n"); + return -1; + } + + /* Set static default settings */ + sdramConfig |= SDRAM_CONFIG_DV; + + DB(mvOsPrintf("Dram: sdramConfigRegCalc set sdramConfig to 0x%x\n", + sdramConfig)); + + return sdramConfig; +} + +/******************************************************************************* +* sdramModeRegCalc - Calculate sdram mode register +* +* DESCRIPTION: Calculate sdram mode register optimized value based +* on the bank info parameters and the minCas. +* +* INPUT: +* minCas - minimum CAS supported. +* +* OUTPUT: +* None +* +* RETURN: +* sdram mode reg value. +* +*******************************************************************************/ +static MV_U32 sdramModeRegCalc(MV_U32 minCas) +{ + MV_U32 sdramMode; + + sdramMode = MV_REG_READ(SDRAM_MODE_REG); + + /* Clear CAS Latency field */ + sdramMode &= ~SDRAM_CL_MASK; + + mvOsPrintf("DRAM CAS Latency "); + + if (MV_REG_READ(SDRAM_CONFIG_REG) & SDRAM_DTYPE_DDR2) + { + switch (minCas) + { + case DDR2_CL_3: + sdramMode |= SDRAM_DDR2_CL_3; + mvOsPrintf("3.\n"); + break; + case DDR2_CL_4: + sdramMode |= SDRAM_DDR2_CL_4; + mvOsPrintf("4.\n"); + break; + case DDR2_CL_5: + sdramMode |= SDRAM_DDR2_CL_5; + mvOsPrintf("5.\n"); + break; + default: + mvOsPrintf("\nsdramModeRegCalc ERROR: Max. CL out of range\n"); + return -1; + } + sdramMode |= DDR2_MODE_REG_DV; + } + else /* DDR1 */ + { + switch (minCas) + { + case DDR1_CL_1_5: + sdramMode |= SDRAM_DDR1_CL_1_5; + mvOsPrintf("1.5\n"); + break; + case DDR1_CL_2: + sdramMode |= SDRAM_DDR1_CL_2; + mvOsPrintf("2\n"); + break; + case DDR1_CL_2_5: + sdramMode |= SDRAM_DDR1_CL_2_5; + mvOsPrintf("2.5\n"); + break; + case DDR1_CL_3: + sdramMode |= SDRAM_DDR1_CL_3; + mvOsPrintf("3\n"); + break; + case DDR1_CL_4: + sdramMode |= SDRAM_DDR1_CL_4; + mvOsPrintf("4\n"); + break; + default: + mvOsPrintf("\nsdramModeRegCalc ERROR: Max. CL out of range\n"); + return -1; + } + sdramMode |= DDR1_MODE_REG_DV; + } + + DB(mvOsPrintf("nsdramModeRegCalc register 0x%x\n", sdramMode )); + + return sdramMode; +} + +/******************************************************************************* +* sdramExtModeRegCalc - Calculate sdram Extended mode register +* +* DESCRIPTION: +* Return sdram Extended mode register value based +* on the bank info parameters and bank presence. +* +* INPUT: +* pBankInfo - sdram bank parameters +* +* OUTPUT: +* None +* +* RETURN: +* sdram Extended mode reg value. +* +*******************************************************************************/ +static MV_U32 sdramExtModeRegCalc(MV_DRAM_BANK_INFO *pBankInfo) +{ + MV_U32 populateBanks = 0; + int bankNum; + if (MV_REG_READ(SDRAM_CONFIG_REG) & SDRAM_DTYPE_DDR2) + { + /* Represent the populate banks in binary form */ + for(bankNum = 0; bankNum < MV_DRAM_MAX_CS; bankNum++) + { + if (0 != pBankInfo[bankNum].size) + { + populateBanks |= (1 << bankNum); + } + } + + switch(populateBanks) + { + case(BANK_PRESENT_CS0): + return DDR_SDRAM_EXT_MODE_CS0_DV; + + case(BANK_PRESENT_CS0_CS1): + return DDR_SDRAM_EXT_MODE_CS0_DV; + + case(BANK_PRESENT_CS0_CS2): + return DDR_SDRAM_EXT_MODE_CS0_CS2_DV; + + case(BANK_PRESENT_CS0_CS1_CS2): + return DDR_SDRAM_EXT_MODE_CS0_CS2_DV; + + case(BANK_PRESENT_CS0_CS2_CS3): + return DDR_SDRAM_EXT_MODE_CS0_CS2_DV; + + case(BANK_PRESENT_CS0_CS2_CS3_CS4): + return DDR_SDRAM_EXT_MODE_CS0_CS2_DV; + + default: + mvOsPrintf("sdramExtModeRegCalc: Invalid DRAM bank presence\n"); + return -1; + } + } + return 0; +} + +/******************************************************************************* +* dunitCtrlLowRegCalc - Calculate sdram dunit control low register +* +* DESCRIPTION: Calculate sdram dunit control low register optimized value based +* on the bank info parameters and the minCas. +* +* INPUT: +* pBankInfo - sdram bank parameters +* minCas - minimum CAS supported. +* +* OUTPUT: +* None +* +* RETURN: +* sdram dunit control low reg value. +* +*******************************************************************************/ +static MV_U32 dunitCtrlLowRegCalc(MV_DRAM_BANK_INFO *pBankInfo, MV_U32 minCas) +{ + MV_U32 dunitCtrlLow; + + dunitCtrlLow = MV_REG_READ(SDRAM_DUNIT_CTRL_REG); + + /* Clear StBurstDel field */ + dunitCtrlLow &= ~SDRAM_ST_BURST_DEL_MASK; + +#ifdef MV_88W8660 + /* Clear address/control output timing field */ + dunitCtrlLow &= ~SDRAM_CTRL_POS_RISE; +#endif /* MV_88W8660 */ + + DB(mvOsPrintf("Dram: dunitCtrlLowRegCalc\n")); + + /* For proper sample of read data set the Dunit Control register's */ + /* stBurstDel bits [27:24] */ + /********-********-********-********-********-********* + * CL=1.5 | CL=2 | CL=2.5 | CL=3 | CL=4 | CL=5 * + *********-********-********-********-********-********* +Not Reg. * 0011 | 0011 | 0100 | 0100 | 0101 | TBD * + *********-********-********-********-********-********* +Registered * 0100 | 0100 | 0101 | 0101 | 0110 | TBD * + *********-********-********-********-********-*********/ + + if (MV_REG_READ(SDRAM_CONFIG_REG) & SDRAM_DTYPE_DDR2) + { + switch (minCas) + { + case DDR2_CL_3: + /* registerd DDR SDRAM? */ + if (pBankInfo->registeredAddrAndControlInputs == MV_TRUE) + dunitCtrlLow |= 0x5 << SDRAM_ST_BURST_DEL_OFFS; + else + dunitCtrlLow |= 0x4 << SDRAM_ST_BURST_DEL_OFFS; + break; + case DDR2_CL_4: + /* registerd DDR SDRAM? */ + if (pBankInfo->registeredAddrAndControlInputs == MV_TRUE) + dunitCtrlLow |= 0x6 << SDRAM_ST_BURST_DEL_OFFS; + else + dunitCtrlLow |= 0x5 << SDRAM_ST_BURST_DEL_OFFS; + break; + default: + mvOsPrintf("Dram: dunitCtrlLowRegCalc Max. CL out of range %d\n", + minCas); + return -1; + } + } + else /* DDR1 */ + { + switch (minCas) + { + case DDR1_CL_1_5: + /* registerd DDR SDRAM? */ + if (pBankInfo->registeredAddrAndControlInputs == MV_TRUE) + dunitCtrlLow |= 0x4 << SDRAM_ST_BURST_DEL_OFFS; + else + dunitCtrlLow |= 0x3 << SDRAM_ST_BURST_DEL_OFFS; + break; + case DDR1_CL_2: + /* registerd DDR SDRAM? */ + if (pBankInfo->registeredAddrAndControlInputs == MV_TRUE) + dunitCtrlLow |= 0x4 << SDRAM_ST_BURST_DEL_OFFS; + else + dunitCtrlLow |= 0x3 << SDRAM_ST_BURST_DEL_OFFS; + break; + case DDR1_CL_2_5: + /* registerd DDR SDRAM? */ + if (pBankInfo->registeredAddrAndControlInputs == MV_TRUE) + dunitCtrlLow |= 0x5 << SDRAM_ST_BURST_DEL_OFFS; + else + dunitCtrlLow |= 0x4 << SDRAM_ST_BURST_DEL_OFFS; + break; + case DDR1_CL_3: + /* registerd DDR SDRAM? */ + if (pBankInfo->registeredAddrAndControlInputs == MV_TRUE) + dunitCtrlLow |= 0x5 << SDRAM_ST_BURST_DEL_OFFS; + else + dunitCtrlLow |= 0x4 << SDRAM_ST_BURST_DEL_OFFS; + break; + case DDR1_CL_4: + /* registerd DDR SDRAM? */ + if (pBankInfo->registeredAddrAndControlInputs == MV_TRUE) + dunitCtrlLow |= 0x6 << SDRAM_ST_BURST_DEL_OFFS; + else + dunitCtrlLow |= 0x5 << SDRAM_ST_BURST_DEL_OFFS; + break; + default: + mvOsPrintf("Dram: dunitCtrlLowRegCalc Max. CL out of range %d\n", + minCas); + return -1; + } + + } + DB(mvOsPrintf("Dram: Reg dunit control low = %x\n", dunitCtrlLow )); + + return dunitCtrlLow; +} + +/******************************************************************************* +* sdramAddrCtrlRegCalc - Calculate sdram address control register +* +* DESCRIPTION: Calculate sdram address control register optimized value based +* on the bank info parameters and the minCas. +* +* INPUT: +* pBankInfo - sdram bank parameters +* +* OUTPUT: +* None +* +* RETURN: +* sdram address control reg value. +* +*******************************************************************************/ +static MV_U32 sdramAddrCtrlRegCalc(MV_DRAM_BANK_INFO *pBankInfo) +{ + MV_U32 addrCtrl = 0; + + /* Set Address Control register static configuration bits */ + addrCtrl = MV_REG_READ(SDRAM_ADDR_CTRL_REG); + + /* Set address control default value */ + addrCtrl |= SDRAM_ADDR_CTRL_DV; + + /* Clear DSize field */ + addrCtrl &= ~SDRAM_DSIZE_MASK; + + /* Note that density is in MB units */ + switch (pBankInfo->deviceDensity) + { + case 128: /* 128 Mbit */ + DB(mvOsPrintf("DRAM Device Density 128Mbit\n")); + addrCtrl |= SDRAM_DSIZE_128Mb; + break; + case 256: /* 256 Mbit */ + DB(mvOsPrintf("DRAM Device Density 256Mbit\n")); + addrCtrl |= SDRAM_DSIZE_256Mb; + break; + case 512: /* 512 Mbit */ + DB(mvOsPrintf("DRAM Device Density 512Mbit\n")); + addrCtrl |= SDRAM_DSIZE_512Mb; + break; + default: + mvOsPrintf("Dram: sdramAddrCtrl unsupported RAM-Device size %d\n", + pBankInfo->deviceDensity); + return -1; + } + + /* SDRAM address control */ + DB(mvOsPrintf("Dram: setting sdram address control with: %x \n", addrCtrl)); + + return addrCtrl; +} + +/******************************************************************************* +* sdramTimeCtrlLowRegCalc - Calculate sdram timing control low register +* +* DESCRIPTION: +* This function calculates sdram timing control low register +* optimized value based on the bank info parameters and the minCas. +* +* INPUT: +* pBankInfo - sdram bank parameters +* busClk - Bus clock +* +* OUTPUT: +* None +* +* RETURN: +* sdram timinf control low reg value. +* +*******************************************************************************/ +static MV_U32 sdramTimeCtrlLowRegCalc(MV_DRAM_BANK_INFO *pBankInfo, + MV_U32 minCas, MV_U32 busClk) +{ + MV_U32 tRp = 0; + MV_U32 tRrd = 0; + MV_U32 tRcd = 0; + MV_U32 tRas = 0; + MV_U32 tWr = 0; + MV_U32 tWtr = 0; + MV_U32 tRtp = 0; + + MV_U32 bankNum; + + busClk = busClk / 1000000; /* In MHz */ + + /* Scan all DRAM banks to find maximum timing values */ + for (bankNum = 0; bankNum < MV_DRAM_MAX_CS; bankNum++) + { + tRp = MV_MAX(tRp, pBankInfo[bankNum].minRowPrechargeTime); + tRrd = MV_MAX(tRrd, pBankInfo[bankNum].minRowActiveToRowActive); + tRcd = MV_MAX(tRcd, pBankInfo[bankNum].minRasToCasDelay); + tRas = MV_MAX(tRas, pBankInfo[bankNum].minRasPulseWidth); + } + + /* Extract timing (in ns) from SPD value. We ignore the tenth ns part. */ + /* by shifting the data two bits right. */ + tRp = tRp >> 2; /* For example 0x50 -> 20ns */ + tRrd = tRrd >> 2; + tRcd = tRcd >> 2; + + /* Extract clock cycles from time parameter. We need to round up */ + tRp = ((busClk * tRp) / 1000) + (((busClk * tRp) % 1000) ? 1 : 0); + /* Micron work around for 133MHz */ + if (busClk == 133) + tRp += 1; + DB(mvOsPrintf("Dram Timing Low: tRp = %d ", tRp)); + tRrd = ((busClk * tRrd) / 1000) + (((busClk * tRrd) % 1000) ? 1 : 0); + /* JEDEC min reqeirments tRrd = 2 */ + if (tRrd < 2) + tRrd = 2; + DB(mvOsPrintf("tRrd = %d ", tRrd)); + tRcd = ((busClk * tRcd) / 1000) + (((busClk * tRcd) % 1000) ? 1 : 0); + DB(mvOsPrintf("tRcd = %d ", tRcd)); + tRas = ((busClk * tRas) / 1000) + (((busClk * tRas) % 1000) ? 1 : 0); + DB(mvOsPrintf("tRas = %d ", tRas)); + + /* tWr and tWtr is different for DDR1 and DDR2. tRtp is only for DDR2 */ + if (MV_REG_READ(SDRAM_CONFIG_REG) & SDRAM_DTYPE_DDR2) + { + /* Scan all DRAM banks to find maximum timing values */ + for (bankNum = 0; bankNum < MV_DRAM_MAX_CS; bankNum++) + { + tWr = MV_MAX(tWr, pBankInfo[bankNum].minWriteRecoveryTime); + tWtr = MV_MAX(tWtr, pBankInfo[bankNum].minWriteToReadCmdDelay); + tRtp = MV_MAX(tRtp, pBankInfo[bankNum].minReadToPrechCmdDelay); + } + + /* Extract timing (in ns) from SPD value. We ignore the tenth ns */ + /* part by shifting the data two bits right. */ + tWr = tWr >> 2; /* For example 0x50 -> 20ns */ + tWtr = tWtr >> 2; + tRtp = tRtp >> 2; + + /* Extract clock cycles from time parameter. We need to round up */ + tWr = ((busClk * tWr) / 1000) + (((busClk * tWr) % 1000) ? 1 : 0); + DB(mvOsPrintf("tWr = %d ", tWr)); + tWtr = ((busClk * tWtr) / 1000) + (((busClk * tWtr) % 1000) ? 1 : 0); + /* JEDEC min reqeirments tWtr = 2 */ + if (tWtr < 2) + tWtr = 2; + DB(mvOsPrintf("tWtr = %d ", tWtr)); + tRtp = ((busClk * tRtp) / 1000) + (((busClk * tRtp) % 1000) ? 1 : 0); + /* JEDEC min reqeirments tRtp = 2 */ + if (tRtp < 2) + tRtp = 2; + DB(mvOsPrintf("tRtp = %d ", tRtp)); + } + else + { + tWr = ((busClk*SDRAM_TWR) / 1000) + (((busClk*SDRAM_TWR) % 1000)?1:0); + + if ((200 == busClk) || ((100 == busClk) && (DDR1_CL_1_5 == minCas))) + { + tWtr = 2; + } + else + { + tWtr = 1; + } + + tRtp = 2; /* Must be set to 0x1 (two cycles) when using DDR1 */ + } + + DB(mvOsPrintf("tWtr = %d\n", tWtr)); + + /* Note: value of 0 in register means one cycle, 1 means two and so on */ + return (((tRp - 1) << SDRAM_TRP_OFFS) | + ((tRrd - 1) << SDRAM_TRRD_OFFS) | + ((tRcd - 1) << SDRAM_TRCD_OFFS) | + ((tRas - 1) << SDRAM_TRAS_OFFS) | + ((tWr - 1) << SDRAM_TWR_OFFS) | + ((tWtr - 1) << SDRAM_TWTR_OFFS) | + ((tRtp - 1) << SDRAM_TRTP_OFFS)); +} + +/******************************************************************************* +* sdramTimeCtrlHighRegCalc - Calculate sdram timing control high register +* +* DESCRIPTION: +* This function calculates sdram timing control high register +* optimized value based on the bank info parameters and the bus clock. +* +* INPUT: +* pBankInfo - sdram bank parameters +* busClk - Bus clock +* +* OUTPUT: +* None +* +* RETURN: +* sdram timinf control high reg value. +* +*******************************************************************************/ +static MV_U32 sdramTimeCtrlHighRegCalc(MV_DRAM_BANK_INFO *pBankInfo, + MV_U32 busClk) +{ + MV_U32 tRfc; + MV_U32 timeNs = 0; + int bankNum; + MV_U32 sdramTw2wCyc = 0; + + busClk = busClk / 1000000; /* In MHz */ + + /* tRfc is different for DDR1 and DDR2. */ + if (MV_REG_READ(SDRAM_CONFIG_REG) & SDRAM_DTYPE_DDR2) + { + MV_U32 bankNum; + + /* Scan all DRAM banks to find maximum timing values */ + for (bankNum = 0; bankNum < MV_DRAM_MAX_CS; bankNum++) + timeNs = MV_MAX(timeNs, pBankInfo[bankNum].minRefreshToActiveCmd); + } + else + { + if (pBankInfo[0].deviceDensity == _1G) + { + timeNs = SDRAM_TRFC_1G; + } + else + { + if (200 == busClk) + { + timeNs = SDRAM_TRFC_64_512M_AT_200MHZ; + } + else + { + timeNs = SDRAM_TRFC_64_512M; + } + } + } + + tRfc = ((busClk * timeNs) / 1000) + (((busClk * timeNs) % 1000) ? 1 : 0); + + DB(mvOsPrintf("Dram Timing High: tRfc = %d\n", tRfc)); + + + /* Represent the populate banks in binary form */ + for(bankNum = 0; bankNum < MV_DRAM_MAX_CS; bankNum++) + { + if (0 != pBankInfo[bankNum].size) + sdramTw2wCyc++; + } + + /* If we have more the 1 bank then we need the TW2W in 1 for ODT switch */ + if (sdramTw2wCyc > 1) + sdramTw2wCyc = 1; + else + sdramTw2wCyc = 0; + + /* Note: value of 0 in register means one cycle, 1 means two and so on */ + return ((((tRfc - 1) & SDRAM_TRFC_MASK) << SDRAM_TRFC_OFFS) | + ((SDRAM_TR2R_CYC - 1) << SDRAM_TR2R_OFFS) | + ((SDRAM_TR2WW2R_CYC - 1) << SDRAM_TR2W_W2R_OFFS) | + (((tRfc - 1) >> 4) << SDRAM_TRFC_EXT_OFFS) | + (sdramTw2wCyc << SDRAM_TW2W_OFFS)); + +} + +/******************************************************************************* +* sdramDDr2OdtConfig - Set DRAM DDR2 On Die Termination registers. +* +* DESCRIPTION: +* This function config DDR2 On Die Termination (ODT) registers. +* ODT configuration is done according to DIMM presence: +* +* Presence Ctrl Low Ctrl High Dunit Ctrl Ext Mode +* CS0 0x84210000 0x00000000 0x0000780F 0x00000440 +* CS0+CS1 0x84210000 0x00000000 0x0000780F 0x00000440 +* CS0+CS2 0x030C030C 0x00000000 0x0000740F 0x00000404 +* CS0+CS1+CS2 0x030C030C 0x00000000 0x0000740F 0x00000404 +* CS0+CS2+CS3 0x030C030C 0x00000000 0x0000740F 0x00000404 +* CS0+CS1+CS2+CS3 0x030C030C 0x00000000 0x0000740F 0x00000404 +* +* INPUT: +* pBankInfo - bank info parameters. +* +* OUTPUT: +* None +* +* RETURN: +* None +*******************************************************************************/ +static void sdramDDr2OdtConfig(MV_DRAM_BANK_INFO *pBankInfo) +{ + MV_U32 populateBanks = 0; + MV_U32 odtCtrlLow, odtCtrlHigh, dunitOdtCtrl; + int bankNum; + + /* Represent the populate banks in binary form */ + for(bankNum = 0; bankNum < MV_DRAM_MAX_CS; bankNum++) + { + if (0 != pBankInfo[bankNum].size) + { + populateBanks |= (1 << bankNum); + } + } + + switch(populateBanks) + { + case(BANK_PRESENT_CS0): + odtCtrlLow = DDR2_ODT_CTRL_LOW_CS0_DV; + odtCtrlHigh = DDR2_ODT_CTRL_HIGH_CS0_DV; + dunitOdtCtrl = DDR2_DUNIT_ODT_CTRL_CS0_DV; + break; + case(BANK_PRESENT_CS0_CS1): + odtCtrlLow = DDR2_ODT_CTRL_LOW_CS0_DV; + odtCtrlHigh = DDR2_ODT_CTRL_HIGH_CS0_DV; + dunitOdtCtrl = DDR2_DUNIT_ODT_CTRL_CS0_DV; + break; + case(BANK_PRESENT_CS0_CS2): + odtCtrlLow = DDR2_ODT_CTRL_LOW_CS0_CS2_DV; + odtCtrlHigh = DDR2_ODT_CTRL_HIGH_CS0_CS2_DV; + dunitOdtCtrl = DDR2_DUNIT_ODT_CTRL_CS0_CS2_DV; + break; + case(BANK_PRESENT_CS0_CS1_CS2): + odtCtrlLow = DDR2_ODT_CTRL_LOW_CS0_CS2_DV; + odtCtrlHigh = DDR2_ODT_CTRL_HIGH_CS0_CS2_DV; + dunitOdtCtrl = DDR2_DUNIT_ODT_CTRL_CS0_CS2_DV; + break; + case(BANK_PRESENT_CS0_CS2_CS3): + odtCtrlLow = DDR2_ODT_CTRL_LOW_CS0_CS2_DV; + odtCtrlHigh = DDR2_ODT_CTRL_HIGH_CS0_CS2_DV; + dunitOdtCtrl = DDR2_DUNIT_ODT_CTRL_CS0_CS2_DV; + break; + case(BANK_PRESENT_CS0_CS2_CS3_CS4): + odtCtrlLow = DDR2_ODT_CTRL_LOW_CS0_CS2_DV; + odtCtrlHigh = DDR2_ODT_CTRL_HIGH_CS0_CS2_DV; + dunitOdtCtrl = DDR2_DUNIT_ODT_CTRL_CS0_CS2_DV; + break; + default: + mvOsPrintf("sdramDDr2OdtConfig: Invalid DRAM bank presence\n"); + return; + } + MV_REG_WRITE(DRAM_BUF_REG7, odtCtrlLow); + MV_REG_WRITE(DRAM_BUF_REG8, odtCtrlHigh); + MV_REG_WRITE(DRAM_BUF_REG9, dunitOdtCtrl); + return; +} +#endif /* defined(MV_INC_BOARD_DDIM) */ + +/******************************************************************************* +* mvDramIfWinSet - Set DRAM interface address decode window +* +* DESCRIPTION: +* This function sets DRAM interface address decode window. +* +* INPUT: +* target - System target. Use only SDRAM targets. +* pAddrDecWin - SDRAM address window structure. +* +* OUTPUT: +* None +* +* RETURN: +* MV_BAD_PARAM if parameters are invalid or window is invalid, MV_OK +* otherwise. +*******************************************************************************/ +MV_STATUS mvDramIfWinSet(MV_TARGET target, MV_DRAM_DEC_WIN *pAddrDecWin) +{ + MV_U32 baseReg=0,sizeReg=0; + MV_U32 baseToReg=0 , sizeToReg=0; + + /* Check parameters */ + if (!MV_TARGET_IS_DRAM(target)) + { + mvOsPrintf("mvDramIfWinSet: target %d is not SDRAM\n", target); + return MV_BAD_PARAM; + } + + /* Check if the requested window overlaps with current enabled windows */ + if (MV_TRUE == sdramIfWinOverlap(target, &pAddrDecWin->addrWin)) + { + mvOsPrintf("mvDramIfWinSet: ERR. Target %d overlaps\n", target); + return MV_BAD_PARAM; + } + + /* check if address is aligned to the size */ + if(MV_IS_NOT_ALIGN(pAddrDecWin->addrWin.baseLow, pAddrDecWin->addrWin.size)) + { + mvOsPrintf("mvDramIfWinSet:Error setting DRAM interface window %d."\ + "\nAddress 0x%08x is unaligned to size 0x%x.\n", + target, + pAddrDecWin->addrWin.baseLow, + pAddrDecWin->addrWin.size); + return MV_ERROR; + } + + /* read base register*/ + baseReg = MV_REG_READ(SDRAM_BASE_ADDR_REG(target)); + + /* read size register */ + sizeReg = MV_REG_READ(SDRAM_SIZE_REG(target)); + + /* BaseLow[31:16] => base register [31:16] */ + baseToReg = pAddrDecWin->addrWin.baseLow & SCBAR_BASE_MASK; + + /* Write to address decode Base Address Register */ + baseReg &= ~SCBAR_BASE_MASK; + baseReg |= baseToReg; + + /* Translate the given window size to register format */ + sizeToReg = ctrlSizeToReg(pAddrDecWin->addrWin.size, SCSR_SIZE_ALIGNMENT); + + /* Size parameter validity check. */ + if (-1 == sizeToReg) + { + mvOsPrintf("mvCtrlAddrDecToReg: ERR. Win %d size invalid.\n",target); + return MV_BAD_PARAM; + } + + /* set size */ + sizeReg &= ~SCSR_SIZE_MASK; + /* Size is located at upper 16 bits */ + sizeReg |= (sizeToReg << SCSR_SIZE_OFFS); + + /* enable/Disable */ + if (MV_TRUE == pAddrDecWin->enable) + { + sizeReg |= SCSR_WIN_EN; + } + else + { + sizeReg &= ~SCSR_WIN_EN; + } + + /* 3) Write to address decode Base Address Register */ + MV_REG_WRITE(SDRAM_BASE_ADDR_REG(target), baseReg); + + /* Write to address decode Size Register */ + MV_REG_WRITE(SDRAM_SIZE_REG(target), sizeReg); + + return MV_OK; +} +/******************************************************************************* +* mvDramIfWinGet - Get DRAM interface address decode window +* +* DESCRIPTION: +* This function gets DRAM interface address decode window. +* +* INPUT: +* target - System target. Use only SDRAM targets. +* +* OUTPUT: +* pAddrDecWin - SDRAM address window structure. +* +* RETURN: +* MV_BAD_PARAM if parameters are invalid or window is invalid, MV_OK +* otherwise. +*******************************************************************************/ +MV_STATUS mvDramIfWinGet(MV_TARGET target, MV_DRAM_DEC_WIN *pAddrDecWin) +{ + MV_U32 baseReg,sizeReg; + MV_U32 sizeRegVal; + + /* Check parameters */ + if (!MV_TARGET_IS_DRAM(target)) + { + mvOsPrintf("mvDramIfWinGet: target %d is Illigal\n", target); + return MV_ERROR; + } + + /* Read base and size registers */ + sizeReg = MV_REG_READ(SDRAM_SIZE_REG(target)); + baseReg = MV_REG_READ(SDRAM_BASE_ADDR_REG(target)); + + sizeRegVal = (sizeReg & SCSR_SIZE_MASK) >> SCSR_SIZE_OFFS; + + pAddrDecWin->addrWin.size = ctrlRegToSize(sizeRegVal, + SCSR_SIZE_ALIGNMENT); + + /* Check if ctrlRegToSize returned OK */ + if (-1 == pAddrDecWin->addrWin.size) + { + mvOsPrintf("mvDramIfWinGet: size of target %d is Illigal\n", target); + return MV_ERROR; + } + + /* Extract base address */ + /* Base register [31:16] ==> baseLow[31:16] */ + pAddrDecWin->addrWin.baseLow = baseReg & SCBAR_BASE_MASK; + + pAddrDecWin->addrWin.baseHigh = 0; + + + if (sizeReg & SCSR_WIN_EN) + { + pAddrDecWin->enable = MV_TRUE; + } + else + { + pAddrDecWin->enable = MV_FALSE; + } + + return MV_OK; +} +/******************************************************************************* +* mvDramIfWinEnable - Enable/Disable SDRAM address decode window +* +* DESCRIPTION: +* This function enable/Disable SDRAM address decode window. +* +* INPUT: +* target - System target. Use only SDRAM targets. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_ERROR in case function parameter are invalid, MV_OK otherewise. +* +*******************************************************************************/ +MV_STATUS mvDramIfWinEnable(MV_TARGET target,MV_BOOL enable) +{ + MV_DRAM_DEC_WIN addrDecWin; + + /* Check parameters */ + if (!MV_TARGET_IS_DRAM(target)) + { + mvOsPrintf("mvDramIfWinEnable: target %d is Illigal\n", target); + return MV_ERROR; + } + + if (enable == MV_TRUE) + { /* First check for overlap with other enabled windows */ + if (MV_OK != mvDramIfWinGet(target, &addrDecWin)) + { + mvOsPrintf("mvDramIfWinEnable:ERR. Getting target %d failed.\n", + target); + return MV_ERROR; + } + /* Check for overlapping */ + if (MV_FALSE == sdramIfWinOverlap(target, &(addrDecWin.addrWin))) + { + /* No Overlap. Enable address decode winNum window */ + MV_REG_BIT_SET(SDRAM_SIZE_REG(target), SCSR_WIN_EN); + } + else + { /* Overlap detected */ + mvOsPrintf("mvDramIfWinEnable: ERR. Target %d overlap detect\n", + target); + return MV_ERROR; + } + } + else + { /* Disable address decode winNum window */ + MV_REG_BIT_RESET(SDRAM_SIZE_REG(target), SCSR_WIN_EN); + } + + return MV_OK; +} + +/******************************************************************************* +* sdramIfWinOverlap - Check if an address window overlap an SDRAM address window +* +* DESCRIPTION: +* This function scan each SDRAM address decode window to test if it +* overlapps the given address windoow +* +* INPUT: +* target - SDRAM target where the function skips checking. +* pAddrDecWin - The tested address window for overlapping with +* SDRAM windows. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_TRUE if the given address window overlaps any enabled address +* decode map, MV_FALSE otherwise. +* +*******************************************************************************/ +static MV_BOOL sdramIfWinOverlap(MV_TARGET target, MV_ADDR_WIN *pAddrWin) +{ + MV_TARGET targetNum; + MV_DRAM_DEC_WIN addrDecWin; + + for(targetNum = SDRAM_CS0; targetNum < MV_DRAM_MAX_CS ; targetNum++) + { + /* don't check our winNum or illegal targets */ + if (targetNum == target) + { + continue; + } + + /* Get window parameters */ + if (MV_OK != mvDramIfWinGet(targetNum, &addrDecWin)) + { + mvOsPrintf("sdramIfWinOverlap: ERR. TargetWinGet failed\n"); + return MV_ERROR; + } + + /* Do not check disabled windows */ + if (MV_FALSE == addrDecWin.enable) + { + continue; + } + + if(MV_TRUE == ctrlWinOverlapTest(pAddrWin, &addrDecWin.addrWin)) + { + mvOsPrintf( + "sdramIfWinOverlap: Required target %d overlap winNum %d\n", + target, targetNum); + return MV_TRUE; + } + } + + return MV_FALSE; +} + +/******************************************************************************* +* mvDramIfBankSizeGet - Get DRAM interface bank size. +* +* DESCRIPTION: +* This function returns the size of a given DRAM bank. +* +* INPUT: +* bankNum - Bank number. +* +* OUTPUT: +* None. +* +* RETURN: +* DRAM bank size. If bank is disabled the function return '0'. In case +* or paramter is invalid, the function returns -1. +* +*******************************************************************************/ +MV_32 mvDramIfBankSizeGet(MV_U32 bankNum) +{ + MV_DRAM_DEC_WIN addrDecWin; + + /* Check parameters */ + if (!MV_TARGET_IS_DRAM(bankNum)) + { + mvOsPrintf("mvDramIfBankBaseGet: bankNum %d is invalid\n", bankNum); + return -1; + } + /* Get window parameters */ + if (MV_OK != mvDramIfWinGet(bankNum, &addrDecWin)) + { + mvOsPrintf("sdramIfWinOverlap: ERR. TargetWinGet failed\n"); + return -1; + } + + if (MV_TRUE == addrDecWin.enable) + { + return addrDecWin.addrWin.size; + } + else + { + return 0; + } +} + + +/******************************************************************************* +* mvDramIfSizeGet - Get DRAM interface total size. +* +* DESCRIPTION: +* This function get the DRAM total size. +* +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* DRAM total size. In case or paramter is invalid, the function +* returns -1. +* +*******************************************************************************/ +MV_32 mvDramIfSizeGet(MV_VOID) +{ + MV_U32 totalSize = 0, bankSize = 0, bankNum; + + for(bankNum = 0; bankNum < MV_DRAM_MAX_CS; bankNum++) + { + bankSize = mvDramIfBankSizeGet(bankNum); + + if (-1 == bankSize) + { + mvOsPrintf("Dram: mvDramIfSizeGet error with bank %d \n",bankNum); + return -1; + } + else + { + totalSize += bankSize; + } + } + + DB(mvOsPrintf("Dram: Total DRAM size is 0x%x \n",totalSize)); + + return totalSize; +} + +/******************************************************************************* +* mvDramIfBankBaseGet - Get DRAM interface bank base. +* +* DESCRIPTION: +* This function returns the 32 bit base address of a given DRAM bank. +* +* INPUT: +* bankNum - Bank number. +* +* OUTPUT: +* None. +* +* RETURN: +* DRAM bank size. If bank is disabled or paramter is invalid, the +* function returns -1. +* +*******************************************************************************/ +MV_32 mvDramIfBankBaseGet(MV_U32 bankNum) +{ + MV_DRAM_DEC_WIN addrDecWin; + + /* Check parameters */ + if (!MV_TARGET_IS_DRAM(bankNum)) + { + mvOsPrintf("mvDramIfBankBaseGet: bankNum %d is invalid\n", bankNum); + return -1; + } + /* Get window parameters */ + if (MV_OK != mvDramIfWinGet(bankNum, &addrDecWin)) + { + mvOsPrintf("sdramIfWinOverlap: ERR. TargetWinGet failed\n"); + return -1; + } + + if (MV_TRUE == addrDecWin.enable) + { + return addrDecWin.addrWin.baseLow; + } + else + { + return -1; + } +} + + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvDramIf.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvDramIf.h new file mode 100644 index 0000000..8bfa3e8 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvDramIf.h @@ -0,0 +1,179 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + + +#ifndef __INCmvDramIfh +#define __INCmvDramIfh + +/* includes */ +#include "ddr1_2/mvDramIfRegs.h" +#include "ddr1_2/mvDramIfConfig.h" +#include "ctrlEnv/mvCtrlEnvLib.h" + +/* defines */ +/* DRAM Timing parameters */ +#define SDRAM_TWR 15 /* ns tWr */ +#define SDRAM_TRFC_64_512M_AT_200MHZ 70 /* ns tRfc for dens 64-512 @ 200MHz */ +#define SDRAM_TRFC_64_512M 75 /* ns tRfc for dens 64-512 */ +#define SDRAM_TRFC_1G 120 /* ns tRfc for dens 1GB */ +#define SDRAM_TR2R_CYC 1 /* cycle for tR2r */ +#define SDRAM_TR2WW2R_CYC 1 /* cycle for tR2wW2r */ + +/* typedefs */ + +/* enumeration for memory types */ +typedef enum _mvMemoryType +{ + MEM_TYPE_SDRAM, + MEM_TYPE_DDR1, + MEM_TYPE_DDR2 +}MV_MEMORY_TYPE; + +/* enumeration for DDR1 supported CAS Latencies */ +typedef enum _mvDimmDdr1Cas +{ + DDR1_CL_1_5 = 0x02, + DDR1_CL_2 = 0x04, + DDR1_CL_2_5 = 0x08, + DDR1_CL_3 = 0x10, + DDR1_CL_4 = 0x40, + DDR1_CL_FAULT +} MV_DIMM_DDR1_CAS; + +/* enumeration for DDR2 supported CAS Latencies */ +typedef enum _mvDimmDdr2Cas +{ + DDR2_CL_3 = 0x08, + DDR2_CL_4 = 0x10, + DDR2_CL_5 = 0x20, + DDR2_CL_FAULT +} MV_DIMM_DDR2_CAS; + + +typedef struct _mvDramBankInfo +{ + MV_MEMORY_TYPE memoryType; /* DDR1, DDR2 or SDRAM */ + + /* DIMM dimensions */ + MV_U32 numOfRowAddr; + MV_U32 numOfColAddr; + MV_U32 dataWidth; + MV_U32 errorCheckType; /* ECC , PARITY..*/ + MV_U32 sdramWidth; /* 4,8,16 or 32 */ + MV_U32 errorCheckDataWidth; /* 0 - no, 1 - Yes */ + MV_U32 burstLengthSupported; + MV_U32 numOfBanksOnEachDevice; + MV_U32 suportedCasLatencies; + MV_U32 refreshInterval; + + /* DIMM timing parameters */ + MV_U32 minCycleTimeAtMaxCasLatPs; + MV_U32 minCycleTimeAtMaxCasLatMinus1Ps; + MV_U32 minCycleTimeAtMaxCasLatMinus2Ps; + MV_U32 minRowPrechargeTime; + MV_U32 minRowActiveToRowActive; + MV_U32 minRasToCasDelay; + MV_U32 minRasPulseWidth; + MV_U32 minWriteRecoveryTime; /* DDR2 only */ + MV_U32 minWriteToReadCmdDelay; /* DDR2 only */ + MV_U32 minReadToPrechCmdDelay; /* DDR2 only */ + MV_U32 minRefreshToActiveCmd; /* DDR2 only */ + + /* Parameters calculated from the extracted DIMM information */ + MV_U32 size; + MV_U32 deviceDensity; /* 16,64,128,256 or 512 Mbit */ + MV_U32 numberOfDevices; + + /* DIMM attributes (MV_TRUE for yes) */ + MV_BOOL registeredAddrAndControlInputs; + +}MV_DRAM_BANK_INFO; + +/* This structure describes CPU interface address decode window */ +typedef struct _mvDramIfDecWin +{ + MV_ADDR_WIN addrWin; /* An address window*/ + MV_BOOL enable; /* Address decode window is enabled/disabled */ +}MV_DRAM_DEC_WIN; + +#include "ddr1_2/mvDram.h" + +/* mvDramIf.h API list */ +MV_VOID mvDramIfBasicAsmInit(MV_VOID); +MV_STATUS mvDramIfDetect(MV_U32 forcedCl); +MV_VOID _mvDramIfConfig(MV_VOID); + +MV_STATUS mvDramIfWinSet(MV_TARGET target, MV_DRAM_DEC_WIN *pAddrDecWin); +MV_STATUS mvDramIfWinGet(MV_TARGET target, MV_DRAM_DEC_WIN *pAddrDecWin); +MV_STATUS mvDramIfWinEnable(MV_TARGET target,MV_BOOL enable); +MV_32 mvDramIfBankSizeGet(MV_U32 bankNum); +MV_32 mvDramIfBankBaseGet(MV_U32 bankNum); +MV_32 mvDramIfSizeGet(MV_VOID); + +#if 0 +MV_STATUS mvDramIfMbusCtrlSet(MV_XBAR_TARGET *pPizzaArbArray); +MV_STATUS mvDramIfMbusToutSet(MV_U32 timeout, MV_BOOL enable); +#endif + +#endif /* __INCmvDramIfh */ diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvDramIfBasicInit.S b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvDramIfBasicInit.S new file mode 100644 index 0000000..f2a9365 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvDramIfBasicInit.S @@ -0,0 +1,988 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#define MV_ASMLANGUAGE +#include "mvSysHwConfig.h" +#include "mvOsAsm.h" +#include "mvBoardEnvSpec.h" +#include "mvCpuIfRegs.h" +#include "mvDramIfConfig.h" +#include "mvDramIfRegs.h" +#include "pex/mvPexRegs.h" +#include "pci/mvPciRegs.h" +#include "mvCtrlEnvSpec.h" +#include "mvCtrlEnvAsm.h" +#include "cpu/mvCpuArm.h" +#include "mvCommon.h" + +/* defines */ + +#if !defined(MV_INC_BOARD_DDIM) +.globl dramBoot1 +dramBoot1: + .word 0 + +/****************************************************************************** +* +* +* +* +*******************************************************************************/ +#if defined(DB_PRPMC) || defined(DB_PEX_PCI) || defined(DB_MNG) + +/* PEX_PCI and PRPMC boards 256 MB*/ +#define STATIC_SDRAM0_BANK0_SIZE 0x0fff0001 +#define STATIC_SDRAM_CONFIG 0x03248400 +#define STATIC_SDRAM_MODE 0x62 +#define STATIC_DUNIT_CTRL_LOW 0x4041000 +#define STATIC_SDRAM_ADDR_CTRL 0x00000020 +#define STATIC_SDRAM_TIME_CTRL_LOW 0x11602220 +#define STATIC_SDRAM_TIME_CTRL_HI 0x0000030F +#define STATIC_SDRAM_ODT_CTRL_LOW 0x0 +#define STATIC_SDRAM_ODT_CTRL_HI 0x0 +#define STATIC_SDRAM_DUNIT_ODT_CTRL 0x0 +#define STATIC_SDRAM_EXT_MODE 0x0 + +#elif defined(DB_FPGA) + +/* FPGA DC boards 256 MB*/ +#define STATIC_SDRAM0_BANK0_SIZE 0x0fff0001 +#define STATIC_SDRAM_CONFIG 0x03208400 /* 32bit */ +#define STATIC_SDRAM_MODE 0x22 +#define STATIC_DUNIT_CTRL_LOW 0x03041000 +#define STATIC_SDRAM_ADDR_CTRL 0x00000020 +#define STATIC_SDRAM_TIME_CTRL_LOW 0x11112220 +#define STATIC_SDRAM_TIME_CTRL_HI 0x0000000D +#define STATIC_SDRAM_ODT_CTRL_LOW 0x0 +#define STATIC_SDRAM_ODT_CTRL_HI 0x0 +#define STATIC_SDRAM_DUNIT_ODT_CTRL 0x0 +#define STATIC_SDRAM_EXT_MODE 0x1 + +#elif defined(RD_88F6183GP) || defined(DB_CUSTOMER) + +/* Customer 1 DDR2 2 devices 512Mbit by 16 bit */ +#define STATIC_SDRAM0_BANK0_SIZE 0x07ff0001 +#define STATIC_SDRAM_CONFIG 0x03158400 +#define STATIC_SDRAM_MODE 0x452 +#define STATIC_DUNIT_CTRL_LOW 0x06041000 +#define STATIC_SDRAM_ADDR_CTRL 0x00000020 +#define STATIC_SDRAM_TIME_CTRL_LOW 0x11912220 +#define STATIC_SDRAM_TIME_CTRL_HI 0x00000502 +#define STATIC_SDRAM_ODT_CTRL_LOW 0x00010000 +#define STATIC_SDRAM_ODT_CTRL_HI 0x00000002 +#define STATIC_SDRAM_DUNIT_ODT_CTRL 0x00000601 +#define STATIC_SDRAM_EXT_MODE 0x00000440 + + +#elif defined(RD_88F6183AP) + +/* DDR2 1 devices 512Mbit by 16 bit */ +#define STATIC_SDRAM0_BANK0_SIZE 0x03ff0001 +#define STATIC_SDRAM_CONFIG 0x1f154400 +#define STATIC_SDRAM_MODE 0x432 +#define STATIC_DUNIT_CTRL_LOW 0x04041000 +#define STATIC_SDRAM_ADDR_CTRL 0x00000020 +#define STATIC_SDRAM_TIME_CTRL_LOW 0x11912220 +#define STATIC_SDRAM_TIME_CTRL_HI 0x00000502 +#define STATIC_SDRAM_ODT_CTRL_LOW 0x00010000 +#define STATIC_SDRAM_ODT_CTRL_HI 0x00000002 +#define STATIC_SDRAM_DUNIT_ODT_CTRL 0x00000601 +#define STATIC_SDRAM_EXT_MODE 0x00000440 + +/* 6082L MARVELL DIMM */ +#elif defined(DB_88F6082LBP) +#define STATIC_SDRAM0_BANK0_SIZE 0x07ff0001 +#define STATIC_SDRAM_CONFIG 0x7f158400 +#define STATIC_SDRAM_MODE 0x432 +#define STATIC_DUNIT_CTRL_LOW 0x04041040 +#define STATIC_SDRAM_ADDR_CTRL 0x00000020 +#define STATIC_SDRAM_TIME_CTRL_LOW 0x11612220 +#define STATIC_SDRAM_TIME_CTRL_HI 0x00000501 +#define STATIC_SDRAM_ODT_CTRL_LOW 0x00010000 +#define STATIC_SDRAM_ODT_CTRL_HI 0x00000002 +#define STATIC_SDRAM_DUNIT_ODT_CTRL 0x00000a01 +#define STATIC_SDRAM_EXT_MODE 0x00000440 + +#elif defined(RD_88W8660_AP82S) + +/* Shark RD */ + +#if defined(MV_DRAM_32M) +#define STATIC_SDRAM0_BANK0_SIZE 0x01ff0001 +#define STATIC_SDRAM_ADDR_CTRL 0x00000010 +#elif defined(MV_DRAM_16M) + +#define STATIC_SDRAM0_BANK0_SIZE 0x00ff0001 +#define STATIC_SDRAM_ADDR_CTRL 0x00000000 + +#else +#error "NO DDR size selected" +#endif + +#define STATIC_SDRAM_CONFIG 0x03144400 +#define STATIC_SDRAM_MODE 0x62 +#define STATIC_DUNIT_CTRL_LOW 0x4041000 + +#define STATIC_SDRAM_TIME_CTRL_LOW 0x11602220 +#define STATIC_SDRAM_TIME_CTRL_HI 0x0000040b +#define STATIC_SDRAM_ODT_CTRL_LOW 0x0 +#define STATIC_SDRAM_ODT_CTRL_HI 0x0 +#define STATIC_SDRAM_DUNIT_ODT_CTRL 0x0 +#define STATIC_SDRAM_EXT_MODE 0x0 + +#elif defined(RD_88W8660) + +/* Shark RD */ +#define STATIC_SDRAM0_BANK0_SIZE 0x03ff0001 +#define STATIC_SDRAM_CONFIG 0x03144400 +#define STATIC_SDRAM_MODE 0x62 +#define STATIC_DUNIT_CTRL_LOW 0x4041000 +#define STATIC_SDRAM_ADDR_CTRL 0x00000010 +#define STATIC_SDRAM_TIME_CTRL_LOW 0x11602220 +#define STATIC_SDRAM_TIME_CTRL_HI 0x0000040b +#define STATIC_SDRAM_ODT_CTRL_LOW 0x0 +#define STATIC_SDRAM_ODT_CTRL_HI 0x0 +#define STATIC_SDRAM_DUNIT_ODT_CTRL 0x0 +#define STATIC_SDRAM_EXT_MODE 0x0 + +#else /* NAS */ + + +#if defined(RD_88F5182) + +#if defined(MV_88F5082) +#define STATIC_SDRAM0_BANK0_SIZE 0x3ff0001 +#define STATIC_SDRAM_ADDR_CTRL 0x20 +#else +#define STATIC_SDRAM0_BANK0_SIZE 0x7ff0001 +#define STATIC_SDRAM_ADDR_CTRL 0x20 +#endif + +#elif defined(RD_88F5182_3) + +#if defined(MV_88F5082) +#define STATIC_SDRAM0_BANK0_SIZE 0x3ff0001 +#define STATIC_SDRAM_ADDR_CTRL 0x20 +#else +#define STATIC_SDRAM0_BANK0_SIZE 0x7ff0001 +#define STATIC_SDRAM_ADDR_CTRL 0x20 +#endif + +#else + +#define STATIC_SDRAM0_BANK0_SIZE 0x1ff0001 +#define STATIC_SDRAM_ADDR_CTRL 0x0 + +#endif + +#if defined(MV_88F5082) +#define STATIC_SDRAM_CONFIG 0x3144400 +#else +#define STATIC_SDRAM_CONFIG 0x3148400 +#endif +#define STATIC_SDRAM_MODE 0x62 +#define STATIC_DUNIT_CTRL_LOW 0x4041000 +#define STATIC_SDRAM_TIME_CTRL_LOW 0x11602220 +#define STATIC_SDRAM_TIME_CTRL_HI 0x40c +#define STATIC_SDRAM_ODT_CTRL_LOW 0x0 +#define STATIC_SDRAM_ODT_CTRL_HI 0x0 +#define STATIC_SDRAM_DUNIT_ODT_CTRL 0x0 +#define STATIC_SDRAM_EXT_MODE 0x0 + +#endif + + .globl _mvDramIfStaticInit +_mvDramIfStaticInit: + + mov r11, LR /* Save link register */ + mov r10, r2 + + /* If we boot from NAND jump to DRAM sddress */ + + mov r5, #1 + ldr r6, =dramBoot1 + str r5, [r6] /* We started executing from DRAM */ + + ldr r6, dramBoot1 + cmp r6, #0 + bne 1f + + + /* set all dram windows to 0 */ + mov r6, #0 + MV_REG_WRITE_ASM(r6, r5, 0x1504) + MV_REG_WRITE_ASM(r6, r5, 0x150c) + MV_REG_WRITE_ASM(r6, r5, 0x1514) + MV_REG_WRITE_ASM(r6, r5, 0x151c) + + /* set all dram configuration in temp registers */ + ldr r6, = STATIC_SDRAM0_BANK0_SIZE + MV_REG_WRITE_ASM(r6, r5, DRAM_BUF_REG0) + ldr r6, = STATIC_SDRAM_CONFIG + MV_REG_WRITE_ASM(r6, r5, DRAM_BUF_REG1) + ldr r6, = STATIC_SDRAM_MODE + MV_REG_WRITE_ASM(r6, r5, DRAM_BUF_REG2) + ldr r6, = STATIC_DUNIT_CTRL_LOW + MV_REG_WRITE_ASM(r6, r5, DRAM_BUF_REG3) + ldr r6, = STATIC_SDRAM_ADDR_CTRL + MV_REG_WRITE_ASM(r6, r5, DRAM_BUF_REG4) + ldr r6, = STATIC_SDRAM_TIME_CTRL_LOW + MV_REG_WRITE_ASM(r6, r5, DRAM_BUF_REG5) + ldr r6, = STATIC_SDRAM_TIME_CTRL_HI + MV_REG_WRITE_ASM(r6, r5, DRAM_BUF_REG6) + ldr r6, = STATIC_SDRAM_ODT_CTRL_LOW + MV_REG_WRITE_ASM(r6, r5, DRAM_BUF_REG7) + ldr r6, = STATIC_SDRAM_ODT_CTRL_HI + MV_REG_WRITE_ASM(r6, r5, DRAM_BUF_REG8) + ldr r6, = STATIC_SDRAM_DUNIT_ODT_CTRL + MV_REG_WRITE_ASM(r6, r5, DRAM_BUF_REG9) + ldr r6, = STATIC_SDRAM_EXT_MODE + MV_REG_WRITE_ASM(r6, r5, DRAM_BUF_REG10) + + mov sp, #0 + bl _mvDramIfConfig +1: + mov r2, r10 + mov PC, r11 /* r11 is saved link register */ + +#else /* #if !defined(MV_INC_BOARD_DDIM) */ + +.globl dramBoot1 +dramBoot1: + .word 0 + +/******************************************************************************* +* mvDramIfBasicInit - Basic initialization of DRAM interface +* +* DESCRIPTION: +* The function will initialize the DRAM for basic usage. The function +* will use the TWSI assembly API to extract DIMM parameters according +* to which DRAM interface will be initialized. +* The function referes to the following DRAM parameters: +* 1) DIMM is registered or not. +* 2) DIMM width detection. +* 3) DIMM density. +* +* INPUT: +* r3 - required size for initial DRAM. +* +* OUTPUT: +* None. +* +* RETURN: +* None. +* +* Note: +* r4 holds I2C EEPROM address +* r5 holds SDRAM register base address +* r7 holds returned values +* r8 holds SDRAM various configuration registers value. +* r11 holds return function address. +*******************************************************************************/ +/* Setting the offsets of the I2C registers */ +#define NUM_OF_ROWS_OFFSET 3 +#define NUM_OF_COLS_OFFSET 4 +#define NUM_OF_RANKS 5 +#define SDRAM_WIDTH_OFFSET 13 +#define NUM_OF_BANKS_OFFSET 17 +#define SUPPORTED_CL_OFFSET 18 +#define DIMM_TYPE_INFO_OFFSET 20 /* DDR2 only */ +#define SDRAM_MODULES_ATTR_OFFSET 21 + +#define DRAM_DEV_DENSITY_128M 0x080 +#define DRAM_DEV_DENSITY_256M 0x100 +#define DRAM_DEV_DENSITY_512M 0x200 + .globl _mvDramIfBasicInit + .extern _i2cInit + +_mvDramIfBasicInit: + + mov r11, LR /* Save link register */ + + mov r5, #1 + ldr r8, =dramBoot1 + str r5, [r8] /* We started executing from DRAM */ + + /* If we boot from NAND jump to DRAM sddress */ + ldr r8, dramBoot1 + cmp r8, #0 + movne pc, r11 + + + + bl _i2cInit /* Initialize TWSI master */ + + /* Get default SDRAM Config values */ + MV_REG_READ_ASM (r8, r5, SDRAM_CONFIG_REG) + bic r8, r8, #SDRAM_DCFG_MASK + + + /* Read device ID */ + MV_CTRL_MODEL_GET_ASM(r4, r5); + + /* Return if OrionN */ + ldr r5, =MV_5180_DEV_ID + cmp r4, r5 + beq cat_through_end + + /* Return if Orion1 */ + ldr r5, =MV_5181_DEV_ID + cmp r4, r5 + beq cat_through_end + + /* Return if Nas */ + ldr r5, =MV_5182_DEV_ID + cmp r4, r5 + beq cat_through_end + + /* Return if Shark */ + ldr r5, =MV_8660_DEV_ID + cmp r4, r5 + beq cat_through_end + + /* goto calcConfigReg if bigger than Orion2*/ + ldr r5, =MV_5281_DEV_ID + cmp r4, r5 + bne cat_through + +cat_through: + /* set cat through - for better performance - in orion2 b0 and higher*/ + orr r8, r8, #SDRAM_CATTHR_EN + +cat_through_end: + + + /* Get registered/non registered info from DIMM */ + bl _is_Registered + beq nonRegistered + +setRegistered: + orr r8, r8, #SDRAM_REGISTERED /* Set registered bit(17) */ + +nonRegistered: + /* Get SDRAM width */ + bl _get_width + + orr r6, r8, #SDRAM_DCFG_X16_DEV /* x16 devices */ + cmp r7, #16 + beq setConfigReg + + orr r6, r8, #SDRAM_DCFG_X8_DEV /* x8 devices */ + cmp r7, #8 + beq setConfigReg + + /* This is an error. return */ + b exit_ddrAutoConfig + +setConfigReg: + mov r8, r6 + ldr r6, =SDRAM_CONFIG_DV + orr r8, r8, r6 /* Add default settings */ + mov r6, r8 /* Do not swap r8 content */ + MV_REG_WRITE_ASM (r6, r5, SDRAM_CONFIG_REG) + + /* Set maximum CL supported by DIMM */ + bl _get_CAL + + /* r7 is DIMM supported CAS (e.g: 3 --> 0x1C) */ + clz r6, r7 + rsb r6, r6, #31 /* r6 = the bit number of MAX CAS supported */ + + /* Check the DDR version */ + tst r8, #SDRAM_DTYPE_DDR2 + bne casDdr2 + +casDdr1: + ldr r7, =3 /* stBurstDel field value */ + ldr r8, =0x52 /* Assuming MAX CL = 1.5 */ + cmp r6, #1 /* If CL = 1.5 break */ + beq setModeReg + + ldr r7, =3 /* stBurstDel field value */ + ldr r8, =0x22 /* Assuming MAX CL = 2 */ + cmp r6, #2 /* If CL = 2 break */ + beq setModeReg + + ldr r7, =4 /* stBurstDel field value */ + ldr r8, =0x62 /* Assuming MAX CL = 2.5 */ + cmp r6, #3 /* If CL = 2.5 break */ + beq setModeReg + + ldr r7, =4 /* stBurstDel field value */ + ldr r8, =0x32 /* Assuming MAX CL = 3 */ + cmp r6, #4 /* If CL = 3 break */ + beq setModeReg + + ldr r7, =5 /* stBurstDel field value */ + ldr r8, =0x42 /* Assuming MAX CL = 4 */ + cmp r6, #6 /* If CL = 4 break */ + b setModeReg + + b exit_ddrAutoConfig /* This is an error !! */ + +casDdr2: + ldr r7, =4 /* stBurstDel field value */ + ldr r8, =0x32 /* Assuming MAX CL = 3 */ + cmp r6, #3 /* If CL = 3 break */ + beq casDdr2Cont + + ldr r7, =5 /* stBurstDel field value */ + ldr r8, =0x42 /* Assuming MAX CL = 4 */ + cmp r6, #4 /* If CL = 4 break */ + beq casDdr2Cont + + /* CL 5 currently unsupported. We use CL 4 instead */ + ldr r7, =5 /* stBurstDel field value */ + ldr r8, =0x42 /* Assuming MAX CL = 5 */ + cmp r6, #5 /* If CL = 5 break */ + beq casDdr2Cont + + b exit_ddrAutoConfig /* This is an error !! */ +casDdr2Cont: + /* Write recovery for auto-precharge relevant only in DDR2 */ + orr r8, r8, #0x400 /* Default value */ + +setModeReg: + /* The CPU must not attempt to change the SDRAM Mode register setting */ + /* prior to DRAM controller completion of the DRAM initialization */ + /* sequence. To guarantee this restriction, it is recommended that */ + /* the CPU sets the SDRAM Operation register to NOP command, performs */ + /* read polling until the register is back in Normal operation value, */ + /* and then sets SDRAM Mode register to it's new value. */ + + /* write 'nop' to SDRAM operation */ + mov r6, #0x5 /* 'NOP' command */ + MV_REG_WRITE_ASM (r6, r5, SDRAM_OPERATION_REG) + + /* poll SDRAM operation. Make sure its back to normal operation */ +_sdramOpPoll1: + ldr r6, [r5] + cmp r6, #0 /* '0' = Normal SDRAM Mode */ + bne _sdramOpPoll1 + + /* Now its safe to write new value to SDRAM Mode register */ + MV_REG_WRITE_ASM (r8, r5, SDRAM_MODE_REG) + + /* Make the Dunit write the DRAM its new mode */ + mov r6, #0x3 /* Mode Register Set command */ + MV_REG_WRITE_ASM (r6, r5, SDRAM_OPERATION_REG) + + /* poll SDRAM operation. Make sure its back to normal operation */ +_sdramOpPoll2: + ldr r6, [r5] + cmp r6, #0 /* '0' = Normal SDRAM Mode */ + bne _sdramOpPoll2 + + /* Set Dunit control register according to max CL detected */ + /* If we use registered DIMM, add 1 to stBurstDel */ + MV_REG_READ_ASM (r6, r5, SDRAM_CONFIG_REG) + tst r6, #SDRAM_REGISTERED + beq setDunitReg + add r7, r7, #1 + +setDunitReg: + ldr r6, =SDRAM_DUNIT_CTRL_LOW_DV + orr r6, r6, r7, LSL #SDRAM_ST_BURST_DEL_OFFS + MV_REG_WRITE_ASM (r6, r5, SDRAM_DUNIT_CTRL_REG) + + + /* DIMM density configuration*/ + /* Density = (1 << (rowNum + colNum)) * dramWidth * dramBankNum */ +Density: + bl _getDensity + mov r8, r7 + mov r8, r8, LSR #20 /* Move density 20 bits to the right */ + /* For example 0x10000000 --> 0x1000 */ + + mov r6, #0x00 + cmp r8, #DRAM_DEV_DENSITY_128M + beq densCont + + mov r6, #0x10 + cmp r8, #DRAM_DEV_DENSITY_256M + beq densCont + + mov r6, #0x20 + cmp r8, #DRAM_DEV_DENSITY_512M + beq densCont + + /* This is an error. return */ + b exit_ddrAutoConfig + +densCont: + MV_REG_WRITE_ASM (r6, r5, SDRAM_ADDR_CTRL_REG) + + /* Config DDR2 registers (Extended mode, ODTs and pad calibration) */ + MV_REG_READ_ASM (r8, r5, SDRAM_CONFIG_REG) + tst r8, #SDRAM_DTYPE_DDR2 + beq _extModeODTEnd + + + /* Set DDR Extended Mode register for working with CS[0] */ + /* write 'nop' to SDRAM operation */ + mov r6, #0x5 /* 'NOP' command */ + MV_REG_WRITE_ASM (r6, r5, SDRAM_OPERATION_REG) + + /* poll SDRAM operation. Make sure its back to normal operation */ +_sdramOpPoll3: + ldr r6, [r5] + cmp r6, #0 /* '0' = Normal SDRAM Mode */ + bne _sdramOpPoll3 + + /* Now its safe to write new value to SDRAM Extended Mode register */ + ldr r6, =DDR_SDRAM_EXT_MODE_CS0_DV + MV_REG_WRITE_ASM (r6, r5, SDRAM_EXTENDED_MODE_REG) + + /* Make the Dunit write the DRAM its new extended mode */ + mov r6, #0x4 /* Extended Mode Register Set command */ + MV_REG_WRITE_ASM (r6, r5, SDRAM_OPERATION_REG) + + /* poll SDRAM operation. Make sure its back to normal operation */ +_sdramOpPoll4: + ldr r6, [r5] + cmp r6, #0 /* '0' = Normal SDRAM Mode */ + bne _sdramOpPoll4 + + /* ODT configuration is done for single bank CS[0] only */ + /* Config DDR2 On Die Termination (ODT) registers */ + ldr r6, =DDR2_ODT_CTRL_LOW_CS0_DV + MV_REG_WRITE_ASM (r6, r5, DDR2_SDRAM_ODT_CTRL_LOW_REG) + + ldr r6, =DDR2_ODT_CTRL_HIGH_CS0_DV + MV_REG_WRITE_ASM (r6, r5, DDR2_SDRAM_ODT_CTRL_HIGH_REG) + + ldr r6, =DDR2_DUNIT_ODT_CTRL_CS0_DV + MV_REG_WRITE_ASM (r6, r5, DDR2_DUNIT_ODT_CONTROL_REG) + + + /* we will check what device we are running and perform + Initialization according to device value */ + +_extModeODTEnd: + + /* Implement Guideline (GL# MEM-2) P_CAL Automatic Calibration */ + /* Does Not Work for Address/Control and Data Pads. */ + /* Relevant for: 88F5181-A1/B0 and 88F5281-A0 */ + + /* Read device ID */ + MV_CTRL_MODEL_GET_ASM(r6, r5); + /* Read device revision */ + MV_CTRL_REV_GET_ASM(r8, r5); + + /* Continue if OrionN */ + ldr r5, =MV_5180_DEV_ID + cmp r6, r5 + bne 1f + b glMem2End +1: + + /* Continue if Orion1 and device revision B1 */ + ldr r5, =MV_5181_DEV_ID + cmp r6, r5 + bne 1f + + cmp r8, #MV_5181_B1_REV + bge glMem2End + b glMem2Start +1: + + /* Orion NAS */ + ldr r5, =MV_5182_DEV_ID + cmp r6, r5 + beq glMem2Start + + /* Orion Shark */ + ldr r5, =MV_8660_DEV_ID + cmp r6, r5 + beq glMem2Start + + b glMem2End + +glMem2Start: + + /* DDR SDRAM Address/Control Pads Calibration */ + MV_REG_READ_ASM (r6, r5, SDRAM_ADDR_CTRL_PADS_CAL_REG) + + /* Set Bit [31] to make the register writable */ + orr r8, r6, #SDRAM_WR_EN + + MV_REG_WRITE_ASM (r8, r5, SDRAM_ADDR_CTRL_PADS_CAL_REG) + + bic r6, r6, #SDRAM_WR_EN /* Make register read-only */ + bic r6, r6, #SDRAM_TUNE_EN /* Disable auto calibration */ + bic r6, r6, #SDRAM_DRVN_MASK /* Clear r5[5:0] */ + bic r6, r6, #SDRAM_DRVP_MASK /* Clear r5[11:6] */ + + /* Get the final N locked value of driving strength [22:17] */ + mov r5, r6 + mov r5, r5, LSL #9 + mov r5, r5, LSR #26 /* r5[5:0] = r6[22:17] */ + orr r5, r5, r5, LSL #6 /* r5[11:6] = r5[5:0] */ + + /* Write to both bits [5:0] and bits [11:6] */ + orr r6, r6, r5 + + MV_REG_WRITE_ASM (r6, r5, SDRAM_ADDR_CTRL_PADS_CAL_REG) + + + /* DDR SDRAM Data Pads Calibration */ + MV_REG_READ_ASM (r6, r5, SDRAM_DATA_PADS_CAL_REG) + + /* Set Bit [31] to make the register writable */ + orr r8, r6, #SDRAM_WR_EN + + MV_REG_WRITE_ASM (r8, r5, SDRAM_DATA_PADS_CAL_REG) + + bic r6, r6, #SDRAM_WR_EN /* Make register read-only */ + bic r6, r6, #SDRAM_TUNE_EN /* Disable auto calibration */ + bic r6, r6, #SDRAM_DRVN_MASK /* Clear r5[5:0] */ + bic r6, r6, #SDRAM_DRVP_MASK /* Clear r5[11:6] */ + + /* Get the final N locked value of driving strength [22:17] */ + mov r5, r6 + mov r5, r5, LSL #9 + mov r5, r5, LSR #26 + orr r5, r5, r5, LSL #6 /* r5[5:0] = r6[22:17] */ + + /* Write to both bits [5:0] and bits [11:6] */ + orr r6, r6, r5 + + MV_REG_WRITE_ASM (r6, r5, SDRAM_DATA_PADS_CAL_REG) + +glMem2End: + /* Implement Guideline (GL# MEM-3) Drive Strength Value */ + /* Relevant for: 88F5181-A1/B0/B1 and 88F5281-A0/B0 */ + + /* Get SDRAM Config value */ + MV_REG_READ_ASM (r8, r5, SDRAM_CONFIG_REG) + + /* Get DIMM type */ + tst r8, #SDRAM_DTYPE_DDR2 + beq ddr1StrengthVal + +ddr2StrengthVal: + ldr r4, =DDR2_ADDR_CTRL_PAD_STRENGTH_TYPICAL_DV + ldr r8, =DDR2_DATA_PAD_STRENGTH_TYPICAL_DV + b setDrvStrength +ddr1StrengthVal: + ldr r4, =DDR1_ADDR_CTRL_PAD_STRENGTH_TYPICAL_DV + ldr r8, =DDR1_DATA_PAD_STRENGTH_TYPICAL_DV + +setDrvStrength: + /* DDR SDRAM Address/Control Pads Calibration */ + MV_REG_READ_ASM (r6, r5, SDRAM_ADDR_CTRL_PADS_CAL_REG) + + orr r6, r6, #SDRAM_WR_EN /* Make register writeable */ + + MV_REG_WRITE_ASM (r6, r5, SDRAM_ADDR_CTRL_PADS_CAL_REG) + HTOLL(r6,r5) + + bic r6, r6, #SDRAM_WR_EN /* Make register read-only */ + bic r6, r6, #SDRAM_PRE_DRIVER_STRENGTH_MASK + orr r6, r4, r6 /* Set default value for DDR */ + + MV_REG_WRITE_ASM (r6, r5, SDRAM_ADDR_CTRL_PADS_CAL_REG) + + + /* DDR SDRAM Data Pads Calibration */ + MV_REG_READ_ASM (r6, r5, SDRAM_DATA_PADS_CAL_REG) + + orr r6, r6, #SDRAM_WR_EN /* Make register writeable */ + + MV_REG_WRITE_ASM (r6, r5, SDRAM_DATA_PADS_CAL_REG) + HTOLL(r6,r5) + + bic r6, r6, #SDRAM_WR_EN /* Make register read-only */ + bic r6, r6, #SDRAM_PRE_DRIVER_STRENGTH_MASK + orr r6, r8, r6 /* Set default value for DDR */ + + MV_REG_WRITE_ASM (r6, r5, SDRAM_DATA_PADS_CAL_REG) + + + /* Implement Guideline (GL# MEM-4) DQS Reference Delay Tuning */ + /* Relevant for: 88F5181-A1/B0/B1 and 88F5281-A0/B0 */ + /* Get the "sample on reset" register for the DDR frequancy */ + +#if defined(MV_RUN_FROM_FLASH) + /* Calc the absolute address of the _cpuARMDDRCLK[] in the boot flash */ + ldr r7, = _cpuARMDDRCLK + ldr r4, =_start + ldr r4, [r4] + sub r7, r7, r4 + ldr r4, = Lrom_start_of_data + ldr r4, [r4] + add r7, r4, r7 +#else + /* Calc the absolute address of the _cpuARMDDRCLK[] in the boot flash */ + ldr r7, = _cpuARMDDRCLK + ldr r4, =_start + sub r7, r7, r4 + add r7, r7, #CFG_MONITOR_BASE +#endif + /* Get the "sample on reset" register for the DDR frequancy */ + MV_REG_READ_ASM (r4, r5, MPP_SAMPLE_AT_RESET) + ldr r5, =MSAR_ARMDDRCLCK_MASK + and r5, r4, r5 +#if 0 /* YOTAM TO BE FIX */ + mov r5, r5, LSR #MSAR_ARMDDRCLCK_OFFS +#endif + + /* Read device ID */ + MV_CTRL_MODEL_GET_ASM(r6, r8); + + /* Continue if TC90 */ + ldr r8, =MV_1281_DEV_ID + cmp r6, r6 + beq armClkMsb + + /* Continue if Orion2 */ + ldr r8, =MV_5281_DEV_ID + cmp r6, r8 +#if 0 /* YOTAM TO BE FIX */ + bne 1f +#endif + +armClkMsb: +#if 0 /* YOTAM TO BE FIX */ + tst r4, #MSAR_ARMDDRCLCK_H_MASK + beq 1f + orr r5, r5, #BIT4 +1: + ldr r4, =MV_CPU_ARM_CLK_ELM_SIZE + mul r5, r4, r5 + add r7, r7, r5 + add r7, r7, #MV_CPU_ARM_CLK_DDR_OFF + ldr r5, [r7] +#endif + + /* Get SDRAM Config value */ + MV_REG_READ_ASM (r8, r4, SDRAM_CONFIG_REG) + + /* Get DIMM type */ + tst r8, #SDRAM_DTYPE_DDR2 + beq ddr1FtdllVal + +ddr2FtdllVal: + ldr r4, =FTDLL_DDR2_250MHZ + ldr r7, =_250MHz + cmp r5, r7 + beq setFtdllReg + ldr r4, =FTDLL_DDR2_200MHZ + ldr r7, =_200MHz + cmp r5, r7 + beq setFtdllReg + ldr r4, =FTDLL_DDR2_166MHZ + ldr r7, =_166MHz + cmp r5, r7 + beq setFtdllReg + ldr r4, =FTDLL_DDR2_133MHZ + b setFtdllReg + +ddr1FtdllVal: + ldr r4, =FTDLL_DDR1_200MHZ + ldr r7, =_200MHz + cmp r5, r7 + beq setFtdllReg + ldr r4, =FTDLL_DDR1_166MHZ + ldr r7, =_166MHz + cmp r5, r7 + beq setFtdllReg + ldr r4, =FTDLL_DDR1_133MHZ + ldr r7, =_133MHz + cmp r5, r7 + beq setFtdllReg + ldr r4, =0 + +setFtdllReg: + +#if !defined(MV_88W8660) && !defined(MV_88F6183) && !defined(MV_88F6183L) + MV_REG_READ_ASM (r8, r5, SDRAM_FTDLL_CONFIG_REG) + orr r8, r8, r4 + MV_REG_WRITE_ASM (r8, r5, SDRAM_FTDLL_CONFIG_REG) + bic r8, r8, #1 + MV_REG_WRITE_ASM (r8, r5, SDRAM_FTDLL_CONFIG_REG) +#endif /* !defined(MV_88W8660) && !defined(MV_88F6183) && !defined(MV_88F6183L)*/ + + +setTimingReg: + /* Set default Timing parameters */ + MV_REG_READ_ASM (r8, r5, SDRAM_CONFIG_REG) + tst r8, #SDRAM_DTYPE_DDR2 + bne ddr2TimeParam + +ddr1TimeParam: + ldr r6, =DDR1_TIMING_LOW_DV + MV_REG_WRITE_ASM (r6, r5, SDRAM_TIMING_CTRL_LOW_REG) + ldr r6, =DDR1_TIMING_HIGH_DV + MV_REG_WRITE_ASM (r6, r5, SDRAM_TIMING_CTRL_HIGH_REG) + b timeParamDone + +ddr2TimeParam: + ldr r6, =DDR2_TIMING_LOW_DV + MV_REG_WRITE_ASM (r6, r5, SDRAM_TIMING_CTRL_LOW_REG) + ldr r6, =DDR2_TIMING_HIGH_DV + MV_REG_WRITE_ASM (r6, r5, SDRAM_TIMING_CTRL_HIGH_REG) + +timeParamDone: + /* Open CS[0] window to requested size and enable it. Disable other */ + /* windows */ + ldr r6, =SCBAR_BASE_MASK + sub r3, r3, #1 + and r3, r3, r6 + orr r3, r3, #1 /* Enable bank */ + MV_REG_WRITE_ASM (r3, r5, SDRAM_SIZE_REG(0)) + ldr r6, =0 + MV_REG_WRITE_ASM (r6, r5, SDRAM_SIZE_REG(1)) + MV_REG_WRITE_ASM (r6, r5, SDRAM_SIZE_REG(2)) + MV_REG_WRITE_ASM (r6, r5, SDRAM_SIZE_REG(3)) + +exit_ddrAutoConfig: + mov PC, r11 /* r11 is saved link register */ + + +/***************************************************************************************/ +/* r4 holds I2C EEPROM address + * r7 holds I2C EEPROM offset parameter for i2cRead and its --> returned value + * r8 holds SDRAM various configuration registers value. + * r13 holds Link register + */ +/**************************/ +_getDensity: + mov r13, LR /* Save link register */ + + mov r4, #MV_BOARD_DIMM0_I2C_ADDR /* reading from DIMM0 */ + mov r7, #NUM_OF_ROWS_OFFSET /* offset 3 */ + bl _i2cRead + mov r8, r7 /* r8 save number of rows */ + + mov r4, #MV_BOARD_DIMM0_I2C_ADDR /* reading from DIMM0 */ + mov r7, #NUM_OF_COLS_OFFSET /* offset 4 */ + bl _i2cRead + add r8, r8, r7 /* r8 = number of rows + number of col */ + + mov r7, #0x1 + mov r8, r7, LSL r8 /* r8 = (1 << r8) */ + + mov r4, #MV_BOARD_DIMM0_I2C_ADDR /* reading from DIMM0 */ + mov r7, #SDRAM_WIDTH_OFFSET /* offset 13 */ + bl _i2cRead + mul r8, r7, r8 + + mov r4, #MV_BOARD_DIMM0_I2C_ADDR /* reading from DIMM0 */ + mov r7, #NUM_OF_BANKS_OFFSET /* offset 17 */ + bl _i2cRead + mul r7, r8, r7 + + mov PC, r13 + +/**************************/ +_get_width: + mov r13, LR /* Save link register */ + + /* Get SDRAM width (SPD offset 13) */ + mov r4, #MV_BOARD_DIMM0_I2C_ADDR /* reading from DIMM0 */ + mov r7, #SDRAM_WIDTH_OFFSET + bl _i2cRead /* result in r7 */ + + mov PC, r13 + +/**************************/ +_get_CAL: + mov r13, LR /* Save link register */ + + /* Set maximum CL supported by DIMM */ + mov r4, #MV_BOARD_DIMM0_I2C_ADDR /* reading from DIMM0 */ + mov r7, #SUPPORTED_CL_OFFSET /* offset 18 */ + bl _i2cRead + + mov PC, r13 + +/**************************/ +/* R8 - sdram configuration register. + * Return value in flag if no-registered then Z-flag is set + */ +_is_Registered: + mov r13, LR /* Save link register */ + + /* Get registered/non registered info from DIMM */ + tst r8, #SDRAM_DTYPE_DDR2 + bne regDdr2 + +regDdr1: + mov r4, #MV_BOARD_DIMM0_I2C_ADDR /* reading from DIMM0 */ + mov r7, #SDRAM_MODULES_ATTR_OFFSET + bl _i2cRead /* result in r7 */ + tst r7, #0x2 + b exit +regDdr2: + mov r4, #MV_BOARD_DIMM0_I2C_ADDR /* reading from DIMM0 */ + mov r7, #DIMM_TYPE_INFO_OFFSET + bl _i2cRead /* result in r7 */ + tst r7, #0x11 /* DIMM type = regular RDIMM (0x01) */ + /* or Mini-RDIMM (0x10) */ +exit: + mov PC, r13 + + +#endif diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvDramIfConfig.S b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvDramIfConfig.S new file mode 100644 index 0000000..e34ebbf --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvDramIfConfig.S @@ -0,0 +1,668 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +/******************************************************************************* +* mvDramIfBasicAsm.s +* +* DESCRIPTION: +* Memory full detection and best timing configuration is done in +* C code. C runtime environment requires a stack. This module API +* initialize DRAM interface chip select 0 for basic functionality for +* the use of stack. +* The module API assumes DRAM information is stored in I2C EEPROM reside +* in a given I2C address MV_BOARD_DIMM0_I2C_ADDR. The I2C EEPROM +* internal data structure is assumed to be orgenzied in common DRAM +* vendor SPD structure. +* NOTE: DFCDL values are assumed to be already initialized prior to +* this module API activity. +* +* +* DEPENDENCIES: +* None. +* +*******************************************************************************/ + +/* includes */ +#define MV_ASMLANGUAGE +#include "mvOsAsm.h" +#include "mvSysHwConfig.h" +#include "mvDramIfRegs.h" +#include "mvDramIfConfig.h" +#include "mvCpuIfRegs.h" +#include "pex/mvPexRegs.h" +#include "pci/mvPciRegs.h" +#include "mvCtrlEnvSpec.h" +#include "mvCtrlEnvAsm.h" +#include "cpu/mvCpuArm.h" +#include "mvCommon.h" + +/* defines */ + +/* locals */ +.data +.globl _mvDramIfConfig + +.text + +/******************************************************************************* +* _mvDramIfConfig - Basic DRAM interface initialization. +* +* DESCRIPTION: +* The function will initialize the following DRAM parameters using the +* values prepared by mvDramIfDetect routine. Values are located +* in predefined registers. +* +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* None. +* +*******************************************************************************/ + +_mvDramIfConfig: + + /* Save register on stack */ + cmp sp, #0 + beq no_stack_s +save_on_stack: + stmdb sp!, {r1, r2, r3, r4, r7, r11} +no_stack_s: + + /* 1) Write to SDRAM coniguration register */ + ldr r1, =(INTER_REGS_BASE + DRAM_BUF_REG1) + ldr r4, [r1] + ldr r1, =(INTER_REGS_BASE + SDRAM_CONFIG_REG) + str r4, [r1] + + /* 2) Write Dunit control low register */ + ldr r1, =(INTER_REGS_BASE + DRAM_BUF_REG3) + ldr r4, [r1] + ldr r1, =(INTER_REGS_BASE + SDRAM_DUNIT_CTRL_REG) + str r4, [r1] + + /* 3) Write SDRAM address control register */ + ldr r1, =(INTER_REGS_BASE + DRAM_BUF_REG4) + ldr r4, [r1] + ldr r1, =(INTER_REGS_BASE + SDRAM_ADDR_CTRL_REG) + str r4, [r1] + + /* 4) Write SDRAM bank 0 size register */ + ldr r1, =(INTER_REGS_BASE + DRAM_BUF_REG0) + ldr r4, [r1] + ldr r1, =(INTER_REGS_BASE + SDRAM_SIZE_REG(0)) + str r4, [r1] + + /* 5) Write SDRAM open pages control register */ + ldr r1, =(INTER_REGS_BASE + SDRAM_OPEN_PAGE_CTRL_REG) + ldr r4, =SDRAM_OPEN_PAGES_CTRL_REG_DV + str r4, [r1] + + /* 6) Write SDRAM timing Low register */ + ldr r1, =(INTER_REGS_BASE + DRAM_BUF_REG5) + ldr r4, [r1] + ldr r1, =(INTER_REGS_BASE + SDRAM_TIMING_CTRL_LOW_REG) + str r4, [r1] + + /* 7) Write SDRAM timing High register */ + ldr r1, =(INTER_REGS_BASE + DRAM_BUF_REG6) + ldr r4, [r1] + ldr r1, =(INTER_REGS_BASE + SDRAM_TIMING_CTRL_HIGH_REG) + str r4, [r1] + + /* 8) Write SDRAM mode register */ + /* The CPU must not attempt to change the SDRAM Mode register setting */ + /* prior to DRAM controller completion of the DRAM initialization */ + /* sequence. To guarantee this restriction, it is recommended that */ + /* the CPU sets the SDRAM Operation register to NOP command, performs */ + /* read polling until the register is back in Normal operation value, */ + /* and then sets SDRAM Mode register to it’s new value. */ + + /* 8.1 write 'nop' to SDRAM operation */ + mov r4, #0x5 /* 'NOP' command */ + MV_REG_WRITE_ASM(r4, r1, SDRAM_OPERATION_REG) + + /* 8.2 poll SDRAM operation. Make sure its back to normal operation */ +_sdramOpPoll1: + ldr r4, [r1] + cmp r4, #0 /* '0' = Normal SDRAM Mode */ + bne _sdramOpPoll1 + + /* 8.3 Now its safe to write new value to SDRAM Mode register */ + ldr r1, =(INTER_REGS_BASE + DRAM_BUF_REG2) + ldr r4, [r1] + ldr r1, =(INTER_REGS_BASE + SDRAM_MODE_REG) + str r4, [r1] + + /* 8.4 Make the Dunit write the DRAM its new mode */ + mov r4, #0x3 /* Mode Register Set command */ + MV_REG_WRITE_ASM (r4, r1, SDRAM_OPERATION_REG) + + /* 8.5 poll SDRAM operation. Make sure its back to normal operation */ +_sdramOpPoll2: + ldr r4, [r1] + cmp r4, #0 /* '0' = Normal SDRAM Mode */ + bne _sdramOpPoll2 + +#ifndef DB_FPGA + /* Config DDR2 registers (Extended mode, ODTs and pad calibration) */ + MV_REG_READ_ASM (r4, r1, SDRAM_CONFIG_REG) + tst r4, #SDRAM_DTYPE_DDR2 + beq _extModeODTEnd +#endif /* DB_FPGA */ + + /* 9) Write SDRAM Extended mode register This operation should be */ + /* done for each memory bank */ + /* write 'nop' to SDRAM operation */ + mov r4, #0x5 /* 'NOP' command */ + MV_REG_WRITE_ASM (r4, r1, SDRAM_OPERATION_REG) + + /* poll SDRAM operation. Make sure its back to normal operation */ +_sdramOpPoll3: + ldr r4, [r1] + cmp r4, #0 /* '0' = Normal SDRAM Mode */ + bne _sdramOpPoll3 + + /* Now its safe to write new value to SDRAM Extended Mode register */ + ldr r1, =(INTER_REGS_BASE + DRAM_BUF_REG10) + ldr r4, [r1] + ldr r1, =(INTER_REGS_BASE + SDRAM_EXTENDED_MODE_REG) + str r4, [r1] + + /* Go over each of the Banks */ + ldr r3, =0 /* r3 = DRAM bank Num */ + +extModeLoop: + /* Set the SDRAM Operation Control to each of the DRAM banks */ + mov r2, r3 /* Do not swap the bank counter value */ + MV_REG_WRITE_ASM (r2, r1, SDRAM_OPERATION_CTRL_REG) + + /* Make the Dunit write the DRAM its new mode */ + mov r4, #0x4 /* Extended Mode Register Set command */ + MV_REG_WRITE_ASM (r4, r1, SDRAM_OPERATION_REG) + + /* poll SDRAM operation. Make sure its back to normal operation */ +_sdramOpPoll4: + ldr r4, [r1] + cmp r4, #0 /* '0' = Normal SDRAM Mode */ + bne _sdramOpPoll4 +#ifndef DB_FPGA + add r3, r3, #1 + cmp r3, #4 /* 4 = Number of banks */ + bne extModeLoop + +extModeEnd: + /* Config DDR2 On Die Termination (ODT) registers */ + /* Write SDRAM DDR2 ODT control low register */ + ldr r1, =(INTER_REGS_BASE + DRAM_BUF_REG7) + ldr r4, [r1] + ldr r1, =(INTER_REGS_BASE + DDR2_SDRAM_ODT_CTRL_LOW_REG) + str r4, [r1] + + /* Write SDRAM DDR2 ODT control high register */ + ldr r1, =(INTER_REGS_BASE + DRAM_BUF_REG8) + ldr r4, [r1] + ldr r1, =(INTER_REGS_BASE + DDR2_SDRAM_ODT_CTRL_HIGH_REG) + str r4, [r1] + + /* Write SDRAM DDR2 Dunit ODT control register */ + ldr r1, =(INTER_REGS_BASE + DRAM_BUF_REG9) + ldr r4, [r1] + ldr r1, =(INTER_REGS_BASE + DDR2_DUNIT_ODT_CONTROL_REG) + str r4, [r1] + +#endif /* DB_FPGA */ +_extModeODTEnd: +#ifndef DB_FPGA + /* Implement Guideline (GL# MEM-2) P_CAL Automatic Calibration */ + /* Does Not Work for Address/Control and Data Pads. */ + /* Relevant for: 88F5181-A1/B0 and 88F5281-A0 */ + + /* Read device ID */ + MV_CTRL_MODEL_GET_ASM(r3, r1); + /* Read device revision */ + MV_CTRL_REV_GET_ASM(r2, r1); + + /* Continue if OrionN */ + ldr r1, =MV_5180_DEV_ID + cmp r3, r1 + bne 1f + b glMem2End +1: + /* Continue if Orion1 and device revision B1 */ + ldr r1, =MV_5181_DEV_ID + cmp r3, r1 + bne 1f + + cmp r2, #MV_5181_B1_REV + bge glMem2End + b glMem2Start +1: + + /* Orion NAS */ + ldr r1, =MV_5182_DEV_ID + cmp r3, r1 + beq glMem2Start + + /* Orion NAS */ + ldr r1, =MV_5082_DEV_ID + cmp r3, r1 + beq glMem2Start + + /* Orion Shark */ + ldr r1, =MV_8660_DEV_ID + cmp r3, r1 + beq glMem2Start + + b glMem2End + +glMem2Start: + + /* DDR SDRAM Address/Control Pads Calibration */ + MV_REG_READ_ASM (r3, r1, SDRAM_ADDR_CTRL_PADS_CAL_REG) + + /* Set Bit [31] to make the register writable */ + orr r2, r3, #SDRAM_WR_EN + + MV_REG_WRITE_ASM (r2, r1, SDRAM_ADDR_CTRL_PADS_CAL_REG) + + bic r3, r3, #SDRAM_WR_EN /* Make register read-only */ + bic r3, r3, #SDRAM_TUNE_EN /* Disable auto calibration */ + bic r3, r3, #SDRAM_DRVN_MASK /* Clear r1[5:0] */ + bic r3, r3, #SDRAM_DRVP_MASK /* Clear r1[11:6] */ + + /* Get the final N locked value of driving strength [22:17] */ + mov r1, r3 + mov r1, r1, LSL #9 + mov r1, r1, LSR #26 /* r1[5:0] = r3[22:17] */ + orr r1, r1, r1, LSL #6 /* r1[11:6] = r1[5:0] */ + + /* Write to both bits [5:0] and bits [11:6] */ + orr r3, r3, r1 + + MV_REG_WRITE_ASM (r3, r1, SDRAM_ADDR_CTRL_PADS_CAL_REG) + + + /* DDR SDRAM Data Pads Calibration */ + MV_REG_READ_ASM (r3, r1, SDRAM_DATA_PADS_CAL_REG) + + /* Set Bit [31] to make the register writable */ + orr r2, r3, #SDRAM_WR_EN + + MV_REG_WRITE_ASM (r2, r1, SDRAM_DATA_PADS_CAL_REG) + + bic r3, r3, #SDRAM_WR_EN /* Make register read-only */ + bic r3, r3, #SDRAM_TUNE_EN /* Disable auto calibration */ + bic r3, r3, #SDRAM_DRVN_MASK /* Clear r1[5:0] */ + bic r3, r3, #SDRAM_DRVP_MASK /* Clear r1[11:6] */ + + /* Get the final N locked value of driving strength [22:17] */ + mov r1, r3 + mov r1, r1, LSL #9 + mov r1, r1, LSR #26 + orr r1, r1, r1, LSL #6 /* r1[5:0] = r3[22:17] */ + + /* Write to both bits [5:0] and bits [11:6] */ + orr r3, r3, r1 + + MV_REG_WRITE_ASM (r3, r1, SDRAM_DATA_PADS_CAL_REG) + +glMem2End: + + + /* Implement Guideline (GL# MEM-3) Drive Strength Value */ + /* Relevant for: 88F5181-A1/B0/B1, 88F5281-A0/B0/C/D, 88F5182, */ + /* 88F5082, 88F5181L, 88F6082/L, 88F6183, 88F6183L */ + + /* Get SDRAM Config value */ + MV_REG_READ_ASM (r2, r1, SDRAM_CONFIG_REG) + + /* Get DIMM type */ + tst r2, #SDRAM_DTYPE_DDR2 + beq ddr1StrengthVal + +ddr2StrengthVal: + ldr r4, =DDR2_ADDR_CTRL_PAD_STRENGTH_TYPICAL_DV + ldr r2, =DDR2_DATA_PAD_STRENGTH_TYPICAL_DV + b setDrvStrength +ddr1StrengthVal: + ldr r4, =DDR1_ADDR_CTRL_PAD_STRENGTH_TYPICAL_DV + ldr r2, =DDR1_DATA_PAD_STRENGTH_TYPICAL_DV + +setDrvStrength: + /* DDR SDRAM Address/Control Pads Calibration */ + MV_REG_READ_ASM (r3, r1, SDRAM_ADDR_CTRL_PADS_CAL_REG) + + orr r3, r3, #SDRAM_WR_EN /* Make register writeable */ + + MV_REG_WRITE_ASM (r3, r1, SDRAM_ADDR_CTRL_PADS_CAL_REG) + HTOLL(r3,r1) + + bic r3, r3, #SDRAM_WR_EN /* Make register read-only */ + bic r3, r3, #SDRAM_PRE_DRIVER_STRENGTH_MASK + orr r3, r4, r3 /* Set default value for DDR */ + + MV_REG_WRITE_ASM (r3, r1, SDRAM_ADDR_CTRL_PADS_CAL_REG) + + + /* DDR SDRAM Data Pads Calibration */ + MV_REG_READ_ASM (r3, r1, SDRAM_DATA_PADS_CAL_REG) + + orr r3, r3, #SDRAM_WR_EN /* Make register writeable */ + + MV_REG_WRITE_ASM (r3, r1, SDRAM_DATA_PADS_CAL_REG) + HTOLL(r3,r1) + + bic r3, r3, #SDRAM_WR_EN /* Make register read-only */ + bic r3, r3, #SDRAM_PRE_DRIVER_STRENGTH_MASK + orr r3, r2, r3 /* Set default value for DDR */ + + MV_REG_WRITE_ASM (r3, r1, SDRAM_DATA_PADS_CAL_REG) + +#if !defined(MV_88W8660) && !defined(MV_88F6183) && !defined(MV_88F6183L) + /* Implement Guideline (GL# MEM-4) DQS Reference Delay Tuning */ + /* Relevant for: 88F5181-A1/B0/B1 and 88F5281-A0/B0/C/D, 88F5182 */ + /* 88F5082, 88F5181L, 88F6082/L */ + + /* Calc the absolute address of the _cpuARMDDRCLK[] in the boot flash */ + ldr r7, = _cpuARMDDRCLK + ldr r4, =_start + sub r7, r7, r4 + add r7, r7, #CFG_MONITOR_BASE + + /* Get the "sample on reset" register for the DDR frequancy */ + MV_REG_READ_ASM (r4, r1, MPP_SAMPLE_AT_RESET) + ldr r1, =MSAR_ARMDDRCLCK_MASK + and r1, r4, r1 +#if 0 /* YOTAM TO BE FIX */ + mov r1, r1, LSR #MSAR_ARMDDRCLCK_OFFS +#endif + + /* Read device ID */ + MV_CTRL_MODEL_GET_ASM(r3, r2); + + /* Continue if TC90 */ + ldr r2, =MV_1281_DEV_ID + cmp r3, r2 + beq armClkMsb + + /* Continue if Orion2 */ + ldr r2, =MV_5281_DEV_ID + cmp r3, r2 +#if 0 /* YOTAM TO BE FIX */ + bne 1f +#endif + +armClkMsb: +#if 0 /* YOTAM TO BE FIX */ + tst r4, #MSAR_ARMDDRCLCK_H_MASK + beq 1f + orr r1, r1, #BIT4 +1: + ldr r4, =MV_CPU_ARM_CLK_ELM_SIZE + mul r1, r4, r1 + add r7, r7, r1 + add r7, r7, #MV_CPU_ARM_CLK_DDR_OFF + ldr r1, [r7] +#endif + + /* Get SDRAM Config value */ + MV_REG_READ_ASM (r2, r4, SDRAM_CONFIG_REG) + + /* Get DIMM type */ + tst r2, #SDRAM_DTYPE_DDR2 + beq ddr1FtdllVal + +ddr2FtdllVal: + ldr r2, =MV_5281_DEV_ID + cmp r3, r2 + bne 2f + MV_CTRL_REV_GET_ASM(r3, r2) + cmp r3, #MV_5281_D0_REV + beq orin2_d0_ddr2_ftdll_val + cmp r3, #MV_5281_D1_REV + beq orin2_d1_ddr2_ftdll_val + cmp r3, #MV_5281_D2_REV + beq orin2_d1_ddr2_ftdll_val + b ddr2_default_val + +/* Set Orion 2 D1 ftdll values for DDR2 */ +orin2_d1_ddr2_ftdll_val: + ldr r4, =FTDLL_DDR2_250MHZ_5281_D1 + ldr r7, =_250MHz + cmp r1, r7 + beq setFtdllReg + ldr r4, =FTDLL_DDR2_200MHZ_5281_D1 + ldr r7, =_200MHz + cmp r1, r7 + beq setFtdllReg + ldr r4, =FTDLL_DDR2_166MHZ_5281_D0 + ldr r7, =_166MHz + cmp r1, r7 + beq setFtdllReg + b ddr2_default_val + +/* Set Orion 2 D0 ftdll values for DDR2 */ +orin2_d0_ddr2_ftdll_val: + ldr r4, =FTDLL_DDR2_250MHZ_5281_D0 + ldr r7, =_250MHz + cmp r1, r7 + beq setFtdllReg + ldr r4, =FTDLL_DDR2_200MHZ_5281_D0 + ldr r7, =_200MHz + cmp r1, r7 + beq setFtdllReg + ldr r4, =FTDLL_DDR2_166MHZ_5281_D0 + ldr r7, =_166MHz + cmp r1, r7 + beq setFtdllReg + b ddr2_default_val +2: + ldr r2, =MV_5182_DEV_ID + cmp r3, r2 + bne 3f + +/* Set Orion nas ftdll values for DDR2 */ +orin_nas_ftdll_val: + ldr r4, =FTDLL_DDR2_166MHZ_5182 + ldr r7, =_166MHz + cmp r1, r7 + beq setFtdllReg + +/* default values for all other devices */ +3: +ddr2_default_val: + ldr r4, =FTDLL_DDR2_250MHZ + ldr r7, =_250MHz + cmp r1, r7 + beq setFtdllReg + ldr r4, =FTDLL_DDR2_200MHZ + ldr r7, =_200MHz + cmp r1, r7 + beq setFtdllReg + ldr r4, =FTDLL_DDR2_166MHZ + ldr r7, =_166MHz + cmp r1, r7 + beq setFtdllReg + ldr r4, =FTDLL_DDR2_133MHZ + ldr r7, =_133MHz + cmp r1, r7 + beq setFtdllReg + ldr r4, =0 + b setFtdllReg + +ddr1FtdllVal: + ldr r2, =MV_5281_DEV_ID + cmp r3, r2 + bne 2f + MV_CTRL_REV_GET_ASM(r3, r2) + cmp r3, #MV_5281_D0_REV + bge orin2_ddr1_ftdll_val + b ddr1_default_val + +/* Set Orion 2 D0 and above ftdll values for DDR1 */ +orin2_ddr1_ftdll_val: + ldr r4, =FTDLL_DDR1_200MHZ_5281_D0 + ldr r7, =_200MHz + cmp r1, r7 + beq setFtdllReg + ldr r4, =FTDLL_DDR1_166MHZ_5281_D0 + ldr r7, =_166MHz + cmp r1, r7 + beq setFtdllReg + b ddr1_default_val +2: + ldr r2, =MV_5181_DEV_ID + cmp r3, r2 + bne 3f + MV_CTRL_REV_GET_ASM(r3, r2) + cmp r3, #MV_5181_B1_REV + bge orin1_ddr1_ftdll_val + b ddr1_default_val + +/* Set Orion 1 ftdll values for DDR1 */ +orin1_ddr1_ftdll_val: + ldr r4, =FTDLL_DDR1_166MHZ_5181_B1 + ldr r7, =_166MHz + cmp r1, r7 + beq setFtdllReg +3: +ddr1_default_val: + ldr r4, =FTDLL_DDR1_133MHZ + ldr r7, =_133MHz + cmp r1, r7 + beq setFtdllReg + + ldr r4, =FTDLL_DDR1_166MHZ + ldr r7, =_166MHz + cmp r1, r7 + beq setFtdllReg + + ldr r4, =FTDLL_DDR1_200MHZ + ldr r7, =_200MHz + cmp r1, r7 + beq setFtdllReg + + ldr r4, =0 + +setFtdllReg: + + MV_REG_WRITE_ASM (r4, r1, SDRAM_FTDLL_CONFIG_REG) + HTOLL(r4,r1) + bic r4, r4, #1 + MV_REG_WRITE_ASM (r4, r1, SDRAM_FTDLL_CONFIG_REG) + +#endif /* !defined(MV_88W8660) && !defined(MV_88F6183) && !defined(MV_88F6183L) */ +#endif /* DB_FPGA */ + +restoreTmpRegs: + /* Restore the registers we used to save the DDR detect values */ + + ldr r4, =DRAM_BUF_REG0_DV + MV_REG_WRITE_ASM (r4, r1, DRAM_BUF_REG0) + + ldr r4, =DRAM_BUF_REG1_DV + MV_REG_WRITE_ASM (r4, r1, DRAM_BUF_REG1) + + ldr r4, =DRAM_BUF_REG2_DV + MV_REG_WRITE_ASM (r4, r1, DRAM_BUF_REG2) + + ldr r4, =DRAM_BUF_REG3_DV + MV_REG_WRITE_ASM (r4, r1, DRAM_BUF_REG3) + + ldr r4, =DRAM_BUF_REG4_DV + MV_REG_WRITE_ASM (r4, r1, DRAM_BUF_REG4) + + ldr r4, =DRAM_BUF_REG5_DV + MV_REG_WRITE_ASM (r4, r1, DRAM_BUF_REG5) + + ldr r4, =DRAM_BUF_REG6_DV + MV_REG_WRITE_ASM (r4, r1, DRAM_BUF_REG6) + + ldr r4, =DRAM_BUF_REG7_DV + MV_REG_WRITE_ASM (r4, r1, DRAM_BUF_REG7) + + ldr r4, =DRAM_BUF_REG8_DV + MV_REG_WRITE_ASM (r4, r1, DRAM_BUF_REG8) + + ldr r4, =DRAM_BUF_REG9_DV + MV_REG_WRITE_ASM (r4, r1, DRAM_BUF_REG9) + + ldr r4, =DRAM_BUF_REG10_DV + MV_REG_WRITE_ASM (r4, r1, DRAM_BUF_REG10) + + + /* Restore registers */ + /* Save register on stack */ + cmp sp, #0 + beq no_stack_l +load_from_stack: + ldmia sp!, {r1, r2, r3, r4, r7, r11} +no_stack_l: + + mov pc, lr + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvDramIfConfig.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvDramIfConfig.h new file mode 100644 index 0000000..a7c6644 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvDramIfConfig.h @@ -0,0 +1,192 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + + +#ifndef __INCmvDramIfConfigh +#define __INCmvDramIfConfigh + +/* includes */ + +/* defines */ + +/* registers defaults values */ + +#define SDRAM_CONFIG_DV \ + (SDRAM_PERR_WRITE | \ + SDRAM_SRMODE | \ + SDRAM_SRCLK_GATED) + +#define SDRAM_DUNIT_CTRL_LOW_DV \ + (SDRAM_CTRL_POS_RISE | \ + SDRAM_CLK1DRV_NORMAL | \ + SDRAM_LOCKEN_ENABLE) + +#define SDRAM_ADDR_CTRL_DV 0 + +#define SDRAM_TIMING_CTRL_LOW_REG_DV \ + ((0x2 << SDRAM_TRCD_OFFS) | \ + (0x2 << SDRAM_TRP_OFFS) | \ + (0x1 << SDRAM_TWR_OFFS) | \ + (0x0 << SDRAM_TWTR_OFFS) | \ + (0x5 << SDRAM_TRAS_OFFS) | \ + (0x1 << SDRAM_TRRD_OFFS)) +/* TRFC 0x27, TW2W 0x1 */ +#define SDRAM_TIMING_CTRL_HIGH_REG_DV (( 0x7 << SDRAM_TRFC_OFFS ) |\ + ( 0x2 << SDRAM_TRFC_EXT_OFFS) |\ + ( 0x1 << SDRAM_TW2W_OFFS)) + +#define SDRAM_OPEN_PAGES_CTRL_REG_DV SDRAM_OPEN_PAGE_EN + +/* DDR2 ODT default register values */ + +/* Presence Ctrl Low Ctrl High Dunit Ctrl Ext Mode */ +/* CS0 0x84210000 0x00000000 0x0000780F 0x00000440 */ +/* CS0+CS1 0x84210000 0x00000000 0x0000780F 0x00000440 */ +/* CS0+CS2 0x030C030C 0x00000000 0x0000740F 0x00000404 */ +/* CS0+CS1+CS2 0x030C030C 0x00000000 0x0000740F 0x00000404 */ +/* CS0+CS2+CS3 0x030C030C 0x00000000 0x0000740F 0x00000404 */ +/* CS0+CS1+CS2+CS3 0x030C030C 0x00000000 0x0000740F 0x00000404 */ + +#define DDR2_ODT_CTRL_LOW_CS0_DV 0x84210000 +#define DDR2_ODT_CTRL_HIGH_CS0_DV 0x00000000 +#define DDR2_DUNIT_ODT_CTRL_CS0_DV 0x0000780F +#define DDR_SDRAM_EXT_MODE_CS0_DV 0x00000440 + +#define DDR2_ODT_CTRL_LOW_CS0_CS2_DV 0x030C030C +#define DDR2_ODT_CTRL_HIGH_CS0_CS2_DV 0x00000000 +#define DDR2_DUNIT_ODT_CTRL_CS0_CS2_DV 0x0000740F +#define DDR_SDRAM_EXT_MODE_CS0_CS2_DV 0x00000404 + + +/* DDR SDRAM Adderss/Control and Data Pads Calibration default values */ +#define DDR1_ADDR_CTRL_PAD_STRENGTH_TYPICAL_DV \ + (1 << SDRAM_PRE_DRIVER_STRENGTH_OFFS) +#define DDR2_ADDR_CTRL_PAD_STRENGTH_TYPICAL_DV \ + (3 << SDRAM_PRE_DRIVER_STRENGTH_OFFS) + + +#define DDR1_DATA_PAD_STRENGTH_TYPICAL_DV \ + (1 << SDRAM_PRE_DRIVER_STRENGTH_OFFS) +#define DDR2_DATA_PAD_STRENGTH_TYPICAL_DV \ + (3 << SDRAM_PRE_DRIVER_STRENGTH_OFFS) + +/* DDR SDRAM Mode Register default value */ +#define DDR1_MODE_REG_DV 0x00000000 +#define DDR2_MODE_REG_DV 0x00000400 + +/* DDR SDRAM Timing parameter default values */ +#define DDR1_TIMING_LOW_DV 0x11602220 +#define DDR1_TIMING_HIGH_DV 0x0000000d + +#define DDR2_TIMING_LOW_DV 0x11812220 +#define DDR2_TIMING_HIGH_DV 0x0000030f + +/* For Guideline (GL# MEM-4) DQS Reference Delay Tuning */ +#define FTDLL_DDR1_166MHZ ((0x1 << 0) | \ + (0x7F<< 12) | \ + (0x1 << 22)) + +#define FTDLL_DDR1_133MHZ FTDLL_DDR1_166MHZ + +#define FTDLL_DDR1_200MHZ ((0x1 << 0) | \ + (0x1 << 12) | \ + (0x3 << 14) | \ + (0x1 << 18) | \ + (0x1 << 22)) + + +#define FTDLL_DDR2_166MHZ ((0x1 << 0) | \ + (0x1 << 12) | \ + (0x1 << 14) | \ + (0x1 << 16) | \ + (0x1 << 19) | \ + (0xF << 20)) + +#define FTDLL_DDR2_133MHZ FTDLL_DDR2_166MHZ + +#define FTDLL_DDR2_200MHZ ((0x1 << 0) | \ + (0x1 << 12) | \ + (0x1 << 14) | \ + (0x1 << 16) | \ + (0x1 << 19) | \ + (0xF << 20)) + +#define FTDLL_DDR2_250MHZ 0x445001 + +/* Orion 1 B1 and above */ +#define FTDLL_DDR1_166MHZ_5181_B1 0x45D001 + +/* Orion nas */ +#define FTDLL_DDR2_166MHZ_5182 0x597001 + +/* Orion 2 D0 and above */ +#define FTDLL_DDR1_166MHZ_5281_D0 0x8D0001 +#define FTDLL_DDR1_200MHZ_5281_D0 0x8D0001 +#define FTDLL_DDR2_166MHZ_5281_D0 0x485001 +#define FTDLL_DDR2_200MHZ_5281_D0 0x485001 +#define FTDLL_DDR2_250MHZ_5281_D0 0x445001 +#define FTDLL_DDR2_200MHZ_5281_D1 0x995001 +#define FTDLL_DDR2_250MHZ_5281_D1 0x984801 + +#endif /* __INCmvDramIfh */ diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvDramIfRegs.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvDramIfRegs.h new file mode 100644 index 0000000..e9cd7c4 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr1_2/mvDramIfRegs.h @@ -0,0 +1,306 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#ifndef __INCmvDramIfRegsh +#define __INCmvDramIfRegsh + + +/* DDR SDRAM Controller Address Decode Registers */ +/* SDRAM CSn Base Address Register (SCBAR) */ +#define SDRAM_BASE_ADDR_REG(csNum) (0x1500 + (csNum * 8)) +#define SCBAR_BASE_OFFS 16 +#define SCBAR_BASE_MASK (0xffff << SCBAR_BASE_OFFS) +#define SCBAR_BASE_ALIGNMENT 0x10000 + +/* SDRAM CSn Size Register (SCSR) */ +#define SDRAM_SIZE_REG(csNum) (0x1504 + (csNum * 8)) +#define SCSR_WIN_EN BIT0 +#define SCSR_SIZE_OFFS 16 +#define SCSR_SIZE_MASK (0xffff << SCSR_SIZE_OFFS) +#define SCSR_SIZE_ALIGNMENT 0x10000 + +/* configuration register */ +#define SDRAM_CONFIG_REG 0x1400 +#define SDRAM_REFRESH_OFFS 0 +#define SDRAM_REFRESH_MAX 0x3000 +#define SDRAM_REFRESH_MASK (SDRAM_REFRESH_MAX << SDRAM_REFRESH_OFFS) +#define SDRAM_DWIDTH_OFFS 14 +#define SDRAM_DWIDTH_MASK (3 << SDRAM_DWIDTH_OFFS) +#define SDRAM_DWIDTH_16BIT (1 << SDRAM_DWIDTH_OFFS) +#define SDRAM_DWIDTH_32BIT (2 << SDRAM_DWIDTH_OFFS) +#define SDRAM_DTYPE_OFFS 16 +#define SDRAM_DTYPE_MASK (1 << SDRAM_DTYPE_OFFS) +#define SDRAM_DTYPE_DDR1 (0 << SDRAM_DTYPE_OFFS) +#define SDRAM_DTYPE_DDR2 (1 << SDRAM_DTYPE_OFFS) +#define SDRAM_REGISTERED (1 << 17) +#define SDRAM_PERR_OFFS 18 +#define SDRAM_PERR_MASK (1 << SDRAM_PERR_OFFS) +#define SDRAM_PERR_NO_WRITE (0 << SDRAM_PERR_OFFS) +#define SDRAM_PERR_WRITE (1 << SDRAM_PERR_OFFS) +#define SDRAM_DCFG_OFFS 20 +#define SDRAM_DCFG_MASK (0x3 << SDRAM_DCFG_OFFS) +#define SDRAM_DCFG_X16_DEV (1 << SDRAM_DCFG_OFFS) +#define SDRAM_DCFG_X8_DEV (2 << SDRAM_DCFG_OFFS) +#define SDRAM_SRMODE (1 << 24) +#define SDRAM_SRCLK_OFFS 25 +#define SDRAM_SRCLK_MASK (1 << SDRAM_SRCLK_OFFS) +#define SDRAM_SRCLK_KEPT (0 << SDRAM_SRCLK_OFFS) +#define SDRAM_SRCLK_GATED (1 << SDRAM_SRCLK_OFFS) +#define SDRAM_CATTH_OFFS 26 +#define SDRAM_CATTHR_EN (1 << SDRAM_CATTH_OFFS) + + +/* dunit control register */ +#define SDRAM_DUNIT_CTRL_REG 0x1404 +#define SDRAM_CTRL_POS_OFFS 6 +#define SDRAM_CTRL_POS_FALL (0 << SDRAM_CTRL_POS_OFFS) +#define SDRAM_CTRL_POS_RISE (1 << SDRAM_CTRL_POS_OFFS) +#define SDRAM_CLK1DRV_OFFS 12 +#define SDRAM_CLK1DRV_MASK (1 << SDRAM_CLK1DRV_OFFS) +#define SDRAM_CLK1DRV_HIGH_Z (0 << SDRAM_CLK1DRV_OFFS) +#define SDRAM_CLK1DRV_NORMAL (1 << SDRAM_CLK1DRV_OFFS) +#define SDRAM_LOCKEN_OFFS 18 +#define SDRAM_LOCKEN_MASK (1 << SDRAM_LOCKEN_OFFS) +#define SDRAM_LOCKEN_DISABLE (0 << SDRAM_LOCKEN_OFFS) +#define SDRAM_LOCKEN_ENABLE (1 << SDRAM_LOCKEN_OFFS) +#define SDRAM_ST_BURST_DEL_OFFS 24 +#define SDRAM_ST_BURST_DEL_MAX 0xf +#define SDRAM_ST_BURST_DEL_MASK (SDRAM_ST_BURST_DEL_MAX< busClkPs) + { + mvOsOutput("Dram: ERR. Bank %d doesn't support memory clock!!!\n", i); + return MV_ERROR; + } + + /* All banks must support registry in order to activate it */ + if(bankInfo[i].registeredAddrAndControlInputs != + bankInfo[0].registeredAddrAndControlInputs) + { + mvOsOutput("Dram: ERR. different Registered settings !!!\n"); + return MV_ERROR; + } + + /* All banks must support same ECC mode */ + if(bankInfo[i].errorCheckType != + bankInfo[0].errorCheckType) + { + mvOsOutput("Dram: ERR. different ECC settings !!!\n"); + return MV_ERROR; + } + + } + else + { + if( i == 0 ) /* bank 0 doesn't exist */ + { + mvOsOutput("Dram: ERR. Fail to detect bank 0 !!!\n"); + return MV_ERROR; + } + else + { + DB(mvOsPrintf("Dram: Could not find bank %d\n", i)); + bankInfo[i].size = 0; /* Mark this bank as non exist */ + } + } + } + +#ifdef MV_INCLUDE_SDRAM_CS2 + if (bankInfo[SDRAM_CS0].size < bankInfo[SDRAM_CS2].size) + { + MV_DRAM_CS_order[0] = SDRAM_CS2; + MV_DRAM_CS_order[1] = SDRAM_CS3; + MV_DRAM_CS_order[2] = SDRAM_CS0; + MV_DRAM_CS_order[3] = SDRAM_CS1; + DRAM_CS_Order[0] = SDRAM_CS2; + DRAM_CS_Order[1] = SDRAM_CS3; + DRAM_CS_Order[2] = SDRAM_CS0; + DRAM_CS_Order[3] = SDRAM_CS1; + + } + else +#endif + { + MV_DRAM_CS_order[0] = SDRAM_CS0; + MV_DRAM_CS_order[1] = SDRAM_CS1; + DRAM_CS_Order[0] = SDRAM_CS0; + DRAM_CS_Order[1] = SDRAM_CS1; +#ifdef MV_INCLUDE_SDRAM_CS2 + MV_DRAM_CS_order[2] = SDRAM_CS2; + MV_DRAM_CS_order[3] = SDRAM_CS3; + DRAM_CS_Order[2] = SDRAM_CS2; + DRAM_CS_Order[3] = SDRAM_CS3; +#endif + } + + for(j = 0; j < MV_DRAM_MAX_CS; j++) + { + i = MV_DRAM_CS_order[j]; + + if (0 == bankInfo[i].size) + continue; + + /* Init the CPU window decode */ + /* Note that the Dimm width might be different then the device DRAM width */ +#ifdef MV78XX0 + temp = MV_REG_READ(SDRAM_CONFIG_REG); + deviceW = ((temp & SDRAM_DWIDTH_MASK) == SDRAM_DWIDTH_32BIT )? 32 : 64; +#else + deviceW = 16 /* KW family */; +#endif + dimmW = bankInfo[0].dataWidth - (bankInfo[0].dataWidth % 16); + size = ((bankInfo[i].size << 20) / (dimmW/deviceW)); + + /* We can not change DRAM window settings while excecuting */ + /* code from it. That is why we skip the DRAM CS[0], saving */ + /* it to the ROM configuration routine */ + + numOfAllDevices += bankInfo[i].numberOfDevices; + if (i == MV_DRAM_CS_order[0]) + { + MV_U32 sizeToReg; + /* Translate the given window size to register format */ + sizeToReg = ctrlSizeToReg(size, SCSR_SIZE_ALIGNMENT); + /* Size parameter validity check. */ + if (-1 == sizeToReg) + { + mvOsOutput("DRAM: mvCtrlAddrDecToReg: ERR. Win %d size invalid.\n" + ,i); + return MV_BAD_PARAM; + } + + DB(mvOsPrintf("Dram: Bank 0 Size - %x\n",sizeToReg);) + sizeToReg = (sizeToReg << SCSR_SIZE_OFFS); + sizeToReg |= SCSR_WIN_EN; + MV_REG_WRITE(DRAM_BUF_REG0, sizeToReg); + } + else + { + dramDecWin.addrWin.baseLow = base; + dramDecWin.addrWin.size = size; + dramDecWin.enable = MV_TRUE; + DB(mvOsPrintf("Dram: Enable window %d base 0x%x, size=0x%x\n",i, base, size)); + + /* Check if the DRAM size is more then 3GByte */ + if (base < 0xC0000000) + { + DB(mvOsPrintf("Dram: Enable window %d base 0x%x, size=0x%x\n",i, base, size)); + if (MV_OK != mvCpuIfTargetWinSet(i, &dramDecWin)) + { + mvOsPrintf("Dram: ERR. Fail to set bank %d!!!\n", SDRAM_CS0 + i); + return MV_ERROR; + } + } + } + + base += size; + + /* update the suportedCasLatencies mask */ + bankInfo[0].suportedCasLatencies &= bankInfo[i].suportedCasLatencies; + } + + /* calculate minimum CAS */ + minCas = minCasCalc(&bankInfo[0], &bankInfo[2], busClk, forcedCl); + if (0 == minCas) + { + mvOsOutput("Dram: Warn: Could not find CAS compatible to SysClk %dMhz\n", + (busClk / 1000000)); + + minCas = DDR2_CL_4; /* Continue with this CAS */ + mvOsOutput("Set default CAS latency 4\n"); + } + + /* calc SDRAM_CONFIG_REG and save it to temp register */ + temp = sdramConfigRegCalc(&bankInfo[0],&bankInfo[2], busClk); + if(-1 == temp) + { + mvOsOutput("Dram: ERR. sdramConfigRegCalc failed !!!\n"); + return MV_ERROR; + } + + /* check if ECC is enabled by the user */ + if(eccDisable) + { + /* turn off ECC*/ + temp &= ~BIT18; + } + DB(mvOsPrintf("Dram: sdramConfigRegCalc - %x\n",temp);) + MV_REG_WRITE(DRAM_BUF_REG1, temp); + + /* calc SDRAM_MODE_REG and save it to temp register */ + temp = sdramModeRegCalc(minCas); + if(-1 == temp) + { + mvOsOutput("Dram: ERR. sdramModeRegCalc failed !!!\n"); + return MV_ERROR; + } + DB(mvOsPrintf("Dram: sdramModeRegCalc - %x\n",temp);) + MV_REG_WRITE(DRAM_BUF_REG2, temp); + + /* calc SDRAM_EXTENDED_MODE_REG and save it to temp register */ + temp = sdramExtModeRegCalc(&bankInfo[0], busClk); + if(-1 == temp) + { + mvOsOutput("Dram: ERR. sdramExtModeRegCalc failed !!!\n"); + return MV_ERROR; + } + DB(mvOsPrintf("Dram: sdramExtModeRegCalc - %x\n",temp);) + MV_REG_WRITE(DRAM_BUF_REG10, temp); + + /* calc D_UNIT_CONTROL_LOW and save it to temp register */ + TTMode = MV_FALSE; + DB(mvOsPrintf("Dram: numOfAllDevices = %x\n",numOfAllDevices);) + if( (numOfAllDevices > 9) && (bankInfo[0].registeredAddrAndControlInputs == MV_FALSE) ) + { + if ( ( (numOfAllDevices > 9) && (busClk > MV_BOARD_SYSCLK_200MHZ) ) || + (numOfAllDevices > 18) ) + { + mvOsOutput("Enable 2T "); + TTMode = MV_TRUE; + } + } + + temp = dunitCtrlLowRegCalc(&bankInfo[0], minCas, busClk, TTMode ); + if(-1 == temp) + { + mvOsOutput("Dram: ERR. dunitCtrlLowRegCalc failed !!!\n"); + return MV_ERROR; + } + DB(mvOsPrintf("Dram: dunitCtrlLowRegCalc - %x\n",temp);) + MV_REG_WRITE(DRAM_BUF_REG3, temp); + + /* calc D_UNIT_CONTROL_HIGH and save it to temp register */ + temp = dunitCtrlHighRegCalc(&bankInfo[0], busClk); + if(-1 == temp) + { + mvOsOutput("Dram: ERR. dunitCtrlHighRegCalc failed !!!\n"); + return MV_ERROR; + } + DB(mvOsPrintf("Dram: dunitCtrlHighRegCalc - %x\n",temp);) + /* check if ECC is enabled by the user */ + if(eccDisable) + { + /* turn off sample stage if no ecc */ + temp &= ~SDRAM__D2P_EN;; + } + MV_REG_WRITE(DRAM_BUF_REG13, temp); + + /* calc SDRAM_ADDR_CTRL_REG and save it to temp register */ + temp = sdramAddrCtrlRegCalc(&bankInfo[0],&bankInfo[2]); + if(-1 == temp) + { + mvOsOutput("Dram: ERR. sdramAddrCtrlRegCalc failed !!!\n"); + return MV_ERROR; + } + DB(mvOsPrintf("Dram: sdramAddrCtrlRegCalc - %x\n",temp);) + MV_REG_WRITE(DRAM_BUF_REG4, temp); + + /* calc SDRAM_TIMING_CTRL_LOW_REG and save it to temp register */ + temp = sdramTimeCtrlLowRegCalc(&bankInfo[0], minCas, busClk); + if(-1 == temp) + { + mvOsOutput("Dram: ERR. sdramTimeCtrlLowRegCalc failed !!!\n"); + return MV_ERROR; + } + DB(mvOsPrintf("Dram: sdramTimeCtrlLowRegCalc - %x\n",temp);) + MV_REG_WRITE(DRAM_BUF_REG5, temp); + + /* calc SDRAM_TIMING_CTRL_HIGH_REG and save it to temp register */ + temp = sdramTimeCtrlHighRegCalc(&bankInfo[0], busClk); + if(-1 == temp) + { + mvOsOutput("Dram: ERR. sdramTimeCtrlHighRegCalc failed !!!\n"); + return MV_ERROR; + } + DB(mvOsPrintf("Dram: sdramTimeCtrlHighRegCalc - %x\n",temp);) + MV_REG_WRITE(DRAM_BUF_REG6, temp); + + sdramDDr2OdtConfig(bankInfo); + + /* calc DDR2_SDRAM_TIMING_LOW_REG and save it to temp register */ + temp = sdramDdr2TimeLoRegCalc(minCas); + if(-1 == temp) + { + mvOsOutput("Dram: ERR. sdramDdr2TimeLoRegCalc failed !!!\n"); + return MV_ERROR; + } + DB(mvOsPrintf("Dram: sdramDdr2TimeLoRegCalc - %x\n",temp);) + MV_REG_WRITE(DRAM_BUF_REG11, temp); + + /* calc DDR2_SDRAM_TIMING_HIGH_REG and save it to temp register */ + temp = sdramDdr2TimeHiRegCalc(minCas); + if(-1 == temp) + { + mvOsOutput("Dram: ERR. sdramDdr2TimeHiRegCalc failed !!!\n"); + return MV_ERROR; + } + DB(mvOsPrintf("Dram: sdramDdr2TimeHiRegCalc - %x\n",temp);) + MV_REG_WRITE(DRAM_BUF_REG12, temp); +#endif + + /* Note that DDR SDRAM Address/Control and Data pad calibration */ + /* settings is done in mvSdramIfConfig.s */ + + return MV_OK; +} + + +/******************************************************************************* +* mvDramIfBankBaseGet - Get DRAM interface bank base. +* +* DESCRIPTION: +* This function returns the 32 bit base address of a given DRAM bank. +* +* INPUT: +* bankNum - Bank number. +* +* OUTPUT: +* None. +* +* RETURN: +* DRAM bank size. If bank is disabled or paramter is invalid, the +* function returns -1. +* +*******************************************************************************/ +MV_U32 mvDramIfBankBaseGet(MV_U32 bankNum) +{ + DB(mvOsPrintf("Dram: mvDramIfBankBaseGet Bank %d base addr is %x \n", + bankNum, mvCpuIfTargetWinBaseLowGet(SDRAM_CS0 + bankNum))); + return mvCpuIfTargetWinBaseLowGet(SDRAM_CS0 + bankNum); +} + +/******************************************************************************* +* mvDramIfBankSizeGet - Get DRAM interface bank size. +* +* DESCRIPTION: +* This function returns the size of a given DRAM bank. +* +* INPUT: +* bankNum - Bank number. +* +* OUTPUT: +* None. +* +* RETURN: +* DRAM bank size. If bank is disabled the function return '0'. In case +* or paramter is invalid, the function returns -1. +* +*******************************************************************************/ +MV_U32 mvDramIfBankSizeGet(MV_U32 bankNum) +{ + DB(mvOsPrintf("Dram: mvDramIfBankSizeGet Bank %d size is %x \n", + bankNum, mvCpuIfTargetWinSizeGet(SDRAM_CS0 + bankNum))); + return mvCpuIfTargetWinSizeGet(SDRAM_CS0 + bankNum); +} + + +/******************************************************************************* +* mvDramIfSizeGet - Get DRAM interface total size. +* +* DESCRIPTION: +* This function get the DRAM total size. +* +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* DRAM total size. In case or paramter is invalid, the function +* returns -1. +* +*******************************************************************************/ +MV_U32 mvDramIfSizeGet(MV_VOID) +{ + MV_U32 size = 0, i; + + for(i = 0; i < MV_DRAM_MAX_CS; i++) + size += mvDramIfBankSizeGet(i); + + DB(mvOsPrintf("Dram: mvDramIfSizeGet size is %x \n",size)); + return size; +} + +/******************************************************************************* +* mvDramIfSingleBitErrThresholdSet - Set single bit ECC threshold. +* +* DESCRIPTION: +* The ECC single bit error threshold is the number of single bit +* errors to happen before the Dunit generates an interrupt. +* This function set single bit ECC threshold. +* +* INPUT: +* threshold - threshold. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_BAD_PARAM if threshold is to big, MV_OK otherwise. +* +*******************************************************************************/ +MV_STATUS mvDramIfSingleBitErrThresholdSet(MV_U32 threshold) +{ + MV_U32 regVal; + + if (threshold > SECR_THRECC_MAX) + { + return MV_BAD_PARAM; + } + + regVal = MV_REG_READ(SDRAM_ECC_CONTROL_REG); + regVal &= ~SECR_THRECC_MASK; + regVal |= ((SECR_THRECC(threshold) & SECR_THRECC_MASK)); + MV_REG_WRITE(SDRAM_ECC_CONTROL_REG, regVal); + + return MV_OK; +} + +#ifndef MV_STATIC_DRAM_ON_BOARD +/******************************************************************************* +* minCasCalc - Calculate the Minimum CAS latency which can be used. +* +* DESCRIPTION: +* Calculate the minimum CAS latency that can be used, base on the DRAM +* parameters and the SDRAM bus Clock freq. +* +* INPUT: +* busClk - the DRAM bus Clock. +* pBankInfo - bank info parameters. +* forcedCl - Forced CAS Latency multiplied by 10. If equal to zero, do not force. +* +* OUTPUT: +* None +* +* RETURN: +* The minimum CAS Latency. The function returns 0 if max CAS latency +* supported by banks is incompatible with system bus clock frequancy. +* +*******************************************************************************/ + +static MV_U32 minCasCalc(MV_DRAM_BANK_INFO *pBankInfo,MV_DRAM_BANK_INFO *pBankInfo2, MV_U32 busClk, MV_U32 forcedCl) +{ + MV_U32 count = 1, j; + MV_U32 busClkPs = 1000000000 / (busClk / 1000); /* in ps units */ + MV_U32 startBit, stopBit; + MV_U32 minCas0 = 0, minCas2 = 0; + + + /* DDR 2: + *******-******-******-******-******-******-******-******* + * bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 * + *******-******-******-******-******-******-******-******* + CAS = * TBD | TBD | 5 | 4 | 3 | 2 | TBD | TBD * + Disco VI= * TBD | TBD | 5 | 4 | 3 | TBD | TBD | TBD * + Disco Duo= * TBD | 6 | 5 | 4 | 3 | TBD | TBD | TBD * + *********************************************************/ + + + /* If we are asked to use the forced CAL we change the suported CAL to be forcedCl only */ + if (forcedCl) + { + mvOsOutput("DRAM: Using forced CL %d.%d\n", (forcedCl / 10), (forcedCl % 10)); + + if (forcedCl == 30) + pBankInfo->suportedCasLatencies = 0x08; + else if (forcedCl == 40) + pBankInfo->suportedCasLatencies = 0x10; + else if (forcedCl == 50) + pBankInfo->suportedCasLatencies = 0x20; + else if (forcedCl == 60) + pBankInfo->suportedCasLatencies = 0x40; + else + { + mvOsPrintf("Forced CL %d.%d not supported. Set default CL 4\n", + (forcedCl / 10), (forcedCl % 10)); + pBankInfo->suportedCasLatencies = 0x10; + } + + return pBankInfo->suportedCasLatencies; + } + + /* go over the supported cas mask from Max Cas down and check if the */ + /* SysClk stands in its time requirments. */ + + DB(mvOsPrintf("Dram: minCasCalc supported mask = %x busClkPs = %x \n", + pBankInfo->suportedCasLatencies,busClkPs )); + count = 1; + for(j = 7; j > 0; j--) + { + if((pBankInfo->suportedCasLatencies >> j) & BIT0 ) + { + /* Reset the bits for CL incompatible for the sysClk */ + switch (count) + { + case 1: + if (pBankInfo->minCycleTimeAtMaxCasLatPs > busClkPs) + pBankInfo->suportedCasLatencies &= ~(BIT0 << j); + count++; + break; + case 2: + if (pBankInfo->minCycleTimeAtMaxCasLatMinus1Ps > busClkPs) + pBankInfo->suportedCasLatencies &= ~(BIT0 << j); + count++; + break; + case 3: + if (pBankInfo->minCycleTimeAtMaxCasLatMinus2Ps > busClkPs) + pBankInfo->suportedCasLatencies &= ~(BIT0 << j); + count++; + break; + default: + pBankInfo->suportedCasLatencies &= ~(BIT0 << j); + break; + } + } + } + + DB(mvOsPrintf("Dram: minCasCalc support = %x (after SysCC calc)\n", + pBankInfo->suportedCasLatencies )); + + count = 1; + DB(mvOsPrintf("Dram2: minCasCalc supported mask = %x busClkPs = %x \n", + pBankInfo2->suportedCasLatencies,busClkPs )); + for(j = 7; j > 0; j--) + { + if((pBankInfo2->suportedCasLatencies >> j) & BIT0 ) + { + /* Reset the bits for CL incompatible for the sysClk */ + switch (count) + { + case 1: + if (pBankInfo2->minCycleTimeAtMaxCasLatPs > busClkPs) + pBankInfo2->suportedCasLatencies &= ~(BIT0 << j); + count++; + break; + case 2: + if (pBankInfo2->minCycleTimeAtMaxCasLatMinus1Ps > busClkPs) + pBankInfo2->suportedCasLatencies &= ~(BIT0 << j); + count++; + break; + case 3: + if (pBankInfo2->minCycleTimeAtMaxCasLatMinus2Ps > busClkPs) + pBankInfo2->suportedCasLatencies &= ~(BIT0 << j); + count++; + break; + default: + pBankInfo2->suportedCasLatencies &= ~(BIT0 << j); + break; + } + } + } + + DB(mvOsPrintf("Dram2: minCasCalc support = %x (after SysCC calc)\n", + pBankInfo2->suportedCasLatencies )); + + startBit = 3; /* DDR2 support CL start with CL3 (bit 3) */ + stopBit = 6; /* DDR2 support CL stops with CL6 (bit 6) */ + + for(j = startBit; j <= stopBit ; j++) + { + if((pBankInfo->suportedCasLatencies >> j) & BIT0 ) + { + DB(mvOsPrintf("Dram: minCasCalc choose CAS %x \n",(BIT0 << j))); + minCas0 = (BIT0 << j); + break; + } + } + + for(j = startBit; j <= stopBit ; j++) + { + if((pBankInfo2->suportedCasLatencies >> j) & BIT0 ) + { + DB(mvOsPrintf("Dram: minCasCalc choose CAS %x \n",(BIT0 << j))); + minCas2 = (BIT0 << j); + break; + } + } + + if (minCas2 > minCas0) + return minCas2; + else + return minCas0; + + return 0; +} + +/******************************************************************************* +* sdramConfigRegCalc - Calculate sdram config register +* +* DESCRIPTION: Calculate sdram config register optimized value based +* on the bank info parameters. +* +* INPUT: +* busClk - the DRAM bus Clock. +* pBankInfo - sdram bank parameters +* +* OUTPUT: +* None +* +* RETURN: +* sdram config reg value. +* +*******************************************************************************/ +static MV_U32 sdramConfigRegCalc(MV_DRAM_BANK_INFO *pBankInfo,MV_DRAM_BANK_INFO *pBankInfo2, MV_U32 busClk) +{ + MV_U32 sdramConfig = 0; + MV_U32 refreshPeriod; + + busClk /= 1000000; /* we work with busClk in MHz */ + + sdramConfig = MV_REG_READ(SDRAM_CONFIG_REG); + + /* figure out the memory refresh internal */ + switch (pBankInfo->refreshInterval & 0xf) + { + case 0x0: /* refresh period is 15.625 usec */ + refreshPeriod = 15625; + break; + case 0x1: /* refresh period is 3.9 usec */ + refreshPeriod = 3900; + break; + case 0x2: /* refresh period is 7.8 usec */ + refreshPeriod = 7800; + break; + case 0x3: /* refresh period is 31.3 usec */ + refreshPeriod = 31300; + break; + case 0x4: /* refresh period is 62.5 usec */ + refreshPeriod = 62500; + break; + case 0x5: /* refresh period is 125 usec */ + refreshPeriod = 125000; + break; + default: /* refresh period undefined */ + mvOsPrintf("Dram: ERR. DRAM refresh period is unknown!\n"); + return -1; + } + + /* Now the refreshPeriod is in register format value */ + refreshPeriod = (busClk * refreshPeriod) / 1000; + + DB(mvOsPrintf("Dram: sdramConfigRegCalc calculated refresh interval %0x\n", + refreshPeriod)); + + /* make sure the refresh value is only 14 bits */ + if(refreshPeriod > SDRAM_REFRESH_MAX) + { + refreshPeriod = SDRAM_REFRESH_MAX; + DB(mvOsPrintf("Dram: sdramConfigRegCalc adjusted refresh interval %0x\n", + refreshPeriod)); + } + + /* Clear the refresh field */ + sdramConfig &= ~SDRAM_REFRESH_MASK; + + /* Set new value to refresh field */ + sdramConfig |= (refreshPeriod & SDRAM_REFRESH_MASK); + + /* registered DRAM ? */ + if ( pBankInfo->registeredAddrAndControlInputs ) + { + /* it's registered DRAM, so set the reg. DRAM bit */ + sdramConfig |= SDRAM_REGISTERED; + DB(mvOsPrintf("DRAM Attribute: Registered address and control inputs.\n");) + } + + /* ECC and IERR support */ + sdramConfig &= ~SDRAM_ECC_MASK; /* Clear ECC field */ + sdramConfig &= ~SDRAM_IERR_MASK; /* Clear IErr field */ + + if ( pBankInfo->errorCheckType ) + { + sdramConfig |= SDRAM_ECC_EN; + sdramConfig |= SDRAM_IERR_REPORTE; + DB(mvOsPrintf("Dram: mvDramIfDetect Enabling ECC\n")); + } + else + { + sdramConfig |= SDRAM_ECC_DIS; + sdramConfig |= SDRAM_IERR_IGNORE; + DB(mvOsPrintf("Dram: mvDramIfDetect Disabling ECC!\n")); + } + /* Set static default settings */ + sdramConfig |= SDRAM_CONFIG_DV; + + DB(mvOsPrintf("Dram: sdramConfigRegCalc set sdramConfig to 0x%x\n", + sdramConfig)); + + return sdramConfig; +} + +/******************************************************************************* +* sdramModeRegCalc - Calculate sdram mode register +* +* DESCRIPTION: Calculate sdram mode register optimized value based +* on the bank info parameters and the minCas. +* +* INPUT: +* minCas - minimum CAS supported. +* +* OUTPUT: +* None +* +* RETURN: +* sdram mode reg value. +* +*******************************************************************************/ +static MV_U32 sdramModeRegCalc(MV_U32 minCas) +{ + MV_U32 sdramMode; + + sdramMode = MV_REG_READ(SDRAM_MODE_REG); + + /* Clear CAS Latency field */ + sdramMode &= ~SDRAM_CL_MASK; + + DB(mvOsPrintf("DRAM CAS Latency ");) + + switch (minCas) + { + case DDR2_CL_3: + sdramMode |= SDRAM_DDR2_CL_3; + DB(mvOsPrintf("3.\n");) + break; + case DDR2_CL_4: + sdramMode |= SDRAM_DDR2_CL_4; + DB(mvOsPrintf("4.\n");) + break; + case DDR2_CL_5: + sdramMode |= SDRAM_DDR2_CL_5; + DB(mvOsPrintf("5.\n");) + break; + case DDR2_CL_6: + sdramMode |= SDRAM_DDR2_CL_6; + DB(mvOsPrintf("6.\n");) + break; + default: + mvOsOutput("\nsdramModeRegCalc ERROR: Max. CL out of range\n"); + return -1; + } + + DB(mvOsPrintf("\nsdramModeRegCalc register 0x%x\n", sdramMode )); + + return sdramMode; +} +/******************************************************************************* +* sdramExtModeRegCalc - Calculate sdram Extended mode register +* +* DESCRIPTION: +* Return sdram Extended mode register value based +* on the bank info parameters and bank presence. +* +* INPUT: +* pBankInfo - sdram bank parameters +* busClk - DRAM frequency +* +* OUTPUT: +* None +* +* RETURN: +* sdram Extended mode reg value. +* +*******************************************************************************/ +static MV_U32 sdramExtModeRegCalc(MV_DRAM_BANK_INFO *pBankInfo, MV_U32 busClk) +{ + MV_U32 populateBanks = 0; + int bankNum; + + /* Represent the populate banks in binary form */ + for(bankNum = 0; bankNum < MV_DRAM_MAX_CS; bankNum++) + { + if (0 != pBankInfo[bankNum].size) + { + populateBanks |= (1 << bankNum); + } + } + + switch(populateBanks) + { + case(BANK_PRESENT_CS0): + case(BANK_PRESENT_CS0_CS1): + return DDR_SDRAM_EXT_MODE_CS0_CS1_DV; + + case(BANK_PRESENT_CS0_CS2): + case(BANK_PRESENT_CS0_CS1_CS2): + case(BANK_PRESENT_CS0_CS2_CS3): + case(BANK_PRESENT_CS0_CS2_CS3_CS4): + if (busClk >= MV_BOARD_SYSCLK_267MHZ) + return DDR_SDRAM_EXT_MODE_FAST_CS0_CS1_CS2_CS3_DV; + else + return DDR_SDRAM_EXT_MODE_CS0_CS1_CS2_CS3_DV; + + default: + mvOsOutput("sdramExtModeRegCalc: Invalid DRAM bank presence\n"); + return -1; + } + return 0; +} + +/******************************************************************************* +* dunitCtrlLowRegCalc - Calculate sdram dunit control low register +* +* DESCRIPTION: Calculate sdram dunit control low register optimized value based +* on the bank info parameters and the minCas. +* +* INPUT: +* pBankInfo - sdram bank parameters +* minCas - minimum CAS supported. +* +* OUTPUT: +* None +* +* RETURN: +* sdram dunit control low reg value. +* +*******************************************************************************/ +static MV_U32 dunitCtrlLowRegCalc(MV_DRAM_BANK_INFO *pBankInfo, MV_U32 minCas, MV_U32 busClk, MV_STATUS TTMode) +{ + MV_U32 dunitCtrlLow, cl; + MV_U32 sbOutR[4]={3,5,7,9} ; + MV_U32 sbOutU[4]={1,3,5,7} ; + + dunitCtrlLow = MV_REG_READ(SDRAM_DUNIT_CTRL_REG); + + DB(mvOsPrintf("Dram: dunitCtrlLowRegCalc\n")); + + /* Clear StBurstOutDel field */ + dunitCtrlLow &= ~SDRAM_SB_OUT_MASK; + + /* Clear StBurstInDel field */ + dunitCtrlLow &= ~SDRAM_SB_IN_MASK; + + /* Clear CtrlPos field */ + dunitCtrlLow &= ~SDRAM_CTRL_POS_MASK; + + /* Clear 2T field */ + dunitCtrlLow &= ~SDRAM_2T_MASK; + if (TTMode == MV_TRUE) + { + dunitCtrlLow |= SDRAM_2T_MODE; + } + + /* For proper sample of read data set the Dunit Control register's */ + /* stBurstInDel bits [27:24] */ + /* 200MHz - 267MHz None reg = CL + 1 */ + /* 200MHz - 267MHz reg = CL + 2 */ + /* > 267MHz None reg = CL + 2 */ + /* > 267MHz reg = CL + 3 */ + + /* For proper sample of read data set the Dunit Control register's */ + /* stBurstOutDel bits [23:20] */ + /********-********-********-********- + * CL=3 | CL=4 | CL=5 | CL=6 | + *********-********-********-********- + Not Reg. * 0001 | 0011 | 0101 | 0111 | + *********-********-********-********- + Registered * 0011 | 0101 | 0111 | 1001 | + *********-********-********-********/ + + /* Set Dunit Control low default value */ + dunitCtrlLow |= SDRAM_DUNIT_CTRL_LOW_DDR2_DV; + + switch (minCas) + { + case DDR2_CL_3: cl = 3; break; + case DDR2_CL_4: cl = 4; break; + case DDR2_CL_5: cl = 5; break; + case DDR2_CL_6: cl = 6; break; + default: + mvOsOutput("Dram: dunitCtrlLowRegCalc Max. CL out of range %d\n", minCas); + return -1; + } + + /* registerd DDR SDRAM? */ + if (pBankInfo->registeredAddrAndControlInputs == MV_TRUE) + { + dunitCtrlLow |= (sbOutR[cl-3]) << SDRAM_SB_OUT_DEL_OFFS; + } + else + { + dunitCtrlLow |= (sbOutU[cl-3]) << SDRAM_SB_OUT_DEL_OFFS; + } + + DB(mvOsPrintf("\n\ndunitCtrlLowRegCalc: CL = %d, frequencies=%d\n", cl, busClk)); + + if (busClk <= MV_BOARD_SYSCLK_267MHZ) + { + if (pBankInfo->registeredAddrAndControlInputs == MV_TRUE) + cl = cl + 2; + else + cl = cl + 1; + } + else + { + if (pBankInfo->registeredAddrAndControlInputs == MV_TRUE) + cl = cl + 3; + else + cl = cl + 2; + } + + DB(mvOsPrintf("dunitCtrlLowRegCalc: SDRAM_SB_IN_DEL_OFFS = %d \n", cl)); + dunitCtrlLow |= cl << SDRAM_SB_IN_DEL_OFFS; + + DB(mvOsPrintf("Dram: Reg dunit control low = %x\n", dunitCtrlLow )); + + return dunitCtrlLow; +} + +/******************************************************************************* +* dunitCtrlHighRegCalc - Calculate sdram dunit control high register +* +* DESCRIPTION: Calculate sdram dunit control high register optimized value based +* on the bus clock. +* +* INPUT: +* busClk - DRAM frequency. +* +* OUTPUT: +* None +* +* RETURN: +* sdram dunit control high reg value. +* +*******************************************************************************/ +static MV_U32 dunitCtrlHighRegCalc(MV_DRAM_BANK_INFO *pBankInfo, MV_U32 busClk) +{ + MV_U32 dunitCtrlHigh; + dunitCtrlHigh = MV_REG_READ(SDRAM_DUNIT_CTRL_HI_REG); + if(busClk > MV_BOARD_SYSCLK_300MHZ) + dunitCtrlHigh |= SDRAM__P2D_EN; + else + dunitCtrlHigh &= ~SDRAM__P2D_EN; + + if(busClk > MV_BOARD_SYSCLK_267MHZ) + dunitCtrlHigh |= (SDRAM__WR_MESH_DELAY_EN | SDRAM__PUP_ZERO_SKEW_EN | SDRAM__ADD_HALF_FCC_EN); + + /* If ECC support we turn on D2P sample */ + dunitCtrlHigh &= ~SDRAM__D2P_EN; /* Clear D2P bit */ + if (( pBankInfo->errorCheckType ) && (busClk > MV_BOARD_SYSCLK_267MHZ)) + dunitCtrlHigh |= SDRAM__D2P_EN; + + return dunitCtrlHigh; +} + +/******************************************************************************* +* sdramAddrCtrlRegCalc - Calculate sdram address control register +* +* DESCRIPTION: Calculate sdram address control register optimized value based +* on the bank info parameters and the minCas. +* +* INPUT: +* pBankInfo - sdram bank parameters +* +* OUTPUT: +* None +* +* RETURN: +* sdram address control reg value. +* +*******************************************************************************/ +static MV_U32 sdramAddrCtrlRegCalc(MV_DRAM_BANK_INFO *pBankInfo, MV_DRAM_BANK_INFO *pBankInfoDIMM1) +{ + MV_U32 addrCtrl = 0; + + if (pBankInfoDIMM1->size) + { + switch (pBankInfoDIMM1->sdramWidth) + { + case 4: /* memory is x4 */ + mvOsOutput("sdramAddrCtrlRegCalc: Error - x4 not supported!\n"); + return -1; + break; + case 8: /* memory is x8 */ + addrCtrl |= SDRAM_ADDRSEL_X8(2) | SDRAM_ADDRSEL_X8(3); + DB(mvOsPrintf("sdramAddrCtrlRegCalc: sdramAddrCtrlRegCalc SDRAM device DIMM2 width x8\n")); + break; + case 16: + addrCtrl |= SDRAM_ADDRSEL_X16(2) | SDRAM_ADDRSEL_X16(3); + DB(mvOsPrintf("sdramAddrCtrlRegCalc: sdramAddrCtrlRegCalc SDRAM device DIMM2 width x16\n")); + break; + default: /* memory width unsupported */ + mvOsOutput("sdramAddrCtrlRegCalc: ERR. DRAM chip width is unknown!\n"); + return -1; + } + } + + switch (pBankInfo->sdramWidth) + { + case 4: /* memory is x4 */ + mvOsOutput("sdramAddrCtrlRegCalc: Error - x4 not supported!\n"); + return -1; + break; + case 8: /* memory is x8 */ + addrCtrl |= SDRAM_ADDRSEL_X8(0) | SDRAM_ADDRSEL_X8(1); + DB(mvOsPrintf("sdramAddrCtrlRegCalc: sdramAddrCtrlRegCalc SDRAM device width x8\n")); + break; + case 16: + addrCtrl |= SDRAM_ADDRSEL_X16(0) | SDRAM_ADDRSEL_X16(1); + DB(mvOsPrintf("sdramAddrCtrlRegCalc: sdramAddrCtrlRegCalc SDRAM device width x16\n")); + break; + default: /* memory width unsupported */ + mvOsOutput("sdramAddrCtrlRegCalc: ERR. DRAM chip width is unknown!\n"); + return -1; + } + + /* Note that density is in MB units */ + switch (pBankInfo->deviceDensity) + { + case 256: /* 256 Mbit */ + DB(mvOsPrintf("DRAM Device Density 256Mbit\n")); + addrCtrl |= SDRAM_DSIZE_256Mb(0) | SDRAM_DSIZE_256Mb(1); + break; + case 512: /* 512 Mbit */ + DB(mvOsPrintf("DRAM Device Density 512Mbit\n")); + addrCtrl |= SDRAM_DSIZE_512Mb(0) | SDRAM_DSIZE_512Mb(1); + break; + case 1024: /* 1 Gbit */ + DB(mvOsPrintf("DRAM Device Density 1Gbit\n")); + addrCtrl |= SDRAM_DSIZE_1Gb(0) | SDRAM_DSIZE_1Gb(1); + break; + case 2048: /* 2 Gbit */ + DB(mvOsPrintf("DRAM Device Density 2Gbit\n")); + addrCtrl |= SDRAM_DSIZE_2Gb(0) | SDRAM_DSIZE_2Gb(1); + break; + default: + mvOsOutput("Dram: sdramAddrCtrl unsupported RAM-Device size %d\n", + pBankInfo->deviceDensity); + return -1; + } + + if (pBankInfoDIMM1->size) + { + switch (pBankInfoDIMM1->deviceDensity) + { + case 256: /* 256 Mbit */ + DB(mvOsPrintf("DIMM2: DRAM Device Density 256Mbit\n")); + addrCtrl |= SDRAM_DSIZE_256Mb(2) | SDRAM_DSIZE_256Mb(3); + break; + case 512: /* 512 Mbit */ + DB(mvOsPrintf("DIMM2: DRAM Device Density 512Mbit\n")); + addrCtrl |= SDRAM_DSIZE_512Mb(2) | SDRAM_DSIZE_512Mb(3); + break; + case 1024: /* 1 Gbit */ + DB(mvOsPrintf("DIMM2: DRAM Device Density 1Gbit\n")); + addrCtrl |= SDRAM_DSIZE_1Gb(2) | SDRAM_DSIZE_1Gb(3); + break; + case 2048: /* 2 Gbit */ + DB(mvOsPrintf("DIMM2: DRAM Device Density 2Gbit\n")); + addrCtrl |= SDRAM_DSIZE_2Gb(2) | SDRAM_DSIZE_2Gb(3); + break; + default: + mvOsOutput("DIMM2: Dram: sdramAddrCtrl unsupported RAM-Device size %d\n", + pBankInfoDIMM1->deviceDensity); + return -1; + } + } + /* SDRAM address control */ + DB(mvOsPrintf("Dram: setting sdram address control with: %x \n", addrCtrl)); + + return addrCtrl; +} + +/******************************************************************************* +* sdramTimeCtrlLowRegCalc - Calculate sdram timing control low register +* +* DESCRIPTION: +* This function calculates sdram timing control low register +* optimized value based on the bank info parameters and the minCas. +* +* INPUT: +* pBankInfo - sdram bank parameters +* minCas - minimum CAS supported. +* busClk - Bus clock +* +* OUTPUT: +* None +* +* RETURN: +* sdram timing control low reg value. +* +*******************************************************************************/ +static MV_U32 sdramTimeCtrlLowRegCalc(MV_DRAM_BANK_INFO *pBankInfo, MV_U32 minCas, MV_U32 busClk) +{ + MV_U32 tRp = 0; + MV_U32 tRrd = 0; + MV_U32 tRcd = 0; + MV_U32 tRas = 0; + MV_U32 tWr = 0; + MV_U32 tWtr = 0; + MV_U32 tRtp = 0; + MV_U32 timeCtrlLow = 0; + + MV_U32 bankNum; + + busClk = busClk / 1000000; /* In MHz */ + + /* Scan all DRAM banks to find maximum timing values */ + for (bankNum = 0; bankNum < MV_DRAM_MAX_CS; bankNum++) + { + tRp = MV_MAX(tRp, pBankInfo[bankNum].minRowPrechargeTime); + tRrd = MV_MAX(tRrd, pBankInfo[bankNum].minRowActiveToRowActive); + tRcd = MV_MAX(tRcd, pBankInfo[bankNum].minRasToCasDelay); + tRas = MV_MAX(tRas, pBankInfo[bankNum].minRasPulseWidth); + } + + /* Extract timing (in ns) from SPD value. We ignore the tenth ns part. */ + /* by shifting the data two bits right. */ + tRp = tRp >> 2; /* For example 0x50 -> 20ns */ + tRrd = tRrd >> 2; + tRcd = tRcd >> 2; + + /* Extract clock cycles from time parameter. We need to round up */ + tRp = ((busClk * tRp) / 1000) + (((busClk * tRp) % 1000) ? 1 : 0); + DB(mvOsPrintf("Dram Timing Low: tRp = %d ", tRp)); + tRrd = ((busClk * tRrd) / 1000) + (((busClk * tRrd) % 1000) ? 1 : 0); + /* JEDEC min reqeirments tRrd = 2 */ + if (tRrd < 2) + tRrd = 2; + DB(mvOsPrintf("tRrd = %d ", tRrd)); + tRcd = ((busClk * tRcd) / 1000) + (((busClk * tRcd) % 1000) ? 1 : 0); + DB(mvOsPrintf("tRcd = %d ", tRcd)); + tRas = ((busClk * tRas) / 1000) + (((busClk * tRas) % 1000) ? 1 : 0); + DB(mvOsPrintf("tRas = %d ", tRas)); + + /* tWr and tWtr is different for DDR1 and DDR2. tRtp is only for DDR2 */ + /* Scan all DRAM banks to find maximum timing values */ + for (bankNum = 0; bankNum < MV_DRAM_MAX_CS; bankNum++) + { + tWr = MV_MAX(tWr, pBankInfo[bankNum].minWriteRecoveryTime); + tWtr = MV_MAX(tWtr, pBankInfo[bankNum].minWriteToReadCmdDelay); + tRtp = MV_MAX(tRtp, pBankInfo[bankNum].minReadToPrechCmdDelay); + } + + /* Extract timing (in ns) from SPD value. We ignore the tenth ns */ + /* part by shifting the data two bits right. */ + tWr = tWr >> 2; /* For example 0x50 -> 20ns */ + tWtr = tWtr >> 2; + tRtp = tRtp >> 2; + /* Extract clock cycles from time parameter. We need to round up */ + tWr = ((busClk * tWr) / 1000) + (((busClk * tWr) % 1000) ? 1 : 0); + DB(mvOsPrintf("tWr = %d ", tWr)); + tWtr = ((busClk * tWtr) / 1000) + (((busClk * tWtr) % 1000) ? 1 : 0); + /* JEDEC min reqeirments tWtr = 2 */ + if (tWtr < 2) + tWtr = 2; + DB(mvOsPrintf("tWtr = %d ", tWtr)); + tRtp = ((busClk * tRtp) / 1000) + (((busClk * tRtp) % 1000) ? 1 : 0); + /* JEDEC min reqeirments tRtp = 2 */ + if (tRtp < 2) + tRtp = 2; + DB(mvOsPrintf("tRtp = %d ", tRtp)); + + /* Note: value of 0 in register means one cycle, 1 means two and so on */ + timeCtrlLow = (((tRp - 1) << SDRAM_TRP_OFFS) | + ((tRrd - 1) << SDRAM_TRRD_OFFS) | + ((tRcd - 1) << SDRAM_TRCD_OFFS) | + (((tRas - 1) << SDRAM_TRAS_OFFS) & SDRAM_TRAS_MASK)| + ((tWr - 1) << SDRAM_TWR_OFFS) | + ((tWtr - 1) << SDRAM_TWTR_OFFS) | + ((tRtp - 1) << SDRAM_TRTP_OFFS)); + + /* Check extended tRas bit */ + if ((tRas - 1) & BIT4) + timeCtrlLow |= (1 << SDRAM_EXT_TRAS_OFFS); + + return timeCtrlLow; +} + +/******************************************************************************* +* sdramTimeCtrlHighRegCalc - Calculate sdram timing control high register +* +* DESCRIPTION: +* This function calculates sdram timing control high register +* optimized value based on the bank info parameters and the bus clock. +* +* INPUT: +* pBankInfo - sdram bank parameters +* busClk - Bus clock +* +* OUTPUT: +* None +* +* RETURN: +* sdram timing control high reg value. +* +*******************************************************************************/ +static MV_U32 sdramTimeCtrlHighRegCalc(MV_DRAM_BANK_INFO *pBankInfo, MV_U32 busClk) +{ + MV_U32 tRfc; + MV_U32 timingHigh; + MV_U32 timeNs = 0; + MV_U32 bankNum; + + busClk = busClk / 1000000; /* In MHz */ + + /* Set DDR timing high register static configuration bits */ + timingHigh = MV_REG_READ(SDRAM_TIMING_CTRL_HIGH_REG); + + /* Set DDR timing high register default value */ + timingHigh |= SDRAM_TIMING_CTRL_HIGH_REG_DV; + + /* Clear tRfc field */ + timingHigh &= ~SDRAM_TRFC_MASK; + + /* Scan all DRAM banks to find maximum timing values */ + for (bankNum = 0; bankNum < MV_DRAM_MAX_CS; bankNum++) + { + timeNs = MV_MAX(timeNs, pBankInfo[bankNum].minRefreshToActiveCmd); + DB(mvOsPrintf("Dram: Timing High: minRefreshToActiveCmd = %d\n", + pBankInfo[bankNum].minRefreshToActiveCmd)); + } + if(busClk >= 333 && mvCtrlModelGet() == MV_78XX0_A1_REV) + { + timingHigh |= 0x1 << SDRAM_TR2W_W2R_OFFS; + } + + tRfc = ((busClk * timeNs) / 1000) + (((busClk * timeNs) % 1000) ? 1 : 0); + /* Note: value of 0 in register means one cycle, 1 means two and so on */ + DB(mvOsPrintf("Dram: Timing High: tRfc = %d\n", tRfc)); + timingHigh |= (((tRfc - 1) & SDRAM_TRFC_MASK) << SDRAM_TRFC_OFFS); + DB(mvOsPrintf("Dram: Timing High: tRfc = %d\n", tRfc)); + + /* SDRAM timing high */ + DB(mvOsPrintf("Dram: setting timing high with: %x \n", timingHigh)); + + return timingHigh; +} +/******************************************************************************* +* sdramDDr2OdtConfig - Set DRAM DDR2 On Die Termination registers. +* +* DESCRIPTION: +* This function config DDR2 On Die Termination (ODT) registers. +* +* INPUT: +* pBankInfo - bank info parameters. +* +* OUTPUT: +* None +* +* RETURN: +* None +*******************************************************************************/ +static void sdramDDr2OdtConfig(MV_DRAM_BANK_INFO *pBankInfo) +{ + MV_U32 populateBanks = 0; + MV_U32 odtCtrlLow, odtCtrlHigh, dunitOdtCtrl; + int bankNum; + + /* Represent the populate banks in binary form */ + for(bankNum = 0; bankNum < MV_DRAM_MAX_CS; bankNum++) + { + if (0 != pBankInfo[bankNum].size) + { + populateBanks |= (1 << bankNum); + } + } + + switch(populateBanks) + { + case(BANK_PRESENT_CS0): + case(BANK_PRESENT_CS0_CS1): + odtCtrlLow = DDR2_ODT_CTRL_LOW_CS0_CS1_DV; + odtCtrlHigh = DDR2_ODT_CTRL_HIGH_CS0_CS1_DV; + dunitOdtCtrl = DDR2_DUNIT_ODT_CTRL_CS0_CS1_DV; + break; + case(BANK_PRESENT_CS0_CS2): + case(BANK_PRESENT_CS0_CS1_CS2): + case(BANK_PRESENT_CS0_CS2_CS3): + case(BANK_PRESENT_CS0_CS2_CS3_CS4): + odtCtrlLow = DDR2_ODT_CTRL_LOW_CS0_CS1_CS2_CS3_DV; + odtCtrlHigh = DDR2_ODT_CTRL_HIGH_CS0_CS1_CS2_CS3_DV; + dunitOdtCtrl = DDR2_DUNIT_ODT_CTRL_CS0_CS1_CS2_CS3_DV; + break; + default: + DB(mvOsPrintf("sdramDDr2OdtConfig: Invalid DRAM bank presence\n")); + return; + } + /* DDR2 SDRAM ODT ctrl low */ + DB(mvOsPrintf("Dram: DDR2 setting ODT ctrl low with: %x \n", odtCtrlLow)); + MV_REG_WRITE(DRAM_BUF_REG7, odtCtrlLow); + + /* DDR2 SDRAM ODT ctrl high */ + DB(mvOsPrintf("Dram: DDR2 setting ODT ctrl high with: %x \n", odtCtrlHigh)); + MV_REG_WRITE(DRAM_BUF_REG8, odtCtrlHigh); + + /* DDR2 DUNIT ODT ctrl */ + if ( ((mvCtrlModelGet() == MV_78XX0_DEV_ID) && (mvCtrlRevGet() == MV_78XX0_Y0_REV)) || + (mvCtrlModelGet() == MV_76100_DEV_ID) || + (mvCtrlModelGet() == MV_78100_DEV_ID) || + (mvCtrlModelGet() == MV_78200_DEV_ID) ) + dunitOdtCtrl &= ~(BIT9|BIT8); /* Clear ODT always on */ + + DB(mvOsPrintf("DUNIT: DDR2 setting ODT ctrl with: %x \n", dunitOdtCtrl)); + MV_REG_WRITE(DRAM_BUF_REG9, dunitOdtCtrl); + return; +} +/******************************************************************************* +* sdramDdr2TimeLoRegCalc - Set DDR2 DRAM Timing Low registers. +* +* DESCRIPTION: +* This function config DDR2 DRAM Timing low registers. +* +* INPUT: +* minCas - minimum CAS supported. +* +* OUTPUT: +* None +* +* RETURN: +* DDR2 sdram timing low reg value. +*******************************************************************************/ +static MV_U32 sdramDdr2TimeLoRegCalc(MV_U32 minCas) +{ + MV_U8 cl = -1; + MV_U32 ddr2TimeLoReg; + + /* read and clear the feilds we are going to set */ + ddr2TimeLoReg = MV_REG_READ(SDRAM_DDR2_TIMING_LO_REG); + ddr2TimeLoReg &= ~(SD2TLR_TODT_ON_RD_MASK | + SD2TLR_TODT_OFF_RD_MASK | + SD2TLR_TODT_ON_CTRL_RD_MASK | + SD2TLR_TODT_OFF_CTRL_RD_MASK); + + if( minCas == DDR2_CL_3 ) + { + cl = 3; + } + else if( minCas == DDR2_CL_4 ) + { + cl = 4; + } + else if( minCas == DDR2_CL_5 ) + { + cl = 5; + } + else if( minCas == DDR2_CL_6 ) + { + cl = 6; + } + else + { + DB(mvOsPrintf("sdramDdr2TimeLoRegCalc: CAS latency %d unsupported. using CAS latency 4\n", + minCas)); + cl = 4; + } + + ddr2TimeLoReg |= ((cl-3) << SD2TLR_TODT_ON_RD_OFFS); + ddr2TimeLoReg |= ( cl << SD2TLR_TODT_OFF_RD_OFFS); + ddr2TimeLoReg |= ( cl << SD2TLR_TODT_ON_CTRL_RD_OFFS); + ddr2TimeLoReg |= ((cl+3) << SD2TLR_TODT_OFF_CTRL_RD_OFFS); + + /* DDR2 SDRAM timing low */ + DB(mvOsPrintf("Dram: DDR2 setting timing low with: %x \n", ddr2TimeLoReg)); + + return ddr2TimeLoReg; +} + +/******************************************************************************* +* sdramDdr2TimeHiRegCalc - Set DDR2 DRAM Timing High registers. +* +* DESCRIPTION: +* This function config DDR2 DRAM Timing high registers. +* +* INPUT: +* minCas - minimum CAS supported. +* +* OUTPUT: +* None +* +* RETURN: +* DDR2 sdram timing high reg value. +*******************************************************************************/ +static MV_U32 sdramDdr2TimeHiRegCalc(MV_U32 minCas) +{ + MV_U8 cl = -1; + MV_U32 ddr2TimeHiReg; + + /* read and clear the feilds we are going to set */ + ddr2TimeHiReg = MV_REG_READ(SDRAM_DDR2_TIMING_HI_REG); + ddr2TimeHiReg &= ~(SD2THR_TODT_ON_WR_MASK | + SD2THR_TODT_OFF_WR_MASK | + SD2THR_TODT_ON_CTRL_WR_MASK | + SD2THR_TODT_OFF_CTRL_WR_MASK); + + if( minCas == DDR2_CL_3 ) + { + cl = 3; + } + else if( minCas == DDR2_CL_4 ) + { + cl = 4; + } + else if( minCas == DDR2_CL_5 ) + { + cl = 5; + } + else if( minCas == DDR2_CL_6 ) + { + cl = 6; + } + else + { + mvOsOutput("sdramDdr2TimeHiRegCalc: CAS latency %d unsupported. using CAS latency 4\n", + minCas); + cl = 4; + } + + ddr2TimeHiReg |= ((cl-3) << SD2THR_TODT_ON_WR_OFFS); + ddr2TimeHiReg |= ( cl << SD2THR_TODT_OFF_WR_OFFS); + ddr2TimeHiReg |= ( cl << SD2THR_TODT_ON_CTRL_WR_OFFS); + ddr2TimeHiReg |= ((cl+3) << SD2THR_TODT_OFF_CTRL_WR_OFFS); + + /* DDR2 SDRAM timin high */ + DB(mvOsPrintf("Dram: DDR2 setting timing high with: %x \n", ddr2TimeHiReg)); + + return ddr2TimeHiReg; +} +#endif + +/******************************************************************************* +* mvDramIfCalGet - Get CAS Latency +* +* DESCRIPTION: +* This function get the CAS Latency. +* +* INPUT: +* None +* +* OUTPUT: +* None +* +* RETURN: +* CAS latency times 10 (to avoid using floating point). +* +*******************************************************************************/ +MV_U32 mvDramIfCalGet(void) +{ + MV_U32 sdramCasLat, casLatMask; + + casLatMask = (MV_REG_READ(SDRAM_MODE_REG) & SDRAM_CL_MASK); + + switch (casLatMask) + { + case SDRAM_DDR2_CL_3: + sdramCasLat = 30; + break; + case SDRAM_DDR2_CL_4: + sdramCasLat = 40; + break; + case SDRAM_DDR2_CL_5: + sdramCasLat = 50; + break; + case SDRAM_DDR2_CL_6: + sdramCasLat = 60; + break; + default: + mvOsOutput("mvDramIfCalGet: Err, unknown DDR2 CAL\n"); + return -1; + } + + return sdramCasLat; +} + + +/******************************************************************************* +* mvDramIfSelfRefreshSet - Put the dram in self refresh mode - +* +* DESCRIPTION: +* add support in power management. +* +* +* INPUT: +* None +* +* OUTPUT: +* None +* +* RETURN: +* None +* +*******************************************************************************/ + +MV_VOID mvDramIfSelfRefreshSet() +{ + MV_U32 operReg; + + operReg = MV_REG_READ(SDRAM_OPERATION_REG); + MV_REG_WRITE(SDRAM_OPERATION_REG ,operReg |SDRAM_CMD_SLF_RFRSH); + /* Read until register is reset to 0 */ + while(MV_REG_READ(SDRAM_OPERATION_REG)); +} +/******************************************************************************* +* mvDramIfDimGetSPDversion - return DIMM SPD version. +* +* DESCRIPTION: +* This function prints the DRAM controller information. +* +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* None. +* +*******************************************************************************/ +static void mvDramIfDimGetSPDversion(MV_U32 *pMajor, MV_U32 *pMinor, MV_U32 bankNum) +{ + MV_DIMM_INFO dimmInfo; + if (bankNum >= MV_DRAM_MAX_CS ) + { + DB(mvOsPrintf("Dram: mvDramIfDimGetSPDversion bad params \n")); + return ; + } + memset(&dimmInfo,0,sizeof(dimmInfo)); + if ( MV_OK != dimmSpdGet((MV_U32)(bankNum/2), &dimmInfo)) + { + DB(mvOsPrintf("Dram: ERR dimmSpdGet failed to get dimm info \n")); + return ; + } + *pMajor = dimmInfo.spdRawData[DIMM_SPD_VERSION]/10; + *pMinor = dimmInfo.spdRawData[DIMM_SPD_VERSION]%10; +} +/******************************************************************************* +* mvDramIfShow - Show DRAM controller information. +* +* DESCRIPTION: +* This function prints the DRAM controller information. +* +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* None. +* +*******************************************************************************/ +void mvDramIfShow(void) +{ + int i, sdramCasLat, sdramCsSize; + MV_U32 Major=0, Minor=0; + + mvOsOutput("DRAM Controller info:\n"); + + mvOsOutput("Total DRAM "); + mvSizePrint(mvDramIfSizeGet()); + mvOsOutput("\n"); + + for(i = 0; i < MV_DRAM_MAX_CS; i++) + { + sdramCsSize = mvDramIfBankSizeGet(i); + if (sdramCsSize) + { + if (0 == (i & 1)) + { + mvDramIfDimGetSPDversion(&Major, &Minor,i); + mvOsOutput("DIMM %d version %d.%d\n", i/2, Major, Minor); + } + mvOsOutput("\tDRAM CS[%d] ", i); + mvSizePrint(sdramCsSize); + mvOsOutput("\n"); + } + } + sdramCasLat = mvDramIfCalGet(); + + if (MV_REG_READ(SDRAM_CONFIG_REG) & SDRAM_ECC_EN) + { + mvOsOutput("ECC enabled, "); + } + else + { + mvOsOutput("ECC Disabled, "); + } + + if (MV_REG_READ(SDRAM_CONFIG_REG) & SDRAM_REGISTERED) + { + mvOsOutput("Registered DIMM\n"); + } + else + { + mvOsOutput("Non registered DIMM\n"); + } + + mvOsOutput("Configured CAS Latency %d.%d\n", sdramCasLat/10, sdramCasLat%10); +} +/******************************************************************************* +* mvDramIfGetFirstCS - find the DRAM bank on the lower address +* +* +* DESCRIPTION: +* This function return the fisrt CS on address 0 +* +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* SDRAM_CS0 or SDRAM_CS2 +* +*******************************************************************************/ +MV_U32 mvDramIfGetFirstCS(void) +{ + MV_DRAM_BANK_INFO bankInfo[MV_DRAM_MAX_CS]; + + if (DRAM_CS_Order[0] == N_A) + { + mvDramBankInfoGet(SDRAM_CS0, &bankInfo[SDRAM_CS0]); +#ifdef MV_INCLUDE_SDRAM_CS2 + mvDramBankInfoGet(SDRAM_CS2, &bankInfo[SDRAM_CS2]); +#endif + +#ifdef MV_INCLUDE_SDRAM_CS2 + if (bankInfo[SDRAM_CS0].size < bankInfo[SDRAM_CS2].size) + { + DRAM_CS_Order[0] = SDRAM_CS2; + DRAM_CS_Order[1] = SDRAM_CS3; + DRAM_CS_Order[2] = SDRAM_CS0; + DRAM_CS_Order[3] = SDRAM_CS1; + + return SDRAM_CS2; + } +#endif + DRAM_CS_Order[0] = SDRAM_CS0; + DRAM_CS_Order[1] = SDRAM_CS1; +#ifdef MV_INCLUDE_SDRAM_CS2 + DRAM_CS_Order[2] = SDRAM_CS2; + DRAM_CS_Order[3] = SDRAM_CS3; +#endif + return SDRAM_CS0; + } + return DRAM_CS_Order[0]; +} +/******************************************************************************* +* mvDramIfGetCSorder - +* +* +* DESCRIPTION: +* This function return the fisrt CS on address 0 +* +* INPUT: +* CS number. +* +* OUTPUT: +* CS order. +* +* RETURN: +* SDRAM_CS0 or SDRAM_CS2 +* +* NOTE: mvDramIfGetFirstCS must be caled before this subroutine +*******************************************************************************/ +MV_U32 mvDramIfGetCSorder(MV_U32 csOrder ) +{ + return DRAM_CS_Order[csOrder]; +} + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr2/mvDramIf.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr2/mvDramIf.h new file mode 100644 index 0000000..23f2e54 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr2/mvDramIf.h @@ -0,0 +1,172 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + + +#ifndef __INCmvDramIfh +#define __INCmvDramIfh + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* includes */ +#include "ddr2/mvDramIfRegs.h" +#include "ddr2/mvDramIfConfig.h" +#include "ctrlEnv/mvCtrlEnvLib.h" + +/* defines */ +/* DRAM Timing parameters */ +#define SDRAM_TWR 15 /* ns tWr */ +#define SDRAM_TRFC_64_512M_AT_200MHZ 70 /* ns tRfc for dens 64-512 @ 200MHz */ +#define SDRAM_TRFC_64_512M 75 /* ns tRfc for dens 64-512 */ +#define SDRAM_TRFC_1G 120 /* ns tRfc for dens 1GB */ +#define SDRAM_TR2R_CYC 1 /* cycle for tR2r */ + +#define CAL_AUTO_DETECT 0 /* Do not force CAS latancy (mvDramIfDetect) */ +#define ECC_DISABLE 1 /* Force ECC to Disable */ +#define ECC_ENABLE 0 /* Force ECC to ENABLE */ +/* typedefs */ + +/* enumeration for memory types */ +typedef enum _mvMemoryType +{ + MEM_TYPE_SDRAM, + MEM_TYPE_DDR1, + MEM_TYPE_DDR2 +}MV_MEMORY_TYPE; + +/* enumeration for DDR2 supported CAS Latencies */ +typedef enum _mvDimmDdr2Cas +{ + DDR2_CL_3 = 0x08, + DDR2_CL_4 = 0x10, + DDR2_CL_5 = 0x20, + DDR2_CL_6 = 0x40, + DDR2_CL_FAULT +} MV_DIMM_DDR2_CAS; + + +typedef struct _mvDramBankInfo +{ + MV_MEMORY_TYPE memoryType; /* DDR1, DDR2 or SDRAM */ + + /* DIMM dimensions */ + MV_U32 numOfRowAddr; + MV_U32 numOfColAddr; + MV_U32 dataWidth; + MV_U32 errorCheckType; /* ECC , PARITY..*/ + MV_U32 sdramWidth; /* 4,8,16 or 32 */ + MV_U32 errorCheckDataWidth; /* 0 - no, 1 - Yes */ + MV_U32 burstLengthSupported; + MV_U32 numOfBanksOnEachDevice; + MV_U32 suportedCasLatencies; + MV_U32 refreshInterval; + + /* DIMM timing parameters */ + MV_U32 minCycleTimeAtMaxCasLatPs; + MV_U32 minCycleTimeAtMaxCasLatMinus1Ps; + MV_U32 minCycleTimeAtMaxCasLatMinus2Ps; + MV_U32 minRowPrechargeTime; + MV_U32 minRowActiveToRowActive; + MV_U32 minRasToCasDelay; + MV_U32 minRasPulseWidth; + MV_U32 minWriteRecoveryTime; /* DDR2 only */ + MV_U32 minWriteToReadCmdDelay; /* DDR2 only */ + MV_U32 minReadToPrechCmdDelay; /* DDR2 only */ + MV_U32 minRefreshToActiveCmd; /* DDR2 only */ + + /* Parameters calculated from the extracted DIMM information */ + MV_U32 size; + MV_U32 deviceDensity; /* 16,64,128,256 or 512 Mbit */ + MV_U32 numberOfDevices; + + /* DIMM attributes (MV_TRUE for yes) */ + MV_BOOL registeredAddrAndControlInputs; + MV_BOOL registeredDQMBinputs; + +}MV_DRAM_BANK_INFO; + +#include "ddr2/spd/mvSpd.h" + +/* mvDramIf.h API list */ +MV_VOID mvDramIfBasicAsmInit(MV_VOID); +MV_STATUS mvDramIfDetect(MV_U32 forcedCl, MV_BOOL eccDisable); +MV_VOID _mvDramIfConfig(int entryNum); + +MV_U32 mvDramIfBankSizeGet(MV_U32 bankNum); +MV_U32 mvDramIfBankBaseGet(MV_U32 bankNum); +MV_U32 mvDramIfSizeGet(MV_VOID); +MV_U32 mvDramIfCalGet(void); +MV_STATUS mvDramIfSingleBitErrThresholdSet(MV_U32 threshold); +MV_VOID mvDramIfSelfRefreshSet(void); +void mvDramIfShow(void); +MV_U32 mvDramIfGetFirstCS(void); +MV_U32 mvDramIfGetCSorder(MV_U32 csOrder ); +MV_U32 mvDramCsSizeGet(MV_U32 csNum); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __INCmvDramIfh */ diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr2/mvDramIfBasicInit.S b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr2/mvDramIfBasicInit.S new file mode 100644 index 0000000..7672381 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr2/mvDramIfBasicInit.S @@ -0,0 +1,986 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#define _ASMLANGUAGE +#define MV_ASMLANGUAGE +#include "mvSysHwConfig.h" +#include "mvOsAsm.h" +#include "boardEnv/mvBoardEnvSpec.h" +#include "ctrlEnv/sys/mvCpuIfRegs.h" +#include "mvDramIfConfig.h" +#include "mvDramIfRegs.h" +#include "pex/mvPexRegs.h" +#include "ctrlEnv/mvCtrlEnvSpec.h" +#include "ctrlEnv/mvCtrlEnvAsm.h" +#include "mvCommon.h" + +/* defines */ + +#if defined(MV_STATIC_DRAM_ON_BOARD) +.globl dramBoot1 +dramBoot1: + .word 0 + +/****************************************************************************** +* +* +* +* +*******************************************************************************/ +#if defined(DB_MV78XX0) || defined(DB_MV88F632X) +/* DDR2 boards 512MB 333MHz */ +#define STATIC_SDRAM0_BANK0_SIZE 0x1ffffff1 /* 0x1504 */ +#define STATIC_SDRAM_CONFIG 0x43048C30 /* 0x1400 */ +#define STATIC_SDRAM_MODE 0x00000652 /* 0x141c */ +#define STATIC_DUNIT_CTRL_LOW 0x38543000 /* 0x1404 */ +#define STATIC_DUNIT_CTRL_HI 0x0000FFFF /* 0x1424 */ +#define STATIC_SDRAM_ADDR_CTRL 0x00000088 /* 0x1410 */ +#define STATIC_SDRAM_TIME_CTRL_LOW 0x22125441 /* 0x1408 */ +#define STATIC_SDRAM_TIME_CTRL_HI 0x00000A29 /* 0x140c */ +#define STATIC_SDRAM_ODT_CTRL_LOW 0x84210000 /* 0x1494 */ +#define STATIC_SDRAM_ODT_CTRL_HI 0x00000000 /* 0x1498 */ +#define STATIC_SDRAM_DUNIT_ODT_CTRL 0x0000E80F /* 0x149c */ +#define STATIC_SDRAM_EXT_MODE 0x00000040 /* 0x1420 */ +#define STATIC_SDRAM_DDR2_TIMING_LO 0x00085520 /* 0x1428 */ +#define STATIC_SDRAM_DDR2_TIMING_HI 0x00008552 /* 0x147C */ + +#elif defined(RD_MV78XX0_AMC) +/* On board DDR2 512MB 400MHz CL5 */ +#define STATIC_SDRAM0_BANK0_SIZE 0x1ffffff1 /* 0x1504 */ +#define STATIC_SDRAM_CONFIG 0x43008C30 /* 0x1400 */ +#define STATIC_SDRAM_MODE 0x00000652 /* 0x141c */ +#define STATIC_DUNIT_CTRL_LOW 0x38543000 /* 0x1404 */ +#define STATIC_DUNIT_CTRL_HI 0x0000F07F /* 0x1424 */ +#define STATIC_SDRAM_ADDR_CTRL 0x000000DD /* 0x1410 */ +#define STATIC_SDRAM_TIME_CTRL_LOW 0x23135441 /* 0x1408 */ +#define STATIC_SDRAM_TIME_CTRL_HI 0x00000A32 /* 0x140c */ +#define STATIC_SDRAM_ODT_CTRL_LOW 0x84210000 /* 0x1494 */ +#define STATIC_SDRAM_ODT_CTRL_HI 0x00000000 /* 0x1498 */ +#define STATIC_SDRAM_DUNIT_ODT_CTRL 0x0000EB0F /* 0x149c */ +#define STATIC_SDRAM_EXT_MODE 0x00000040 /* 0x1420 */ +#define STATIC_SDRAM_DDR2_TIMING_LO 0x00085520 /* 0x1428 */ +#define STATIC_SDRAM_DDR2_TIMING_HI 0x00008552 /* 0x147C */ + +#elif defined(RD_MV78XX0_H3C) +/* DDR2 boards 512MB 333MHz */ +#define STATIC_SDRAM0_BANK0_SIZE 0x1ffffff1 /* 0x1504 */ +#define STATIC_SDRAM_CONFIG 0x43048a25 /* 0x1400 */ +#define STATIC_SDRAM_MODE 0x00000652 /* 0x141c */ +#define STATIC_DUNIT_CTRL_LOW 0x38543000 /* 0x1404 */ +#define STATIC_DUNIT_CTRL_HI 0x0000F07F /* 0x1424 */ +#define STATIC_SDRAM_ADDR_CTRL 0x00000088 /* 0x1410 */ +#define STATIC_SDRAM_TIME_CTRL_LOW 0x2202444e /* 0x1408 */ +#define STATIC_SDRAM_TIME_CTRL_HI 0x00000A22 /* 0x140c */ +#define STATIC_SDRAM_ODT_CTRL_LOW 0x84210000 /* 0x1494 */ +#define STATIC_SDRAM_ODT_CTRL_HI 0x00000000 /* 0x1498 */ +#define STATIC_SDRAM_DUNIT_ODT_CTRL 0x0000EB0F /* 0x149c */ +#define STATIC_SDRAM_EXT_MODE 0x00000040 /* 0x1420 */ +#define STATIC_SDRAM_DDR2_TIMING_LO 0x00085520 /* 0x1428 */ +#define STATIC_SDRAM_DDR2_TIMING_HI 0x00008552 /* 0x147C */ + +#elif defined(RD_MV78XX0_PCAC) +/* DDR2 boards 256MB 200MHz */ +#define STATIC_SDRAM0_BANK0_SIZE 0x0ffffff1 /* 0x1504 */ +#define STATIC_SDRAM_CONFIG 0x43000a25 /* 0x1400 */ +#define STATIC_SDRAM_MODE 0x00000652 /* 0x141c */ +#define STATIC_DUNIT_CTRL_LOW 0x38543000 /* 0x1404 */ +#define STATIC_DUNIT_CTRL_HI 0x0000F07F /* 0x1424 */ +#define STATIC_SDRAM_ADDR_CTRL 0x000000DD /* 0x1410 */ +#define STATIC_SDRAM_TIME_CTRL_LOW 0x2202444e /* 0x1408 */ +#define STATIC_SDRAM_TIME_CTRL_HI 0x00000822 /* 0x140c */ +#define STATIC_SDRAM_ODT_CTRL_LOW 0x84210000 /* 0x1494 */ +#define STATIC_SDRAM_ODT_CTRL_HI 0x00000000 /* 0x1498 */ +#define STATIC_SDRAM_DUNIT_ODT_CTRL 0x0000EB0F /* 0x149c */ +#define STATIC_SDRAM_EXT_MODE 0x00000040 /* 0x1420 */ +#define STATIC_SDRAM_DDR2_TIMING_LO 0x00085520 /* 0x1428 */ +#define STATIC_SDRAM_DDR2_TIMING_HI 0x00008552 /* 0x147C */ + +#else +/* DDR2 MV88F6281 boards 256MB 400MHz */ +#define STATIC_SDRAM0_BANK0_SIZE 0x0FFFFFF1 /* 0x1504 */ +#define STATIC_SDRAM_CONFIG 0x43000c30 /* 0x1400 */ +#define STATIC_SDRAM_MODE 0x00000C52 /* 0x141c */ +#define STATIC_DUNIT_CTRL_LOW 0x39543000 /* 0x1404 */ +#define STATIC_DUNIT_CTRL_HI 0x0000F1FF /* 0x1424 */ +#define STATIC_SDRAM_ADDR_CTRL 0x000000cc /* 0x1410 */ +#define STATIC_SDRAM_TIME_CTRL_LOW 0x22125451 /* 0x1408 */ +#define STATIC_SDRAM_TIME_CTRL_HI 0x00000A33 /* 0x140c */ +#define STATIC_SDRAM_ODT_CTRL_LOW 0x003C0000 /* 0x1494 */ +#define STATIC_SDRAM_ODT_CTRL_HI 0x00000000 /* 0x1498 */ +#define STATIC_SDRAM_DUNIT_ODT_CTRL 0x0000F80F /* 0x149c */ +#define STATIC_SDRAM_EXT_MODE 0x00000042 /* 0x1420 */ +#define STATIC_SDRAM_DDR2_TIMING_LO 0x00085520 /* 0x1428 */ +#define STATIC_SDRAM_DDR2_TIMING_HI 0x00008552 /* 0x147C */ +#endif /* MV78XX0 */ + + .globl _mvDramIfStaticInit +_mvDramIfStaticInit: + + mov r11, LR /* Save link register */ + mov r10, r2 + +#ifdef MV78XX0 + MV_REG_READ_ASM (r6, r5, SDRAM_DUNIT_CTRL_REG) + orr r6, r6, #BIT4 /* Enable 2T mode */ + bic r6, r6, #BIT6 /* clear ctrlPos */ + MV_REG_WRITE_ASM (r6, r5, SDRAM_DUNIT_CTRL_REG) +#endif + + /*DDR SDRAM Initialization Control */ + ldr r6, =DSICR_INIT_EN + MV_REG_WRITE_ASM (r6, r1, DDR_SDRAM_INIT_CTRL_REG) +2: MV_REG_READ_ASM (r6, r1, DDR_SDRAM_INIT_CTRL_REG) + and r6, r6, #DSICR_INIT_EN + cmp r6, #0 + bne 2b + + /* If we boot from NAND jump to DRAM address */ + mov r5, #1 + ldr r6, =dramBoot1 + str r5, [r6] /* We started executing from DRAM */ + + ldr r6, dramBoot1 + cmp r6, #0 + bne 1f + + /* set all dram windows to 0 */ + mov r6, #0 + MV_REG_WRITE_ASM(r6, r5, SDRAM_SIZE_REG(0,0)) + MV_REG_WRITE_ASM(r6, r5, SDRAM_SIZE_REG(0,1)) + MV_REG_WRITE_ASM(r6, r5, SDRAM_SIZE_REG(0,2)) + MV_REG_WRITE_ASM(r6, r5, SDRAM_SIZE_REG(0,3)) + ldr r6, = STATIC_SDRAM0_BANK0_SIZE + MV_REG_WRITE_ASM(r6, r5, SDRAM_SIZE_REG(0,0)) + + + /* set all dram configuration in temp registers */ + ldr r6, = STATIC_SDRAM0_BANK0_SIZE + MV_REG_WRITE_ASM(r6, r5, DRAM_BUF_REG0) + ldr r6, = STATIC_SDRAM_CONFIG + MV_REG_WRITE_ASM(r6, r5, DRAM_BUF_REG1) + ldr r6, = STATIC_SDRAM_MODE + MV_REG_WRITE_ASM(r6, r5, DRAM_BUF_REG2) + ldr r6, = STATIC_DUNIT_CTRL_LOW + MV_REG_WRITE_ASM(r6, r5, DRAM_BUF_REG3) + ldr r6, = STATIC_SDRAM_ADDR_CTRL + MV_REG_WRITE_ASM(r6, r5, DRAM_BUF_REG4) + ldr r6, = STATIC_SDRAM_TIME_CTRL_LOW + MV_REG_WRITE_ASM(r6, r5, DRAM_BUF_REG5) + ldr r6, = STATIC_SDRAM_TIME_CTRL_HI + MV_REG_WRITE_ASM(r6, r5, DRAM_BUF_REG6) + ldr r6, = STATIC_SDRAM_ODT_CTRL_LOW + MV_REG_WRITE_ASM(r6, r5, DRAM_BUF_REG7) + ldr r6, = STATIC_SDRAM_ODT_CTRL_HI + MV_REG_WRITE_ASM(r6, r5, DRAM_BUF_REG8) + ldr r6, = STATIC_SDRAM_DUNIT_ODT_CTRL + MV_REG_WRITE_ASM(r6, r5, DRAM_BUF_REG9) + ldr r6, = STATIC_SDRAM_EXT_MODE + MV_REG_WRITE_ASM(r6, r5, DRAM_BUF_REG10) + ldr r6, = STATIC_SDRAM_DDR2_TIMING_LO + MV_REG_WRITE_ASM(r6, r5, DRAM_BUF_REG11) + ldr r6, = STATIC_SDRAM_DDR2_TIMING_HI + MV_REG_WRITE_ASM(r6, r5, DRAM_BUF_REG12) +#ifndef MV_NAND_BOOT + ldr r6, = STATIC_DUNIT_CTRL_HI + MV_REG_WRITE_ASM(r6, r5, DRAM_BUF_REG13) +#endif + + ldr sp,=0 + bl _mvDramIfConfig + ldr r0, =0 +#ifdef MV78XX0 + bl _mvDramIfEccMemInit +#endif +1: + mov r2, r10 + mov PC, r11 /* r11 is saved link register */ + +#else /* #if defined(MV_STATIC_DRAM_ON_BOARD) */ + +.globl dramBoot1 +dramBoot1: + .word 0 + +/******************************************************************************* +* mvDramIfBasicInit - Basic initialization of DRAM interface +* +* DESCRIPTION: +* The function will initialize the DRAM for basic usage. The function +* will use the TWSI assembly API to extract DIMM parameters according +* to which DRAM interface will be initialized. +* The function referes to the following DRAM parameters: +* 1) DIMM is registered or not. +* 2) DIMM width detection. +* 3) DIMM density. +* +* INPUT: +* r3 - required size for initial DRAM. +* +* OUTPUT: +* None. +* +* RETURN: +* None. +* +* Note: +* r4 holds I2C EEPROM address +* r5 holds SDRAM register base address +* r7 holds returned values +* r8 holds SDRAM various configuration registers value. +* r11 holds return function address. +*******************************************************************************/ +/* Setting the offsets of the I2C registers */ +#define DIMM_TYPE_OFFSET 2 +#define NUM_OF_ROWS_OFFSET 3 +#define NUM_OF_COLS_OFFSET 4 +#define NUM_OF_RANKS 5 +#define DIMM_CONFIG_TYPE 11 +#define SDRAM_WIDTH_OFFSET 13 +#define NUM_OF_BANKS_OFFSET 17 +#define SUPPORTED_CL_OFFSET 18 +#define DIMM_TYPE_INFO_OFFSET 20 /* DDR2 only */ +#define SDRAM_MODULES_ATTR_OFFSET 21 +#define RANK_SIZE_OFFSET 31 + +#define DRAM_DEV_DENSITY_128M 128 +#define DRAM_DEV_DENSITY_256M 256 +#define DRAM_DEV_DENSITY_512M 512 +#define DRAM_DEV_DENSITY_1G 1024 +#define DRAM_DEV_DENSITY_2G 2048 + +#define DRAM_RANK_DENSITY_128M 0x20 +#define DRAM_RANK_DENSITY_256M 0x40 +#define DRAM_RANK_DENSITY_512M 0x80 +#define DRAM_RANK_DENSITY_1G 0x1 +#define DRAM_RANK_DENSITY_2G 0x2 + + .globl _mvDramIfBasicInit + .extern _i2cInit +_mvDramIfBasicInit: + + mov r11, LR /* Save link register */ + + /* Set Dunit high control register */ + MV_REG_READ_ASM (r6, r5, SDRAM_DUNIT_CTRL_HI_REG) + orr r6, r6, #BIT7 /* SDRAM__D2P_EN */ + orr r6, r6, #BIT8 /* SDRAM__P2D_EN */ +#ifdef MV78XX0 + orr r6, r6, #BIT9 /* SDRAM__ADD_HALF_FCC_EN */ + orr r6, r6, #BIT10 /* SDRAM__PUP_ZERO_SKEW_EN */ + orr r6, r6, #BIT11 /* SDRAM__WR_MASH_DELAY_EN */ +#endif + MV_REG_WRITE_ASM (r6, r5, SDRAM_DUNIT_CTRL_HI_REG) + +#ifdef MV78XX0 + MV_REG_READ_ASM (r6, r5, SDRAM_DUNIT_CTRL_REG) + orr r6, r6, #BIT4 /* Enable 2T mode */ + bic r6, r6, #BIT6 /* clear ctrlPos */ + MV_REG_WRITE_ASM (r6, r5, SDRAM_DUNIT_CTRL_REG) +#endif + + /*DDR SDRAM Initialization Control */ + ldr r6, =DSICR_INIT_EN + MV_REG_WRITE_ASM (r6, r1, DDR_SDRAM_INIT_CTRL_REG) +2: MV_REG_READ_ASM (r6, r1, DDR_SDRAM_INIT_CTRL_REG) + and r6, r6, #DSICR_INIT_EN + cmp r6, #0 + bne 2b + + mov r5, #1 + ldr r8, =dramBoot1 + str r5, [r8] /* We started executing from DRAM */ + + /* If we boot from NAND jump to DRAM address */ + ldr r8, dramBoot1 + cmp r8, #0 + movne pc, r11 + + bl _i2cInit /* Initialize TWSI master */ + + /* Check if we have more then 1 dimm */ + ldr r6, =0 + MV_REG_WRITE_ASM (r6, r1, DRAM_BUF_REG14) +#ifdef MV78XX0 + bl _is_Second_Dimm_Exist + beq single_dimm + ldr r6, =1 + MV_REG_WRITE_ASM (r6, r1, DRAM_BUF_REG14) +single_dimm: + bl _i2cInit /* Initialize TWSI master */ +#endif + + /* Get default SDRAM Config values */ + MV_REG_READ_ASM (r8, r5, SDRAM_CONFIG_REG) + + /* Get registered/non registered info from DIMM */ + bl _is_Registered + beq nonRegistered + +setRegistered: + orr r8, r8, #SDRAM_REGISTERED /* Set registered bit(17) */ +nonRegistered: +#ifdef MV78XX0 + /* Get ECC/non ECC info from DIMM */ + bl _is_Ecc + beq setConfigReg + +setEcc: + orr r8, r8, #SDRAM_ECC_EN /* Set ecc bit(18) */ +#endif +setConfigReg: + MV_REG_WRITE_ASM (r8, r5, DRAM_BUF_REG1) + + /* Set maximum CL supported by DIMM */ + bl _get_CAL + + /* r7 is DIMM supported CAS (e.g: 3 --> 0x1C) */ + clz r6, r7 + rsb r6, r6, #31 /* r6 = the bit number of MAX CAS supported */ + +casDdr2: + ldr r7, =0x41 /* stBurstInDel|stBurstOutDel field value */ + ldr r3, =0x53 /* stBurstInDel|stBurstOutDel registered value*/ + ldr r8, =0x32 /* Assuming MAX CL = 3 */ + cmp r6, #3 /* If CL = 3 break */ + beq casDdr2Cont + + ldr r7, =0x53 /* stBurstInDel|stBurstOutDel field value */ + ldr r3, =0x65 /* stBurstInDel|stBurstOutDel registered value*/ + ldr r8, =0x42 /* Assuming MAX CL = 4 */ + cmp r6, #4 /* If CL = 4 break */ + beq casDdr2Cont + + ldr r7, =0x65 /* stBurstInDel|stBurstOutDel field value */ + ldr r3, =0x77 /* stBurstInDel|stBurstOutDel registered value*/ + ldr r8, =0x52 /* Assuming MAX CL = 5 */ + cmp r6, #5 /* If CL = 5 break */ + beq casDdr2Cont + + ldr r7, =0x77 /* stBurstInDel|stBurstOutDel field value */ + ldr r3, =0x89 /* stBurstInDel|stBurstOutDel registered value*/ + ldr r8, =0x62 /* Assuming MAX CL = 6 */ + cmp r6, #6 /* If CL = 5 break */ + beq casDdr2Cont + + /* This is an error. return */ + b exit_ddrAutoConfig /* This is an error !! */ +casDdr2Cont: + + /* Get default SDRAM Mode values */ + MV_REG_READ_ASM (r6, r5, SDRAM_MODE_REG) + bic r6, r6, #(BIT6 | BIT5 | BIT4) /* Clear CL filed */ + orr r6, r6, r8 + MV_REG_WRITE_ASM (r6, r5, DRAM_BUF_REG2) + + /* Set Dunit control register according to max CL detected */ + MV_REG_READ_ASM (r6, r5, DRAM_BUF_REG1) + tst r6, #SDRAM_REGISTERED + beq setDunitReg + mov r7, r3 + +setDunitReg: +#ifdef MV78XX0 + /* Set SDRAM Extended Mode register for double DIMM */ + /* Check DRAM frequency for more then 267MHz set ODT Rtt to 50ohm */ + + MV_REG_READ_ASM (r4, r5, CPU_RESET_SAMPLE_L_REG) + ldr r5, =MSAR_SYSCLCK_MASK + and r4, r4, r5 + ldr r5, =MSAR_SYSCLCK_333 + cmp r4, r5 + ble Clock333 + add r7, r7, #0x10 +Clock333: +#endif + + MV_REG_READ_ASM (r6, r5, SDRAM_DUNIT_CTRL_REG) + bic r6, r6, #(0xff << 20) /* Clear SBout and SBin */ + orr r6, r6, #BIT4 /* Enable 2T mode */ + bic r6, r6, #BIT6 /* clear ctrlPos */ + orr r6, r6, r7, LSL #20 + MV_REG_WRITE_ASM (r6, r5, DRAM_BUF_REG3) + + /* Set Dunit high control register */ + MV_REG_READ_ASM (r6, r5, SDRAM_DUNIT_CTRL_HI_REG) + orr r6, r6, #BIT7 /* SDRAM__D2P_EN */ + orr r6, r6, #BIT8 /* SDRAM__P2D_EN */ +#ifdef MV78XX0 + orr r6, r6, #BIT9 /* SDRAM__ADD_HALF_FCC_EN */ + orr r6, r6, #BIT10 /* SDRAM__PUP_ZERO_SKEW_EN */ + orr r6, r6, #BIT11 /* SDRAM__WR_MASH_DELAY_EN */ +#endif + MV_REG_WRITE_ASM (r6, r5, DRAM_BUF_REG13) + + /* DIMM density configuration*/ + /* Density = (1 << (rowNum + colNum)) * dramWidth * dramBankNum */ +Density: + /* Get bank 0 and 1 density */ + ldr r6, =0 + bl _getDensity + + mov r8, r7 + mov r8, r8, LSR #20 /* Move density 20 bits to the right */ + /* For example 0x10000000 --> 0x1000 */ + + mov r3, #(SDRAM_DSIZE_256Mb(0) | SDRAM_DSIZE_256Mb(1)) + cmp r8, #DRAM_DEV_DENSITY_256M + beq get_bank_2_density + + mov r3, #(SDRAM_DSIZE_512Mb(0) | SDRAM_DSIZE_512Mb(1)) + cmp r8, #DRAM_DEV_DENSITY_512M + beq get_bank_2_density + + mov r3, #(SDRAM_DSIZE_1Gb(0) | SDRAM_DSIZE_1Gb(1)) + cmp r8, #DRAM_DEV_DENSITY_1G + beq get_bank_2_density + + mov r3, #(SDRAM_DSIZE_2Gb(0) | SDRAM_DSIZE_2Gb(1)) + cmp r8, #DRAM_DEV_DENSITY_2G + beq get_bank_2_density + + /* This is an error. return */ + b exit_ddrAutoConfig + +get_bank_2_density: + /* Check for second dimm */ + MV_REG_READ_ASM (r6, r1, DRAM_BUF_REG14) + cmp r6, #1 + bne get_width + + /* Get bank 2 and 3 density */ + ldr r6, =2 + bl _getDensity + + mov r8, r7 + mov r8, r8, LSR #20 /* Move density 20 bits to the right */ + /* For example 0x10000000 --> 0x1000 */ + + orr r3, r3, #(SDRAM_DSIZE_256Mb(2) | SDRAM_DSIZE_256Mb(3)) + cmp r8, #DRAM_DEV_DENSITY_256M + beq get_width + + and r3, r3, #~(SDRAM_DSIZE_MASK(2) | SDRAM_DSIZE_MASK(3)) + orr r3, r3, #(SDRAM_DSIZE_512Mb(2) | SDRAM_DSIZE_512Mb(3)) + cmp r8, #DRAM_DEV_DENSITY_512M + beq get_width + + and r3, r3, #~(SDRAM_DSIZE_MASK(2) | SDRAM_DSIZE_MASK(3)) + orr r3, r3, #(SDRAM_DSIZE_1Gb(2) | SDRAM_DSIZE_1Gb(3)) + cmp r8, #DRAM_DEV_DENSITY_1G + beq get_width + + and r3, r3, #~(SDRAM_DSIZE_MASK(2) | SDRAM_DSIZE_MASK(3)) + orr r3, r3, #(SDRAM_DSIZE_2Gb(2) | SDRAM_DSIZE_2Gb(3)) + cmp r8, #DRAM_DEV_DENSITY_2G + beq get_width + + /* This is an error. return */ + b exit_ddrAutoConfig + + /* Get SDRAM width */ +get_width: + /* Get bank 0 and 1 width */ + ldr r6, =0 + bl _get_width + + cmp r7, #8 /* x8 devices */ + beq get_bank_2_width + + orr r3, r3, #(SDRAM_ADDRSEL_X16(0) | SDRAM_ADDRSEL_X16(1)) /* x16 devices */ + cmp r7, #16 + beq get_bank_2_width + + /* This is an error. return */ + b exit_ddrAutoConfig + +get_bank_2_width: + /* Check for second dimm */ + MV_REG_READ_ASM (r6, r1, DRAM_BUF_REG14) + cmp r6, #1 + bne densCont + + /* Get bank 2 and 3 width */ + ldr r6, =2 + bl _get_width + + cmp r7, #8 /* x8 devices */ + beq densCont + + orr r3, r3, #(SDRAM_ADDRSEL_X16(2) | SDRAM_ADDRSEL_X16(3)) /* x16 devices */ + cmp r7, #16 + beq densCont + + /* This is an error. return */ + b exit_ddrAutoConfig + +densCont: + MV_REG_WRITE_ASM (r3, r5, DRAM_BUF_REG4) + + /* Set SDRAM timing control low register */ + ldr r4, =SDRAM_TIMING_CTRL_LOW_REG_DEFAULT + /* MV_REG_READ_ASM (r4, r5, SDRAM_TIMING_CTRL_LOW_REG) */ + MV_REG_WRITE_ASM(r4, r5, DRAM_BUF_REG5) + + /* Set SDRAM timing control high register */ + ldr r6, =SDRAM_TIMING_CTRL_HIGH_REG_DEFAULT + + MV_REG_READ_ASM (r4, r5, CPU_RESET_SAMPLE_L_REG) + ldr r5, =MSAR_SYSCLCK_MASK + and r4, r4, r5 + ldr r5, =MSAR_SYSCLCK_333 + cmp r4, r5 + blt timingHighClock333 + orr r6, r6, #BIT9 + +timingHighClock333: + /* MV_REG_READ_ASM (r6, r5, SDRAM_TIMING_CTRL_HIGH_REG) */ + MV_REG_WRITE_ASM(r6, r5, DRAM_BUF_REG6) + + /* Check for second dimm */ + MV_REG_READ_ASM (r6, r1, DRAM_BUF_REG14) + cmp r6, #1 + bne single_dimm_odt + + /* Set SDRAM ODT control low register for double DIMM*/ + ldr r4, =DDR2_ODT_CTRL_LOW_CS0_CS1_CS2_CS3_DV + MV_REG_WRITE_ASM(r4, r5, DRAM_BUF_REG7) + + /* Set DUNIT ODT control register for double DIMM */ + ldr r4, =DDR2_DUNIT_ODT_CTRL_CS0_CS1_CS2_CS3_DV + MV_REG_WRITE_ASM(r4, r5, DRAM_BUF_REG9) + +#ifdef MV78XX0 + /* Set SDRAM Extended Mode register for double DIMM */ + /* Check DRAM frequency for more then 267MHz set ODT Rtt to 50ohm */ + + MV_REG_READ_ASM (r4, r5, CPU_RESET_SAMPLE_L_REG) + ldr r5, =MSAR_SYSCLCK_MASK + and r4, r4, r5 + ldr r5, =MSAR_SYSCLCK_267 + cmp r4, r5 + beq slow_dram_clock_rtt + ldr r5, =MSAR_SYSCLCK_300 + cmp r4, r5 + beq slow_dram_clock_rtt + ldr r5, =MSAR_SYSCLCK_333 + cmp r4, r5 + beq fast_dram_clock_rtt + ldr r5, =MSAR_SYSCLCK_400 + cmp r4, r5 + beq fast_dram_clock_rtt + + b slow_dram_clock_rtt + +fast_dram_clock_rtt: + ldr r4, =DDR_SDRAM_EXT_MODE_FAST_CS0_CS1_CS2_CS3_DV + MV_REG_WRITE_ASM(r4, r5, DRAM_BUF_REG10) + b odt_config_end +#endif +slow_dram_clock_rtt: + ldr r4, =DDR_SDRAM_EXT_MODE_CS0_CS1_CS2_CS3_DV + MV_REG_WRITE_ASM(r4, r5, DRAM_BUF_REG10) + b odt_config_end + +single_dimm_odt: + /* Set SDRAM ODT control low register */ + ldr r4, =DDR2_ODT_CTRL_LOW_CS0_CS1_DV + MV_REG_WRITE_ASM(r4, r5, DRAM_BUF_REG7) + + /* Set DUNIT ODT control register */ + ldr r4, =DDR2_DUNIT_ODT_CTRL_CS0_CS1_DV + MV_REG_WRITE_ASM(r4, r5, DRAM_BUF_REG9) + + /* Set SDRAM Extended Mode register */ + ldr r4, =DDR_SDRAM_EXT_MODE_CS0_CS1_DV + MV_REG_WRITE_ASM(r4, r5, DRAM_BUF_REG10) + +odt_config_end: + /* SDRAM ODT control high register is left as default */ + MV_REG_READ_ASM (r4, r5, DDR2_SDRAM_ODT_CTRL_HIGH_REG) + MV_REG_WRITE_ASM(r4, r5, DRAM_BUF_REG8) + + /*Read CL and set the DDR2 registers accordingly */ + MV_REG_READ_ASM (r6, r5, DRAM_BUF_REG2) + and r6, r6, #SDRAM_CL_MASK + mov r4, r6 + orr r4, r4, r6, LSL #4 + orr r4, r4, r6, LSL #8 + orr r4, r4, r6, LSL #12 + mov r5, #0x30000 + add r4, r4, r5 + sub r4, r4, #0x30 + /* Set SDRAM Ddr2 Timing Low register */ + MV_REG_WRITE_ASM(r4, r5, DRAM_BUF_REG11) + + /* Set SDRAM Ddr2 Timing High register */ + mov r4, r4, LSR #4 + MV_REG_WRITE_ASM(r4, r5, DRAM_BUF_REG12) + +timeParamDone: + /* Close all windows */ + MV_REG_READ_ASM (r6, r5, SDRAM_SIZE_REG(0,0)) + and r6, r6,#~SCSR_SIZE_MASK + and r6, r6,#~1 + MV_REG_WRITE_ASM (r6, r5, SDRAM_SIZE_REG(0,0)) + MV_REG_READ_ASM (r6, r5, SDRAM_SIZE_REG(0,1)) + and r6, r6,#~SCSR_SIZE_MASK + and r6, r6,#~1 + MV_REG_WRITE_ASM (r6, r5, SDRAM_SIZE_REG(0,1)) + MV_REG_READ_ASM (r6, r5, SDRAM_SIZE_REG(0,2)) + and r6, r6,#~SCSR_SIZE_MASK + and r6, r6,#~1 + MV_REG_WRITE_ASM (r6, r5, SDRAM_SIZE_REG(0,2)) + MV_REG_READ_ASM (r6, r5, SDRAM_SIZE_REG(0,3)) + and r6, r6,#~SCSR_SIZE_MASK + and r6, r6,#~1 + MV_REG_WRITE_ASM (r6, r5, SDRAM_SIZE_REG(0,3)) + + /* Set sdram bank 0 size and enable it */ + ldr r6, =0 + bl _mvDramIfGetDimmSizeFromSpd +#ifdef MV78XX0 + /* Check DRAM width */ + MV_REG_READ_ASM (r4, r5, SDRAM_CONFIG_REG) + ldr r5, =SDRAM_DWIDTH_MASK + and r4, r4, r5 + ldr r5, =SDRAM_DWIDTH_64BIT + cmp r4, r5 + beq dram_64bit_width + /* Utilize only 32bit width */ + mov r8, r8, LSR #1 +#else + /* Utilize only 16bit width */ + mov r8, r8, LSR #2 +#endif +dram_64bit_width: + /* Update first dimm size return value R8 */ + MV_REG_READ_ASM (r5, r6, SDRAM_SIZE_REG(0,0)) + ldr r6, =~SCSR_SIZE_MASK + and r5, r5, r6 + orr r5, r5, r8 + MV_REG_WRITE_ASM(r5, r8, SDRAM_SIZE_REG(0,0)) + + /* Clear bank 2 size */ + MV_REG_READ_ASM (r6, r5, SDRAM_SIZE_REG(0,2)) + and r6, r6,#~SCSR_SIZE_MASK + MV_REG_WRITE_ASM (r6, r5, SDRAM_SIZE_REG(0,2)) + + /* Check for second dimm */ + MV_REG_READ_ASM (r6, r1, DRAM_BUF_REG14) + cmp r6, #1 + bne defualt_order + + /* Set sdram bank 2 size */ + ldr r6, =2 + bl _mvDramIfGetDimmSizeFromSpd +#ifdef MV78XX0 + /* Check DRAM width */ + MV_REG_READ_ASM (r4, r5, SDRAM_CONFIG_REG) + ldr r5, =SDRAM_DWIDTH_MASK + and r4, r4, r5 + ldr r5, =SDRAM_DWIDTH_64BIT + cmp r4, r5 + beq dram_64bit_width2 + /* Utilize only 32bit width */ + mov r8, r8, LSR #1 +#else + /* Utilize only 16bit width */ + mov r8, r8, LSR #2 +#endif +dram_64bit_width2: + /* Update first dimm size return value R8 */ + MV_REG_READ_ASM (r5, r6, SDRAM_SIZE_REG(0,2)) + ldr r6, =~SCSR_SIZE_MASK + and r5, r5, r6 + orr r5, r5, r8 + MV_REG_WRITE_ASM(r5, r8, SDRAM_SIZE_REG(0,2)) + + /* Close windows 1 and 3 */ + MV_REG_READ_ASM (r6, r5, SDRAM_SIZE_REG(0,1)) + and r6, r6,#~1 + MV_REG_WRITE_ASM (r6, r5, SDRAM_SIZE_REG(0,1)) + MV_REG_READ_ASM (r6, r5, SDRAM_SIZE_REG(0,3)) + and r6, r6,#~1 + MV_REG_WRITE_ASM (r6, r5, SDRAM_SIZE_REG(0,3)) + + /* Check dimm size for setting dram bank order */ + MV_REG_READ_ASM (r6, r5, SDRAM_SIZE_REG(0,0)) + MV_REG_READ_ASM (r4, r5, SDRAM_SIZE_REG(0,2)) + and r6, r6,#SCSR_SIZE_MASK + and r4, r4,#SCSR_SIZE_MASK + cmp r6, r4 + bge defualt_order + + /* Bank 2 is biger then bank 0 */ + ldr r6,=0 + MV_REG_WRITE_ASM (r6, r5, SDRAM_BASE_ADDR_REG(0,2)) + + /* Open win 2 */ + MV_REG_READ_ASM (r6, r5, SDRAM_SIZE_REG(0,2)) + orr r6, r6,#1 + MV_REG_WRITE_ASM (r6, r5, SDRAM_SIZE_REG(0,2)) + + ldr sp,=0 + bl _mvDramIfConfig +#ifdef MV78XX0 + /* Init ECC on CS 2 */ + ldr r0, =2 + bl _mvDramIfEccMemInit +#endif + mov PC, r11 /* r11 is saved link register */ + +defualt_order: + + /* Open win 0 */ + MV_REG_READ_ASM (r6, r5, SDRAM_SIZE_REG(0,0)) + orr r6, r6,#1 + MV_REG_WRITE_ASM (r6, r5, SDRAM_SIZE_REG(0,0)) + + ldr sp,=0 + bl _mvDramIfConfig +#ifdef MV78XX0 + /* Init ECC on CS 0 */ + ldr r0, =0 + bl _mvDramIfEccMemInit +#endif +exit_ddrAutoConfig: + mov PC, r11 /* r11 is saved link register */ + + +/***************************************************************************************/ +/* r4 holds I2C EEPROM address + * r7 holds I2C EEPROM offset parameter for i2cRead and its --> returned value + * r8 holds SDRAM various configuration registers value. + * r13 holds Link register + */ +/**************************/ +_getDensity: + mov r13, LR /* Save link register */ + + /* Read SPD rank size from DIMM0 */ + mov r4, #MV_BOARD_DIMM0_I2C_ADDR /* reading from DIMM0 */ + + cmp r6, #0 + beq 1f + + /* Read SPD rank size from DIMM1 */ + mov r4, #MV_BOARD_DIMM1_I2C_ADDR /* reading from DIMM1 */ + +1: + mov r7, #NUM_OF_ROWS_OFFSET /* offset 3 */ + bl _i2cRead + mov r8, r7 /* r8 save number of rows */ + + mov r7, #NUM_OF_COLS_OFFSET /* offset 4 */ + bl _i2cRead + add r8, r8, r7 /* r8 = number of rows + number of col */ + + mov r7, #0x1 + mov r8, r7, LSL r8 /* r8 = (1 << r8) */ + + mov r7, #SDRAM_WIDTH_OFFSET /* offset 13 */ + bl _i2cRead + mul r8, r7, r8 + + mov r7, #NUM_OF_BANKS_OFFSET /* offset 17 */ + bl _i2cRead + mul r7, r8, r7 + + mov PC, r13 + +/**************************/ +_get_width: + mov r13, LR /* Save link register */ + + /* Read SPD rank size from DIMM0 */ + mov r4, #MV_BOARD_DIMM0_I2C_ADDR /* reading from DIMM0 */ + + cmp r6, #0 + beq 1f + + /* Read SPD rank size from DIMM1 */ + mov r4, #MV_BOARD_DIMM1_I2C_ADDR /* reading from DIMM1 */ + +1: + /* Get SDRAM width (SPD offset 13) */ + mov r7, #SDRAM_WIDTH_OFFSET + bl _i2cRead /* result in r7 */ + + mov PC, r13 + +/**************************/ +_get_CAL: + mov r13, LR /* Save link register */ + + /* Set maximum CL supported by DIMM */ + mov r4, #MV_BOARD_DIMM0_I2C_ADDR /* reading from DIMM0 */ + mov r7, #SUPPORTED_CL_OFFSET /* offset 18 */ + bl _i2cRead + + mov PC, r13 + +/**************************/ +/* R8 - sdram configuration register. + * Return value in flag if no-registered then Z-flag is set + */ +_is_Registered: + mov r13, LR /* Save link register */ +#if defined(MV645xx) + /* Get registered/non registered info from DIMM */ + tst r8, #SDRAM_DTYPE_DDR2 + bne regDdr2 + +regDdr1: + mov r4, #MV_BOARD_DIMM0_I2C_ADDR /* reading from DIMM0 */ + mov r7, #SDRAM_MODULES_ATTR_OFFSET + bl _i2cRead /* result in r7 */ + + tst r7, #0x2 + b exit +#endif +regDdr2: + mov r4, #MV_BOARD_DIMM0_I2C_ADDR /* reading from DIMM0 */ + mov r7, #DIMM_TYPE_INFO_OFFSET + bl _i2cRead /* result in r7 */ + + tst r7, #0x11 /* DIMM type = regular RDIMM (0x01) */ + /* or Mini-RDIMM (0x10) */ +exit: + mov PC, r13 + + +/**************************/ +/* Return value in flag if no-Ecc then Z-flag is set */ +_is_Ecc: + mov r13, LR /* Save link register */ + + mov r4, #MV_BOARD_DIMM0_I2C_ADDR /* reading from DIMM0 */ + mov r7, #DIMM_CONFIG_TYPE + bl _i2cRead /* result in r7 */ + + tst r7, #0x2 /* bit 1 -> Data ECC */ + mov PC, r13 + +/**************************/ +/* Return value in flag if no second DIMM then Z-flag is set */ +_is_Second_Dimm_Exist: + mov r13, LR /* Save link register */ + + mov r4, #MV_BOARD_DIMM1_I2C_ADDR /* reading from DIMM0 */ + mov r7, #DIMM_TYPE_OFFSET + bl _i2cRead /* result in r7 */ + + tst r7, #0x8 /* bit3 is '1' -> DDR 2 */ + mov PC, r13 + +/******************************************************************************* +* _mvDramIfGetDimmSizeFromSpd - read bank 0 dram's size +* +* DESCRIPTION: +* The function will read the bank 0 dram size(SPD version 1.0 and above ) +* +* INPUT: +* r6 - dram bank number. +* +* OUTPUT: +* none +*/ +_mvDramIfGetDimmSizeFromSpd: + + mov r13, LR /* Save link register */ + + /* Read SPD rank size from DIMM0 */ + mov r4, #MV_BOARD_DIMM0_I2C_ADDR /* reading from DIMM0 */ + + cmp r6, #0 + beq 1f + + /* Read SPD rank size from DIMM1 */ + mov r4, #MV_BOARD_DIMM1_I2C_ADDR /* reading from DIMM1 */ + +1: + mov r7, #RANK_SIZE_OFFSET /* offset 31 */ + bl _i2cRead + +pass_read: + ldr r8, =(0x7 << SCSR_SIZE_OFFS) + cmp r7, #DRAM_RANK_DENSITY_128M + beq endDimmSize + + ldr r8, =(0xf << SCSR_SIZE_OFFS) + cmp r7, #DRAM_RANK_DENSITY_256M + beq endDimmSize + + ldr r8, =(0x1f << SCSR_SIZE_OFFS) + cmp r7, #DRAM_RANK_DENSITY_512M + beq endDimmSize + + ldr r8, =(0x3f << SCSR_SIZE_OFFS) + cmp r7, #DRAM_RANK_DENSITY_1G + beq endDimmSize + + ldr r8, =(0x7f << SCSR_SIZE_OFFS) /* DRAM_RANK_DENSITY_2G */ +endDimmSize: + mov PC, r13 +#endif diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr2/mvDramIfConfig.S b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr2/mvDramIfConfig.S new file mode 100644 index 0000000..88527e5 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr2/mvDramIfConfig.S @@ -0,0 +1,528 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +/******************************************************************************* +* mvDramIfBasicAsm.s +* +* DESCRIPTION: +* Memory full detection and best timing configuration is done in +* C code. C runtime environment requires a stack. This module API +* initialize DRAM interface chip select 0 for basic functionality for +* the use of stack. +* The module API assumes DRAM information is stored in I2C EEPROM reside +* in a given I2C address MV_BOARD_DIMM0_I2C_ADDR. The I2C EEPROM +* internal data structure is assumed to be orgenzied in common DRAM +* vendor SPD structure. +* NOTE: DFCDL values are assumed to be already initialized prior to +* this module API activity. +* +* +* DEPENDENCIES: +* None. +* +*******************************************************************************/ + +/* includes */ +#define _ASMLANGUAGE +#define MV_ASMLANGUAGE +#include "mvOsAsm.h" +#include "mvSysHwConfig.h" +#include "mvDramIfRegs.h" +#include "mvDramIfConfig.h" +#include "ctrlEnv/sys/mvCpuIfRegs.h" +#include "pex/mvPexRegs.h" +#include "ctrlEnv/mvCtrlEnvSpec.h" +#include "mvCommon.h" + +/* defines */ + +/* locals */ +.data +.globl _mvDramIfConfig +.text +.globl _mvDramIfMemInit + +/******************************************************************************* +* _mvDramIfConfig - Basic DRAM interface initialization. +* +* DESCRIPTION: +* The function will initialize the following DRAM parameters using the +* values prepared by mvDramIfDetect routine. Values are located +* in predefined registers. +* +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* None. +* +*******************************************************************************/ + +_mvDramIfConfig: + + /* Save register on stack */ + cmp sp, #0 + beq no_stack_s +save_on_stack: + stmdb sp!, {r1, r2, r3, r4} +no_stack_s: + + /* Dunit FTDLL Configuration Register */ + /* 0) Write to SDRAM FTDLL coniguration register */ + ldr r4, = SDRAM_FTDLL_REG_DEFAULT_LEFT; + ldr r1, =(INTER_REGS_BASE + SDRAM_FTDLL_CONFIG_LEFT_REG) + str r4, [r1] + ldr r4, = SDRAM_FTDLL_REG_DEFAULT_RIGHT; + ldr r1, =(INTER_REGS_BASE + SDRAM_FTDLL_CONFIG_RIGHT_REG) + str r4, [r1] + ldr r4, = SDRAM_FTDLL_REG_DEFAULT_UP; + ldr r1, =(INTER_REGS_BASE + SDRAM_FTDLL_CONFIG_UP_REG) + str r4, [r1] + + /* 1) Write to SDRAM coniguration register */ + ldr r1, =(INTER_REGS_BASE + DRAM_BUF_REG1) + ldr r4, [r1] + ldr r1, =(INTER_REGS_BASE + SDRAM_CONFIG_REG) + str r4, [r1] + + /* 2) Write Dunit control low register */ + ldr r1, =(INTER_REGS_BASE + DRAM_BUF_REG3) + ldr r4, [r1] + ldr r1, =(INTER_REGS_BASE + SDRAM_DUNIT_CTRL_REG) + str r4, [r1] + + /* 2) Write Dunit control high register */ + ldr r1, =(INTER_REGS_BASE + DRAM_BUF_REG13) + ldr r4, [r1] + ldr r1, =(INTER_REGS_BASE + SDRAM_DUNIT_CTRL_HI_REG) + str r4, [r1] + + /* 3) Write SDRAM address control register */ + ldr r1, =(INTER_REGS_BASE + DRAM_BUF_REG4) + ldr r4, [r1] + ldr r1, =(INTER_REGS_BASE + SDRAM_ADDR_CTRL_REG) + str r4, [r1] +#if defined(MV_STATIC_DRAM_ON_BOARD) + /* 4) Write SDRAM bank 0 size register */ + ldr r1, =(INTER_REGS_BASE + DRAM_BUF_REG0) + ldr r4, [r1] + ldr r1, =(INTER_REGS_BASE + SDRAM_SIZE_REG(0,0)) + str r4, [r1] +#endif + + /* 5) Write SDRAM open pages control register */ + ldr r1, =(INTER_REGS_BASE + SDRAM_OPEN_PAGE_CTRL_REG) + ldr r4, =SDRAM_OPEN_PAGES_CTRL_REG_DV + str r4, [r1] + + /* 6) Write SDRAM timing Low register */ + ldr r1, =(INTER_REGS_BASE + DRAM_BUF_REG5) + ldr r4, [r1] + ldr r1, =(INTER_REGS_BASE + SDRAM_TIMING_CTRL_LOW_REG) + str r4, [r1] + + /* 7) Write SDRAM timing High register */ + ldr r1, =(INTER_REGS_BASE + DRAM_BUF_REG6) + ldr r4, [r1] + ldr r1, =(INTER_REGS_BASE + SDRAM_TIMING_CTRL_HIGH_REG) + str r4, [r1] + + /* Config DDR2 On Die Termination (ODT) registers */ + /* Write SDRAM DDR2 ODT control low register */ + ldr r1, =(INTER_REGS_BASE + DRAM_BUF_REG7) + ldr r4, [r1] + ldr r1, =(INTER_REGS_BASE + DDR2_SDRAM_ODT_CTRL_LOW_REG) + str r4, [r1] + + /* Write SDRAM DDR2 ODT control high register */ + ldr r1, =(INTER_REGS_BASE + DRAM_BUF_REG8) + ldr r4, [r1] + ldr r1, =(INTER_REGS_BASE + DDR2_SDRAM_ODT_CTRL_HIGH_REG) + str r4, [r1] + + /* Write SDRAM DDR2 Dunit ODT control register */ + ldr r1, =(INTER_REGS_BASE + DRAM_BUF_REG9) + ldr r4, [r1] + ldr r1, =(INTER_REGS_BASE + DDR2_DUNIT_ODT_CONTROL_REG) + str r4, [r1] + + /* Write DDR2 SDRAM timing Low register */ + ldr r1, =(INTER_REGS_BASE + DRAM_BUF_REG11) + ldr r4, [r1] + ldr r1, =(INTER_REGS_BASE + SDRAM_DDR2_TIMING_LO_REG) + str r4, [r1] + + /* Write DDR2 SDRAM timing High register */ + ldr r1, =(INTER_REGS_BASE + DRAM_BUF_REG12) + ldr r4, [r1] + ldr r1, =(INTER_REGS_BASE + SDRAM_DDR2_TIMING_HI_REG) + str r4, [r1] + + /* 8) Write SDRAM mode register */ + /* The CPU must not attempt to change the SDRAM Mode register setting */ + /* prior to DRAM controller completion of the DRAM initialization */ + /* sequence. To guarantee this restriction, it is recommended that */ + /* the CPU sets the SDRAM Operation register to NOP command, performs */ + /* read polling until the register is back in Normal operation value, */ + /* and then sets SDRAM Mode register to its new value. */ + + /* 8.1 write 'nop' to SDRAM operation */ + mov r4, #0x5 /* 'NOP' command */ + MV_REG_WRITE_ASM(r4, r1, SDRAM_OPERATION_REG) + + /* 8.2 poll SDRAM operation. Make sure its back to normal operation */ +_sdramOpPoll1: + ldr r4, [r1] + cmp r4, #0 /* '0' = Normal SDRAM Mode */ + bne _sdramOpPoll1 + + /* 8.3 Now its safe to write new value to SDRAM Mode register */ + ldr r1, =(INTER_REGS_BASE + DRAM_BUF_REG2) + ldr r4, [r1] + ldr r1, =(INTER_REGS_BASE + SDRAM_MODE_REG) + str r4, [r1] + + /* 8.4 Make the Dunit write the DRAM its new mode */ + mov r4, #0x3 /* Mode Register Set command */ + MV_REG_WRITE_ASM (r4, r1, SDRAM_OPERATION_REG) + + /* 8.5 poll SDRAM operation. Make sure its back to normal operation */ +_sdramOpPoll2: + ldr r4, [r1] + cmp r4, #0 /* '0' = Normal SDRAM Mode */ + bne _sdramOpPoll2 + + /* Now its safe to write new value to SDRAM Extended Mode regist */ + ldr r1, =(INTER_REGS_BASE + DRAM_BUF_REG10) + ldr r4, [r1] + ldr r1, =(INTER_REGS_BASE + SDRAM_EXTENDED_MODE_REG) + str r4, [r1] + + /* 9) Write SDRAM Extended mode register This operation should be */ + /* done for each memory bank */ + /* write 'nop' to SDRAM operation */ + mov r4, #0x5 /* 'NOP' command */ + MV_REG_WRITE_ASM (r4, r1, SDRAM_OPERATION_REG) + + /* poll SDRAM operation. Make sure its back to normal operation */ +_sdramOpPoll3: + ldr r4, [r1] + cmp r4, #0 /* '0' = Normal SDRAM Mode */ + bne _sdramOpPoll3 + /* Go over each of the Banks */ + ldr r3, =0 /* r3 = DRAM bank Num */ + +extModeLoop: + /* Set the SDRAM Operation Control to each of the DRAM banks */ + mov r4, r3 /* Do not swap the bank counter value */ + MV_REG_WRITE_ASM (r4, r1, SDRAM_OPERATION_CTRL_REG) + + /* Make the Dunit write the DRAM its new mode */ + mov r4, #0x4 /* Extended Mode Register Set command */ + MV_REG_WRITE_ASM (r4, r1, SDRAM_OPERATION_REG) + + /* poll SDRAM operation. Make sure its back to normal operation */ +_sdramOpPoll4: + ldr r4, [r1] + cmp r4, #0 /* '0' = Normal SDRAM Mode */ + bne _sdramOpPoll4 + + add r3, r3, #1 + cmp r3, #4 /* 4 = Number of banks */ + bne extModeLoop + +extModeEnd: +cmp sp, #0 + beq no_stack_l + mov r1, LR /* Save link register */ +#if defined(MV78XX0) + bl _mvDramIfMemInit +#endif + mov LR,r1 /* restore link register */ +load_from_stack: + /* Restore registers */ + ldmia sp!, {r1, r2, r3, r4} +no_stack_l: + + mov pc, lr + + +/******************************************************************************* +* _mvDramIfEccMemInit - Basic DRAM ECC initialization. +* +* DESCRIPTION: +* +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* None. +* +*******************************************************************************/ +#define XOR_CHAN0 0 /* XOR channel 0 used for memory initialization */ +#define XOR_UNIT0 0 /* XOR unit 0 used for memory initialization */ +#define XOR_ADDR_DEC_WIN0 0 /* Enable DRAM access using XOR decode window 0 */ +/* XOR engine register offsets macros */ +#define XOR_CONFIG_REG(chan) (XOR_UNIT_BASE(0) + 0x10 + ((chan) * 4)) +#define XOR_ACTIVATION_REG(chan) (XOR_UNIT_BASE(0) + 0x20 + ((chan) * 4)) +#define XOR_CAUSE_REG (XOR_UNIT_BASE(0) + 0x30) +#define XOR_ERROR_CAUSE_REG (XOR_UNIT_BASE(0) + 0x50) +#define XOR_ERROR_ADDR_REG (XOR_UNIT_BASE(0) + 0x60) +#define XOR_INIT_VAL_LOW_REG (XOR_UNIT_BASE(0) + 0x2E0) +#define XOR_INIT_VAL_HIGH_REG (XOR_UNIT_BASE(0) + 0x2E4) +#define XOR_DST_PTR_REG(chan) (XOR_UNIT_BASE(0) + 0x2B0 + ((chan) * 4)) +#define XOR_BLOCK_SIZE_REG(chan) (XOR_UNIT_BASE(0) + 0x2C0 + ((chan) * 4)) + +/* XOR Engine Address Decoding Register Map */ +#define XOR_WINDOW_CTRL_REG(unit,chan) (XOR_UNIT_BASE(unit)+(0x240 + ((chan) * 4))) +#define XOR_BASE_ADDR_REG(unit,winNum) (XOR_UNIT_BASE(unit)+(0x250 + ((winNum) * 4))) +#define XOR_SIZE_MASK_REG(unit,winNum) (XOR_UNIT_BASE(unit)+(0x270 + ((winNum) * 4))) + +.globl _mvDramIfEccMemInit +/******************************************************************************* +* _mvDramIfEccMemInit - mem init for dram cs +* +* DESCRIPTION: +* This function will clean the cs by ussing the XOR mem init. +* +* INPUT: +* r0 - dram bank number. +* +* OUTPUT: +* none +*/ +_mvDramIfEccMemInit: + + /* Save register on stack */ + cmp sp, #0 + beq no_stack_s1 +save_on_stack1: + stmdb sp!, {r0,r1, r2, r3, r4, r5, r6} +no_stack_s1: + + ldr r1, = 0 + + /* Disable all XOR address decode windows to avoid possible overlap */ + MV_REG_WRITE_ASM (r1, r5, (XOR_WINDOW_CTRL_REG(XOR_UNIT0,XOR_CHAN0))) + + /* Init r5 to first XOR_SIZE_MASK_REG */ + mov r5, r0, LSL #3 + add r5, r5,#0x1500 + add r5, r5,#0x04 + add r5, r5,#(INTER_REGS_BASE) + ldr r6, [r5] + HTOLL(r6,r5) + MV_REG_WRITE_ASM (r6, r5, XOR_SIZE_MASK_REG(XOR_UNIT0,XOR_ADDR_DEC_WIN0)) + + mov r5, r0, LSL #3 + add r5, r5,#0x1500 + add r5, r5,#(INTER_REGS_BASE) + ldr r6, [r5] + /* Update destination & size */ + MV_REG_WRITE_ASM(r6, r5, XOR_DST_PTR_REG(XOR_CHAN0)) + HTOLL(r6,r5) + /* Init r6 to first XOR_BASE_ADDR_REG */ + ldr r4, = 0xf + ldr r5, = 0x1 + mov r5, r5, LSL r0 + bic r4, r4, r5 + mov r4, r4, LSL #8 + + orr r6, r6, r4 + MV_REG_WRITE_ASM (r6, r5, XOR_BASE_ADDR_REG(XOR_UNIT0,XOR_ADDR_DEC_WIN0)) + + ldr r6, = 0xff0001 + MV_REG_WRITE_ASM (r6, r5, XOR_WINDOW_CTRL_REG(XOR_UNIT0,XOR_CHAN0)) + + /* Configure XOR engine for memory init function. */ + MV_REG_READ_ASM (r6, r5, XOR_CONFIG_REG(XOR_CHAN0)) + and r6, r6, #~0x7 /* Clear operation mode field */ + orr r6, r6, #0x4 /* Set operation to memory init */ + MV_REG_WRITE_ASM(r6, r5, XOR_CONFIG_REG(XOR_CHAN0)) + + /* Set initVal in the XOR Engine Initial Value Registers */ + ldr r6, = 0xfeedfeed + MV_REG_WRITE_ASM(r6, r5, XOR_INIT_VAL_LOW_REG) + ldr r6, = 0xfeedfeed + MV_REG_WRITE_ASM(r6, r5, XOR_INIT_VAL_HIGH_REG) + + /* Set block size using DRAM bank size */ + + mov r5, r0, LSL #3 + add r5, r5,#0x1500 + add r5, r5,#0x04 + add r5, r5,#(INTER_REGS_BASE) + + ldr r6, [r5] + HTOLL(r6,r5) + and r6, r6, #SCSR_SIZE_MASK + mov r5, r6, LSR #SCSR_SIZE_OFFS + add r5, r5, #1 + mov r6, r5, LSL #SCSR_SIZE_OFFS + MV_REG_WRITE_ASM(r6, r5, XOR_BLOCK_SIZE_REG(XOR_CHAN0)) + + /* Clean interrupt cause*/ + MV_REG_WRITE_ASM(r1, r5, XOR_CAUSE_REG) + + /* Clean error interrupt cause*/ + MV_REG_READ_ASM(r6, r5, XOR_ERROR_CAUSE_REG) + MV_REG_READ_ASM(r6, r5, XOR_ERROR_ADDR_REG) + + /* Start transfer */ + MV_REG_READ_ASM (r6, r5, XOR_ACTIVATION_REG(XOR_CHAN0)) + orr r6, r6, #0x1 /* Preform start command */ + MV_REG_WRITE_ASM(r6, r5, XOR_ACTIVATION_REG(XOR_CHAN0)) + + /* Wait for engine to finish */ +waitForComplete: + MV_REG_READ_ASM(r6, r5, XOR_CAUSE_REG) + and r6, r6, #2 + cmp r6, #0 + beq waitForComplete + + /* Clear all error report registers */ + MV_REG_WRITE_ASM(r1, r5, SDRAM_SINGLE_BIT_ERR_CNTR_REG) + MV_REG_WRITE_ASM(r1, r5, SDRAM_DOUBLE_BIT_ERR_CNTR_REG) + + MV_REG_WRITE_ASM(r1, r5, SDRAM_ERROR_CAUSE_REG) + + cmp sp, #0 + beq no_stack_l1 +load_from_stack1: + ldmia sp!, {r0, r1, r2, r3, r4, r5, r6} +no_stack_l1: + mov pc, lr + + +/******************************************************************************* +* mvDramIfMemInit - Use XOR to clear all memory. +* +* DESCRIPTION: +* Use assembler function _mvDramIfEccMemInit to fill all memory with FEADFEAD pattern. +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* None. +* +*******************************************************************************/ +#if defined(MV78XX0) + +_mvDramIfMemInit: + stmdb sp!, {r0,r1, r2, r3, r4, r5, r6} + mov r6, LR /* Save link register */ + /* Check if dram bank 0 has to be init for ECC */ + MV_REG_READ_ASM (r0, r5, SDRAM_SIZE_REG(0,0)) + and r3, r0, #SCSR_WIN_EN + cmp r3, #0 + beq no_bank_0 + MV_REG_READ_ASM(r0, r5, SDRAM_BASE_ADDR_REG(0,0)) + cmp r0, #0 + beq no_bank_0 + mov r0,#0 + bl _mvDramIfEccMemInit + +no_bank_0: + /* Check if dram bank 1 has to be init for ECC */ + MV_REG_READ_ASM (r0, r5, SDRAM_SIZE_REG(0,1)) + and r0, r0, #SCSR_WIN_EN + cmp r0, #0 + beq no_bank_1 + mov r0,#1 + bl _mvDramIfEccMemInit +no_bank_1: + /* Check if dram bank 2 has to be init for ECC */ + MV_REG_READ_ASM (r0, r5, SDRAM_SIZE_REG(0,2)) + and r0, r0, #SCSR_WIN_EN + cmp r0, #0 + beq no_bank_2 + MV_REG_READ_ASM(r0, r5, SDRAM_BASE_ADDR_REG(0,2)) + cmp r0, #0 + beq no_bank_2 + mov r0,#2 + bl _mvDramIfEccMemInit + +no_bank_2: + /* Check if dram bank 3 has to be init for ECC */ + MV_REG_READ_ASM (r0, r5, SDRAM_SIZE_REG(0,3)) + and r0, r0, #SCSR_WIN_EN + cmp r0, #0 + beq no_bank_3 + mov r0,#3 + bl _mvDramIfEccMemInit +no_bank_3: + mov LR ,r6 /* restore link register */ + ldmia sp!, {r0, r1, r2, r3, r4, r5, r6} + mov pc, lr +#endif + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr2/mvDramIfConfig.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr2/mvDramIfConfig.h new file mode 100644 index 0000000..6141c46 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr2/mvDramIfConfig.h @@ -0,0 +1,157 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + + +#ifndef __INCmvDramIfConfigh +#define __INCmvDramIfConfigh + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* includes */ + +/* defines */ + +/* registers defaults values */ + +#define SDRAM_CONFIG_DV (SDRAM_SRMODE_DRAM | BIT25 | BIT30) + +#define SDRAM_DUNIT_CTRL_LOW_DDR2_DV \ + (SDRAM_SRCLK_KEPT | \ + SDRAM_CLK1DRV_NORMAL | \ + (BIT28 | BIT29)) + +#define SDRAM_ADDR_CTRL_DV 2 + +#define SDRAM_TIMING_CTRL_LOW_REG_DV \ + ((0x2 << SDRAM_TRCD_OFFS) | \ + (0x2 << SDRAM_TRP_OFFS) | \ + (0x1 << SDRAM_TWR_OFFS) | \ + (0x0 << SDRAM_TWTR_OFFS) | \ + (0x5 << SDRAM_TRAS_OFFS) | \ + (0x1 << SDRAM_TRRD_OFFS)) + +/* Note: value of 0 in register means one cycle, 1 means two and so on */ +#define SDRAM_TIMING_CTRL_HIGH_REG_DV \ + ((0x0 << SDRAM_TR2R_OFFS) | \ + (0x0 << SDRAM_TR2W_W2R_OFFS) | \ + (0x1 << SDRAM_TW2W_OFFS)) + +#define SDRAM_OPEN_PAGES_CTRL_REG_DV SDRAM_OPEN_PAGE_EN + +/* Presence Ctrl Low Ctrl High Dunit Ctrl Ext Mode */ +/* CS0 0x84210000 0x00000000 0x0000780F 0x00000440 */ +/* CS0+CS1 0x84210000 0x00000000 0x0000780F 0x00000440 */ +/* CS0+CS2 0x030C030C 0x00000000 0x0000740F 0x00000404 */ +/* CS0+CS1+CS2 0x030C030C 0x00000000 0x0000740F 0x00000404 */ +/* CS0+CS2+CS3 0x030C030C 0x00000000 0x0000740F 0x00000404 */ +/* CS0+CS1+CS2+CS3 0x030C030C 0x00000000 0x0000740F 0x00000404 */ + +#define DDR2_ODT_CTRL_LOW_CS0_CS1_DV 0x84210000 +#define DDR2_ODT_CTRL_HIGH_CS0_CS1_DV 0x00000000 +#define DDR2_DUNIT_ODT_CTRL_CS0_CS1_DV 0x0000E80F +#ifdef MV78XX0 +#define DDR_SDRAM_EXT_MODE_CS0_CS1_DV 0x00000040 +#else +#define DDR_SDRAM_EXT_MODE_CS0_CS1_DV 0x00000440 +#endif + +#define DDR2_ODT_CTRL_LOW_CS0_CS1_CS2_CS3_DV 0x030C030C +#define DDR2_ODT_CTRL_HIGH_CS0_CS1_CS2_CS3_DV 0x00000000 +#define DDR2_DUNIT_ODT_CTRL_CS0_CS1_CS2_CS3_DV 0x0000F40F +#ifdef MV78XX0 +#define DDR_SDRAM_EXT_MODE_CS0_CS1_CS2_CS3_DV 0x00000004 +#define DDR_SDRAM_EXT_MODE_FAST_CS0_CS1_CS2_CS3_DV 0x00000044 +#else +#define DDR_SDRAM_EXT_MODE_CS0_CS1_CS2_CS3_DV 0x00000404 +#define DDR_SDRAM_EXT_MODE_FAST_CS0_CS1_CS2_CS3_DV 0x00000444 +#endif + +/* DDR SDRAM Adderss/Control and Data Pads Calibration default values */ +#define DDR2_ADDR_CTRL_PAD_STRENGTH_TYPICAL_DV \ + (3 << SDRAM_PRE_DRIVER_STRENGTH_OFFS) + +#define DDR2_DATA_PAD_STRENGTH_TYPICAL_DV \ + (3 << SDRAM_PRE_DRIVER_STRENGTH_OFFS) + +/* DDR SDRAM Mode Register default value */ +#define DDR2_MODE_REG_DV (SDRAM_BURST_LEN_4 | SDRAM_WR_3_CYC) +/* DDR SDRAM Timing parameter default values */ +#define SDRAM_TIMING_CTRL_LOW_REG_DEFAULT 0x33136552 +#define SDRAM_TRFC_DEFAULT_VALUE 0x34 +#define SDRAM_TRFC_DEFAULT SDRAM_TRFC_DEFAULT_VALUE +#define SDRAM_TW2W_DEFALT (0x1 << SDRAM_TW2W_OFFS) + +#define SDRAM_TIMING_CTRL_HIGH_REG_DEFAULT (SDRAM_TRFC_DEFAULT | SDRAM_TW2W_DEFALT) + +#define SDRAM_FTDLL_REG_DEFAULT_LEFT 0x88C800 +#define SDRAM_FTDLL_REG_DEFAULT_RIGHT 0x88C800 +#define SDRAM_FTDLL_REG_DEFAULT_UP 0x88C800 + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __INCmvDramIfh */ diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr2/mvDramIfRegs.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr2/mvDramIfRegs.h new file mode 100644 index 0000000..369eda6 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr2/mvDramIfRegs.h @@ -0,0 +1,423 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#ifndef __INCmvDramIfRegsh +#define __INCmvDramIfRegsh + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* DDR SDRAM Controller Address Decode Registers */ + /* SDRAM CSn Base Address Register (SCBAR) */ +#define SDRAM_BASE_ADDR_REG(cpu,csNum) (0x1500 + ((csNum) * 8) + ((cpu) * 0x70)) +#define SCBAR_BASE_OFFS 16 +#define SCBAR_BASE_MASK (0xffff << SCBAR_BASE_OFFS) +#define SCBAR_BASE_ALIGNMENT 0x10000 + +/* SDRAM CSn Size Register (SCSR) */ +#define SDRAM_SIZE_REG(cpu,csNum) (0x1504 + ((csNum) * 8) + ((cpu) * 0x70)) +#define SCSR_SIZE_OFFS 24 +#define SCSR_SIZE_MASK (0xff << SCSR_SIZE_OFFS) +#define SCSR_SIZE_ALIGNMENT 0x1000000 +#define SCSR_WIN_EN BIT0 + +/* configuration register */ +#define SDRAM_CONFIG_REG (DRAM_BASE + 0x1400) +#define SDRAM_REFRESH_OFFS 0 +#define SDRAM_REFRESH_MAX 0x3FFF +#define SDRAM_REFRESH_MASK (SDRAM_REFRESH_MAX << SDRAM_REFRESH_OFFS) +#define SDRAM_DWIDTH_OFFS 15 +#define SDRAM_DWIDTH_MASK (1 << SDRAM_DWIDTH_OFFS) +#define SDRAM_DWIDTH_32BIT (0 << SDRAM_DWIDTH_OFFS) +#define SDRAM_DWIDTH_64BIT (1 << SDRAM_DWIDTH_OFFS) +#define SDRAM_REGISTERED (1 << 17) +#define SDRAM_ECC_OFFS 18 +#define SDRAM_ECC_MASK (1 << SDRAM_ECC_OFFS) +#define SDRAM_ECC_DIS (0 << SDRAM_ECC_OFFS) +#define SDRAM_ECC_EN (1 << SDRAM_ECC_OFFS) +#define SDRAM_IERR_OFFS 19 +#define SDRAM_IERR_MASK (1 << SDRAM_IERR_OFFS) +#define SDRAM_IERR_REPORTE (0 << SDRAM_IERR_OFFS) +#define SDRAM_IERR_IGNORE (1 << SDRAM_IERR_OFFS) +#define SDRAM_SRMODE_OFFS 24 +#define SDRAM_SRMODE_MASK (1 << SDRAM_SRMODE_OFFS) +#define SDRAM_SRMODE_POWER (0 << SDRAM_SRMODE_OFFS) +#define SDRAM_SRMODE_DRAM (1 << SDRAM_SRMODE_OFFS) + +/* dunit control low register */ +#define SDRAM_DUNIT_CTRL_REG (DRAM_BASE + 0x1404) +#define SDRAM_2T_OFFS 4 +#define SDRAM_2T_MASK (1 << SDRAM_2T_OFFS) +#define SDRAM_2T_MODE (1 << SDRAM_2T_OFFS) + +#define SDRAM_SRCLK_OFFS 5 +#define SDRAM_SRCLK_MASK (1 << SDRAM_SRCLK_OFFS) +#define SDRAM_SRCLK_KEPT (0 << SDRAM_SRCLK_OFFS) +#define SDRAM_SRCLK_GATED (1 << SDRAM_SRCLK_OFFS) +#define SDRAM_CTRL_POS_OFFS 6 +#define SDRAM_CTRL_POS_MASK (1 << SDRAM_CTRL_POS_OFFS) +#define SDRAM_CTRL_POS_FALL (0 << SDRAM_CTRL_POS_OFFS) +#define SDRAM_CTRL_POS_RISE (1 << SDRAM_CTRL_POS_OFFS) +#define SDRAM_CLK1DRV_OFFS 12 +#define SDRAM_CLK1DRV_MASK (1 << SDRAM_CLK1DRV_OFFS) +#define SDRAM_CLK1DRV_HIGH_Z (0 << SDRAM_CLK1DRV_OFFS) +#define SDRAM_CLK1DRV_NORMAL (1 << SDRAM_CLK1DRV_OFFS) +#define SDRAM_CLK2DRV_OFFS 13 +#define SDRAM_CLK2DRV_MASK (1 << SDRAM_CLK2DRV_OFFS) +#define SDRAM_CLK2DRV_HIGH_Z (0 << SDRAM_CLK2DRV_OFFS) +#define SDRAM_CLK2DRV_NORMAL (1 << SDRAM_CLK2DRV_OFFS) +#define SDRAM_SB_OUT_DEL_OFFS 20 +#define SDRAM_SB_OUT_DEL_MAX 0xf +#define SDRAM_SB_OUT_MASK (SDRAM_SB_OUT_DEL_MAX<= MV_DRAM_MAX_CS )) + { + DB(mvOsPrintf("Dram: mvDramBankInfoGet bad params \n")); + return MV_BAD_PARAM; + } + memset(pBankInfo, 0, sizeof(*pBankInfo)); + + if ( MV_OK != dimmSpdGet((MV_U32)(bankNum/2), &dimmInfo)) + { + DB(mvOsPrintf("Dram: ERR dimmSpdGet failed to get dimm info \n")); + return MV_FAIL; + } + if ((dimmInfo.numOfModuleBanks == 1) && ((bankNum % 2) == 1)) + { + DB(mvOsPrintf("Dram: ERR dimmSpdGet. Can't find DIMM bank 2 \n")); + return MV_FAIL; + } + /* convert Dimm info to Bank info */ + cpyDimm2BankInfo(&dimmInfo, pBankInfo); + return MV_OK; +} + +/******************************************************************************* +* cpyDimm2BankInfo - Convert a Dimm info struct into a bank info struct. +* +* DESCRIPTION: +* Convert a Dimm info struct into a bank info struct. +* +* INPUT: +* pDimmInfo - DIMM information structure. +* +* OUTPUT: +* pBankInfo - DRAM bank information struct. +* +* RETURN: +* None. +* +*******************************************************************************/ +static MV_VOID cpyDimm2BankInfo(MV_DIMM_INFO *pDimmInfo, + MV_DRAM_BANK_INFO *pBankInfo) +{ + pBankInfo->memoryType = pDimmInfo->memoryType; + + /* DIMM dimensions */ + pBankInfo->numOfRowAddr = pDimmInfo->numOfRowAddr; + pBankInfo->numOfColAddr = pDimmInfo->numOfColAddr; + pBankInfo->dataWidth = pDimmInfo->dataWidth; + pBankInfo->errorCheckType = pDimmInfo->errorCheckType; + pBankInfo->sdramWidth = pDimmInfo->sdramWidth; + pBankInfo->errorCheckDataWidth = pDimmInfo->errorCheckDataWidth; + pBankInfo->numOfBanksOnEachDevice = pDimmInfo->numOfBanksOnEachDevice; + pBankInfo->suportedCasLatencies = pDimmInfo->suportedCasLatencies; + pBankInfo->refreshInterval = pDimmInfo->refreshInterval; + + /* DIMM timing parameters */ + pBankInfo->minCycleTimeAtMaxCasLatPs = pDimmInfo->minCycleTimeAtMaxCasLatPs; + pBankInfo->minCycleTimeAtMaxCasLatMinus1Ps = + pDimmInfo->minCycleTimeAtMaxCasLatMinus1Ps; + pBankInfo->minCycleTimeAtMaxCasLatMinus2Ps = + pDimmInfo->minCycleTimeAtMaxCasLatMinus2Ps; + + pBankInfo->minRowPrechargeTime = pDimmInfo->minRowPrechargeTime; + pBankInfo->minRowActiveToRowActive = pDimmInfo->minRowActiveToRowActive; + pBankInfo->minRasToCasDelay = pDimmInfo->minRasToCasDelay; + pBankInfo->minRasPulseWidth = pDimmInfo->minRasPulseWidth; + pBankInfo->minWriteRecoveryTime = pDimmInfo->minWriteRecoveryTime; + pBankInfo->minWriteToReadCmdDelay = pDimmInfo->minWriteToReadCmdDelay; + pBankInfo->minReadToPrechCmdDelay = pDimmInfo->minReadToPrechCmdDelay; + pBankInfo->minRefreshToActiveCmd = pDimmInfo->minRefreshToActiveCmd; + + /* Parameters calculated from the extracted DIMM information */ + pBankInfo->size = pDimmInfo->size/pDimmInfo->numOfModuleBanks; + pBankInfo->deviceDensity = pDimmInfo->deviceDensity; + pBankInfo->numberOfDevices = pDimmInfo->numberOfDevices / + pDimmInfo->numOfModuleBanks; + + /* DIMM attributes (MV_TRUE for yes) */ + + if ((pDimmInfo->memoryType == MEM_TYPE_SDRAM) || + (pDimmInfo->memoryType == MEM_TYPE_DDR1) ) + { + if (pDimmInfo->dimmAttributes & BIT1) + pBankInfo->registeredAddrAndControlInputs = MV_TRUE; + else + pBankInfo->registeredAddrAndControlInputs = MV_FALSE; + } + else /* pDimmInfo->memoryType == MEM_TYPE_DDR2 */ + { + if (pDimmInfo->dimmTypeInfo & (BIT0 | BIT4)) + pBankInfo->registeredAddrAndControlInputs = MV_TRUE; + else + pBankInfo->registeredAddrAndControlInputs = MV_FALSE; + } + + return; +} +/******************************************************************************* +* dimmSpdCpy - Cpy SPD parameters from dimm 0 to dimm 1. +* +* DESCRIPTION: +* Read the DIMM SPD parameters from dimm 0 into dimm 1 SPD. +* +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_TRUE if function could read DIMM parameters, MV_FALSE otherwise. +* +*******************************************************************************/ +MV_STATUS dimmSpdCpy(MV_VOID) +{ + MV_U32 i; + MV_U32 spdChecksum; + + MV_TWSI_SLAVE twsiSlave; + MV_U8 data[SPD_SIZE]; + + /* zero dimmInfo structure */ + memset(data, 0, SPD_SIZE); + + /* read the dimm eeprom */ + DB(mvOsPrintf("DRAM: Read Dimm eeprom\n")); + twsiSlave.slaveAddr.address = MV_BOARD_DIMM0_I2C_ADDR; + twsiSlave.slaveAddr.type = ADDR7_BIT; + twsiSlave.validOffset = MV_TRUE; + twsiSlave.offset = 0; + twsiSlave.moreThen256 = MV_FALSE; + + if( MV_OK != mvTwsiRead (MV_BOARD_DIMM_I2C_CHANNEL, &twsiSlave, data, SPD_SIZE) ) + { + DB(mvOsPrintf("DRAM: ERR. no DIMM in dimmNum 0\n")); + return MV_FAIL; + } + DB(puts("DRAM: Reading dimm info succeded.\n")); + + /* calculate SPD checksum */ + spdChecksum = 0; + + for(i = 0 ; i <= 62 ; i++) + { + spdChecksum += data[i]; + } + + if ((spdChecksum & 0xff) != data[63]) + { + DB(mvOsPrintf("DRAM: Warning. Wrong SPD Checksum %2x, expValue=%2x\n", + (MV_U32)(spdChecksum & 0xff), data[63])); + } + else + { + DB(mvOsPrintf("DRAM: SPD Checksum ok!\n")); + } + + /* copy the SPD content 1:1 into the DIMM 1 SPD */ + twsiSlave.slaveAddr.address = MV_BOARD_DIMM1_I2C_ADDR; + twsiSlave.slaveAddr.type = ADDR7_BIT; + twsiSlave.validOffset = MV_TRUE; + twsiSlave.offset = 0; + twsiSlave.moreThen256 = MV_FALSE; + + for(i = 0 ; i < SPD_SIZE ; i++) + { + twsiSlave.offset = i; + if( MV_OK != mvTwsiWrite (MV_BOARD_DIMM_I2C_CHANNEL, &twsiSlave, &data[i], 1) ) + { + mvOsPrintf("DRAM: ERR. no DIMM in dimmNum 1 byte %d \n",i); + return MV_FAIL; + } + mvOsDelay(5); + } + + DB(puts("DRAM: Reading dimm info succeded.\n")); + return MV_OK; +} + +/******************************************************************************* +* dimmSpdGet - Get the SPD parameters. +* +* DESCRIPTION: +* Read the DIMM SPD parameters into given struct parameter. +* +* INPUT: +* dimmNum - DIMM number. See MV_BOARD_DIMM_NUM enumerator. +* +* OUTPUT: +* pDimmInfo - DIMM information structure. +* +* RETURN: +* MV_TRUE if function could read DIMM parameters, MV_FALSE otherwise. +* +*******************************************************************************/ +MV_STATUS dimmSpdGet(MV_U32 dimmNum, MV_DIMM_INFO *pDimmInfo) +{ + MV_U32 i; + MV_U32 density = 1; + MV_U32 spdChecksum; + + MV_TWSI_SLAVE twsiSlave; + MV_U8 data[SPD_SIZE]; + + if((NULL == pDimmInfo)|| (dimmNum >= MAX_DIMM_NUM)) + { + DB(mvOsPrintf("Dram: mvDramBankInfoGet bad params \n")); + return MV_BAD_PARAM; + } + + /* zero dimmInfo structure */ + memset(data, 0, SPD_SIZE); + + /* read the dimm eeprom */ + DB(mvOsPrintf("DRAM: Read Dimm eeprom\n")); + twsiSlave.slaveAddr.address = (dimmNum == 0) ? + MV_BOARD_DIMM0_I2C_ADDR : MV_BOARD_DIMM1_I2C_ADDR; + twsiSlave.slaveAddr.type = ADDR7_BIT; + twsiSlave.validOffset = MV_TRUE; + twsiSlave.offset = 0; + twsiSlave.moreThen256 = MV_FALSE; + + if( MV_OK != mvTwsiRead (MV_BOARD_DIMM_I2C_CHANNEL, &twsiSlave, data, SPD_SIZE) ) + { + DB(mvOsPrintf("DRAM: ERR. no DIMM in dimmNum %d \n", dimmNum)); + return MV_FAIL; + } + DB(puts("DRAM: Reading dimm info succeded.\n")); + + /* calculate SPD checksum */ + spdChecksum = 0; + + for(i = 0 ; i <= 62 ; i++) + { + spdChecksum += data[i]; + } + + if ((spdChecksum & 0xff) != data[63]) + { + DB(mvOsPrintf("DRAM: Warning. Wrong SPD Checksum %2x, expValue=%2x\n", + (MV_U32)(spdChecksum & 0xff), data[63])); + } + else + { + DB(mvOsPrintf("DRAM: SPD Checksum ok!\n")); + } + + /* copy the SPD content 1:1 into the dimmInfo structure*/ + for(i = 0 ; i < SPD_SIZE ; i++) + { + pDimmInfo->spdRawData[i] = data[i]; + DB(mvOsPrintf("SPD-EEPROM Byte %3d = %3x (%3d)\n",i, data[i], data[i])); + } + + DB(mvOsPrintf("DRAM SPD Information:\n")); + + /* Memory type (DDR / SDRAM) */ + switch (data[DIMM_MEM_TYPE]) + { + case (DIMM_MEM_TYPE_SDRAM): + pDimmInfo->memoryType = MEM_TYPE_SDRAM; + DB(mvOsPrintf("DRAM Memeory type SDRAM\n")); + break; + case (DIMM_MEM_TYPE_DDR1): + pDimmInfo->memoryType = MEM_TYPE_DDR1; + DB(mvOsPrintf("DRAM Memeory type DDR1\n")); + break; + case (DIMM_MEM_TYPE_DDR2): + pDimmInfo->memoryType = MEM_TYPE_DDR2; + DB(mvOsPrintf("DRAM Memeory type DDR2\n")); + break; + default: + mvOsPrintf("ERROR: Undefined memory type!\n"); + return MV_ERROR; + } + + + /* Number Of Row Addresses */ + pDimmInfo->numOfRowAddr = data[DIMM_ROW_NUM]; + DB(mvOsPrintf("DRAM numOfRowAddr[3] %d\n",pDimmInfo->numOfRowAddr)); + + /* Number Of Column Addresses */ + pDimmInfo->numOfColAddr = data[DIMM_COL_NUM]; + DB(mvOsPrintf("DRAM numOfColAddr[4] %d\n",pDimmInfo->numOfColAddr)); + + /* Number Of Module Banks */ + pDimmInfo->numOfModuleBanks = data[DIMM_MODULE_BANK_NUM]; + DB(mvOsPrintf("DRAM numOfModuleBanks[5] 0x%x\n", + pDimmInfo->numOfModuleBanks)); + + /* Number of module banks encoded differently for DDR2 */ + if (pDimmInfo->memoryType == MEM_TYPE_DDR2) + pDimmInfo->numOfModuleBanks = (pDimmInfo->numOfModuleBanks & 0x7)+1; + + /* Data Width */ + pDimmInfo->dataWidth = data[DIMM_DATA_WIDTH]; + DB(mvOsPrintf("DRAM dataWidth[6] 0x%x\n", pDimmInfo->dataWidth)); + + /* Minimum Cycle Time At Max CasLatancy */ + pDimmInfo->minCycleTimeAtMaxCasLatPs = cas2ps(data[DIMM_MIN_CC_AT_MAX_CAS]); + + /* Error Check Type */ + pDimmInfo->errorCheckType = data[DIMM_ERR_CHECK_TYPE]; + DB(mvOsPrintf("DRAM errorCheckType[11] 0x%x\n", + pDimmInfo->errorCheckType)); + + /* Refresh Interval */ + pDimmInfo->refreshInterval = data[DIMM_REFRESH_INTERVAL]; + DB(mvOsPrintf("DRAM refreshInterval[12] 0x%x\n", + pDimmInfo->refreshInterval)); + + /* Sdram Width */ + pDimmInfo->sdramWidth = data[DIMM_SDRAM_WIDTH]; + DB(mvOsPrintf("DRAM sdramWidth[13] 0x%x\n",pDimmInfo->sdramWidth)); + + /* Error Check Data Width */ + pDimmInfo->errorCheckDataWidth = data[DIMM_ERR_CHECK_DATA_WIDTH]; + DB(mvOsPrintf("DRAM errorCheckDataWidth[14] 0x%x\n", + pDimmInfo->errorCheckDataWidth)); + + /* Burst Length Supported */ + /* SDRAM/DDR1: + *******-******-******-******-******-******-******-******* + * bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 * + *******-******-******-******-******-******-******-******* + burst length = * Page | TBD | TBD | TBD | 8 | 4 | 2 | 1 * + *********************************************************/ + /* DDR2: + *******-******-******-******-******-******-******-******* + * bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 * + *******-******-******-******-******-******-******-******* + burst length = * Page | TBD | TBD | TBD | 8 | 4 | TBD | TBD * + *********************************************************/ + + pDimmInfo->burstLengthSupported = data[DIMM_BURST_LEN_SUP]; + DB(mvOsPrintf("DRAM burstLengthSupported[16] 0x%x\n", + pDimmInfo->burstLengthSupported)); + + /* Number Of Banks On Each Device */ + pDimmInfo->numOfBanksOnEachDevice = data[DIMM_DEV_BANK_NUM]; + DB(mvOsPrintf("DRAM numOfBanksOnEachDevice[17] 0x%x\n", + pDimmInfo->numOfBanksOnEachDevice)); + + /* Suported Cas Latencies */ + + /* SDRAM: + *******-******-******-******-******-******-******-******* + * bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 * + *******-******-******-******-******-******-******-******* + CAS = * TBD | 7 | 6 | 5 | 4 | 3 | 2 | 1 * + ********************************************************/ + + /* DDR 1: + *******-******-******-******-******-******-******-******* + * bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 * + *******-******-******-******-******-******-******-******* + CAS = * TBD | 4 | 3.5 | 3 | 2.5 | 2 | 1.5 | 1 * + *********************************************************/ + + /* DDR 2: + *******-******-******-******-******-******-******-******* + * bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 * + *******-******-******-******-******-******-******-******* + CAS = * TBD | TBD | 5 | 4 | 3 | 2 | TBD | TBD * + *********************************************************/ + + pDimmInfo->suportedCasLatencies = data[DIMM_SUP_CAL]; + DB(mvOsPrintf("DRAM suportedCasLatencies[18] 0x%x\n", + pDimmInfo->suportedCasLatencies)); + + /* For DDR2 only, get the DIMM type information */ + if (pDimmInfo->memoryType == MEM_TYPE_DDR2) + { + pDimmInfo->dimmTypeInfo = data[DIMM_DDR2_TYPE_INFORMATION]; + DB(mvOsPrintf("DRAM dimmTypeInfo[20] (DDR2) 0x%x\n", + pDimmInfo->dimmTypeInfo)); + } + + /* SDRAM Modules Attributes */ + pDimmInfo->dimmAttributes = data[DIMM_BUF_ADDR_CONT_IN]; + DB(mvOsPrintf("DRAM dimmAttributes[21] 0x%x\n", + pDimmInfo->dimmAttributes)); + + /* Minimum Cycle Time At Max CasLatancy Minus 1*/ + pDimmInfo->minCycleTimeAtMaxCasLatMinus1Ps = + cas2ps(data[DIMM_MIN_CC_AT_MAX_CAS_MINUS1]); + + /* Minimum Cycle Time At Max CasLatancy Minus 2*/ + pDimmInfo->minCycleTimeAtMaxCasLatMinus2Ps = + cas2ps(data[DIMM_MIN_CC_AT_MAX_CAS_MINUS2]); + + pDimmInfo->minRowPrechargeTime = data[DIMM_MIN_ROW_PRECHARGE_TIME]; + DB(mvOsPrintf("DRAM minRowPrechargeTime[27] 0x%x\n", + pDimmInfo->minRowPrechargeTime)); + pDimmInfo->minRowActiveToRowActive = data[DIMM_MIN_ROW_ACTIVE_TO_ROW_ACTIVE]; + DB(mvOsPrintf("DRAM minRowActiveToRowActive[28] 0x%x\n", + pDimmInfo->minRowActiveToRowActive)); + pDimmInfo->minRasToCasDelay = data[DIMM_MIN_RAS_TO_CAS_DELAY]; + DB(mvOsPrintf("DRAM minRasToCasDelay[29] 0x%x\n", + pDimmInfo->minRasToCasDelay)); + pDimmInfo->minRasPulseWidth = data[DIMM_MIN_RAS_PULSE_WIDTH]; + DB(mvOsPrintf("DRAM minRasPulseWidth[30] 0x%x\n", + pDimmInfo->minRasPulseWidth)); + + /* DIMM Bank Density */ + pDimmInfo->dimmBankDensity = data[DIMM_BANK_DENSITY]; + DB(mvOsPrintf("DRAM dimmBankDensity[31] 0x%x\n", + pDimmInfo->dimmBankDensity)); + + /* Only DDR2 includes Write Recovery Time field. Other SDRAM ignore */ + pDimmInfo->minWriteRecoveryTime = data[DIMM_MIN_WRITE_RECOVERY_TIME]; + DB(mvOsPrintf("DRAM minWriteRecoveryTime[36] 0x%x\n", + pDimmInfo->minWriteRecoveryTime)); + + /* Only DDR2 includes Internal Write To Read Command Delay field. */ + pDimmInfo->minWriteToReadCmdDelay = data[DIMM_MIN_WRITE_TO_READ_CMD_DELAY]; + DB(mvOsPrintf("DRAM minWriteToReadCmdDelay[37] 0x%x\n", + pDimmInfo->minWriteToReadCmdDelay)); + + /* Only DDR2 includes Internal Read To Precharge Command Delay field. */ + pDimmInfo->minReadToPrechCmdDelay = data[DIMM_MIN_READ_TO_PRECH_CMD_DELAY]; + DB(mvOsPrintf("DRAM minReadToPrechCmdDelay[38] 0x%x\n", + pDimmInfo->minReadToPrechCmdDelay)); + + /* Only DDR2 includes Minimum Refresh to Activate/Refresh Command field */ + pDimmInfo->minRefreshToActiveCmd = data[DIMM_MIN_REFRESH_TO_ACTIVATE_CMD]; + DB(mvOsPrintf("DRAM minRefreshToActiveCmd[42] 0x%x\n", + pDimmInfo->minRefreshToActiveCmd)); + + /* calculating the sdram density. Representing device density from */ + /* bit 20 to allow representation of 4GB and above. */ + /* For example, if density is 512Mbit 0x20000000, will be represent in */ + /* deviceDensity by 0x20000000 >> 16 --> 0x00000200. Another example */ + /* is density 8GB 0x200000000 >> 16 --> 0x00002000. */ + density = (1 << ((pDimmInfo->numOfRowAddr + pDimmInfo->numOfColAddr) - 20)); + pDimmInfo->deviceDensity = density * + pDimmInfo->numOfBanksOnEachDevice * + pDimmInfo->sdramWidth; + DB(mvOsPrintf("DRAM deviceDensity %d\n",pDimmInfo->deviceDensity)); + + /* Number of devices includeing Error correction */ + pDimmInfo->numberOfDevices = (pDimmInfo->dataWidth/pDimmInfo->sdramWidth) * + pDimmInfo->numOfModuleBanks; + DB(mvOsPrintf("DRAM numberOfDevices %d\n", + pDimmInfo->numberOfDevices)); + + pDimmInfo->size = 0; + + /* Note that pDimmInfo->size is in MB units */ + if (pDimmInfo->memoryType == MEM_TYPE_SDRAM) + { + if (pDimmInfo->dimmBankDensity & BIT0) + pDimmInfo->size += 1024; /* Equal to 1GB */ + else if (pDimmInfo->dimmBankDensity & BIT1) + pDimmInfo->size += 8; /* Equal to 8MB */ + else if (pDimmInfo->dimmBankDensity & BIT2) + pDimmInfo->size += 16; /* Equal to 16MB */ + else if (pDimmInfo->dimmBankDensity & BIT3) + pDimmInfo->size += 32; /* Equal to 32MB */ + else if (pDimmInfo->dimmBankDensity & BIT4) + pDimmInfo->size += 64; /* Equal to 64MB */ + else if (pDimmInfo->dimmBankDensity & BIT5) + pDimmInfo->size += 128; /* Equal to 128MB */ + else if (pDimmInfo->dimmBankDensity & BIT6) + pDimmInfo->size += 256; /* Equal to 256MB */ + else if (pDimmInfo->dimmBankDensity & BIT7) + pDimmInfo->size += 512; /* Equal to 512MB */ + } + else if (pDimmInfo->memoryType == MEM_TYPE_DDR1) + { + if (pDimmInfo->dimmBankDensity & BIT0) + pDimmInfo->size += 1024; /* Equal to 1GB */ + else if (pDimmInfo->dimmBankDensity & BIT1) + pDimmInfo->size += 2048; /* Equal to 2GB */ + else if (pDimmInfo->dimmBankDensity & BIT2) + pDimmInfo->size += 16; /* Equal to 16MB */ + else if (pDimmInfo->dimmBankDensity & BIT3) + pDimmInfo->size += 32; /* Equal to 32MB */ + else if (pDimmInfo->dimmBankDensity & BIT4) + pDimmInfo->size += 64; /* Equal to 64MB */ + else if (pDimmInfo->dimmBankDensity & BIT5) + pDimmInfo->size += 128; /* Equal to 128MB */ + else if (pDimmInfo->dimmBankDensity & BIT6) + pDimmInfo->size += 256; /* Equal to 256MB */ + else if (pDimmInfo->dimmBankDensity & BIT7) + pDimmInfo->size += 512; /* Equal to 512MB */ + } + else /* if (dimmInfo.memoryType == MEM_TYPE_DDR2) */ + { + if (pDimmInfo->dimmBankDensity & BIT0) + pDimmInfo->size += 1024; /* Equal to 1GB */ + else if (pDimmInfo->dimmBankDensity & BIT1) + pDimmInfo->size += 2048; /* Equal to 2GB */ + else if (pDimmInfo->dimmBankDensity & BIT2) + pDimmInfo->size += 4096; /* Equal to 4GB */ + else if (pDimmInfo->dimmBankDensity & BIT3) + pDimmInfo->size += 8192; /* Equal to 8GB */ + else if (pDimmInfo->dimmBankDensity & BIT4) + pDimmInfo->size += 16384; /* Equal to 16GB */ + else if (pDimmInfo->dimmBankDensity & BIT5) + pDimmInfo->size += 128; /* Equal to 128MB */ + else if (pDimmInfo->dimmBankDensity & BIT6) + pDimmInfo->size += 256; /* Equal to 256MB */ + else if (pDimmInfo->dimmBankDensity & BIT7) + pDimmInfo->size += 512; /* Equal to 512MB */ + } + + pDimmInfo->size *= pDimmInfo->numOfModuleBanks; + + DB(mvOsPrintf("Dram: dimm size %dMB \n",pDimmInfo->size)); + + return MV_OK; +} + +/******************************************************************************* +* dimmSpdPrint - Print the SPD parameters. +* +* DESCRIPTION: +* Print the Dimm SPD parameters. +* +* INPUT: +* pDimmInfo - DIMM information structure. +* +* OUTPUT: +* None. +* +* RETURN: +* None. +* +*******************************************************************************/ +MV_VOID dimmSpdPrint(MV_U32 dimmNum) +{ + MV_DIMM_INFO dimmInfo; + MV_U32 i, temp = 0; + MV_U32 k, maskLeftOfPoint = 0, maskRightOfPoint = 0; + MV_U32 rightOfPoint = 0,leftOfPoint = 0, div, time_tmp, shift; + MV_U32 busClkPs; + MV_U8 trp_clocks=0, trcd_clocks, tras_clocks, trrd_clocks, + temp_buf[40], *spdRawData; + + busClkPs = 1000000000 / (mvBoardSysClkGet() / 100); /* in 10 ps units */ + + spdRawData = dimmInfo.spdRawData; + + if(MV_OK != dimmSpdGet(dimmNum, &dimmInfo)) + { + mvOsOutput("ERROR: Could not read SPD information!\n"); + return; + } + + /* find Manufactura of Dimm Module */ + mvOsOutput("\nManufacturer's JEDEC ID Code: "); + for(i = 0 ; i < DIMM_MODULE_MANU_SIZE ; i++) + { + mvOsOutput("%x",spdRawData[DIMM_MODULE_MANU_OFFS + i]); + } + mvOsOutput("\n"); + + /* Manufacturer's Specific Data */ + for(i = 0 ; i < DIMM_MODULE_ID_SIZE ; i++) + { + temp_buf[i] = spdRawData[DIMM_MODULE_ID_OFFS + i]; + } + mvOsOutput("Manufacturer's Specific Data: %s\n", temp_buf); + + /* Module Part Number */ + for(i = 0 ; i < DIMM_MODULE_VEN_SIZE ; i++) + { + temp_buf[i] = spdRawData[DIMM_MODULE_VEN_OFFS + i]; + } + mvOsOutput("Module Part Number: %s\n", temp_buf); + + /* Module Serial Number */ + for(i = 0; i < sizeof(MV_U32); i++) + { + temp |= spdRawData[95+i] << 8*i; + } + mvOsOutput("DIMM Serial No. %ld (%lx)\n", (long)temp, + (long)temp); + + /* find Manufac-Data of Dimm Module */ + mvOsOutput("Manufactoring Date: Year 20%d%d/ ww %d%d\n", + ((spdRawData[93] & 0xf0) >> 4), (spdRawData[93] & 0xf), + ((spdRawData[94] & 0xf0) >> 4), (spdRawData[94] & 0xf)); + /* find modul_revision of Dimm Module */ + mvOsOutput("Module Revision: %d.%d\n", + spdRawData[62]/10, spdRawData[62]%10); + + /* find manufac_place of Dimm Module */ + mvOsOutput("manufac_place: %d\n", spdRawData[72]); + + /* go over the first 35 I2C data bytes */ + for(i = 2 ; i <= 35 ; i++) + switch(i) + { + case 2: /* Memory type (DDR1/2 / SDRAM) */ + if (dimmInfo.memoryType == MEM_TYPE_SDRAM) + mvOsOutput("Dram Type is: SDRAM\n"); + else if (dimmInfo.memoryType == MEM_TYPE_DDR1) + mvOsOutput("Dram Type is: SDRAM DDR1\n"); + else if (dimmInfo.memoryType == MEM_TYPE_DDR2) + mvOsOutput("Dram Type is: SDRAM DDR2\n"); + else + mvOsOutput("Dram Type unknown\n"); + break; +/*----------------------------------------------------------------------------*/ + + case 3: /* Number Of Row Addresses */ + mvOsOutput("Module Number of row addresses: %d\n", + dimmInfo.numOfRowAddr); + break; +/*----------------------------------------------------------------------------*/ + + case 4: /* Number Of Column Addresses */ + mvOsOutput("Module Number of col addresses: %d\n", + dimmInfo.numOfColAddr); + break; +/*----------------------------------------------------------------------------*/ + + case 5: /* Number Of Module Banks */ + mvOsOutput("Number of Banks on Mod.: %d\n", + dimmInfo.numOfModuleBanks); + break; +/*----------------------------------------------------------------------------*/ + + case 6: /* Data Width */ + mvOsOutput("Module Data Width: %d bit\n", + dimmInfo.dataWidth); + break; +/*----------------------------------------------------------------------------*/ + + case 8: /* Voltage Interface */ + switch(spdRawData[i]) + { + case 0x0: + mvOsOutput("Module is TTL_5V_TOLERANT\n"); + break; + case 0x1: + mvOsOutput("Module is LVTTL\n"); + break; + case 0x2: + mvOsOutput("Module is HSTL_1_5V\n"); + break; + case 0x3: + mvOsOutput("Module is SSTL_3_3V\n"); + break; + case 0x4: + mvOsOutput("Module is SSTL_2_5V\n"); + break; + case 0x5: + if (dimmInfo.memoryType != MEM_TYPE_SDRAM) + { + mvOsOutput("Module is SSTL_1_8V\n"); + break; + } + default: + mvOsOutput("Module is VOLTAGE_UNKNOWN\n"); + break; + } + break; +/*----------------------------------------------------------------------------*/ + + case 9: /* Minimum Cycle Time At Max CasLatancy */ + leftOfPoint = (spdRawData[i] & 0xf0) >> 4; + rightOfPoint = (spdRawData[i] & 0x0f) * 10; + + /* DDR2 addition of right of point */ + if ((spdRawData[i] & 0x0f) == 0xA) + { + rightOfPoint = 25; + } + if ((spdRawData[i] & 0x0f) == 0xB) + { + rightOfPoint = 33; + } + if ((spdRawData[i] & 0x0f) == 0xC) + { + rightOfPoint = 66; + } + if ((spdRawData[i] & 0x0f) == 0xD) + { + rightOfPoint = 75; + } + mvOsOutput("Minimum Cycle Time At Max CL: %d.%d [ns]\n", + leftOfPoint, rightOfPoint); + break; +/*----------------------------------------------------------------------------*/ + + case 10: /* Clock To Data Out */ + div = (dimmInfo.memoryType == MEM_TYPE_SDRAM)? 10:100; + time_tmp = (((spdRawData[i] & 0xf0) >> 4)*10) + + ((spdRawData[i] & 0x0f)); + leftOfPoint = time_tmp / div; + rightOfPoint = time_tmp % div; + mvOsOutput("Clock To Data Out: %d.%d [ns]\n", + leftOfPoint, rightOfPoint); + break; +/*----------------------------------------------------------------------------*/ + + case 11: /* Error Check Type */ + mvOsOutput("Error Check Type (0=NONE): %d\n", + dimmInfo.errorCheckType); + break; +/*----------------------------------------------------------------------------*/ + + case 12: /* Refresh Interval */ + mvOsOutput("Refresh Rate: %x\n", + dimmInfo.refreshInterval); + break; +/*----------------------------------------------------------------------------*/ + + case 13: /* Sdram Width */ + mvOsOutput("Sdram Width: %d bits\n", + dimmInfo.sdramWidth); + break; +/*----------------------------------------------------------------------------*/ + + case 14: /* Error Check Data Width */ + mvOsOutput("Error Check Data Width: %d bits\n", + dimmInfo.errorCheckDataWidth); + break; +/*----------------------------------------------------------------------------*/ + + case 15: /* Minimum Clock Delay is unsupported */ + if ((dimmInfo.memoryType == MEM_TYPE_SDRAM) || + (dimmInfo.memoryType == MEM_TYPE_DDR1)) + { + mvOsOutput("Minimum Clk Delay back to back: %d\n", + spdRawData[i]); + } + break; +/*----------------------------------------------------------------------------*/ + + case 16: /* Burst Length Supported */ + /* SDRAM/DDR1: + *******-******-******-******-******-******-******-******* + * bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 * + *******-******-******-******-******-******-******-******* + burst length = * Page | TBD | TBD | TBD | 8 | 4 | 2 | 1 * + *********************************************************/ + /* DDR2: + *******-******-******-******-******-******-******-******* + * bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 * + *******-******-******-******-******-******-******-******* + burst length = * Page | TBD | TBD | TBD | 8 | 4 | TBD | TBD * + *********************************************************/ + mvOsOutput("Burst Length Supported: "); + if ((dimmInfo.memoryType == MEM_TYPE_SDRAM) || + (dimmInfo.memoryType == MEM_TYPE_DDR1)) + { + if (dimmInfo.burstLengthSupported & BIT0) + mvOsOutput("1, "); + if (dimmInfo.burstLengthSupported & BIT1) + mvOsOutput("2, "); + } + if (dimmInfo.burstLengthSupported & BIT2) + mvOsOutput("4, "); + if (dimmInfo.burstLengthSupported & BIT3) + mvOsOutput("8, "); + + mvOsOutput(" Bit \n"); + break; +/*----------------------------------------------------------------------------*/ + + case 17: /* Number Of Banks On Each Device */ + mvOsOutput("Number Of Banks On Each Chip: %d\n", + dimmInfo.numOfBanksOnEachDevice); + break; +/*----------------------------------------------------------------------------*/ + + case 18: /* Suported Cas Latencies */ + + /* SDRAM: + *******-******-******-******-******-******-******-******* + * bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 * + *******-******-******-******-******-******-******-******* + CAS = * TBD | 7 | 6 | 5 | 4 | 3 | 2 | 1 * + ********************************************************/ + + /* DDR 1: + *******-******-******-******-******-******-******-******* + * bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 * + *******-******-******-******-******-******-******-******* + CAS = * TBD | 4 | 3.5 | 3 | 2.5 | 2 | 1.5 | 1 * + *********************************************************/ + + /* DDR 2: + *******-******-******-******-******-******-******-******* + * bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 * + *******-******-******-******-******-******-******-******* + CAS = * TBD | TBD | 5 | 4 | 3 | 2 | TBD | TBD * + *********************************************************/ + + mvOsOutput("Suported Cas Latencies: (CL) "); + if (dimmInfo.memoryType == MEM_TYPE_SDRAM) + { + for (k = 0; k <=7; k++) + { + if (dimmInfo.suportedCasLatencies & (1 << k)) + mvOsOutput("%d, ", k+1); + } + } + else if (dimmInfo.memoryType == MEM_TYPE_DDR1) + { + if (dimmInfo.suportedCasLatencies & BIT0) + mvOsOutput("1, "); + if (dimmInfo.suportedCasLatencies & BIT1) + mvOsOutput("1.5, "); + if (dimmInfo.suportedCasLatencies & BIT2) + mvOsOutput("2, "); + if (dimmInfo.suportedCasLatencies & BIT3) + mvOsOutput("2.5, "); + if (dimmInfo.suportedCasLatencies & BIT4) + mvOsOutput("3, "); + if (dimmInfo.suportedCasLatencies & BIT5) + mvOsOutput("3.5, "); + } + else if (dimmInfo.memoryType == MEM_TYPE_DDR2) + { + if (dimmInfo.suportedCasLatencies & BIT2) + mvOsOutput("2, "); + if (dimmInfo.suportedCasLatencies & BIT3) + mvOsOutput("3, "); + if (dimmInfo.suportedCasLatencies & BIT4) + mvOsOutput("4, "); + if (dimmInfo.suportedCasLatencies & BIT5) + mvOsOutput("5, "); + } + else + mvOsOutput("?.?, "); + mvOsOutput("\n"); + break; +/*----------------------------------------------------------------------------*/ + + case 20: /* DDR2 DIMM type info */ + if (dimmInfo.memoryType == MEM_TYPE_DDR2) + { + if (dimmInfo.dimmTypeInfo & (BIT0 | BIT4)) + mvOsOutput("Registered DIMM (RDIMM)\n"); + else if (dimmInfo.dimmTypeInfo & (BIT1 | BIT5)) + mvOsOutput("Unbuffered DIMM (UDIMM)\n"); + else + mvOsOutput("Unknown DIMM type.\n"); + } + + break; +/*----------------------------------------------------------------------------*/ + + case 21: /* SDRAM Modules Attributes */ + mvOsOutput("\nModule Attributes (SPD Byte 21): \n"); + + if (dimmInfo.memoryType == MEM_TYPE_SDRAM) + { + if (dimmInfo.dimmAttributes & BIT0) + mvOsOutput(" Buffered Addr/Control Input: Yes\n"); + else + mvOsOutput(" Buffered Addr/Control Input: No\n"); + + if (dimmInfo.dimmAttributes & BIT1) + mvOsOutput(" Registered Addr/Control Input: Yes\n"); + else + mvOsOutput(" Registered Addr/Control Input: No\n"); + + if (dimmInfo.dimmAttributes & BIT2) + mvOsOutput(" On-Card PLL (clock): Yes \n"); + else + mvOsOutput(" On-Card PLL (clock): No \n"); + + if (dimmInfo.dimmAttributes & BIT3) + mvOsOutput(" Bufferd DQMB Input: Yes \n"); + else + mvOsOutput(" Bufferd DQMB Inputs: No \n"); + + if (dimmInfo.dimmAttributes & BIT4) + mvOsOutput(" Registered DQMB Inputs: Yes \n"); + else + mvOsOutput(" Registered DQMB Inputs: No \n"); + + if (dimmInfo.dimmAttributes & BIT5) + mvOsOutput(" Differential Clock Input: Yes \n"); + else + mvOsOutput(" Differential Clock Input: No \n"); + + if (dimmInfo.dimmAttributes & BIT6) + mvOsOutput(" redundant Row Addressing: Yes \n"); + else + mvOsOutput(" redundant Row Addressing: No \n"); + } + else if (dimmInfo.memoryType == MEM_TYPE_DDR1) + { + if (dimmInfo.dimmAttributes & BIT0) + mvOsOutput(" Buffered Addr/Control Input: Yes\n"); + else + mvOsOutput(" Buffered Addr/Control Input: No\n"); + + if (dimmInfo.dimmAttributes & BIT1) + mvOsOutput(" Registered Addr/Control Input: Yes\n"); + else + mvOsOutput(" Registered Addr/Control Input: No\n"); + + if (dimmInfo.dimmAttributes & BIT2) + mvOsOutput(" On-Card PLL (clock): Yes \n"); + else + mvOsOutput(" On-Card PLL (clock): No \n"); + + if (dimmInfo.dimmAttributes & BIT3) + mvOsOutput(" FET Switch On-Card Enabled: Yes \n"); + else + mvOsOutput(" FET Switch On-Card Enabled: No \n"); + + if (dimmInfo.dimmAttributes & BIT4) + mvOsOutput(" FET Switch External Enabled: Yes \n"); + else + mvOsOutput(" FET Switch External Enabled: No \n"); + + if (dimmInfo.dimmAttributes & BIT5) + mvOsOutput(" Differential Clock Input: Yes \n"); + else + mvOsOutput(" Differential Clock Input: No \n"); + } + else /* if (dimmInfo.memoryType == MEM_TYPE_DDR2) */ + { + mvOsOutput(" Number of Active Registers on the DIMM: %d\n", + (dimmInfo.dimmAttributes & 0x3) + 1); + + mvOsOutput(" Number of PLLs on the DIMM: %d\n", + ((dimmInfo.dimmAttributes) >> 2) & 0x3); + + if (dimmInfo.dimmAttributes & BIT4) + mvOsOutput(" FET Switch External Enabled: Yes \n"); + else + mvOsOutput(" FET Switch External Enabled: No \n"); + + if (dimmInfo.dimmAttributes & BIT6) + mvOsOutput(" Analysis probe installed: Yes \n"); + else + mvOsOutput(" Analysis probe installed: No \n"); + } + + break; +/*----------------------------------------------------------------------------*/ + + case 22: /* Suported AutoPreCharge */ + mvOsOutput("\nModul Attributes (SPD Byte 22): \n"); + if (dimmInfo.memoryType == MEM_TYPE_SDRAM) + { + if ( spdRawData[i] & BIT0 ) + mvOsOutput(" Early Ras Precharge: Yes \n"); + else + mvOsOutput(" Early Ras Precharge: No \n"); + + if ( spdRawData[i] & BIT1 ) + mvOsOutput(" AutoPreCharge: Yes \n"); + else + mvOsOutput(" AutoPreCharge: No \n"); + + if ( spdRawData[i] & BIT2 ) + mvOsOutput(" Precharge All: Yes \n"); + else + mvOsOutput(" Precharge All: No \n"); + + if ( spdRawData[i] & BIT3 ) + mvOsOutput(" Write 1/ReadBurst: Yes \n"); + else + mvOsOutput(" Write 1/ReadBurst: No \n"); + + if ( spdRawData[i] & BIT4 ) + mvOsOutput(" lower VCC tolerance: 5%%\n"); + else + mvOsOutput(" lower VCC tolerance: 10%%\n"); + + if ( spdRawData[i] & BIT5 ) + mvOsOutput(" upper VCC tolerance: 5%%\n"); + else + mvOsOutput(" upper VCC tolerance: 10%%\n"); + } + else if (dimmInfo.memoryType == MEM_TYPE_DDR1) + { + if ( spdRawData[i] & BIT0 ) + mvOsOutput(" Supports Weak Driver: Yes \n"); + else + mvOsOutput(" Supports Weak Driver: No \n"); + + if ( !(spdRawData[i] & BIT4) ) + mvOsOutput(" lower VCC tolerance: 0.2V\n"); + + if ( !(spdRawData[i] & BIT5) ) + mvOsOutput(" upper VCC tolerance: 0.2V\n"); + + if ( spdRawData[i] & BIT6 ) + mvOsOutput(" Concurrent Auto Preharge: Yes \n"); + else + mvOsOutput(" Concurrent Auto Preharge: No \n"); + + if ( spdRawData[i] & BIT7 ) + mvOsOutput(" Supports Fast AP: Yes \n"); + else + mvOsOutput(" Supports Fast AP: No \n"); + } + else if (dimmInfo.memoryType == MEM_TYPE_DDR2) + { + if ( spdRawData[i] & BIT0 ) + mvOsOutput(" Supports Weak Driver: Yes \n"); + else + mvOsOutput(" Supports Weak Driver: No \n"); + } + break; +/*----------------------------------------------------------------------------*/ + + case 23: + /* Minimum Cycle Time At Maximum Cas Latancy Minus 1 (2nd highest CL) */ + leftOfPoint = (spdRawData[i] & 0xf0) >> 4; + rightOfPoint = (spdRawData[i] & 0x0f) * 10; + + /* DDR2 addition of right of point */ + if ((spdRawData[i] & 0x0f) == 0xA) + { + rightOfPoint = 25; + } + if ((spdRawData[i] & 0x0f) == 0xB) + { + rightOfPoint = 33; + } + if ((spdRawData[i] & 0x0f) == 0xC) + { + rightOfPoint = 66; + } + if ((spdRawData[i] & 0x0f) == 0xD) + { + rightOfPoint = 75; + } + + mvOsOutput("Minimum Cycle Time At 2nd highest CasLatancy" + "(0 = Not supported): %d.%d [ns]\n", + leftOfPoint, rightOfPoint ); + break; +/*----------------------------------------------------------------------------*/ + + case 24: /* Clock To Data Out 2nd highest Cas Latency Value*/ + div = (dimmInfo.memoryType == MEM_TYPE_SDRAM) ? 10:100; + time_tmp = (((spdRawData[i] & 0xf0) >> 4)*10) + + ((spdRawData[i] & 0x0f)); + leftOfPoint = time_tmp / div; + rightOfPoint = time_tmp % div; + mvOsOutput("Clock To Data Out (2nd CL value): %d.%d [ns]\n", + leftOfPoint, rightOfPoint); + break; +/*----------------------------------------------------------------------------*/ + + case 25: + /* Minimum Cycle Time At Maximum Cas Latancy Minus 2 (3rd highest CL) */ + if (dimmInfo.memoryType == MEM_TYPE_SDRAM) + { + leftOfPoint = (spdRawData[i] & 0xfc) >> 2; + rightOfPoint = (spdRawData[i] & 0x3) * 25; + } + else /* DDR1 or DDR2 */ + { + leftOfPoint = (spdRawData[i] & 0xf0) >> 4; + rightOfPoint = (spdRawData[i] & 0x0f) * 10; + + /* DDR2 addition of right of point */ + if ((spdRawData[i] & 0x0f) == 0xA) + { + rightOfPoint = 25; + } + if ((spdRawData[i] & 0x0f) == 0xB) + { + rightOfPoint = 33; + } + if ((spdRawData[i] & 0x0f) == 0xC) + { + rightOfPoint = 66; + } + if ((spdRawData[i] & 0x0f) == 0xD) + { + rightOfPoint = 75; + } + } + mvOsOutput("Minimum Cycle Time At 3rd highest CasLatancy" + "(0 = Not supported): %d.%d [ns]\n", + leftOfPoint, rightOfPoint ); + break; +/*----------------------------------------------------------------------------*/ + + case 26: /* Clock To Data Out 3rd highest Cas Latency Value*/ + if (dimmInfo.memoryType == MEM_TYPE_SDRAM) + { + leftOfPoint = (spdRawData[i] & 0xfc) >> 2; + rightOfPoint = (spdRawData[i] & 0x3) * 25; + } + else /* DDR1 or DDR2 */ + { + time_tmp = (((spdRawData[i] & 0xf0) >> 4)*10) + + ((spdRawData[i] & 0x0f)); + leftOfPoint = 0; + rightOfPoint = time_tmp; + } + mvOsOutput("Clock To Data Out (3rd CL value): %d.%2d[ns]\n", + leftOfPoint, rightOfPoint ); + break; +/*----------------------------------------------------------------------------*/ + + case 27: /* Minimum Row Precharge Time */ + shift = (dimmInfo.memoryType == MEM_TYPE_SDRAM)? 0:2; + maskLeftOfPoint = (dimmInfo.memoryType == MEM_TYPE_SDRAM) ? + 0xff : 0xfc; + maskRightOfPoint = (dimmInfo.memoryType == MEM_TYPE_SDRAM) ? + 0x00 : 0x03; + leftOfPoint = ((spdRawData[i] & maskLeftOfPoint) >> shift); + rightOfPoint = (spdRawData[i] & maskRightOfPoint)*25; + temp = ((leftOfPoint*100) + rightOfPoint);/* in 10ps Intervals*/ + trp_clocks = (temp + (busClkPs-1)) / busClkPs; + mvOsOutput("Minimum Row Precharge Time [ns]: %d.%d = " + "in Clk cycles %d\n", + leftOfPoint, rightOfPoint, trp_clocks); + break; +/*----------------------------------------------------------------------------*/ + + case 28: /* Minimum Row Active to Row Active Time */ + shift = (dimmInfo.memoryType == MEM_TYPE_SDRAM)? 0:2; + maskLeftOfPoint = (dimmInfo.memoryType == MEM_TYPE_SDRAM) ? + 0xff : 0xfc; + maskRightOfPoint = (dimmInfo.memoryType == MEM_TYPE_SDRAM) ? + 0x00 : 0x03; + leftOfPoint = ((spdRawData[i] & maskLeftOfPoint) >> shift); + rightOfPoint = (spdRawData[i] & maskRightOfPoint)*25; + temp = ((leftOfPoint*100) + rightOfPoint);/* in 100ns Interval*/ + trrd_clocks = (temp + (busClkPs-1)) / busClkPs; + mvOsOutput("Minimum Row Active -To- Row Active Delay [ns]: " + "%d.%d = in Clk cycles %d\n", + leftOfPoint, rightOfPoint, trp_clocks); + break; +/*----------------------------------------------------------------------------*/ + + case 29: /* Minimum Ras-To-Cas Delay */ + shift = (dimmInfo.memoryType == MEM_TYPE_SDRAM)? 0:2; + maskLeftOfPoint = (dimmInfo.memoryType == MEM_TYPE_SDRAM) ? + 0xff : 0xfc; + maskRightOfPoint = (dimmInfo.memoryType == MEM_TYPE_SDRAM) ? + 0x00 : 0x03; + leftOfPoint = ((spdRawData[i] & maskLeftOfPoint) >> shift); + rightOfPoint = (spdRawData[i] & maskRightOfPoint)*25; + temp = ((leftOfPoint*100) + rightOfPoint);/* in 100ns Interval*/ + trcd_clocks = (temp + (busClkPs-1) )/ busClkPs; + mvOsOutput("Minimum Ras-To-Cas Delay [ns]: %d.%d = " + "in Clk cycles %d\n", + leftOfPoint, rightOfPoint, trp_clocks); + break; +/*----------------------------------------------------------------------------*/ + + case 30: /* Minimum Ras Pulse Width */ + tras_clocks = (cas2ps(spdRawData[i])+(busClkPs-1)) / busClkPs; + mvOsOutput("Minimum Ras Pulse Width [ns]: %d = " + "in Clk cycles %d\n", spdRawData[i], tras_clocks); + break; +/*----------------------------------------------------------------------------*/ + + case 31: /* Module Bank Density */ + mvOsOutput("Module Bank Density (more than 1= Multisize-Module):"); + + if (dimmInfo.memoryType == MEM_TYPE_SDRAM) + { + if (dimmInfo.dimmBankDensity & BIT0) + mvOsOutput("1GB, "); + if (dimmInfo.dimmBankDensity & BIT1) + mvOsOutput("8MB, "); + if (dimmInfo.dimmBankDensity & BIT2) + mvOsOutput("16MB, "); + if (dimmInfo.dimmBankDensity & BIT3) + mvOsOutput("32MB, "); + if (dimmInfo.dimmBankDensity & BIT4) + mvOsOutput("64MB, "); + if (dimmInfo.dimmBankDensity & BIT5) + mvOsOutput("128MB, "); + if (dimmInfo.dimmBankDensity & BIT6) + mvOsOutput("256MB, "); + if (dimmInfo.dimmBankDensity & BIT7) + mvOsOutput("512MB, "); + } + else if (dimmInfo.memoryType == MEM_TYPE_DDR1) + { + if (dimmInfo.dimmBankDensity & BIT0) + mvOsOutput("1GB, "); + if (dimmInfo.dimmBankDensity & BIT1) + mvOsOutput("2GB, "); + if (dimmInfo.dimmBankDensity & BIT2) + mvOsOutput("16MB, "); + if (dimmInfo.dimmBankDensity & BIT3) + mvOsOutput("32MB, "); + if (dimmInfo.dimmBankDensity & BIT4) + mvOsOutput("64MB, "); + if (dimmInfo.dimmBankDensity & BIT5) + mvOsOutput("128MB, "); + if (dimmInfo.dimmBankDensity & BIT6) + mvOsOutput("256MB, "); + if (dimmInfo.dimmBankDensity & BIT7) + mvOsOutput("512MB, "); + } + else /* if (dimmInfo.memoryType == MEM_TYPE_DDR2) */ + { + if (dimmInfo.dimmBankDensity & BIT0) + mvOsOutput("1GB, "); + if (dimmInfo.dimmBankDensity & BIT1) + mvOsOutput("2GB, "); + if (dimmInfo.dimmBankDensity & BIT2) + mvOsOutput("4GB, "); + if (dimmInfo.dimmBankDensity & BIT3) + mvOsOutput("8GB, "); + if (dimmInfo.dimmBankDensity & BIT4) + mvOsOutput("16GB, "); + if (dimmInfo.dimmBankDensity & BIT5) + mvOsOutput("128MB, "); + if (dimmInfo.dimmBankDensity & BIT6) + mvOsOutput("256MB, "); + if (dimmInfo.dimmBankDensity & BIT7) + mvOsOutput("512MB, "); + } + mvOsOutput("\n"); + break; +/*----------------------------------------------------------------------------*/ + + case 32: /* Address And Command Setup Time (measured in ns/1000) */ + if (dimmInfo.memoryType == MEM_TYPE_SDRAM) + { + rightOfPoint = (spdRawData[i] & 0x0f); + leftOfPoint = (spdRawData[i] & 0xf0) >> 4; + if(leftOfPoint > 7) + { + leftOfPoint *= -1; + } + } + else /* DDR1 or DDR2 */ + { + time_tmp = (((spdRawData[i] & 0xf0) >> 4)*10) + + ((spdRawData[i] & 0x0f)); + leftOfPoint = time_tmp / 100; + rightOfPoint = time_tmp % 100; + } + mvOsOutput("Address And Command Setup Time [ns]: %d.%d\n", + leftOfPoint, rightOfPoint); + break; +/*----------------------------------------------------------------------------*/ + + case 33: /* Address And Command Hold Time */ + if (dimmInfo.memoryType == MEM_TYPE_SDRAM) + { + rightOfPoint = (spdRawData[i] & 0x0f); + leftOfPoint = (spdRawData[i] & 0xf0) >> 4; + if(leftOfPoint > 7) + { + leftOfPoint *= -1; + } + } + else /* DDR1 or DDR2 */ + { + time_tmp = (((spdRawData[i] & 0xf0) >> 4)*10) + + ((spdRawData[i] & 0x0f)); + leftOfPoint = time_tmp / 100; + rightOfPoint = time_tmp % 100; + } + mvOsOutput("Address And Command Hold Time [ns]: %d.%d\n", + leftOfPoint, rightOfPoint); + break; +/*----------------------------------------------------------------------------*/ + + case 34: /* Data Input Setup Time */ + if (dimmInfo.memoryType == MEM_TYPE_SDRAM) + { + rightOfPoint = (spdRawData[i] & 0x0f); + leftOfPoint = (spdRawData[i] & 0xf0) >> 4; + if(leftOfPoint > 7) + { + leftOfPoint *= -1; + } + } + else /* DDR1 or DDR2 */ + { + time_tmp = (((spdRawData[i] & 0xf0) >> 4)*10) + + ((spdRawData[i] & 0x0f)); + leftOfPoint = time_tmp / 100; + rightOfPoint = time_tmp % 100; + } + mvOsOutput("Data Input Setup Time [ns]: %d.%d\n", + leftOfPoint, rightOfPoint); + break; +/*----------------------------------------------------------------------------*/ + + case 35: /* Data Input Hold Time */ + if (dimmInfo.memoryType == MEM_TYPE_SDRAM) + { + rightOfPoint = (spdRawData[i] & 0x0f); + leftOfPoint = (spdRawData[i] & 0xf0) >> 4; + if(leftOfPoint > 7) + { + leftOfPoint *= -1; + } + } + else /* DDR1 or DDR2 */ + { + time_tmp = (((spdRawData[i] & 0xf0) >> 4)*10) + + ((spdRawData[i] & 0x0f)); + leftOfPoint = time_tmp / 100; + rightOfPoint = time_tmp % 100; + } + mvOsOutput("Data Input Hold Time [ns]: %d.%d\n\n", + leftOfPoint, rightOfPoint); + break; +/*----------------------------------------------------------------------------*/ + + case 36: /* Relevant for DDR2 only: Write Recovery Time */ + leftOfPoint = ((spdRawData[i] & maskLeftOfPoint) >> 2); + rightOfPoint = (spdRawData[i] & maskRightOfPoint) * 25; + mvOsOutput("Write Recovery Time [ns]: %d.%d\n", + leftOfPoint, rightOfPoint); + break; +/*----------------------------------------------------------------------------*/ + } + +} + + +/* + * translate ns.ns/10 coding of SPD timing values + * into ps unit values + */ +/******************************************************************************* +* cas2ps - Translate x.y ns parameter to pico-seconds values +* +* DESCRIPTION: +* This function translates x.y nano seconds to its value in pico seconds. +* For example 3.75ns will return 3750. +* +* INPUT: +* spd_byte - DIMM SPD byte. +* +* OUTPUT: +* None. +* +* RETURN: +* value in pico seconds. +* +*******************************************************************************/ +static MV_U32 cas2ps(MV_U8 spd_byte) +{ + MV_U32 ns, ns10; + + /* isolate upper nibble */ + ns = (spd_byte >> 4) & 0x0F; + /* isolate lower nibble */ + ns10 = (spd_byte & 0x0F); + + if( ns10 < 10 ) { + ns10 *= 10; + } + else if( ns10 == 10 ) + ns10 = 25; + else if( ns10 == 11 ) + ns10 = 33; + else if( ns10 == 12 ) + ns10 = 66; + else if( ns10 == 13 ) + ns10 = 75; + else + { + mvOsOutput("cas2ps Err. unsupported cycle time.\n"); + } + + return (ns*1000 + ns10*10); +} + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr2/spd/mvSpd.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr2/spd/mvSpd.h new file mode 100644 index 0000000..f955466 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/ddr2/spd/mvSpd.h @@ -0,0 +1,192 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#ifndef __INCmvDram +#define __INCmvDram + +#include "ddr2/mvDramIf.h" +#include "twsi/mvTwsi.h" + +#define MAX_DIMM_NUM 2 +#define SPD_SIZE 128 + +/* Dimm spd offsets */ +#define DIMM_MEM_TYPE 2 +#define DIMM_ROW_NUM 3 +#define DIMM_COL_NUM 4 +#define DIMM_MODULE_BANK_NUM 5 +#define DIMM_DATA_WIDTH 6 +#define DIMM_VOLT_IF 8 +#define DIMM_MIN_CC_AT_MAX_CAS 9 +#define DIMM_ERR_CHECK_TYPE 11 +#define DIMM_REFRESH_INTERVAL 12 +#define DIMM_SDRAM_WIDTH 13 +#define DIMM_ERR_CHECK_DATA_WIDTH 14 +#define DIMM_MIN_CLK_DEL 15 +#define DIMM_BURST_LEN_SUP 16 +#define DIMM_DEV_BANK_NUM 17 +#define DIMM_SUP_CAL 18 +#define DIMM_DDR2_TYPE_INFORMATION 20 /* DDR2 only */ +#define DIMM_BUF_ADDR_CONT_IN 21 +#define DIMM_MIN_CC_AT_MAX_CAS_MINUS1 23 +#define DIMM_MIN_CC_AT_MAX_CAS_MINUS2 25 +#define DIMM_MIN_ROW_PRECHARGE_TIME 27 +#define DIMM_MIN_ROW_ACTIVE_TO_ROW_ACTIVE 28 +#define DIMM_MIN_RAS_TO_CAS_DELAY 29 +#define DIMM_MIN_RAS_PULSE_WIDTH 30 +#define DIMM_BANK_DENSITY 31 +#define DIMM_MIN_WRITE_RECOVERY_TIME 36 +#define DIMM_MIN_WRITE_TO_READ_CMD_DELAY 37 +#define DIMM_MIN_READ_TO_PRECH_CMD_DELAY 38 +#define DIMM_MIN_REFRESH_TO_ACTIVATE_CMD 42 +#define DIMM_SPD_VERSION 62 + +/* Dimm Memory Type values */ +#define DIMM_MEM_TYPE_SDRAM 0x4 +#define DIMM_MEM_TYPE_DDR1 0x7 +#define DIMM_MEM_TYPE_DDR2 0x8 + +#define DIMM_MODULE_MANU_OFFS 64 +#define DIMM_MODULE_MANU_SIZE 8 +#define DIMM_MODULE_VEN_OFFS 73 +#define DIMM_MODULE_VEN_SIZE 25 +#define DIMM_MODULE_ID_OFFS 99 +#define DIMM_MODULE_ID_SIZE 18 + +/* enumeration for voltage levels. */ +typedef enum _mvDimmVoltageIf +{ + TTL_5V_TOLERANT, + LVTTL, + HSTL_1_5V, + SSTL_3_3V, + SSTL_2_5V, + VOLTAGE_UNKNOWN, +} MV_DIMM_VOLTAGE_IF; + + +/* enumaration for SDRAM CAS Latencies. */ +typedef enum _mvDimmSdramCas +{ + SD_CL_1 =1, + SD_CL_2, + SD_CL_3, + SD_CL_4, + SD_CL_5, + SD_CL_6, + SD_CL_7, + SD_FAULT +}MV_DIMM_SDRAM_CAS; + + +/* DIMM information structure */ +typedef struct _mvDimmInfo +{ + MV_MEMORY_TYPE memoryType; /* DDR or SDRAM */ + + MV_U8 spdRawData[SPD_SIZE]; /* Content of SPD-EEPROM copied 1:1 */ + + /* DIMM dimensions */ + MV_U32 numOfRowAddr; + MV_U32 numOfColAddr; + MV_U32 numOfModuleBanks; + MV_U32 dataWidth; + MV_U32 errorCheckType; /* ECC , PARITY..*/ + MV_U32 sdramWidth; /* 4,8,16 or 32 */ + MV_U32 errorCheckDataWidth; /* 0 - no, 1 - Yes */ + MV_U32 burstLengthSupported; + MV_U32 numOfBanksOnEachDevice; + MV_U32 suportedCasLatencies; + MV_U32 refreshInterval; + MV_U32 dimmBankDensity; + MV_U32 dimmTypeInfo; /* DDR2 only */ + MV_U32 dimmAttributes; + + /* DIMM timing parameters */ + MV_U32 minCycleTimeAtMaxCasLatPs; + MV_U32 minCycleTimeAtMaxCasLatMinus1Ps; + MV_U32 minCycleTimeAtMaxCasLatMinus2Ps; + MV_U32 minRowPrechargeTime; + MV_U32 minRowActiveToRowActive; + MV_U32 minRasToCasDelay; + MV_U32 minRasPulseWidth; + MV_U32 minWriteRecoveryTime; /* DDR2 only */ + MV_U32 minWriteToReadCmdDelay; /* DDR2 only */ + MV_U32 minReadToPrechCmdDelay; /* DDR2 only */ + MV_U32 minRefreshToActiveCmd; /* DDR2 only */ + + /* Parameters calculated from the extracted DIMM information */ + MV_U32 size; /* 16,64,128,256 or 512 MByte in MB units */ + MV_U32 deviceDensity; /* 16,64,128,256 or 512 Mbit in MB units */ + MV_U32 numberOfDevices; + +} MV_DIMM_INFO; + + +MV_STATUS mvDramBankInfoGet(MV_U32 bankNum, MV_DRAM_BANK_INFO *pBankInfo); +MV_STATUS dimmSpdGet(MV_U32 dimmNum, MV_DIMM_INFO *pDimmInfo); +MV_VOID dimmSpdPrint(MV_U32 dimmNum); +MV_STATUS dimmSpdCpy(MV_VOID); + +#endif /* __INCmvDram */ diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/eth/gbe/mvEth.c b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/eth/gbe/mvEth.c new file mode 100644 index 0000000..d24e788 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/eth/gbe/mvEth.c @@ -0,0 +1,2952 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +/******************************************************************************* +* mvEth.c - Marvell's Gigabit Ethernet controller low level driver +* +* DESCRIPTION: +* This file introduce OS independent APIs to Marvell's Gigabit Ethernet +* controller. This Gigabit Ethernet Controller driver API controls +* 1) Operations (i.e. port Init, Finish, Up, Down, PhyReset etc'). +* 2) Data flow (i.e. port Send, Receive etc'). +* 3) MAC Filtering functions (ethSetMcastAddr, ethSetRxFilterMode, etc.) +* 4) MIB counters support (ethReadMibCounter) +* 5) Debug functions (ethPortRegs, ethPortCounters, ethPortQueues, etc.) +* Each Gigabit Ethernet port is controlled via ETH_PORT_CTRL struct. +* This struct includes configuration information as well as driver +* internal data needed for its operations. +* +* Supported Features: +* - OS independent. All required OS services are implemented via external +* OS dependent components (like osLayer or ethOsg) +* - The user is free from Rx/Tx queue managing. +* - Simple Gigabit Ethernet port operation API. +* - Simple Gigabit Ethernet port data flow API. +* - Data flow and operation API support per queue functionality. +* - Support cached descriptors for better performance. +* - PHY access and control API. +* - Port Configuration API. +* - Full control over Special and Other Multicast MAC tables. +* +*******************************************************************************/ +/* includes */ +#include "mvTypes.h" +#include "mv802_3.h" +#include "mvDebug.h" +#include "mvCommon.h" +#include "mvOs.h" +#include "ctrlEnv/mvCtrlEnvLib.h" +#include "eth-phy/mvEthPhy.h" +#include "eth/mvEth.h" +#include "eth/gbe/mvEthGbe.h" +#include "cpu/mvCpu.h" + +#ifdef INCLUDE_SYNC_BARR +#include "sys/mvCpuIf.h" +#endif + +#ifdef MV_RT_DEBUG +# define ETH_DEBUG +#endif + + +/* locals */ +MV_BOOL ethDescInSram; +MV_BOOL ethDescSwCoher; + +/* This array holds the control structure of each port */ +ETH_PORT_CTRL* ethPortCtrl[MV_ETH_MAX_PORTS]; + +/* Ethernet Port Local routines */ + +static void ethInitRxDescRing(ETH_PORT_CTRL* pPortCtrl, int queue); + +static void ethInitTxDescRing(ETH_PORT_CTRL* pPortCtrl, int queue); + +static void ethSetUcastTable(int portNo, int queue); + +static MV_BOOL ethSetUcastAddr (int ethPortNum, MV_U8 lastNibble, int queue); +static MV_BOOL ethSetSpecialMcastAddr(int ethPortNum, MV_U8 lastByte, int queue); +static MV_BOOL ethSetOtherMcastAddr(int ethPortNum, MV_U8 crc8, int queue); + +static void ethFreeDescrMemory(ETH_PORT_CTRL* pEthPortCtrl, MV_BUF_INFO* pDescBuf); +static MV_U8* ethAllocDescrMemory(ETH_PORT_CTRL* pEthPortCtrl, int size, + MV_ULONG* pPhysAddr, MV_U32 *memHandle); + +static MV_U32 mvEthMruGet(MV_U32 maxRxPktSize); + +static void mvEthPortSgmiiConfig(int port); + + + +/******************************************************************************/ +/* EthDrv Initialization functions */ +/******************************************************************************/ + +/******************************************************************************* +* mvEthHalInit - Initialize the Giga Ethernet unit +* +* DESCRIPTION: +* This function initialize the Giga Ethernet unit. +* 1) Configure Address decode windows of the unit +* 2) Set registers to HW default values. +* 3) Clear and Disable interrupts +* +* INPUT: NONE +* +* RETURN: NONE +* +* NOTE: this function is called once in the boot process. +*******************************************************************************/ +void mvEthHalInit(void) +{ + int port; + + /* Init static data structures */ + for (port=0; port 0) + { + isSram = MV_TRUE; + #if (INTEG_SRAM_COHER == MV_CACHE_COHER_SW) + isSwCoher = MV_TRUE; + #else + isSwCoher = MV_FALSE; + #endif + } +#endif /* ETH_DESCR_IN_SRAM */ + + if(pIsSram != NULL) + *pIsSram = isSram; + + if(pIsSwCoher != NULL) + *pIsSwCoher = isSwCoher; +} + + + +/******************************************************************************/ +/* Port Initialization functions */ +/******************************************************************************/ + +/******************************************************************************* +* mvEthPortInit - Initialize the Ethernet port driver +* +* DESCRIPTION: +* This function initialize the ethernet port. +* 1) Allocate and initialize internal port Control structure. +* 2) Create RX and TX descriptor rings for default RX and TX queues +* 3) Disable RX and TX operations, clear cause registers and +* mask all interrupts. +* 4) Set all registers to default values and clean all MAC tables. +* +* INPUT: +* int portNo - Ethernet port number +* ETH_PORT_INIT *pEthPortInit - Ethernet port init structure +* +* RETURN: +* void* - ethernet port handler, that should be passed to the most other +* functions dealing with this port. +* +* NOTE: This function is called once per port when loading the eth module. +*******************************************************************************/ +void* mvEthPortInit(int portNo, MV_ETH_PORT_INIT *pEthPortInit) +{ + int queue, descSize; + ETH_PORT_CTRL* pPortCtrl; + + /* Check validity of parameters */ + if( (portNo >= (int)mvCtrlEthMaxPortGet()) || + (pEthPortInit->rxDefQ >= MV_ETH_RX_Q_NUM) || + (pEthPortInit->maxRxPktSize < 1518) ) + { + mvOsPrintf("EthPort #%d: Bad initialization parameters\n", portNo); + return NULL; + } + if( (pEthPortInit->rxDescrNum[pEthPortInit->rxDefQ]) == 0) + { + mvOsPrintf("EthPort #%d: rxDefQ (%d) must be created\n", + portNo, pEthPortInit->rxDefQ); + return NULL; + } + + pPortCtrl = (ETH_PORT_CTRL*)mvOsMalloc( sizeof(ETH_PORT_CTRL) ); + if(pPortCtrl == NULL) + { + mvOsPrintf("EthDrv: Can't allocate %dB for port #%d control structure!\n", + (int)sizeof(ETH_PORT_CTRL), portNo); + return NULL; + } + + memset(pPortCtrl, 0, sizeof(ETH_PORT_CTRL) ); + ethPortCtrl[portNo] = pPortCtrl; + + pPortCtrl->portState = MV_UNDEFINED_STATE; + + pPortCtrl->portNo = portNo; + + pPortCtrl->osHandle = pEthPortInit->osHandle; + + /* Copy Configuration parameters */ + pPortCtrl->portConfig.maxRxPktSize = pEthPortInit->maxRxPktSize; + pPortCtrl->portConfig.rxDefQ = pEthPortInit->rxDefQ; + pPortCtrl->portConfig.ejpMode = 0; + + for( queue=0; queuerxQueueConfig[queue].descrNum = pEthPortInit->rxDescrNum[queue]; + } + for( queue=0; queuetxQueueConfig[queue].descrNum = pEthPortInit->txDescrNum[queue]; + } + + mvEthPortDisable(pPortCtrl); + + /* Set the board information regarding PHY address */ + mvEthPhyAddrSet(pPortCtrl, mvBoardPhyAddrGet(portNo) ); + + /* Create all requested RX queues */ + for(queue=0; queuerxQueueConfig[queue].descrNum == 0) + continue; + + /* Allocate memory for RX descriptors */ + descSize = ((pPortCtrl->rxQueueConfig[queue].descrNum * ETH_RX_DESC_ALIGNED_SIZE) + + CPU_D_CACHE_LINE_SIZE); + + pPortCtrl->rxQueue[queue].descBuf.bufVirtPtr = + ethAllocDescrMemory(pPortCtrl, descSize, + &pPortCtrl->rxQueue[queue].descBuf.bufPhysAddr, + &pPortCtrl->rxQueue[queue].descBuf.memHandle); + pPortCtrl->rxQueue[queue].descBuf.bufSize = descSize; + if(pPortCtrl->rxQueue[queue].descBuf.bufVirtPtr == NULL) + { + mvOsPrintf("EthPort #%d, rxQ=%d: Can't allocate %d bytes in %s for %d RX descr\n", + pPortCtrl->portNo, queue, descSize, + ethDescInSram ? "SRAM" : "DRAM", + pPortCtrl->rxQueueConfig[queue].descrNum); + return NULL; + } + + ethInitRxDescRing(pPortCtrl, queue); + } + /* Create TX queues */ + for(queue=0; queuetxQueueConfig[queue].descrNum == 0) + continue; + + /* Allocate memory for TX descriptors */ + descSize = ((pPortCtrl->txQueueConfig[queue].descrNum * ETH_TX_DESC_ALIGNED_SIZE) + + CPU_D_CACHE_LINE_SIZE); + + pPortCtrl->txQueue[queue].descBuf.bufVirtPtr = + ethAllocDescrMemory(pPortCtrl, descSize, + &pPortCtrl->txQueue[queue].descBuf.bufPhysAddr, + &pPortCtrl->txQueue[queue].descBuf.memHandle); + pPortCtrl->txQueue[queue].descBuf.bufSize = descSize; + if(pPortCtrl->txQueue[queue].descBuf.bufVirtPtr == NULL) + { + mvOsPrintf("EthPort #%d, txQ=%d: Can't allocate %d bytes in %s for %d TX descr\n", + pPortCtrl->portNo, queue, descSize, ethDescInSram ? "SRAM" : "DRAM", + pPortCtrl->txQueueConfig[queue].descrNum); + return NULL; + } + + ethInitTxDescRing(pPortCtrl, queue); + } + mvEthDefaultsSet(pPortCtrl); + + pPortCtrl->portState = MV_IDLE; + return pPortCtrl; +} + +/******************************************************************************* +* ethPortFinish - Finish the Ethernet port driver +* +* DESCRIPTION: +* This function finish the ethernet port. +* 1) Down ethernet port if needed. +* 2) Delete RX and TX descriptor rings for all created RX and TX queues +* 3) Free internal port Control structure. +* +* INPUT: +* void* pEthPortHndl - Ethernet port handler +* +* RETURN: NONE. +* +*******************************************************************************/ +void mvEthPortFinish(void* pPortHndl) +{ + ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHndl; + int queue, portNo = pPortCtrl->portNo; + + if(pPortCtrl->portState == MV_ACTIVE) + { + mvOsPrintf("ethPort #%d: Warning !!! Finish port in Active state\n", + portNo); + mvEthPortDisable(pPortHndl); + } + + /* Free all allocated RX queues */ + for(queue=0; queuerxQueue[queue].descBuf); + } + + /* Free all allocated TX queues */ + for(queue=0; queuetxQueue[queue].descBuf); + } + + /* Free port control structure */ + mvOsFree(pPortCtrl); + + ethPortCtrl[portNo] = NULL; +} + +/******************************************************************************* +* mvEthDefaultsSet - Set defaults to the ethernet port +* +* DESCRIPTION: +* This function set default values to the ethernet port. +* 1) Clear Cause registers and Mask all interrupts +* 2) Clear all MAC tables +* 3) Set defaults to all registers +* 4) Reset all created RX and TX descriptors ring +* 5) Reset PHY +* +* INPUT: +* void* pEthPortHndl - Ethernet port handler +* +* RETURN: MV_STATUS +* MV_OK - Success, Others - Failure +* NOTE: +* This function update all the port configuration except those set +* Initialy by the OsGlue by MV_ETH_PORT_INIT. +* This function can be called after portDown to return the port setting +* to defaults. +*******************************************************************************/ +MV_STATUS mvEthDefaultsSet(void* pPortHndl) +{ + int ethPortNo, queue; + ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHndl; + ETH_QUEUE_CTRL* pQueueCtrl; + MV_U32 txPrio; + MV_U32 portCfgReg, portCfgExtReg, portSerialCtrlReg, portSerialCtrl1Reg, portSdmaCfgReg; + MV_BOARD_MAC_SPEED boardMacCfg; + + ethPortNo = pPortCtrl->portNo; + + /* Clear Cause registers */ + MV_REG_WRITE(ETH_INTR_CAUSE_REG(ethPortNo),0); + MV_REG_WRITE(ETH_INTR_CAUSE_EXT_REG(ethPortNo),0); + + /* Mask all interrupts */ + MV_REG_WRITE(ETH_INTR_MASK_REG(ethPortNo),0); + MV_REG_WRITE(ETH_INTR_MASK_EXT_REG(ethPortNo),0); + + portCfgReg = PORT_CONFIG_VALUE; + portCfgExtReg = PORT_CONFIG_EXTEND_VALUE; + + boardMacCfg = mvBoardMacSpeedGet(ethPortNo); + + if(boardMacCfg == BOARD_MAC_SPEED_100M) + { + portSerialCtrlReg = PORT_SERIAL_CONTROL_100MB_FORCE_VALUE; + } + else if(boardMacCfg == BOARD_MAC_SPEED_1000M) + { + portSerialCtrlReg = PORT_SERIAL_CONTROL_1000MB_FORCE_VALUE; + } + else + { + portSerialCtrlReg = PORT_SERIAL_CONTROL_VALUE; + } + + /* build PORT_SDMA_CONFIG_REG */ + portSdmaCfgReg = ETH_TX_INTR_COAL_MASK(0); + portSdmaCfgReg |= ETH_TX_BURST_SIZE_MASK(ETH_BURST_SIZE_16_64BIT_VALUE); + +#if ( (ETHER_DRAM_COHER == MV_CACHE_COHER_HW_WB) || \ + (ETHER_DRAM_COHER == MV_CACHE_COHER_HW_WT) ) + /* some devices have restricted RX burst size when using HW coherency */ + portSdmaCfgReg |= ETH_RX_BURST_SIZE_MASK(ETH_BURST_SIZE_4_64BIT_VALUE); +#else + portSdmaCfgReg |= ETH_RX_BURST_SIZE_MASK(ETH_BURST_SIZE_16_64BIT_VALUE); +#endif + +#if defined(MV_CPU_BE) + /* big endian */ +# if defined(MV_ARM) + portSdmaCfgReg |= (ETH_RX_NO_DATA_SWAP_MASK | + ETH_TX_NO_DATA_SWAP_MASK | + ETH_DESC_SWAP_MASK); +# elif defined(MV_PPC) + portSdmaCfgReg |= (ETH_RX_DATA_SWAP_MASK | + ETH_TX_DATA_SWAP_MASK | + ETH_NO_DESC_SWAP_MASK); +# else +# error "Giga Ethernet Swap policy is not defined for the CPU_ARCH" +# endif /* MV_ARM / MV_PPC */ + +#else /* MV_CPU_LE */ + /* little endian */ + portSdmaCfgReg |= (ETH_RX_NO_DATA_SWAP_MASK | + ETH_TX_NO_DATA_SWAP_MASK | + ETH_NO_DESC_SWAP_MASK); +#endif /* MV_CPU_BE / MV_CPU_LE */ + + pPortCtrl->portRxQueueCmdReg = 0; + pPortCtrl->portTxQueueCmdReg = 0; + +#if (MV_ETH_VERSION >= 4) + if(pPortCtrl->portConfig.ejpMode == MV_TRUE) + { + MV_REG_WRITE(ETH_TXQ_CMD_1_REG(ethPortNo), ETH_TX_EJP_ENABLE_MASK); + } + else + { + MV_REG_WRITE(ETH_TXQ_CMD_1_REG(ethPortNo), 0) + } +#endif /* (MV_ETH_VERSION >= 4) */ + + ethSetUcastTable(ethPortNo, -1); + mvEthSetSpecialMcastTable(ethPortNo, -1); + mvEthSetOtherMcastTable(ethPortNo, -1); + + portSerialCtrlReg &= ~ETH_MAX_RX_PACKET_SIZE_MASK; + + portSerialCtrlReg |= mvEthMruGet(pPortCtrl->portConfig.maxRxPktSize); + + MV_REG_WRITE(ETH_PORT_SERIAL_CTRL_REG(ethPortNo), portSerialCtrlReg); + + /* Update value of PortConfig register accordingly with all RxQueue types */ + pPortCtrl->portConfig.rxArpQ = pPortCtrl->portConfig.rxDefQ; + pPortCtrl->portConfig.rxBpduQ = pPortCtrl->portConfig.rxDefQ; + pPortCtrl->portConfig.rxTcpQ = pPortCtrl->portConfig.rxDefQ; + pPortCtrl->portConfig.rxUdpQ = pPortCtrl->portConfig.rxDefQ; + + portCfgReg &= ~ETH_DEF_RX_QUEUE_ALL_MASK; + portCfgReg |= ETH_DEF_RX_QUEUE_MASK(pPortCtrl->portConfig.rxDefQ); + + portCfgReg &= ~ETH_DEF_RX_ARP_QUEUE_ALL_MASK; + portCfgReg |= ETH_DEF_RX_ARP_QUEUE_MASK(pPortCtrl->portConfig.rxArpQ); + + portCfgReg &= ~ETH_DEF_RX_BPDU_QUEUE_ALL_MASK; + portCfgReg |= ETH_DEF_RX_BPDU_QUEUE_MASK(pPortCtrl->portConfig.rxBpduQ); + + portCfgReg &= ~ETH_DEF_RX_TCP_QUEUE_ALL_MASK; + portCfgReg |= ETH_DEF_RX_TCP_QUEUE_MASK(pPortCtrl->portConfig.rxTcpQ); + + portCfgReg &= ~ETH_DEF_RX_UDP_QUEUE_ALL_MASK; + portCfgReg |= ETH_DEF_RX_UDP_QUEUE_MASK(pPortCtrl->portConfig.rxUdpQ); + + /* Assignment of Tx CTRP of given queue */ + txPrio = 0; + + for(queue=0; queuetxQueue[queue]; + + if(pQueueCtrl->pFirstDescr != NULL) + { + ethResetTxDescRing(pPortCtrl, queue); + + MV_REG_WRITE(ETH_TXQ_TOKEN_COUNT_REG(ethPortNo, queue), + 0x3fffffff); + MV_REG_WRITE(ETH_TXQ_TOKEN_CFG_REG(ethPortNo, queue), + 0x03ffffff); + } + else + { + MV_REG_WRITE(ETH_TXQ_TOKEN_COUNT_REG(ethPortNo, queue), 0x0); + MV_REG_WRITE(ETH_TXQ_TOKEN_CFG_REG(ethPortNo, queue), 0x0); + } + } + + /* Assignment of Rx CRDP of given queue */ + for(queue=0; queueportNo; + + if( (pPortCtrl->portState != MV_ACTIVE) && + (pPortCtrl->portState != MV_PAUSED) ) + { + mvOsPrintf("ethDrv port%d: Unexpected port state %d\n", + ethPortNo, pPortCtrl->portState); + return MV_BAD_STATE; + } + + ethPortNo = pPortCtrl->portNo; + + /* Enable port RX. */ + MV_REG_WRITE(ETH_RX_QUEUE_COMMAND_REG(ethPortNo), pPortCtrl->portRxQueueCmdReg); + + /* Enable port TX. */ + MV_REG_VALUE(ETH_TX_QUEUE_COMMAND_REG(ethPortNo)) = pPortCtrl->portTxQueueCmdReg; + + pPortCtrl->portState = MV_ACTIVE; + + return MV_OK; +} + +/******************************************************************************* +* ethPortDown - Stop the Ethernet port activity. +* +* DESCRIPTION: +* +* INPUT: +* void* pEthPortHndl - Ethernet port handler +* +* RETURN: MV_STATUS +* MV_OK - Success, Others - Failure. +* +* NOTE : used for port link down. +*******************************************************************************/ +MV_STATUS mvEthPortDown(void* pEthPortHndl) +{ + ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pEthPortHndl; + int ethPortNum = pPortCtrl->portNo; + unsigned int regData; + volatile int uDelay, mDelay; + + /* Stop Rx port activity. Check port Rx activity. */ + regData = (MV_REG_READ(ETH_RX_QUEUE_COMMAND_REG(ethPortNum))) & ETH_RXQ_ENABLE_MASK; + if(regData != 0) + { + /* Issue stop command for active channels only */ + MV_REG_WRITE(ETH_RX_QUEUE_COMMAND_REG(ethPortNum), (regData << ETH_RXQ_DISABLE_OFFSET)); + } + + /* Stop Tx port activity. Check port Tx activity. */ + regData = (MV_REG_READ(ETH_TX_QUEUE_COMMAND_REG(ethPortNum))) & ETH_TXQ_ENABLE_MASK; + if(regData != 0) + { + /* Issue stop command for active channels only */ + MV_REG_WRITE(ETH_TX_QUEUE_COMMAND_REG(ethPortNum), + (regData << ETH_TXQ_DISABLE_OFFSET) ); + } + + /* Force link down */ +/* + regData = MV_REG_READ(ETH_PORT_SERIAL_CTRL_REG(ethPortNum)); + regData &= ~(ETH_DO_NOT_FORCE_LINK_FAIL_MASK); + MV_REG_WRITE(ETH_PORT_SERIAL_CTRL_REG(ethPortNum), regData); +*/ + /* Wait for all Rx activity to terminate. */ + mDelay = 0; + do + { + if(mDelay >= RX_DISABLE_TIMEOUT_MSEC) + { + mvOsPrintf("ethPort_%d: TIMEOUT for RX stopped !!! rxQueueCmd - 0x08%x\n", + ethPortNum, regData); + break; + } + mvOsDelay(1); + mDelay++; + + /* Check port RX Command register that all Rx queues are stopped */ + regData = MV_REG_READ(ETH_RX_QUEUE_COMMAND_REG(ethPortNum)); + } + while(regData & 0xFF); + + /* Wait for all Tx activity to terminate. */ + mDelay = 0; + do + { + if(mDelay >= TX_DISABLE_TIMEOUT_MSEC) + { + mvOsPrintf("ethPort_%d: TIMEOUT for TX stoped !!! txQueueCmd - 0x08%x\n", + ethPortNum, regData); + break; + } + mvOsDelay(1); + mDelay++; + + /* Check port TX Command register that all Tx queues are stopped */ + regData = MV_REG_READ(ETH_TX_QUEUE_COMMAND_REG(ethPortNum)); + } + while(regData & 0xFF); + + /* Double check to Verify that TX FIFO is Empty */ + mDelay = 0; + while(MV_TRUE) + { + do + { + if(mDelay >= TX_FIFO_EMPTY_TIMEOUT_MSEC) + { + mvOsPrintf("\n ethPort_%d: TIMEOUT for TX FIFO empty !!! portStatus - 0x08%x\n", + ethPortNum, regData); + break; + } + mvOsDelay(1); + mDelay++; + + regData = MV_REG_READ(ETH_PORT_STATUS_REG(ethPortNum)); + } + while( ((regData & ETH_TX_FIFO_EMPTY_MASK) == 0) || + ((regData & ETH_TX_IN_PROGRESS_MASK) != 0) ); + + if(mDelay >= TX_FIFO_EMPTY_TIMEOUT_MSEC) + break; + + /* Double check */ + regData = MV_REG_READ(ETH_PORT_STATUS_REG(ethPortNum)); + if( ((regData & ETH_TX_FIFO_EMPTY_MASK) != 0) && + ((regData & ETH_TX_IN_PROGRESS_MASK) == 0) ) + { + break; + } + else + mvOsPrintf("ethPort_%d: TX FIFO Empty double check failed. %d msec, portStatus=0x%x\n", + ethPortNum, mDelay, regData); + } + + /* Do NOT force link down */ +/* + regData = MV_REG_READ(ETH_PORT_SERIAL_CTRL_REG(ethPortNum)); + regData |= (ETH_DO_NOT_FORCE_LINK_FAIL_MASK); + MV_REG_WRITE(ETH_PORT_SERIAL_CTRL_REG(ethPortNum), regData); +*/ + /* Wait about 2500 tclk cycles */ + uDelay = (PORT_DISABLE_WAIT_TCLOCKS/(mvBoardTclkGet()/1000000)); + mvOsUDelay(uDelay); + + pPortCtrl->portState = MV_PAUSED; + + return MV_OK; +} + + +/******************************************************************************* +* ethPortEnable - Enable the Ethernet port and Start RX and TX. +* +* DESCRIPTION: +* This routine enable the Ethernet port and Rx and Tx activity: +* +* Note: Each Rx and Tx queue descriptor's list must be initialized prior +* to calling this function (use etherInitTxDescRing for Tx queues and +* etherInitRxDescRing for Rx queues). +* +* INPUT: +* void* pEthPortHndl - Ethernet port handler +* +* RETURN: MV_STATUS +* MV_OK - Success, Others - Failure. +* +* NOTE: main usage is to enable the port after ifconfig up. +*******************************************************************************/ +MV_STATUS mvEthPortEnable(void* pEthPortHndl) +{ + int ethPortNo; + ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pEthPortHndl; + MV_U32 portSerialCtrlReg; + + ethPortNo = pPortCtrl->portNo; + + /* Enable port */ + portSerialCtrlReg = MV_REG_READ(ETH_PORT_SERIAL_CTRL_REG(ethPortNo)); + portSerialCtrlReg |= (ETH_DO_NOT_FORCE_LINK_FAIL_MASK | ETH_PORT_ENABLE_MASK); + + MV_REG_WRITE(ETH_PORT_SERIAL_CTRL_REG(ethPortNo), portSerialCtrlReg); + + mvEthMibCountersClear(pEthPortHndl); + + pPortCtrl->portState = MV_PAUSED; + + /* If Link is UP, Start RX and TX traffic */ + if( MV_REG_READ( ETH_PORT_STATUS_REG(ethPortNo) ) & ETH_LINK_UP_MASK) + return( mvEthPortUp(pEthPortHndl) ); + + return MV_NOT_READY; +} + + +/******************************************************************************* +* mvEthPortDisable - Stop RX and TX activities and Disable the Ethernet port. +* +* DESCRIPTION: +* +* INPUT: +* void* pEthPortHndl - Ethernet port handler +* +* RETURN: MV_STATUS +* MV_OK - Success, Others - Failure. +* +* NOTE: main usage is to disable the port after ifconfig down. +*******************************************************************************/ +MV_STATUS mvEthPortDisable(void* pEthPortHndl) +{ + ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pEthPortHndl; + int ethPortNum = pPortCtrl->portNo; + unsigned int regData; + volatile int mvDelay; + + if(pPortCtrl->portState == MV_ACTIVE) + { + /* Stop RX and TX activities */ + mvEthPortDown(pEthPortHndl); + } + + /* Reset the Enable bit in the Serial Control Register */ + regData = MV_REG_READ(ETH_PORT_SERIAL_CTRL_REG(ethPortNum)); + regData &= ~(ETH_PORT_ENABLE_MASK); + MV_REG_WRITE(ETH_PORT_SERIAL_CTRL_REG(ethPortNum), regData); + + /* Wait about 2500 tclk cycles */ + mvDelay = (PORT_DISABLE_WAIT_TCLOCKS*(mvCpuPclkGet()/mvBoardTclkGet())); + for(mvDelay; mvDelay>0; mvDelay--); + + pPortCtrl->portState = MV_IDLE; + return MV_OK; +} + +/******************************************************************************* +* mvEthPortForceTxDone - Get next buffer from TX queue in spite of buffer ownership. +* +* DESCRIPTION: +* This routine used to free buffers attached to the Tx ring and should +* be called only when Giga Ethernet port is Down +* +* INPUT: +* void* pEthPortHndl - Ethernet Port handler. +* int txQueue - Number of TX queue. +* +* OUTPUT: +* MV_PKT_INFO *pPktInfo - Pointer to packet was sent. +* +* RETURN: +* MV_EMPTY - There is no more buffers in this queue. +* MV_OK - Buffer detached from the queue and pPktInfo structure +* filled with relevant information. +* +*******************************************************************************/ +MV_PKT_INFO* mvEthPortForceTxDone(void* pEthPortHndl, int txQueue) +{ + ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pEthPortHndl; + ETH_QUEUE_CTRL* pQueueCtrl; + MV_PKT_INFO* pPktInfo; + ETH_TX_DESC* pTxDesc; + int port = pPortCtrl->portNo; + + pQueueCtrl = &pPortCtrl->txQueue[txQueue]; + + while( (pQueueCtrl->pUsedDescr != pQueueCtrl->pCurrentDescr) || + (pQueueCtrl->resource == 0) ) + { + /* Free next descriptor */ + pQueueCtrl->resource++; + pTxDesc = (ETH_TX_DESC*)pQueueCtrl->pUsedDescr; + + /* pPktInfo is available only in descriptors which are last descriptors */ + pPktInfo = (MV_PKT_INFO*)pTxDesc->returnInfo; + if (pPktInfo) + pPktInfo->status = pTxDesc->cmdSts; + + pTxDesc->cmdSts = 0x0; + pTxDesc->returnInfo = 0x0; + ETH_DESCR_FLUSH_INV(pPortCtrl, pTxDesc); + + pQueueCtrl->pUsedDescr = TX_NEXT_DESC_PTR(pTxDesc, pQueueCtrl); + + if (pPktInfo) + if (pPktInfo->status & ETH_TX_LAST_DESC_MASK) + return pPktInfo; + } + MV_REG_WRITE( ETH_TX_CUR_DESC_PTR_REG(port, txQueue), + (MV_U32)ethDescVirtToPhy(pQueueCtrl, pQueueCtrl->pCurrentDescr) ); + return NULL; +} + + + +/******************************************************************************* +* mvEthPortForceRx - Get next buffer from RX queue in spite of buffer ownership. +* +* DESCRIPTION: +* This routine used to free buffers attached to the Rx ring and should +* be called only when Giga Ethernet port is Down +* +* INPUT: +* void* pEthPortHndl - Ethernet Port handler. +* int rxQueue - Number of Rx queue. +* +* OUTPUT: +* MV_PKT_INFO *pPktInfo - Pointer to received packet. +* +* RETURN: +* MV_EMPTY - There is no more buffers in this queue. +* MV_OK - Buffer detached from the queue and pBufInfo structure +* filled with relevant information. +* +*******************************************************************************/ +MV_PKT_INFO* mvEthPortForceRx(void* pEthPortHndl, int rxQueue) +{ + ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pEthPortHndl; + ETH_QUEUE_CTRL* pQueueCtrl; + ETH_RX_DESC* pRxDesc; + MV_PKT_INFO* pPktInfo; + int port = pPortCtrl->portNo; + + pQueueCtrl = &pPortCtrl->rxQueue[rxQueue]; + + if(pQueueCtrl->resource == 0) + { + MV_REG_WRITE( ETH_RX_CUR_DESC_PTR_REG(port, rxQueue), + (MV_U32)ethDescVirtToPhy(pQueueCtrl, pQueueCtrl->pCurrentDescr) ); + + return NULL; + } + /* Free next descriptor */ + pQueueCtrl->resource--; + pRxDesc = (ETH_RX_DESC*)pQueueCtrl->pCurrentDescr; + pPktInfo = (MV_PKT_INFO*)pRxDesc->returnInfo; + + pPktInfo->status = pRxDesc->cmdSts; + pRxDesc->cmdSts = 0x0; + pRxDesc->returnInfo = 0x0; + ETH_DESCR_FLUSH_INV(pPortCtrl, pRxDesc); + + pQueueCtrl->pCurrentDescr = RX_NEXT_DESC_PTR(pRxDesc, pQueueCtrl); + return pPktInfo; +} + + +/******************************************************************************/ +/* Port Configuration functions */ +/******************************************************************************/ +/******************************************************************************* +* mvEthMruGet - Get MRU configuration for Max Rx packet size. +* +* INPUT: +* MV_U32 maxRxPktSize - max packet size. +* +* RETURN: MV_U32 - MRU configuration. +* +*******************************************************************************/ +static MV_U32 mvEthMruGet(MV_U32 maxRxPktSize) +{ + MV_U32 portSerialCtrlReg = 0; + + if(maxRxPktSize > 9192) + portSerialCtrlReg |= ETH_MAX_RX_PACKET_9700BYTE; + else if(maxRxPktSize > 9022) + portSerialCtrlReg |= ETH_MAX_RX_PACKET_9192BYTE; + else if(maxRxPktSize > 1552) + portSerialCtrlReg |= ETH_MAX_RX_PACKET_9022BYTE; + else if(maxRxPktSize > 1522) + portSerialCtrlReg |= ETH_MAX_RX_PACKET_1552BYTE; + else if(maxRxPktSize > 1518) + portSerialCtrlReg |= ETH_MAX_RX_PACKET_1522BYTE; + else + portSerialCtrlReg |= ETH_MAX_RX_PACKET_1518BYTE; + + return portSerialCtrlReg; +} + +/******************************************************************************* +* mvEthRxCoalSet - Sets coalescing interrupt mechanism on RX path +* +* DESCRIPTION: +* This routine sets the RX coalescing interrupt mechanism parameter. +* This parameter is a timeout counter, that counts in 64 tClk +* chunks, that when timeout event occurs a maskable interrupt occurs. +* The parameter is calculated using the tCLK frequency of the +* MV-64xxx chip, and the required number is in micro seconds. +* +* INPUT: +* void* pPortHndl - Ethernet Port handler. +* MV_U32 uSec - Number of micro seconds between +* RX interrupts +* +* RETURN: +* None. +* +* COMMENT: +* 1 sec - TCLK_RATE clocks +* 1 uSec - TCLK_RATE / 1,000,000 clocks +* +* Register Value for N micro seconds - ((N * ( (TCLK_RATE / 1,000,000)) / 64) +* +* RETURN: +* None. +* +*******************************************************************************/ +MV_U32 mvEthRxCoalSet (void* pPortHndl, MV_U32 uSec) +{ + ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHndl; + MV_U32 coal = ((uSec * (mvBoardTclkGet() / 1000000)) / 64); + MV_U32 portSdmaCfgReg; + + portSdmaCfgReg = MV_REG_READ(ETH_SDMA_CONFIG_REG(pPortCtrl->portNo)); + portSdmaCfgReg &= ~ETH_RX_INTR_COAL_ALL_MASK; + + portSdmaCfgReg |= ETH_RX_INTR_COAL_MASK(coal); + +#if (MV_ETH_VERSION >= 2) + /* Set additional bit if needed ETH_RX_INTR_COAL_MSB_BIT (25) */ + if(ETH_RX_INTR_COAL_MASK(coal) > ETH_RX_INTR_COAL_ALL_MASK) + portSdmaCfgReg |= ETH_RX_INTR_COAL_MSB_MASK; +#endif /* MV_ETH_VERSION >= 2 */ + + MV_REG_WRITE (ETH_SDMA_CONFIG_REG(pPortCtrl->portNo), portSdmaCfgReg); + return coal; +} + +/******************************************************************************* +* mvEthTxCoalSet - Sets coalescing interrupt mechanism on TX path +* +* DESCRIPTION: +* This routine sets the TX coalescing interrupt mechanism parameter. +* This parameter is a timeout counter, that counts in 64 tClk +* chunks, that when timeout event occurs a maskable interrupt +* occurs. +* The parameter is calculated using the tCLK frequency of the +* MV-64xxx chip, and the required number is in micro seconds. +* +* INPUT: +* void* pPortHndl - Ethernet Port handler. +* MV_U32 uSec - Number of micro seconds between +* RX interrupts +* +* RETURN: +* None. +* +* COMMENT: +* 1 sec - TCLK_RATE clocks +* 1 uSec - TCLK_RATE / 1,000,000 clocks +* +* Register Value for N micro seconds - ((N * ( (TCLK_RATE / 1,000,000)) / 64) +* +*******************************************************************************/ +MV_U32 mvEthTxCoalSet(void* pPortHndl, MV_U32 uSec) +{ + ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHndl; + MV_U32 coal = ((uSec * (mvBoardTclkGet() / 1000000)) / 64); + MV_U32 regVal; + + regVal = MV_REG_READ(ETH_TX_FIFO_URGENT_THRESH_REG(pPortCtrl->portNo)); + regVal &= ~ETH_TX_INTR_COAL_ALL_MASK; + regVal |= ETH_TX_INTR_COAL_MASK(coal); + + /* Set TX Coalescing mechanism */ + MV_REG_WRITE (ETH_TX_FIFO_URGENT_THRESH_REG(pPortCtrl->portNo), regVal); + return coal; +} + +/******************************************************************************* +* mvEthCoalGet - Gets RX and TX coalescing values in micro seconds +* +* DESCRIPTION: +* This routine gets the RX and TX coalescing interrupt values. +* The parameter is calculated using the tCLK frequency of the +* MV-64xxx chip, and the returned numbers are in micro seconds. +* +* INPUTs: +* void* pPortHndl - Ethernet Port handler. +* +* OUTPUTs: +* MV_U32* pRxCoal - Number of micro seconds between RX interrupts +* MV_U32* pTxCoal - Number of micro seconds between TX interrupts +* +* RETURN: +* MV_STATUS MV_OK - success +* Others - failure. +* +* COMMENT: +* 1 sec - TCLK_RATE clocks +* 1 uSec - TCLK_RATE / 1,000,000 clocks +* +* Register Value for N micro seconds - ((N * ( (TCLK_RATE / 1,000,000)) / 64) +* +*******************************************************************************/ +MV_STATUS mvEthCoalGet(void* pPortHndl, MV_U32* pRxCoal, MV_U32* pTxCoal) +{ + MV_U32 regVal, coal, usec; + + ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHndl; + + /* get TX Coalescing */ + regVal = MV_REG_READ (ETH_TX_FIFO_URGENT_THRESH_REG(pPortCtrl->portNo)); + coal = ((regVal & ETH_TX_INTR_COAL_ALL_MASK) >> ETH_TX_INTR_COAL_OFFSET); + + usec = (coal * 64) / (mvBoardTclkGet() / 1000000); + if(pTxCoal != NULL) + *pTxCoal = usec; + + /* Get RX Coalescing */ + regVal = MV_REG_READ(ETH_SDMA_CONFIG_REG(pPortCtrl->portNo)); + coal = ((regVal & ETH_RX_INTR_COAL_ALL_MASK) >> ETH_RX_INTR_COAL_OFFSET); + +#if (MV_ETH_VERSION >= 2) + if(regVal & ETH_RX_INTR_COAL_MSB_MASK) + { + /* Add MSB */ + coal |= (ETH_RX_INTR_COAL_ALL_MASK + 1); + } +#endif /* MV_ETH_VERSION >= 2 */ + + usec = (coal * 64) / (mvBoardTclkGet() / 1000000); + if(pRxCoal != NULL) + *pRxCoal = usec; + + return MV_OK; +} + +/******************************************************************************* +* mvEthMaxRxSizeSet - +* +* DESCRIPTION: +* Change maximum receive size of the port. This configuration will take place +* after next call of ethPortSetDefaults() function. +* +* INPUT: +* +* RETURN: +*******************************************************************************/ +MV_STATUS mvEthMaxRxSizeSet(void* pPortHndl, int maxRxSize) +{ + ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHndl; + MV_U32 portSerialCtrlReg; + + if((maxRxSize < 1518) || (maxRxSize & ~ETH_RX_BUFFER_MASK)) + return MV_BAD_PARAM; + + pPortCtrl->portConfig.maxRxPktSize = maxRxSize; + + portSerialCtrlReg = MV_REG_READ(ETH_PORT_SERIAL_CTRL_REG(pPortCtrl->portNo)); + portSerialCtrlReg &= ~ETH_MAX_RX_PACKET_SIZE_MASK; + portSerialCtrlReg |= mvEthMruGet(pPortCtrl->portConfig.maxRxPktSize); + MV_REG_WRITE(ETH_PORT_SERIAL_CTRL_REG(pPortCtrl->portNo), portSerialCtrlReg); + + return MV_OK; +} + + +/******************************************************************************/ +/* MAC Filtering functions */ +/******************************************************************************/ + +/******************************************************************************* +* mvEthRxFilterModeSet - Configure Fitering mode of Ethernet port +* +* DESCRIPTION: +* This routine used to free buffers attached to the Rx ring and should +* be called only when Giga Ethernet port is Down +* +* INPUT: +* void* pEthPortHndl - Ethernet Port handler. +* MV_BOOL isPromisc - Promiscous mode +* MV_TRUE - accept all Broadcast, Multicast +* and Unicast packets +* MV_FALSE - accept all Broadcast, +* specially added Multicast and +* single Unicast packets +* +* RETURN: MV_STATUS MV_OK - Success, Other - Failure +* +*******************************************************************************/ +MV_STATUS mvEthRxFilterModeSet(void* pEthPortHndl, MV_BOOL isPromisc) +{ + ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pEthPortHndl; + int queue; + MV_U32 portCfgReg; + + portCfgReg = MV_REG_READ(ETH_PORT_CONFIG_REG(pPortCtrl->portNo)); + /* Set / Clear UPM bit in port configuration register */ + if(isPromisc) + { + /* Accept all multicast packets to RX default queue */ + queue = pPortCtrl->portConfig.rxDefQ; + portCfgReg |= ETH_UNICAST_PROMISCUOUS_MODE_MASK; + memset(pPortCtrl->mcastCount, 1, sizeof(pPortCtrl->mcastCount)); + MV_REG_WRITE(ETH_MAC_ADDR_LOW_REG(pPortCtrl->portNo),0xFFFF); + MV_REG_WRITE(ETH_MAC_ADDR_HIGH_REG(pPortCtrl->portNo),0xFFFFFFFF); + } + else + { + /* Reject all Multicast addresses */ + queue = -1; + portCfgReg &= ~ETH_UNICAST_PROMISCUOUS_MODE_MASK; + /* Clear all mcastCount */ + memset(pPortCtrl->mcastCount, 0, sizeof(pPortCtrl->mcastCount)); + } + MV_REG_WRITE(ETH_PORT_CONFIG_REG(pPortCtrl->portNo), portCfgReg); + + /* Set Special Multicast and Other Multicast tables */ + mvEthSetSpecialMcastTable(pPortCtrl->portNo, queue); + mvEthSetOtherMcastTable(pPortCtrl->portNo, queue); + ethSetUcastTable(pPortCtrl->portNo, queue); + + return MV_OK; +} + +/******************************************************************************* +* mvEthMacAddrSet - This function Set the port Unicast address. +* +* DESCRIPTION: +* This function Set the port Ethernet MAC address. This address +* will be used to send Pause frames if enabled. Packets with this +* address will be accepted and dispatched to default RX queue +* +* INPUT: +* void* pEthPortHndl - Ethernet port handler. +* char* pAddr - Address to be set +* +* RETURN: MV_STATUS +* MV_OK - Success, Other - Faulure +* +*******************************************************************************/ +MV_STATUS mvEthMacAddrSet(void* pPortHndl, unsigned char *pAddr, int queue) +{ + ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHndl; + unsigned int macH; + unsigned int macL; + + if(queue >= MV_ETH_RX_Q_NUM) + { + mvOsPrintf("ethDrv: RX queue #%d is out of range\n", queue); + return MV_BAD_PARAM; + } + + if(queue != -1) + { + macL = (pAddr[4] << 8) | (pAddr[5]); + macH = (pAddr[0] << 24)| (pAddr[1] << 16) | + (pAddr[2] << 8) | (pAddr[3] << 0); + + MV_REG_WRITE(ETH_MAC_ADDR_LOW_REG(pPortCtrl->portNo), macL); + MV_REG_WRITE(ETH_MAC_ADDR_HIGH_REG(pPortCtrl->portNo), macH); + } + + /* Accept frames of this address */ + ethSetUcastAddr(pPortCtrl->portNo, pAddr[5], queue); + + return MV_OK; +} + +/******************************************************************************* +* mvEthMacAddrGet - This function returns the port Unicast address. +* +* DESCRIPTION: +* This function returns the port Ethernet MAC address. +* +* INPUT: +* int portNo - Ethernet port number. +* char* pAddr - Pointer where address will be written to +* +* RETURN: MV_STATUS +* MV_OK - Success, Other - Faulure +* +*******************************************************************************/ +MV_STATUS mvEthMacAddrGet(int portNo, unsigned char *pAddr) +{ + unsigned int macH; + unsigned int macL; + + if(pAddr == NULL) + { + mvOsPrintf("mvEthMacAddrGet: NULL pointer.\n"); + return MV_BAD_PARAM; + } + + macH = MV_REG_READ(ETH_MAC_ADDR_HIGH_REG(portNo)); + macL = MV_REG_READ(ETH_MAC_ADDR_LOW_REG(portNo)); + pAddr[0] = (macH >> 24) & 0xff; + pAddr[1] = (macH >> 16) & 0xff; + pAddr[2] = (macH >> 8) & 0xff; + pAddr[3] = macH & 0xff; + pAddr[4] = (macL >> 8) & 0xff; + pAddr[5] = macL & 0xff; + + return MV_OK; +} + +/******************************************************************************* +* mvEthMcastCrc8Get - Calculate CRC8 of MAC address. +* +* DESCRIPTION: +* +* INPUT: +* MV_U8* pAddr - Address to calculate CRC-8 +* +* RETURN: MV_U8 - CRC-8 of this MAC address +* +*******************************************************************************/ +MV_U8 mvEthMcastCrc8Get(MV_U8* pAddr) +{ + unsigned int macH; + unsigned int macL; + int macArray[48]; + int crc[8]; + int i; + unsigned char crcResult = 0; + + /* Calculate CRC-8 out of the given address */ + macH = (pAddr[0] << 8) | (pAddr[1]); + macL = (pAddr[2] << 24)| (pAddr[3] << 16) | + (pAddr[4] << 8) | (pAddr[5] << 0); + + for(i=0; i<32; i++) + macArray[i] = (macL >> i) & 0x1; + + for(i=32; i<48; i++) + macArray[i] = (macH >> (i - 32)) & 0x1; + + crc[0] = macArray[45] ^ macArray[43] ^ macArray[40] ^ macArray[39] ^ + macArray[35] ^ macArray[34] ^ macArray[31] ^ macArray[30] ^ + macArray[28] ^ macArray[23] ^ macArray[21] ^ macArray[19] ^ + macArray[18] ^ macArray[16] ^ macArray[14] ^ macArray[12] ^ + macArray[8] ^ macArray[7] ^ macArray[6] ^ macArray[0]; + + crc[1] = macArray[46] ^ macArray[45] ^ macArray[44] ^ macArray[43] ^ + macArray[41] ^ macArray[39] ^ macArray[36] ^ macArray[34] ^ + macArray[32] ^ macArray[30] ^ macArray[29] ^ macArray[28] ^ + macArray[24] ^ macArray[23] ^ macArray[22] ^ macArray[21] ^ + macArray[20] ^ macArray[18] ^ macArray[17] ^ macArray[16] ^ + macArray[15] ^ macArray[14] ^ macArray[13] ^ macArray[12] ^ + macArray[9] ^ macArray[6] ^ macArray[1] ^ macArray[0]; + + crc[2] = macArray[47] ^ macArray[46] ^ macArray[44] ^ macArray[43] ^ + macArray[42] ^ macArray[39] ^ macArray[37] ^ macArray[34] ^ + macArray[33] ^ macArray[29] ^ macArray[28] ^ macArray[25] ^ + macArray[24] ^ macArray[22] ^ macArray[17] ^ macArray[15] ^ + macArray[13] ^ macArray[12] ^ macArray[10] ^ macArray[8] ^ + macArray[6] ^ macArray[2] ^ macArray[1] ^ macArray[0]; + + crc[3] = macArray[47] ^ macArray[45] ^ macArray[44] ^ macArray[43] ^ + macArray[40] ^ macArray[38] ^ macArray[35] ^ macArray[34] ^ + macArray[30] ^ macArray[29] ^ macArray[26] ^ macArray[25] ^ + macArray[23] ^ macArray[18] ^ macArray[16] ^ macArray[14] ^ + macArray[13] ^ macArray[11] ^ macArray[9] ^ macArray[7] ^ + macArray[3] ^ macArray[2] ^ macArray[1]; + + crc[4] = macArray[46] ^ macArray[45] ^ macArray[44] ^ macArray[41] ^ + macArray[39] ^ macArray[36] ^ macArray[35] ^ macArray[31] ^ + macArray[30] ^ macArray[27] ^ macArray[26] ^ macArray[24] ^ + macArray[19] ^ macArray[17] ^ macArray[15] ^ macArray[14] ^ + macArray[12] ^ macArray[10] ^ macArray[8] ^ macArray[4] ^ + macArray[3] ^ macArray[2]; + + crc[5] = macArray[47] ^ macArray[46] ^ macArray[45] ^ macArray[42] ^ + macArray[40] ^ macArray[37] ^ macArray[36] ^ macArray[32] ^ + macArray[31] ^ macArray[28] ^ macArray[27] ^ macArray[25] ^ + macArray[20] ^ macArray[18] ^ macArray[16] ^ macArray[15] ^ + macArray[13] ^ macArray[11] ^ macArray[9] ^ macArray[5] ^ + macArray[4] ^ macArray[3]; + + crc[6] = macArray[47] ^ macArray[46] ^ macArray[43] ^ macArray[41] ^ + macArray[38] ^ macArray[37] ^ macArray[33] ^ macArray[32] ^ + macArray[29] ^ macArray[28] ^ macArray[26] ^ macArray[21] ^ + macArray[19] ^ macArray[17] ^ macArray[16] ^ macArray[14] ^ + macArray[12] ^ macArray[10] ^ macArray[6] ^ macArray[5] ^ + macArray[4]; + + crc[7] = macArray[47] ^ macArray[44] ^ macArray[42] ^ macArray[39] ^ + macArray[38] ^ macArray[34] ^ macArray[33] ^ macArray[30] ^ + macArray[29] ^ macArray[27] ^ macArray[22] ^ macArray[20] ^ + macArray[18] ^ macArray[17] ^ macArray[15] ^ macArray[13] ^ + macArray[11] ^ macArray[7] ^ macArray[6] ^ macArray[5]; + + for(i=0; i<8; i++) + crcResult = crcResult | (crc[i] << i); + + return crcResult; +} +/******************************************************************************* +* mvEthMcastAddrSet - Multicast address settings. +* +* DESCRIPTION: +* This API controls the MV device MAC multicast support. +* The MV device supports multicast using two tables: +* 1) Special Multicast Table for MAC addresses of the form +* 0x01-00-5E-00-00-XX (where XX is between 0x00 and 0xFF). +* The MAC DA[7:0] bits are used as a pointer to the Special Multicast +* Table entries in the DA-Filter table. +* In this case, the function calls ethPortSmcAddr() routine to set the +* Special Multicast Table. +* 2) Other Multicast Table for multicast of another type. A CRC-8bit +* is used as an index to the Other Multicast Table entries in the +* DA-Filter table. +* In this case, the function calculates the CRC-8bit value and calls +* ethPortOmcAddr() routine to set the Other Multicast Table. +* +* INPUT: +* void* pEthPortHndl - Ethernet port handler. +* MV_U8* pAddr - Address to be set +* int queue - RX queue to capture all packets with this +* Multicast MAC address. +* -1 means delete this Multicast address. +* +* RETURN: MV_STATUS +* MV_TRUE - Success, Other - Failure +* +*******************************************************************************/ +MV_STATUS mvEthMcastAddrSet(void* pPortHndl, MV_U8 *pAddr, int queue) +{ + ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHndl; + unsigned char crcResult = 0; + + if(queue >= MV_ETH_RX_Q_NUM) + { + mvOsPrintf("ethPort %d: RX queue #%d is out of range\n", + pPortCtrl->portNo, queue); + return MV_BAD_PARAM; + } + + if((pAddr[0] == 0x01) && + (pAddr[1] == 0x00) && + (pAddr[2] == 0x5E) && + (pAddr[3] == 0x00) && + (pAddr[4] == 0x00)) + { + ethSetSpecialMcastAddr(pPortCtrl->portNo, pAddr[5], queue); + } + else + { + crcResult = mvEthMcastCrc8Get(pAddr); + + /* Check Add counter for this CRC value */ + if(queue == -1) + { + if(pPortCtrl->mcastCount[crcResult] == 0) + { + mvOsPrintf("ethPort #%d: No valid Mcast for crc8=0x%02x\n", + pPortCtrl->portNo, (unsigned)crcResult); + return MV_NO_SUCH; + } + + pPortCtrl->mcastCount[crcResult]--; + if(pPortCtrl->mcastCount[crcResult] != 0) + { + mvOsPrintf("ethPort #%d: After delete there are %d valid Mcast for crc8=0x%02x\n", + pPortCtrl->portNo, pPortCtrl->mcastCount[crcResult], + (unsigned)crcResult); + return MV_NO_CHANGE; + } + } + else + { + pPortCtrl->mcastCount[crcResult]++; + if(pPortCtrl->mcastCount[crcResult] > 1) + { + mvOsPrintf("ethPort #%d: Valid Mcast for crc8=0x%02x already exists\n", + pPortCtrl->portNo, (unsigned)crcResult); + return MV_NO_CHANGE; + } + } + ethSetOtherMcastAddr(pPortCtrl->portNo, crcResult, queue); + } + return MV_OK; +} + +/******************************************************************************* +* ethSetUcastTable - Unicast address settings. +* +* DESCRIPTION: +* Set all entries in the Unicast MAC Table queue==-1 means reject all +* INPUT: +* +* RETURN: +* +*******************************************************************************/ +static void ethSetUcastTable(int portNo, int queue) +{ + int offset; + MV_U32 regValue; + + if(queue == -1) + { + regValue = 0; + } + else + { + regValue = (((0x01 | (queue<<1)) << 0) | + ((0x01 | (queue<<1)) << 8) | + ((0x01 | (queue<<1)) << 16) | + ((0x01 | (queue<<1)) << 24)); + } + + for (offset=0; offset<=0xC; offset+=4) + MV_REG_WRITE((ETH_DA_FILTER_UCAST_BASE(portNo) + offset), regValue); +} + +/******************************************************************************* +* mvEthSetSpecialMcastTable - Special Multicast address settings. +* +* DESCRIPTION: +* Set all entries to the Special Multicast MAC Table. queue==-1 means reject all +* INPUT: +* +* RETURN: +* +*******************************************************************************/ +MV_VOID mvEthSetSpecialMcastTable(int portNo, int queue) +{ + int offset; + MV_U32 regValue; + + if(queue == -1) + { + regValue = 0; + } + else + { + regValue = (((0x01 | (queue<<1)) << 0) | + ((0x01 | (queue<<1)) << 8) | + ((0x01 | (queue<<1)) << 16) | + ((0x01 | (queue<<1)) << 24)); + } + + for (offset=0; offset<=0xFC; offset+=4) + { + MV_REG_WRITE((ETH_DA_FILTER_SPEC_MCAST_BASE(portNo) + + offset), regValue); + } +} + +/******************************************************************************* +* mvEthSetOtherMcastTable - Other Multicast address settings. +* +* DESCRIPTION: +* Set all entries to the Other Multicast MAC Table. queue==-1 means reject all +* INPUT: +* +* RETURN: +* +*******************************************************************************/ +MV_VOID mvEthSetOtherMcastTable(int portNo, int queue) +{ + int offset; + MV_U32 regValue; + + if(queue == -1) + { + regValue = 0; + } + else + { + regValue = (((0x01 | (queue<<1)) << 0) | + ((0x01 | (queue<<1)) << 8) | + ((0x01 | (queue<<1)) << 16) | + ((0x01 | (queue<<1)) << 24)); + } + + for (offset=0; offset<=0xFC; offset+=4) + { + MV_REG_WRITE((ETH_DA_FILTER_OTH_MCAST_BASE(portNo) + + offset), regValue); + } +} + +/******************************************************************************* +* ethSetUcastAddr - This function Set the port unicast address table +* +* DESCRIPTION: +* This function locates the proper entry in the Unicast table for the +* specified MAC nibble and sets its properties according to function +* parameters. +* +* INPUT: +* int ethPortNum - Port number. +* MV_U8 lastNibble - Unicast MAC Address last nibble. +* int queue - Rx queue number for this MAC address. +* value "-1" means remove address +* +* OUTPUT: +* This function add/removes MAC addresses from the port unicast address +* table. +* +* RETURN: +* MV_TRUE is output succeeded. +* MV_FALSE if option parameter is invalid. +* +*******************************************************************************/ +static MV_BOOL ethSetUcastAddr(int portNo, MV_U8 lastNibble, int queue) +{ + unsigned int unicastReg; + unsigned int tblOffset; + unsigned int regOffset; + + /* Locate the Unicast table entry */ + lastNibble = (0xf & lastNibble); + tblOffset = (lastNibble / 4) * 4; /* Register offset from unicast table base*/ + regOffset = lastNibble % 4; /* Entry offset within the above register */ + + + unicastReg = MV_REG_READ( (ETH_DA_FILTER_UCAST_BASE(portNo) + + tblOffset)); + + + if(queue == -1) + { + /* Clear accepts frame bit at specified unicast DA table entry */ + unicastReg &= ~(0xFF << (8*regOffset)); + } + else + { + unicastReg &= ~(0xFF << (8*regOffset)); + unicastReg |= ((0x01 | (queue<<1)) << (8*regOffset)); + } + MV_REG_WRITE( (ETH_DA_FILTER_UCAST_BASE(portNo) + tblOffset), + unicastReg); + + return MV_TRUE; +} + +/******************************************************************************* +* ethSetSpecialMcastAddr - Special Multicast address settings. +* +* DESCRIPTION: +* This routine controls the MV device special MAC multicast support. +* The Special Multicast Table for MAC addresses supports MAC of the form +* 0x01-00-5E-00-00-XX (where XX is between 0x00 and 0xFF). +* The MAC DA[7:0] bits are used as a pointer to the Special Multicast +* Table entries in the DA-Filter table. +* This function set the Special Multicast Table appropriate entry +* according to the argument given. +* +* INPUT: +* int ethPortNum Port number. +* unsigned char mcByte Multicast addr last byte (MAC DA[7:0] bits). +* int queue Rx queue number for this MAC address. +* int option 0 = Add, 1 = remove address. +* +* OUTPUT: +* See description. +* +* RETURN: +* MV_TRUE is output succeeded. +* MV_FALSE if option parameter is invalid. +* +*******************************************************************************/ +static MV_BOOL ethSetSpecialMcastAddr(int ethPortNum, MV_U8 lastByte, int queue) +{ + unsigned int smcTableReg; + unsigned int tblOffset; + unsigned int regOffset; + + /* Locate the SMC table entry */ + tblOffset = (lastByte / 4); /* Register offset from SMC table base */ + regOffset = lastByte % 4; /* Entry offset within the above register */ + + smcTableReg = MV_REG_READ((ETH_DA_FILTER_SPEC_MCAST_BASE(ethPortNum) + tblOffset*4)); + + if(queue == -1) + { + /* Clear accepts frame bit at specified Special DA table entry */ + smcTableReg &= ~(0xFF << (8 * regOffset)); + } + else + { + smcTableReg &= ~(0xFF << (8 * regOffset)); + smcTableReg |= ((0x01 | (queue<<1)) << (8 * regOffset)); + } + MV_REG_WRITE((ETH_DA_FILTER_SPEC_MCAST_BASE(ethPortNum) + + tblOffset*4), smcTableReg); + + return MV_TRUE; +} + +/******************************************************************************* +* ethSetOtherMcastAddr - Multicast address settings. +* +* DESCRIPTION: +* This routine controls the MV device Other MAC multicast support. +* The Other Multicast Table is used for multicast of another type. +* A CRC-8bit is used as an index to the Other Multicast Table entries +* in the DA-Filter table. +* The function gets the CRC-8bit value from the calling routine and +* set the Other Multicast Table appropriate entry according to the +* CRC-8 argument given. +* +* INPUT: +* int ethPortNum Port number. +* MV_U8 crc8 A CRC-8bit (Polynomial: x^8+x^2+x^1+1). +* int queue Rx queue number for this MAC address. +* +* OUTPUT: +* See description. +* +* RETURN: +* MV_TRUE is output succeeded. +* MV_FALSE if option parameter is invalid. +* +*******************************************************************************/ +static MV_BOOL ethSetOtherMcastAddr(int ethPortNum, MV_U8 crc8, int queue) +{ + unsigned int omcTableReg; + unsigned int tblOffset; + unsigned int regOffset; + + /* Locate the OMC table entry */ + tblOffset = (crc8 / 4) * 4; /* Register offset from OMC table base */ + regOffset = crc8 % 4; /* Entry offset within the above register */ + + omcTableReg = MV_REG_READ( + (ETH_DA_FILTER_OTH_MCAST_BASE(ethPortNum) + tblOffset)); + + if(queue == -1) + { + /* Clear accepts frame bit at specified Other DA table entry */ + omcTableReg &= ~(0xFF << (8 * regOffset)); + } + else + { + omcTableReg &= ~(0xFF << (8 * regOffset)); + omcTableReg |= ((0x01 | (queue<<1)) << (8 * regOffset)); + } + + MV_REG_WRITE((ETH_DA_FILTER_OTH_MCAST_BASE(ethPortNum) + tblOffset), + omcTableReg); + + return MV_TRUE; +} + + +/******************************************************************************/ +/* MIB Counters functions */ +/******************************************************************************/ + + +/******************************************************************************* +* mvEthMibCounterRead - Read a MIB counter +* +* DESCRIPTION: +* This function reads a MIB counter of a specific ethernet port. +* NOTE - Read from ETH_MIB_GOOD_OCTETS_RECEIVED_LOW or +* ETH_MIB_GOOD_OCTETS_SENT_LOW counters will return 64 bits value, +* so pHigh32 pointer should not be NULL in this case. +* +* INPUT: +* int ethPortNum - Ethernet Port number. +* unsigned int mibOffset - MIB counter offset. +* +* OUTPUT: +* MV_U32* pHigh32 - pointer to place where 32 most significant bits +* of the counter will be stored. +* +* RETURN: +* 32 low sgnificant bits of MIB counter value. +* +*******************************************************************************/ +MV_U32 mvEthMibCounterRead(void* pPortHandle, unsigned int mibOffset, + MV_U32* pHigh32) +{ + int portNo; + MV_U32 valLow32, valHigh32; + ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHandle; + + portNo = pPortCtrl->portNo; + + valLow32 = MV_REG_READ(ETH_MIB_COUNTERS_BASE(portNo) + mibOffset); + + /* Implement FEr ETH. Erroneous Value when Reading the Upper 32-bits */ + /* of a 64-bit MIB Counter. */ + if( (mibOffset == ETH_MIB_GOOD_OCTETS_RECEIVED_LOW) || + (mibOffset == ETH_MIB_GOOD_OCTETS_SENT_LOW) ) + { + valHigh32 = MV_REG_READ(ETH_MIB_COUNTERS_BASE(portNo) + mibOffset + 4); + if(pHigh32 != NULL) + *pHigh32 = valHigh32; + } + return valLow32; +} + +/******************************************************************************* +* mvEthMibCountersClear - Clear all MIB counters +* +* DESCRIPTION: +* This function clears all MIB counters +* +* INPUT: +* int ethPortNum - Ethernet Port number. +* +* +* RETURN: void +* +*******************************************************************************/ +void mvEthMibCountersClear(void* pPortHandle) +{ + int i, portNo; + unsigned int dummy; + ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHandle; + + portNo = pPortCtrl->portNo; + + /* Perform dummy reads from MIB counters */ + for(i=ETH_MIB_GOOD_OCTETS_RECEIVED_LOW; i 0xFF) + { + mvOsPrintf("eth_%d: tos=0x%x is out of range\n", pPortCtrl->portNo, tos); + return -1; + } + regIdx = mvOsDivide(tos>>2, 10); + regOffs = mvOsReminder(tos>>2, 10); + + regValue = MV_REG_READ(ETH_DIFF_SERV_PRIO_REG(pPortCtrl->portNo, regIdx) ); + rxq = (regValue >> (regOffs*3)); + rxq &= 0x7; + + return rxq; +} + +/******************************************************************************* +* mvEthTosToRxqSet - Map packets with special TOS value to special RX queue +* +* DESCRIPTION: +* +* INPUT: +* void* pPortHandle - Pointer to port specific handler; +* int tos - TOS value in the IP header of the packet +* int rxq - RX Queue for packets with the configured TOS value +* Negative value (-1) means no special processing for these packets, +* so they will be processed as regular packets. +* +* RETURN: MV_STATUS +*******************************************************************************/ +MV_STATUS mvEthTosToRxqSet(void* pPortHandle, int tos, int rxq) +{ + MV_U32 regValue; + int regIdx, regOffs; + ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHandle; + + if( (rxq < 0) || (rxq >= MV_ETH_RX_Q_NUM) ) + { + mvOsPrintf("eth_%d: RX queue #%d is out of range\n", pPortCtrl->portNo, rxq); + return MV_BAD_PARAM; + } + if(tos > 0xFF) + { + mvOsPrintf("eth_%d: tos=0x%x is out of range\n", pPortCtrl->portNo, tos); + return MV_BAD_PARAM; + } + regIdx = mvOsDivide(tos>>2, 10); + regOffs = mvOsReminder(tos>>2, 10); + + regValue = MV_REG_READ(ETH_DIFF_SERV_PRIO_REG(pPortCtrl->portNo, regIdx) ); + regValue &= ~(0x7 << (regOffs*3)); + regValue |= (rxq << (regOffs*3)); + + MV_REG_WRITE(ETH_DIFF_SERV_PRIO_REG(pPortCtrl->portNo, regIdx), regValue); + return MV_OK; +} + +/******************************************************************************* +* mvEthVlanPrioRxQueue - Configure RX queue to capture VLAN tagged packets with +* special priority bits [0-2] +* +* DESCRIPTION: +* +* INPUT: +* void* pPortHandle - Pointer to port specific handler; +* int bpduQueue - Special queue to capture VLAN tagged packets with special +* priority. +* Negative value (-1) means no special processing for these packets, +* so they will be processed as regular packets. +* +* RETURN: MV_STATUS +* MV_OK - Success +* MV_FAIL - Failed. +* +*******************************************************************************/ +MV_STATUS mvEthVlanPrioRxQueue(void* pPortHandle, int vlanPrio, int vlanPrioQueue) +{ + ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHandle; + MV_U32 vlanPrioReg; + + if(vlanPrioQueue >= MV_ETH_RX_Q_NUM) + { + mvOsPrintf("ethDrv: RX queue #%d is out of range\n", vlanPrioQueue); + return MV_BAD_PARAM; + } + if(vlanPrio >= 8) + { + mvOsPrintf("ethDrv: vlanPrio=%d is out of range\n", vlanPrio); + return MV_BAD_PARAM; + } + + vlanPrioReg = MV_REG_READ(ETH_VLAN_TAG_TO_PRIO_REG(pPortCtrl->portNo)); + vlanPrioReg &= ~(0x7 << (vlanPrio*3)); + vlanPrioReg |= (vlanPrioQueue << (vlanPrio*3)); + MV_REG_WRITE(ETH_VLAN_TAG_TO_PRIO_REG(pPortCtrl->portNo), vlanPrioReg); + + return MV_OK; +} + + +/******************************************************************************* +* mvEthBpduRxQueue - Configure RX queue to capture BPDU packets. +* +* DESCRIPTION: +* This function defines processing of BPDU packets. +* BPDU packets can be accepted and captured to one of RX queues +* or can be processing as regular Multicast packets. +* +* INPUT: +* void* pPortHandle - Pointer to port specific handler; +* int bpduQueue - Special queue to capture BPDU packets (DA is equal to +* 01-80-C2-00-00-00 through 01-80-C2-00-00-FF, +* except for the Flow-Control Pause packets). +* Negative value (-1) means no special processing for BPDU, +* packets so they will be processed as regular Multicast packets. +* +* RETURN: MV_STATUS +* MV_OK - Success +* MV_FAIL - Failed. +* +*******************************************************************************/ +MV_STATUS mvEthBpduRxQueue(void* pPortHandle, int bpduQueue) +{ + ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHandle; + MV_U32 portCfgReg; + MV_U32 portCfgExtReg; + + if(bpduQueue >= MV_ETH_RX_Q_NUM) + { + mvOsPrintf("ethDrv: RX queue #%d is out of range\n", bpduQueue); + return MV_BAD_PARAM; + } + + portCfgExtReg = MV_REG_READ(ETH_PORT_CONFIG_EXTEND_REG(pPortCtrl->portNo)); + + portCfgReg = MV_REG_READ(ETH_PORT_CONFIG_REG(pPortCtrl->portNo)); + if(bpduQueue >= 0) + { + pPortCtrl->portConfig.rxBpduQ = bpduQueue; + + portCfgReg &= ~ETH_DEF_RX_BPDU_QUEUE_ALL_MASK; + portCfgReg |= ETH_DEF_RX_BPDU_QUEUE_MASK(pPortCtrl->portConfig.rxBpduQ); + + MV_REG_WRITE(ETH_PORT_CONFIG_REG(pPortCtrl->portNo), portCfgReg); + + portCfgExtReg |= ETH_CAPTURE_SPAN_BPDU_ENABLE_MASK; + } + else + { + pPortCtrl->portConfig.rxBpduQ = -1; + /* no special processing for BPDU packets */ + portCfgExtReg &= (~ETH_CAPTURE_SPAN_BPDU_ENABLE_MASK); + } + + MV_REG_WRITE(ETH_PORT_CONFIG_EXTEND_REG(pPortCtrl->portNo), portCfgExtReg); + + return MV_OK; +} + + +/******************************************************************************* +* mvEthArpRxQueue - Configure RX queue to capture ARP packets. +* +* DESCRIPTION: +* This function defines processing of ARP (type=0x0806) packets. +* ARP packets can be accepted and captured to one of RX queues +* or can be processed as other Broadcast packets. +* +* INPUT: +* void* pPortHandle - Pointer to port specific handler; +* int arpQueue - Special queue to capture ARP packets (type=0x806). +* Negative value (-1) means discard ARP packets +* +* RETURN: MV_STATUS +* MV_OK - Success +* MV_FAIL - Failed. +* +*******************************************************************************/ +MV_STATUS mvEthArpRxQueue(void* pPortHandle, int arpQueue) +{ + ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHandle; + MV_U32 portCfgReg; + + if(arpQueue >= MV_ETH_RX_Q_NUM) + { + mvOsPrintf("ethDrv: RX queue #%d is out of range\n", arpQueue); + return MV_BAD_PARAM; + } + + portCfgReg = MV_REG_READ(ETH_PORT_CONFIG_REG(pPortCtrl->portNo)); + + if(arpQueue >= 0) + { + pPortCtrl->portConfig.rxArpQ = arpQueue; + portCfgReg &= ~ETH_DEF_RX_ARP_QUEUE_ALL_MASK; + portCfgReg |= ETH_DEF_RX_ARP_QUEUE_MASK(pPortCtrl->portConfig.rxArpQ); + + portCfgReg &= (~ETH_REJECT_ARP_BCAST_MASK); + } + else + { + pPortCtrl->portConfig.rxArpQ = -1; + portCfgReg |= ETH_REJECT_ARP_BCAST_MASK; + } + + MV_REG_WRITE(ETH_PORT_CONFIG_REG(pPortCtrl->portNo), portCfgReg); + + return MV_OK; +} + + +/******************************************************************************* +* mvEthTcpRxQueue - Configure RX queue to capture TCP packets. +* +* DESCRIPTION: +* This function defines processing of TCP packets. +* TCP packets can be accepted and captured to one of RX queues +* or can be processed as regular Unicast packets. +* +* INPUT: +* void* pPortHandle - Pointer to port specific handler; +* int tcpQueue - Special queue to capture TCP packets. Value "-1" +* means no special processing for TCP packets, +* so they will be processed as regular +* +* RETURN: MV_STATUS +* MV_OK - Success +* MV_FAIL - Failed. +* +*******************************************************************************/ +MV_STATUS mvEthTcpRxQueue(void* pPortHandle, int tcpQueue) +{ + ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHandle; + MV_U32 portCfgReg; + + if(tcpQueue >= MV_ETH_RX_Q_NUM) + { + mvOsPrintf("ethDrv: RX queue #%d is out of range\n", tcpQueue); + return MV_BAD_PARAM; + } + portCfgReg = MV_REG_READ(ETH_PORT_CONFIG_REG(pPortCtrl->portNo)); + + if(tcpQueue >= 0) + { + pPortCtrl->portConfig.rxTcpQ = tcpQueue; + portCfgReg &= ~ETH_DEF_RX_TCP_QUEUE_ALL_MASK; + portCfgReg |= ETH_DEF_RX_TCP_QUEUE_MASK(pPortCtrl->portConfig.rxTcpQ); + + portCfgReg |= ETH_CAPTURE_TCP_FRAMES_ENABLE_MASK; + } + else + { + pPortCtrl->portConfig.rxTcpQ = -1; + portCfgReg &= (~ETH_CAPTURE_TCP_FRAMES_ENABLE_MASK); + } + + MV_REG_WRITE(ETH_PORT_CONFIG_REG(pPortCtrl->portNo), portCfgReg); + + return MV_OK; +} + + +/******************************************************************************* +* mvEthUdpRxQueue - Configure RX queue to capture UDP packets. +* +* DESCRIPTION: +* This function defines processing of UDP packets. +* TCP packets can be accepted and captured to one of RX queues +* or can be processed as regular Unicast packets. +* +* INPUT: +* void* pPortHandle - Pointer to port specific handler; +* int udpQueue - Special queue to capture UDP packets. Value "-1" +* means no special processing for UDP packets, +* so they will be processed as regular +* +* RETURN: MV_STATUS +* MV_OK - Success +* MV_FAIL - Failed. +* +*******************************************************************************/ +MV_STATUS mvEthUdpRxQueue(void* pPortHandle, int udpQueue) +{ + ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHandle; + MV_U32 portCfgReg; + + if(udpQueue >= MV_ETH_RX_Q_NUM) + { + mvOsPrintf("ethDrv: RX queue #%d is out of range\n", udpQueue); + return MV_BAD_PARAM; + } + + portCfgReg = MV_REG_READ(ETH_PORT_CONFIG_REG(pPortCtrl->portNo)); + + if(udpQueue >= 0) + { + pPortCtrl->portConfig.rxUdpQ = udpQueue; + portCfgReg &= ~ETH_DEF_RX_UDP_QUEUE_ALL_MASK; + portCfgReg |= ETH_DEF_RX_UDP_QUEUE_MASK(pPortCtrl->portConfig.rxUdpQ); + + portCfgReg |= ETH_CAPTURE_UDP_FRAMES_ENABLE_MASK; + } + else + { + pPortCtrl->portConfig.rxUdpQ = -1; + portCfgReg &= ~ETH_CAPTURE_UDP_FRAMES_ENABLE_MASK; + } + + MV_REG_WRITE(ETH_PORT_CONFIG_REG(pPortCtrl->portNo), portCfgReg); + + return MV_OK; +} + + +/******************************************************************************/ +/* Speed, Duplex, FlowControl routines */ +/******************************************************************************/ + +/******************************************************************************* +* mvEthSpeedDuplexSet - Set Speed and Duplex of the port. +* +* DESCRIPTION: +* This function configure the port to work with desirable Duplex and Speed. +* Changing of these parameters are allowed only when port is disabled. +* This function disable the port if was enabled, change duplex and speed +* and, enable the port back if needed. +* +* INPUT: +* void* pPortHandle - Pointer to port specific handler; +* ETH_PORT_SPEED speed - Speed of the port. +* ETH_PORT_SPEED duplex - Duplex of the port. +* +* RETURN: MV_STATUS +* MV_OK - Success +* MV_OUT_OF_RANGE - Failed. Port is out of valid range +* MV_NOT_FOUND - Failed. Port is not initialized. +* MV_BAD_PARAM - Input parameters (speed/duplex) in conflict. +* MV_BAD_VALUE - Value of one of input parameters (speed, duplex) +* is not valid +* +*******************************************************************************/ +MV_STATUS mvEthSpeedDuplexSet(void* pPortHandle, MV_ETH_PORT_SPEED speed, + MV_ETH_PORT_DUPLEX duplex) +{ + ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHandle; + int port = pPortCtrl->portNo; + MV_U32 portSerialCtrlReg; + + if( (port < 0) || (port >= (int)mvCtrlEthMaxPortGet()) ) + return MV_OUT_OF_RANGE; + + pPortCtrl = ethPortCtrl[port]; + if(pPortCtrl == NULL) + return MV_NOT_FOUND; + + /* Check validity */ + if( (speed == MV_ETH_SPEED_1000) && (duplex == MV_ETH_DUPLEX_HALF) ) + return MV_BAD_PARAM; + + portSerialCtrlReg = MV_REG_READ(ETH_PORT_SERIAL_CTRL_REG(port)); + /* Set Speed */ + switch(speed) + { + case MV_ETH_SPEED_AN: + portSerialCtrlReg &= ~ETH_DISABLE_SPEED_AUTO_NEG_MASK; + break; + + case MV_ETH_SPEED_10: + portSerialCtrlReg |= ETH_DISABLE_SPEED_AUTO_NEG_MASK; + portSerialCtrlReg &= ~ETH_SET_GMII_SPEED_1000_MASK; + portSerialCtrlReg &= ~ETH_SET_MII_SPEED_100_MASK; + break; + + case MV_ETH_SPEED_100: + portSerialCtrlReg |= ETH_DISABLE_SPEED_AUTO_NEG_MASK; + portSerialCtrlReg &= ~ETH_SET_GMII_SPEED_1000_MASK; + portSerialCtrlReg |= ETH_SET_MII_SPEED_100_MASK; + break; + + case MV_ETH_SPEED_1000: + portSerialCtrlReg |= ETH_DISABLE_SPEED_AUTO_NEG_MASK; + portSerialCtrlReg |= ETH_SET_GMII_SPEED_1000_MASK; + break; + + default: + mvOsPrintf("ethDrv: Unexpected Speed value %d\n", speed); + return MV_BAD_VALUE; + } + /* Set duplex */ + switch(duplex) + { + case MV_ETH_DUPLEX_AN: + portSerialCtrlReg &= ~ETH_DISABLE_DUPLEX_AUTO_NEG_MASK; + break; + + case MV_ETH_DUPLEX_HALF: + portSerialCtrlReg |= ETH_DISABLE_DUPLEX_AUTO_NEG_MASK; + portSerialCtrlReg &= ~ETH_SET_FULL_DUPLEX_MASK; + break; + + case MV_ETH_DUPLEX_FULL: + portSerialCtrlReg |= ETH_DISABLE_DUPLEX_AUTO_NEG_MASK; + portSerialCtrlReg |= ETH_SET_FULL_DUPLEX_MASK; + break; + + default: + mvOsPrintf("ethDrv: Unexpected Duplex value %d\n", duplex); + return MV_BAD_VALUE; + } + MV_REG_WRITE(ETH_PORT_SERIAL_CTRL_REG(port), portSerialCtrlReg); + + return MV_OK; +} + +/******************************************************************************* +* mvEthFlowCtrlSet - Set Flow Control of the port. +* +* DESCRIPTION: +* This function configure the port to work with desirable Duplex and +* Speed. Changing of these parameters are allowed only when port is +* disabled. This function disable the port if was enabled, change +* duplex and speed and, enable the port back if needed. +* +* INPUT: +* void* pPortHandle - Pointer to port specific handler; +* MV_ETH_PORT_FC flowControl - Flow control of the port. +* +* RETURN: MV_STATUS +* MV_OK - Success +* MV_OUT_OF_RANGE - Failed. Port is out of valid range +* MV_NOT_FOUND - Failed. Port is not initialized. +* MV_BAD_VALUE - Value flowControl parameters is not valid +* +*******************************************************************************/ +MV_STATUS mvEthFlowCtrlSet(void* pPortHandle, MV_ETH_PORT_FC flowControl) +{ + ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHandle; + int port = pPortCtrl->portNo; + MV_U32 portSerialCtrlReg; + + if( (port < 0) || (port >= (int)mvCtrlEthMaxPortGet() ) ) + return MV_OUT_OF_RANGE; + + pPortCtrl = ethPortCtrl[port]; + if(pPortCtrl == NULL) + return MV_NOT_FOUND; + + portSerialCtrlReg = MV_REG_READ(ETH_PORT_SERIAL_CTRL_REG(port)); + switch(flowControl) + { + case MV_ETH_FC_AN_ADV_DIS: + portSerialCtrlReg &= ~ETH_DISABLE_FC_AUTO_NEG_MASK; + portSerialCtrlReg &= ~ETH_ADVERTISE_SYM_FC_MASK; + break; + + case MV_ETH_FC_AN_ADV_SYM: + portSerialCtrlReg &= ~ETH_DISABLE_FC_AUTO_NEG_MASK; + portSerialCtrlReg |= ETH_ADVERTISE_SYM_FC_MASK; + break; + + case MV_ETH_FC_DISABLE: + portSerialCtrlReg |= ETH_DISABLE_FC_AUTO_NEG_MASK; + portSerialCtrlReg &= ~ETH_SET_FLOW_CTRL_MASK; + break; + + case MV_ETH_FC_ENABLE: + portSerialCtrlReg |= ETH_DISABLE_FC_AUTO_NEG_MASK; + portSerialCtrlReg |= ETH_SET_FLOW_CTRL_MASK; + break; + + default: + mvOsPrintf("ethDrv: Unexpected FlowControl value %d\n", flowControl); + return MV_BAD_VALUE; + } + MV_REG_WRITE(ETH_PORT_SERIAL_CTRL_REG(port), portSerialCtrlReg); + + return MV_OK; +} + +/******************************************************************************* +* mvEthHeaderModeSet - Set port header mode. +* +* DESCRIPTION: +* This function configures the port to work in Marvell-Header mode. +* +* INPUT: +* void* pPortHandle - Pointer to port specific handler; +* MV_ETH_HEADER_MODE headerMode - The header mode to set the port in. +* +* RETURN: MV_STATUS +* MV_OK - Success +* MV_NOT_SUPPORTED- Feature not supported. +* MV_OUT_OF_RANGE - Failed. Port is out of valid range +* MV_NOT_FOUND - Failed. Port is not initialized. +* MV_BAD_VALUE - Value of headerMode or numRxQueue parameter is not valid. +* +*******************************************************************************/ +MV_STATUS mvEthHeaderModeSet(void* pPortHandle, MV_ETH_HEADER_MODE headerMode) +{ + ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHandle; + int port = pPortCtrl->portNo; + MV_U32 mvHeaderReg; + MV_U32 numRxQ = MV_ETH_RX_Q_NUM; + + if((port < 0) || (port >= mvCtrlEthMaxPortGet())) + return MV_OUT_OF_RANGE; + + pPortCtrl = ethPortCtrl[port]; + if(pPortCtrl == NULL) + return MV_NOT_FOUND; + + mvHeaderReg = MV_REG_READ(ETH_PORT_MARVELL_HEADER_REG(port)); + /* Disable header mode. */ + mvHeaderReg &= ~ETH_MVHDR_EN_MASK; + + if(headerMode != MV_ETH_DISABLE_HEADER_MODE) + { + /* Enable Header mode. */ + mvHeaderReg |= ETH_MVHDR_EN_MASK; + + /* Clear DA-Prefix & MHMask fields.*/ + mvHeaderReg &= ~(ETH_MVHDR_DAPREFIX_MASK | ETH_MVHDR_MHMASK_MASK); + + if(numRxQ > 1) + { + switch (headerMode) + { + case(MV_ETH_ENABLE_HEADER_MODE_PRI_2_1): + mvHeaderReg |= ETH_MVHDR_DAPREFIX_PRI_1_2; + break; + case(MV_ETH_ENABLE_HEADER_MODE_PRI_DBNUM): + mvHeaderReg |= ETH_MVHDR_DAPREFIX_DBNUM_PRI; + break; + case(MV_ETH_ENABLE_HEADER_MODE_PRI_SPID): + mvHeaderReg |= ETH_MVHDR_DAPREFIX_SPID_PRI; + break; + default: + break; + } + + switch (numRxQ) + { + case (4): + mvHeaderReg |= ETH_MVHDR_MHMASK_4_QUEUE; + break; + case (8): + mvHeaderReg |= ETH_MVHDR_MHMASK_8_QUEUE; + break; + default: + break; + } + } + } + + MV_REG_WRITE(ETH_PORT_MARVELL_HEADER_REG(port), mvHeaderReg); + + return MV_OK; +} + +#if (MV_ETH_VERSION >= 4) +/******************************************************************************* +* mvEthEjpModeSet - Enable / Disable EJP policy for TX. +* +* DESCRIPTION: +* This function +* +* INPUT: +* void* pPortHandle - Pointer to port specific handler; +* MV_BOOL TRUE - enable EJP mode +* FALSE - disable EJP mode +* +* OUTPUT: MV_STATUS +* MV_OK - Success +* Other - Failure +* +* RETURN: None. +* +*******************************************************************************/ +MV_STATUS mvEthEjpModeSet(void* pPortHandle, int mode) +{ + ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHandle; + int port = pPortCtrl->portNo; + + if((port < 0) || (port >= mvCtrlEthMaxPortGet())) + return MV_OUT_OF_RANGE; + + pPortCtrl = ethPortCtrl[port]; + if(pPortCtrl == NULL) + return MV_NOT_FOUND; + + pPortCtrl->portConfig.ejpMode = mode; + if(mode) + { + /* EJP enabled */ + MV_REG_WRITE(ETH_TXQ_CMD_1_REG(port), ETH_TX_EJP_ENABLE_MASK); + } + else + { + /* EJP disabled */ + MV_REG_WRITE(ETH_TXQ_CMD_1_REG(port), 0); + } + mvOsPrintf("eth_%d: EJP %s - ETH_TXQ_CMD_1_REG: 0x%x = 0x%08x\n", + port, mode ? "Enabled" : "Disabled", ETH_TXQ_CMD_1_REG(port), + MV_REG_READ(ETH_TXQ_CMD_1_REG(port))); + + return MV_OK; +} +#endif /* MV_ETH_VERSION >= 4 */ + +/******************************************************************************* +* mvEthStatusGet - Get major properties of the port . +* +* DESCRIPTION: +* This function get major properties of the port (link, speed, duplex, +* flowControl, etc) and return them using the single structure. +* +* INPUT: +* void* pPortHandle - Pointer to port specific handler; +* +* OUTPUT: +* MV_ETH_PORT_STATUS* pStatus - Pointer to structure, were port status +* will be placed. +* +* RETURN: None. +* +*******************************************************************************/ +void mvEthStatusGet(void* pPortHandle, MV_ETH_PORT_STATUS* pStatus) +{ + ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHandle; + int port = pPortCtrl->portNo; + + MV_U32 regValue; + + regValue = MV_REG_READ( ETH_PORT_STATUS_REG(port) ); + + if(regValue & ETH_GMII_SPEED_1000_MASK) + pStatus->speed = MV_ETH_SPEED_1000; + else if(regValue & ETH_MII_SPEED_100_MASK) + pStatus->speed = MV_ETH_SPEED_100; + else + pStatus->speed = MV_ETH_SPEED_10; + + if(regValue & ETH_LINK_UP_MASK) + pStatus->isLinkUp = MV_TRUE; + else + pStatus->isLinkUp = MV_FALSE; + + if(regValue & ETH_FULL_DUPLEX_MASK) + pStatus->duplex = MV_ETH_DUPLEX_FULL; + else + pStatus->duplex = MV_ETH_DUPLEX_HALF; + + + if(regValue & ETH_ENABLE_RCV_FLOW_CTRL_MASK) + pStatus->flowControl = MV_ETH_FC_ENABLE; + else + pStatus->flowControl = MV_ETH_FC_DISABLE; +} + + +/******************************************************************************/ +/* PHY Control Functions */ +/******************************************************************************/ + + +/******************************************************************************* +* mvEthPhyAddrSet - Set the ethernet port PHY address. +* +* DESCRIPTION: +* This routine set the ethernet port PHY address according to given +* parameter. +* +* INPUT: +* void* pPortHandle - Pointer to port specific handler; +* int phyAddr - PHY address +* +* RETURN: +* None. +* +*******************************************************************************/ +void mvEthPhyAddrSet(void* pPortHandle, int phyAddr) +{ + ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHandle; + int port = pPortCtrl->portNo; + unsigned int regData; + + regData = MV_REG_READ(ETH_PHY_ADDR_REG(port)); + + regData &= ~ETH_PHY_ADDR_MASK; + regData |= phyAddr; + + MV_REG_WRITE(ETH_PHY_ADDR_REG(port), regData); + + return; +} + +/******************************************************************************* +* mvEthPhyAddrGet - Get the ethernet port PHY address. +* +* DESCRIPTION: +* This routine returns the given ethernet port PHY address. +* +* INPUT: +* void* pPortHandle - Pointer to port specific handler; +* +* +* RETURN: int - PHY address. +* +*******************************************************************************/ +int mvEthPhyAddrGet(void* pPortHandle) +{ + ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHandle; + int port = pPortCtrl->portNo; + unsigned int regData; + + regData = MV_REG_READ(ETH_PHY_ADDR_REG(port)); + + return ((regData >> (5 * port)) & 0x1f); +} + +/******************************************************************************/ +/* Descriptor handling Functions */ +/******************************************************************************/ + +/******************************************************************************* +* etherInitRxDescRing - Curve a Rx chain desc list and buffer in memory. +* +* DESCRIPTION: +* This function prepares a Rx chained list of descriptors and packet +* buffers in a form of a ring. The routine must be called after port +* initialization routine and before port start routine. +* The Ethernet SDMA engine uses CPU bus addresses to access the various +* devices in the system (i.e. DRAM). This function uses the ethernet +* struct 'virtual to physical' routine (set by the user) to set the ring +* with physical addresses. +* +* INPUT: +* ETH_QUEUE_CTRL *pEthPortCtrl Ethernet Port Control srtuct. +* int rxQueue Number of Rx queue. +* int rxDescNum Number of Rx descriptors +* MV_U8* rxDescBaseAddr Rx descriptors memory area base addr. +* +* OUTPUT: +* The routine updates the Ethernet port control struct with information +* regarding the Rx descriptors and buffers. +* +* RETURN: None +* +*******************************************************************************/ +static void ethInitRxDescRing(ETH_PORT_CTRL* pPortCtrl, int queue) +{ + ETH_RX_DESC *pRxDescBase, *pRxDesc, *pRxPrevDesc; + int ix, rxDescNum = pPortCtrl->rxQueueConfig[queue].descrNum; + ETH_QUEUE_CTRL *pQueueCtrl = &pPortCtrl->rxQueue[queue]; + + /* Make sure descriptor address is cache line size aligned */ + pRxDescBase = (ETH_RX_DESC*)MV_ALIGN_UP((MV_ULONG)pQueueCtrl->descBuf.bufVirtPtr, + CPU_D_CACHE_LINE_SIZE); + + pRxDesc = (ETH_RX_DESC*)pRxDescBase; + pRxPrevDesc = pRxDesc; + + /* initialize the Rx descriptors ring */ + for (ix=0; ixbufSize = 0x0; + pRxDesc->byteCnt = 0x0; + pRxDesc->cmdSts = ETH_BUFFER_OWNED_BY_HOST; + pRxDesc->bufPtr = 0x0; + pRxDesc->returnInfo = 0x0; + pRxPrevDesc = pRxDesc; + if(ix == (rxDescNum-1)) + { + /* Closing Rx descriptors ring */ + pRxPrevDesc->nextDescPtr = (MV_U32)ethDescVirtToPhy(pQueueCtrl, (void*)pRxDescBase); + } + else + { + pRxDesc = (ETH_RX_DESC*)((MV_ULONG)pRxDesc + ETH_RX_DESC_ALIGNED_SIZE); + pRxPrevDesc->nextDescPtr = (MV_U32)ethDescVirtToPhy(pQueueCtrl, (void*)pRxDesc); + } + ETH_DESCR_FLUSH_INV(pPortCtrl, pRxPrevDesc); + } + + pQueueCtrl->pCurrentDescr = pRxDescBase; + pQueueCtrl->pUsedDescr = pRxDescBase; + + pQueueCtrl->pFirstDescr = pRxDescBase; + pQueueCtrl->pLastDescr = pRxDesc; + pQueueCtrl->resource = 0; +} + +void ethResetRxDescRing(void* pPortHndl, int queue) +{ + ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHndl; + ETH_QUEUE_CTRL* pQueueCtrl = &pPortCtrl->rxQueue[queue]; + ETH_RX_DESC* pRxDesc = (ETH_RX_DESC*)pQueueCtrl->pFirstDescr; + + pQueueCtrl->resource = 0; + if(pQueueCtrl->pFirstDescr != NULL) + { + while(MV_TRUE) + { + pRxDesc->bufSize = 0x0; + pRxDesc->byteCnt = 0x0; + pRxDesc->cmdSts = ETH_BUFFER_OWNED_BY_HOST; + pRxDesc->bufPtr = 0x0; + pRxDesc->returnInfo = 0x0; + ETH_DESCR_FLUSH_INV(pPortCtrl, pRxDesc); + if( (void*)pRxDesc == pQueueCtrl->pLastDescr) + break; + pRxDesc = RX_NEXT_DESC_PTR(pRxDesc, pQueueCtrl); + } + pQueueCtrl->pCurrentDescr = pQueueCtrl->pFirstDescr; + pQueueCtrl->pUsedDescr = pQueueCtrl->pFirstDescr; + + /* Update RX Command register */ + pPortCtrl->portRxQueueCmdReg |= (1 << queue); + + /* update HW */ + MV_REG_WRITE( ETH_RX_CUR_DESC_PTR_REG(pPortCtrl->portNo, queue), + (MV_U32)ethDescVirtToPhy(pQueueCtrl, pQueueCtrl->pCurrentDescr) ); + } + else + { + /* Update RX Command register */ + pPortCtrl->portRxQueueCmdReg &= ~(1 << queue); + + /* update HW */ + MV_REG_WRITE( ETH_RX_CUR_DESC_PTR_REG(pPortCtrl->portNo, queue), 0); + } +} + +/******************************************************************************* +* etherInitTxDescRing - Curve a Tx chain desc list and buffer in memory. +* +* DESCRIPTION: +* This function prepares a Tx chained list of descriptors and packet +* buffers in a form of a ring. The routine must be called after port +* initialization routine and before port start routine. +* The Ethernet SDMA engine uses CPU bus addresses to access the various +* devices in the system (i.e. DRAM). This function uses the ethernet +* struct 'virtual to physical' routine (set by the user) to set the ring +* with physical addresses. +* +* INPUT: +* ETH_PORT_CTRL *pEthPortCtrl Ethernet Port Control srtuct. +* int txQueue Number of Tx queue. +* int txDescNum Number of Tx descriptors +* int txBuffSize Size of Tx buffer +* MV_U8* pTxDescBase Tx descriptors memory area base addr. +* +* OUTPUT: +* The routine updates the Ethernet port control struct with information +* regarding the Tx descriptors and buffers. +* +* RETURN: None. +* +*******************************************************************************/ +static void ethInitTxDescRing(ETH_PORT_CTRL* pPortCtrl, int queue) +{ + ETH_TX_DESC *pTxDescBase, *pTxDesc, *pTxPrevDesc; + int ix, txDescNum = pPortCtrl->txQueueConfig[queue].descrNum; + ETH_QUEUE_CTRL *pQueueCtrl = &pPortCtrl->txQueue[queue]; + + /* Make sure descriptor address is cache line size aligned */ + pTxDescBase = (ETH_TX_DESC*)MV_ALIGN_UP((MV_ULONG)pQueueCtrl->descBuf.bufVirtPtr, + CPU_D_CACHE_LINE_SIZE); + + pTxDesc = (ETH_TX_DESC*)pTxDescBase; + pTxPrevDesc = pTxDesc; + + /* initialize the Tx descriptors ring */ + for (ix=0; ixbyteCnt = 0x0000; + pTxDesc->L4iChk = 0x0000; + pTxDesc->cmdSts = ETH_BUFFER_OWNED_BY_HOST; + pTxDesc->bufPtr = 0x0; + pTxDesc->returnInfo = 0x0; + + pTxPrevDesc = pTxDesc; + + if(ix == (txDescNum-1)) + { + /* Closing Tx descriptors ring */ + pTxPrevDesc->nextDescPtr = (MV_U32)ethDescVirtToPhy(pQueueCtrl, (void*)pTxDescBase); + } + else + { + pTxDesc = (ETH_TX_DESC*)((MV_ULONG)pTxDesc + ETH_TX_DESC_ALIGNED_SIZE); + pTxPrevDesc->nextDescPtr = (MV_U32)ethDescVirtToPhy(pQueueCtrl, (void*)pTxDesc); + } + ETH_DESCR_FLUSH_INV(pPortCtrl, pTxPrevDesc); + } + + pQueueCtrl->pCurrentDescr = pTxDescBase; + pQueueCtrl->pUsedDescr = pTxDescBase; + + pQueueCtrl->pFirstDescr = pTxDescBase; + pQueueCtrl->pLastDescr = pTxDesc; + /* Leave one TX descriptor out of use */ + pQueueCtrl->resource = txDescNum - 1; +} + +void ethResetTxDescRing(void* pPortHndl, int queue) +{ + ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHndl; + ETH_QUEUE_CTRL* pQueueCtrl = &pPortCtrl->txQueue[queue]; + ETH_TX_DESC* pTxDesc = (ETH_TX_DESC*)pQueueCtrl->pFirstDescr; + + pQueueCtrl->resource = 0; + if(pQueueCtrl->pFirstDescr != NULL) + { + while(MV_TRUE) + { + pTxDesc->byteCnt = 0x0000; + pTxDesc->L4iChk = 0x0000; + pTxDesc->cmdSts = ETH_BUFFER_OWNED_BY_HOST; + pTxDesc->bufPtr = 0x0; + pTxDesc->returnInfo = 0x0; + ETH_DESCR_FLUSH_INV(pPortCtrl, pTxDesc); + pQueueCtrl->resource++; + if( (void*)pTxDesc == pQueueCtrl->pLastDescr) + break; + pTxDesc = TX_NEXT_DESC_PTR(pTxDesc, pQueueCtrl); + } + /* Leave one TX descriptor out of use */ + pQueueCtrl->resource--; + pQueueCtrl->pCurrentDescr = pQueueCtrl->pFirstDescr; + pQueueCtrl->pUsedDescr = pQueueCtrl->pFirstDescr; + + /* Update TX Command register */ + pPortCtrl->portTxQueueCmdReg |= MV_32BIT_LE_FAST(1 << queue); + /* update HW */ + MV_REG_WRITE( ETH_TX_CUR_DESC_PTR_REG(pPortCtrl->portNo, queue), + (MV_U32)ethDescVirtToPhy(pQueueCtrl, pQueueCtrl->pCurrentDescr) ); + } + else + { + /* Update TX Command register */ + pPortCtrl->portTxQueueCmdReg &= MV_32BIT_LE_FAST(~(1 << queue)); + /* update HW */ + MV_REG_WRITE( ETH_TX_CUR_DESC_PTR_REG(pPortCtrl->portNo, queue), 0 ); + } +} + +/******************************************************************************* +* ethAllocDescrMemory - Free memory allocated for RX and TX descriptors. +* +* DESCRIPTION: +* This function allocates memory for RX and TX descriptors. +* - If ETH_DESCR_IN_SRAM defined, allocate memory from SRAM. +* - If ETH_DESCR_IN_SDRAM defined, allocate memory in SDRAM. +* +* INPUT: +* int size - size of memory should be allocated. +* +* RETURN: None +* +*******************************************************************************/ +static MV_U8* ethAllocDescrMemory(ETH_PORT_CTRL* pPortCtrl, int descSize, + MV_ULONG* pPhysAddr, MV_U32 *memHandle) +{ + MV_U8* pVirt; + +#if defined(ETH_DESCR_IN_SRAM) + if(ethDescInSram == MV_TRUE) + pVirt = (char*)mvSramMalloc(descSize, pPhysAddr); + else +#endif /* ETH_DESCR_IN_SRAM */ + { +#ifdef ETH_DESCR_UNCACHED + pVirt = (MV_U8*)mvOsIoUncachedMalloc(pPortCtrl->osHandle, descSize, + pPhysAddr,memHandle); +#else + pVirt = (MV_U8*)mvOsIoCachedMalloc(pPortCtrl->osHandle, descSize, + pPhysAddr, memHandle); +#endif /* ETH_DESCR_UNCACHED */ + } + memset(pVirt, 0, descSize); + + return pVirt; +} + +/******************************************************************************* +* ethFreeDescrMemory - Free memory allocated for RX and TX descriptors. +* +* DESCRIPTION: +* This function frees memory allocated for RX and TX descriptors. +* - If ETH_DESCR_IN_SRAM defined, free memory using gtSramFree() function. +* - If ETH_DESCR_IN_SDRAM defined, free memory using mvOsFree() function. +* +* INPUT: +* void* pVirtAddr - virtual pointer to memory allocated for RX and TX +* desriptors. +* +* RETURN: None +* +*******************************************************************************/ +void ethFreeDescrMemory(ETH_PORT_CTRL* pPortCtrl, MV_BUF_INFO* pDescBuf) +{ + if( (pDescBuf == NULL) || (pDescBuf->bufVirtPtr == NULL) ) + return; + +#if defined(ETH_DESCR_IN_SRAM) + if( ethDescInSram ) + { + mvSramFree(pDescBuf->bufSize, pDescBuf->bufPhysAddr, pDescBuf->bufVirtPtr); + return; + } +#endif /* ETH_DESCR_IN_SRAM */ + +#ifdef ETH_DESCR_UNCACHED + mvOsIoUncachedFree(pPortCtrl->osHandle, pDescBuf->bufSize, pDescBuf->bufPhysAddr, + pDescBuf->bufVirtPtr,pDescBuf->memHandle); +#else + mvOsIoCachedFree(pPortCtrl->osHandle, pDescBuf->bufSize, pDescBuf->bufPhysAddr, + pDescBuf->bufVirtPtr,pDescBuf->memHandle); +#endif /* ETH_DESCR_UNCACHED */ +} + +/******************************************************************************/ +/* Other Functions */ +/******************************************************************************/ + +void mvEthPortPowerUp(int port) +{ + MV_U32 regVal; + + /* MAC Cause register should be cleared */ + MV_REG_WRITE(ETH_UNIT_INTR_CAUSE_REG(port), 0); + + if (mvBoardIsPortInSgmii(port)) + mvEthPortSgmiiConfig(port); + + /* Cancel Port Reset */ + regVal = MV_REG_READ(ETH_PORT_SERIAL_CTRL_1_REG(port)); + regVal &= (~ETH_PORT_RESET_MASK); + MV_REG_WRITE(ETH_PORT_SERIAL_CTRL_1_REG(port), regVal); + while( (MV_REG_READ(ETH_PORT_SERIAL_CTRL_1_REG(port)) & ETH_PORT_RESET_MASK) != 0); +} + +void mvEthPortPowerDown(int port) +{ + MV_U32 regVal; + + /* Port must be DISABLED */ + regVal = MV_REG_READ(ETH_PORT_SERIAL_CTRL_REG(port)); + if( (regVal & ETH_PORT_ENABLE_MASK) != 0) + { + mvOsPrintf("ethPort #%d: PowerDown - port must be Disabled (PSC=0x%x)\n", + port, regVal); + return; + } + + /* Port Reset (Read after write the register as a precaution) */ + regVal = MV_REG_READ(ETH_PORT_SERIAL_CTRL_1_REG(port)); + MV_REG_WRITE(ETH_PORT_SERIAL_CTRL_1_REG(port), regVal | ETH_PORT_RESET_MASK); + while((MV_REG_READ(ETH_PORT_SERIAL_CTRL_1_REG(port)) & ETH_PORT_RESET_MASK) == 0); +} + +static void mvEthPortSgmiiConfig(int port) +{ + MV_U32 regVal; + + regVal = MV_REG_READ(ETH_PORT_SERIAL_CTRL_1_REG(port)); + + regVal |= (ETH_SGMII_MODE_MASK /*| ETH_INBAND_AUTO_NEG_ENABLE_MASK */); + regVal &= (~ETH_INBAND_AUTO_NEG_BYPASS_MASK); + + MV_REG_WRITE(ETH_PORT_SERIAL_CTRL_1_REG(port), regVal); +} + + + + + + + + + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/eth/gbe/mvEthDebug.c b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/eth/gbe/mvEthDebug.c new file mode 100644 index 0000000..f533475 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/eth/gbe/mvEthDebug.c @@ -0,0 +1,748 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +/******************************************************************************* +* mvEthDebug.c - Source file for user friendly debug functions +* +* DESCRIPTION: +* +* DEPENDENCIES: +* None. +* +*******************************************************************************/ + +#include "mvOs.h" +#include "mvCommon.h" +#include "mvTypes.h" +#include "mv802_3.h" +#include "mvDebug.h" +#include "ctrlEnv/mvCtrlEnvLib.h" +#include "eth-phy/mvEthPhy.h" +#include "eth/mvEth.h" +#include "eth/gbe/mvEthDebug.h" + +/* #define mvOsPrintf printf */ + +void mvEthPortShow(void* pHndl); +void mvEthQueuesShow(void* pHndl, int rxQueue, int txQueue, int mode); + +/******************************************************************************/ +/* Debug functions */ +/******************************************************************************/ +void ethRxCoal(int port, int usec) +{ + void* pHndl; + + pHndl = mvEthPortHndlGet(port); + if(pHndl != NULL) + { + mvEthRxCoalSet(pHndl, usec); + } +} + +void ethTxCoal(int port, int usec) +{ + void* pHndl; + + pHndl = mvEthPortHndlGet(port); + if(pHndl != NULL) + { + mvEthTxCoalSet(pHndl, usec); + } +} + +#if (MV_ETH_VERSION >= 4) +void ethEjpModeSet(int port, int mode) +{ + void* pHndl; + + pHndl = mvEthPortHndlGet(port); + if(pHndl != NULL) + { + mvEthEjpModeSet(pHndl, mode); + } +} +#endif /* (MV_ETH_VERSION >= 4) */ + +void ethBpduRxQ(int port, int bpduQueue) +{ + void* pHndl; + + pHndl = mvEthPortHndlGet(port); + if(pHndl != NULL) + { + mvEthBpduRxQueue(pHndl, bpduQueue); + } +} + +void ethArpRxQ(int port, int arpQueue) +{ + void* pHndl; + + pHndl = mvEthPortHndlGet(port); + if(pHndl != NULL) + { + mvEthArpRxQueue(pHndl, arpQueue); + } +} + +void ethTcpRxQ(int port, int tcpQueue) +{ + void* pHndl; + + pHndl = mvEthPortHndlGet(port); + if(pHndl != NULL) + { + mvEthTcpRxQueue(pHndl, tcpQueue); + } +} + +void ethUdpRxQ(int port, int udpQueue) +{ + void* pHndl; + + pHndl = mvEthPortHndlGet(port); + if(pHndl != NULL) + { + mvEthUdpRxQueue(pHndl, udpQueue); + } +} + +void ethTxPolicyRegs(int port) +{ + int queue; + ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)mvEthPortHndlGet(port); + + if(pPortCtrl == NULL) + { + return; + } + mvOsPrintf("Port #%d TX Policy: EJP=%d, TXQs: ", + port, pPortCtrl->portConfig.ejpMode); + for(queue=0; queuetxQueueConfig[queue].descrNum > 0) + mvOsPrintf("%d, ", queue); + } + mvOsPrintf("\n"); + + mvOsPrintf("\n\t TX policy Port #%d configuration registers\n", port); + + mvOsPrintf("ETH_TX_QUEUE_COMMAND_REG : 0x%X = 0x%08x\n", + ETH_TX_QUEUE_COMMAND_REG(port), + MV_REG_READ( ETH_TX_QUEUE_COMMAND_REG(port) ) ); + + mvOsPrintf("ETH_TX_FIXED_PRIO_CFG_REG : 0x%X = 0x%08x\n", + ETH_TX_FIXED_PRIO_CFG_REG(port), + MV_REG_READ( ETH_TX_FIXED_PRIO_CFG_REG(port) ) ); + + mvOsPrintf("ETH_TX_TOKEN_RATE_CFG_REG : 0x%X = 0x%08x\n", + ETH_TX_TOKEN_RATE_CFG_REG(port), + MV_REG_READ( ETH_TX_TOKEN_RATE_CFG_REG(port) ) ); + + mvOsPrintf("ETH_MAX_TRANSMIT_UNIT_REG : 0x%X = 0x%08x\n", + ETH_MAX_TRANSMIT_UNIT_REG(port), + MV_REG_READ( ETH_MAX_TRANSMIT_UNIT_REG(port) ) ); + + mvOsPrintf("ETH_TX_TOKEN_BUCKET_SIZE_REG : 0x%X = 0x%08x\n", + ETH_TX_TOKEN_BUCKET_SIZE_REG(port), + MV_REG_READ( ETH_TX_TOKEN_BUCKET_SIZE_REG(port) ) ); + + mvOsPrintf("ETH_TX_TOKEN_BUCKET_COUNT_REG : 0x%X = 0x%08x\n", + ETH_TX_TOKEN_BUCKET_COUNT_REG(port), + MV_REG_READ( ETH_TX_TOKEN_BUCKET_COUNT_REG(port) ) ); + + for(queue=0; queue> 24) & 0xff), ((macH >> 16) & 0xff), + ((macH >> 8) & 0xff), (macH & 0xff), + ((macL >> 8) & 0xff), (macL & 0xff) ); + + for (i=0; i<4; i++) + { + unicastReg = MV_REG_READ( (ETH_DA_FILTER_UCAST_BASE(port) + i*4)); + for(j=0; j<4; j++) + { + MV_U8 macEntry = (unicastReg >> (8*j)) & 0xFF; + + mvOsPrintf("%X: %8s, Q = %d\n", i*4+j, + (macEntry & BIT0) ? "Accept" : "Reject", (macEntry >> 1) & 0x7); + } + } +} + +void ethMcastAdd(int port, char* macStr, int queue) +{ + void* pHndl; + MV_U8 macAddr[MV_MAC_ADDR_SIZE]; + + pHndl = mvEthPortHndlGet(port); + if(pHndl != NULL) + { + mvMacStrToHex(macStr, macAddr); + mvEthMcastAddrSet(pHndl, macAddr, queue); + } +} + +void ethPortMcast(int port) +{ + int tblIdx, regIdx; + MV_U32 regVal; + + mvOsPrintf("\n\t Port #%d Special (IP) Multicast table: 01:00:5E:00:00:XX\n\n", + port); + + for(tblIdx=0; tblIdx<(256/4); tblIdx++) + { + regVal = MV_REG_READ((ETH_DA_FILTER_SPEC_MCAST_BASE(port) + tblIdx*4)); + for(regIdx=0; regIdx<4; regIdx++) + { + if((regVal & (0x01 << (regIdx*8))) != 0) + { + mvOsPrintf("0x%02X: Accepted, rxQ = %d\n", + tblIdx*4+regIdx, ((regVal >> (regIdx*8+1)) & 0x07)); + } + } + } + mvOsPrintf("\n\t Port #%d Other Multicast table\n\n", port); + for(tblIdx=0; tblIdx<(256/4); tblIdx++) + { + regVal = MV_REG_READ((ETH_DA_FILTER_OTH_MCAST_BASE(port) + tblIdx*4)); + for(regIdx=0; regIdx<4; regIdx++) + { + if((regVal & (0x01 << (regIdx*8))) != 0) + { + mvOsPrintf("Crc8=0x%02X: Accepted, rxQ = %d\n", + tblIdx*4+regIdx, ((regVal >> (regIdx*8+1)) & 0x07)); + } + } + } +} + + +/* Print status of Ethernet port */ +void mvEthPortShow(void* pHndl) +{ + MV_U32 regValue, rxCoal, txCoal; + int speed, queue, port; + ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pHndl; + + port = pPortCtrl->portNo; + + regValue = MV_REG_READ( ETH_PORT_STATUS_REG(port) ); + + mvOsPrintf("\n\t ethGiga #%d port Status: 0x%04x = 0x%08x\n\n", + port, ETH_PORT_STATUS_REG(port), regValue); + + mvOsPrintf("descInSram=%d, descSwCoher=%d\n", + ethDescInSram, ethDescSwCoher); + + if(regValue & ETH_GMII_SPEED_1000_MASK) + speed = 1000; + else if(regValue & ETH_MII_SPEED_100_MASK) + speed = 100; + else + speed = 10; + + mvEthCoalGet(pPortCtrl, &rxCoal, &txCoal); + + /* Link, Speed, Duplex, FlowControl */ + mvOsPrintf("Link=%s, Speed=%d, Duplex=%s, RxFlowControl=%s", + (regValue & ETH_LINK_UP_MASK) ? "UP" : "DOWN", + speed, + (regValue & ETH_FULL_DUPLEX_MASK) ? "FULL" : "HALF", + (regValue & ETH_ENABLE_RCV_FLOW_CTRL_MASK) ? "ENABLE" : "DISABLE"); + + mvOsPrintf("\n"); + + mvOsPrintf("RxCoal = %d usec, TxCoal = %d usec\n", + rxCoal, txCoal); + + mvOsPrintf("rxDefQ=%d, arpQ=%d, bpduQ=%d, tcpQ=%d, udpQ=%d\n\n", + pPortCtrl->portConfig.rxDefQ, pPortCtrl->portConfig.rxArpQ, + pPortCtrl->portConfig.rxBpduQ, + pPortCtrl->portConfig.rxTcpQ, pPortCtrl->portConfig.rxUdpQ); + + /* Print all RX and TX queues */ + for(queue=0; queuerxQueue[queue].pFirstDescr, + mvEthRxResourceGet(pPortCtrl, queue) ); + } + mvOsPrintf("\n"); + for(queue=0; queuetxQueue[queue].pFirstDescr, + mvEthTxResourceGet(pPortCtrl, queue) ); + } +} + +/* Print RX and TX queue of the Ethernet port */ +void mvEthQueuesShow(void* pHndl, int rxQueue, int txQueue, int mode) +{ + ETH_PORT_CTRL *pPortCtrl = (ETH_PORT_CTRL*)pHndl; + ETH_QUEUE_CTRL *pQueueCtrl; + MV_U32 regValue; + ETH_RX_DESC *pRxDescr; + ETH_TX_DESC *pTxDescr; + int i, port = pPortCtrl->portNo; + + if( (rxQueue >=0) && (rxQueue < MV_ETH_RX_Q_NUM) ) + { + pQueueCtrl = &(pPortCtrl->rxQueue[rxQueue]); + mvOsPrintf("Port #%d, RX Queue #%d\n\n", port, rxQueue); + + mvOsPrintf("CURR_RX_DESC_PTR : 0x%X = 0x%08x\n", + ETH_RX_CUR_DESC_PTR_REG(port, rxQueue), + MV_REG_READ( ETH_RX_CUR_DESC_PTR_REG(port, rxQueue))); + + + if(pQueueCtrl->pFirstDescr != NULL) + { + mvOsPrintf("pFirstDescr=0x%lx, pLastDescr=0x%lx, numOfResources=%d\n", + (MV_ULONG)pQueueCtrl->pFirstDescr, (MV_ULONG)pQueueCtrl->pLastDescr, + pQueueCtrl->resource); + mvOsPrintf("pCurrDescr: 0x%lx, pUsedDescr: 0x%lx\n", + (MV_ULONG)pQueueCtrl->pCurrentDescr, + (MV_ULONG)pQueueCtrl->pUsedDescr); + + if(mode == 1) + { + pRxDescr = (ETH_RX_DESC*)pQueueCtrl->pFirstDescr; + i = 0; + do + { + mvOsPrintf("%3d. desc=%08x (%08x), cmd=%08x, data=%4d, buf=%4d, buf=%08x, pkt=%lx, os=%lx\n", + i, (MV_U32)pRxDescr, (MV_U32)ethDescVirtToPhy(pQueueCtrl, (MV_U8*)pRxDescr), + pRxDescr->cmdSts, pRxDescr->byteCnt, (MV_U32)pRxDescr->bufSize, + (unsigned int)pRxDescr->bufPtr, (MV_ULONG)pRxDescr->returnInfo, + ((MV_PKT_INFO*)pRxDescr->returnInfo)->osInfo); + + ETH_DESCR_INV(pPortCtrl, pRxDescr); + pRxDescr = RX_NEXT_DESC_PTR(pRxDescr, pQueueCtrl); + i++; + } while (pRxDescr != pQueueCtrl->pFirstDescr); + } + } + else + mvOsPrintf("RX Queue #%d is NOT CREATED\n", rxQueue); + } + + if( (txQueue >=0) && (txQueue < MV_ETH_TX_Q_NUM) ) + { + pQueueCtrl = &(pPortCtrl->txQueue[txQueue]); + mvOsPrintf("Port #%d, TX Queue #%d\n\n", port, txQueue); + + regValue = MV_REG_READ( ETH_TX_CUR_DESC_PTR_REG(port, txQueue)); + mvOsPrintf("CURR_TX_DESC_PTR : 0x%X = 0x%08x\n", + ETH_TX_CUR_DESC_PTR_REG(port, txQueue), regValue); + + if(pQueueCtrl->pFirstDescr != NULL) + { + mvOsPrintf("pFirstDescr=0x%lx, pLastDescr=0x%lx, numOfResources=%d\n", + (MV_ULONG)pQueueCtrl->pFirstDescr, + (MV_ULONG)pQueueCtrl->pLastDescr, + pQueueCtrl->resource); + mvOsPrintf("pCurrDescr: 0x%lx, pUsedDescr: 0x%lx\n", + (MV_ULONG)pQueueCtrl->pCurrentDescr, + (MV_ULONG)pQueueCtrl->pUsedDescr); + + if(mode == 1) + { + pTxDescr = (ETH_TX_DESC*)pQueueCtrl->pFirstDescr; + i = 0; + do + { + mvOsPrintf("%3d. desc=%08x (%08x), cmd=%08x, data=%4d, buf=%08x, pkt=%lx, os=%lx\n", + i, (MV_U32)pTxDescr, (MV_U32)ethDescVirtToPhy(pQueueCtrl, (MV_U8*)pTxDescr), + pTxDescr->cmdSts, pTxDescr->byteCnt, + (MV_U32)pTxDescr->bufPtr, (MV_ULONG)pTxDescr->returnInfo, + pTxDescr->returnInfo ? (((MV_PKT_INFO*)pTxDescr->returnInfo)->osInfo) : 0x0); + + ETH_DESCR_INV(pPortCtrl, pTxDescr); + pTxDescr = TX_NEXT_DESC_PTR(pTxDescr, pQueueCtrl); + i++; + } while (pTxDescr != pQueueCtrl->pFirstDescr); + } + } + else + mvOsPrintf("TX Queue #%d is NOT CREATED\n", txQueue); + } +} diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/eth/gbe/mvEthDebug.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/eth/gbe/mvEthDebug.h new file mode 100644 index 0000000..f026f96 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/eth/gbe/mvEthDebug.h @@ -0,0 +1,146 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ +#ifndef __MV_ETH_DEBUG_H__ +#define __MV_ETH_DEBUG_H__ + +#if 0 +/* + ** Externs + */ +void ethBpduRxQ(int port, int bpduQueue); +void ethArpRxQ(int port, int bpduQueue); +void ethTcpRxQ(int port, int bpduQueue); +void ethUdpRxQ(int port, int bpduQueue); +void ethMcastAdd(int port, char* macStr, int queue); + +#ifdef INCLUDE_MULTI_QUEUE +void ethRxPolicy( int port); +void ethTxPolicy( int port); +void ethTxPolDA(int port, char* macStr, int txQ, char* headerHexStr); +void ethRxPolMode(int port, MV_ETH_PRIO_MODE prioMode); +void ethRxPolQ(int port, int rxQueue, int rxQuota); +#endif /* INCLUDE_MULTI_QUEUE */ + +void print_egiga_stat(void *sc, unsigned int port); +void ethPortStatus (int port); +void ethPortQueues( int port, int rxQueue, int txQueue, int mode); +void ethPortMcast(int port); +void ethPortRegs(int port); +void ethPortCounters(int port); +void ethPortRmonCounters(int port); +void ethRxCoal(int port, int usec); +void ethTxCoal(int port, int usec); + +void ethRegs(int port); +void ethClearCounters(int port); +void ethUcastSet(int port, char* macStr, int queue); +void ethPortUcastShow(int port); + +#ifdef CONFIG_MV_ETH_HEADER +void run_com_header(const char *buffer); +#endif + +#ifdef INCLUDE_MULTI_QUEUE +void ethRxPolMode(int port, MV_ETH_PRIO_MODE prioMode); +void ethRxPolQ(int port, int queue, int quota); +void ethRxPolicy(int port); +void ethTxPolDef(int port, int txQ, char* headerHexStr); +void ethTxPolDA(int port, char* macStr, int txQ, char* headerHexStr); +void ethTxPolicy(int port); +#endif /* INCLUDE_MULTI_QUEUE */ + +#if (MV_ETH_VERSION >= 4) +void ethEjpModeSet(int port, int mode) +#endif +#endif /* 0 */ + + + + +void ethRxCoal(int port, int usec); +void ethTxCoal(int port, int usec); +#if (MV_ETH_VERSION >= 4) +void ethEjpModeSet(int port, int mode); +#endif /* (MV_ETH_VERSION >= 4) */ + +void ethBpduRxQ(int port, int bpduQueue); +void ethArpRxQ(int port, int arpQueue); +void ethTcpRxQ(int port, int tcpQueue); +void ethUdpRxQ(int port, int udpQueue); +void ethTxPolicyRegs(int port); +void ethPortRegs(int port); +void ethRegs(int port); +void ethClearCounters(int port); +void ethPortCounters(int port); +void ethPortRmonCounters(int port); +void ethPortStatus(int port); +void ethPortQueues(int port, int rxQueue, int txQueue, int mode); +void ethUcastSet(int port, char* macStr, int queue); +void ethPortUcastShow(int port); +void ethMcastAdd(int port, char* macStr, int queue); +void ethPortMcast(int port); +void mvEthPortShow(void* pHndl); +void mvEthQueuesShow(void* pHndl, int rxQueue, int txQueue, int mode); + +#endif diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/eth/gbe/mvEthGbe.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/eth/gbe/mvEthGbe.h new file mode 100644 index 0000000..f4cae50 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/eth/gbe/mvEthGbe.h @@ -0,0 +1,751 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +/******************************************************************************* +* mvEth.h - Header File for : Marvell Gigabit Ethernet Controller +* +* DESCRIPTION: +* This header file contains macros typedefs and function declaration specific to +* the Marvell Gigabit Ethernet Controller. +* +* DEPENDENCIES: +* None. +* +*******************************************************************************/ + +#ifndef __mvEthGbe_h__ +#define __mvEthGbe_h__ + +extern MV_BOOL ethDescInSram; +extern MV_BOOL ethDescSwCoher; +extern ETH_PORT_CTRL* ethPortCtrl[]; + +static INLINE MV_ULONG ethDescVirtToPhy(ETH_QUEUE_CTRL* pQueueCtrl, MV_U8* pDesc) +{ +#if defined (ETH_DESCR_IN_SRAM) + if( ethDescInSram ) + return mvSramVirtToPhy(pDesc); + else +#endif /* ETH_DESCR_IN_SRAM */ + return (pQueueCtrl->descBuf.bufPhysAddr + (pDesc - pQueueCtrl->descBuf.bufVirtPtr)); +} +/* Return port handler */ +#define mvEthPortHndlGet(port) ethPortCtrl[port] + +/* Used as WA for HW/SW race on TX */ +static INLINE int mvEthPortTxEnable(void* pPortHndl, int queue, int max_deep) +{ + int deep = 0; + MV_U32 txCurrReg, txEnReg; + ETH_TX_DESC* pTxLastDesc; + ETH_QUEUE_CTRL* pQueueCtrl; + ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHndl; + + txEnReg = MV_REG_VALUE(ETH_TX_QUEUE_COMMAND_REG(pPortCtrl->portNo)); + if( (txEnReg & MV_32BIT_LE_FAST(ETH_TXQ_ENABLE_MASK)) == 0) + { + MV_REG_VALUE(ETH_TX_QUEUE_COMMAND_REG(pPortCtrl->portNo)) = pPortCtrl->portTxQueueCmdReg; + return 0; + } + + pQueueCtrl = &pPortCtrl->txQueue[queue]; + pTxLastDesc = pQueueCtrl->pCurrentDescr; + txCurrReg = MV_REG_READ(ETH_TX_CUR_DESC_PTR_REG(pPortCtrl->portNo, queue)); + if(ethDescVirtToPhy(pQueueCtrl, (MV_U8*)pTxLastDesc) == txCurrReg) + { + /* All descriptors are processed, no chance for race */ + return 0; + } + + /* Check distance betwee HW and SW location: */ + /* If distance between HW and SW pointers is less than max_deep descriptors */ + /* Race condition is possible, so wait end of TX and restart TXQ */ + while(deep < max_deep) + { + pTxLastDesc = TX_PREV_DESC_PTR(pTxLastDesc, pQueueCtrl); + if(ethDescVirtToPhy(pQueueCtrl, (MV_U8*)pTxLastDesc) == txCurrReg) + { + int count = 0; + + while( (txEnReg & MV_32BIT_LE_FAST(ETH_TXQ_ENABLE_MASK)) != 0) + { + count++; + if(count > 10000) + { + mvOsPrintf("mvEthPortTxEnable: timeout - TXQ_CMD=0x%08x\n", + MV_REG_READ(ETH_TX_QUEUE_COMMAND_REG(pPortCtrl->portNo)) ); + break; + } + txEnReg = MV_REG_VALUE(ETH_TX_QUEUE_COMMAND_REG(pPortCtrl->portNo)); + } + + MV_REG_VALUE(ETH_TX_QUEUE_COMMAND_REG(pPortCtrl->portNo)) = pPortCtrl->portTxQueueCmdReg; + return count; + } + deep++; + } + /* Distance between HW and SW pointers is more than max_deep descriptors, */ + /* So NO race condition - do nothing */ + return -1; +} + + +/* defines */ +#define ETH_CSUM_MIN_BYTE_COUNT 72 + +/* Tailgate and Kirwood have only 2K TX FIFO */ +#if (MV_ETH_VERSION == 2) || (MV_ETH_VERSION == 4) +#define ETH_CSUM_MAX_BYTE_COUNT 1600 +#else +#define ETH_CSUM_MAX_BYTE_COUNT 9*1024 +#endif /* MV_ETH_VERSION */ + +#define ETH_MV_HEADER_SIZE 2 +#define ETH_MV_TX_EN + +/* An offest in Tx descriptors to store data for buffers less than 8 Bytes */ +#define MIN_TX_BUFF_LOAD 8 +#define TX_BUF_OFFSET_IN_DESC (ETH_TX_DESC_ALIGNED_SIZE - MIN_TX_BUFF_LOAD) + +/* Default port configuration value */ +#define PORT_CONFIG_VALUE \ + ETH_DEF_RX_QUEUE_MASK(0) | \ + ETH_DEF_RX_ARP_QUEUE_MASK(0) | \ + ETH_DEF_RX_TCP_QUEUE_MASK(0) | \ + ETH_DEF_RX_UDP_QUEUE_MASK(0) | \ + ETH_DEF_RX_BPDU_QUEUE_MASK(0) | \ + ETH_RX_CHECKSUM_WITH_PSEUDO_HDR + +/* Default port extend configuration value */ +#define PORT_CONFIG_EXTEND_VALUE 0 + +#define PORT_SERIAL_CONTROL_VALUE \ + ETH_DISABLE_FC_AUTO_NEG_MASK | \ + BIT9 | \ + ETH_DO_NOT_FORCE_LINK_FAIL_MASK | \ + ETH_MAX_RX_PACKET_1552BYTE | \ + ETH_SET_FULL_DUPLEX_MASK + +#define PORT_SERIAL_CONTROL_100MB_FORCE_VALUE \ + ETH_FORCE_LINK_PASS_MASK | \ + ETH_DISABLE_DUPLEX_AUTO_NEG_MASK | \ + ETH_DISABLE_FC_AUTO_NEG_MASK | \ + BIT9 | \ + ETH_DO_NOT_FORCE_LINK_FAIL_MASK | \ + ETH_DISABLE_SPEED_AUTO_NEG_MASK | \ + ETH_SET_FULL_DUPLEX_MASK | \ + ETH_SET_MII_SPEED_100_MASK | \ + ETH_MAX_RX_PACKET_1552BYTE + + +#define PORT_SERIAL_CONTROL_1000MB_FORCE_VALUE \ + ETH_FORCE_LINK_PASS_MASK | \ + ETH_DISABLE_DUPLEX_AUTO_NEG_MASK | \ + ETH_DISABLE_FC_AUTO_NEG_MASK | \ + BIT9 | \ + ETH_DO_NOT_FORCE_LINK_FAIL_MASK | \ + ETH_DISABLE_SPEED_AUTO_NEG_MASK | \ + ETH_SET_FULL_DUPLEX_MASK | \ + ETH_SET_GMII_SPEED_1000_MASK | \ + ETH_MAX_RX_PACKET_1552BYTE + +#define PORT_SERIAL_CONTROL_SGMII_IBAN_VALUE \ + ETH_DISABLE_FC_AUTO_NEG_MASK | \ + BIT9 | \ + ETH_IN_BAND_AN_EN_MASK | \ + ETH_DO_NOT_FORCE_LINK_FAIL_MASK | \ + ETH_MAX_RX_PACKET_1552BYTE + +/* Function headers: */ +MV_VOID mvEthSetSpecialMcastTable(int portNo, int queue); +MV_STATUS mvEthArpRxQueue(void* pPortHandle, int arpQueue); +MV_STATUS mvEthUdpRxQueue(void* pPortHandle, int udpQueue); +MV_STATUS mvEthTcpRxQueue(void* pPortHandle, int tcpQueue); +MV_STATUS mvEthMacAddrGet(int portNo, unsigned char *pAddr); +MV_VOID mvEthSetOtherMcastTable(int portNo, int queue); +MV_STATUS mvEthHeaderModeSet(void* pPortHandle, MV_ETH_HEADER_MODE headerMode); +/* Interrupt Coalesting functions */ +MV_U32 mvEthRxCoalSet(void* pPortHndl, MV_U32 uSec); +MV_U32 mvEthTxCoalSet(void* pPortHndl, MV_U32 uSec); +MV_STATUS mvEthCoalGet(void* pPortHndl, MV_U32* pRxCoal, MV_U32* pTxCoal); + +/******************************************************************************/ +/* Data Flow functions */ +/******************************************************************************/ +static INLINE void mvEthPortTxRestart(void* pPortHndl) +{ + ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHndl; + + MV_REG_VALUE(ETH_TX_QUEUE_COMMAND_REG(pPortCtrl->portNo)) = pPortCtrl->portTxQueueCmdReg; +} + +/* Get number of Free resources in specific TX queue */ +static INLINE int mvEthTxResourceGet(void* pPortHndl, int txQueue) +{ + ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHndl; + + return (pPortCtrl->txQueue[txQueue].resource); +} + +/* Get number of Free resources in specific RX queue */ +static INLINE int mvEthRxResourceGet(void* pPortHndl, int rxQueue) +{ + ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHndl; + + return (pPortCtrl->rxQueue[rxQueue].resource); +} + +static INLINE int mvEthTxQueueIsFull(void* pPortHndl, int txQueue) +{ + ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHndl; + + if(pPortCtrl->txQueue[txQueue].resource == 0) + return MV_TRUE; + + return MV_FALSE; +} + +/* Get number of Free resources in specific RX queue */ +static INLINE int mvEthRxQueueIsFull(void* pPortHndl, int rxQueue) +{ + ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHndl; + ETH_QUEUE_CTRL* pQueueCtrl = &pPortCtrl->rxQueue[rxQueue]; + + if( (pQueueCtrl->pUsedDescr == pQueueCtrl->pCurrentDescr) && + (pQueueCtrl->resource != 0) ) + return MV_TRUE; + + return MV_FALSE; +} + +static INLINE int mvEthTxQueueIsEmpty(void* pPortHndl, int txQueue) +{ + ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHndl; + ETH_QUEUE_CTRL* pQueueCtrl = &pPortCtrl->txQueue[txQueue]; + + if( (pQueueCtrl->pUsedDescr == pQueueCtrl->pCurrentDescr) && + (pQueueCtrl->resource != 0) ) + { + return MV_TRUE; + } + return MV_FALSE; +} + +/* Get number of Free resources in specific RX queue */ +static INLINE int mvEthRxQueueIsEmpty(void* pPortHndl, int rxQueue) +{ + ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pPortHndl; + + if(pPortCtrl->rxQueue[rxQueue].resource == 0) + return MV_TRUE; + + return MV_FALSE; +} + +/******************************************************************************* +* mvEthPortTx - Send an Ethernet packet +* +* DESCRIPTION: +* This routine send a given packet described by pPktInfo parameter. +* Single buffer only. +* +* INPUT: +* void* pEthPortHndl - Ethernet Port handler. +* int txQueue - Number of Tx queue. +* MV_PKT_INFO *pPktInfo - User packet to send. +* +* RETURN: +* MV_NO_RESOURCE - No enough resources to send this packet. +* MV_ERROR - Unexpected Fatal error. +* MV_OK - Packet send successfully. +* +*******************************************************************************/ +static INLINE MV_STATUS mvEthPortTx(void* pEthPortHndl, int txQueue, MV_PKT_INFO* pPktInfo) +{ + ETH_TX_DESC* pTxCurrDesc; + ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pEthPortHndl; + ETH_QUEUE_CTRL* pQueueCtrl; + int portNo; + MV_BUF_INFO* pBufInfo = pPktInfo->pFrags; + +#ifdef ETH_DEBUG + if(pPortCtrl->portState != MV_ACTIVE) + return MV_BAD_STATE; +#endif /* ETH_DEBUG */ + + portNo = pPortCtrl->portNo; + pQueueCtrl = &pPortCtrl->txQueue[txQueue]; + + /* Get the Tx Desc ring indexes */ + pTxCurrDesc = pQueueCtrl->pCurrentDescr; + + /* Check if there is enough resources to send the packet */ + if(pQueueCtrl->resource == 0) + return MV_NO_RESOURCE; + + pTxCurrDesc->byteCnt = pBufInfo->dataSize; + + /* Flash Buffer */ + if(pPktInfo->pktSize != 0) + { +#ifdef MV_NETBSD + pTxCurrDesc->bufPtr = pBufInfo->bufPhysAddr; + ETH_PACKET_CACHE_FLUSH(pBufInfo->bufVirtPtr, pPktInfo->pktSize); +#else + pTxCurrDesc->bufPtr = ETH_PACKET_CACHE_FLUSH(pBufInfo->bufVirtPtr, pPktInfo->pktSize); +#endif + pPktInfo->pktSize = 0; + } + else + pTxCurrDesc->bufPtr = pBufInfo->bufPhysAddr; + + pTxCurrDesc->returnInfo = (MV_ULONG)pPktInfo; + + /* There is only one buffer in the packet */ + /* The OSG might set some bits for checksum offload, so add them to first descriptor */ + pTxCurrDesc->cmdSts = pPktInfo->status | + ETH_BUFFER_OWNED_BY_DMA | + ETH_TX_GENERATE_CRC_MASK | + ETH_TX_ENABLE_INTERRUPT_MASK | + ETH_TX_ZERO_PADDING_MASK | + ETH_TX_FIRST_DESC_MASK | + ETH_TX_LAST_DESC_MASK; + + ETH_DESCR_FLUSH_INV(pPortCtrl, pTxCurrDesc); + + pQueueCtrl->resource--; + pQueueCtrl->pCurrentDescr = TX_NEXT_DESC_PTR(pTxCurrDesc, pQueueCtrl); + + /* Apply send command */ + MV_REG_VALUE(ETH_TX_QUEUE_COMMAND_REG(portNo)) = pPortCtrl->portTxQueueCmdReg; + + return MV_OK; +} + + +/******************************************************************************* +* mvEthPortSgTx - Send an Ethernet packet +* +* DESCRIPTION: +* This routine send a given packet described by pBufInfo parameter. It +* supports transmitting of a packet spaned over multiple buffers. +* +* INPUT: +* void* pEthPortHndl - Ethernet Port handler. +* int txQueue - Number of Tx queue. +* MV_PKT_INFO *pPktInfo - User packet to send. +* +* RETURN: +* MV_NO_RESOURCE - No enough resources to send this packet. +* MV_ERROR - Unexpected Fatal error. +* MV_OK - Packet send successfully. +* +*******************************************************************************/ +static INLINE MV_STATUS mvEthPortSgTx(void* pEthPortHndl, int txQueue, MV_PKT_INFO* pPktInfo) +{ + ETH_TX_DESC* pTxFirstDesc; + ETH_TX_DESC* pTxCurrDesc; + ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pEthPortHndl; + ETH_QUEUE_CTRL* pQueueCtrl; + int portNo, bufCount; + MV_BUF_INFO* pBufInfo = pPktInfo->pFrags; + MV_U8* pTxBuf; + +#ifdef ETH_DEBUG + if(pPortCtrl->portState != MV_ACTIVE) + return MV_BAD_STATE; +#endif /* ETH_DEBUG */ + + portNo = pPortCtrl->portNo; + pQueueCtrl = &pPortCtrl->txQueue[txQueue]; + + /* Get the Tx Desc ring indexes */ + pTxCurrDesc = pQueueCtrl->pCurrentDescr; + + /* Check if there is enough resources to send the packet */ + if(pQueueCtrl->resource < pPktInfo->numFrags) + return MV_NO_RESOURCE; + + /* Remember first desc */ + pTxFirstDesc = pTxCurrDesc; + + bufCount = 0; + while(MV_TRUE) + { + if(pBufInfo[bufCount].dataSize <= MIN_TX_BUFF_LOAD) + { + /* Buffers with a payload smaller than MIN_TX_BUFF_LOAD (8 bytes) must be aligned */ + /* to 64-bit boundary. Two options here: */ + /* 1) Usually, copy the payload to the reserved 8 bytes inside descriptor. */ + /* 2) In the Half duplex workaround, the reserved 8 bytes inside descriptor are used */ + /* as a pointer to the aligned buffer, copy the small payload to this buffer. */ + pTxBuf = ((MV_U8*)pTxCurrDesc)+TX_BUF_OFFSET_IN_DESC; + mvOsBCopy(pBufInfo[bufCount].bufVirtPtr, pTxBuf, pBufInfo[bufCount].dataSize); + pTxCurrDesc->bufPtr = ethDescVirtToPhy(pQueueCtrl, pTxBuf); + } + else + { + /* Flash Buffer */ +#ifdef MV_NETBSD + pTxCurrDesc->bufPtr = pBufInfo[bufCount].bufPhysAddr; + ETH_PACKET_CACHE_FLUSH(pBufInfo[bufCount].bufVirtPtr, pBufInfo[bufCount].dataSize); +#else + pTxCurrDesc->bufPtr = ETH_PACKET_CACHE_FLUSH(pBufInfo[bufCount].bufVirtPtr, pBufInfo[bufCount].dataSize); +#endif + } + + pTxCurrDesc->byteCnt = pBufInfo[bufCount].dataSize; + bufCount++; + + if(bufCount >= pPktInfo->numFrags) + break; + + if(bufCount > 1) + { + /* There is middle buffer of the packet Not First and Not Last */ + pTxCurrDesc->cmdSts = ETH_BUFFER_OWNED_BY_DMA; + ETH_DESCR_FLUSH_INV(pPortCtrl, pTxCurrDesc); + } + /* Go to next descriptor and next buffer */ + pTxCurrDesc = TX_NEXT_DESC_PTR(pTxCurrDesc, pQueueCtrl); + } + /* Set last desc with DMA ownership and interrupt enable. */ + pTxCurrDesc->returnInfo = (MV_ULONG)pPktInfo; + if(bufCount == 1) + { + /* There is only one buffer in the packet */ + /* The OSG might set some bits for checksum offload, so add them to first descriptor */ + pTxCurrDesc->cmdSts = pPktInfo->status | + ETH_BUFFER_OWNED_BY_DMA | + ETH_TX_GENERATE_CRC_MASK | + ETH_TX_ENABLE_INTERRUPT_MASK | + ETH_TX_ZERO_PADDING_MASK | + ETH_TX_FIRST_DESC_MASK | + ETH_TX_LAST_DESC_MASK; + + ETH_DESCR_FLUSH_INV(pPortCtrl, pTxCurrDesc); + } + else + { + /* Last but not First */ + pTxCurrDesc->cmdSts = ETH_BUFFER_OWNED_BY_DMA | + ETH_TX_ENABLE_INTERRUPT_MASK | + ETH_TX_ZERO_PADDING_MASK | + ETH_TX_LAST_DESC_MASK; + + ETH_DESCR_FLUSH_INV(pPortCtrl, pTxCurrDesc); + + /* Update First when more than one buffer in the packet */ + /* The OSG might set some bits for checksum offload, so add them to first descriptor */ + pTxFirstDesc->cmdSts = pPktInfo->status | + ETH_BUFFER_OWNED_BY_DMA | + ETH_TX_GENERATE_CRC_MASK | + ETH_TX_FIRST_DESC_MASK; + + ETH_DESCR_FLUSH_INV(pPortCtrl, pTxFirstDesc); + } + /* Update txQueue state */ + pQueueCtrl->resource -= bufCount; + pQueueCtrl->pCurrentDescr = TX_NEXT_DESC_PTR(pTxCurrDesc, pQueueCtrl); + + /* Apply send command */ + MV_REG_VALUE(ETH_TX_QUEUE_COMMAND_REG(portNo)) = pPortCtrl->portTxQueueCmdReg; + + return MV_OK; +} + +/******************************************************************************* +* mvEthPortTxDone - Free all used Tx descriptors and mBlks. +* +* DESCRIPTION: +* This routine returns the transmitted packet information to the caller. +* +* INPUT: +* void* pEthPortHndl - Ethernet Port handler. +* int txQueue - Number of Tx queue. +* +* OUTPUT: +* MV_PKT_INFO *pPktInfo - Pointer to packet was sent. +* +* RETURN: +* MV_NOT_FOUND - No transmitted packets to return. Transmit in progress. +* MV_EMPTY - No transmitted packets to return. TX Queue is empty. +* MV_ERROR - Unexpected Fatal error. +* MV_OK - There is transmitted packet in the queue, +* 'pPktInfo' filled with relevant information. +* +*******************************************************************************/ +static INLINE MV_PKT_INFO* mvEthPortTxDone(void* pEthPortHndl, int txQueue) +{ + ETH_TX_DESC* pTxCurrDesc; + ETH_TX_DESC* pTxUsedDesc; + ETH_QUEUE_CTRL* pQueueCtrl; + ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pEthPortHndl; + MV_PKT_INFO* pPktInfo; + MV_U32 commandStatus; + + pQueueCtrl = &pPortCtrl->txQueue[txQueue]; + + pTxUsedDesc = pQueueCtrl->pUsedDescr; + pTxCurrDesc = pQueueCtrl->pCurrentDescr; + + while(MV_TRUE) + { + /* No more used descriptors */ + commandStatus = pTxUsedDesc->cmdSts; + if (commandStatus & (ETH_BUFFER_OWNED_BY_DMA)) + { + ETH_DESCR_INV(pPortCtrl, pTxUsedDesc); + return NULL; + } + if( (pTxUsedDesc == pTxCurrDesc) && + (pQueueCtrl->resource != 0) ) + { + return NULL; + } + pQueueCtrl->resource++; + pQueueCtrl->pUsedDescr = TX_NEXT_DESC_PTR(pTxUsedDesc, pQueueCtrl); + if(commandStatus & (ETH_TX_LAST_DESC_MASK)) + { + pPktInfo = (MV_PKT_INFO*)pTxUsedDesc->returnInfo; + pPktInfo->status = commandStatus; + return pPktInfo; + } + pTxUsedDesc = pQueueCtrl->pUsedDescr; + } +} + +/******************************************************************************* +* mvEthPortRx - Get new received packets from Rx queue. +* +* DESCRIPTION: +* This routine returns the received data to the caller. There is no +* data copying during routine operation. All information is returned +* using pointer to packet information struct passed from the caller. +* +* INPUT: +* void* pEthPortHndl - Ethernet Port handler. +* int rxQueue - Number of Rx queue. +* +* OUTPUT: +* MV_PKT_INFO *pPktInfo - Pointer to received packet. +* +* RETURN: +* MV_NO_RESOURCE - No free resources in RX queue. +* MV_ERROR - Unexpected Fatal error. +* MV_OK - New packet received and 'pBufInfo' structure filled +* with relevant information. +* +*******************************************************************************/ +static INLINE MV_PKT_INFO* mvEthPortRx(void* pEthPortHndl, int rxQueue) +{ + ETH_RX_DESC *pRxCurrDesc; + MV_U32 commandStatus; + ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pEthPortHndl; + ETH_QUEUE_CTRL* pQueueCtrl; + MV_PKT_INFO* pPktInfo; + + pQueueCtrl = &(pPortCtrl->rxQueue[rxQueue]); + + /* Check resources */ + if(pQueueCtrl->resource == 0) + { + mvOsPrintf("ethPortRx: no more resources\n"); + return NULL; + } + while(MV_TRUE) + { + /* Get the Rx Desc ring 'curr and 'used' indexes */ + pRxCurrDesc = pQueueCtrl->pCurrentDescr; + + commandStatus = pRxCurrDesc->cmdSts; + if (commandStatus & (ETH_BUFFER_OWNED_BY_DMA)) + { + /* Nothing to receive... */ + ETH_DESCR_INV(pPortCtrl, pRxCurrDesc); + return NULL; + } + + /* Valid RX only if FIRST and LAST bits are set */ + if( (commandStatus & (ETH_RX_LAST_DESC_MASK | ETH_RX_FIRST_DESC_MASK)) == + (ETH_RX_LAST_DESC_MASK | ETH_RX_FIRST_DESC_MASK) ) + { + pPktInfo = (MV_PKT_INFO*)pRxCurrDesc->returnInfo; + pPktInfo->pFrags->dataSize = pRxCurrDesc->byteCnt - 4; + pPktInfo->status = commandStatus; + pPktInfo->fragIP = pRxCurrDesc->bufSize & ETH_RX_IP_FRAGMENTED_FRAME_MASK; + + pQueueCtrl->resource--; + /* Update 'curr' in data structure */ + pQueueCtrl->pCurrentDescr = RX_NEXT_DESC_PTR(pRxCurrDesc, pQueueCtrl); + +#ifdef INCLUDE_SYNC_BARR + mvCpuIfSyncBarr(DRAM_TARGET); +#endif + return pPktInfo; + } + else + { + ETH_RX_DESC* pRxUsedDesc = pQueueCtrl->pUsedDescr; + +#ifdef ETH_DEBUG + mvOsPrintf("ethDrv: Unexpected Jumbo frame: " + "status=0x%08x, byteCnt=%d, pData=0x%x\n", + commandStatus, pRxCurrDesc->byteCnt, pRxCurrDesc->bufPtr); +#endif /* ETH_DEBUG */ + + /* move buffer from pCurrentDescr position to pUsedDescr position */ + pRxUsedDesc->bufPtr = pRxCurrDesc->bufPtr; + pRxUsedDesc->returnInfo = pRxCurrDesc->returnInfo; + pRxUsedDesc->bufSize = pRxCurrDesc->bufSize & ETH_RX_BUFFER_MASK; + + /* Return the descriptor to DMA ownership */ + pRxUsedDesc->cmdSts = ETH_BUFFER_OWNED_BY_DMA | + ETH_RX_ENABLE_INTERRUPT_MASK; + + /* Flush descriptor and CPU pipe */ + ETH_DESCR_FLUSH_INV(pPortCtrl, pRxUsedDesc); + + /* Move the used descriptor pointer to the next descriptor */ + pQueueCtrl->pUsedDescr = RX_NEXT_DESC_PTR(pRxUsedDesc, pQueueCtrl); + pQueueCtrl->pCurrentDescr = RX_NEXT_DESC_PTR(pRxCurrDesc, pQueueCtrl); + } + } +} + +/******************************************************************************* +* mvEthPortRxDone - Returns a Rx buffer back to the Rx ring. +* +* DESCRIPTION: +* This routine returns a Rx buffer back to the Rx ring. +* +* INPUT: +* void* pEthPortHndl - Ethernet Port handler. +* int rxQueue - Number of Rx queue. +* MV_PKT_INFO *pPktInfo - Pointer to received packet. +* +* RETURN: +* MV_ERROR - Unexpected Fatal error. +* MV_OUT_OF_RANGE - RX queue is already FULL, so this buffer can't be +* returned to this queue. +* MV_FULL - Buffer returned successfully and RX queue became full. +* More buffers should not be returned at the time. +* MV_OK - Buffer returned successfully and there are more free +* places in the queue. +* +*******************************************************************************/ +static INLINE MV_STATUS mvEthPortRxDone(void* pEthPortHndl, int rxQueue, MV_PKT_INFO *pPktInfo) +{ + ETH_RX_DESC* pRxUsedDesc; + ETH_QUEUE_CTRL* pQueueCtrl; + ETH_PORT_CTRL* pPortCtrl = (ETH_PORT_CTRL*)pEthPortHndl; + + pQueueCtrl = &pPortCtrl->rxQueue[rxQueue]; + + /* Get 'used' Rx descriptor */ + pRxUsedDesc = pQueueCtrl->pUsedDescr; + + /* Check that ring is not FULL */ + if( (pQueueCtrl->pUsedDescr == pQueueCtrl->pCurrentDescr) && + (pQueueCtrl->resource != 0) ) + { + mvOsPrintf("%s %d: out of range Error resource=%d, curr=%p, used=%p\n", + __FUNCTION__, pPortCtrl->portNo, pQueueCtrl->resource, + pQueueCtrl->pCurrentDescr, pQueueCtrl->pUsedDescr); + return MV_OUT_OF_RANGE; + } + + pRxUsedDesc->bufPtr = pPktInfo->pFrags->bufPhysAddr; + pRxUsedDesc->returnInfo = (MV_ULONG)pPktInfo; + pRxUsedDesc->bufSize = pPktInfo->pFrags->bufSize & ETH_RX_BUFFER_MASK; + + /* Invalidate data buffer accordingly with pktSize */ + if(pPktInfo->pktSize != 0) + { + ETH_PACKET_CACHE_INVALIDATE(pPktInfo->pFrags->bufVirtPtr, pPktInfo->pktSize); + pPktInfo->pktSize = 0; + } + + /* Return the descriptor to DMA ownership */ + pRxUsedDesc->cmdSts = ETH_BUFFER_OWNED_BY_DMA | ETH_RX_ENABLE_INTERRUPT_MASK; + + /* Flush descriptor and CPU pipe */ + ETH_DESCR_FLUSH_INV(pPortCtrl, pRxUsedDesc); + + pQueueCtrl->resource++; + + /* Move the used descriptor pointer to the next descriptor */ + pQueueCtrl->pUsedDescr = RX_NEXT_DESC_PTR(pRxUsedDesc, pQueueCtrl); + + /* If ring became Full return MV_FULL */ + if(pQueueCtrl->pUsedDescr == pQueueCtrl->pCurrentDescr) + return MV_FULL; + + return MV_OK; +} + + +#endif /* __mvEthGbe_h__ */ + + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/eth/gbe/mvEthRegs.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/eth/gbe/mvEthRegs.h new file mode 100644 index 0000000..7b9f052 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/eth/gbe/mvEthRegs.h @@ -0,0 +1,700 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + + +#ifndef __INCmvEthRegsh +#define __INCmvEthRegsh + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include "ctrlEnv/mvCtrlEnvSpec.h" + +/****************************************/ +/* Ethernet Unit Registers */ +/****************************************/ +#define ETH_REG_BASE MV_ETH_REG_BASE + +#define ETH_PHY_ADDR_REG(port) (ETH_REG_BASE(port) + 0x000) +#define ETH_SMI_REG(port) (ETH_REG_BASE(port) + 0x004) +#define ETH_UNIT_DEF_ADDR_REG(port) (ETH_REG_BASE(port) + 0x008) +#define ETH_UNIT_DEF_ID_REG(port) (ETH_REG_BASE(port) + 0x00c) +#define ETH_UNIT_RESERVED(port) (ETH_REG_BASE(port) + 0x014) +#define ETH_UNIT_INTR_CAUSE_REG(port) (ETH_REG_BASE(port) + 0x080) +#define ETH_UNIT_INTR_MASK_REG(port) (ETH_REG_BASE(port) + 0x084) + + +#define ETH_UNIT_ERROR_ADDR_REG(port) (ETH_REG_BASE(port) + 0x094) +#define ETH_UNIT_INT_ADDR_ERROR_REG(port) (ETH_REG_BASE(port) + 0x098) +#define ETH_UNIT_CONTROL_REG(port) (ETH_REG_BASE(port) + 0x0B0) + +#define ETH_PORT_CONFIG_REG(port) (ETH_REG_BASE(port) + 0x400) +#define ETH_PORT_CONFIG_EXTEND_REG(port) (ETH_REG_BASE(port) + 0x404) +#define ETH_MII_SERIAL_PARAM_REG(port) (ETH_REG_BASE(port) + 0x408) +#define ETH_GMII_SERIAL_PARAM_REG(port) (ETH_REG_BASE(port) + 0x40c) +#define ETH_VLAN_ETHER_TYPE_REG(port) (ETH_REG_BASE(port) + 0x410) +#define ETH_MAC_ADDR_LOW_REG(port) (ETH_REG_BASE(port) + 0x414) +#define ETH_MAC_ADDR_HIGH_REG(port) (ETH_REG_BASE(port) + 0x418) +#define ETH_SDMA_CONFIG_REG(port) (ETH_REG_BASE(port) + 0x41c) +#define ETH_DIFF_SERV_PRIO_REG(port, code) (ETH_REG_BASE(port) + 0x420 + ((code)<<2)) +#define ETH_PORT_SERIAL_CTRL_REG(port) (ETH_REG_BASE(port) + 0x43c) +#define ETH_VLAN_TAG_TO_PRIO_REG(port) (ETH_REG_BASE(port) + 0x440) +#define ETH_PORT_STATUS_REG(port) (ETH_REG_BASE(port) + 0x444) + +#define ETH_RX_QUEUE_COMMAND_REG(port) (ETH_REG_BASE(port) + 0x680) +#define ETH_TX_QUEUE_COMMAND_REG(port) (ETH_REG_BASE(port) + 0x448) + +#define ETH_PORT_SERIAL_CTRL_1_REG(port) (ETH_REG_BASE(port) + 0x44c) +#define ETH_PORT_STATUS_1_REG(port) (ETH_REG_BASE(port) + 0x450) +#define ETH_PORT_MARVELL_HEADER_REG(port) (ETH_REG_BASE(port) + 0x454) +#define ETH_PORT_FIFO_PARAMS_REG(port) (ETH_REG_BASE(port) + 0x458) +#define ETH_MAX_TOKEN_BUCKET_SIZE_REG(port) (ETH_REG_BASE(port) + 0x45c) +#define ETH_INTR_CAUSE_REG(port) (ETH_REG_BASE(port) + 0x460) +#define ETH_INTR_CAUSE_EXT_REG(port) (ETH_REG_BASE(port) + 0x464) +#define ETH_INTR_MASK_REG(port) (ETH_REG_BASE(port) + 0x468) +#define ETH_INTR_MASK_EXT_REG(port) (ETH_REG_BASE(port) + 0x46c) +#define ETH_TX_FIFO_URGENT_THRESH_REG(port) (ETH_REG_BASE(port) + 0x474) +#define ETH_RX_MINIMAL_FRAME_SIZE_REG(port) (ETH_REG_BASE(port) + 0x47c) +#define ETH_RX_DISCARD_PKTS_CNTR_REG(port) (ETH_REG_BASE(port) + 0x484) +#define ETH_RX_OVERRUN_PKTS_CNTR_REG(port) (ETH_REG_BASE(port) + 0x488) +#define ETH_INTERNAL_ADDR_ERROR_REG(port) (ETH_REG_BASE(port) + 0x494) +#define ETH_TX_FIXED_PRIO_CFG_REG(port) (ETH_REG_BASE(port) + 0x4dc) +#define ETH_TX_TOKEN_RATE_CFG_REG(port) (ETH_REG_BASE(port) + 0x4e0) +#define ETH_TX_QUEUE_COMMAND1_REG(port) (ETH_REG_BASE(port) + 0x4e4) +#define ETH_MAX_TRANSMIT_UNIT_REG(port) (ETH_REG_BASE(port) + 0x4e8) +#define ETH_TX_TOKEN_BUCKET_SIZE_REG(port) (ETH_REG_BASE(port) + 0x4ec) +#define ETH_TX_TOKEN_BUCKET_COUNT_REG(port) (ETH_REG_BASE(port) + 0x780) +#define ETH_RX_DESCR_STAT_CMD_REG(port, q) (ETH_REG_BASE(port) + 0x600 + ((q)<<4)) +#define ETH_RX_BYTE_COUNT_REG(port, q) (ETH_REG_BASE(port) + 0x604 + ((q)<<4)) +#define ETH_RX_BUF_PTR_REG(port, q) (ETH_REG_BASE(port) + 0x608 + ((q)<<4)) +#define ETH_RX_CUR_DESC_PTR_REG(port, q) (ETH_REG_BASE(port) + 0x60c + ((q)<<4)) +#define ETH_TX_CUR_DESC_PTR_REG(port, q) (ETH_REG_BASE(port) + 0x6c0 + ((q)<<2)) + +#define ETH_TXQ_TOKEN_COUNT_REG(port, q) (ETH_REG_BASE(port) + 0x700 + ((q)<<4)) +#define ETH_TXQ_TOKEN_CFG_REG(port, q) (ETH_REG_BASE(port) + 0x704 + ((q)<<4)) +#define ETH_TXQ_ARBITER_CFG_REG(port, q) (ETH_REG_BASE(port) + 0x708 + ((q)<<4)) + +#if (MV_ETH_VERSION >= 4) +#define ETH_TXQ_CMD_1_REG(port) (ETH_REG_BASE(port) + 0x4E4) +#define ETH_EJP_TX_HI_IPG_REG(port) (ETH_REG_BASE(port) + 0x7A8) +#define ETH_EJP_TX_LO_IPG_REG(port) (ETH_REG_BASE(port) + 0x7B8) +#define ETH_EJP_HI_TKN_LO_PKT_REG(port) (ETH_REG_BASE(port) + 0x7C0) +#define ETH_EJP_HI_TKN_ASYNC_PKT_REG(port) (ETH_REG_BASE(port) + 0x7C4) +#define ETH_EJP_LO_TKN_ASYNC_PKT_REG(port) (ETH_REG_BASE(port) + 0x7C8) +#define ETH_EJP_TX_SPEED_REG(port) (ETH_REG_BASE(port) + 0x7D0) +#endif /* MV_ETH_VERSION >= 4 */ + +#define ETH_MIB_COUNTERS_BASE(port) (ETH_REG_BASE(port) + 0x1000) +#define ETH_DA_FILTER_SPEC_MCAST_BASE(port) (ETH_REG_BASE(port) + 0x1400) +#define ETH_DA_FILTER_OTH_MCAST_BASE(port) (ETH_REG_BASE(port) + 0x1500) +#define ETH_DA_FILTER_UCAST_BASE(port) (ETH_REG_BASE(port) + 0x1600) + +/* Phy address register definitions */ +#define ETH_PHY_ADDR_OFFS 0 +#define ETH_PHY_ADDR_MASK (0x1f <= 4) +#define ETH_TX_EJP_RESET_BIT 0 +#define ETH_TX_EJP_RESET_MASK (1 << ETH_TX_EJP_RESET_BIT) + +#define ETH_TX_EJP_ENABLE_BIT 2 +#define ETH_TX_EJP_ENABLE_MASK (1 << ETH_TX_EJP_ENABLE_BIT) + +#define ETH_TX_LEGACY_WRR_BIT 3 +#define ETH_TX_LEGACY_WRR_MASK (1 << ETH_TX_LEGACY_WRR_BIT) +#endif /* (MV_ETH_VERSION >= 4) */ + +/***** BITs of Ethernet Port Status reg (PSR) *****/ +#define ETH_LINK_UP_BIT 1 +#define ETH_LINK_UP_MASK (1<= 4) +MV_STATUS mvEthEjpModeSet(void* pPortHandle, int mode); +#endif /* (MV_ETH_VERSION >= 4) */ + +void mvEthStatusGet(void* pPortHandle, MV_ETH_PORT_STATUS* pStatus); + +/* Marvell Header control */ +MV_STATUS mvEthHeaderModeSet(void* pPortHandle, MV_ETH_HEADER_MODE headerMode); + +/* PHY routines */ +void mvEthPhyAddrSet(void* pPortHandle, int phyAddr); +int mvEthPhyAddrGet(void* pPortHandle); + +/* Power management routines */ +void mvEthPortPowerDown(int port); +void mvEthPortPowerUp(int port); + +/******************** ETH PRIVATE ************************/ + +/*#define UNCACHED_TX_BUFFERS*/ +/*#define UNCACHED_RX_BUFFERS*/ + + +/* Port attributes */ +/* Size of a Tx/Rx descriptor used in chain list data structure */ +#define ETH_RX_DESC_ALIGNED_SIZE 32 +#define ETH_TX_DESC_ALIGNED_SIZE 32 + +#define TX_DISABLE_TIMEOUT_MSEC 1000 +#define RX_DISABLE_TIMEOUT_MSEC 1000 +#define TX_FIFO_EMPTY_TIMEOUT_MSEC 10000 +#define PORT_DISABLE_WAIT_TCLOCKS 5000 + +/* Macros that save access to desc in order to find next desc pointer */ +#define RX_NEXT_DESC_PTR(pRxDescr, pQueueCtrl) \ + ((pRxDescr) == (pQueueCtrl)->pLastDescr) ? \ + (ETH_RX_DESC*)((pQueueCtrl)->pFirstDescr) : \ + (ETH_RX_DESC*)(((MV_ULONG)(pRxDescr)) + ETH_RX_DESC_ALIGNED_SIZE) + +#define TX_NEXT_DESC_PTR(pTxDescr, pQueueCtrl) \ + ((pTxDescr) == (pQueueCtrl)->pLastDescr) ? \ + (ETH_TX_DESC*)((pQueueCtrl)->pFirstDescr) : \ + (ETH_TX_DESC*)(((MV_ULONG)(pTxDescr)) + ETH_TX_DESC_ALIGNED_SIZE) + +#define RX_PREV_DESC_PTR(pRxDescr, pQueueCtrl) \ + ((pRxDescr) == (pQueueCtrl)->pFirstDescr) ? \ + (ETH_RX_DESC*)((pQueueCtrl)->pLastDescr) : \ + (ETH_RX_DESC*)(((MV_ULONG)(pRxDescr)) - ETH_RX_DESC_ALIGNED_SIZE) + +#define TX_PREV_DESC_PTR(pTxDescr, pQueueCtrl) \ + ((pTxDescr) == (pQueueCtrl)->pFirstDescr) ? \ + (ETH_TX_DESC*)((pQueueCtrl)->pLastDescr) : \ + (ETH_TX_DESC*)(((MV_ULONG)(pTxDescr)) - ETH_TX_DESC_ALIGNED_SIZE) + + +/* Queue specific information */ +typedef struct +{ + void* pFirstDescr; + void* pLastDescr; + void* pCurrentDescr; + void* pUsedDescr; + int resource; + MV_BUF_INFO descBuf; +} ETH_QUEUE_CTRL; + + +/* Ethernet port specific infomation */ +typedef struct _ethPortCtrl +{ + int portNo; + ETH_QUEUE_CTRL rxQueue[MV_ETH_RX_Q_NUM]; /* Rx ring resource */ + ETH_QUEUE_CTRL txQueue[MV_ETH_TX_Q_NUM]; /* Tx ring resource */ + + MV_ETH_PORT_CFG portConfig; + MV_ETH_RX_Q_CFG rxQueueConfig[MV_ETH_RX_Q_NUM]; + MV_ETH_TX_Q_CFG txQueueConfig[MV_ETH_TX_Q_NUM]; + + /* Register images - For DP */ + MV_U32 portTxQueueCmdReg; /* Port active Tx queues summary */ + MV_U32 portRxQueueCmdReg; /* Port active Rx queues summary */ + + MV_STATE portState; + + MV_U8 mcastCount[256]; + MV_U32* hashPtr; + void *osHandle; +} ETH_PORT_CTRL; + +/************** MACROs ****************/ + +/* MACROs to Flush / Invalidate TX / RX Buffers */ +#if (ETHER_DRAM_COHER == MV_CACHE_COHER_SW) && !defined(UNCACHED_TX_BUFFERS) +# define ETH_PACKET_CACHE_FLUSH(pAddr, size) \ + mvOsCacheClear(NULL, (pAddr), (size)); \ + /*CPU_PIPE_FLUSH;*/ +#else +# define ETH_PACKET_CACHE_FLUSH(pAddr, size) \ + mvOsIoVirtToPhy(NULL, (pAddr)); +#endif /* ETHER_DRAM_COHER == MV_CACHE_COHER_SW */ + +#if ( (ETHER_DRAM_COHER == MV_CACHE_COHER_SW) && !defined(UNCACHED_RX_BUFFERS) ) +# define ETH_PACKET_CACHE_INVALIDATE(pAddr, size) \ + mvOsCacheInvalidate (NULL, (pAddr), (size)); \ + /*CPU_PIPE_FLUSH;*/ +#else +# define ETH_PACKET_CACHE_INVALIDATE(pAddr, size) +#endif /* ETHER_DRAM_COHER == MV_CACHE_COHER_SW && !UNCACHED_RX_BUFFERS */ + +#ifdef ETH_DESCR_UNCACHED + +#define ETH_DESCR_FLUSH_INV(pPortCtrl, pDescr) +#define ETH_DESCR_INV(pPortCtrl, pDescr) + +#else + +#define ETH_DESCR_FLUSH_INV(pPortCtrl, pDescr) \ + mvOsCacheLineFlushInv(pPortCtrl->osHandle, (MV_ULONG)(pDescr)) + +#define ETH_DESCR_INV(pPortCtrl, pDescr) \ + mvOsCacheLineInv(pPortCtrl->osHandle, (MV_ULONG)(pDescr)) + +#endif /* ETH_DESCR_UNCACHED */ + +#include "eth/gbe/mvEthGbe.h" + +#endif /* __mvEth_h__ */ + + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/gpp/mvCompVer.txt b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/gpp/mvCompVer.txt new file mode 100644 index 0000000..38a9264 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/gpp/mvCompVer.txt @@ -0,0 +1,4 @@ +Global HAL Version: FEROCEON_HAL_3_1_7 +Unit HAL Version: 3.1.4 +Description: This component includes an implementation of the unit HAL drivers + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/gpp/mvGpp.c b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/gpp/mvGpp.c new file mode 100644 index 0000000..889d4d9 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/gpp/mvGpp.c @@ -0,0 +1,362 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#include "gpp/mvGpp.h" +#include "ctrlEnv/mvCtrlEnvLib.h" +/* defines */ +#ifdef MV_DEBUG + #define DB(x) x +#else + #define DB(x) +#endif + +static MV_VOID gppRegSet(MV_U32 group, MV_U32 regOffs,MV_U32 mask,MV_U32 value); + +/******************************************************************************* +* mvGppTypeSet - Enable a GPP (OUT) pin +* +* DESCRIPTION: +* +* INPUT: +* group - GPP group number +* mask - 32bit mask value. Each set bit in the mask means that the type +* of corresponding GPP will be set. Other GPPs are ignored. +* value - 32bit value that describes GPP type per pin. +* +* OUTPUT: +* None. +* +* EXAMPLE: +* Set GPP8 to input and GPP15 to output. +* mvGppTypeSet(0, (GPP8 | GPP15), +* ((MV_GPP_IN & GPP8) | (MV_GPP_OUT & GPP15)) ); +* +* RETURN: +* None. +* +*******************************************************************************/ +MV_STATUS mvGppTypeSet(MV_U32 group, MV_U32 mask, MV_U32 value) +{ + if (group >= MV_GPP_MAX_GROUP) + { + DB(mvOsPrintf("mvGppTypeSet: ERR. invalid group number \n")); + return MV_BAD_PARAM; + } + + gppRegSet(group, GPP_DATA_OUT_EN_REG(group), mask, value); + + /* Workaround for Erratum FE-MISC-70*/ + if(mvCtrlRevGet()==MV_88F6XXX_A0_REV && (group == 1)) + { + mask &= 0x2; + gppRegSet(0, GPP_DATA_OUT_EN_REG(0), mask, value); + } /*End of WA*/ + + return MV_OK; + +} + +/******************************************************************************* +* mvGppBlinkEn - Set a GPP (IN) Pin list to blink every ~100ms +* +* DESCRIPTION: +* +* INPUT: +* group - GPP group number +* mask - 32bit mask value. Each set bit in the mask means that the type +* of corresponding GPP will be set. Other GPPs are ignored. +* value - 32bit value that describes GPP blink per pin. +* +* OUTPUT: +* None. +* +* EXAMPLE: +* Set GPP8 to be static and GPP15 to be blinking. +* mvGppBlinkEn(0, (GPP8 | GPP15), +* ((MV_GPP_OUT_STATIC & GPP8) | (MV_GPP_OUT_BLINK & GPP15)) ); +* +* RETURN: +* None. +* +*******************************************************************************/ +MV_STATUS mvGppBlinkEn(MV_U32 group, MV_U32 mask, MV_U32 value) +{ + if (group >= MV_GPP_MAX_GROUP) + { + DB(mvOsPrintf("mvGppBlinkEn: ERR. invalid group number \n")); + return MV_BAD_PARAM; + } + + gppRegSet(group, GPP_BLINK_EN_REG(group), mask, value); + + return MV_OK; + +} +/******************************************************************************* +* mvGppPolaritySet - Set a GPP (IN) Pin list Polarity mode +* +* DESCRIPTION: +* +* INPUT: +* group - GPP group number +* mask - 32bit mask value. Each set bit in the mask means that the type +* of corresponding GPP will be set. Other GPPs are ignored. +* value - 32bit value that describes GPP polarity per pin. +* +* OUTPUT: +* None. +* +* EXAMPLE: +* Set GPP8 to the actual pin value and GPP15 to be inverted. +* mvGppPolaritySet(0, (GPP8 | GPP15), +* ((MV_GPP_IN_ORIGIN & GPP8) | (MV_GPP_IN_INVERT & GPP15)) ); +* +* RETURN: +* None. +* +*******************************************************************************/ +MV_STATUS mvGppPolaritySet(MV_U32 group, MV_U32 mask, MV_U32 value) +{ + if (group >= MV_GPP_MAX_GROUP) + { + DB(mvOsPrintf("mvGppPolaritySet: ERR. invalid group number \n")); + return MV_BAD_PARAM; + } + + gppRegSet(group, GPP_DATA_IN_POL_REG(group), mask, value); + + return MV_OK; + +} + +/******************************************************************************* +* mvGppPolarityGet - Get a value of relevant bits from GPP Polarity register. +* +* DESCRIPTION: +* +* INPUT: +* group - GPP group number +* mask - 32bit mask value. Each set bit in the mask means that the +* returned value is valid for it. +* +* OUTPUT: +* None. +* +* EXAMPLE: +* Get GPP8 and GPP15 value. +* mvGppPolarityGet(0, (GPP8 | GPP15)); +* +* RETURN: +* 32bit value that describes GPP polatity mode per pin. +* +*******************************************************************************/ +MV_U32 mvGppPolarityGet(MV_U32 group, MV_U32 mask) +{ + MV_U32 regVal; + + if (group >= MV_GPP_MAX_GROUP) + { + DB(mvOsPrintf("mvGppActiveSet: Error invalid group number \n")); + return MV_ERROR; + } + regVal = MV_REG_READ(GPP_DATA_IN_POL_REG(group)); + + return (regVal & mask); +} + +/******************************************************************************* +* mvGppValueGet - Get a GPP Pin list value. +* +* DESCRIPTION: +* This function get GPP value. +* +* INPUT: +* group - GPP group number +* mask - 32bit mask value. Each set bit in the mask means that the +* returned value is valid for it. +* +* OUTPUT: +* None. +* +* EXAMPLE: +* Get GPP8 and GPP15 value. +* mvGppValueGet(0, (GPP8 | GPP15)); +* +* RETURN: +* 32bit value that describes GPP activity mode per pin. +* +*******************************************************************************/ +MV_U32 mvGppValueGet(MV_U32 group, MV_U32 mask) +{ + MV_U32 gppData; + + gppData = MV_REG_READ(GPP_DATA_IN_REG(group)); + + gppData &= mask; + + return gppData; + +} + +/******************************************************************************* +* mvGppValueSet - Set a GPP Pin list value. +* +* DESCRIPTION: +* This function set value for given GPP pin list. +* +* INPUT: +* group - GPP group number +* mask - 32bit mask value. Each set bit in the mask means that the +* value of corresponding GPP will be set accordingly. Other GPP +* are not affected. +* value - 32bit value that describes GPP value per pin. +* +* OUTPUT: +* None. +* +* EXAMPLE: +* Set GPP8 value of '0' and GPP15 value of '1'. +* mvGppActiveSet(0, (GPP8 | GPP15), ((0 & GPP8) | (GPP15)) ); +* +* RETURN: +* None. +* +*******************************************************************************/ +MV_STATUS mvGppValueSet (MV_U32 group, MV_U32 mask, MV_U32 value) +{ + MV_U32 outEnable, tmp; + MV_U32 i; + + if (group >= MV_GPP_MAX_GROUP) + { + DB(mvOsPrintf("mvGppValueSet: Error invalid group number \n")); + return MV_BAD_PARAM; + } + + /* verify that the gpp pin is configured as output */ + /* Note that in the register out enabled -> bit = '0'. */ + outEnable = ~MV_REG_READ(GPP_DATA_OUT_EN_REG(group)); + + /* Workaround for Erratum FE-MISC-70*/ + if(mvCtrlRevGet()==MV_88F6XXX_A0_REV && (group == 1)) + { + tmp = ~MV_REG_READ(GPP_DATA_OUT_EN_REG(0)); + outEnable &= 0xfffffffd; + outEnable |= (tmp & 0x2); + } /*End of WA*/ + + for (i = 0 ; i < 32 ;i++) + { + if (((mask & (1 << i)) & (outEnable & (1 << i))) != (mask & (1 << i))) + { + mvOsPrintf("mvGppValueSet: Err. An attempt to set output "\ + "value to GPP %d in input mode.\n", i); + return MV_ERROR; + } + } + + gppRegSet(group, GPP_DATA_OUT_REG(group), mask, value); + + return MV_OK; + +} +/******************************************************************************* +* gppRegSet - Set a specific GPP pin on a specific GPP register +* +* DESCRIPTION: +* This function set a specific GPP pin on a specific GPP register +* +* INPUT: +* regOffs - GPP Register offset +* group - GPP group number +* mask - 32bit mask value. Each set bit in the mask means that the +* value of corresponding GPP will be set accordingly. Other GPP +* are not affected. +* value - 32bit value that describes GPP value per pin. +* +* OUTPUT: +* None. +* +* EXAMPLE: +* Set GPP8 value of '0' and GPP15 value of '1'. +* mvGppActiveSet(0, (GPP8 | GPP15), ((0 & GPP8) | (1 & GPP15)) ); +* +* RETURN: +* None. +* +*******************************************************************************/ +static MV_VOID gppRegSet (MV_U32 group, MV_U32 regOffs,MV_U32 mask,MV_U32 value) +{ + MV_U32 gppData; + + gppData = MV_REG_READ(regOffs); + + gppData &= ~mask; + + gppData |= (value & mask); + + MV_REG_WRITE(regOffs, gppData); +} + + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/gpp/mvGpp.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/gpp/mvGpp.h new file mode 100644 index 0000000..526d324 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/gpp/mvGpp.h @@ -0,0 +1,118 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#ifndef __INCmvGppH +#define __INCmvGppH + +#include "mvCommon.h" +#include "mvOs.h" +#include "ctrlEnv/mvCtrlEnvSpec.h" +#include "gpp/mvGppRegs.h" + +/* These macros describes the GPP type. Each of the GPPs pins can */ +/* be assigned to act as a general purpose input or output pin. */ +#define MV_GPP_IN 0xFFFFFFFF /* GPP input */ +#define MV_GPP_OUT 0 /* GPP output */ + + +/* These macros describes the GPP Out Enable. */ +#define MV_GPP_OUT_DIS 0xFFFFFFFF /* Out pin disabled*/ +#define MV_GPP_OUT_EN 0 /* Out pin enabled*/ + +/* These macros describes the GPP Out Blinking. */ +/* When set and the corresponding bit in GPIO Data Out Enable Control */ +/* Register is enabled, the GPIO pin blinks every ~100 ms (a period of */ +/* 2^24 TCLK clocks). */ +#define MV_GPP_OUT_BLINK 0xFFFFFFFF /* Out pin blinking*/ +#define MV_GPP_OUT_STATIC 0 /* Out pin static*/ + + +/* These macros describes the GPP Polarity. */ +/* When set to 1 GPIO Data In Register reflects the inverted value of the */ +/* corresponding pin. */ + +#define MV_GPP_IN_INVERT 0xFFFFFFFF /* Inverted value is got*/ +#define MV_GPP_IN_ORIGIN 0 /* original value is got*/ + +/* mvGppTypeSet - Set PP pin mode (IN or OUT) */ +MV_STATUS mvGppTypeSet(MV_U32 group, MV_U32 mask, MV_U32 value); + +/* mvGppBlinkEn - Set a GPP (IN) Pin list to blink every ~100ms */ +MV_STATUS mvGppBlinkEn(MV_U32 group, MV_U32 mask, MV_U32 value); + +/* mvGppPolaritySet - Set a GPP (IN) Pin list Polarity mode. */ +MV_STATUS mvGppPolaritySet(MV_U32 group, MV_U32 mask, MV_U32 value); + +/* mvGppPolarityGet - Get the Polarity of a GPP Pin */ +MV_U32 mvGppPolarityGet(MV_U32 group, MV_U32 mask); + +/* mvGppValueGet - Get a GPP Pin list value.*/ +MV_U32 mvGppValueGet(MV_U32 group, MV_U32 mask); + + +/* mvGppValueSet - Set a GPP Pin list value. */ +MV_STATUS mvGppValueSet (MV_U32 group, MV_U32 mask, MV_U32 value); + +#endif /* #ifndef __INCmvGppH */ + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/gpp/mvGppRegs.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/gpp/mvGppRegs.h new file mode 100644 index 0000000..b6fec34 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/gpp/mvGppRegs.h @@ -0,0 +1,116 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#ifndef __INCmvGppRegsH +#define __INCmvGppRegsH + +#define MV_GPP0 BIT0 +#define MV_GPP1 BIT1 +#define MV_GPP2 BIT2 +#define MV_GPP3 BIT3 +#define MV_GPP4 BIT4 +#define MV_GPP5 BIT5 +#define MV_GPP6 BIT6 +#define MV_GPP7 BIT7 +#define MV_GPP8 BIT8 +#define MV_GPP9 BIT9 +#define MV_GPP10 BIT10 +#define MV_GPP11 BIT11 +#define MV_GPP12 BIT12 +#define MV_GPP13 BIT13 +#define MV_GPP14 BIT14 +#define MV_GPP15 BIT15 +#define MV_GPP16 BIT16 +#define MV_GPP17 BIT17 +#define MV_GPP18 BIT18 +#define MV_GPP19 BIT19 +#define MV_GPP20 BIT20 +#define MV_GPP21 BIT21 +#define MV_GPP22 BIT22 +#define MV_GPP23 BIT23 +#define MV_GPP24 BIT24 +#define MV_GPP25 BIT25 +#define MV_GPP26 BIT26 +#define MV_GPP27 BIT27 +#define MV_GPP28 BIT28 +#define MV_GPP29 BIT29 +#define MV_GPP30 BIT30 +#define MV_GPP31 BIT31 + + +/* registers offsets */ + +#define GPP_DATA_OUT_REG(grp) ((grp == 0) ? 0x10100 : 0x10140) +#define GPP_DATA_OUT_EN_REG(grp) ((grp == 0) ? 0x10104 : 0x10144) +#define GPP_BLINK_EN_REG(grp) ((grp == 0) ? 0x10108 : 0x10148) +#define GPP_DATA_IN_POL_REG(grp) ((grp == 0) ? 0x1010C : 0x1014c) +#define GPP_DATA_IN_REG(grp) ((grp == 0) ? 0x10110 : 0x10150) +#define GPP_INT_CAUSE_REG(grp) ((grp == 0) ? 0x10114 : 0x10154) +#define GPP_INT_MASK_REG(grp) ((grp == 0) ? 0x10118 : 0x10158) +#define GPP_INT_LVL_REG(grp) ((grp == 0) ? 0x1011c : 0x1015c) + +#define GPP_DATA_OUT_SET_REG 0x10120 +#define GPP_DATA_OUT_CLEAR_REG 0x10124 + +#endif /* #ifndef __INCmvGppRegsH */ diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/pci-if/mvCompVer.txt b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/pci-if/mvCompVer.txt new file mode 100644 index 0000000..85bfa61 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/pci-if/mvCompVer.txt @@ -0,0 +1,4 @@ +Global HAL Version: FEROCEON_HAL_3_1_7 +Unit HAL Version: 3.1.3 +Description: This component includes an implementation of the unit HAL drivers + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/pci-if/mvPciIf.c b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/pci-if/mvPciIf.c new file mode 100644 index 0000000..672d3e3 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/pci-if/mvPciIf.c @@ -0,0 +1,669 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#include "mvPciIf.h" +#include "ctrlEnv/sys/mvSysPex.h" + +#if defined(MV_INCLUDE_PCI) +#include "ctrlEnv/sys/mvSysPci.h" +#endif + + +/* defines */ +#ifdef MV_DEBUG + #define DB(x) x +#else + #define DB(x) +#endif + + +/******************************************************************************* +* mvPciInit - Initialize PCI interfaces +* +* DESCRIPTION: +* +* INPUT: +* +* +* OUTPUT: +* None. +* +* RETURN: +* MV_OK if function success otherwise MV_ERROR or MV_BAD_PARAM +* +*******************************************************************************/ + + +MV_STATUS mvPciIfInit(MV_U32 pciIf, PCI_IF_MODE pciIfmode) +{ + PCI_IF_TYPE pciIfType = mvPciIfTypeGet(pciIf); + + if (PCI_IF_TYPE_CONVEN_PCIX == pciIfType) + { + #if defined(MV_INCLUDE_PCI) + + MV_PCI_MOD pciMod; + + if (PCI_IF_MODE_HOST == pciIfmode) + { + pciMod = MV_PCI_MOD_HOST; + } + else if (PCI_IF_MODE_DEVICE == pciIfmode) + { + pciMod = MV_PCI_MOD_DEVICE; + } + else + { + mvOsPrintf("%s: ERROR!!! Bus %d mode %d neither host nor device!\n", + __FUNCTION__, pciIf, pciIfmode); + return MV_FAIL; + } + + return mvPciInit(pciIf - MV_PCI_START_IF, pciMod); + #else + return MV_OK; + #endif + } + else if (PCI_IF_TYPE_PEX == pciIfType) + { + #if defined(MV_INCLUDE_PEX) + + MV_PEX_TYPE pexType; + + if (PCI_IF_MODE_HOST == pciIfmode) + { + pexType = MV_PEX_ROOT_COMPLEX; + } + else if (PCI_IF_MODE_DEVICE == pciIfmode) + { + pexType = MV_PEX_END_POINT; + } + else + { + mvOsPrintf("%s: ERROR!!! Bus %d type %d neither root complex nor" \ + " end point\n", __FUNCTION__, pciIf, pciIfmode); + return MV_FAIL; + } + return mvPexInit(pciIf - MV_PEX_START_IF, pexType); + + #else + return MV_OK; + #endif + + } + else + { + mvOsPrintf("%s: ERROR!!! Invalid pciIf %d\n", __FUNCTION__, pciIf); + } + + return MV_FAIL; + +} + +/* PCI configuration space read write */ + +/******************************************************************************* +* mvPciConfigRead - Read from configuration space +* +* DESCRIPTION: +* This function performs a 32 bit read from PCI configuration space. +* It supports both type 0 and type 1 of Configuration Transactions +* (local and over bridge). In order to read from local bus segment, use +* bus number retrieved from mvPciLocalBusNumGet(). Other bus numbers +* will result configuration transaction of type 1 (over bridge). +* +* INPUT: +* pciIf - PCI interface number. +* bus - PCI segment bus number. +* dev - PCI device number. +* func - Function number. +* regOffs - Register offset. +* +* OUTPUT: +* None. +* +* RETURN: +* 32bit register data, 0xffffffff on error +* +*******************************************************************************/ +MV_U32 mvPciIfConfigRead (MV_U32 pciIf, MV_U32 bus, MV_U32 dev, MV_U32 func, + MV_U32 regOff) +{ + PCI_IF_TYPE pciIfType = mvPciIfTypeGet(pciIf); + + if (PCI_IF_TYPE_CONVEN_PCIX == pciIfType) + { + #if defined(MV_INCLUDE_PCI) + return mvPciConfigRead(pciIf - MV_PCI_START_IF, + bus, + dev, + func, + regOff); + #else + return 0xffffffff; + #endif + } + else if (PCI_IF_TYPE_PEX == pciIfType) + { + #if defined(MV_INCLUDE_PEX) + return mvPexConfigRead(pciIf - MV_PEX_START_IF, + bus, + dev, + func, + regOff); + #else + return 0xffffffff; + #endif + + } + else + { + mvOsPrintf("%s: ERROR!!! Invalid pciIf %d\n", __FUNCTION__, pciIf); + } + + return 0; + +} + +/******************************************************************************* +* mvPciConfigWrite - Write to configuration space +* +* DESCRIPTION: +* This function performs a 32 bit write to PCI configuration space. +* It supports both type 0 and type 1 of Configuration Transactions +* (local and over bridge). In order to write to local bus segment, use +* bus number retrieved from mvPciLocalBusNumGet(). Other bus numbers +* will result configuration transaction of type 1 (over bridge). +* +* INPUT: +* pciIf - PCI interface number. +* bus - PCI segment bus number. +* dev - PCI device number. +* func - Function number. +* regOffs - Register offset. +* data - 32bit data. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_BAD_PARAM for bad parameters ,MV_ERROR on error ! otherwise MV_OK +* +*******************************************************************************/ +MV_STATUS mvPciIfConfigWrite(MV_U32 pciIf, MV_U32 bus, MV_U32 dev, + MV_U32 func, MV_U32 regOff, MV_U32 data) +{ + PCI_IF_TYPE pciIfType = mvPciIfTypeGet(pciIf); + + if (PCI_IF_TYPE_CONVEN_PCIX == pciIfType) + { + #if defined(MV_INCLUDE_PCI) + return mvPciConfigWrite(pciIf - MV_PCI_START_IF, + bus, + dev, + func, + regOff, + data); + #else + return MV_OK; + #endif + } + else if (PCI_IF_TYPE_PEX == pciIfType) + { + #if defined(MV_INCLUDE_PEX) + return mvPexConfigWrite(pciIf - MV_PEX_START_IF, + bus, + dev, + func, + regOff, + data); + #else + return MV_OK; + #endif + + } + else + { + mvOsPrintf("%s: ERROR!!! Invalid pciIf %d\n", __FUNCTION__, pciIf); + } + + return MV_FAIL; + +} + +/******************************************************************************* +* mvPciMasterEnable - Enable/disale PCI interface master transactions. +* +* DESCRIPTION: +* This function performs read modified write to PCI command status +* (offset 0x4) to set/reset bit 2. After this bit is set, the PCI +* master is allowed to gain ownership on the bus, otherwise it is +* incapable to do so. +* +* INPUT: +* pciIf - PCI interface number. +* enable - Enable/disable parameter. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_BAD_PARAM for bad parameters ,MV_ERROR on error ! otherwise MV_OK +* +*******************************************************************************/ +MV_STATUS mvPciIfMasterEnable(MV_U32 pciIf, MV_BOOL enable) +{ + + PCI_IF_TYPE pciIfType = mvPciIfTypeGet(pciIf); + + if (PCI_IF_TYPE_CONVEN_PCIX == pciIfType) + { + #if defined(MV_INCLUDE_PCI) + return mvPciMasterEnable(pciIf - MV_PCI_START_IF, + enable); + #else + return MV_OK; + #endif + } + else if (PCI_IF_TYPE_PEX == pciIfType) + { + #if defined(MV_INCLUDE_PEX) + return mvPexMasterEnable(pciIf - MV_PEX_START_IF, + enable); + #else + return MV_OK; + #endif + } + else + { + mvOsPrintf("%s: ERROR!!! Invalid pciIf %d\n", __FUNCTION__, pciIf); + } + + return MV_FAIL; + +} + + +/******************************************************************************* +* mvPciSlaveEnable - Enable/disale PCI interface slave transactions. +* +* DESCRIPTION: +* This function performs read modified write to PCI command status +* (offset 0x4) to set/reset bit 0 and 1. After those bits are set, +* the PCI slave is allowed to respond to PCI IO space access (bit 0) +* and PCI memory space access (bit 1). +* +* INPUT: +* pciIf - PCI interface number. +* dev - PCI device number. +* enable - Enable/disable parameter. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_BAD_PARAM for bad parameters ,MV_ERROR on error ! otherwise MV_OK +* +*******************************************************************************/ +MV_STATUS mvPciIfSlaveEnable(MV_U32 pciIf,MV_U32 bus, MV_U32 dev, MV_BOOL enable) +{ + + PCI_IF_TYPE pciIfType = mvPciIfTypeGet(pciIf); + + if (PCI_IF_TYPE_CONVEN_PCIX == pciIfType) + { + #if defined(MV_INCLUDE_PCI) + return mvPciSlaveEnable(pciIf - MV_PCI_START_IF,bus,dev, + enable); + #else + return MV_OK; + #endif + } + else if (PCI_IF_TYPE_PEX == pciIfType) + { + #if defined(MV_INCLUDE_PEX) + return mvPexSlaveEnable(pciIf - MV_PEX_START_IF,bus,dev, + enable); + #else + return MV_OK; + #endif + } + else + { + mvOsPrintf("%s: ERROR!!! Invalid pciIf %d\n", __FUNCTION__, pciIf); + } + + return MV_FAIL; + +} + +/******************************************************************************* +* mvPciLocalBusNumSet - Set PCI interface local bus number. +* +* DESCRIPTION: +* This function sets given PCI interface its local bus number. +* Note: In case the PCI interface is PCI-X, the information is read-only. +* +* INPUT: +* pciIf - PCI interface number. +* busNum - Bus number. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_NOT_ALLOWED in case PCI interface is PCI-X. +* MV_BAD_PARAM on bad parameters , +* otherwise MV_OK +* +*******************************************************************************/ +MV_STATUS mvPciIfLocalBusNumSet(MV_U32 pciIf, MV_U32 busNum) +{ + PCI_IF_TYPE pciIfType = mvPciIfTypeGet(pciIf); + + if (PCI_IF_TYPE_CONVEN_PCIX == pciIfType) + { + #if defined(MV_INCLUDE_PCI) + return mvPciLocalBusNumSet(pciIf - MV_PCI_START_IF, + busNum); + #else + return MV_OK; + #endif + } + else if (PCI_IF_TYPE_PEX == pciIfType) + { + #if defined(MV_INCLUDE_PEX) + return mvPexLocalBusNumSet(pciIf - MV_PEX_START_IF, + busNum); + #else + return MV_OK; + #endif + } + else + { + mvOsPrintf("%s: ERROR!!! Invalid pciIf %d\n", __FUNCTION__, pciIf); + } + + return MV_FAIL; + +} + +/******************************************************************************* +* mvPciLocalBusNumGet - Get PCI interface local bus number. +* +* DESCRIPTION: +* This function gets the local bus number of a given PCI interface. +* +* INPUT: +* pciIf - PCI interface number. +* +* OUTPUT: +* None. +* +* RETURN: +* Local bus number.0xffffffff on Error +* +*******************************************************************************/ +MV_U32 mvPciIfLocalBusNumGet(MV_U32 pciIf) +{ + PCI_IF_TYPE pciIfType = mvPciIfTypeGet(pciIf); + + if (PCI_IF_TYPE_CONVEN_PCIX == pciIfType) + { + #if defined(MV_INCLUDE_PCI) + return mvPciLocalBusNumGet(pciIf - MV_PCI_START_IF); + #else + return 0xFFFFFFFF; + #endif + } + else if (PCI_IF_TYPE_PEX == pciIfType) + { + #if defined(MV_INCLUDE_PEX) + return mvPexLocalBusNumGet(pciIf - MV_PEX_START_IF); + #else + return 0xFFFFFFFF; + #endif + + } + else + { + mvOsPrintf("%s: ERROR!!! Invalid pciIf %d\n",__FUNCTION__, pciIf); + } + + return 0; + +} + + +/******************************************************************************* +* mvPciLocalDevNumSet - Set PCI interface local device number. +* +* DESCRIPTION: +* This function sets given PCI interface its local device number. +* Note: In case the PCI interface is PCI-X, the information is read-only. +* +* INPUT: +* pciIf - PCI interface number. +* devNum - Device number. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_NOT_ALLOWED in case PCI interface is PCI-X. MV_BAD_PARAM on bad parameters , +* otherwise MV_OK +* +*******************************************************************************/ +MV_STATUS mvPciIfLocalDevNumSet(MV_U32 pciIf, MV_U32 devNum) +{ + PCI_IF_TYPE pciIfType = mvPciIfTypeGet(pciIf); + + if (PCI_IF_TYPE_CONVEN_PCIX == pciIfType) + { + #if defined(MV_INCLUDE_PCI) + return mvPciLocalDevNumSet(pciIf - MV_PCI_START_IF, + devNum); + #else + return MV_OK; + #endif + } + else if (PCI_IF_TYPE_PEX == pciIfType) + { + #if defined(MV_INCLUDE_PEX) + return mvPexLocalDevNumSet(pciIf - MV_PEX_START_IF, + devNum); + #else + return MV_OK; + #endif + } + else + { + mvOsPrintf("%s: ERROR!!! Invalid pciIf %d\n", __FUNCTION__, pciIf); + } + + return MV_FAIL; + +} + +/******************************************************************************* +* mvPciLocalDevNumGet - Get PCI interface local device number. +* +* DESCRIPTION: +* This function gets the local device number of a given PCI interface. +* +* INPUT: +* pciIf - PCI interface number. +* +* OUTPUT: +* None. +* +* RETURN: +* Local device number. 0xffffffff on Error +* +*******************************************************************************/ +MV_U32 mvPciIfLocalDevNumGet(MV_U32 pciIf) +{ + PCI_IF_TYPE pciIfType = mvPciIfTypeGet(pciIf); + + if (PCI_IF_TYPE_CONVEN_PCIX == pciIfType) + { + #if defined(MV_INCLUDE_PCI) + return mvPciLocalDevNumGet(pciIf - MV_PCI_START_IF); + #else + return 0xFFFFFFFF; + #endif + } + else if (PCI_IF_TYPE_PEX == pciIfType) + { + #if defined(MV_INCLUDE_PEX) + return mvPexLocalDevNumGet(pciIf - MV_PEX_START_IF); + #else + return 0xFFFFFFFF; + #endif + + } + else + { + mvOsPrintf("%s: ERROR!!! Invalid pciIf %d\n", __FUNCTION__, pciIf); + } + + return 0; + +} + +/******************************************************************************* +* mvPciIfTypeGet - +* +* DESCRIPTION: +* +* INPUT: +* +* OUTPUT: +* None. +* +* RETURN: +* +*******************************************************************************/ + +PCI_IF_TYPE mvPciIfTypeGet(MV_U32 pciIf) +{ + + if ((pciIf >= MV_PCI_START_IF)&&(pciIf < MV_PCI_MAX_IF + MV_PCI_START_IF)) + { + return PCI_IF_TYPE_CONVEN_PCIX; + } + else if ((pciIf >= MV_PEX_START_IF) && + (pciIf < MV_PEX_MAX_IF + MV_PEX_START_IF)) + { + return PCI_IF_TYPE_PEX; + + } + else + { + mvOsPrintf("%s: ERROR!!! Invalid pciIf %d\n", __FUNCTION__, pciIf); + } + + return 0xffffffff; + +} + +/******************************************************************************* +* mvPciIfTypeGet - +* +* DESCRIPTION: +* +* INPUT: +* +* OUTPUT: +* None. +* +* RETURN: +* +*******************************************************************************/ + +MV_U32 mvPciRealIfNumGet(MV_U32 pciIf) +{ + + PCI_IF_TYPE pciIfType = mvPciIfTypeGet(pciIf); + + if (PCI_IF_TYPE_CONVEN_PCIX == pciIfType) + { + return (pciIf - MV_PCI_START_IF); + } + else if (PCI_IF_TYPE_PEX == pciIfType) + { + return (pciIf - MV_PEX_START_IF); + + } + else + { + mvOsPrintf("%s: ERROR!!! Invalid pciIf %d\n", __FUNCTION__, pciIf); + } + + return 0xffffffff; + +} + + + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/pci-if/mvPciIf.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/pci-if/mvPciIf.h new file mode 100644 index 0000000..9c2d160 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/pci-if/mvPciIf.h @@ -0,0 +1,134 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#ifndef __INCPCIIFH +#define __INCPCIIFH + +#include "mvSysHwConfig.h" +#include "pci-if/mvPciIfRegs.h" +#if defined(MV_INCLUDE_PEX) +#include "pex/mvPex.h" +#endif +#if defined(MV_INCLUDE_PCI) +#include "pci/mvPci.h" +#endif +#include "ctrlEnv/mvCtrlEnvLib.h" +#include "ctrlEnv/mvCtrlEnvAddrDec.h" + +typedef enum _mvPCIIfType +{ + PCI_IF_TYPE_CONVEN_PCIX, + PCI_IF_TYPE_PEX + +}PCI_IF_TYPE; + +typedef enum _mvPCIIfMode +{ + PCI_IF_MODE_HOST, + PCI_IF_MODE_DEVICE +}PCI_IF_MODE; + + +/* Global Functions prototypes */ + +/* mvPciIfInit - Initialize PCI interfaces*/ +MV_STATUS mvPciIfInit(MV_U32 pciIf, PCI_IF_MODE pciIfmode); + +/* mvPciIfConfigRead - Read from configuration space */ +MV_U32 mvPciIfConfigRead (MV_U32 pciIf, MV_U32 bus, MV_U32 dev, + MV_U32 func,MV_U32 regOff); + +/* mvPciIfConfigWrite - Write to configuration space */ +MV_STATUS mvPciIfConfigWrite(MV_U32 pciIf, MV_U32 bus, MV_U32 dev, + MV_U32 func, MV_U32 regOff, MV_U32 data); + +/* mvPciIfMasterEnable - Enable/disale PCI interface master transactions.*/ +MV_STATUS mvPciIfMasterEnable(MV_U32 pciIf, MV_BOOL enable); + +/* mvPciIfSlaveEnable - Enable/disale PCI interface slave transactions.*/ +MV_STATUS mvPciIfSlaveEnable(MV_U32 pciIf,MV_U32 bus, MV_U32 dev, + MV_BOOL enable); + +/* mvPciIfLocalBusNumSet - Set PCI interface local bus number.*/ +MV_STATUS mvPciIfLocalBusNumSet(MV_U32 pciIf, MV_U32 busNum); + +/* mvPciIfLocalBusNumGet - Get PCI interface local bus number.*/ +MV_U32 mvPciIfLocalBusNumGet(MV_U32 pciIf); + +/* mvPciIfLocalDevNumSet - Set PCI interface local device number.*/ +MV_STATUS mvPciIfLocalDevNumSet(MV_U32 pciIf, MV_U32 devNum); + +/* mvPciIfLocalDevNumGet - Get PCI interface local device number.*/ +MV_U32 mvPciIfLocalDevNumGet(MV_U32 pciIf); + +/* mvPciIfTypeGet - Get PCI If type*/ +PCI_IF_TYPE mvPciIfTypeGet(MV_U32 pciIf); + +MV_U32 mvPciRealIfNumGet(MV_U32 pciIf); + +/* mvPciIfAddrDecShow - Display address decode windows attributes */ +MV_VOID mvPciIfAddrDecShow(MV_VOID); + +#endif /* #ifndef __INCPCIIFH */ + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/pci-if/mvPciIfRegs.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/pci-if/mvPciIfRegs.h new file mode 100644 index 0000000..08d4d2d --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/pci-if/mvPciIfRegs.h @@ -0,0 +1,245 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#ifndef __INCPCIIFREGSH +#define __INCPCIIFREGSH + + +/* defines */ +#define MAX_PCI_DEVICES 32 +#define MAX_PCI_FUNCS 8 +#define MAX_PCI_BUSSES 128 + +/***************************************/ +/* PCI Configuration registers */ +/***************************************/ + +/*********************************************/ +/* PCI Configuration, Function 0, Registers */ +/*********************************************/ + + +/* Standard registers */ +#define PCI_DEVICE_AND_VENDOR_ID 0x000 +#define PCI_STATUS_AND_COMMAND 0x004 +#define PCI_CLASS_CODE_AND_REVISION_ID 0x008 +#define PCI_BIST_HDR_TYPE_LAT_TMR_CACHE_LINE 0x00C +#define PCI_MEMORY_BAR_BASE_ADDR(barNum) (0x010 + ((barNum) << 2)) +#define PCI_SUBSYS_ID_AND_SUBSYS_VENDOR_ID 0x02C +#define PCI_EXPANSION_ROM_BASE_ADDR_REG 0x030 +#define PCI_CAPABILTY_LIST_POINTER 0x034 +#define PCI_INTERRUPT_PIN_AND_LINE 0x03C + + +/* PCI Device and Vendor ID Register (PDVIR) */ +#define PDVIR_VEN_ID_OFFS 0 /* Vendor ID */ +#define PDVIR_VEN_ID_MASK (0xffff << PDVIR_VEN_ID_OFFS) + +#define PDVIR_DEV_ID_OFFS 16 /* Device ID */ +#define PDVIR_DEV_ID_MASK (0xffff << PDVIR_DEV_ID_OFFS) + +/* PCI Status and Command Register (PSCR) */ +#define PSCR_IO_EN BIT0 /* IO Enable */ +#define PSCR_MEM_EN BIT1 /* Memory Enable */ +#define PSCR_MASTER_EN BIT2 /* Master Enable */ +#define PSCR_SPECIAL_EN BIT3 /* Special Cycle Enable */ +#define PSCR_MEM_WRI_INV BIT4 /* Memory Write and Invalidate Enable */ +#define PSCR_VGA BIT5 /* VGA Palette Snoops */ +#define PSCR_PERR_EN BIT6 /* Parity Errors Respond Enable */ +#define PSCR_ADDR_STEP BIT7 /* Address Stepping Enable (Wait Cycle En)*/ +#define PSCR_SERR_EN BIT8 /* Ability to assert SERR# line */ +#define PSCR_FAST_BTB_EN BIT9 /* generate fast back-to-back transactions*/ +#define PSCR_CAP_LIST BIT20 /* Capability List Support */ +#define PSCR_66MHZ_EN BIT21 /* 66 MHz Capable */ +#define PSCR_UDF_EN BIT22 /* User definable features */ +#define PSCR_TAR_FAST_BB BIT23 /* fast back-to-back transactions capable */ +#define PSCR_DATA_PERR BIT24 /* Data Parity reported */ + +#define PSCR_DEVSEL_TIM_OFFS 25 /* DEVSEL timing */ +#define PSCR_DEVSEL_TIM_MASK (0x3 << PSCR_DEVSEL_TIM_OFFS) +#define PSCR_DEVSEL_TIM_FAST (0x0 << PSCR_DEVSEL_TIM_OFFS) +#define PSCR_DEVSEL_TIM_MED (0x1 << PSCR_DEVSEL_TIM_OFFS) +#define PSCR_DEVSEL_TIM_SLOW (0x2 << PSCR_DEVSEL_TIM_OFFS) + +#define PSCR_SLAVE_TABORT BIT27 /* Signalled Target Abort */ +#define PSCR_MASTER_TABORT BIT28 /* Recieved Target Abort */ +#define PSCR_MABORT BIT29 /* Recieved Master Abort */ +#define PSCR_SYSERR BIT30 /* Signalled system error */ +#define PSCR_DET_PARERR BIT31 /* Detect Parity Error */ + +/* PCI configuration register offset=0x08 fields + (PCI_CLASS_CODE_AND_REVISION_ID)(PCCRI) */ + +#define PCCRIR_REVID_OFFS 0 /* Revision ID */ +#define PCCRIR_REVID_MASK (0xff << PCCRIR_REVID_OFFS) + +#define PCCRIR_FULL_CLASS_OFFS 8 /* Full Class Code */ +#define PCCRIR_FULL_CLASS_MASK (0xffffff << PCCRIR_FULL_CLASS_OFFS) + +#define PCCRIR_PROGIF_OFFS 8 /* Prog .I/F*/ +#define PCCRIR_PROGIF_MASK (0xff << PCCRIR_PROGIF_OFFS) + +#define PCCRIR_SUB_CLASS_OFFS 16 /* Sub Class*/ +#define PCCRIR_SUB_CLASS_MASK (0xff << PCCRIR_SUB_CLASS_OFFS) + +#define PCCRIR_BASE_CLASS_OFFS 24 /* Base Class*/ +#define PCCRIR_BASE_CLASS_MASK (0xff << PCCRIR_BASE_CLASS_OFFS) + +/* PCI configuration register offset=0x0C fields + (PCI_BIST_HEADER_TYPE_LATENCY_TIMER_CACHE_LINE)(PBHTLTCL) */ + +#define PBHTLTCLR_CACHELINE_OFFS 0 /* Specifies the cache line size */ +#define PBHTLTCLR_CACHELINE_MASK (0xff << PBHTLTCLR_CACHELINE_OFFS) + +#define PBHTLTCLR_LATTIMER_OFFS 8 /* latency timer */ +#define PBHTLTCLR_LATTIMER_MASK (0xff << PBHTLTCLR_LATTIMER_OFFS) + +#define PBHTLTCLR_HEADTYPE_FULL_OFFS 16 /* Full Header Type */ +#define PBHTLTCLR_HEADTYPE_FULL_MASK (0xff << PBHTLTCLR_HEADTYPE_FULL_OFFS) + +#define PBHTLTCLR_MULTI_FUNC BIT23 /* Multi/Single function */ + +#define PBHTLTCLR_HEADER_OFFS 16 /* Header type */ +#define PBHTLTCLR_HEADER_MASK (0x7f << PBHTLTCLR_HEADER_OFFS) +#define PBHTLTCLR_HEADER_STANDARD (0x0 << PBHTLTCLR_HEADER_OFFS) +#define PBHTLTCLR_HEADER_PCI2PCI_BRIDGE (0x1 << PBHTLTCLR_HEADER_OFFS) + + +#define PBHTLTCLR_BISTCOMP_OFFS 24 /* BIST Completion Code */ +#define PBHTLTCLR_BISTCOMP_MASK (0xf << PBHTLTCLR_BISTCOMP_OFFS) + +#define PBHTLTCLR_BISTACT BIT30 /* BIST Activate bit */ +#define PBHTLTCLR_BISTCAP BIT31 /* BIST Capable Bit */ + + +/* PCI Bar Base Low Register (PBBLR) */ +#define PBBLR_IOSPACE BIT0 /* Memory Space Indicator */ + +#define PBBLR_TYPE_OFFS 1 /* BAR Type/Init Val. */ +#define PBBLR_TYPE_MASK (0x3 << PBBLR_TYPE_OFFS) +#define PBBLR_TYPE_32BIT_ADDR (0x0 << PBBLR_TYPE_OFFS) +#define PBBLR_TYPE_64BIT_ADDR (0x2 << PBBLR_TYPE_OFFS) + +#define PBBLR_PREFETCH_EN BIT3 /* Prefetch Enable */ + + +#define PBBLR_MEM_BASE_OFFS 4 /* Memory Bar Base address. Corresponds to + address bits [31:4] */ +#define PBBLR_MEM_BASE_MASK (0xfffffff << PBBLR_MEM_BASE_OFFS) + +#define PBBLR_IO_BASE_OFFS 2 /* IO Bar Base address. Corresponds to + address bits [31:2] */ +#define PBBLR_IO_BASE_MASK (0x3fffffff << PBBLR_IO_BASE_OFFS) + + +#define PBBLR_BASE_OFFS 12 /* Base address. Address bits [31:12] */ +#define PBBLR_BASE_MASK (0xfffff << PBBLR_BASE_OFFS) +#define PBBLR_BASE_ALIGNMET (1 << PBBLR_BASE_OFFS) + + +/* PCI Bar Base High Fegister (PBBHR) */ +#define PBBHR_BASE_OFFS 0 /* Base address. Address bits [31:12] */ +#define PBBHR_BASE_MASK (0xffffffff << PBBHR_BASE_OFFS) + + +/* PCI configuration register offset=0x2C fields + (PCI_SUBSYSTEM_ID_AND_SUBSYSTEM_VENDOR_ID)(PSISVI) */ + +#define PSISVIR_VENID_OFFS 0 /* Subsystem Manufacturer Vendor ID Number */ +#define PSISVIR_VENID_MASK (0xffff << PSISVIR_VENID_OFFS) + +#define PSISVIR_DEVID_OFFS 16 /* Subsystem Device ID Number */ +#define PSISVIR_DEVID_MASK (0xffff << PSISVIR_DEVID_OFFS) + +/* PCI configuration register offset=0x30 fields + (PCI_EXPANSION_ROM_BASE_ADDR_REG)(PERBA) */ + +#define PERBAR_EXPROMEN BIT0 /* Expansion ROM Enable */ + +#define PERBAR_BASE_OFFS 12 /* Expansion ROM Base Address */ +#define PERBAR_BASE_MASK (0xfffff << PERBAR_BASE_OFFS) + +/* PCI configuration register offset=0x34 fields + (PCI_CAPABILTY_LIST_POINTER)(PCLP) */ + +#define PCLPR_CAPPTR_OFFS 0 /* Capability List Pointer */ +#define PCLPR_CAPPTR_MASK (0xff << PCLPR_CAPPTR_OFFS) + +/* PCI configuration register offset=0x3C fields + (PCI_INTERRUPT_PIN_AND_LINE)(PIPL) */ + +#define PIPLR_INTLINE_OFFS 0 /* Interrupt line (IRQ) */ +#define PIPLR_INTLINE_MASK (0xff << PIPLR_INTLINE_OFFS) + +#define PIPLR_INTPIN_OFFS 8 /* interrupt pin (A,B,C,D) */ +#define PIPLR_INTPIN_MASK (0xff << PIPLR_INTPIN_OFFS) + +#define PIPLR_MINGRANT_OFFS 16 /* Minimum Grant on 250 nano seconds units */ +#define PIPLR_MINGRANT_MASK (0xff << PIPLR_MINGRANT_OFFS) + +#define PIPLR_MAXLATEN_OFFS 24 /* Maximum latency on 250 nano seconds units */ +#define PIPLR_MAXLATEN_MASK (0xff << PIPLR_MAXLATEN_OFFS) + +#endif /* #ifndef __INCPCIIFREGSH */ + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/pci-if/pci_util/mvPciUtils.c b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/pci-if/pci_util/mvPciUtils.c new file mode 100644 index 0000000..f216979 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/pci-if/pci_util/mvPciUtils.c @@ -0,0 +1,1006 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +/* includes */ +#include "mvPciUtils.h" + +#include "ctrlEnv/mvCtrlEnvLib.h" + +/* #define MV_DEBUG */ +/* defines */ +#ifdef MV_DEBUG + #define DB(x) x + #define mvOsPrintf printf +#else + #define DB(x) +#endif + +/* +This module only support scanning of Header type 00h of pci devices +There is no suppotr for Header type 01h of pci devices ( PCI bridges ) +*/ + + +static MV_STATUS pciDetectDevice(MV_U32 pciIf, + MV_U32 bus, + MV_U32 dev, + MV_U32 func, + MV_PCI_DEVICE *pPciAgent); + +static MV_U32 pciDetectDeviceBars(MV_U32 pciIf, + MV_U32 bus, + MV_U32 dev, + MV_U32 func, + MV_PCI_DEVICE *pPciAgent); + + + + + + +/******************************************************************************* +* mvPciScan - Scan a PCI interface bus +* +* DESCRIPTION: +* Performs a full scan on a PCI interface and returns all possible details +* on the agents found on the bus. +* +* INPUT: +* pciIf - PCI Interface +* pPciAgents - Pointer to an Array of the pci agents to be detected +* pPciAgentsNum - pPciAgents array maximum number of elements +* +* OUTPUT: +* pPciAgents - Array of the pci agents detected on the bus +* pPciAgentsNum - Number of pci agents detected on the bus +* +* RETURN: +* MV_BAD_PARAM for bad parameters ,MV_ERROR on error ! otherwise MV_OK +* +*******************************************************************************/ + +MV_STATUS mvPciScan(MV_U32 pciIf, + MV_PCI_DEVICE *pPciAgents, + MV_U32 *pPciAgentsNum) +{ + + MV_U32 devIndex,funcIndex=0,busIndex=0,detectedDevNum=0; + MV_U32 localBus=mvPciIfLocalBusNumGet(pciIf); + MV_PCI_DEVICE *pPciDevice; + MV_PCI_DEVICE *pMainDevice; + + DB(mvOsPrintf("mvPciScan: PCI interface num %d\n", pciIf)); + /* Parameter checking */ + if (pciIf >= mvCtrlPexMaxIfGet()) + { + DB(mvOsPrintf("mvPciScan: ERR. Invalid PCI interface num %d\n", pciIf)); + return MV_BAD_PARAM; + } + if (NULL == pPciAgents) + { + DB(mvOsPrintf("mvPciScan: ERR. pPciAgents=NULL \n")); + return MV_BAD_PARAM; + } + if (NULL == pPciAgentsNum) + { + DB(mvOsPrintf("mvPciScan: ERR. pPciAgentsNum=NULL \n")); + return MV_BAD_PARAM; + } + + + DB(mvOsPrintf("mvPciScan: PCI interface num %d mvPciMasterEnable\n", pciIf)); + /* Master enable the MV PCI master */ + if (MV_OK != mvPciIfMasterEnable(pciIf,MV_TRUE)) + { + DB(mvOsPrintf("mvPciScan: ERR. mvPciMasterEnable failed \n")); + return MV_ERROR; + + } + + DB(mvOsPrintf("mvPciScan: PCI interface num scan%d\n", pciIf)); + + /* go through all busses */ + for (busIndex=localBus ; busIndex < MAX_PCI_BUSSES ; busIndex++) + { + /* go through all possible devices on the local bus */ + for (devIndex=0 ; devIndex < MAX_PCI_DEVICES ; devIndex++) + { + /* always start with function equal to zero */ + funcIndex=0; + + pPciDevice=&pPciAgents[detectedDevNum]; + DB(mvOsPrintf("mvPciScan: PCI interface num scan%d:%d\n", busIndex, devIndex)); + + if (MV_ERROR == pciDetectDevice(pciIf, + busIndex, + devIndex, + funcIndex, + pPciDevice)) + { + /* no device detected , try the next address */ + continue; + } + + /* We are here ! means we have detected a device*/ + /* always we start with only one function per device */ + pMainDevice = pPciDevice; + pPciDevice->funtionsNum = 1; + + + /* move on */ + detectedDevNum++; + + + /* check if we have no more room for a new device */ + if (detectedDevNum == *pPciAgentsNum) + { + DB(mvOsPrintf("mvPciScan: ERR. array passed too small \n")); + return MV_ERROR; + } + + /* check the detected device if it is a multi functional device then + scan all device functions*/ + if (pPciDevice->isMultiFunction == MV_TRUE) + { + /* start with function number 1 because we have already detected + function 0 */ + for (funcIndex=1; funcIndexfuntionsNum++; + detectedDevNum++; + + /* check if we have no more room for a new device */ + if (detectedDevNum == *pPciAgentsNum) + { + DB(mvOsPrintf("mvPciScan: ERR. Array too small\n")); + return MV_ERROR; + } + + + } + } + + } + + } + + /* return the number of devices actually detected on the bus ! */ + *pPciAgentsNum = detectedDevNum; + + return MV_OK; + +} + + +/******************************************************************************* +* pciDetectDevice - Detect a pci device parameters +* +* DESCRIPTION: +* This function detect if a pci agent exist on certain address ! +* and if exists then it fills all possible information on the +* agent +* +* INPUT: +* pciIf - PCI Interface +* bus - Bus number +* dev - Device number +* func - Function number +* +* +* +* OUTPUT: +* pPciAgent - pointer to the pci agent filled with its information +* +* RETURN: +* MV_ERROR if no device , MV_OK otherwise +* +*******************************************************************************/ + +static MV_STATUS pciDetectDevice(MV_U32 pciIf, + MV_U32 bus, + MV_U32 dev, + MV_U32 func, + MV_PCI_DEVICE *pPciAgent) +{ + MV_U32 pciData; + + /* no Parameters checking ! because it is static function and it is assumed + that all parameters were checked in the calling function */ + + + /* Try read the PCI Vendor ID and Device ID */ + + /* We will scan only ourselves and the PCI slots that exist on the + board, because we may have a case that we have one slot that has + a Cardbus connector, and because CardBus answers all IDsels we want + to scan only this slot and ourseleves. + + */ + #if defined(MV_INCLUDE_PCI) + if ((PCI_IF_TYPE_CONVEN_PCIX == mvPciIfTypeGet(pciIf)) && + (DB_88F5181_DDR1_PRPMC != mvBoardIdGet()) && + (DB_88F5181_DDR1_PEXPCI != mvBoardIdGet()) && + (DB_88F5181_DDR1_MNG != mvBoardIdGet())) + { + + if (mvBoardIsOurPciSlot(bus, dev) == MV_FALSE) + { + return MV_ERROR; + } + } + #endif /* defined(MV_INCLUDE_PCI) */ + + pciData = mvPciIfConfigRead(pciIf, bus,dev,func, PCI_DEVICE_AND_VENDOR_ID); + + if (PCI_ERROR_CODE == pciData) + { + /* no device exist */ + return MV_ERROR; + } + + /* we are here ! means a device is detected */ + + /* fill basic information */ + pPciAgent->busNumber=bus; + pPciAgent->deviceNum=dev; + pPciAgent->function=func; + + /* Fill the PCI Vendor ID and Device ID */ + + pPciAgent->venID = (pciData & PDVIR_VEN_ID_MASK) >> PDVIR_VEN_ID_OFFS; + pPciAgent->deviceID = (pciData & PDVIR_DEV_ID_MASK) >> PDVIR_DEV_ID_OFFS; + + /* Read Status and command */ + pciData = mvPciIfConfigRead(pciIf, + bus,dev,func, + PCI_STATUS_AND_COMMAND); + + + /* Fill related Status and Command information*/ + + if (pciData & PSCR_TAR_FAST_BB) + { + pPciAgent->isFastB2BCapable = MV_TRUE; + } + else + { + pPciAgent->isFastB2BCapable = MV_FALSE; + } + + if (pciData & PSCR_CAP_LIST) + { + pPciAgent->isCapListSupport=MV_TRUE; + } + else + { + pPciAgent->isCapListSupport=MV_FALSE; + } + + if (pciData & PSCR_66MHZ_EN) + { + pPciAgent->is66MHZCapable=MV_TRUE; + } + else + { + pPciAgent->is66MHZCapable=MV_FALSE; + } + + /* Read Class Code and Revision */ + pciData = mvPciIfConfigRead(pciIf, + bus,dev,func, + PCI_CLASS_CODE_AND_REVISION_ID); + + + pPciAgent->baseClassCode = + (pciData & PCCRIR_BASE_CLASS_MASK) >> PCCRIR_BASE_CLASS_OFFS; + + pPciAgent->subClassCode = + (pciData & PCCRIR_SUB_CLASS_MASK) >> PCCRIR_SUB_CLASS_OFFS; + + pPciAgent->progIf = + (pciData & PCCRIR_PROGIF_MASK) >> PCCRIR_PROGIF_OFFS; + + pPciAgent->revisionID = + (pciData & PCCRIR_REVID_MASK) >> PCCRIR_REVID_OFFS; + + /* Read PCI_BIST_HDR_TYPE_LAT_TMR_CACHE_LINE */ + pciData = mvPciIfConfigRead(pciIf, + bus,dev,func, + PCI_BIST_HDR_TYPE_LAT_TMR_CACHE_LINE); + + + + pPciAgent->pciCacheLine= + (pciData & PBHTLTCLR_CACHELINE_MASK ) >> PBHTLTCLR_CACHELINE_OFFS; + pPciAgent->pciLatencyTimer= + (pciData & PBHTLTCLR_LATTIMER_MASK) >> PBHTLTCLR_LATTIMER_OFFS; + + switch (pciData & PBHTLTCLR_HEADER_MASK) + { + case PBHTLTCLR_HEADER_STANDARD: + + pPciAgent->pciHeader=MV_PCI_STANDARD; + break; + case PBHTLTCLR_HEADER_PCI2PCI_BRIDGE: + + pPciAgent->pciHeader=MV_PCI_PCI2PCI_BRIDGE; + break; + + } + + if (pciData & PBHTLTCLR_MULTI_FUNC) + { + pPciAgent->isMultiFunction=MV_TRUE; + } + else + { + pPciAgent->isMultiFunction=MV_FALSE; + } + + if (pciData & PBHTLTCLR_BISTCAP) + { + pPciAgent->isBISTCapable=MV_TRUE; + } + else + { + pPciAgent->isBISTCapable=MV_FALSE; + } + + + /* read this device pci bars */ + + pciDetectDeviceBars(pciIf, + bus,dev,func, + pPciAgent); + + + /* check if we are bridge*/ + if ((pPciAgent->baseClassCode == PCI_BRIDGE_CLASS)&& + (pPciAgent->subClassCode == P2P_BRIDGE_SUB_CLASS_CODE)) + { + + /* Read P2P_BUSSES_NUM */ + pciData = mvPciIfConfigRead(pciIf, + bus,dev,func, + P2P_BUSSES_NUM); + + pPciAgent->p2pPrimBusNum = + (pciData & PBM_PRIME_BUS_NUM_MASK) >> PBM_PRIME_BUS_NUM_OFFS; + + pPciAgent->p2pSecBusNum = + (pciData & PBM_SEC_BUS_NUM_MASK) >> PBM_SEC_BUS_NUM_OFFS; + + pPciAgent->p2pSubBusNum = + (pciData & PBM_SUB_BUS_NUM_MASK) >> PBM_SUB_BUS_NUM_OFFS; + + pPciAgent->p2pSecLatencyTimer = + (pciData & PBM_SEC_LAT_TMR_MASK) >> PBM_SEC_LAT_TMR_OFFS; + + /* Read P2P_IO_BASE_LIMIT_SEC_STATUS */ + pciData = mvPciIfConfigRead(pciIf, + bus,dev,func, + P2P_IO_BASE_LIMIT_SEC_STATUS); + + pPciAgent->p2pSecStatus = + (pciData & PIBLSS_SEC_STATUS_MASK) >> PIBLSS_SEC_STATUS_OFFS; + + + pPciAgent->p2pIObase = + (pciData & PIBLSS_IO_BASE_MASK) << PIBLSS_IO_LIMIT_OFFS; + + /* clear low address (should be zero)*/ + pPciAgent->p2pIObase &= PIBLSS_HIGH_ADDR_MASK; + + pPciAgent->p2pIOLimit = + (pciData & PIBLSS_IO_LIMIT_MASK); + + /* fill low address with 0xfff */ + pPciAgent->p2pIOLimit |= PIBLSS_LOW_ADDR_MASK; + + + switch ((pciData & PIBLSS_ADD_CAP_MASK) >> PIBLSS_ADD_CAP_OFFS) + { + case PIBLSS_ADD_CAP_16BIT: + + pPciAgent->bIO32 = MV_FALSE; + + break; + case PIBLSS_ADD_CAP_32BIT: + + pPciAgent->bIO32 = MV_TRUE; + + /* Read P2P_IO_BASE_LIMIT_UPPER_16 */ + pciData = mvPciIfConfigRead(pciIf, + bus,dev,func, + P2P_IO_BASE_LIMIT_UPPER_16); + + pPciAgent->p2pIObase |= + (pciData & PRBU_IO_UPP_BASE_MASK) << PRBU_IO_UPP_LIMIT_OFFS; + + + pPciAgent->p2pIOLimit |= + (pciData & PRBU_IO_UPP_LIMIT_MASK); + + break; + + } + + + /* Read P2P_MEM_BASE_LIMIT */ + pciData = mvPciIfConfigRead(pciIf, + bus,dev,func, + P2P_MEM_BASE_LIMIT); + + pPciAgent->p2pMemBase = + (pciData & PMBL_MEM_BASE_MASK) << PMBL_MEM_LIMIT_OFFS; + + /* clear low address */ + pPciAgent->p2pMemBase &= PMBL_HIGH_ADDR_MASK; + + pPciAgent->p2pMemLimit = + (pciData & PMBL_MEM_LIMIT_MASK); + + /* add 0xfffff */ + pPciAgent->p2pMemLimit |= PMBL_LOW_ADDR_MASK; + + + /* Read P2P_PREF_MEM_BASE_LIMIT */ + pciData = mvPciIfConfigRead(pciIf, + bus,dev,func, + P2P_PREF_MEM_BASE_LIMIT); + + + pPciAgent->p2pPrefMemBase = + (pciData & PRMBL_PREF_MEM_BASE_MASK) << PRMBL_PREF_MEM_LIMIT_OFFS; + + /* get high address only */ + pPciAgent->p2pPrefMemBase &= PRMBL_HIGH_ADDR_MASK; + + + + pPciAgent->p2pPrefMemLimit = + (pciData & PRMBL_PREF_MEM_LIMIT_MASK); + + /* add 0xfffff */ + pPciAgent->p2pPrefMemLimit |= PRMBL_LOW_ADDR_MASK; + + switch (pciData & PRMBL_ADD_CAP_MASK) + { + case PRMBL_ADD_CAP_32BIT: + + pPciAgent->bPrefMem64 = MV_FALSE; + + /* Read P2P_PREF_BASE_UPPER_32 */ + pPciAgent->p2pPrefBaseUpper32Bits = 0; + + /* Read P2P_PREF_LIMIT_UPPER_32 */ + pPciAgent->p2pPrefLimitUpper32Bits = 0; + + break; + case PRMBL_ADD_CAP_64BIT: + + pPciAgent->bPrefMem64 = MV_TRUE; + + /* Read P2P_PREF_BASE_UPPER_32 */ + pPciAgent->p2pPrefBaseUpper32Bits = mvPciIfConfigRead(pciIf, + bus,dev,func, + P2P_PREF_BASE_UPPER_32); + + /* Read P2P_PREF_LIMIT_UPPER_32 */ + pPciAgent->p2pPrefLimitUpper32Bits = mvPciIfConfigRead(pciIf, + bus,dev,func, + P2P_PREF_LIMIT_UPPER_32); + + break; + + } + + } + else /* no bridge */ + { + /* Read PCI_SUBSYS_ID_AND_SUBSYS_VENDOR_ID */ + pciData = mvPciIfConfigRead(pciIf, + bus,dev,func, + PCI_SUBSYS_ID_AND_SUBSYS_VENDOR_ID); + + + pPciAgent->subSysVenID = + (pciData & PSISVIR_VENID_MASK) >> PSISVIR_VENID_OFFS; + pPciAgent->subSysID = + (pciData & PSISVIR_DEVID_MASK) >> PSISVIR_DEVID_OFFS; + + + /* Read PCI_EXPANSION_ROM_BASE_ADDR_REG */ + pciData = mvPciIfConfigRead(pciIf, + bus,dev,func, + PCI_EXPANSION_ROM_BASE_ADDR_REG); + + + if (pciData & PERBAR_EXPROMEN) + { + pPciAgent->isExpRom = MV_TRUE; + } + else + { + pPciAgent->isExpRom = MV_FALSE; + } + + pPciAgent->expRomAddr = + (pciData & PERBAR_BASE_MASK) >> PERBAR_BASE_OFFS; + + } + + + if (MV_TRUE == pPciAgent->isCapListSupport) + { + /* Read PCI_CAPABILTY_LIST_POINTER */ + pciData = mvPciIfConfigRead(pciIf, + bus,dev,func, + PCI_CAPABILTY_LIST_POINTER); + + pPciAgent->capListPointer = + (pciData & PCLPR_CAPPTR_MASK) >> PCLPR_CAPPTR_OFFS; + + } + + /* Read PCI_INTERRUPT_PIN_AND_LINE */ + pciData = mvPciIfConfigRead(pciIf, + bus,dev,func, + PCI_INTERRUPT_PIN_AND_LINE); + + + pPciAgent->irqLine= + (pciData & PIPLR_INTLINE_MASK) >> PIPLR_INTLINE_OFFS; + + pPciAgent->intPin= + (MV_PCI_INT_PIN)(pciData & PIPLR_INTPIN_MASK) >> PIPLR_INTPIN_OFFS; + + pPciAgent->minGrant= + (pciData & PIPLR_MINGRANT_MASK) >> PIPLR_MINGRANT_OFFS; + pPciAgent->maxLatency= + (pciData & PIPLR_MAXLATEN_MASK) >> PIPLR_MAXLATEN_OFFS; + + mvPciClassNameGet(pPciAgent->baseClassCode, + (MV_8 *)pPciAgent->type); + + return MV_OK; + + +} + +/******************************************************************************* +* pciDetectDeviceBars - Detect a pci device bars +* +* DESCRIPTION: +* This function detects all pci agent bars +* +* INPUT: +* pciIf - PCI Interface +* bus - Bus number +* dev - Device number +* func - Function number +* +* +* +* OUTPUT: +* pPciAgent - pointer to the pci agent filled with its information +* +* RETURN: +* detected bars number +* +*******************************************************************************/ +static MV_U32 pciDetectDeviceBars(MV_U32 pciIf, + MV_U32 bus, + MV_U32 dev, + MV_U32 func, + MV_PCI_DEVICE *pPciAgent) +{ + MV_U32 pciData,barIndex,detectedBar=0; + MV_U32 tmpBaseHigh=0,tmpBaseLow=0; + MV_U32 pciMaxBars=0; + + pPciAgent->barsNum=0; + + /* check if we are bridge*/ + if ((pPciAgent->baseClassCode == PCI_BRIDGE_CLASS)&& + (pPciAgent->subClassCode == P2P_BRIDGE_SUB_CLASS_CODE)) + { + pciMaxBars = 2; + } + else /* no bridge */ + { + pciMaxBars = 6; + } + + /* read this device pci bars */ + for (barIndex = 0 ; barIndex < pciMaxBars ; barIndex++ ) + { + /* Read PCI_MEMORY_BAR_BASE_ADDR */ + tmpBaseLow = pciData = mvPciIfConfigRead(pciIf, + bus,dev,func, + PCI_MEMORY_BAR_BASE_ADDR(barIndex)); + + pPciAgent->pciBar[detectedBar].barOffset = + PCI_MEMORY_BAR_BASE_ADDR(barIndex); + + /* check if the bar is 32bit or 64bit bar */ + switch (pciData & PBBLR_TYPE_MASK) + { + case PBBLR_TYPE_32BIT_ADDR: + pPciAgent->pciBar[detectedBar].barType = PCI_32BIT_BAR; + break; + case PBBLR_TYPE_64BIT_ADDR: + pPciAgent->pciBar[detectedBar].barType = PCI_64BIT_BAR; + break; + + } + + /* check if it is memory or IO bar */ + if (pciData & PBBLR_IOSPACE) + { + pPciAgent->pciBar[detectedBar].barMapping=PCI_IO_BAR; + } + else + { + pPciAgent->pciBar[detectedBar].barMapping=PCI_MEMORY_BAR; + } + + /* if it is memory bar then check if it is prefetchable */ + if (PCI_MEMORY_BAR == pPciAgent->pciBar[detectedBar].barMapping) + { + if (pciData & PBBLR_PREFETCH_EN) + { + pPciAgent->pciBar[detectedBar].isPrefetchable = MV_TRUE; + } + else + { + pPciAgent->pciBar[detectedBar].isPrefetchable = MV_FALSE; + } + + pPciAgent->pciBar[detectedBar].barBaseLow = + pciData & PBBLR_MEM_BASE_MASK; + + + } + else /* IO Bar */ + { + pPciAgent->pciBar[detectedBar].barBaseLow = + pciData & PBBLR_IO_BASE_MASK; + + } + + pPciAgent->pciBar[detectedBar].barBaseHigh=0; + + if (PCI_64BIT_BAR == pPciAgent->pciBar[detectedBar].barType) + { + barIndex++; + + tmpBaseHigh = pPciAgent->pciBar[detectedBar].barBaseHigh = + mvPciIfConfigRead(pciIf, + bus,dev,func, + PCI_MEMORY_BAR_BASE_ADDR(barIndex)); + + + } + + /* calculating full base address (64bit) */ + pPciAgent->pciBar[detectedBar].barBaseAddr = + (MV_U64)pPciAgent->pciBar[detectedBar].barBaseHigh; + + pPciAgent->pciBar[detectedBar].barBaseAddr <<= 32; + + pPciAgent->pciBar[detectedBar].barBaseAddr |= + (MV_U64)pPciAgent->pciBar[detectedBar].barBaseLow; + + + + /* get the sizes of the the bar */ + + pPciAgent->pciBar[detectedBar].barSizeHigh=0; + + if ((PCI_64BIT_BAR == pPciAgent->pciBar[detectedBar].barType) && + (PCI_MEMORY_BAR == pPciAgent->pciBar[detectedBar].barMapping)) + + { + /* write oxffffffff to the bar to get the size */ + /* start with sizelow ( original value was saved in tmpBaseLow ) */ + mvPciIfConfigWrite(pciIf, + bus,dev,func, + PCI_MEMORY_BAR_BASE_ADDR(barIndex-1), + 0xffffffff); + + /* read size */ + pPciAgent->pciBar[detectedBar].barSizeLow = + mvPciIfConfigRead(pciIf, + bus,dev,func, + PCI_MEMORY_BAR_BASE_ADDR(barIndex-1)); + + + + /* restore original value */ + mvPciIfConfigWrite(pciIf, + bus,dev,func, + PCI_MEMORY_BAR_BASE_ADDR(barIndex-1), + tmpBaseLow); + + + /* now do the same for BaseHigh */ + + /* write oxffffffff to the bar to get the size */ + mvPciIfConfigWrite(pciIf, + bus,dev,func, + PCI_MEMORY_BAR_BASE_ADDR(barIndex), + 0xffffffff); + + /* read size */ + pPciAgent->pciBar[detectedBar].barSizeHigh = + mvPciIfConfigRead(pciIf, + bus,dev,func, + PCI_MEMORY_BAR_BASE_ADDR(barIndex)); + + /* restore original value */ + mvPciIfConfigWrite(pciIf, + bus,dev,func, + PCI_MEMORY_BAR_BASE_ADDR(barIndex), + tmpBaseHigh); + + if ((0 == pPciAgent->pciBar[detectedBar].barSizeLow)&& + (0 == pPciAgent->pciBar[detectedBar].barSizeHigh)) + { + /* this bar is not applicable for this device, + ignore all previous settings and check the next bar*/ + + /* we though this was a 64bit bar , and it seems this + was wrong ! so decrement barIndex */ + barIndex--; + continue; + } + + /* calculate the full 64 bit size */ + + if (0 != pPciAgent->pciBar[detectedBar].barSizeHigh) + { + pPciAgent->pciBar[detectedBar].barSizeLow &= PBBLR_MEM_BASE_MASK; + + pPciAgent->pciBar[detectedBar].barSizeLow = + ~pPciAgent->pciBar[detectedBar].barSizeLow + 1; + + pPciAgent->pciBar[detectedBar].barSizeHigh = 0; + + } + else + { + + pPciAgent->pciBar[detectedBar].barSizeLow &= PBBLR_MEM_BASE_MASK; + + pPciAgent->pciBar[detectedBar].barSizeLow = + ~pPciAgent->pciBar[detectedBar].barSizeLow + 1; + + pPciAgent->pciBar[detectedBar].barSizeHigh = 0; + + } + + + + } + else /* 32bit bar */ + { + /* write oxffffffff to the bar to get the size */ + mvPciIfConfigWrite(pciIf, + bus,dev,func, + PCI_MEMORY_BAR_BASE_ADDR(barIndex), + 0xffffffff); + + /* read size */ + pPciAgent->pciBar[detectedBar].barSizeLow = + mvPciIfConfigRead(pciIf, + bus,dev,func, + PCI_MEMORY_BAR_BASE_ADDR(barIndex)); + + if (0 == pPciAgent->pciBar[detectedBar].barSizeLow) + { + /* this bar is not applicable for this device, + ignore all previous settings and check the next bar*/ + continue; + } + + + /* restore original value */ + mvPciIfConfigWrite(pciIf, + bus,dev,func, + PCI_MEMORY_BAR_BASE_ADDR(barIndex), + tmpBaseLow); + + /* calculate size low */ + + if (PCI_MEMORY_BAR == pPciAgent->pciBar[detectedBar].barMapping) + { + pPciAgent->pciBar[detectedBar].barSizeLow &= PBBLR_MEM_BASE_MASK; + } + else + { + pPciAgent->pciBar[detectedBar].barSizeLow &= PBBLR_IO_BASE_MASK; + } + + pPciAgent->pciBar[detectedBar].barSizeLow = + ~pPciAgent->pciBar[detectedBar].barSizeLow + 1; + + pPciAgent->pciBar[detectedBar].barSizeHigh = 0; + pPciAgent->pciBar[detectedBar].barSize = + (MV_U64)pPciAgent->pciBar[detectedBar].barSizeLow; + + + } + + /* we are here ! this means we have already detected a bar for + this device , now move on */ + + detectedBar++; + pPciAgent->barsNum++; + } + + return detectedBar; +} + + +/******************************************************************************* +* mvPciClassNameGet - get PCI class name +* +* DESCRIPTION: +* This function returns the PCI class name +* +* INPUT: +* baseClassCode - Base Class Code. +* +* OUTPUT: +* pType - the class name +* +* RETURN: +* MV_BAD_PARAM for bad parameters ,MV_ERROR on error ! otherwise MV_OK +* +*******************************************************************************/ +MV_STATUS mvPciClassNameGet(MV_U32 baseClassCode, MV_8 *pType) +{ + + switch(baseClassCode) + { + case 0x0: + strcpy(pType,"Old generation device"); + break; + case 0x1: + strcpy(pType,"Mass storage controller"); + break; + case 0x2: + strcpy(pType,"Network controller"); + break; + case 0x3: + strcpy(pType,"Display controller"); + break; + case 0x4: + strcpy(pType,"Multimedia device"); + break; + case 0x5: + strcpy(pType,"Memory controller"); + break; + case 0x6: + strcpy(pType,"Bridge Device"); + break; + case 0x7: + strcpy(pType,"Simple Communication controllers"); + break; + case 0x8: + strcpy(pType,"Base system peripherals"); + break; + case 0x9: + strcpy(pType,"Input Devices"); + break; + case 0xa: + strcpy(pType,"Docking stations"); + break; + case 0xb: + strcpy(pType,"Processors"); + break; + case 0xc: + strcpy(pType,"Serial bus controllers"); + break; + case 0xd: + strcpy(pType,"Wireless controllers"); + break; + case 0xe: + strcpy(pType,"Intelligent I/O controllers"); + break; + case 0xf: + strcpy(pType,"Satellite communication controllers"); + break; + case 0x10: + strcpy(pType,"Encryption/Decryption controllers"); + break; + case 0x11: + strcpy(pType,"Data acquisition and signal processing controllers"); + break; + default: + strcpy(pType,"Unknown device"); + break; + } + + return MV_OK; + +} + + + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/pci-if/pci_util/mvPciUtils.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/pci-if/pci_util/mvPciUtils.h new file mode 100644 index 0000000..2ee0b17 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/pci-if/pci_util/mvPciUtils.h @@ -0,0 +1,323 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#ifndef __INCmvPciUtilsh +#define __INCmvPciUtilsh + +/* +This module only support scanning of Header type 00h of pci devices +There is no suppotr for Header type 01h of pci devices ( PCI bridges ) +*/ + +/* includes */ +#include "mvSysHwConfig.h" +#include "pci-if/mvPciIf.h" +#include "pci/mvPciRegs.h" + + + +/* PCI base address low bar mask */ +#define PCI_ERROR_CODE 0xffffffff + +#define PCI_BRIDGE_CLASS 0x6 +#define P2P_BRIDGE_SUB_CLASS_CODE 0x4 + + +#define P2P_BUSSES_NUM 0x18 +#define P2P_IO_BASE_LIMIT_SEC_STATUS 0x1C +#define P2P_MEM_BASE_LIMIT 0x20 +#define P2P_PREF_MEM_BASE_LIMIT 0x24 +#define P2P_PREF_BASE_UPPER_32 0x28 +#define P2P_PREF_LIMIT_UPPER_32 0x2C +#define P2P_IO_BASE_LIMIT_UPPER_16 0x30 +#define P2P_EXP_ROM 0x38 + +/* P2P_BUSSES_NUM (PBM) */ + +#define PBM_PRIME_BUS_NUM_OFFS 0 +#define PBM_PRIME_BUS_NUM_MASK (0xff << PBM_PRIME_BUS_NUM_OFFS) + +#define PBM_SEC_BUS_NUM_OFFS 8 +#define PBM_SEC_BUS_NUM_MASK (0xff << PBM_SEC_BUS_NUM_OFFS) + +#define PBM_SUB_BUS_NUM_OFFS 16 +#define PBM_SUB_BUS_NUM_MASK (0xff << PBM_SUB_BUS_NUM_OFFS) + +#define PBM_SEC_LAT_TMR_OFFS 24 +#define PBM_SEC_LAT_TMR_MASK (0xff << PBM_SEC_LAT_TMR_OFFS) + +/* P2P_IO_BASE_LIMIT_SEC_STATUS (PIBLSS) */ + +#define PIBLSS_IO_BASE_OFFS 0 +#define PIBLSS_IO_BASE_MASK (0xff << PIBLSS_IO_BASE_OFFS) + +#define PIBLSS_ADD_CAP_OFFS 0 +#define PIBLSS_ADD_CAP_MASK (0x3 << PIBLSS_ADD_CAP_OFFS) +#define PIBLSS_ADD_CAP_16BIT (0x0 << PIBLSS_ADD_CAP_OFFS) +#define PIBLSS_ADD_CAP_32BIT (0x1 << PIBLSS_ADD_CAP_OFFS) + +#define PIBLSS_LOW_ADDR_OFFS 0 +#define PIBLSS_LOW_ADDR_MASK (0xFFF << PIBLSS_LOW_ADDR_OFFS) + +#define PIBLSS_HIGH_ADDR_OFFS 12 +#define PIBLSS_HIGH_ADDR_MASK (0xF << PIBLSS_HIGH_ADDR_OFFS) + +#define PIBLSS_IO_LIMIT_OFFS 8 +#define PIBLSS_IO_LIMIT_MASK (0xff << PIBLSS_IO_LIMIT_OFFS) + +#define PIBLSS_SEC_STATUS_OFFS 16 +#define PIBLSS_SEC_STATUS_MASK (0xffff << PIBLSS_SEC_STATUS_OFFS) + + +/* P2P_MEM_BASE_LIMIT (PMBL)*/ + +#define PMBL_MEM_BASE_OFFS 0 +#define PMBL_MEM_BASE_MASK (0xffff << PMBL_MEM_BASE_OFFS) + +#define PMBL_MEM_LIMIT_OFFS 16 +#define PMBL_MEM_LIMIT_MASK (0xffff << PMBL_MEM_LIMIT_OFFS) + + +#define PMBL_LOW_ADDR_OFFS 0 +#define PMBL_LOW_ADDR_MASK (0xFFFFF << PMBL_LOW_ADDR_OFFS) + +#define PMBL_HIGH_ADDR_OFFS 20 +#define PMBL_HIGH_ADDR_MASK (0xFFF << PMBL_HIGH_ADDR_OFFS) + + +/* P2P_PREF_MEM_BASE_LIMIT (PRMBL) */ + +#define PRMBL_PREF_MEM_BASE_OFFS 0 +#define PRMBL_PREF_MEM_BASE_MASK (0xffff << PRMBL_PREF_MEM_BASE_OFFS) + +#define PRMBL_PREF_MEM_LIMIT_OFFS 16 +#define PRMBL_PREF_MEM_LIMIT_MASK (0xffff<= mvCtrlPciMaxIfGet()) + { + mvOsPrintf("mvPciCommandSet: ERR. Invalid PCI IF num %d\n", pciIf); + return MV_BAD_PARAM; + } + + /* Set command register */ + MV_REG_WRITE(PCI_CMD_REG(pciIf), command); + + /* Upodate device max outstanding split tarnsaction */ + if ((command & PCR_CPU_TO_PCI_ORDER_EN) && + (command & PCR_PCI_TO_CPU_ORDER_EN)) + { + /* Read PCI-X command register */ + regVal = mvPciConfigRead (pciIf, locBusNum, locDevNum, 0, PCIX_COMMAND); + + /* clear bits 22:20 */ + regVal &= 0xff8fffff; + + /* set reset value */ + regVal |= (0x3 << 20); + + /* Write back the value */ + mvPciConfigWrite (pciIf, locBusNum, locDevNum, 0, PCIX_COMMAND, regVal); + } + + return MV_OK; + + +} + + +/******************************************************************************* +* mvPciModeGet - Get PCI interface mode. +* +* DESCRIPTION: +* This function returns the given PCI interface mode. +* +* INPUT: +* pciIf - PCI interface number. +* +* OUTPUT: +* pPciMode - Pointer to PCI mode structure. +* +* RETURN: +* MV_BAD_PARAM for bad parameters ,MV_ERROR on error ! otherwise MV_OK +* +*******************************************************************************/ +MV_STATUS mvPciModeGet(MV_U32 pciIf, MV_PCI_MODE *pPciMode) +{ + MV_U32 pciMode; + + /* Parameter checking */ + if (pciIf >= mvCtrlPciMaxIfGet()) + { + mvOsPrintf("mvPciModeGet: ERR. Invalid PCI interface %d\n", pciIf); + return MV_BAD_PARAM; + } + if (NULL == pPciMode) + { + mvOsPrintf("mvPciModeGet: ERR. pPciMode = NULL \n"); + return MV_BAD_PARAM; + } + + /* Read pci mode register */ + pciMode = MV_REG_READ(PCI_MODE_REG(pciIf)); + + switch (pciMode & PMR_PCI_MODE_MASK) + { + case PMR_PCI_MODE_CONV: + pPciMode->pciType = MV_PCI_CONV; + + if (MV_REG_READ(PCI_DLL_CTRL_REG(pciIf)) & PDC_DLL_EN) + { + pPciMode->pciSpeed = 66000000; /* 66MHZ */ + } + else + { + pPciMode->pciSpeed = 33000000; /* 33MHZ */ + } + + break; + + case PMR_PCI_MODE_PCIX_66MHZ: + pPciMode->pciType = MV_PCIX; + pPciMode->pciSpeed = 66000000; /* 66MHZ */ + break; + + case PMR_PCI_MODE_PCIX_100MHZ: + pPciMode->pciType = MV_PCIX; + pPciMode->pciSpeed = 100000000; /* 100MHZ */ + break; + + case PMR_PCI_MODE_PCIX_133MHZ: + pPciMode->pciType = MV_PCIX; + pPciMode->pciSpeed = 133000000; /* 133MHZ */ + break; + + default: + { + mvOsPrintf("mvPciModeGet: ERR. Non existing mode !!\n"); + return MV_ERROR; + } + } + + switch (pciMode & PMR_PCI_64_MASK) + { + case PMR_PCI_64_64BIT: + pPciMode->pciWidth = MV_PCI_64; + break; + + case PMR_PCI_64_32BIT: + pPciMode->pciWidth = MV_PCI_32; + break; + + default: + { + mvOsPrintf("mvPciModeGet: ERR. Non existing mode !!\n"); + return MV_ERROR; + } + } + + return MV_OK; +} + +/******************************************************************************* +* mvPciRetrySet - Set PCI retry counters +* +* DESCRIPTION: +* This function specifies the number of times the PCI controller +* retries a transaction before it quits. +* Applies to the PCI Master when acting as a requester. +* Applies to the PCI slave when acting as a completer (PCI-X mode). +* A 0x00 value means a "retry forever". +* +* INPUT: +* pciIf - PCI interface number. +* counter - Number of times PCI controller retry. Use counter value +* up to PRR_RETRY_CNTR_MAX. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_BAD_PARAM for bad parameters ,MV_ERROR on error ! otherwise MV_OK +* +*******************************************************************************/ +MV_STATUS mvPciRetrySet(MV_U32 pciIf, MV_U32 counter) +{ + MV_U32 pciRetry; + + /* Parameter checking */ + if (pciIf >= mvCtrlPciMaxIfGet()) + { + mvOsPrintf("mvPciRetrySet: ERR. Invalid PCI interface %d\n", pciIf); + return MV_BAD_PARAM; + } + + if (counter >= PRR_RETRY_CNTR_MAX) + { + mvOsPrintf("mvPciRetrySet: ERR. Invalid counter: %d\n", counter); + return MV_BAD_PARAM; + + } + + /* Reading PCI retry register */ + pciRetry = MV_REG_READ(PCI_RETRY_REG(pciIf)); + + pciRetry &= ~PRR_RETRY_CNTR_MASK; + + pciRetry |= (counter << PRR_RETRY_CNTR_OFFS); + + /* write new value */ + MV_REG_WRITE(PCI_RETRY_REG(pciIf), pciRetry); + + return MV_OK; +} + + +/******************************************************************************* +* mvPciDiscardTimerSet - Set PCI discard timer +* +* DESCRIPTION: +* This function set PCI discard timer. +* In conventional PCI mode: +* Specifies the number of PCLK cycles the PCI slave keeps a non-accessed +* read buffers (non-completed delayed read) before invalidate the buffer. +* Set to '0' to disable the timer. The PCI slave waits for delayed +* read completion forever. +* In PCI-X mode: +* Specifies the number of PCLK cycles the PCI master waits for split +* completion transaction, before it invalidates the pre-allocated read +* buffer. +* Set to '0' to disable the timer. The PCI master waits for split +* completion forever. +* NOTE: Must be set to a number greater than MV_PCI_MAX_DISCARD_CLK, +* unless using the "wait for ever" setting 0x0. +* NOTE: Must not be updated while there are pending read requests. +* +* INPUT: +* pciIf - PCI interface number. +* pClkCycles - Number of PCI clock cycles. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_BAD_PARAM for bad parameters ,MV_ERROR on error ! otherwise MV_OK +* +*******************************************************************************/ +MV_STATUS mvPciDiscardTimerSet(MV_U32 pciIf, MV_U32 pClkCycles) +{ + MV_U32 pciDiscardTimer; + + /* Parameter checking */ + if (pciIf >= mvCtrlPciMaxIfGet()) + { + mvOsPrintf("mvPciDiscardTimerSet: ERR. Invalid PCI interface %d\n", + pciIf); + return MV_BAD_PARAM; + } + + if (pClkCycles >= PDTR_TIMER_MIN) + { + mvOsPrintf("mvPciDiscardTimerSet: ERR. Invalid Clk value: %d\n", + pClkCycles); + return MV_BAD_PARAM; + + } + + /* Read PCI Discard Timer */ + pciDiscardTimer = MV_REG_READ(PCI_DISCARD_TIMER_REG(pciIf)); + + pciDiscardTimer &= ~PDTR_TIMER_MASK; + + pciDiscardTimer |= (pClkCycles << PDTR_TIMER_OFFS); + + /* Write new value */ + MV_REG_WRITE(PCI_DISCARD_TIMER_REG(pciIf), pciDiscardTimer); + + return MV_OK; + +} + +/* PCI Arbiter routines */ + +/******************************************************************************* +* mvPciArbEnable - PCI arbiter enable/disable +* +* DESCRIPTION: +* This fuction enable/disables a given PCI interface arbiter. +* NOTE: Arbiter setting can not be changed while in work. It should only +* be set once. +* INPUT: +* pciIf - PCI interface number. +* enable - Enable/disable parameter. If enable = MV_TRUE then enable. +* +* OUTPUT: +* None. +* +* RETURN: +* None. +* +*******************************************************************************/ +MV_STATUS mvPciArbEnable(MV_U32 pciIf, MV_BOOL enable) +{ + MV_U32 regVal; + + /* Parameter checking */ + if (pciIf >= mvCtrlPciMaxIfGet()) + { + mvOsPrintf("mvPciArbEnable: ERR. Invalid PCI interface %d\n", pciIf); + return MV_ERROR; + } + + /* Set PCI Arbiter Control register according to default configuration */ + regVal = MV_REG_READ(PCI_ARBITER_CTRL_REG(pciIf)); + + /* Make sure arbiter disabled before changing its values */ + MV_REG_BIT_RESET(PCI_ARBITER_CTRL_REG(pciIf), PACR_ARB_ENABLE); + + regVal &= ~PCI_ARBITER_CTRL_DEFAULT_MASK; + + regVal |= PCI_ARBITER_CTRL_DEFAULT; /* Set default configuration */ + + if (MV_TRUE == enable) + { + regVal |= PACR_ARB_ENABLE; + } + else + { + regVal &= ~PACR_ARB_ENABLE; + } + + /* Write to register */ + MV_REG_WRITE(PCI_ARBITER_CTRL_REG(pciIf), regVal); + + return MV_OK; +} + + +/******************************************************************************* +* mvPciArbParkDis - Disable arbiter parking on agent +* +* DESCRIPTION: +* This function disables the PCI arbiter from parking on the given agent +* list. +* +* INPUT: +* pciIf - PCI interface number. +* pciAgentMask - When a bit in the mask is set to '1', parking on +* the associated PCI master is disabled. Mask bit +* refers to bit 0 - 6. For example disable parking on PCI +* agent 3 set pciAgentMask 0x4 (bit 3 is set). +* +* OUTPUT: +* None. +* +* RETURN: +* None. +* +*******************************************************************************/ +MV_STATUS mvPciArbParkDis(MV_U32 pciIf, MV_U32 pciAgentMask) +{ + MV_U32 pciArbiterCtrl; + + /* Parameter checking */ + if (pciIf >= mvCtrlPciMaxIfGet()) + { + mvOsPrintf("mvPciArbParkDis: ERR. Invalid PCI interface %d\n", pciIf); + return MV_ERROR; + } + + /* Reading Arbiter Control register */ + pciArbiterCtrl = MV_REG_READ(PCI_ARBITER_CTRL_REG(pciIf)); + + /* Arbiter must be disabled before changing parking */ + MV_REG_BIT_RESET(PCI_ARBITER_CTRL_REG(pciIf), PACR_ARB_ENABLE); + + /* do the change */ + pciArbiterCtrl &= ~PACR_PARK_DIS_MASK; + pciArbiterCtrl |= (pciAgentMask << PACR_PARK_DIS_OFFS); + + /* writing new value ( if th earbiter was enabled before the change */ + /* here it will be reenabled */ + MV_REG_WRITE(PCI_ARBITER_CTRL_REG(pciIf), pciArbiterCtrl); + + return MV_OK; +} + + +/******************************************************************************* +* mvPciArbBrokDetectSet - Set PCI arbiter broken detection +* +* DESCRIPTION: +* This function sets the maximum number of cycles that the arbiter +* waits for a PCI master to respond to its grant assertion. If a +* PCI agent fails to respond within this time, the PCI arbiter aborts +* the transaction and performs a new arbitration cycle. +* NOTE: Value must be greater than '1' for conventional PCI and +* greater than '5' for PCI-X. +* +* INPUT: +* pciIf - PCI interface number. +* pClkCycles - Number of PCI clock cycles. If equal to '0' the broken +* master detection is disabled. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_BAD_PARAM for bad parameters ,MV_ERROR on error ! otherwise MV_OK +* +*******************************************************************************/ +MV_STATUS mvPciArbBrokDetectSet(MV_U32 pciIf, MV_U32 pClkCycles) +{ + MV_U32 pciArbiterCtrl; + MV_U32 pciMode; + + /* Parameter checking */ + if (pciIf >= mvCtrlPciMaxIfGet()) + { + mvOsPrintf("mvPciArbBrokDetectSet: ERR. Invalid PCI interface %d\n", + pciIf); + return MV_BAD_PARAM; + } + + /* Checking PCI mode and if pClkCycles is legal value */ + pciMode = MV_REG_READ(PCI_MODE_REG(pciIf)); + pciMode &= PMR_PCI_MODE_MASK; + + if (PMR_PCI_MODE_CONV == pciMode) + { + if (pClkCycles < PACR_BROKEN_VAL_CONV_MIN) + return MV_ERROR; + } + else + { + if (pClkCycles < PACR_BROKEN_VAL_PCIX_MIN) + return MV_ERROR; + } + + pClkCycles <<= PACR_BROKEN_VAL_OFFS; + + /* Reading Arbiter Control register */ + pciArbiterCtrl = MV_REG_READ(PCI_ARBITER_CTRL_REG(pciIf)); + pciArbiterCtrl &= ~PACR_BROKEN_VAL_MASK; + pciArbiterCtrl |= pClkCycles; + + /* Arbiter must be disabled before changing broken detection */ + MV_REG_BIT_RESET(PCI_ARBITER_CTRL_REG(pciIf), PACR_ARB_ENABLE); + + /* writing new value ( if th earbiter was enabled before the change */ + /* here it will be reenabled */ + + MV_REG_WRITE(PCI_ARBITER_CTRL_REG(pciIf), pciArbiterCtrl); + + return MV_OK; +} + +/* PCI configuration space read write */ + +/******************************************************************************* +* mvPciConfigRead - Read from configuration space +* +* DESCRIPTION: +* This function performs a 32 bit read from PCI configuration space. +* It supports both type 0 and type 1 of Configuration Transactions +* (local and over bridge). In order to read from local bus segment, use +* bus number retrieved from mvPciLocalBusNumGet(). Other bus numbers +* will result configuration transaction of type 1 (over bridge). +* +* INPUT: +* pciIf - PCI interface number. +* bus - PCI segment bus number. +* dev - PCI device number. +* func - Function number. +* regOffs - Register offset. +* +* OUTPUT: +* None. +* +* RETURN: +* 32bit register data, 0xffffffff on error +* +*******************************************************************************/ +MV_U32 mvPciConfigRead (MV_U32 pciIf, MV_U32 bus, MV_U32 dev, MV_U32 func, + MV_U32 regOff) +{ + MV_U32 pciData = 0; + + /* Parameter checking */ + if (PCI_DEFAULT_IF != pciIf) + { + if (pciIf >= mvCtrlPciMaxIfGet()) + { + mvOsPrintf("mvPciConfigRead: ERR. Invalid PCI interface %d\n",pciIf); + return 0xFFFFFFFF; + } + } + + if (dev >= MAX_PCI_DEVICES) + { + DB(mvOsPrintf("mvPciConfigRead: ERR. device number illigal %d\n", dev)); + return 0xFFFFFFFF; + } + + if (func >= MAX_PCI_FUNCS) + { + DB(mvOsPrintf("mvPciConfigRead: ERR. function number illigal %d\n", func)); + return 0xFFFFFFFF; + } + + if (bus >= MAX_PCI_BUSSES) + { + DB(mvOsPrintf("mvPciConfigRead: ERR. bus number illigal %d\n", bus)); + return MV_ERROR; + } + + + /* Creating PCI address to be passed */ + pciData |= (bus << PCAR_BUS_NUM_OFFS); + pciData |= (dev << PCAR_DEVICE_NUM_OFFS); + pciData |= (func << PCAR_FUNC_NUM_OFFS); + pciData |= (regOff & PCAR_REG_NUM_MASK); + + pciData |= PCAR_CONFIG_EN; + + /* Write the address to the PCI configuration address register */ + MV_REG_WRITE(PCI_CONFIG_ADDR_REG(pciIf), pciData); + + /* In order to let the PCI controller absorbed the address of the read */ + /* transaction we perform a validity check that the address was written */ + if(pciData != MV_REG_READ(PCI_CONFIG_ADDR_REG(pciIf))) + { + return MV_ERROR; + } + /* Read the Data returned in the PCI Data register */ + pciData = MV_REG_READ(PCI_CONFIG_DATA_REG(pciIf)); + + return pciData; +} + +/******************************************************************************* +* mvPciConfigWrite - Write to configuration space +* +* DESCRIPTION: +* This function performs a 32 bit write to PCI configuration space. +* It supports both type 0 and type 1 of Configuration Transactions +* (local and over bridge). In order to write to local bus segment, use +* bus number retrieved from mvPciLocalBusNumGet(). Other bus numbers +* will result configuration transaction of type 1 (over bridge). +* +* INPUT: +* pciIf - PCI interface number. +* bus - PCI segment bus number. +* dev - PCI device number. +* func - Function number. +* regOffs - Register offset. +* data - 32bit data. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_BAD_PARAM for bad parameters ,MV_ERROR on error ! otherwise MV_OK +* +*******************************************************************************/ +MV_STATUS mvPciConfigWrite(MV_U32 pciIf, MV_U32 bus, MV_U32 dev, + MV_U32 func, MV_U32 regOff, MV_U32 data) +{ + MV_U32 pciData = 0; + + /* Parameter checking */ + if (PCI_DEFAULT_IF != pciIf) + { + if (pciIf >= mvCtrlPciMaxIfGet()) + { + mvOsPrintf("mvPciConfigWrite: ERR. Invalid PCI interface %d\n", + pciIf); + return 0xFFFFFFFF; + } + } + + if (dev >= MAX_PCI_DEVICES) + { + mvOsPrintf("mvPciConfigWrite: ERR. device number illigal %d\n",dev); + return MV_BAD_PARAM; + } + + if (func >= MAX_PCI_FUNCS) + { + mvOsPrintf("mvPciConfigWrite: ERR. function number illigal %d\n", func); + return MV_ERROR; + } + + if (bus >= MAX_PCI_BUSSES) + { + mvOsPrintf("mvPciConfigWrite: ERR. bus number illigal %d\n", bus); + return MV_ERROR; + } + + /* Creating PCI address to be passed */ + pciData |= (bus << PCAR_BUS_NUM_OFFS); + pciData |= (dev << PCAR_DEVICE_NUM_OFFS); + pciData |= (func << PCAR_FUNC_NUM_OFFS); + pciData |= (regOff & PCAR_REG_NUM_MASK); + + pciData |= PCAR_CONFIG_EN; + + /* Write the address to the PCI configuration address register */ + MV_REG_WRITE(PCI_CONFIG_ADDR_REG(pciIf), pciData); + + /* In order to let the PCI controller absorbed the address of the read */ + /* transaction we perform a validity check that the address was written */ + if(pciData != MV_REG_READ(PCI_CONFIG_ADDR_REG(pciIf))) + { + return MV_ERROR; + } + + /* Write the Data passed to the PCI Data register */ + MV_REG_WRITE(PCI_CONFIG_DATA_REG(pciIf), data); + + return MV_OK; +} + +/******************************************************************************* +* mvPciMasterEnable - Enable/disale PCI interface master transactions. +* +* DESCRIPTION: +* This function performs read modified write to PCI command status +* (offset 0x4) to set/reset bit 2. After this bit is set, the PCI +* master is allowed to gain ownership on the bus, otherwise it is +* incapable to do so. +* +* INPUT: +* pciIf - PCI interface number. +* enable - Enable/disable parameter. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_BAD_PARAM for bad parameters ,MV_ERROR on error ! otherwise MV_OK +* +*******************************************************************************/ +MV_STATUS mvPciMasterEnable(MV_U32 pciIf, MV_BOOL enable) +{ + MV_U32 pciCommandStatus; + MV_U32 RegOffs; + MV_U32 localBus; + MV_U32 localDev; + + /* Parameter checking */ + if (pciIf >= mvCtrlPciMaxIfGet()) + { + mvOsPrintf("mvPciMasterEnable: ERR. Invalid PCI interface %d\n", pciIf); + return MV_ERROR; + } + + localBus = mvPciLocalBusNumGet(pciIf); + localDev = mvPciLocalDevNumGet(pciIf); + + RegOffs = PCI_STATUS_AND_COMMAND; + + pciCommandStatus = mvPciConfigRead(pciIf, localBus, localDev, 0, RegOffs); + + if (MV_TRUE == enable) + { + pciCommandStatus |= PSCR_MASTER_EN; + } + else + { + pciCommandStatus &= ~PSCR_MASTER_EN; + } + + mvPciConfigWrite(pciIf, localBus, localDev, 0, RegOffs, pciCommandStatus); + + return MV_OK; +} + + +/******************************************************************************* +* mvPciSlaveEnable - Enable/disale PCI interface slave transactions. +* +* DESCRIPTION: +* This function performs read modified write to PCI command status +* (offset 0x4) to set/reset bit 0 and 1. After those bits are set, +* the PCI slave is allowed to respond to PCI IO space access (bit 0) +* and PCI memory space access (bit 1). +* +* INPUT: +* pciIf - PCI interface number. +* dev - PCI device number. +* enable - Enable/disable parameter. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_BAD_PARAM for bad parameters ,MV_ERROR on error ! otherwise MV_OK +* +*******************************************************************************/ +MV_STATUS mvPciSlaveEnable(MV_U32 pciIf, MV_U32 bus, MV_U32 dev, MV_BOOL enable) +{ + MV_U32 pciCommandStatus; + MV_U32 RegOffs; + + /* Parameter checking */ + if (pciIf >= mvCtrlPciMaxIfGet()) + { + mvOsPrintf("mvPciSlaveEnable: ERR. Invalid PCI interface %d\n", pciIf); + return MV_BAD_PARAM; + } + if (dev >= MAX_PCI_DEVICES) + { + mvOsPrintf("mvPciLocalDevNumSet: ERR. device number illigal %d\n", dev); + return MV_BAD_PARAM; + + } + + RegOffs = PCI_STATUS_AND_COMMAND; + + pciCommandStatus=mvPciConfigRead(pciIf, bus, dev, 0, RegOffs); + + if (MV_TRUE == enable) + { + pciCommandStatus |= (PSCR_IO_EN | PSCR_MEM_EN); + } + else + { + pciCommandStatus &= ~(PSCR_IO_EN | PSCR_MEM_EN); + } + + mvPciConfigWrite(pciIf, bus, dev, 0, RegOffs, pciCommandStatus); + + return MV_OK; +} + +/******************************************************************************* +* mvPciLocalBusNumSet - Set PCI interface local bus number. +* +* DESCRIPTION: +* This function sets given PCI interface its local bus number. +* Note: In case the PCI interface is PCI-X, the information is read-only. +* +* INPUT: +* pciIf - PCI interface number. +* busNum - Bus number. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_NOT_ALLOWED in case PCI interface is PCI-X. +* MV_BAD_PARAM on bad parameters , +* otherwise MV_OK +* +*******************************************************************************/ +MV_STATUS mvPciLocalBusNumSet(MV_U32 pciIf, MV_U32 busNum) +{ + MV_U32 pciP2PConfig; + MV_PCI_MODE pciMode; + MV_U32 localBus; + MV_U32 localDev; + + + /* Parameter checking */ + if (pciIf >= mvCtrlPciMaxIfGet()) + { + mvOsPrintf("mvPciLocalBusNumSet: ERR. Invalid PCI interface %d\n",pciIf); + return MV_BAD_PARAM; + } + if (busNum >= MAX_PCI_BUSSES) + { + mvOsPrintf("mvPciLocalBusNumSet: ERR. bus number illigal %d\n", busNum); + return MV_ERROR; + + } + + localBus = mvPciLocalBusNumGet(pciIf); + localDev = mvPciLocalDevNumGet(pciIf); + + + /* PCI interface mode */ + mvPciModeGet(pciIf, &pciMode); + + /* if PCI type is PCI-X then it is not allowed to change the dev number */ + if (MV_PCIX == pciMode.pciType) + { + pciP2PConfig = mvPciConfigRead(pciIf, localBus, localDev, 0, PCIX_STATUS ); + + pciP2PConfig &= ~PXS_BN_MASK; + + pciP2PConfig |= (busNum << PXS_BN_OFFS) & PXS_BN_MASK; + + mvPciConfigWrite(pciIf, localBus, localDev, 0, PCIX_STATUS,pciP2PConfig ); + + } + else + { + pciP2PConfig = MV_REG_READ(PCI_P2P_CONFIG_REG(pciIf)); + + pciP2PConfig &= ~PPCR_BUS_NUM_MASK; + + pciP2PConfig |= (busNum << PPCR_BUS_NUM_OFFS) & PPCR_BUS_NUM_MASK; + + MV_REG_WRITE(PCI_P2P_CONFIG_REG(pciIf), pciP2PConfig); + + } + + + return MV_OK; +} + + +/******************************************************************************* +* mvPciLocalBusNumGet - Get PCI interface local bus number. +* +* DESCRIPTION: +* This function gets the local bus number of a given PCI interface. +* +* INPUT: +* pciIf - PCI interface number. +* +* OUTPUT: +* None. +* +* RETURN: +* Local bus number.0xffffffff on Error +* +*******************************************************************************/ +MV_U32 mvPciLocalBusNumGet(MV_U32 pciIf) +{ + MV_U32 pciP2PConfig; + + /* Parameter checking */ + if (PCI_DEFAULT_IF != pciIf) + { + if (pciIf >= mvCtrlPciMaxIfGet()) + { + mvOsPrintf("mvPciLocalBusNumGet: ERR. Invalid PCI interface %d\n", + pciIf); + return 0xFFFFFFFF; + } + } + + pciP2PConfig = MV_REG_READ(PCI_P2P_CONFIG_REG(pciIf)); + pciP2PConfig &= PPCR_BUS_NUM_MASK; + return (pciP2PConfig >> PPCR_BUS_NUM_OFFS); +} + + +/******************************************************************************* +* mvPciLocalDevNumSet - Set PCI interface local device number. +* +* DESCRIPTION: +* This function sets given PCI interface its local device number. +* Note: In case the PCI interface is PCI-X, the information is read-only. +* +* INPUT: +* pciIf - PCI interface number. +* devNum - Device number. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_NOT_ALLOWED in case PCI interface is PCI-X. MV_BAD_PARAM on bad parameters , +* otherwise MV_OK +* +*******************************************************************************/ +MV_STATUS mvPciLocalDevNumSet(MV_U32 pciIf, MV_U32 devNum) +{ + MV_U32 pciP2PConfig; + MV_PCI_MODE pciMode; + MV_U32 localBus; + MV_U32 localDev; + + /* Parameter checking */ + if (pciIf >= mvCtrlPciMaxIfGet()) + { + mvOsPrintf("mvPciLocalDevNumSet: ERR. Invalid PCI interface %d\n",pciIf); + return MV_BAD_PARAM; + } + if (devNum >= MAX_PCI_DEVICES) + { + mvOsPrintf("mvPciLocalDevNumSet: ERR. device number illigal %d\n", + devNum); + return MV_BAD_PARAM; + + } + + localBus = mvPciLocalBusNumGet(pciIf); + localDev = mvPciLocalDevNumGet(pciIf); + + /* PCI interface mode */ + mvPciModeGet(pciIf, &pciMode); + + /* if PCI type is PCIX then it is not allowed to change the dev number */ + if (MV_PCIX == pciMode.pciType) + { + pciP2PConfig = mvPciConfigRead(pciIf, localBus, localDev, 0, PCIX_STATUS ); + + pciP2PConfig &= ~PXS_DN_MASK; + + pciP2PConfig |= (devNum << PXS_DN_OFFS) & PXS_DN_MASK; + + mvPciConfigWrite(pciIf,localBus, localDev, 0, PCIX_STATUS,pciP2PConfig ); + } + else + { + pciP2PConfig = MV_REG_READ(PCI_P2P_CONFIG_REG(pciIf)); + + pciP2PConfig &= ~PPCR_DEV_NUM_MASK; + + pciP2PConfig |= (devNum << PPCR_DEV_NUM_OFFS) & PPCR_DEV_NUM_MASK; + + MV_REG_WRITE(PCI_P2P_CONFIG_REG(pciIf), pciP2PConfig); + } + + return MV_OK; +} + +/******************************************************************************* +* mvPciLocalDevNumGet - Get PCI interface local device number. +* +* DESCRIPTION: +* This function gets the local device number of a given PCI interface. +* +* INPUT: +* pciIf - PCI interface number. +* +* OUTPUT: +* None. +* +* RETURN: +* Local device number. 0xffffffff on Error +* +*******************************************************************************/ +MV_U32 mvPciLocalDevNumGet(MV_U32 pciIf) +{ + MV_U32 pciP2PConfig; + + /* Parameter checking */ + + if (PCI_DEFAULT_IF != pciIf) + { + if (pciIf >= mvCtrlPciMaxIfGet()) + { + mvOsPrintf("mvPciLocalDevNumGet: ERR. Invalid PCI interface %d\n", + pciIf); + return 0xFFFFFFFF; + } + } + + pciP2PConfig = MV_REG_READ(PCI_P2P_CONFIG_REG(pciIf)); + + pciP2PConfig &= PPCR_DEV_NUM_MASK; + + return (pciP2PConfig >> PPCR_DEV_NUM_OFFS); +} + + + + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/pci/mvPci.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/pci/mvPci.h new file mode 100644 index 0000000..4746336 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/pci/mvPci.h @@ -0,0 +1,185 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + + +#ifndef __INCPCIH +#define __INCPCIH + +#include "mvCommon.h" +#include "mvOs.h" +#include "ctrlEnv/mvCtrlEnvSpec.h" +#include "pci/mvPciRegs.h" + + +/* NOTE not supported in this driver: + + Built In Self Test (BIST) + Vital Product Data (VPD) + Message Signaled Interrupt (MSI) + Power Management + Compact PCI Hot Swap + Header retarget + +Registers not supported: +1) PCI DLL Status and Control (PCI0 0x1D20, PCI1 0x1DA0) +2) PCI/MPP Pads Calibration (CI0/MPP[31:16] 0x1D1C, PCI1/MPP[15:0] 0X1D9C) +*/ + +/* defines */ +/* The number of supported PCI interfaces depend on Marvell controller */ +/* device number. This device number ID is located on the PCI unit */ +/* configuration header. This creates a loop where calling PCI */ +/* configuration read/write routine results a call to get PCI configuration */ +/* information etc. This macro defines a default PCI interface. This PCI */ +/* interface is sure to exist. */ +#define PCI_DEFAULT_IF 0 + + +/* typedefs */ +/* The Marvell controller supports both conventional PCI and PCI-X. */ +/* This enumeration describes the PCI type. */ +typedef enum _mvPciType +{ + MV_PCI_CONV, /* Conventional PCI */ + MV_PCIX /* PCI-X */ +}MV_PCI_TYPE; + +typedef enum _mvPciMod +{ + MV_PCI_MOD_HOST, + MV_PCI_MOD_DEVICE +}MV_PCI_MOD; + + +/* The Marvell controller supports both PCI width of 32 and 64 bit. */ +/* This enumerator describes PCI width */ +typedef enum _mvPciWidth +{ + MV_PCI_32, /* PCI width 32bit */ + MV_PCI_64 /* PCI width 64bit */ +}MV_PCI_WIDTH; + +/* This structure describes the PCI unit configured type, speed and width. */ +typedef struct _mvPciMode +{ + MV_PCI_TYPE pciType; /* PCI type */ + MV_U32 pciSpeed; /* Assuming PCI base clock on board is 33MHz */ + MV_PCI_WIDTH pciWidth; /* PCI bus width */ +}MV_PCI_MODE; + +/* mvPciInit - Initialize PCI interfaces*/ +MV_VOID mvPciHalInit(MV_U32 pciIf, MV_PCI_MOD pciIfmod); + +/* mvPciCommandSet - Set PCI comman register value.*/ +MV_STATUS mvPciCommandSet(MV_U32 pciIf, MV_U32 command); + +/* mvPciModeGet - Get PCI interface mode.*/ +MV_STATUS mvPciModeGet(MV_U32 pciIf, MV_PCI_MODE *pPciMode); + +/* mvPciRetrySet - Set PCI retry counters*/ +MV_STATUS mvPciRetrySet(MV_U32 pciIf, MV_U32 counter); + +/* mvPciDiscardTimerSet - Set PCI discard timer*/ +MV_STATUS mvPciDiscardTimerSet(MV_U32 pciIf, MV_U32 pClkCycles); + +/* mvPciArbEnable - PCI arbiter enable/disable*/ +MV_STATUS mvPciArbEnable(MV_U32 pciIf, MV_BOOL enable); + +/* mvPciArbParkDis - Disable arbiter parking on agent */ +MV_STATUS mvPciArbParkDis(MV_U32 pciIf, MV_U32 pciAgentMask); + +/* mvPciArbBrokDetectSet - Set PCI arbiter broken detection */ +MV_STATUS mvPciArbBrokDetectSet(MV_U32 pciIf, MV_U32 pClkCycles); + +/* mvPciConfigRead - Read from configuration space */ +MV_U32 mvPciConfigRead (MV_U32 pciIf, MV_U32 bus, MV_U32 dev, + MV_U32 func,MV_U32 regOff); + +/* mvPciConfigWrite - Write to configuration space */ +MV_STATUS mvPciConfigWrite(MV_U32 pciIf, MV_U32 bus, MV_U32 dev, + MV_U32 func, MV_U32 regOff, MV_U32 data); + +/* mvPciMasterEnable - Enable/disale PCI interface master transactions.*/ +MV_STATUS mvPciMasterEnable(MV_U32 pciIf, MV_BOOL enable); + +/* mvPciSlaveEnable - Enable/disale PCI interface slave transactions.*/ +MV_STATUS mvPciSlaveEnable(MV_U32 pciIf, MV_U32 bus, MV_U32 dev,MV_BOOL enable); + +/* mvPciLocalBusNumSet - Set PCI interface local bus number.*/ +MV_STATUS mvPciLocalBusNumSet(MV_U32 pciIf, MV_U32 busNum); + +/* mvPciLocalBusNumGet - Get PCI interface local bus number.*/ +MV_U32 mvPciLocalBusNumGet(MV_U32 pciIf); + +/* mvPciLocalDevNumSet - Set PCI interface local device number.*/ +MV_STATUS mvPciLocalDevNumSet(MV_U32 pciIf, MV_U32 devNum); + +/* mvPciLocalDevNumGet - Get PCI interface local device number.*/ +MV_U32 mvPciLocalDevNumGet(MV_U32 pciIf); + + +#endif /* #ifndef __INCPCIH */ + + + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/pci/mvPciRegs.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/pci/mvPciRegs.h new file mode 100644 index 0000000..89d0ef1 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/pci/mvPciRegs.h @@ -0,0 +1,411 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#ifndef __INCPCIREGSH +#define __INCPCIREGSH + + +#include "pci-if/mvPciIfRegs.h" +/* defines */ +#define MAX_PCI_DEVICES 32 +#define MAX_PCI_FUNCS 8 +#define MAX_PCI_BUSSES 128 + +/* enumerators */ + +/* This enumerator described the possible PCI slave targets. */ +/* PCI slave targets are designated memory/IO address spaces that the */ +/* PCI slave targets can access. They are also refered as "targets" */ +/* this enumeratoe order is determined by the content of : + PCI_BASE_ADDR_ENABLE_REG */ + + +/* registers offsetes defines */ + + + +/*************************/ +/* PCI control registers */ +/*************************/ +/* maen : should add new registers */ +#define PCI_CMD_REG(pciIf) (0x30c00 + ((pciIf) * 0x80)) +#define PCI_MODE_REG(pciIf) (0x30d00 + ((pciIf) * 0x80)) +#define PCI_RETRY_REG(pciIf) (0x30c04 + ((pciIf) * 0x80)) +#define PCI_DISCARD_TIMER_REG(pciIf) (0x30d04 + ((pciIf) * 0x80)) +#define PCI_ARBITER_CTRL_REG(pciIf) (0x31d00 + ((pciIf) * 0x80)) +#define PCI_P2P_CONFIG_REG(pciIf) (0x31d14 + ((pciIf) * 0x80)) +#define PCI_ACCESS_CTRL_BASEL_REG(pciIf, targetWin) \ + (0x31e00 + ((pciIf) * 0x80) + ((targetWin) * 0x10)) +#define PCI_ACCESS_CTRL_BASEH_REG(pciIf, targetWin) \ + (0x31e04 + ((pciIf) * 0x80) + ((targetWin) * 0x10)) +#define PCI_ACCESS_CTRL_SIZE_REG(pciIf, targetWin) \ + (0x31e08 + ((pciIf) * 0x80) + ((targetWin) * 0x10)) + +#define PCI_DLL_CTRL_REG(pciIf) (0x31d20 + ((pciIf) * 0x80)) + +/* PCI Dll Control (PDC)*/ +#define PDC_DLL_EN BIT0 + + +/* PCI Command Register (PCR) */ +#define PCR_MASTER_BYTE_SWAP_EN BIT0 +#define PCR_MASTER_WR_COMBINE_EN BIT4 +#define PCR_MASTER_RD_COMBINE_EN BIT5 +#define PCR_MASTER_WR_TRIG_WHOLE BIT6 +#define PCR_MASTER_RD_TRIG_WHOLE BIT7 +#define PCR_MASTER_MEM_RD_LINE_EN BIT8 +#define PCR_MASTER_MEM_RD_MULT_EN BIT9 +#define PCR_MASTER_WORD_SWAP_EN BIT10 +#define PCR_SLAVE_WORD_SWAP_EN BIT11 +#define PCR_NS_ACCORDING_RCV_TRANS BIT14 +#define PCR_MASTER_PCIX_REQ64N_EN BIT15 +#define PCR_SLAVE_BYTE_SWAP_EN BIT16 +#define PCR_MASTER_DAC_EN BIT17 +#define PCR_MASTER_M64_ALLIGN BIT18 +#define PCR_ERRORS_PROPAGATION_EN BIT19 +#define PCR_SLAVE_SWAP_ENABLE BIT20 +#define PCR_MASTER_SWAP_ENABLE BIT21 +#define PCR_MASTER_INT_SWAP_EN BIT22 +#define PCR_LOOP_BACK_ENABLE BIT23 +#define PCR_SLAVE_INTREG_SWAP_OFFS 24 +#define PCR_SLAVE_INTREG_SWAP_MASK 0x3 +#define PCR_SLAVE_INTREG_BYTE_SWAP \ + (MV_BYTE_SWAP << PCR_SLAVE_INT_REG_SWAP_MASK) +#define PCR_SLAVE_INTREG_NO_SWAP \ + (MV_NO_SWAP << PCR_SLAVE_INT_REG_SWAP_MASK) +#define PCR_SLAVE_INTREG_BYTE_WORD \ + (MV_BYTE_WORD_SWAP << PCR_SLAVE_INT_REG_SWAP_MASK) +#define PCR_SLAVE_INTREG_WORD_SWAP \ + (MV_WORD_SWAP << PCR_SLAVE_INT_REG_SWAP_MASK) +#define PCR_RESET_REASSERTION_EN BIT26 +#define PCR_PCI_TO_CPU_REG_ORDER_EN BIT28 +#define PCR_CPU_TO_PCI_ORDER_EN BIT29 +#define PCR_PCI_TO_CPU_ORDER_EN BIT30 + +/* PCI Mode Register (PMR) */ +#define PMR_PCI_ID_OFFS 0 /* PCI Interface ID */ +#define PMR_PCI_ID_MASK (0x1 << PMR_PCI_ID_OFFS) +#define PMR_PCI_ID_PCI(pciNum) ((pciNum) << PCI_MODE_PCIID_OFFS) + +#define PMR_PCI_64_OFFS 2 /* 64-bit PCI Interface */ +#define PMR_PCI_64_MASK (0x1 << PMR_PCI_64_OFFS) +#define PMR_PCI_64_64BIT (0x1 << PMR_PCI_64_OFFS) +#define PMR_PCI_64_32BIT (0x0 << PMR_PCI_64_OFFS) + +#define PMR_PCI_MODE_OFFS 4 /* PCI interface mode of operation */ +#define PMR_PCI_MODE_MASK (0x3 << PMR_PCI_MODE_OFFS) +#define PMR_PCI_MODE_CONV (0x0 << PMR_PCI_MODE_OFFS) +#define PMR_PCI_MODE_PCIX_66MHZ (0x1 << PMR_PCI_MODE_OFFS) +#define PMR_PCI_MODE_PCIX_100MHZ (0x2 << PMR_PCI_MODE_OFFS) +#define PMR_PCI_MODE_PCIX_133MHZ (0x3 << PMR_PCI_MODE_OFFS) + +#define PMR_EXP_ROM_SUPPORT BIT8 /* Expansion ROM Active */ + +#define PMR_PCI_RESET_OFFS 31 /* PCI Interface Reset Indication */ +#define PMR_PCI_RESET_MASK (0x1 << PMR_PCI_RESET_OFFS) +#define PMR_PCI_RESET_PCIXRST (0x0 << PMR_PCI_RESET_OFFS) + + +/* PCI Retry Register (PRR) */ +#define PRR_RETRY_CNTR_OFFS 16 /* Retry Counter */ +#define PRR_RETRY_CNTR_MAX 0xff +#define PRR_RETRY_CNTR_MASK (PRR_RETRY_CNTR_MAX << PRR_RETRY_CNTR_OFFS) + + +/* PCI Discard Timer Register (PDTR) */ +#define PDTR_TIMER_OFFS 0 /* Timer */ +#define PDTR_TIMER_MAX 0xffff +#define PDTR_TIMER_MIN 0x7F +#define PDTR_TIMER_MASK (PDTR_TIMER_MAX << PDTR_TIMER_OFFS) + + +/* PCI Arbiter Control Register (PACR) */ +#define PACR_BROKEN_DETECT_EN BIT1 /* Broken Detection Enable */ + +#define PACR_BROKEN_VAL_OFFS 3 /* Broken Value */ +#define PACR_BROKEN_VAL_MASK (0xf << PACR_BROKEN_VAL_OFFS) +#define PACR_BROKEN_VAL_CONV_MIN 0x2 +#define PACR_BROKEN_VAL_PCIX_MIN 0x6 + +#define PACR_PARK_DIS_OFFS 14 /* Parking Disable */ +#define PACR_PARK_DIS_MAX_AGENT 0x3f +#define PACR_PARK_DIS_MASK (PACR_PARK_DIS_MAX_AGENT<= mvCtrlPexMaxIfGet()) + { + mvOsPrintf("mvPexModeGet: ERR. Invalid PEX interface %d\n",pexIf); + return MV_ERROR; + } + } + + pexData = MV_REG_READ(PEX_CTRL_REG(pexIf)); + + switch (pexData & PXCR_DEV_TYPE_CTRL_MASK) + { + case PXCR_DEV_TYPE_CTRL_CMPLX: + pexMode->pexType = MV_PEX_ROOT_COMPLEX; + break; + case PXCR_DEV_TYPE_CTRL_POINT: + pexMode->pexType = MV_PEX_END_POINT; + break; + + } + + /* Check if we have link */ + if (MV_REG_READ(PEX_STATUS_REG(pexIf)) & PXSR_DL_DOWN) + { + pexMode->pexLinkUp = MV_FALSE; + + /* If there is no link, the auto negotiation data is worthless */ + pexMode->pexWidth = MV_PEX_WITDH_INVALID; + } + else + { + pexMode->pexLinkUp = MV_TRUE; + + /* We have link. The link width is now valid */ + pexData = MV_REG_READ(PEX_CFG_DIRECT_ACCESS(pexIf, PEX_LINK_CTRL_STAT_REG)); + pexMode->pexWidth = ((pexData & PXLCSR_NEG_LNK_WDTH_MASK) >> + PXLCSR_NEG_LNK_WDTH_OFFS); + } + + return MV_OK; +} + + +/* PEX configuration space read write */ + +/******************************************************************************* +* mvPexConfigRead - Read from configuration space +* +* DESCRIPTION: +* This function performs a 32 bit read from PEX configuration space. +* It supports both type 0 and type 1 of Configuration Transactions +* (local and over bridge). In order to read from local bus segment, use +* bus number retrieved from mvPexLocalBusNumGet(). Other bus numbers +* will result configuration transaction of type 1 (over bridge). +* +* INPUT: +* pexIf - PEX interface number. +* bus - PEX segment bus number. +* dev - PEX device number. +* func - Function number. +* regOffs - Register offset. +* +* OUTPUT: +* None. +* +* RETURN: +* 32bit register data, 0xffffffff on error +* +*******************************************************************************/ +MV_U32 mvPexConfigRead (MV_U32 pexIf, MV_U32 bus, MV_U32 dev, MV_U32 func, + MV_U32 regOff) +{ +#if defined(PCIE_VIRTUAL_BRIDGE_SUPPORT) + return mvPexVrtBrgConfigRead (pexIf, bus, dev, func, regOff); +} + +MV_U32 mvPexHwConfigRead (MV_U32 pexIf, MV_U32 bus, MV_U32 dev, MV_U32 func, + MV_U32 regOff) +{ +#endif + MV_U32 pexData = 0; + MV_U32 localDev,localBus; + + /* Parameter checking */ + if (PEX_DEFAULT_IF != pexIf) + { + if (pexIf >= mvCtrlPexMaxIfGet()) + { + mvOsPrintf("mvPexConfigRead: ERR. Invalid PEX interface %d\n",pexIf); + return 0xFFFFFFFF; + } + } + + if (dev >= MAX_PEX_DEVICES) + { + DB(mvOsPrintf("mvPexConfigRead: ERR. device number illigal %d\n", dev)); + return 0xFFFFFFFF; + } + + if (func >= MAX_PEX_FUNCS) + { + DB(mvOsPrintf("mvPexConfigRead: ERR. function num illigal %d\n", func)); + return 0xFFFFFFFF; + } + + if (bus >= MAX_PEX_BUSSES) + { + DB(mvOsPrintf("mvPexConfigRead: ERR. bus number illigal %d\n", bus)); + return MV_ERROR; + } + + DB(mvOsPrintf("mvPexConfigRead: pexIf %d, bus %d, dev %d, func %d, regOff 0x%x\n", + pexIf, bus, dev, func, regOff)); + + localDev = mvPexLocalDevNumGet(pexIf); + localBus = mvPexLocalBusNumGet(pexIf); + + /* Speed up the process. In case on no link, return MV_ERROR */ + if ((dev != localDev) || (bus != localBus)) + { + pexData = MV_REG_READ(PEX_STATUS_REG(pexIf)); + + if ((pexData & PXSR_DL_DOWN)) + { + return MV_ERROR; + } + } + + /* in PCI Express we have only one device number */ + /* and this number is the first number we encounter + else that the localDev*/ + /* spec pex define return on config read/write on any device */ + if (bus == localBus) + { + if (localDev == 0) + { + /* if local dev is 0 then the first number we encounter + after 0 is 1 */ + if ((dev != 1)&&(dev != localDev)) + { + return MV_ERROR; + } + } + else + { + /* if local dev is not 0 then the first number we encounter + is 0 */ + + if ((dev != 0)&&(dev != localDev)) + { + return MV_ERROR; + } + } + if(func != 0 ) /* i.e bridge */ + { + return MV_ERROR; + } + } + + + /* Creating PEX address to be passed */ + pexData = (bus << PXCAR_BUS_NUM_OFFS); + pexData |= (dev << PXCAR_DEVICE_NUM_OFFS); + pexData |= (func << PXCAR_FUNC_NUM_OFFS); + pexData |= (regOff & PXCAR_REG_NUM_MASK); /* lgacy register space */ + /* extended register space */ + pexData |=(((regOff & PXCAR_REAL_EXT_REG_NUM_MASK) >> + PXCAR_REAL_EXT_REG_NUM_OFFS) << PXCAR_EXT_REG_NUM_OFFS); + + pexData |= PXCAR_CONFIG_EN; + + /* Write the address to the PEX configuration address register */ + MV_REG_WRITE(PEX_CFG_ADDR_REG(pexIf), pexData); + + DB(mvOsPrintf("mvPexConfigRead:address pexData=%x ",pexData)); + + + /* In order to let the PEX controller absorbed the address of the read */ + /* transaction we perform a validity check that the address was written */ + if(pexData != MV_REG_READ(PEX_CFG_ADDR_REG(pexIf))) + { + return MV_ERROR; + } + + /* cleaning Master Abort */ + MV_REG_BIT_SET(PEX_CFG_DIRECT_ACCESS(pexIf,PEX_STATUS_AND_COMMAND), + PXSAC_MABORT); +#if 0 + /* Guideline (GL# PCI Express-1) Erroneous Read Data on Configuration */ + /* This guideline is relevant for all devices except of the following devices: + 88F5281-BO and above, 88F5181L-A0 and above, 88F1281 A0 and above + 88F6183 A0 and above, 88F6183L */ + if ( ( (dev != localDev) || (bus != localBus) ) && + ( + !(MV_5281_DEV_ID == mvCtrlModelGet())&& + !((MV_5181_DEV_ID == mvCtrlModelGet())&& (mvCtrlRevGet() >= MV_5181L_A0_REV))&& + !(MV_1281_DEV_ID == mvCtrlModelGet())&& + !(MV_6183_DEV_ID == mvCtrlModelGet())&& + !(MV_6183L_DEV_ID == mvCtrlModelGet())&& + !(MV_6281_DEV_ID == mvCtrlModelGet())&& + !(MV_6192_DEV_ID == mvCtrlModelGet())&& + !(MV_6190_DEV_ID == mvCtrlModelGet())&& + !(MV_6180_DEV_ID == mvCtrlModelGet())&& + !(MV_78XX0_DEV_ID == mvCtrlModelGet()) + )) + { + + /* PCI-Express configuration read work-around */ + + /* we will use one of the Punit (AHBToMbus) windows to access the xbar + and read the data from there */ + /* + Need to configure the 2 free Punit (AHB to MBus bridge) + address decoding windows: + Configure the flash Window to handle Configuration space requests + for PEX0/1: + 1. write 0x7931/0x7941 to the flash window and the size, + 79-xbar attr (pci cfg), 3/4-xbar target (pex0/1), 1-WinEn + 2. write base to flash window + + Configuration transactions from the CPU should write/read the data + to/from address of the form: + addr[31:28] = 0x5 (for PEX0) or 0x6 (for PEX1) + addr[27:24] = extended register number + addr[23:16] = bus number + addr[15:11] = device number + addr[10:8] = function number + addr[7:0] = register number + */ + + #include "ctrlEnv/sys/mvAhbToMbus.h" + { + MV_U32 winNum; + MV_AHB_TO_MBUS_DEC_WIN originWin; + MV_U32 pciAddr=0; + MV_U32 remapLow=0,remapHigh=0; + + /* + We will use DEV_CS2\Flash window for this workarround + */ + + winNum = mvAhbToMbusWinTargetGet(PEX_CONFIG_RW_WA_TARGET); + + /* save remap values if exist */ + if ((1 == winNum)||(0 == winNum)) + { + remapLow = MV_REG_READ(AHB_TO_MBUS_WIN_REMAP_LOW_REG(winNum)); + remapHigh = MV_REG_READ(AHB_TO_MBUS_WIN_REMAP_HIGH_REG(winNum)); + + } + + + /* save the original window values */ + mvAhbToMbusWinGet(winNum,&originWin); + + if (PEX_CONFIG_RW_WA_USE_ORIGINAL_WIN_VALUES) + { + /* set the window as xbar window */ + if (pexIf) + { + MV_REG_WRITE(AHB_TO_MBUS_WIN_CTRL_REG(winNum), + (0x7931 | (((originWin.addrWin.size >> 16)-1) ) << 16)); + } + else + { + MV_REG_WRITE(AHB_TO_MBUS_WIN_CTRL_REG(winNum), + (0x7941 | (((originWin.addrWin.size >> 16)-1) ) << 16)); + } + + MV_REG_WRITE(AHB_TO_MBUS_WIN_BASE_REG(winNum), + originWin.addrWin.baseLow); + + /*pciAddr = originWin.addrWin.baseLow;*/ + pciAddr = (MV_U32)CPU_MEMIO_UNCACHED_ADDR( + (MV_U32)originWin.addrWin.baseLow); + + } + else + { + /* set the window as xbar window */ + if (pexIf) + { + MV_REG_WRITE(AHB_TO_MBUS_WIN_CTRL_REG(winNum), + (0x7931 | (((PEX_CONFIG_RW_WA_SIZE >> 16)-1) ) << 16)); + } + else + { + MV_REG_WRITE(AHB_TO_MBUS_WIN_CTRL_REG(winNum), + (0x7941 | (((PEX_CONFIG_RW_WA_SIZE >> 16)-1) ) << 16)); + } + + MV_REG_WRITE(AHB_TO_MBUS_WIN_BASE_REG(winNum), + PEX_CONFIG_RW_WA_BASE); + + pciAddr = (MV_U32)CPU_MEMIO_UNCACHED_ADDR(PEX_CONFIG_RW_WA_BASE); + } + + + /* remap should be as base */ + if ((1 == winNum)||(0 == winNum)) + { + MV_REG_WRITE(AHB_TO_MBUS_WIN_REMAP_LOW_REG(winNum),pciAddr); + MV_REG_WRITE(AHB_TO_MBUS_WIN_REMAP_HIGH_REG(winNum),0); + + } + + /* extended register space */ + pciAddr |= (bus << 16); + pciAddr |= (dev << 11); + pciAddr |= (func << 8); + pciAddr |= (regOff & PXCAR_REG_NUM_MASK); /* lgacy register space */ + + pexData = *(MV_U32*)pciAddr; + pexData = MV_32BIT_LE(pexData); /* Data always in LE */ + + /* restore the original window values */ + mvAhbToMbusWinSet(winNum,&originWin); + + /* restore original remap values*/ + if ((1 == winNum)||(0 == winNum)) + { + MV_REG_WRITE(AHB_TO_MBUS_WIN_REMAP_LOW_REG(winNum),remapLow); + MV_REG_WRITE(AHB_TO_MBUS_WIN_REMAP_HIGH_REG(winNum),remapHigh); + + } + } + } + else +#endif + { + /* Read the Data returned in the PEX Data register */ + pexData = MV_REG_READ(PEX_CFG_DATA_REG(pexIf)); + + } + + DB(mvOsPrintf("mvPexConfigRead: got : %x \n",pexData)); + + return pexData; + +} + +/******************************************************************************* +* mvPexConfigWrite - Write to configuration space +* +* DESCRIPTION: +* This function performs a 32 bit write to PEX configuration space. +* It supports both type 0 and type 1 of Configuration Transactions +* (local and over bridge). In order to write to local bus segment, use +* bus number retrieved from mvPexLocalBusNumGet(). Other bus numbers +* will result configuration transaction of type 1 (over bridge). +* +* INPUT: +* pexIf - PEX interface number. +* bus - PEX segment bus number. +* dev - PEX device number. +* func - Function number. +* regOffs - Register offset. +* data - 32bit data. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_BAD_PARAM for bad parameters ,MV_ERROR on error ! otherwise MV_OK +* +*******************************************************************************/ +MV_STATUS mvPexConfigWrite(MV_U32 pexIf, MV_U32 bus, MV_U32 dev, + MV_U32 func, MV_U32 regOff, MV_U32 data) +{ +#if defined(PCIE_VIRTUAL_BRIDGE_SUPPORT) + return mvPexVrtBrgConfigWrite (pexIf, bus, dev, func, regOff, data); +} + +MV_STATUS mvPexHwConfigWrite(MV_U32 pexIf, MV_U32 bus, MV_U32 dev, + MV_U32 func, MV_U32 regOff, MV_U32 data) +{ +#endif + MV_U32 pexData = 0; + MV_U32 localDev,localBus; + + /* Parameter checking */ + if (PEX_DEFAULT_IF != pexIf) + { + if (pexIf >= mvCtrlPexMaxIfGet()) + { + mvOsPrintf("mvPexConfigWrite: ERR. Invalid PEX interface %d\n", + pexIf); + return MV_ERROR; + } + } + + if (dev >= MAX_PEX_DEVICES) + { + mvOsPrintf("mvPexConfigWrite: ERR. device number illigal %d\n",dev); + return MV_BAD_PARAM; + } + + if (func >= MAX_PEX_FUNCS) + { + mvOsPrintf("mvPexConfigWrite: ERR. function number illigal %d\n", func); + return MV_ERROR; + } + + if (bus >= MAX_PEX_BUSSES) + { + mvOsPrintf("mvPexConfigWrite: ERR. bus number illigal %d\n", bus); + return MV_ERROR; + } + + + + localDev = mvPexLocalDevNumGet(pexIf); + localBus = mvPexLocalBusNumGet(pexIf); + + + /* in PCI Express we have only one device number other than ourselves*/ + /* and this number is the first number we encounter + else than the localDev that can be any valid dev number*/ + /* pex spec define return on config read/write on any device */ + if (bus == localBus) + { + + if (localDev == 0) + { + /* if local dev is 0 then the first number we encounter + after 0 is 1 */ + if ((dev != 1)&&(dev != localDev)) + { + return MV_ERROR; + } + + } + else + { + /* if local dev is not 0 then the first number we encounter + is 0 */ + + if ((dev != 0)&&(dev != localDev)) + { + return MV_ERROR; + } + } + + + } + + /* if we are not accessing ourselves , then check the link */ + if ((dev != localDev) || (bus != localBus) ) + { + /* workarround */ + /* when no link return MV_ERROR */ + + pexData = MV_REG_READ(PEX_STATUS_REG(pexIf)); + + if ((pexData & PXSR_DL_DOWN)) + { + return MV_ERROR; + } + + } + + pexData =0; + + /* Creating PEX address to be passed */ + pexData |= (bus << PXCAR_BUS_NUM_OFFS); + pexData |= (dev << PXCAR_DEVICE_NUM_OFFS); + pexData |= (func << PXCAR_FUNC_NUM_OFFS); + pexData |= (regOff & PXCAR_REG_NUM_MASK); /* lgacy register space */ + /* extended register space */ + pexData |=(((regOff & PXCAR_REAL_EXT_REG_NUM_MASK) >> + PXCAR_REAL_EXT_REG_NUM_OFFS) << PXCAR_EXT_REG_NUM_OFFS); + pexData |= PXCAR_CONFIG_EN; + + DB(mvOsPrintf("mvPexConfigWrite: If=%x bus=%x func=%x dev=%x regOff=%x data=%x \n", + pexIf,bus,func,dev,regOff,data,pexData) ); + + /* Write the address to the PEX configuration address register */ + MV_REG_WRITE(PEX_CFG_ADDR_REG(pexIf), pexData); + + /* Clear CPU pipe. Important where CPU can perform OOO execution */ + CPU_PIPE_FLUSH; + + /* In order to let the PEX controller absorbed the address of the read */ + /* transaction we perform a validity check that the address was written */ + if(pexData != MV_REG_READ(PEX_CFG_ADDR_REG(pexIf))) + { + return MV_ERROR; + } + + /* Write the Data passed to the PEX Data register */ + MV_REG_WRITE(PEX_CFG_DATA_REG(pexIf), data); + + return MV_OK; + +} + +/******************************************************************************* +* mvPexMasterEnable - Enable/disale PEX interface master transactions. +* +* DESCRIPTION: +* This function performs read modified write to PEX command status +* (offset 0x4) to set/reset bit 2. After this bit is set, the PEX +* master is allowed to gain ownership on the bus, otherwise it is +* incapable to do so. +* +* INPUT: +* pexIf - PEX interface number. +* enable - Enable/disable parameter. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_BAD_PARAM for bad parameters ,MV_ERROR on error ! otherwise MV_OK +* +*******************************************************************************/ +MV_STATUS mvPexMasterEnable(MV_U32 pexIf, MV_BOOL enable) +{ + MV_U32 pexCommandStatus; + MV_U32 localBus; + MV_U32 localDev; + + /* Parameter checking */ + if (pexIf >= mvCtrlPexMaxIfGet()) + { + mvOsPrintf("mvPexMasterEnable: ERR. Invalid PEX interface %d\n", pexIf); + return MV_ERROR; + } + + localBus = mvPexLocalBusNumGet(pexIf); + localDev = mvPexLocalDevNumGet(pexIf); + + pexCommandStatus = MV_REG_READ(PEX_CFG_DIRECT_ACCESS(pexIf, + PEX_STATUS_AND_COMMAND)); + + + if (MV_TRUE == enable) + { + pexCommandStatus |= PXSAC_MASTER_EN; + } + else + { + pexCommandStatus &= ~PXSAC_MASTER_EN; + } + + + MV_REG_WRITE(PEX_CFG_DIRECT_ACCESS(pexIf,PEX_STATUS_AND_COMMAND), + pexCommandStatus); + + return MV_OK; +} + + +/******************************************************************************* +* mvPexSlaveEnable - Enable/disale PEX interface slave transactions. +* +* DESCRIPTION: +* This function performs read modified write to PEX command status +* (offset 0x4) to set/reset bit 0 and 1. After those bits are set, +* the PEX slave is allowed to respond to PEX IO space access (bit 0) +* and PEX memory space access (bit 1). +* +* INPUT: +* pexIf - PEX interface number. +* dev - PEX device number. +* enable - Enable/disable parameter. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_BAD_PARAM for bad parameters ,MV_ERROR on error ! otherwise MV_OK +* +*******************************************************************************/ +MV_STATUS mvPexSlaveEnable(MV_U32 pexIf, MV_U32 bus,MV_U32 dev, MV_BOOL enable) +{ + MV_U32 pexCommandStatus; + MV_U32 RegOffs; + + /* Parameter checking */ + if (pexIf >= mvCtrlPexMaxIfGet()) + { + mvOsPrintf("mvPexSlaveEnable: ERR. Invalid PEX interface %d\n", pexIf); + return MV_BAD_PARAM; + } + if (dev >= MAX_PEX_DEVICES) + { + mvOsPrintf("mvPexLocalDevNumSet: ERR. device number illigal %d\n", dev); + return MV_BAD_PARAM; + + } + + + RegOffs = PEX_STATUS_AND_COMMAND; + + pexCommandStatus = mvPexConfigRead(pexIf, bus, dev, 0, RegOffs); + + if (MV_TRUE == enable) + { + pexCommandStatus |= (PXSAC_IO_EN | PXSAC_MEM_EN); + } + else + { + pexCommandStatus &= ~(PXSAC_IO_EN | PXSAC_MEM_EN); + } + + mvPexConfigWrite(pexIf, bus, dev, 0, RegOffs, pexCommandStatus); + + return MV_OK; + +} + +/******************************************************************************* +* mvPexLocalBusNumSet - Set PEX interface local bus number. +* +* DESCRIPTION: +* This function sets given PEX interface its local bus number. +* Note: In case the PEX interface is PEX-X, the information is read-only. +* +* INPUT: +* pexIf - PEX interface number. +* busNum - Bus number. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_NOT_ALLOWED in case PEX interface is PEX-X. +* MV_BAD_PARAM on bad parameters , +* otherwise MV_OK +* +*******************************************************************************/ +MV_STATUS mvPexLocalBusNumSet(MV_U32 pexIf, MV_U32 busNum) +{ + MV_U32 pexStatus; + MV_U32 localBus; + MV_U32 localDev; + + + /* Parameter checking */ + if (pexIf >= mvCtrlPexMaxIfGet()) + { + mvOsPrintf("mvPexLocalBusNumSet: ERR. Invalid PEX interface %d\n",pexIf); + return MV_BAD_PARAM; + } + if (busNum >= MAX_PEX_BUSSES) + { + mvOsPrintf("mvPexLocalBusNumSet: ERR. bus number illigal %d\n", busNum); + return MV_ERROR; + + } + + localBus = mvPexLocalBusNumGet(pexIf); + localDev = mvPexLocalDevNumGet(pexIf); + + + + pexStatus = MV_REG_READ(PEX_STATUS_REG(pexIf)); + + pexStatus &= ~PXSR_PEX_BUS_NUM_MASK; + + pexStatus |= (busNum << PXSR_PEX_BUS_NUM_OFFS) & PXSR_PEX_BUS_NUM_MASK; + + MV_REG_WRITE(PEX_STATUS_REG(pexIf), pexStatus); + + + return MV_OK; +} + + +/******************************************************************************* +* mvPexLocalBusNumGet - Get PEX interface local bus number. +* +* DESCRIPTION: +* This function gets the local bus number of a given PEX interface. +* +* INPUT: +* pexIf - PEX interface number. +* +* OUTPUT: +* None. +* +* RETURN: +* Local bus number.0xffffffff on Error +* +*******************************************************************************/ +MV_U32 mvPexLocalBusNumGet(MV_U32 pexIf) +{ + MV_U32 pexStatus; + + /* Parameter checking */ + if (PEX_DEFAULT_IF != pexIf) + { + if (pexIf >= mvCtrlPexMaxIfGet()) + { + mvOsPrintf("mvPexLocalBusNumGet: ERR. Invalid PEX interface %d\n",pexIf); + return 0xFFFFFFFF; + } + } + + + pexStatus = MV_REG_READ(PEX_STATUS_REG(pexIf)); + + pexStatus &= PXSR_PEX_BUS_NUM_MASK; + + return (pexStatus >> PXSR_PEX_BUS_NUM_OFFS); + +} + + +/******************************************************************************* +* mvPexLocalDevNumSet - Set PEX interface local device number. +* +* DESCRIPTION: +* This function sets given PEX interface its local device number. +* Note: In case the PEX interface is PEX-X, the information is read-only. +* +* INPUT: +* pexIf - PEX interface number. +* devNum - Device number. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_NOT_ALLOWED in case PEX interface is PEX-X. +* MV_BAD_PARAM on bad parameters , +* otherwise MV_OK +* +*******************************************************************************/ +MV_STATUS mvPexLocalDevNumSet(MV_U32 pexIf, MV_U32 devNum) +{ + MV_U32 pexStatus; + MV_U32 localBus; + MV_U32 localDev; + + /* Parameter checking */ + if (pexIf >= mvCtrlPexMaxIfGet()) + { + mvOsPrintf("mvPexLocalDevNumSet: ERR. Invalid PEX interface %d\n",pexIf); + return MV_BAD_PARAM; + } + if (devNum >= MAX_PEX_DEVICES) + { + mvOsPrintf("mvPexLocalDevNumSet: ERR. device number illigal %d\n", + devNum); + return MV_BAD_PARAM; + + } + + localBus = mvPexLocalBusNumGet(pexIf); + localDev = mvPexLocalDevNumGet(pexIf); + + + pexStatus = MV_REG_READ(PEX_STATUS_REG(pexIf)); + + pexStatus &= ~PXSR_PEX_DEV_NUM_MASK; + + pexStatus |= (devNum << PXSR_PEX_DEV_NUM_OFFS) & PXSR_PEX_DEV_NUM_MASK; + + MV_REG_WRITE(PEX_STATUS_REG(pexIf), pexStatus); + + + return MV_OK; +} + +/******************************************************************************* +* mvPexLocalDevNumGet - Get PEX interface local device number. +* +* DESCRIPTION: +* This function gets the local device number of a given PEX interface. +* +* INPUT: +* pexIf - PEX interface number. +* +* OUTPUT: +* None. +* +* RETURN: +* Local device number. 0xffffffff on Error +* +*******************************************************************************/ +MV_U32 mvPexLocalDevNumGet(MV_U32 pexIf) +{ + MV_U32 pexStatus; + + /* Parameter checking */ + + if (PEX_DEFAULT_IF != pexIf) + { + if (pexIf >= mvCtrlPexMaxIfGet()) + { + mvOsPrintf("mvPexLocalDevNumGet: ERR. Invalid PEX interface %d\n", + pexIf); + return 0xFFFFFFFF; + } + } + + pexStatus = MV_REG_READ(PEX_STATUS_REG(pexIf)); + + pexStatus &= PXSR_PEX_DEV_NUM_MASK; + + return (pexStatus >> PXSR_PEX_DEV_NUM_OFFS); +} + +MV_VOID mvPexPhyRegRead(MV_U32 pexIf, MV_U32 regOffset, MV_U16 *value) +{ + + MV_U32 regAddr; + if (pexIf >= mvCtrlPexMaxIfGet()) + { + mvOsPrintf("mvPexPhyRegRead: ERR. Invalid PEX interface %d\n", pexIf); + return; + } + regAddr = (BIT31 | ((regOffset & 0x3fff) << 16)); + MV_REG_WRITE(PEX_PHY_ACCESS_REG(pexIf), regAddr); + *value = MV_REG_READ(PEX_PHY_ACCESS_REG(pexIf)); +} + + +MV_VOID mvPexPhyRegWrite(MV_U32 pexIf, MV_U32 regOffset, MV_U16 value) +{ + + MV_U32 regAddr; + if(pexIf >= mvCtrlPexMaxIfGet()) + { + mvOsPrintf("mvPexPhyRegWrite: ERR. Invalid PEX interface %d\n", pexIf); + return; + } + regAddr = (((regOffset & 0x3fff) << 16) | value); + MV_REG_WRITE(PEX_PHY_ACCESS_REG(pexIf), regAddr); +} + +/******************************************************************************* +* mvPexActiveStateLinkPMEnable +* +* DESCRIPTION: +* Enable Active Link State Power Management +* +* INPUT: +* pexIf - PEX interface number. +* enable - MV_TRUE to enable ASPM, MV_FALSE to disable. +* +* OUTPUT: +* None +* +* RETURN: +* MV_OK on success , MV_ERROR otherwise +* +*******************************************************************************/ +MV_STATUS mvPexActiveStateLinkPMEnable(MV_U32 pexIf, MV_BOOL enable) +{ + MV_U32 reg; + + if(pexIf >= mvCtrlPexMaxIfGet()) + { + mvOsPrintf("mvPexActiveStateLinkPMEnable: ERR. Invalid PEX interface %d\n", pexIf); + return MV_ERROR; + } + + reg = MV_REG_READ(PEX_PWR_MNG_EXT_REG(pexIf)) & ~PXPMER_L1_ASPM_EN_MASK; + if(enable == MV_TRUE) + reg |= PXPMER_L1_ASPM_EN_MASK; + MV_REG_WRITE(PEX_PWR_MNG_EXT_REG(pexIf), reg); + + /* Enable / Disable L0/1 entry */ + reg = MV_REG_READ(PEX_CFG_DIRECT_ACCESS(pexIf, PEX_LINK_CTRL_STAT_REG)) + & ~PXLCSR_ASPM_CNT_MASK; + if(enable == MV_TRUE) + reg |= PXLCSR_ASPM_CNT_L0S_L1S_ENT_SUPP; + MV_REG_WRITE(PEX_CFG_DIRECT_ACCESS(pexIf, PEX_LINK_CTRL_STAT_REG), reg); + + return MV_OK; +} + + +/******************************************************************************* +* mvPexForceX1 +* +* DESCRIPTION: +* shut down lanes 1-3 if recognize that attached to an x1 end-point +* INPUT: +* pexIf - PEX interface number. +* +* OUTPUT: +* None +* +* RETURN: +* MV_OK on success , MV_ERROR otherwise +* +*******************************************************************************/ +MV_U32 mvPexForceX1(MV_U32 pexIf) +{ + MV_U32 regData = 0; + if(pexIf >= mvCtrlPexMaxIfGet()) + { + mvOsPrintf("mvPexForceX1: ERR. Invalid PEX interface %d\n", pexIf); + return MV_BAD_PARAM; + } + + regData = MV_REG_READ(PEX_CTRL_REG(pexIf)) & ~(PXCR_CONF_LINK_MASK) ; + regData |= PXCR_CONF_LINK_X1; + + MV_REG_WRITE(PEX_CTRL_REG(pexIf), regData); + return MV_OK; +} + +MV_BOOL mvPexIsPowerUp(MV_U32 pexIf) +{ + if(pexIf >= mvCtrlPexMaxIfGet()) + { + mvOsPrintf("mvPexIsPowerUp: ERR. Invalid PEX interface %d\n", pexIf); + return MV_FALSE; + } + return mvCtrlPwrClckGet(PEX_UNIT_ID, pexIf); +} + + +MV_VOID mvPexPowerDown(MV_U32 pexIf) +{ + if ( (mvCtrlModelGet() == MV_78XX0_DEV_ID) || + (mvCtrlModelGet() == MV_76100_DEV_ID) || + (mvCtrlModelGet() == MV_78100_DEV_ID) || + (mvCtrlModelGet() == MV_78200_DEV_ID) ) + { + mvCtrlPwrClckSet(PEX_UNIT_ID, pexIf, MV_FALSE); + } + else + { + MV_REG_WRITE((0x41B00 -(pexIf)*0x10000), 0x20800087); + } +} + + + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/pex/mvPex.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/pex/mvPex.h new file mode 100644 index 0000000..d8f1cdd --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/pex/mvPex.h @@ -0,0 +1,168 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#ifndef __INCPEXH +#define __INCPEXH + +#include "mvCommon.h" +#include "mvOs.h" +#include "pex/mvPexRegs.h" +#include "ctrlEnv/mvCtrlEnvSpec.h" + + + +/* NOTE not supported in this driver:*/ + + +/* defines */ +/* The number of supported PEX interfaces depend on Marvell controller */ +/* device number. This device number ID is located on the PEX unit */ +/* configuration header. This creates a loop where calling PEX */ +/* configuration read/write routine results a call to get PEX configuration */ +/* information etc. This macro defines a default PEX interface. This PEX */ +/* interface is sure to exist. */ +#define PEX_DEFAULT_IF 0 + + +/* typedefs */ +/* The Marvell controller supports both root complex and end point devices */ +/* This enumeration describes the PEX type. */ +typedef enum _mvPexType +{ + MV_PEX_ROOT_COMPLEX, /* root complex device */ + MV_PEX_END_POINT /* end point device */ +}MV_PEX_TYPE; + +typedef enum _mvPexWidth +{ + MV_PEX_WITDH_X1 = 1, + MV_PEX_WITDH_X2, + MV_PEX_WITDH_X3, + MV_PEX_WITDH_X4, + MV_PEX_WITDH_INVALID +}MV_PEX_WIDTH; + +/* PEX Bar attributes */ +typedef struct _mvPexMode +{ + MV_PEX_TYPE pexType; + MV_PEX_WIDTH pexWidth; + MV_BOOL pexLinkUp; +}MV_PEX_MODE; + + + +/* Global Functions prototypes */ +/* mvPexInit - Initialize PEX interfaces*/ +MV_STATUS mvPexHalInit(MV_U32 pexIf, MV_PEX_TYPE pexType); + +/* mvPexModeGet - Get Pex If mode */ +MV_U32 mvPexModeGet(MV_U32 pexIf,MV_PEX_MODE *pexMode); + +/* mvPexConfigRead - Read from configuration space */ +MV_U32 mvPexConfigRead (MV_U32 pexIf, MV_U32 bus, MV_U32 dev, + MV_U32 func,MV_U32 regOff); + +/* mvPexConfigWrite - Write to configuration space */ +MV_STATUS mvPexConfigWrite(MV_U32 pexIf, MV_U32 bus, MV_U32 dev, + MV_U32 func, MV_U32 regOff, MV_U32 data); + +/* mvPexMasterEnable - Enable/disale PEX interface master transactions.*/ +MV_STATUS mvPexMasterEnable(MV_U32 pexIf, MV_BOOL enable); + +/* mvPexSlaveEnable - Enable/disale PEX interface slave transactions.*/ +MV_STATUS mvPexSlaveEnable(MV_U32 pexIf, MV_U32 bus,MV_U32 dev, MV_BOOL enable); + +/* mvPexLocalBusNumSet - Set PEX interface local bus number.*/ +MV_STATUS mvPexLocalBusNumSet(MV_U32 pexIf, MV_U32 busNum); + +/* mvPexLocalBusNumGet - Get PEX interface local bus number.*/ +MV_U32 mvPexLocalBusNumGet(MV_U32 pexIf); + +/* mvPexLocalDevNumSet - Set PEX interface local device number.*/ +MV_STATUS mvPexLocalDevNumSet(MV_U32 pexIf, MV_U32 devNum); + +/* mvPexLocalDevNumGet - Get PEX interface local device number.*/ +MV_U32 mvPexLocalDevNumGet(MV_U32 pexIf); +/* mvPexForceX1 - Force PEX interface to X1 mode. */ +MV_U32 mvPexForceX1(MV_U32 pexIf); + +/* mvPexIsPowerUp - Is PEX interface Power up? */ +MV_BOOL mvPexIsPowerUp(MV_U32 pexIf); + +/* mvPexPowerDown - Power Down */ +MV_VOID mvPexPowerDown(MV_U32 pexIf); + +/* mvPexPowerUp - Power Up */ +MV_VOID mvPexPowerUp(MV_U32 pexIf); + +/* mvPexPhyRegRead - Pex phy read */ +MV_VOID mvPexPhyRegRead(MV_U32 pexIf, MV_U32 regOffset, MV_U16 *value); + +/* mvPexPhyRegWrite - Pex phy write */ +MV_VOID mvPexPhyRegWrite(MV_U32 pexIf, MV_U32 regOffset, MV_U16 value); + +MV_STATUS mvPexActiveStateLinkPMEnable(MV_U32 pexIf, MV_BOOL enable); + +#endif /* #ifndef __INCPEXH */ diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/pex/mvPexRegs.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/pex/mvPexRegs.h new file mode 100644 index 0000000..8ac1698 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/pex/mvPexRegs.h @@ -0,0 +1,751 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#ifndef __INCPEXREGSH +#define __INCPEXREGSH + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* defines */ +#define MAX_PEX_DEVICES 32 +#define MAX_PEX_FUNCS 8 +#define MAX_PEX_BUSSES 256 + + + +/*********************************************************/ +/* PCI Express Configuration Cycles Generation Registers */ +/*********************************************************/ + +#define PEX_CFG_ADDR_REG(pexIf) ((PEX_IF_BASE(pexIf)) + 0x18F8) +#define PEX_CFG_DATA_REG(pexIf) ((PEX_IF_BASE(pexIf)) + 0x18FC) +#define PEX_PHY_ACCESS_REG(pexIf) ((PEX_IF_BASE(pexIf)) + 0x1B00) +/* PCI Express Configuration Address Register */ +/* PEX_CFG_ADDR_REG (PXCAR)*/ + +#define PXCAR_REG_NUM_OFFS 2 +#define PXCAR_REG_NUM_MAX 0x3F +#define PXCAR_REG_NUM_MASK (PXCAR_REG_NUM_MAX << PXCAR_REG_NUM_OFFS) +#define PXCAR_FUNC_NUM_OFFS 8 +#define PXCAR_FUNC_NUM_MAX 0x7 +#define PXCAR_FUNC_NUM_MASK (PXCAR_FUNC_NUM_MAX << PXCAR_FUNC_NUM_OFFS) +#define PXCAR_DEVICE_NUM_OFFS 11 +#define PXCAR_DEVICE_NUM_MAX 0x1F +#define PXCAR_DEVICE_NUM_MASK (PXCAR_DEVICE_NUM_MAX << PXCAR_DEVICE_NUM_OFFS) +#define PXCAR_BUS_NUM_OFFS 16 +#define PXCAR_BUS_NUM_MAX 0xFF +#define PXCAR_BUS_NUM_MASK (PXCAR_BUS_NUM_MAX << PXCAR_BUS_NUM_OFFS) +#define PXCAR_EXT_REG_NUM_OFFS 24 +#define PXCAR_EXT_REG_NUM_MAX 0xF + +/* in pci express register address is now the legacy register address (8 bits) +with the new extended register address (more 4 bits) , below is the mask of +the upper 4 bits of the full register address */ + +#define PXCAR_REAL_EXT_REG_NUM_OFFS 8 +#define PXCAR_EXT_REG_NUM_MASK (PXCAR_EXT_REG_NUM_MAX << PXCAR_EXT_REG_NUM_OFFS) +#define PXCAR_CONFIG_EN BIT31 + +#define PXCAR_REAL_EXT_REG_NUM_OFFS 8 +#define PXCAR_REAL_EXT_REG_NUM_MASK (0xF << PXCAR_REAL_EXT_REG_NUM_OFFS) + +/* The traditional PCI spec defined 6-bit field to describe register offset.*/ +/* The new PCI Express extend the register offset by an extra 4-bits. */ +/* The below macro assign 10-bit register offset into the apprpreate */ +/* fields in the CFG_ADDR_REG */ +#define PXCAR_REG_OFFS_SET(regOffs) \ + ( (regOff & PXCAR_REG_NUM_MASK) | \ + ( ((regOff & PXCAR_REAL_EXT_REG_NUM_MASK) >> PXCAR_REAL_EXT_REG_NUM_OFFS) << PXCAR_EXT_REG_NUM_OFFS) ) + +/***********************************/ +/* PCI Express Interrupt registers */ +/***********************************/ +#define PEX_CAUSE_REG(pexIf) ((PEX_IF_BASE(pexIf)) + 0x1900) +#define PEX_MASK_REG(pexIf) ((PEX_IF_BASE(pexIf)) + 0x1910) + +#define PXICR_TX_REQ_IN_DLDOWN_ERR BIT0 /* Transmit request while field */ + /* of the PCI Express */ +/* PCI Express Interrupt Cause */ +/* PEX_INT_CAUSE_REG (PXICR)*/ +/* PEX_INT_MASK_REG*/ +/* +NOTE:All bits except bits[27:24] are Read/Write Clear only. A cause bit sets +upon an error event occurrence. A write of 0 clears the bit. A write of 1 has +no affect. Bits[24:27} are set and cleared upon reception of interrupt +emulation messages. + +Mask bit per cause bit. If a bit is set to 1, the corresponding event is +enabled. Mask does not affect setting of the Interrupt Cause register bits; +it only affects the assertion of the interrupt .*/ + + +#define PXICR_MDIS_CAUSE BIT1 /* Attempt to generate PCI transaction + while master is disabled */ +#define PXICR_ERR_WRTO_REG_CAUSE BIT3 /* Erroneous write attempt to + PCI Express internal register*/ +#define PXICR_HIT_DFLT_WIN_ERR BIT4 /* Hit Default Window Error */ +#define PXICR_RX_RAM_PAR_ERR BIT6 /* Rx RAM Parity Error */ +#define PXICR_TX_RAM_PAR_ERR BIT7 /* Tx RAM Parity Error */ +#define PXICR_COR_ERR_DET BIT8 /* Correctable Error Detected*/ +#define PXICR_NF_ERR_DET BIT9 /* Non-Fatal Error Detected*/ +#define PXICR_FERR_DET BIT10 /* Fatal Error Detected*/ +#define PXICR_DSTATE_CHANGE BIT11 /* Dstate Change Indication*/ +#define PXICR_BIST BIT12 /* PCI-Express BIST activated*/ +#define PXICR_FLW_CTRL_PROT BIT14 /* Flow Control Protocol Error */ + +#define PXICR_RCV_UR_CA_ERR BIT15 /* Received UR or CA status. */ +#define PXICR_RCV_ERR_FATAL BIT16 /* Received ERR_FATAL message.*/ +#define PXICR_RCV_ERR_NON_FATAL BIT17 /* Received ERR_NONFATAL message*/ +#define PXICR_RCV_ERR_COR BIT18 /* Received ERR_COR message.*/ +#define PXICR_RCV_CRS BIT19 /* Received CRS completion status*/ +#define PXICR_SLV_HOT_RESET BIT20 /* Received Hot Reset Indication*/ +#define PXICR_SLV_DIS_LINK BIT21 /* Slave Disable Link Indication*/ +#define PXICR_SLV_LB BIT22 /* Slave Loopback Indication*/ +#define PXICR_LINK_FAIL BIT23 /* Link Failure indication.*/ +#define PXICR_RCV_INTA BIT24 /* IntA status.*/ +#define PXICR_RCV_INTB BIT25 /* IntB status.*/ +#define PXICR_RCV_INTC BIT26 /* IntC status.*/ +#define PXICR_RCV_INTD BIT27 /* IntD status.*/ +#define PXICR_RCV_PM_PME BIT28 /* Received PM_PME message. */ + + +/********************************************/ +/* PCI Express Control and Status Registers */ +/********************************************/ +#define PEX_CTRL_REG(pexIf) ((PEX_IF_BASE(pexIf)) + 0x1A00) +#define PEX_STATUS_REG(pexIf) ((PEX_IF_BASE(pexIf)) + 0x1A04) +#define PEX_COMPLT_TMEOUT_REG(pexIf) ((PEX_IF_BASE(pexIf)) + 0x1A10) +#define PEX_PWR_MNG_EXT_REG(pexIf) ((PEX_IF_BASE(pexIf)) + 0x1A18) +#define PEX_FLOW_CTRL_REG(pexIf) ((PEX_IF_BASE(pexIf)) + 0x1A20) +#define PEX_ACK_TMR_4X_REG(pexIf) ((PEX_IF_BASE(pexIf)) + 0x1A30) +#define PEX_ACK_TMR_1X_REG(pexIf) ((PEX_IF_BASE(pexIf)) + 0x1A40) +#define PEX_TL_CTRL_REG(pexIf) ((PEX_IF_BASE(pexIf)) + 0x1AB0) + + +#define PEX_RAM_PARITY_CTRL_REG(pexIf) ((PEX_IF_BASE(pexIf)) + 0x1A50) +/* PCI Express Control Register */ +/* PEX_CTRL_REG (PXCR) */ + +#define PXCR_CONF_LINK_OFFS 0 +#define PXCR_CONF_LINK_MASK (1 << PXCR_CONF_LINK_OFFS) +#define PXCR_CONF_LINK_X4 (0 << PXCR_CONF_LINK_OFFS) +#define PXCR_CONF_LINK_X1 (1 << PXCR_CONF_LINK_OFFS) +#define PXCR_DEV_TYPE_CTRL_OFFS 1 /*PCI ExpressDevice Type Control*/ +#define PXCR_DEV_TYPE_CTRL_MASK BIT1 +#define PXCR_DEV_TYPE_CTRL_CMPLX (1 << PXCR_DEV_TYPE_CTRL_OFFS) +#define PXCR_DEV_TYPE_CTRL_POINT (0 << PXCR_DEV_TYPE_CTRL_OFFS) +#define PXCR_CFG_MAP_TO_MEM_EN BIT2 /* Configuration Header Mapping + to Memory Space Enable */ + +#define PXCR_CFG_MAP_TO_MEM_EN BIT2 /* Configuration Header Mapping + to Memory Space Enable*/ + +#define PXCR_RSRV1_OFFS 5 +#define PXCR_RSRV1_MASK (0x7 << PXCR_RSRV1_OFFS) +#define PXCR_RSRV1_VAL (0x0 << PXCR_RSRV1_OFFS) + +#define PXCR_CONF_MAX_OUTSTND_OFFS 8 /*Maximum outstanding NP requests as a master*/ +#define PXCR_CONF_MAX_OUTSTND_MASK (0x3 << PXCR_CONF_MAX_OUTSTND_OFFS) + + +#define PXCR_CONF_NFTS_OFFS 16 /*number of FTS Ordered-Sets*/ +#define PXCR_CONF_NFTS_MASK (0xff << PXCR_CONF_NFTS_OFFS) + +#define PXCR_CONF_MSTR_HOT_RESET BIT24 /*Master Hot-Reset.*/ +#define PXCR_CONF_MSTR_LB BIT26 /* Master Loopback */ +#define PXCR_CONF_MSTR_DIS_SCRMB BIT27 /* Master Disable Scrambling*/ +#define PXCR_CONF_DIRECT_DIS_SCRMB BIT28 /* Direct Disable Scrambling*/ + +/* PCI Express Status Register */ +/* PEX_STATUS_REG (PXSR) */ + +#define PXSR_DL_DOWN BIT0 /* DL_Down indication.*/ + +#define PXSR_PEX_BUS_NUM_OFFS 8 /* Bus Number Indication */ +#define PXSR_PEX_BUS_NUM_MASK (0xff << PXSR_PEX_BUS_NUM_OFFS) + +#define PXSR_PEX_DEV_NUM_OFFS 16 /* Device Number Indication */ +#define PXSR_PEX_DEV_NUM_MASK (0x1f << PXSR_PEX_DEV_NUM_OFFS) + +#define PXSR_PEX_SLV_HOT_RESET BIT24 /* Slave Hot Reset Indication*/ +#define PXSR_PEX_SLV_DIS_LINK BIT25 /* Slave Disable Link Indication*/ +#define PXSR_PEX_SLV_LB BIT26 /* Slave Loopback Indication*/ +#define PXSR_PEX_SLV_DIS_SCRMB BIT27 /* Slave Disable Scrambling Indication*/ + + +/* PCI Express Completion Timeout Register */ +/* PEX_COMPLT_TMEOUT_REG (PXCTR)*/ + +#define PXCTR_CMP_TO_THRSHLD_OFFS 0 /* Completion Timeout Threshold */ +#define PXCTR_CMP_TO_THRSHLD_MASK (0xffff << PXCTR_CMP_TO_THRSHLD_OFFS) + +/* PCI Express Power Management Extended Register */ +/* PEX_PWR_MNG_EXT_REG (PXPMER) */ + +#define PXPMER_L1_ASPM_EN_OFFS 1 +#define PXPMER_L1_ASPM_EN_MASK (0x1 << PXPMER_L1_ASPM_EN_OFFS) + +/* PCI Express Flow Control Register */ +/* PEX_FLOW_CTRL_REG (PXFCR)*/ + +#define PXFCR_PH_INIT_FC_OFFS 0 /*Posted Headers Flow Control Credit + Initial Value.*/ +#define PXFCR_PH_INIT_FC_MASK (0xff << PXFCR_PH_INIT_FC_OFFS) + + +#define PXFCR_NPH_INIT_FC_OFFS 8 /* Classified Non-Posted Headers + Flow Control Credit Initial Value*/ +#define PXFCR_NPH_INIT_FC_MASK (0xff << PXFCR_NPH_INIT_FC_OFFS) + +#define PXFCR_CH_INIT_FC_OFFS 16 /* Completion Headers Flow Control + Credit Initial Value Infinite*/ + +#define PXFCR_CH_INIT_FC_MASK (0xff << PXFCR_CH_INIT_FC_OFFS) + +#define PXFCR_FC_UPDATE_TO_OFFS 24 /* Flow Control Update Timeout */ +#define PXFCR_FC_UPDATE_TO_MASK (0xff << PXFCR_FC_UPDATE_TO_OFFS) + +/* PCI Express Acknowledge Timers (4X) Register */ +/* PEX_ACK_TMR_4X_REG (PXAT4R) */ +#define PXAT1R_ACK_LAT_TOX4_OFFS 0 /* Ack Latency Timer Timeout Value */ +#define PXAT1R_ACK_LAT_TOX4_MASK (0xffff << PXAT4R_ACK_LAT_TOX1_OFFS) +#define PXAT1R_ACK_RPLY_TOX4_OFFS 16 /* Ack Replay Timer Timeout Value */ +#define PXAT1R_ACK_RPLY_TOX4_MASK (0xffff << PXAT1R_ACK_RPLY_TOX1_OFFS) + +/* PCI Express Acknowledge Timers (1X) Register */ +/* PEX_ACK_TMR_1X_REG (PXAT1R) */ + +#define PXAT1R_ACK_LAT_TOX1_OFFS 0 /* Acknowledge Latency Timer Timeout + Value for 1X Link*/ +#define PXAT1R_ACK_LAT_TOX1_MASK (0xffff << PXAT1R_ACK_LAT_TOX1_OFFS) + +#define PXAT1R_ACK_RPLY_TOX1_OFFS 16 /* Acknowledge Replay Timer Timeout + Value for 1X*/ +#define PXAT1R_ACK_RPLY_TOX1_MASK (0xffff << PXAT1R_ACK_RPLY_TOX1_OFFS) + + +/* PCI Express TL Control Register */ +/* PEX_TL_CTRL_REG (PXTCR) */ + +#define PXTCR_TX_CMP_BUFF_NO_OFFS 8 /*Number of completion buffers in Tx*/ +#define PXTCR_TX_CMP_BUFF_NO_MASK (0xf << PXTCR_TX_CMP_BUFF_NO_OFFS) + +/* PCI Express Debug MAC Control Register */ +/* PEX_DEBUG_MAC_CTRL_REG (PXDMCR) */ + +#define PXDMCR_LINKUP BIT4 + + + +/**********************************************/ +/* PCI Express Configuration Header Registers */ +/**********************************************/ +#define PEX_CFG_DIRECT_ACCESS(pexIf,cfgReg) ((PEX_IF_BASE(pexIf)) + (cfgReg)) + +#define PEX_DEVICE_AND_VENDOR_ID 0x000 +#define PEX_STATUS_AND_COMMAND 0x004 +#define PEX_CLASS_CODE_AND_REVISION_ID 0x008 +#define PEX_BIST_HDR_TYPE_LAT_TMR_CACHE_LINE 0x00C +#define PEX_MEMORY_BAR_BASE_ADDR(barNum) (0x010 + ((barNum) << 2)) +#define PEX_MV_BAR_BASE(barNum) (0x010 + (barNum) * 8) +#define PEX_MV_BAR_BASE_HIGH(barNum) (0x014 + (barNum) * 8) +#define PEX_BAR0_INTER_REG 0x010 +#define PEX_BAR0_INTER_REG_HIGH 0x014 +#define PEX_BAR1_REG 0x018 +#define PEX_BAR1_REG_HIGH 0x01C +#define PEX_BAR2_REG 0x020 +#define PEX_BAR2_REG_HIGH 0x024 + +#define PEX_SUBSYS_ID_AND_SUBSYS_VENDOR_ID 0x02C +#define PEX_EXPANSION_ROM_BASE_ADDR_REG 0x030 +#define PEX_CAPABILTY_LIST_POINTER 0x034 +#define PEX_INTERRUPT_PIN_AND_LINE 0x03C + +/* capability list */ +#define PEX_POWER_MNG_CAPABILITY 0x040 +#define PEX_POWER_MNG_STATUS_CONTROL 0x044 + +#define PEX_MSI_MESSAGE_CONTROL 0x050 +#define PEX_MSI_MESSAGE_ADDR 0x054 +#define PEX_MSI_MESSAGE_HIGH_ADDR 0x058 +#define PEX_MSI_MESSAGE_DATA 0x05C + +#define PEX_CAPABILITY_REG 0x60 +#define PEX_DEV_CAPABILITY_REG 0x64 +#define PEX_DEV_CTRL_STAT_REG 0x68 +#define PEX_LINK_CAPABILITY_REG 0x6C +#define PEX_LINK_CTRL_STAT_REG 0x70 + +#define PEX_ADV_ERR_RPRT_HDR_TRGT_REG 0x100 +#define PEX_UNCORRECT_ERR_STAT_REG 0x104 +#define PEX_UNCORRECT_ERR_MASK_REG 0x108 +#define PEX_UNCORRECT_ERR_SERVITY_REG 0x10C +#define PEX_CORRECT_ERR_STAT_REG 0x110 +#define PEX_CORRECT_ERR_MASK_REG 0x114 +#define PEX_ADV_ERR_CAPABILITY_CTRL_REG 0x118 +#define PEX_HDR_LOG_FIRST_DWORD_REG 0x11C +#define PEX_HDR_LOG_SECOND_DWORD_REG 0x120 +#define PEX_HDR_LOG_THIRD_DWORD_REG 0x124 +#define PEX_HDR_LOG_FOURTH_DWORD_REG 0x128 + + + +/* PCI Express Device and Vendor ID Register*/ +/*PEX_DEVICE_AND_VENDOR_ID (PXDAVI)*/ + +#define PXDAVI_VEN_ID_OFFS 0 /* Vendor ID */ +#define PXDAVI_VEN_ID_MASK (0xffff << PXDAVI_VEN_ID_OFFS) + +#define PXDAVI_DEV_ID_OFFS 16 /* Device ID */ +#define PXDAVI_DEV_ID_MASK (0xffff << PXDAVI_DEV_ID_OFFS) + + +/* PCI Express Command and Status Register*/ +/*PEX_STATUS_AND_COMMAND (PXSAC)*/ + +#define PXSAC_IO_EN BIT0 /* IO Enable */ +#define PXSAC_MEM_EN BIT1 /* Memory Enable */ +#define PXSAC_MASTER_EN BIT2 /* Master Enable */ +#define PXSAC_PERR_EN BIT6 /* Parity Errors Respond Enable */ +#define PXSAC_SERR_EN BIT8 /* Ability to assert SERR# line */ +#define PXSAC_INT_DIS BIT10 /* Interrupt Disable */ +#define PXSAC_INT_STAT BIT19 /* Interrupt Status */ +#define PXSAC_CAP_LIST BIT20 /* Capability List Support */ +#define PXSAC_MAS_DATA_PERR BIT24 /* Master Data Parity Error */ +#define PXSAC_SLAVE_TABORT BIT27 /* Signalled Target Abort */ +#define PXSAC_RT_ABORT BIT28 /* Recieved Target Abort */ +#define PXSAC_MABORT BIT29 /* Recieved Master Abort */ +#define PXSAC_SYSERR BIT30 /* Signalled system error */ +#define PXSAC_DET_PARERR BIT31 /* Detect Parity Error */ + + +/* PCI Express Class Code and Revision ID Register*/ +/*PEX_CLASS_CODE_AND_REVISION_ID (PXCCARI)*/ + +#define PXCCARI_REVID_OFFS 0 /* Revision ID */ +#define PXCCARI_REVID_MASK (0xff << PXCCARI_REVID_OFFS) + +#define PXCCARI_FULL_CLASS_OFFS 8 /* Full Class Code */ +#define PXCCARI_FULL_CLASS_MASK (0xffffff << PXCCARI_FULL_CLASS_OFFS) + +#define PXCCARI_PROGIF_OFFS 8 /* Prog .I/F*/ +#define PXCCARI_PROGIF_MASK (0xff << PXCCARI_PROGIF_OFFS) + +#define PXCCARI_SUB_CLASS_OFFS 16 /* Sub Class*/ +#define PXCCARI_SUB_CLASS_MASK (0xff << PXCCARI_SUB_CLASS_OFFS) + +#define PXCCARI_BASE_CLASS_OFFS 24 /* Base Class*/ +#define PXCCARI_BASE_CLASS_MASK (0xff << PXCCARI_BASE_CLASS_OFFS) + + +/* PCI Express BIST, Header Type and Cache Line Size Register*/ +/*PEX_BIST_HDR_TYPE_LAT_TMR_CACHE_LINE (PXBHTLTCL)*/ + +#define PXBHTLTCL_CACHELINE_OFFS 0 /* Specifies the cache line size */ +#define PXBHTLTCL_CACHELINE_MASK (0xff << PXBHTLTCL_CACHELINE_OFFS) + +#define PXBHTLTCL_HEADTYPE_FULL_OFFS 16 /* Full Header Type */ +#define PXBHTLTCL_HEADTYPE_FULL_MASK (0xff << PXBHTLTCL_HEADTYPE_FULL_OFFS) + +#define PXBHTLTCL_MULTI_FUNC BIT23 /* Multi/Single function */ + +#define PXBHTLTCL_HEADER_OFFS 16 /* Header type */ +#define PXBHTLTCL_HEADER_MASK (0x7f << PXBHTLTCL_HEADER_OFFS) +#define PXBHTLTCL_HEADER_STANDARD (0x0 << PXBHTLTCL_HEADER_OFFS) +#define PXBHTLTCL_HEADER_PCI2PCI_BRIDGE (0x1 << PXBHTLTCL_HEADER_OFFS) + + +#define PXBHTLTCL_BISTCOMP_OFFS 24 /* BIST Completion Code */ +#define PXBHTLTCL_BISTCOMP_MASK (0xf << PXBHTLTCL_BISTCOMP_OFFS) + +#define PXBHTLTCL_BISTACT BIT30 /* BIST Activate bit */ +#define PXBHTLTCL_BISTCAP BIT31 /* BIST Capable Bit */ +#define PXBHTLTCL_BISTCAP_OFFS 31 +#define PXBHTLTCL_BISTCAP_MASK BIT31 +#define PXBHTLTCL_BISTCAP_VAL 0 + + +/* PCI Express Subsystem Device and Vendor ID */ +/*PEX_SUBSYS_ID_AND_SUBSYS_VENDOR_ID (PXSIASVI)*/ + +#define PXSIASVI_VENID_OFFS 0 /* Subsystem Manufacturer Vendor ID Number */ +#define PXSIASVI_VENID_MASK (0xffff << PXSIASVI_VENID_OFFS) + +#define PXSIASVI_DEVID_OFFS 16 /* Subsystem Device ID Number */ +#define PXSIASVI_DEVID_MASK (0xffff << PXSIASVI_DEVID_OFFS) + + +/* PCI Express Capability List Pointer Register*/ +/*PEX_CAPABILTY_LIST_POINTER (PXCLP)*/ + +#define PXCLP_CAPPTR_OFFS 0 /* Capability List Pointer */ +#define PXCLP_CAPPTR_MASK (0xff << PXCLP_CAPPTR_OFFS) + +/* PCI Express Interrupt Pin and Line Register */ +/*PEX_INTERRUPT_PIN_AND_LINE (PXIPAL)*/ + +#define PXIPAL_INTLINE_OFFS 0 /* Interrupt line (IRQ) */ +#define PXIPAL_INTLINE_MASK (0xff << PXIPAL_INTLINE_OFFS) + +#define PXIPAL_INTPIN_OFFS 8 /* interrupt pin (A,B,C,D) */ +#define PXIPAL_INTPIN_MASK (0xff << PXIPAL_INTPIN_OFFS) + + +/* PCI Express Power Management Capability Header Register*/ +/*PEX_POWER_MNG_CAPABILITY (PXPMC)*/ + +#define PXPMC_CAP_ID_OFFS 0 /* Capability ID */ +#define PXPMC_CAP_ID_MASK (0xff << PXPMC_CAP_ID_OFFS) + +#define PXPMC_NEXT_PTR_OFFS 8 /* Next Item Pointer */ +#define PXPMC_NEXT_PTR_MASK (0xff << PXPMC_NEXT_PTR_OFFS) + +#define PXPMC_PMC_VER_OFFS 16 /* PCI Power Management Capability Version*/ +#define PXPMC_PMC_VER_MASK (0x7 << PXPMC_PMC_VER_OFFS) + +#define PXPMC_DSI BIT21/* Device Specific Initialization */ + +#define PXPMC_AUX_CUR_OFFS 22 /* Auxiliary Current Requirements */ +#define PXPMC_AUX_CUR_MASK (0x7 << PXPMC_AUX_CUR_OFFS) + +#define PXPMC_D1_SUP BIT25 /* D1 Power Management support*/ + +#define PXPMC_D2_SUP BIT26 /* D2 Power Management support*/ + +#define PXPMC_PME_SUP_OFFS 27 /* PM Event generation support*/ +#define PXPMC_PME_SUP_MASK (0x1f << PXPMC_PME_SUP_OFFS) + +/* PCI Express Power Management Control and Status Register*/ +/*PEX_POWER_MNG_STATUS_CONTROL (PXPMSC)*/ + +#define PXPMSC_PM_STATE_OFFS 0 /* Power State */ +#define PXPMSC_PM_STATE_MASK (0x3 << PXPMSC_PM_STATE_OFFS) +#define PXPMSC_PM_STATE_D0 (0x0 << PXPMSC_PM_STATE_OFFS) +#define PXPMSC_PM_STATE_D1 (0x1 << PXPMSC_PM_STATE_OFFS) +#define PXPMSC_PM_STATE_D2 (0x2 << PXPMSC_PM_STATE_OFFS) +#define PXPMSC_PM_STATE_D3 (0x3 << PXPMSC_PM_STATE_OFFS) + +#define PXPMSC_PME_EN BIT8/* PM_PME Message Generation Enable */ + +#define PXPMSC_PM_DATA_SEL_OFFS 9 /* Data Select*/ +#define PXPMSC_PM_DATA_SEL_MASK (0xf << PXPMSC_PM_DATA_SEL_OFFS) + +#define PXPMSC_PM_DATA_SCALE_OFFS 13 /* Data Scale */ +#define PXPMSC_PM_DATA_SCALE_MASK (0x3 << PXPMSC_PM_DATA_SCALE_OFFS) + +#define PXPMSC_PME_STAT BIT15/* PME Status */ + +#define PXPMSC_PM_DATA_OFFS 24 /* State Data */ +#define PXPMSC_PM_DATA_MASK (0xff << PXPMSC_PM_DATA_OFFS) + + +/* PCI Express MSI Message Control Register*/ +/*PEX_MSI_MESSAGE_CONTROL (PXMMC)*/ + +#define PXMMC_CAP_ID_OFFS 0 /* Capability ID */ +#define PXMMC_CAP_ID_MASK (0xff << PXMMC_CAP_ID_OFFS) + +#define PXMMC_NEXT_PTR_OFFS 8 /* Next Item Pointer */ +#define PXMMC_NEXT_PTR_MASK (0xff << PXMMC_NEXT_PTR_OFFS) + +#define PXMMC_MSI_EN BIT18 /* MSI Enable */ + +#define PXMMC_MULTI_CAP_OFFS 17 /* Multiple Message Capable */ +#define PXMMC_MULTI_CAP_MASK (0x7 << PXMMC_MULTI_CAP_OFFS) + +#define PXMMC_MULTI_EN_OFFS 20 /* Multiple Messages Enable */ +#define PXMMC_MULTI_EN_MASK (0x7 << PXMMC_MULTI_EN_OFFS) + +#define PXMMC_ADDR64 BIT23 /* 64-bit Addressing Capable */ + + +/* PCI Express MSI Message Address Register*/ +/*PEX_MSI_MESSAGE_ADDR (PXMMA)*/ + +#define PXMMA_MSI_ADDR_OFFS 2 /* Message Address corresponds to + Address[31:2] of the MSI MWr TLP*/ +#define PXMMA_MSI_ADDR_MASK (0x3fffffff << PXMMA_MSI_ADDR_OFFS) + + +/* PCI Express MSI Message Address (High) Register */ +/*PEX_MSI_MESSAGE_HIGH_ADDR (PXMMHA)*/ + +#define PXMMA_MSI_ADDR_H_OFFS 0 /* Message Upper Address corresponds to + Address[63:32] of the MSI MWr TLP*/ +#define PXMMA_MSI_ADDR_H_MASK (0xffffffff << PXMMA_MSI_ADDR_H_OFFS ) + + +/* PCI Express MSI Message Data Register*/ +/*PEX_MSI_MESSAGE_DATA (PXMMD)*/ + +#define PXMMD_MSI_DATA_OFFS 0 /* Message Data */ +#define PXMMD_MSI_DATA_MASK (0xffff << PXMMD_MSI_DATA_OFFS ) + + +/* PCI Express Capability Register*/ +/*PEX_CAPABILITY_REG (PXCR)*/ + +#define PXCR_CAP_ID_OFFS 0 /* Capability ID*/ +#define PXCR_CAP_ID_MASK (0xff << PXCR_CAP_ID_OFFS) + +#define PXCR_NEXT_PTR_OFFS 8 /* Next Item Pointer*/ +#define PXCR_NEXT_PTR_MASK (0xff << PXCR_NEXT_PTR_OFFS) + +#define PXCR_CAP_VER_OFFS 16 /* Capability Version*/ +#define PXCR_CAP_VER_MASK (0xf << PXCR_CAP_VER_OFFS) + +#define PXCR_DEV_TYPE_OFFS 20 /* Device/Port Type*/ +#define PXCR_DEV_TYPE_MASK (0xf << PXCR_DEV_TYPE_OFFS) + +#define PXCR_SLOT_IMP BIT24 /* Slot Implemented*/ + +#define PXCR_INT_MSG_NUM_OFFS 25 /* Interrupt Message Number*/ +#define PXCR_INT_MSG_NUM_MASK (0x1f << PXCR_INT_MSG_NUM_OFFS) + + +/* PCI Express Device Capabilities Register */ +/*PEX_DEV_CAPABILITY_REG (PXDCR)*/ + +#define PXDCR_MAX_PLD_SIZE_SUP_OFFS 0 /* Maximum Payload Size Supported*/ +#define PXDCR_MAX_PLD_SIZE_SUP_MASK (0x7 << PXDCR_MAX_PLD_SIZE_SUP_OFFS) + +#define PXDCR_EP_L0S_ACC_LAT_OFFS 6/* Endpoint L0s Acceptable Latency*/ +#define PXDCR_EP_L0S_ACC_LAT_MASK (0x7 << PXDCR_EP_L0S_ACC_LAT_OFFS) +#define PXDCR_EP_L0S_ACC_LAT_64NS_LESS (0x0 << PXDCR_EP_L0S_ACC_LAT_OFFS) +#define PXDCR_EP_L0S_ACC_LAT_64NS_128NS (0x1 << PXDCR_EP_L0S_ACC_LAT_OFFS) +#define PXDCR_EP_L0S_ACC_LAT_128NS_256NS (0x2 << PXDCR_EP_L0S_ACC_LAT_OFFS) +#define PXDCR_EP_L0S_ACC_LAT_256NS_512NS (0x3 << PXDCR_EP_L0S_ACC_LAT_OFFS) +#define PXDCR_EP_L0S_ACC_LAT_512NS_1US (0x4 << PXDCR_EP_L0S_ACC_LAT_OFFS) +#define PXDCR_EP_L0S_ACC_LAT_1US_2US (0x5 << PXDCR_EP_L0S_ACC_LAT_OFFS) +#define PXDCR_EP_L0S_ACC_LAT_2US_4US (0x6 << PXDCR_EP_L0S_ACC_LAT_OFFS) +#define PXDCR_EP_L0S_ACC_LAT_4US_MORE (0x7 << PXDCR_EP_L0S_ACC_LAT_OFFS) + +#define PXDCR_EP_L1_ACC_LAT_OFFS 9 /* Endpoint L1 Acceptable Latency*/ +#define PXDCR_EP_L1_ACC_LAT_MASK (0x7 << PXDCR_EP_L1_ACC_LAT_OFFS) +#define PXDCR_EP_L1_ACC_LAT_64NS_LESS (0x0 << PXDCR_EP_L1_ACC_LAT_OFFS) +#define PXDCR_EP_L1_ACC_LAT_64NS_128NS (0x1 << PXDCR_EP_L1_ACC_LAT_OFFS) +#define PXDCR_EP_L1_ACC_LAT_128NS_256NS (0x2 << PXDCR_EP_L1_ACC_LAT_OFFS) +#define PXDCR_EP_L1_ACC_LAT_256NS_512NS (0x3 << PXDCR_EP_L1_ACC_LAT_OFFS) +#define PXDCR_EP_L1_ACC_LAT_512NS_1US (0x4 << PXDCR_EP_L1_ACC_LAT_OFFS) +#define PXDCR_EP_L1_ACC_LAT_1US_2US (0x5 << PXDCR_EP_L1_ACC_LAT_OFFS) +#define PXDCR_EP_L1_ACC_LAT_2US_4US (0x6 << PXDCR_EP_L1_ACC_LAT_OFFS) +#define PXDCR_EP_L1_ACC_LAT_4US_MORE (0x7 << PXDCR_EP_L1_ACC_LAT_OFFS) + + +#define PXDCR_ATT_BUT_PRS_OFFS 12 /* Attention Button Present*/ +#define PXDCR_ATT_BUT_PRS_MASK BIT12 +#define PXDCR_ATT_BUT_PRS_IMPLEMENTED BIT12 + +#define PXDCR_ATT_IND_PRS_OFFS 13 /* Attention Indicator Present*/ +#define PXDCR_ATT_IND_PRS_MASK BIT13 +#define PXDCR_ATT_IND_PRS_IMPLEMENTED BIT13 + +#define PXDCR_PWR_IND_PRS_OFFS 14/* Power Indicator Present*/ +#define PXDCR_PWR_IND_PRS_MASK BIT14 +#define PXDCR_PWR_IND_PRS_IMPLEMENTED BIT14 + +#define PXDCR_CAP_SPL_VAL_OFFS 18 /*Captured Slot Power Limit + Value*/ +#define PXDCR_CAP_SPL_VAL_MASK (0xff << PXDCR_CAP_SPL_VAL_OFFS) + +#define PXDCR_CAP_SP_LSCL_OFFS 26 /* Captured Slot Power Limit + Scale */ +#define PXDCR_CAP_SP_LSCL_MASK (0x3 << PXDCR_CAP_SP_LSCL_OFFS) + +/* PCI Express Device Control Status Register */ +/*PEX_DEV_CTRL_STAT_REG (PXDCSR)*/ + +#define PXDCSR_COR_ERR_REP_EN BIT0 /* Correctable Error Reporting Enable*/ +#define PXDCSR_NF_ERR_REP_EN BIT1 /* Non-Fatal Error Reporting Enable*/ +#define PXDCSR_F_ERR_REP_EN BIT2 /* Fatal Error Reporting Enable*/ +#define PXDCSR_UR_REP_EN BIT3 /* Unsupported Request (UR) + Reporting Enable*/ +#define PXDCSR_EN_RO BIT4 /* Enable Relaxed Ordering*/ + +#define PXDCSR_MAX_PLD_SZ_OFFS 5 /* Maximum Payload Size*/ +#define PXDCSR_MAX_PLD_SZ_MASK (0x7 << PXDCSR_MAX_PLD_SZ_OFFS) +#define PXDCSR_MAX_PLD_SZ_128B (0x0 << PXDCSR_MAX_PLD_SZ_OFFS) +#define PXDCSR_EN_NS BIT11 /* Enable No Snoop*/ + +#define PXDCSR_MAX_RD_RQ_SZ_OFFS 12 /* Maximum Read Request Size*/ +#define PXDCSR_MAX_RD_RQ_SZ_MASK (0x7 << PXDCSR_MAX_RD_RQ_SZ_OFFS) +#define PXDCSR_MAX_RD_RQ_SZ_128B (0x0 << PXDCSR_MAX_RD_RQ_SZ_OFFS) +#define PXDCSR_MAX_RD_RQ_SZ_256B (0x1 << PXDCSR_MAX_RD_RQ_SZ_OFFS) +#define PXDCSR_MAX_RD_RQ_SZ_512B (0x2 << PXDCSR_MAX_RD_RQ_SZ_OFFS) +#define PXDCSR_MAX_RD_RQ_SZ_1KB (0x3 << PXDCSR_MAX_RD_RQ_SZ_OFFS) +#define PXDCSR_MAX_RD_RQ_SZ_2KB (0x4 << PXDCSR_MAX_RD_RQ_SZ_OFFS) +#define PXDCSR_MAX_RD_RQ_SZ_4KB (0x5 << PXDCSR_MAX_RD_RQ_SZ_OFFS) + +#define PXDCSR_COR_ERR_DET BIT16 /* Correctable Error Detected*/ +#define PXDCSR_NF_ERR_DET BIT17 /* Non-Fatal Error Detected.*/ +#define PXDCSR_F_ERR_DET BIT18 /* Fatal Error Detected.*/ +#define PXDCSR_UR_DET BIT19 /* Unsupported Request Detected */ +#define PXDCSR_AUX_PWR_DET BIT20 /* Reserved*/ + +#define PXDCSR_TRANS_PEND_OFFS 21 /* Transactions Pending*/ +#define PXDCSR_TRANS_PEND_MASK BIT21 +#define PXDCSR_TRANS_PEND_NOT_COMPLETED (0x1 << PXDCSR_TRANS_PEND_OFFS) + + +/* PCI Express Link Capabilities Register*/ +/*PEX_LINK_CAPABILITY_REG (PXLCR)*/ + +#define PXLCR_MAX_LINK_SPD_OFFS 0 /* Maximum Link Speed*/ +#define PXLCR_MAX_LINK_SPD_MASK (0xf << PXLCR_MAX_LINK_SPD_OFFS) + +#define PXLCR_MAX_LNK_WDTH_OFFS 3 /* Maximum Link Width*/ +#define PXLCR_MAX_LNK_WDTH_MASK (0x3f << PXLCR_MAX_LNK_WDTH_OFFS) + +#define PXLCR_ASPM_SUP_OFFS 10 /* Active State Link PM Support*/ +#define PXLCR_ASPM_SUP_MASK (0x3 << PXLCR_ASPM_SUP_OFFS) + +#define PXLCR_L0S_EXT_LAT_OFFS 12 /* L0s Exit Latency*/ +#define PXLCR_L0S_EXT_LAT_MASK (0x7 << PXLCR_L0S_EXT_LAT_OFFS) +#define PXLCR_L0S_EXT_LAT_64NS_LESS (0x0 << PXDCR_EP_L1_ACC_LAT_OFFS) +#define PXLCR_L0S_EXT_LAT_64NS_128NS (0x1 << PXDCR_EP_L1_ACC_LAT_OFFS) +#define PXLCR_L0S_EXT_LAT_128NS_256NS (0x2 << PXDCR_EP_L1_ACC_LAT_OFFS) +#define PXLCR_L0S_EXT_LAT_256NS_512NS (0x3 << PXDCR_EP_L1_ACC_LAT_OFFS) +#define PXLCR_L0S_EXT_LAT_512NS_1US (0x4 << PXDCR_EP_L1_ACC_LAT_OFFS) +#define PXLCR_L0S_EXT_LAT_1US_2US (0x5 << PXDCR_EP_L1_ACC_LAT_OFFS) +#define PXLCR_L0S_EXT_LAT_2US_4US (0x6 << PXDCR_EP_L1_ACC_LAT_OFFS) + +#define PXLCR_POR_TNUM_OFFS 24 /* Port Number */ +#define PXLCR_POR_TNUM_MASK (0xff << PXLCR_POR_TNUM_OFFS) + +/* PCI Express Link Control Status Register */ +/*PEX_LINK_CTRL_STAT_REG (PXLCSR)*/ + +#define PXLCSR_ASPM_CNT_OFFS 0 /* Active State Link PM Control */ +#define PXLCSR_ASPM_CNT_MASK (0x3 << PXLCSR_ASPM_CNT_OFFS) +#define PXLCSR_ASPM_CNT_DISABLED (0x0 << PXLCSR_ASPM_CNT_OFFS) +#define PXLCSR_ASPM_CNT_L0S_ENT_SUPP (0x1 << PXLCSR_ASPM_CNT_OFFS) +#define PXLCSR_ASPM_CNT_L1S_ENT_SUPP (0x2 << PXLCSR_ASPM_CNT_OFFS) +#define PXLCSR_ASPM_CNT_L0S_L1S_ENT_SUPP (0x3 << PXLCSR_ASPM_CNT_OFFS) + +#define PXLCSR_RCB_OFFS 3 /* Read Completion Boundary */ +#define PXLCSR_RCB_MASK BIT3 +#define PXLCSR_RCB_64B (0 << PXLCSR_RCB_OFFS) +#define PXLCSR_RCB_128B (1 << PXLCSR_RCB_OFFS) + +#define PXLCSR_LNK_DIS BIT4 /* Link Disable */ +#define PXLCSR_RETRN_LNK BIT5 /* Retrain Link */ +#define PXLCSR_CMN_CLK_CFG BIT6 /* Common Clock Configuration */ +#define PXLCSR_EXTD_SNC BIT7 /* Extended Sync */ + +#define PXLCSR_LNK_SPD_OFFS 16 /* Link Speed */ +#define PXLCSR_LNK_SPD_MASK (0xf << PXLCSR_LNK_SPD_OFFS) + +#define PXLCSR_NEG_LNK_WDTH_OFFS 20 /* Negotiated Link Width */ +#define PXLCSR_NEG_LNK_WDTH_MASK (0x3f << PXLCSR_NEG_LNK_WDTH_OFFS) +#define PXLCSR_NEG_LNK_WDTH_X1 (0x1 << PXLCSR_NEG_LNK_WDTH_OFFS) + +#define PXLCSR_LNK_TRN BIT27 /* Link Training */ + +#define PXLCSR_SLT_CLK_CFG_OFFS 28 /* Slot Clock Configuration */ +#define PXLCSR_SLT_CLK_CFG_MASK BIT28 +#define PXLCSR_SLT_CLK_CFG_INDPNT (0x0 << PXLCSR_SLT_CLK_CFG_OFFS) +#define PXLCSR_SLT_CLK_CFG_REF (0x1 << PXLCSR_SLT_CLK_CFG_OFFS) + +/* PCI Express Advanced Error Report Header Register */ +/*PEX_ADV_ERR_RPRT_HDR_TRGT_REG (PXAERHTR)*/ + +/* PCI Express Uncorrectable Error Status Register*/ +/*PEX_UNCORRECT_ERR_STAT_REG (PXUESR)*/ + +/* PCI Express Uncorrectable Error Mask Register */ +/*PEX_UNCORRECT_ERR_MASK_REG (PXUEMR)*/ + +/* PCI Express Uncorrectable Error Severity Register */ +/*PEX_UNCORRECT_ERR_SERVITY_REG (PXUESR)*/ + +/* PCI Express Correctable Error Status Register */ +/*PEX_CORRECT_ERR_STAT_REG (PXCESR)*/ + +/* PCI Express Correctable Error Mask Register */ +/*PEX_CORRECT_ERR_MASK_REG (PXCEMR)*/ + +/* PCI Express Advanced Error Capability and Control Register*/ +/*PEX_ADV_ERR_CAPABILITY_CTRL_REG (PXAECCR)*/ + +/* PCI Express Header Log First DWORD Register*/ +/*PEX_HDR_LOG_FIRST_DWORD_REG (PXHLFDR)*/ + +/* PCI Express Header Log Second DWORD Register*/ +/*PEX_HDR_LOG_SECOND_DWORD_REG (PXHLSDR)*/ + +/* PCI Express Header Log Third DWORD Register*/ +/*PEX_HDR_LOG_THIRD_DWORD_REG (PXHLTDR)*/ + +/* PCI Express Header Log Fourth DWORD Register*/ +/*PEX_HDR_LOG_FOURTH_DWORD_REG (PXHLFDR)*/ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* #ifndef __INCPEXREGSH */ + + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/pex/mvVrtBrgPex.c b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/pex/mvVrtBrgPex.c new file mode 100644 index 0000000..19c871a --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/pex/mvVrtBrgPex.c @@ -0,0 +1,313 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#include "mvPex.h" + +//#define MV_DEBUG +/* defines */ +#ifdef MV_DEBUG + #define DB(x) x +#else + #define DB(x) +#endif + +/* locals */ +typedef struct +{ + MV_U32 data; + MV_U32 mask; +}PEX_HEADER_DATA; + +/* local function forwad decleration */ +MV_U32 mvPexHwConfigRead (MV_U32 pexIf, MV_U32 bus, MV_U32 dev, MV_U32 func, + MV_U32 regOff); +MV_STATUS mvPexHwConfigWrite(MV_U32 pexIf, MV_U32 bus, MV_U32 dev, + MV_U32 func, MV_U32 regOff, MV_U32 data); +void resetPexConfig(MV_U32 pexIf, MV_U32 bus, MV_U32 dev); + + +PEX_HEADER_DATA configHdr[16] = +{ +{0x888811ab, 0x00000000}, /*[device ID, vendor ID] */ +{0x00100007, 0x0000ffff}, /*[status register, command register] */ +{0x0604000e, 0x00000000}, /*[programming interface, sub class code, class code, revision ID] */ +{0x00010008, 0x00000000}, /*[BIST, header type, latency time, cache line] */ +{0x00000000, 0x00000000}, /*[base address 0] */ +{0x00000000, 0x00000000}, /*[base address 1] */ +{0x00000000, 0x00ffffff}, /*[secondary latency timersubordinate bus number, secondary bus number, primary bus number] */ +{0x0000f101, 0x00000000}, /*[secondary status ,IO limit, IO base] */ +{0x9ff0a000, 0x00000000}, /*[memory limit, memory base] */ +{0x0001fff1, 0x00000000}, /*[prefetch memory limit, prefetch memory base] */ +{0xffffffff, 0x00000000}, /*[prefetch memory base upper] */ +{0x00000000, 0x00000000}, /*[prefetch memory limit upper] */ +{0xeffff000, 0x00000000}, /*[IO limit upper 16 bits, IO base upper 16 bits] */ +{0x00000000, 0x00000000}, /*[reserved, capability pointer] */ +{0x00000000, 0x00000000}, /*[expansion ROM base address] */ +{0x00000000, 0x000000FF}, /*[bridge control, interrupt pin, interrupt line] */ +}; + + +#define HEADER_WRITE(data, offset) configHdr[offset/4].data = ((configHdr[offset/4].data & ~configHdr[offset/4].mask) | \ + (data & configHdr[offset/4].mask)) +#define HEADER_READ(offset) configHdr[offset/4].data + +/******************************************************************************* +* mvVrtBrgPexInit - Initialize PEX interfaces +* +* DESCRIPTION: +* +* This function is responsible of intialization of the Pex Interface , It +* configure the Pex Bars and Windows in the following manner: +* +* Assumptions : +* Bar0 is always internal registers bar +* Bar1 is always the DRAM bar +* Bar2 is always the Device bar +* +* 1) Sets the Internal registers bar base by obtaining the base from +* the CPU Interface +* 2) Sets the DRAM bar base and size by getting the base and size from +* the CPU Interface when the size is the sum of all enabled DRAM +* chip selects and the base is the base of CS0 . +* 3) Sets the Device bar base and size by getting these values from the +* CPU Interface when the base is the base of the lowest base of the +* Device chip selects, and the +* +* +* INPUT: +* +* pexIf - PEX interface number. +* +* +* OUTPUT: +* None. +* +* RETURN: +* MV_OK if function success otherwise MV_ERROR or MV_BAD_PARAM +* +*******************************************************************************/ +MV_STATUS mvPexVrtBrgInit(MV_U32 pexIf) +{ + /* reset PEX tree to recover previous U-boot/Boot configurations */ + MV_U32 localBus = mvPexLocalBusNumGet(pexIf); + + + resetPexConfig(pexIf, localBus, 1); + return MV_OK; +} + + +MV_U32 mvPexVrtBrgConfigRead (MV_U32 pexIf, MV_U32 bus, MV_U32 dev, MV_U32 func, + MV_U32 regOff) +{ + + MV_U32 localBus = mvPexLocalBusNumGet(pexIf); + MV_U32 localDev = mvPexLocalDevNumGet(pexIf); + MV_U32 val; + if(bus == localBus) + { + if(dev > 1) + { +/* on the local device allow only device #0 & #1 */ + return 0xffffffff; + } + else + if (dev == localDev) + { + /* read the memory controller registers */ + return mvPexHwConfigRead (pexIf, bus, dev, func, regOff); + } + else + { + /* access the virtual brg header */ + return HEADER_READ(regOff); + } + } + else + if(bus == (localBus + 1)) + { + /* access the device behind the virtual bridge */ + if((dev == localDev) || (dev > 1)) + { + return 0xffffffff; + } + else + { + /* access the device behind the virtual bridge, in this case + * change the bus number to the local bus number in order to + * generate type 0 config cycle + */ + mvPexLocalBusNumSet(pexIf, bus); + mvPexLocalDevNumSet(pexIf, 1); + val = mvPexHwConfigRead (pexIf, bus, 0, func, regOff); + mvPexLocalBusNumSet(pexIf, localBus); + mvPexLocalDevNumSet(pexIf, localDev); + return val; + } + } + /* for all other devices use the HW function to get the + * requested registers + */ + mvPexLocalDevNumSet(pexIf, 1); + val = mvPexHwConfigRead (pexIf, bus, dev, func, regOff); + mvPexLocalDevNumSet(pexIf, localDev); + return val; +} + + +MV_STATUS mvPexVrtBrgConfigWrite(MV_U32 pexIf, MV_U32 bus, MV_U32 dev, + MV_U32 func, MV_U32 regOff, MV_U32 data) +{ + MV_U32 localBus = mvPexLocalBusNumGet(pexIf); + MV_U32 localDev = mvPexLocalDevNumGet(pexIf); + MV_STATUS status; + + if(bus == localBus) + { + if(dev > 1) + { + /* on the local device allow only device #0 & #1 */ + return MV_ERROR; + } + else + if (dev == localDev) + { + /* read the memory controller registers */ + return mvPexHwConfigWrite (pexIf, bus, dev, func, regOff, data); + } + else + { + /* access the virtual brg header */ + HEADER_WRITE(data, regOff); + return MV_OK; + } + } + else + if(bus == (localBus + 1)) + { + /* access the device behind the virtual bridge */ + if((dev == localDev) || (dev > 1)) + { + return MV_ERROR; + } + else + { + /* access the device behind the virtual bridge, in this case + * change the bus number to the local bus number in order to + * generate type 0 config cycle + */ + //return mvPexHwConfigWrite (pexIf, localBus, dev, func, regOff, data); + mvPexLocalBusNumSet(pexIf, bus); + mvPexLocalDevNumSet(pexIf, 1); + status = mvPexHwConfigWrite (pexIf, bus, 0, func, regOff, data); + mvPexLocalBusNumSet(pexIf, localBus); + mvPexLocalDevNumSet(pexIf, localDev); + return status; + + } + } + /* for all other devices use the HW function to get the + * requested registers + */ + mvPexLocalDevNumSet(pexIf, 1); + status = mvPexHwConfigWrite (pexIf, bus, dev, func, regOff, data); + mvPexLocalDevNumSet(pexIf, localDev); + return status; +} + + + + +void resetPexConfig(MV_U32 pexIf, MV_U32 bus, MV_U32 dev) +{ + MV_U32 tData; + MV_U32 i; + + /* restore the PEX configuration to initialization state */ + /* in case PEX P2P call recursive and reset config */ + tData = mvPexHwConfigRead (pexIf, bus, dev, 0x0, 0x0); + if(tData != 0xffffffff) + { + /* agent had been found - check whether P2P */ + tData = mvPexHwConfigRead (pexIf, bus, dev, 0x0, 0x8); + if((tData & 0xffff0000) == 0x06040000) + {/* P2P */ + /* get the sec bus and the subordinate */ + MV_U32 secBus; + tData = mvPexHwConfigRead (pexIf, bus, dev, 0x0, 0x18); + secBus = ((tData >> 8) & 0xff); + /* now scan on sec bus */ + for(i = 0;i < 0xff;i++) + { + resetPexConfig(pexIf, secBus, i); + } + /* now reset this device */ + DB(mvOsPrintf("Reset bus %d dev %d\n", bus, dev)); + mvPexHwConfigWrite(pexIf, bus, dev, 0x0, 0x18, 0x0); + DB(mvOsPrintf("Reset bus %d dev %d\n", bus, dev)); + } + } +} + + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/pex/mvVrtBrgPex.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/pex/mvVrtBrgPex.h new file mode 100644 index 0000000..82eb72d --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/pex/mvVrtBrgPex.h @@ -0,0 +1,82 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#ifndef __INCVRTBRGPEXH +#define __INCVRTBRGPEXH + + +/* Global Functions prototypes */ +/* mvPexInit - Initialize PEX interfaces*/ +MV_STATUS mvPexVrtBrgInit(MV_U32 pexIf); + +/* mvPexConfigRead - Read from configuration space */ +MV_U32 mvPexVrtBrgConfigRead (MV_U32 pexIf, MV_U32 bus, MV_U32 dev, + MV_U32 func,MV_U32 regOff); + +/* mvPexConfigWrite - Write to configuration space */ +MV_STATUS mvPexVrtBrgConfigWrite(MV_U32 pexIf, MV_U32 bus, MV_U32 dev, + MV_U32 func, MV_U32 regOff, MV_U32 data); + + +#endif /* #ifndef __INCPEXH */ diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/sflash/mvCompVer.txt b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/sflash/mvCompVer.txt new file mode 100644 index 0000000..85bfa61 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/sflash/mvCompVer.txt @@ -0,0 +1,4 @@ +Global HAL Version: FEROCEON_HAL_3_1_7 +Unit HAL Version: 3.1.3 +Description: This component includes an implementation of the unit HAL drivers + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/sflash/mvSFlash.c b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/sflash/mvSFlash.c new file mode 100644 index 0000000..6c5bc19 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/sflash/mvSFlash.c @@ -0,0 +1,1522 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ +#include "mvOs.h" +#include "sflash/mvSFlash.h" +#include "sflash/mvSFlashSpec.h" +#include "spi/mvSpi.h" +#include "spi/mvSpiCmnd.h" +#include "ctrlEnv/mvCtrlEnvLib.h" + +/*#define MV_DEBUG*/ +#ifdef MV_DEBUG +#define DB(x) x +#else +#define DB(x) +#endif + +/* Globals */ +static MV_SFLASH_DEVICE_PARAMS sflash[] = { + /* ST M25P32 SPI flash, 4MB, 64 sectors of 64K each */ + { + MV_M25P_WREN_CMND_OPCD, + MV_M25P_WRDI_CMND_OPCD, + MV_M25P_RDID_CMND_OPCD, + MV_M25P_RDSR_CMND_OPCD, + MV_M25P_WRSR_CMND_OPCD, + MV_M25P_READ_CMND_OPCD, + MV_M25P_FAST_RD_CMND_OPCD, + MV_M25P_PP_CMND_OPCD, + MV_M25P_SE_CMND_OPCD, + MV_M25P_BE_CMND_OPCD, + MV_M25P_RES_CMND_OPCD, + MV_SFLASH_NO_SPECIFIC_OPCD, /* power save not supported */ + MV_M25P32_SECTOR_SIZE, + MV_M25P32_SECTOR_NUMBER, + MV_M25P_PAGE_SIZE, + "ST M25P32", + MV_M25PXXX_ST_MANF_ID, + MV_M25P32_DEVICE_ID, + MV_M25P32_MAX_SPI_FREQ, + MV_M25P32_MAX_FAST_SPI_FREQ, + MV_M25P32_FAST_READ_DUMMY_BYTES + }, + /* ST M25P64 SPI flash, 8MB, 128 sectors of 64K each */ + { + MV_M25P_WREN_CMND_OPCD, + MV_M25P_WRDI_CMND_OPCD, + MV_M25P_RDID_CMND_OPCD, + MV_M25P_RDSR_CMND_OPCD, + MV_M25P_WRSR_CMND_OPCD, + MV_M25P_READ_CMND_OPCD, + MV_M25P_FAST_RD_CMND_OPCD, + MV_M25P_PP_CMND_OPCD, + MV_M25P_SE_CMND_OPCD, + MV_M25P_BE_CMND_OPCD, + MV_M25P_RES_CMND_OPCD, + MV_SFLASH_NO_SPECIFIC_OPCD, /* power save not supported */ + MV_M25P64_SECTOR_SIZE, + MV_M25P64_SECTOR_NUMBER, + MV_M25P_PAGE_SIZE, + "ST M25P64", + MV_M25PXXX_ST_MANF_ID, + MV_M25P64_DEVICE_ID, + MV_M25P64_MAX_SPI_FREQ, + MV_M25P64_MAX_FAST_SPI_FREQ, + MV_M25P64_FAST_READ_DUMMY_BYTES + }, + /* ST M25P128 SPI flash, 16MB, 64 sectors of 256K each */ + { + MV_M25P_WREN_CMND_OPCD, + MV_M25P_WRDI_CMND_OPCD, + MV_M25P_RDID_CMND_OPCD, + MV_M25P_RDSR_CMND_OPCD, + MV_M25P_WRSR_CMND_OPCD, + MV_M25P_READ_CMND_OPCD, + MV_M25P_FAST_RD_CMND_OPCD, + MV_M25P_PP_CMND_OPCD, + MV_M25P_SE_CMND_OPCD, + MV_M25P_BE_CMND_OPCD, + MV_M25P_RES_CMND_OPCD, + MV_SFLASH_NO_SPECIFIC_OPCD, /* power save not supported */ + MV_M25P128_SECTOR_SIZE, + MV_M25P128_SECTOR_NUMBER, + MV_M25P_PAGE_SIZE, + "ST M25P128", + MV_M25PXXX_ST_MANF_ID, + MV_M25P128_DEVICE_ID, + MV_M25P128_MAX_SPI_FREQ, + MV_M25P128_MAX_FAST_SPI_FREQ, + MV_M25P128_FAST_READ_DUMMY_BYTES + }, + /* Macronix MXIC MX25L6405 SPI flash, 8MB, 128 sectors of 64K each */ + { + MV_MX25L_WREN_CMND_OPCD, + MV_MX25L_WRDI_CMND_OPCD, + MV_MX25L_RDID_CMND_OPCD, + MV_MX25L_RDSR_CMND_OPCD, + MV_MX25L_WRSR_CMND_OPCD, + MV_MX25L_READ_CMND_OPCD, + MV_MX25L_FAST_RD_CMND_OPCD, + MV_MX25L_PP_CMND_OPCD, + MV_MX25L_SE_CMND_OPCD, + MV_MX25L_BE_CMND_OPCD, + MV_MX25L_RES_CMND_OPCD, + MV_MX25L_DP_CMND_OPCD, + MV_MX25L6405_SECTOR_SIZE, + MV_MX25L6405_SECTOR_NUMBER, + MV_MXIC_PAGE_SIZE, + "MXIC MX25L6405", + MV_MXIC_MANF_ID, + MV_MX25L6405_DEVICE_ID, + MV_MX25L6405_MAX_SPI_FREQ, + MV_MX25L6405_MAX_FAST_SPI_FREQ, + MV_MX25L6405_FAST_READ_DUMMY_BYTES + }, + /* SPANSION S25FL128P SPI flash, 16MB, 64 sectors of 256K each */ + { + MV_S25FL_WREN_CMND_OPCD, + MV_S25FL_WRDI_CMND_OPCD, + MV_S25FL_RDID_CMND_OPCD, + MV_S25FL_RDSR_CMND_OPCD, + MV_S25FL_WRSR_CMND_OPCD, + MV_S25FL_READ_CMND_OPCD, + MV_S25FL_FAST_RD_CMND_OPCD, + MV_S25FL_PP_CMND_OPCD, + MV_S25FL_SE_CMND_OPCD, + MV_S25FL_BE_CMND_OPCD, + MV_S25FL_RES_CMND_OPCD, + MV_S25FL_DP_CMND_OPCD, + MV_S25FL128_SECTOR_SIZE, + MV_S25FL128_SECTOR_NUMBER, + MV_S25FL_PAGE_SIZE, + "SPANSION S25FL128", + MV_SPANSION_MANF_ID, + MV_S25FL128_DEVICE_ID, + MV_S25FL128_MAX_SPI_FREQ, + MV_M25P128_MAX_FAST_SPI_FREQ, + MV_M25P128_FAST_READ_DUMMY_BYTES + } +}; + +/* Static Functions */ +static MV_STATUS mvWriteEnable (MV_SFLASH_INFO * pFlinfo); +static MV_STATUS mvStatusRegGet (MV_SFLASH_INFO * pFlinfo, MV_U8 * pStatReg); +static MV_STATUS mvStatusRegSet (MV_SFLASH_INFO * pFlinfo, MV_U8 sr); +static MV_STATUS mvWaitOnWipClear(MV_SFLASH_INFO * pFlinfo); +static MV_STATUS mvSFlashPageWr (MV_SFLASH_INFO * pFlinfo, MV_U32 offset, \ + MV_U8* pPageBuff, MV_U32 buffSize); +static MV_STATUS mvSFlashWithDefaultsIdGet (MV_SFLASH_INFO * pFlinfo, \ + MV_U8* manId, MV_U16* devId); + +/******************************************************************************* +* mvWriteEnable - serialize the write enable sequence +* +* DESCRIPTION: +* transmit the sequence for write enable +* +********************************************************************************/ +static MV_STATUS mvWriteEnable(MV_SFLASH_INFO * pFlinfo) +{ + MV_U8 cmd[MV_SFLASH_WREN_CMND_LENGTH]; + + + cmd[0] = sflash[pFlinfo->index].opcdWREN; + + return mvSpiWriteThenRead(cmd, MV_SFLASH_WREN_CMND_LENGTH, NULL, 0, 0); +} + +/******************************************************************************* +* mvStatusRegGet - Retrieve the value of the status register +* +* DESCRIPTION: +* perform the RDSR sequence to get the 8bit status register +* +********************************************************************************/ +static MV_STATUS mvStatusRegGet(MV_SFLASH_INFO * pFlinfo, MV_U8 * pStatReg) +{ + MV_STATUS ret; + MV_U8 cmd[MV_SFLASH_RDSR_CMND_LENGTH]; + MV_U8 sr[MV_SFLASH_RDSR_REPLY_LENGTH]; + + + + + cmd[0] = sflash[pFlinfo->index].opcdRDSR; + + if ((ret = mvSpiWriteThenRead(cmd, MV_SFLASH_RDSR_CMND_LENGTH, sr, + MV_SFLASH_RDSR_REPLY_LENGTH,0)) != MV_OK) + return ret; + + *pStatReg = sr[0]; + + return MV_OK; +} + +/******************************************************************************* +* mvWaitOnWipClear - Block waiting for the WIP (write in progress) to be cleared +* +* DESCRIPTION: +* Block waiting for the WIP (write in progress) to be cleared +* +********************************************************************************/ +static MV_STATUS mvWaitOnWipClear(MV_SFLASH_INFO * pFlinfo) +{ + MV_STATUS ret; + MV_U32 i; + MV_U8 stat; + + for (i=0; iindex].opcdWRSR; + cmd[1] = sr; + + if ((ret = mvSpiWriteThenRead(cmd, MV_SFLASH_WRSR_CMND_LENGTH, NULL, 0, 0)) != MV_OK) + return ret; + + if ((ret = mvWaitOnWipClear(pFlinfo)) != MV_OK) + return ret; + + mvOsDelay(1); + + return MV_OK; +} + +/******************************************************************************* +* mvSFlashPageWr - Write up to 256 Bytes in the same page +* +* DESCRIPTION: +* Write a buffer up to the page size in length provided that the whole address +* range is within the same page (alligned to page bounderies) +* +*******************************************************************************/ +static MV_STATUS mvSFlashPageWr (MV_SFLASH_INFO * pFlinfo, MV_U32 offset, + MV_U8* pPageBuff, MV_U32 buffSize) +{ + MV_STATUS ret; + MV_U8 cmd[MV_SFLASH_PP_CMND_LENGTH]; + + + /* Protection - check if the model was detected */ + if (pFlinfo->index >= MV_ARRAY_SIZE(sflash)) + { + DB(mvOsPrintf("%s WARNING: Invalid parameter device index!\n", __FUNCTION__);) + return MV_BAD_PARAM; + } + + /* check that we do not cross the page bounderies */ + if (((offset & (sflash[pFlinfo->index].pageSize - 1)) + buffSize) > + sflash[pFlinfo->index].pageSize) + { + DB(mvOsPrintf("%s WARNING: Page allignment problem!\n", __FUNCTION__);) + return MV_OUT_OF_RANGE; + } + + /* Issue the Write enable command prior the page program command */ + if ((ret = mvWriteEnable(pFlinfo)) != MV_OK) + return ret; + + cmd[0] = sflash[pFlinfo->index].opcdPP; + cmd[1] = ((offset >> 16) & 0xFF); + cmd[2] = ((offset >> 8) & 0xFF); + cmd[3] = (offset & 0xFF); + + if ((ret = mvSpiWriteThenWrite(cmd, MV_SFLASH_PP_CMND_LENGTH, pPageBuff, buffSize)) != MV_OK) + return ret; + + if ((ret = mvWaitOnWipClear(pFlinfo)) != MV_OK) + return ret; + + return MV_OK; +} + +/******************************************************************************* +* mvSFlashWithDefaultsIdGet - Try to read the manufacturer and Device IDs from +* the device using the default RDID opcode and the default WREN opcode. +* +* DESCRIPTION: +* This is used to detect a generic device that uses the default opcodes +* for the WREN and RDID. +* +********************************************************************************/ +static MV_STATUS mvSFlashWithDefaultsIdGet (MV_SFLASH_INFO * pFlinfo, MV_U8* manId, MV_U16* devId) +{ + MV_STATUS ret; + MV_U8 cmdRDID[MV_SFLASH_RDID_CMND_LENGTH]; + MV_U8 id[MV_SFLASH_RDID_REPLY_LENGTH]; + + + + /* Use the default RDID opcode to read the IDs */ + cmdRDID[0] = MV_SFLASH_DEFAULT_RDID_OPCD; /* unknown model try default */ + if ((ret = mvSpiWriteThenRead(cmdRDID, MV_SFLASH_RDID_CMND_LENGTH, id, MV_SFLASH_RDID_REPLY_LENGTH, 0)) != MV_OK) + return ret; + + *manId = id[0]; + *devId = 0; + *devId |= (id[1] << 8); + *devId |= id[2]; + + return MV_OK; +} + +/* +##################################################################################### +##################################################################################### +*/ + +/******************************************************************************* +* mvSFlashInit - Initialize the serial flash device +* +* DESCRIPTION: +* Perform the neccessary initialization and configuration +* +* INPUT: +* pFlinfo: pointer to the Flash information structure +* pFlinfo->baseAddr: base address in fast mode. +* pFlinfo->index: Index of the flash in the sflash tabel. If the SPI +* flash device does not support read Id command with +* the standard opcode, then the user should supply this +* as an input to skip the autodetection process!!!! +* +* OUTPUT: +* pFlinfo: pointer to the Flash information structure after detection +* pFlinfo->manufacturerId: Manufacturer ID +* pFlinfo->deviceId: Device ID +* pFlinfo->sectorSize: size of the sector (all sectors are the same). +* pFlinfo->sectorNumber: number of sectors. +* pFlinfo->pageSize: size of the page. +* pFlinfo->index: Index of the detected flash in the sflash tabel +* +* RETURN: +* Success or Error code. +* +* +*******************************************************************************/ +MV_STATUS mvSFlashInit (MV_SFLASH_INFO * pFlinfo) +{ + MV_STATUS ret; + MV_U8 manf; + MV_U16 dev; + MV_U32 indx; + MV_BOOL detectFlag = MV_FALSE; + + /* check for NULL pointer */ + if (pFlinfo == NULL) + { + mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__); + return MV_BAD_PARAM; + } + + /* Initialize the SPI interface with low frequency to make sure that the read ID succeeds */ + if ((ret = mvSpiInit(MV_SFLASH_BASIC_SPI_FREQ)) != MV_OK) + { + mvOsPrintf("%s ERROR: Failed to initialize the SPI interface!\n", __FUNCTION__); + return ret; + } + + /* First try to read the Manufacturer and Device IDs */ + if ((ret = mvSFlashIdGet(pFlinfo, &manf, &dev)) != MV_OK) + { + mvOsPrintf("%s ERROR: Failed to get the SFlash ID!\n", __FUNCTION__); + return ret; + } + + /* loop over the whole table and look for the appropriate SFLASH */ + for (indx=0; indxmanufacturerId = manf; + pFlinfo->deviceId = dev; + pFlinfo->index = indx; + detectFlag = MV_TRUE; + } + } + + if(!detectFlag) + { + mvOsPrintf("%s ERROR: Unknown SPI flash device!\n", __FUNCTION__); + return MV_FAIL; + } + + /* fill the info based on the model detected */ + pFlinfo->sectorSize = sflash[pFlinfo->index].sectorSize; + pFlinfo->sectorNumber = sflash[pFlinfo->index].sectorNumber; + pFlinfo->pageSize = sflash[pFlinfo->index].pageSize; + + /* Set the SPI frequency to the MAX allowed for the device for best performance */ + if ((ret = mvSpiBaudRateSet(sflash[pFlinfo->index].spiMaxFreq)) != MV_OK) + { + mvOsPrintf("%s ERROR: Failed to set the SPI frequency!\n", __FUNCTION__); + return ret; + } + + /* As default lock the SR */ + if ((ret = mvSFlashStatRegLock(pFlinfo, MV_TRUE)) != MV_OK) + return ret; + + return MV_OK; +} + +/******************************************************************************* +* mvSFlashSectorErase - Erasse a single sector of the serial flash +* +* DESCRIPTION: +* Issue the erase sector command and address +* +* INPUT: +* pFlinfo: pointer to the Flash information structure +* secNumber: sector Number to erase (0 -> (sectorNumber-1)) +* +* OUTPUT: +* None +* +* RETURN: +* Success or Error code. +* +* +*******************************************************************************/ +MV_STATUS mvSFlashSectorErase (MV_SFLASH_INFO * pFlinfo, MV_U32 secNumber) +{ + MV_STATUS ret; + MV_U8 cmd[MV_SFLASH_SE_CMND_LENGTH]; + + MV_U32 secAddr = (secNumber * pFlinfo->sectorSize); +#if 0 + MV_U32 i; + MV_U32 * pW = (MV_U32*) (secAddr + pFlinfo->baseAddr); + MV_U32 erasedWord = 0xFFFFFFFF; + MV_U32 wordsPerSector = (pFlinfo->sectorSize / sizeof(MV_U32)); + MV_BOOL eraseNeeded = MV_FALSE; +#endif + /* check for NULL pointer */ + if (pFlinfo == NULL) + { + mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__); + return MV_BAD_PARAM; + } + + /* Protection - check if the model was detected */ + if (pFlinfo->index >= MV_ARRAY_SIZE(sflash)) + { + DB(mvOsPrintf("%s WARNING: Invaild parameter index!\n", __FUNCTION__);) + return MV_BAD_PARAM; + } + + /* check that the sector number is valid */ + if (secNumber >= pFlinfo->sectorNumber) + { + DB(mvOsPrintf("%s WARNING: Invaild parameter sector number!\n", __FUNCTION__);) + return MV_BAD_PARAM; + } + + /* we don't want to access SPI in direct mode from in-direct API, + becasue of timing issue between CS asserts. */ +#if 0 + /* First compare to FF and check if erase is needed */ + for (i=0; iindex].opcdSE; + cmd[1] = ((secAddr >> 16) & 0xFF); + cmd[2] = ((secAddr >> 8) & 0xFF); + cmd[3] = (secAddr & 0xFF); + + /* Issue the Write enable command prior the sector erase command */ + if ((ret = mvWriteEnable(pFlinfo)) != MV_OK) + return ret; + + if ((ret = mvSpiWriteThenWrite(cmd, MV_SFLASH_SE_CMND_LENGTH, NULL, 0)) != MV_OK) + return ret; + + if ((ret = mvWaitOnWipClear(pFlinfo)) != MV_OK) + return ret; + + return MV_OK; +} + +/******************************************************************************* +* mvSFlashChipErase - Erasse the whole serial flash +* +* DESCRIPTION: +* Issue the bulk (chip) erase command +* +* INPUT: +* pFlinfo: pointer to the Flash information structure +* +* OUTPUT: +* None +* +* RETURN: +* Success or Error code. +* +* +*******************************************************************************/ +MV_STATUS mvSFlashChipErase (MV_SFLASH_INFO * pFlinfo) +{ + MV_STATUS ret; + MV_U8 cmd[MV_SFLASH_BE_CMND_LENGTH]; + + + /* check for NULL pointer */ + if (pFlinfo == NULL) + { + mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__); + return MV_BAD_PARAM; + } + + /* Protection - check if the model was detected */ + if (pFlinfo->index >= MV_ARRAY_SIZE(sflash)) + { + DB(mvOsPrintf("%s WARNING: Invaild parameter index!\n", __FUNCTION__);) + return MV_BAD_PARAM; + } + + cmd[0] = sflash[pFlinfo->index].opcdBE; + + /* Issue the Write enable command prior the Bulk erase command */ + if ((ret = mvWriteEnable(pFlinfo)) != MV_OK) + return ret; + + if ((ret = mvSpiWriteThenWrite(cmd, MV_SFLASH_BE_CMND_LENGTH, NULL, 0)) != MV_OK) + return ret; + + if ((ret = mvWaitOnChipEraseDone(pFlinfo)) != MV_OK) + return ret; + + return MV_OK; +} + +/******************************************************************************* +* mvSFlashBlockRd - Read from the serial flash +* +* DESCRIPTION: +* Issue the read command and address then perfom the needed read +* +* INPUT: +* pFlinfo: pointer to the Flash information structure +* offset: byte offset with the flash to start reading from +* pReadBuff: pointer to the buffer to read the data in +* buffSize: size of the buffer to read. +* +* OUTPUT: +* pReadBuff: pointer to the buffer containing the read data +* +* RETURN: +* Success or Error code. +* +* +*******************************************************************************/ +MV_STATUS mvSFlashBlockRd (MV_SFLASH_INFO * pFlinfo, MV_U32 offset, + MV_U8* pReadBuff, MV_U32 buffSize) +{ + MV_U8 cmd[MV_SFLASH_READ_CMND_LENGTH]; + + + /* check for NULL pointer */ + if ((pFlinfo == NULL) || (pReadBuff == NULL)) + { + mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__); + return MV_BAD_PARAM; + } + + /* Protection - check if the model was detected */ + if (pFlinfo->index >= MV_ARRAY_SIZE(sflash)) + { + DB(mvOsPrintf("%s WARNING: Invaild parameter index!\n", __FUNCTION__);) + return MV_BAD_PARAM; + } + + cmd[0] = sflash[pFlinfo->index].opcdREAD; + cmd[1] = ((offset >> 16) & 0xFF); + cmd[2] = ((offset >> 8) & 0xFF); + cmd[3] = (offset & 0xFF); + + return mvSpiWriteThenRead(cmd, MV_SFLASH_READ_CMND_LENGTH, pReadBuff, buffSize, 0); +} + +/******************************************************************************* +* mvSFlashFastBlockRd - Fast read from the serial flash +* +* DESCRIPTION: +* Issue the fast read command and address then perfom the needed read +* +* INPUT: +* pFlinfo: pointer to the Flash information structure +* offset: byte offset with the flash to start reading from +* pReadBuff: pointer to the buffer to read the data in +* buffSize: size of the buffer to read. +* +* OUTPUT: +* pReadBuff: pointer to the buffer containing the read data +* +* RETURN: +* Success or Error code. +* +* +*******************************************************************************/ +MV_STATUS mvSFlashFastBlockRd (MV_SFLASH_INFO * pFlinfo, MV_U32 offset, + MV_U8* pReadBuff, MV_U32 buffSize) +{ + MV_U8 cmd[MV_SFLASH_READ_CMND_LENGTH]; + MV_STATUS ret; + + /* check for NULL pointer */ + if ((pFlinfo == NULL) || (pReadBuff == NULL)) + { + mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__); + return MV_BAD_PARAM; + } + + /* Protection - check if the model was detected */ + if (pFlinfo->index >= MV_ARRAY_SIZE(sflash)) + { + DB(mvOsPrintf("%s WARNING: Invaild parameter index!\n", __FUNCTION__);) + return MV_BAD_PARAM; + } + + /* Set the SPI frequency to the MAX allowed for fast-read operations */ + mvOsPrintf("Setting freq to %d.\n",sflash[pFlinfo->index].spiMaxFastFreq); + if ((ret = mvSpiBaudRateSet(sflash[pFlinfo->index].spiMaxFastFreq)) != MV_OK) + { + mvOsPrintf("%s ERROR: Failed to set the SPI fast frequency!\n", __FUNCTION__); + return ret; + } + + cmd[0] = sflash[pFlinfo->index].opcdFSTRD; + cmd[1] = ((offset >> 16) & 0xFF); + cmd[2] = ((offset >> 8) & 0xFF); + cmd[3] = (offset & 0xFF); + + + ret = mvSpiWriteThenRead(cmd, MV_SFLASH_READ_CMND_LENGTH, pReadBuff, buffSize, + sflash[pFlinfo->index].spiFastRdDummyBytes); + + /* Reset the SPI frequency to the MAX allowed for the device for best performance */ + if ((ret = mvSpiBaudRateSet(sflash[pFlinfo->index].spiMaxFreq)) != MV_OK) + { + mvOsPrintf("%s ERROR: Failed to set the SPI frequency!\n", __FUNCTION__); + return ret; + } + + return ret; +} + + +/******************************************************************************* +* mvSFlashBlockWr - Write a buffer with any size +* +* DESCRIPTION: +* write regardless of the page boundaries and size limit per Page +* program command +* +* INPUT: +* pFlinfo: pointer to the Flash information structure +* offset: byte offset within the flash region +* pWriteBuff: pointer to the buffer holding the data to program +* buffSize: size of the buffer to write +* +* OUTPUT: +* None +* +* RETURN: +* Success or Error code. +* +* +*******************************************************************************/ +MV_STATUS mvSFlashBlockWr (MV_SFLASH_INFO * pFlinfo, MV_U32 offset, + MV_U8* pWriteBuff, MV_U32 buffSize) +{ + MV_STATUS ret; + MV_U32 data2write = buffSize; + MV_U32 preAllOffset = (offset & MV_SFLASH_PAGE_ALLIGN_MASK(MV_M25P_PAGE_SIZE)); + MV_U32 preAllSz = (preAllOffset ? (MV_M25P_PAGE_SIZE - preAllOffset) : 0); + MV_U32 writeOffset = offset; + + /* check for NULL pointer */ +#ifndef CONFIG_MARVELL + if(NULL == pWriteBuff) + { + mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__); + return MV_BAD_PARAM; + } +#endif + + if (pFlinfo == NULL) + { + mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__); + return MV_BAD_PARAM; + } + + /* Protection - check if the model was detected */ + if (pFlinfo->index >= MV_ARRAY_SIZE(sflash)) + { + DB(mvOsPrintf("%s WARNING: Invaild parameter index!\n", __FUNCTION__);) + return MV_BAD_PARAM; + } + + /* check that the buffer size does not exceed the flash size */ + if ((offset + buffSize) > mvSFlashSizeGet(pFlinfo)) + { + DB(mvOsPrintf("%s WARNING: Write exceeds flash size!\n", __FUNCTION__);) + return MV_OUT_OF_RANGE; + } + + /* check if the total block size is less than the first chunk remainder */ + if (data2write < preAllSz) + preAllSz = data2write; + + /* check if programing does not start at a 64byte alligned offset */ + if (preAllSz) + { + if ((ret = mvSFlashPageWr(pFlinfo, writeOffset, pWriteBuff, preAllSz)) != MV_OK) + return ret; + + /* increment pointers and counters */ + writeOffset += preAllSz; + data2write -= preAllSz; + pWriteBuff += preAllSz; + } + + /* program the data that fits in complete page chunks */ + while (data2write >= sflash[pFlinfo->index].pageSize) + { + if ((ret = mvSFlashPageWr(pFlinfo, writeOffset, pWriteBuff, sflash[pFlinfo->index].pageSize)) != MV_OK) + return ret; + + /* increment pointers and counters */ + writeOffset += sflash[pFlinfo->index].pageSize; + data2write -= sflash[pFlinfo->index].pageSize; + pWriteBuff += sflash[pFlinfo->index].pageSize; + } + + /* program the last partial chunk */ + if (data2write) + { + if ((ret = mvSFlashPageWr(pFlinfo, writeOffset, pWriteBuff, data2write)) != MV_OK) + return ret; + } + + return MV_OK; +} + +/******************************************************************************* +* mvSFlashIdGet - Get the manufacturer and device IDs. +* +* DESCRIPTION: +* Get the Manufacturer and device IDs from the serial flash through +* writing the RDID command then reading 3 bytes of data. In case that +* this command was called for the first time in order to detect the +* manufacturer and device IDs, then the default RDID opcode will be used +* unless the device index is indicated by the user (in case the SPI flash +* does not use the default RDID opcode). +* +* INPUT: +* pFlinfo: pointer to the Flash information structure +* pManId: pointer to the 8bit variable to hold the manufacturing ID +* pDevId: pointer to the 16bit variable to hold the device ID +* +* OUTPUT: +* pManId: pointer to the 8bit variable holding the manufacturing ID +* pDevId: pointer to the 16bit variable holding the device ID +* +* RETURN: +* Success or Error code. +* +* +*******************************************************************************/ +MV_STATUS mvSFlashIdGet (MV_SFLASH_INFO * pFlinfo, MV_U8* pManId, MV_U16* pDevId) +{ + MV_STATUS ret; + MV_U8 cmd[MV_SFLASH_RDID_CMND_LENGTH]; + MV_U8 id[MV_SFLASH_RDID_REPLY_LENGTH]; + + + + /* check for NULL pointer */ + if ((pFlinfo == NULL) || (pManId == NULL) || (pDevId == NULL)) + { + mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__); + return MV_BAD_PARAM; + } + + if (pFlinfo->index >= MV_ARRAY_SIZE(sflash)) + return mvSFlashWithDefaultsIdGet(pFlinfo, pManId, pDevId); + else + cmd[0] = sflash[pFlinfo->index].opcdRDID; + + if ((ret = mvSpiWriteThenRead(cmd, MV_SFLASH_RDID_CMND_LENGTH, id, MV_SFLASH_RDID_REPLY_LENGTH, 0)) != MV_OK) + return ret; + + *pManId = id[0]; + *pDevId = 0; + *pDevId |= (id[1] << 8); + *pDevId |= id[2]; + + return MV_OK; +} + +/******************************************************************************* +* mvSFlashWpRegionSet - Set the Write-Protected region +* +* DESCRIPTION: +* Set the Write-Protected region +* +* INPUT: +* pFlinfo: pointer to the Flash information structure +* wpRegion: which region will be protected +* +* OUTPUT: +* None +* +* RETURN: +* Success or Error code. +* +* +*******************************************************************************/ +MV_STATUS mvSFlashWpRegionSet (MV_SFLASH_INFO * pFlinfo, MV_SFLASH_WP_REGION wpRegion) +{ + MV_U8 wpMask; + + /* check for NULL pointer */ + if (pFlinfo == NULL) + { + mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__); + return MV_BAD_PARAM; + } + + /* Protection - check if the model was detected */ + if (pFlinfo->index >= MV_ARRAY_SIZE(sflash)) + { + DB(mvOsPrintf("%s WARNING: Invaild parameter index!\n", __FUNCTION__);) + return MV_BAD_PARAM; + } + + /* Check if the chip is an ST flash; then WP supports only 3 bits */ + if (pFlinfo->manufacturerId == MV_M25PXXX_ST_MANF_ID) + { + switch (wpRegion) + { + case MV_WP_NONE: + wpMask = MV_M25P_STATUS_BP_NONE; + break; + + case MV_WP_UPR_1OF128: + DB(mvOsPrintf("%s WARNING: Invaild option for this flash chip!\n", __FUNCTION__);) + return MV_NOT_SUPPORTED; + + case MV_WP_UPR_1OF64: + wpMask = MV_M25P_STATUS_BP_1_OF_64; + break; + + case MV_WP_UPR_1OF32: + wpMask = MV_M25P_STATUS_BP_1_OF_32; + break; + + case MV_WP_UPR_1OF16: + wpMask = MV_M25P_STATUS_BP_1_OF_16; + break; + + case MV_WP_UPR_1OF8: + wpMask = MV_M25P_STATUS_BP_1_OF_8; + break; + + case MV_WP_UPR_1OF4: + wpMask = MV_M25P_STATUS_BP_1_OF_4; + break; + + case MV_WP_UPR_1OF2: + wpMask = MV_M25P_STATUS_BP_1_OF_2; + break; + + case MV_WP_ALL: + wpMask = MV_M25P_STATUS_BP_ALL; + break; + + default: + DB(mvOsPrintf("%s WARNING: Invaild parameter WP region!\n", __FUNCTION__);) + return MV_BAD_PARAM; + } + } + /* check if the manufacturer is MXIC then the WP is 4bits */ + else if (pFlinfo->manufacturerId == MV_MXIC_MANF_ID) + { + switch (wpRegion) + { + case MV_WP_NONE: + wpMask = MV_MX25L_STATUS_BP_NONE; + break; + + case MV_WP_UPR_1OF128: + wpMask = MV_MX25L_STATUS_BP_1_OF_128; + break; + + case MV_WP_UPR_1OF64: + wpMask = MV_MX25L_STATUS_BP_1_OF_64; + break; + + case MV_WP_UPR_1OF32: + wpMask = MV_MX25L_STATUS_BP_1_OF_32; + break; + + case MV_WP_UPR_1OF16: + wpMask = MV_MX25L_STATUS_BP_1_OF_16; + break; + + case MV_WP_UPR_1OF8: + wpMask = MV_MX25L_STATUS_BP_1_OF_8; + break; + + case MV_WP_UPR_1OF4: + wpMask = MV_MX25L_STATUS_BP_1_OF_4; + break; + + case MV_WP_UPR_1OF2: + wpMask = MV_MX25L_STATUS_BP_1_OF_2; + break; + + case MV_WP_ALL: + wpMask = MV_MX25L_STATUS_BP_ALL; + break; + + default: + DB(mvOsPrintf("%s WARNING: Invaild parameter WP region!\n", __FUNCTION__);) + return MV_BAD_PARAM; + } + } + /* check if the manufacturer is SPANSION then the WP is 4bits */ + else if (pFlinfo->manufacturerId == MV_SPANSION_MANF_ID) + { + switch (wpRegion) + { + case MV_WP_NONE: + wpMask = MV_S25FL_STATUS_BP_NONE; + break; + + case MV_WP_UPR_1OF128: + DB(mvOsPrintf("%s WARNING: Invaild option for this flash chip!\n", __FUNCTION__);) + return MV_NOT_SUPPORTED; + + case MV_WP_UPR_1OF64: + wpMask = MV_S25FL_STATUS_BP_1_OF_64; + break; + + case MV_WP_UPR_1OF32: + wpMask = MV_S25FL_STATUS_BP_1_OF_32; + break; + + case MV_WP_UPR_1OF16: + wpMask = MV_S25FL_STATUS_BP_1_OF_16; + break; + + case MV_WP_UPR_1OF8: + wpMask = MV_S25FL_STATUS_BP_1_OF_8; + break; + + case MV_WP_UPR_1OF4: + wpMask = MV_S25FL_STATUS_BP_1_OF_4; + break; + + case MV_WP_UPR_1OF2: + wpMask = MV_S25FL_STATUS_BP_1_OF_2; + break; + + case MV_WP_ALL: + wpMask = MV_S25FL_STATUS_BP_ALL; + break; + + + default: + DB(mvOsPrintf("%s WARNING: Invaild parameter WP region!\n", __FUNCTION__);) + return MV_BAD_PARAM; + } + } + else + { + DB(mvOsPrintf("%s WARNING: Invaild parameter Manufacturer ID!\n", __FUNCTION__);) + return MV_BAD_PARAM; + } + + /* Verify that the SRWD bit is always set - register is s/w locked */ + wpMask |= MV_SFLASH_STATUS_REG_SRWD_MASK; + + return mvStatusRegSet(pFlinfo, wpMask); +} + +/******************************************************************************* +* mvSFlashWpRegionGet - Get the Write-Protected region configured +* +* DESCRIPTION: +* Get from the chip the Write-Protected region configured +* +* INPUT: +* pFlinfo: pointer to the Flash information structure +* pWpRegion: pointer to the variable to return the WP region in +* +* OUTPUT: +* wpRegion: pointer to the variable holding the WP region configured +* +* RETURN: +* Success or Error code. +* +* +*******************************************************************************/ +MV_STATUS mvSFlashWpRegionGet (MV_SFLASH_INFO * pFlinfo, MV_SFLASH_WP_REGION * pWpRegion) +{ + MV_STATUS ret; + MV_U8 reg; + + /* check for NULL pointer */ + if ((pFlinfo == NULL) || (pWpRegion == NULL)) + { + mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__); + return MV_BAD_PARAM; + } + + /* Protection - check if the model was detected */ + if (pFlinfo->index >= MV_ARRAY_SIZE(sflash)) + { + DB(mvOsPrintf("%s WARNING: Invaild parameter index!\n", __FUNCTION__);) + return MV_BAD_PARAM; + } + + if ((ret = mvStatusRegGet(pFlinfo, ®)) != MV_OK) + return ret; + + /* Check if the chip is an ST flash; then WP supports only 3 bits */ + if (pFlinfo->manufacturerId == MV_M25PXXX_ST_MANF_ID) + { + switch ((reg & MV_M25P_STATUS_REG_WP_MASK)) + { + case MV_M25P_STATUS_BP_NONE: + *pWpRegion = MV_WP_NONE; + break; + + case MV_M25P_STATUS_BP_1_OF_64: + *pWpRegion = MV_WP_UPR_1OF64; + break; + + case MV_M25P_STATUS_BP_1_OF_32: + *pWpRegion = MV_WP_UPR_1OF32; + break; + + case MV_M25P_STATUS_BP_1_OF_16: + *pWpRegion = MV_WP_UPR_1OF16; + break; + + case MV_M25P_STATUS_BP_1_OF_8: + *pWpRegion = MV_WP_UPR_1OF8; + break; + + case MV_M25P_STATUS_BP_1_OF_4: + *pWpRegion = MV_WP_UPR_1OF4; + break; + + case MV_M25P_STATUS_BP_1_OF_2: + *pWpRegion = MV_WP_UPR_1OF2; + break; + + case MV_M25P_STATUS_BP_ALL: + *pWpRegion = MV_WP_ALL; + break; + + default: + DB(mvOsPrintf("%s WARNING: Unidentified WP region in h/w!\n", __FUNCTION__);) + return MV_BAD_VALUE; + } + } + /* check if the manufacturer is MXIC then the WP is 4bits */ + else if (pFlinfo->manufacturerId == MV_MXIC_MANF_ID) + { + switch ((reg & MV_MX25L_STATUS_REG_WP_MASK)) + { + case MV_MX25L_STATUS_BP_NONE: + *pWpRegion = MV_WP_NONE; + break; + + case MV_MX25L_STATUS_BP_1_OF_128: + *pWpRegion = MV_WP_UPR_1OF128; + break; + + case MV_MX25L_STATUS_BP_1_OF_64: + *pWpRegion = MV_WP_UPR_1OF64; + break; + + case MV_MX25L_STATUS_BP_1_OF_32: + *pWpRegion = MV_WP_UPR_1OF32; + break; + + case MV_MX25L_STATUS_BP_1_OF_16: + *pWpRegion = MV_WP_UPR_1OF16; + break; + + case MV_MX25L_STATUS_BP_1_OF_8: + *pWpRegion = MV_WP_UPR_1OF8; + break; + + case MV_MX25L_STATUS_BP_1_OF_4: + *pWpRegion = MV_WP_UPR_1OF4; + break; + + case MV_MX25L_STATUS_BP_1_OF_2: + *pWpRegion = MV_WP_UPR_1OF2; + break; + + case MV_MX25L_STATUS_BP_ALL: + *pWpRegion = MV_WP_ALL; + break; + + default: + DB(mvOsPrintf("%s WARNING: Unidentified WP region in h/w!\n", __FUNCTION__);) + return MV_BAD_VALUE; + } + } + /* Check if the chip is an SPANSION flash; then WP supports only 3 bits */ + else if (pFlinfo->manufacturerId == MV_SPANSION_MANF_ID) + { + switch ((reg & MV_S25FL_STATUS_REG_WP_MASK)) + { + case MV_S25FL_STATUS_BP_NONE: + *pWpRegion = MV_WP_NONE; + break; + + case MV_S25FL_STATUS_BP_1_OF_64: + *pWpRegion = MV_WP_UPR_1OF64; + break; + + case MV_S25FL_STATUS_BP_1_OF_32: + *pWpRegion = MV_WP_UPR_1OF32; + break; + + case MV_S25FL_STATUS_BP_1_OF_16: + *pWpRegion = MV_WP_UPR_1OF16; + break; + + case MV_S25FL_STATUS_BP_1_OF_8: + *pWpRegion = MV_WP_UPR_1OF8; + break; + + case MV_S25FL_STATUS_BP_1_OF_4: + *pWpRegion = MV_WP_UPR_1OF4; + break; + + case MV_S25FL_STATUS_BP_1_OF_2: + *pWpRegion = MV_WP_UPR_1OF2; + break; + + case MV_S25FL_STATUS_BP_ALL: + *pWpRegion = MV_WP_ALL; + break; + + default: + DB(mvOsPrintf("%s WARNING: Unidentified WP region in h/w!\n", __FUNCTION__);) + return MV_BAD_VALUE; + } + } + else + { + DB(mvOsPrintf("%s WARNING: Invaild parameter Manufacturer ID!\n", __FUNCTION__);) + return MV_BAD_PARAM; + } + + return MV_OK; +} + +/******************************************************************************* +* mvSFlashStatRegLock - Lock the status register for writing - W/Vpp +* pin should be low to take effect +* +* DESCRIPTION: +* Lock the access to the Status Register for writing. This will +* cause the flash to enter the hardware protection mode if the W/Vpp +* is low. If the W/Vpp is hi, the chip will be in soft protection mode, but +* the register will continue to be writable if WREN sequence was used. +* +* INPUT: +* pFlinfo: pointer to the Flash information structure +* srLock: enable/disable (MV_TRUE/MV_FALSE) status registor lock mechanism +* +* OUTPUT: +* None +* +* RETURN: +* Success or Error code. +* +* +*******************************************************************************/ +MV_STATUS mvSFlashStatRegLock (MV_SFLASH_INFO * pFlinfo, MV_BOOL srLock) +{ + MV_STATUS ret; + MV_U8 reg; + + /* check for NULL pointer */ + if (pFlinfo == NULL) + { + mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__); + return MV_BAD_PARAM; + } + + /* Protection - check if the model was detected */ + if (pFlinfo->index >= MV_ARRAY_SIZE(sflash)) + { + DB(mvOsPrintf("%s WARNING: Invaild parameter index!\n", __FUNCTION__);) + return MV_BAD_PARAM; + } + + if ((ret = mvStatusRegGet(pFlinfo, ®)) != MV_OK) + return ret; + + if (srLock) + reg |= MV_SFLASH_STATUS_REG_SRWD_MASK; + else + reg &= ~MV_SFLASH_STATUS_REG_SRWD_MASK; + + return mvStatusRegSet(pFlinfo, reg); +} + +/******************************************************************************* +* mvSFlashSizeGet - Get the size of the SPI flash +* +* DESCRIPTION: +* based on the sector number and size of each sector calculate the total +* size of the flash memory. +* +* INPUT: +* pFlinfo: pointer to the Flash information structure +* +* OUTPUT: +* None. +* +* RETURN: +* Size of the flash in bytes. +* +* +*******************************************************************************/ +MV_U32 mvSFlashSizeGet (MV_SFLASH_INFO * pFlinfo) +{ + /* check for NULL pointer */ + if (pFlinfo == NULL) + { + mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__); + return 0; + } + + return (pFlinfo->sectorSize * pFlinfo->sectorNumber); +} + +/******************************************************************************* +* mvSFlashPowerSaveEnter - Cause the falsh device to go into power save mode +* +* DESCRIPTION: +* Enter a special power save mode. +* +* INPUT: +* pFlinfo: pointer to the Flash information structure +* +* OUTPUT: +* None. +* +* RETURN: +* Size of the flash in bytes. +* +* +*******************************************************************************/ +MV_STATUS mvSFlashPowerSaveEnter(MV_SFLASH_INFO * pFlinfo) +{ + MV_STATUS ret; + MV_U8 cmd[MV_SFLASH_DP_CMND_LENGTH]; + + + /* check for NULL pointer */ + if (pFlinfo == NULL) + { + mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__); + return 0; + } + + /* Protection - check if the model was detected */ + if (pFlinfo->index >= MV_ARRAY_SIZE(sflash)) + { + DB(mvOsPrintf("%s WARNING: Invaild parameter index!\n", __FUNCTION__);) + return MV_BAD_PARAM; + } + + /* check that power save mode is supported in the specific device */ + if (sflash[pFlinfo->index].opcdPwrSave == MV_SFLASH_NO_SPECIFIC_OPCD) + { + DB(mvOsPrintf("%s WARNING: Power save not supported for this device!\n", __FUNCTION__);) + return MV_NOT_SUPPORTED; + } + + cmd[0] = sflash[pFlinfo->index].opcdPwrSave; + + if ((ret = mvSpiWriteThenWrite(cmd, MV_SFLASH_DP_CMND_LENGTH, NULL, 0)) != MV_OK) + return ret; + + return MV_OK; + +} + +/******************************************************************************* +* mvSFlashPowerSaveExit - Cause the falsh device to exit the power save mode +* +* DESCRIPTION: +* Exit the deep power save mode. +* +* INPUT: +* pFlinfo: pointer to the Flash information structure +* +* OUTPUT: +* None. +* +* RETURN: +* Size of the flash in bytes. +* +* +*******************************************************************************/ +MV_STATUS mvSFlashPowerSaveExit (MV_SFLASH_INFO * pFlinfo) +{ + MV_STATUS ret; + MV_U8 cmd[MV_SFLASH_RES_CMND_LENGTH]; + + + /* check for NULL pointer */ + if (pFlinfo == NULL) + { + mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__); + return 0; + } + + /* Protection - check if the model was detected */ + if (pFlinfo->index >= MV_ARRAY_SIZE(sflash)) + { + DB(mvOsPrintf("%s WARNING: Invaild parameter index!\n", __FUNCTION__);) + return MV_BAD_PARAM; + } + + /* check that power save mode is supported in the specific device */ + if (sflash[pFlinfo->index].opcdRES == MV_SFLASH_NO_SPECIFIC_OPCD) + { + DB(mvOsPrintf("%s WARNING: Read Electronic Signature not supported for this device!\n", __FUNCTION__);) + return MV_NOT_SUPPORTED; + } + + cmd[0] = sflash[pFlinfo->index].opcdRES; + + if ((ret = mvSpiWriteThenWrite(cmd, MV_SFLASH_RES_CMND_LENGTH, NULL, 0)) != MV_OK) + return ret; + + /* add the delay needed for the device to wake up */ + mvOsDelay(MV_MXIC_DP_EXIT_DELAY); /* 30 ms */ + + return MV_OK; + +} + +/******************************************************************************* +* mvSFlashModelGet - Retreive the string with the device manufacturer and model +* +* DESCRIPTION: +* Retreive the string with the device manufacturer and model +* +* INPUT: +* pFlinfo: pointer to the Flash information structure +* +* OUTPUT: +* None. +* +* RETURN: +* pointer to the string indicating the device manufacturer and model +* +* +*******************************************************************************/ +const MV_8 * mvSFlashModelGet (MV_SFLASH_INFO * pFlinfo) +{ + static const MV_8 * unknModel = (const MV_8 *)"Unknown"; + + /* check for NULL pointer */ + if (pFlinfo == NULL) + { + mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__); + return 0; + } + + /* Protection - check if the model was detected */ + if (pFlinfo->index >= MV_ARRAY_SIZE(sflash)) + { + DB(mvOsPrintf("%s WARNING: Invaild parameter index!\n", __FUNCTION__);) + return unknModel; + } + + return sflash[pFlinfo->index].deviceModel; +} + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/sflash/mvSFlash.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/sflash/mvSFlash.h new file mode 100644 index 0000000..f441a5c --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/sflash/mvSFlash.h @@ -0,0 +1,166 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#ifndef __INCmvSFlashH +#define __INCmvSFlashH + +#include "mvTypes.h" + +/* MCAROS */ +#define MV_SFLASH_PAGE_ALLIGN_MASK(pgSz) (pgSz-1) +#define MV_ARRAY_SIZE(a) ((sizeof(a)) / (sizeof(a[0]))) + +/* Constants */ +#define MV_INVALID_DEVICE_NUMBER 0xFFFFFFFF +/* 10 MHz is the minimum possible SPI frequency when tclk is set 200MHz*/ +#define MV_SFLASH_BASIC_SPI_FREQ 10000000 +/* enumerations */ +typedef enum +{ + MV_WP_NONE, /* Unprotect the whole chip */ + MV_WP_UPR_1OF128, /* Write protect the upper 1/128 part */ + MV_WP_UPR_1OF64, /* Write protect the upper 1/64 part */ + MV_WP_UPR_1OF32, /* Write protect the upper 1/32 part */ + MV_WP_UPR_1OF16, /* Write protect the upper 1/16 part */ + MV_WP_UPR_1OF8, /* Write protect the upper 1/8 part */ + MV_WP_UPR_1OF4, /* Write protect the upper 1/4 part */ + MV_WP_UPR_1OF2, /* Write protect the upper 1/2 part */ + MV_WP_ALL /* Write protect the whole chip */ +} MV_SFLASH_WP_REGION; + +/* Type Definitions */ +typedef struct +{ + MV_U8 opcdWREN; /* Write enable opcode */ + MV_U8 opcdWRDI; /* Write disable opcode */ + MV_U8 opcdRDID; /* Read ID opcode */ + MV_U8 opcdRDSR; /* Read Status Register opcode */ + MV_U8 opcdWRSR; /* Write Status register opcode */ + MV_U8 opcdREAD; /* Read opcode */ + MV_U8 opcdFSTRD; /* Fast Read opcode */ + MV_U8 opcdPP; /* Page program opcode */ + MV_U8 opcdSE; /* Sector erase opcode */ + MV_U8 opcdBE; /* Bulk erase opcode */ + MV_U8 opcdRES; /* Read electronic signature */ + MV_U8 opcdPwrSave; /* Go into power save mode */ + MV_U32 sectorSize; /* Size of each sector */ + MV_U32 sectorNumber; /* Number of sectors */ + MV_U32 pageSize; /* size of each page */ + const char * deviceModel; /* string with the device model */ + MV_U32 manufacturerId; /* The manufacturer ID */ + MV_U32 deviceId; /* Device ID */ + MV_U32 spiMaxFreq; /* The MAX frequency that can be used with the device */ + MV_U32 spiMaxFastFreq; /* The MAX frequency that can be used with the device for fast reads */ + MV_U32 spiFastRdDummyBytes; /* Number of dumy bytes to read before real data when working in fast read mode. */ +} MV_SFLASH_DEVICE_PARAMS; + +typedef struct +{ + MV_U32 baseAddr; /* Flash Base Address used in fast mode */ + MV_U8 manufacturerId; /* Manufacturer ID */ + MV_U16 deviceId; /* Device ID */ + MV_U32 sectorSize; /* Size of each sector - all the same */ + MV_U32 sectorNumber; /* Number of sectors */ + MV_U32 pageSize; /* Page size - affect allignment */ + MV_U32 index; /* index of the device in the sflash table (internal parameter) */ +} MV_SFLASH_INFO; + +/* Function Prototypes */ +/* Init */ +MV_STATUS mvSFlashInit (MV_SFLASH_INFO * pFlinfo); + +/* erase */ +MV_STATUS mvSFlashSectorErase (MV_SFLASH_INFO * pFlinfo, MV_U32 secNumber); +MV_STATUS mvSFlashChipErase (MV_SFLASH_INFO * pFlinfo); + +/* Read */ +MV_STATUS mvSFlashBlockRd (MV_SFLASH_INFO * pFlinfo, MV_U32 offset, + MV_U8* pReadBuff, MV_U32 buffSize); +MV_STATUS mvSFlashFastBlockRd (MV_SFLASH_INFO * pFlinfo, MV_U32 offset, + MV_U8* pReadBuff, MV_U32 buffSize); + +/* write regardless of the page boundaries and size limit per Page program command */ +MV_STATUS mvSFlashBlockWr (MV_SFLASH_INFO * pFlinfo, MV_U32 offset, + MV_U8* pWriteBuff, MV_U32 buffSize); +/* Get IDs */ +MV_STATUS mvSFlashIdGet (MV_SFLASH_INFO * pFlinfo, MV_U8* pManId, MV_U16* pDevId); + +/* Set and Get the Write Protection region - if the Status register is not locked */ +MV_STATUS mvSFlashWpRegionSet (MV_SFLASH_INFO * pFlinfo, MV_SFLASH_WP_REGION wpRegion); +MV_STATUS mvSFlashWpRegionGet (MV_SFLASH_INFO * pFlinfo, MV_SFLASH_WP_REGION * pWpRegion); + +/* Lock the status register for writing - W/Vpp pin should be low to take effect */ +MV_STATUS mvSFlashStatRegLock (MV_SFLASH_INFO * pFlinfo, MV_BOOL srLock); + +/* Get the regions sizes */ +MV_U32 mvSFlashSizeGet (MV_SFLASH_INFO * pFlinfo); + +/* Cause the falsh device to go into power save mode */ +MV_STATUS mvSFlashPowerSaveEnter(MV_SFLASH_INFO * pFlinfo); +MV_STATUS mvSFlashPowerSaveExit (MV_SFLASH_INFO * pFlinfo); + +/* Retreive the string with the device manufacturer and model */ +const MV_8 * mvSFlashModelGet (MV_SFLASH_INFO * pFlinfo); + +#endif /* __INCmvSFlashH */ diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/sflash/mvSFlashSpec.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/sflash/mvSFlashSpec.h new file mode 100644 index 0000000..eeb4426 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/sflash/mvSFlashSpec.h @@ -0,0 +1,233 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#ifndef __INCmvSFlashSpecH +#define __INCmvSFlashSpecH + +/* Constants */ +#define MV_SFLASH_READ_CMND_LENGTH 4 /* 1B opcode + 3B address */ +#define MV_SFLASH_SE_CMND_LENGTH 4 /* 1B opcode + 3B address */ +#define MV_SFLASH_BE_CMND_LENGTH 1 /* 1B opcode */ +#define MV_SFLASH_PP_CMND_LENGTH 4 /* 1B opcode + 3B address */ +#define MV_SFLASH_WREN_CMND_LENGTH 1 /* 1B opcode */ +#define MV_SFLASH_WRDI_CMND_LENGTH 1 /* 1B opcode */ +#define MV_SFLASH_RDID_CMND_LENGTH 1 /* 1B opcode */ +#define MV_SFLASH_RDID_REPLY_LENGTH 3 /* 1B manf ID and 2B device ID */ +#define MV_SFLASH_RDSR_CMND_LENGTH 1 /* 1B opcode */ +#define MV_SFLASH_RDSR_REPLY_LENGTH 1 /* 1B status */ +#define MV_SFLASH_WRSR_CMND_LENGTH 2 /* 1B opcode + 1B status value */ +#define MV_SFLASH_DP_CMND_LENGTH 1 /* 1B opcode */ +#define MV_SFLASH_RES_CMND_LENGTH 1 /* 1B opcode */ + +/* Status Register Bit Masks */ +#define MV_SFLASH_STATUS_REG_WIP_OFFSET 0 /* bit 0; write in progress */ +#define MV_SFLASH_STATUS_REG_WP_OFFSET 2 /* bit 2-4; write protect option */ +#define MV_SFLASH_STATUS_REG_SRWD_OFFSET 7 /* bit 7; lock status register write */ +#define MV_SFLASH_STATUS_REG_WIP_MASK (0x1 << MV_SFLASH_STATUS_REG_WIP_OFFSET) +#define MV_SFLASH_STATUS_REG_SRWD_MASK (0x1 << MV_SFLASH_STATUS_REG_SRWD_OFFSET) + +#define MV_SFLASH_MAX_WAIT_LOOP 1000000 +#define MV_SFLASH_CHIP_ERASE_MAX_WAIT_LOOP 0x50000000 + +#define MV_SFLASH_DEFAULT_RDID_OPCD 0x9F /* Default Read ID */ +#define MV_SFLASH_DEFAULT_WREN_OPCD 0x06 /* Default Write Enable */ +#define MV_SFLASH_NO_SPECIFIC_OPCD 0x00 + +/********************************/ +/* ST M25Pxxx Device Specific */ +/********************************/ + +/* Manufacturer IDs and Device IDs for SFLASHs supported by the driver */ +#define MV_M25PXXX_ST_MANF_ID 0x20 +#define MV_M25P32_DEVICE_ID 0x2016 +#define MV_M25P32_MAX_SPI_FREQ 20000000 /* 20MHz */ +#define MV_M25P32_MAX_FAST_SPI_FREQ 50000000 /* 50MHz */ +#define MV_M25P32_FAST_READ_DUMMY_BYTES 1 +#define MV_M25P64_DEVICE_ID 0x2017 +#define MV_M25P64_MAX_SPI_FREQ 20000000 /* 20MHz */ +#define MV_M25P64_MAX_FAST_SPI_FREQ 50000000 /* 50MHz */ +#define MV_M25P64_FAST_READ_DUMMY_BYTES 1 +#define MV_M25P128_DEVICE_ID 0x2018 +#define MV_M25P128_MAX_SPI_FREQ 20000000 /* 20MHz */ +#define MV_M25P128_MAX_FAST_SPI_FREQ 50000000 /* 50MHz */ +#define MV_M25P128_FAST_READ_DUMMY_BYTES 1 + + +/* Sector Sizes and population per device model*/ +#define MV_M25P32_SECTOR_SIZE 0x10000 /* 64K */ +#define MV_M25P64_SECTOR_SIZE 0x10000 /* 64K */ +#define MV_M25P128_SECTOR_SIZE 0x40000 /* 256K */ +#define MV_M25P32_SECTOR_NUMBER 64 +#define MV_M25P64_SECTOR_NUMBER 128 +#define MV_M25P128_SECTOR_NUMBER 64 +#define MV_M25P_PAGE_SIZE 0x100 /* 256 byte */ + +#define MV_M25P_WREN_CMND_OPCD 0x06 /* Write Enable */ +#define MV_M25P_WRDI_CMND_OPCD 0x04 /* Write Disable */ +#define MV_M25P_RDID_CMND_OPCD 0x9F /* Read ID */ +#define MV_M25P_RDSR_CMND_OPCD 0x05 /* Read Status Register */ +#define MV_M25P_WRSR_CMND_OPCD 0x01 /* Write Status Register */ +#define MV_M25P_READ_CMND_OPCD 0x03 /* Sequential Read */ +#define MV_M25P_FAST_RD_CMND_OPCD 0x0B /* Fast Read */ +#define MV_M25P_PP_CMND_OPCD 0x02 /* Page Program */ +#define MV_M25P_SE_CMND_OPCD 0xD8 /* Sector Erase */ +#define MV_M25P_BE_CMND_OPCD 0xC7 /* Bulk Erase */ +#define MV_M25P_RES_CMND_OPCD 0xAB /* Read Electronic Signature */ + +/* Status Register Write Protect Bit Masks - 3bits */ +#define MV_M25P_STATUS_REG_WP_MASK (0x07 << MV_SFLASH_STATUS_REG_WP_OFFSET) +#define MV_M25P_STATUS_BP_NONE (0x00 << MV_SFLASH_STATUS_REG_WP_OFFSET) +#define MV_M25P_STATUS_BP_1_OF_64 (0x01 << MV_SFLASH_STATUS_REG_WP_OFFSET) +#define MV_M25P_STATUS_BP_1_OF_32 (0x02 << MV_SFLASH_STATUS_REG_WP_OFFSET) +#define MV_M25P_STATUS_BP_1_OF_16 (0x03 << MV_SFLASH_STATUS_REG_WP_OFFSET) +#define MV_M25P_STATUS_BP_1_OF_8 (0x04 << MV_SFLASH_STATUS_REG_WP_OFFSET) +#define MV_M25P_STATUS_BP_1_OF_4 (0x05 << MV_SFLASH_STATUS_REG_WP_OFFSET) +#define MV_M25P_STATUS_BP_1_OF_2 (0x06 << MV_SFLASH_STATUS_REG_WP_OFFSET) +#define MV_M25P_STATUS_BP_ALL (0x07 << MV_SFLASH_STATUS_REG_WP_OFFSET) + +/************************************/ +/* MXIC MX25L6405 Device Specific */ +/************************************/ + +/* Manufacturer IDs and Device IDs for SFLASHs supported by the driver */ +#define MV_MXIC_MANF_ID 0xC2 +#define MV_MX25L6405_DEVICE_ID 0x2017 +#define MV_MX25L6405_MAX_SPI_FREQ 20000000 /* 20MHz */ +#define MV_MX25L6405_MAX_FAST_SPI_FREQ 50000000 /* 50MHz */ +#define MV_MX25L6405_FAST_READ_DUMMY_BYTES 1 +#define MV_MXIC_DP_EXIT_DELAY 30 /* 30 ms */ + +/* Sector Sizes and population per device model*/ +#define MV_MX25L6405_SECTOR_SIZE 0x10000 /* 64K */ +#define MV_MX25L6405_SECTOR_NUMBER 128 +#define MV_MXIC_PAGE_SIZE 0x100 /* 256 byte */ + +#define MV_MX25L_WREN_CMND_OPCD 0x06 /* Write Enable */ +#define MV_MX25L_WRDI_CMND_OPCD 0x04 /* Write Disable */ +#define MV_MX25L_RDID_CMND_OPCD 0x9F /* Read ID */ +#define MV_MX25L_RDSR_CMND_OPCD 0x05 /* Read Status Register */ +#define MV_MX25L_WRSR_CMND_OPCD 0x01 /* Write Status Register */ +#define MV_MX25L_READ_CMND_OPCD 0x03 /* Sequential Read */ +#define MV_MX25L_FAST_RD_CMND_OPCD 0x0B /* Fast Read */ +#define MV_MX25L_PP_CMND_OPCD 0x02 /* Page Program */ +#define MV_MX25L_SE_CMND_OPCD 0xD8 /* Sector Erase */ +#define MV_MX25L_BE_CMND_OPCD 0xC7 /* Bulk Erase */ +#define MV_MX25L_DP_CMND_OPCD 0xB9 /* Deep Power Down */ +#define MV_MX25L_RES_CMND_OPCD 0xAB /* Read Electronic Signature */ + +/* Status Register Write Protect Bit Masks - 4bits */ +#define MV_MX25L_STATUS_REG_WP_MASK (0x0F << MV_SFLASH_STATUS_REG_WP_OFFSET) +#define MV_MX25L_STATUS_BP_NONE (0x00 << MV_SFLASH_STATUS_REG_WP_OFFSET) +#define MV_MX25L_STATUS_BP_1_OF_128 (0x01 << MV_SFLASH_STATUS_REG_WP_OFFSET) +#define MV_MX25L_STATUS_BP_1_OF_64 (0x02 << MV_SFLASH_STATUS_REG_WP_OFFSET) +#define MV_MX25L_STATUS_BP_1_OF_32 (0x03 << MV_SFLASH_STATUS_REG_WP_OFFSET) +#define MV_MX25L_STATUS_BP_1_OF_16 (0x04 << MV_SFLASH_STATUS_REG_WP_OFFSET) +#define MV_MX25L_STATUS_BP_1_OF_8 (0x05 << MV_SFLASH_STATUS_REG_WP_OFFSET) +#define MV_MX25L_STATUS_BP_1_OF_4 (0x06 << MV_SFLASH_STATUS_REG_WP_OFFSET) +#define MV_MX25L_STATUS_BP_1_OF_2 (0x07 << MV_SFLASH_STATUS_REG_WP_OFFSET) +#define MV_MX25L_STATUS_BP_ALL (0x0F << MV_SFLASH_STATUS_REG_WP_OFFSET) + +/************************************/ +/* SPANSION S25FL128P Device Specific */ +/************************************/ + +/* Manufacturer IDs and Device IDs for SFLASHs supported by the driver */ +#define MV_SPANSION_MANF_ID 0x01 +#define MV_S25FL128_DEVICE_ID 0x2018 +#define MV_S25FL128_MAX_SPI_FREQ 33000000 /* 33MHz */ +#define MV_S25FL128_MAX_FAST_SPI_FREQ 104000000 /* 104MHz */ +#define MV_S25FL128_FAST_READ_DUMMY_BYTES 1 + +/* Sector Sizes and population per device model*/ +#define MV_S25FL128_SECTOR_SIZE 0x40000 /* 256K */ +#define MV_S25FL128_SECTOR_NUMBER 64 +#define MV_S25FL_PAGE_SIZE 0x100 /* 256 byte */ + +#define MV_S25FL_WREN_CMND_OPCD 0x06 /* Write Enable */ +#define MV_S25FL_WRDI_CMND_OPCD 0x04 /* Write Disable */ +#define MV_S25FL_RDID_CMND_OPCD 0x9F /* Read ID */ +#define MV_S25FL_RDSR_CMND_OPCD 0x05 /* Read Status Register */ +#define MV_S25FL_WRSR_CMND_OPCD 0x01 /* Write Status Register */ +#define MV_S25FL_READ_CMND_OPCD 0x03 /* Sequential Read */ +#define MV_S25FL_FAST_RD_CMND_OPCD 0x0B /* Fast Read */ +#define MV_S25FL_PP_CMND_OPCD 0x02 /* Page Program */ +#define MV_S25FL_SE_CMND_OPCD 0xD8 /* Sector Erase */ +#define MV_S25FL_BE_CMND_OPCD 0xC7 /* Bulk Erase */ +#define MV_S25FL_DP_CMND_OPCD 0xB9 /* Deep Power Down */ +#define MV_S25FL_RES_CMND_OPCD 0xAB /* Read Electronic Signature */ + +/* Status Register Write Protect Bit Masks - 4bits */ +#define MV_S25FL_STATUS_REG_WP_MASK (0x0F << MV_SFLASH_STATUS_REG_WP_OFFSET) +#define MV_S25FL_STATUS_BP_NONE (0x00 << MV_SFLASH_STATUS_REG_WP_OFFSET) +#define MV_S25FL_STATUS_BP_1_OF_128 (0x01 << MV_SFLASH_STATUS_REG_WP_OFFSET) +#define MV_S25FL_STATUS_BP_1_OF_64 (0x02 << MV_SFLASH_STATUS_REG_WP_OFFSET) +#define MV_S25FL_STATUS_BP_1_OF_32 (0x03 << MV_SFLASH_STATUS_REG_WP_OFFSET) +#define MV_S25FL_STATUS_BP_1_OF_16 (0x04 << MV_SFLASH_STATUS_REG_WP_OFFSET) +#define MV_S25FL_STATUS_BP_1_OF_8 (0x05 << MV_SFLASH_STATUS_REG_WP_OFFSET) +#define MV_S25FL_STATUS_BP_1_OF_4 (0x06 << MV_SFLASH_STATUS_REG_WP_OFFSET) +#define MV_S25FL_STATUS_BP_1_OF_2 (0x07 << MV_SFLASH_STATUS_REG_WP_OFFSET) +#define MV_S25FL_STATUS_BP_ALL (0x0F << MV_SFLASH_STATUS_REG_WP_OFFSET) + +#endif /* __INCmvSFlashSpecH */ + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/spi/mvCompVer.txt b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/spi/mvCompVer.txt new file mode 100644 index 0000000..85bfa61 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/spi/mvCompVer.txt @@ -0,0 +1,4 @@ +Global HAL Version: FEROCEON_HAL_3_1_7 +Unit HAL Version: 3.1.3 +Description: This component includes an implementation of the unit HAL drivers + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/spi/mvSpi.c b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/spi/mvSpi.c new file mode 100644 index 0000000..39e0b72 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/spi/mvSpi.c @@ -0,0 +1,576 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#include "spi/mvSpi.h" +#include "spi/mvSpiSpec.h" + +#include "ctrlEnv/mvCtrlEnvLib.h" + +/* #define MV_DEBUG */ +#ifdef MV_DEBUG +#define DB(x) x +#define mvOsPrintf printf +#else +#define DB(x) +#endif + + +/******************************************************************************* +* mvSpi16bitDataTxRx - Transmt and receive data +* +* DESCRIPTION: +* Tx data and block waiting for data to be transmitted +* +********************************************************************************/ +static MV_STATUS mvSpi16bitDataTxRx (MV_U16 txData, MV_U16 * pRxData) +{ + MV_U32 i; + MV_BOOL ready = MV_FALSE; + + /* First clear the bit in the interrupt cause register */ + MV_REG_WRITE(MV_SPI_INT_CAUSE_REG, 0x0); + + /* Transmit data */ + MV_REG_WRITE(MV_SPI_DATA_OUT_REG, MV_16BIT_LE(txData)); + + /* wait with timeout for memory ready */ + for (i=0; i> 8) & 0xFF); + +#elif defined(MV_CPU_BE) + + /* perform the data write to the buffer in two stages with 8bit each */ + MV_U8 * bptr = (MV_U8 *)pRxData; + MV_U16 data = MV_16BIT_LE(MV_REG_READ(MV_SPI_DATA_IN_REG)); + *bptr = ((data >> 8) & 0xFF); + ++bptr; + *bptr = (data & 0xFF); + +#else + #error "CPU endianess isn't defined!\n" +#endif + + } + else + *pRxData = MV_16BIT_LE(MV_REG_READ(MV_SPI_DATA_IN_REG)); + } + + return MV_OK; +} + + +/******************************************************************************* +* mvSpi8bitDataTxRx - Transmt and receive data (8bits) +* +* DESCRIPTION: +* Tx data and block waiting for data to be transmitted +* +********************************************************************************/ +static MV_STATUS mvSpi8bitDataTxRx (MV_U8 txData, MV_U8 * pRxData) +{ + MV_U32 i; + MV_BOOL ready = MV_FALSE; + + /* First clear the bit in the interrupt cause register */ + MV_REG_WRITE(MV_SPI_INT_CAUSE_REG, 0x0); + + /* Transmit data */ + MV_REG_WRITE(MV_SPI_DATA_OUT_REG, txData); + + /* wait with timeout for memory ready */ + for (i=0; i serialBaudRate) + continue; + + /* check for exact fit */ + if ((cpuClk / preScale[i]) == serialBaudRate) + { + bestPrescaleIndx = i; + break; + } + + /* check if this is better than the previous one */ + if ((serialBaudRate - (cpuClk / preScale[i])) < minBaudOffset) + { + minBaudOffset = (serialBaudRate - (cpuClk / preScale[i])); + bestPrescaleIndx = i; + } + } + + if (bestPrescaleIndx > 14) + { + mvOsPrintf("%s ERROR: SPI baud rate prescale error!\n", __FUNCTION__); + return MV_OUT_OF_RANGE; + } + + /* configure the Prescale */ + tempReg = MV_REG_READ(MV_SPI_IF_CONFIG_REG); + tempReg = ((tempReg & ~MV_SPI_CLK_PRESCALE_MASK) | (bestPrescaleIndx + 0x12)); + MV_REG_WRITE(MV_SPI_IF_CONFIG_REG, tempReg); + + return MV_OK; +} + +/******************************************************************************* +* mvSpiCsAssert - Assert the Chip Select pin indicating a new transfer +* +* DESCRIPTION: +* Assert The chip select - used to select an external SPI device +* +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* Success or Error code. +* +********************************************************************************/ +MV_VOID mvSpiCsAssert(MV_VOID) +{ + /* For devices in which the SPI is muxed on the MPP with other interfaces*/ + mvMPPConfigToSPI(); + mvOsUDelay(1); + MV_REG_BIT_SET(MV_SPI_IF_CTRL_REG, MV_SPI_CS_ENABLE_MASK); +} + +/******************************************************************************* +* mvSpiCsDeassert - DeAssert the Chip Select pin indicating the end of a +* SPI transfer sequence +* +* DESCRIPTION: +* DeAssert the chip select pin +* +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* Success or Error code. +* +********************************************************************************/ +MV_VOID mvSpiCsDeassert(MV_VOID) +{ + MV_REG_BIT_RESET(MV_SPI_IF_CTRL_REG, MV_SPI_CS_ENABLE_MASK); + + /* For devices in which the SPI is muxed on the MPP with other interfaces*/ + mvMPPConfigToDefault(); +} + +/******************************************************************************* +* mvSpiRead - Read a buffer over the SPI interface +* +* DESCRIPTION: +* Receive (read) a buffer over the SPI interface in 16bit chunks. If the +* buffer size is odd, then the last chunk will be 8bits. Chip select is not +* handled at this level. +* +* INPUT: +* pRxBuff: Pointer to the buffer to hold the received data +* buffSize: length of the pRxBuff +* +* OUTPUT: +* pRxBuff: Pointer to the buffer with the received data +* +* RETURN: +* Success or Error code. +* +* +*******************************************************************************/ +MV_STATUS mvSpiRead (MV_U8* pRxBuff, MV_U32 buffSize) +{ + MV_STATUS ret; + MV_U32 bytesLeft = buffSize; + MV_U16* rxPtr = (MV_U16*)pRxBuff; + + /* check for null parameters */ + if (pRxBuff == NULL) + { + mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__); + return MV_BAD_PARAM; + } + + /* Check that the buffer pointer and the buffer size are 16bit aligned */ + if ((((MV_U32)buffSize & 1) == 0) && (((MV_U32)pRxBuff & 1) == 0)) + { + /* Verify that the SPI mode is in 16bit mode */ + MV_REG_BIT_SET(MV_SPI_IF_CONFIG_REG, MV_SPI_BYTE_LENGTH_MASK); + + /* TX/RX as long we have complete 16bit chunks */ + while (bytesLeft >= MV_SPI_16_BIT_CHUNK_SIZE) + { + /* Transmitted and wait for the transfer to be completed */ + if ((ret = mvSpi16bitDataTxRx(MV_SPI_DUMMY_WRITE_16BITS, rxPtr)) != MV_OK) + return ret; + + /* increment the pointers */ + rxPtr++; + bytesLeft -= MV_SPI_16_BIT_CHUNK_SIZE; + } + + } + else + { + /* Verify that the SPI mode is in 8bit mode */ + MV_REG_BIT_RESET(MV_SPI_IF_CONFIG_REG, MV_SPI_BYTE_LENGTH_MASK); + + /* TX/RX in 8bit chanks */ + while (bytesLeft > 0) + { + /* Transmitted and wait for the transfer to be completed */ + if ((ret = mvSpi8bitDataTxRx(MV_SPI_DUMMY_WRITE_8BITS, pRxBuff)) != MV_OK) + return ret; + /* increment the pointers */ + pRxBuff++; + bytesLeft--; + } + } + + return MV_OK; +} + +/******************************************************************************* +* mvSpiWrite - Transmit a buffer over the SPI interface +* +* DESCRIPTION: +* Transmit a buffer over the SPI interface in 16bit chunks. If the +* buffer size is odd, then the last chunk will be 8bits. No chip select +* action is taken. +* +* INPUT: +* pTxBuff: Pointer to the buffer holding the TX data +* buffSize: length of the pTxBuff +* +* OUTPUT: +* None. +* +* RETURN: +* Success or Error code. +* +* +*******************************************************************************/ +MV_STATUS mvSpiWrite(MV_U8* pTxBuff, MV_U32 buffSize) +{ + MV_STATUS ret; + MV_U32 bytesLeft = buffSize; + MV_U16* txPtr = (MV_U16*)pTxBuff; + + /* check for null parameters */ + if (pTxBuff == NULL) + { + mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__); + return MV_BAD_PARAM; + } + + /* Check that the buffer pointer and the buffer size are 16bit aligned */ + if ((((MV_U32)buffSize & 1) == 0) && (((MV_U32)pTxBuff & 1) == 0)) + { + /* Verify that the SPI mode is in 16bit mode */ + MV_REG_BIT_SET(MV_SPI_IF_CONFIG_REG, MV_SPI_BYTE_LENGTH_MASK); + + /* TX/RX as long we have complete 16bit chunks */ + while (bytesLeft >= MV_SPI_16_BIT_CHUNK_SIZE) + { + /* Transmitted and wait for the transfer to be completed */ + if ((ret = mvSpi16bitDataTxRx(*txPtr, NULL)) != MV_OK) + return ret; + + /* increment the pointers */ + txPtr++; + bytesLeft -= MV_SPI_16_BIT_CHUNK_SIZE; + } + } + else + { + + /* Verify that the SPI mode is in 8bit mode */ + MV_REG_BIT_RESET(MV_SPI_IF_CONFIG_REG, MV_SPI_BYTE_LENGTH_MASK); + + /* TX/RX in 8bit chanks */ + while (bytesLeft > 0) + { + /* Transmitted and wait for the transfer to be completed */ + if ((ret = mvSpi8bitDataTxRx(*pTxBuff, NULL)) != MV_OK) + return ret; + + /* increment the pointers */ + pTxBuff++; + bytesLeft--; + } + } + + return MV_OK; +} + + +/******************************************************************************* +* mvSpiReadWrite - Read and Write a buffer simultanuosely +* +* DESCRIPTION: +* Transmit and receive a buffer over the SPI in 16bit chunks. If the +* buffer size is odd, then the last chunk will be 8bits. The SPI chip +* select is not handled implicitely. +* +* INPUT: +* pRxBuff: Pointer to the buffer to write the RX info in +* pTxBuff: Pointer to the buffer holding the TX info +* buffSize: length of both the pTxBuff and pRxBuff +* +* OUTPUT: +* pRxBuff: Pointer of the buffer holding the RX data +* +* RETURN: +* Success or Error code. +* +* +*******************************************************************************/ +MV_STATUS mvSpiReadWrite(MV_U8* pRxBuff, MV_U8* pTxBuff, MV_U32 buffSize) +{ + MV_STATUS ret; + MV_U32 bytesLeft = buffSize; + MV_U16* txPtr = (MV_U16*)pTxBuff; + MV_U16* rxPtr = (MV_U16*)pRxBuff; + + /* check for null parameters */ + if ((pRxBuff == NULL) || (pTxBuff == NULL)) + { + mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__); + return MV_BAD_PARAM; + } + + /* Check that the buffer pointer and the buffer size are 16bit aligned */ + if ((((MV_U32)buffSize & 1) == 0) && (((MV_U32)pTxBuff & 1) == 0) && (((MV_U32)pRxBuff & 1) == 0)) + { + /* Verify that the SPI mode is in 16bit mode */ + MV_REG_BIT_SET(MV_SPI_IF_CONFIG_REG, MV_SPI_BYTE_LENGTH_MASK); + + /* TX/RX as long we have complete 16bit chunks */ + while (bytesLeft >= MV_SPI_16_BIT_CHUNK_SIZE) + { + /* Transmitted and wait for the transfer to be completed */ + if ((ret = mvSpi16bitDataTxRx(*txPtr, rxPtr)) != MV_OK) + return ret; + + /* increment the pointers */ + txPtr++; + rxPtr++; + bytesLeft -= MV_SPI_16_BIT_CHUNK_SIZE; + } + } + else + { + /* Verify that the SPI mode is in 8bit mode */ + MV_REG_BIT_RESET(MV_SPI_IF_CONFIG_REG, MV_SPI_BYTE_LENGTH_MASK); + + /* TX/RX in 8bit chanks */ + while (bytesLeft > 0) + { + /* Transmitted and wait for the transfer to be completed */ + if ( (ret = mvSpi8bitDataTxRx(*pTxBuff, pRxBuff) ) != MV_OK) + return ret; + pRxBuff++; + pTxBuff++; + bytesLeft--; + } + } + + return MV_OK; +} + + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/spi/mvSpi.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/spi/mvSpi.h new file mode 100644 index 0000000..74859f0 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/spi/mvSpi.h @@ -0,0 +1,94 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#ifndef __INCmvSpihH +#define __INCmvSpihH + +#include "mvCommon.h" +#include "mvOs.h" +#include "ctrlEnv/mvCtrlEnvSpec.h" + +/* Function Prototypes */ +/* Init */ +MV_STATUS mvSpiInit (MV_U32 serialBaudRate); + +/* Set the Frequency of the Spi clock */ +MV_STATUS mvSpiBaudRateSet(MV_U32 serialBaudRate); + +/* Assert the SPI chip select */ +MV_VOID mvSpiCsAssert (MV_VOID); + +/* De-assert the SPI chip select */ +MV_VOID mvSpiCsDeassert (MV_VOID); + +/* Simultanuous Read and write */ +MV_STATUS mvSpiReadWrite (MV_U8* pRxBuff, MV_U8* pTxBuff, MV_U32 buffSize); + +/* serialize a buffer on the TX line - Rx is ignored */ +MV_STATUS mvSpiWrite (MV_U8* pTxBuff, MV_U32 buffSize); + +/* read from the RX line by writing dummy values to the TX line */ +MV_STATUS mvSpiRead (MV_U8* pRxBuff, MV_U32 buffSize); + +#endif /* __INCmvSpihH */ diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/spi/mvSpiCmnd.c b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/spi/mvSpiCmnd.c new file mode 100644 index 0000000..a5d5a64 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/spi/mvSpiCmnd.c @@ -0,0 +1,249 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#include "spi/mvSpi.h" +#include "spi/mvSpiSpec.h" + +/*#define MV_DEBUG*/ +#ifdef MV_DEBUG +#define DB(x) x +#else +#define DB(x) +#endif + + +/******************************************************************************* +* mvSpiReadAndWrite - Read and Write a buffer simultanuousely +* +* DESCRIPTION: +* Transmit and receive a buffer over the SPI in 16bit chunks. If the +* buffer size is odd, then the last chunk will be 8bits. +* +* INPUT: +* pRxBuff: Pointer to the buffer to write the RX info in +* pTxBuff: Pointer to the buffer holding the TX info +* buffSize: length of both the pTxBuff and pRxBuff +* +* OUTPUT: +* pRxBuff: Pointer of the buffer holding the RX data +* +* RETURN: +* Success or Error code. +* +* +*******************************************************************************/ +MV_STATUS mvSpiReadAndWrite(MV_U8* pRxBuff, MV_U8* pTxBuff, MV_U32 buffSize) +{ + MV_STATUS ret; + + /* check for null parameters */ + if ((pRxBuff == NULL) || (pTxBuff == NULL) || (buffSize == 0)) + { + mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__); + return MV_BAD_PARAM; + } + + /* First assert the chip select */ + mvSpiCsAssert(); + + ret = mvSpiReadWrite(pRxBuff, pTxBuff, buffSize); + + /* Finally deassert the chip select */ + mvSpiCsDeassert(); + + return ret; +} + +/******************************************************************************* +* mvSpiWriteThenWrite - Serialize a command followed by the data over the TX line +* +* DESCRIPTION: +* Assert the chip select line. Transmit the command buffer followed by +* the data buffer. Then deassert the CS line. +* +* INPUT: +* pCmndBuff: Pointer to the command buffer to transmit +* cmndSize: length of the command size +* pTxDataBuff: Pointer to the data buffer to transmit +* txDataSize: length of the data buffer +* +* OUTPUT: +* None. +* +* RETURN: +* Success or Error code. +* +* +*******************************************************************************/ +MV_STATUS mvSpiWriteThenWrite (MV_U8* pCmndBuff, MV_U32 cmndSize, MV_U8* pTxDataBuff, + MV_U32 txDataSize) +{ + MV_STATUS ret = MV_OK, tempRet; + + /* check for null parameters */ +#ifndef CONFIG_MARVELL + if(NULL == pTxDataBuff) + { + mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__); + return MV_BAD_PARAM; + } +#endif + + if (pCmndBuff == NULL) + { + mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__); + return MV_BAD_PARAM; + } + + /* First assert the chip select */ + mvSpiCsAssert(); + + /* first write the command */ + if ((cmndSize) && (pCmndBuff != NULL)) + { + if ((tempRet = mvSpiWrite(pCmndBuff, cmndSize)) != MV_OK) + ret = tempRet; + } + + /* Then write the data buffer */ +#ifndef CONFIG_MARVELL + if (txDataSize) +#else + if ((txDataSize) && (pTxDataBuff != NULL)) +#endif + { + if ((tempRet = mvSpiWrite(pTxDataBuff, txDataSize)) != MV_OK) + ret = tempRet; + } + + /* Finally deassert the chip select */ + mvSpiCsDeassert(); + + return ret; +} + +/******************************************************************************* +* mvSpiWriteThenRead - Serialize a command then read a data buffer +* +* DESCRIPTION: +* Assert the chip select line. Transmit the command buffer then read +* the data buffer. Then deassert the CS line. +* +* INPUT: +* pCmndBuff: Pointer to the command buffer to transmit +* cmndSize: length of the command size +* pRxDataBuff: Pointer to the buffer to read the data in +* txDataSize: length of the data buffer +* +* OUTPUT: +* pRxDataBuff: Pointer to the buffer holding the data +* +* RETURN: +* Success or Error code. +* +* +*******************************************************************************/ +MV_STATUS mvSpiWriteThenRead (MV_U8* pCmndBuff, MV_U32 cmndSize, MV_U8* pRxDataBuff, + MV_U32 rxDataSize,MV_U32 dummyBytesToRead) +{ + MV_STATUS ret = MV_OK, tempRet; + MV_U8 dummyByte; + + /* check for null parameters */ + if ((pCmndBuff == NULL) && (pRxDataBuff == NULL)) + { + mvOsPrintf("%s ERROR: Null pointer parameter!\n", __FUNCTION__); + return MV_BAD_PARAM; + } + + /* First assert the chip select */ + mvSpiCsAssert(); + + /* first write the command */ + if ((cmndSize) && (pCmndBuff != NULL)) + { + if ((tempRet = mvSpiWrite(pCmndBuff, cmndSize)) != MV_OK) + ret = tempRet; + } + + /* Read dummy bytes before real data. */ + while(dummyBytesToRead) + { + mvSpiRead(&dummyByte,1); + dummyBytesToRead--; + } + + /* Then write the data buffer */ + if ((rxDataSize) && (pRxDataBuff != NULL)) + { + if ((tempRet = mvSpiRead(pRxDataBuff, rxDataSize)) != MV_OK) + ret = tempRet; + } + + /* Finally deassert the chip select */ + mvSpiCsDeassert(); + + return ret; +} + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/spi/mvSpiCmnd.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/spi/mvSpiCmnd.h new file mode 100644 index 0000000..329e26b --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/spi/mvSpiCmnd.h @@ -0,0 +1,82 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#ifndef __INCmvSpiCmndhH +#define __INCmvSpiCmndhH + +#include "mvTypes.h" + +/* Function Prototypes */ + +/* Simultanuous Read and write */ +MV_STATUS mvSpiReadAndWrite (MV_U8* pRxBuff, MV_U8* pTxBuff, MV_U32 buffSize); + +/* write command - write a command and then write data */ +MV_STATUS mvSpiWriteThenWrite (MV_U8* pCmndBuff, MV_U32 cmndSize, MV_U8* pTxDataBuff, MV_U32 txDataSize); + +/* read command - write a command and then read data by writing dummy data */ +MV_STATUS mvSpiWriteThenRead (MV_U8* pCmndBuff, MV_U32 cmndSize, MV_U8* pRxDataBuff, + MV_U32 rxDataSize,MV_U32 dummyBytesToRead); + +#endif /* __INCmvSpiCmndhH */ diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/spi/mvSpiSpec.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/spi/mvSpiSpec.h new file mode 100644 index 0000000..658159a --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/spi/mvSpiSpec.h @@ -0,0 +1,98 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#ifndef __INCmvSpiSpecH +#define __INCmvSpiSpecH + +/* Constants */ +#define MV_SPI_WAIT_RDY_MAX_LOOP 100000 +#define MV_SPI_16_BIT_CHUNK_SIZE 2 +#define MV_SPI_DUMMY_WRITE_16BITS 0xFFFF +#define MV_SPI_DUMMY_WRITE_8BITS 0xFF + +/* Marvell Flash Device Controller Registers */ +#define MV_SPI_CTRLR_OFST 0x10600 +#define MV_SPI_IF_CTRL_REG (MV_SPI_CTRLR_OFST + 0x00) +#define MV_SPI_IF_CONFIG_REG (MV_SPI_CTRLR_OFST + 0x04) +#define MV_SPI_DATA_OUT_REG (MV_SPI_CTRLR_OFST + 0x08) +#define MV_SPI_DATA_IN_REG (MV_SPI_CTRLR_OFST + 0x0c) +#define MV_SPI_INT_CAUSE_REG (MV_SPI_CTRLR_OFST + 0x10) +#define MV_SPI_INT_CAUSE_MASK_REG (MV_SPI_CTRLR_OFST + 0x14) + +/* Serial Memory Interface Control Register Masks */ +#define MV_SPI_CS_ENABLE_OFFSET 0 /* bit 0 */ +#define MV_SPI_MEMORY_READY_OFFSET 1 /* bit 1 */ +#define MV_SPI_CS_ENABLE_MASK (0x1 << MV_SPI_CS_ENABLE_OFFSET) +#define MV_SPI_MEMORY_READY_MASK (0x1 << MV_SPI_MEMORY_READY_OFFSET) + +/* Serial Memory Interface Configuration Register Masks */ +#define MV_SPI_CLK_PRESCALE_OFFSET 0 /* bit 0-4 */ +#define MV_SPI_BYTE_LENGTH_OFFSET 5 /* bit 5 */ +#define MV_SPI_ADDRESS_BURST_LENGTH_OFFSET 8 /* bit 8-9 */ +#define MV_SPI_CLK_PRESCALE_MASK (0x1F << MV_SPI_CLK_PRESCALE_OFFSET) +#define MV_SPI_BYTE_LENGTH_MASK (0x1 << MV_SPI_BYTE_LENGTH_OFFSET) +#define MV_SPI_ADDRESS_BURST_LENGTH_MASK (0x3 << MV_SPI_ADDRESS_BURST_LENGTH_OFFSET) + +#endif /* __INCmvSpiSpecH */ + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/twsi/mvCompVer.txt b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/twsi/mvCompVer.txt new file mode 100644 index 0000000..4053116 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/twsi/mvCompVer.txt @@ -0,0 +1,4 @@ +Global HAL Version: FEROCEON_HAL_3_1_7 +Unit HAL Version: 3.1.5 +Description: This component includes an implementation of the unit HAL drivers + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/twsi/mvTwsi.c b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/twsi/mvTwsi.c new file mode 100644 index 0000000..0bf8b75 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/twsi/mvTwsi.c @@ -0,0 +1,1023 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + + +#include "mvTwsi.h" +#include "mvTwsiSpec.h" +#include "cpu/mvCpu.h" + + +/*#define MV_DEBUG*/ +#ifdef MV_DEBUG +#define DB(x) x +#else +#define DB(x) +#endif + +static MV_VOID twsiIntFlgClr(MV_U8 chanNum); +static MV_BOOL twsiMainIntGet(MV_U8 chanNum); +static MV_VOID twsiAckBitSet(MV_U8 chanNum); +static MV_U32 twsiStsGet(MV_U8 chanNum); +static MV_VOID twsiReset(MV_U8 chanNum); +static MV_STATUS twsiAddr7BitSet(MV_U8 chanNum, MV_U32 deviceAddress,MV_TWSI_CMD command); +static MV_STATUS twsiAddr10BitSet(MV_U8 chanNum, MV_U32 deviceAddress,MV_TWSI_CMD command); +static MV_STATUS twsiDataTransmit(MV_U8 chanNum, MV_U8 *pBlock, MV_U32 blockSize); +static MV_STATUS twsiDataReceive(MV_U8 chanNum, MV_U8 *pBlock, MV_U32 blockSize); +static MV_STATUS twsiTargetOffsSet(MV_U8 chanNum, MV_U32 offset,MV_BOOL moreThen256); + + +static MV_BOOL twsiTimeoutChk(MV_U32 timeout, const MV_8 *pString) +{ + if(timeout >= TWSI_TIMEOUT_VALUE) + { + DB(mvOsPrintf("%s",pString)); + return MV_TRUE; + } + return MV_FALSE; + +} +/******************************************************************************* +* mvTwsiStartBitSet - Set start bit on the bus +* +* DESCRIPTION: +* This routine sets the start bit on the TWSI bus. +* The routine first checks for interrupt flag condition, then it sets +* the start bit in the TWSI Control register. +* If the interrupt flag condition check previously was set, the function +* will clear it. +* The function then wait for the start bit to be cleared by the HW. +* Then it waits for the interrupt flag to be set and eventually, the +* TWSI status is checked to be 0x8 or 0x10(repeated start bit). +* +* INPUT: +* chanNum - TWSI channel. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_OK is start bit was set successfuly on the bus. +* MV_FAIL if interrupt flag was set before setting start bit. +* +*******************************************************************************/ +MV_STATUS mvTwsiStartBitSet(MV_U8 chanNum) +{ + MV_BOOL isIntFlag = MV_FALSE; + MV_U32 timeout, temp; + + DB(mvOsPrintf("TWSI: mvTwsiStartBitSet \n")); + /* check Int flag */ + if(twsiMainIntGet(chanNum)) + isIntFlag = MV_TRUE; + /* set start Bit */ + temp = MV_REG_READ(TWSI_CONTROL_REG(chanNum)); + MV_REG_WRITE(TWSI_CONTROL_REG(chanNum), temp | TWSI_CONTROL_START_BIT); + + /* in case that the int flag was set before i.e. repeated start bit */ + if(isIntFlag){ + DB(mvOsPrintf("TWSI: mvTwsiStartBitSet repeated start Bit\n")); + twsiIntFlgClr(chanNum); + } + + /* wait for interrupt */ + timeout = 0; + while(!twsiMainIntGet(chanNum) && (timeout++ < TWSI_TIMEOUT_VALUE)); + + /* check for timeout */ + if(MV_TRUE == twsiTimeoutChk(timeout,"TWSI: mvTwsiStartBitSet ERROR - Start Clear bit TimeOut .\n")) + return MV_TIMEOUT; + + + /* check that start bit went down */ + if((MV_REG_READ(TWSI_CONTROL_REG(chanNum)) & TWSI_CONTROL_START_BIT) != 0) + { + mvOsPrintf("TWSI: mvTwsiStartBitSet ERROR - start bit didn't went down\n"); + return MV_FAIL; + } + + /* check the status */ + temp = twsiStsGet(chanNum); + if(( temp != TWSI_START_CON_TRA ) && ( temp != TWSI_REPEATED_START_CON_TRA )) + { + mvOsPrintf("TWSI: mvTwsiStartBitSet ERROR - status %x after Set Start Bit. \n",temp); + return MV_FAIL; + } + + return MV_OK; + +} + +/******************************************************************************* +* mvTwsiStopBitSet - Set stop bit on the bus +* +* DESCRIPTION: +* This routine set the stop bit on the TWSI bus. +* The function then wait for the stop bit to be cleared by the HW. +* Finally the function checks for status of 0xF8. +* +* INPUT: +* chanNum - TWSI channel +* +* OUTPUT: +* None. +* +* RETURN: +* MV_TRUE is stop bit was set successfuly on the bus. +* +*******************************************************************************/ +MV_STATUS mvTwsiStopBitSet(MV_U8 chanNum) +{ + MV_U32 timeout, temp; + + /* Generate stop bit */ + temp = MV_REG_READ(TWSI_CONTROL_REG(chanNum)); + MV_REG_WRITE(TWSI_CONTROL_REG(chanNum), temp | TWSI_CONTROL_STOP_BIT); + + twsiIntFlgClr(chanNum); + + /* wait for stop bit to come down */ + timeout = 0; + while( ((MV_REG_READ(TWSI_CONTROL_REG(chanNum)) & TWSI_CONTROL_STOP_BIT) != 0) && (timeout++ < TWSI_TIMEOUT_VALUE)); + + /* check for timeout */ + if(MV_TRUE == twsiTimeoutChk(timeout,"TWSI: mvTwsiStopBitSet ERROR - Stop bit TimeOut .\n")) + return MV_TIMEOUT; + + /* check that the stop bit went down */ + if((MV_REG_READ(TWSI_CONTROL_REG(chanNum)) & TWSI_CONTROL_STOP_BIT) != 0) + { + mvOsPrintf("TWSI: mvTwsiStopBitSet ERROR - stop bit didn't went down. \n"); + return MV_FAIL; + } + + /* check the status */ + temp = twsiStsGet(chanNum); + if( temp != TWSI_NO_REL_STS_INT_FLAG_IS_KEPT_0){ + mvOsPrintf("TWSI: mvTwsiStopBitSet ERROR - status %x after Stop Bit. \n", temp); + return MV_FAIL; + } + + return MV_OK; +} + +/******************************************************************************* +* twsiMainIntGet - Get twsi bit from main Interrupt cause. +* +* DESCRIPTION: +* This routine returns the twsi interrupt flag value. +* +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_TRUE is interrupt flag is set, MV_FALSE otherwise. +* +*******************************************************************************/ +static MV_BOOL twsiMainIntGet(MV_U8 chanNum) +{ + MV_U32 temp; + + /* get the int flag bit */ + + temp = MV_REG_READ(TWSI_CPU_MAIN_INT_CAUSE_REG); + if (temp & (TWSI0_CPU_MAIN_INT_BIT << chanNum)) + return MV_TRUE; + + return MV_FALSE; +} +/******************************************************************************* +* twsiIntFlgClr - Clear Interrupt flag. +* +* DESCRIPTION: +* This routine clears the interrupt flag. It does NOT poll the interrupt +* to make sure the clear. After clearing the interrupt, it waits for at +* least 1 miliseconds. +* +* INPUT: +* chanNum - TWSI channel +* +* OUTPUT: +* None. +* +* RETURN: +* None. +* +*******************************************************************************/ +static MV_VOID twsiIntFlgClr(MV_U8 chanNum) +{ + MV_U32 temp; + + /* wait for 1 mili to prevent TWSI register write after write problems */ + mvOsDelay(1); + /* clear the int flag bit */ + temp = MV_REG_READ(TWSI_CONTROL_REG(chanNum)); + MV_REG_WRITE(TWSI_CONTROL_REG(chanNum),temp & ~(TWSI_CONTROL_INT_FLAG_SET)); + + /* wait for 1 mili sec for the clear to take effect */ + mvOsDelay(1); + + return; +} + + +/******************************************************************************* +* twsiAckBitSet - Set acknowledge bit on the bus +* +* DESCRIPTION: +* This routine set the acknowledge bit on the TWSI bus. +* +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* None. +* +*******************************************************************************/ +static MV_VOID twsiAckBitSet(MV_U8 chanNum) +{ + MV_U32 temp; + + /*Set the Ack bit */ + temp = MV_REG_READ(TWSI_CONTROL_REG(chanNum)); + MV_REG_WRITE(TWSI_CONTROL_REG(chanNum), temp | TWSI_CONTROL_ACK); + + /* Add delay of 1ms */ + mvOsDelay(1); + return; +} + + +/******************************************************************************* +* twsiInit - Initialize TWSI interface +* +* DESCRIPTION: +* This routine: +* -Reset the TWSI. +* -Initialize the TWSI clock baud rate according to given frequancy +* parameter based on Tclk frequancy and enables TWSI slave. +* -Set the ack bit. +* -Assign the TWSI slave address according to the TWSI address Type. +* +* +* INPUT: +* chanNum - TWSI channel +* frequancy - TWSI frequancy in KHz. (up to 100KHZ) +* +* OUTPUT: +* None. +* +* RETURN: +* Actual frequancy. +* +*******************************************************************************/ +MV_U32 mvTwsiInit(MV_U8 chanNum, MV_HZ frequancy, MV_U32 Tclk, MV_TWSI_ADDR *pTwsiAddr, MV_BOOL generalCallEnable) +{ + MV_U32 n,m,freq,margin,minMargin = 0xffffffff; + MV_U32 power; + MV_U32 actualFreq = 0,actualN = 0,actualM = 0,val; + + if(frequancy > 100000) + { + mvOsPrintf("Warning TWSI frequancy is too high, please use up tp 100Khz. \n"); + } + + DB(mvOsPrintf("TWSI: mvTwsiInit - Tclk = %d freq = %d\n",Tclk,frequancy)); + /* Calucalte N and M for the TWSI clock baud rate */ + for(n = 0 ; n < 8 ; n++) + { + for(m = 0 ; m < 16 ; m++) + { + power = 2 << n; /* power = 2^(n+1) */ + freq = Tclk/(10*(m+1)*power); + margin = MV_ABS(frequancy - freq); + if(margin < minMargin) + { + minMargin = margin; + actualFreq = freq; + actualN = n; + actualM = m; + } + } + } + DB(mvOsPrintf("TWSI: mvTwsiInit - actN %d actM %d actFreq %d\n",actualN , actualM, actualFreq)); + /* Reset the TWSI logic */ + twsiReset(chanNum); + + /* Set the baud rate */ + val = ((actualM<< TWSI_BAUD_RATE_M_OFFS) | actualN << TWSI_BAUD_RATE_N_OFFS); + MV_REG_WRITE(TWSI_STATUS_BAUDE_RATE_REG(chanNum),val); + + /* Enable the TWSI and slave */ + MV_REG_WRITE(TWSI_CONTROL_REG(chanNum), TWSI_CONTROL_ENA | TWSI_CONTROL_ACK); + + /* set the TWSI slave address */ + if( pTwsiAddr->type == ADDR10_BIT )/* 10 Bit deviceAddress */ + { + /* writing the 2 most significant bits of the 10 bit address*/ + val = ((pTwsiAddr->address & TWSI_SLAVE_ADDR_10BIT_MASK) >> TWSI_SLAVE_ADDR_10BIT_OFFS ); + /* bits 7:3 must be 0x11110 */ + val |= TWSI_SLAVE_ADDR_10BIT_CONST; + /* set GCE bit */ + if(generalCallEnable) + val |= TWSI_SLAVE_ADDR_GCE_ENA; + /* write slave address */ + MV_REG_WRITE(TWSI_SLAVE_ADDR_REG(chanNum),val); + + /* writing the 8 least significant bits of the 10 bit address*/ + val = (pTwsiAddr->address << TWSI_EXTENDED_SLAVE_OFFS) & TWSI_EXTENDED_SLAVE_MASK; + MV_REG_WRITE(TWSI_EXTENDED_SLAVE_ADDR_REG(chanNum), val); + } + else /*7 bit address*/ + { + /* set the 7 Bits address */ + MV_REG_WRITE(TWSI_EXTENDED_SLAVE_ADDR_REG(chanNum),0x0); + val = (pTwsiAddr->address << TWSI_SLAVE_ADDR_7BIT_OFFS) & TWSI_SLAVE_ADDR_7BIT_MASK; + MV_REG_WRITE(TWSI_SLAVE_ADDR_REG(chanNum), val); + } + + /* unmask twsi int */ + val = MV_REG_READ(TWSI_CONTROL_REG(chanNum)); + MV_REG_WRITE(TWSI_CONTROL_REG(chanNum), val | TWSI_CONTROL_INT_ENA); + /* Add delay of 1ms */ + mvOsDelay(1); + + return actualFreq; +} + + +/******************************************************************************* +* twsiStsGet - Get the TWSI status value. +* +* DESCRIPTION: +* This routine returns the TWSI status value. +* +* INPUT: +* chanNum - TWSI channel +* +* OUTPUT: +* None. +* +* RETURN: +* MV_U32 - the TWSI status. +* +*******************************************************************************/ +static MV_U32 twsiStsGet(MV_U8 chanNum) +{ + return MV_REG_READ(TWSI_STATUS_BAUDE_RATE_REG(chanNum)); + +} + +/******************************************************************************* +* twsiReset - Reset the TWSI. +* +* DESCRIPTION: +* Resets the TWSI logic and sets all TWSI registers to their reset values. +* +* INPUT: +* chanNum - TWSI channel +* +* OUTPUT: +* None. +* +* RETURN: +* None +* +*******************************************************************************/ +static MV_VOID twsiReset(MV_U8 chanNum) +{ + /* Reset the TWSI logic */ + MV_REG_WRITE(TWSI_SOFT_RESET_REG(chanNum),0); + + /* wait for 2 mili sec */ + mvOsDelay(2); + + return; +} + + + + +/******************************* POLICY ****************************************/ + + + +/******************************************************************************* +* mvTwsiAddrSet - Set address on TWSI bus. +* +* DESCRIPTION: +* This function Set address (7 or 10 Bit address) on the Twsi Bus. +* +* INPUT: +* chanNum - TWSI channel +* pTwsiAddr - twsi address. +* command - read / write . +* +* OUTPUT: +* None. +* +* RETURN: +* MV_OK - if setting the address completed succesfully. +* MV_FAIL otherwmise. +* +*******************************************************************************/ +MV_STATUS mvTwsiAddrSet(MV_U8 chanNum, MV_TWSI_ADDR *pTwsiAddr, MV_TWSI_CMD command) +{ + DB(mvOsPrintf("TWSI: mvTwsiAddr7BitSet addr %x , type %d, cmd is %s\n",pTwsiAddr->address,\ + pTwsiAddr->type, ((command==MV_TWSI_WRITE)?"Write":"Read") )); + /* 10 Bit address */ + if(pTwsiAddr->type == ADDR10_BIT) + { + return twsiAddr10BitSet(chanNum, pTwsiAddr->address,command); + } + /* 7 Bit address */ + else + { + return twsiAddr7BitSet(chanNum, pTwsiAddr->address,command); + } + +} + +/******************************************************************************* +* twsiAddr10BitSet - Set 10 Bit address on TWSI bus. +* +* DESCRIPTION: +* There are two address phases: +* 1) Write '11110' to data register bits [7:3] and 10-bit address MSB +* (bits [9:8]) to data register bits [2:1] plus a write(0) or read(1) bit +* to the Data register. Then it clears interrupt flag which drive +* the address on the TWSI bus. The function then waits for interrupt +* flag to be active and status 0x18 (write) or 0x40 (read) to be set. +* 2) write the rest of 10-bit address to data register and clears +* interrupt flag which drive the address on the TWSI bus. The +* function then waits for interrupt flag to be active and status +* 0xD0 (write) or 0xE0 (read) to be set. +* +* INPUT: +* chanNum - TWSI channel +* deviceAddress - twsi address. +* command - read / write . +* +* OUTPUT: +* None. +* +* RETURN: +* MV_OK - if setting the address completed succesfully. +* MV_FAIL otherwmise. +* +*******************************************************************************/ +static MV_STATUS twsiAddr10BitSet(MV_U8 chanNum, MV_U32 deviceAddress,MV_TWSI_CMD command) +{ + MV_U32 val,timeout; + + /* writing the 2 most significant bits of the 10 bit address*/ + val = ((deviceAddress & TWSI_DATA_ADDR_10BIT_MASK) >> TWSI_DATA_ADDR_10BIT_OFFS ); + /* bits 7:3 must be 0x11110 */ + val |= TWSI_DATA_ADDR_10BIT_CONST; + /* set command */ + val |= command; + MV_REG_WRITE(TWSI_DATA_REG(chanNum), val); + /* WA add a delay */ + mvOsDelay(1); + + /* clear Int flag */ + twsiIntFlgClr(chanNum); + + /* wait for Int to be Set */ + timeout = 0; + while( !twsiMainIntGet(chanNum) && (timeout++ < TWSI_TIMEOUT_VALUE)); + + /* check for timeout */ + if(MV_TRUE == twsiTimeoutChk(timeout,"TWSI: twsiAddr10BitSet ERROR - 1st addr (10Bit) Int TimeOut.\n")) + return MV_TIMEOUT; + + /* check the status */ + val = twsiStsGet(chanNum); + if(( (val != TWSI_AD_PLS_RD_BIT_TRA_ACK_REC) && (command == MV_TWSI_READ ) ) || + ( (val != TWSI_AD_PLS_WR_BIT_TRA_ACK_REC) && (command == MV_TWSI_WRITE) )) + { + mvOsPrintf("TWSI: twsiAddr10BitSet ERROR - status %x 1st addr (10 Bit) in %s mode.\n"\ + ,val, ((command==MV_TWSI_WRITE)?"Write":"Read") ); + return MV_FAIL; + } + + /* set 8 LSB of the address */ + val = (deviceAddress << TWSI_DATA_ADDR_7BIT_OFFS) & TWSI_DATA_ADDR_7BIT_MASK; + MV_REG_WRITE(TWSI_DATA_REG(chanNum), val); + + /* clear Int flag */ + twsiIntFlgClr(chanNum); + + /* wait for Int to be Set */ + timeout = 0; + while( !twsiMainIntGet(chanNum) && (timeout++ < TWSI_TIMEOUT_VALUE)); + + /* check for timeout */ + if(MV_TRUE == twsiTimeoutChk(timeout,"TWSI: twsiAddr10BitSet ERROR - 2nd (10 Bit) Int TimOut.\n")) + return MV_TIMEOUT; + + /* check the status */ + val = twsiStsGet(chanNum); + if(( (val != TWSI_SEC_AD_PLS_RD_BIT_TRA_ACK_REC) && (command == MV_TWSI_READ ) ) || + ( (val != TWSI_SEC_AD_PLS_WR_BIT_TRA_ACK_REC) && (command == MV_TWSI_WRITE) )) + { + mvOsPrintf("TWSI: twsiAddr10BitSet ERROR - status %x 2nd addr(10 Bit) in %s mode.\n"\ + ,val, ((command==MV_TWSI_WRITE)?"Write":"Read") ); + return MV_FAIL; + } + + return MV_OK; +} + +/******************************************************************************* +* twsiAddr7BitSet - Set 7 Bit address on TWSI bus. +* +* DESCRIPTION: +* This function writes 7 bit address plus a write or read bit to the +* Data register. Then it clears interrupt flag which drive the address on +* the TWSI bus. The function then waits for interrupt flag to be active +* and status 0x18 (write) or 0x40 (read) to be set. +* +* INPUT: +* chanNum - TWSI channel +* deviceAddress - twsi address. +* command - read / write . +* +* OUTPUT: +* None. +* +* RETURN: +* MV_OK - if setting the address completed succesfully. +* MV_FAIL otherwmise. +* +*******************************************************************************/ +static MV_STATUS twsiAddr7BitSet(MV_U8 chanNum, MV_U32 deviceAddress,MV_TWSI_CMD command) +{ + MV_U32 val,timeout; + + /* set the address */ + val = (deviceAddress << TWSI_DATA_ADDR_7BIT_OFFS) & TWSI_DATA_ADDR_7BIT_MASK; + /* set command */ + val |= command; + MV_REG_WRITE(TWSI_DATA_REG(chanNum), val); + /* WA add a delay */ + mvOsDelay(1); + + /* clear Int flag */ + twsiIntFlgClr(chanNum); + + /* wait for Int to be Set */ + timeout = 0; + while( !twsiMainIntGet(chanNum) && (timeout++ < TWSI_TIMEOUT_VALUE)); + + /* check for timeout */ + if(MV_TRUE == twsiTimeoutChk(timeout,"TWSI: twsiAddr7BitSet ERROR - Addr (7 Bit) int TimeOut.\n")) + return MV_TIMEOUT; + + /* check the status */ + val = twsiStsGet(chanNum); + if(( (val != TWSI_AD_PLS_RD_BIT_TRA_ACK_REC) && (command == MV_TWSI_READ ) ) || + ( (val != TWSI_AD_PLS_WR_BIT_TRA_ACK_REC) && (command == MV_TWSI_WRITE) )) + { + /* only in debug, since in boot we try to read the SPD of both DRAM, and we don't + want error messeges in case DIMM doesn't exist. */ + DB(mvOsPrintf("TWSI: twsiAddr7BitSet ERROR - status %x addr (7 Bit) in %s mode.\n"\ + ,val,((command==MV_TWSI_WRITE)?"Write":"Read") )); + return MV_FAIL; + } + + return MV_OK; +} + +/******************************************************************************* +* twsiDataWrite - Trnasmit a data block over TWSI bus. +* +* DESCRIPTION: +* This function writes a given data block to TWSI bus in 8 bit granularity. +* first The function waits for interrupt flag to be active then +* For each 8-bit data: +* The function writes data to data register. It then clears +* interrupt flag which drives the data on the TWSI bus. +* The function then waits for interrupt flag to be active and status +* 0x28 to be set. +* +* +* INPUT: +* chanNum - TWSI channel +* pBlock - Data block. +* blockSize - number of chars in pBlock. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_OK - if transmiting the block completed succesfully, +* MV_BAD_PARAM - if pBlock is NULL, +* MV_FAIL otherwmise. +* +*******************************************************************************/ +static MV_STATUS twsiDataTransmit(MV_U8 chanNum, MV_U8 *pBlock, MV_U32 blockSize) +{ + MV_U32 timeout, temp, blockSizeWr = blockSize; + + if(NULL == pBlock) + return MV_BAD_PARAM; + + /* wait for Int to be Set */ + timeout = 0; + while( !twsiMainIntGet(chanNum) && (timeout++ < TWSI_TIMEOUT_VALUE)); + + /* check for timeout */ + if(MV_TRUE == twsiTimeoutChk(timeout,"TWSI: twsiDataTransmit ERROR - Read Data Int TimeOut.\n")) + return MV_TIMEOUT; + + while(blockSizeWr) + { + /* write the data*/ + MV_REG_WRITE(TWSI_DATA_REG(chanNum),(MV_U32)*pBlock); + DB(mvOsPrintf("TWSI: twsiDataTransmit place = %d write %x \n",\ + blockSize - blockSizeWr, *pBlock)); + pBlock++; + blockSizeWr--; + + twsiIntFlgClr(chanNum); + + /* wait for Int to be Set */ + timeout = 0; + while( !twsiMainIntGet(chanNum) && (timeout++ < TWSI_TIMEOUT_VALUE)); + + /* check for timeout */ + if(MV_TRUE == twsiTimeoutChk(timeout,"TWSI: twsiDataTransmit ERROR - Read Data Int TimeOut.\n")) + return MV_TIMEOUT; + + /* check the status */ + temp = twsiStsGet(chanNum); + if(temp != TWSI_M_TRAN_DATA_BYTE_ACK_REC) + { + mvOsPrintf("TWSI: twsiDataTransmit ERROR - status %x in write trans\n",temp); + return MV_FAIL; + } + + } + + return MV_OK; +} + +/******************************************************************************* +* twsiDataReceive - Receive data block from TWSI bus. +* +* DESCRIPTION: +* This function receive data block from TWSI bus in 8bit granularity +* into pBlock buffer. +* first The function waits for interrupt flag to be active then +* For each 8-bit data: +* It clears the interrupt flag which allows the next data to be +* received from TWSI bus. +* The function waits for interrupt flag to be active, +* and status reg is 0x50. +* Then the function reads data from data register, and copies it to +* the given buffer. +* +* INPUT: +* chanNum - TWSI channel +* blockSize - number of bytes to read. +* +* OUTPUT: +* pBlock - Data block. +* +* RETURN: +* MV_OK - if receive transaction completed succesfully, +* MV_BAD_PARAM - if pBlock is NULL, +* MV_FAIL otherwmise. +* +*******************************************************************************/ +static MV_STATUS twsiDataReceive(MV_U8 chanNum, MV_U8 *pBlock, MV_U32 blockSize) +{ + MV_U32 timeout, temp, blockSizeRd = blockSize; + if(NULL == pBlock) + return MV_BAD_PARAM; + + /* wait for Int to be Set */ + timeout = 0; + while( !twsiMainIntGet(chanNum) && (timeout++ < TWSI_TIMEOUT_VALUE)); + + /* check for timeout */ + if(MV_TRUE == twsiTimeoutChk(timeout,"TWSI: twsiDataReceive ERROR - Read Data int Time out .\n")) + return MV_TIMEOUT; + + while(blockSizeRd) + { + if(blockSizeRd == 1) + { + /* clear ack and Int flag */ + temp = MV_REG_READ(TWSI_CONTROL_REG(chanNum)); + temp &= ~(TWSI_CONTROL_ACK); + MV_REG_WRITE(TWSI_CONTROL_REG(chanNum), temp); + } + twsiIntFlgClr(chanNum); + /* wait for Int to be Set */ + timeout = 0; + while( (!twsiMainIntGet(chanNum)) && (timeout++ < TWSI_TIMEOUT_VALUE)); + + /* check for timeout */ + if(MV_TRUE == twsiTimeoutChk(timeout,"TWSI: twsiDataReceive ERROR - Read Data Int Time out .\n")) + return MV_TIMEOUT; + + /* check the status */ + temp = twsiStsGet(chanNum); + if((temp != TWSI_M_REC_RD_DATA_ACK_TRA) && (blockSizeRd !=1)) + { + mvOsPrintf("TWSI: twsiDataReceive ERROR - status %x in read trans \n",temp); + return MV_FAIL; + } + else if((temp != TWSI_M_REC_RD_DATA_ACK_NOT_TRA) && (blockSizeRd ==1)) + { + mvOsPrintf("TWSI: twsiDataReceive ERROR - status %x in Rd Terminate\n",temp); + return MV_FAIL; + } + + /* read the data*/ + *pBlock = (MV_U8)MV_REG_READ(TWSI_DATA_REG(chanNum)); + DB(mvOsPrintf("TWSI: twsiDataReceive place %d read %x \n",\ + blockSize - blockSizeRd,*pBlock)); + pBlock++; + blockSizeRd--; + } + + return MV_OK; +} + + + +/******************************************************************************* +* twsiTargetOffsSet - Set TWST target offset on TWSI bus. +* +* DESCRIPTION: +* The function support TWSI targets that have inside address space (for +* example EEPROMs). The function: +* 1) Convert the given offset into pBlock and size. +* in case the offset should be set to a TWSI slave which support +* more then 256 bytes offset, the offset setting will be done +* in 2 transactions. +* 2) Use twsiDataTransmit to place those on the bus. +* +* INPUT: +* chanNum - TWSI channel +* offset - offset to be set on the EEPROM device. +* moreThen256 - whether the EEPROM device support more then 256 byte offset. +* +* OUTPUT: +* None. +* +* RETURN: +* MV_OK - if setting the offset completed succesfully. +* MV_FAIL otherwmise. +* +*******************************************************************************/ +static MV_STATUS twsiTargetOffsSet(MV_U8 chanNum, MV_U32 offset, MV_BOOL moreThen256) +{ + MV_U8 offBlock[2]; + MV_U32 offSize; + + if(moreThen256 == MV_TRUE) + { + offBlock[0] = (offset >> 8) & 0xff; + offBlock[1] = offset & 0xff; + offSize = 2; + } + else + { + offBlock[0] = offset & 0xff; + offSize = 1; + } + DB(mvOsPrintf("TWSI: twsiTargetOffsSet offSize = %x addr1 = %x addr2 = %x\n",\ + offSize,offBlock[0],offBlock[1])); + return twsiDataTransmit(chanNum, offBlock, offSize); + +} + +/******************************************************************************* +* mvTwsiRead - Read data block from a TWSI Slave. +* +* DESCRIPTION: +* The function calls the following functions: +* -) mvTwsiStartBitSet(); +* if(EEPROM device) +* -) mvTwsiAddrSet(w); +* -) twsiTargetOffsSet(); +* -) mvTwsiStartBitSet(); +* -) mvTwsiAddrSet(r); +* -) twsiDataReceive(); +* -) mvTwsiStopBitSet(); +* +* INPUT: +* chanNum - TWSI channel +* pTwsiSlave - Twsi Slave structure. +* blockSize - number of bytes to read. +* +* OUTPUT: +* pBlock - Data block. +* +* RETURN: +* MV_OK - if EEPROM read transaction completed succesfully, +* MV_BAD_PARAM - if pBlock is NULL, +* MV_FAIL otherwmise. +* +*******************************************************************************/ +MV_STATUS mvTwsiRead(MV_U8 chanNum, MV_TWSI_SLAVE *pTwsiSlave, MV_U8 *pBlock, MV_U32 blockSize) +{ + if((NULL == pBlock) || (NULL == pTwsiSlave)) + return MV_BAD_PARAM; + if(MV_OK != mvTwsiStartBitSet(chanNum)) + { + mvTwsiStopBitSet(chanNum); + return MV_FAIL; + } + + DB(mvOsPrintf("TWSI: mvTwsiEepromRead after mvTwsiStartBitSet\n")); + + /* in case offset exsist (i.e. eeprom ) */ + if(MV_TRUE == pTwsiSlave->validOffset) + { + if(MV_OK != mvTwsiAddrSet(chanNum, &(pTwsiSlave->slaveAddr), MV_TWSI_WRITE)) + { + mvTwsiStopBitSet(chanNum); + return MV_FAIL; + } + DB(mvOsPrintf("TWSI: mvTwsiEepromRead after mvTwsiAddrSet\n")); + if(MV_OK != twsiTargetOffsSet(chanNum, pTwsiSlave->offset, pTwsiSlave->moreThen256)) + { + mvTwsiStopBitSet(chanNum); + return MV_FAIL; + } + DB(mvOsPrintf("TWSI: mvTwsiEepromRead after twsiTargetOffsSet\n")); + if(MV_OK != mvTwsiStartBitSet(chanNum)) + { + mvTwsiStopBitSet(chanNum); + return MV_FAIL; + } + DB(mvOsPrintf("TWSI: mvTwsiEepromRead after mvTwsiStartBitSet\n")); + } + if(MV_OK != mvTwsiAddrSet(chanNum, &(pTwsiSlave->slaveAddr), MV_TWSI_READ)) + { + mvTwsiStopBitSet(chanNum); + return MV_FAIL; + } + DB(mvOsPrintf("TWSI: mvTwsiEepromRead after mvTwsiAddrSet\n")); + if(MV_OK != twsiDataReceive(chanNum, pBlock, blockSize)) + { + mvTwsiStopBitSet(chanNum); + return MV_FAIL; + } + DB(mvOsPrintf("TWSI: mvTwsiEepromRead after twsiDataReceive\n")); + + if(MV_OK != mvTwsiStopBitSet(chanNum)) + { + return MV_FAIL; + } + + twsiAckBitSet(chanNum); + + DB(mvOsPrintf("TWSI: mvTwsiEepromRead after mvTwsiStopBitSet\n")); + + return MV_OK; +} + +/******************************************************************************* +* mvTwsiWrite - Write data block to a TWSI Slave. +* +* DESCRIPTION: +* The function calls the following functions: +* -) mvTwsiStartBitSet(); +* -) mvTwsiAddrSet(); +* -)if(EEPROM device) +* -) twsiTargetOffsSet(); +* -) twsiDataTransmit(); +* -) mvTwsiStopBitSet(); +* +* INPUT: +* chanNum - TWSI channel +* eepromAddress - eeprom address. +* blockSize - number of bytes to write. +* pBlock - Data block. +* +* OUTPUT: +* None +* +* RETURN: +* MV_OK - if EEPROM read transaction completed succesfully. +* MV_BAD_PARAM - if pBlock is NULL, +* MV_FAIL otherwmise. +* +* NOTE: Part of the EEPROM, required that the offset will be aligned to the +* max write burst supported. +*******************************************************************************/ +MV_STATUS mvTwsiWrite(MV_U8 chanNum, MV_TWSI_SLAVE *pTwsiSlave, MV_U8 *pBlock, MV_U32 blockSize) +{ + if((NULL == pBlock) || (NULL == pTwsiSlave)) + return MV_BAD_PARAM; + + if(MV_OK != mvTwsiStartBitSet(chanNum)) + { + mvTwsiStopBitSet(chanNum); + return MV_FAIL; + } + + DB(mvOsPrintf("TWSI: mvTwsiEepromWrite after mvTwsiStartBitSet\n")); + if(MV_OK != mvTwsiAddrSet(chanNum, &(pTwsiSlave->slaveAddr), MV_TWSI_WRITE)) + { + mvTwsiStopBitSet(chanNum); + return MV_FAIL; + } + DB(mvOsPrintf("TWSI :mvTwsiEepromWrite after mvTwsiAddrSet\n")); + + /* in case offset exsist (i.e. eeprom ) */ + if(MV_TRUE == pTwsiSlave->validOffset) + { + if(MV_OK != twsiTargetOffsSet(chanNum, pTwsiSlave->offset, pTwsiSlave->moreThen256)) + { + mvTwsiStopBitSet(chanNum); + return MV_FAIL; + } + DB(mvOsPrintf("TWSI: mvTwsiEepromWrite after twsiTargetOffsSet\n")); + } + if(MV_OK != twsiDataTransmit(chanNum, pBlock, blockSize)) + { + mvTwsiStopBitSet(chanNum); + return MV_FAIL; + } + DB(mvOsPrintf("TWSI: mvTwsiEepromWrite after twsiDataTransmit\n")); + if(MV_OK != mvTwsiStopBitSet(chanNum)) + { + return MV_FAIL; + } + DB(mvOsPrintf("TWSI: mvTwsiEepromWrite after mvTwsiStopBitSet\n")); + + return MV_OK; +} diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/twsi/mvTwsi.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/twsi/mvTwsi.h new file mode 100644 index 0000000..bd5b6d0 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/twsi/mvTwsi.h @@ -0,0 +1,121 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ +#ifndef __INCmvTwsiH +#define __INCmvTwsiH + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* need to update this includes */ +#include "twsi/mvTwsiSpec.h" +#include "ctrlEnv/mvCtrlEnvLib.h" + + +/* The TWSI interface supports both 7-bit and 10-bit addressing. */ +/* This enumerator describes addressing type. */ +typedef enum _mvTwsiAddrType +{ + ADDR7_BIT, /* 7 bit address */ + ADDR10_BIT /* 10 bit address */ +}MV_TWSI_ADDR_TYPE; + +/* This structure describes TWSI address. */ +typedef struct _mvTwsiAddr +{ + MV_U32 address; /* address */ + MV_TWSI_ADDR_TYPE type; /* Address type */ +}MV_TWSI_ADDR; + +/* This structure describes a TWSI slave. */ +typedef struct _mvTwsiSlave +{ + MV_TWSI_ADDR slaveAddr; + MV_BOOL validOffset; /* whether the slave has offset (i.e. Eeprom etc.) */ + MV_U32 offset; /* offset in the slave. */ + MV_BOOL moreThen256; /* whether the ofset is bigger then 256 */ +}MV_TWSI_SLAVE; + +/* This enumerator describes TWSI protocol commands. */ +typedef enum _mvTwsiCmd +{ + MV_TWSI_WRITE, /* TWSI write command - 0 according to spec */ + MV_TWSI_READ /* TWSI read command - 1 according to spec */ +}MV_TWSI_CMD; + +MV_STATUS mvTwsiStartBitSet(MV_U8 chanNum); +MV_STATUS mvTwsiStopBitSet(MV_U8 chanNum); +MV_STATUS mvTwsiAddrSet(MV_U8 chanNum, MV_TWSI_ADDR *twsiAddr, MV_TWSI_CMD command); + +MV_U32 mvTwsiInit(MV_U8 chanNum, MV_KHZ frequancy, MV_U32 Tclk, MV_TWSI_ADDR *twsiAddr, MV_BOOL generalCallEnable); +MV_STATUS mvTwsiRead (MV_U8 chanNum, MV_TWSI_SLAVE *twsiSlave, MV_U8 *pBlock, MV_U32 blockSize); +MV_STATUS mvTwsiWrite(MV_U8 chanNum, MV_TWSI_SLAVE *twsiSlave, MV_U8 *pBlock, MV_U32 blockSize); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __INCmvTwsiH */ + diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/twsi/mvTwsiEeprom.S b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/twsi/mvTwsiEeprom.S new file mode 100644 index 0000000..9d81ef2 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/twsi/mvTwsiEeprom.S @@ -0,0 +1,457 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + + +/* includes */ +#define MV_ASMLANGUAGE +#include "ctrlEnv/mvCtrlEnvSpec.h" +#include "boardEnv/mvBoardEnvSpec.h" +#include "mvOsAsm.h" +#include "mvTwsiSpec.h" +#include "mvSysHwConfig.h" +#include "ctrlEnv/sys/mvCpuIfRegs.h" +#include "mvCommon.h" + +#define I2C_CH MV_BOARD_DIMM_I2C_CHANNEL + +/* defines */ +/* defines */ + + + .data + .global _i2cInit + .global _i2cRead + + .text + +/******************************************************************************* +* _i2cInit - Initialize TWSI interface +* +* DESCRIPTION: +* The function performs TWSI interface initialization. It resets the +* TWSI state machine and initialize its clock to 100KHz assuming Tclock +* of 133MHz. +* +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* None. +* +*******************************************************************************/ +_i2cInit: + mov r9, LR /* Save link register */ + mov r0, #0 /* Make sure r0 is zero */ + + /* Reset the i2c Mechanism first */ + MV_REG_WRITE_ASM (r0, r1, TWSI_SOFT_RESET_REG(I2C_CH)) + + bl _twsiDelay + bl _twsiDelay + + /* Initializing the I2C mechanism. Assuming Tclock frequency */ + /* of 166MHz. The I2C frequency in that case will be 100KHz. */ + /* For this settings, M = 9 and N = 3. Set the baud-rate with the */ + /* value of 0x2b (freq of ==> 100KHz */ + /* see spec for more details about the calculation of this value) */ + mov r6, #(9 << 3 | 3) + MV_REG_WRITE_ASM (r6, r1, TWSI_STATUS_BAUDE_RATE_REG(I2C_CH)) + + /* Enable the I2C master */ + /* Enable TWSI interrupt in main mask reg */ + mov r6, #0xC4 + MV_REG_WRITE_ASM (r6, r1, TWSI_CONTROL_REG(I2C_CH)) + + /* Let the slow TWSI machine get used to the idea that it is enabled */ + bl _twsiDelay + + + mov PC, r9 /* r9 is saved link register */ + +/******************************************************************************* +* _twsiDelay - Perform delay. +* +* DESCRIPTION: +* The function performs a delay to enable TWSI logic to stable. +* +* INPUT: +* None. +* +* OUTPUT: +* None. +* +* RETURN: +* None. +* +*******************************************************************************/ +_twsiDelay: + mov r10, #0x100000 /*was 0x400*/ + +_twsiDelayLoop: + subs r10, r10, #1 + bne _twsiDelayLoop + + mov PC, LR + +/******************************************************************************* +* _i2cRead - Read byte from I2C EEPROM device. +* +* DESCRIPTION: +* The function returns a byte from I2C EEPROM device. +* The EEPROM device is 7-bit address type. +* +* INPUT: +* r4 has the DIMM0 base address with shift 1 bit to the left +* r7 has the EEPROM offset +* +* OUTPUT: +* None. +* +* RETURN: +* r4 returns '0' if address can not be read. +* r7 has byte value in case read is successful. +* +*******************************************************************************/ +_i2cRead: + mov r9, LR /* Save link register */ + + /* Transmit the device address and desired offset within the EEPROM. */ + + /* Generate Start Bit */ + MV_REG_READ_ASM (r6, r1, TWSI_CONTROL_REG(I2C_CH)) + orr r6, r6, #TWSI_CONTROL_START_BIT + MV_REG_WRITE_ASM (r6, r1, TWSI_CONTROL_REG(I2C_CH)) + + /* Wait for the interrupt flag (bit3) to be set */ + mov r10, #0x50000 +loop_1: + subs r10, r10, #1 + beq loop_1_timeout +#ifdef MV78XX0 + MV_REG_READ_ASM (r6, r1, CPU_INT_LOW_REG(I2C_CH)) + tst r6, #BIT2 +#else + MV_REG_READ_ASM (r6, r1, CPU_MAIN_INT_CAUSE_REG) + tst r6, #BIT5 +#endif + beq loop_1 + +loop_1_timeout: + + /* Wait for the start bit to be reset by HW */ + mov r10, #0x50000 +loop_2: + subs r10, r10, #1 + beq loop_2_timeout + MV_REG_READ_ASM (r6, r1, TWSI_CONTROL_REG(I2C_CH)) + tst r6, #TWSI_CONTROL_START_BIT + bne loop_2 + +loop_2_timeout: + + /* Wait for the status TWSI_START_CONDITION_TRA = 0x8 */ + mov r10, #0x50000 +loop_3: + subs r10, r10, #1 + beq loop_3_timeout + MV_REG_READ_ASM (r6, r1, TWSI_STATUS_BAUDE_RATE_REG(I2C_CH)) + cmp r6, #0x08 + bne loop_3 + +loop_3_timeout: + + /* writing the address of (DIMM0/1 << 1) with write indication */ + mov r6, r4, LSL #1 /* Write operation address bit 0 must be 0 */ + MV_REG_WRITE_ASM (r6, r1, TWSI_DATA_REG(I2C_CH)) + + bl _twsiDelay + /* Clear the interrupt flag */ + MV_REG_READ_ASM (r6, r1, TWSI_CONTROL_REG(I2C_CH)) + bic r6, r6, #TWSI_CONTROL_INT_FLAG_SET + MV_REG_WRITE_ASM (r6, r1, TWSI_CONTROL_REG(I2C_CH)) + bl _twsiDelay + + /* Waiting for the interrupt flag to be set which means that the + address has been transmitted */ +loop_4: +#ifdef MV78XX0 + MV_REG_READ_ASM (r6, r1, CPU_INT_LOW_REG(I2C_CH)) + tst r6, #BIT2 +#else + MV_REG_READ_ASM (r6, r1, CPU_MAIN_INT_CAUSE_REG) + tst r6, #BIT5 +#endif + beq loop_4 /* if tst = 0, then the bit is not set yet */ + + /* Wait for status TWSI_ADDR_PLUS_WRITE_BIT_TRA_ACK_REC = 0x18 */ + mov r10, #0x50000 /* Set r10 to 0x50000 =~ 328,000 */ + +loop_5: + subs r10, r10, #1 /* timeout count down */ + bne testStatus + mov r4, #0 /* r4 = 0 -> operation failed */ + b exit_i2cRead /* Exit if timeout (No DIMM) */ + +testStatus: + MV_REG_READ_ASM (r6, r1, TWSI_STATUS_BAUDE_RATE_REG(I2C_CH)) + cmp r6, #0x18 + bne loop_5 + + + /* check if the offset is bigger than 256 byte*/ + tst r7, #0x80000000 + bne great_than_256 + + /* Write the offset to be read from the DIMM EEPROM */ + MV_REG_WRITE_ASM (r7, r1, TWSI_DATA_REG(I2C_CH)) + + b after_offset + +great_than_256: + mov r10, r7, LSR #8 + and r10, r10, #0xff + /* Write the offset0 to be read from the EEPROM */ + MV_REG_WRITE_ASM (r10, r1, TWSI_DATA_REG(I2C_CH)) + + /* Clear the interrupt flag ==> signaling that the address can now + be transmited */ + + bl _twsiDelay + MV_REG_READ_ASM (r6, r1, TWSI_CONTROL_REG(I2C_CH)) + bic r6, r6, #TWSI_CONTROL_INT_FLAG_SET + MV_REG_WRITE_ASM (r6, r1, TWSI_CONTROL_REG(I2C_CH)) + bl _twsiDelay + + /* Wait for the interrupt to be set again ==> address has transmited */ +loop_6_1: +#ifdef MV78XX0 + MV_REG_READ_ASM (r6, r1, CPU_INT_LOW_REG(I2C_CH)) + tst r6, #BIT2 +#else + MV_REG_READ_ASM (r6, r1, CPU_MAIN_INT_CAUSE_REG) + tst r6, #BIT5 +#endif + beq loop_6_1 + + /* Wait for status TWSI_MAS_TRAN_DATA_BYTE_ACK_REC = 0x28 */ +loop_7_1: + MV_REG_READ_ASM (r6, r1, TWSI_STATUS_BAUDE_RATE_REG(I2C_CH)) + cmp r6, #0x28 + bne loop_7_1 + + + mov r10, r7 + and r10, r10, #0xff + /* Write the offset1 to be read from the EEPROM */ + MV_REG_WRITE_ASM (r10, r1, TWSI_DATA_REG(I2C_CH)) + + + +after_offset: + + /* Clear the interrupt flag ==> signaling that the address can now + be transmited */ + + bl _twsiDelay + MV_REG_READ_ASM (r6, r1, TWSI_CONTROL_REG(I2C_CH)) + bic r6, r6, #TWSI_CONTROL_INT_FLAG_SET + MV_REG_WRITE_ASM (r6, r1, TWSI_CONTROL_REG(I2C_CH)) + bl _twsiDelay + + /* Wait for the interrupt to be set again ==> address has transmited */ +loop_6: +#ifdef MV78XX0 + MV_REG_READ_ASM (r6, r1, CPU_INT_LOW_REG(I2C_CH)) + tst r6, #BIT2 +#else + MV_REG_READ_ASM (r6, r1, CPU_MAIN_INT_CAUSE_REG) + tst r6, #BIT5 +#endif + beq loop_6 + + /* Wait for status TWSI_MAS_TRAN_DATA_BYTE_ACK_REC = 0x28 */ +loop_7: + MV_REG_READ_ASM (r6, r1, TWSI_STATUS_BAUDE_RATE_REG(I2C_CH)) + cmp r6, #0x28 + bne loop_7 + + /* Retransmit the device address with read indication to get the data */ + + /* generate a repeated start bit */ + MV_REG_READ_ASM (r6, r1, TWSI_CONTROL_REG(I2C_CH)) + orr r6, r6, #TWSI_CONTROL_START_BIT + MV_REG_WRITE_ASM (r6, r1, TWSI_CONTROL_REG(I2C_CH)) + + + /* Clear the interrupt flag ==> the start bit will be transmitted. */ + bl _twsiDelay + MV_REG_READ_ASM (r6, r1, TWSI_CONTROL_REG(I2C_CH)) + bic r6, r6, #TWSI_CONTROL_INT_FLAG_SET + MV_REG_WRITE_ASM (r6, r1, TWSI_CONTROL_REG(I2C_CH)) + bl _twsiDelay + + /* Wait for the interrupt flag (bit3) to be set */ +loop_9: +#ifdef MV78XX0 + MV_REG_READ_ASM (r6, r1, CPU_INT_LOW_REG(I2C_CH)) + tst r6, #BIT2 +#else + MV_REG_READ_ASM (r6, r1, CPU_MAIN_INT_CAUSE_REG) + tst r6, #BIT5 +#endif + beq loop_9 + + /* Wait for the start bit to be reset by HW */ +loop_8: + MV_REG_READ_ASM (r6, r1, TWSI_CONTROL_REG(I2C_CH)) + tst r6, #TWSI_CONTROL_START_BIT + bne loop_8 + + /* Wait for status TWSI_REPEATED_START_CONDITION_TRA = 0x10 */ +loop_10: + MV_REG_READ_ASM (r6, r1, TWSI_STATUS_BAUDE_RATE_REG(I2C_CH)) + cmp r6, #0x10 + bne loop_10 + + /* Writing the address of (DIMM0<<1) with read indication (bit0 is 1) */ + mov r6, r4, LSL #1 + orr r6, r6, #1 /* Read operation address bit 0 must be 1 */ + MV_REG_WRITE_ASM (r6, r1, TWSI_DATA_REG(I2C_CH)) + + /* Clear the interrupt flag ==> the address will be transmitted */ + bl _twsiDelay + MV_REG_READ_ASM (r6, r1, TWSI_CONTROL_REG(I2C_CH)) + bic r6, r6, #TWSI_CONTROL_INT_FLAG_SET + MV_REG_WRITE_ASM (r6, r1, TWSI_CONTROL_REG(I2C_CH)) + bl _twsiDelay + + /* Wait for the interrupt flag (bit3) to be set as a result of + transmitting the address. */ +loop_11: +#ifdef MV78XX0 + MV_REG_READ_ASM (r6, r1, CPU_INT_LOW_REG(I2C_CH)) + tst r6, #BIT2 +#else + MV_REG_READ_ASM (r6, r1, CPU_MAIN_INT_CAUSE_REG) + tst r6, #BIT5 +#endif + beq loop_11 + + /* Wait for status TWSI_ADDR_PLUS_READ_BIT_TRA_ACK_REC = 0x40 */ +loop_12: + MV_REG_READ_ASM (r6, r1, TWSI_STATUS_BAUDE_RATE_REG(I2C_CH)) + cmp r6, #0x40 + bne loop_12 + + /* Clear the interrupt flag and the Acknoledge bit */ + bl _twsiDelay + MV_REG_READ_ASM (r6, r1, TWSI_CONTROL_REG(I2C_CH)) + bic r6, r6, #(TWSI_CONTROL_INT_FLAG_SET | TWSI_CONTROL_ACK) + MV_REG_WRITE_ASM (r6, r1, TWSI_CONTROL_REG(I2C_CH)) + bl _twsiDelay + + /* Wait for the interrupt flag (bit3) to be set */ +loop_14: +#ifdef MV78XX0 + MV_REG_READ_ASM (r6, r1, CPU_INT_LOW_REG(I2C_CH)) + tst r6, #BIT2 +#else + MV_REG_READ_ASM (r6, r1, CPU_MAIN_INT_CAUSE_REG) + tst r6, #BIT5 +#endif + beq loop_14 + + /* Wait for status TWSI_MAS_REC_READ_DATA_ACK_NOT_TRA = 0x58 */ +loop_15: + MV_REG_READ_ASM (r6, r1, TWSI_STATUS_BAUDE_RATE_REG(I2C_CH)) + cmp r6, #0x58 + bne loop_15 + + /* Store the data in r7. */ + MV_REG_READ_ASM (r7, r1, TWSI_DATA_REG(I2C_CH)) + + /* Generate stop bit */ + MV_REG_READ_ASM (r6, r1, TWSI_CONTROL_REG(I2C_CH)) + orr r6, r6, #TWSI_CONTROL_STOP_BIT + MV_REG_WRITE_ASM (r6, r1, TWSI_CONTROL_REG(I2C_CH)) + + + /* Clear the interrupt flag */ + bl _twsiDelay + MV_REG_READ_ASM (r6, r1, TWSI_CONTROL_REG(I2C_CH)) + bic r6, r6, #TWSI_CONTROL_INT_FLAG_SET + MV_REG_WRITE_ASM (r6, r1, TWSI_CONTROL_REG(I2C_CH)) + bl _twsiDelay + + /* Wait for the stop bit to be reset by HW */ +loop_16: + MV_REG_READ_ASM (r6, r1, TWSI_CONTROL_REG(I2C_CH)) + tst r6, #TWSI_CONTROL_INT_FLAG_SET + bne loop_16 + +exit_i2cRead: + mov PC, r9 /* r9 is saved link register */ diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/twsi/mvTwsiSpec.h b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/twsi/mvTwsiSpec.h new file mode 100644 index 0000000..d0c2b9e --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/kirkwood/mvHal/mv_hal/twsi/mvTwsiSpec.h @@ -0,0 +1,160 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +This software file (the "File") is owned and distributed by Marvell +International Ltd. and/or its affiliates ("Marvell") under the following +alternative licensing terms. Once you have made an election to distribute the +File under one of the following license alternatives, please (i) delete this +introductory statement regarding license alternatives, (ii) delete the two +license alternatives that you have not elected to use and (iii) preserve the +Marvell copyright notice above. + +******************************************************************************** +Marvell Commercial License Option + +If you received this File from Marvell and you have entered into a commercial +license agreement (a "Commercial License") with Marvell, the File is licensed +to you under the terms of the applicable Commercial License. + +******************************************************************************** +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or +on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. +******************************************************************************** +Marvell BSD License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File under the following licensing terms. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Marvell nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ +/****************************************/ +/* TWSI Registers */ +/****************************************/ +#ifndef __INCmvTwsiSpech +#define __INCmvTwsiSpech + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* defines */ +#define TWSI_SLAVE_ADDR_REG(chanNum) (TWSI_SLAVE_BASE(chanNum)+ 0x00) + +#define TWSI_SLAVE_ADDR_GCE_ENA BIT0 +#define TWSI_SLAVE_ADDR_7BIT_OFFS 0x1 +#define TWSI_SLAVE_ADDR_7BIT_MASK (0xFF << TWSI_SLAVE_ADDR_7BIT_OFFS) +#define TWSI_SLAVE_ADDR_10BIT_OFFS 0x7 +#define TWSI_SLAVE_ADDR_10BIT_MASK 0x300 +#define TWSI_SLAVE_ADDR_10BIT_CONST 0xF0 + + +#define TWSI_EXTENDED_SLAVE_ADDR_REG(chanNum) (TWSI_SLAVE_BASE(chanNum) + 0x10) +#define TWSI_EXTENDED_SLAVE_OFFS 0 +#define TWSI_EXTENDED_SLAVE_MASK (0xFF << TWSI_EXTENDED_SLAVE_OFFS) + + +#define TWSI_DATA_REG(chanNum) (TWSI_SLAVE_BASE(chanNum) + 0x04) +#define TWSI_DATA_COMMAND_OFFS 0x0 +#define TWSI_DATA_COMMAND_MASK (0x1 << TWSI_DATA_COMMAND_OFFS) +#define TWSI_DATA_COMMAND_WR (0x1 << TWSI_DATA_COMMAND_OFFS) +#define TWSI_DATA_COMMAND_RD (0x0 << TWSI_DATA_COMMAND_OFFS) +#define TWSI_DATA_ADDR_7BIT_OFFS 0x1 +#define TWSI_DATA_ADDR_7BIT_MASK (0xFF << TWSI_DATA_ADDR_7BIT_OFFS) +#define TWSI_DATA_ADDR_10BIT_OFFS 0x7 +#define TWSI_DATA_ADDR_10BIT_MASK 0x300 +#define TWSI_DATA_ADDR_10BIT_CONST 0xF0 + + +#define TWSI_CONTROL_REG(chanNum) (TWSI_SLAVE_BASE(chanNum) + 0x08) +#define TWSI_CONTROL_ACK BIT2 +#define TWSI_CONTROL_INT_FLAG_SET BIT3 +#define TWSI_CONTROL_STOP_BIT BIT4 +#define TWSI_CONTROL_START_BIT BIT5 +#define TWSI_CONTROL_ENA BIT6 +#define TWSI_CONTROL_INT_ENA BIT7 + + +#define TWSI_STATUS_BAUDE_RATE_REG(chanNum) (TWSI_SLAVE_BASE(chanNum) + 0x0c) +#define TWSI_BAUD_RATE_N_OFFS 0 +#define TWSI_BAUD_RATE_N_MASK (0x7 << TWSI_BAUD_RATE_N_OFFS) +#define TWSI_BAUD_RATE_M_OFFS 3 +#define TWSI_BAUD_RATE_M_MASK (0xF << TWSI_BAUD_RATE_M_OFFS) + +#define TWSI_SOFT_RESET_REG(chanNum) (TWSI_SLAVE_BASE(chanNum) + 0x1c) + +/* defines */ +#define TWSI_TIMEOUT_VALUE 0x500 + +/* TWSI status codes */ +#define TWSI_BUS_ERROR 0x00 +#define TWSI_START_CON_TRA 0x08 +#define TWSI_REPEATED_START_CON_TRA 0x10 +#define TWSI_AD_PLS_WR_BIT_TRA_ACK_REC 0x18 +#define TWSI_AD_PLS_WR_BIT_TRA_ACK_NOT_REC 0x20 +#define TWSI_M_TRAN_DATA_BYTE_ACK_REC 0x28 +#define TWSI_M_TRAN_DATA_BYTE_ACK_NOT_REC 0x30 +#define TWSI_M_LOST_ARB_DUR_AD_OR_DATA_TRA 0x38 +#define TWSI_AD_PLS_RD_BIT_TRA_ACK_REC 0x40 +#define TWSI_AD_PLS_RD_BIT_TRA_ACK_NOT_REC 0x48 +#define TWSI_M_REC_RD_DATA_ACK_TRA 0x50 +#define TWSI_M_REC_RD_DATA_ACK_NOT_TRA 0x58 +#define TWSI_SLA_REC_AD_PLS_WR_BIT_ACK_TRA 0x60 +#define TWSI_M_LOST_ARB_DUR_AD_TRA_AD_IS_TRGT_TO_SLA_ACK_TRA_W 0x68 +#define TWSI_GNL_CALL_REC_ACK_TRA 0x70 +#define TWSI_M_LOST_ARB_DUR_AD_TRA_GNL_CALL_AD_REC_ACK_TRA 0x78 +#define TWSI_SLA_REC_WR_DATA_AF_REC_SLA_AD_ACK_TRAN 0x80 +#define TWSI_SLA_REC_WR_DATA_AF_REC_SLA_AD_ACK_NOT_TRAN 0x88 +#define TWSI_SLA_REC_WR_DATA_AF_REC_GNL_CALL_ACK_TRAN 0x90 +#define TWSI_SLA_REC_WR_DATA_AF_REC_GNL_CALL_ACK_NOT_TRAN 0x98 +#define TWSI_SLA_REC_STOP_OR_REPEATED_STRT_CON 0xA0 +#define TWSI_SLA_REC_AD_PLS_RD_BIT_ACK_TRA 0xA8 +#define TWSI_M_LOST_ARB_DUR_AD_TRA_AD_IS_TRGT_TO_SLA_ACK_TRA_R 0xB0 +#define TWSI_SLA_TRA_RD_DATA_ACK_REC 0xB8 +#define TWSI_SLA_TRA_RD_DATA_ACK_NOT_REC 0xC0 +#define TWSI_SLA_TRA_LAST_RD_DATA_ACK_REC 0xC8 +#define TWSI_SEC_AD_PLS_WR_BIT_TRA_ACK_REC 0xD0 +#define TWSI_SEC_AD_PLS_WR_BIT_TRA_ACK_NOT_REC 0xD8 +#define TWSI_SEC_AD_PLS_RD_BIT_TRA_ACK_REC 0xE0 +#define TWSI_SEC_AD_PLS_RD_BIT_TRA_ACK_NOT_REC 0xE8 +#define TWSI_NO_REL_STS_INT_FLAG_IS_KEPT_0 0xF8 + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __INCmvTwsiSpech */ diff --git a/target/linux/generic/files/crypto/ocf/ocf-bench.c b/target/linux/generic/files/crypto/ocf/ocf-bench.c new file mode 100644 index 0000000..a9a9538 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/ocf-bench.c @@ -0,0 +1,514 @@ +/* + * A loadable module that benchmarks the OCF crypto speed from kernel space. + * + * Copyright (C) 2004-2010 David McCullough + * + * LICENSE TERMS + * + * The free distribution and use of this software in both source and binary + * form is allowed (with or without changes) provided that: + * + * 1. distributions of this source code include the above copyright + * notice, this list of conditions and the following disclaimer; + * + * 2. distributions in binary form include the above copyright + * notice, this list of conditions and the following disclaimer + * in the documentation and/or other associated materials; + * + * 3. the copyright holder's name is not used to endorse products + * built using this software without specific written permission. + * + * ALTERNATIVELY, provided that this notice is retained in full, this product + * may be distributed under the terms of the GNU General Public License (GPL), + * in which case the provisions of the GPL apply INSTEAD OF those given above. + * + * DISCLAIMER + * + * This software is provided 'as is' with no explicit or implied warranties + * in respect of its properties, including, but not limited to, correctness + * and/or fitness for purpose. + */ + + +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) && !defined(AUTOCONF_INCLUDED) +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef I_HAVE_AN_XSCALE_WITH_INTEL_SDK +#define BENCH_IXP_ACCESS_LIB 1 +#endif +#ifdef BENCH_IXP_ACCESS_LIB +#include +#include +#include +#include +#include +#include +#include +#endif + +/* + * support for access lib version 1.4 + */ +#ifndef IX_MBUF_PRIV +#define IX_MBUF_PRIV(x) ((x)->priv) +#endif + +/* + * the number of simultaneously active requests + */ +static int request_q_len = 40; +module_param(request_q_len, int, 0); +MODULE_PARM_DESC(request_q_len, "Number of outstanding requests"); + +/* + * how many requests we want to have processed + */ +static int request_num = 1024; +module_param(request_num, int, 0); +MODULE_PARM_DESC(request_num, "run for at least this many requests"); + +/* + * the size of each request + */ +static int request_size = 1488; +module_param(request_size, int, 0); +MODULE_PARM_DESC(request_size, "size of each request"); + +/* + * OCF batching of requests + */ +static int request_batch = 1; +module_param(request_batch, int, 0); +MODULE_PARM_DESC(request_batch, "enable OCF request batching"); + +/* + * OCF immediate callback on completion + */ +static int request_cbimm = 1; +module_param(request_cbimm, int, 0); +MODULE_PARM_DESC(request_cbimm, "enable OCF immediate callback on completion"); + +/* + * a structure for each request + */ +typedef struct { + struct work_struct work; +#ifdef BENCH_IXP_ACCESS_LIB + IX_MBUF mbuf; +#endif + unsigned char *buffer; +} request_t; + +static request_t *requests; + +static spinlock_t ocfbench_counter_lock; +static int outstanding; +static int total; + +/*************************************************************************/ +/* + * OCF benchmark routines + */ + +static uint64_t ocf_cryptoid; +static unsigned long jstart, jstop; + +static int ocf_init(void); +static int ocf_cb(struct cryptop *crp); +static void ocf_request(void *arg); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) +static void ocf_request_wq(struct work_struct *work); +#endif + +static int +ocf_init(void) +{ + int error; + struct cryptoini crie, cria; + struct cryptodesc crda, crde; + + memset(&crie, 0, sizeof(crie)); + memset(&cria, 0, sizeof(cria)); + memset(&crde, 0, sizeof(crde)); + memset(&crda, 0, sizeof(crda)); + + cria.cri_alg = CRYPTO_SHA1_HMAC; + cria.cri_klen = 20 * 8; + cria.cri_key = "0123456789abcdefghij"; + + //crie.cri_alg = CRYPTO_3DES_CBC; + crie.cri_alg = CRYPTO_AES_CBC; + crie.cri_klen = 24 * 8; + crie.cri_key = "0123456789abcdefghijklmn"; + + crie.cri_next = &cria; + + error = crypto_newsession(&ocf_cryptoid, &crie, + CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE); + if (error) { + printk("crypto_newsession failed %d\n", error); + return -1; + } + return 0; +} + +static int +ocf_cb(struct cryptop *crp) +{ + request_t *r = (request_t *) crp->crp_opaque; + unsigned long flags; + + if (crp->crp_etype) + printk("Error in OCF processing: %d\n", crp->crp_etype); + crypto_freereq(crp); + crp = NULL; + + /* do all requests but take at least 1 second */ + spin_lock_irqsave(&ocfbench_counter_lock, flags); + total++; + if (total > request_num && jstart + HZ < jiffies) { + outstanding--; + spin_unlock_irqrestore(&ocfbench_counter_lock, flags); + return 0; + } + spin_unlock_irqrestore(&ocfbench_counter_lock, flags); + + schedule_work(&r->work); + return 0; +} + + +static void +ocf_request(void *arg) +{ + request_t *r = arg; + struct cryptop *crp = crypto_getreq(2); + struct cryptodesc *crde, *crda; + unsigned long flags; + + if (!crp) { + spin_lock_irqsave(&ocfbench_counter_lock, flags); + outstanding--; + spin_unlock_irqrestore(&ocfbench_counter_lock, flags); + return; + } + + crde = crp->crp_desc; + crda = crde->crd_next; + + crda->crd_skip = 0; + crda->crd_flags = 0; + crda->crd_len = request_size; + crda->crd_inject = request_size; + crda->crd_alg = CRYPTO_SHA1_HMAC; + crda->crd_key = "0123456789abcdefghij"; + crda->crd_klen = 20 * 8; + + crde->crd_skip = 0; + crde->crd_flags = CRD_F_IV_EXPLICIT | CRD_F_ENCRYPT; + crde->crd_len = request_size; + crde->crd_inject = request_size; + //crde->crd_alg = CRYPTO_3DES_CBC; + crde->crd_alg = CRYPTO_AES_CBC; + crde->crd_key = "0123456789abcdefghijklmn"; + crde->crd_klen = 24 * 8; + + crp->crp_ilen = request_size + 64; + crp->crp_flags = 0; + if (request_batch) + crp->crp_flags |= CRYPTO_F_BATCH; + if (request_cbimm) + crp->crp_flags |= CRYPTO_F_CBIMM; + crp->crp_buf = (caddr_t) r->buffer; + crp->crp_callback = ocf_cb; + crp->crp_sid = ocf_cryptoid; + crp->crp_opaque = (caddr_t) r; + crypto_dispatch(crp); +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) +static void +ocf_request_wq(struct work_struct *work) +{ + request_t *r = container_of(work, request_t, work); + ocf_request(r); +} +#endif + +static void +ocf_done(void) +{ + crypto_freesession(ocf_cryptoid); +} + +/*************************************************************************/ +#ifdef BENCH_IXP_ACCESS_LIB +/*************************************************************************/ +/* + * CryptoAcc benchmark routines + */ + +static IxCryptoAccCtx ixp_ctx; +static UINT32 ixp_ctx_id; +static IX_MBUF ixp_pri; +static IX_MBUF ixp_sec; +static int ixp_registered = 0; + +static void ixp_register_cb(UINT32 ctx_id, IX_MBUF *bufp, + IxCryptoAccStatus status); +static void ixp_perform_cb(UINT32 ctx_id, IX_MBUF *sbufp, IX_MBUF *dbufp, + IxCryptoAccStatus status); +static void ixp_request(void *arg); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) +static void ixp_request_wq(struct work_struct *work); +#endif + +static int +ixp_init(void) +{ + IxCryptoAccStatus status; + + ixp_ctx.cipherCtx.cipherAlgo = IX_CRYPTO_ACC_CIPHER_3DES; + ixp_ctx.cipherCtx.cipherMode = IX_CRYPTO_ACC_MODE_CBC; + ixp_ctx.cipherCtx.cipherKeyLen = 24; + ixp_ctx.cipherCtx.cipherBlockLen = IX_CRYPTO_ACC_DES_BLOCK_64; + ixp_ctx.cipherCtx.cipherInitialVectorLen = IX_CRYPTO_ACC_DES_IV_64; + memcpy(ixp_ctx.cipherCtx.key.cipherKey, "0123456789abcdefghijklmn", 24); + + ixp_ctx.authCtx.authAlgo = IX_CRYPTO_ACC_AUTH_SHA1; + ixp_ctx.authCtx.authDigestLen = 12; + ixp_ctx.authCtx.aadLen = 0; + ixp_ctx.authCtx.authKeyLen = 20; + memcpy(ixp_ctx.authCtx.key.authKey, "0123456789abcdefghij", 20); + + ixp_ctx.useDifferentSrcAndDestMbufs = 0; + ixp_ctx.operation = IX_CRYPTO_ACC_OP_ENCRYPT_AUTH ; + + IX_MBUF_MLEN(&ixp_pri) = IX_MBUF_PKT_LEN(&ixp_pri) = 128; + IX_MBUF_MDATA(&ixp_pri) = (unsigned char *) kmalloc(128, SLAB_ATOMIC); + IX_MBUF_MLEN(&ixp_sec) = IX_MBUF_PKT_LEN(&ixp_sec) = 128; + IX_MBUF_MDATA(&ixp_sec) = (unsigned char *) kmalloc(128, SLAB_ATOMIC); + + status = ixCryptoAccCtxRegister(&ixp_ctx, &ixp_pri, &ixp_sec, + ixp_register_cb, ixp_perform_cb, &ixp_ctx_id); + + if (IX_CRYPTO_ACC_STATUS_SUCCESS == status) { + while (!ixp_registered) + schedule(); + return ixp_registered < 0 ? -1 : 0; + } + + printk("ixp: ixCryptoAccCtxRegister failed %d\n", status); + return -1; +} + +static void +ixp_register_cb(UINT32 ctx_id, IX_MBUF *bufp, IxCryptoAccStatus status) +{ + if (bufp) { + IX_MBUF_MLEN(bufp) = IX_MBUF_PKT_LEN(bufp) = 0; + kfree(IX_MBUF_MDATA(bufp)); + IX_MBUF_MDATA(bufp) = NULL; + } + + if (IX_CRYPTO_ACC_STATUS_WAIT == status) + return; + if (IX_CRYPTO_ACC_STATUS_SUCCESS == status) + ixp_registered = 1; + else + ixp_registered = -1; +} + +static void +ixp_perform_cb( + UINT32 ctx_id, + IX_MBUF *sbufp, + IX_MBUF *dbufp, + IxCryptoAccStatus status) +{ + request_t *r = NULL; + unsigned long flags; + + /* do all requests but take at least 1 second */ + spin_lock_irqsave(&ocfbench_counter_lock, flags); + total++; + if (total > request_num && jstart + HZ < jiffies) { + outstanding--; + spin_unlock_irqrestore(&ocfbench_counter_lock, flags); + return; + } + + if (!sbufp || !(r = IX_MBUF_PRIV(sbufp))) { + printk("crappo %p %p\n", sbufp, r); + outstanding--; + spin_unlock_irqrestore(&ocfbench_counter_lock, flags); + return; + } + spin_unlock_irqrestore(&ocfbench_counter_lock, flags); + + schedule_work(&r->work); +} + +static void +ixp_request(void *arg) +{ + request_t *r = arg; + IxCryptoAccStatus status; + unsigned long flags; + + memset(&r->mbuf, 0, sizeof(r->mbuf)); + IX_MBUF_MLEN(&r->mbuf) = IX_MBUF_PKT_LEN(&r->mbuf) = request_size + 64; + IX_MBUF_MDATA(&r->mbuf) = r->buffer; + IX_MBUF_PRIV(&r->mbuf) = r; + status = ixCryptoAccAuthCryptPerform(ixp_ctx_id, &r->mbuf, NULL, + 0, request_size, 0, request_size, request_size, r->buffer); + if (IX_CRYPTO_ACC_STATUS_SUCCESS != status) { + printk("status1 = %d\n", status); + spin_lock_irqsave(&ocfbench_counter_lock, flags); + outstanding--; + spin_unlock_irqrestore(&ocfbench_counter_lock, flags); + return; + } + return; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) +static void +ixp_request_wq(struct work_struct *work) +{ + request_t *r = container_of(work, request_t, work); + ixp_request(r); +} +#endif + +static void +ixp_done(void) +{ + /* we should free the session here but I am lazy :-) */ +} + +/*************************************************************************/ +#endif /* BENCH_IXP_ACCESS_LIB */ +/*************************************************************************/ + +int +ocfbench_init(void) +{ + int i; + unsigned long mbps; + unsigned long flags; + + printk("Crypto Speed tests\n"); + + requests = kmalloc(sizeof(request_t) * request_q_len, GFP_KERNEL); + if (!requests) { + printk("malloc failed\n"); + return -EINVAL; + } + + for (i = 0; i < request_q_len; i++) { + /* +64 for return data */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + INIT_WORK(&requests[i].work, ocf_request_wq); +#else + INIT_WORK(&requests[i].work, ocf_request, &requests[i]); +#endif + requests[i].buffer = kmalloc(request_size + 128, GFP_DMA); + if (!requests[i].buffer) { + printk("malloc failed\n"); + return -EINVAL; + } + memset(requests[i].buffer, '0' + i, request_size + 128); + } + + /* + * OCF benchmark + */ + printk("OCF: testing ...\n"); + if (ocf_init() == -1) + return -EINVAL; + + spin_lock_init(&ocfbench_counter_lock); + total = outstanding = 0; + jstart = jiffies; + for (i = 0; i < request_q_len; i++) { + spin_lock_irqsave(&ocfbench_counter_lock, flags); + outstanding++; + spin_unlock_irqrestore(&ocfbench_counter_lock, flags); + ocf_request(&requests[i]); + } + while (outstanding > 0) + schedule(); + jstop = jiffies; + + mbps = 0; + if (jstop > jstart) { + mbps = (unsigned long) total * (unsigned long) request_size * 8; + mbps /= ((jstop - jstart) * 1000) / HZ; + } + printk("OCF: %d requests of %d bytes in %d jiffies (%d.%03d Mbps)\n", + total, request_size, (int)(jstop - jstart), + ((int)mbps) / 1000, ((int)mbps) % 1000); + ocf_done(); + +#ifdef BENCH_IXP_ACCESS_LIB + /* + * IXP benchmark + */ + printk("IXP: testing ...\n"); + ixp_init(); + total = outstanding = 0; + jstart = jiffies; + for (i = 0; i < request_q_len; i++) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + INIT_WORK(&requests[i].work, ixp_request_wq); +#else + INIT_WORK(&requests[i].work, ixp_request, &requests[i]); +#endif + spin_lock_irqsave(&ocfbench_counter_lock, flags); + outstanding++; + spin_unlock_irqrestore(&ocfbench_counter_lock, flags); + ixp_request(&requests[i]); + } + while (outstanding > 0) + schedule(); + jstop = jiffies; + + mbps = 0; + if (jstop > jstart) { + mbps = (unsigned long) total * (unsigned long) request_size * 8; + mbps /= ((jstop - jstart) * 1000) / HZ; + } + printk("IXP: %d requests of %d bytes in %d jiffies (%d.%03d Mbps)\n", + total, request_size, jstop - jstart, + ((int)mbps) / 1000, ((int)mbps) % 1000); + ixp_done(); +#endif /* BENCH_IXP_ACCESS_LIB */ + + for (i = 0; i < request_q_len; i++) + kfree(requests[i].buffer); + kfree(requests); + return -EINVAL; /* always fail to load so it can be re-run quickly ;-) */ +} + +static void __exit ocfbench_exit(void) +{ +} + +module_init(ocfbench_init); +module_exit(ocfbench_exit); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_AUTHOR("David McCullough "); +MODULE_DESCRIPTION("Benchmark various in-kernel crypto speeds"); diff --git a/target/linux/generic/files/crypto/ocf/ocf-compat.h b/target/linux/generic/files/crypto/ocf/ocf-compat.h new file mode 100644 index 0000000..b38cf27 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/ocf-compat.h @@ -0,0 +1,380 @@ +#ifndef _BSD_COMPAT_H_ +#define _BSD_COMPAT_H_ 1 +/****************************************************************************/ +/* + * Provide compat routines for older linux kernels and BSD kernels + * + * Written by David McCullough + * Copyright (C) 2010 David McCullough + * + * LICENSE TERMS + * + * The free distribution and use of this software in both source and binary + * form is allowed (with or without changes) provided that: + * + * 1. distributions of this source code include the above copyright + * notice, this list of conditions and the following disclaimer; + * + * 2. distributions in binary form include the above copyright + * notice, this list of conditions and the following disclaimer + * in the documentation and/or other associated materials; + * + * 3. the copyright holder's name is not used to endorse products + * built using this software without specific written permission. + * + * ALTERNATIVELY, provided that this notice is retained in full, this file + * may be distributed under the terms of the GNU General Public License (GPL), + * in which case the provisions of the GPL apply INSTEAD OF those given above. + * + * DISCLAIMER + * + * This software is provided 'as is' with no explicit or implied warranties + * in respect of its properties, including, but not limited to, correctness + * and/or fitness for purpose. + */ +/****************************************************************************/ +#ifdef __KERNEL__ +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) && !defined(AUTOCONF_INCLUDED) +#include +#endif + +/* + * fake some BSD driver interface stuff specifically for OCF use + */ + +typedef struct ocf_device *device_t; + +typedef struct { + int (*cryptodev_newsession)(device_t dev, u_int32_t *sidp, struct cryptoini *cri); + int (*cryptodev_freesession)(device_t dev, u_int64_t tid); + int (*cryptodev_process)(device_t dev, struct cryptop *crp, int hint); + int (*cryptodev_kprocess)(device_t dev, struct cryptkop *krp, int hint); +} device_method_t; +#define DEVMETHOD(id, func) id: func + +struct ocf_device { + char name[32]; /* the driver name */ + char nameunit[32]; /* the driver name + HW instance */ + int unit; + device_method_t methods; + void *softc; +}; + +#define CRYPTODEV_NEWSESSION(dev, sid, cri) \ + ((*(dev)->methods.cryptodev_newsession)(dev,sid,cri)) +#define CRYPTODEV_FREESESSION(dev, sid) \ + ((*(dev)->methods.cryptodev_freesession)(dev, sid)) +#define CRYPTODEV_PROCESS(dev, crp, hint) \ + ((*(dev)->methods.cryptodev_process)(dev, crp, hint)) +#define CRYPTODEV_KPROCESS(dev, krp, hint) \ + ((*(dev)->methods.cryptodev_kprocess)(dev, krp, hint)) + +#define device_get_name(dev) ((dev)->name) +#define device_get_nameunit(dev) ((dev)->nameunit) +#define device_get_unit(dev) ((dev)->unit) +#define device_get_softc(dev) ((dev)->softc) + +#define softc_device_decl \ + struct ocf_device _device; \ + device_t + +#define softc_device_init(_sc, _name, _unit, _methods) \ + if (1) {\ + strncpy((_sc)->_device.name, _name, sizeof((_sc)->_device.name) - 1); \ + snprintf((_sc)->_device.nameunit, sizeof((_sc)->_device.name), "%s%d", _name, _unit); \ + (_sc)->_device.unit = _unit; \ + (_sc)->_device.methods = _methods; \ + (_sc)->_device.softc = (void *) _sc; \ + *(device_t *)((softc_get_device(_sc))+1) = &(_sc)->_device; \ + } else + +#define softc_get_device(_sc) (&(_sc)->_device) + +/* + * iomem support for 2.4 and 2.6 kernels + */ +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) +#define ocf_iomem_t unsigned long + +/* + * implement simple workqueue like support for older kernels + */ + +#include + +#define work_struct tq_struct + +#define INIT_WORK(wp, fp, ap) \ + do { \ + (wp)->sync = 0; \ + (wp)->routine = (fp); \ + (wp)->data = (ap); \ + } while (0) + +#define schedule_work(wp) \ + do { \ + queue_task((wp), &tq_immediate); \ + mark_bh(IMMEDIATE_BH); \ + } while (0) + +#define flush_scheduled_work() run_task_queue(&tq_immediate) + +#else +#define ocf_iomem_t void __iomem * + +#include + +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) +#include +#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11) +#define files_fdtable(files) (files) +#endif + +#ifdef MODULE_PARM +#undef module_param /* just in case */ +#define module_param(a,b,c) MODULE_PARM(a,"i") +#endif + +#define bzero(s,l) memset(s,0,l) +#define bcopy(s,d,l) memcpy(d,s,l) +#define bcmp(x, y, l) memcmp(x,y,l) + +#define MIN(x,y) ((x) < (y) ? (x) : (y)) + +#define device_printf(dev, a...) ({ \ + printk("%s: ", device_get_nameunit(dev)); printk(a); \ + }) + +#undef printf +#define printf(fmt...) printk(fmt) + +#define KASSERT(c,p) if (!(c)) { printk p ; } else + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) +#define ocf_daemonize(str) \ + daemonize(); \ + spin_lock_irq(¤t->sigmask_lock); \ + sigemptyset(¤t->blocked); \ + recalc_sigpending(current); \ + spin_unlock_irq(¤t->sigmask_lock); \ + sprintf(current->comm, str); \ +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,8,0) \ + spin_lock_irq(¤t->sigmask_lock); \ + sigemptyset(¤t->blocked); \ + recalc_sigpending(current); \ + spin_unlock_irq(¤t->sigmask_lock); \ + sprintf(current->comm, str); \ +#else +#define ocf_daemonize(str) daemonize(str); +#endif + +#define TAILQ_INSERT_TAIL(q,d,m) list_add_tail(&(d)->m, (q)) +#define TAILQ_EMPTY(q) list_empty(q) +#define TAILQ_FOREACH(v, q, m) list_for_each_entry(v, q, m) + +#define read_random(p,l) get_random_bytes(p,l) + +#define DELAY(x) ((x) > 2000 ? mdelay((x)/1000) : udelay(x)) +#define strtoul simple_strtoul + +#define pci_get_vendor(dev) ((dev)->vendor) +#define pci_get_device(dev) ((dev)->device) + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) +#define pci_set_consistent_dma_mask(dev, mask) (0) +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) +#define pci_dma_sync_single_for_cpu pci_dma_sync_single +#endif + +#ifndef DMA_32BIT_MASK +#define DMA_32BIT_MASK 0x00000000ffffffffULL +#endif + +#ifndef htole32 +#define htole32(x) cpu_to_le32(x) +#endif +#ifndef htobe32 +#define htobe32(x) cpu_to_be32(x) +#endif +#ifndef htole16 +#define htole16(x) cpu_to_le16(x) +#endif +#ifndef htobe16 +#define htobe16(x) cpu_to_be16(x) +#endif + +/* older kernels don't have these */ + +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30) +#if !defined(IRQ_NONE) && !defined(IRQ_RETVAL) +#define IRQ_NONE +#define IRQ_HANDLED +#define IRQ_WAKE_THREAD +#define IRQ_RETVAL +#define irqreturn_t void +typedef irqreturn_t (*irq_handler_t)(int irq, void *arg, struct pt_regs *regs); +#endif +#ifndef IRQF_SHARED +#define IRQF_SHARED SA_SHIRQ +#endif +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +# define strlcpy(dest,src,len) \ + ({strncpy(dest,src,(len)-1); ((char *)dest)[(len)-1] = '\0'; }) +#endif + +#ifndef MAX_ERRNO +#define MAX_ERRNO 4095 +#endif +#ifndef IS_ERR_VALUE +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,5) +#include +#endif +#ifndef IS_ERR_VALUE +#define IS_ERR_VALUE(x) ((unsigned long)(x) >= (unsigned long)-MAX_ERRNO) +#endif +#endif + +/* + * common debug for all + */ +#if 1 +#define dprintk(a...) do { if (debug) printk(a); } while(0) +#else +#define dprintk(a...) +#endif + +#ifndef SLAB_ATOMIC +/* Changed in 2.6.20, must use GFP_ATOMIC now */ +#define SLAB_ATOMIC GFP_ATOMIC +#endif + +/* + * need some additional support for older kernels */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,2) +#define pci_register_driver_compat(driver, rc) \ + do { \ + if ((rc) > 0) { \ + (rc) = 0; \ + } else if (rc == 0) { \ + (rc) = -ENODEV; \ + } else { \ + pci_unregister_driver(driver); \ + } \ + } while (0) +#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) +#define pci_register_driver_compat(driver,rc) ((rc) = (rc) < 0 ? (rc) : 0) +#else +#define pci_register_driver_compat(driver,rc) +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) + +#include +#include + +static inline void sg_set_page(struct scatterlist *sg, struct page *page, + unsigned int len, unsigned int offset) +{ + sg->page = page; + sg->offset = offset; + sg->length = len; +} + +static inline void *sg_virt(struct scatterlist *sg) +{ + return page_address(sg->page) + sg->offset; +} + +#define sg_init_table(sg, n) + +#define sg_mark_end(sg) + +#endif + +#ifndef late_initcall +#define late_initcall(init) module_init(init) +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,4) || !defined(CONFIG_SMP) +#define ocf_for_each_cpu(cpu) for ((cpu) = 0; (cpu) == 0; (cpu)++) +#else +#define ocf_for_each_cpu(cpu) for_each_present_cpu(cpu) +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) +#include +#define kill_proc(p,s,v) send_sig(s,find_task_by_vpid(p),0) +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,4) + +struct ocf_thread { + struct task_struct *task; + int (*func)(void *arg); + void *arg; +}; + +/* thread startup helper func */ +static inline int ocf_run_thread(void *arg) +{ + struct ocf_thread *t = (struct ocf_thread *) arg; + if (!t) + return -1; /* very bad */ + t->task = current; + daemonize(); + spin_lock_irq(¤t->sigmask_lock); + sigemptyset(¤t->blocked); + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + return (*t->func)(t->arg); +} + +#define kthread_create(f,a,fmt...) \ + ({ \ + struct ocf_thread t; \ + pid_t p; \ + t.task = NULL; \ + t.func = (f); \ + t.arg = (a); \ + p = kernel_thread(ocf_run_thread, &t, CLONE_FS|CLONE_FILES); \ + while (p != (pid_t) -1 && t.task == NULL) \ + schedule(); \ + if (t.task) \ + snprintf(t.task->comm, sizeof(t.task->comm), fmt); \ + (t.task); \ + }) + +#define kthread_bind(t,cpu) /**/ + +#define kthread_should_stop() (strcmp(current->comm, "stopping") == 0) + +#define kthread_stop(t) \ + ({ \ + strcpy((t)->comm, "stopping"); \ + kill_proc((t)->pid, SIGTERM, 1); \ + do { \ + schedule(); \ + } while (kill_proc((t)->pid, SIGTERM, 1) == 0); \ + }) + +#else +#include +#endif + + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,2,0) +#define skb_frag_page(x) ((x)->page) +#endif + +#endif /* __KERNEL__ */ + +/****************************************************************************/ +#endif /* _BSD_COMPAT_H_ */ diff --git a/target/linux/generic/files/crypto/ocf/ocfnull/Makefile b/target/linux/generic/files/crypto/ocf/ocfnull/Makefile new file mode 100644 index 0000000..044bcac --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/ocfnull/Makefile @@ -0,0 +1,12 @@ +# for SGlinux builds +-include $(ROOTDIR)/modules/.config + +obj-$(CONFIG_OCF_OCFNULL) += ocfnull.o + +obj ?= . +EXTRA_CFLAGS += -I$(obj)/.. + +ifdef TOPDIR +-include $(TOPDIR)/Rules.make +endif + diff --git a/target/linux/generic/files/crypto/ocf/ocfnull/ocfnull.c b/target/linux/generic/files/crypto/ocf/ocfnull/ocfnull.c new file mode 100644 index 0000000..9cf3f6e --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/ocfnull/ocfnull.c @@ -0,0 +1,204 @@ +/* + * An OCF module for determining the cost of crypto versus the cost of + * IPSec processing outside of OCF. This modules gives us the effect of + * zero cost encryption, of course you will need to run it at both ends + * since it does no crypto at all. + * + * Written by David McCullough + * Copyright (C) 2006-2010 David McCullough + * + * LICENSE TERMS + * + * The free distribution and use of this software in both source and binary + * form is allowed (with or without changes) provided that: + * + * 1. distributions of this source code include the above copyright + * notice, this list of conditions and the following disclaimer; + * + * 2. distributions in binary form include the above copyright + * notice, this list of conditions and the following disclaimer + * in the documentation and/or other associated materials; + * + * 3. the copyright holder's name is not used to endorse products + * built using this software without specific written permission. + * + * ALTERNATIVELY, provided that this notice is retained in full, this product + * may be distributed under the terms of the GNU General Public License (GPL), + * in which case the provisions of the GPL apply INSTEAD OF those given above. + * + * DISCLAIMER + * + * This software is provided 'as is' with no explicit or implied warranties + * in respect of its properties, including, but not limited to, correctness + * and/or fitness for purpose. + */ + +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) && !defined(AUTOCONF_INCLUDED) +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static int32_t null_id = -1; +static u_int32_t null_sesnum = 0; + +static int null_process(device_t, struct cryptop *, int); +static int null_newsession(device_t, u_int32_t *, struct cryptoini *); +static int null_freesession(device_t, u_int64_t); + +#define debug ocfnull_debug +int ocfnull_debug = 0; +module_param(ocfnull_debug, int, 0644); +MODULE_PARM_DESC(ocfnull_debug, "Enable debug"); + +/* + * dummy device structure + */ + +static struct { + softc_device_decl sc_dev; +} nulldev; + +static device_method_t null_methods = { + /* crypto device methods */ + DEVMETHOD(cryptodev_newsession, null_newsession), + DEVMETHOD(cryptodev_freesession,null_freesession), + DEVMETHOD(cryptodev_process, null_process), +}; + +/* + * Generate a new software session. + */ +static int +null_newsession(device_t arg, u_int32_t *sid, struct cryptoini *cri) +{ + dprintk("%s()\n", __FUNCTION__); + if (sid == NULL || cri == NULL) { + dprintk("%s,%d - EINVAL\n", __FILE__, __LINE__); + return EINVAL; + } + + if (null_sesnum == 0) + null_sesnum++; + *sid = null_sesnum++; + return 0; +} + + +/* + * Free a session. + */ +static int +null_freesession(device_t arg, u_int64_t tid) +{ + u_int32_t sid = CRYPTO_SESID2LID(tid); + + dprintk("%s()\n", __FUNCTION__); + if (sid > null_sesnum) { + dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__); + return EINVAL; + } + + /* Silently accept and return */ + if (sid == 0) + return 0; + return 0; +} + + +/* + * Process a request. + */ +static int +null_process(device_t arg, struct cryptop *crp, int hint) +{ + unsigned int lid; + + dprintk("%s()\n", __FUNCTION__); + + /* Sanity check */ + if (crp == NULL) { + dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__); + return EINVAL; + } + + crp->crp_etype = 0; + + if (crp->crp_desc == NULL || crp->crp_buf == NULL) { + dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__); + crp->crp_etype = EINVAL; + goto done; + } + + /* + * find the session we are using + */ + + lid = crp->crp_sid & 0xffffffff; + if (lid >= null_sesnum || lid == 0) { + crp->crp_etype = ENOENT; + dprintk("%s,%d: ENOENT\n", __FILE__, __LINE__); + goto done; + } + +done: + crypto_done(crp); + return 0; +} + + +/* + * our driver startup and shutdown routines + */ + +static int +null_init(void) +{ + dprintk("%s(%p)\n", __FUNCTION__, null_init); + + memset(&nulldev, 0, sizeof(nulldev)); + softc_device_init(&nulldev, "ocfnull", 0, null_methods); + + null_id = crypto_get_driverid(softc_get_device(&nulldev), + CRYPTOCAP_F_HARDWARE); + if (null_id < 0) + panic("ocfnull: crypto device cannot initialize!"); + +#define REGISTER(alg) \ + crypto_register(null_id,alg,0,0) + REGISTER(CRYPTO_DES_CBC); + REGISTER(CRYPTO_3DES_CBC); + REGISTER(CRYPTO_RIJNDAEL128_CBC); + REGISTER(CRYPTO_MD5); + REGISTER(CRYPTO_SHA1); + REGISTER(CRYPTO_MD5_HMAC); + REGISTER(CRYPTO_SHA1_HMAC); +#undef REGISTER + + return 0; +} + +static void +null_exit(void) +{ + dprintk("%s()\n", __FUNCTION__); + crypto_unregister_all(null_id); + null_id = -1; +} + +module_init(null_init); +module_exit(null_exit); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_AUTHOR("David McCullough "); +MODULE_DESCRIPTION("ocfnull - claims a lot but does nothing"); diff --git a/target/linux/generic/files/crypto/ocf/pasemi/Makefile b/target/linux/generic/files/crypto/ocf/pasemi/Makefile new file mode 100644 index 0000000..b0a3980 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/pasemi/Makefile @@ -0,0 +1,12 @@ +# for SGlinux builds +-include $(ROOTDIR)/modules/.config + +obj-$(CONFIG_OCF_PASEMI) += pasemi.o + +obj ?= . +EXTRA_CFLAGS += -I$(obj)/.. -I$(obj)/ + +ifdef TOPDIR +-include $(TOPDIR)/Rules.make +endif + diff --git a/target/linux/generic/files/crypto/ocf/pasemi/pasemi.c b/target/linux/generic/files/crypto/ocf/pasemi/pasemi.c new file mode 100644 index 0000000..216c578 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/pasemi/pasemi.c @@ -0,0 +1,1007 @@ +/* + * Copyright (C) 2007 PA Semi, Inc + * + * Driver for the PA Semi PWRficient DMA Crypto Engine + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) && !defined(AUTOCONF_INCLUDED) +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pasemi_fnu.h" + +#define DRV_NAME "pasemi" + +#define TIMER_INTERVAL 1000 + +static void pasemi_dma_remove(struct pci_dev *pdev); +static struct pasdma_status volatile * dma_status; + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Enable debug"); + +static void pasemi_desc_start(struct pasemi_desc *desc, u64 hdr) +{ + desc->postop = 0; + desc->quad[0] = hdr; + desc->quad_cnt = 1; + desc->size = 1; +} + +static void pasemi_desc_build(struct pasemi_desc *desc, u64 val) +{ + desc->quad[desc->quad_cnt++] = val; + desc->size = (desc->quad_cnt + 1) / 2; +} + +static void pasemi_desc_hdr(struct pasemi_desc *desc, u64 hdr) +{ + desc->quad[0] |= hdr; +} + +static int pasemi_desc_size(struct pasemi_desc *desc) +{ + return desc->size; +} + +static void pasemi_ring_add_desc( + struct pasemi_fnu_txring *ring, + struct pasemi_desc *desc, + struct cryptop *crp) { + int i; + int ring_index = 2 * (ring->next_to_fill & (TX_RING_SIZE-1)); + + TX_DESC_INFO(ring, ring->next_to_fill).desc_size = desc->size; + TX_DESC_INFO(ring, ring->next_to_fill).desc_postop = desc->postop; + TX_DESC_INFO(ring, ring->next_to_fill).cf_crp = crp; + + for (i = 0; i < desc->quad_cnt; i += 2) { + ring_index = 2 * (ring->next_to_fill & (TX_RING_SIZE-1)); + ring->desc[ring_index] = desc->quad[i]; + ring->desc[ring_index + 1] = desc->quad[i + 1]; + ring->next_to_fill++; + } + + if (desc->quad_cnt & 1) + ring->desc[ring_index + 1] = 0; +} + +static void pasemi_ring_incr(struct pasemi_softc *sc, int chan_index, int incr) +{ + out_le32(sc->dma_regs + PAS_DMA_TXCHAN_INCR(sc->base_chan + chan_index), + incr); +} + +/* + * Generate a new software session. + */ +static int +pasemi_newsession(device_t dev, u_int32_t *sidp, struct cryptoini *cri) +{ + struct cryptoini *c, *encini = NULL, *macini = NULL; + struct pasemi_softc *sc = device_get_softc(dev); + struct pasemi_session *ses = NULL, **sespp; + int sesn, blksz = 0; + u64 ccmd = 0; + unsigned long flags; + struct pasemi_desc init_desc; + struct pasemi_fnu_txring *txring; + + DPRINTF("%s()\n", __FUNCTION__); + if (sidp == NULL || cri == NULL || sc == NULL) { + DPRINTF("%s,%d - EINVAL\n", __FILE__, __LINE__); + return -EINVAL; + } + for (c = cri; c != NULL; c = c->cri_next) { + if (ALG_IS_SIG(c->cri_alg)) { + if (macini) + return -EINVAL; + macini = c; + } else if (ALG_IS_CIPHER(c->cri_alg)) { + if (encini) + return -EINVAL; + encini = c; + } else { + DPRINTF("UNKNOWN c->cri_alg %d\n", c->cri_alg); + return -EINVAL; + } + } + if (encini == NULL && macini == NULL) + return -EINVAL; + if (encini) { + /* validate key length */ + switch (encini->cri_alg) { + case CRYPTO_DES_CBC: + if (encini->cri_klen != 64) + return -EINVAL; + ccmd = DMA_CALGO_DES; + break; + case CRYPTO_3DES_CBC: + if (encini->cri_klen != 192) + return -EINVAL; + ccmd = DMA_CALGO_3DES; + break; + case CRYPTO_AES_CBC: + if (encini->cri_klen != 128 && + encini->cri_klen != 192 && + encini->cri_klen != 256) + return -EINVAL; + ccmd = DMA_CALGO_AES; + break; + case CRYPTO_ARC4: + if (encini->cri_klen != 128) + return -EINVAL; + ccmd = DMA_CALGO_ARC; + break; + default: + DPRINTF("UNKNOWN encini->cri_alg %d\n", + encini->cri_alg); + return -EINVAL; + } + } + + if (macini) { + switch (macini->cri_alg) { + case CRYPTO_MD5: + case CRYPTO_MD5_HMAC: + blksz = 16; + break; + case CRYPTO_SHA1: + case CRYPTO_SHA1_HMAC: + blksz = 20; + break; + default: + DPRINTF("UNKNOWN macini->cri_alg %d\n", + macini->cri_alg); + return -EINVAL; + } + if (((macini->cri_klen + 7) / 8) > blksz) { + DPRINTF("key length %d bigger than blksize %d not supported\n", + ((macini->cri_klen + 7) / 8), blksz); + return -EINVAL; + } + } + + for (sesn = 0; sesn < sc->sc_nsessions; sesn++) { + if (sc->sc_sessions[sesn] == NULL) { + sc->sc_sessions[sesn] = (struct pasemi_session *) + kzalloc(sizeof(struct pasemi_session), GFP_ATOMIC); + ses = sc->sc_sessions[sesn]; + break; + } else if (sc->sc_sessions[sesn]->used == 0) { + ses = sc->sc_sessions[sesn]; + break; + } + } + + if (ses == NULL) { + sespp = (struct pasemi_session **) + kzalloc(sc->sc_nsessions * 2 * + sizeof(struct pasemi_session *), GFP_ATOMIC); + if (sespp == NULL) + return -ENOMEM; + memcpy(sespp, sc->sc_sessions, + sc->sc_nsessions * sizeof(struct pasemi_session *)); + kfree(sc->sc_sessions); + sc->sc_sessions = sespp; + sesn = sc->sc_nsessions; + ses = sc->sc_sessions[sesn] = (struct pasemi_session *) + kzalloc(sizeof(struct pasemi_session), GFP_ATOMIC); + if (ses == NULL) + return -ENOMEM; + sc->sc_nsessions *= 2; + } + + ses->used = 1; + + ses->dma_addr = pci_map_single(sc->dma_pdev, (void *) ses->civ, + sizeof(struct pasemi_session), DMA_TO_DEVICE); + + /* enter the channel scheduler */ + spin_lock_irqsave(&sc->sc_chnlock, flags); + + /* ARC4 has to be processed by the even channel */ + if (encini && (encini->cri_alg == CRYPTO_ARC4)) + ses->chan = sc->sc_lastchn & ~1; + else + ses->chan = sc->sc_lastchn; + sc->sc_lastchn = (sc->sc_lastchn + 1) % sc->sc_num_channels; + + spin_unlock_irqrestore(&sc->sc_chnlock, flags); + + txring = &sc->tx[ses->chan]; + + if (encini) { + ses->ccmd = ccmd; + ses->keysz = (encini->cri_klen - 63) / 64; + memcpy(ses->key, encini->cri_key, (ses->keysz + 1) * 8); + + pasemi_desc_start(&init_desc, + XCT_CTRL_HDR(ses->chan, (encini && macini) ? 0x68 : 0x40, DMA_FN_CIV0)); + pasemi_desc_build(&init_desc, + XCT_FUN_SRC_PTR((encini && macini) ? 0x68 : 0x40, ses->dma_addr)); + } + if (macini) { + if (macini->cri_alg == CRYPTO_MD5_HMAC || + macini->cri_alg == CRYPTO_SHA1_HMAC) + memcpy(ses->hkey, macini->cri_key, blksz); + else { + /* Load initialization constants(RFC 1321, 3174) */ + ses->hiv[0] = 0x67452301efcdab89ULL; + ses->hiv[1] = 0x98badcfe10325476ULL; + ses->hiv[2] = 0xc3d2e1f000000000ULL; + } + ses->hseq = 0ULL; + } + + spin_lock_irqsave(&txring->fill_lock, flags); + + if (((txring->next_to_fill + pasemi_desc_size(&init_desc)) - + txring->next_to_clean) > TX_RING_SIZE) { + spin_unlock_irqrestore(&txring->fill_lock, flags); + return ERESTART; + } + + if (encini) { + pasemi_ring_add_desc(txring, &init_desc, NULL); + pasemi_ring_incr(sc, ses->chan, + pasemi_desc_size(&init_desc)); + } + + txring->sesn = sesn; + spin_unlock_irqrestore(&txring->fill_lock, flags); + + *sidp = PASEMI_SID(sesn); + return 0; +} + +/* + * Deallocate a session. + */ +static int +pasemi_freesession(device_t dev, u_int64_t tid) +{ + struct pasemi_softc *sc = device_get_softc(dev); + int session; + u_int32_t sid = ((u_int32_t) tid) & 0xffffffff; + + DPRINTF("%s()\n", __FUNCTION__); + + if (sc == NULL) + return -EINVAL; + session = PASEMI_SESSION(sid); + if (session >= sc->sc_nsessions || !sc->sc_sessions[session]) + return -EINVAL; + + pci_unmap_single(sc->dma_pdev, + sc->sc_sessions[session]->dma_addr, + sizeof(struct pasemi_session), DMA_TO_DEVICE); + memset(sc->sc_sessions[session], 0, + sizeof(struct pasemi_session)); + + return 0; +} + +static int +pasemi_process(device_t dev, struct cryptop *crp, int hint) +{ + + int err = 0, ivsize, srclen = 0, reinit = 0, reinit_size = 0, chsel; + struct pasemi_softc *sc = device_get_softc(dev); + struct cryptodesc *crd1, *crd2, *maccrd, *enccrd; + caddr_t ivp; + struct pasemi_desc init_desc, work_desc; + struct pasemi_session *ses; + struct sk_buff *skb; + struct uio *uiop; + unsigned long flags; + struct pasemi_fnu_txring *txring; + + DPRINTF("%s()\n", __FUNCTION__); + + if (crp == NULL || crp->crp_callback == NULL || sc == NULL) + return -EINVAL; + + crp->crp_etype = 0; + if (PASEMI_SESSION(crp->crp_sid) >= sc->sc_nsessions) + return -EINVAL; + + ses = sc->sc_sessions[PASEMI_SESSION(crp->crp_sid)]; + + crd1 = crp->crp_desc; + if (crd1 == NULL) { + err = -EINVAL; + goto errout; + } + crd2 = crd1->crd_next; + + if (ALG_IS_SIG(crd1->crd_alg)) { + maccrd = crd1; + if (crd2 == NULL) + enccrd = NULL; + else if (ALG_IS_CIPHER(crd2->crd_alg) && + (crd2->crd_flags & CRD_F_ENCRYPT) == 0) + enccrd = crd2; + else + goto erralg; + } else if (ALG_IS_CIPHER(crd1->crd_alg)) { + enccrd = crd1; + if (crd2 == NULL) + maccrd = NULL; + else if (ALG_IS_SIG(crd2->crd_alg) && + (crd1->crd_flags & CRD_F_ENCRYPT)) + maccrd = crd2; + else + goto erralg; + } else + goto erralg; + + chsel = ses->chan; + + txring = &sc->tx[chsel]; + + if (enccrd && !maccrd) { + if (enccrd->crd_alg == CRYPTO_ARC4) + reinit = 1; + reinit_size = 0x40; + srclen = crp->crp_ilen; + + pasemi_desc_start(&work_desc, XCT_FUN_O | XCT_FUN_I + | XCT_FUN_FUN(chsel)); + if (enccrd->crd_flags & CRD_F_ENCRYPT) + pasemi_desc_hdr(&work_desc, XCT_FUN_CRM_ENC); + else + pasemi_desc_hdr(&work_desc, XCT_FUN_CRM_DEC); + } else if (enccrd && maccrd) { + if (enccrd->crd_alg == CRYPTO_ARC4) + reinit = 1; + reinit_size = 0x68; + + if (enccrd->crd_flags & CRD_F_ENCRYPT) { + /* Encrypt -> Authenticate */ + pasemi_desc_start(&work_desc, XCT_FUN_O | XCT_FUN_I | XCT_FUN_CRM_ENC_SIG + | XCT_FUN_A | XCT_FUN_FUN(chsel)); + srclen = maccrd->crd_skip + maccrd->crd_len; + } else { + /* Authenticate -> Decrypt */ + pasemi_desc_start(&work_desc, XCT_FUN_O | XCT_FUN_I | XCT_FUN_CRM_SIG_DEC + | XCT_FUN_24BRES | XCT_FUN_FUN(chsel)); + pasemi_desc_build(&work_desc, 0); + pasemi_desc_build(&work_desc, 0); + pasemi_desc_build(&work_desc, 0); + work_desc.postop = PASEMI_CHECK_SIG; + srclen = crp->crp_ilen; + } + + pasemi_desc_hdr(&work_desc, XCT_FUN_SHL(maccrd->crd_skip / 4)); + pasemi_desc_hdr(&work_desc, XCT_FUN_CHL(enccrd->crd_skip - maccrd->crd_skip)); + } else if (!enccrd && maccrd) { + srclen = maccrd->crd_len; + + pasemi_desc_start(&init_desc, + XCT_CTRL_HDR(chsel, 0x58, DMA_FN_HKEY0)); + pasemi_desc_build(&init_desc, + XCT_FUN_SRC_PTR(0x58, ((struct pasemi_session *)ses->dma_addr)->hkey)); + + pasemi_desc_start(&work_desc, XCT_FUN_O | XCT_FUN_I | XCT_FUN_CRM_SIG + | XCT_FUN_A | XCT_FUN_FUN(chsel)); + } + + if (enccrd) { + switch (enccrd->crd_alg) { + case CRYPTO_3DES_CBC: + pasemi_desc_hdr(&work_desc, XCT_FUN_ALG_3DES | + XCT_FUN_BCM_CBC); + ivsize = sizeof(u64); + break; + case CRYPTO_DES_CBC: + pasemi_desc_hdr(&work_desc, XCT_FUN_ALG_DES | + XCT_FUN_BCM_CBC); + ivsize = sizeof(u64); + break; + case CRYPTO_AES_CBC: + pasemi_desc_hdr(&work_desc, XCT_FUN_ALG_AES | + XCT_FUN_BCM_CBC); + ivsize = 2 * sizeof(u64); + break; + case CRYPTO_ARC4: + pasemi_desc_hdr(&work_desc, XCT_FUN_ALG_ARC); + ivsize = 0; + break; + default: + printk(DRV_NAME ": unimplemented enccrd->crd_alg %d\n", + enccrd->crd_alg); + err = -EINVAL; + goto errout; + } + + ivp = (ivsize == sizeof(u64)) ? (caddr_t) &ses->civ[1] : (caddr_t) &ses->civ[0]; + if (enccrd->crd_flags & CRD_F_ENCRYPT) { + if (enccrd->crd_flags & CRD_F_IV_EXPLICIT) + memcpy(ivp, enccrd->crd_iv, ivsize); + else + read_random(ivp, ivsize); + /* If IV is not present in the buffer already, it has to be copied there */ + if ((enccrd->crd_flags & CRD_F_IV_PRESENT) == 0) + crypto_copyback(crp->crp_flags, crp->crp_buf, + enccrd->crd_inject, ivsize, ivp); + } else { + if (enccrd->crd_flags & CRD_F_IV_EXPLICIT) + /* IV is provided expicitly in descriptor */ + memcpy(ivp, enccrd->crd_iv, ivsize); + else + /* IV is provided in the packet */ + crypto_copydata(crp->crp_flags, crp->crp_buf, + enccrd->crd_inject, ivsize, + ivp); + } + } + + if (maccrd) { + switch (maccrd->crd_alg) { + case CRYPTO_MD5: + pasemi_desc_hdr(&work_desc, XCT_FUN_SIG_MD5 | + XCT_FUN_HSZ((crp->crp_ilen - maccrd->crd_inject) / 4)); + break; + case CRYPTO_SHA1: + pasemi_desc_hdr(&work_desc, XCT_FUN_SIG_SHA1 | + XCT_FUN_HSZ((crp->crp_ilen - maccrd->crd_inject) / 4)); + break; + case CRYPTO_MD5_HMAC: + pasemi_desc_hdr(&work_desc, XCT_FUN_SIG_HMAC_MD5 | + XCT_FUN_HSZ((crp->crp_ilen - maccrd->crd_inject) / 4)); + break; + case CRYPTO_SHA1_HMAC: + pasemi_desc_hdr(&work_desc, XCT_FUN_SIG_HMAC_SHA1 | + XCT_FUN_HSZ((crp->crp_ilen - maccrd->crd_inject) / 4)); + break; + default: + printk(DRV_NAME ": unimplemented maccrd->crd_alg %d\n", + maccrd->crd_alg); + err = -EINVAL; + goto errout; + } + } + + if (crp->crp_flags & CRYPTO_F_SKBUF) { + /* using SKB buffers */ + skb = (struct sk_buff *)crp->crp_buf; + if (skb_shinfo(skb)->nr_frags) { + printk(DRV_NAME ": skb frags unimplemented\n"); + err = -EINVAL; + goto errout; + } + pasemi_desc_build( + &work_desc, + XCT_FUN_DST_PTR(skb->len, pci_map_single( + sc->dma_pdev, skb->data, + skb->len, DMA_TO_DEVICE))); + pasemi_desc_build( + &work_desc, + XCT_FUN_SRC_PTR( + srclen, pci_map_single( + sc->dma_pdev, skb->data, + srclen, DMA_TO_DEVICE))); + pasemi_desc_hdr(&work_desc, XCT_FUN_LLEN(srclen)); + } else if (crp->crp_flags & CRYPTO_F_IOV) { + /* using IOV buffers */ + uiop = (struct uio *)crp->crp_buf; + if (uiop->uio_iovcnt > 1) { + printk(DRV_NAME ": iov frags unimplemented\n"); + err = -EINVAL; + goto errout; + } + + /* crp_olen is never set; always use crp_ilen */ + pasemi_desc_build( + &work_desc, + XCT_FUN_DST_PTR(crp->crp_ilen, pci_map_single( + sc->dma_pdev, + uiop->uio_iov->iov_base, + crp->crp_ilen, DMA_TO_DEVICE))); + pasemi_desc_hdr(&work_desc, XCT_FUN_LLEN(srclen)); + + pasemi_desc_build( + &work_desc, + XCT_FUN_SRC_PTR(srclen, pci_map_single( + sc->dma_pdev, + uiop->uio_iov->iov_base, + srclen, DMA_TO_DEVICE))); + } else { + /* using contig buffers */ + pasemi_desc_build( + &work_desc, + XCT_FUN_DST_PTR(crp->crp_ilen, pci_map_single( + sc->dma_pdev, + crp->crp_buf, + crp->crp_ilen, DMA_TO_DEVICE))); + pasemi_desc_build( + &work_desc, + XCT_FUN_SRC_PTR(srclen, pci_map_single( + sc->dma_pdev, + crp->crp_buf, srclen, + DMA_TO_DEVICE))); + pasemi_desc_hdr(&work_desc, XCT_FUN_LLEN(srclen)); + } + + spin_lock_irqsave(&txring->fill_lock, flags); + + if (txring->sesn != PASEMI_SESSION(crp->crp_sid)) { + txring->sesn = PASEMI_SESSION(crp->crp_sid); + reinit = 1; + } + + if (enccrd) { + pasemi_desc_start(&init_desc, + XCT_CTRL_HDR(chsel, reinit ? reinit_size : 0x10, DMA_FN_CIV0)); + pasemi_desc_build(&init_desc, + XCT_FUN_SRC_PTR(reinit ? reinit_size : 0x10, ses->dma_addr)); + } + + if (((txring->next_to_fill + pasemi_desc_size(&init_desc) + + pasemi_desc_size(&work_desc)) - + txring->next_to_clean) > TX_RING_SIZE) { + spin_unlock_irqrestore(&txring->fill_lock, flags); + err = ERESTART; + goto errout; + } + + pasemi_ring_add_desc(txring, &init_desc, NULL); + pasemi_ring_add_desc(txring, &work_desc, crp); + + pasemi_ring_incr(sc, chsel, + pasemi_desc_size(&init_desc) + + pasemi_desc_size(&work_desc)); + + spin_unlock_irqrestore(&txring->fill_lock, flags); + + mod_timer(&txring->crypto_timer, jiffies + TIMER_INTERVAL); + + return 0; + +erralg: + printk(DRV_NAME ": unsupported algorithm or algorithm order alg1 %d alg2 %d\n", + crd1->crd_alg, crd2->crd_alg); + err = -EINVAL; + +errout: + if (err != ERESTART) { + crp->crp_etype = err; + crypto_done(crp); + } + return err; +} + +static int pasemi_clean_tx(struct pasemi_softc *sc, int chan) +{ + int i, j, ring_idx; + struct pasemi_fnu_txring *ring = &sc->tx[chan]; + u16 delta_cnt; + int flags, loops = 10; + int desc_size; + struct cryptop *crp; + + spin_lock_irqsave(&ring->clean_lock, flags); + + while ((delta_cnt = (dma_status->tx_sta[sc->base_chan + chan] + & PAS_STATUS_PCNT_M) - ring->total_pktcnt) + && loops--) { + + for (i = 0; i < delta_cnt; i++) { + desc_size = TX_DESC_INFO(ring, ring->next_to_clean).desc_size; + crp = TX_DESC_INFO(ring, ring->next_to_clean).cf_crp; + if (crp) { + ring_idx = 2 * (ring->next_to_clean & (TX_RING_SIZE-1)); + if (TX_DESC_INFO(ring, ring->next_to_clean).desc_postop & PASEMI_CHECK_SIG) { + /* Need to make sure signature matched, + * if not - return error */ + if (!(ring->desc[ring_idx + 1] & (1ULL << 63))) + crp->crp_etype = -EINVAL; + } + crypto_done(TX_DESC_INFO(ring, + ring->next_to_clean).cf_crp); + TX_DESC_INFO(ring, ring->next_to_clean).cf_crp = NULL; + pci_unmap_single( + sc->dma_pdev, + XCT_PTR_ADDR_LEN(ring->desc[ring_idx + 1]), + PCI_DMA_TODEVICE); + + ring->desc[ring_idx] = ring->desc[ring_idx + 1] = 0; + + ring->next_to_clean++; + for (j = 1; j < desc_size; j++) { + ring_idx = 2 * + (ring->next_to_clean & + (TX_RING_SIZE-1)); + pci_unmap_single( + sc->dma_pdev, + XCT_PTR_ADDR_LEN(ring->desc[ring_idx]), + PCI_DMA_TODEVICE); + if (ring->desc[ring_idx + 1]) + pci_unmap_single( + sc->dma_pdev, + XCT_PTR_ADDR_LEN( + ring->desc[ + ring_idx + 1]), + PCI_DMA_TODEVICE); + ring->desc[ring_idx] = + ring->desc[ring_idx + 1] = 0; + ring->next_to_clean++; + } + } else { + for (j = 0; j < desc_size; j++) { + ring_idx = 2 * (ring->next_to_clean & (TX_RING_SIZE-1)); + ring->desc[ring_idx] = + ring->desc[ring_idx + 1] = 0; + ring->next_to_clean++; + } + } + } + + ring->total_pktcnt += delta_cnt; + } + spin_unlock_irqrestore(&ring->clean_lock, flags); + + return 0; +} + +static void sweepup_tx(struct pasemi_softc *sc) +{ + int i; + + for (i = 0; i < sc->sc_num_channels; i++) + pasemi_clean_tx(sc, i); +} + +static irqreturn_t pasemi_intr(int irq, void *arg, struct pt_regs *regs) +{ + struct pasemi_softc *sc = arg; + unsigned int reg; + int chan = irq - sc->base_irq; + int chan_index = sc->base_chan + chan; + u64 stat = dma_status->tx_sta[chan_index]; + + DPRINTF("%s()\n", __FUNCTION__); + + if (!(stat & PAS_STATUS_CAUSE_M)) + return IRQ_NONE; + + pasemi_clean_tx(sc, chan); + + stat = dma_status->tx_sta[chan_index]; + + reg = PAS_IOB_DMA_TXCH_RESET_PINTC | + PAS_IOB_DMA_TXCH_RESET_PCNT(sc->tx[chan].total_pktcnt); + + if (stat & PAS_STATUS_SOFT) + reg |= PAS_IOB_DMA_RXCH_RESET_SINTC; + + out_le32(sc->iob_regs + PAS_IOB_DMA_TXCH_RESET(chan_index), reg); + + + return IRQ_HANDLED; +} + +static int pasemi_dma_setup_tx_resources(struct pasemi_softc *sc, int chan) +{ + u32 val; + int chan_index = chan + sc->base_chan; + int ret; + struct pasemi_fnu_txring *ring; + + ring = &sc->tx[chan]; + + spin_lock_init(&ring->fill_lock); + spin_lock_init(&ring->clean_lock); + + ring->desc_info = kzalloc(sizeof(struct pasemi_desc_info) * + TX_RING_SIZE, GFP_KERNEL); + if (!ring->desc_info) + return -ENOMEM; + + /* Allocate descriptors */ + ring->desc = dma_alloc_coherent(&sc->dma_pdev->dev, + TX_RING_SIZE * + 2 * sizeof(u64), + &ring->dma, GFP_KERNEL); + if (!ring->desc) + return -ENOMEM; + + memset((void *) ring->desc, 0, TX_RING_SIZE * 2 * sizeof(u64)); + + out_le32(sc->iob_regs + PAS_IOB_DMA_TXCH_RESET(chan_index), 0x30); + + ring->total_pktcnt = 0; + + out_le32(sc->dma_regs + PAS_DMA_TXCHAN_BASEL(chan_index), + PAS_DMA_TXCHAN_BASEL_BRBL(ring->dma)); + + val = PAS_DMA_TXCHAN_BASEU_BRBH(ring->dma >> 32); + val |= PAS_DMA_TXCHAN_BASEU_SIZ(TX_RING_SIZE >> 2); + + out_le32(sc->dma_regs + PAS_DMA_TXCHAN_BASEU(chan_index), val); + + out_le32(sc->dma_regs + PAS_DMA_TXCHAN_CFG(chan_index), + PAS_DMA_TXCHAN_CFG_TY_FUNC | + PAS_DMA_TXCHAN_CFG_TATTR(chan) | + PAS_DMA_TXCHAN_CFG_WT(2)); + + /* enable tx channel */ + out_le32(sc->dma_regs + + PAS_DMA_TXCHAN_TCMDSTA(chan_index), + PAS_DMA_TXCHAN_TCMDSTA_EN); + + out_le32(sc->iob_regs + PAS_IOB_DMA_TXCH_CFG(chan_index), + PAS_IOB_DMA_TXCH_CFG_CNTTH(1000)); + + ring->next_to_fill = 0; + ring->next_to_clean = 0; + + snprintf(ring->irq_name, sizeof(ring->irq_name), + "%s%d", "crypto", chan); + + ring->irq = irq_create_mapping(NULL, sc->base_irq + chan); + ret = request_irq(ring->irq, (irq_handler_t) + pasemi_intr, 0, ring->irq_name, sc); + if (ret) { + printk(KERN_ERR DRV_NAME ": failed to hook irq %d ret %d\n", + ring->irq, ret); + ring->irq = -1; + return ret; + } + + setup_timer(&ring->crypto_timer, (void *) sweepup_tx, (unsigned long) sc); + + return 0; +} + +static device_method_t pasemi_methods = { + /* crypto device methods */ + DEVMETHOD(cryptodev_newsession, pasemi_newsession), + DEVMETHOD(cryptodev_freesession, pasemi_freesession), + DEVMETHOD(cryptodev_process, pasemi_process), +}; + +/* Set up the crypto device structure, private data, + * and anything else we need before we start */ + +static int +pasemi_dma_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + struct pasemi_softc *sc; + int ret, i; + + DPRINTF(KERN_ERR "%s()\n", __FUNCTION__); + + sc = kzalloc(sizeof(*sc), GFP_KERNEL); + if (!sc) + return -ENOMEM; + + softc_device_init(sc, DRV_NAME, 1, pasemi_methods); + + pci_set_drvdata(pdev, sc); + + spin_lock_init(&sc->sc_chnlock); + + sc->sc_sessions = (struct pasemi_session **) + kzalloc(PASEMI_INITIAL_SESSIONS * + sizeof(struct pasemi_session *), GFP_ATOMIC); + if (sc->sc_sessions == NULL) { + ret = -ENOMEM; + goto out; + } + + sc->sc_nsessions = PASEMI_INITIAL_SESSIONS; + sc->sc_lastchn = 0; + sc->base_irq = pdev->irq + 6; + sc->base_chan = 6; + sc->sc_cid = -1; + sc->dma_pdev = pdev; + + sc->iob_pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa001, NULL); + if (!sc->iob_pdev) { + dev_err(&pdev->dev, "Can't find I/O Bridge\n"); + ret = -ENODEV; + goto out; + } + + /* This is hardcoded and ugly, but we have some firmware versions + * who don't provide the register space in the device tree. Luckily + * they are at well-known locations so we can just do the math here. + */ + sc->dma_regs = + ioremap(0xe0000000 + (sc->dma_pdev->devfn << 12), 0x2000); + sc->iob_regs = + ioremap(0xe0000000 + (sc->iob_pdev->devfn << 12), 0x2000); + if (!sc->dma_regs || !sc->iob_regs) { + dev_err(&pdev->dev, "Can't map registers\n"); + ret = -ENODEV; + goto out; + } + + dma_status = __ioremap(0xfd800000, 0x1000, 0); + if (!dma_status) { + ret = -ENODEV; + dev_err(&pdev->dev, "Can't map dmastatus space\n"); + goto out; + } + + sc->tx = (struct pasemi_fnu_txring *) + kzalloc(sizeof(struct pasemi_fnu_txring) + * 8, GFP_KERNEL); + if (!sc->tx) { + ret = -ENOMEM; + goto out; + } + + /* Initialize the h/w */ + out_le32(sc->dma_regs + PAS_DMA_COM_CFG, + (in_le32(sc->dma_regs + PAS_DMA_COM_CFG) | + PAS_DMA_COM_CFG_FWF)); + out_le32(sc->dma_regs + PAS_DMA_COM_TXCMD, PAS_DMA_COM_TXCMD_EN); + + for (i = 0; i < PASEMI_FNU_CHANNELS; i++) { + sc->sc_num_channels++; + ret = pasemi_dma_setup_tx_resources(sc, i); + if (ret) + goto out; + } + + sc->sc_cid = crypto_get_driverid(softc_get_device(sc), + CRYPTOCAP_F_HARDWARE); + if (sc->sc_cid < 0) { + printk(KERN_ERR DRV_NAME ": could not get crypto driver id\n"); + ret = -ENXIO; + goto out; + } + + /* register algorithms with the framework */ + printk(DRV_NAME ":"); + + crypto_register(sc->sc_cid, CRYPTO_DES_CBC, 0, 0); + crypto_register(sc->sc_cid, CRYPTO_3DES_CBC, 0, 0); + crypto_register(sc->sc_cid, CRYPTO_AES_CBC, 0, 0); + crypto_register(sc->sc_cid, CRYPTO_ARC4, 0, 0); + crypto_register(sc->sc_cid, CRYPTO_SHA1, 0, 0); + crypto_register(sc->sc_cid, CRYPTO_MD5, 0, 0); + crypto_register(sc->sc_cid, CRYPTO_SHA1_HMAC, 0, 0); + crypto_register(sc->sc_cid, CRYPTO_MD5_HMAC, 0, 0); + + return 0; + +out: + pasemi_dma_remove(pdev); + return ret; +} + +#define MAX_RETRIES 5000 + +static void pasemi_free_tx_resources(struct pasemi_softc *sc, int chan) +{ + struct pasemi_fnu_txring *ring = &sc->tx[chan]; + int chan_index = chan + sc->base_chan; + int retries; + u32 stat; + + /* Stop the channel */ + out_le32(sc->dma_regs + + PAS_DMA_TXCHAN_TCMDSTA(chan_index), + PAS_DMA_TXCHAN_TCMDSTA_ST); + + for (retries = 0; retries < MAX_RETRIES; retries++) { + stat = in_le32(sc->dma_regs + + PAS_DMA_TXCHAN_TCMDSTA(chan_index)); + if (!(stat & PAS_DMA_TXCHAN_TCMDSTA_ACT)) + break; + cond_resched(); + } + + if (stat & PAS_DMA_TXCHAN_TCMDSTA_ACT) + dev_err(&sc->dma_pdev->dev, "Failed to stop tx channel %d\n", + chan_index); + + /* Disable the channel */ + out_le32(sc->dma_regs + + PAS_DMA_TXCHAN_TCMDSTA(chan_index), + 0); + + if (ring->desc_info) + kfree((void *) ring->desc_info); + if (ring->desc) + dma_free_coherent(&sc->dma_pdev->dev, + TX_RING_SIZE * + 2 * sizeof(u64), + (void *) ring->desc, ring->dma); + if (ring->irq != -1) + free_irq(ring->irq, sc); + + del_timer(&ring->crypto_timer); +} + +static void pasemi_dma_remove(struct pci_dev *pdev) +{ + struct pasemi_softc *sc = pci_get_drvdata(pdev); + int i; + + DPRINTF("%s()\n", __FUNCTION__); + + if (sc->sc_cid >= 0) { + crypto_unregister_all(sc->sc_cid); + } + + if (sc->tx) { + for (i = 0; i < sc->sc_num_channels; i++) + pasemi_free_tx_resources(sc, i); + + kfree(sc->tx); + } + if (sc->sc_sessions) { + for (i = 0; i < sc->sc_nsessions; i++) + kfree(sc->sc_sessions[i]); + kfree(sc->sc_sessions); + } + if (sc->iob_pdev) + pci_dev_put(sc->iob_pdev); + if (sc->dma_regs) + iounmap(sc->dma_regs); + if (sc->iob_regs) + iounmap(sc->iob_regs); + kfree(sc); +} + +static struct pci_device_id pasemi_dma_pci_tbl[] = { + { PCI_DEVICE(PCI_VENDOR_ID_PASEMI, 0xa007) }, +}; + +MODULE_DEVICE_TABLE(pci, pasemi_dma_pci_tbl); + +static struct pci_driver pasemi_dma_driver = { + .name = "pasemi_dma", + .id_table = pasemi_dma_pci_tbl, + .probe = pasemi_dma_probe, + .remove = pasemi_dma_remove, +}; + +static void __exit pasemi_dma_cleanup_module(void) +{ + pci_unregister_driver(&pasemi_dma_driver); + __iounmap(dma_status); + dma_status = NULL; +} + +int pasemi_dma_init_module(void) +{ + return pci_register_driver(&pasemi_dma_driver); +} + +module_init(pasemi_dma_init_module); +module_exit(pasemi_dma_cleanup_module); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_AUTHOR("Egor Martovetsky egor@pasemi.com"); +MODULE_DESCRIPTION("OCF driver for PA Semi PWRficient DMA Crypto Engine"); diff --git a/target/linux/generic/files/crypto/ocf/pasemi/pasemi_fnu.h b/target/linux/generic/files/crypto/ocf/pasemi/pasemi_fnu.h new file mode 100644 index 0000000..1a0dcc8 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/pasemi/pasemi_fnu.h @@ -0,0 +1,410 @@ +/* + * Copyright (C) 2007 PA Semi, Inc + * + * Driver for the PA Semi PWRficient DMA Crypto Engine, soft state and + * hardware register layouts. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef PASEMI_FNU_H +#define PASEMI_FNU_H + +#include + +#define PASEMI_SESSION(sid) ((sid) & 0xffffffff) +#define PASEMI_SID(sesn) ((sesn) & 0xffffffff) +#define DPRINTF(a...) if (debug) { printk(DRV_NAME ": " a); } + +/* Must be a power of two */ +#define RX_RING_SIZE 512 +#define TX_RING_SIZE 512 +#define TX_DESC(ring, num) ((ring)->desc[2 * (num & (TX_RING_SIZE-1))]) +#define TX_DESC_INFO(ring, num) ((ring)->desc_info[(num) & (TX_RING_SIZE-1)]) +#define MAX_DESC_SIZE 8 +#define PASEMI_INITIAL_SESSIONS 10 +#define PASEMI_FNU_CHANNELS 8 + +/* DMA descriptor */ +struct pasemi_desc { + u64 quad[2*MAX_DESC_SIZE]; + int quad_cnt; + int size; + int postop; +}; + +/* + * Holds per descriptor data + */ +struct pasemi_desc_info { + int desc_size; + int desc_postop; +#define PASEMI_CHECK_SIG 0x1 + + struct cryptop *cf_crp; +}; + +/* + * Holds per channel data + */ +struct pasemi_fnu_txring { + volatile u64 *desc; + volatile struct + pasemi_desc_info *desc_info; + dma_addr_t dma; + struct timer_list crypto_timer; + spinlock_t fill_lock; + spinlock_t clean_lock; + unsigned int next_to_fill; + unsigned int next_to_clean; + u16 total_pktcnt; + int irq; + int sesn; + char irq_name[10]; +}; + +/* + * Holds data specific to a single pasemi device. + */ +struct pasemi_softc { + softc_device_decl sc_cdev; + struct pci_dev *dma_pdev; /* device backpointer */ + struct pci_dev *iob_pdev; /* device backpointer */ + void __iomem *dma_regs; + void __iomem *iob_regs; + int base_irq; + int base_chan; + int32_t sc_cid; /* crypto tag */ + int sc_nsessions; + struct pasemi_session **sc_sessions; + int sc_num_channels;/* number of crypto channels */ + + /* pointer to the array of txring datastructures, one txring per channel */ + struct pasemi_fnu_txring *tx; + + /* + * mutual exclusion for the channel scheduler + */ + spinlock_t sc_chnlock; + /* last channel used, for now use round-robin to allocate channels */ + int sc_lastchn; +}; + +struct pasemi_session { + u64 civ[2]; + u64 keysz; + u64 key[4]; + u64 ccmd; + u64 hkey[4]; + u64 hseq; + u64 giv[2]; + u64 hiv[4]; + + int used; + dma_addr_t dma_addr; + int chan; +}; + +/* status register layout in IOB region, at 0xfd800000 */ +struct pasdma_status { + u64 rx_sta[64]; + u64 tx_sta[20]; +}; + +#define ALG_IS_CIPHER(alg) ((alg == CRYPTO_DES_CBC) || \ + (alg == CRYPTO_3DES_CBC) || \ + (alg == CRYPTO_AES_CBC) || \ + (alg == CRYPTO_ARC4) || \ + (alg == CRYPTO_NULL_CBC)) + +#define ALG_IS_SIG(alg) ((alg == CRYPTO_MD5) || \ + (alg == CRYPTO_MD5_HMAC) || \ + (alg == CRYPTO_SHA1) || \ + (alg == CRYPTO_SHA1_HMAC) || \ + (alg == CRYPTO_NULL_HMAC)) + +enum { + PAS_DMA_COM_TXCMD = 0x100, /* Transmit Command Register */ + PAS_DMA_COM_TXSTA = 0x104, /* Transmit Status Register */ + PAS_DMA_COM_RXCMD = 0x108, /* Receive Command Register */ + PAS_DMA_COM_RXSTA = 0x10c, /* Receive Status Register */ + PAS_DMA_COM_CFG = 0x114, /* DMA Configuration Register */ +}; + +/* All these registers live in the PCI configuration space for the DMA PCI + * device. Use the normal PCI config access functions for them. + */ + +#define PAS_DMA_COM_CFG_FWF 0x18000000 + +#define PAS_DMA_COM_TXCMD_EN 0x00000001 /* enable */ +#define PAS_DMA_COM_TXSTA_ACT 0x00000001 /* active */ +#define PAS_DMA_COM_RXCMD_EN 0x00000001 /* enable */ +#define PAS_DMA_COM_RXSTA_ACT 0x00000001 /* active */ + +#define _PAS_DMA_TXCHAN_STRIDE 0x20 /* Size per channel */ +#define _PAS_DMA_TXCHAN_TCMDSTA 0x300 /* Command / Status */ +#define _PAS_DMA_TXCHAN_CFG 0x304 /* Configuration */ +#define _PAS_DMA_TXCHAN_DSCRBU 0x308 /* Descriptor BU Allocation */ +#define _PAS_DMA_TXCHAN_INCR 0x310 /* Descriptor increment */ +#define _PAS_DMA_TXCHAN_CNT 0x314 /* Descriptor count/offset */ +#define _PAS_DMA_TXCHAN_BASEL 0x318 /* Descriptor ring base (low) */ +#define _PAS_DMA_TXCHAN_BASEU 0x31c /* (high) */ +#define PAS_DMA_TXCHAN_TCMDSTA(c) (0x300+(c)*_PAS_DMA_TXCHAN_STRIDE) +#define PAS_DMA_TXCHAN_TCMDSTA_EN 0x00000001 /* Enabled */ +#define PAS_DMA_TXCHAN_TCMDSTA_ST 0x00000002 /* Stop interface */ +#define PAS_DMA_TXCHAN_TCMDSTA_ACT 0x00010000 /* Active */ +#define PAS_DMA_TXCHAN_CFG(c) (0x304+(c)*_PAS_DMA_TXCHAN_STRIDE) +#define PAS_DMA_TXCHAN_CFG_TY_FUNC 0x00000002 /* Type = interface */ +#define PAS_DMA_TXCHAN_CFG_TY_IFACE 0x00000000 /* Type = interface */ +#define PAS_DMA_TXCHAN_CFG_TATTR_M 0x0000003c +#define PAS_DMA_TXCHAN_CFG_TATTR_S 2 +#define PAS_DMA_TXCHAN_CFG_TATTR(x) (((x) << PAS_DMA_TXCHAN_CFG_TATTR_S) & \ + PAS_DMA_TXCHAN_CFG_TATTR_M) +#define PAS_DMA_TXCHAN_CFG_WT_M 0x000001c0 +#define PAS_DMA_TXCHAN_CFG_WT_S 6 +#define PAS_DMA_TXCHAN_CFG_WT(x) (((x) << PAS_DMA_TXCHAN_CFG_WT_S) & \ + PAS_DMA_TXCHAN_CFG_WT_M) +#define PAS_DMA_TXCHAN_CFG_LPSQ_FAST 0x00000400 +#define PAS_DMA_TXCHAN_CFG_LPDQ_FAST 0x00000800 +#define PAS_DMA_TXCHAN_CFG_CF 0x00001000 /* Clean first line */ +#define PAS_DMA_TXCHAN_CFG_CL 0x00002000 /* Clean last line */ +#define PAS_DMA_TXCHAN_CFG_UP 0x00004000 /* update tx descr when sent */ +#define PAS_DMA_TXCHAN_INCR(c) (0x310+(c)*_PAS_DMA_TXCHAN_STRIDE) +#define PAS_DMA_TXCHAN_BASEL(c) (0x318+(c)*_PAS_DMA_TXCHAN_STRIDE) +#define PAS_DMA_TXCHAN_BASEL_BRBL_M 0xffffffc0 +#define PAS_DMA_TXCHAN_BASEL_BRBL_S 0 +#define PAS_DMA_TXCHAN_BASEL_BRBL(x) (((x) << PAS_DMA_TXCHAN_BASEL_BRBL_S) & \ + PAS_DMA_TXCHAN_BASEL_BRBL_M) +#define PAS_DMA_TXCHAN_BASEU(c) (0x31c+(c)*_PAS_DMA_TXCHAN_STRIDE) +#define PAS_DMA_TXCHAN_BASEU_BRBH_M 0x00000fff +#define PAS_DMA_TXCHAN_BASEU_BRBH_S 0 +#define PAS_DMA_TXCHAN_BASEU_BRBH(x) (((x) << PAS_DMA_TXCHAN_BASEU_BRBH_S) & \ + PAS_DMA_TXCHAN_BASEU_BRBH_M) +/* # of cache lines worth of buffer ring */ +#define PAS_DMA_TXCHAN_BASEU_SIZ_M 0x3fff0000 +#define PAS_DMA_TXCHAN_BASEU_SIZ_S 16 /* 0 = 16K */ +#define PAS_DMA_TXCHAN_BASEU_SIZ(x) (((x) << PAS_DMA_TXCHAN_BASEU_SIZ_S) & \ + PAS_DMA_TXCHAN_BASEU_SIZ_M) + +#define PAS_STATUS_PCNT_M 0x000000000000ffffull +#define PAS_STATUS_PCNT_S 0 +#define PAS_STATUS_DCNT_M 0x00000000ffff0000ull +#define PAS_STATUS_DCNT_S 16 +#define PAS_STATUS_BPCNT_M 0x0000ffff00000000ull +#define PAS_STATUS_BPCNT_S 32 +#define PAS_STATUS_CAUSE_M 0xf000000000000000ull +#define PAS_STATUS_TIMER 0x1000000000000000ull +#define PAS_STATUS_ERROR 0x2000000000000000ull +#define PAS_STATUS_SOFT 0x4000000000000000ull +#define PAS_STATUS_INT 0x8000000000000000ull + +#define PAS_IOB_DMA_RXCH_CFG(i) (0x1100 + (i)*4) +#define PAS_IOB_DMA_RXCH_CFG_CNTTH_M 0x00000fff +#define PAS_IOB_DMA_RXCH_CFG_CNTTH_S 0 +#define PAS_IOB_DMA_RXCH_CFG_CNTTH(x) (((x) << PAS_IOB_DMA_RXCH_CFG_CNTTH_S) & \ + PAS_IOB_DMA_RXCH_CFG_CNTTH_M) +#define PAS_IOB_DMA_TXCH_CFG(i) (0x1200 + (i)*4) +#define PAS_IOB_DMA_TXCH_CFG_CNTTH_M 0x00000fff +#define PAS_IOB_DMA_TXCH_CFG_CNTTH_S 0 +#define PAS_IOB_DMA_TXCH_CFG_CNTTH(x) (((x) << PAS_IOB_DMA_TXCH_CFG_CNTTH_S) & \ + PAS_IOB_DMA_TXCH_CFG_CNTTH_M) +#define PAS_IOB_DMA_RXCH_STAT(i) (0x1300 + (i)*4) +#define PAS_IOB_DMA_RXCH_STAT_INTGEN 0x00001000 +#define PAS_IOB_DMA_RXCH_STAT_CNTDEL_M 0x00000fff +#define PAS_IOB_DMA_RXCH_STAT_CNTDEL_S 0 +#define PAS_IOB_DMA_RXCH_STAT_CNTDEL(x) (((x) << PAS_IOB_DMA_RXCH_STAT_CNTDEL_S) &\ + PAS_IOB_DMA_RXCH_STAT_CNTDEL_M) +#define PAS_IOB_DMA_TXCH_STAT(i) (0x1400 + (i)*4) +#define PAS_IOB_DMA_TXCH_STAT_INTGEN 0x00001000 +#define PAS_IOB_DMA_TXCH_STAT_CNTDEL_M 0x00000fff +#define PAS_IOB_DMA_TXCH_STAT_CNTDEL_S 0 +#define PAS_IOB_DMA_TXCH_STAT_CNTDEL(x) (((x) << PAS_IOB_DMA_TXCH_STAT_CNTDEL_S) &\ + PAS_IOB_DMA_TXCH_STAT_CNTDEL_M) +#define PAS_IOB_DMA_RXCH_RESET(i) (0x1500 + (i)*4) +#define PAS_IOB_DMA_RXCH_RESET_PCNT_M 0xffff0000 +#define PAS_IOB_DMA_RXCH_RESET_PCNT_S 16 +#define PAS_IOB_DMA_RXCH_RESET_PCNT(x) (((x) << PAS_IOB_DMA_RXCH_RESET_PCNT_S) & \ + PAS_IOB_DMA_RXCH_RESET_PCNT_M) +#define PAS_IOB_DMA_RXCH_RESET_PCNTRST 0x00000020 +#define PAS_IOB_DMA_RXCH_RESET_DCNTRST 0x00000010 +#define PAS_IOB_DMA_RXCH_RESET_TINTC 0x00000008 +#define PAS_IOB_DMA_RXCH_RESET_DINTC 0x00000004 +#define PAS_IOB_DMA_RXCH_RESET_SINTC 0x00000002 +#define PAS_IOB_DMA_RXCH_RESET_PINTC 0x00000001 +#define PAS_IOB_DMA_TXCH_RESET(i) (0x1600 + (i)*4) +#define PAS_IOB_DMA_TXCH_RESET_PCNT_M 0xffff0000 +#define PAS_IOB_DMA_TXCH_RESET_PCNT_S 16 +#define PAS_IOB_DMA_TXCH_RESET_PCNT(x) (((x) << PAS_IOB_DMA_TXCH_RESET_PCNT_S) & \ + PAS_IOB_DMA_TXCH_RESET_PCNT_M) +#define PAS_IOB_DMA_TXCH_RESET_PCNTRST 0x00000020 +#define PAS_IOB_DMA_TXCH_RESET_DCNTRST 0x00000010 +#define PAS_IOB_DMA_TXCH_RESET_TINTC 0x00000008 +#define PAS_IOB_DMA_TXCH_RESET_DINTC 0x00000004 +#define PAS_IOB_DMA_TXCH_RESET_SINTC 0x00000002 +#define PAS_IOB_DMA_TXCH_RESET_PINTC 0x00000001 + +#define PAS_IOB_DMA_COM_TIMEOUTCFG 0x1700 +#define PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT_M 0x00ffffff +#define PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT_S 0 +#define PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(x) (((x) << PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT_S) & \ + PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT_M) + +/* Transmit descriptor fields */ +#define XCT_MACTX_T 0x8000000000000000ull +#define XCT_MACTX_ST 0x4000000000000000ull +#define XCT_MACTX_NORES 0x0000000000000000ull +#define XCT_MACTX_8BRES 0x1000000000000000ull +#define XCT_MACTX_24BRES 0x2000000000000000ull +#define XCT_MACTX_40BRES 0x3000000000000000ull +#define XCT_MACTX_I 0x0800000000000000ull +#define XCT_MACTX_O 0x0400000000000000ull +#define XCT_MACTX_E 0x0200000000000000ull +#define XCT_MACTX_VLAN_M 0x0180000000000000ull +#define XCT_MACTX_VLAN_NOP 0x0000000000000000ull +#define XCT_MACTX_VLAN_REMOVE 0x0080000000000000ull +#define XCT_MACTX_VLAN_INSERT 0x0100000000000000ull +#define XCT_MACTX_VLAN_REPLACE 0x0180000000000000ull +#define XCT_MACTX_CRC_M 0x0060000000000000ull +#define XCT_MACTX_CRC_NOP 0x0000000000000000ull +#define XCT_MACTX_CRC_INSERT 0x0020000000000000ull +#define XCT_MACTX_CRC_PAD 0x0040000000000000ull +#define XCT_MACTX_CRC_REPLACE 0x0060000000000000ull +#define XCT_MACTX_SS 0x0010000000000000ull +#define XCT_MACTX_LLEN_M 0x00007fff00000000ull +#define XCT_MACTX_LLEN_S 32ull +#define XCT_MACTX_LLEN(x) ((((long)(x)) << XCT_MACTX_LLEN_S) & \ + XCT_MACTX_LLEN_M) +#define XCT_MACTX_IPH_M 0x00000000f8000000ull +#define XCT_MACTX_IPH_S 27ull +#define XCT_MACTX_IPH(x) ((((long)(x)) << XCT_MACTX_IPH_S) & \ + XCT_MACTX_IPH_M) +#define XCT_MACTX_IPO_M 0x0000000007c00000ull +#define XCT_MACTX_IPO_S 22ull +#define XCT_MACTX_IPO(x) ((((long)(x)) << XCT_MACTX_IPO_S) & \ + XCT_MACTX_IPO_M) +#define XCT_MACTX_CSUM_M 0x0000000000000060ull +#define XCT_MACTX_CSUM_NOP 0x0000000000000000ull +#define XCT_MACTX_CSUM_TCP 0x0000000000000040ull +#define XCT_MACTX_CSUM_UDP 0x0000000000000060ull +#define XCT_MACTX_V6 0x0000000000000010ull +#define XCT_MACTX_C 0x0000000000000004ull +#define XCT_MACTX_AL2 0x0000000000000002ull + +#define XCT_PTR_T 0x8000000000000000ull +#define XCT_PTR_LEN_M 0x7ffff00000000000ull +#define XCT_PTR_LEN_S 44 +#define XCT_PTR_LEN(x) ((((long)(x)) << XCT_PTR_LEN_S) & \ + XCT_PTR_LEN_M) +#define XCT_PTR_ADDR_M 0x00000fffffffffffull +#define XCT_PTR_ADDR_S 0 +#define XCT_PTR_ADDR(x) ((((long)(x)) << XCT_PTR_ADDR_S) & \ + XCT_PTR_ADDR_M) + +/* Function descriptor fields */ +#define XCT_FUN_T 0x8000000000000000ull +#define XCT_FUN_ST 0x4000000000000000ull +#define XCT_FUN_NORES 0x0000000000000000ull +#define XCT_FUN_8BRES 0x1000000000000000ull +#define XCT_FUN_24BRES 0x2000000000000000ull +#define XCT_FUN_40BRES 0x3000000000000000ull +#define XCT_FUN_I 0x0800000000000000ull +#define XCT_FUN_O 0x0400000000000000ull +#define XCT_FUN_E 0x0200000000000000ull +#define XCT_FUN_FUN_S 54 +#define XCT_FUN_FUN_M 0x01c0000000000000ull +#define XCT_FUN_FUN(num) ((((long)(num)) << XCT_FUN_FUN_S) & \ + XCT_FUN_FUN_M) +#define XCT_FUN_CRM_NOP 0x0000000000000000ull +#define XCT_FUN_CRM_SIG 0x0008000000000000ull +#define XCT_FUN_CRM_ENC 0x0010000000000000ull +#define XCT_FUN_CRM_DEC 0x0018000000000000ull +#define XCT_FUN_CRM_SIG_ENC 0x0020000000000000ull +#define XCT_FUN_CRM_ENC_SIG 0x0028000000000000ull +#define XCT_FUN_CRM_SIG_DEC 0x0030000000000000ull +#define XCT_FUN_CRM_DEC_SIG 0x0038000000000000ull +#define XCT_FUN_LLEN_M 0x0007ffff00000000ull +#define XCT_FUN_LLEN_S 32ULL +#define XCT_FUN_LLEN(x) ((((long)(x)) << XCT_FUN_LLEN_S) & \ + XCT_FUN_LLEN_M) +#define XCT_FUN_SHL_M 0x00000000f8000000ull +#define XCT_FUN_SHL_S 27ull +#define XCT_FUN_SHL(x) ((((long)(x)) << XCT_FUN_SHL_S) & \ + XCT_FUN_SHL_M) +#define XCT_FUN_CHL_M 0x0000000007c00000ull +#define XCT_FUN_CHL_S 22ull +#define XCT_FUN_CHL(x) ((((long)(x)) << XCT_FUN_CHL_S) & \ + XCT_FUN_CHL_M) +#define XCT_FUN_HSZ_M 0x00000000003c0000ull +#define XCT_FUN_HSZ_S 18ull +#define XCT_FUN_HSZ(x) ((((long)(x)) << XCT_FUN_HSZ_S) & \ + XCT_FUN_HSZ_M) +#define XCT_FUN_ALG_DES 0x0000000000000000ull +#define XCT_FUN_ALG_3DES 0x0000000000008000ull +#define XCT_FUN_ALG_AES 0x0000000000010000ull +#define XCT_FUN_ALG_ARC 0x0000000000018000ull +#define XCT_FUN_ALG_KASUMI 0x0000000000020000ull +#define XCT_FUN_BCM_ECB 0x0000000000000000ull +#define XCT_FUN_BCM_CBC 0x0000000000001000ull +#define XCT_FUN_BCM_CFB 0x0000000000002000ull +#define XCT_FUN_BCM_OFB 0x0000000000003000ull +#define XCT_FUN_BCM_CNT 0x0000000000003800ull +#define XCT_FUN_BCM_KAS_F8 0x0000000000002800ull +#define XCT_FUN_BCM_KAS_F9 0x0000000000001800ull +#define XCT_FUN_BCP_NO_PAD 0x0000000000000000ull +#define XCT_FUN_BCP_ZRO 0x0000000000000200ull +#define XCT_FUN_BCP_PL 0x0000000000000400ull +#define XCT_FUN_BCP_INCR 0x0000000000000600ull +#define XCT_FUN_SIG_MD5 (0ull << 4) +#define XCT_FUN_SIG_SHA1 (2ull << 4) +#define XCT_FUN_SIG_HMAC_MD5 (8ull << 4) +#define XCT_FUN_SIG_HMAC_SHA1 (10ull << 4) +#define XCT_FUN_A 0x0000000000000008ull +#define XCT_FUN_C 0x0000000000000004ull +#define XCT_FUN_AL2 0x0000000000000002ull +#define XCT_FUN_SE 0x0000000000000001ull + +#define XCT_FUN_SRC_PTR(len, addr) (XCT_PTR_LEN(len) | XCT_PTR_ADDR(addr)) +#define XCT_FUN_DST_PTR(len, addr) (XCT_FUN_SRC_PTR(len, addr) | \ + 0x8000000000000000ull) + +#define XCT_CTRL_HDR_FUN_NUM_M 0x01c0000000000000ull +#define XCT_CTRL_HDR_FUN_NUM_S 54 +#define XCT_CTRL_HDR_LEN_M 0x0007ffff00000000ull +#define XCT_CTRL_HDR_LEN_S 32 +#define XCT_CTRL_HDR_REG_M 0x00000000000000ffull +#define XCT_CTRL_HDR_REG_S 0 + +#define XCT_CTRL_HDR(funcN,len,reg) (0x9400000000000000ull | \ + ((((long)(funcN)) << XCT_CTRL_HDR_FUN_NUM_S) \ + & XCT_CTRL_HDR_FUN_NUM_M) | \ + ((((long)(len)) << \ + XCT_CTRL_HDR_LEN_S) & XCT_CTRL_HDR_LEN_M) | \ + ((((long)(reg)) << \ + XCT_CTRL_HDR_REG_S) & XCT_CTRL_HDR_REG_M)) + +/* Function config command options */ +#define DMA_CALGO_DES 0x00 +#define DMA_CALGO_3DES 0x01 +#define DMA_CALGO_AES 0x02 +#define DMA_CALGO_ARC 0x03 + +#define DMA_FN_CIV0 0x02 +#define DMA_FN_CIV1 0x03 +#define DMA_FN_HKEY0 0x0a + +#define XCT_PTR_ADDR_LEN(ptr) ((ptr) & XCT_PTR_ADDR_M), \ + (((ptr) & XCT_PTR_LEN_M) >> XCT_PTR_LEN_S) + +#endif /* PASEMI_FNU_H */ diff --git a/target/linux/generic/files/crypto/ocf/random.c b/target/linux/generic/files/crypto/ocf/random.c new file mode 100644 index 0000000..9fc070e --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/random.c @@ -0,0 +1,317 @@ +/* + * A system independant way of adding entropy to the kernels pool + * this way the drivers can focus on the real work and we can take + * care of pushing it to the appropriate place in the kernel. + * + * This should be fast and callable from timers/interrupts + * + * Written by David McCullough + * Copyright (C) 2006-2010 David McCullough + * Copyright (C) 2004-2005 Intel Corporation. + * + * LICENSE TERMS + * + * The free distribution and use of this software in both source and binary + * form is allowed (with or without changes) provided that: + * + * 1. distributions of this source code include the above copyright + * notice, this list of conditions and the following disclaimer; + * + * 2. distributions in binary form include the above copyright + * notice, this list of conditions and the following disclaimer + * in the documentation and/or other associated materials; + * + * 3. the copyright holder's name is not used to endorse products + * built using this software without specific written permission. + * + * ALTERNATIVELY, provided that this notice is retained in full, this product + * may be distributed under the terms of the GNU General Public License (GPL), + * in which case the provisions of the GPL apply INSTEAD OF those given above. + * + * DISCLAIMER + * + * This software is provided 'as is' with no explicit or implied warranties + * in respect of its properties, including, but not limited to, correctness + * and/or fitness for purpose. + */ + +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) && !defined(AUTOCONF_INCLUDED) +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_OCF_FIPS +#include "rndtest.h" +#endif + +#ifndef HAS_RANDOM_INPUT_WAIT +#error "Please do not enable OCF_RANDOMHARVEST unless you have applied patches" +#endif + +/* + * a hack to access the debug levels from the crypto driver + */ +extern int crypto_debug; +#define debug crypto_debug + +/* + * a list of all registered random providers + */ +static LIST_HEAD(random_ops); +static int started = 0; +static int initted = 0; + +struct random_op { + struct list_head random_list; + u_int32_t driverid; + int (*read_random)(void *arg, u_int32_t *buf, int len); + void *arg; +}; + +static struct task_struct *random_thread; +static int random_proc(void *arg); + +static spinlock_t random_lock; + +/* + * just init the spin locks + */ +static int +crypto_random_init(void) +{ + spin_lock_init(&random_lock); + initted = 1; + return(0); +} + +/* + * Add the given random reader to our list (if not present) + * and start the thread (if not already started) + * + * we have to assume that driver id is ok for now + */ +int +crypto_rregister( + u_int32_t driverid, + int (*read_random)(void *arg, u_int32_t *buf, int len), + void *arg) +{ + unsigned long flags; + int ret = 0; + struct random_op *rops, *tmp; + + dprintk("%s,%d: %s(0x%x, %p, %p)\n", __FILE__, __LINE__, + __FUNCTION__, driverid, read_random, arg); + + if (!initted) + crypto_random_init(); + +#if 0 + struct cryptocap *cap; + + cap = crypto_checkdriver(driverid); + if (!cap) + return EINVAL; +#endif + + list_for_each_entry_safe(rops, tmp, &random_ops, random_list) { + if (rops->driverid == driverid && rops->read_random == read_random) + return EEXIST; + } + + rops = (struct random_op *) kmalloc(sizeof(*rops), GFP_KERNEL); + if (!rops) + return ENOMEM; + + rops->driverid = driverid; + rops->read_random = read_random; + rops->arg = arg; + + spin_lock_irqsave(&random_lock, flags); + list_add_tail(&rops->random_list, &random_ops); + if (!started) { + random_thread = kthread_run(random_proc, NULL, "ocf-random"); + if (IS_ERR(random_thread)) + ret = PTR_ERR(random_thread); + else + started = 1; + } + spin_unlock_irqrestore(&random_lock, flags); + + return ret; +} +EXPORT_SYMBOL(crypto_rregister); + +int +crypto_runregister_all(u_int32_t driverid) +{ + struct random_op *rops, *tmp; + unsigned long flags; + + dprintk("%s,%d: %s(0x%x)\n", __FILE__, __LINE__, __FUNCTION__, driverid); + + list_for_each_entry_safe(rops, tmp, &random_ops, random_list) { + if (rops->driverid == driverid) { + list_del(&rops->random_list); + kfree(rops); + } + } + + spin_lock_irqsave(&random_lock, flags); + if (list_empty(&random_ops) && started) + kthread_stop(random_thread); + spin_unlock_irqrestore(&random_lock, flags); + return(0); +} +EXPORT_SYMBOL(crypto_runregister_all); + +/* + * while we can add entropy to random.c continue to read random data from + * the drivers and push it to random. + */ +static int +random_proc(void *arg) +{ + int n; + int wantcnt; + int bufcnt = 0; + int retval = 0; + int *buf = NULL; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) + daemonize(); + spin_lock_irq(¤t->sigmask_lock); + sigemptyset(¤t->blocked); + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + sprintf(current->comm, "ocf-random"); +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,8,0) + recalc_sigpending(); + sprintf(current->comm, "ocf-random"); +#else + daemonize("ocf-random"); +#endif + + (void) get_fs(); + set_fs(get_ds()); + +#ifdef CONFIG_OCF_FIPS +#define NUM_INT (RNDTEST_NBYTES/sizeof(int)) +#else +#define NUM_INT 32 +#endif + + /* + * some devices can transferr their RNG data direct into memory, + * so make sure it is device friendly + */ + buf = kmalloc(NUM_INT * sizeof(int), GFP_DMA); + if (NULL == buf) { + printk("crypto: RNG could not allocate memory\n"); + retval = -ENOMEM; + goto bad_alloc; + } + + wantcnt = NUM_INT; /* start by adding some entropy */ + + /* + * its possible due to errors or driver removal that we no longer + * have anything to do, if so exit or we will consume all the CPU + * doing nothing + */ + while (!list_empty(&random_ops)) { + struct random_op *rops, *tmp; + +#ifdef CONFIG_OCF_FIPS + if (wantcnt) + wantcnt = NUM_INT; /* FIPs mode can do 20000 bits or none */ +#endif + + /* see if we can get enough entropy to make the world + * a better place. + */ + while (bufcnt < wantcnt && bufcnt < NUM_INT) { + list_for_each_entry_safe(rops, tmp, &random_ops, random_list) { + + n = (*rops->read_random)(rops->arg, &buf[bufcnt], + NUM_INT - bufcnt); + + /* on failure remove the random number generator */ + if (n == -1) { + list_del(&rops->random_list); + printk("crypto: RNG (driverid=0x%x) failed, disabling\n", + rops->driverid); + kfree(rops); + } else if (n > 0) + bufcnt += n; + } + /* give up CPU for a bit, just in case as this is a loop */ + schedule(); + } + + +#ifdef CONFIG_OCF_FIPS + if (bufcnt > 0 && rndtest_buf((unsigned char *) &buf[0])) { + dprintk("crypto: buffer had fips errors, discarding\n"); + bufcnt = 0; + } +#endif + + /* + * if we have a certified buffer, we can send some data + * to /dev/random and move along + */ + if (bufcnt > 0) { + /* add what we have */ + random_input_words(buf, bufcnt, bufcnt*sizeof(int)*8); + bufcnt = 0; + } + + /* give up CPU for a bit so we don't hog while filling */ + schedule(); + + /* wait for needing more */ + wantcnt = random_input_wait(); + + if (wantcnt <= 0) + wantcnt = 0; /* try to get some info again */ + else + /* round up to one word or we can loop forever */ + wantcnt = (wantcnt + (sizeof(int)*8)) / (sizeof(int)*8); + if (wantcnt > NUM_INT) { + wantcnt = NUM_INT; + } + + if (signal_pending(current)) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) + spin_lock_irq(¤t->sigmask_lock); +#endif + flush_signals(current); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) + spin_unlock_irq(¤t->sigmask_lock); +#endif + } + } + + kfree(buf); + +bad_alloc: + spin_lock_irq(&random_lock); + started = 0; + spin_unlock_irq(&random_lock); + + return retval; +} + diff --git a/target/linux/generic/files/crypto/ocf/rndtest.c b/target/linux/generic/files/crypto/ocf/rndtest.c new file mode 100644 index 0000000..7bed6a1 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/rndtest.c @@ -0,0 +1,300 @@ +/* $OpenBSD$ */ + +/* + * OCF/Linux port done by David McCullough + * Copyright (C) 2006-2010 David McCullough + * Copyright (C) 2004-2005 Intel Corporation. + * The license and original author are listed below. + * + * Copyright (c) 2002 Jason L. Wright (jason@thought.net) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Jason L. Wright + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) && !defined(AUTOCONF_INCLUDED) +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "rndtest.h" + +static struct rndtest_stats rndstats; + +static void rndtest_test(struct rndtest_state *); + +/* The tests themselves */ +static int rndtest_monobit(struct rndtest_state *); +static int rndtest_runs(struct rndtest_state *); +static int rndtest_longruns(struct rndtest_state *); +static int rndtest_chi_4(struct rndtest_state *); + +static int rndtest_runs_check(struct rndtest_state *, int, int *); +static void rndtest_runs_record(struct rndtest_state *, int, int *); + +static const struct rndtest_testfunc { + int (*test)(struct rndtest_state *); +} rndtest_funcs[] = { + { rndtest_monobit }, + { rndtest_runs }, + { rndtest_chi_4 }, + { rndtest_longruns }, +}; + +#define RNDTEST_NTESTS (sizeof(rndtest_funcs)/sizeof(rndtest_funcs[0])) + +static void +rndtest_test(struct rndtest_state *rsp) +{ + int i, rv = 0; + + rndstats.rst_tests++; + for (i = 0; i < RNDTEST_NTESTS; i++) + rv |= (*rndtest_funcs[i].test)(rsp); + rsp->rs_discard = (rv != 0); +} + + +extern int crypto_debug; +#define rndtest_verbose 2 +#define rndtest_report(rsp, failure, fmt, a...) \ + { if (failure || crypto_debug) { printk("rng_test: " fmt "\n", a); } else; } + +#define RNDTEST_MONOBIT_MINONES 9725 +#define RNDTEST_MONOBIT_MAXONES 10275 + +static int +rndtest_monobit(struct rndtest_state *rsp) +{ + int i, ones = 0, j; + u_int8_t r; + + for (i = 0; i < RNDTEST_NBYTES; i++) { + r = rsp->rs_buf[i]; + for (j = 0; j < 8; j++, r <<= 1) + if (r & 0x80) + ones++; + } + if (ones > RNDTEST_MONOBIT_MINONES && + ones < RNDTEST_MONOBIT_MAXONES) { + if (rndtest_verbose > 1) + rndtest_report(rsp, 0, "monobit pass (%d < %d < %d)", + RNDTEST_MONOBIT_MINONES, ones, + RNDTEST_MONOBIT_MAXONES); + return (0); + } else { + if (rndtest_verbose) + rndtest_report(rsp, 1, + "monobit failed (%d ones)", ones); + rndstats.rst_monobit++; + return (-1); + } +} + +#define RNDTEST_RUNS_NINTERVAL 6 + +static const struct rndtest_runs_tabs { + u_int16_t min, max; +} rndtest_runs_tab[] = { + { 2343, 2657 }, + { 1135, 1365 }, + { 542, 708 }, + { 251, 373 }, + { 111, 201 }, + { 111, 201 }, +}; + +static int +rndtest_runs(struct rndtest_state *rsp) +{ + int i, j, ones, zeros, rv = 0; + int onei[RNDTEST_RUNS_NINTERVAL], zeroi[RNDTEST_RUNS_NINTERVAL]; + u_int8_t c; + + bzero(onei, sizeof(onei)); + bzero(zeroi, sizeof(zeroi)); + ones = zeros = 0; + for (i = 0; i < RNDTEST_NBYTES; i++) { + c = rsp->rs_buf[i]; + for (j = 0; j < 8; j++, c <<= 1) { + if (c & 0x80) { + ones++; + rndtest_runs_record(rsp, zeros, zeroi); + zeros = 0; + } else { + zeros++; + rndtest_runs_record(rsp, ones, onei); + ones = 0; + } + } + } + rndtest_runs_record(rsp, ones, onei); + rndtest_runs_record(rsp, zeros, zeroi); + + rv |= rndtest_runs_check(rsp, 0, zeroi); + rv |= rndtest_runs_check(rsp, 1, onei); + + if (rv) + rndstats.rst_runs++; + + return (rv); +} + +static void +rndtest_runs_record(struct rndtest_state *rsp, int len, int *intrv) +{ + if (len == 0) + return; + if (len > RNDTEST_RUNS_NINTERVAL) + len = RNDTEST_RUNS_NINTERVAL; + len -= 1; + intrv[len]++; +} + +static int +rndtest_runs_check(struct rndtest_state *rsp, int val, int *src) +{ + int i, rv = 0; + + for (i = 0; i < RNDTEST_RUNS_NINTERVAL; i++) { + if (src[i] < rndtest_runs_tab[i].min || + src[i] > rndtest_runs_tab[i].max) { + rndtest_report(rsp, 1, + "%s interval %d failed (%d, %d-%d)", + val ? "ones" : "zeros", + i + 1, src[i], rndtest_runs_tab[i].min, + rndtest_runs_tab[i].max); + rv = -1; + } else { + rndtest_report(rsp, 0, + "runs pass %s interval %d (%d < %d < %d)", + val ? "ones" : "zeros", + i + 1, rndtest_runs_tab[i].min, src[i], + rndtest_runs_tab[i].max); + } + } + return (rv); +} + +static int +rndtest_longruns(struct rndtest_state *rsp) +{ + int i, j, ones = 0, zeros = 0, maxones = 0, maxzeros = 0; + u_int8_t c; + + for (i = 0; i < RNDTEST_NBYTES; i++) { + c = rsp->rs_buf[i]; + for (j = 0; j < 8; j++, c <<= 1) { + if (c & 0x80) { + zeros = 0; + ones++; + if (ones > maxones) + maxones = ones; + } else { + ones = 0; + zeros++; + if (zeros > maxzeros) + maxzeros = zeros; + } + } + } + + if (maxones < 26 && maxzeros < 26) { + rndtest_report(rsp, 0, "longruns pass (%d ones, %d zeros)", + maxones, maxzeros); + return (0); + } else { + rndtest_report(rsp, 1, "longruns fail (%d ones, %d zeros)", + maxones, maxzeros); + rndstats.rst_longruns++; + return (-1); + } +} + +/* + * chi^2 test over 4 bits: (this is called the poker test in FIPS 140-2, + * but it is really the chi^2 test over 4 bits (the poker test as described + * by Knuth vol 2 is something different, and I take him as authoritative + * on nomenclature over NIST). + */ +#define RNDTEST_CHI4_K 16 +#define RNDTEST_CHI4_K_MASK (RNDTEST_CHI4_K - 1) + +/* + * The unnormalized values are used so that we don't have to worry about + * fractional precision. The "real" value is found by: + * (V - 1562500) * (16 / 5000) = Vn (where V is the unnormalized value) + */ +#define RNDTEST_CHI4_VMIN 1563181 /* 2.1792 */ +#define RNDTEST_CHI4_VMAX 1576929 /* 46.1728 */ + +static int +rndtest_chi_4(struct rndtest_state *rsp) +{ + unsigned int freq[RNDTEST_CHI4_K], i, sum; + + for (i = 0; i < RNDTEST_CHI4_K; i++) + freq[i] = 0; + + /* Get number of occurances of each 4 bit pattern */ + for (i = 0; i < RNDTEST_NBYTES; i++) { + freq[(rsp->rs_buf[i] >> 4) & RNDTEST_CHI4_K_MASK]++; + freq[(rsp->rs_buf[i] >> 0) & RNDTEST_CHI4_K_MASK]++; + } + + for (i = 0, sum = 0; i < RNDTEST_CHI4_K; i++) + sum += freq[i] * freq[i]; + + if (sum >= 1563181 && sum <= 1576929) { + rndtest_report(rsp, 0, "chi^2(4): pass (sum %u)", sum); + return (0); + } else { + rndtest_report(rsp, 1, "chi^2(4): failed (sum %u)", sum); + rndstats.rst_chi++; + return (-1); + } +} + +int +rndtest_buf(unsigned char *buf) +{ + struct rndtest_state rsp; + + memset(&rsp, 0, sizeof(rsp)); + rsp.rs_buf = buf; + rndtest_test(&rsp); + return(rsp.rs_discard); +} + diff --git a/target/linux/generic/files/crypto/ocf/rndtest.h b/target/linux/generic/files/crypto/ocf/rndtest.h new file mode 100644 index 0000000..e9d8ec8 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/rndtest.h @@ -0,0 +1,54 @@ +/* $FreeBSD: src/sys/dev/rndtest/rndtest.h,v 1.1 2003/03/11 22:54:44 sam Exp $ */ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2002 Jason L. Wright (jason@thought.net) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Jason L. Wright + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + + +/* Some of the tests depend on these values */ +#define RNDTEST_NBYTES 2500 +#define RNDTEST_NBITS (8 * RNDTEST_NBYTES) + +struct rndtest_state { + int rs_discard; /* discard/accept random data */ + u_int8_t *rs_buf; +}; + +struct rndtest_stats { + u_int32_t rst_discard; /* number of bytes discarded */ + u_int32_t rst_tests; /* number of test runs */ + u_int32_t rst_monobit; /* monobit test failures */ + u_int32_t rst_runs; /* 0/1 runs failures */ + u_int32_t rst_longruns; /* longruns failures */ + u_int32_t rst_chi; /* chi^2 failures */ +}; + +extern int rndtest_buf(unsigned char *buf); diff --git a/target/linux/generic/files/crypto/ocf/safe/Makefile b/target/linux/generic/files/crypto/ocf/safe/Makefile new file mode 100644 index 0000000..9a36b08 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/safe/Makefile @@ -0,0 +1,12 @@ +# for SGlinux builds +-include $(ROOTDIR)/modules/.config + +obj-$(CONFIG_OCF_SAFE) += safe.o + +obj ?= . +EXTRA_CFLAGS += -I$(obj)/.. -I$(obj)/ + +ifdef TOPDIR +-include $(TOPDIR)/Rules.make +endif + diff --git a/target/linux/generic/files/crypto/ocf/safe/hmachack.h b/target/linux/generic/files/crypto/ocf/safe/hmachack.h new file mode 100644 index 0000000..598c958 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/safe/hmachack.h @@ -0,0 +1,37 @@ +/* + * until we find a cleaner way, include the BSD md5/sha1 code + * here + */ +#ifdef HMAC_HACK +#define LITTLE_ENDIAN 1234 +#define BIG_ENDIAN 4321 +#ifdef __LITTLE_ENDIAN +#define BYTE_ORDER LITTLE_ENDIAN +#endif +#ifdef __BIG_ENDIAN +#define BYTE_ORDER BIG_ENDIAN +#endif + +u_int8_t hmac_ipad_buffer[64] = { + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36 +}; + +u_int8_t hmac_opad_buffer[64] = { + 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, + 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, + 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, + 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, + 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, + 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, + 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, + 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C +}; +#endif /* HMAC_HACK */ + diff --git a/target/linux/generic/files/crypto/ocf/safe/md5.c b/target/linux/generic/files/crypto/ocf/safe/md5.c new file mode 100644 index 0000000..077c42e --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/safe/md5.c @@ -0,0 +1,308 @@ +/* $KAME: md5.c,v 1.5 2000/11/08 06:13:08 itojun Exp $ */ +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if 0 +#include +__FBSDID("$FreeBSD: src/sys/crypto/md5.c,v 1.9 2004/01/27 19:49:19 des Exp $"); + +#include +#include +#include +#include +#include +#endif + +#define SHIFT(X, s) (((X) << (s)) | ((X) >> (32 - (s)))) + +#define F(X, Y, Z) (((X) & (Y)) | ((~X) & (Z))) +#define G(X, Y, Z) (((X) & (Z)) | ((Y) & (~Z))) +#define H(X, Y, Z) ((X) ^ (Y) ^ (Z)) +#define I(X, Y, Z) ((Y) ^ ((X) | (~Z))) + +#define ROUND1(a, b, c, d, k, s, i) { \ + (a) = (a) + F((b), (c), (d)) + X[(k)] + T[(i)]; \ + (a) = SHIFT((a), (s)); \ + (a) = (b) + (a); \ +} + +#define ROUND2(a, b, c, d, k, s, i) { \ + (a) = (a) + G((b), (c), (d)) + X[(k)] + T[(i)]; \ + (a) = SHIFT((a), (s)); \ + (a) = (b) + (a); \ +} + +#define ROUND3(a, b, c, d, k, s, i) { \ + (a) = (a) + H((b), (c), (d)) + X[(k)] + T[(i)]; \ + (a) = SHIFT((a), (s)); \ + (a) = (b) + (a); \ +} + +#define ROUND4(a, b, c, d, k, s, i) { \ + (a) = (a) + I((b), (c), (d)) + X[(k)] + T[(i)]; \ + (a) = SHIFT((a), (s)); \ + (a) = (b) + (a); \ +} + +#define Sa 7 +#define Sb 12 +#define Sc 17 +#define Sd 22 + +#define Se 5 +#define Sf 9 +#define Sg 14 +#define Sh 20 + +#define Si 4 +#define Sj 11 +#define Sk 16 +#define Sl 23 + +#define Sm 6 +#define Sn 10 +#define So 15 +#define Sp 21 + +#define MD5_A0 0x67452301 +#define MD5_B0 0xefcdab89 +#define MD5_C0 0x98badcfe +#define MD5_D0 0x10325476 + +/* Integer part of 4294967296 times abs(sin(i)), where i is in radians. */ +static const u_int32_t T[65] = { + 0, + 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, + 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, + 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, + + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, + 0xd62f105d, 0x2441453, 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, + 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, + + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, + 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05, + 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, + + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, + 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, + 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391, +}; + +static const u_int8_t md5_paddat[MD5_BUFLEN] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static void md5_calc(u_int8_t *, md5_ctxt *); + +void md5_init(ctxt) + md5_ctxt *ctxt; +{ + ctxt->md5_n = 0; + ctxt->md5_i = 0; + ctxt->md5_sta = MD5_A0; + ctxt->md5_stb = MD5_B0; + ctxt->md5_stc = MD5_C0; + ctxt->md5_std = MD5_D0; + bzero(ctxt->md5_buf, sizeof(ctxt->md5_buf)); +} + +void md5_loop(ctxt, input, len) + md5_ctxt *ctxt; + u_int8_t *input; + u_int len; /* number of bytes */ +{ + u_int gap, i; + + ctxt->md5_n += len * 8; /* byte to bit */ + gap = MD5_BUFLEN - ctxt->md5_i; + + if (len >= gap) { + bcopy((void *)input, (void *)(ctxt->md5_buf + ctxt->md5_i), + gap); + md5_calc(ctxt->md5_buf, ctxt); + + for (i = gap; i + MD5_BUFLEN <= len; i += MD5_BUFLEN) { + md5_calc((u_int8_t *)(input + i), ctxt); + } + + ctxt->md5_i = len - i; + bcopy((void *)(input + i), (void *)ctxt->md5_buf, ctxt->md5_i); + } else { + bcopy((void *)input, (void *)(ctxt->md5_buf + ctxt->md5_i), + len); + ctxt->md5_i += len; + } +} + +void md5_pad(ctxt) + md5_ctxt *ctxt; +{ + u_int gap; + + /* Don't count up padding. Keep md5_n. */ + gap = MD5_BUFLEN - ctxt->md5_i; + if (gap > 8) { + bcopy(md5_paddat, + (void *)(ctxt->md5_buf + ctxt->md5_i), + gap - sizeof(ctxt->md5_n)); + } else { + /* including gap == 8 */ + bcopy(md5_paddat, (void *)(ctxt->md5_buf + ctxt->md5_i), + gap); + md5_calc(ctxt->md5_buf, ctxt); + bcopy((md5_paddat + gap), + (void *)ctxt->md5_buf, + MD5_BUFLEN - sizeof(ctxt->md5_n)); + } + + /* 8 byte word */ +#if BYTE_ORDER == LITTLE_ENDIAN + bcopy(&ctxt->md5_n8[0], &ctxt->md5_buf[56], 8); +#endif +#if BYTE_ORDER == BIG_ENDIAN + ctxt->md5_buf[56] = ctxt->md5_n8[7]; + ctxt->md5_buf[57] = ctxt->md5_n8[6]; + ctxt->md5_buf[58] = ctxt->md5_n8[5]; + ctxt->md5_buf[59] = ctxt->md5_n8[4]; + ctxt->md5_buf[60] = ctxt->md5_n8[3]; + ctxt->md5_buf[61] = ctxt->md5_n8[2]; + ctxt->md5_buf[62] = ctxt->md5_n8[1]; + ctxt->md5_buf[63] = ctxt->md5_n8[0]; +#endif + + md5_calc(ctxt->md5_buf, ctxt); +} + +void md5_result(digest, ctxt) + u_int8_t *digest; + md5_ctxt *ctxt; +{ + /* 4 byte words */ +#if BYTE_ORDER == LITTLE_ENDIAN + bcopy(&ctxt->md5_st8[0], digest, 16); +#endif +#if BYTE_ORDER == BIG_ENDIAN + digest[ 0] = ctxt->md5_st8[ 3]; digest[ 1] = ctxt->md5_st8[ 2]; + digest[ 2] = ctxt->md5_st8[ 1]; digest[ 3] = ctxt->md5_st8[ 0]; + digest[ 4] = ctxt->md5_st8[ 7]; digest[ 5] = ctxt->md5_st8[ 6]; + digest[ 6] = ctxt->md5_st8[ 5]; digest[ 7] = ctxt->md5_st8[ 4]; + digest[ 8] = ctxt->md5_st8[11]; digest[ 9] = ctxt->md5_st8[10]; + digest[10] = ctxt->md5_st8[ 9]; digest[11] = ctxt->md5_st8[ 8]; + digest[12] = ctxt->md5_st8[15]; digest[13] = ctxt->md5_st8[14]; + digest[14] = ctxt->md5_st8[13]; digest[15] = ctxt->md5_st8[12]; +#endif +} + +static void md5_calc(b64, ctxt) + u_int8_t *b64; + md5_ctxt *ctxt; +{ + u_int32_t A = ctxt->md5_sta; + u_int32_t B = ctxt->md5_stb; + u_int32_t C = ctxt->md5_stc; + u_int32_t D = ctxt->md5_std; +#if BYTE_ORDER == LITTLE_ENDIAN + u_int32_t *X = (u_int32_t *)b64; +#endif +#if BYTE_ORDER == BIG_ENDIAN + /* 4 byte words */ + /* what a brute force but fast! */ + u_int32_t X[16]; + u_int8_t *y = (u_int8_t *)X; + y[ 0] = b64[ 3]; y[ 1] = b64[ 2]; y[ 2] = b64[ 1]; y[ 3] = b64[ 0]; + y[ 4] = b64[ 7]; y[ 5] = b64[ 6]; y[ 6] = b64[ 5]; y[ 7] = b64[ 4]; + y[ 8] = b64[11]; y[ 9] = b64[10]; y[10] = b64[ 9]; y[11] = b64[ 8]; + y[12] = b64[15]; y[13] = b64[14]; y[14] = b64[13]; y[15] = b64[12]; + y[16] = b64[19]; y[17] = b64[18]; y[18] = b64[17]; y[19] = b64[16]; + y[20] = b64[23]; y[21] = b64[22]; y[22] = b64[21]; y[23] = b64[20]; + y[24] = b64[27]; y[25] = b64[26]; y[26] = b64[25]; y[27] = b64[24]; + y[28] = b64[31]; y[29] = b64[30]; y[30] = b64[29]; y[31] = b64[28]; + y[32] = b64[35]; y[33] = b64[34]; y[34] = b64[33]; y[35] = b64[32]; + y[36] = b64[39]; y[37] = b64[38]; y[38] = b64[37]; y[39] = b64[36]; + y[40] = b64[43]; y[41] = b64[42]; y[42] = b64[41]; y[43] = b64[40]; + y[44] = b64[47]; y[45] = b64[46]; y[46] = b64[45]; y[47] = b64[44]; + y[48] = b64[51]; y[49] = b64[50]; y[50] = b64[49]; y[51] = b64[48]; + y[52] = b64[55]; y[53] = b64[54]; y[54] = b64[53]; y[55] = b64[52]; + y[56] = b64[59]; y[57] = b64[58]; y[58] = b64[57]; y[59] = b64[56]; + y[60] = b64[63]; y[61] = b64[62]; y[62] = b64[61]; y[63] = b64[60]; +#endif + + ROUND1(A, B, C, D, 0, Sa, 1); ROUND1(D, A, B, C, 1, Sb, 2); + ROUND1(C, D, A, B, 2, Sc, 3); ROUND1(B, C, D, A, 3, Sd, 4); + ROUND1(A, B, C, D, 4, Sa, 5); ROUND1(D, A, B, C, 5, Sb, 6); + ROUND1(C, D, A, B, 6, Sc, 7); ROUND1(B, C, D, A, 7, Sd, 8); + ROUND1(A, B, C, D, 8, Sa, 9); ROUND1(D, A, B, C, 9, Sb, 10); + ROUND1(C, D, A, B, 10, Sc, 11); ROUND1(B, C, D, A, 11, Sd, 12); + ROUND1(A, B, C, D, 12, Sa, 13); ROUND1(D, A, B, C, 13, Sb, 14); + ROUND1(C, D, A, B, 14, Sc, 15); ROUND1(B, C, D, A, 15, Sd, 16); + + ROUND2(A, B, C, D, 1, Se, 17); ROUND2(D, A, B, C, 6, Sf, 18); + ROUND2(C, D, A, B, 11, Sg, 19); ROUND2(B, C, D, A, 0, Sh, 20); + ROUND2(A, B, C, D, 5, Se, 21); ROUND2(D, A, B, C, 10, Sf, 22); + ROUND2(C, D, A, B, 15, Sg, 23); ROUND2(B, C, D, A, 4, Sh, 24); + ROUND2(A, B, C, D, 9, Se, 25); ROUND2(D, A, B, C, 14, Sf, 26); + ROUND2(C, D, A, B, 3, Sg, 27); ROUND2(B, C, D, A, 8, Sh, 28); + ROUND2(A, B, C, D, 13, Se, 29); ROUND2(D, A, B, C, 2, Sf, 30); + ROUND2(C, D, A, B, 7, Sg, 31); ROUND2(B, C, D, A, 12, Sh, 32); + + ROUND3(A, B, C, D, 5, Si, 33); ROUND3(D, A, B, C, 8, Sj, 34); + ROUND3(C, D, A, B, 11, Sk, 35); ROUND3(B, C, D, A, 14, Sl, 36); + ROUND3(A, B, C, D, 1, Si, 37); ROUND3(D, A, B, C, 4, Sj, 38); + ROUND3(C, D, A, B, 7, Sk, 39); ROUND3(B, C, D, A, 10, Sl, 40); + ROUND3(A, B, C, D, 13, Si, 41); ROUND3(D, A, B, C, 0, Sj, 42); + ROUND3(C, D, A, B, 3, Sk, 43); ROUND3(B, C, D, A, 6, Sl, 44); + ROUND3(A, B, C, D, 9, Si, 45); ROUND3(D, A, B, C, 12, Sj, 46); + ROUND3(C, D, A, B, 15, Sk, 47); ROUND3(B, C, D, A, 2, Sl, 48); + + ROUND4(A, B, C, D, 0, Sm, 49); ROUND4(D, A, B, C, 7, Sn, 50); + ROUND4(C, D, A, B, 14, So, 51); ROUND4(B, C, D, A, 5, Sp, 52); + ROUND4(A, B, C, D, 12, Sm, 53); ROUND4(D, A, B, C, 3, Sn, 54); + ROUND4(C, D, A, B, 10, So, 55); ROUND4(B, C, D, A, 1, Sp, 56); + ROUND4(A, B, C, D, 8, Sm, 57); ROUND4(D, A, B, C, 15, Sn, 58); + ROUND4(C, D, A, B, 6, So, 59); ROUND4(B, C, D, A, 13, Sp, 60); + ROUND4(A, B, C, D, 4, Sm, 61); ROUND4(D, A, B, C, 11, Sn, 62); + ROUND4(C, D, A, B, 2, So, 63); ROUND4(B, C, D, A, 9, Sp, 64); + + ctxt->md5_sta += A; + ctxt->md5_stb += B; + ctxt->md5_stc += C; + ctxt->md5_std += D; +} diff --git a/target/linux/generic/files/crypto/ocf/safe/md5.h b/target/linux/generic/files/crypto/ocf/safe/md5.h new file mode 100644 index 0000000..690f5bf --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/safe/md5.h @@ -0,0 +1,76 @@ +/* $FreeBSD: src/sys/crypto/md5.h,v 1.4 2002/03/20 05:13:50 alfred Exp $ */ +/* $KAME: md5.h,v 1.4 2000/03/27 04:36:22 sumikawa Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _NETINET6_MD5_H_ +#define _NETINET6_MD5_H_ + +#define MD5_BUFLEN 64 + +typedef struct { + union { + u_int32_t md5_state32[4]; + u_int8_t md5_state8[16]; + } md5_st; + +#define md5_sta md5_st.md5_state32[0] +#define md5_stb md5_st.md5_state32[1] +#define md5_stc md5_st.md5_state32[2] +#define md5_std md5_st.md5_state32[3] +#define md5_st8 md5_st.md5_state8 + + union { + u_int64_t md5_count64; + u_int8_t md5_count8[8]; + } md5_count; +#define md5_n md5_count.md5_count64 +#define md5_n8 md5_count.md5_count8 + + u_int md5_i; + u_int8_t md5_buf[MD5_BUFLEN]; +} md5_ctxt; + +extern void md5_init(md5_ctxt *); +extern void md5_loop(md5_ctxt *, u_int8_t *, u_int); +extern void md5_pad(md5_ctxt *); +extern void md5_result(u_int8_t *, md5_ctxt *); + +/* compatibility */ +#define MD5_CTX md5_ctxt +#define MD5Init(x) md5_init((x)) +#define MD5Update(x, y, z) md5_loop((x), (y), (z)) +#define MD5Final(x, y) \ +do { \ + md5_pad((y)); \ + md5_result((x), (y)); \ +} while (0) + +#endif /* ! _NETINET6_MD5_H_*/ diff --git a/target/linux/generic/files/crypto/ocf/safe/safe.c b/target/linux/generic/files/crypto/ocf/safe/safe.c new file mode 100644 index 0000000..f4daa5f --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/safe/safe.c @@ -0,0 +1,2230 @@ +/*- + * Linux port done by David McCullough + * Copyright (C) 2004-2010 David McCullough + * The license and original author are listed below. + * + * Copyright (c) 2003 Sam Leffler, Errno Consulting + * Copyright (c) 2003 Global Technology Associates, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * +__FBSDID("$FreeBSD: src/sys/dev/safe/safe.c,v 1.18 2007/03/21 03:42:50 sam Exp $"); + */ + +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) && !defined(AUTOCONF_INCLUDED) +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * SafeNet SafeXcel-1141 hardware crypto accelerator + */ + +#include +#include +#include +#include + +#if 1 +#define DPRINTF(a) do { \ + if (debug) { \ + printk("%s: ", sc ? \ + device_get_nameunit(sc->sc_dev) : "safe"); \ + printk a; \ + } \ + } while (0) +#else +#define DPRINTF(a) +#endif + +/* + * until we find a cleaner way, include the BSD md5/sha1 code + * here + */ +#define HMAC_HACK 1 +#ifdef HMAC_HACK +#include +#include +#include +#include +#include +#endif /* HMAC_HACK */ + +/* add proc entry for this */ +struct safe_stats safestats; + +#define debug safe_debug +int safe_debug = 0; +module_param(safe_debug, int, 0644); +MODULE_PARM_DESC(safe_debug, "Enable debug"); + +static void safe_callback(struct safe_softc *, struct safe_ringentry *); +static void safe_feed(struct safe_softc *, struct safe_ringentry *); +#if defined(CONFIG_OCF_RANDOMHARVEST) && !defined(SAFE_NO_RNG) +static void safe_rng_init(struct safe_softc *); +int safe_rngbufsize = 8; /* 32 bytes each read */ +module_param(safe_rngbufsize, int, 0644); +MODULE_PARM_DESC(safe_rngbufsize, "RNG polling buffer size (32-bit words)"); +int safe_rngmaxalarm = 8; /* max alarms before reset */ +module_param(safe_rngmaxalarm, int, 0644); +MODULE_PARM_DESC(safe_rngmaxalarm, "RNG max alarms before reset"); +#endif /* SAFE_NO_RNG */ + +static void safe_totalreset(struct safe_softc *sc); +static int safe_dmamap_aligned(struct safe_softc *sc, const struct safe_operand *op); +static int safe_dmamap_uniform(struct safe_softc *sc, const struct safe_operand *op); +static int safe_free_entry(struct safe_softc *sc, struct safe_ringentry *re); +static int safe_kprocess(device_t dev, struct cryptkop *krp, int hint); +static int safe_kstart(struct safe_softc *sc); +static int safe_ksigbits(struct safe_softc *sc, struct crparam *cr); +static void safe_kfeed(struct safe_softc *sc); +static void safe_kpoll(unsigned long arg); +static void safe_kload_reg(struct safe_softc *sc, u_int32_t off, + u_int32_t len, struct crparam *n); + +static int safe_newsession(device_t, u_int32_t *, struct cryptoini *); +static int safe_freesession(device_t, u_int64_t); +static int safe_process(device_t, struct cryptop *, int); + +static device_method_t safe_methods = { + /* crypto device methods */ + DEVMETHOD(cryptodev_newsession, safe_newsession), + DEVMETHOD(cryptodev_freesession,safe_freesession), + DEVMETHOD(cryptodev_process, safe_process), + DEVMETHOD(cryptodev_kprocess, safe_kprocess), +}; + +#define READ_REG(sc,r) readl((sc)->sc_base_addr + (r)) +#define WRITE_REG(sc,r,val) writel((val), (sc)->sc_base_addr + (r)) + +#define SAFE_MAX_CHIPS 8 +static struct safe_softc *safe_chip_idx[SAFE_MAX_CHIPS]; + +/* + * split our buffers up into safe DMAable byte fragments to avoid lockup + * bug in 1141 HW on rev 1.0. + */ + +static int +pci_map_linear( + struct safe_softc *sc, + struct safe_operand *buf, + void *addr, + int len) +{ + dma_addr_t tmp; + int chunk, tlen = len; + + tmp = pci_map_single(sc->sc_pcidev, addr, len, PCI_DMA_BIDIRECTIONAL); + + buf->mapsize += len; + while (len > 0) { + chunk = (len > sc->sc_max_dsize) ? sc->sc_max_dsize : len; + buf->segs[buf->nsegs].ds_addr = tmp; + buf->segs[buf->nsegs].ds_len = chunk; + buf->segs[buf->nsegs].ds_tlen = tlen; + buf->nsegs++; + tmp += chunk; + len -= chunk; + tlen = 0; + } + return 0; +} + +/* + * map in a given uio buffer (great on some arches :-) + */ + +static int +pci_map_uio(struct safe_softc *sc, struct safe_operand *buf, struct uio *uio) +{ + struct iovec *iov = uio->uio_iov; + int n; + + DPRINTF(("%s()\n", __FUNCTION__)); + + buf->mapsize = 0; + buf->nsegs = 0; + + for (n = 0; n < uio->uio_iovcnt; n++) { + pci_map_linear(sc, buf, iov->iov_base, iov->iov_len); + iov++; + } + + /* identify this buffer by the first segment */ + buf->map = (void *) buf->segs[0].ds_addr; + return(0); +} + +/* + * map in a given sk_buff + */ + +static int +pci_map_skb(struct safe_softc *sc,struct safe_operand *buf,struct sk_buff *skb) +{ + int i; + + DPRINTF(("%s()\n", __FUNCTION__)); + + buf->mapsize = 0; + buf->nsegs = 0; + + pci_map_linear(sc, buf, skb->data, skb_headlen(skb)); + + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + pci_map_linear(sc, buf, + page_address(skb_frag_page(&skb_shinfo(skb)->frags[i])) + + skb_shinfo(skb)->frags[i].page_offset, + skb_shinfo(skb)->frags[i].size); + } + + /* identify this buffer by the first segment */ + buf->map = (void *) buf->segs[0].ds_addr; + return(0); +} + + +#if 0 /* not needed at this time */ +static void +pci_sync_operand(struct safe_softc *sc, struct safe_operand *buf) +{ + int i; + + DPRINTF(("%s()\n", __FUNCTION__)); + for (i = 0; i < buf->nsegs; i++) + pci_dma_sync_single_for_cpu(sc->sc_pcidev, buf->segs[i].ds_addr, + buf->segs[i].ds_len, PCI_DMA_BIDIRECTIONAL); +} +#endif + +static void +pci_unmap_operand(struct safe_softc *sc, struct safe_operand *buf) +{ + int i; + DPRINTF(("%s()\n", __FUNCTION__)); + for (i = 0; i < buf->nsegs; i++) { + if (buf->segs[i].ds_tlen) { + DPRINTF(("%s - unmap %d 0x%x %d\n", __FUNCTION__, i, buf->segs[i].ds_addr, buf->segs[i].ds_tlen)); + pci_unmap_single(sc->sc_pcidev, buf->segs[i].ds_addr, + buf->segs[i].ds_tlen, PCI_DMA_BIDIRECTIONAL); + DPRINTF(("%s - unmap %d 0x%x %d done\n", __FUNCTION__, i, buf->segs[i].ds_addr, buf->segs[i].ds_tlen)); + } + buf->segs[i].ds_addr = 0; + buf->segs[i].ds_len = 0; + buf->segs[i].ds_tlen = 0; + } + buf->nsegs = 0; + buf->mapsize = 0; + buf->map = 0; +} + + +/* + * SafeXcel Interrupt routine + */ +static irqreturn_t +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19) +safe_intr(int irq, void *arg) +#else +safe_intr(int irq, void *arg, struct pt_regs *regs) +#endif +{ + struct safe_softc *sc = arg; + int stat; + unsigned long flags; + + stat = READ_REG(sc, SAFE_HM_STAT); + + DPRINTF(("%s(stat=0x%x)\n", __FUNCTION__, stat)); + + if (stat == 0) /* shared irq, not for us */ + return IRQ_NONE; + + WRITE_REG(sc, SAFE_HI_CLR, stat); /* IACK */ + + if ((stat & SAFE_INT_PE_DDONE)) { + /* + * Descriptor(s) done; scan the ring and + * process completed operations. + */ + spin_lock_irqsave(&sc->sc_ringmtx, flags); + while (sc->sc_back != sc->sc_front) { + struct safe_ringentry *re = sc->sc_back; + +#ifdef SAFE_DEBUG + if (debug) { + safe_dump_ringstate(sc, __func__); + safe_dump_request(sc, __func__, re); + } +#endif + /* + * safe_process marks ring entries that were allocated + * but not used with a csr of zero. This insures the + * ring front pointer never needs to be set backwards + * in the event that an entry is allocated but not used + * because of a setup error. + */ + DPRINTF(("%s re->re_desc.d_csr=0x%x\n", __FUNCTION__, re->re_desc.d_csr)); + if (re->re_desc.d_csr != 0) { + if (!SAFE_PE_CSR_IS_DONE(re->re_desc.d_csr)) { + DPRINTF(("%s !CSR_IS_DONE\n", __FUNCTION__)); + break; + } + if (!SAFE_PE_LEN_IS_DONE(re->re_desc.d_len)) { + DPRINTF(("%s !LEN_IS_DONE\n", __FUNCTION__)); + break; + } + sc->sc_nqchip--; + safe_callback(sc, re); + } + if (++(sc->sc_back) == sc->sc_ringtop) + sc->sc_back = sc->sc_ring; + } + spin_unlock_irqrestore(&sc->sc_ringmtx, flags); + } + + /* + * Check to see if we got any DMA Error + */ + if (stat & SAFE_INT_PE_ERROR) { + printk("%s: dmaerr dmastat %08x\n", device_get_nameunit(sc->sc_dev), + (int)READ_REG(sc, SAFE_PE_DMASTAT)); + safestats.st_dmaerr++; + safe_totalreset(sc); +#if 0 + safe_feed(sc); +#endif + } + + if (sc->sc_needwakeup) { /* XXX check high watermark */ + int wakeup = sc->sc_needwakeup & (CRYPTO_SYMQ|CRYPTO_ASYMQ); + DPRINTF(("%s: wakeup crypto %x\n", __func__, + sc->sc_needwakeup)); + sc->sc_needwakeup &= ~wakeup; + crypto_unblock(sc->sc_cid, wakeup); + } + + return IRQ_HANDLED; +} + +/* + * safe_feed() - post a request to chip + */ +static void +safe_feed(struct safe_softc *sc, struct safe_ringentry *re) +{ + DPRINTF(("%s()\n", __FUNCTION__)); +#ifdef SAFE_DEBUG + if (debug) { + safe_dump_ringstate(sc, __func__); + safe_dump_request(sc, __func__, re); + } +#endif + sc->sc_nqchip++; + if (sc->sc_nqchip > safestats.st_maxqchip) + safestats.st_maxqchip = sc->sc_nqchip; + /* poke h/w to check descriptor ring, any value can be written */ + WRITE_REG(sc, SAFE_HI_RD_DESCR, 0); +} + +#define N(a) (sizeof(a) / sizeof (a[0])) +static void +safe_setup_enckey(struct safe_session *ses, caddr_t key) +{ + int i; + + bcopy(key, ses->ses_key, ses->ses_klen / 8); + + /* PE is little-endian, insure proper byte order */ + for (i = 0; i < N(ses->ses_key); i++) + ses->ses_key[i] = htole32(ses->ses_key[i]); +} + +static void +safe_setup_mackey(struct safe_session *ses, int algo, caddr_t key, int klen) +{ +#ifdef HMAC_HACK + MD5_CTX md5ctx; + SHA1_CTX sha1ctx; + int i; + + + for (i = 0; i < klen; i++) + key[i] ^= HMAC_IPAD_VAL; + + if (algo == CRYPTO_MD5_HMAC) { + MD5Init(&md5ctx); + MD5Update(&md5ctx, key, klen); + MD5Update(&md5ctx, hmac_ipad_buffer, MD5_HMAC_BLOCK_LEN - klen); + bcopy(md5ctx.md5_st8, ses->ses_hminner, sizeof(md5ctx.md5_st8)); + } else { + SHA1Init(&sha1ctx); + SHA1Update(&sha1ctx, key, klen); + SHA1Update(&sha1ctx, hmac_ipad_buffer, + SHA1_HMAC_BLOCK_LEN - klen); + bcopy(sha1ctx.h.b32, ses->ses_hminner, sizeof(sha1ctx.h.b32)); + } + + for (i = 0; i < klen; i++) + key[i] ^= (HMAC_IPAD_VAL ^ HMAC_OPAD_VAL); + + if (algo == CRYPTO_MD5_HMAC) { + MD5Init(&md5ctx); + MD5Update(&md5ctx, key, klen); + MD5Update(&md5ctx, hmac_opad_buffer, MD5_HMAC_BLOCK_LEN - klen); + bcopy(md5ctx.md5_st8, ses->ses_hmouter, sizeof(md5ctx.md5_st8)); + } else { + SHA1Init(&sha1ctx); + SHA1Update(&sha1ctx, key, klen); + SHA1Update(&sha1ctx, hmac_opad_buffer, + SHA1_HMAC_BLOCK_LEN - klen); + bcopy(sha1ctx.h.b32, ses->ses_hmouter, sizeof(sha1ctx.h.b32)); + } + + for (i = 0; i < klen; i++) + key[i] ^= HMAC_OPAD_VAL; + +#if 0 + /* + * this code prevents SHA working on a BE host, + * so it is obviously wrong. I think the byte + * swap setup we do with the chip fixes this for us + */ + + /* PE is little-endian, insure proper byte order */ + for (i = 0; i < N(ses->ses_hminner); i++) { + ses->ses_hminner[i] = htole32(ses->ses_hminner[i]); + ses->ses_hmouter[i] = htole32(ses->ses_hmouter[i]); + } +#endif +#else /* HMAC_HACK */ + printk("safe: md5/sha not implemented\n"); +#endif /* HMAC_HACK */ +} +#undef N + +/* + * Allocate a new 'session' and return an encoded session id. 'sidp' + * contains our registration id, and should contain an encoded session + * id on successful allocation. + */ +static int +safe_newsession(device_t dev, u_int32_t *sidp, struct cryptoini *cri) +{ + struct safe_softc *sc = device_get_softc(dev); + struct cryptoini *c, *encini = NULL, *macini = NULL; + struct safe_session *ses = NULL; + int sesn; + + DPRINTF(("%s()\n", __FUNCTION__)); + + if (sidp == NULL || cri == NULL || sc == NULL) + return (EINVAL); + + for (c = cri; c != NULL; c = c->cri_next) { + if (c->cri_alg == CRYPTO_MD5_HMAC || + c->cri_alg == CRYPTO_SHA1_HMAC || + c->cri_alg == CRYPTO_NULL_HMAC) { + if (macini) + return (EINVAL); + macini = c; + } else if (c->cri_alg == CRYPTO_DES_CBC || + c->cri_alg == CRYPTO_3DES_CBC || + c->cri_alg == CRYPTO_AES_CBC || + c->cri_alg == CRYPTO_NULL_CBC) { + if (encini) + return (EINVAL); + encini = c; + } else + return (EINVAL); + } + if (encini == NULL && macini == NULL) + return (EINVAL); + if (encini) { /* validate key length */ + switch (encini->cri_alg) { + case CRYPTO_DES_CBC: + if (encini->cri_klen != 64) + return (EINVAL); + break; + case CRYPTO_3DES_CBC: + if (encini->cri_klen != 192) + return (EINVAL); + break; + case CRYPTO_AES_CBC: + if (encini->cri_klen != 128 && + encini->cri_klen != 192 && + encini->cri_klen != 256) + return (EINVAL); + break; + } + } + + if (sc->sc_sessions == NULL) { + ses = sc->sc_sessions = (struct safe_session *) + kmalloc(sizeof(struct safe_session), SLAB_ATOMIC); + if (ses == NULL) + return (ENOMEM); + memset(ses, 0, sizeof(struct safe_session)); + sesn = 0; + sc->sc_nsessions = 1; + } else { + for (sesn = 0; sesn < sc->sc_nsessions; sesn++) { + if (sc->sc_sessions[sesn].ses_used == 0) { + ses = &sc->sc_sessions[sesn]; + break; + } + } + + if (ses == NULL) { + sesn = sc->sc_nsessions; + ses = (struct safe_session *) + kmalloc((sesn + 1) * sizeof(struct safe_session), SLAB_ATOMIC); + if (ses == NULL) + return (ENOMEM); + memset(ses, 0, (sesn + 1) * sizeof(struct safe_session)); + bcopy(sc->sc_sessions, ses, sesn * + sizeof(struct safe_session)); + bzero(sc->sc_sessions, sesn * + sizeof(struct safe_session)); + kfree(sc->sc_sessions); + sc->sc_sessions = ses; + ses = &sc->sc_sessions[sesn]; + sc->sc_nsessions++; + } + } + + bzero(ses, sizeof(struct safe_session)); + ses->ses_used = 1; + + if (encini) { + ses->ses_klen = encini->cri_klen; + if (encini->cri_key != NULL) + safe_setup_enckey(ses, encini->cri_key); + } + + if (macini) { + ses->ses_mlen = macini->cri_mlen; + if (ses->ses_mlen == 0) { + if (macini->cri_alg == CRYPTO_MD5_HMAC) + ses->ses_mlen = MD5_HASH_LEN; + else + ses->ses_mlen = SHA1_HASH_LEN; + } + + if (macini->cri_key != NULL) { + safe_setup_mackey(ses, macini->cri_alg, macini->cri_key, + macini->cri_klen / 8); + } + } + + *sidp = SAFE_SID(device_get_unit(sc->sc_dev), sesn); + return (0); +} + +/* + * Deallocate a session. + */ +static int +safe_freesession(device_t dev, u_int64_t tid) +{ + struct safe_softc *sc = device_get_softc(dev); + int session, ret; + u_int32_t sid = ((u_int32_t) tid) & 0xffffffff; + + DPRINTF(("%s()\n", __FUNCTION__)); + + if (sc == NULL) + return (EINVAL); + + session = SAFE_SESSION(sid); + if (session < sc->sc_nsessions) { + bzero(&sc->sc_sessions[session], sizeof(sc->sc_sessions[session])); + ret = 0; + } else + ret = EINVAL; + return (ret); +} + + +static int +safe_process(device_t dev, struct cryptop *crp, int hint) +{ + struct safe_softc *sc = device_get_softc(dev); + int err = 0, i, nicealign, uniform; + struct cryptodesc *crd1, *crd2, *maccrd, *enccrd; + int bypass, oplen, ivsize; + caddr_t iv; + int16_t coffset; + struct safe_session *ses; + struct safe_ringentry *re; + struct safe_sarec *sa; + struct safe_pdesc *pd; + u_int32_t cmd0, cmd1, staterec, rand_iv[4]; + unsigned long flags; + + DPRINTF(("%s()\n", __FUNCTION__)); + + if (crp == NULL || crp->crp_callback == NULL || sc == NULL) { + safestats.st_invalid++; + return (EINVAL); + } + if (SAFE_SESSION(crp->crp_sid) >= sc->sc_nsessions) { + safestats.st_badsession++; + return (EINVAL); + } + + spin_lock_irqsave(&sc->sc_ringmtx, flags); + if (sc->sc_front == sc->sc_back && sc->sc_nqchip != 0) { + safestats.st_ringfull++; + sc->sc_needwakeup |= CRYPTO_SYMQ; + spin_unlock_irqrestore(&sc->sc_ringmtx, flags); + return (ERESTART); + } + re = sc->sc_front; + + staterec = re->re_sa.sa_staterec; /* save */ + /* NB: zero everything but the PE descriptor */ + bzero(&re->re_sa, sizeof(struct safe_ringentry) - sizeof(re->re_desc)); + re->re_sa.sa_staterec = staterec; /* restore */ + + re->re_crp = crp; + re->re_sesn = SAFE_SESSION(crp->crp_sid); + + re->re_src.nsegs = 0; + re->re_dst.nsegs = 0; + + if (crp->crp_flags & CRYPTO_F_SKBUF) { + re->re_src_skb = (struct sk_buff *)crp->crp_buf; + re->re_dst_skb = (struct sk_buff *)crp->crp_buf; + } else if (crp->crp_flags & CRYPTO_F_IOV) { + re->re_src_io = (struct uio *)crp->crp_buf; + re->re_dst_io = (struct uio *)crp->crp_buf; + } else { + safestats.st_badflags++; + err = EINVAL; + goto errout; /* XXX we don't handle contiguous blocks! */ + } + + sa = &re->re_sa; + ses = &sc->sc_sessions[re->re_sesn]; + + crd1 = crp->crp_desc; + if (crd1 == NULL) { + safestats.st_nodesc++; + err = EINVAL; + goto errout; + } + crd2 = crd1->crd_next; + + cmd0 = SAFE_SA_CMD0_BASIC; /* basic group operation */ + cmd1 = 0; + if (crd2 == NULL) { + if (crd1->crd_alg == CRYPTO_MD5_HMAC || + crd1->crd_alg == CRYPTO_SHA1_HMAC || + crd1->crd_alg == CRYPTO_NULL_HMAC) { + maccrd = crd1; + enccrd = NULL; + cmd0 |= SAFE_SA_CMD0_OP_HASH; + } else if (crd1->crd_alg == CRYPTO_DES_CBC || + crd1->crd_alg == CRYPTO_3DES_CBC || + crd1->crd_alg == CRYPTO_AES_CBC || + crd1->crd_alg == CRYPTO_NULL_CBC) { + maccrd = NULL; + enccrd = crd1; + cmd0 |= SAFE_SA_CMD0_OP_CRYPT; + } else { + safestats.st_badalg++; + err = EINVAL; + goto errout; + } + } else { + if ((crd1->crd_alg == CRYPTO_MD5_HMAC || + crd1->crd_alg == CRYPTO_SHA1_HMAC || + crd1->crd_alg == CRYPTO_NULL_HMAC) && + (crd2->crd_alg == CRYPTO_DES_CBC || + crd2->crd_alg == CRYPTO_3DES_CBC || + crd2->crd_alg == CRYPTO_AES_CBC || + crd2->crd_alg == CRYPTO_NULL_CBC) && + ((crd2->crd_flags & CRD_F_ENCRYPT) == 0)) { + maccrd = crd1; + enccrd = crd2; + } else if ((crd1->crd_alg == CRYPTO_DES_CBC || + crd1->crd_alg == CRYPTO_3DES_CBC || + crd1->crd_alg == CRYPTO_AES_CBC || + crd1->crd_alg == CRYPTO_NULL_CBC) && + (crd2->crd_alg == CRYPTO_MD5_HMAC || + crd2->crd_alg == CRYPTO_SHA1_HMAC || + crd2->crd_alg == CRYPTO_NULL_HMAC) && + (crd1->crd_flags & CRD_F_ENCRYPT)) { + enccrd = crd1; + maccrd = crd2; + } else { + safestats.st_badalg++; + err = EINVAL; + goto errout; + } + cmd0 |= SAFE_SA_CMD0_OP_BOTH; + } + + if (enccrd) { + if (enccrd->crd_flags & CRD_F_KEY_EXPLICIT) + safe_setup_enckey(ses, enccrd->crd_key); + + if (enccrd->crd_alg == CRYPTO_DES_CBC) { + cmd0 |= SAFE_SA_CMD0_DES; + cmd1 |= SAFE_SA_CMD1_CBC; + ivsize = 2*sizeof(u_int32_t); + } else if (enccrd->crd_alg == CRYPTO_3DES_CBC) { + cmd0 |= SAFE_SA_CMD0_3DES; + cmd1 |= SAFE_SA_CMD1_CBC; + ivsize = 2*sizeof(u_int32_t); + } else if (enccrd->crd_alg == CRYPTO_AES_CBC) { + cmd0 |= SAFE_SA_CMD0_AES; + cmd1 |= SAFE_SA_CMD1_CBC; + if (ses->ses_klen == 128) + cmd1 |= SAFE_SA_CMD1_AES128; + else if (ses->ses_klen == 192) + cmd1 |= SAFE_SA_CMD1_AES192; + else + cmd1 |= SAFE_SA_CMD1_AES256; + ivsize = 4*sizeof(u_int32_t); + } else { + cmd0 |= SAFE_SA_CMD0_CRYPT_NULL; + ivsize = 0; + } + + /* + * Setup encrypt/decrypt state. When using basic ops + * we can't use an inline IV because hash/crypt offset + * must be from the end of the IV to the start of the + * crypt data and this leaves out the preceding header + * from the hash calculation. Instead we place the IV + * in the state record and set the hash/crypt offset to + * copy both the header+IV. + */ + if (enccrd->crd_flags & CRD_F_ENCRYPT) { + cmd0 |= SAFE_SA_CMD0_OUTBOUND; + + if (enccrd->crd_flags & CRD_F_IV_EXPLICIT) + iv = enccrd->crd_iv; + else + read_random((iv = (caddr_t) &rand_iv[0]), sizeof(rand_iv)); + if ((enccrd->crd_flags & CRD_F_IV_PRESENT) == 0) { + crypto_copyback(crp->crp_flags, crp->crp_buf, + enccrd->crd_inject, ivsize, iv); + } + bcopy(iv, re->re_sastate.sa_saved_iv, ivsize); + /* make iv LE */ + for (i = 0; i < ivsize/sizeof(re->re_sastate.sa_saved_iv[0]); i++) + re->re_sastate.sa_saved_iv[i] = + cpu_to_le32(re->re_sastate.sa_saved_iv[i]); + cmd0 |= SAFE_SA_CMD0_IVLD_STATE | SAFE_SA_CMD0_SAVEIV; + re->re_flags |= SAFE_QFLAGS_COPYOUTIV; + } else { + cmd0 |= SAFE_SA_CMD0_INBOUND; + + if (enccrd->crd_flags & CRD_F_IV_EXPLICIT) { + bcopy(enccrd->crd_iv, + re->re_sastate.sa_saved_iv, ivsize); + } else { + crypto_copydata(crp->crp_flags, crp->crp_buf, + enccrd->crd_inject, ivsize, + (caddr_t)re->re_sastate.sa_saved_iv); + } + /* make iv LE */ + for (i = 0; i < ivsize/sizeof(re->re_sastate.sa_saved_iv[0]); i++) + re->re_sastate.sa_saved_iv[i] = + cpu_to_le32(re->re_sastate.sa_saved_iv[i]); + cmd0 |= SAFE_SA_CMD0_IVLD_STATE; + } + /* + * For basic encryption use the zero pad algorithm. + * This pads results to an 8-byte boundary and + * suppresses padding verification for inbound (i.e. + * decrypt) operations. + * + * NB: Not sure if the 8-byte pad boundary is a problem. + */ + cmd0 |= SAFE_SA_CMD0_PAD_ZERO; + + /* XXX assert key bufs have the same size */ + bcopy(ses->ses_key, sa->sa_key, sizeof(sa->sa_key)); + } + + if (maccrd) { + if (maccrd->crd_flags & CRD_F_KEY_EXPLICIT) { + safe_setup_mackey(ses, maccrd->crd_alg, + maccrd->crd_key, maccrd->crd_klen / 8); + } + + if (maccrd->crd_alg == CRYPTO_MD5_HMAC) { + cmd0 |= SAFE_SA_CMD0_MD5; + cmd1 |= SAFE_SA_CMD1_HMAC; /* NB: enable HMAC */ + } else if (maccrd->crd_alg == CRYPTO_SHA1_HMAC) { + cmd0 |= SAFE_SA_CMD0_SHA1; + cmd1 |= SAFE_SA_CMD1_HMAC; /* NB: enable HMAC */ + } else { + cmd0 |= SAFE_SA_CMD0_HASH_NULL; + } + /* + * Digest data is loaded from the SA and the hash + * result is saved to the state block where we + * retrieve it for return to the caller. + */ + /* XXX assert digest bufs have the same size */ + bcopy(ses->ses_hminner, sa->sa_indigest, + sizeof(sa->sa_indigest)); + bcopy(ses->ses_hmouter, sa->sa_outdigest, + sizeof(sa->sa_outdigest)); + + cmd0 |= SAFE_SA_CMD0_HSLD_SA | SAFE_SA_CMD0_SAVEHASH; + re->re_flags |= SAFE_QFLAGS_COPYOUTICV; + } + + if (enccrd && maccrd) { + /* + * The offset from hash data to the start of + * crypt data is the difference in the skips. + */ + bypass = maccrd->crd_skip; + coffset = enccrd->crd_skip - maccrd->crd_skip; + if (coffset < 0) { + DPRINTF(("%s: hash does not precede crypt; " + "mac skip %u enc skip %u\n", + __func__, maccrd->crd_skip, enccrd->crd_skip)); + safestats.st_skipmismatch++; + err = EINVAL; + goto errout; + } + oplen = enccrd->crd_skip + enccrd->crd_len; + if (maccrd->crd_skip + maccrd->crd_len != oplen) { + DPRINTF(("%s: hash amount %u != crypt amount %u\n", + __func__, maccrd->crd_skip + maccrd->crd_len, + oplen)); + safestats.st_lenmismatch++; + err = EINVAL; + goto errout; + } +#ifdef SAFE_DEBUG + if (debug) { + printf("mac: skip %d, len %d, inject %d\n", + maccrd->crd_skip, maccrd->crd_len, + maccrd->crd_inject); + printf("enc: skip %d, len %d, inject %d\n", + enccrd->crd_skip, enccrd->crd_len, + enccrd->crd_inject); + printf("bypass %d coffset %d oplen %d\n", + bypass, coffset, oplen); + } +#endif + if (coffset & 3) { /* offset must be 32-bit aligned */ + DPRINTF(("%s: coffset %u misaligned\n", + __func__, coffset)); + safestats.st_coffmisaligned++; + err = EINVAL; + goto errout; + } + coffset >>= 2; + if (coffset > 255) { /* offset must be <256 dwords */ + DPRINTF(("%s: coffset %u too big\n", + __func__, coffset)); + safestats.st_cofftoobig++; + err = EINVAL; + goto errout; + } + /* + * Tell the hardware to copy the header to the output. + * The header is defined as the data from the end of + * the bypass to the start of data to be encrypted. + * Typically this is the inline IV. Note that you need + * to do this even if src+dst are the same; it appears + * that w/o this bit the crypted data is written + * immediately after the bypass data. + */ + cmd1 |= SAFE_SA_CMD1_HDRCOPY; + /* + * Disable IP header mutable bit handling. This is + * needed to get correct HMAC calculations. + */ + cmd1 |= SAFE_SA_CMD1_MUTABLE; + } else { + if (enccrd) { + bypass = enccrd->crd_skip; + oplen = bypass + enccrd->crd_len; + } else { + bypass = maccrd->crd_skip; + oplen = bypass + maccrd->crd_len; + } + coffset = 0; + } + /* XXX verify multiple of 4 when using s/g */ + if (bypass > 96) { /* bypass offset must be <= 96 bytes */ + DPRINTF(("%s: bypass %u too big\n", __func__, bypass)); + safestats.st_bypasstoobig++; + err = EINVAL; + goto errout; + } + + if (crp->crp_flags & CRYPTO_F_SKBUF) { + if (pci_map_skb(sc, &re->re_src, re->re_src_skb)) { + safestats.st_noload++; + err = ENOMEM; + goto errout; + } + } else if (crp->crp_flags & CRYPTO_F_IOV) { + if (pci_map_uio(sc, &re->re_src, re->re_src_io)) { + safestats.st_noload++; + err = ENOMEM; + goto errout; + } + } + nicealign = safe_dmamap_aligned(sc, &re->re_src); + uniform = safe_dmamap_uniform(sc, &re->re_src); + + DPRINTF(("src nicealign %u uniform %u nsegs %u\n", + nicealign, uniform, re->re_src.nsegs)); + if (re->re_src.nsegs > 1) { + re->re_desc.d_src = sc->sc_spalloc.dma_paddr + + ((caddr_t) sc->sc_spfree - (caddr_t) sc->sc_spring); + for (i = 0; i < re->re_src_nsegs; i++) { + /* NB: no need to check if there's space */ + pd = sc->sc_spfree; + if (++(sc->sc_spfree) == sc->sc_springtop) + sc->sc_spfree = sc->sc_spring; + + KASSERT((pd->pd_flags&3) == 0 || + (pd->pd_flags&3) == SAFE_PD_DONE, + ("bogus source particle descriptor; flags %x", + pd->pd_flags)); + pd->pd_addr = re->re_src_segs[i].ds_addr; + pd->pd_size = re->re_src_segs[i].ds_len; + pd->pd_flags = SAFE_PD_READY; + } + cmd0 |= SAFE_SA_CMD0_IGATHER; + } else { + /* + * No need for gather, reference the operand directly. + */ + re->re_desc.d_src = re->re_src_segs[0].ds_addr; + } + + if (enccrd == NULL && maccrd != NULL) { + /* + * Hash op; no destination needed. + */ + } else { + if (crp->crp_flags & (CRYPTO_F_IOV|CRYPTO_F_SKBUF)) { + if (!nicealign) { + safestats.st_iovmisaligned++; + err = EINVAL; + goto errout; + } + if (uniform != 1) { + device_printf(sc->sc_dev, "!uniform source\n"); + if (!uniform) { + /* + * There's no way to handle the DMA + * requirements with this uio. We + * could create a separate DMA area for + * the result and then copy it back, + * but for now we just bail and return + * an error. Note that uio requests + * > SAFE_MAX_DSIZE are handled because + * the DMA map and segment list for the + * destination wil result in a + * destination particle list that does + * the necessary scatter DMA. + */ + safestats.st_iovnotuniform++; + err = EINVAL; + goto errout; + } + } else + re->re_dst = re->re_src; + } else { + safestats.st_badflags++; + err = EINVAL; + goto errout; + } + + if (re->re_dst.nsegs > 1) { + re->re_desc.d_dst = sc->sc_dpalloc.dma_paddr + + ((caddr_t) sc->sc_dpfree - (caddr_t) sc->sc_dpring); + for (i = 0; i < re->re_dst_nsegs; i++) { + pd = sc->sc_dpfree; + KASSERT((pd->pd_flags&3) == 0 || + (pd->pd_flags&3) == SAFE_PD_DONE, + ("bogus dest particle descriptor; flags %x", + pd->pd_flags)); + if (++(sc->sc_dpfree) == sc->sc_dpringtop) + sc->sc_dpfree = sc->sc_dpring; + pd->pd_addr = re->re_dst_segs[i].ds_addr; + pd->pd_flags = SAFE_PD_READY; + } + cmd0 |= SAFE_SA_CMD0_OSCATTER; + } else { + /* + * No need for scatter, reference the operand directly. + */ + re->re_desc.d_dst = re->re_dst_segs[0].ds_addr; + } + } + + /* + * All done with setup; fillin the SA command words + * and the packet engine descriptor. The operation + * is now ready for submission to the hardware. + */ + sa->sa_cmd0 = cmd0 | SAFE_SA_CMD0_IPCI | SAFE_SA_CMD0_OPCI; + sa->sa_cmd1 = cmd1 + | (coffset << SAFE_SA_CMD1_OFFSET_S) + | SAFE_SA_CMD1_SAREV1 /* Rev 1 SA data structure */ + | SAFE_SA_CMD1_SRPCI + ; + /* + * NB: the order of writes is important here. In case the + * chip is scanning the ring because of an outstanding request + * it might nab this one too. In that case we need to make + * sure the setup is complete before we write the length + * field of the descriptor as it signals the descriptor is + * ready for processing. + */ + re->re_desc.d_csr = SAFE_PE_CSR_READY | SAFE_PE_CSR_SAPCI; + if (maccrd) + re->re_desc.d_csr |= SAFE_PE_CSR_LOADSA | SAFE_PE_CSR_HASHFINAL; + wmb(); + re->re_desc.d_len = oplen + | SAFE_PE_LEN_READY + | (bypass << SAFE_PE_LEN_BYPASS_S) + ; + + safestats.st_ipackets++; + safestats.st_ibytes += oplen; + + if (++(sc->sc_front) == sc->sc_ringtop) + sc->sc_front = sc->sc_ring; + + /* XXX honor batching */ + safe_feed(sc, re); + spin_unlock_irqrestore(&sc->sc_ringmtx, flags); + return (0); + +errout: + if (re->re_src.map != re->re_dst.map) + pci_unmap_operand(sc, &re->re_dst); + if (re->re_src.map) + pci_unmap_operand(sc, &re->re_src); + spin_unlock_irqrestore(&sc->sc_ringmtx, flags); + if (err != ERESTART) { + crp->crp_etype = err; + crypto_done(crp); + } else { + sc->sc_needwakeup |= CRYPTO_SYMQ; + } + return (err); +} + +static void +safe_callback(struct safe_softc *sc, struct safe_ringentry *re) +{ + struct cryptop *crp = (struct cryptop *)re->re_crp; + struct cryptodesc *crd; + + DPRINTF(("%s()\n", __FUNCTION__)); + + safestats.st_opackets++; + safestats.st_obytes += re->re_dst.mapsize; + + if (re->re_desc.d_csr & SAFE_PE_CSR_STATUS) { + device_printf(sc->sc_dev, "csr 0x%x cmd0 0x%x cmd1 0x%x\n", + re->re_desc.d_csr, + re->re_sa.sa_cmd0, re->re_sa.sa_cmd1); + safestats.st_peoperr++; + crp->crp_etype = EIO; /* something more meaningful? */ + } + + if (re->re_dst.map != NULL && re->re_dst.map != re->re_src.map) + pci_unmap_operand(sc, &re->re_dst); + pci_unmap_operand(sc, &re->re_src); + + /* + * If result was written to a differet mbuf chain, swap + * it in as the return value and reclaim the original. + */ + if ((crp->crp_flags & CRYPTO_F_SKBUF) && re->re_src_skb != re->re_dst_skb) { + device_printf(sc->sc_dev, "no CRYPTO_F_SKBUF swapping support\n"); + /* kfree_skb(skb) */ + /* crp->crp_buf = (caddr_t)re->re_dst_skb */ + return; + } + + if (re->re_flags & SAFE_QFLAGS_COPYOUTICV) { + /* copy out ICV result */ + for (crd = crp->crp_desc; crd; crd = crd->crd_next) { + if (!(crd->crd_alg == CRYPTO_MD5_HMAC || + crd->crd_alg == CRYPTO_SHA1_HMAC || + crd->crd_alg == CRYPTO_NULL_HMAC)) + continue; + if (crd->crd_alg == CRYPTO_SHA1_HMAC) { + /* + * SHA-1 ICV's are byte-swapped; fix 'em up + * before copy them to their destination. + */ + re->re_sastate.sa_saved_indigest[0] = + cpu_to_be32(re->re_sastate.sa_saved_indigest[0]); + re->re_sastate.sa_saved_indigest[1] = + cpu_to_be32(re->re_sastate.sa_saved_indigest[1]); + re->re_sastate.sa_saved_indigest[2] = + cpu_to_be32(re->re_sastate.sa_saved_indigest[2]); + } else { + re->re_sastate.sa_saved_indigest[0] = + cpu_to_le32(re->re_sastate.sa_saved_indigest[0]); + re->re_sastate.sa_saved_indigest[1] = + cpu_to_le32(re->re_sastate.sa_saved_indigest[1]); + re->re_sastate.sa_saved_indigest[2] = + cpu_to_le32(re->re_sastate.sa_saved_indigest[2]); + } + crypto_copyback(crp->crp_flags, crp->crp_buf, + crd->crd_inject, + sc->sc_sessions[re->re_sesn].ses_mlen, + (caddr_t)re->re_sastate.sa_saved_indigest); + break; + } + } + crypto_done(crp); +} + + +#if defined(CONFIG_OCF_RANDOMHARVEST) && !defined(SAFE_NO_RNG) +#define SAFE_RNG_MAXWAIT 1000 + +static void +safe_rng_init(struct safe_softc *sc) +{ + u_int32_t w, v; + int i; + + DPRINTF(("%s()\n", __FUNCTION__)); + + WRITE_REG(sc, SAFE_RNG_CTRL, 0); + /* use default value according to the manual */ + WRITE_REG(sc, SAFE_RNG_CNFG, 0x834); /* magic from SafeNet */ + WRITE_REG(sc, SAFE_RNG_ALM_CNT, 0); + + /* + * There is a bug in rev 1.0 of the 1140 that when the RNG + * is brought out of reset the ready status flag does not + * work until the RNG has finished its internal initialization. + * + * So in order to determine the device is through its + * initialization we must read the data register, using the + * status reg in the read in case it is initialized. Then read + * the data register until it changes from the first read. + * Once it changes read the data register until it changes + * again. At this time the RNG is considered initialized. + * This could take between 750ms - 1000ms in time. + */ + i = 0; + w = READ_REG(sc, SAFE_RNG_OUT); + do { + v = READ_REG(sc, SAFE_RNG_OUT); + if (v != w) { + w = v; + break; + } + DELAY(10); + } while (++i < SAFE_RNG_MAXWAIT); + + /* Wait Until data changes again */ + i = 0; + do { + v = READ_REG(sc, SAFE_RNG_OUT); + if (v != w) + break; + DELAY(10); + } while (++i < SAFE_RNG_MAXWAIT); +} + +static __inline void +safe_rng_disable_short_cycle(struct safe_softc *sc) +{ + DPRINTF(("%s()\n", __FUNCTION__)); + + WRITE_REG(sc, SAFE_RNG_CTRL, + READ_REG(sc, SAFE_RNG_CTRL) &~ SAFE_RNG_CTRL_SHORTEN); +} + +static __inline void +safe_rng_enable_short_cycle(struct safe_softc *sc) +{ + DPRINTF(("%s()\n", __FUNCTION__)); + + WRITE_REG(sc, SAFE_RNG_CTRL, + READ_REG(sc, SAFE_RNG_CTRL) | SAFE_RNG_CTRL_SHORTEN); +} + +static __inline u_int32_t +safe_rng_read(struct safe_softc *sc) +{ + int i; + + i = 0; + while (READ_REG(sc, SAFE_RNG_STAT) != 0 && ++i < SAFE_RNG_MAXWAIT) + ; + return READ_REG(sc, SAFE_RNG_OUT); +} + +static int +safe_read_random(void *arg, u_int32_t *buf, int maxwords) +{ + struct safe_softc *sc = (struct safe_softc *) arg; + int i, rc; + + DPRINTF(("%s()\n", __FUNCTION__)); + + safestats.st_rng++; + /* + * Fetch the next block of data. + */ + if (maxwords > safe_rngbufsize) + maxwords = safe_rngbufsize; + if (maxwords > SAFE_RNG_MAXBUFSIZ) + maxwords = SAFE_RNG_MAXBUFSIZ; +retry: + /* read as much as we can */ + for (rc = 0; rc < maxwords; rc++) { + if (READ_REG(sc, SAFE_RNG_STAT) != 0) + break; + buf[rc] = READ_REG(sc, SAFE_RNG_OUT); + } + if (rc == 0) + return 0; + /* + * Check the comparator alarm count and reset the h/w if + * it exceeds our threshold. This guards against the + * hardware oscillators resonating with external signals. + */ + if (READ_REG(sc, SAFE_RNG_ALM_CNT) > safe_rngmaxalarm) { + u_int32_t freq_inc, w; + + DPRINTF(("%s: alarm count %u exceeds threshold %u\n", __func__, + (unsigned)READ_REG(sc, SAFE_RNG_ALM_CNT), safe_rngmaxalarm)); + safestats.st_rngalarm++; + safe_rng_enable_short_cycle(sc); + freq_inc = 18; + for (i = 0; i < 64; i++) { + w = READ_REG(sc, SAFE_RNG_CNFG); + freq_inc = ((w + freq_inc) & 0x3fL); + w = ((w & ~0x3fL) | freq_inc); + WRITE_REG(sc, SAFE_RNG_CNFG, w); + + WRITE_REG(sc, SAFE_RNG_ALM_CNT, 0); + + (void) safe_rng_read(sc); + DELAY(25); + + if (READ_REG(sc, SAFE_RNG_ALM_CNT) == 0) { + safe_rng_disable_short_cycle(sc); + goto retry; + } + freq_inc = 1; + } + safe_rng_disable_short_cycle(sc); + } else + WRITE_REG(sc, SAFE_RNG_ALM_CNT, 0); + + return(rc); +} +#endif /* defined(CONFIG_OCF_RANDOMHARVEST) && !defined(SAFE_NO_RNG) */ + + +/* + * Resets the board. Values in the regesters are left as is + * from the reset (i.e. initial values are assigned elsewhere). + */ +static void +safe_reset_board(struct safe_softc *sc) +{ + u_int32_t v; + /* + * Reset the device. The manual says no delay + * is needed between marking and clearing reset. + */ + DPRINTF(("%s()\n", __FUNCTION__)); + + v = READ_REG(sc, SAFE_PE_DMACFG) &~ + (SAFE_PE_DMACFG_PERESET | SAFE_PE_DMACFG_PDRRESET | + SAFE_PE_DMACFG_SGRESET); + WRITE_REG(sc, SAFE_PE_DMACFG, v + | SAFE_PE_DMACFG_PERESET + | SAFE_PE_DMACFG_PDRRESET + | SAFE_PE_DMACFG_SGRESET); + WRITE_REG(sc, SAFE_PE_DMACFG, v); +} + +/* + * Initialize registers we need to touch only once. + */ +static void +safe_init_board(struct safe_softc *sc) +{ + u_int32_t v, dwords; + + DPRINTF(("%s()\n", __FUNCTION__)); + + v = READ_REG(sc, SAFE_PE_DMACFG); + v &=~ ( SAFE_PE_DMACFG_PEMODE + | SAFE_PE_DMACFG_FSENA /* failsafe enable */ + | SAFE_PE_DMACFG_GPRPCI /* gather ring on PCI */ + | SAFE_PE_DMACFG_SPRPCI /* scatter ring on PCI */ + | SAFE_PE_DMACFG_ESDESC /* endian-swap descriptors */ + | SAFE_PE_DMACFG_ESPDESC /* endian-swap part. desc's */ + | SAFE_PE_DMACFG_ESSA /* endian-swap SA's */ + | SAFE_PE_DMACFG_ESPACKET /* swap the packet data */ + ); + v |= SAFE_PE_DMACFG_FSENA /* failsafe enable */ + | SAFE_PE_DMACFG_GPRPCI /* gather ring on PCI */ + | SAFE_PE_DMACFG_SPRPCI /* scatter ring on PCI */ + | SAFE_PE_DMACFG_ESDESC /* endian-swap descriptors */ + | SAFE_PE_DMACFG_ESPDESC /* endian-swap part. desc's */ + | SAFE_PE_DMACFG_ESSA /* endian-swap SA's */ +#if 0 + | SAFE_PE_DMACFG_ESPACKET /* swap the packet data */ +#endif + ; + WRITE_REG(sc, SAFE_PE_DMACFG, v); + +#ifdef __BIG_ENDIAN + /* tell the safenet that we are 4321 and not 1234 */ + WRITE_REG(sc, SAFE_ENDIAN, 0xe4e41b1b); +#endif + + if (sc->sc_chiprev == SAFE_REV(1,0)) { + /* + * Avoid large PCI DMA transfers. Rev 1.0 has a bug where + * "target mode transfers" done while the chip is DMA'ing + * >1020 bytes cause the hardware to lockup. To avoid this + * we reduce the max PCI transfer size and use small source + * particle descriptors (<= 256 bytes). + */ + WRITE_REG(sc, SAFE_DMA_CFG, 256); + device_printf(sc->sc_dev, + "Reduce max DMA size to %u words for rev %u.%u WAR\n", + (unsigned) ((READ_REG(sc, SAFE_DMA_CFG)>>2) & 0xff), + (unsigned) SAFE_REV_MAJ(sc->sc_chiprev), + (unsigned) SAFE_REV_MIN(sc->sc_chiprev)); + sc->sc_max_dsize = 256; + } else { + sc->sc_max_dsize = SAFE_MAX_DSIZE; + } + + /* NB: operands+results are overlaid */ + WRITE_REG(sc, SAFE_PE_PDRBASE, sc->sc_ringalloc.dma_paddr); + WRITE_REG(sc, SAFE_PE_RDRBASE, sc->sc_ringalloc.dma_paddr); + /* + * Configure ring entry size and number of items in the ring. + */ + KASSERT((sizeof(struct safe_ringentry) % sizeof(u_int32_t)) == 0, + ("PE ring entry not 32-bit aligned!")); + dwords = sizeof(struct safe_ringentry) / sizeof(u_int32_t); + WRITE_REG(sc, SAFE_PE_RINGCFG, + (dwords << SAFE_PE_RINGCFG_OFFSET_S) | SAFE_MAX_NQUEUE); + WRITE_REG(sc, SAFE_PE_RINGPOLL, 0); /* disable polling */ + + WRITE_REG(sc, SAFE_PE_GRNGBASE, sc->sc_spalloc.dma_paddr); + WRITE_REG(sc, SAFE_PE_SRNGBASE, sc->sc_dpalloc.dma_paddr); + WRITE_REG(sc, SAFE_PE_PARTSIZE, + (SAFE_TOTAL_DPART<<16) | SAFE_TOTAL_SPART); + /* + * NB: destination particles are fixed size. We use + * an mbuf cluster and require all results go to + * clusters or smaller. + */ + WRITE_REG(sc, SAFE_PE_PARTCFG, sc->sc_max_dsize); + + /* it's now safe to enable PE mode, do it */ + WRITE_REG(sc, SAFE_PE_DMACFG, v | SAFE_PE_DMACFG_PEMODE); + + /* + * Configure hardware to use level-triggered interrupts and + * to interrupt after each descriptor is processed. + */ + WRITE_REG(sc, SAFE_HI_CFG, SAFE_HI_CFG_LEVEL); + WRITE_REG(sc, SAFE_HI_CLR, 0xffffffff); + WRITE_REG(sc, SAFE_HI_DESC_CNT, 1); + WRITE_REG(sc, SAFE_HI_MASK, SAFE_INT_PE_DDONE | SAFE_INT_PE_ERROR); +} + + +/* + * Clean up after a chip crash. + * It is assumed that the caller in splimp() + */ +static void +safe_cleanchip(struct safe_softc *sc) +{ + DPRINTF(("%s()\n", __FUNCTION__)); + + if (sc->sc_nqchip != 0) { + struct safe_ringentry *re = sc->sc_back; + + while (re != sc->sc_front) { + if (re->re_desc.d_csr != 0) + safe_free_entry(sc, re); + if (++re == sc->sc_ringtop) + re = sc->sc_ring; + } + sc->sc_back = re; + sc->sc_nqchip = 0; + } +} + +/* + * free a safe_q + * It is assumed that the caller is within splimp(). + */ +static int +safe_free_entry(struct safe_softc *sc, struct safe_ringentry *re) +{ + struct cryptop *crp; + + DPRINTF(("%s()\n", __FUNCTION__)); + + /* + * Free header MCR + */ + if ((re->re_dst_skb != NULL) && (re->re_src_skb != re->re_dst_skb)) +#ifdef NOTYET + m_freem(re->re_dst_m); +#else + printk("%s,%d: SKB not supported\n", __FILE__, __LINE__); +#endif + + crp = (struct cryptop *)re->re_crp; + + re->re_desc.d_csr = 0; + + crp->crp_etype = EFAULT; + crypto_done(crp); + return(0); +} + +/* + * Routine to reset the chip and clean up. + * It is assumed that the caller is in splimp() + */ +static void +safe_totalreset(struct safe_softc *sc) +{ + DPRINTF(("%s()\n", __FUNCTION__)); + + safe_reset_board(sc); + safe_init_board(sc); + safe_cleanchip(sc); +} + +/* + * Is the operand suitable aligned for direct DMA. Each + * segment must be aligned on a 32-bit boundary and all + * but the last segment must be a multiple of 4 bytes. + */ +static int +safe_dmamap_aligned(struct safe_softc *sc, const struct safe_operand *op) +{ + int i; + + DPRINTF(("%s()\n", __FUNCTION__)); + + for (i = 0; i < op->nsegs; i++) { + if (op->segs[i].ds_addr & 3) + return (0); + if (i != (op->nsegs - 1) && (op->segs[i].ds_len & 3)) + return (0); + } + return (1); +} + +/* + * Is the operand suitable for direct DMA as the destination + * of an operation. The hardware requires that each ``particle'' + * but the last in an operation result have the same size. We + * fix that size at SAFE_MAX_DSIZE bytes. This routine returns + * 0 if some segment is not a multiple of of this size, 1 if all + * segments are exactly this size, or 2 if segments are at worst + * a multple of this size. + */ +static int +safe_dmamap_uniform(struct safe_softc *sc, const struct safe_operand *op) +{ + int result = 1; + + DPRINTF(("%s()\n", __FUNCTION__)); + + if (op->nsegs > 0) { + int i; + + for (i = 0; i < op->nsegs-1; i++) { + if (op->segs[i].ds_len % sc->sc_max_dsize) + return (0); + if (op->segs[i].ds_len != sc->sc_max_dsize) + result = 2; + } + } + return (result); +} + +static int +safe_kprocess(device_t dev, struct cryptkop *krp, int hint) +{ + struct safe_softc *sc = device_get_softc(dev); + struct safe_pkq *q; + unsigned long flags; + + DPRINTF(("%s()\n", __FUNCTION__)); + + if (sc == NULL) { + krp->krp_status = EINVAL; + goto err; + } + + if (krp->krp_op != CRK_MOD_EXP) { + krp->krp_status = EOPNOTSUPP; + goto err; + } + + q = (struct safe_pkq *) kmalloc(sizeof(*q), GFP_KERNEL); + if (q == NULL) { + krp->krp_status = ENOMEM; + goto err; + } + memset(q, 0, sizeof(*q)); + q->pkq_krp = krp; + INIT_LIST_HEAD(&q->pkq_list); + + spin_lock_irqsave(&sc->sc_pkmtx, flags); + list_add_tail(&q->pkq_list, &sc->sc_pkq); + safe_kfeed(sc); + spin_unlock_irqrestore(&sc->sc_pkmtx, flags); + return (0); + +err: + crypto_kdone(krp); + return (0); +} + +#define SAFE_CRK_PARAM_BASE 0 +#define SAFE_CRK_PARAM_EXP 1 +#define SAFE_CRK_PARAM_MOD 2 + +static int +safe_kstart(struct safe_softc *sc) +{ + struct cryptkop *krp = sc->sc_pkq_cur->pkq_krp; + int exp_bits, mod_bits, base_bits; + u_int32_t op, a_off, b_off, c_off, d_off; + + DPRINTF(("%s()\n", __FUNCTION__)); + + if (krp->krp_iparams < 3 || krp->krp_oparams != 1) { + krp->krp_status = EINVAL; + return (1); + } + + base_bits = safe_ksigbits(sc, &krp->krp_param[SAFE_CRK_PARAM_BASE]); + if (base_bits > 2048) + goto too_big; + if (base_bits <= 0) /* 5. base not zero */ + goto too_small; + + exp_bits = safe_ksigbits(sc, &krp->krp_param[SAFE_CRK_PARAM_EXP]); + if (exp_bits > 2048) + goto too_big; + if (exp_bits <= 0) /* 1. exponent word length > 0 */ + goto too_small; /* 4. exponent not zero */ + + mod_bits = safe_ksigbits(sc, &krp->krp_param[SAFE_CRK_PARAM_MOD]); + if (mod_bits > 2048) + goto too_big; + if (mod_bits <= 32) /* 2. modulus word length > 1 */ + goto too_small; /* 8. MSW of modulus != zero */ + if (mod_bits < exp_bits) /* 3 modulus len >= exponent len */ + goto too_small; + if ((krp->krp_param[SAFE_CRK_PARAM_MOD].crp_p[0] & 1) == 0) + goto bad_domain; /* 6. modulus is odd */ + if (mod_bits > krp->krp_param[krp->krp_iparams].crp_nbits) + goto too_small; /* make sure result will fit */ + + /* 7. modulus > base */ + if (mod_bits < base_bits) + goto too_small; + if (mod_bits == base_bits) { + u_int8_t *basep, *modp; + int i; + + basep = krp->krp_param[SAFE_CRK_PARAM_BASE].crp_p + + ((base_bits + 7) / 8) - 1; + modp = krp->krp_param[SAFE_CRK_PARAM_MOD].crp_p + + ((mod_bits + 7) / 8) - 1; + + for (i = 0; i < (mod_bits + 7) / 8; i++, basep--, modp--) { + if (*modp < *basep) + goto too_small; + if (*modp > *basep) + break; + } + } + + /* And on the 9th step, he rested. */ + + WRITE_REG(sc, SAFE_PK_A_LEN, (exp_bits + 31) / 32); + WRITE_REG(sc, SAFE_PK_B_LEN, (mod_bits + 31) / 32); + if (mod_bits > 1024) { + op = SAFE_PK_FUNC_EXP4; + a_off = 0x000; + b_off = 0x100; + c_off = 0x200; + d_off = 0x300; + } else { + op = SAFE_PK_FUNC_EXP16; + a_off = 0x000; + b_off = 0x080; + c_off = 0x100; + d_off = 0x180; + } + sc->sc_pk_reslen = b_off - a_off; + sc->sc_pk_resoff = d_off; + + /* A is exponent, B is modulus, C is base, D is result */ + safe_kload_reg(sc, a_off, b_off - a_off, + &krp->krp_param[SAFE_CRK_PARAM_EXP]); + WRITE_REG(sc, SAFE_PK_A_ADDR, a_off >> 2); + safe_kload_reg(sc, b_off, b_off - a_off, + &krp->krp_param[SAFE_CRK_PARAM_MOD]); + WRITE_REG(sc, SAFE_PK_B_ADDR, b_off >> 2); + safe_kload_reg(sc, c_off, b_off - a_off, + &krp->krp_param[SAFE_CRK_PARAM_BASE]); + WRITE_REG(sc, SAFE_PK_C_ADDR, c_off >> 2); + WRITE_REG(sc, SAFE_PK_D_ADDR, d_off >> 2); + + WRITE_REG(sc, SAFE_PK_FUNC, op | SAFE_PK_FUNC_RUN); + + return (0); + +too_big: + krp->krp_status = E2BIG; + return (1); +too_small: + krp->krp_status = ERANGE; + return (1); +bad_domain: + krp->krp_status = EDOM; + return (1); +} + +static int +safe_ksigbits(struct safe_softc *sc, struct crparam *cr) +{ + u_int plen = (cr->crp_nbits + 7) / 8; + int i, sig = plen * 8; + u_int8_t c, *p = cr->crp_p; + + DPRINTF(("%s()\n", __FUNCTION__)); + + for (i = plen - 1; i >= 0; i--) { + c = p[i]; + if (c != 0) { + while ((c & 0x80) == 0) { + sig--; + c <<= 1; + } + break; + } + sig -= 8; + } + return (sig); +} + +static void +safe_kfeed(struct safe_softc *sc) +{ + struct safe_pkq *q, *tmp; + + DPRINTF(("%s()\n", __FUNCTION__)); + + if (list_empty(&sc->sc_pkq) && sc->sc_pkq_cur == NULL) + return; + if (sc->sc_pkq_cur != NULL) + return; + list_for_each_entry_safe(q, tmp, &sc->sc_pkq, pkq_list) { + sc->sc_pkq_cur = q; + list_del(&q->pkq_list); + if (safe_kstart(sc) != 0) { + crypto_kdone(q->pkq_krp); + kfree(q); + sc->sc_pkq_cur = NULL; + } else { + /* op started, start polling */ + mod_timer(&sc->sc_pkto, jiffies + 1); + break; + } + } +} + +static void +safe_kpoll(unsigned long arg) +{ + struct safe_softc *sc = NULL; + struct safe_pkq *q; + struct crparam *res; + int i; + u_int32_t buf[64]; + unsigned long flags; + + DPRINTF(("%s()\n", __FUNCTION__)); + + if (arg >= SAFE_MAX_CHIPS) + return; + sc = safe_chip_idx[arg]; + if (!sc) { + DPRINTF(("%s() - bad callback\n", __FUNCTION__)); + return; + } + + spin_lock_irqsave(&sc->sc_pkmtx, flags); + if (sc->sc_pkq_cur == NULL) + goto out; + if (READ_REG(sc, SAFE_PK_FUNC) & SAFE_PK_FUNC_RUN) { + /* still running, check back later */ + mod_timer(&sc->sc_pkto, jiffies + 1); + goto out; + } + + q = sc->sc_pkq_cur; + res = &q->pkq_krp->krp_param[q->pkq_krp->krp_iparams]; + bzero(buf, sizeof(buf)); + bzero(res->crp_p, (res->crp_nbits + 7) / 8); + for (i = 0; i < sc->sc_pk_reslen >> 2; i++) + buf[i] = le32_to_cpu(READ_REG(sc, SAFE_PK_RAM_START + + sc->sc_pk_resoff + (i << 2))); + bcopy(buf, res->crp_p, (res->crp_nbits + 7) / 8); + /* + * reduce the bits that need copying if possible + */ + res->crp_nbits = min(res->crp_nbits,sc->sc_pk_reslen * 8); + res->crp_nbits = safe_ksigbits(sc, res); + + for (i = SAFE_PK_RAM_START; i < SAFE_PK_RAM_END; i += 4) + WRITE_REG(sc, i, 0); + + crypto_kdone(q->pkq_krp); + kfree(q); + sc->sc_pkq_cur = NULL; + + safe_kfeed(sc); +out: + spin_unlock_irqrestore(&sc->sc_pkmtx, flags); +} + +static void +safe_kload_reg(struct safe_softc *sc, u_int32_t off, u_int32_t len, + struct crparam *n) +{ + u_int32_t buf[64], i; + + DPRINTF(("%s()\n", __FUNCTION__)); + + bzero(buf, sizeof(buf)); + bcopy(n->crp_p, buf, (n->crp_nbits + 7) / 8); + + for (i = 0; i < len >> 2; i++) + WRITE_REG(sc, SAFE_PK_RAM_START + off + (i << 2), + cpu_to_le32(buf[i])); +} + +#ifdef SAFE_DEBUG +static void +safe_dump_dmastatus(struct safe_softc *sc, const char *tag) +{ + printf("%s: ENDIAN 0x%x SRC 0x%x DST 0x%x STAT 0x%x\n" + , tag + , READ_REG(sc, SAFE_DMA_ENDIAN) + , READ_REG(sc, SAFE_DMA_SRCADDR) + , READ_REG(sc, SAFE_DMA_DSTADDR) + , READ_REG(sc, SAFE_DMA_STAT) + ); +} + +static void +safe_dump_intrstate(struct safe_softc *sc, const char *tag) +{ + printf("%s: HI_CFG 0x%x HI_MASK 0x%x HI_DESC_CNT 0x%x HU_STAT 0x%x HM_STAT 0x%x\n" + , tag + , READ_REG(sc, SAFE_HI_CFG) + , READ_REG(sc, SAFE_HI_MASK) + , READ_REG(sc, SAFE_HI_DESC_CNT) + , READ_REG(sc, SAFE_HU_STAT) + , READ_REG(sc, SAFE_HM_STAT) + ); +} + +static void +safe_dump_ringstate(struct safe_softc *sc, const char *tag) +{ + u_int32_t estat = READ_REG(sc, SAFE_PE_ERNGSTAT); + + /* NB: assume caller has lock on ring */ + printf("%s: ERNGSTAT %x (next %u) back %lu front %lu\n", + tag, + estat, (estat >> SAFE_PE_ERNGSTAT_NEXT_S), + (unsigned long)(sc->sc_back - sc->sc_ring), + (unsigned long)(sc->sc_front - sc->sc_ring)); +} + +static void +safe_dump_request(struct safe_softc *sc, const char* tag, struct safe_ringentry *re) +{ + int ix, nsegs; + + ix = re - sc->sc_ring; + printf("%s: %p (%u): csr %x src %x dst %x sa %x len %x\n" + , tag + , re, ix + , re->re_desc.d_csr + , re->re_desc.d_src + , re->re_desc.d_dst + , re->re_desc.d_sa + , re->re_desc.d_len + ); + if (re->re_src.nsegs > 1) { + ix = (re->re_desc.d_src - sc->sc_spalloc.dma_paddr) / + sizeof(struct safe_pdesc); + for (nsegs = re->re_src.nsegs; nsegs; nsegs--) { + printf(" spd[%u] %p: %p size %u flags %x" + , ix, &sc->sc_spring[ix] + , (caddr_t)(uintptr_t) sc->sc_spring[ix].pd_addr + , sc->sc_spring[ix].pd_size + , sc->sc_spring[ix].pd_flags + ); + if (sc->sc_spring[ix].pd_size == 0) + printf(" (zero!)"); + printf("\n"); + if (++ix == SAFE_TOTAL_SPART) + ix = 0; + } + } + if (re->re_dst.nsegs > 1) { + ix = (re->re_desc.d_dst - sc->sc_dpalloc.dma_paddr) / + sizeof(struct safe_pdesc); + for (nsegs = re->re_dst.nsegs; nsegs; nsegs--) { + printf(" dpd[%u] %p: %p flags %x\n" + , ix, &sc->sc_dpring[ix] + , (caddr_t)(uintptr_t) sc->sc_dpring[ix].pd_addr + , sc->sc_dpring[ix].pd_flags + ); + if (++ix == SAFE_TOTAL_DPART) + ix = 0; + } + } + printf("sa: cmd0 %08x cmd1 %08x staterec %x\n", + re->re_sa.sa_cmd0, re->re_sa.sa_cmd1, re->re_sa.sa_staterec); + printf("sa: key %x %x %x %x %x %x %x %x\n" + , re->re_sa.sa_key[0] + , re->re_sa.sa_key[1] + , re->re_sa.sa_key[2] + , re->re_sa.sa_key[3] + , re->re_sa.sa_key[4] + , re->re_sa.sa_key[5] + , re->re_sa.sa_key[6] + , re->re_sa.sa_key[7] + ); + printf("sa: indigest %x %x %x %x %x\n" + , re->re_sa.sa_indigest[0] + , re->re_sa.sa_indigest[1] + , re->re_sa.sa_indigest[2] + , re->re_sa.sa_indigest[3] + , re->re_sa.sa_indigest[4] + ); + printf("sa: outdigest %x %x %x %x %x\n" + , re->re_sa.sa_outdigest[0] + , re->re_sa.sa_outdigest[1] + , re->re_sa.sa_outdigest[2] + , re->re_sa.sa_outdigest[3] + , re->re_sa.sa_outdigest[4] + ); + printf("sr: iv %x %x %x %x\n" + , re->re_sastate.sa_saved_iv[0] + , re->re_sastate.sa_saved_iv[1] + , re->re_sastate.sa_saved_iv[2] + , re->re_sastate.sa_saved_iv[3] + ); + printf("sr: hashbc %u indigest %x %x %x %x %x\n" + , re->re_sastate.sa_saved_hashbc + , re->re_sastate.sa_saved_indigest[0] + , re->re_sastate.sa_saved_indigest[1] + , re->re_sastate.sa_saved_indigest[2] + , re->re_sastate.sa_saved_indigest[3] + , re->re_sastate.sa_saved_indigest[4] + ); +} + +static void +safe_dump_ring(struct safe_softc *sc, const char *tag) +{ + unsigned long flags; + + spin_lock_irqsave(&sc->sc_ringmtx, flags); + printf("\nSafeNet Ring State:\n"); + safe_dump_intrstate(sc, tag); + safe_dump_dmastatus(sc, tag); + safe_dump_ringstate(sc, tag); + if (sc->sc_nqchip) { + struct safe_ringentry *re = sc->sc_back; + do { + safe_dump_request(sc, tag, re); + if (++re == sc->sc_ringtop) + re = sc->sc_ring; + } while (re != sc->sc_front); + } + spin_unlock_irqrestore(&sc->sc_ringmtx, flags); +} +#endif /* SAFE_DEBUG */ + + +static int safe_probe(struct pci_dev *dev, const struct pci_device_id *ent) +{ + struct safe_softc *sc = NULL; + u32 mem_start, mem_len, cmd; + int i, rc, devinfo; + dma_addr_t raddr; + static int num_chips = 0; + + DPRINTF(("%s()\n", __FUNCTION__)); + + if (pci_enable_device(dev) < 0) + return(-ENODEV); + + if (!dev->irq) { + printk("safe: found device with no IRQ assigned. check BIOS settings!"); + pci_disable_device(dev); + return(-ENODEV); + } + + if (pci_set_mwi(dev)) { + printk("safe: pci_set_mwi failed!"); + return(-ENODEV); + } + + sc = (struct safe_softc *) kmalloc(sizeof(*sc), GFP_KERNEL); + if (!sc) + return(-ENOMEM); + memset(sc, 0, sizeof(*sc)); + + softc_device_init(sc, "safe", num_chips, safe_methods); + + sc->sc_irq = -1; + sc->sc_cid = -1; + sc->sc_pcidev = dev; + if (num_chips < SAFE_MAX_CHIPS) { + safe_chip_idx[device_get_unit(sc->sc_dev)] = sc; + num_chips++; + } + + INIT_LIST_HEAD(&sc->sc_pkq); + spin_lock_init(&sc->sc_pkmtx); + + pci_set_drvdata(sc->sc_pcidev, sc); + + /* we read its hardware registers as memory */ + mem_start = pci_resource_start(sc->sc_pcidev, 0); + mem_len = pci_resource_len(sc->sc_pcidev, 0); + + sc->sc_base_addr = (ocf_iomem_t) ioremap(mem_start, mem_len); + if (!sc->sc_base_addr) { + device_printf(sc->sc_dev, "failed to ioremap 0x%x-0x%x\n", + mem_start, mem_start + mem_len - 1); + goto out; + } + + /* fix up the bus size */ + if (pci_set_dma_mask(sc->sc_pcidev, DMA_32BIT_MASK)) { + device_printf(sc->sc_dev, "No usable DMA configuration, aborting.\n"); + goto out; + } + if (pci_set_consistent_dma_mask(sc->sc_pcidev, DMA_32BIT_MASK)) { + device_printf(sc->sc_dev, "No usable consistent DMA configuration, aborting.\n"); + goto out; + } + + pci_set_master(sc->sc_pcidev); + + pci_read_config_dword(sc->sc_pcidev, PCI_COMMAND, &cmd); + + if (!(cmd & PCI_COMMAND_MEMORY)) { + device_printf(sc->sc_dev, "failed to enable memory mapping\n"); + goto out; + } + + if (!(cmd & PCI_COMMAND_MASTER)) { + device_printf(sc->sc_dev, "failed to enable bus mastering\n"); + goto out; + } + + rc = request_irq(dev->irq, safe_intr, IRQF_SHARED, "safe", sc); + if (rc) { + device_printf(sc->sc_dev, "failed to hook irq %d\n", sc->sc_irq); + goto out; + } + sc->sc_irq = dev->irq; + + sc->sc_chiprev = READ_REG(sc, SAFE_DEVINFO) & + (SAFE_DEVINFO_REV_MAJ | SAFE_DEVINFO_REV_MIN); + + /* + * Allocate packet engine descriptors. + */ + sc->sc_ringalloc.dma_vaddr = pci_alloc_consistent(sc->sc_pcidev, + SAFE_MAX_NQUEUE * sizeof (struct safe_ringentry), + &sc->sc_ringalloc.dma_paddr); + if (!sc->sc_ringalloc.dma_vaddr) { + device_printf(sc->sc_dev, "cannot allocate PE descriptor ring\n"); + goto out; + } + + /* + * Hookup the static portion of all our data structures. + */ + sc->sc_ring = (struct safe_ringentry *) sc->sc_ringalloc.dma_vaddr; + sc->sc_ringtop = sc->sc_ring + SAFE_MAX_NQUEUE; + sc->sc_front = sc->sc_ring; + sc->sc_back = sc->sc_ring; + raddr = sc->sc_ringalloc.dma_paddr; + bzero(sc->sc_ring, SAFE_MAX_NQUEUE * sizeof(struct safe_ringentry)); + for (i = 0; i < SAFE_MAX_NQUEUE; i++) { + struct safe_ringentry *re = &sc->sc_ring[i]; + + re->re_desc.d_sa = raddr + + offsetof(struct safe_ringentry, re_sa); + re->re_sa.sa_staterec = raddr + + offsetof(struct safe_ringentry, re_sastate); + + raddr += sizeof (struct safe_ringentry); + } + spin_lock_init(&sc->sc_ringmtx); + + /* + * Allocate scatter and gather particle descriptors. + */ + sc->sc_spalloc.dma_vaddr = pci_alloc_consistent(sc->sc_pcidev, + SAFE_TOTAL_SPART * sizeof (struct safe_pdesc), + &sc->sc_spalloc.dma_paddr); + if (!sc->sc_spalloc.dma_vaddr) { + device_printf(sc->sc_dev, "cannot allocate source particle descriptor ring\n"); + goto out; + } + sc->sc_spring = (struct safe_pdesc *) sc->sc_spalloc.dma_vaddr; + sc->sc_springtop = sc->sc_spring + SAFE_TOTAL_SPART; + sc->sc_spfree = sc->sc_spring; + bzero(sc->sc_spring, SAFE_TOTAL_SPART * sizeof(struct safe_pdesc)); + + sc->sc_dpalloc.dma_vaddr = pci_alloc_consistent(sc->sc_pcidev, + SAFE_TOTAL_DPART * sizeof (struct safe_pdesc), + &sc->sc_dpalloc.dma_paddr); + if (!sc->sc_dpalloc.dma_vaddr) { + device_printf(sc->sc_dev, "cannot allocate destination particle descriptor ring\n"); + goto out; + } + sc->sc_dpring = (struct safe_pdesc *) sc->sc_dpalloc.dma_vaddr; + sc->sc_dpringtop = sc->sc_dpring + SAFE_TOTAL_DPART; + sc->sc_dpfree = sc->sc_dpring; + bzero(sc->sc_dpring, SAFE_TOTAL_DPART * sizeof(struct safe_pdesc)); + + sc->sc_cid = crypto_get_driverid(softc_get_device(sc), CRYPTOCAP_F_HARDWARE); + if (sc->sc_cid < 0) { + device_printf(sc->sc_dev, "could not get crypto driver id\n"); + goto out; + } + + printf("%s:", device_get_nameunit(sc->sc_dev)); + + devinfo = READ_REG(sc, SAFE_DEVINFO); + if (devinfo & SAFE_DEVINFO_RNG) { + sc->sc_flags |= SAFE_FLAGS_RNG; + printf(" rng"); + } + if (devinfo & SAFE_DEVINFO_PKEY) { + printf(" key"); + sc->sc_flags |= SAFE_FLAGS_KEY; + crypto_kregister(sc->sc_cid, CRK_MOD_EXP, 0); +#if 0 + crypto_kregister(sc->sc_cid, CRK_MOD_EXP_CRT, 0); +#endif + init_timer(&sc->sc_pkto); + sc->sc_pkto.function = safe_kpoll; + sc->sc_pkto.data = (unsigned long) device_get_unit(sc->sc_dev); + } + if (devinfo & SAFE_DEVINFO_DES) { + printf(" des/3des"); + crypto_register(sc->sc_cid, CRYPTO_3DES_CBC, 0, 0); + crypto_register(sc->sc_cid, CRYPTO_DES_CBC, 0, 0); + } + if (devinfo & SAFE_DEVINFO_AES) { + printf(" aes"); + crypto_register(sc->sc_cid, CRYPTO_AES_CBC, 0, 0); + } + if (devinfo & SAFE_DEVINFO_MD5) { + printf(" md5"); + crypto_register(sc->sc_cid, CRYPTO_MD5_HMAC, 0, 0); + } + if (devinfo & SAFE_DEVINFO_SHA1) { + printf(" sha1"); + crypto_register(sc->sc_cid, CRYPTO_SHA1_HMAC, 0, 0); + } + printf(" null"); + crypto_register(sc->sc_cid, CRYPTO_NULL_CBC, 0, 0); + crypto_register(sc->sc_cid, CRYPTO_NULL_HMAC, 0, 0); + /* XXX other supported algorithms */ + printf("\n"); + + safe_reset_board(sc); /* reset h/w */ + safe_init_board(sc); /* init h/w */ + +#if defined(CONFIG_OCF_RANDOMHARVEST) && !defined(SAFE_NO_RNG) + if (sc->sc_flags & SAFE_FLAGS_RNG) { + safe_rng_init(sc); + crypto_rregister(sc->sc_cid, safe_read_random, sc); + } +#endif /* SAFE_NO_RNG */ + + return (0); + +out: + if (sc->sc_cid >= 0) + crypto_unregister_all(sc->sc_cid); + if (sc->sc_irq != -1) + free_irq(sc->sc_irq, sc); + if (sc->sc_ringalloc.dma_vaddr) + pci_free_consistent(sc->sc_pcidev, + SAFE_MAX_NQUEUE * sizeof (struct safe_ringentry), + sc->sc_ringalloc.dma_vaddr, sc->sc_ringalloc.dma_paddr); + if (sc->sc_spalloc.dma_vaddr) + pci_free_consistent(sc->sc_pcidev, + SAFE_TOTAL_DPART * sizeof (struct safe_pdesc), + sc->sc_spalloc.dma_vaddr, sc->sc_spalloc.dma_paddr); + if (sc->sc_dpalloc.dma_vaddr) + pci_free_consistent(sc->sc_pcidev, + SAFE_TOTAL_DPART * sizeof (struct safe_pdesc), + sc->sc_dpalloc.dma_vaddr, sc->sc_dpalloc.dma_paddr); + kfree(sc); + return(-ENODEV); +} + +static void safe_remove(struct pci_dev *dev) +{ + struct safe_softc *sc = pci_get_drvdata(dev); + + DPRINTF(("%s()\n", __FUNCTION__)); + + /* XXX wait/abort active ops */ + + WRITE_REG(sc, SAFE_HI_MASK, 0); /* disable interrupts */ + + del_timer_sync(&sc->sc_pkto); + + crypto_unregister_all(sc->sc_cid); + + safe_cleanchip(sc); + + if (sc->sc_irq != -1) + free_irq(sc->sc_irq, sc); + if (sc->sc_ringalloc.dma_vaddr) + pci_free_consistent(sc->sc_pcidev, + SAFE_MAX_NQUEUE * sizeof (struct safe_ringentry), + sc->sc_ringalloc.dma_vaddr, sc->sc_ringalloc.dma_paddr); + if (sc->sc_spalloc.dma_vaddr) + pci_free_consistent(sc->sc_pcidev, + SAFE_TOTAL_DPART * sizeof (struct safe_pdesc), + sc->sc_spalloc.dma_vaddr, sc->sc_spalloc.dma_paddr); + if (sc->sc_dpalloc.dma_vaddr) + pci_free_consistent(sc->sc_pcidev, + SAFE_TOTAL_DPART * sizeof (struct safe_pdesc), + sc->sc_dpalloc.dma_vaddr, sc->sc_dpalloc.dma_paddr); + sc->sc_irq = -1; + sc->sc_ringalloc.dma_vaddr = NULL; + sc->sc_spalloc.dma_vaddr = NULL; + sc->sc_dpalloc.dma_vaddr = NULL; +} + +static struct pci_device_id safe_pci_tbl[] = { + { PCI_VENDOR_SAFENET, PCI_PRODUCT_SAFEXCEL, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, + { }, +}; +MODULE_DEVICE_TABLE(pci, safe_pci_tbl); + +static struct pci_driver safe_driver = { + .name = "safe", + .id_table = safe_pci_tbl, + .probe = safe_probe, + .remove = safe_remove, + /* add PM stuff here one day */ +}; + +static int __init safe_init (void) +{ + struct safe_softc *sc = NULL; + int rc; + + DPRINTF(("%s(%p)\n", __FUNCTION__, safe_init)); + + rc = pci_register_driver(&safe_driver); + pci_register_driver_compat(&safe_driver, rc); + + return rc; +} + +static void __exit safe_exit (void) +{ + pci_unregister_driver(&safe_driver); +} + +module_init(safe_init); +module_exit(safe_exit); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_AUTHOR("David McCullough "); +MODULE_DESCRIPTION("OCF driver for safenet PCI crypto devices"); diff --git a/target/linux/generic/files/crypto/ocf/safe/safereg.h b/target/linux/generic/files/crypto/ocf/safe/safereg.h new file mode 100644 index 0000000..dbaf98f --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/safe/safereg.h @@ -0,0 +1,421 @@ +/*- + * Copyright (c) 2003 Sam Leffler, Errno Consulting + * Copyright (c) 2003 Global Technology Associates, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/dev/safe/safereg.h,v 1.1 2003/07/21 21:46:07 sam Exp $ + */ +#ifndef _SAFE_SAFEREG_H_ +#define _SAFE_SAFEREG_H_ + +/* + * Register definitions for SafeNet SafeXcel-1141 crypto device. + * Definitions from revision 1.3 (Nov 6 2002) of the User's Manual. + */ + +#define BS_BAR 0x10 /* DMA base address register */ +#define BS_TRDY_TIMEOUT 0x40 /* TRDY timeout */ +#define BS_RETRY_TIMEOUT 0x41 /* DMA retry timeout */ + +#define PCI_VENDOR_SAFENET 0x16ae /* SafeNet, Inc. */ + +/* SafeNet */ +#define PCI_PRODUCT_SAFEXCEL 0x1141 /* 1141 */ + +#define SAFE_PE_CSR 0x0000 /* Packet Enginge Ctrl/Status */ +#define SAFE_PE_SRC 0x0004 /* Packet Engine Source */ +#define SAFE_PE_DST 0x0008 /* Packet Engine Destination */ +#define SAFE_PE_SA 0x000c /* Packet Engine SA */ +#define SAFE_PE_LEN 0x0010 /* Packet Engine Length */ +#define SAFE_PE_DMACFG 0x0040 /* Packet Engine DMA Configuration */ +#define SAFE_PE_DMASTAT 0x0044 /* Packet Engine DMA Status */ +#define SAFE_PE_PDRBASE 0x0048 /* Packet Engine Descriptor Ring Base */ +#define SAFE_PE_RDRBASE 0x004c /* Packet Engine Result Ring Base */ +#define SAFE_PE_RINGCFG 0x0050 /* Packet Engine Ring Configuration */ +#define SAFE_PE_RINGPOLL 0x0054 /* Packet Engine Ring Poll */ +#define SAFE_PE_IRNGSTAT 0x0058 /* Packet Engine Internal Ring Status */ +#define SAFE_PE_ERNGSTAT 0x005c /* Packet Engine External Ring Status */ +#define SAFE_PE_IOTHRESH 0x0060 /* Packet Engine I/O Threshold */ +#define SAFE_PE_GRNGBASE 0x0064 /* Packet Engine Gather Ring Base */ +#define SAFE_PE_SRNGBASE 0x0068 /* Packet Engine Scatter Ring Base */ +#define SAFE_PE_PARTSIZE 0x006c /* Packet Engine Particlar Ring Size */ +#define SAFE_PE_PARTCFG 0x0070 /* Packet Engine Particle Ring Config */ +#define SAFE_CRYPTO_CTRL 0x0080 /* Crypto Control */ +#define SAFE_DEVID 0x0084 /* Device ID */ +#define SAFE_DEVINFO 0x0088 /* Device Info */ +#define SAFE_HU_STAT 0x00a0 /* Host Unmasked Status */ +#define SAFE_HM_STAT 0x00a4 /* Host Masked Status (read-only) */ +#define SAFE_HI_CLR 0x00a4 /* Host Clear Interrupt (write-only) */ +#define SAFE_HI_MASK 0x00a8 /* Host Mask Control */ +#define SAFE_HI_CFG 0x00ac /* Interrupt Configuration */ +#define SAFE_HI_RD_DESCR 0x00b4 /* Force Descriptor Read */ +#define SAFE_HI_DESC_CNT 0x00b8 /* Host Descriptor Done Count */ +#define SAFE_DMA_ENDIAN 0x00c0 /* Master Endian Status */ +#define SAFE_DMA_SRCADDR 0x00c4 /* DMA Source Address Status */ +#define SAFE_DMA_DSTADDR 0x00c8 /* DMA Destination Address Status */ +#define SAFE_DMA_STAT 0x00cc /* DMA Current Status */ +#define SAFE_DMA_CFG 0x00d4 /* DMA Configuration/Status */ +#define SAFE_ENDIAN 0x00e0 /* Endian Configuration */ +#define SAFE_PK_A_ADDR 0x0800 /* Public Key A Address */ +#define SAFE_PK_B_ADDR 0x0804 /* Public Key B Address */ +#define SAFE_PK_C_ADDR 0x0808 /* Public Key C Address */ +#define SAFE_PK_D_ADDR 0x080c /* Public Key D Address */ +#define SAFE_PK_A_LEN 0x0810 /* Public Key A Length */ +#define SAFE_PK_B_LEN 0x0814 /* Public Key B Length */ +#define SAFE_PK_SHIFT 0x0818 /* Public Key Shift */ +#define SAFE_PK_FUNC 0x081c /* Public Key Function */ +#define SAFE_PK_RAM_START 0x1000 /* Public Key RAM start address */ +#define SAFE_PK_RAM_END 0x1fff /* Public Key RAM end address */ + +#define SAFE_RNG_OUT 0x0100 /* RNG Output */ +#define SAFE_RNG_STAT 0x0104 /* RNG Status */ +#define SAFE_RNG_CTRL 0x0108 /* RNG Control */ +#define SAFE_RNG_A 0x010c /* RNG A */ +#define SAFE_RNG_B 0x0110 /* RNG B */ +#define SAFE_RNG_X_LO 0x0114 /* RNG X [31:0] */ +#define SAFE_RNG_X_MID 0x0118 /* RNG X [63:32] */ +#define SAFE_RNG_X_HI 0x011c /* RNG X [80:64] */ +#define SAFE_RNG_X_CNTR 0x0120 /* RNG Counter */ +#define SAFE_RNG_ALM_CNT 0x0124 /* RNG Alarm Count */ +#define SAFE_RNG_CNFG 0x0128 /* RNG Configuration */ +#define SAFE_RNG_LFSR1_LO 0x012c /* RNG LFSR1 [31:0] */ +#define SAFE_RNG_LFSR1_HI 0x0130 /* RNG LFSR1 [47:32] */ +#define SAFE_RNG_LFSR2_LO 0x0134 /* RNG LFSR1 [31:0] */ +#define SAFE_RNG_LFSR2_HI 0x0138 /* RNG LFSR1 [47:32] */ + +#define SAFE_PE_CSR_READY 0x00000001 /* ready for processing */ +#define SAFE_PE_CSR_DONE 0x00000002 /* h/w completed processing */ +#define SAFE_PE_CSR_LOADSA 0x00000004 /* load SA digests */ +#define SAFE_PE_CSR_HASHFINAL 0x00000010 /* do hash pad & write result */ +#define SAFE_PE_CSR_SABUSID 0x000000c0 /* bus id for SA */ +#define SAFE_PE_CSR_SAPCI 0x00000040 /* PCI bus id for SA */ +#define SAFE_PE_CSR_NXTHDR 0x0000ff00 /* next hdr value for IPsec */ +#define SAFE_PE_CSR_FPAD 0x0000ff00 /* fixed pad for basic ops */ +#define SAFE_PE_CSR_STATUS 0x00ff0000 /* operation result status */ +#define SAFE_PE_CSR_AUTH_FAIL 0x00010000 /* ICV mismatch (inbound) */ +#define SAFE_PE_CSR_PAD_FAIL 0x00020000 /* pad verify fail (inbound) */ +#define SAFE_PE_CSR_SEQ_FAIL 0x00040000 /* sequence number (inbound) */ +#define SAFE_PE_CSR_XERROR 0x00080000 /* extended error follows */ +#define SAFE_PE_CSR_XECODE 0x00f00000 /* extended error code */ +#define SAFE_PE_CSR_XECODE_S 20 +#define SAFE_PE_CSR_XECODE_BADCMD 0 /* invalid command */ +#define SAFE_PE_CSR_XECODE_BADALG 1 /* invalid algorithm */ +#define SAFE_PE_CSR_XECODE_ALGDIS 2 /* algorithm disabled */ +#define SAFE_PE_CSR_XECODE_ZEROLEN 3 /* zero packet length */ +#define SAFE_PE_CSR_XECODE_DMAERR 4 /* bus DMA error */ +#define SAFE_PE_CSR_XECODE_PIPEABORT 5 /* secondary bus DMA error */ +#define SAFE_PE_CSR_XECODE_BADSPI 6 /* IPsec SPI mismatch */ +#define SAFE_PE_CSR_XECODE_TIMEOUT 10 /* failsafe timeout */ +#define SAFE_PE_CSR_PAD 0xff000000 /* ESP padding control/status */ +#define SAFE_PE_CSR_PAD_MIN 0x00000000 /* minimum IPsec padding */ +#define SAFE_PE_CSR_PAD_16 0x08000000 /* pad to 16-byte boundary */ +#define SAFE_PE_CSR_PAD_32 0x10000000 /* pad to 32-byte boundary */ +#define SAFE_PE_CSR_PAD_64 0x20000000 /* pad to 64-byte boundary */ +#define SAFE_PE_CSR_PAD_128 0x40000000 /* pad to 128-byte boundary */ +#define SAFE_PE_CSR_PAD_256 0x80000000 /* pad to 256-byte boundary */ + +/* + * Check the CSR to see if the PE has returned ownership to + * the host. Note that before processing a descriptor this + * must be done followed by a check of the SAFE_PE_LEN register + * status bits to avoid premature processing of a descriptor + * on its way back to the host. + */ +#define SAFE_PE_CSR_IS_DONE(_csr) \ + (((_csr) & (SAFE_PE_CSR_READY | SAFE_PE_CSR_DONE)) == SAFE_PE_CSR_DONE) + +#define SAFE_PE_LEN_LENGTH 0x000fffff /* total length (bytes) */ +#define SAFE_PE_LEN_READY 0x00400000 /* ready for processing */ +#define SAFE_PE_LEN_DONE 0x00800000 /* h/w completed processing */ +#define SAFE_PE_LEN_BYPASS 0xff000000 /* bypass offset (bytes) */ +#define SAFE_PE_LEN_BYPASS_S 24 + +#define SAFE_PE_LEN_IS_DONE(_len) \ + (((_len) & (SAFE_PE_LEN_READY | SAFE_PE_LEN_DONE)) == SAFE_PE_LEN_DONE) + +/* NB: these apply to HU_STAT, HM_STAT, HI_CLR, and HI_MASK */ +#define SAFE_INT_PE_CDONE 0x00000002 /* PE context done */ +#define SAFE_INT_PE_DDONE 0x00000008 /* PE descriptor done */ +#define SAFE_INT_PE_ERROR 0x00000010 /* PE error */ +#define SAFE_INT_PE_ODONE 0x00000020 /* PE operation done */ + +#define SAFE_HI_CFG_PULSE 0x00000001 /* use pulse interrupt */ +#define SAFE_HI_CFG_LEVEL 0x00000000 /* use level interrupt */ +#define SAFE_HI_CFG_AUTOCLR 0x00000002 /* auto-clear pulse interrupt */ + +#define SAFE_ENDIAN_PASS 0x000000e4 /* straight pass-thru */ +#define SAFE_ENDIAN_SWAB 0x0000001b /* swap bytes in 32-bit word */ + +#define SAFE_PE_DMACFG_PERESET 0x00000001 /* reset packet engine */ +#define SAFE_PE_DMACFG_PDRRESET 0x00000002 /* reset PDR counters/ptrs */ +#define SAFE_PE_DMACFG_SGRESET 0x00000004 /* reset scatter/gather cache */ +#define SAFE_PE_DMACFG_FSENA 0x00000008 /* enable failsafe reset */ +#define SAFE_PE_DMACFG_PEMODE 0x00000100 /* packet engine mode */ +#define SAFE_PE_DMACFG_SAPREC 0x00000200 /* SA precedes packet */ +#define SAFE_PE_DMACFG_PKFOLL 0x00000400 /* packet follows descriptor */ +#define SAFE_PE_DMACFG_GPRBID 0x00003000 /* gather particle ring busid */ +#define SAFE_PE_DMACFG_GPRPCI 0x00001000 /* PCI gather particle ring */ +#define SAFE_PE_DMACFG_SPRBID 0x0000c000 /* scatter part. ring busid */ +#define SAFE_PE_DMACFG_SPRPCI 0x00004000 /* PCI scatter part. ring */ +#define SAFE_PE_DMACFG_ESDESC 0x00010000 /* endian swap descriptors */ +#define SAFE_PE_DMACFG_ESSA 0x00020000 /* endian swap SA data */ +#define SAFE_PE_DMACFG_ESPACKET 0x00040000 /* endian swap packet data */ +#define SAFE_PE_DMACFG_ESPDESC 0x00080000 /* endian swap particle desc. */ +#define SAFE_PE_DMACFG_NOPDRUP 0x00100000 /* supp. PDR ownership update */ +#define SAFE_PD_EDMACFG_PCIMODE 0x01000000 /* PCI target mode */ + +#define SAFE_PE_DMASTAT_PEIDONE 0x00000001 /* PE core input done */ +#define SAFE_PE_DMASTAT_PEODONE 0x00000002 /* PE core output done */ +#define SAFE_PE_DMASTAT_ENCDONE 0x00000004 /* encryption done */ +#define SAFE_PE_DMASTAT_IHDONE 0x00000008 /* inner hash done */ +#define SAFE_PE_DMASTAT_OHDONE 0x00000010 /* outer hash (HMAC) done */ +#define SAFE_PE_DMASTAT_PADFLT 0x00000020 /* crypto pad fault */ +#define SAFE_PE_DMASTAT_ICVFLT 0x00000040 /* ICV fault */ +#define SAFE_PE_DMASTAT_SPIMIS 0x00000080 /* SPI mismatch */ +#define SAFE_PE_DMASTAT_CRYPTO 0x00000100 /* crypto engine timeout */ +#define SAFE_PE_DMASTAT_CQACT 0x00000200 /* command queue active */ +#define SAFE_PE_DMASTAT_IRACT 0x00000400 /* input request active */ +#define SAFE_PE_DMASTAT_ORACT 0x00000800 /* output request active */ +#define SAFE_PE_DMASTAT_PEISIZE 0x003ff000 /* PE input size:32-bit words */ +#define SAFE_PE_DMASTAT_PEOSIZE 0xffc00000 /* PE out. size:32-bit words */ + +#define SAFE_PE_RINGCFG_SIZE 0x000003ff /* ring size (descriptors) */ +#define SAFE_PE_RINGCFG_OFFSET 0xffff0000 /* offset btw desc's (dwords) */ +#define SAFE_PE_RINGCFG_OFFSET_S 16 + +#define SAFE_PE_RINGPOLL_POLL 0x00000fff /* polling frequency/divisor */ +#define SAFE_PE_RINGPOLL_RETRY 0x03ff0000 /* polling frequency/divisor */ +#define SAFE_PE_RINGPOLL_CONT 0x80000000 /* continuously poll */ + +#define SAFE_PE_IRNGSTAT_CQAVAIL 0x00000001 /* command queue available */ + +#define SAFE_PE_ERNGSTAT_NEXT 0x03ff0000 /* index of next packet desc. */ +#define SAFE_PE_ERNGSTAT_NEXT_S 16 + +#define SAFE_PE_IOTHRESH_INPUT 0x000003ff /* input threshold (dwords) */ +#define SAFE_PE_IOTHRESH_OUTPUT 0x03ff0000 /* output threshold (dwords) */ + +#define SAFE_PE_PARTCFG_SIZE 0x0000ffff /* scatter particle size */ +#define SAFE_PE_PARTCFG_GBURST 0x00030000 /* gather particle burst */ +#define SAFE_PE_PARTCFG_GBURST_2 0x00000000 +#define SAFE_PE_PARTCFG_GBURST_4 0x00010000 +#define SAFE_PE_PARTCFG_GBURST_8 0x00020000 +#define SAFE_PE_PARTCFG_GBURST_16 0x00030000 +#define SAFE_PE_PARTCFG_SBURST 0x000c0000 /* scatter particle burst */ +#define SAFE_PE_PARTCFG_SBURST_2 0x00000000 +#define SAFE_PE_PARTCFG_SBURST_4 0x00040000 +#define SAFE_PE_PARTCFG_SBURST_8 0x00080000 +#define SAFE_PE_PARTCFG_SBURST_16 0x000c0000 + +#define SAFE_PE_PARTSIZE_SCAT 0xffff0000 /* scatter particle ring size */ +#define SAFE_PE_PARTSIZE_GATH 0x0000ffff /* gather particle ring size */ + +#define SAFE_CRYPTO_CTRL_3DES 0x00000001 /* enable 3DES support */ +#define SAFE_CRYPTO_CTRL_PKEY 0x00010000 /* enable public key support */ +#define SAFE_CRYPTO_CTRL_RNG 0x00020000 /* enable RNG support */ + +#define SAFE_DEVINFO_REV_MIN 0x0000000f /* minor rev for chip */ +#define SAFE_DEVINFO_REV_MAJ 0x000000f0 /* major rev for chip */ +#define SAFE_DEVINFO_REV_MAJ_S 4 +#define SAFE_DEVINFO_DES 0x00000100 /* DES/3DES support present */ +#define SAFE_DEVINFO_ARC4 0x00000200 /* ARC4 support present */ +#define SAFE_DEVINFO_AES 0x00000400 /* AES support present */ +#define SAFE_DEVINFO_MD5 0x00001000 /* MD5 support present */ +#define SAFE_DEVINFO_SHA1 0x00002000 /* SHA-1 support present */ +#define SAFE_DEVINFO_RIPEMD 0x00004000 /* RIPEMD support present */ +#define SAFE_DEVINFO_DEFLATE 0x00010000 /* Deflate support present */ +#define SAFE_DEVINFO_SARAM 0x00100000 /* on-chip SA RAM present */ +#define SAFE_DEVINFO_EMIBUS 0x00200000 /* EMI bus present */ +#define SAFE_DEVINFO_PKEY 0x00400000 /* public key support present */ +#define SAFE_DEVINFO_RNG 0x00800000 /* RNG present */ + +#define SAFE_REV(_maj, _min) (((_maj) << SAFE_DEVINFO_REV_MAJ_S) | (_min)) +#define SAFE_REV_MAJ(_chiprev) \ + (((_chiprev) & SAFE_DEVINFO_REV_MAJ) >> SAFE_DEVINFO_REV_MAJ_S) +#define SAFE_REV_MIN(_chiprev) ((_chiprev) & SAFE_DEVINFO_REV_MIN) + +#define SAFE_PK_FUNC_MULT 0x00000001 /* Multiply function */ +#define SAFE_PK_FUNC_SQUARE 0x00000004 /* Square function */ +#define SAFE_PK_FUNC_ADD 0x00000010 /* Add function */ +#define SAFE_PK_FUNC_SUB 0x00000020 /* Subtract function */ +#define SAFE_PK_FUNC_LSHIFT 0x00000040 /* Left-shift function */ +#define SAFE_PK_FUNC_RSHIFT 0x00000080 /* Right-shift function */ +#define SAFE_PK_FUNC_DIV 0x00000100 /* Divide function */ +#define SAFE_PK_FUNC_CMP 0x00000400 /* Compare function */ +#define SAFE_PK_FUNC_COPY 0x00000800 /* Copy function */ +#define SAFE_PK_FUNC_EXP16 0x00002000 /* Exponentiate (4-bit ACT) */ +#define SAFE_PK_FUNC_EXP4 0x00004000 /* Exponentiate (2-bit ACT) */ +#define SAFE_PK_FUNC_RUN 0x00008000 /* start/status */ + +#define SAFE_RNG_STAT_BUSY 0x00000001 /* busy, data not valid */ + +#define SAFE_RNG_CTRL_PRE_LFSR 0x00000001 /* enable output pre-LFSR */ +#define SAFE_RNG_CTRL_TST_MODE 0x00000002 /* enable test mode */ +#define SAFE_RNG_CTRL_TST_RUN 0x00000004 /* start test state machine */ +#define SAFE_RNG_CTRL_ENA_RING1 0x00000008 /* test entropy oscillator #1 */ +#define SAFE_RNG_CTRL_ENA_RING2 0x00000010 /* test entropy oscillator #2 */ +#define SAFE_RNG_CTRL_DIS_ALARM 0x00000020 /* disable RNG alarm reports */ +#define SAFE_RNG_CTRL_TST_CLOCK 0x00000040 /* enable test clock */ +#define SAFE_RNG_CTRL_SHORTEN 0x00000080 /* shorten state timers */ +#define SAFE_RNG_CTRL_TST_ALARM 0x00000100 /* simulate alarm state */ +#define SAFE_RNG_CTRL_RST_LFSR 0x00000200 /* reset LFSR */ + +/* + * Packet engine descriptor. Note that d_csr is a copy of the + * SAFE_PE_CSR register and all definitions apply, and d_len + * is a copy of the SAFE_PE_LEN register and all definitions apply. + * d_src and d_len may point directly to contiguous data or to a + * list of ``particle descriptors'' when using scatter/gather i/o. + */ +struct safe_desc { + u_int32_t d_csr; /* per-packet control/status */ + u_int32_t d_src; /* source address */ + u_int32_t d_dst; /* destination address */ + u_int32_t d_sa; /* SA address */ + u_int32_t d_len; /* length, bypass, status */ +}; + +/* + * Scatter/Gather particle descriptor. + * + * NB: scatter descriptors do not specify a size; this is fixed + * by the setting of the SAFE_PE_PARTCFG register. + */ +struct safe_pdesc { + u_int32_t pd_addr; /* particle address */ +#ifdef __BIG_ENDIAN + u_int16_t pd_flags; /* control word */ + u_int16_t pd_size; /* particle size (bytes) */ +#else + u_int16_t pd_flags; /* control word */ + u_int16_t pd_size; /* particle size (bytes) */ +#endif +}; + +#define SAFE_PD_READY 0x0001 /* ready for processing */ +#define SAFE_PD_DONE 0x0002 /* h/w completed processing */ + +/* + * Security Association (SA) Record (Rev 1). One of these is + * required for each operation processed by the packet engine. + */ +struct safe_sarec { + u_int32_t sa_cmd0; + u_int32_t sa_cmd1; + u_int32_t sa_resv0; + u_int32_t sa_resv1; + u_int32_t sa_key[8]; /* DES/3DES/AES key */ + u_int32_t sa_indigest[5]; /* inner digest */ + u_int32_t sa_outdigest[5]; /* outer digest */ + u_int32_t sa_spi; /* SPI */ + u_int32_t sa_seqnum; /* sequence number */ + u_int32_t sa_seqmask[2]; /* sequence number mask */ + u_int32_t sa_resv2; + u_int32_t sa_staterec; /* address of state record */ + u_int32_t sa_resv3[2]; + u_int32_t sa_samgmt0; /* SA management field 0 */ + u_int32_t sa_samgmt1; /* SA management field 0 */ +}; + +#define SAFE_SA_CMD0_OP 0x00000007 /* operation code */ +#define SAFE_SA_CMD0_OP_CRYPT 0x00000000 /* encrypt/decrypt (basic) */ +#define SAFE_SA_CMD0_OP_BOTH 0x00000001 /* encrypt-hash/hash-decrypto */ +#define SAFE_SA_CMD0_OP_HASH 0x00000003 /* hash (outbound-only) */ +#define SAFE_SA_CMD0_OP_ESP 0x00000000 /* ESP in/out (proto) */ +#define SAFE_SA_CMD0_OP_AH 0x00000001 /* AH in/out (proto) */ +#define SAFE_SA_CMD0_INBOUND 0x00000008 /* inbound operation */ +#define SAFE_SA_CMD0_OUTBOUND 0x00000000 /* outbound operation */ +#define SAFE_SA_CMD0_GROUP 0x00000030 /* operation group */ +#define SAFE_SA_CMD0_BASIC 0x00000000 /* basic operation */ +#define SAFE_SA_CMD0_PROTO 0x00000010 /* protocol/packet operation */ +#define SAFE_SA_CMD0_BUNDLE 0x00000020 /* bundled operation (resvd) */ +#define SAFE_SA_CMD0_PAD 0x000000c0 /* crypto pad method */ +#define SAFE_SA_CMD0_PAD_IPSEC 0x00000000 /* IPsec padding */ +#define SAFE_SA_CMD0_PAD_PKCS7 0x00000040 /* PKCS#7 padding */ +#define SAFE_SA_CMD0_PAD_CONS 0x00000080 /* constant padding */ +#define SAFE_SA_CMD0_PAD_ZERO 0x000000c0 /* zero padding */ +#define SAFE_SA_CMD0_CRYPT_ALG 0x00000f00 /* symmetric crypto algorithm */ +#define SAFE_SA_CMD0_DES 0x00000000 /* DES crypto algorithm */ +#define SAFE_SA_CMD0_3DES 0x00000100 /* 3DES crypto algorithm */ +#define SAFE_SA_CMD0_AES 0x00000300 /* AES crypto algorithm */ +#define SAFE_SA_CMD0_CRYPT_NULL 0x00000f00 /* null crypto algorithm */ +#define SAFE_SA_CMD0_HASH_ALG 0x0000f000 /* hash algorithm */ +#define SAFE_SA_CMD0_MD5 0x00000000 /* MD5 hash algorithm */ +#define SAFE_SA_CMD0_SHA1 0x00001000 /* SHA-1 hash algorithm */ +#define SAFE_SA_CMD0_HASH_NULL 0x0000f000 /* null hash algorithm */ +#define SAFE_SA_CMD0_HDR_PROC 0x00080000 /* header processing */ +#define SAFE_SA_CMD0_IBUSID 0x00300000 /* input bus id */ +#define SAFE_SA_CMD0_IPCI 0x00100000 /* PCI input bus id */ +#define SAFE_SA_CMD0_OBUSID 0x00c00000 /* output bus id */ +#define SAFE_SA_CMD0_OPCI 0x00400000 /* PCI output bus id */ +#define SAFE_SA_CMD0_IVLD 0x03000000 /* IV loading */ +#define SAFE_SA_CMD0_IVLD_NONE 0x00000000 /* IV no load (reuse) */ +#define SAFE_SA_CMD0_IVLD_IBUF 0x01000000 /* IV load from input buffer */ +#define SAFE_SA_CMD0_IVLD_STATE 0x02000000 /* IV load from state */ +#define SAFE_SA_CMD0_HSLD 0x0c000000 /* hash state loading */ +#define SAFE_SA_CMD0_HSLD_SA 0x00000000 /* hash state load from SA */ +#define SAFE_SA_CMD0_HSLD_STATE 0x08000000 /* hash state load from state */ +#define SAFE_SA_CMD0_HSLD_NONE 0x0c000000 /* hash state no load */ +#define SAFE_SA_CMD0_SAVEIV 0x10000000 /* save IV */ +#define SAFE_SA_CMD0_SAVEHASH 0x20000000 /* save hash state */ +#define SAFE_SA_CMD0_IGATHER 0x40000000 /* input gather */ +#define SAFE_SA_CMD0_OSCATTER 0x80000000 /* output scatter */ + +#define SAFE_SA_CMD1_HDRCOPY 0x00000002 /* copy header to output */ +#define SAFE_SA_CMD1_PAYCOPY 0x00000004 /* copy payload to output */ +#define SAFE_SA_CMD1_PADCOPY 0x00000008 /* copy pad to output */ +#define SAFE_SA_CMD1_IPV4 0x00000000 /* IPv4 protocol */ +#define SAFE_SA_CMD1_IPV6 0x00000010 /* IPv6 protocol */ +#define SAFE_SA_CMD1_MUTABLE 0x00000020 /* mutable bit processing */ +#define SAFE_SA_CMD1_SRBUSID 0x000000c0 /* state record bus id */ +#define SAFE_SA_CMD1_SRPCI 0x00000040 /* state record from PCI */ +#define SAFE_SA_CMD1_CRMODE 0x00000300 /* crypto mode */ +#define SAFE_SA_CMD1_ECB 0x00000000 /* ECB crypto mode */ +#define SAFE_SA_CMD1_CBC 0x00000100 /* CBC crypto mode */ +#define SAFE_SA_CMD1_OFB 0x00000200 /* OFB crypto mode */ +#define SAFE_SA_CMD1_CFB 0x00000300 /* CFB crypto mode */ +#define SAFE_SA_CMD1_CRFEEDBACK 0x00000c00 /* crypto feedback mode */ +#define SAFE_SA_CMD1_64BIT 0x00000000 /* 64-bit crypto feedback */ +#define SAFE_SA_CMD1_8BIT 0x00000400 /* 8-bit crypto feedback */ +#define SAFE_SA_CMD1_1BIT 0x00000800 /* 1-bit crypto feedback */ +#define SAFE_SA_CMD1_128BIT 0x00000c00 /* 128-bit crypto feedback */ +#define SAFE_SA_CMD1_OPTIONS 0x00001000 /* HMAC/options mutable bit */ +#define SAFE_SA_CMD1_HMAC SAFE_SA_CMD1_OPTIONS +#define SAFE_SA_CMD1_SAREV1 0x00008000 /* SA Revision 1 */ +#define SAFE_SA_CMD1_OFFSET 0x00ff0000 /* hash/crypto offset(dwords) */ +#define SAFE_SA_CMD1_OFFSET_S 16 +#define SAFE_SA_CMD1_AESKEYLEN 0x0f000000 /* AES key length */ +#define SAFE_SA_CMD1_AES128 0x02000000 /* 128-bit AES key */ +#define SAFE_SA_CMD1_AES192 0x03000000 /* 192-bit AES key */ +#define SAFE_SA_CMD1_AES256 0x04000000 /* 256-bit AES key */ + +/* + * Security Associate State Record (Rev 1). + */ +struct safe_sastate { + u_int32_t sa_saved_iv[4]; /* saved IV (DES/3DES/AES) */ + u_int32_t sa_saved_hashbc; /* saved hash byte count */ + u_int32_t sa_saved_indigest[5]; /* saved inner digest */ +}; +#endif /* _SAFE_SAFEREG_H_ */ diff --git a/target/linux/generic/files/crypto/ocf/safe/safevar.h b/target/linux/generic/files/crypto/ocf/safe/safevar.h new file mode 100644 index 0000000..11d8304 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/safe/safevar.h @@ -0,0 +1,229 @@ +/*- + * The linux port of this code done by David McCullough + * Copyright (C) 2004-2010 David McCullough + * The license and original author are listed below. + * + * Copyright (c) 2003 Sam Leffler, Errno Consulting + * Copyright (c) 2003 Global Technology Associates, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/dev/safe/safevar.h,v 1.2 2006/05/17 18:34:26 pjd Exp $ + */ +#ifndef _SAFE_SAFEVAR_H_ +#define _SAFE_SAFEVAR_H_ + +/* Maximum queue length */ +#ifndef SAFE_MAX_NQUEUE +#define SAFE_MAX_NQUEUE 60 +#endif + +#define SAFE_MAX_PART 64 /* Maximum scatter/gather depth */ +#define SAFE_DMA_BOUNDARY 0 /* No boundary for source DMA ops */ +#define SAFE_MAX_DSIZE 2048 /* MCLBYTES Fixed scatter particle size */ +#define SAFE_MAX_SSIZE 0x0ffff /* Maximum gather particle size */ +#define SAFE_MAX_DMA 0xfffff /* Maximum PE operand size (20 bits) */ +/* total src+dst particle descriptors */ +#define SAFE_TOTAL_DPART (SAFE_MAX_NQUEUE * SAFE_MAX_PART) +#define SAFE_TOTAL_SPART (SAFE_MAX_NQUEUE * SAFE_MAX_PART) + +#define SAFE_RNG_MAXBUFSIZ 128 /* 32-bit words */ + +#define SAFE_CARD(sid) (((sid) & 0xf0000000) >> 28) +#define SAFE_SESSION(sid) ( (sid) & 0x0fffffff) +#define SAFE_SID(crd, sesn) (((crd) << 28) | ((sesn) & 0x0fffffff)) + +#define SAFE_DEF_RTY 0xff /* PCI Retry Timeout */ +#define SAFE_DEF_TOUT 0xff /* PCI TRDY Timeout */ +#define SAFE_DEF_CACHELINE 0x01 /* Cache Line setting */ + +#ifdef __KERNEL__ +/* + * State associated with the allocation of each chunk + * of memory setup for DMA. + */ +struct safe_dma_alloc { + dma_addr_t dma_paddr; + void *dma_vaddr; +}; + +/* + * Cryptographic operand state. One of these exists for each + * source and destination operand passed in from the crypto + * subsystem. When possible source and destination operands + * refer to the same memory. More often they are distinct. + * We track the virtual address of each operand as well as + * where each is mapped for DMA. + */ +struct safe_operand { + union { + struct sk_buff *skb; + struct uio *io; + } u; + void *map; + int mapsize; /* total number of bytes in segs */ + struct { + dma_addr_t ds_addr; + int ds_len; + int ds_tlen; + } segs[SAFE_MAX_PART]; + int nsegs; +}; + +/* + * Packet engine ring entry and cryptographic operation state. + * The packet engine requires a ring of descriptors that contain + * pointers to various cryptographic state. However the ring + * configuration register allows you to specify an arbitrary size + * for ring entries. We use this feature to collect most of the + * state for each cryptographic request into one spot. Other than + * ring entries only the ``particle descriptors'' (scatter/gather + * lists) and the actual operand data are kept separate. The + * particle descriptors must also be organized in rings. The + * operand data can be located aribtrarily (modulo alignment constraints). + * + * Note that the descriptor ring is mapped onto the PCI bus so + * the hardware can DMA data. This means the entire ring must be + * contiguous. + */ +struct safe_ringentry { + struct safe_desc re_desc; /* command descriptor */ + struct safe_sarec re_sa; /* SA record */ + struct safe_sastate re_sastate; /* SA state record */ + + struct cryptop *re_crp; /* crypto operation */ + + struct safe_operand re_src; /* source operand */ + struct safe_operand re_dst; /* destination operand */ + + int re_sesn; /* crypto session ID */ + int re_flags; +#define SAFE_QFLAGS_COPYOUTIV 0x1 /* copy back on completion */ +#define SAFE_QFLAGS_COPYOUTICV 0x2 /* copy back on completion */ +}; + +#define re_src_skb re_src.u.skb +#define re_src_io re_src.u.io +#define re_src_map re_src.map +#define re_src_nsegs re_src.nsegs +#define re_src_segs re_src.segs +#define re_src_mapsize re_src.mapsize + +#define re_dst_skb re_dst.u.skb +#define re_dst_io re_dst.u.io +#define re_dst_map re_dst.map +#define re_dst_nsegs re_dst.nsegs +#define re_dst_segs re_dst.segs +#define re_dst_mapsize re_dst.mapsize + +struct rndstate_test; + +struct safe_session { + u_int32_t ses_used; + u_int32_t ses_klen; /* key length in bits */ + u_int32_t ses_key[8]; /* DES/3DES/AES key */ + u_int32_t ses_mlen; /* hmac length in bytes */ + u_int32_t ses_hminner[5]; /* hmac inner state */ + u_int32_t ses_hmouter[5]; /* hmac outer state */ +}; + +struct safe_pkq { + struct list_head pkq_list; + struct cryptkop *pkq_krp; +}; + +struct safe_softc { + softc_device_decl sc_dev; + u32 sc_irq; + + struct pci_dev *sc_pcidev; + ocf_iomem_t sc_base_addr; + + u_int sc_chiprev; /* major/minor chip revision */ + int sc_flags; /* device specific flags */ +#define SAFE_FLAGS_KEY 0x01 /* has key accelerator */ +#define SAFE_FLAGS_RNG 0x02 /* hardware rng */ + int sc_suspended; + int sc_needwakeup; /* notify crypto layer */ + int32_t sc_cid; /* crypto tag */ + + struct safe_dma_alloc sc_ringalloc; /* PE ring allocation state */ + struct safe_ringentry *sc_ring; /* PE ring */ + struct safe_ringentry *sc_ringtop; /* PE ring top */ + struct safe_ringentry *sc_front; /* next free entry */ + struct safe_ringentry *sc_back; /* next pending entry */ + int sc_nqchip; /* # passed to chip */ + spinlock_t sc_ringmtx; /* PE ring lock */ + struct safe_pdesc *sc_spring; /* src particle ring */ + struct safe_pdesc *sc_springtop; /* src particle ring top */ + struct safe_pdesc *sc_spfree; /* next free src particle */ + struct safe_dma_alloc sc_spalloc; /* src particle ring state */ + struct safe_pdesc *sc_dpring; /* dest particle ring */ + struct safe_pdesc *sc_dpringtop; /* dest particle ring top */ + struct safe_pdesc *sc_dpfree; /* next free dest particle */ + struct safe_dma_alloc sc_dpalloc; /* dst particle ring state */ + int sc_nsessions; /* # of sessions */ + struct safe_session *sc_sessions; /* sessions */ + + struct timer_list sc_pkto; /* PK polling */ + spinlock_t sc_pkmtx; /* PK lock */ + struct list_head sc_pkq; /* queue of PK requests */ + struct safe_pkq *sc_pkq_cur; /* current processing request */ + u_int32_t sc_pk_reslen, sc_pk_resoff; + + int sc_max_dsize; /* maximum safe DMA size */ +}; +#endif /* __KERNEL__ */ + +struct safe_stats { + u_int64_t st_ibytes; + u_int64_t st_obytes; + u_int32_t st_ipackets; + u_int32_t st_opackets; + u_int32_t st_invalid; /* invalid argument */ + u_int32_t st_badsession; /* invalid session id */ + u_int32_t st_badflags; /* flags indicate !(mbuf | uio) */ + u_int32_t st_nodesc; /* op submitted w/o descriptors */ + u_int32_t st_badalg; /* unsupported algorithm */ + u_int32_t st_ringfull; /* PE descriptor ring full */ + u_int32_t st_peoperr; /* PE marked error */ + u_int32_t st_dmaerr; /* PE DMA error */ + u_int32_t st_bypasstoobig; /* bypass > 96 bytes */ + u_int32_t st_skipmismatch; /* enc part begins before auth part */ + u_int32_t st_lenmismatch; /* enc length different auth length */ + u_int32_t st_coffmisaligned; /* crypto offset not 32-bit aligned */ + u_int32_t st_cofftoobig; /* crypto offset > 255 words */ + u_int32_t st_iovmisaligned; /* iov op not aligned */ + u_int32_t st_iovnotuniform; /* iov op not suitable */ + u_int32_t st_unaligned; /* unaligned src caused copy */ + u_int32_t st_notuniform; /* non-uniform src caused copy */ + u_int32_t st_nomap; /* bus_dmamap_create failed */ + u_int32_t st_noload; /* bus_dmamap_load_* failed */ + u_int32_t st_nombuf; /* MGET* failed */ + u_int32_t st_nomcl; /* MCLGET* failed */ + u_int32_t st_maxqchip; /* max mcr1 ops out for processing */ + u_int32_t st_rng; /* RNG requests */ + u_int32_t st_rngalarm; /* RNG alarm requests */ + u_int32_t st_noicvcopy; /* ICV data copies suppressed */ +}; +#endif /* _SAFE_SAFEVAR_H_ */ diff --git a/target/linux/generic/files/crypto/ocf/safe/sha1.c b/target/linux/generic/files/crypto/ocf/safe/sha1.c new file mode 100644 index 0000000..4e360e2 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/safe/sha1.c @@ -0,0 +1,279 @@ +/* $KAME: sha1.c,v 1.5 2000/11/08 06:13:08 itojun Exp $ */ +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * FIPS pub 180-1: Secure Hash Algorithm (SHA-1) + * based on: http://csrc.nist.gov/fips/fip180-1.txt + * implemented by Jun-ichiro itojun Itoh + */ + +#if 0 +#include +__FBSDID("$FreeBSD: src/sys/crypto/sha1.c,v 1.9 2003/06/10 21:36:57 obrien Exp $"); + +#include +#include +#include +#include + +#include +#endif + +/* sanity check */ +#if BYTE_ORDER != BIG_ENDIAN +# if BYTE_ORDER != LITTLE_ENDIAN +# define unsupported 1 +# endif +#endif + +#ifndef unsupported + +/* constant table */ +static u_int32_t _K[] = { 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6 }; +#define K(t) _K[(t) / 20] + +#define F0(b, c, d) (((b) & (c)) | ((~(b)) & (d))) +#define F1(b, c, d) (((b) ^ (c)) ^ (d)) +#define F2(b, c, d) (((b) & (c)) | ((b) & (d)) | ((c) & (d))) +#define F3(b, c, d) (((b) ^ (c)) ^ (d)) + +#define S(n, x) (((x) << (n)) | ((x) >> (32 - n))) + +#undef H +#define H(n) (ctxt->h.b32[(n)]) +#define COUNT (ctxt->count) +#define BCOUNT (ctxt->c.b64[0] / 8) +#define W(n) (ctxt->m.b32[(n)]) + +#define PUTBYTE(x) { \ + ctxt->m.b8[(COUNT % 64)] = (x); \ + COUNT++; \ + COUNT %= 64; \ + ctxt->c.b64[0] += 8; \ + if (COUNT % 64 == 0) \ + sha1_step(ctxt); \ + } + +#define PUTPAD(x) { \ + ctxt->m.b8[(COUNT % 64)] = (x); \ + COUNT++; \ + COUNT %= 64; \ + if (COUNT % 64 == 0) \ + sha1_step(ctxt); \ + } + +static void sha1_step(struct sha1_ctxt *); + +static void +sha1_step(ctxt) + struct sha1_ctxt *ctxt; +{ + u_int32_t a, b, c, d, e; + size_t t, s; + u_int32_t tmp; + +#if BYTE_ORDER == LITTLE_ENDIAN + struct sha1_ctxt tctxt; + bcopy(&ctxt->m.b8[0], &tctxt.m.b8[0], 64); + ctxt->m.b8[0] = tctxt.m.b8[3]; ctxt->m.b8[1] = tctxt.m.b8[2]; + ctxt->m.b8[2] = tctxt.m.b8[1]; ctxt->m.b8[3] = tctxt.m.b8[0]; + ctxt->m.b8[4] = tctxt.m.b8[7]; ctxt->m.b8[5] = tctxt.m.b8[6]; + ctxt->m.b8[6] = tctxt.m.b8[5]; ctxt->m.b8[7] = tctxt.m.b8[4]; + ctxt->m.b8[8] = tctxt.m.b8[11]; ctxt->m.b8[9] = tctxt.m.b8[10]; + ctxt->m.b8[10] = tctxt.m.b8[9]; ctxt->m.b8[11] = tctxt.m.b8[8]; + ctxt->m.b8[12] = tctxt.m.b8[15]; ctxt->m.b8[13] = tctxt.m.b8[14]; + ctxt->m.b8[14] = tctxt.m.b8[13]; ctxt->m.b8[15] = tctxt.m.b8[12]; + ctxt->m.b8[16] = tctxt.m.b8[19]; ctxt->m.b8[17] = tctxt.m.b8[18]; + ctxt->m.b8[18] = tctxt.m.b8[17]; ctxt->m.b8[19] = tctxt.m.b8[16]; + ctxt->m.b8[20] = tctxt.m.b8[23]; ctxt->m.b8[21] = tctxt.m.b8[22]; + ctxt->m.b8[22] = tctxt.m.b8[21]; ctxt->m.b8[23] = tctxt.m.b8[20]; + ctxt->m.b8[24] = tctxt.m.b8[27]; ctxt->m.b8[25] = tctxt.m.b8[26]; + ctxt->m.b8[26] = tctxt.m.b8[25]; ctxt->m.b8[27] = tctxt.m.b8[24]; + ctxt->m.b8[28] = tctxt.m.b8[31]; ctxt->m.b8[29] = tctxt.m.b8[30]; + ctxt->m.b8[30] = tctxt.m.b8[29]; ctxt->m.b8[31] = tctxt.m.b8[28]; + ctxt->m.b8[32] = tctxt.m.b8[35]; ctxt->m.b8[33] = tctxt.m.b8[34]; + ctxt->m.b8[34] = tctxt.m.b8[33]; ctxt->m.b8[35] = tctxt.m.b8[32]; + ctxt->m.b8[36] = tctxt.m.b8[39]; ctxt->m.b8[37] = tctxt.m.b8[38]; + ctxt->m.b8[38] = tctxt.m.b8[37]; ctxt->m.b8[39] = tctxt.m.b8[36]; + ctxt->m.b8[40] = tctxt.m.b8[43]; ctxt->m.b8[41] = tctxt.m.b8[42]; + ctxt->m.b8[42] = tctxt.m.b8[41]; ctxt->m.b8[43] = tctxt.m.b8[40]; + ctxt->m.b8[44] = tctxt.m.b8[47]; ctxt->m.b8[45] = tctxt.m.b8[46]; + ctxt->m.b8[46] = tctxt.m.b8[45]; ctxt->m.b8[47] = tctxt.m.b8[44]; + ctxt->m.b8[48] = tctxt.m.b8[51]; ctxt->m.b8[49] = tctxt.m.b8[50]; + ctxt->m.b8[50] = tctxt.m.b8[49]; ctxt->m.b8[51] = tctxt.m.b8[48]; + ctxt->m.b8[52] = tctxt.m.b8[55]; ctxt->m.b8[53] = tctxt.m.b8[54]; + ctxt->m.b8[54] = tctxt.m.b8[53]; ctxt->m.b8[55] = tctxt.m.b8[52]; + ctxt->m.b8[56] = tctxt.m.b8[59]; ctxt->m.b8[57] = tctxt.m.b8[58]; + ctxt->m.b8[58] = tctxt.m.b8[57]; ctxt->m.b8[59] = tctxt.m.b8[56]; + ctxt->m.b8[60] = tctxt.m.b8[63]; ctxt->m.b8[61] = tctxt.m.b8[62]; + ctxt->m.b8[62] = tctxt.m.b8[61]; ctxt->m.b8[63] = tctxt.m.b8[60]; +#endif + + a = H(0); b = H(1); c = H(2); d = H(3); e = H(4); + + for (t = 0; t < 20; t++) { + s = t & 0x0f; + if (t >= 16) { + W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^ W((s+2) & 0x0f) ^ W(s)); + } + tmp = S(5, a) + F0(b, c, d) + e + W(s) + K(t); + e = d; d = c; c = S(30, b); b = a; a = tmp; + } + for (t = 20; t < 40; t++) { + s = t & 0x0f; + W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^ W((s+2) & 0x0f) ^ W(s)); + tmp = S(5, a) + F1(b, c, d) + e + W(s) + K(t); + e = d; d = c; c = S(30, b); b = a; a = tmp; + } + for (t = 40; t < 60; t++) { + s = t & 0x0f; + W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^ W((s+2) & 0x0f) ^ W(s)); + tmp = S(5, a) + F2(b, c, d) + e + W(s) + K(t); + e = d; d = c; c = S(30, b); b = a; a = tmp; + } + for (t = 60; t < 80; t++) { + s = t & 0x0f; + W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^ W((s+2) & 0x0f) ^ W(s)); + tmp = S(5, a) + F3(b, c, d) + e + W(s) + K(t); + e = d; d = c; c = S(30, b); b = a; a = tmp; + } + + H(0) = H(0) + a; + H(1) = H(1) + b; + H(2) = H(2) + c; + H(3) = H(3) + d; + H(4) = H(4) + e; + + bzero(&ctxt->m.b8[0], 64); +} + +/*------------------------------------------------------------*/ + +void +sha1_init(ctxt) + struct sha1_ctxt *ctxt; +{ + bzero(ctxt, sizeof(struct sha1_ctxt)); + H(0) = 0x67452301; + H(1) = 0xefcdab89; + H(2) = 0x98badcfe; + H(3) = 0x10325476; + H(4) = 0xc3d2e1f0; +} + +void +sha1_pad(ctxt) + struct sha1_ctxt *ctxt; +{ + size_t padlen; /*pad length in bytes*/ + size_t padstart; + + PUTPAD(0x80); + + padstart = COUNT % 64; + padlen = 64 - padstart; + if (padlen < 8) { + bzero(&ctxt->m.b8[padstart], padlen); + COUNT += padlen; + COUNT %= 64; + sha1_step(ctxt); + padstart = COUNT % 64; /* should be 0 */ + padlen = 64 - padstart; /* should be 64 */ + } + bzero(&ctxt->m.b8[padstart], padlen - 8); + COUNT += (padlen - 8); + COUNT %= 64; +#if BYTE_ORDER == BIG_ENDIAN + PUTPAD(ctxt->c.b8[0]); PUTPAD(ctxt->c.b8[1]); + PUTPAD(ctxt->c.b8[2]); PUTPAD(ctxt->c.b8[3]); + PUTPAD(ctxt->c.b8[4]); PUTPAD(ctxt->c.b8[5]); + PUTPAD(ctxt->c.b8[6]); PUTPAD(ctxt->c.b8[7]); +#else + PUTPAD(ctxt->c.b8[7]); PUTPAD(ctxt->c.b8[6]); + PUTPAD(ctxt->c.b8[5]); PUTPAD(ctxt->c.b8[4]); + PUTPAD(ctxt->c.b8[3]); PUTPAD(ctxt->c.b8[2]); + PUTPAD(ctxt->c.b8[1]); PUTPAD(ctxt->c.b8[0]); +#endif +} + +void +sha1_loop(ctxt, input, len) + struct sha1_ctxt *ctxt; + const u_int8_t *input; + size_t len; +{ + size_t gaplen; + size_t gapstart; + size_t off; + size_t copysiz; + + off = 0; + + while (off < len) { + gapstart = COUNT % 64; + gaplen = 64 - gapstart; + + copysiz = (gaplen < len - off) ? gaplen : len - off; + bcopy(&input[off], &ctxt->m.b8[gapstart], copysiz); + COUNT += copysiz; + COUNT %= 64; + ctxt->c.b64[0] += copysiz * 8; + if (COUNT % 64 == 0) + sha1_step(ctxt); + off += copysiz; + } +} + +void +sha1_result(ctxt, digest0) + struct sha1_ctxt *ctxt; + caddr_t digest0; +{ + u_int8_t *digest; + + digest = (u_int8_t *)digest0; + sha1_pad(ctxt); +#if BYTE_ORDER == BIG_ENDIAN + bcopy(&ctxt->h.b8[0], digest, 20); +#else + digest[0] = ctxt->h.b8[3]; digest[1] = ctxt->h.b8[2]; + digest[2] = ctxt->h.b8[1]; digest[3] = ctxt->h.b8[0]; + digest[4] = ctxt->h.b8[7]; digest[5] = ctxt->h.b8[6]; + digest[6] = ctxt->h.b8[5]; digest[7] = ctxt->h.b8[4]; + digest[8] = ctxt->h.b8[11]; digest[9] = ctxt->h.b8[10]; + digest[10] = ctxt->h.b8[9]; digest[11] = ctxt->h.b8[8]; + digest[12] = ctxt->h.b8[15]; digest[13] = ctxt->h.b8[14]; + digest[14] = ctxt->h.b8[13]; digest[15] = ctxt->h.b8[12]; + digest[16] = ctxt->h.b8[19]; digest[17] = ctxt->h.b8[18]; + digest[18] = ctxt->h.b8[17]; digest[19] = ctxt->h.b8[16]; +#endif +} + +#endif /*unsupported*/ diff --git a/target/linux/generic/files/crypto/ocf/safe/sha1.h b/target/linux/generic/files/crypto/ocf/safe/sha1.h new file mode 100644 index 0000000..0e19d90 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/safe/sha1.h @@ -0,0 +1,72 @@ +/* $FreeBSD: src/sys/crypto/sha1.h,v 1.8 2002/03/20 05:13:50 alfred Exp $ */ +/* $KAME: sha1.h,v 1.5 2000/03/27 04:36:23 sumikawa Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +/* + * FIPS pub 180-1: Secure Hash Algorithm (SHA-1) + * based on: http://csrc.nist.gov/fips/fip180-1.txt + * implemented by Jun-ichiro itojun Itoh + */ + +#ifndef _NETINET6_SHA1_H_ +#define _NETINET6_SHA1_H_ + +struct sha1_ctxt { + union { + u_int8_t b8[20]; + u_int32_t b32[5]; + } h; + union { + u_int8_t b8[8]; + u_int64_t b64[1]; + } c; + union { + u_int8_t b8[64]; + u_int32_t b32[16]; + } m; + u_int8_t count; +}; + +#ifdef __KERNEL__ +extern void sha1_init(struct sha1_ctxt *); +extern void sha1_pad(struct sha1_ctxt *); +extern void sha1_loop(struct sha1_ctxt *, const u_int8_t *, size_t); +extern void sha1_result(struct sha1_ctxt *, caddr_t); + +/* compatibilty with other SHA1 source codes */ +typedef struct sha1_ctxt SHA1_CTX; +#define SHA1Init(x) sha1_init((x)) +#define SHA1Update(x, y, z) sha1_loop((x), (y), (z)) +#define SHA1Final(x, y) sha1_result((y), (x)) +#endif /* __KERNEL__ */ + +#define SHA1_RESULTLEN (160/8) + +#endif /*_NETINET6_SHA1_H_*/ diff --git a/target/linux/generic/files/crypto/ocf/talitos/Makefile b/target/linux/generic/files/crypto/ocf/talitos/Makefile new file mode 100644 index 0000000..2591b8a --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/talitos/Makefile @@ -0,0 +1,12 @@ +# for SGlinux builds +-include $(ROOTDIR)/modules/.config + +obj-$(CONFIG_OCF_TALITOS) += talitos.o + +obj ?= . +EXTRA_CFLAGS += -I$(obj)/.. -I$(obj)/ + +ifdef TOPDIR +-include $(TOPDIR)/Rules.make +endif + diff --git a/target/linux/generic/files/crypto/ocf/talitos/talitos.c b/target/linux/generic/files/crypto/ocf/talitos/talitos.c new file mode 100644 index 0000000..c4bc8c0 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/talitos/talitos.c @@ -0,0 +1,1355 @@ +/* + * crypto/ocf/talitos/talitos.c + * + * An OCF-Linux module that uses Freescale's SEC to do the crypto. + * Based on crypto/ocf/hifn and crypto/ocf/safe OCF drivers + * + * Copyright (c) 2006 Freescale Semiconductor, Inc. + * + * This code written by Kim A. B. Phillips + * some code copied from files with the following: + * Copyright (C) 2004-2007 David McCullough + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * --------------------------------------------------------------------------- + * + * NOTES: + * + * The Freescale SEC (also known as 'talitos') resides on the + * internal bus, and runs asynchronous to the processor core. It has + * a wide gamut of cryptographic acceleration features, including single- + * pass IPsec (also known as algorithm chaining). To properly utilize + * all of the SEC's performance enhancing features, further reworking + * of higher level code (framework, applications) will be necessary. + * + * The following table shows which SEC version is present in which devices: + * + * Devices SEC version + * + * 8272, 8248 SEC 1.0 + * 885, 875 SEC 1.2 + * 8555E, 8541E SEC 2.0 + * 8349E SEC 2.01 + * 8548E SEC 2.1 + * + * The following table shows the features offered by each SEC version: + * + * Max. chan- + * version Bus I/F Clock nels DEU AESU AFEU MDEU PKEU RNG KEU + * + * SEC 1.0 internal 64b 100MHz 4 1 1 1 1 1 1 0 + * SEC 1.2 internal 32b 66MHz 1 1 1 0 1 0 0 0 + * SEC 2.0 internal 64b 166MHz 4 1 1 1 1 1 1 0 + * SEC 2.01 internal 64b 166MHz 4 1 1 1 1 1 1 0 + * SEC 2.1 internal 64b 333MHz 4 1 1 1 1 1 1 1 + * + * Each execution unit in the SEC has two modes of execution; channel and + * slave/debug. This driver employs the channel infrastructure in the + * device for convenience. Only the RNG is directly accessed due to the + * convenience of its random fifo pool. The relationship between the + * channels and execution units is depicted in the following diagram: + * + * ------- ------------ + * ---| ch0 |---| | + * ------- | | + * | |------+-------+-------+-------+------------ + * ------- | | | | | | | + * ---| ch1 |---| | | | | | | + * ------- | | ------ ------ ------ ------ ------ + * |controller| |DEU | |AESU| |MDEU| |PKEU| ... |RNG | + * ------- | | ------ ------ ------ ------ ------ + * ---| ch2 |---| | | | | | | + * ------- | | | | | | | + * | |------+-------+-------+-------+------------ + * ------- | | + * ---| ch3 |---| | + * ------- ------------ + * + * Channel ch0 may drive an aes operation to the aes unit (AESU), + * and, at the same time, ch1 may drive a message digest operation + * to the mdeu. Each channel has an input descriptor FIFO, and the + * FIFO can contain, e.g. on the 8541E, up to 24 entries, before a + * a buffer overrun error is triggered. The controller is responsible + * for fetching the data from descriptor pointers, and passing the + * data to the appropriate EUs. The controller also writes the + * cryptographic operation's result to memory. The SEC notifies + * completion by triggering an interrupt and/or setting the 1st byte + * of the hdr field to 0xff. + * + * TODO: + * o support more algorithms + * o support more versions of the SEC + * o add support for linux 2.4 + * o scatter-gather (sg) support + * o add support for public key ops (PKEU) + * o add statistics + */ + +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) && !defined(AUTOCONF_INCLUDED) +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include /* dma_map_single() */ +#include + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15) +#include +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19) +#include +#endif + +#include +#include + +#define DRV_NAME "talitos" + +#include "talitos_dev.h" +#include "talitos_soft.h" + +#define read_random(p,l) get_random_bytes(p,l) + +const char talitos_driver_name[] = "Talitos OCF"; +const char talitos_driver_version[] = "0.2"; + +static int talitos_newsession(device_t dev, u_int32_t *sidp, + struct cryptoini *cri); +static int talitos_freesession(device_t dev, u_int64_t tid); +static int talitos_process(device_t dev, struct cryptop *crp, int hint); +static void dump_talitos_status(struct talitos_softc *sc); +static int talitos_submit(struct talitos_softc *sc, struct talitos_desc *td, + int chsel); +static void talitos_doneprocessing(struct talitos_softc *sc); +static void talitos_init_device(struct talitos_softc *sc); +static void talitos_reset_device_master(struct talitos_softc *sc); +static void talitos_reset_device(struct talitos_softc *sc); +static void talitos_errorprocessing(struct talitos_softc *sc); +#ifdef CONFIG_PPC_MERGE +static int talitos_probe(struct of_device *ofdev, const struct of_device_id *match); +static int talitos_remove(struct of_device *ofdev); +#else +static int talitos_probe(struct platform_device *pdev); +static int talitos_remove(struct platform_device *pdev); +#endif +#ifdef CONFIG_OCF_RANDOMHARVEST +static int talitos_read_random(void *arg, u_int32_t *buf, int maxwords); +static void talitos_rng_init(struct talitos_softc *sc); +#endif + +static device_method_t talitos_methods = { + /* crypto device methods */ + DEVMETHOD(cryptodev_newsession, talitos_newsession), + DEVMETHOD(cryptodev_freesession,talitos_freesession), + DEVMETHOD(cryptodev_process, talitos_process), +}; + +#define debug talitos_debug +int talitos_debug = 0; +module_param(talitos_debug, int, 0644); +MODULE_PARM_DESC(talitos_debug, "Enable debug"); + +static inline void talitos_write(volatile unsigned *addr, u32 val) +{ + out_be32(addr, val); +} + +static inline u32 talitos_read(volatile unsigned *addr) +{ + u32 val; + val = in_be32(addr); + return val; +} + +static void dump_talitos_status(struct talitos_softc *sc) +{ + unsigned int v, v_hi, i, *ptr; + v = talitos_read(sc->sc_base_addr + TALITOS_MCR); + v_hi = talitos_read(sc->sc_base_addr + TALITOS_MCR_HI); + printk(KERN_INFO "%s: MCR 0x%08x_%08x\n", + device_get_nameunit(sc->sc_cdev), v, v_hi); + v = talitos_read(sc->sc_base_addr + TALITOS_IMR); + v_hi = talitos_read(sc->sc_base_addr + TALITOS_IMR_HI); + printk(KERN_INFO "%s: IMR 0x%08x_%08x\n", + device_get_nameunit(sc->sc_cdev), v, v_hi); + v = talitos_read(sc->sc_base_addr + TALITOS_ISR); + v_hi = talitos_read(sc->sc_base_addr + TALITOS_ISR_HI); + printk(KERN_INFO "%s: ISR 0x%08x_%08x\n", + device_get_nameunit(sc->sc_cdev), v, v_hi); + for (i = 0; i < sc->sc_num_channels; i++) { + v = talitos_read(sc->sc_base_addr + i*TALITOS_CH_OFFSET + + TALITOS_CH_CDPR); + v_hi = talitos_read(sc->sc_base_addr + i*TALITOS_CH_OFFSET + + TALITOS_CH_CDPR_HI); + printk(KERN_INFO "%s: CDPR ch%d 0x%08x_%08x\n", + device_get_nameunit(sc->sc_cdev), i, v, v_hi); + } + for (i = 0; i < sc->sc_num_channels; i++) { + v = talitos_read(sc->sc_base_addr + i*TALITOS_CH_OFFSET + + TALITOS_CH_CCPSR); + v_hi = talitos_read(sc->sc_base_addr + i*TALITOS_CH_OFFSET + + TALITOS_CH_CCPSR_HI); + printk(KERN_INFO "%s: CCPSR ch%d 0x%08x_%08x\n", + device_get_nameunit(sc->sc_cdev), i, v, v_hi); + } + ptr = sc->sc_base_addr + TALITOS_CH_DESCBUF; + for (i = 0; i < 16; i++) { + v = talitos_read(ptr++); v_hi = talitos_read(ptr++); + printk(KERN_INFO "%s: DESCBUF ch0 0x%08x_%08x (tdp%02d)\n", + device_get_nameunit(sc->sc_cdev), v, v_hi, i); + } + return; +} + + +#ifdef CONFIG_OCF_RANDOMHARVEST +/* + * pull random numbers off the RNG FIFO, not exceeding amount available + */ +static int +talitos_read_random(void *arg, u_int32_t *buf, int maxwords) +{ + struct talitos_softc *sc = (struct talitos_softc *) arg; + int rc; + u_int32_t v; + + DPRINTF("%s()\n", __FUNCTION__); + + /* check for things like FIFO underflow */ + v = talitos_read(sc->sc_base_addr + TALITOS_RNGISR_HI); + if (unlikely(v)) { + printk(KERN_ERR "%s: RNGISR_HI error %08x\n", + device_get_nameunit(sc->sc_cdev), v); + return 0; + } + /* + * OFL is number of available 64-bit words, + * shift and convert to a 32-bit word count + */ + v = talitos_read(sc->sc_base_addr + TALITOS_RNGSR_HI); + v = (v & TALITOS_RNGSR_HI_OFL) >> (16 - 1); + if (maxwords > v) + maxwords = v; + for (rc = 0; rc < maxwords; rc++) { + buf[rc] = talitos_read(sc->sc_base_addr + + TALITOS_RNG_FIFO + rc*sizeof(u_int32_t)); + } + if (maxwords & 1) { + /* + * RNG will complain with an AE in the RNGISR + * if we don't complete the pairs of 32-bit reads + * to its 64-bit register based FIFO + */ + v = talitos_read(sc->sc_base_addr + + TALITOS_RNG_FIFO + rc*sizeof(u_int32_t)); + } + + return rc; +} + +static void +talitos_rng_init(struct talitos_softc *sc) +{ + u_int32_t v; + + DPRINTF("%s()\n", __FUNCTION__); + /* reset RNG EU */ + v = talitos_read(sc->sc_base_addr + TALITOS_RNGRCR_HI); + v |= TALITOS_RNGRCR_HI_SR; + talitos_write(sc->sc_base_addr + TALITOS_RNGRCR_HI, v); + while ((talitos_read(sc->sc_base_addr + TALITOS_RNGSR_HI) + & TALITOS_RNGSR_HI_RD) == 0) + cpu_relax(); + /* + * we tell the RNG to start filling the RNG FIFO + * by writing the RNGDSR + */ + v = talitos_read(sc->sc_base_addr + TALITOS_RNGDSR_HI); + talitos_write(sc->sc_base_addr + TALITOS_RNGDSR_HI, v); + /* + * 64 bits of data will be pushed onto the FIFO every + * 256 SEC cycles until the FIFO is full. The RNG then + * attempts to keep the FIFO full. + */ + v = talitos_read(sc->sc_base_addr + TALITOS_RNGISR_HI); + if (v) { + printk(KERN_ERR "%s: RNGISR_HI error %08x\n", + device_get_nameunit(sc->sc_cdev), v); + return; + } + /* + * n.b. we need to add a FIPS test here - if the RNG is going + * to fail, it's going to fail at reset time + */ + return; +} +#endif /* CONFIG_OCF_RANDOMHARVEST */ + +/* + * Generate a new software session. + */ +static int +talitos_newsession(device_t dev, u_int32_t *sidp, struct cryptoini *cri) +{ + struct cryptoini *c, *encini = NULL, *macini = NULL; + struct talitos_softc *sc = device_get_softc(dev); + struct talitos_session *ses = NULL; + int sesn; + + DPRINTF("%s()\n", __FUNCTION__); + if (sidp == NULL || cri == NULL || sc == NULL) { + DPRINTF("%s,%d - EINVAL\n", __FILE__, __LINE__); + return EINVAL; + } + for (c = cri; c != NULL; c = c->cri_next) { + if (c->cri_alg == CRYPTO_MD5 || + c->cri_alg == CRYPTO_MD5_HMAC || + c->cri_alg == CRYPTO_SHA1 || + c->cri_alg == CRYPTO_SHA1_HMAC || + c->cri_alg == CRYPTO_NULL_HMAC) { + if (macini) + return EINVAL; + macini = c; + } else if (c->cri_alg == CRYPTO_DES_CBC || + c->cri_alg == CRYPTO_3DES_CBC || + c->cri_alg == CRYPTO_AES_CBC || + c->cri_alg == CRYPTO_NULL_CBC) { + if (encini) + return EINVAL; + encini = c; + } else { + DPRINTF("UNKNOWN c->cri_alg %d\n", encini->cri_alg); + return EINVAL; + } + } + if (encini == NULL && macini == NULL) + return EINVAL; + if (encini) { + /* validate key length */ + switch (encini->cri_alg) { + case CRYPTO_DES_CBC: + if (encini->cri_klen != 64) + return EINVAL; + break; + case CRYPTO_3DES_CBC: + if (encini->cri_klen != 192) { + return EINVAL; + } + break; + case CRYPTO_AES_CBC: + if (encini->cri_klen != 128 && + encini->cri_klen != 192 && + encini->cri_klen != 256) + return EINVAL; + break; + default: + DPRINTF("UNKNOWN encini->cri_alg %d\n", + encini->cri_alg); + return EINVAL; + } + } + + if (sc->sc_sessions == NULL) { + ses = sc->sc_sessions = (struct talitos_session *) + kmalloc(sizeof(struct talitos_session), SLAB_ATOMIC); + if (ses == NULL) + return ENOMEM; + memset(ses, 0, sizeof(struct talitos_session)); + sesn = 0; + sc->sc_nsessions = 1; + } else { + for (sesn = 0; sesn < sc->sc_nsessions; sesn++) { + if (sc->sc_sessions[sesn].ses_used == 0) { + ses = &sc->sc_sessions[sesn]; + break; + } + } + + if (ses == NULL) { + /* allocating session */ + sesn = sc->sc_nsessions; + ses = (struct talitos_session *) kmalloc( + (sesn + 1) * sizeof(struct talitos_session), + SLAB_ATOMIC); + if (ses == NULL) + return ENOMEM; + memset(ses, 0, + (sesn + 1) * sizeof(struct talitos_session)); + memcpy(ses, sc->sc_sessions, + sesn * sizeof(struct talitos_session)); + memset(sc->sc_sessions, 0, + sesn * sizeof(struct talitos_session)); + kfree(sc->sc_sessions); + sc->sc_sessions = ses; + ses = &sc->sc_sessions[sesn]; + sc->sc_nsessions++; + } + } + + ses->ses_used = 1; + + if (encini) { + ses->ses_klen = (encini->cri_klen + 7) / 8; + memcpy(ses->ses_key, encini->cri_key, ses->ses_klen); + if (macini) { + /* doing hash on top of cipher */ + ses->ses_hmac_len = (macini->cri_klen + 7) / 8; + memcpy(ses->ses_hmac, macini->cri_key, + ses->ses_hmac_len); + } + } else if (macini) { + /* doing hash */ + ses->ses_klen = (macini->cri_klen + 7) / 8; + memcpy(ses->ses_key, macini->cri_key, ses->ses_klen); + } + + /* back compat way of determining MSC result len */ + if (macini) { + ses->ses_mlen = macini->cri_mlen; + if (ses->ses_mlen == 0) { + if (macini->cri_alg == CRYPTO_MD5_HMAC) + ses->ses_mlen = MD5_HASH_LEN; + else + ses->ses_mlen = SHA1_HASH_LEN; + } + } + + /* really should make up a template td here, + * and only fill things like i/o and direction in process() */ + + /* assign session ID */ + *sidp = TALITOS_SID(sc->sc_num, sesn); + return 0; +} + +/* + * Deallocate a session. + */ +static int +talitos_freesession(device_t dev, u_int64_t tid) +{ + struct talitos_softc *sc = device_get_softc(dev); + int session, ret; + u_int32_t sid = ((u_int32_t) tid) & 0xffffffff; + + if (sc == NULL) + return EINVAL; + session = TALITOS_SESSION(sid); + if (session < sc->sc_nsessions) { + memset(&sc->sc_sessions[session], 0, + sizeof(sc->sc_sessions[session])); + ret = 0; + } else + ret = EINVAL; + return ret; +} + +/* + * launch device processing - it will come back with done notification + * in the form of an interrupt and/or HDR_DONE_BITS in header + */ +static int +talitos_submit( + struct talitos_softc *sc, + struct talitos_desc *td, + int chsel) +{ + u_int32_t v; + + v = dma_map_single(NULL, td, sizeof(*td), DMA_TO_DEVICE); + talitos_write(sc->sc_base_addr + + chsel*TALITOS_CH_OFFSET + TALITOS_CH_FF, 0); + talitos_write(sc->sc_base_addr + + chsel*TALITOS_CH_OFFSET + TALITOS_CH_FF_HI, v); + return 0; +} + +static int +talitos_process(device_t dev, struct cryptop *crp, int hint) +{ + int i, err = 0, ivsize; + struct talitos_softc *sc = device_get_softc(dev); + struct cryptodesc *crd1, *crd2, *maccrd, *enccrd; + caddr_t iv; + struct talitos_session *ses; + struct talitos_desc *td; + unsigned long flags; + /* descriptor mappings */ + int hmac_key, hmac_data, cipher_iv, cipher_key, + in_fifo, out_fifo, cipher_iv_out; + static int chsel = -1; + u_int32_t rand_iv[4]; + + DPRINTF("%s()\n", __FUNCTION__); + + if (crp == NULL || crp->crp_callback == NULL || sc == NULL) { + return EINVAL; + } + crp->crp_etype = 0; + if (TALITOS_SESSION(crp->crp_sid) >= sc->sc_nsessions) { + return EINVAL; + } + + ses = &sc->sc_sessions[TALITOS_SESSION(crp->crp_sid)]; + + /* enter the channel scheduler */ + spin_lock_irqsave(&sc->sc_chnfifolock[sc->sc_num_channels], flags); + + /* reuse channel that already had/has requests for the required EU */ + for (i = 0; i < sc->sc_num_channels; i++) { + if (sc->sc_chnlastalg[i] == crp->crp_desc->crd_alg) + break; + } + if (i == sc->sc_num_channels) { + /* + * haven't seen this algo the last sc_num_channels or more + * use round robin in this case + * nb: sc->sc_num_channels must be power of 2 + */ + chsel = (chsel + 1) & (sc->sc_num_channels - 1); + } else { + /* + * matches channel with same target execution unit; + * use same channel in this case + */ + chsel = i; + } + sc->sc_chnlastalg[chsel] = crp->crp_desc->crd_alg; + + /* release the channel scheduler lock */ + spin_unlock_irqrestore(&sc->sc_chnfifolock[sc->sc_num_channels], flags); + + /* acquire the selected channel fifo lock */ + spin_lock_irqsave(&sc->sc_chnfifolock[chsel], flags); + + /* find and reserve next available descriptor-cryptop pair */ + for (i = 0; i < sc->sc_chfifo_len; i++) { + if (sc->sc_chnfifo[chsel][i].cf_desc.hdr == 0) { + /* + * ensure correct descriptor formation by + * avoiding inadvertently setting "optional" entries + * e.g. not using "optional" dptr2 for MD/HMAC descs + */ + memset(&sc->sc_chnfifo[chsel][i].cf_desc, + 0, sizeof(*td)); + /* reserve it with done notification request bit */ + sc->sc_chnfifo[chsel][i].cf_desc.hdr |= + TALITOS_DONE_NOTIFY; + break; + } + } + spin_unlock_irqrestore(&sc->sc_chnfifolock[chsel], flags); + + if (i == sc->sc_chfifo_len) { + /* fifo full */ + err = ERESTART; + goto errout; + } + + td = &sc->sc_chnfifo[chsel][i].cf_desc; + sc->sc_chnfifo[chsel][i].cf_crp = crp; + + crd1 = crp->crp_desc; + if (crd1 == NULL) { + err = EINVAL; + goto errout; + } + crd2 = crd1->crd_next; + /* prevent compiler warning */ + hmac_key = 0; + hmac_data = 0; + if (crd2 == NULL) { + td->hdr |= TD_TYPE_COMMON_NONSNOOP_NO_AFEU; + /* assign descriptor dword ptr mappings for this desc. type */ + cipher_iv = 1; + cipher_key = 2; + in_fifo = 3; + cipher_iv_out = 5; + if (crd1->crd_alg == CRYPTO_MD5_HMAC || + crd1->crd_alg == CRYPTO_SHA1_HMAC || + crd1->crd_alg == CRYPTO_SHA1 || + crd1->crd_alg == CRYPTO_MD5) { + out_fifo = 5; + maccrd = crd1; + enccrd = NULL; + } else if (crd1->crd_alg == CRYPTO_DES_CBC || + crd1->crd_alg == CRYPTO_3DES_CBC || + crd1->crd_alg == CRYPTO_AES_CBC || + crd1->crd_alg == CRYPTO_ARC4) { + out_fifo = 4; + maccrd = NULL; + enccrd = crd1; + } else { + DPRINTF("UNKNOWN crd1->crd_alg %d\n", crd1->crd_alg); + err = EINVAL; + goto errout; + } + } else { + if (sc->sc_desc_types & TALITOS_HAS_DT_IPSEC_ESP) { + td->hdr |= TD_TYPE_IPSEC_ESP; + } else { + DPRINTF("unimplemented: multiple descriptor ipsec\n"); + err = EINVAL; + goto errout; + } + /* assign descriptor dword ptr mappings for this desc. type */ + hmac_key = 0; + hmac_data = 1; + cipher_iv = 2; + cipher_key = 3; + in_fifo = 4; + out_fifo = 5; + cipher_iv_out = 6; + if ((crd1->crd_alg == CRYPTO_MD5_HMAC || + crd1->crd_alg == CRYPTO_SHA1_HMAC || + crd1->crd_alg == CRYPTO_MD5 || + crd1->crd_alg == CRYPTO_SHA1) && + (crd2->crd_alg == CRYPTO_DES_CBC || + crd2->crd_alg == CRYPTO_3DES_CBC || + crd2->crd_alg == CRYPTO_AES_CBC || + crd2->crd_alg == CRYPTO_ARC4) && + ((crd2->crd_flags & CRD_F_ENCRYPT) == 0)) { + maccrd = crd1; + enccrd = crd2; + } else if ((crd1->crd_alg == CRYPTO_DES_CBC || + crd1->crd_alg == CRYPTO_ARC4 || + crd1->crd_alg == CRYPTO_3DES_CBC || + crd1->crd_alg == CRYPTO_AES_CBC) && + (crd2->crd_alg == CRYPTO_MD5_HMAC || + crd2->crd_alg == CRYPTO_SHA1_HMAC || + crd2->crd_alg == CRYPTO_MD5 || + crd2->crd_alg == CRYPTO_SHA1) && + (crd1->crd_flags & CRD_F_ENCRYPT)) { + enccrd = crd1; + maccrd = crd2; + } else { + /* We cannot order the SEC as requested */ + printk("%s: cannot do the order\n", + device_get_nameunit(sc->sc_cdev)); + err = EINVAL; + goto errout; + } + } + /* assign in_fifo and out_fifo based on input/output struct type */ + if (crp->crp_flags & CRYPTO_F_SKBUF) { + /* using SKB buffers */ + struct sk_buff *skb = (struct sk_buff *)crp->crp_buf; + if (skb_shinfo(skb)->nr_frags) { + printk("%s: skb frags unimplemented\n", + device_get_nameunit(sc->sc_cdev)); + err = EINVAL; + goto errout; + } + td->ptr[in_fifo].ptr = dma_map_single(NULL, skb->data, + skb->len, DMA_TO_DEVICE); + td->ptr[in_fifo].len = skb->len; + td->ptr[out_fifo].ptr = dma_map_single(NULL, skb->data, + skb->len, DMA_TO_DEVICE); + td->ptr[out_fifo].len = skb->len; + td->ptr[hmac_data].ptr = dma_map_single(NULL, skb->data, + skb->len, DMA_TO_DEVICE); + } else if (crp->crp_flags & CRYPTO_F_IOV) { + /* using IOV buffers */ + struct uio *uiop = (struct uio *)crp->crp_buf; + if (uiop->uio_iovcnt > 1) { + printk("%s: iov frags unimplemented\n", + device_get_nameunit(sc->sc_cdev)); + err = EINVAL; + goto errout; + } + td->ptr[in_fifo].ptr = dma_map_single(NULL, + uiop->uio_iov->iov_base, crp->crp_ilen, DMA_TO_DEVICE); + td->ptr[in_fifo].len = crp->crp_ilen; + /* crp_olen is never set; always use crp_ilen */ + td->ptr[out_fifo].ptr = dma_map_single(NULL, + uiop->uio_iov->iov_base, + crp->crp_ilen, DMA_TO_DEVICE); + td->ptr[out_fifo].len = crp->crp_ilen; + } else { + /* using contig buffers */ + td->ptr[in_fifo].ptr = dma_map_single(NULL, + crp->crp_buf, crp->crp_ilen, DMA_TO_DEVICE); + td->ptr[in_fifo].len = crp->crp_ilen; + td->ptr[out_fifo].ptr = dma_map_single(NULL, + crp->crp_buf, crp->crp_ilen, DMA_TO_DEVICE); + td->ptr[out_fifo].len = crp->crp_ilen; + } + if (enccrd) { + switch (enccrd->crd_alg) { + case CRYPTO_3DES_CBC: + td->hdr |= TALITOS_MODE0_DEU_3DES; + /* FALLTHROUGH */ + case CRYPTO_DES_CBC: + td->hdr |= TALITOS_SEL0_DEU + | TALITOS_MODE0_DEU_CBC; + if (enccrd->crd_flags & CRD_F_ENCRYPT) + td->hdr |= TALITOS_MODE0_DEU_ENC; + ivsize = 2*sizeof(u_int32_t); + DPRINTF("%cDES ses %d ch %d len %d\n", + (td->hdr & TALITOS_MODE0_DEU_3DES)?'3':'1', + (u32)TALITOS_SESSION(crp->crp_sid), + chsel, td->ptr[in_fifo].len); + break; + case CRYPTO_AES_CBC: + td->hdr |= TALITOS_SEL0_AESU + | TALITOS_MODE0_AESU_CBC; + if (enccrd->crd_flags & CRD_F_ENCRYPT) + td->hdr |= TALITOS_MODE0_AESU_ENC; + ivsize = 4*sizeof(u_int32_t); + DPRINTF("AES ses %d ch %d len %d\n", + (u32)TALITOS_SESSION(crp->crp_sid), + chsel, td->ptr[in_fifo].len); + break; + default: + printk("%s: unimplemented enccrd->crd_alg %d\n", + device_get_nameunit(sc->sc_cdev), enccrd->crd_alg); + err = EINVAL; + goto errout; + } + /* + * Setup encrypt/decrypt state. When using basic ops + * we can't use an inline IV because hash/crypt offset + * must be from the end of the IV to the start of the + * crypt data and this leaves out the preceding header + * from the hash calculation. Instead we place the IV + * in the state record and set the hash/crypt offset to + * copy both the header+IV. + */ + if (enccrd->crd_flags & CRD_F_ENCRYPT) { + td->hdr |= TALITOS_DIR_OUTBOUND; + if (enccrd->crd_flags & CRD_F_IV_EXPLICIT) + iv = enccrd->crd_iv; + else + read_random((iv = (caddr_t) rand_iv), sizeof(rand_iv)); + if ((enccrd->crd_flags & CRD_F_IV_PRESENT) == 0) { + crypto_copyback(crp->crp_flags, crp->crp_buf, + enccrd->crd_inject, ivsize, iv); + } + } else { + td->hdr |= TALITOS_DIR_INBOUND; + if (enccrd->crd_flags & CRD_F_IV_EXPLICIT) { + iv = enccrd->crd_iv; + } else { + iv = (caddr_t) rand_iv; + crypto_copydata(crp->crp_flags, crp->crp_buf, + enccrd->crd_inject, ivsize, iv); + } + } + td->ptr[cipher_iv].ptr = dma_map_single(NULL, iv, ivsize, + DMA_TO_DEVICE); + td->ptr[cipher_iv].len = ivsize; + /* + * we don't need the cipher iv out length/pointer + * field to do ESP IPsec. Therefore we set the len field as 0, + * which tells the SEC not to do anything with this len/ptr + * field. Previously, when length/pointer as pointing to iv, + * it gave us corruption of packets. + */ + td->ptr[cipher_iv_out].len = 0; + } + if (enccrd && maccrd) { + /* this is ipsec only for now */ + td->hdr |= TALITOS_SEL1_MDEU + | TALITOS_MODE1_MDEU_INIT + | TALITOS_MODE1_MDEU_PAD; + switch (maccrd->crd_alg) { + case CRYPTO_MD5: + td->hdr |= TALITOS_MODE1_MDEU_MD5; + break; + case CRYPTO_MD5_HMAC: + td->hdr |= TALITOS_MODE1_MDEU_MD5_HMAC; + break; + case CRYPTO_SHA1: + td->hdr |= TALITOS_MODE1_MDEU_SHA1; + break; + case CRYPTO_SHA1_HMAC: + td->hdr |= TALITOS_MODE1_MDEU_SHA1_HMAC; + break; + default: + /* We cannot order the SEC as requested */ + printk("%s: cannot do the order\n", + device_get_nameunit(sc->sc_cdev)); + err = EINVAL; + goto errout; + } + if ((maccrd->crd_alg == CRYPTO_MD5_HMAC) || + (maccrd->crd_alg == CRYPTO_SHA1_HMAC)) { + /* + * The offset from hash data to the start of + * crypt data is the difference in the skips. + */ + /* ipsec only for now */ + td->ptr[hmac_key].ptr = dma_map_single(NULL, + ses->ses_hmac, ses->ses_hmac_len, DMA_TO_DEVICE); + td->ptr[hmac_key].len = ses->ses_hmac_len; + td->ptr[in_fifo].ptr += enccrd->crd_skip; + td->ptr[in_fifo].len = enccrd->crd_len; + td->ptr[out_fifo].ptr += enccrd->crd_skip; + td->ptr[out_fifo].len = enccrd->crd_len; + /* bytes of HMAC to postpend to ciphertext */ + td->ptr[out_fifo].extent = ses->ses_mlen; + td->ptr[hmac_data].ptr += maccrd->crd_skip; + td->ptr[hmac_data].len = enccrd->crd_skip - maccrd->crd_skip; + } + if (enccrd->crd_flags & CRD_F_KEY_EXPLICIT) { + printk("%s: CRD_F_KEY_EXPLICIT unimplemented\n", + device_get_nameunit(sc->sc_cdev)); + } + } + if (!enccrd && maccrd) { + /* single MD5 or SHA */ + td->hdr |= TALITOS_SEL0_MDEU + | TALITOS_MODE0_MDEU_INIT + | TALITOS_MODE0_MDEU_PAD; + switch (maccrd->crd_alg) { + case CRYPTO_MD5: + td->hdr |= TALITOS_MODE0_MDEU_MD5; + DPRINTF("MD5 ses %d ch %d len %d\n", + (u32)TALITOS_SESSION(crp->crp_sid), + chsel, td->ptr[in_fifo].len); + break; + case CRYPTO_MD5_HMAC: + td->hdr |= TALITOS_MODE0_MDEU_MD5_HMAC; + break; + case CRYPTO_SHA1: + td->hdr |= TALITOS_MODE0_MDEU_SHA1; + DPRINTF("SHA1 ses %d ch %d len %d\n", + (u32)TALITOS_SESSION(crp->crp_sid), + chsel, td->ptr[in_fifo].len); + break; + case CRYPTO_SHA1_HMAC: + td->hdr |= TALITOS_MODE0_MDEU_SHA1_HMAC; + break; + default: + /* We cannot order the SEC as requested */ + DPRINTF("cannot do the order\n"); + err = EINVAL; + goto errout; + } + + if (crp->crp_flags & CRYPTO_F_IOV) + td->ptr[out_fifo].ptr += maccrd->crd_inject; + + if ((maccrd->crd_alg == CRYPTO_MD5_HMAC) || + (maccrd->crd_alg == CRYPTO_SHA1_HMAC)) { + td->ptr[hmac_key].ptr = dma_map_single(NULL, + ses->ses_hmac, ses->ses_hmac_len, + DMA_TO_DEVICE); + td->ptr[hmac_key].len = ses->ses_hmac_len; + } + } + else { + /* using process key (session data has duplicate) */ + td->ptr[cipher_key].ptr = dma_map_single(NULL, + enccrd->crd_key, (enccrd->crd_klen + 7) / 8, + DMA_TO_DEVICE); + td->ptr[cipher_key].len = (enccrd->crd_klen + 7) / 8; + } + /* descriptor complete - GO! */ + return talitos_submit(sc, td, chsel); + +errout: + if (err != ERESTART) { + crp->crp_etype = err; + crypto_done(crp); + } + return err; +} + +/* go through all channels descriptors, notifying OCF what has + * _and_hasn't_ successfully completed and reset the device + * (otherwise it's up to decoding desc hdrs!) + */ +static void talitos_errorprocessing(struct talitos_softc *sc) +{ + unsigned long flags; + int i, j; + + /* disable further scheduling until under control */ + spin_lock_irqsave(&sc->sc_chnfifolock[sc->sc_num_channels], flags); + + if (debug) dump_talitos_status(sc); + /* go through descriptors, try and salvage those successfully done, + * and EIO those that weren't + */ + for (i = 0; i < sc->sc_num_channels; i++) { + spin_lock_irqsave(&sc->sc_chnfifolock[i], flags); + for (j = 0; j < sc->sc_chfifo_len; j++) { + if (sc->sc_chnfifo[i][j].cf_desc.hdr) { + if ((sc->sc_chnfifo[i][j].cf_desc.hdr + & TALITOS_HDR_DONE_BITS) + != TALITOS_HDR_DONE_BITS) { + /* this one didn't finish */ + /* signify in crp->etype */ + sc->sc_chnfifo[i][j].cf_crp->crp_etype + = EIO; + } + } else + continue; /* free entry */ + /* either way, notify ocf */ + crypto_done(sc->sc_chnfifo[i][j].cf_crp); + /* and tag it available again + * + * memset to ensure correct descriptor formation by + * avoiding inadvertently setting "optional" entries + * e.g. not using "optional" dptr2 MD/HMAC processing + */ + memset(&sc->sc_chnfifo[i][j].cf_desc, + 0, sizeof(struct talitos_desc)); + } + spin_unlock_irqrestore(&sc->sc_chnfifolock[i], flags); + } + /* reset and initialize the SEC h/w device */ + talitos_reset_device(sc); + talitos_init_device(sc); +#ifdef CONFIG_OCF_RANDOMHARVEST + if (sc->sc_exec_units & TALITOS_HAS_EU_RNG) + talitos_rng_init(sc); +#endif + + /* Okay. Stand by. */ + spin_unlock_irqrestore(&sc->sc_chnfifolock[sc->sc_num_channels], flags); + + return; +} + +/* go through all channels descriptors, notifying OCF what's been done */ +static void talitos_doneprocessing(struct talitos_softc *sc) +{ + unsigned long flags; + int i, j; + + /* go through descriptors looking for done bits */ + for (i = 0; i < sc->sc_num_channels; i++) { + spin_lock_irqsave(&sc->sc_chnfifolock[i], flags); + for (j = 0; j < sc->sc_chfifo_len; j++) { + /* descriptor has done bits set? */ + if ((sc->sc_chnfifo[i][j].cf_desc.hdr + & TALITOS_HDR_DONE_BITS) + == TALITOS_HDR_DONE_BITS) { + /* notify ocf */ + crypto_done(sc->sc_chnfifo[i][j].cf_crp); + /* and tag it available again + * + * memset to ensure correct descriptor formation by + * avoiding inadvertently setting "optional" entries + * e.g. not using "optional" dptr2 MD/HMAC processing + */ + memset(&sc->sc_chnfifo[i][j].cf_desc, + 0, sizeof(struct talitos_desc)); + } + } + spin_unlock_irqrestore(&sc->sc_chnfifolock[i], flags); + } + return; +} + +static irqreturn_t +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19) +talitos_intr(int irq, void *arg) +#else +talitos_intr(int irq, void *arg, struct pt_regs *regs) +#endif +{ + struct talitos_softc *sc = arg; + u_int32_t v, v_hi; + + /* ack */ + v = talitos_read(sc->sc_base_addr + TALITOS_ISR); + v_hi = talitos_read(sc->sc_base_addr + TALITOS_ISR_HI); + talitos_write(sc->sc_base_addr + TALITOS_ICR, v); + talitos_write(sc->sc_base_addr + TALITOS_ICR_HI, v_hi); + + if (unlikely(v & TALITOS_ISR_ERROR)) { + /* Okay, Houston, we've had a problem here. */ + printk(KERN_DEBUG "%s: got error interrupt - ISR 0x%08x_%08x\n", + device_get_nameunit(sc->sc_cdev), v, v_hi); + talitos_errorprocessing(sc); + } else + if (likely(v & TALITOS_ISR_DONE)) { + talitos_doneprocessing(sc); + } + return IRQ_HANDLED; +} + +/* + * Initialize registers we need to touch only once. + */ +static void +talitos_init_device(struct talitos_softc *sc) +{ + u_int32_t v; + int i; + + DPRINTF("%s()\n", __FUNCTION__); + + /* init all channels */ + for (i = 0; i < sc->sc_num_channels; i++) { + v = talitos_read(sc->sc_base_addr + + i*TALITOS_CH_OFFSET + TALITOS_CH_CCCR_HI); + v |= TALITOS_CH_CCCR_HI_CDWE + | TALITOS_CH_CCCR_HI_CDIE; /* invoke interrupt if done */ + talitos_write(sc->sc_base_addr + + i*TALITOS_CH_OFFSET + TALITOS_CH_CCCR_HI, v); + } + /* enable all interrupts */ + v = talitos_read(sc->sc_base_addr + TALITOS_IMR); + v |= TALITOS_IMR_ALL; + talitos_write(sc->sc_base_addr + TALITOS_IMR, v); + v = talitos_read(sc->sc_base_addr + TALITOS_IMR_HI); + v |= TALITOS_IMR_HI_ERRONLY; + talitos_write(sc->sc_base_addr + TALITOS_IMR_HI, v); + return; +} + +/* + * set the master reset bit on the device. + */ +static void +talitos_reset_device_master(struct talitos_softc *sc) +{ + u_int32_t v; + + /* Reset the device by writing 1 to MCR:SWR and waiting 'til cleared */ + v = talitos_read(sc->sc_base_addr + TALITOS_MCR); + talitos_write(sc->sc_base_addr + TALITOS_MCR, v | TALITOS_MCR_SWR); + + while (talitos_read(sc->sc_base_addr + TALITOS_MCR) & TALITOS_MCR_SWR) + cpu_relax(); + + return; +} + +/* + * Resets the device. Values in the registers are left as is + * from the reset (i.e. initial values are assigned elsewhere). + */ +static void +talitos_reset_device(struct talitos_softc *sc) +{ + u_int32_t v; + int i; + + DPRINTF("%s()\n", __FUNCTION__); + + /* + * Master reset + * errata documentation: warning: certain SEC interrupts + * are not fully cleared by writing the MCR:SWR bit, + * set bit twice to completely reset + */ + talitos_reset_device_master(sc); /* once */ + talitos_reset_device_master(sc); /* and once again */ + + /* reset all channels */ + for (i = 0; i < sc->sc_num_channels; i++) { + v = talitos_read(sc->sc_base_addr + i*TALITOS_CH_OFFSET + + TALITOS_CH_CCCR); + talitos_write(sc->sc_base_addr + i*TALITOS_CH_OFFSET + + TALITOS_CH_CCCR, v | TALITOS_CH_CCCR_RESET); + } +} + +/* Set up the crypto device structure, private data, + * and anything else we need before we start */ +#ifdef CONFIG_PPC_MERGE +static int talitos_probe(struct of_device *ofdev, const struct of_device_id *match) +#else +static int talitos_probe(struct platform_device *pdev) +#endif +{ + struct talitos_softc *sc = NULL; + struct resource *r; +#ifdef CONFIG_PPC_MERGE + struct device *device = &ofdev->dev; + struct device_node *np = ofdev->node; + const unsigned int *prop; + int err; + struct resource res; +#endif + static int num_chips = 0; + int rc; + int i; + + DPRINTF("%s()\n", __FUNCTION__); + + sc = (struct talitos_softc *) kmalloc(sizeof(*sc), GFP_KERNEL); + if (!sc) + return -ENOMEM; + memset(sc, 0, sizeof(*sc)); + + softc_device_init(sc, DRV_NAME, num_chips, talitos_methods); + + sc->sc_irq = -1; + sc->sc_cid = -1; +#ifndef CONFIG_PPC_MERGE + sc->sc_dev = pdev; +#endif + sc->sc_num = num_chips++; + +#ifdef CONFIG_PPC_MERGE + dev_set_drvdata(device, sc); +#else + platform_set_drvdata(sc->sc_dev, sc); +#endif + + /* get the irq line */ +#ifdef CONFIG_PPC_MERGE + err = of_address_to_resource(np, 0, &res); + if (err) + return -EINVAL; + r = &res; + + sc->sc_irq = irq_of_parse_and_map(np, 0); +#else + /* get a pointer to the register memory */ + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + sc->sc_irq = platform_get_irq(pdev, 0); +#endif + rc = request_irq(sc->sc_irq, talitos_intr, 0, + device_get_nameunit(sc->sc_cdev), sc); + if (rc) { + printk(KERN_ERR "%s: failed to hook irq %d\n", + device_get_nameunit(sc->sc_cdev), sc->sc_irq); + sc->sc_irq = -1; + goto out; + } + + sc->sc_base_addr = (ocf_iomem_t) ioremap(r->start, (r->end - r->start)); + if (!sc->sc_base_addr) { + printk(KERN_ERR "%s: failed to ioremap\n", + device_get_nameunit(sc->sc_cdev)); + goto out; + } + + /* figure out our SEC's properties and capabilities */ + sc->sc_chiprev = (u64)talitos_read(sc->sc_base_addr + TALITOS_ID) << 32 + | talitos_read(sc->sc_base_addr + TALITOS_ID_HI); + DPRINTF("sec id 0x%llx\n", sc->sc_chiprev); + +#ifdef CONFIG_PPC_MERGE + /* get SEC properties from device tree, defaulting to SEC 2.0 */ + + prop = of_get_property(np, "num-channels", NULL); + sc->sc_num_channels = prop ? *prop : TALITOS_NCHANNELS_SEC_2_0; + + prop = of_get_property(np, "channel-fifo-len", NULL); + sc->sc_chfifo_len = prop ? *prop : TALITOS_CHFIFOLEN_SEC_2_0; + + prop = of_get_property(np, "exec-units-mask", NULL); + sc->sc_exec_units = prop ? *prop : TALITOS_HAS_EUS_SEC_2_0; + + prop = of_get_property(np, "descriptor-types-mask", NULL); + sc->sc_desc_types = prop ? *prop : TALITOS_HAS_DESCTYPES_SEC_2_0; +#else + /* bulk should go away with openfirmware flat device tree support */ + if (sc->sc_chiprev & TALITOS_ID_SEC_2_0) { + sc->sc_num_channels = TALITOS_NCHANNELS_SEC_2_0; + sc->sc_chfifo_len = TALITOS_CHFIFOLEN_SEC_2_0; + sc->sc_exec_units = TALITOS_HAS_EUS_SEC_2_0; + sc->sc_desc_types = TALITOS_HAS_DESCTYPES_SEC_2_0; + } else { + printk(KERN_ERR "%s: failed to id device\n", + device_get_nameunit(sc->sc_cdev)); + goto out; + } +#endif + + /* + 1 is for the meta-channel lock used by the channel scheduler */ + sc->sc_chnfifolock = (spinlock_t *) kmalloc( + (sc->sc_num_channels + 1) * sizeof(spinlock_t), GFP_KERNEL); + if (!sc->sc_chnfifolock) + goto out; + for (i = 0; i < sc->sc_num_channels + 1; i++) { + spin_lock_init(&sc->sc_chnfifolock[i]); + } + + sc->sc_chnlastalg = (int *) kmalloc( + sc->sc_num_channels * sizeof(int), GFP_KERNEL); + if (!sc->sc_chnlastalg) + goto out; + memset(sc->sc_chnlastalg, 0, sc->sc_num_channels * sizeof(int)); + + sc->sc_chnfifo = (struct desc_cryptop_pair **) kmalloc( + sc->sc_num_channels * sizeof(struct desc_cryptop_pair *), + GFP_KERNEL); + if (!sc->sc_chnfifo) + goto out; + for (i = 0; i < sc->sc_num_channels; i++) { + sc->sc_chnfifo[i] = (struct desc_cryptop_pair *) kmalloc( + sc->sc_chfifo_len * sizeof(struct desc_cryptop_pair), + GFP_KERNEL); + if (!sc->sc_chnfifo[i]) + goto out; + memset(sc->sc_chnfifo[i], 0, + sc->sc_chfifo_len * sizeof(struct desc_cryptop_pair)); + } + + /* reset and initialize the SEC h/w device */ + talitos_reset_device(sc); + talitos_init_device(sc); + + sc->sc_cid = crypto_get_driverid(softc_get_device(sc),CRYPTOCAP_F_HARDWARE); + if (sc->sc_cid < 0) { + printk(KERN_ERR "%s: could not get crypto driver id\n", + device_get_nameunit(sc->sc_cdev)); + goto out; + } + + /* register algorithms with the framework */ + printk("%s:", device_get_nameunit(sc->sc_cdev)); + + if (sc->sc_exec_units & TALITOS_HAS_EU_RNG) { + printk(" rng"); +#ifdef CONFIG_OCF_RANDOMHARVEST + talitos_rng_init(sc); + crypto_rregister(sc->sc_cid, talitos_read_random, sc); +#endif + } + if (sc->sc_exec_units & TALITOS_HAS_EU_DEU) { + printk(" des/3des"); + crypto_register(sc->sc_cid, CRYPTO_3DES_CBC, 0, 0); + crypto_register(sc->sc_cid, CRYPTO_DES_CBC, 0, 0); + } + if (sc->sc_exec_units & TALITOS_HAS_EU_AESU) { + printk(" aes"); + crypto_register(sc->sc_cid, CRYPTO_AES_CBC, 0, 0); + } + if (sc->sc_exec_units & TALITOS_HAS_EU_MDEU) { + printk(" md5"); + crypto_register(sc->sc_cid, CRYPTO_MD5, 0, 0); + /* HMAC support only with IPsec for now */ + crypto_register(sc->sc_cid, CRYPTO_MD5_HMAC, 0, 0); + printk(" sha1"); + crypto_register(sc->sc_cid, CRYPTO_SHA1, 0, 0); + /* HMAC support only with IPsec for now */ + crypto_register(sc->sc_cid, CRYPTO_SHA1_HMAC, 0, 0); + } + printk("\n"); + return 0; + +out: +#ifndef CONFIG_PPC_MERGE + talitos_remove(pdev); +#endif + return -ENOMEM; +} + +#ifdef CONFIG_PPC_MERGE +static int talitos_remove(struct of_device *ofdev) +#else +static int talitos_remove(struct platform_device *pdev) +#endif +{ +#ifdef CONFIG_PPC_MERGE + struct talitos_softc *sc = dev_get_drvdata(&ofdev->dev); +#else + struct talitos_softc *sc = platform_get_drvdata(pdev); +#endif + int i; + + DPRINTF("%s()\n", __FUNCTION__); + if (sc->sc_cid >= 0) + crypto_unregister_all(sc->sc_cid); + if (sc->sc_chnfifo) { + for (i = 0; i < sc->sc_num_channels; i++) + if (sc->sc_chnfifo[i]) + kfree(sc->sc_chnfifo[i]); + kfree(sc->sc_chnfifo); + } + if (sc->sc_chnlastalg) + kfree(sc->sc_chnlastalg); + if (sc->sc_chnfifolock) + kfree(sc->sc_chnfifolock); + if (sc->sc_irq != -1) + free_irq(sc->sc_irq, sc); + if (sc->sc_base_addr) + iounmap((void *) sc->sc_base_addr); + kfree(sc); + return 0; +} + +#ifdef CONFIG_PPC_MERGE +static struct of_device_id talitos_match[] = { + { + .type = "crypto", + .compatible = "talitos", + }, + {}, +}; + +MODULE_DEVICE_TABLE(of, talitos_match); + +static struct of_platform_driver talitos_driver = { + .name = DRV_NAME, + .match_table = talitos_match, + .probe = talitos_probe, + .remove = talitos_remove, +}; + +static int __init talitos_init(void) +{ + return of_register_platform_driver(&talitos_driver); +} + +static void __exit talitos_exit(void) +{ + of_unregister_platform_driver(&talitos_driver); +} +#else +/* Structure for a platform device driver */ +static struct platform_driver talitos_driver = { + .probe = talitos_probe, + .remove = talitos_remove, + .driver = { + .name = "fsl-sec2", + } +}; + +static int __init talitos_init(void) +{ + return platform_driver_register(&talitos_driver); +} + +static void __exit talitos_exit(void) +{ + platform_driver_unregister(&talitos_driver); +} +#endif + +module_init(talitos_init); +module_exit(talitos_exit); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_AUTHOR("kim.phillips@freescale.com"); +MODULE_DESCRIPTION("OCF driver for Freescale SEC (talitos)"); diff --git a/target/linux/generic/files/crypto/ocf/talitos/talitos_dev.h b/target/linux/generic/files/crypto/ocf/talitos/talitos_dev.h new file mode 100644 index 0000000..a8b0479 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/talitos/talitos_dev.h @@ -0,0 +1,277 @@ +/* + * Freescale SEC (talitos) device dependent data structures + * + * Copyright (c) 2006 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +/* device ID register values */ +#define TALITOS_ID_SEC_2_0 0x40 +#define TALITOS_ID_SEC_2_1 0x40 /* cross ref with IP block revision reg */ + +/* + * following num_channels, channel-fifo-depth, exec-unit-mask, and + * descriptor-types-mask are for forward-compatibility with openfirmware + * flat device trees + */ + +/* + * num_channels : the number of channels available in each SEC version. + */ + +/* n.b. this driver requires these values be a power of 2 */ +#define TALITOS_NCHANNELS_SEC_1_0 4 +#define TALITOS_NCHANNELS_SEC_1_2 1 +#define TALITOS_NCHANNELS_SEC_2_0 4 +#define TALITOS_NCHANNELS_SEC_2_01 4 +#define TALITOS_NCHANNELS_SEC_2_1 4 +#define TALITOS_NCHANNELS_SEC_2_4 4 + +/* + * channel-fifo-depth : The number of descriptor + * pointers a channel fetch fifo can hold. + */ +#define TALITOS_CHFIFOLEN_SEC_1_0 1 +#define TALITOS_CHFIFOLEN_SEC_1_2 1 +#define TALITOS_CHFIFOLEN_SEC_2_0 24 +#define TALITOS_CHFIFOLEN_SEC_2_01 24 +#define TALITOS_CHFIFOLEN_SEC_2_1 24 +#define TALITOS_CHFIFOLEN_SEC_2_4 24 + +/* + * exec-unit-mask : The bitmask representing what Execution Units (EUs) + * are available. EU information should be encoded following the SEC's + * EU_SEL0 bitfield documentation, i.e. as follows: + * + * bit 31 = set if SEC permits no-EU selection (should be always set) + * bit 30 = set if SEC has the ARC4 EU (AFEU) + * bit 29 = set if SEC has the des/3des EU (DEU) + * bit 28 = set if SEC has the message digest EU (MDEU) + * bit 27 = set if SEC has the random number generator EU (RNG) + * bit 26 = set if SEC has the public key EU (PKEU) + * bit 25 = set if SEC has the aes EU (AESU) + * bit 24 = set if SEC has the Kasumi EU (KEU) + * + */ +#define TALITOS_HAS_EU_NONE (1<<0) +#define TALITOS_HAS_EU_AFEU (1<<1) +#define TALITOS_HAS_EU_DEU (1<<2) +#define TALITOS_HAS_EU_MDEU (1<<3) +#define TALITOS_HAS_EU_RNG (1<<4) +#define TALITOS_HAS_EU_PKEU (1<<5) +#define TALITOS_HAS_EU_AESU (1<<6) +#define TALITOS_HAS_EU_KEU (1<<7) + +/* the corresponding masks for each SEC version */ +#define TALITOS_HAS_EUS_SEC_1_0 0x7f +#define TALITOS_HAS_EUS_SEC_1_2 0x4d +#define TALITOS_HAS_EUS_SEC_2_0 0x7f +#define TALITOS_HAS_EUS_SEC_2_01 0x7f +#define TALITOS_HAS_EUS_SEC_2_1 0xff +#define TALITOS_HAS_EUS_SEC_2_4 0x7f + +/* + * descriptor-types-mask : The bitmask representing what descriptors + * are available. Descriptor type information should be encoded + * following the SEC's Descriptor Header Dword DESC_TYPE field + * documentation, i.e. as follows: + * + * bit 0 = set if SEC supports the aesu_ctr_nonsnoop desc. type + * bit 1 = set if SEC supports the ipsec_esp descriptor type + * bit 2 = set if SEC supports the common_nonsnoop desc. type + * bit 3 = set if SEC supports the 802.11i AES ccmp desc. type + * bit 4 = set if SEC supports the hmac_snoop_no_afeu desc. type + * bit 5 = set if SEC supports the srtp descriptor type + * bit 6 = set if SEC supports the non_hmac_snoop_no_afeu desc.type + * bit 7 = set if SEC supports the pkeu_assemble descriptor type + * bit 8 = set if SEC supports the aesu_key_expand_output desc.type + * bit 9 = set if SEC supports the pkeu_ptmul descriptor type + * bit 10 = set if SEC supports the common_nonsnoop_afeu desc. type + * bit 11 = set if SEC supports the pkeu_ptadd_dbl descriptor type + * + * ..and so on and so forth. + */ +#define TALITOS_HAS_DT_AESU_CTR_NONSNOOP (1<<0) +#define TALITOS_HAS_DT_IPSEC_ESP (1<<1) +#define TALITOS_HAS_DT_COMMON_NONSNOOP (1<<2) + +/* the corresponding masks for each SEC version */ +#define TALITOS_HAS_DESCTYPES_SEC_2_0 0x01010ebf +#define TALITOS_HAS_DESCTYPES_SEC_2_1 0x012b0ebf + +/* + * a TALITOS_xxx_HI address points to the low data bits (32-63) of the register + */ + +/* global register offset addresses */ +#define TALITOS_ID 0x1020 +#define TALITOS_ID_HI 0x1024 +#define TALITOS_MCR 0x1030 /* master control register */ +#define TALITOS_MCR_HI 0x1038 /* master control register */ +#define TALITOS_MCR_SWR 0x1 +#define TALITOS_IMR 0x1008 /* interrupt mask register */ +#define TALITOS_IMR_ALL 0x00010fff /* enable all interrupts mask */ +#define TALITOS_IMR_ERRONLY 0x00010aaa /* enable error interrupts */ +#define TALITOS_IMR_HI 0x100C /* interrupt mask register */ +#define TALITOS_IMR_HI_ALL 0x00323333 /* enable all interrupts mask */ +#define TALITOS_IMR_HI_ERRONLY 0x00222222 /* enable error interrupts */ +#define TALITOS_ISR 0x1010 /* interrupt status register */ +#define TALITOS_ISR_ERROR 0x00010faa /* errors mask */ +#define TALITOS_ISR_DONE 0x00000055 /* channel(s) done mask */ +#define TALITOS_ISR_HI 0x1014 /* interrupt status register */ +#define TALITOS_ICR 0x1018 /* interrupt clear register */ +#define TALITOS_ICR_HI 0x101C /* interrupt clear register */ + +/* channel register address stride */ +#define TALITOS_CH_OFFSET 0x100 + +/* channel register offset addresses and bits */ +#define TALITOS_CH_CCCR 0x1108 /* Crypto-Channel Config Register */ +#define TALITOS_CH_CCCR_RESET 0x1 /* Channel Reset bit */ +#define TALITOS_CH_CCCR_HI 0x110c /* Crypto-Channel Config Register */ +#define TALITOS_CH_CCCR_HI_CDWE 0x10 /* Channel done writeback enable bit */ +#define TALITOS_CH_CCCR_HI_NT 0x4 /* Notification type bit */ +#define TALITOS_CH_CCCR_HI_CDIE 0x2 /* Channel Done Interrupt Enable bit */ +#define TALITOS_CH_CCPSR 0x1110 /* Crypto-Channel Pointer Status Reg */ +#define TALITOS_CH_CCPSR_HI 0x1114 /* Crypto-Channel Pointer Status Reg */ +#define TALITOS_CH_FF 0x1148 /* Fetch FIFO */ +#define TALITOS_CH_FF_HI 0x114c /* Fetch FIFO's FETCH_ADRS */ +#define TALITOS_CH_CDPR 0x1140 /* Crypto-Channel Pointer Status Reg */ +#define TALITOS_CH_CDPR_HI 0x1144 /* Crypto-Channel Pointer Status Reg */ +#define TALITOS_CH_DESCBUF 0x1180 /* (thru 11bf) Crypto-Channel + * Descriptor Buffer (debug) */ + +/* execution unit register offset addresses and bits */ +#define TALITOS_DEUSR 0x2028 /* DEU status register */ +#define TALITOS_DEUSR_HI 0x202c /* DEU status register */ +#define TALITOS_DEUISR 0x2030 /* DEU interrupt status register */ +#define TALITOS_DEUISR_HI 0x2034 /* DEU interrupt status register */ +#define TALITOS_DEUICR 0x2038 /* DEU interrupt control register */ +#define TALITOS_DEUICR_HI 0x203c /* DEU interrupt control register */ +#define TALITOS_AESUISR 0x4030 /* AESU interrupt status register */ +#define TALITOS_AESUISR_HI 0x4034 /* AESU interrupt status register */ +#define TALITOS_AESUICR 0x4038 /* AESU interrupt control register */ +#define TALITOS_AESUICR_HI 0x403c /* AESU interrupt control register */ +#define TALITOS_MDEUISR 0x6030 /* MDEU interrupt status register */ +#define TALITOS_MDEUISR_HI 0x6034 /* MDEU interrupt status register */ +#define TALITOS_RNGSR 0xa028 /* RNG status register */ +#define TALITOS_RNGSR_HI 0xa02c /* RNG status register */ +#define TALITOS_RNGSR_HI_RD 0x1 /* RNG Reset done */ +#define TALITOS_RNGSR_HI_OFL 0xff0000/* number of dwords in RNG output FIFO*/ +#define TALITOS_RNGDSR 0xa010 /* RNG data size register */ +#define TALITOS_RNGDSR_HI 0xa014 /* RNG data size register */ +#define TALITOS_RNG_FIFO 0xa800 /* RNG FIFO - pool of random numbers */ +#define TALITOS_RNGISR 0xa030 /* RNG Interrupt status register */ +#define TALITOS_RNGISR_HI 0xa034 /* RNG Interrupt status register */ +#define TALITOS_RNGRCR 0xa018 /* RNG Reset control register */ +#define TALITOS_RNGRCR_HI 0xa01c /* RNG Reset control register */ +#define TALITOS_RNGRCR_HI_SR 0x1 /* RNG RNGRCR:Software Reset */ + +/* descriptor pointer entry */ +struct talitos_desc_ptr { + u16 len; /* length */ + u8 extent; /* jump (to s/g link table) and extent */ + u8 res; /* reserved */ + u32 ptr; /* pointer */ +}; + +/* descriptor */ +struct talitos_desc { + u32 hdr; /* header */ + u32 res; /* reserved */ + struct talitos_desc_ptr ptr[7]; /* ptr/len pair array */ +}; + +/* talitos descriptor header (hdr) bits */ + +/* primary execution unit select */ +#define TALITOS_SEL0_AFEU 0x10000000 +#define TALITOS_SEL0_DEU 0x20000000 +#define TALITOS_SEL0_MDEU 0x30000000 +#define TALITOS_SEL0_RNG 0x40000000 +#define TALITOS_SEL0_PKEU 0x50000000 +#define TALITOS_SEL0_AESU 0x60000000 + +/* primary execution unit mode (MODE0) and derivatives */ +#define TALITOS_MODE0_AESU_CBC 0x00200000 +#define TALITOS_MODE0_AESU_ENC 0x00100000 +#define TALITOS_MODE0_DEU_CBC 0x00400000 +#define TALITOS_MODE0_DEU_3DES 0x00200000 +#define TALITOS_MODE0_DEU_ENC 0x00100000 +#define TALITOS_MODE0_MDEU_INIT 0x01000000 /* init starting regs */ +#define TALITOS_MODE0_MDEU_HMAC 0x00800000 +#define TALITOS_MODE0_MDEU_PAD 0x00400000 /* PD */ +#define TALITOS_MODE0_MDEU_MD5 0x00200000 +#define TALITOS_MODE0_MDEU_SHA256 0x00100000 +#define TALITOS_MODE0_MDEU_SHA1 0x00000000 /* SHA-160 */ +#define TALITOS_MODE0_MDEU_MD5_HMAC \ + (TALITOS_MODE0_MDEU_MD5 | TALITOS_MODE0_MDEU_HMAC) +#define TALITOS_MODE0_MDEU_SHA256_HMAC \ + (TALITOS_MODE0_MDEU_SHA256 | TALITOS_MODE0_MDEU_HMAC) +#define TALITOS_MODE0_MDEU_SHA1_HMAC \ + (TALITOS_MODE0_MDEU_SHA1 | TALITOS_MODE0_MDEU_HMAC) + +/* secondary execution unit select (SEL1) */ +/* it's MDEU or nothing */ +#define TALITOS_SEL1_MDEU 0x00030000 + +/* secondary execution unit mode (MODE1) and derivatives */ +#define TALITOS_MODE1_MDEU_INIT 0x00001000 /* init starting regs */ +#define TALITOS_MODE1_MDEU_HMAC 0x00000800 +#define TALITOS_MODE1_MDEU_PAD 0x00000400 /* PD */ +#define TALITOS_MODE1_MDEU_MD5 0x00000200 +#define TALITOS_MODE1_MDEU_SHA256 0x00000100 +#define TALITOS_MODE1_MDEU_SHA1 0x00000000 /* SHA-160 */ +#define TALITOS_MODE1_MDEU_MD5_HMAC \ + (TALITOS_MODE1_MDEU_MD5 | TALITOS_MODE1_MDEU_HMAC) +#define TALITOS_MODE1_MDEU_SHA256_HMAC \ + (TALITOS_MODE1_MDEU_SHA256 | TALITOS_MODE1_MDEU_HMAC) +#define TALITOS_MODE1_MDEU_SHA1_HMAC \ + (TALITOS_MODE1_MDEU_SHA1 | TALITOS_MODE1_MDEU_HMAC) + +/* direction of overall data flow (DIR) */ +#define TALITOS_DIR_OUTBOUND 0x00000000 +#define TALITOS_DIR_INBOUND 0x00000002 + +/* done notification (DN) */ +#define TALITOS_DONE_NOTIFY 0x00000001 + +/* descriptor types */ +/* odd numbers here are valid on SEC2 and greater only (e.g. ipsec_esp) */ +#define TD_TYPE_AESU_CTR_NONSNOOP (0 << 3) +#define TD_TYPE_IPSEC_ESP (1 << 3) +#define TD_TYPE_COMMON_NONSNOOP_NO_AFEU (2 << 3) +#define TD_TYPE_HMAC_SNOOP_NO_AFEU (4 << 3) + +#define TALITOS_HDR_DONE_BITS 0xff000000 + +#define DPRINTF(a...) do { \ + if (debug) { \ + printk("%s: ", sc ? \ + device_get_nameunit(sc->sc_cdev) : "talitos"); \ + printk(a); \ + } \ + } while (0) diff --git a/target/linux/generic/files/crypto/ocf/talitos/talitos_soft.h b/target/linux/generic/files/crypto/ocf/talitos/talitos_soft.h new file mode 100644 index 0000000..eda9c2e --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/talitos/talitos_soft.h @@ -0,0 +1,76 @@ +/* + * Freescale SEC data structures for integration with ocf-linux + * + * Copyright (c) 2006 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * paired descriptor and associated crypto operation + */ +struct desc_cryptop_pair { + struct talitos_desc cf_desc; /* descriptor ptr */ + struct cryptop *cf_crp; /* cryptop ptr */ +}; + +/* + * Holds data specific to a single talitos device. + */ +struct talitos_softc { + softc_device_decl sc_cdev; + struct platform_device *sc_dev; /* device backpointer */ + ocf_iomem_t sc_base_addr; + int sc_irq; + int sc_num; /* if we have multiple chips */ + int32_t sc_cid; /* crypto tag */ + u64 sc_chiprev; /* major/minor chip revision */ + int sc_nsessions; + struct talitos_session *sc_sessions; + int sc_num_channels;/* number of crypto channels */ + int sc_chfifo_len; /* channel fetch fifo len */ + int sc_exec_units; /* execution units mask */ + int sc_desc_types; /* descriptor types mask */ + /* + * mutual exclusion for intra-channel resources, e.g. fetch fifos + * the last entry is a meta-channel lock used by the channel scheduler + */ + spinlock_t *sc_chnfifolock; + /* sc_chnlastalgo contains last algorithm for that channel */ + int *sc_chnlastalg; + /* sc_chnfifo holds pending descriptor--crypto operation pairs */ + struct desc_cryptop_pair **sc_chnfifo; +}; + +struct talitos_session { + u_int32_t ses_used; + u_int32_t ses_klen; /* key length in bits */ + u_int32_t ses_key[8]; /* DES/3DES/AES key */ + u_int32_t ses_hmac[5]; /* hmac inner state */ + u_int32_t ses_hmac_len; /* hmac length */ + u_int32_t ses_mlen; /* desired hash result len (12=ipsec or 16) */ +}; + +#define TALITOS_SESSION(sid) ((sid) & 0x0fffffff) +#define TALITOS_SID(crd, sesn) (((crd) << 28) | ((sesn) & 0x0fffffff)) diff --git a/target/linux/generic/files/crypto/ocf/ubsec_ssb/Makefile b/target/linux/generic/files/crypto/ocf/ubsec_ssb/Makefile new file mode 100644 index 0000000..f973efd --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/ubsec_ssb/Makefile @@ -0,0 +1,12 @@ +# for SGlinux builds +-include $(ROOTDIR)/modules/.config + +obj-$(CONFIG_OCF_UBSEC_SSB) += ubsec_ssb.o + +obj ?= . +EXTRA_CFLAGS += -I$(obj)/.. -I$(obj)/ + +ifdef TOPDIR +-include $(TOPDIR)/Rules.make +endif + diff --git a/target/linux/generic/files/crypto/ocf/ubsec_ssb/bsdqueue.h b/target/linux/generic/files/crypto/ocf/ubsec_ssb/bsdqueue.h new file mode 100644 index 0000000..6010552 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/ubsec_ssb/bsdqueue.h @@ -0,0 +1,527 @@ +/* $OpenBSD: queue.h,v 1.32 2007/04/30 18:42:34 pedro Exp $ */ +/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */ + +/* + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)queue.h 8.5 (Berkeley) 8/20/94 + */ + +#ifndef _BSD_SYS_QUEUE_H_ +#define _BSD_SYS_QUEUE_H_ + +/* + * This file defines five types of data structures: singly-linked lists, + * lists, simple queues, tail queues, and circular queues. + * + * + * A singly-linked list is headed by a single forward pointer. The elements + * are singly linked for minimum space and pointer manipulation overhead at + * the expense of O(n) removal for arbitrary elements. New elements can be + * added to the list after an existing element or at the head of the list. + * Elements being removed from the head of the list should use the explicit + * macro for this purpose for optimum efficiency. A singly-linked list may + * only be traversed in the forward direction. Singly-linked lists are ideal + * for applications with large datasets and few or no removals or for + * implementing a LIFO queue. + * + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may only be traversed in the forward direction. + * + * A simple queue is headed by a pair of pointers, one the head of the + * list and the other to the tail of the list. The elements are singly + * linked to save space, so elements can only be removed from the + * head of the list. New elements can be added to the list before or after + * an existing element, at the head of the list, or at the end of the + * list. A simple queue may only be traversed in the forward direction. + * + * A tail queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or + * after an existing element, at the head of the list, or at the end of + * the list. A tail queue may be traversed in either direction. + * + * A circle queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or after + * an existing element, at the head of the list, or at the end of the list. + * A circle queue may be traversed in either direction, but has a more + * complex end of list detection. + * + * For details on the use of these macros, see the queue(3) manual page. + */ + +#if defined(QUEUE_MACRO_DEBUG) || (defined(_KERNEL) && defined(DIAGNOSTIC)) +#define _Q_INVALIDATE(a) (a) = ((void *)-1) +#else +#define _Q_INVALIDATE(a) +#endif + +/* + * Singly-linked List definitions. + */ +#define BSD_SLIST_HEAD(name, type) \ +struct name { \ + struct type *slh_first; /* first element */ \ +} + +#define BSD_SLIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define BSD_SLIST_ENTRY(type) \ +struct { \ + struct type *sle_next; /* next element */ \ +} + +/* + * Singly-linked List access methods. + */ +#define BSD_SLIST_FIRST(head) ((head)->slh_first) +#define BSD_SLIST_END(head) NULL +#define BSD_SLIST_EMPTY(head) (BSD_SLIST_FIRST(head) == BSD_SLIST_END(head)) +#define BSD_SLIST_NEXT(elm, field) ((elm)->field.sle_next) + +#define BSD_SLIST_FOREACH(var, head, field) \ + for((var) = BSD_SLIST_FIRST(head); \ + (var) != BSD_SLIST_END(head); \ + (var) = BSD_SLIST_NEXT(var, field)) + +#define BSD_SLIST_FOREACH_PREVPTR(var, varp, head, field) \ + for ((varp) = &BSD_SLIST_FIRST((head)); \ + ((var) = *(varp)) != BSD_SLIST_END(head); \ + (varp) = &BSD_SLIST_NEXT((var), field)) + +/* + * Singly-linked List functions. + */ +#define BSD_SLIST_INIT(head) { \ + BSD_SLIST_FIRST(head) = BSD_SLIST_END(head); \ +} + +#define BSD_SLIST_INSERT_AFTER(slistelm, elm, field) do { \ + (elm)->field.sle_next = (slistelm)->field.sle_next; \ + (slistelm)->field.sle_next = (elm); \ +} while (0) + +#define BSD_SLIST_INSERT_HEAD(head, elm, field) do { \ + (elm)->field.sle_next = (head)->slh_first; \ + (head)->slh_first = (elm); \ +} while (0) + +#define BSD_SLIST_REMOVE_NEXT(head, elm, field) do { \ + (elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \ +} while (0) + +#define BSD_SLIST_REMOVE_HEAD(head, field) do { \ + (head)->slh_first = (head)->slh_first->field.sle_next; \ +} while (0) + +#define BSD_SLIST_REMOVE(head, elm, type, field) do { \ + if ((head)->slh_first == (elm)) { \ + BSD_SLIST_REMOVE_HEAD((head), field); \ + } else { \ + struct type *curelm = (head)->slh_first; \ + \ + while (curelm->field.sle_next != (elm)) \ + curelm = curelm->field.sle_next; \ + curelm->field.sle_next = \ + curelm->field.sle_next->field.sle_next; \ + _Q_INVALIDATE((elm)->field.sle_next); \ + } \ +} while (0) + +/* + * List definitions. + */ +#define BSD_LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +#define BSD_LIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define BSD_LIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ +} + +/* + * List access methods + */ +#define BSD_LIST_FIRST(head) ((head)->lh_first) +#define BSD_LIST_END(head) NULL +#define BSD_LIST_EMPTY(head) (BSD_LIST_FIRST(head) == BSD_LIST_END(head)) +#define BSD_LIST_NEXT(elm, field) ((elm)->field.le_next) + +#define BSD_LIST_FOREACH(var, head, field) \ + for((var) = BSD_LIST_FIRST(head); \ + (var)!= BSD_LIST_END(head); \ + (var) = BSD_LIST_NEXT(var, field)) + +/* + * List functions. + */ +#define BSD_LIST_INIT(head) do { \ + BSD_LIST_FIRST(head) = BSD_LIST_END(head); \ +} while (0) + +#define BSD_LIST_INSERT_AFTER(listelm, elm, field) do { \ + if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ + (listelm)->field.le_next->field.le_prev = \ + &(elm)->field.le_next; \ + (listelm)->field.le_next = (elm); \ + (elm)->field.le_prev = &(listelm)->field.le_next; \ +} while (0) + +#define BSD_LIST_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + (elm)->field.le_next = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &(elm)->field.le_next; \ +} while (0) + +#define BSD_LIST_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.le_next = (head)->lh_first) != NULL) \ + (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ + (head)->lh_first = (elm); \ + (elm)->field.le_prev = &(head)->lh_first; \ +} while (0) + +#define BSD_LIST_REMOVE(elm, field) do { \ + if ((elm)->field.le_next != NULL) \ + (elm)->field.le_next->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = (elm)->field.le_next; \ + _Q_INVALIDATE((elm)->field.le_prev); \ + _Q_INVALIDATE((elm)->field.le_next); \ +} while (0) + +#define BSD_LIST_REPLACE(elm, elm2, field) do { \ + if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \ + (elm2)->field.le_next->field.le_prev = \ + &(elm2)->field.le_next; \ + (elm2)->field.le_prev = (elm)->field.le_prev; \ + *(elm2)->field.le_prev = (elm2); \ + _Q_INVALIDATE((elm)->field.le_prev); \ + _Q_INVALIDATE((elm)->field.le_next); \ +} while (0) + +/* + * Simple queue definitions. + */ +#define BSD_SIMPLEQ_HEAD(name, type) \ +struct name { \ + struct type *sqh_first; /* first element */ \ + struct type **sqh_last; /* addr of last next element */ \ +} + +#define BSD_SIMPLEQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).sqh_first } + +#define BSD_SIMPLEQ_ENTRY(type) \ +struct { \ + struct type *sqe_next; /* next element */ \ +} + +/* + * Simple queue access methods. + */ +#define BSD_SIMPLEQ_FIRST(head) ((head)->sqh_first) +#define BSD_SIMPLEQ_END(head) NULL +#define BSD_SIMPLEQ_EMPTY(head) (BSD_SIMPLEQ_FIRST(head) == BSD_SIMPLEQ_END(head)) +#define BSD_SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next) + +#define BSD_SIMPLEQ_FOREACH(var, head, field) \ + for((var) = BSD_SIMPLEQ_FIRST(head); \ + (var) != BSD_SIMPLEQ_END(head); \ + (var) = BSD_SIMPLEQ_NEXT(var, field)) + +/* + * Simple queue functions. + */ +#define BSD_SIMPLEQ_INIT(head) do { \ + (head)->sqh_first = NULL; \ + (head)->sqh_last = &(head)->sqh_first; \ +} while (0) + +#define BSD_SIMPLEQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (head)->sqh_first = (elm); \ +} while (0) + +#define BSD_SIMPLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.sqe_next = NULL; \ + *(head)->sqh_last = (elm); \ + (head)->sqh_last = &(elm)->field.sqe_next; \ +} while (0) + +#define BSD_SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (listelm)->field.sqe_next = (elm); \ +} while (0) + +#define BSD_SIMPLEQ_REMOVE_HEAD(head, field) do { \ + if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \ + (head)->sqh_last = &(head)->sqh_first; \ +} while (0) + +/* + * Tail queue definitions. + */ +#define BSD_TAILQ_HEAD(name, type) \ +struct name { \ + struct type *tqh_first; /* first element */ \ + struct type **tqh_last; /* addr of last next element */ \ +} + +#define BSD_TAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).tqh_first } + +#define BSD_TAILQ_ENTRY(type) \ +struct { \ + struct type *tqe_next; /* next element */ \ + struct type **tqe_prev; /* address of previous next element */ \ +} + +/* + * tail queue access methods + */ +#define BSD_TAILQ_FIRST(head) ((head)->tqh_first) +#define BSD_TAILQ_END(head) NULL +#define BSD_TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) +#define BSD_TAILQ_LAST(head, headname) \ + (*(((struct headname *)((head)->tqh_last))->tqh_last)) +/* XXX */ +#define BSD_TAILQ_PREV(elm, headname, field) \ + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) +#define BSD_TAILQ_EMPTY(head) \ + (BSD_TAILQ_FIRST(head) == BSD_TAILQ_END(head)) + +#define BSD_TAILQ_FOREACH(var, head, field) \ + for((var) = BSD_TAILQ_FIRST(head); \ + (var) != BSD_TAILQ_END(head); \ + (var) = BSD_TAILQ_NEXT(var, field)) + +#define BSD_TAILQ_FOREACH_REVERSE(var, head, headname, field) \ + for((var) = BSD_TAILQ_LAST(head, headname); \ + (var) != BSD_TAILQ_END(head); \ + (var) = BSD_TAILQ_PREV(var, headname, field)) + +/* + * Tail queue functions. + */ +#define BSD_TAILQ_INIT(head) do { \ + (head)->tqh_first = NULL; \ + (head)->tqh_last = &(head)->tqh_first; \ +} while (0) + +#define BSD_TAILQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ + (head)->tqh_first->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (head)->tqh_first = (elm); \ + (elm)->field.tqe_prev = &(head)->tqh_first; \ +} while (0) + +#define BSD_TAILQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.tqe_next = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &(elm)->field.tqe_next; \ +} while (0) + +#define BSD_TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ + (elm)->field.tqe_next->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (listelm)->field.tqe_next = (elm); \ + (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ +} while (0) + +#define BSD_TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + (elm)->field.tqe_next = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ +} while (0) + +#define BSD_TAILQ_REMOVE(head, elm, field) do { \ + if (((elm)->field.tqe_next) != NULL) \ + (elm)->field.tqe_next->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ + _Q_INVALIDATE((elm)->field.tqe_prev); \ + _Q_INVALIDATE((elm)->field.tqe_next); \ +} while (0) + +#define BSD_TAILQ_REPLACE(head, elm, elm2, field) do { \ + if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \ + (elm2)->field.tqe_next->field.tqe_prev = \ + &(elm2)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm2)->field.tqe_next; \ + (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \ + *(elm2)->field.tqe_prev = (elm2); \ + _Q_INVALIDATE((elm)->field.tqe_prev); \ + _Q_INVALIDATE((elm)->field.tqe_next); \ +} while (0) + +/* + * Circular queue definitions. + */ +#define BSD_CIRCLEQ_HEAD(name, type) \ +struct name { \ + struct type *cqh_first; /* first element */ \ + struct type *cqh_last; /* last element */ \ +} + +#define BSD_CIRCLEQ_HEAD_INITIALIZER(head) \ + { BSD_CIRCLEQ_END(&head), BSD_CIRCLEQ_END(&head) } + +#define BSD_CIRCLEQ_ENTRY(type) \ +struct { \ + struct type *cqe_next; /* next element */ \ + struct type *cqe_prev; /* previous element */ \ +} + +/* + * Circular queue access methods + */ +#define BSD_CIRCLEQ_FIRST(head) ((head)->cqh_first) +#define BSD_CIRCLEQ_LAST(head) ((head)->cqh_last) +#define BSD_CIRCLEQ_END(head) ((void *)(head)) +#define BSD_CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next) +#define BSD_CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev) +#define BSD_CIRCLEQ_EMPTY(head) \ + (BSD_CIRCLEQ_FIRST(head) == BSD_CIRCLEQ_END(head)) + +#define BSD_CIRCLEQ_FOREACH(var, head, field) \ + for((var) = BSD_CIRCLEQ_FIRST(head); \ + (var) != BSD_CIRCLEQ_END(head); \ + (var) = BSD_CIRCLEQ_NEXT(var, field)) + +#define BSD_CIRCLEQ_FOREACH_REVERSE(var, head, field) \ + for((var) = BSD_CIRCLEQ_LAST(head); \ + (var) != BSD_CIRCLEQ_END(head); \ + (var) = BSD_CIRCLEQ_PREV(var, field)) + +/* + * Circular queue functions. + */ +#define BSD_CIRCLEQ_INIT(head) do { \ + (head)->cqh_first = BSD_CIRCLEQ_END(head); \ + (head)->cqh_last = BSD_CIRCLEQ_END(head); \ +} while (0) + +#define BSD_CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + (elm)->field.cqe_next = (listelm)->field.cqe_next; \ + (elm)->field.cqe_prev = (listelm); \ + if ((listelm)->field.cqe_next == BSD_CIRCLEQ_END(head)) \ + (head)->cqh_last = (elm); \ + else \ + (listelm)->field.cqe_next->field.cqe_prev = (elm); \ + (listelm)->field.cqe_next = (elm); \ +} while (0) + +#define BSD_CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ + (elm)->field.cqe_next = (listelm); \ + (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \ + if ((listelm)->field.cqe_prev == BSD_CIRCLEQ_END(head)) \ + (head)->cqh_first = (elm); \ + else \ + (listelm)->field.cqe_prev->field.cqe_next = (elm); \ + (listelm)->field.cqe_prev = (elm); \ +} while (0) + +#define BSD_CIRCLEQ_INSERT_HEAD(head, elm, field) do { \ + (elm)->field.cqe_next = (head)->cqh_first; \ + (elm)->field.cqe_prev = BSD_CIRCLEQ_END(head); \ + if ((head)->cqh_last == BSD_CIRCLEQ_END(head)) \ + (head)->cqh_last = (elm); \ + else \ + (head)->cqh_first->field.cqe_prev = (elm); \ + (head)->cqh_first = (elm); \ +} while (0) + +#define BSD_CIRCLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.cqe_next = BSD_CIRCLEQ_END(head); \ + (elm)->field.cqe_prev = (head)->cqh_last; \ + if ((head)->cqh_first == BSD_CIRCLEQ_END(head)) \ + (head)->cqh_first = (elm); \ + else \ + (head)->cqh_last->field.cqe_next = (elm); \ + (head)->cqh_last = (elm); \ +} while (0) + +#define BSD_CIRCLEQ_REMOVE(head, elm, field) do { \ + if ((elm)->field.cqe_next == BSD_CIRCLEQ_END(head)) \ + (head)->cqh_last = (elm)->field.cqe_prev; \ + else \ + (elm)->field.cqe_next->field.cqe_prev = \ + (elm)->field.cqe_prev; \ + if ((elm)->field.cqe_prev == BSD_CIRCLEQ_END(head)) \ + (head)->cqh_first = (elm)->field.cqe_next; \ + else \ + (elm)->field.cqe_prev->field.cqe_next = \ + (elm)->field.cqe_next; \ + _Q_INVALIDATE((elm)->field.cqe_prev); \ + _Q_INVALIDATE((elm)->field.cqe_next); \ +} while (0) + +#define BSD_CIRCLEQ_REPLACE(head, elm, elm2, field) do { \ + if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \ + BSD_CIRCLEQ_END(head)) \ + (head).cqh_last = (elm2); \ + else \ + (elm2)->field.cqe_next->field.cqe_prev = (elm2); \ + if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \ + BSD_CIRCLEQ_END(head)) \ + (head).cqh_first = (elm2); \ + else \ + (elm2)->field.cqe_prev->field.cqe_next = (elm2); \ + _Q_INVALIDATE((elm)->field.cqe_prev); \ + _Q_INVALIDATE((elm)->field.cqe_next); \ +} while (0) + +#endif /* !_BSD_SYS_QUEUE_H_ */ diff --git a/target/linux/generic/files/crypto/ocf/ubsec_ssb/ubsec_ssb.c b/target/linux/generic/files/crypto/ocf/ubsec_ssb/ubsec_ssb.c new file mode 100644 index 0000000..e557e7a --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/ubsec_ssb/ubsec_ssb.c @@ -0,0 +1,2220 @@ + +/* + * Copyright (c) 2008 Daniel Mueller (daniel@danm.de) + * Copyright (c) 2007 David McCullough (david_mccullough@securecomputing.com) + * Copyright (c) 2000 Jason L. Wright (jason@thought.net) + * Copyright (c) 2000 Theo de Raadt (deraadt@openbsd.org) + * Copyright (c) 2001 Patrik Lindergren (patrik@ipunplugged.com) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Effort sponsored in part by the Defense Advanced Research Projects + * Agency (DARPA) and Air Force Research Laboratory, Air Force + * Materiel Command, USAF, under agreement number F30602-01-2-0537. + * + */ +#undef UBSEC_DEBUG +#undef UBSEC_VERBOSE_DEBUG + +#ifdef UBSEC_VERBOSE_DEBUG +#define UBSEC_DEBUG +#endif + +/* + * uBsec BCM5365 hardware crypto accelerator + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* + * BSD queue + */ +//#include "bsdqueue.h" + +/* + * OCF + */ +#include +#include + +#define HMAC_HACK 1 + +#define HMAC_HACK 1 +#ifdef HMAC_HACK +#include +#include +#include +#include +#include +#endif + +#include "bsdqueue.h" +#include "ubsecreg.h" +#include "ubsecvar.h" + +#define DRV_MODULE_NAME "ubsec_ssb" +#define PFX DRV_MODULE_NAME ": " +#define DRV_MODULE_VERSION "0.02" +#define DRV_MODULE_RELDATE "Feb 21, 2009" + +#if 1 +#define DPRINTF(a...) \ + if (debug) \ + { \ + printk(DRV_MODULE_NAME ": " a); \ + } +#else +#define DPRINTF(a...) +#endif + +/* + * Prototypes + */ +static irqreturn_t ubsec_ssb_isr(int, void *, struct pt_regs *); +static int ubsec_ssb_probe(struct ssb_device *sdev, + const struct ssb_device_id *ent); +static void ubsec_ssb_remove(struct ssb_device *sdev); +int ubsec_attach(struct ssb_device *sdev, const struct ssb_device_id *ent, + struct device *self); +static void ubsec_setup_mackey(struct ubsec_session *ses, int algo, + caddr_t key, int klen); +static int dma_map_skb(struct ubsec_softc *sc, + struct ubsec_dma_alloc* q_map, struct sk_buff *skb, int *mlen); +static int dma_map_uio(struct ubsec_softc *sc, + struct ubsec_dma_alloc *q_map, struct uio *uio, int *mlen); +static void dma_unmap(struct ubsec_softc *sc, + struct ubsec_dma_alloc *q_map, int mlen); +static int ubsec_dmamap_aligned(struct ubsec_softc *sc, + const struct ubsec_dma_alloc *q_map, int mlen); + +#ifdef UBSEC_DEBUG +static int proc_read(char *buf, char **start, off_t offset, + int size, int *peof, void *data); +#endif + +void ubsec_reset_board(struct ubsec_softc *); +void ubsec_init_board(struct ubsec_softc *); +void ubsec_cleanchip(struct ubsec_softc *); +void ubsec_totalreset(struct ubsec_softc *); +int ubsec_free_q(struct ubsec_softc*, struct ubsec_q *); + +static int ubsec_newsession(device_t, u_int32_t *, struct cryptoini *); +static int ubsec_freesession(device_t, u_int64_t); +static int ubsec_process(device_t, struct cryptop *, int); + +void ubsec_callback(struct ubsec_softc *, struct ubsec_q *); +void ubsec_feed(struct ubsec_softc *); +void ubsec_mcopy(struct sk_buff *, struct sk_buff *, int, int); +void ubsec_dma_free(struct ubsec_softc *, struct ubsec_dma_alloc *); +int ubsec_dma_malloc(struct ubsec_softc *, struct ubsec_dma_alloc *, + size_t, int); + +/* DEBUG crap... */ +void ubsec_dump_pb(struct ubsec_pktbuf *); +void ubsec_dump_mcr(struct ubsec_mcr *); + +#define READ_REG(sc,r) \ + ssb_read32((sc)->sdev, (r)); +#define WRITE_REG(sc,r,val) \ + ssb_write32((sc)->sdev, (r), (val)); +#define READ_REG_SDEV(sdev,r) \ + ssb_read32((sdev), (r)); +#define WRITE_REG_SDEV(sdev,r,val) \ + ssb_write32((sdev), (r), (val)); + +#define SWAP32(x) (x) = htole32(ntohl((x))) +#define HTOLE32(x) (x) = htole32(x) + +#ifdef __LITTLE_ENDIAN +#define letoh16(x) (x) +#define letoh32(x) (x) +#endif + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Enable debug output"); + +#define UBSEC_SSB_MAX_CHIPS 1 +static struct ubsec_softc *ubsec_chip_idx[UBSEC_SSB_MAX_CHIPS]; +static struct ubsec_stats ubsecstats; + +#ifdef UBSEC_DEBUG +static struct proc_dir_entry *procdebug; +#endif + +static struct ssb_device_id ubsec_ssb_tbl[] = { + /* Broadcom BCM5365P IPSec Core */ + SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_IPSEC, SSB_ANY_REV), + {}, +}; + +static struct ssb_driver ubsec_ssb_driver = { + .name = DRV_MODULE_NAME, + .id_table = ubsec_ssb_tbl, + .probe = ubsec_ssb_probe, + .remove = ubsec_ssb_remove, + /* + .suspend = ubsec_ssb_suspend, + .resume = ubsec_ssb_resume + */ +}; + +static device_method_t ubsec_ssb_methods = { + /* crypto device methods */ + DEVMETHOD(cryptodev_newsession, ubsec_newsession), + DEVMETHOD(cryptodev_freesession,ubsec_freesession), + DEVMETHOD(cryptodev_process, ubsec_process), +}; + +#ifdef UBSEC_DEBUG +static int +proc_read(char *buf, char **start, off_t offset, + int size, int *peof, void *data) +{ + int i = 0, byteswritten = 0, ret; + unsigned int stat, ctrl; +#ifdef UBSEC_VERBOSE_DEBUG + struct ubsec_q *q; + struct ubsec_dma *dmap; +#endif + + while ((i < UBSEC_SSB_MAX_CHIPS) && (ubsec_chip_idx[i] != NULL)) + { + struct ubsec_softc *sc = ubsec_chip_idx[i]; + + stat = READ_REG(sc, BS_STAT); + ctrl = READ_REG(sc, BS_CTRL); + ret = snprintf((buf + byteswritten), + (size - byteswritten) , + "DEV %d, DMASTAT %08x, DMACTRL %08x\n", i, stat, ctrl); + + byteswritten += ret; + +#ifdef UBSEC_VERBOSE_DEBUG + printf("DEV %d, DMASTAT %08x, DMACTRL %08x\n", i, stat, ctrl); + + /* Dump all queues MCRs */ + if (!BSD_SIMPLEQ_EMPTY(&sc->sc_qchip)) { + BSD_SIMPLEQ_FOREACH(q, &sc->sc_qchip, q_next) + { + dmap = q->q_dma; + ubsec_dump_mcr(&dmap->d_dma->d_mcr); + } + } +#endif + + i++; + } + + *peof = 1; + + return byteswritten; +} +#endif + +/* + * map in a given sk_buff + */ +static int +dma_map_skb(struct ubsec_softc *sc, struct ubsec_dma_alloc* q_map, struct sk_buff *skb, int *mlen) +{ + int i = 0; + dma_addr_t tmp; + +#ifdef UBSEC_DEBUG + DPRINTF("%s()\n", __FUNCTION__); +#endif + + /* + * We support only a limited number of fragments. + */ + if (unlikely((skb_shinfo(skb)->nr_frags + 1) >= UBS_MAX_SCATTER)) + { + printk(KERN_ERR "Only %d scatter fragments are supported.\n", UBS_MAX_SCATTER); + return (-ENOMEM); + } + +#ifdef UBSEC_VERBOSE_DEBUG + DPRINTF("%s - map %d 0x%x %d\n", __FUNCTION__, 0, (unsigned int)skb->data, skb_headlen(skb)); +#endif + + /* first data package */ + tmp = dma_map_single(sc->sc_dv, + skb->data, + skb_headlen(skb), + DMA_BIDIRECTIONAL); + + q_map[i].dma_paddr = tmp; + q_map[i].dma_vaddr = skb->data; + q_map[i].dma_size = skb_headlen(skb); + + if (unlikely(tmp == 0)) + { + printk(KERN_ERR "Could not map memory region for dma.\n"); + return (-EINVAL); + } + +#ifdef UBSEC_VERBOSE_DEBUG + DPRINTF("%s - map %d done physical addr 0x%x\n", __FUNCTION__, 0, (unsigned int)tmp); +#endif + + + /* all other data packages */ + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + +#ifdef UBSEC_VERBOSE_DEBUG + DPRINTF("%s - map %d 0x%x %d\n", __FUNCTION__, i + 1, + (unsigned int)page_address(skb_frag_page(&skb_shinfo(skb)->frags[i])) + + skb_shinfo(skb)->frags[i].page_offset, skb_shinfo(skb)->frags[i].size); +#endif + + tmp = dma_map_single(sc->sc_dv, + page_address(skb_frag_page(&skb_shinfo(skb)->frags[i])) + + skb_shinfo(skb)->frags[i].page_offset, + skb_shinfo(skb)->frags[i].size, + DMA_BIDIRECTIONAL); + + q_map[i + 1].dma_paddr = tmp; + q_map[i + 1].dma_vaddr = (void*)(page_address(skb_frag_page(&skb_shinfo(skb)->frags[i])) + + skb_shinfo(skb)->frags[i].page_offset); + q_map[i + 1].dma_size = skb_shinfo(skb)->frags[i].size; + + if (unlikely(tmp == 0)) + { + printk(KERN_ERR "Could not map memory region for dma.\n"); + return (-EINVAL); + } + +#ifdef UBSEC_VERBOSE_DEBUG + DPRINTF("%s - map %d done physical addr 0x%x\n", __FUNCTION__, i + 1, (unsigned int)tmp); +#endif + + } + *mlen = i + 1; + + return(0); +} + +/* + * map in a given uio buffer + */ + +static int +dma_map_uio(struct ubsec_softc *sc, struct ubsec_dma_alloc *q_map, struct uio *uio, int *mlen) +{ + struct iovec *iov = uio->uio_iov; + int n; + dma_addr_t tmp; + +#ifdef UBSEC_DEBUG + DPRINTF("%s()\n", __FUNCTION__); +#endif + + /* + * We support only a limited number of fragments. + */ + if (unlikely(uio->uio_iovcnt >= UBS_MAX_SCATTER)) + { + printk(KERN_ERR "Only %d scatter fragments are supported.\n", UBS_MAX_SCATTER); + return (-ENOMEM); + } + + for (n = 0; n < uio->uio_iovcnt; n++) { +#ifdef UBSEC_VERBOSE_DEBUG + DPRINTF("%s - map %d 0x%x %d\n", __FUNCTION__, n, (unsigned int)iov->iov_base, iov->iov_len); +#endif + tmp = dma_map_single(sc->sc_dv, + iov->iov_base, + iov->iov_len, + DMA_BIDIRECTIONAL); + + q_map[n].dma_paddr = tmp; + q_map[n].dma_vaddr = iov->iov_base; + q_map[n].dma_size = iov->iov_len; + + if (unlikely(tmp == 0)) + { + printk(KERN_ERR "Could not map memory region for dma.\n"); + return (-EINVAL); + } + +#ifdef UBSEC_VERBOSE_DEBUG + DPRINTF("%s - map %d done physical addr 0x%x\n", __FUNCTION__, n, (unsigned int)tmp); +#endif + + iov++; + } + *mlen = n; + + return(0); +} + +static void +dma_unmap(struct ubsec_softc *sc, struct ubsec_dma_alloc *q_map, int mlen) +{ + int i; + +#ifdef UBSEC_DEBUG + DPRINTF("%s()\n", __FUNCTION__); +#endif + + for(i = 0; i < mlen; i++) + { +#ifdef UBSEC_VERBOSE_DEBUG + DPRINTF("%s - unmap %d 0x%x %d\n", __FUNCTION__, i, (unsigned int)q_map[i].dma_paddr, q_map[i].dma_size); +#endif + dma_unmap_single(sc->sc_dv, + q_map[i].dma_paddr, + q_map[i].dma_size, + DMA_BIDIRECTIONAL); + } + return; +} + +/* + * Is the operand suitable aligned for direct DMA. Each + * segment must be aligned on a 32-bit boundary and all + * but the last segment must be a multiple of 4 bytes. + */ +static int +ubsec_dmamap_aligned(struct ubsec_softc *sc, const struct ubsec_dma_alloc *q_map, int mlen) +{ + int i; + +#ifdef UBSEC_DEBUG + DPRINTF("%s()\n", __FUNCTION__); +#endif + + for (i = 0; i < mlen; i++) { + if (q_map[i].dma_paddr & 3) + return (0); + if (i != (mlen - 1) && (q_map[i].dma_size & 3)) + return (0); + } + return (1); +} + + +#define N(a) (sizeof(a) / sizeof (a[0])) +static void +ubsec_setup_mackey(struct ubsec_session *ses, int algo, caddr_t key, int klen) +{ +#ifdef HMAC_HACK + MD5_CTX md5ctx; + SHA1_CTX sha1ctx; + int i; + +#ifdef UBSEC_DEBUG + DPRINTF("%s()\n", __FUNCTION__); +#endif + + for (i = 0; i < klen; i++) + key[i] ^= HMAC_IPAD_VAL; + + if (algo == CRYPTO_MD5_HMAC) { + MD5Init(&md5ctx); + MD5Update(&md5ctx, key, klen); + MD5Update(&md5ctx, hmac_ipad_buffer, MD5_HMAC_BLOCK_LEN - klen); + bcopy(md5ctx.md5_st8, ses->ses_hminner, sizeof(md5ctx.md5_st8)); + } else { + SHA1Init(&sha1ctx); + SHA1Update(&sha1ctx, key, klen); + SHA1Update(&sha1ctx, hmac_ipad_buffer, + SHA1_HMAC_BLOCK_LEN - klen); + bcopy(sha1ctx.h.b32, ses->ses_hminner, sizeof(sha1ctx.h.b32)); + } + + for (i = 0; i < klen; i++) + key[i] ^= (HMAC_IPAD_VAL ^ HMAC_OPAD_VAL); + + if (algo == CRYPTO_MD5_HMAC) { + MD5Init(&md5ctx); + MD5Update(&md5ctx, key, klen); + MD5Update(&md5ctx, hmac_opad_buffer, MD5_HMAC_BLOCK_LEN - klen); + bcopy(md5ctx.md5_st8, ses->ses_hmouter, sizeof(md5ctx.md5_st8)); + } else { + SHA1Init(&sha1ctx); + SHA1Update(&sha1ctx, key, klen); + SHA1Update(&sha1ctx, hmac_opad_buffer, + SHA1_HMAC_BLOCK_LEN - klen); + bcopy(sha1ctx.h.b32, ses->ses_hmouter, sizeof(sha1ctx.h.b32)); + } + + for (i = 0; i < klen; i++) + key[i] ^= HMAC_OPAD_VAL; + +#else /* HMAC_HACK */ + DPRINTF("md5/sha not implemented\n"); +#endif /* HMAC_HACK */ +} +#undef N + +static int +ubsec_ssb_probe(struct ssb_device *sdev, + const struct ssb_device_id *ent) +{ + int err; + +#ifdef UBSEC_DEBUG + DPRINTF("%s()\n", __FUNCTION__); +#endif + + err = ssb_bus_powerup(sdev->bus, 0); + if (err) { + dev_err(sdev->dev, "Failed to powerup the bus\n"); + goto err_out; + } + + err = request_irq(sdev->irq, (irq_handler_t)ubsec_ssb_isr, + IRQF_SHARED, DRV_MODULE_NAME, sdev); + if (err) { + dev_err(sdev->dev, "Could not request irq\n"); + goto err_out_powerdown; + } + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)) + err = dma_set_mask(sdev->dma_dev, DMA_BIT_MASK(32)) || + dma_set_coherent_mask(sdev->dma_dev, DMA_BIT_MASK(32)); +#else + err = ssb_dma_set_mask(sdev, DMA_32BIT_MASK); +#endif + if (err) { + dev_err(sdev->dev, + "Required 32BIT DMA mask unsupported by the system.\n"); + goto err_out_free_irq; + } + + printk(KERN_INFO "Sentry5(tm) ROBOGateway(tm) IPSec Core at IRQ %u\n", + sdev->irq); + + DPRINTF("Vendor: %x, core id: %x, revision: %x\n", + sdev->id.vendor, sdev->id.coreid, sdev->id.revision); + + ssb_device_enable(sdev, 0); + + if (ubsec_attach(sdev, ent, sdev->dev) != 0) + goto err_out_disable; + +#ifdef UBSEC_DEBUG + procdebug = create_proc_entry(DRV_MODULE_NAME, S_IRUSR, NULL); + if (procdebug) + { + procdebug->read_proc = proc_read; + procdebug->data = NULL; + } else + DPRINTF("Unable to create proc file.\n"); +#endif + + return 0; + +err_out_disable: + ssb_device_disable(sdev, 0); + +err_out_free_irq: + free_irq(sdev->irq, sdev); + +err_out_powerdown: + ssb_bus_may_powerdown(sdev->bus); + +err_out: + return err; +} + +static void ubsec_ssb_remove(struct ssb_device *sdev) { + + struct ubsec_softc *sc; + unsigned int ctrlflgs; + struct ubsec_dma *dmap; + u_int32_t i; + +#ifdef UBSEC_DEBUG + DPRINTF("%s()\n", __FUNCTION__); +#endif + + ctrlflgs = READ_REG_SDEV(sdev, BS_CTRL); + /* disable all IPSec Core interrupts globally */ + ctrlflgs ^= (BS_CTRL_MCR1INT | BS_CTRL_MCR2INT | + BS_CTRL_DMAERR); + WRITE_REG_SDEV(sdev, BS_CTRL, ctrlflgs); + + free_irq(sdev->irq, sdev); + + sc = (struct ubsec_softc *)ssb_get_drvdata(sdev); + + /* unregister all crypto algorithms */ + crypto_unregister_all(sc->sc_cid); + + /* Free queue / dma memory */ + for (i = 0; i < UBS_MAX_NQUEUE; i++) { + struct ubsec_q *q; + + q = sc->sc_queuea[i]; + if (q != NULL) + { + dmap = q->q_dma; + if (dmap != NULL) + { + ubsec_dma_free(sc, &dmap->d_alloc); + q->q_dma = NULL; + } + kfree(q); + } + sc->sc_queuea[i] = NULL; + } + + ssb_device_disable(sdev, 0); + ssb_bus_may_powerdown(sdev->bus); + ssb_set_drvdata(sdev, NULL); + +#ifdef UBSEC_DEBUG + if (procdebug) + remove_proc_entry(DRV_MODULE_NAME, NULL); +#endif + +} + + +int +ubsec_attach(struct ssb_device *sdev, const struct ssb_device_id *ent, + struct device *self) +{ + struct ubsec_softc *sc = NULL; + struct ubsec_dma *dmap; + u_int32_t i; + static int num_chips = 0; + +#ifdef UBSEC_DEBUG + DPRINTF("%s()\n", __FUNCTION__); +#endif + + sc = (struct ubsec_softc *) kmalloc(sizeof(*sc), GFP_KERNEL); + if (!sc) + return(-ENOMEM); + memset(sc, 0, sizeof(*sc)); + + sc->sc_dv = sdev->dev; + sc->sdev = sdev; + + spin_lock_init(&sc->sc_ringmtx); + + softc_device_init(sc, "ubsec_ssb", num_chips, ubsec_ssb_methods); + + /* Maybe someday there are boards with more than one chip available */ + if (num_chips < UBSEC_SSB_MAX_CHIPS) { + ubsec_chip_idx[device_get_unit(sc->sc_dev)] = sc; + num_chips++; + } + + ssb_set_drvdata(sdev, sc); + + BSD_SIMPLEQ_INIT(&sc->sc_queue); + BSD_SIMPLEQ_INIT(&sc->sc_qchip); + BSD_SIMPLEQ_INIT(&sc->sc_queue2); + BSD_SIMPLEQ_INIT(&sc->sc_qchip2); + BSD_SIMPLEQ_INIT(&sc->sc_q2free); + + sc->sc_statmask = BS_STAT_MCR1_DONE | BS_STAT_DMAERR; + + sc->sc_cid = crypto_get_driverid(softc_get_device(sc), CRYPTOCAP_F_HARDWARE); + if (sc->sc_cid < 0) { + device_printf(sc->sc_dev, "could not get crypto driver id\n"); + return -1; + } + + BSD_SIMPLEQ_INIT(&sc->sc_freequeue); + dmap = sc->sc_dmaa; + for (i = 0; i < UBS_MAX_NQUEUE; i++, dmap++) { + struct ubsec_q *q; + + q = (struct ubsec_q *)kmalloc(sizeof(struct ubsec_q), GFP_KERNEL); + if (q == NULL) { + printf(": can't allocate queue buffers\n"); + break; + } + + if (ubsec_dma_malloc(sc, &dmap->d_alloc, sizeof(struct ubsec_dmachunk),0)) { + printf(": can't allocate dma buffers\n"); + kfree(q); + break; + } + dmap->d_dma = (struct ubsec_dmachunk *)dmap->d_alloc.dma_vaddr; + + q->q_dma = dmap; + sc->sc_queuea[i] = q; + + BSD_SIMPLEQ_INSERT_TAIL(&sc->sc_freequeue, q, q_next); + } + + /* + * Reset Broadcom chip + */ + ubsec_reset_board(sc); + + /* + * Init Broadcom chip + */ + ubsec_init_board(sc); + + /* supported crypto algorithms */ + crypto_register(sc->sc_cid, CRYPTO_3DES_CBC, 0, 0); + crypto_register(sc->sc_cid, CRYPTO_DES_CBC, 0, 0); + + if (sc->sc_flags & UBS_FLAGS_AES) { + crypto_register(sc->sc_cid, CRYPTO_AES_CBC, 0, 0); + printf(KERN_INFO DRV_MODULE_NAME ": DES 3DES AES128 AES192 AES256 MD5_HMAC SHA1_HMAC\n"); + } + else + printf(KERN_INFO DRV_MODULE_NAME ": DES 3DES MD5_HMAC SHA1_HMAC\n"); + + crypto_register(sc->sc_cid, CRYPTO_MD5_HMAC, 0, 0); + crypto_register(sc->sc_cid, CRYPTO_SHA1_HMAC, 0, 0); + + return 0; +} + +/* + * UBSEC Interrupt routine + */ +static irqreturn_t +ubsec_ssb_isr(int irq, void *arg, struct pt_regs *regs) +{ + struct ubsec_softc *sc = NULL; + volatile u_int32_t stat; + struct ubsec_q *q; + struct ubsec_dma *dmap; + int npkts = 0, i; + +#ifdef UBSEC_VERBOSE_DEBUG + DPRINTF("%s()\n", __FUNCTION__); +#endif + + sc = (struct ubsec_softc *)ssb_get_drvdata(arg); + + stat = READ_REG(sc, BS_STAT); + + stat &= sc->sc_statmask; + if (stat == 0) + return IRQ_NONE; + + WRITE_REG(sc, BS_STAT, stat); /* IACK */ + + /* + * Check to see if we have any packets waiting for us + */ + if ((stat & BS_STAT_MCR1_DONE)) { + while (!BSD_SIMPLEQ_EMPTY(&sc->sc_qchip)) { + q = BSD_SIMPLEQ_FIRST(&sc->sc_qchip); + dmap = q->q_dma; + + if ((dmap->d_dma->d_mcr.mcr_flags & htole16(UBS_MCR_DONE)) == 0) + { + DPRINTF("error while processing MCR. Flags = %x\n", dmap->d_dma->d_mcr.mcr_flags); + break; + } + + BSD_SIMPLEQ_REMOVE_HEAD(&sc->sc_qchip, q_next); + + npkts = q->q_nstacked_mcrs; + /* + * search for further sc_qchip ubsec_q's that share + * the same MCR, and complete them too, they must be + * at the top. + */ + for (i = 0; i < npkts; i++) { + if(q->q_stacked_mcr[i]) + ubsec_callback(sc, q->q_stacked_mcr[i]); + else + break; + } + ubsec_callback(sc, q); + } + + /* + * Don't send any more packet to chip if there has been + * a DMAERR. + */ + if (likely(!(stat & BS_STAT_DMAERR))) + ubsec_feed(sc); + else + DPRINTF("DMA error occurred. Stop feeding crypto chip.\n"); + } + + /* + * Check to see if we got any DMA Error + */ + if (stat & BS_STAT_DMAERR) { + volatile u_int32_t a = READ_REG(sc, BS_ERR); + + printf(KERN_ERR "%s: dmaerr %s@%08x\n", DRV_MODULE_NAME, + (a & BS_ERR_READ) ? "read" : "write", a & BS_ERR_ADDR); + + ubsecstats.hst_dmaerr++; + ubsec_totalreset(sc); + ubsec_feed(sc); + } + + return IRQ_HANDLED; +} + +/* + * ubsec_feed() - aggregate and post requests to chip + * It is assumed that the caller set splnet() + */ +void +ubsec_feed(struct ubsec_softc *sc) +{ +#ifdef UBSEC_VERBOSE_DEBUG + static int max; +#endif + struct ubsec_q *q, *q2; + int npkts, i; + void *v; + u_int32_t stat; + + npkts = sc->sc_nqueue; + if (npkts > UBS_MAX_AGGR) + npkts = UBS_MAX_AGGR; + if (npkts < 2) + goto feed1; + + stat = READ_REG(sc, BS_STAT); + + if (stat & (BS_STAT_MCR1_FULL | BS_STAT_DMAERR)) { + if(stat & BS_STAT_DMAERR) { + ubsec_totalreset(sc); + ubsecstats.hst_dmaerr++; + } + return; + } + +#ifdef UBSEC_VERBOSE_DEBUG + DPRINTF("merging %d records\n", npkts); + + /* XXX temporary aggregation statistics reporting code */ + if (max < npkts) { + max = npkts; + DPRINTF("%s: new max aggregate %d\n", DRV_MODULE_NAME, max); + } +#endif /* UBSEC_VERBOSE_DEBUG */ + + q = BSD_SIMPLEQ_FIRST(&sc->sc_queue); + BSD_SIMPLEQ_REMOVE_HEAD(&sc->sc_queue, q_next); + --sc->sc_nqueue; + +#if 0 + /* + * XXX + * We use dma_map_single() - no sync required! + */ + + bus_dmamap_sync(sc->sc_dmat, q->q_src_map, + 0, q->q_src_map->dm_mapsize, BUS_DMASYNC_PREWRITE); + if (q->q_dst_map != NULL) + bus_dmamap_sync(sc->sc_dmat, q->q_dst_map, + 0, q->q_dst_map->dm_mapsize, BUS_DMASYNC_PREREAD); +#endif + + q->q_nstacked_mcrs = npkts - 1; /* Number of packets stacked */ + + for (i = 0; i < q->q_nstacked_mcrs; i++) { + q2 = BSD_SIMPLEQ_FIRST(&sc->sc_queue); + +#if 0 + bus_dmamap_sync(sc->sc_dmat, q2->q_src_map, + 0, q2->q_src_map->dm_mapsize, BUS_DMASYNC_PREWRITE); + if (q2->q_dst_map != NULL) + bus_dmamap_sync(sc->sc_dmat, q2->q_dst_map, + 0, q2->q_dst_map->dm_mapsize, BUS_DMASYNC_PREREAD); +#endif + BSD_SIMPLEQ_REMOVE_HEAD(&sc->sc_queue, q_next); + --sc->sc_nqueue; + + v = ((char *)&q2->q_dma->d_dma->d_mcr) + sizeof(struct ubsec_mcr) - + sizeof(struct ubsec_mcr_add); + bcopy(v, &q->q_dma->d_dma->d_mcradd[i], sizeof(struct ubsec_mcr_add)); + q->q_stacked_mcr[i] = q2; + } + q->q_dma->d_dma->d_mcr.mcr_pkts = htole16(npkts); + BSD_SIMPLEQ_INSERT_TAIL(&sc->sc_qchip, q, q_next); +#if 0 + bus_dmamap_sync(sc->sc_dmat, q->q_dma->d_alloc.dma_map, + 0, q->q_dma->d_alloc.dma_map->dm_mapsize, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); +#endif + WRITE_REG(sc, BS_MCR1, q->q_dma->d_alloc.dma_paddr + + offsetof(struct ubsec_dmachunk, d_mcr)); +#ifdef UBSEC_VERBOSE_DEBUG + DPRINTF("feed (1): q->chip %p %08x %08x\n", q, + (u_int32_t)q->q_dma->d_alloc.dma_paddr, + (u_int32_t)(q->q_dma->d_alloc.dma_paddr + + offsetof(struct ubsec_dmachunk, d_mcr))); +#endif /* UBSEC_DEBUG */ + return; + +feed1: + while (!BSD_SIMPLEQ_EMPTY(&sc->sc_queue)) { + stat = READ_REG(sc, BS_STAT); + + if (stat & (BS_STAT_MCR1_FULL | BS_STAT_DMAERR)) { + if(stat & BS_STAT_DMAERR) { + ubsec_totalreset(sc); + ubsecstats.hst_dmaerr++; + } + break; + } + + q = BSD_SIMPLEQ_FIRST(&sc->sc_queue); + +#if 0 + bus_dmamap_sync(sc->sc_dmat, q->q_src_map, + 0, q->q_src_map->dm_mapsize, BUS_DMASYNC_PREWRITE); + if (q->q_dst_map != NULL) + bus_dmamap_sync(sc->sc_dmat, q->q_dst_map, + 0, q->q_dst_map->dm_mapsize, BUS_DMASYNC_PREREAD); + bus_dmamap_sync(sc->sc_dmat, q->q_dma->d_alloc.dma_map, + 0, q->q_dma->d_alloc.dma_map->dm_mapsize, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); +#endif + + WRITE_REG(sc, BS_MCR1, q->q_dma->d_alloc.dma_paddr + + offsetof(struct ubsec_dmachunk, d_mcr)); +#ifdef UBSEC_VERBOSE_DEBUG + DPRINTF("feed (2): q->chip %p %08x %08x\n", q, + (u_int32_t)q->q_dma->d_alloc.dma_paddr, + (u_int32_t)(q->q_dma->d_alloc.dma_paddr + + offsetof(struct ubsec_dmachunk, d_mcr))); +#endif /* UBSEC_DEBUG */ + BSD_SIMPLEQ_REMOVE_HEAD(&sc->sc_queue, q_next); + --sc->sc_nqueue; + BSD_SIMPLEQ_INSERT_TAIL(&sc->sc_qchip, q, q_next); + } +} + +/* + * Allocate a new 'session' and return an encoded session id. 'sidp' + * contains our registration id, and should contain an encoded session + * id on successful allocation. + */ +static int +ubsec_newsession(device_t dev, u_int32_t *sidp, struct cryptoini *cri) +{ + struct cryptoini *c, *encini = NULL, *macini = NULL; + struct ubsec_softc *sc = NULL; + struct ubsec_session *ses = NULL; + int sesn, i; + +#ifdef UBSEC_DEBUG + DPRINTF("%s()\n", __FUNCTION__); +#endif + + if (sidp == NULL || cri == NULL) + return (EINVAL); + + sc = device_get_softc(dev); + + if (sc == NULL) + return (EINVAL); + + for (c = cri; c != NULL; c = c->cri_next) { + if (c->cri_alg == CRYPTO_MD5_HMAC || + c->cri_alg == CRYPTO_SHA1_HMAC) { + if (macini) + return (EINVAL); + macini = c; + } else if (c->cri_alg == CRYPTO_DES_CBC || + c->cri_alg == CRYPTO_3DES_CBC || + c->cri_alg == CRYPTO_AES_CBC) { + if (encini) + return (EINVAL); + encini = c; + } else + return (EINVAL); + } + if (encini == NULL && macini == NULL) + return (EINVAL); + + if (sc->sc_sessions == NULL) { + ses = sc->sc_sessions = (struct ubsec_session *)kmalloc( + sizeof(struct ubsec_session), SLAB_ATOMIC); + if (ses == NULL) + return (ENOMEM); + memset(ses, 0, sizeof(struct ubsec_session)); + sesn = 0; + sc->sc_nsessions = 1; + } else { + for (sesn = 0; sesn < sc->sc_nsessions; sesn++) { + if (sc->sc_sessions[sesn].ses_used == 0) { + ses = &sc->sc_sessions[sesn]; + break; + } + } + + if (ses == NULL) { + sesn = sc->sc_nsessions; + ses = (struct ubsec_session *)kmalloc((sesn + 1) * + sizeof(struct ubsec_session), SLAB_ATOMIC); + if (ses == NULL) + return (ENOMEM); + memset(ses, 0, (sesn + 1) * sizeof(struct ubsec_session)); + bcopy(sc->sc_sessions, ses, sesn * + sizeof(struct ubsec_session)); + bzero(sc->sc_sessions, sesn * + sizeof(struct ubsec_session)); + kfree(sc->sc_sessions); + sc->sc_sessions = ses; + ses = &sc->sc_sessions[sesn]; + sc->sc_nsessions++; + } + } + + bzero(ses, sizeof(struct ubsec_session)); + ses->ses_used = 1; + if (encini) { + /* get an IV */ + /* XXX may read fewer than requested */ + read_random(ses->ses_iv, sizeof(ses->ses_iv)); + + /* Go ahead and compute key in ubsec's byte order */ + if (encini->cri_alg == CRYPTO_DES_CBC) { + /* DES uses the same key three times: + * 1st encrypt -> 2nd decrypt -> 3nd encrypt */ + bcopy(encini->cri_key, &ses->ses_key[0], 8); + bcopy(encini->cri_key, &ses->ses_key[2], 8); + bcopy(encini->cri_key, &ses->ses_key[4], 8); + ses->ses_keysize = 192; /* Fake! Actually its only 64bits .. + oh no it is even less: 54bits. */ + } else if(encini->cri_alg == CRYPTO_3DES_CBC) { + bcopy(encini->cri_key, ses->ses_key, 24); + ses->ses_keysize = 192; + } else if(encini->cri_alg == CRYPTO_AES_CBC) { + ses->ses_keysize = encini->cri_klen; + + if (ses->ses_keysize != 128 && + ses->ses_keysize != 192 && + ses->ses_keysize != 256) + { + DPRINTF("unsupported AES key size: %d\n", ses->ses_keysize); + return (EINVAL); + } + bcopy(encini->cri_key, ses->ses_key, (ses->ses_keysize / 8)); + } + + /* Hardware requires the keys in little endian byte order */ + for (i=0; i < (ses->ses_keysize / 32); i++) + SWAP32(ses->ses_key[i]); + } + + if (macini) { + ses->ses_mlen = macini->cri_mlen; + + if (ses->ses_mlen == 0 || + ses->ses_mlen > SHA1_HASH_LEN) { + + if (macini->cri_alg == CRYPTO_MD5_HMAC || + macini->cri_alg == CRYPTO_SHA1_HMAC) + { + ses->ses_mlen = DEFAULT_HMAC_LEN; + } else + { + /* + * Reserved for future usage. MD5/SHA1 calculations have + * different hash sizes. + */ + printk(KERN_ERR DRV_MODULE_NAME ": unsupported hash operation with mac/hash len: %d\n", ses->ses_mlen); + return (EINVAL); + } + + } + + if (macini->cri_key != NULL) { + ubsec_setup_mackey(ses, macini->cri_alg, macini->cri_key, + macini->cri_klen / 8); + } + } + + *sidp = UBSEC_SID(device_get_unit(sc->sc_dev), sesn); + return (0); +} + +/* + * Deallocate a session. + */ +static int +ubsec_freesession(device_t dev, u_int64_t tid) +{ + struct ubsec_softc *sc = device_get_softc(dev); + int session; + u_int32_t sid = ((u_int32_t)tid) & 0xffffffff; + +#ifdef UBSEC_DEBUG + DPRINTF("%s()\n", __FUNCTION__); +#endif + + if (sc == NULL) + return (EINVAL); + + session = UBSEC_SESSION(sid); + if (session < sc->sc_nsessions) { + bzero(&sc->sc_sessions[session], sizeof(sc->sc_sessions[session])); + return (0); + } else + return (EINVAL); +} + +static int +ubsec_process(device_t dev, struct cryptop *crp, int hint) +{ + struct ubsec_q *q = NULL; + int err = 0, i, j, nicealign; + struct ubsec_softc *sc = device_get_softc(dev); + struct cryptodesc *crd1, *crd2, *maccrd, *enccrd; + int encoffset = 0, macoffset = 0, cpskip, cpoffset; + int sskip, dskip, stheend, dtheend, ivsize = 8; + int16_t coffset; + struct ubsec_session *ses; + struct ubsec_generic_ctx ctx; + struct ubsec_dma *dmap = NULL; + unsigned long flags; + +#ifdef UBSEC_DEBUG + DPRINTF("%s()\n", __FUNCTION__); +#endif + + if (unlikely(crp == NULL || crp->crp_callback == NULL)) { + ubsecstats.hst_invalid++; + return (EINVAL); + } + + if (unlikely(sc == NULL)) + return (EINVAL); + +#ifdef UBSEC_VERBOSE_DEBUG + DPRINTF("spin_lock_irqsave\n"); +#endif + spin_lock_irqsave(&sc->sc_ringmtx, flags); + //spin_lock_irq(&sc->sc_ringmtx); + + if (BSD_SIMPLEQ_EMPTY(&sc->sc_freequeue)) { + ubsecstats.hst_queuefull++; +#ifdef UBSEC_VERBOSE_DEBUG + DPRINTF("spin_unlock_irqrestore\n"); +#endif + spin_unlock_irqrestore(&sc->sc_ringmtx, flags); + //spin_unlock_irq(&sc->sc_ringmtx); + err = ENOMEM; + goto errout2; + } + + q = BSD_SIMPLEQ_FIRST(&sc->sc_freequeue); + BSD_SIMPLEQ_REMOVE_HEAD(&sc->sc_freequeue, q_next); +#ifdef UBSEC_VERBOSE_DEBUG + DPRINTF("spin_unlock_irqrestore\n"); +#endif + spin_unlock_irqrestore(&sc->sc_ringmtx, flags); + //spin_unlock_irq(&sc->sc_ringmtx); + + dmap = q->q_dma; /* Save dma pointer */ + bzero(q, sizeof(struct ubsec_q)); + bzero(&ctx, sizeof(ctx)); + + q->q_sesn = UBSEC_SESSION(crp->crp_sid); + q->q_dma = dmap; + ses = &sc->sc_sessions[q->q_sesn]; + + if (crp->crp_flags & CRYPTO_F_SKBUF) { + q->q_src_m = (struct sk_buff *)crp->crp_buf; + q->q_dst_m = (struct sk_buff *)crp->crp_buf; + } else if (crp->crp_flags & CRYPTO_F_IOV) { + q->q_src_io = (struct uio *)crp->crp_buf; + q->q_dst_io = (struct uio *)crp->crp_buf; + } else { + err = EINVAL; + goto errout; /* XXX we don't handle contiguous blocks! */ + } + + bzero(&dmap->d_dma->d_mcr, sizeof(struct ubsec_mcr)); + + dmap->d_dma->d_mcr.mcr_pkts = htole16(1); + dmap->d_dma->d_mcr.mcr_flags = 0; + q->q_crp = crp; + + crd1 = crp->crp_desc; + if (crd1 == NULL) { + err = EINVAL; + goto errout; + } + crd2 = crd1->crd_next; + + if (crd2 == NULL) { + if (crd1->crd_alg == CRYPTO_MD5_HMAC || + crd1->crd_alg == CRYPTO_SHA1_HMAC) { + maccrd = crd1; + enccrd = NULL; + } else if (crd1->crd_alg == CRYPTO_DES_CBC || + crd1->crd_alg == CRYPTO_3DES_CBC || + crd1->crd_alg == CRYPTO_AES_CBC) { + maccrd = NULL; + enccrd = crd1; + } else { + err = EINVAL; + goto errout; + } + } else { + if ((crd1->crd_alg == CRYPTO_MD5_HMAC || + crd1->crd_alg == CRYPTO_SHA1_HMAC) && + (crd2->crd_alg == CRYPTO_DES_CBC || + crd2->crd_alg == CRYPTO_3DES_CBC || + crd2->crd_alg == CRYPTO_AES_CBC) && + ((crd2->crd_flags & CRD_F_ENCRYPT) == 0)) { + maccrd = crd1; + enccrd = crd2; + } else if ((crd1->crd_alg == CRYPTO_DES_CBC || + crd1->crd_alg == CRYPTO_3DES_CBC || + crd1->crd_alg == CRYPTO_AES_CBC) && + (crd2->crd_alg == CRYPTO_MD5_HMAC || + crd2->crd_alg == CRYPTO_SHA1_HMAC) && + (crd1->crd_flags & CRD_F_ENCRYPT)) { + enccrd = crd1; + maccrd = crd2; + } else { + /* + * We cannot order the ubsec as requested + */ + printk(KERN_ERR DRV_MODULE_NAME ": got wrong algorithm/signature order.\n"); + err = EINVAL; + goto errout; + } + } + + /* Encryption/Decryption requested */ + if (enccrd) { + encoffset = enccrd->crd_skip; + + if (enccrd->crd_alg == CRYPTO_DES_CBC || + enccrd->crd_alg == CRYPTO_3DES_CBC) + { + ctx.pc_flags |= htole16(UBS_PKTCTX_ENC_3DES); + ctx.pc_type = htole16(UBS_PKTCTX_TYPE_IPSEC_DES); + ivsize = 8; /* [3]DES uses 64bit IVs */ + } else { + ctx.pc_flags |= htole16(UBS_PKTCTX_ENC_AES); + ctx.pc_type = htole16(UBS_PKTCTX_TYPE_IPSEC_AES); + ivsize = 16; /* AES uses 128bit IVs / [3]DES 64bit IVs */ + + switch(ses->ses_keysize) + { + case 128: + ctx.pc_flags |= htole16(UBS_PKTCTX_AES128); + break; + case 192: + ctx.pc_flags |= htole16(UBS_PKTCTX_AES192); + break; + case 256: + ctx.pc_flags |= htole16(UBS_PKTCTX_AES256); + break; + default: + DPRINTF("invalid AES key size: %d\n", ses->ses_keysize); + err = EINVAL; + goto errout; + } + } + + if (enccrd->crd_flags & CRD_F_ENCRYPT) { + /* Direction: Outbound */ + + q->q_flags |= UBSEC_QFLAGS_COPYOUTIV; + + if (enccrd->crd_flags & CRD_F_IV_EXPLICIT) { + bcopy(enccrd->crd_iv, ctx.pc_iv, ivsize); + } else { + for(i=0; i < (ivsize / 4); i++) + ctx.pc_iv[i] = ses->ses_iv[i]; + } + + /* If there is no IV in the buffer -> copy it here */ + if ((enccrd->crd_flags & CRD_F_IV_PRESENT) == 0) { + if (crp->crp_flags & CRYPTO_F_SKBUF) + /* + m_copyback(q->q_src_m, + enccrd->crd_inject, + 8, ctx.pc_iv); + */ + crypto_copyback(crp->crp_flags, (caddr_t)q->q_src_m, + enccrd->crd_inject, ivsize, (caddr_t)ctx.pc_iv); + else if (crp->crp_flags & CRYPTO_F_IOV) + /* + cuio_copyback(q->q_src_io, + enccrd->crd_inject, + 8, ctx.pc_iv); + */ + crypto_copyback(crp->crp_flags, (caddr_t)q->q_src_io, + enccrd->crd_inject, ivsize, (caddr_t)ctx.pc_iv); + } + } else { + /* Direction: Inbound */ + + ctx.pc_flags |= htole16(UBS_PKTCTX_INBOUND); + + if (enccrd->crd_flags & CRD_F_IV_EXPLICIT) + bcopy(enccrd->crd_iv, ctx.pc_iv, ivsize); + else if (crp->crp_flags & CRYPTO_F_SKBUF) + /* + m_copydata(q->q_src_m, enccrd->crd_inject, + 8, (caddr_t)ctx.pc_iv); + */ + crypto_copydata(crp->crp_flags, (caddr_t)q->q_src_m, + enccrd->crd_inject, ivsize, + (caddr_t)ctx.pc_iv); + else if (crp->crp_flags & CRYPTO_F_IOV) + /* + cuio_copydata(q->q_src_io, + enccrd->crd_inject, 8, + (caddr_t)ctx.pc_iv); + */ + crypto_copydata(crp->crp_flags, (caddr_t)q->q_src_io, + enccrd->crd_inject, ivsize, + (caddr_t)ctx.pc_iv); + + } + + /* Even though key & IV sizes differ from cipher to cipher + * copy / swap the full array lengths. Let the compiler unroll + * the loop to increase the cpu pipeline performance... */ + for(i=0; i < 8; i++) + ctx.pc_key[i] = ses->ses_key[i]; + for(i=0; i < 4; i++) + SWAP32(ctx.pc_iv[i]); + } + + /* Authentication requested */ + if (maccrd) { + macoffset = maccrd->crd_skip; + + if (maccrd->crd_alg == CRYPTO_MD5_HMAC) + ctx.pc_flags |= htole16(UBS_PKTCTX_AUTH_MD5); + else + ctx.pc_flags |= htole16(UBS_PKTCTX_AUTH_SHA1); + + for (i = 0; i < 5; i++) { + ctx.pc_hminner[i] = ses->ses_hminner[i]; + ctx.pc_hmouter[i] = ses->ses_hmouter[i]; + + HTOLE32(ctx.pc_hminner[i]); + HTOLE32(ctx.pc_hmouter[i]); + } + } + + if (enccrd && maccrd) { + /* + * ubsec cannot handle packets where the end of encryption + * and authentication are not the same, or where the + * encrypted part begins before the authenticated part. + */ + if (((encoffset + enccrd->crd_len) != + (macoffset + maccrd->crd_len)) || + (enccrd->crd_skip < maccrd->crd_skip)) { + err = EINVAL; + goto errout; + } + sskip = maccrd->crd_skip; + cpskip = dskip = enccrd->crd_skip; + stheend = maccrd->crd_len; + dtheend = enccrd->crd_len; + coffset = enccrd->crd_skip - maccrd->crd_skip; + cpoffset = cpskip + dtheend; +#ifdef UBSEC_DEBUG + DPRINTF("mac: skip %d, len %d, inject %d\n", + maccrd->crd_skip, maccrd->crd_len, maccrd->crd_inject); + DPRINTF("enc: skip %d, len %d, inject %d\n", + enccrd->crd_skip, enccrd->crd_len, enccrd->crd_inject); + DPRINTF("src: skip %d, len %d\n", sskip, stheend); + DPRINTF("dst: skip %d, len %d\n", dskip, dtheend); + DPRINTF("ubs: coffset %d, pktlen %d, cpskip %d, cpoffset %d\n", + coffset, stheend, cpskip, cpoffset); +#endif + } else { + cpskip = dskip = sskip = macoffset + encoffset; + dtheend = stheend = (enccrd)?enccrd->crd_len:maccrd->crd_len; + cpoffset = cpskip + dtheend; + coffset = 0; + } + ctx.pc_offset = htole16(coffset >> 2); + +#if 0 + if (bus_dmamap_create(sc->sc_dmat, 0xfff0, UBS_MAX_SCATTER, + 0xfff0, 0, BUS_DMA_NOWAIT, &q->q_src_map) != 0) { + err = ENOMEM; + goto errout; + } +#endif + + if (crp->crp_flags & CRYPTO_F_SKBUF) { +#if 0 + if (bus_dmamap_load_mbuf(sc->sc_dmat, q->q_src_map, + q->q_src_m, BUS_DMA_NOWAIT) != 0) { + bus_dmamap_destroy(sc->sc_dmat, q->q_src_map); + q->q_src_map = NULL; + err = ENOMEM; + goto errout; + } +#endif + err = dma_map_skb(sc, q->q_src_map, q->q_src_m, &q->q_src_len); + if (unlikely(err != 0)) + goto errout; + + } else if (crp->crp_flags & CRYPTO_F_IOV) { +#if 0 + if (bus_dmamap_load_uio(sc->sc_dmat, q->q_src_map, + q->q_src_io, BUS_DMA_NOWAIT) != 0) { + bus_dmamap_destroy(sc->sc_dmat, q->q_src_map); + q->q_src_map = NULL; + err = ENOMEM; + goto errout; + } +#endif + err = dma_map_uio(sc, q->q_src_map, q->q_src_io, &q->q_src_len); + if (unlikely(err != 0)) + goto errout; + } + + /* + * Check alignment + */ + nicealign = ubsec_dmamap_aligned(sc, q->q_src_map, q->q_src_len); + + dmap->d_dma->d_mcr.mcr_pktlen = htole16(stheend); + +#ifdef UBSEC_DEBUG + DPRINTF("src skip: %d\n", sskip); +#endif + for (i = j = 0; i < q->q_src_len; i++) { + struct ubsec_pktbuf *pb; + size_t packl = q->q_src_map[i].dma_size; + dma_addr_t packp = q->q_src_map[i].dma_paddr; + + if (sskip >= packl) { + sskip -= packl; + continue; + } + + packl -= sskip; + packp += sskip; + sskip = 0; + + /* maximum fragment size is 0xfffc */ + if (packl > 0xfffc) { + DPRINTF("Error: fragment size is bigger than 0xfffc.\n"); + err = EIO; + goto errout; + } + + if (j == 0) + pb = &dmap->d_dma->d_mcr.mcr_ipktbuf; + else + pb = &dmap->d_dma->d_sbuf[j - 1]; + + pb->pb_addr = htole32(packp); + + if (stheend) { + if (packl > stheend) { + pb->pb_len = htole32(stheend); + stheend = 0; + } else { + pb->pb_len = htole32(packl); + stheend -= packl; + } + } else + pb->pb_len = htole32(packl); + + if ((i + 1) == q->q_src_len) + pb->pb_next = 0; + else + pb->pb_next = htole32(dmap->d_alloc.dma_paddr + + offsetof(struct ubsec_dmachunk, d_sbuf[j])); + j++; + } + + if (enccrd == NULL && maccrd != NULL) { + /* Authentication only */ + dmap->d_dma->d_mcr.mcr_opktbuf.pb_addr = 0; + dmap->d_dma->d_mcr.mcr_opktbuf.pb_len = 0; + dmap->d_dma->d_mcr.mcr_opktbuf.pb_next = + htole32(dmap->d_alloc.dma_paddr + + offsetof(struct ubsec_dmachunk, d_macbuf[0])); +#ifdef UBSEC_DEBUG + DPRINTF("opkt: %x %x %x\n", + dmap->d_dma->d_mcr.mcr_opktbuf.pb_addr, + dmap->d_dma->d_mcr.mcr_opktbuf.pb_len, + dmap->d_dma->d_mcr.mcr_opktbuf.pb_next); +#endif + } else { + if (crp->crp_flags & CRYPTO_F_IOV) { + if (!nicealign) { + err = EINVAL; + goto errout; + } +#if 0 + if (bus_dmamap_create(sc->sc_dmat, 0xfff0, + UBS_MAX_SCATTER, 0xfff0, 0, BUS_DMA_NOWAIT, + &q->q_dst_map) != 0) { + err = ENOMEM; + goto errout; + } + if (bus_dmamap_load_uio(sc->sc_dmat, q->q_dst_map, + q->q_dst_io, BUS_DMA_NOWAIT) != 0) { + bus_dmamap_destroy(sc->sc_dmat, q->q_dst_map); + q->q_dst_map = NULL; + goto errout; + } +#endif + + /* HW shall copy the result into the source memory */ + for(i = 0; i < q->q_src_len; i++) + q->q_dst_map[i] = q->q_src_map[i]; + + q->q_dst_len = q->q_src_len; + q->q_has_dst = 0; + + } else if (crp->crp_flags & CRYPTO_F_SKBUF) { + if (nicealign) { + + /* HW shall copy the result into the source memory */ + q->q_dst_m = q->q_src_m; + for(i = 0; i < q->q_src_len; i++) + q->q_dst_map[i] = q->q_src_map[i]; + + q->q_dst_len = q->q_src_len; + q->q_has_dst = 0; + + } else { +#ifdef NOTYET + int totlen, len; + struct sk_buff *m, *top, **mp; + + totlen = q->q_src_map->dm_mapsize; + if (q->q_src_m->m_flags & M_PKTHDR) { + len = MHLEN; + MGETHDR(m, M_DONTWAIT, MT_DATA); + } else { + len = MLEN; + MGET(m, M_DONTWAIT, MT_DATA); + } + if (m == NULL) { + err = ENOMEM; + goto errout; + } + if (len == MHLEN) + M_DUP_PKTHDR(m, q->q_src_m); + if (totlen >= MINCLSIZE) { + MCLGET(m, M_DONTWAIT); + if (m->m_flags & M_EXT) + len = MCLBYTES; + } + m->m_len = len; + top = NULL; + mp = ⊤ + + while (totlen > 0) { + if (top) { + MGET(m, M_DONTWAIT, MT_DATA); + if (m == NULL) { + m_freem(top); + err = ENOMEM; + goto errout; + } + len = MLEN; + } + if (top && totlen >= MINCLSIZE) { + MCLGET(m, M_DONTWAIT); + if (m->m_flags & M_EXT) + len = MCLBYTES; + } + m->m_len = len = min(totlen, len); + totlen -= len; + *mp = m; + mp = &m->m_next; + } + q->q_dst_m = top; + ubsec_mcopy(q->q_src_m, q->q_dst_m, + cpskip, cpoffset); + if (bus_dmamap_create(sc->sc_dmat, 0xfff0, + UBS_MAX_SCATTER, 0xfff0, 0, BUS_DMA_NOWAIT, + &q->q_dst_map) != 0) { + err = ENOMEM; + goto errout; + } + if (bus_dmamap_load_mbuf(sc->sc_dmat, + q->q_dst_map, q->q_dst_m, + BUS_DMA_NOWAIT) != 0) { + bus_dmamap_destroy(sc->sc_dmat, + q->q_dst_map); + q->q_dst_map = NULL; + err = ENOMEM; + goto errout; + } +#else + device_printf(sc->sc_dev, + "%s,%d: CRYPTO_F_SKBUF unaligned not implemented\n", + __FILE__, __LINE__); + err = EINVAL; + goto errout; +#endif + } + } else { + err = EINVAL; + goto errout; + } + +#ifdef UBSEC_DEBUG + DPRINTF("dst skip: %d\n", dskip); +#endif + for (i = j = 0; i < q->q_dst_len; i++) { + struct ubsec_pktbuf *pb; + size_t packl = q->q_dst_map[i].dma_size; + dma_addr_t packp = q->q_dst_map[i].dma_paddr; + + if (dskip >= packl) { + dskip -= packl; + continue; + } + + packl -= dskip; + packp += dskip; + dskip = 0; + + if (packl > 0xfffc) { + DPRINTF("Error: fragment size is bigger than 0xfffc.\n"); + err = EIO; + goto errout; + } + + if (j == 0) + pb = &dmap->d_dma->d_mcr.mcr_opktbuf; + else + pb = &dmap->d_dma->d_dbuf[j - 1]; + + pb->pb_addr = htole32(packp); + + if (dtheend) { + if (packl > dtheend) { + pb->pb_len = htole32(dtheend); + dtheend = 0; + } else { + pb->pb_len = htole32(packl); + dtheend -= packl; + } + } else + pb->pb_len = htole32(packl); + + if ((i + 1) == q->q_dst_len) { + if (maccrd) + /* Authentication: + * The last fragment of the output buffer + * contains the HMAC. */ + pb->pb_next = htole32(dmap->d_alloc.dma_paddr + + offsetof(struct ubsec_dmachunk, d_macbuf[0])); + else + pb->pb_next = 0; + } else + pb->pb_next = htole32(dmap->d_alloc.dma_paddr + + offsetof(struct ubsec_dmachunk, d_dbuf[j])); + j++; + } + } + + dmap->d_dma->d_mcr.mcr_cmdctxp = htole32(dmap->d_alloc.dma_paddr + + offsetof(struct ubsec_dmachunk, d_ctx)); + + if (sc->sc_flags & UBS_FLAGS_LONGCTX) { + /* new Broadcom cards with dynamic long command context structure */ + + if (enccrd != NULL && + enccrd->crd_alg == CRYPTO_AES_CBC) + { + struct ubsec_pktctx_aes128 *ctxaes128; + struct ubsec_pktctx_aes192 *ctxaes192; + struct ubsec_pktctx_aes256 *ctxaes256; + + switch(ses->ses_keysize) + { + /* AES 128bit */ + case 128: + ctxaes128 = (struct ubsec_pktctx_aes128 *) + (dmap->d_alloc.dma_vaddr + + offsetof(struct ubsec_dmachunk, d_ctx)); + + ctxaes128->pc_len = htole16(sizeof(struct ubsec_pktctx_aes128)); + ctxaes128->pc_type = ctx.pc_type; + ctxaes128->pc_flags = ctx.pc_flags; + ctxaes128->pc_offset = ctx.pc_offset; + for (i = 0; i < 4; i++) + ctxaes128->pc_aeskey[i] = ctx.pc_key[i]; + for (i = 0; i < 5; i++) + ctxaes128->pc_hminner[i] = ctx.pc_hminner[i]; + for (i = 0; i < 5; i++) + ctxaes128->pc_hmouter[i] = ctx.pc_hmouter[i]; + for (i = 0; i < 4; i++) + ctxaes128->pc_iv[i] = ctx.pc_iv[i]; + break; + + /* AES 192bit */ + case 192: + ctxaes192 = (struct ubsec_pktctx_aes192 *) + (dmap->d_alloc.dma_vaddr + + offsetof(struct ubsec_dmachunk, d_ctx)); + + ctxaes192->pc_len = htole16(sizeof(struct ubsec_pktctx_aes192)); + ctxaes192->pc_type = ctx.pc_type; + ctxaes192->pc_flags = ctx.pc_flags; + ctxaes192->pc_offset = ctx.pc_offset; + for (i = 0; i < 6; i++) + ctxaes192->pc_aeskey[i] = ctx.pc_key[i]; + for (i = 0; i < 5; i++) + ctxaes192->pc_hminner[i] = ctx.pc_hminner[i]; + for (i = 0; i < 5; i++) + ctxaes192->pc_hmouter[i] = ctx.pc_hmouter[i]; + for (i = 0; i < 4; i++) + ctxaes192->pc_iv[i] = ctx.pc_iv[i]; + break; + + /* AES 256bit */ + case 256: + ctxaes256 = (struct ubsec_pktctx_aes256 *) + (dmap->d_alloc.dma_vaddr + + offsetof(struct ubsec_dmachunk, d_ctx)); + + ctxaes256->pc_len = htole16(sizeof(struct ubsec_pktctx_aes256)); + ctxaes256->pc_type = ctx.pc_type; + ctxaes256->pc_flags = ctx.pc_flags; + ctxaes256->pc_offset = ctx.pc_offset; + for (i = 0; i < 8; i++) + ctxaes256->pc_aeskey[i] = ctx.pc_key[i]; + for (i = 0; i < 5; i++) + ctxaes256->pc_hminner[i] = ctx.pc_hminner[i]; + for (i = 0; i < 5; i++) + ctxaes256->pc_hmouter[i] = ctx.pc_hmouter[i]; + for (i = 0; i < 4; i++) + ctxaes256->pc_iv[i] = ctx.pc_iv[i]; + break; + + } + } else { + /* + * [3]DES / MD5_HMAC / SHA1_HMAC + * + * MD5_HMAC / SHA1_HMAC can use the IPSEC 3DES operation without + * encryption. + */ + struct ubsec_pktctx_des *ctxdes; + + ctxdes = (struct ubsec_pktctx_des *)(dmap->d_alloc.dma_vaddr + + offsetof(struct ubsec_dmachunk, d_ctx)); + + ctxdes->pc_len = htole16(sizeof(struct ubsec_pktctx_des)); + ctxdes->pc_type = ctx.pc_type; + ctxdes->pc_flags = ctx.pc_flags; + ctxdes->pc_offset = ctx.pc_offset; + for (i = 0; i < 6; i++) + ctxdes->pc_deskey[i] = ctx.pc_key[i]; + for (i = 0; i < 5; i++) + ctxdes->pc_hminner[i] = ctx.pc_hminner[i]; + for (i = 0; i < 5; i++) + ctxdes->pc_hmouter[i] = ctx.pc_hmouter[i]; + ctxdes->pc_iv[0] = ctx.pc_iv[0]; + ctxdes->pc_iv[1] = ctx.pc_iv[1]; + } + } else + { + /* old Broadcom card with fixed small command context structure */ + + /* + * [3]DES / MD5_HMAC / SHA1_HMAC + */ + struct ubsec_pktctx *ctxs; + + ctxs = (struct ubsec_pktctx *)(dmap->d_alloc.dma_vaddr + + offsetof(struct ubsec_dmachunk, d_ctx)); + + /* transform generic context into small context */ + for (i = 0; i < 6; i++) + ctxs->pc_deskey[i] = ctx.pc_key[i]; + for (i = 0; i < 5; i++) + ctxs->pc_hminner[i] = ctx.pc_hminner[i]; + for (i = 0; i < 5; i++) + ctxs->pc_hmouter[i] = ctx.pc_hmouter[i]; + ctxs->pc_iv[0] = ctx.pc_iv[0]; + ctxs->pc_iv[1] = ctx.pc_iv[1]; + ctxs->pc_flags = ctx.pc_flags; + ctxs->pc_offset = ctx.pc_offset; + } + +#ifdef UBSEC_VERBOSE_DEBUG + DPRINTF("spin_lock_irqsave\n"); +#endif + spin_lock_irqsave(&sc->sc_ringmtx, flags); + //spin_lock_irq(&sc->sc_ringmtx); + + BSD_SIMPLEQ_INSERT_TAIL(&sc->sc_queue, q, q_next); + sc->sc_nqueue++; + ubsecstats.hst_ipackets++; + ubsecstats.hst_ibytes += stheend; + ubsec_feed(sc); + +#ifdef UBSEC_VERBOSE_DEBUG + DPRINTF("spin_unlock_irqrestore\n"); +#endif + spin_unlock_irqrestore(&sc->sc_ringmtx, flags); + //spin_unlock_irq(&sc->sc_ringmtx); + + return (0); + +errout: + if (q != NULL) { +#ifdef NOTYET + if ((q->q_dst_m != NULL) && (q->q_src_m != q->q_dst_m)) + m_freem(q->q_dst_m); +#endif + + if ((q->q_has_dst == 1) && q->q_dst_len > 0) { +#if 0 + bus_dmamap_unload(sc->sc_dmat, q->q_dst_map); + bus_dmamap_destroy(sc->sc_dmat, q->q_dst_map); +#endif + dma_unmap(sc, q->q_dst_map, q->q_dst_len); + } + if (q->q_src_len > 0) { +#if 0 + bus_dmamap_unload(sc->sc_dmat, q->q_src_map); + bus_dmamap_destroy(sc->sc_dmat, q->q_src_map); +#endif + dma_unmap(sc, q->q_src_map, q->q_src_len); + } + +#ifdef UBSEC_VERBOSE_DEBUG + DPRINTF("spin_lock_irqsave\n"); +#endif + spin_lock_irqsave(&sc->sc_ringmtx, flags); + //spin_lock_irq(&sc->sc_ringmtx); + + BSD_SIMPLEQ_INSERT_TAIL(&sc->sc_freequeue, q, q_next); + +#ifdef UBSEC_VERBOSE_DEBUG + DPRINTF("spin_unlock_irqrestore\n"); +#endif + spin_unlock_irqrestore(&sc->sc_ringmtx, flags); + //spin_unlock_irq(&sc->sc_ringmtx); + + } + if (err == EINVAL) + ubsecstats.hst_invalid++; + else + ubsecstats.hst_nomem++; +errout2: + crp->crp_etype = err; + crypto_done(crp); + +#ifdef UBSEC_DEBUG + DPRINTF("%s() err = %x\n", __FUNCTION__, err); +#endif + + return (0); +} + +void +ubsec_callback(struct ubsec_softc *sc, struct ubsec_q *q) +{ + struct cryptop *crp = (struct cryptop *)q->q_crp; + struct cryptodesc *crd; + struct ubsec_dma *dmap = q->q_dma; + int ivsize = 8; + +#ifdef UBSEC_DEBUG + DPRINTF("%s()\n", __FUNCTION__); +#endif + + ubsecstats.hst_opackets++; + ubsecstats.hst_obytes += dmap->d_alloc.dma_size; + +#if 0 + bus_dmamap_sync(sc->sc_dmat, dmap->d_alloc.dma_map, 0, + dmap->d_alloc.dma_map->dm_mapsize, + BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); + if (q->q_dst_map != NULL && q->q_dst_map != q->q_src_map) { + bus_dmamap_sync(sc->sc_dmat, q->q_dst_map, + 0, q->q_dst_map->dm_mapsize, BUS_DMASYNC_POSTREAD); + bus_dmamap_unload(sc->sc_dmat, q->q_dst_map); + bus_dmamap_destroy(sc->sc_dmat, q->q_dst_map); + } + bus_dmamap_sync(sc->sc_dmat, q->q_src_map, + 0, q->q_src_map->dm_mapsize, BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(sc->sc_dmat, q->q_src_map); + bus_dmamap_destroy(sc->sc_dmat, q->q_src_map); +#endif + + if ((q->q_has_dst == 1) && q->q_dst_len > 0) + dma_unmap(sc, q->q_dst_map, q->q_dst_len); + + dma_unmap(sc, q->q_src_map, q->q_src_len); + +#ifdef NOTYET + if ((crp->crp_flags & CRYPTO_F_SKBUF) && (q->q_src_m != q->q_dst_m)) { + m_freem(q->q_src_m); + crp->crp_buf = (caddr_t)q->q_dst_m; + } +#endif + + /* copy out IV for future use */ + if (q->q_flags & UBSEC_QFLAGS_COPYOUTIV) { + for (crd = crp->crp_desc; crd; crd = crd->crd_next) { + if (crd->crd_alg != CRYPTO_DES_CBC && + crd->crd_alg != CRYPTO_3DES_CBC && + crd->crd_alg != CRYPTO_AES_CBC) + continue; + + if (crd->crd_alg == CRYPTO_AES_CBC) + ivsize = 16; + else + ivsize = 8; + + if (crp->crp_flags & CRYPTO_F_SKBUF) +#if 0 + m_copydata((struct sk_buff *)crp->crp_buf, + crd->crd_skip + crd->crd_len - 8, 8, + (caddr_t)sc->sc_sessions[q->q_sesn].ses_iv); +#endif + crypto_copydata(crp->crp_flags, (caddr_t)crp->crp_buf, + crd->crd_skip + crd->crd_len - ivsize, ivsize, + (caddr_t)sc->sc_sessions[q->q_sesn].ses_iv); + + else if (crp->crp_flags & CRYPTO_F_IOV) { +#if 0 + cuio_copydata((struct uio *)crp->crp_buf, + crd->crd_skip + crd->crd_len - 8, 8, + (caddr_t)sc->sc_sessions[q->q_sesn].ses_iv); +#endif + crypto_copydata(crp->crp_flags, (caddr_t)crp->crp_buf, + crd->crd_skip + crd->crd_len - ivsize, ivsize, + (caddr_t)sc->sc_sessions[q->q_sesn].ses_iv); + + } + break; + } + } + + for (crd = crp->crp_desc; crd; crd = crd->crd_next) { + if (crd->crd_alg != CRYPTO_MD5_HMAC && + crd->crd_alg != CRYPTO_SHA1_HMAC) + continue; +#if 0 + if (crp->crp_flags & CRYPTO_F_SKBUF) + m_copyback((struct sk_buff *)crp->crp_buf, + crd->crd_inject, 12, + dmap->d_dma->d_macbuf); +#endif +#if 0 + /* BUG? it does not honor the mac len.. */ + crypto_copyback(crp->crp_flags, crp->crp_buf, + crd->crd_inject, 12, + (caddr_t)dmap->d_dma->d_macbuf); +#endif + crypto_copyback(crp->crp_flags, crp->crp_buf, + crd->crd_inject, + sc->sc_sessions[q->q_sesn].ses_mlen, + (caddr_t)dmap->d_dma->d_macbuf); +#if 0 + else if (crp->crp_flags & CRYPTO_F_IOV && crp->crp_mac) + bcopy((caddr_t)dmap->d_dma->d_macbuf, + crp->crp_mac, 12); +#endif + break; + } + BSD_SIMPLEQ_INSERT_TAIL(&sc->sc_freequeue, q, q_next); + crypto_done(crp); +} + +void +ubsec_mcopy(struct sk_buff *srcm, struct sk_buff *dstm, int hoffset, int toffset) +{ + int i, j, dlen, slen; + caddr_t dptr, sptr; + + j = 0; + sptr = srcm->data; + slen = srcm->len; + dptr = dstm->data; + dlen = dstm->len; + + while (1) { + for (i = 0; i < min(slen, dlen); i++) { + if (j < hoffset || j >= toffset) + *dptr++ = *sptr++; + slen--; + dlen--; + j++; + } + if (slen == 0) { + srcm = srcm->next; + if (srcm == NULL) + return; + sptr = srcm->data; + slen = srcm->len; + } + if (dlen == 0) { + dstm = dstm->next; + if (dstm == NULL) + return; + dptr = dstm->data; + dlen = dstm->len; + } + } +} + +int +ubsec_dma_malloc(struct ubsec_softc *sc, struct ubsec_dma_alloc *dma, + size_t size, int mapflags) +{ + dma->dma_vaddr = dma_alloc_coherent(sc->sc_dv, + size, &dma->dma_paddr, GFP_KERNEL); + + if (likely(dma->dma_vaddr)) + { + dma->dma_size = size; + return (0); + } + + DPRINTF("could not allocate %d bytes of coherent memory.\n", size); + + return (1); +} + +void +ubsec_dma_free(struct ubsec_softc *sc, struct ubsec_dma_alloc *dma) +{ + dma_free_coherent(sc->sc_dv, dma->dma_size, dma->dma_vaddr, + dma->dma_paddr); +} + +/* + * Resets the board. Values in the regesters are left as is + * from the reset (i.e. initial values are assigned elsewhere). + */ +void +ubsec_reset_board(struct ubsec_softc *sc) +{ + volatile u_int32_t ctrl; + +#ifdef UBSEC_DEBUG + DPRINTF("%s()\n", __FUNCTION__); +#endif + DPRINTF("Send reset signal to chip.\n"); + + ctrl = READ_REG(sc, BS_CTRL); + ctrl |= BS_CTRL_RESET; + WRITE_REG(sc, BS_CTRL, ctrl); + + /* + * Wait aprox. 30 PCI clocks = 900 ns = 0.9 us + */ + DELAY(10); +} + +/* + * Init Broadcom registers + */ +void +ubsec_init_board(struct ubsec_softc *sc) +{ + u_int32_t ctrl; + +#ifdef UBSEC_DEBUG + DPRINTF("%s()\n", __FUNCTION__); +#endif + DPRINTF("Initialize chip.\n"); + + ctrl = READ_REG(sc, BS_CTRL); + ctrl &= ~(BS_CTRL_BE32 | BS_CTRL_BE64); + ctrl |= BS_CTRL_LITTLE_ENDIAN | BS_CTRL_MCR1INT | BS_CTRL_DMAERR; + + WRITE_REG(sc, BS_CTRL, ctrl); + + /* Set chip capabilities (BCM5365P) */ + sc->sc_flags |= UBS_FLAGS_LONGCTX | UBS_FLAGS_AES; +} + +/* + * Clean up after a chip crash. + * It is assumed that the caller has spin_lock_irq(sc_ringmtx). + */ +void +ubsec_cleanchip(struct ubsec_softc *sc) +{ + struct ubsec_q *q; + +#ifdef UBSEC_DEBUG + DPRINTF("%s()\n", __FUNCTION__); +#endif + DPRINTF("Clean up queues after chip crash.\n"); + + while (!BSD_SIMPLEQ_EMPTY(&sc->sc_qchip)) { + q = BSD_SIMPLEQ_FIRST(&sc->sc_qchip); + BSD_SIMPLEQ_REMOVE_HEAD(&sc->sc_qchip, q_next); + ubsec_free_q(sc, q); + } +} + +/* + * free a ubsec_q + * It is assumed that the caller has spin_lock_irq(sc_ringmtx). + */ +int +ubsec_free_q(struct ubsec_softc *sc, struct ubsec_q *q) +{ + struct ubsec_q *q2; + struct cryptop *crp; + int npkts; + int i; + +#ifdef UBSEC_DEBUG + DPRINTF("%s()\n", __FUNCTION__); +#endif + + npkts = q->q_nstacked_mcrs; + + for (i = 0; i < npkts; i++) { + if(q->q_stacked_mcr[i]) { + q2 = q->q_stacked_mcr[i]; + + if ((q2->q_dst_m != NULL) && (q2->q_src_m != q2->q_dst_m)) +#ifdef NOTYET + m_freem(q2->q_dst_m); +#else + printk(KERN_ERR "%s,%d: SKB not supported\n", __FILE__, __LINE__); +#endif + + crp = (struct cryptop *)q2->q_crp; + + BSD_SIMPLEQ_INSERT_TAIL(&sc->sc_freequeue, q2, q_next); + + crp->crp_etype = EFAULT; + crypto_done(crp); + } else { + break; + } + } + + /* + * Free header MCR + */ + if ((q->q_dst_m != NULL) && (q->q_src_m != q->q_dst_m)) +#ifdef NOTYET + m_freem(q->q_dst_m); +#else + printk(KERN_ERR "%s,%d: SKB not supported\n", __FILE__, __LINE__); +#endif + + crp = (struct cryptop *)q->q_crp; + + BSD_SIMPLEQ_INSERT_TAIL(&sc->sc_freequeue, q, q_next); + + crp->crp_etype = EFAULT; + crypto_done(crp); + return(0); +} + +/* + * Routine to reset the chip and clean up. + * It is assumed that the caller has spin_lock_irq(sc_ringmtx). + */ +void +ubsec_totalreset(struct ubsec_softc *sc) +{ + +#ifdef UBSEC_DEBUG + DPRINTF("%s()\n", __FUNCTION__); +#endif + DPRINTF("initiate total chip reset.. \n"); + ubsec_reset_board(sc); + ubsec_init_board(sc); + ubsec_cleanchip(sc); +} + +void +ubsec_dump_pb(struct ubsec_pktbuf *pb) +{ + printf("addr 0x%x (0x%x) next 0x%x\n", + pb->pb_addr, pb->pb_len, pb->pb_next); +} + +void +ubsec_dump_mcr(struct ubsec_mcr *mcr) +{ + struct ubsec_mcr_add *ma; + int i; + + printf("MCR:\n"); + printf(" pkts: %u, flags 0x%x\n", + letoh16(mcr->mcr_pkts), letoh16(mcr->mcr_flags)); + ma = (struct ubsec_mcr_add *)&mcr->mcr_cmdctxp; + for (i = 0; i < letoh16(mcr->mcr_pkts); i++) { + printf(" %d: ctx 0x%x len 0x%x rsvd 0x%x\n", i, + letoh32(ma->mcr_cmdctxp), letoh16(ma->mcr_pktlen), + letoh16(ma->mcr_reserved)); + printf(" %d: ipkt ", i); + ubsec_dump_pb(&ma->mcr_ipktbuf); + printf(" %d: opkt ", i); + ubsec_dump_pb(&ma->mcr_opktbuf); + ma++; + } + printf("END MCR\n"); +} + +static int __init mod_init(void) { + return ssb_driver_register(&ubsec_ssb_driver); +} + +static void __exit mod_exit(void) { + ssb_driver_unregister(&ubsec_ssb_driver); +} + +module_init(mod_init); +module_exit(mod_exit); + +// Meta information +MODULE_AUTHOR("Daniel Mueller "); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_DESCRIPTION("OCF driver for BCM5365P IPSec Core"); +MODULE_VERSION(DRV_MODULE_VERSION); + diff --git a/target/linux/generic/files/crypto/ocf/ubsec_ssb/ubsecreg.h b/target/linux/generic/files/crypto/ocf/ubsec_ssb/ubsecreg.h new file mode 100644 index 0000000..dafac5b --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/ubsec_ssb/ubsecreg.h @@ -0,0 +1,233 @@ + +/* + * Copyright (c) 2008 Daniel Mueller (daniel@danm.de) + * Copyright (c) 2000 Theo de Raadt + * Copyright (c) 2001 Patrik Lindergren (patrik@ipunplugged.com) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Effort sponsored in part by the Defense Advanced Research Projects + * Agency (DARPA) and Air Force Research Laboratory, Air Force + * Materiel Command, USAF, under agreement number F30602-01-2-0537. + * + */ + +/* + * Register definitions for 5601 BlueSteel Networks Ubiquitous Broadband + * Security "uBSec" chip. Definitions from revision 2.8 of the product + * datasheet. + */ + +#define BS_BAR 0x10 /* DMA base address register */ +#define BS_TRDY_TIMEOUT 0x40 /* TRDY timeout */ +#define BS_RETRY_TIMEOUT 0x41 /* DMA retry timeout */ + +#define UBS_PCI_RTY_SHIFT 8 +#define UBS_PCI_RTY_MASK 0xff +#define UBS_PCI_RTY(misc) \ + (((misc) >> UBS_PCI_RTY_SHIFT) & UBS_PCI_RTY_MASK) + +#define UBS_PCI_TOUT_SHIFT 0 +#define UBS_PCI_TOUT_MASK 0xff +#define UBS_PCI_TOUT(misc) \ + (((misc) >> PCI_TOUT_SHIFT) & PCI_TOUT_MASK) + +/* + * DMA Control & Status Registers (offset from BS_BAR) + */ +#define BS_MCR1 0x20 /* DMA Master Command Record 1 */ +#define BS_CTRL 0x24 /* DMA Control */ +#define BS_STAT 0x28 /* DMA Status */ +#define BS_ERR 0x2c /* DMA Error Address */ +#define BS_DEV_ID 0x34 /* IPSec Device ID */ + +/* BS_CTRL - DMA Control */ +#define BS_CTRL_RESET 0x80000000 /* hardware reset, 5805/5820 */ +#define BS_CTRL_MCR2INT 0x40000000 /* enable intr MCR for MCR2 */ +#define BS_CTRL_MCR1INT 0x20000000 /* enable intr MCR for MCR1 */ +#define BS_CTRL_OFM 0x10000000 /* Output fragment mode */ +#define BS_CTRL_BE32 0x08000000 /* big-endian, 32bit bytes */ +#define BS_CTRL_BE64 0x04000000 /* big-endian, 64bit bytes */ +#define BS_CTRL_DMAERR 0x02000000 /* enable intr DMA error */ +#define BS_CTRL_RNG_M 0x01800000 /* RNG mode */ +#define BS_CTRL_RNG_1 0x00000000 /* 1bit rn/one slow clock */ +#define BS_CTRL_RNG_4 0x00800000 /* 1bit rn/four slow clocks */ +#define BS_CTRL_RNG_8 0x01000000 /* 1bit rn/eight slow clocks */ +#define BS_CTRL_RNG_16 0x01800000 /* 1bit rn/16 slow clocks */ +#define BS_CTRL_SWNORM 0x00400000 /* 582[01], sw normalization */ +#define BS_CTRL_FRAG_M 0x0000ffff /* output fragment size mask */ +#define BS_CTRL_LITTLE_ENDIAN (BS_CTRL_BE32 | BS_CTRL_BE64) + +/* BS_STAT - DMA Status */ +#define BS_STAT_MCR1_BUSY 0x80000000 /* MCR1 is busy */ +#define BS_STAT_MCR1_FULL 0x40000000 /* MCR1 is full */ +#define BS_STAT_MCR1_DONE 0x20000000 /* MCR1 is done */ +#define BS_STAT_DMAERR 0x10000000 /* DMA error */ +#define BS_STAT_MCR2_FULL 0x08000000 /* MCR2 is full */ +#define BS_STAT_MCR2_DONE 0x04000000 /* MCR2 is done */ +#define BS_STAT_MCR1_ALLEMPTY 0x02000000 /* 5821, MCR1 is empty */ +#define BS_STAT_MCR2_ALLEMPTY 0x01000000 /* 5821, MCR2 is empty */ + +/* BS_ERR - DMA Error Address */ +#define BS_ERR_ADDR 0xfffffffc /* error address mask */ +#define BS_ERR_READ 0x00000002 /* fault was on read */ + +struct ubsec_pktctx { + u_int32_t pc_deskey[6]; /* 3DES key */ + u_int32_t pc_hminner[5]; /* hmac inner state */ + u_int32_t pc_hmouter[5]; /* hmac outer state */ + u_int32_t pc_iv[2]; /* [3]DES iv */ + u_int16_t pc_flags; /* flags, below */ + u_int16_t pc_offset; /* crypto offset */ +} __attribute__ ((packed)); + +#define UBS_PKTCTX_ENC_3DES 0x8000 /* use 3des */ +#define UBS_PKTCTX_ENC_AES 0x8000 /* use aes */ +#define UBS_PKTCTX_ENC_NONE 0x0000 /* no encryption */ +#define UBS_PKTCTX_INBOUND 0x4000 /* inbound packet */ +#define UBS_PKTCTX_AUTH 0x3000 /* authentication mask */ +#define UBS_PKTCTX_AUTH_NONE 0x0000 /* no authentication */ +#define UBS_PKTCTX_AUTH_MD5 0x1000 /* use hmac-md5 */ +#define UBS_PKTCTX_AUTH_SHA1 0x2000 /* use hmac-sha1 */ +#define UBS_PKTCTX_AES128 0x0 /* AES 128bit keys */ +#define UBS_PKTCTX_AES192 0x100 /* AES 192bit keys */ +#define UBS_PKTCTX_AES256 0x200 /* AES 256bit keys */ + +struct ubsec_pktctx_des { + volatile u_int16_t pc_len; /* length of ctx struct */ + volatile u_int16_t pc_type; /* context type */ + volatile u_int16_t pc_flags; /* flags, same as above */ + volatile u_int16_t pc_offset; /* crypto/auth offset */ + volatile u_int32_t pc_deskey[6]; /* 3DES key */ + volatile u_int32_t pc_iv[2]; /* [3]DES iv */ + volatile u_int32_t pc_hminner[5]; /* hmac inner state */ + volatile u_int32_t pc_hmouter[5]; /* hmac outer state */ +} __attribute__ ((packed)); + +struct ubsec_pktctx_aes128 { + volatile u_int16_t pc_len; /* length of ctx struct */ + volatile u_int16_t pc_type; /* context type */ + volatile u_int16_t pc_flags; /* flags, same as above */ + volatile u_int16_t pc_offset; /* crypto/auth offset */ + volatile u_int32_t pc_aeskey[4]; /* AES 128bit key */ + volatile u_int32_t pc_iv[4]; /* AES iv */ + volatile u_int32_t pc_hminner[5]; /* hmac inner state */ + volatile u_int32_t pc_hmouter[5]; /* hmac outer state */ +} __attribute__ ((packed)); + +struct ubsec_pktctx_aes192 { + volatile u_int16_t pc_len; /* length of ctx struct */ + volatile u_int16_t pc_type; /* context type */ + volatile u_int16_t pc_flags; /* flags, same as above */ + volatile u_int16_t pc_offset; /* crypto/auth offset */ + volatile u_int32_t pc_aeskey[6]; /* AES 192bit key */ + volatile u_int32_t pc_iv[4]; /* AES iv */ + volatile u_int32_t pc_hminner[5]; /* hmac inner state */ + volatile u_int32_t pc_hmouter[5]; /* hmac outer state */ +} __attribute__ ((packed)); + +struct ubsec_pktctx_aes256 { + volatile u_int16_t pc_len; /* length of ctx struct */ + volatile u_int16_t pc_type; /* context type */ + volatile u_int16_t pc_flags; /* flags, same as above */ + volatile u_int16_t pc_offset; /* crypto/auth offset */ + volatile u_int32_t pc_aeskey[8]; /* AES 256bit key */ + volatile u_int32_t pc_iv[4]; /* AES iv */ + volatile u_int32_t pc_hminner[5]; /* hmac inner state */ + volatile u_int32_t pc_hmouter[5]; /* hmac outer state */ +} __attribute__ ((packed)); + +#define UBS_PKTCTX_TYPE_IPSEC_DES 0x0000 +#define UBS_PKTCTX_TYPE_IPSEC_AES 0x0040 + +struct ubsec_pktbuf { + volatile u_int32_t pb_addr; /* address of buffer start */ + volatile u_int32_t pb_next; /* pointer to next pktbuf */ + volatile u_int32_t pb_len; /* packet length */ +} __attribute__ ((packed)); +#define UBS_PKTBUF_LEN 0x0000ffff /* length mask */ + +struct ubsec_mcr { + volatile u_int16_t mcr_pkts; /* #pkts in this mcr */ + volatile u_int16_t mcr_flags; /* mcr flags (below) */ + volatile u_int32_t mcr_cmdctxp; /* command ctx pointer */ + struct ubsec_pktbuf mcr_ipktbuf; /* input chain header */ + volatile u_int16_t mcr_reserved; + volatile u_int16_t mcr_pktlen; + struct ubsec_pktbuf mcr_opktbuf; /* output chain header */ +} __attribute__ ((packed)); + +struct ubsec_mcr_add { + volatile u_int32_t mcr_cmdctxp; /* command ctx pointer */ + struct ubsec_pktbuf mcr_ipktbuf; /* input chain header */ + volatile u_int16_t mcr_reserved; + volatile u_int16_t mcr_pktlen; + struct ubsec_pktbuf mcr_opktbuf; /* output chain header */ +} __attribute__ ((packed)); + +#define UBS_MCR_DONE 0x0001 /* mcr has been processed */ +#define UBS_MCR_ERROR 0x0002 /* error in processing */ +#define UBS_MCR_ERRORCODE 0xff00 /* error type */ + +struct ubsec_ctx_keyop { + volatile u_int16_t ctx_len; /* command length */ + volatile u_int16_t ctx_op; /* operation code */ + volatile u_int8_t ctx_pad[60]; /* padding */ +} __attribute__ ((packed)); +#define UBS_CTXOP_DHPKGEN 0x01 /* dh public key generation */ +#define UBS_CTXOP_DHSSGEN 0x02 /* dh shared secret gen. */ +#define UBS_CTXOP_RSAPUB 0x03 /* rsa public key op */ +#define UBS_CTXOP_RSAPRIV 0x04 /* rsa private key op */ +#define UBS_CTXOP_DSASIGN 0x05 /* dsa signing op */ +#define UBS_CTXOP_DSAVRFY 0x06 /* dsa verification */ +#define UBS_CTXOP_RNGBYPASS 0x41 /* rng direct test mode */ +#define UBS_CTXOP_RNGSHA1 0x42 /* rng sha1 test mode */ +#define UBS_CTXOP_MODADD 0x43 /* modular addition */ +#define UBS_CTXOP_MODSUB 0x44 /* modular subtraction */ +#define UBS_CTXOP_MODMUL 0x45 /* modular multiplication */ +#define UBS_CTXOP_MODRED 0x46 /* modular reduction */ +#define UBS_CTXOP_MODEXP 0x47 /* modular exponentiation */ +#define UBS_CTXOP_MODINV 0x48 /* modular inverse */ + +struct ubsec_ctx_rngbypass { + volatile u_int16_t rbp_len; /* command length, 64 */ + volatile u_int16_t rbp_op; /* rng bypass, 0x41 */ + volatile u_int8_t rbp_pad[60]; /* padding */ +} __attribute__ ((packed)); + +/* modexp: C = (M ^ E) mod N */ +struct ubsec_ctx_modexp { + volatile u_int16_t me_len; /* command length */ + volatile u_int16_t me_op; /* modexp, 0x47 */ + volatile u_int16_t me_E_len; /* E (bits) */ + volatile u_int16_t me_N_len; /* N (bits) */ + u_int8_t me_N[2048/8]; /* N */ +} __attribute__ ((packed)); + +struct ubsec_ctx_rsapriv { + volatile u_int16_t rpr_len; /* command length */ + volatile u_int16_t rpr_op; /* rsaprivate, 0x04 */ + volatile u_int16_t rpr_q_len; /* q (bits) */ + volatile u_int16_t rpr_p_len; /* p (bits) */ + u_int8_t rpr_buf[5 * 1024 / 8]; /* parameters: */ + /* p, q, dp, dq, pinv */ +} __attribute__ ((packed)); diff --git a/target/linux/generic/files/crypto/ocf/ubsec_ssb/ubsecvar.h b/target/linux/generic/files/crypto/ocf/ubsec_ssb/ubsecvar.h new file mode 100644 index 0000000..c808f95 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/ubsec_ssb/ubsecvar.h @@ -0,0 +1,228 @@ + +/* + * Copyright (c) 2008 Daniel Mueller (daniel@danm.de) + * Copyright (c) 2000 Theo de Raadt + * Copyright (c) 2001 Patrik Lindergren (patrik@ipunplugged.com) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Effort sponsored in part by the Defense Advanced Research Projects + * Agency (DARPA) and Air Force Research Laboratory, Air Force + * Materiel Command, USAF, under agreement number F30602-01-2-0537. + * + */ + +/* Maximum queue length */ +#ifndef UBS_MAX_NQUEUE +#define UBS_MAX_NQUEUE 60 +#endif + +#define UBS_MAX_SCATTER 64 /* Maximum scatter/gather depth */ + +#ifndef UBS_MAX_AGGR +#define UBS_MAX_AGGR 5 /* Maximum aggregation count */ +#endif + +#define UBSEC_CARD(sid) (((sid) & 0xf0000000) >> 28) +#define UBSEC_SESSION(sid) ( (sid) & 0x0fffffff) +#define UBSEC_SID(crd, sesn) (((crd) << 28) | ((sesn) & 0x0fffffff)) + +#define UBS_DEF_RTY 0xff /* PCI Retry Timeout */ +#define UBS_DEF_TOUT 0xff /* PCI TRDY Timeout */ +#define UBS_DEF_CACHELINE 0x01 /* Cache Line setting */ + +#define DEFAULT_HMAC_LEN 12 + +struct ubsec_dma_alloc { + dma_addr_t dma_paddr; + void *dma_vaddr; + /* + bus_dmamap_t dma_map; + bus_dma_segment_t dma_seg; + */ + size_t dma_size; + /* + int dma_nseg; + */ +}; + +struct ubsec_q2 { + BSD_SIMPLEQ_ENTRY(ubsec_q2) q_next; + struct ubsec_dma_alloc q_mcr; + struct ubsec_dma_alloc q_ctx; + u_int q_type; +}; + +struct ubsec_q2_rng { + struct ubsec_q2 rng_q; + struct ubsec_dma_alloc rng_buf; + int rng_used; +}; + +/* C = (M ^ E) mod N */ +#define UBS_MODEXP_PAR_M 0 +#define UBS_MODEXP_PAR_E 1 +#define UBS_MODEXP_PAR_N 2 +struct ubsec_q2_modexp { + struct ubsec_q2 me_q; + struct cryptkop * me_krp; + struct ubsec_dma_alloc me_M; + struct ubsec_dma_alloc me_E; + struct ubsec_dma_alloc me_C; + struct ubsec_dma_alloc me_epb; + int me_modbits; + int me_shiftbits; + int me_normbits; +}; + +#define UBS_RSAPRIV_PAR_P 0 +#define UBS_RSAPRIV_PAR_Q 1 +#define UBS_RSAPRIV_PAR_DP 2 +#define UBS_RSAPRIV_PAR_DQ 3 +#define UBS_RSAPRIV_PAR_PINV 4 +#define UBS_RSAPRIV_PAR_MSGIN 5 +#define UBS_RSAPRIV_PAR_MSGOUT 6 +struct ubsec_q2_rsapriv { + struct ubsec_q2 rpr_q; + struct cryptkop * rpr_krp; + struct ubsec_dma_alloc rpr_msgin; + struct ubsec_dma_alloc rpr_msgout; +}; + +#define UBSEC_RNG_BUFSIZ 16 /* measured in 32bit words */ + +struct ubsec_dmachunk { + struct ubsec_mcr d_mcr; + struct ubsec_mcr_add d_mcradd[UBS_MAX_AGGR-1]; + struct ubsec_pktbuf d_sbuf[UBS_MAX_SCATTER-1]; + struct ubsec_pktbuf d_dbuf[UBS_MAX_SCATTER-1]; + u_int32_t d_macbuf[5]; + union { + struct ubsec_pktctx_aes256 ctxaes256; + struct ubsec_pktctx_aes192 ctxaes192; + struct ubsec_pktctx_des ctxdes; + struct ubsec_pktctx_aes128 ctxaes128; + struct ubsec_pktctx ctx; + } d_ctx; +}; + +struct ubsec_dma { + BSD_SIMPLEQ_ENTRY(ubsec_dma) d_next; + struct ubsec_dmachunk *d_dma; + struct ubsec_dma_alloc d_alloc; +}; + +#define UBS_FLAGS_KEY 0x01 /* has key accelerator */ +#define UBS_FLAGS_LONGCTX 0x02 /* uses long ipsec ctx */ +#define UBS_FLAGS_BIGKEY 0x04 /* 2048bit keys */ +#define UBS_FLAGS_HWNORM 0x08 /* hardware normalization */ +#define UBS_FLAGS_RNG 0x10 /* hardware rng */ +#define UBS_FLAGS_AES 0x20 /* hardware AES support */ + +struct ubsec_q { + BSD_SIMPLEQ_ENTRY(ubsec_q) q_next; + int q_nstacked_mcrs; + struct ubsec_q *q_stacked_mcr[UBS_MAX_AGGR-1]; + struct cryptop *q_crp; + struct ubsec_dma *q_dma; + + //struct mbuf *q_src_m, *q_dst_m; + struct sk_buff *q_src_m, *q_dst_m; + struct uio *q_src_io, *q_dst_io; + + /* + bus_dmamap_t q_src_map; + bus_dmamap_t q_dst_map; + */ + + /* DMA addresses for In-/Out packages */ + int q_src_len; + int q_dst_len; + struct ubsec_dma_alloc q_src_map[UBS_MAX_SCATTER]; + struct ubsec_dma_alloc q_dst_map[UBS_MAX_SCATTER]; + int q_has_dst; + + int q_sesn; + int q_flags; +}; + +struct ubsec_softc { + softc_device_decl sc_dev; + struct ssb_device *sdev; /* device backpointer */ + + struct device *sc_dv; /* generic device */ + void *sc_ih; /* interrupt handler cookie */ + int sc_flags; /* device specific flags */ + u_int32_t sc_statmask; /* interrupt status mask */ + int32_t sc_cid; /* crypto tag */ + BSD_SIMPLEQ_HEAD(,ubsec_q) sc_queue; /* packet queue, mcr1 */ + int sc_nqueue; /* count enqueued, mcr1 */ + BSD_SIMPLEQ_HEAD(,ubsec_q) sc_qchip; /* on chip, mcr1 */ + BSD_SIMPLEQ_HEAD(,ubsec_q) sc_freequeue; /* list of free queue elements */ + BSD_SIMPLEQ_HEAD(,ubsec_q2) sc_queue2; /* packet queue, mcr2 */ + int sc_nqueue2; /* count enqueued, mcr2 */ + BSD_SIMPLEQ_HEAD(,ubsec_q2) sc_qchip2; /* on chip, mcr2 */ + int sc_nsessions; /* # of sessions */ + struct ubsec_session *sc_sessions; /* sessions */ + int sc_rnghz; /* rng poll time */ + struct ubsec_q2_rng sc_rng; + struct ubsec_dma sc_dmaa[UBS_MAX_NQUEUE]; + struct ubsec_q *sc_queuea[UBS_MAX_NQUEUE]; + BSD_SIMPLEQ_HEAD(,ubsec_q2) sc_q2free; /* free list */ + spinlock_t sc_ringmtx; /* PE ring lock */ +}; + +#define UBSEC_QFLAGS_COPYOUTIV 0x1 + +struct ubsec_session { + u_int32_t ses_used; + u_int32_t ses_key[8]; /* 3DES/AES key */ + u_int32_t ses_hminner[5]; /* hmac inner state */ + u_int32_t ses_hmouter[5]; /* hmac outer state */ + u_int32_t ses_iv[4]; /* [3]DES/AES iv */ + u_int32_t ses_keysize; /* AES key size */ + u_int32_t ses_mlen; /* hmac/hash length */ +}; + +struct ubsec_stats { + u_int64_t hst_ibytes; + u_int64_t hst_obytes; + u_int32_t hst_ipackets; + u_int32_t hst_opackets; + u_int32_t hst_invalid; + u_int32_t hst_nomem; + u_int32_t hst_queuefull; + u_int32_t hst_dmaerr; + u_int32_t hst_mcrerr; + u_int32_t hst_nodmafree; +}; + +struct ubsec_generic_ctx { + u_int32_t pc_key[8]; /* [3]DES/AES key */ + u_int32_t pc_hminner[5]; /* hmac inner state */ + u_int32_t pc_hmouter[5]; /* hmac outer state */ + u_int32_t pc_iv[4]; /* [3]DES/AES iv */ + u_int16_t pc_flags; /* flags, below */ + u_int16_t pc_offset; /* crypto offset */ + u_int16_t pc_type; /* Cryptographic operation */ +}; + diff --git a/target/linux/generic/files/crypto/ocf/uio.h b/target/linux/generic/files/crypto/ocf/uio.h new file mode 100644 index 0000000..03a6249 --- /dev/null +++ b/target/linux/generic/files/crypto/ocf/uio.h @@ -0,0 +1,54 @@ +#ifndef _OCF_UIO_H_ +#define _OCF_UIO_H_ + +#include + +/* + * The linux uio.h doesn't have all we need. To be fully api compatible + * with the BSD cryptodev, we need to keep this around. Perhaps this can + * be moved back into the linux/uio.h + * + * Linux port done by David McCullough + * Copyright (C) 2006-2010 David McCullough + * Copyright (C) 2004-2005 Intel Corporation. + * + * LICENSE TERMS + * + * The free distribution and use of this software in both source and binary + * form is allowed (with or without changes) provided that: + * + * 1. distributions of this source code include the above copyright + * notice, this list of conditions and the following disclaimer; + * + * 2. distributions in binary form include the above copyright + * notice, this list of conditions and the following disclaimer + * in the documentation and/or other associated materials; + * + * 3. the copyright holder's name is not used to endorse products + * built using this software without specific written permission. + * + * ALTERNATIVELY, provided that this notice is retained in full, this product + * may be distributed under the terms of the GNU General Public License (GPL), + * in which case the provisions of the GPL apply INSTEAD OF those given above. + * + * DISCLAIMER + * + * This software is provided 'as is' with no explicit or implied warranties + * in respect of its properties, including, but not limited to, correctness + * and/or fitness for purpose. + * --------------------------------------------------------------------------- + */ + +struct uio { + struct iovec *uio_iov; + int uio_iovcnt; + off_t uio_offset; + int uio_resid; +#if 0 + enum uio_seg uio_segflg; + enum uio_rw uio_rw; + struct thread *uio_td; +#endif +}; + +#endif diff --git a/target/linux/generic/files/drivers/leds/ledtrig-morse.c b/target/linux/generic/files/drivers/leds/ledtrig-morse.c new file mode 100644 index 0000000..bc58afe --- /dev/null +++ b/target/linux/generic/files/drivers/leds/ledtrig-morse.c @@ -0,0 +1,366 @@ +/* + * LED Morse Trigger + * + * Copyright (C) 2007 Gabor Juhos + * + * This file was based on: drivers/led/ledtrig-timer.c + * Copyright 2005-2006 Openedhand Ltd. + * Author: Richard Purdie + * + * also based on the patch '[PATCH] 2.5.59 morse code panics' posted + * in the LKML by Tomas Szepe at Thu, 30 Jan 2003 + * Copyright (C) 2002 Andrew Rodland + * Copyright (C) 2003 Tomas Szepe + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "leds.h" + +#define MORSE_DELAY_BASE (HZ/2) + +#define MORSE_STATE_BLINK_START 0 +#define MORSE_STATE_BLINK_STOP 1 + +#define MORSE_DIT_LEN 1 +#define MORSE_DAH_LEN 3 +#define MORSE_SPACE_LEN 7 + +struct morse_trig_data { + unsigned long delay; + char *msg; + + unsigned char morse; + unsigned char state; + char *msgpos; + struct timer_list timer; +}; + +const unsigned char morsetable[] = { + 0122, 0, 0310, 0, 0, 0163, /* "#$%&' */ + 055, 0155, 0, 0, 0163, 0141, 0152, 0051, /* ()*+,-./ */ + 077, 076, 074, 070, 060, 040, 041, 043, 047, 057, /* 0-9 */ + 0107, 0125, 0, 0061, 0, 0114, 0, /* :;<=>?@ */ + 006, 021, 025, 011, 002, 024, 013, 020, 004, /* A-I */ + 036, 015, 022, 007, 005, 017, 026, 033, 012, /* J-R */ + 010, 003, 014, 030, 016, 031, 035, 023, /* S-Z */ + 0, 0, 0, 0, 0154 /* [\]^_ */ +}; + +static inline unsigned char tomorse(char c) { + if (c >= 'a' && c <= 'z') + c = c - 'a' + 'A'; + if (c >= '"' && c <= '_') { + return morsetable[c - '"']; + } else + return 0; +} + +static inline unsigned long dit_len(struct morse_trig_data *morse_data) +{ + return MORSE_DIT_LEN*morse_data->delay; +} + +static inline unsigned long dah_len(struct morse_trig_data *morse_data) +{ + return MORSE_DAH_LEN*morse_data->delay; +} + +static inline unsigned long space_len(struct morse_trig_data *morse_data) +{ + return MORSE_SPACE_LEN*morse_data->delay; +} + +static void morse_timer_function(unsigned long data) +{ + struct led_classdev *led_cdev = (struct led_classdev *)data; + struct morse_trig_data *morse_data = led_cdev->trigger_data; + unsigned long brightness = LED_OFF; + unsigned long delay = 0; + + if (!morse_data->msg) + goto set_led; + + switch (morse_data->state) { + case MORSE_STATE_BLINK_START: + /* Starting a new blink. We have a valid code in morse. */ + delay = (morse_data->morse & 001) ? dah_len(morse_data): + dit_len(morse_data); + brightness = LED_FULL; + morse_data->state = MORSE_STATE_BLINK_STOP; + morse_data->morse >>= 1; + break; + case MORSE_STATE_BLINK_STOP: + /* Coming off of a blink. */ + morse_data->state = MORSE_STATE_BLINK_START; + + if (morse_data->morse > 1) { + /* Not done yet, just a one-dit pause. */ + delay = dit_len(morse_data); + break; + } + + /* Get a new char, figure out how much space. */ + /* First time through */ + if (!morse_data->msgpos) + morse_data->msgpos = (char *)morse_data->msg; + + if (!*morse_data->msgpos) { + /* Repeating */ + morse_data->msgpos = (char *)morse_data->msg; + delay = space_len(morse_data); + } else { + /* Inter-letter space */ + delay = dah_len(morse_data); + } + + if (!(morse_data->morse = tomorse(*morse_data->msgpos))) { + delay = space_len(morse_data); + /* And get us back here */ + morse_data->state = MORSE_STATE_BLINK_STOP; + } + morse_data->msgpos++; + break; + } + + mod_timer(&morse_data->timer, jiffies + msecs_to_jiffies(delay)); + +set_led: + led_set_brightness(led_cdev, brightness); +} + +static ssize_t _morse_delay_show(struct led_classdev *led_cdev, char *buf) +{ + struct morse_trig_data *morse_data = led_cdev->trigger_data; + + sprintf(buf, "%lu\n", morse_data->delay); + + return strlen(buf) + 1; +} + +static ssize_t _morse_delay_store(struct led_classdev *led_cdev, + const char *buf, size_t size) +{ + struct morse_trig_data *morse_data = led_cdev->trigger_data; + char *after; + unsigned long state = simple_strtoul(buf, &after, 10); + size_t count = after - buf; + int ret = -EINVAL; + + if (*after && isspace(*after)) + count++; + + if (count == size) { + morse_data->delay = state; + mod_timer(&morse_data->timer, jiffies + 1); + ret = count; + } + + return ret; +} + +static ssize_t _morse_msg_show(struct led_classdev *led_cdev, char *buf) +{ + struct morse_trig_data *morse_data = led_cdev->trigger_data; + + if (!morse_data->msg) + sprintf(buf, "\n"); + else + sprintf(buf, "%s\n", morse_data->msg); + + return strlen(buf) + 1; +} + +static ssize_t _morse_msg_store(struct led_classdev *led_cdev, + const char *buf, size_t size) +{ + struct morse_trig_data *morse_data = led_cdev->trigger_data; + char *m; + + m = kmalloc(size, GFP_KERNEL); + if (!m) + return -ENOMEM; + + memcpy(m,buf,size); + m[size]='\0'; + + if (morse_data->msg) + kfree(morse_data->msg); + + morse_data->msg = m; + morse_data->msgpos = NULL; + morse_data->state = MORSE_STATE_BLINK_STOP; + + mod_timer(&morse_data->timer, jiffies + 1); + + return size; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23) +static ssize_t morse_delay_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + + return _morse_delay_show(led_cdev, buf); +} + +static ssize_t morse_delay_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + + return _morse_delay_store(led_cdev, buf, size); +} + +static ssize_t morse_msg_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + + return _morse_msg_show(led_cdev, buf); +} + +static ssize_t morse_msg_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + + return _morse_msg_store(led_cdev, buf, size); +} + +static DEVICE_ATTR(delay, 0644, morse_delay_show, morse_delay_store); +static DEVICE_ATTR(message, 0644, morse_msg_show, morse_msg_store); + +#define led_device_create_file(leddev, attr) \ + device_create_file(leddev->dev, &dev_attr_ ## attr) +#define led_device_remove_file(leddev, attr) \ + device_remove_file(leddev->dev, &dev_attr_ ## attr) + +#else +static ssize_t morse_delay_show(struct class_device *dev, char *buf) +{ + struct led_classdev *led_cdev = class_get_devdata(dev); + + return _morse_delay_show(led_cdev, buf); +} + +static ssize_t morse_delay_store(struct class_device *dev, const char *buf, + size_t size) +{ + struct led_classdev *led_cdev = class_get_devdata(dev); + + return _morse_delay_store(led_cdev, buf, size); +} + +static ssize_t morse_msg_show(struct class_device *dev, char *buf) +{ + struct led_classdev *led_cdev = class_get_devdata(dev); + + return _morse_msg_show(led_cdev, buf); +} + +static ssize_t morse_msg_store(struct class_device *dev, const char *buf, + size_t size) +{ + struct led_classdev *led_cdev = class_get_devdata(dev); + + return _morse_msg_store(led_cdev, buf, size); +} + +static CLASS_DEVICE_ATTR(delay, 0644, morse_delay_show, morse_delay_store); +static CLASS_DEVICE_ATTR(message, 0644, morse_msg_show, morse_msg_store); + +#define led_device_create_file(leddev, attr) \ + class_device_create_file(leddev->class_dev, &class_device_attr_ ## attr) +#define led_device_remove_file(leddev, attr) \ + class_device_remove_file(leddev->class_dev, &class_device_attr_ ## attr) + +#endif + +static void morse_trig_activate(struct led_classdev *led_cdev) +{ + struct morse_trig_data *morse_data; + int rc; + + morse_data = kzalloc(sizeof(*morse_data), GFP_KERNEL); + if (!morse_data) + return; + + morse_data->delay = MORSE_DELAY_BASE; + init_timer(&morse_data->timer); + morse_data->timer.function = morse_timer_function; + morse_data->timer.data = (unsigned long)led_cdev; + + rc = led_device_create_file(led_cdev, delay); + if (rc) goto err; + + rc = led_device_create_file(led_cdev, message); + if (rc) goto err_delay; + + led_cdev->trigger_data = morse_data; + + return; + +err_delay: + led_device_remove_file(led_cdev, delay); +err: + kfree(morse_data); +} + +static void morse_trig_deactivate(struct led_classdev *led_cdev) +{ + struct morse_trig_data *morse_data = led_cdev->trigger_data; + + if (!morse_data) + return; + + led_device_remove_file(led_cdev, message); + led_device_remove_file(led_cdev, delay); + + del_timer_sync(&morse_data->timer); + if (morse_data->msg) + kfree(morse_data->msg); + + kfree(morse_data); +} + +static struct led_trigger morse_led_trigger = { + .name = "morse", + .activate = morse_trig_activate, + .deactivate = morse_trig_deactivate, +}; + +static int __init morse_trig_init(void) +{ + return led_trigger_register(&morse_led_trigger); +} + +static void __exit morse_trig_exit(void) +{ + led_trigger_unregister(&morse_led_trigger); +} + +module_init(morse_trig_init); +module_exit(morse_trig_exit); + +MODULE_AUTHOR("Gabor Juhos "); +MODULE_DESCRIPTION("Morse LED trigger"); +MODULE_LICENSE("GPL"); diff --git a/target/linux/generic/files/drivers/leds/ledtrig-netdev.c b/target/linux/generic/files/drivers/leds/ledtrig-netdev.c new file mode 100644 index 0000000..4a20d7c --- /dev/null +++ b/target/linux/generic/files/drivers/leds/ledtrig-netdev.c @@ -0,0 +1,438 @@ +/* + * LED Kernel Netdev Trigger + * + * Toggles the LED to reflect the link and traffic state of a named net device + * + * Copyright 2007 Oliver Jowett + * + * Derived from ledtrig-timer.c which is: + * Copyright 2005-2006 Openedhand Ltd. + * Author: Richard Purdie + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "leds.h" + +/* + * Configurable sysfs attributes: + * + * device_name - network device name to monitor + * + * interval - duration of LED blink, in milliseconds + * + * mode - either "none" (LED is off) or a space separated list of one or more of: + * link: LED's normal state reflects whether the link is up (has carrier) or not + * tx: LED blinks on transmitted data + * rx: LED blinks on receive data + * + * Some suggestions: + * + * Simple link status LED: + * $ echo netdev >someled/trigger + * $ echo eth0 >someled/device_name + * $ echo link >someled/mode + * + * Ethernet-style link/activity LED: + * $ echo netdev >someled/trigger + * $ echo eth0 >someled/device_name + * $ echo "link tx rx" >someled/mode + * + * Modem-style tx/rx LEDs: + * $ echo netdev >led1/trigger + * $ echo ppp0 >led1/device_name + * $ echo tx >led1/mode + * $ echo netdev >led2/trigger + * $ echo ppp0 >led2/device_name + * $ echo rx >led2/mode + * + */ + +#define MODE_LINK 1 +#define MODE_TX 2 +#define MODE_RX 4 + +struct led_netdev_data { + rwlock_t lock; + + struct timer_list timer; + struct notifier_block notifier; + + struct led_classdev *led_cdev; + struct net_device *net_dev; + + char device_name[IFNAMSIZ]; + unsigned interval; + unsigned mode; + unsigned link_up; + unsigned last_activity; +}; + +static void set_baseline_state(struct led_netdev_data *trigger_data) +{ + if ((trigger_data->mode & MODE_LINK) != 0 && trigger_data->link_up) + led_set_brightness(trigger_data->led_cdev, LED_FULL); + else + led_set_brightness(trigger_data->led_cdev, LED_OFF); + + if ((trigger_data->mode & (MODE_TX | MODE_RX)) != 0 && trigger_data->link_up) + mod_timer(&trigger_data->timer, jiffies + trigger_data->interval); + else + del_timer(&trigger_data->timer); +} + +static ssize_t led_device_name_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct led_netdev_data *trigger_data = led_cdev->trigger_data; + + read_lock(&trigger_data->lock); + sprintf(buf, "%s\n", trigger_data->device_name); + read_unlock(&trigger_data->lock); + + return strlen(buf) + 1; +} + +static ssize_t led_device_name_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct led_netdev_data *trigger_data = led_cdev->trigger_data; + + if (size < 0 || size >= IFNAMSIZ) + return -EINVAL; + + write_lock(&trigger_data->lock); + + strcpy(trigger_data->device_name, buf); + if (size > 0 && trigger_data->device_name[size-1] == '\n') + trigger_data->device_name[size-1] = 0; + + if (trigger_data->device_name[0] != 0) { + /* check for existing device to update from */ + trigger_data->net_dev = dev_get_by_name(&init_net, trigger_data->device_name); + if (trigger_data->net_dev != NULL) + trigger_data->link_up = (dev_get_flags(trigger_data->net_dev) & IFF_LOWER_UP) != 0; + set_baseline_state(trigger_data); /* updates LEDs, may start timers */ + } + + write_unlock(&trigger_data->lock); + return size; +} + +static DEVICE_ATTR(device_name, 0644, led_device_name_show, led_device_name_store); + +static ssize_t led_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct led_netdev_data *trigger_data = led_cdev->trigger_data; + + read_lock(&trigger_data->lock); + + if (trigger_data->mode == 0) { + strcpy(buf, "none\n"); + } else { + if (trigger_data->mode & MODE_LINK) + strcat(buf, "link "); + if (trigger_data->mode & MODE_TX) + strcat(buf, "tx "); + if (trigger_data->mode & MODE_RX) + strcat(buf, "rx "); + strcat(buf, "\n"); + } + + read_unlock(&trigger_data->lock); + + return strlen(buf)+1; +} + +static ssize_t led_mode_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct led_netdev_data *trigger_data = led_cdev->trigger_data; + char copybuf[128]; + int new_mode = -1; + char *p, *token; + + /* take a copy since we don't want to trash the inbound buffer when using strsep */ + strncpy(copybuf, buf, sizeof(copybuf)); + copybuf[sizeof(copybuf) - 1] = 0; + p = copybuf; + + while ((token = strsep(&p, " \t\n")) != NULL) { + if (!*token) + continue; + + if (new_mode == -1) + new_mode = 0; + + if (!strcmp(token, "none")) + new_mode = 0; + else if (!strcmp(token, "tx")) + new_mode |= MODE_TX; + else if (!strcmp(token, "rx")) + new_mode |= MODE_RX; + else if (!strcmp(token, "link")) + new_mode |= MODE_LINK; + else + return -EINVAL; + } + + if (new_mode == -1) + return -EINVAL; + + write_lock(&trigger_data->lock); + trigger_data->mode = new_mode; + set_baseline_state(trigger_data); + write_unlock(&trigger_data->lock); + + return size; +} + +static DEVICE_ATTR(mode, 0644, led_mode_show, led_mode_store); + +static ssize_t led_interval_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct led_netdev_data *trigger_data = led_cdev->trigger_data; + + read_lock(&trigger_data->lock); + sprintf(buf, "%u\n", jiffies_to_msecs(trigger_data->interval)); + read_unlock(&trigger_data->lock); + + return strlen(buf) + 1; +} + +static ssize_t led_interval_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct led_netdev_data *trigger_data = led_cdev->trigger_data; + int ret = -EINVAL; + char *after; + unsigned long value = simple_strtoul(buf, &after, 10); + size_t count = after - buf; + + if (isspace(*after)) + count++; + + /* impose some basic bounds on the timer interval */ + if (count == size && value >= 5 && value <= 10000) { + write_lock(&trigger_data->lock); + trigger_data->interval = msecs_to_jiffies(value); + set_baseline_state(trigger_data); /* resets timer */ + write_unlock(&trigger_data->lock); + ret = count; + } + + return ret; +} + +static DEVICE_ATTR(interval, 0644, led_interval_show, led_interval_store); + +static int netdev_trig_notify(struct notifier_block *nb, + unsigned long evt, + void *dv) +{ + struct net_device *dev = dv; + struct led_netdev_data *trigger_data = container_of(nb, struct led_netdev_data, notifier); + + if (evt != NETDEV_UP && evt != NETDEV_DOWN && evt != NETDEV_CHANGE && evt != NETDEV_REGISTER && evt != NETDEV_UNREGISTER) + return NOTIFY_DONE; + + write_lock(&trigger_data->lock); + + if (strcmp(dev->name, trigger_data->device_name)) + goto done; + + if (evt == NETDEV_REGISTER) { + if (trigger_data->net_dev != NULL) + dev_put(trigger_data->net_dev); + dev_hold(dev); + trigger_data->net_dev = dev; + trigger_data->link_up = 0; + goto done; + } + + if (evt == NETDEV_UNREGISTER && trigger_data->net_dev != NULL) { + dev_put(trigger_data->net_dev); + trigger_data->net_dev = NULL; + goto done; + } + + /* UP / DOWN / CHANGE */ + + trigger_data->link_up = (evt != NETDEV_DOWN && netif_carrier_ok(dev)); + set_baseline_state(trigger_data); + +done: + write_unlock(&trigger_data->lock); + return NOTIFY_DONE; +} + +/* here's the real work! */ +static void netdev_trig_timer(unsigned long arg) +{ + struct led_netdev_data *trigger_data = (struct led_netdev_data *)arg; + const struct net_device_stats *dev_stats; + unsigned new_activity; + + write_lock(&trigger_data->lock); + + if (!trigger_data->link_up || !trigger_data->net_dev || (trigger_data->mode & (MODE_TX | MODE_RX)) == 0) { + /* we don't need to do timer work, just reflect link state. */ + led_set_brightness(trigger_data->led_cdev, ((trigger_data->mode & MODE_LINK) != 0 && trigger_data->link_up) ? LED_FULL : LED_OFF); + goto no_restart; + } + + dev_stats = dev_get_stats(trigger_data->net_dev); + new_activity = + ((trigger_data->mode & MODE_TX) ? dev_stats->tx_packets : 0) + + ((trigger_data->mode & MODE_RX) ? dev_stats->rx_packets : 0); + + if (trigger_data->mode & MODE_LINK) { + /* base state is ON (link present) */ + /* if there's no link, we don't get this far and the LED is off */ + + /* OFF -> ON always */ + /* ON -> OFF on activity */ + if (trigger_data->led_cdev->brightness == LED_OFF) { + led_set_brightness(trigger_data->led_cdev, LED_FULL); + } else if (trigger_data->last_activity != new_activity) { + led_set_brightness(trigger_data->led_cdev, LED_OFF); + } + } else { + /* base state is OFF */ + /* ON -> OFF always */ + /* OFF -> ON on activity */ + if (trigger_data->led_cdev->brightness == LED_FULL) { + led_set_brightness(trigger_data->led_cdev, LED_OFF); + } else if (trigger_data->last_activity != new_activity) { + led_set_brightness(trigger_data->led_cdev, LED_FULL); + } + } + + trigger_data->last_activity = new_activity; + mod_timer(&trigger_data->timer, jiffies + trigger_data->interval); + +no_restart: + write_unlock(&trigger_data->lock); +} + +static void netdev_trig_activate(struct led_classdev *led_cdev) +{ + struct led_netdev_data *trigger_data; + int rc; + + trigger_data = kzalloc(sizeof(struct led_netdev_data), GFP_KERNEL); + if (!trigger_data) + return; + + rwlock_init(&trigger_data->lock); + + trigger_data->notifier.notifier_call = netdev_trig_notify; + trigger_data->notifier.priority = 10; + + setup_timer(&trigger_data->timer, netdev_trig_timer, (unsigned long) trigger_data); + + trigger_data->led_cdev = led_cdev; + trigger_data->net_dev = NULL; + trigger_data->device_name[0] = 0; + + trigger_data->mode = 0; + trigger_data->interval = msecs_to_jiffies(50); + trigger_data->link_up = 0; + trigger_data->last_activity = 0; + + led_cdev->trigger_data = trigger_data; + + rc = device_create_file(led_cdev->dev, &dev_attr_device_name); + if (rc) + goto err_out; + rc = device_create_file(led_cdev->dev, &dev_attr_mode); + if (rc) + goto err_out_device_name; + rc = device_create_file(led_cdev->dev, &dev_attr_interval); + if (rc) + goto err_out_mode; + + register_netdevice_notifier(&trigger_data->notifier); + return; + +err_out_mode: + device_remove_file(led_cdev->dev, &dev_attr_mode); +err_out_device_name: + device_remove_file(led_cdev->dev, &dev_attr_device_name); +err_out: + led_cdev->trigger_data = NULL; + kfree(trigger_data); +} + +static void netdev_trig_deactivate(struct led_classdev *led_cdev) +{ + struct led_netdev_data *trigger_data = led_cdev->trigger_data; + + if (trigger_data) { + unregister_netdevice_notifier(&trigger_data->notifier); + + device_remove_file(led_cdev->dev, &dev_attr_device_name); + device_remove_file(led_cdev->dev, &dev_attr_mode); + device_remove_file(led_cdev->dev, &dev_attr_interval); + + write_lock(&trigger_data->lock); + + if (trigger_data->net_dev) { + dev_put(trigger_data->net_dev); + trigger_data->net_dev = NULL; + } + + write_unlock(&trigger_data->lock); + + del_timer_sync(&trigger_data->timer); + + kfree(trigger_data); + } +} + +static struct led_trigger netdev_led_trigger = { + .name = "netdev", + .activate = netdev_trig_activate, + .deactivate = netdev_trig_deactivate, +}; + +static int __init netdev_trig_init(void) +{ + return led_trigger_register(&netdev_led_trigger); +} + +static void __exit netdev_trig_exit(void) +{ + led_trigger_unregister(&netdev_led_trigger); +} + +module_init(netdev_trig_init); +module_exit(netdev_trig_exit); + +MODULE_AUTHOR("Oliver Jowett "); +MODULE_DESCRIPTION("Netdev LED trigger"); +MODULE_LICENSE("GPL"); diff --git a/target/linux/generic/files/drivers/leds/ledtrig-usbdev.c b/target/linux/generic/files/drivers/leds/ledtrig-usbdev.c new file mode 100644 index 0000000..70b0e39 --- /dev/null +++ b/target/linux/generic/files/drivers/leds/ledtrig-usbdev.c @@ -0,0 +1,348 @@ +/* + * LED USB device Trigger + * + * Toggles the LED to reflect the presence and activity of an USB device + * Copyright (C) Gabor Juhos + * + * derived from ledtrig-netdev.c: + * Copyright 2007 Oliver Jowett + * + * ledtrig-netdev.c derived from ledtrig-timer.c: + * Copyright 2005-2006 Openedhand Ltd. + * Author: Richard Purdie + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "leds.h" + +#define DEV_BUS_ID_SIZE 32 + +/* + * Configurable sysfs attributes: + * + * device_name - name of the USB device to monitor + * activity_interval - duration of LED blink, in milliseconds + */ + +struct usbdev_trig_data { + rwlock_t lock; + + struct timer_list timer; + struct notifier_block notifier; + + struct led_classdev *led_cdev; + struct usb_device *usb_dev; + + char device_name[DEV_BUS_ID_SIZE]; + unsigned interval; + int last_urbnum; +}; + +static void usbdev_trig_update_state(struct usbdev_trig_data *td) +{ + if (td->usb_dev) + led_set_brightness(td->led_cdev, LED_FULL); + else + led_set_brightness(td->led_cdev, LED_OFF); + + if (td->interval && td->usb_dev) + mod_timer(&td->timer, jiffies + td->interval); + else + del_timer(&td->timer); +} + +static ssize_t usbdev_trig_name_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct usbdev_trig_data *td = led_cdev->trigger_data; + + read_lock(&td->lock); + sprintf(buf, "%s\n", td->device_name); + read_unlock(&td->lock); + + return strlen(buf) + 1; +} + +static ssize_t usbdev_trig_name_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct usbdev_trig_data *td = led_cdev->trigger_data; + + if (size < 0 || size >= DEV_BUS_ID_SIZE) + return -EINVAL; + + write_lock(&td->lock); + + strcpy(td->device_name, buf); + if (size > 0 && td->device_name[size - 1] == '\n') + td->device_name[size - 1] = 0; + + if (td->device_name[0] != 0) { + struct usb_device *usb_dev; + + /* check for existing device to update from */ + usb_dev = usb_find_device_by_name(td->device_name); + if (usb_dev) { + if (td->usb_dev) + usb_put_dev(td->usb_dev); + + td->usb_dev = usb_dev; + td->last_urbnum = atomic_read(&usb_dev->urbnum); + } + + /* updates LEDs, may start timers */ + usbdev_trig_update_state(td); + } + + write_unlock(&td->lock); + return size; +} + +static DEVICE_ATTR(device_name, 0644, usbdev_trig_name_show, + usbdev_trig_name_store); + +static ssize_t usbdev_trig_interval_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct usbdev_trig_data *td = led_cdev->trigger_data; + + read_lock(&td->lock); + sprintf(buf, "%u\n", jiffies_to_msecs(td->interval)); + read_unlock(&td->lock); + + return strlen(buf) + 1; +} + +static ssize_t usbdev_trig_interval_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct usbdev_trig_data *td = led_cdev->trigger_data; + int ret = -EINVAL; + char *after; + unsigned long value = simple_strtoul(buf, &after, 10); + size_t count = after - buf; + + if (*after && isspace(*after)) + count++; + + if (count == size && value <= 10000) { + write_lock(&td->lock); + td->interval = msecs_to_jiffies(value); + usbdev_trig_update_state(td); /* resets timer */ + write_unlock(&td->lock); + ret = count; + } + + return ret; +} + +static DEVICE_ATTR(activity_interval, 0644, usbdev_trig_interval_show, + usbdev_trig_interval_store); + +static int usbdev_trig_notify(struct notifier_block *nb, + unsigned long evt, + void *data) +{ + struct usb_device *usb_dev; + struct usbdev_trig_data *td; + + if (evt != USB_DEVICE_ADD && evt != USB_DEVICE_REMOVE) + return NOTIFY_DONE; + + usb_dev = data; + td = container_of(nb, struct usbdev_trig_data, notifier); + + write_lock(&td->lock); + + if (strcmp(dev_name(&usb_dev->dev), td->device_name)) + goto done; + + if (evt == USB_DEVICE_ADD) { + usb_get_dev(usb_dev); + if (td->usb_dev != NULL) + usb_put_dev(td->usb_dev); + td->usb_dev = usb_dev; + td->last_urbnum = atomic_read(&usb_dev->urbnum); + } else if (evt == USB_DEVICE_REMOVE) { + if (td->usb_dev != NULL) { + usb_put_dev(td->usb_dev); + td->usb_dev = NULL; + } + } + + usbdev_trig_update_state(td); + +done: + write_unlock(&td->lock); + return NOTIFY_DONE; +} + +/* here's the real work! */ +static void usbdev_trig_timer(unsigned long arg) +{ + struct usbdev_trig_data *td = (struct usbdev_trig_data *)arg; + int new_urbnum; + + write_lock(&td->lock); + + if (!td->usb_dev || td->interval == 0) { + /* + * we don't need to do timer work, just reflect device presence + */ + if (td->usb_dev) + led_set_brightness(td->led_cdev, LED_FULL); + else + led_set_brightness(td->led_cdev, LED_OFF); + + goto no_restart; + } + + if (td->interval) + new_urbnum = atomic_read(&td->usb_dev->urbnum); + else + new_urbnum = 0; + + if (td->usb_dev) { + /* + * Base state is ON (device is present). If there's no device, + * we don't get this far and the LED is off. + * OFF -> ON always + * ON -> OFF on activity + */ + if (td->led_cdev->brightness == LED_OFF) + led_set_brightness(td->led_cdev, LED_FULL); + else if (td->last_urbnum != new_urbnum) + led_set_brightness(td->led_cdev, LED_OFF); + } else { + /* + * base state is OFF + * ON -> OFF always + * OFF -> ON on activity + */ + if (td->led_cdev->brightness == LED_FULL) + led_set_brightness(td->led_cdev, LED_OFF); + else if (td->last_urbnum != new_urbnum) + led_set_brightness(td->led_cdev, LED_FULL); + } + + td->last_urbnum = new_urbnum; + mod_timer(&td->timer, jiffies + td->interval); + +no_restart: + write_unlock(&td->lock); +} + +static void usbdev_trig_activate(struct led_classdev *led_cdev) +{ + struct usbdev_trig_data *td; + int rc; + + td = kzalloc(sizeof(struct usbdev_trig_data), GFP_KERNEL); + if (!td) + return; + + rwlock_init(&td->lock); + + td->notifier.notifier_call = usbdev_trig_notify; + td->notifier.priority = 10; + + setup_timer(&td->timer, usbdev_trig_timer, (unsigned long) td); + + td->led_cdev = led_cdev; + td->interval = msecs_to_jiffies(50); + + led_cdev->trigger_data = td; + + rc = device_create_file(led_cdev->dev, &dev_attr_device_name); + if (rc) + goto err_out; + + rc = device_create_file(led_cdev->dev, &dev_attr_activity_interval); + if (rc) + goto err_out_device_name; + + usb_register_notify(&td->notifier); + return; + +err_out_device_name: + device_remove_file(led_cdev->dev, &dev_attr_device_name); +err_out: + led_cdev->trigger_data = NULL; + kfree(td); +} + +static void usbdev_trig_deactivate(struct led_classdev *led_cdev) +{ + struct usbdev_trig_data *td = led_cdev->trigger_data; + + if (td) { + usb_unregister_notify(&td->notifier); + + device_remove_file(led_cdev->dev, &dev_attr_device_name); + device_remove_file(led_cdev->dev, &dev_attr_activity_interval); + + write_lock(&td->lock); + + if (td->usb_dev) { + usb_put_dev(td->usb_dev); + td->usb_dev = NULL; + } + + write_unlock(&td->lock); + + del_timer_sync(&td->timer); + + kfree(td); + } +} + +static struct led_trigger usbdev_led_trigger = { + .name = "usbdev", + .activate = usbdev_trig_activate, + .deactivate = usbdev_trig_deactivate, +}; + +static int __init usbdev_trig_init(void) +{ + return led_trigger_register(&usbdev_led_trigger); +} + +static void __exit usbdev_trig_exit(void) +{ + led_trigger_unregister(&usbdev_led_trigger); +} + +module_init(usbdev_trig_init); +module_exit(usbdev_trig_exit); + +MODULE_AUTHOR("Gabor Juhos "); +MODULE_DESCRIPTION("USB device LED trigger"); +MODULE_LICENSE("GPL v2"); diff --git a/target/linux/generic/files/drivers/mtd/mtdsplit/Kconfig b/target/linux/generic/files/drivers/mtd/mtdsplit/Kconfig new file mode 100644 index 0000000..c4e3418 --- /dev/null +++ b/target/linux/generic/files/drivers/mtd/mtdsplit/Kconfig @@ -0,0 +1,51 @@ +config MTD_SPLIT + def_bool n + help + Generic MTD split support. + +config MTD_SPLIT_SUPPORT + def_bool MTD = y + +comment "Rootfs partition parsers" + +config MTD_SPLIT_SQUASHFS_ROOT + bool "Squashfs based root partition parser" + depends on MTD_SPLIT_SUPPORT + select MTD_SPLIT + default n + help + This provides a parsing function which allows to detect the + offset and size of the unused portion of a rootfs partition + containing a squashfs. + +comment "Firmware partition parsers" + +config MTD_SPLIT_SEAMA_FW + bool "Seama firmware parser" + depends on MTD_SPLIT_SUPPORT + select MTD_SPLIT + +config MTD_SPLIT_UIMAGE_FW + bool "uImage based firmware partition parser" + depends on MTD_SPLIT_SUPPORT + select MTD_SPLIT + +config MTD_SPLIT_FIT_FW + bool "FIT based firmware partition parser" + depends on MTD_SPLIT_SUPPORT + select MTD_SPLIT + +config MTD_SPLIT_LZMA_FW + bool "LZMA compressed kernel based firmware partition parser" + depends on MTD_SPLIT_SUPPORT + select MTD_SPLIT + +config MTD_SPLIT_TPLINK_FW + bool "TP-Link firmware parser" + depends on MTD_SPLIT_SUPPORT + select MTD_SPLIT + +config MTD_SPLIT_TRX_FW + bool "TRX image based firmware partition parser" + depends on MTD_SPLIT_SUPPORT + select MTD_SPLIT diff --git a/target/linux/generic/files/drivers/mtd/mtdsplit/Makefile b/target/linux/generic/files/drivers/mtd/mtdsplit/Makefile new file mode 100644 index 0000000..e09476b --- /dev/null +++ b/target/linux/generic/files/drivers/mtd/mtdsplit/Makefile @@ -0,0 +1,8 @@ +obj-$(CONFIG_MTD_SPLIT) += mtdsplit.o +obj-$(CONFIG_MTD_SPLIT_SEAMA_FW) += mtdsplit_seama.o +obj-$(CONFIG_MTD_SPLIT_SQUASHFS_ROOT) += mtdsplit_squashfs.o +obj-$(CONFIG_MTD_SPLIT_UIMAGE_FW) += mtdsplit_uimage.o +obj-$(CONFIG_MTD_SPLIT_FIT_FW) += mtdsplit_fit.o +obj-$(CONFIG_MTD_SPLIT_LZMA_FW) += mtdsplit_lzma.o +obj-$(CONFIG_MTD_SPLIT_TPLINK_FW) += mtdsplit_tplink.o +obj-$(CONFIG_MTD_SPLIT_TRX_FW) += mtdsplit_trx.o diff --git a/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit.c b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit.c new file mode 100644 index 0000000..162739f --- /dev/null +++ b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit.c @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2009-2013 Felix Fietkau + * Copyright (C) 2009-2013 Gabor Juhos + * Copyright (C) 2012 Jonas Gorski + * Copyright (C) 2013 Hauke Mehrtens + * + * 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. + * + */ + +#define pr_fmt(fmt) "mtdsplit: " fmt + +#include +#include +#include +#include +#include +#include +#include + +#include "mtdsplit.h" + +struct squashfs_super_block { + __le32 s_magic; + __le32 pad0[9]; + __le64 bytes_used; +}; + +int mtd_get_squashfs_len(struct mtd_info *master, + size_t offset, + size_t *squashfs_len) +{ + struct squashfs_super_block sb; + size_t retlen; + int err; + + err = mtd_read(master, offset, sizeof(sb), &retlen, (void *)&sb); + if (err || (retlen != sizeof(sb))) { + pr_alert("error occured while reading from \"%s\"\n", + master->name); + return -EIO; + } + + if (le32_to_cpu(sb.s_magic) != SQUASHFS_MAGIC) { + pr_alert("no squashfs found in \"%s\"\n", master->name); + return -EINVAL; + } + + retlen = le64_to_cpu(sb.bytes_used); + if (retlen <= 0) { + pr_alert("squashfs is empty in \"%s\"\n", master->name); + return -ENODEV; + } + + if (offset + retlen > master->size) { + pr_alert("squashfs has invalid size in \"%s\"\n", + master->name); + return -EINVAL; + } + + *squashfs_len = retlen; + return 0; +} +EXPORT_SYMBOL_GPL(mtd_get_squashfs_len); + +static ssize_t mtd_next_eb(struct mtd_info *mtd, size_t offset) +{ + return mtd_rounddown_to_eb(offset, mtd) + mtd->erasesize; +} + +int mtd_check_rootfs_magic(struct mtd_info *mtd, size_t offset) +{ + u32 magic; + size_t retlen; + int ret; + + ret = mtd_read(mtd, offset, sizeof(magic), &retlen, + (unsigned char *) &magic); + if (ret) + return ret; + + if (retlen != sizeof(magic)) + return -EIO; + + if (le32_to_cpu(magic) != SQUASHFS_MAGIC && + magic != 0x19852003) + return -EINVAL; + + return 0; +} +EXPORT_SYMBOL_GPL(mtd_check_rootfs_magic); + +int mtd_find_rootfs_from(struct mtd_info *mtd, + size_t from, + size_t limit, + size_t *ret_offset) +{ + size_t offset; + int err; + + for (offset = from; offset < limit; + offset = mtd_next_eb(mtd, offset)) { + err = mtd_check_rootfs_magic(mtd, offset); + if (err) + continue; + + *ret_offset = offset; + return 0; + } + + return -ENODEV; +} +EXPORT_SYMBOL_GPL(mtd_find_rootfs_from); + diff --git a/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit.h b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit.h new file mode 100644 index 0000000..7ee88b0 --- /dev/null +++ b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2009-2013 Felix Fietkau + * Copyright (C) 2009-2013 Gabor Juhos + * Copyright (C) 2012 Jonas Gorski + * Copyright (C) 2013 Hauke Mehrtens + * + * 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. + * + */ + +#ifndef _MTDSPLIT_H +#define _MTDSPLIT_H + +#define KERNEL_PART_NAME "kernel" +#define ROOTFS_PART_NAME "rootfs" + +#define ROOTFS_SPLIT_NAME "rootfs_data" + +#ifdef CONFIG_MTD_SPLIT +int mtd_get_squashfs_len(struct mtd_info *master, + size_t offset, + size_t *squashfs_len); + +int mtd_check_rootfs_magic(struct mtd_info *mtd, size_t offset); + +int mtd_find_rootfs_from(struct mtd_info *mtd, + size_t from, + size_t limit, + size_t *ret_offset); + +#else +static inline int mtd_get_squashfs_len(struct mtd_info *master, + size_t offset, + size_t *squashfs_len) +{ + return -ENODEV; +} + +static inline int mtd_check_rootfs_magic(struct mtd_info *mtd, size_t offset) +{ + return -EINVAL; +} + +static inline int mtd_find_rootfs_from(struct mtd_info *mtd, + size_t from, + size_t limit, + size_t *ret_offset) +{ + return -ENODEV; +} +#endif /* CONFIG_MTD_SPLIT */ + +#endif /* _MTDSPLIT_H */ diff --git a/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_fit.c b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_fit.c new file mode 100644 index 0000000..d1087f6 --- /dev/null +++ b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_fit.c @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2015 The Linux Foundation + * Copyright (C) 2014 Gabor Juhos + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "mtdsplit.h" + +struct fdt_header { + uint32_t magic; /* magic word FDT_MAGIC */ + uint32_t totalsize; /* total size of DT block */ + uint32_t off_dt_struct; /* offset to structure */ + uint32_t off_dt_strings; /* offset to strings */ + uint32_t off_mem_rsvmap; /* offset to memory reserve map */ + uint32_t version; /* format version */ + uint32_t last_comp_version; /* last compatible version */ + + /* version 2 fields below */ + uint32_t boot_cpuid_phys; /* Which physical CPU id we're + booting on */ + /* version 3 fields below */ + uint32_t size_dt_strings; /* size of the strings block */ + + /* version 17 fields below */ + uint32_t size_dt_struct; /* size of the structure block */ +}; + +static int +mtdsplit_fit_parse(struct mtd_info *mtd, struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + struct fdt_header hdr; + size_t hdr_len, retlen; + size_t offset; + size_t fit_offset, fit_size; + size_t rootfs_offset, rootfs_size; + struct mtd_partition *parts; + int ret; + + hdr_len = sizeof(struct fdt_header); + + /* Parse the MTD device & search for the FIT image location */ + for(offset = 0; offset < mtd->size; offset += mtd->erasesize) { + ret = mtd_read(mtd, 0, hdr_len, &retlen, (void*) &hdr); + if (ret) { + pr_err("read error in \"%s\" at offset 0x%llx\n", + mtd->name, (unsigned long long) offset); + return ret; + } + + if (retlen != hdr_len) { + pr_err("short read in \"%s\"\n", mtd->name); + return -EIO; + } + + /* Check the magic - see if this is a FIT image */ + if (be32_to_cpu(hdr.magic) != OF_DT_HEADER) { + pr_debug("no valid FIT image found in \"%s\" at offset %llx\n", + mtd->name, (unsigned long long) offset); + continue; + } + + /* We found a FIT image. Let's keep going */ + break; + } + + fit_offset = offset; + fit_size = be32_to_cpu(hdr.totalsize); + + if (fit_size == 0) { + pr_err("FIT image in \"%s\" at offset %llx has null size\n", + mtd->name, (unsigned long long) fit_offset); + return -ENODEV; + } + + /* Search for the rootfs partition after the FIT image */ + ret = mtd_find_rootfs_from(mtd, fit_offset + fit_size, + mtd->size, &rootfs_offset); + if (ret) { + pr_info("no rootfs found after FIT image in \"%s\"\n", + mtd->name); + return ret; + } + + rootfs_size = mtd->size - rootfs_offset; + + parts = kzalloc(2 * sizeof(*parts), GFP_KERNEL); + if (!parts) + return -ENOMEM; + + parts[0].name = KERNEL_PART_NAME; + parts[0].offset = fit_offset; + parts[0].size = mtd_rounddown_to_eb(fit_size, mtd) + mtd->erasesize; + + parts[1].name = ROOTFS_PART_NAME; + parts[1].offset = rootfs_offset; + parts[1].size = rootfs_size; + + *pparts = parts; + return 2; +} + +static struct mtd_part_parser uimage_parser = { + .owner = THIS_MODULE, + .name = "fit-fw", + .parse_fn = mtdsplit_fit_parse, + .type = MTD_PARSER_TYPE_FIRMWARE, +}; + +/************************************************** + * Init + **************************************************/ + +static int __init mtdsplit_fit_init(void) +{ + register_mtd_parser(&uimage_parser); + + return 0; +} + +module_init(mtdsplit_fit_init); diff --git a/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_lzma.c b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_lzma.c new file mode 100644 index 0000000..64dc7cb --- /dev/null +++ b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_lzma.c @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2014 Gabor Juhos + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "mtdsplit.h" + +#define LZMA_NR_PARTS 2 +#define LZMA_PROPERTIES_SIZE 5 + +struct lzma_header { + u8 props[LZMA_PROPERTIES_SIZE]; + u8 size_low[4]; + u8 size_high[4]; +}; + +static int mtdsplit_parse_lzma(struct mtd_info *master, + struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + struct lzma_header hdr; + size_t hdr_len, retlen; + size_t rootfs_offset; + u32 t; + struct mtd_partition *parts; + int err; + + hdr_len = sizeof(hdr); + err = mtd_read(master, 0, hdr_len, &retlen, (void *) &hdr); + if (err) + return err; + + if (retlen != hdr_len) + return -EIO; + + /* verify LZMA properties */ + if (hdr.props[0] >= (9 * 5 * 5)) + return -EINVAL; + + t = get_unaligned_le32(&hdr.props[1]); + if (!is_power_of_2(t)) + return -EINVAL; + + t = get_unaligned_le32(&hdr.size_high); + if (t) + return -EINVAL; + + err = mtd_find_rootfs_from(master, master->erasesize, + master->size, &rootfs_offset); + if (err) + return err; + + parts = kzalloc(LZMA_NR_PARTS * sizeof(*parts), GFP_KERNEL); + if (!parts) + return -ENOMEM; + + parts[0].name = KERNEL_PART_NAME; + parts[0].offset = 0; + parts[0].size = rootfs_offset; + + parts[1].name = ROOTFS_PART_NAME; + parts[1].offset = rootfs_offset; + parts[1].size = master->size - rootfs_offset; + + *pparts = parts; + return LZMA_NR_PARTS; +} + +static struct mtd_part_parser mtdsplit_lzma_parser = { + .owner = THIS_MODULE, + .name = "lzma-fw", + .parse_fn = mtdsplit_parse_lzma, + .type = MTD_PARSER_TYPE_FIRMWARE, +}; + +static int __init mtdsplit_lzma_init(void) +{ + register_mtd_parser(&mtdsplit_lzma_parser); + + return 0; +} + +subsys_initcall(mtdsplit_lzma_init); diff --git a/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_seama.c b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_seama.c new file mode 100644 index 0000000..6f21f8f --- /dev/null +++ b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_seama.c @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2013 Gabor Juhos + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "mtdsplit.h" + +#define SEAMA_MAGIC 0x5EA3A417 +#define SEAMA_NR_PARTS 2 +#define SEAMA_MIN_ROOTFS_OFFS 0x80000 /* 512KiB */ + +struct seama_header { + __be32 magic; /* should always be SEAMA_MAGIC. */ + __be16 reserved; /* reserved for */ + __be16 metasize; /* size of the META data */ + __be32 size; /* size of the image */ +}; + +static int mtdsplit_parse_seama(struct mtd_info *master, + struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + struct seama_header hdr; + size_t hdr_len, retlen, kernel_size; + size_t rootfs_offset; + struct mtd_partition *parts; + int err; + + hdr_len = sizeof(hdr); + err = mtd_read(master, 0, hdr_len, &retlen, (void *) &hdr); + if (err) + return err; + + if (retlen != hdr_len) + return -EIO; + + /* sanity checks */ + if (be32_to_cpu(hdr.magic) != SEAMA_MAGIC) + return -EINVAL; + + kernel_size = hdr_len + be32_to_cpu(hdr.size) + + be16_to_cpu(hdr.metasize); + if (kernel_size > master->size) + return -EINVAL; + + /* Find the rootfs after the kernel. */ + err = mtd_check_rootfs_magic(master, kernel_size); + if (!err) { + rootfs_offset = kernel_size; + } else { + /* + * The size in the header might cover the rootfs as well. + * Start the search from an arbitrary offset. + */ + err = mtd_find_rootfs_from(master, SEAMA_MIN_ROOTFS_OFFS, + master->size, &rootfs_offset); + if (err) + return err; + } + + parts = kzalloc(SEAMA_NR_PARTS * sizeof(*parts), GFP_KERNEL); + if (!parts) + return -ENOMEM; + + parts[0].name = KERNEL_PART_NAME; + parts[0].offset = 0; + parts[0].size = rootfs_offset; + + parts[1].name = ROOTFS_PART_NAME; + parts[1].offset = rootfs_offset; + parts[1].size = master->size - rootfs_offset; + + *pparts = parts; + return SEAMA_NR_PARTS; +} + +static struct mtd_part_parser mtdsplit_seama_parser = { + .owner = THIS_MODULE, + .name = "seama-fw", + .parse_fn = mtdsplit_parse_seama, + .type = MTD_PARSER_TYPE_FIRMWARE, +}; + +static int __init mtdsplit_seama_init(void) +{ + register_mtd_parser(&mtdsplit_seama_parser); + + return 0; +} + +subsys_initcall(mtdsplit_seama_init); diff --git a/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_squashfs.c b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_squashfs.c new file mode 100644 index 0000000..3d80e07 --- /dev/null +++ b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_squashfs.c @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2013 Felix Fietkau + * Copyright (C) 2013 Gabor Juhos + * + * 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. + * + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mtdsplit.h" + +static int +mtdsplit_parse_squashfs(struct mtd_info *master, + struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + struct mtd_partition *part; + struct mtd_info *parent_mtd; + size_t part_offset; + size_t squashfs_len; + int err; + + err = mtd_get_squashfs_len(master, 0, &squashfs_len); + if (err) + return err; + + parent_mtd = mtdpart_get_master(master); + part_offset = mtdpart_get_offset(master); + + part = kzalloc(sizeof(*part), GFP_KERNEL); + if (!part) { + pr_alert("unable to allocate memory for \"%s\" partition\n", + ROOTFS_SPLIT_NAME); + return -ENOMEM; + } + + part->name = ROOTFS_SPLIT_NAME; + part->offset = mtd_roundup_to_eb(part_offset + squashfs_len, + parent_mtd) - part_offset; + part->size = master->size - part->offset; + + *pparts = part; + return 1; +} + +static struct mtd_part_parser mtdsplit_squashfs_parser = { + .owner = THIS_MODULE, + .name = "squashfs-split", + .parse_fn = mtdsplit_parse_squashfs, + .type = MTD_PARSER_TYPE_ROOTFS, +}; + +static int __init mtdsplit_squashfs_init(void) +{ + register_mtd_parser(&mtdsplit_squashfs_parser); + + return 0; +} + +subsys_initcall(mtdsplit_squashfs_init); diff --git a/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_tplink.c b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_tplink.c new file mode 100644 index 0000000..00c2d39 --- /dev/null +++ b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_tplink.c @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2013 Gabor Juhos + * Copyright (C) 2014 Felix Fietkau + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "mtdsplit.h" + +#define TPLINK_NR_PARTS 2 +#define TPLINK_MIN_ROOTFS_OFFS 0x80000 /* 512KiB */ + +#define MD5SUM_LEN 16 + +struct fw_v1 { + char vendor_name[24]; + char fw_version[36]; + uint32_t hw_id; /* hardware id */ + uint32_t hw_rev; /* hardware revision */ + uint32_t unk1; + uint8_t md5sum1[MD5SUM_LEN]; + uint32_t unk2; + uint8_t md5sum2[MD5SUM_LEN]; + uint32_t unk3; + uint32_t kernel_la; /* kernel load address */ + uint32_t kernel_ep; /* kernel entry point */ + uint32_t fw_length; /* total length of the firmware */ + uint32_t kernel_ofs; /* kernel data offset */ + uint32_t kernel_len; /* kernel data length */ + uint32_t rootfs_ofs; /* rootfs data offset */ + uint32_t rootfs_len; /* rootfs data length */ + uint32_t boot_ofs; /* bootloader data offset */ + uint32_t boot_len; /* bootloader data length */ + uint8_t pad[360]; +} __attribute__ ((packed)); + +struct fw_v2 { + char fw_version[48]; /* 0x04: fw version string */ + uint32_t hw_id; /* 0x34: hardware id */ + uint32_t hw_rev; /* 0x38: FIXME: hardware revision? */ + uint32_t unk1; /* 0x3c: 0x00000000 */ + uint8_t md5sum1[MD5SUM_LEN]; /* 0x40 */ + uint32_t unk2; /* 0x50: 0x00000000 */ + uint8_t md5sum2[MD5SUM_LEN]; /* 0x54 */ + uint32_t unk3; /* 0x64: 0xffffffff */ + + uint32_t kernel_la; /* 0x68: kernel load address */ + uint32_t kernel_ep; /* 0x6c: kernel entry point */ + uint32_t fw_length; /* 0x70: total length of the image */ + uint32_t kernel_ofs; /* 0x74: kernel data offset */ + uint32_t kernel_len; /* 0x78: kernel data length */ + uint32_t rootfs_ofs; /* 0x7c: rootfs data offset */ + uint32_t rootfs_len; /* 0x80: rootfs data length */ + uint32_t boot_ofs; /* 0x84: FIXME: seems to be unused */ + uint32_t boot_len; /* 0x88: FIXME: seems to be unused */ + uint16_t unk4; /* 0x8c: 0x55aa */ + uint8_t sver_hi; /* 0x8e */ + uint8_t sver_lo; /* 0x8f */ + uint8_t unk5; /* 0x90: magic: 0xa5 */ + uint8_t ver_hi; /* 0x91 */ + uint8_t ver_mid; /* 0x92 */ + uint8_t ver_lo; /* 0x93 */ + uint8_t pad[364]; +} __attribute__ ((packed)); + +struct tplink_fw_header { + uint32_t version; + union { + struct fw_v1 v1; + struct fw_v2 v2; + }; +}; + +static int mtdsplit_parse_tplink(struct mtd_info *master, + struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + struct tplink_fw_header hdr; + size_t hdr_len, retlen, kernel_size; + size_t rootfs_offset; + struct mtd_partition *parts; + int err; + + hdr_len = sizeof(hdr); + err = mtd_read(master, 0, hdr_len, &retlen, (void *) &hdr); + if (err) + return err; + + if (retlen != hdr_len) + return -EIO; + + switch (le32_to_cpu(hdr.version)) { + case 1: + if (be32_to_cpu(hdr.v1.kernel_ofs) != sizeof(hdr)) + return -EINVAL; + + kernel_size = sizeof(hdr) + be32_to_cpu(hdr.v1.kernel_len); + break; + case 2: + case 3: + if (be32_to_cpu(hdr.v2.kernel_ofs) != sizeof(hdr)) + return -EINVAL; + + kernel_size = sizeof(hdr) + be32_to_cpu(hdr.v2.kernel_len); + break; + default: + return -EINVAL; + } + + if (kernel_size > master->size) + return -EINVAL; + + /* Find the rootfs after the kernel. */ + err = mtd_check_rootfs_magic(master, kernel_size); + if (!err) { + rootfs_offset = kernel_size; + } else { + /* + * The size in the header might cover the rootfs as well. + * Start the search from an arbitrary offset. + */ + err = mtd_find_rootfs_from(master, TPLINK_MIN_ROOTFS_OFFS, + master->size, &rootfs_offset); + if (err) + return err; + } + + parts = kzalloc(TPLINK_NR_PARTS * sizeof(*parts), GFP_KERNEL); + if (!parts) + return -ENOMEM; + + parts[0].name = KERNEL_PART_NAME; + parts[0].offset = 0; + parts[0].size = rootfs_offset; + + parts[1].name = ROOTFS_PART_NAME; + parts[1].offset = rootfs_offset; + parts[1].size = master->size - rootfs_offset; + + *pparts = parts; + return TPLINK_NR_PARTS; +} + +static struct mtd_part_parser mtdsplit_tplink_parser = { + .owner = THIS_MODULE, + .name = "tplink-fw", + .parse_fn = mtdsplit_parse_tplink, + .type = MTD_PARSER_TYPE_FIRMWARE, +}; + +static int __init mtdsplit_tplink_init(void) +{ + register_mtd_parser(&mtdsplit_tplink_parser); + + return 0; +} + +subsys_initcall(mtdsplit_tplink_init); diff --git a/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_trx.c b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_trx.c new file mode 100644 index 0000000..6efffce --- /dev/null +++ b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_trx.c @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2013 Gabor Juhos + * Copyright (C) 2014 Felix Fietkau + * + * 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. + * + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include + +#include "mtdsplit.h" + +#define TRX_MAGIC 0x30524448 /* "HDR0" */ + +struct trx_header { + __le32 magic; + __le32 len; + __le32 crc32; + __le32 flag_version; + __le32 offset[4]; +}; + +static int +read_trx_header(struct mtd_info *mtd, size_t offset, + struct trx_header *header) +{ + size_t header_len; + size_t retlen; + int ret; + + header_len = sizeof(*header); + ret = mtd_read(mtd, offset, header_len, &retlen, + (unsigned char *) header); + if (ret) { + pr_debug("read error in \"%s\"\n", mtd->name); + return ret; + } + + if (retlen != header_len) { + pr_debug("short read in \"%s\"\n", mtd->name); + return -EIO; + } + + return 0; +} + +static int +mtdsplit_parse_trx(struct mtd_info *master, + struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + struct mtd_partition *parts; + struct trx_header hdr; + int nr_parts; + size_t offset; + size_t trx_offset; + size_t trx_size = 0; + size_t rootfs_offset; + size_t rootfs_size = 0; + int ret; + + nr_parts = 2; + parts = kzalloc(nr_parts * sizeof(*parts), GFP_KERNEL); + if (!parts) + return -ENOMEM; + + /* find trx image on erase block boundaries */ + for (offset = 0; offset < master->size; offset += master->erasesize) { + trx_size = 0; + + ret = read_trx_header(master, offset, &hdr); + if (ret) + continue; + + if (hdr.magic != cpu_to_le32(TRX_MAGIC)) { + pr_debug("no valid trx header found in \"%s\" at offset %llx\n", + master->name, (unsigned long long) offset); + continue; + } + + trx_size = le32_to_cpu(hdr.len); + if ((offset + trx_size) > master->size) { + pr_debug("trx image exceeds MTD device \"%s\"\n", + master->name); + continue; + } + break; + } + + if (trx_size == 0) { + pr_debug("no trx header found in \"%s\"\n", master->name); + ret = -ENODEV; + goto err; + } + + trx_offset = offset + hdr.offset[0]; + rootfs_offset = offset + hdr.offset[1]; + rootfs_size = master->size - rootfs_offset; + trx_size = rootfs_offset - trx_offset; + + if (rootfs_size == 0) { + pr_debug("no rootfs found in \"%s\"\n", master->name); + ret = -ENODEV; + goto err; + } + + parts[0].name = KERNEL_PART_NAME; + parts[0].offset = trx_offset; + parts[0].size = trx_size; + + parts[1].name = ROOTFS_PART_NAME; + parts[1].offset = rootfs_offset; + parts[1].size = rootfs_size; + + *pparts = parts; + return nr_parts; + +err: + kfree(parts); + return ret; +} + +static struct mtd_part_parser trx_parser = { + .owner = THIS_MODULE, + .name = "trx-fw", + .parse_fn = mtdsplit_parse_trx, + .type = MTD_PARSER_TYPE_FIRMWARE, +}; + +static int __init mtdsplit_trx_init(void) +{ + register_mtd_parser(&trx_parser); + + return 0; +} + +module_init(mtdsplit_trx_init); diff --git a/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_uimage.c b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_uimage.c new file mode 100644 index 0000000..2602f98 --- /dev/null +++ b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_uimage.c @@ -0,0 +1,361 @@ +/* + * Copyright (C) 2013 Gabor Juhos + * + * 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. + * + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mtdsplit.h" + +/* + * uimage_header itself is only 64B, but it may be prepended with another data. + * Currently the biggest size is for Edimax devices: 20B + 64B + */ +#define MAX_HEADER_LEN 84 + +#define IH_MAGIC 0x27051956 /* Image Magic Number */ +#define IH_NMLEN 32 /* Image Name Length */ + +#define IH_OS_LINUX 5 /* Linux */ + +#define IH_TYPE_KERNEL 2 /* OS Kernel Image */ +#define IH_TYPE_FILESYSTEM 7 /* Filesystem Image */ + +/* + * Legacy format image header, + * all data in network byte order (aka natural aka bigendian). + */ +struct uimage_header { + uint32_t ih_magic; /* Image Header Magic Number */ + uint32_t ih_hcrc; /* Image Header CRC Checksum */ + uint32_t ih_time; /* Image Creation Timestamp */ + uint32_t ih_size; /* Image Data Size */ + uint32_t ih_load; /* Data Load Address */ + uint32_t ih_ep; /* Entry Point Address */ + uint32_t ih_dcrc; /* Image Data CRC Checksum */ + uint8_t ih_os; /* Operating System */ + uint8_t ih_arch; /* CPU architecture */ + uint8_t ih_type; /* Image Type */ + uint8_t ih_comp; /* Compression Type */ + uint8_t ih_name[IH_NMLEN]; /* Image Name */ +}; + +static int +read_uimage_header(struct mtd_info *mtd, size_t offset, u_char *buf, + size_t header_len) +{ + size_t retlen; + int ret; + + ret = mtd_read(mtd, offset, header_len, &retlen, buf); + if (ret) { + pr_debug("read error in \"%s\"\n", mtd->name); + return ret; + } + + if (retlen != header_len) { + pr_debug("short read in \"%s\"\n", mtd->name); + return -EIO; + } + + return 0; +} + +/** + * __mtdsplit_parse_uimage - scan partition and create kernel + rootfs parts + * + * @find_header: function to call for a block of data that will return offset + * of a valid uImage header if found + */ +static int __mtdsplit_parse_uimage(struct mtd_info *master, + struct mtd_partition **pparts, + struct mtd_part_parser_data *data, + ssize_t (*find_header)(u_char *buf, size_t len)) +{ + struct mtd_partition *parts; + u_char *buf; + int nr_parts; + size_t offset; + size_t uimage_offset; + size_t uimage_size = 0; + size_t rootfs_offset; + size_t rootfs_size = 0; + int uimage_part, rf_part; + int ret; + + nr_parts = 2; + parts = kzalloc(nr_parts * sizeof(*parts), GFP_KERNEL); + if (!parts) + return -ENOMEM; + + buf = vmalloc(MAX_HEADER_LEN); + if (!buf) { + ret = -ENOMEM; + goto err_free_parts; + } + + /* find uImage on erase block boundaries */ + for (offset = 0; offset < master->size; offset += master->erasesize) { + struct uimage_header *header; + + uimage_size = 0; + + ret = read_uimage_header(master, offset, buf, MAX_HEADER_LEN); + if (ret) + continue; + + ret = find_header(buf, MAX_HEADER_LEN); + if (ret < 0) { + pr_debug("no valid uImage found in \"%s\" at offset %llx\n", + master->name, (unsigned long long) offset); + continue; + } + header = (struct uimage_header *)(buf + ret); + + uimage_size = sizeof(*header) + be32_to_cpu(header->ih_size); + if ((offset + uimage_size) > master->size) { + pr_debug("uImage exceeds MTD device \"%s\"\n", + master->name); + continue; + } + break; + } + + if (uimage_size == 0) { + pr_debug("no uImage found in \"%s\"\n", master->name); + ret = -ENODEV; + goto err_free_buf; + } + + uimage_offset = offset; + + if (uimage_offset == 0) { + uimage_part = 0; + rf_part = 1; + + /* find the roots after the uImage */ + ret = mtd_find_rootfs_from(master, + uimage_offset + uimage_size, + master->size, + &rootfs_offset); + if (ret) { + pr_debug("no rootfs after uImage in \"%s\"\n", + master->name); + goto err_free_buf; + } + + rootfs_size = master->size - rootfs_offset; + uimage_size = rootfs_offset - uimage_offset; + } else { + rf_part = 0; + uimage_part = 1; + + /* check rootfs presence at offset 0 */ + ret = mtd_check_rootfs_magic(master, 0); + if (ret) { + pr_debug("no rootfs before uImage in \"%s\"\n", + master->name); + goto err_free_buf; + } + + rootfs_offset = 0; + rootfs_size = uimage_offset; + } + + if (rootfs_size == 0) { + pr_debug("no rootfs found in \"%s\"\n", master->name); + ret = -ENODEV; + goto err_free_buf; + } + + parts[uimage_part].name = KERNEL_PART_NAME; + parts[uimage_part].offset = uimage_offset; + parts[uimage_part].size = uimage_size; + + parts[rf_part].name = ROOTFS_PART_NAME; + parts[rf_part].offset = rootfs_offset; + parts[rf_part].size = rootfs_size; + + vfree(buf); + + *pparts = parts; + return nr_parts; + +err_free_buf: + vfree(buf); + +err_free_parts: + kfree(parts); + return ret; +} + +static ssize_t uimage_verify_default(u_char *buf, size_t len) +{ + struct uimage_header *header = (struct uimage_header *)buf; + + /* default sanity checks */ + if (be32_to_cpu(header->ih_magic) != IH_MAGIC) { + pr_debug("invalid uImage magic: %08x\n", + be32_to_cpu(header->ih_magic)); + return -EINVAL; + } + + if (header->ih_os != IH_OS_LINUX) { + pr_debug("invalid uImage OS: %08x\n", + be32_to_cpu(header->ih_os)); + return -EINVAL; + } + + if (header->ih_type != IH_TYPE_KERNEL) { + pr_debug("invalid uImage type: %08x\n", + be32_to_cpu(header->ih_type)); + return -EINVAL; + } + + return 0; +} + +static int +mtdsplit_uimage_parse_generic(struct mtd_info *master, + struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + return __mtdsplit_parse_uimage(master, pparts, data, + uimage_verify_default); +} + +static struct mtd_part_parser uimage_generic_parser = { + .owner = THIS_MODULE, + .name = "uimage-fw", + .parse_fn = mtdsplit_uimage_parse_generic, + .type = MTD_PARSER_TYPE_FIRMWARE, +}; + +#define FW_MAGIC_WNR2000V3 0x32303033 +#define FW_MAGIC_WNR2000V4 0x32303034 +#define FW_MAGIC_WNR2200 0x32323030 +#define FW_MAGIC_WNR612V2 0x32303631 +#define FW_MAGIC_WNR1000V2 0x31303031 +#define FW_MAGIC_WNR1000V2_VC 0x31303030 +#define FW_MAGIC_WNDR3700 0x33373030 +#define FW_MAGIC_WNDR3700V2 0x33373031 + +static ssize_t uimage_verify_wndr3700(u_char *buf, size_t len) +{ + struct uimage_header *header = (struct uimage_header *)buf; + uint8_t expected_type = IH_TYPE_FILESYSTEM; + + switch be32_to_cpu(header->ih_magic) { + case FW_MAGIC_WNR612V2: + case FW_MAGIC_WNR1000V2: + case FW_MAGIC_WNR1000V2_VC: + case FW_MAGIC_WNR2000V3: + case FW_MAGIC_WNR2200: + case FW_MAGIC_WNDR3700: + case FW_MAGIC_WNDR3700V2: + break; + case FW_MAGIC_WNR2000V4: + expected_type = IH_TYPE_KERNEL; + break; + default: + return -EINVAL; + } + + if (header->ih_os != IH_OS_LINUX || + header->ih_type != expected_type) + return -EINVAL; + + return 0; +} + +static int +mtdsplit_uimage_parse_netgear(struct mtd_info *master, + struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + return __mtdsplit_parse_uimage(master, pparts, data, + uimage_verify_wndr3700); +} + +static struct mtd_part_parser uimage_netgear_parser = { + .owner = THIS_MODULE, + .name = "netgear-fw", + .parse_fn = mtdsplit_uimage_parse_netgear, + .type = MTD_PARSER_TYPE_FIRMWARE, +}; + +/************************************************** + * Edimax + **************************************************/ + +#define FW_EDIMAX_OFFSET 20 +#define FW_MAGIC_EDIMAX 0x43535953 + +static ssize_t uimage_find_edimax(u_char *buf, size_t len) +{ + struct uimage_header *header; + + if (len < FW_EDIMAX_OFFSET + sizeof(*header)) { + pr_err("Buffer too small for checking Edimax header\n"); + return -ENOSPC; + } + + header = (struct uimage_header *)(buf + FW_EDIMAX_OFFSET); + + switch be32_to_cpu(header->ih_magic) { + case FW_MAGIC_EDIMAX: + break; + default: + return -EINVAL; + } + + if (header->ih_os != IH_OS_LINUX || + header->ih_type != IH_TYPE_FILESYSTEM) + return -EINVAL; + + return FW_EDIMAX_OFFSET; +} + +static int +mtdsplit_uimage_parse_edimax(struct mtd_info *master, + struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + return __mtdsplit_parse_uimage(master, pparts, data, + uimage_find_edimax); +} + +static struct mtd_part_parser uimage_edimax_parser = { + .owner = THIS_MODULE, + .name = "edimax-fw", + .parse_fn = mtdsplit_uimage_parse_edimax, + .type = MTD_PARSER_TYPE_FIRMWARE, +}; + +/************************************************** + * Init + **************************************************/ + +static int __init mtdsplit_uimage_init(void) +{ + register_mtd_parser(&uimage_generic_parser); + register_mtd_parser(&uimage_netgear_parser); + register_mtd_parser(&uimage_edimax_parser); + + return 0; +} + +module_init(mtdsplit_uimage_init); diff --git a/target/linux/generic/files/drivers/mtd/myloader.c b/target/linux/generic/files/drivers/mtd/myloader.c new file mode 100644 index 0000000..cd57369 --- /dev/null +++ b/target/linux/generic/files/drivers/mtd/myloader.c @@ -0,0 +1,182 @@ +/* + * Parse MyLoader-style flash partition tables and produce a Linux partition + * array to match. + * + * Copyright (C) 2007-2009 Gabor Juhos + * + * This file was based on drivers/mtd/redboot.c + * Author: Red Hat, Inc. - David Woodhouse + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BLOCK_LEN_MIN 0x10000 +#define PART_NAME_LEN 32 + +struct part_data { + struct mylo_partition_table tab; + char names[MYLO_MAX_PARTITIONS][PART_NAME_LEN]; +}; + +static int myloader_parse_partitions(struct mtd_info *master, + struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + struct part_data *buf; + struct mylo_partition_table *tab; + struct mylo_partition *part; + struct mtd_partition *mtd_parts; + struct mtd_partition *mtd_part; + int num_parts; + int ret, i; + size_t retlen; + char *names; + unsigned long offset; + unsigned long blocklen; + + buf = vmalloc(sizeof(*buf)); + if (!buf) { + return -ENOMEM; + goto out; + } + tab = &buf->tab; + + blocklen = master->erasesize; + if (blocklen < BLOCK_LEN_MIN) + blocklen = BLOCK_LEN_MIN; + + offset = blocklen; + + /* Find the partition table */ + for (i = 0; i < 4; i++, offset += blocklen) { + printk(KERN_DEBUG "%s: searching for MyLoader partition table" + " at offset 0x%lx\n", master->name, offset); + + ret = mtd_read(master, offset, sizeof(*buf), &retlen, + (void *)buf); + if (ret) + goto out_free_buf; + + if (retlen != sizeof(*buf)) { + ret = -EIO; + goto out_free_buf; + } + + /* Check for Partition Table magic number */ + if (tab->magic == le32_to_cpu(MYLO_MAGIC_PARTITIONS)) + break; + + } + + if (tab->magic != le32_to_cpu(MYLO_MAGIC_PARTITIONS)) { + printk(KERN_DEBUG "%s: no MyLoader partition table found\n", + master->name); + ret = 0; + goto out_free_buf; + } + + /* The MyLoader and the Partition Table is always present */ + num_parts = 2; + + /* Detect number of used partitions */ + for (i = 0; i < MYLO_MAX_PARTITIONS; i++) { + part = &tab->partitions[i]; + + if (le16_to_cpu(part->type) == PARTITION_TYPE_FREE) + continue; + + num_parts++; + } + + mtd_parts = kzalloc((num_parts * sizeof(*mtd_part) + + num_parts * PART_NAME_LEN), GFP_KERNEL); + + if (!mtd_parts) { + ret = -ENOMEM; + goto out_free_buf; + } + + mtd_part = mtd_parts; + names = (char *)&mtd_parts[num_parts]; + + strncpy(names, "myloader", PART_NAME_LEN); + mtd_part->name = names; + mtd_part->offset = 0; + mtd_part->size = offset; + mtd_part->mask_flags = MTD_WRITEABLE; + mtd_part++; + names += PART_NAME_LEN; + + strncpy(names, "partition_table", PART_NAME_LEN); + mtd_part->name = names; + mtd_part->offset = offset; + mtd_part->size = blocklen; + mtd_part->mask_flags = MTD_WRITEABLE; + mtd_part++; + names += PART_NAME_LEN; + + for (i = 0; i < MYLO_MAX_PARTITIONS; i++) { + part = &tab->partitions[i]; + + if (le16_to_cpu(part->type) == PARTITION_TYPE_FREE) + continue; + + if ((buf->names[i][0]) && (buf->names[i][0] != '\xff')) + strncpy(names, buf->names[i], PART_NAME_LEN); + else + snprintf(names, PART_NAME_LEN, "partition%d", i); + + mtd_part->offset = le32_to_cpu(part->addr); + mtd_part->size = le32_to_cpu(part->size); + mtd_part->name = names; + mtd_part++; + names += PART_NAME_LEN; + } + + *pparts = mtd_parts; + ret = num_parts; + + out_free_buf: + vfree(buf); + out: + return ret; +} + +static struct mtd_part_parser myloader_mtd_parser = { + .owner = THIS_MODULE, + .parse_fn = myloader_parse_partitions, + .name = "MyLoader", +}; + +static int __init myloader_mtd_parser_init(void) +{ + register_mtd_parser(&myloader_mtd_parser); + + return 0; +} + +static void __exit myloader_mtd_parser_exit(void) +{ + deregister_mtd_parser(&myloader_mtd_parser); +} + +module_init(myloader_mtd_parser_init); +module_exit(myloader_mtd_parser_exit); + +MODULE_AUTHOR("Gabor Juhos "); +MODULE_DESCRIPTION("Parsing code for MyLoader partition tables"); +MODULE_LICENSE("GPL v2"); diff --git a/target/linux/generic/files/drivers/net/phy/adm6996.c b/target/linux/generic/files/drivers/net/phy/adm6996.c new file mode 100644 index 0000000..bf5ed15 --- /dev/null +++ b/target/linux/generic/files/drivers/net/phy/adm6996.c @@ -0,0 +1,1204 @@ +/* + * ADM6996 switch driver + * + * swconfig interface based on ar8216.c + * + * Copyright (c) 2008 Felix Fietkau + * VLAN support Copyright (c) 2010, 2011 Peter Lebbing + * Copyright (c) 2013 Hauke Mehrtens + * Copyright (c) 2014 Matti Laakso + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License v2 as published by the + * Free Software Foundation + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +/*#define DEBUG 1*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "adm6996.h" + +MODULE_DESCRIPTION("Infineon ADM6996 Switch"); +MODULE_AUTHOR("Felix Fietkau, Peter Lebbing "); +MODULE_LICENSE("GPL"); + +static const char * const adm6996_model_name[] = +{ + NULL, + "ADM6996FC", + "ADM6996M", + "ADM6996L" +}; + +struct adm6996_mib_desc { + unsigned int offset; + const char *name; +}; + +struct adm6996_priv { + struct switch_dev dev; + void *priv; + + u8 eecs; + u8 eesk; + u8 eedi; + u8 eerc; + + enum adm6996_model model; + + bool enable_vlan; + bool vlan_enabled; /* Current hardware state */ + +#ifdef DEBUG + u16 addr; /* Debugging: register address to operate on */ +#endif + + u16 pvid[ADM_NUM_PORTS]; /* Primary VLAN ID */ + u8 tagged_ports; + + u16 vlan_id[ADM_NUM_VLANS]; + u8 vlan_table[ADM_NUM_VLANS]; /* bitmap, 1 = port is member */ + u8 vlan_tagged[ADM_NUM_VLANS]; /* bitmap, 1 = tagged member */ + + struct mutex mib_lock; + char buf[2048]; + + struct mutex reg_mutex; + + /* use abstraction for regops, we want to add gpio support in the future */ + u16 (*read)(struct adm6996_priv *priv, enum admreg reg); + void (*write)(struct adm6996_priv *priv, enum admreg reg, u16 val); +}; + +#define to_adm(_dev) container_of(_dev, struct adm6996_priv, dev) +#define phy_to_adm(_phy) ((struct adm6996_priv *) (_phy)->priv) + +#define MIB_DESC(_o, _n) \ + { \ + .offset = (_o), \ + .name = (_n), \ + } + +static const struct adm6996_mib_desc adm6996_mibs[] = { + MIB_DESC(ADM_CL0, "RxPacket"), + MIB_DESC(ADM_CL6, "RxByte"), + MIB_DESC(ADM_CL12, "TxPacket"), + MIB_DESC(ADM_CL18, "TxByte"), + MIB_DESC(ADM_CL24, "Collision"), + MIB_DESC(ADM_CL30, "Error"), +}; + +static inline u16 +r16(struct adm6996_priv *priv, enum admreg reg) +{ + return priv->read(priv, reg); +} + +static inline void +w16(struct adm6996_priv *priv, enum admreg reg, u16 val) +{ + priv->write(priv, reg, val); +} + +/* Minimum timing constants */ +#define EECK_EDGE_TIME 3 /* 3us - max(adm 2.5us, 93c 1us) */ +#define EEDI_SETUP_TIME 1 /* 1us - max(adm 10ns, 93c 400ns) */ +#define EECS_SETUP_TIME 1 /* 1us - max(adm no, 93c 200ns) */ + +static void adm6996_gpio_write(struct adm6996_priv *priv, int cs, char *buf, unsigned int bits) +{ + int i, len = (bits + 7) / 8; + u8 mask; + + gpio_set_value(priv->eecs, cs); + udelay(EECK_EDGE_TIME); + + /* Byte assemble from MSB to LSB */ + for (i = 0; i < len; i++) { + /* Bit bang from MSB to LSB */ + for (mask = 0x80; mask && bits > 0; mask >>= 1, bits --) { + /* Clock low */ + gpio_set_value(priv->eesk, 0); + udelay(EECK_EDGE_TIME); + + /* Output on rising edge */ + gpio_set_value(priv->eedi, (mask & buf[i])); + udelay(EEDI_SETUP_TIME); + + /* Clock high */ + gpio_set_value(priv->eesk, 1); + udelay(EECK_EDGE_TIME); + } + } + + /* Clock low */ + gpio_set_value(priv->eesk, 0); + udelay(EECK_EDGE_TIME); + + if (cs) + gpio_set_value(priv->eecs, 0); +} + +static void adm6996_gpio_read(struct adm6996_priv *priv, int cs, char *buf, unsigned int bits) +{ + int i, len = (bits + 7) / 8; + u8 mask; + + gpio_set_value(priv->eecs, cs); + udelay(EECK_EDGE_TIME); + + /* Byte assemble from MSB to LSB */ + for (i = 0; i < len; i++) { + u8 byte; + + /* Bit bang from MSB to LSB */ + for (mask = 0x80, byte = 0; mask && bits > 0; mask >>= 1, bits --) { + u8 gp; + + /* Clock low */ + gpio_set_value(priv->eesk, 0); + udelay(EECK_EDGE_TIME); + + /* Input on rising edge */ + gp = gpio_get_value(priv->eedi); + if (gp) + byte |= mask; + + /* Clock high */ + gpio_set_value(priv->eesk, 1); + udelay(EECK_EDGE_TIME); + } + + *buf++ = byte; + } + + /* Clock low */ + gpio_set_value(priv->eesk, 0); + udelay(EECK_EDGE_TIME); + + if (cs) + gpio_set_value(priv->eecs, 0); +} + +/* Advance clock(s) */ +static void adm6996_gpio_adclk(struct adm6996_priv *priv, int clocks) +{ + int i; + for (i = 0; i < clocks; i++) { + /* Clock high */ + gpio_set_value(priv->eesk, 1); + udelay(EECK_EDGE_TIME); + + /* Clock low */ + gpio_set_value(priv->eesk, 0); + udelay(EECK_EDGE_TIME); + } +} + +static u16 +adm6996_read_gpio_reg(struct adm6996_priv *priv, enum admreg reg) +{ + /* cmd: 01 10 T DD R RRRRRR */ + u8 bits[6] = { + 0xFF, 0xFF, 0xFF, 0xFF, + (0x06 << 4) | ((0 & 0x01) << 3 | (reg&64)>>6), + ((reg&63)<<2) + }; + + u8 rbits[4]; + + /* Enable GPIO outputs with all pins to 0 */ + gpio_direction_output(priv->eecs, 0); + gpio_direction_output(priv->eesk, 0); + gpio_direction_output(priv->eedi, 0); + + adm6996_gpio_write(priv, 0, bits, 46); + gpio_direction_input(priv->eedi); + adm6996_gpio_adclk(priv, 2); + adm6996_gpio_read(priv, 0, rbits, 32); + + /* Extra clock(s) required per datasheet */ + adm6996_gpio_adclk(priv, 2); + + /* Disable GPIO outputs */ + gpio_direction_input(priv->eecs); + gpio_direction_input(priv->eesk); + + /* EEPROM has 16-bit registers, but pumps out two registers in one request */ + return (reg & 0x01 ? (rbits[0]<<8) | rbits[1] : (rbits[2]<<8) | (rbits[3])); +} + +/* Write chip configuration register */ +/* Follow 93c66 timing and chip's min EEPROM timing requirement */ +static void +adm6996_write_gpio_reg(struct adm6996_priv *priv, enum admreg reg, u16 val) +{ + /* cmd(27bits): sb(1) + opc(01) + addr(bbbbbbbb) + data(bbbbbbbbbbbbbbbb) */ + u8 bits[4] = { + (0x05 << 5) | (reg >> 3), + (reg << 5) | (u8)(val >> 11), + (u8)(val >> 3), + (u8)(val << 5) + }; + + /* Enable GPIO outputs with all pins to 0 */ + gpio_direction_output(priv->eecs, 0); + gpio_direction_output(priv->eesk, 0); + gpio_direction_output(priv->eedi, 0); + + /* Write cmd. Total 27 bits */ + adm6996_gpio_write(priv, 1, bits, 27); + + /* Extra clock(s) required per datasheet */ + adm6996_gpio_adclk(priv, 2); + + /* Disable GPIO outputs */ + gpio_direction_input(priv->eecs); + gpio_direction_input(priv->eesk); + gpio_direction_input(priv->eedi); +} + +static u16 +adm6996_read_mii_reg(struct adm6996_priv *priv, enum admreg reg) +{ + struct phy_device *phydev = priv->priv; + struct mii_bus *bus = phydev->bus; + + return bus->read(bus, PHYADDR(reg)); +} + +static void +adm6996_write_mii_reg(struct adm6996_priv *priv, enum admreg reg, u16 val) +{ + struct phy_device *phydev = priv->priv; + struct mii_bus *bus = phydev->bus; + + bus->write(bus, PHYADDR(reg), val); +} + +static int +adm6996_set_enable_vlan(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + struct adm6996_priv *priv = to_adm(dev); + + if (val->value.i > 1) + return -EINVAL; + + priv->enable_vlan = val->value.i; + + return 0; +}; + +static int +adm6996_get_enable_vlan(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + struct adm6996_priv *priv = to_adm(dev); + + val->value.i = priv->enable_vlan; + + return 0; +}; + +#ifdef DEBUG + +static int +adm6996_set_addr(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + struct adm6996_priv *priv = to_adm(dev); + + if (val->value.i > 1023) + return -EINVAL; + + priv->addr = val->value.i; + + return 0; +}; + +static int +adm6996_get_addr(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + struct adm6996_priv *priv = to_adm(dev); + + val->value.i = priv->addr; + + return 0; +}; + +static int +adm6996_set_data(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + struct adm6996_priv *priv = to_adm(dev); + + if (val->value.i > 65535) + return -EINVAL; + + w16(priv, priv->addr, val->value.i); + + return 0; +}; + +static int +adm6996_get_data(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + struct adm6996_priv *priv = to_adm(dev); + + val->value.i = r16(priv, priv->addr); + + return 0; +}; + +#endif /* def DEBUG */ + +static int +adm6996_set_pvid(struct switch_dev *dev, int port, int vlan) +{ + struct adm6996_priv *priv = to_adm(dev); + + pr_devel("set_pvid port %d vlan %d\n", port, vlan); + + if (vlan > ADM_VLAN_MAX_ID) + return -EINVAL; + + priv->pvid[port] = vlan; + + return 0; +} + +static int +adm6996_get_pvid(struct switch_dev *dev, int port, int *vlan) +{ + struct adm6996_priv *priv = to_adm(dev); + + pr_devel("get_pvid port %d\n", port); + *vlan = priv->pvid[port]; + + return 0; +} + +static int +adm6996_set_vid(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + struct adm6996_priv *priv = to_adm(dev); + + pr_devel("set_vid port %d vid %d\n", val->port_vlan, val->value.i); + + if (val->value.i > ADM_VLAN_MAX_ID) + return -EINVAL; + + priv->vlan_id[val->port_vlan] = val->value.i; + + return 0; +}; + +static int +adm6996_get_vid(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + struct adm6996_priv *priv = to_adm(dev); + + pr_devel("get_vid port %d\n", val->port_vlan); + + val->value.i = priv->vlan_id[val->port_vlan]; + + return 0; +}; + +static int +adm6996_get_ports(struct switch_dev *dev, struct switch_val *val) +{ + struct adm6996_priv *priv = to_adm(dev); + u8 ports = priv->vlan_table[val->port_vlan]; + u8 tagged = priv->vlan_tagged[val->port_vlan]; + int i; + + pr_devel("get_ports port_vlan %d\n", val->port_vlan); + + val->len = 0; + + for (i = 0; i < ADM_NUM_PORTS; i++) { + struct switch_port *p; + + if (!(ports & (1 << i))) + continue; + + p = &val->value.ports[val->len++]; + p->id = i; + if (tagged & (1 << i)) + p->flags = (1 << SWITCH_PORT_FLAG_TAGGED); + else + p->flags = 0; + } + + return 0; +}; + +static int +adm6996_set_ports(struct switch_dev *dev, struct switch_val *val) +{ + struct adm6996_priv *priv = to_adm(dev); + u8 *ports = &priv->vlan_table[val->port_vlan]; + u8 *tagged = &priv->vlan_tagged[val->port_vlan]; + int i; + + pr_devel("set_ports port_vlan %d ports", val->port_vlan); + + *ports = 0; + *tagged = 0; + + for (i = 0; i < val->len; i++) { + struct switch_port *p = &val->value.ports[i]; + +#ifdef DEBUG + pr_cont(" %d%s", p->id, + ((p->flags & (1 << SWITCH_PORT_FLAG_TAGGED)) ? "T" : + "")); +#endif + + if (p->flags & (1 << SWITCH_PORT_FLAG_TAGGED)) { + *tagged |= (1 << p->id); + priv->tagged_ports |= (1 << p->id); + } + + *ports |= (1 << p->id); + } + +#ifdef DEBUG + pr_cont("\n"); +#endif + + return 0; +}; + +/* + * Precondition: reg_mutex must be held + */ +static void +adm6996_enable_vlan(struct adm6996_priv *priv) +{ + u16 reg; + + reg = r16(priv, ADM_OTBE_P2_PVID); + reg &= ~(ADM_OTBE_MASK); + w16(priv, ADM_OTBE_P2_PVID, reg); + reg = r16(priv, ADM_IFNTE); + reg &= ~(ADM_IFNTE_MASK); + w16(priv, ADM_IFNTE, reg); + reg = r16(priv, ADM_VID_CHECK); + reg |= ADM_VID_CHECK_MASK; + w16(priv, ADM_VID_CHECK, reg); + reg = r16(priv, ADM_SYSC0); + reg |= ADM_NTTE; + reg &= ~(ADM_RVID1); + w16(priv, ADM_SYSC0, reg); + reg = r16(priv, ADM_SYSC3); + reg |= ADM_TBV; + w16(priv, ADM_SYSC3, reg); +} + +static void +adm6996_enable_vlan_6996l(struct adm6996_priv *priv) +{ + u16 reg; + + reg = r16(priv, ADM_SYSC3); + reg |= ADM_TBV; + reg |= ADM_MAC_CLONE; + w16(priv, ADM_SYSC3, reg); +} + +/* + * Disable VLANs + * + * Sets VLAN mapping for port-based VLAN with all ports connected to + * eachother (this is also the power-on default). + * + * Precondition: reg_mutex must be held + */ +static void +adm6996_disable_vlan(struct adm6996_priv *priv) +{ + u16 reg; + int i; + + for (i = 0; i < ADM_NUM_VLANS; i++) { + reg = ADM_VLAN_FILT_MEMBER_MASK; + w16(priv, ADM_VLAN_FILT_L(i), reg); + reg = ADM_VLAN_FILT_VALID | ADM_VLAN_FILT_VID(1); + w16(priv, ADM_VLAN_FILT_H(i), reg); + } + + reg = r16(priv, ADM_OTBE_P2_PVID); + reg |= ADM_OTBE_MASK; + w16(priv, ADM_OTBE_P2_PVID, reg); + reg = r16(priv, ADM_IFNTE); + reg |= ADM_IFNTE_MASK; + w16(priv, ADM_IFNTE, reg); + reg = r16(priv, ADM_VID_CHECK); + reg &= ~(ADM_VID_CHECK_MASK); + w16(priv, ADM_VID_CHECK, reg); + reg = r16(priv, ADM_SYSC0); + reg &= ~(ADM_NTTE); + reg |= ADM_RVID1; + w16(priv, ADM_SYSC0, reg); + reg = r16(priv, ADM_SYSC3); + reg &= ~(ADM_TBV); + w16(priv, ADM_SYSC3, reg); +} + +/* + * Disable VLANs + * + * Sets VLAN mapping for port-based VLAN with all ports connected to + * eachother (this is also the power-on default). + * + * Precondition: reg_mutex must be held + */ +static void +adm6996_disable_vlan_6996l(struct adm6996_priv *priv) +{ + u16 reg; + int i; + + for (i = 0; i < ADM_NUM_VLANS; i++) { + w16(priv, ADM_VLAN_MAP(i), 0); + } + + reg = r16(priv, ADM_SYSC3); + reg &= ~(ADM_TBV); + reg &= ~(ADM_MAC_CLONE); + w16(priv, ADM_SYSC3, reg); +} + +/* + * Precondition: reg_mutex must be held + */ +static void +adm6996_apply_port_pvids(struct adm6996_priv *priv) +{ + u16 reg; + int i; + + for (i = 0; i < ADM_NUM_PORTS; i++) { + reg = r16(priv, adm_portcfg[i]); + reg &= ~(ADM_PORTCFG_PVID_MASK); + reg |= ADM_PORTCFG_PVID(priv->pvid[i]); + if (priv->model == ADM6996L) { + if (priv->tagged_ports & (1 << i)) + reg |= (1 << 4); + else + reg &= ~(1 << 4); + } + w16(priv, adm_portcfg[i], reg); + } + + w16(priv, ADM_P0_PVID, ADM_P0_PVID_VAL(priv->pvid[0])); + w16(priv, ADM_P1_PVID, ADM_P1_PVID_VAL(priv->pvid[1])); + reg = r16(priv, ADM_OTBE_P2_PVID); + reg &= ~(ADM_P2_PVID_MASK); + reg |= ADM_P2_PVID_VAL(priv->pvid[2]); + w16(priv, ADM_OTBE_P2_PVID, reg); + reg = ADM_P3_PVID_VAL(priv->pvid[3]); + reg |= ADM_P4_PVID_VAL(priv->pvid[4]); + w16(priv, ADM_P3_P4_PVID, reg); + reg = r16(priv, ADM_P5_PVID); + reg &= ~(ADM_P2_PVID_MASK); + reg |= ADM_P5_PVID_VAL(priv->pvid[5]); + w16(priv, ADM_P5_PVID, reg); +} + +/* + * Precondition: reg_mutex must be held + */ +static void +adm6996_apply_vlan_filters(struct adm6996_priv *priv) +{ + u8 ports, tagged; + u16 vid, reg; + int i; + + for (i = 0; i < ADM_NUM_VLANS; i++) { + vid = priv->vlan_id[i]; + ports = priv->vlan_table[i]; + tagged = priv->vlan_tagged[i]; + + if (ports == 0) { + /* Disable VLAN entry */ + w16(priv, ADM_VLAN_FILT_H(i), 0); + w16(priv, ADM_VLAN_FILT_L(i), 0); + continue; + } + + reg = ADM_VLAN_FILT_MEMBER(ports); + reg |= ADM_VLAN_FILT_TAGGED(tagged); + w16(priv, ADM_VLAN_FILT_L(i), reg); + reg = ADM_VLAN_FILT_VALID | ADM_VLAN_FILT_VID(vid); + w16(priv, ADM_VLAN_FILT_H(i), reg); + } +} + +static void +adm6996_apply_vlan_filters_6996l(struct adm6996_priv *priv) +{ + u8 ports; + u16 reg; + int i; + + for (i = 0; i < ADM_NUM_VLANS; i++) { + ports = priv->vlan_table[i]; + + if (ports == 0) { + /* Disable VLAN entry */ + w16(priv, ADM_VLAN_MAP(i), 0); + continue; + } else { + reg = ADM_VLAN_FILT(ports); + w16(priv, ADM_VLAN_MAP(i), reg); + } + } +} + +static int +adm6996_hw_apply(struct switch_dev *dev) +{ + struct adm6996_priv *priv = to_adm(dev); + + pr_devel("hw_apply\n"); + + mutex_lock(&priv->reg_mutex); + + if (!priv->enable_vlan) { + if (priv->vlan_enabled) { + if (priv->model == ADM6996L) + adm6996_disable_vlan_6996l(priv); + else + adm6996_disable_vlan(priv); + priv->vlan_enabled = 0; + } + goto out; + } + + if (!priv->vlan_enabled) { + if (priv->model == ADM6996L) + adm6996_enable_vlan_6996l(priv); + else + adm6996_enable_vlan(priv); + priv->vlan_enabled = 1; + } + + adm6996_apply_port_pvids(priv); + if (priv->model == ADM6996L) + adm6996_apply_vlan_filters_6996l(priv); + else + adm6996_apply_vlan_filters(priv); + +out: + mutex_unlock(&priv->reg_mutex); + + return 0; +} + +/* + * Reset the switch + * + * The ADM6996 can't do a software-initiated reset, so we just initialise the + * registers we support in this driver. + * + * Precondition: reg_mutex must be held + */ +static void +adm6996_perform_reset (struct adm6996_priv *priv) +{ + int i; + + /* initialize port and vlan settings */ + for (i = 0; i < ADM_NUM_PORTS - 1; i++) { + w16(priv, adm_portcfg[i], ADM_PORTCFG_INIT | + ADM_PORTCFG_PVID(0)); + } + w16(priv, adm_portcfg[5], ADM_PORTCFG_CPU); + + if (priv->model == ADM6996M || priv->model == ADM6996FC) { + /* reset all PHY ports */ + for (i = 0; i < ADM_PHY_PORTS; i++) { + w16(priv, ADM_PHY_PORT(i), ADM_PHYCFG_INIT); + } + } + + priv->enable_vlan = 0; + priv->vlan_enabled = 0; + + for (i = 0; i < ADM_NUM_PORTS; i++) { + priv->pvid[i] = 0; + } + + for (i = 0; i < ADM_NUM_VLANS; i++) { + priv->vlan_id[i] = i; + priv->vlan_table[i] = 0; + priv->vlan_tagged[i] = 0; + } + + if (priv->model == ADM6996M) { + /* Clear VLAN priority map so prio's are unused */ + w16 (priv, ADM_VLAN_PRIOMAP, 0); + + adm6996_disable_vlan(priv); + adm6996_apply_port_pvids(priv); + } else if (priv->model == ADM6996L) { + /* Clear VLAN priority map so prio's are unused */ + w16 (priv, ADM_VLAN_PRIOMAP, 0); + + adm6996_disable_vlan_6996l(priv); + adm6996_apply_port_pvids(priv); + } +} + +static int +adm6996_reset_switch(struct switch_dev *dev) +{ + struct adm6996_priv *priv = to_adm(dev); + + pr_devel("reset\n"); + + mutex_lock(&priv->reg_mutex); + adm6996_perform_reset (priv); + mutex_unlock(&priv->reg_mutex); + return 0; +} + +static int +adm6996_get_port_link(struct switch_dev *dev, int port, + struct switch_port_link *link) +{ + struct adm6996_priv *priv = to_adm(dev); + + u16 reg = 0; + + if (port >= ADM_NUM_PORTS) + return -EINVAL; + + switch (port) { + case 0: + reg = r16(priv, ADM_PS0); + break; + case 1: + reg = r16(priv, ADM_PS0); + reg = reg >> 8; + break; + case 2: + reg = r16(priv, ADM_PS1); + break; + case 3: + reg = r16(priv, ADM_PS1); + reg = reg >> 8; + break; + case 4: + reg = r16(priv, ADM_PS1); + reg = reg >> 12; + break; + case 5: + reg = r16(priv, ADM_PS2); + /* Bits 0, 1, 3 and 4. */ + reg = (reg & 3) | ((reg & 24) >> 1); + break; + default: + return -EINVAL; + } + + link->link = reg & ADM_PS_LS; + if (!link->link) + return 0; + link->aneg = true; + link->duplex = reg & ADM_PS_DS; + link->tx_flow = reg & ADM_PS_FCS; + link->rx_flow = reg & ADM_PS_FCS; + if (reg & ADM_PS_SS) + link->speed = SWITCH_PORT_SPEED_100; + else + link->speed = SWITCH_PORT_SPEED_10; + + return 0; +} + +static int +adm6996_sw_get_port_mib(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct adm6996_priv *priv = to_adm(dev); + int port; + char *buf = priv->buf; + int i, len = 0; + u32 reg = 0; + + port = val->port_vlan; + if (port >= ADM_NUM_PORTS) + return -EINVAL; + + mutex_lock(&priv->mib_lock); + + len += snprintf(buf + len, sizeof(priv->buf) - len, + "Port %d MIB counters\n", + port); + + for (i = 0; i < ARRAY_SIZE(adm6996_mibs); i++) { + reg = r16(priv, adm6996_mibs[i].offset + ADM_OFFSET_PORT(port)); + reg += r16(priv, adm6996_mibs[i].offset + ADM_OFFSET_PORT(port) + 1) << 16; + len += snprintf(buf + len, sizeof(priv->buf) - len, + "%-12s: %u\n", + adm6996_mibs[i].name, + reg); + } + + mutex_unlock(&priv->mib_lock); + + val->value.s = buf; + val->len = len; + + return 0; +} + +static struct switch_attr adm6996_globals[] = { + { + .type = SWITCH_TYPE_INT, + .name = "enable_vlan", + .description = "Enable VLANs", + .set = adm6996_set_enable_vlan, + .get = adm6996_get_enable_vlan, + }, +#ifdef DEBUG + { + .type = SWITCH_TYPE_INT, + .name = "addr", + .description = + "Direct register access: set register address (0 - 1023)", + .set = adm6996_set_addr, + .get = adm6996_get_addr, + }, + { + .type = SWITCH_TYPE_INT, + .name = "data", + .description = + "Direct register access: read/write to register (0 - 65535)", + .set = adm6996_set_data, + .get = adm6996_get_data, + }, +#endif /* def DEBUG */ +}; + +static struct switch_attr adm6996_port[] = { + { + .type = SWITCH_TYPE_STRING, + .name = "mib", + .description = "Get port's MIB counters", + .set = NULL, + .get = adm6996_sw_get_port_mib, + }, +}; + +static struct switch_attr adm6996_vlan[] = { + { + .type = SWITCH_TYPE_INT, + .name = "vid", + .description = "VLAN ID", + .set = adm6996_set_vid, + .get = adm6996_get_vid, + }, +}; + +static struct switch_dev_ops adm6996_ops = { + .attr_global = { + .attr = adm6996_globals, + .n_attr = ARRAY_SIZE(adm6996_globals), + }, + .attr_port = { + .attr = adm6996_port, + .n_attr = ARRAY_SIZE(adm6996_port), + }, + .attr_vlan = { + .attr = adm6996_vlan, + .n_attr = ARRAY_SIZE(adm6996_vlan), + }, + .get_port_pvid = adm6996_get_pvid, + .set_port_pvid = adm6996_set_pvid, + .get_vlan_ports = adm6996_get_ports, + .set_vlan_ports = adm6996_set_ports, + .apply_config = adm6996_hw_apply, + .reset_switch = adm6996_reset_switch, + .get_port_link = adm6996_get_port_link, +}; + +static int adm6996_switch_init(struct adm6996_priv *priv, const char *alias, struct net_device *netdev) +{ + struct switch_dev *swdev; + u16 test, old; + + if (!priv->model) { + /* Detect type of chip */ + old = r16(priv, ADM_VID_CHECK); + test = old ^ (1 << 12); + w16(priv, ADM_VID_CHECK, test); + test ^= r16(priv, ADM_VID_CHECK); + if (test & (1 << 12)) { + /* + * Bit 12 of this register is read-only. + * This is the FC model. + */ + priv->model = ADM6996FC; + } else { + /* Bit 12 is read-write. This is the M model. */ + priv->model = ADM6996M; + w16(priv, ADM_VID_CHECK, old); + } + } + + swdev = &priv->dev; + swdev->name = (adm6996_model_name[priv->model]); + swdev->cpu_port = ADM_CPU_PORT; + swdev->ports = ADM_NUM_PORTS; + swdev->vlans = ADM_NUM_VLANS; + swdev->ops = &adm6996_ops; + swdev->alias = alias; + + /* The ADM6996L connected through GPIOs does not support any switch + status calls */ + if (priv->model == ADM6996L) { + adm6996_ops.attr_port.n_attr = 0; + adm6996_ops.get_port_link = NULL; + } + + pr_info ("%s: %s model PHY found.\n", alias, swdev->name); + + mutex_lock(&priv->reg_mutex); + adm6996_perform_reset (priv); + mutex_unlock(&priv->reg_mutex); + + if (priv->model == ADM6996M || priv->model == ADM6996L) { + return register_switch(swdev, netdev); + } + + return -ENODEV; +} + +static int adm6996_config_init(struct phy_device *pdev) +{ + struct adm6996_priv *priv; + int ret; + + pdev->supported = ADVERTISED_100baseT_Full; + pdev->advertising = ADVERTISED_100baseT_Full; + + if (pdev->addr != 0) { + pr_info ("%s: PHY overlaps ADM6996, providing fixed PHY 0x%x.\n" + , pdev->attached_dev->name, pdev->addr); + return 0; + } + + priv = devm_kzalloc(&pdev->dev, sizeof(struct adm6996_priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + mutex_init(&priv->reg_mutex); + mutex_init(&priv->mib_lock); + priv->priv = pdev; + priv->read = adm6996_read_mii_reg; + priv->write = adm6996_write_mii_reg; + + ret = adm6996_switch_init(priv, pdev->attached_dev->name, pdev->attached_dev); + if (ret < 0) + return ret; + + pdev->priv = priv; + + return 0; +} + +/* + * Warning: phydev->priv is NULL if phydev->addr != 0 + */ +static int adm6996_read_status(struct phy_device *phydev) +{ + phydev->speed = SPEED_100; + phydev->duplex = DUPLEX_FULL; + phydev->link = 1; + return 0; +} + +/* + * Warning: phydev->priv is NULL if phydev->addr != 0 + */ +static int adm6996_config_aneg(struct phy_device *phydev) +{ + return 0; +} + +static int adm6996_fixup(struct phy_device *dev) +{ + struct mii_bus *bus = dev->bus; + u16 reg; + + /* Our custom registers are at PHY addresses 0-10. Claim those. */ + if (dev->addr > 10) + return 0; + + /* look for the switch on the bus */ + reg = bus->read(bus, PHYADDR(ADM_SIG0)) & ADM_SIG0_MASK; + if (reg != ADM_SIG0_VAL) + return 0; + + reg = bus->read(bus, PHYADDR(ADM_SIG1)) & ADM_SIG1_MASK; + if (reg != ADM_SIG1_VAL) + return 0; + + dev->phy_id = (ADM_SIG0_VAL << 16) | ADM_SIG1_VAL; + + return 0; +} + +static int adm6996_probe(struct phy_device *pdev) +{ + return 0; +} + +static void adm6996_remove(struct phy_device *pdev) +{ + struct adm6996_priv *priv = phy_to_adm(pdev); + + if (priv && (priv->model == ADM6996M || priv->model == ADM6996L)) + unregister_switch(&priv->dev); +} + + +static struct phy_driver adm6996_phy_driver = { + .name = "Infineon ADM6996", + .phy_id = (ADM_SIG0_VAL << 16) | ADM_SIG1_VAL, + .phy_id_mask = 0xffffffff, + .features = PHY_BASIC_FEATURES, + .probe = adm6996_probe, + .remove = adm6996_remove, + .config_init = &adm6996_config_init, + .config_aneg = &adm6996_config_aneg, + .read_status = &adm6996_read_status, + .driver = { .owner = THIS_MODULE,}, +}; + +static int adm6996_gpio_probe(struct platform_device *pdev) +{ + struct adm6996_gpio_platform_data *pdata = pdev->dev.platform_data; + struct adm6996_priv *priv; + int ret; + + if (!pdata) + return -EINVAL; + + priv = devm_kzalloc(&pdev->dev, sizeof(struct adm6996_priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + mutex_init(&priv->reg_mutex); + mutex_init(&priv->mib_lock); + + priv->eecs = pdata->eecs; + priv->eedi = pdata->eedi; + priv->eerc = pdata->eerc; + priv->eesk = pdata->eesk; + + priv->model = pdata->model; + priv->read = adm6996_read_gpio_reg; + priv->write = adm6996_write_gpio_reg; + + ret = devm_gpio_request(&pdev->dev, priv->eecs, "adm_eecs"); + if (ret) + return ret; + ret = devm_gpio_request(&pdev->dev, priv->eedi, "adm_eedi"); + if (ret) + return ret; + ret = devm_gpio_request(&pdev->dev, priv->eerc, "adm_eerc"); + if (ret) + return ret; + ret = devm_gpio_request(&pdev->dev, priv->eesk, "adm_eesk"); + if (ret) + return ret; + + ret = adm6996_switch_init(priv, dev_name(&pdev->dev), NULL); + if (ret < 0) + return ret; + + platform_set_drvdata(pdev, priv); + + return 0; +} + +static int adm6996_gpio_remove(struct platform_device *pdev) +{ + struct adm6996_priv *priv = platform_get_drvdata(pdev); + + if (priv && (priv->model == ADM6996M || priv->model == ADM6996L)) + unregister_switch(&priv->dev); + + return 0; +} + +static struct platform_driver adm6996_gpio_driver = { + .probe = adm6996_gpio_probe, + .remove = adm6996_gpio_remove, + .driver = { + .name = "adm6996_gpio", + }, +}; + +static int __init adm6996_init(void) +{ + int err; + + phy_register_fixup_for_id(PHY_ANY_ID, adm6996_fixup); + err = phy_driver_register(&adm6996_phy_driver); + if (err) + return err; + + err = platform_driver_register(&adm6996_gpio_driver); + if (err) + phy_driver_unregister(&adm6996_phy_driver); + + return err; +} + +static void __exit adm6996_exit(void) +{ + platform_driver_unregister(&adm6996_gpio_driver); + phy_driver_unregister(&adm6996_phy_driver); +} + +module_init(adm6996_init); +module_exit(adm6996_exit); diff --git a/target/linux/generic/files/drivers/net/phy/adm6996.h b/target/linux/generic/files/drivers/net/phy/adm6996.h new file mode 100644 index 0000000..66c77a0 --- /dev/null +++ b/target/linux/generic/files/drivers/net/phy/adm6996.h @@ -0,0 +1,186 @@ +/* + * ADM6996 switch driver + * + * Copyright (c) 2008 Felix Fietkau + * Copyright (c) 2010,2011 Peter Lebbing + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License v2 as published by the + * Free Software Foundation + */ +#ifndef __ADM6996_H +#define __ADM6996_H + +/* + * ADM_PHY_PORTS: Number of ports with a PHY. + * We only control ports 0 to 3, because if 4 is connected, it is most likely + * not connected to the switch but to a separate MII and MAC for the WAN port. + */ +#define ADM_PHY_PORTS 4 +#define ADM_NUM_PORTS 6 +#define ADM_CPU_PORT 5 + +#define ADM_NUM_VLANS 16 +#define ADM_VLAN_MAX_ID 4094 + +enum admreg { + ADM_EEPROM_BASE = 0x0, + ADM_P0_CFG = ADM_EEPROM_BASE + 1, + ADM_P1_CFG = ADM_EEPROM_BASE + 3, + ADM_P2_CFG = ADM_EEPROM_BASE + 5, + ADM_P3_CFG = ADM_EEPROM_BASE + 7, + ADM_P4_CFG = ADM_EEPROM_BASE + 8, + ADM_P5_CFG = ADM_EEPROM_BASE + 9, + ADM_SYSC0 = ADM_EEPROM_BASE + 0xa, + ADM_VLAN_PRIOMAP = ADM_EEPROM_BASE + 0xe, + ADM_SYSC3 = ADM_EEPROM_BASE + 0x11, + /* Input Force No Tag Enable */ + ADM_IFNTE = ADM_EEPROM_BASE + 0x20, + ADM_VID_CHECK = ADM_EEPROM_BASE + 0x26, + ADM_P0_PVID = ADM_EEPROM_BASE + 0x28, + ADM_P1_PVID = ADM_EEPROM_BASE + 0x29, + /* Output Tag Bypass Enable and P2 PVID */ + ADM_OTBE_P2_PVID = ADM_EEPROM_BASE + 0x2a, + ADM_P3_P4_PVID = ADM_EEPROM_BASE + 0x2b, + ADM_P5_PVID = ADM_EEPROM_BASE + 0x2c, + ADM_EEPROM_EXT_BASE = 0x40, +#define ADM_VLAN_FILT_L(n) (ADM_EEPROM_EXT_BASE + 2 * (n)) +#define ADM_VLAN_FILT_H(n) (ADM_EEPROM_EXT_BASE + 1 + 2 * (n)) +#define ADM_VLAN_MAP(n) (ADM_EEPROM_BASE + 0x13 + n) + ADM_COUNTER_BASE = 0xa0, + ADM_SIG0 = ADM_COUNTER_BASE + 0, + ADM_SIG1 = ADM_COUNTER_BASE + 1, + ADM_PS0 = ADM_COUNTER_BASE + 2, + ADM_PS1 = ADM_COUNTER_BASE + 3, + ADM_PS2 = ADM_COUNTER_BASE + 4, + ADM_CL0 = ADM_COUNTER_BASE + 8, /* RxPacket */ + ADM_CL6 = ADM_COUNTER_BASE + 0x1a, /* RxByte */ + ADM_CL12 = ADM_COUNTER_BASE + 0x2c, /* TxPacket */ + ADM_CL18 = ADM_COUNTER_BASE + 0x3e, /* TxByte */ + ADM_CL24 = ADM_COUNTER_BASE + 0x50, /* Coll */ + ADM_CL30 = ADM_COUNTER_BASE + 0x62, /* Err */ +#define ADM_OFFSET_PORT(n) ((n * 4) - (n / 4) * 2 - (n / 5) * 2) + ADM_PHY_BASE = 0x200, +#define ADM_PHY_PORT(n) (ADM_PHY_BASE + (0x20 * n)) +}; + +/* Chip identification patterns */ +#define ADM_SIG0_MASK 0xffff +#define ADM_SIG0_VAL 0x1023 +#define ADM_SIG1_MASK 0xffff +#define ADM_SIG1_VAL 0x0007 + +enum { + ADM_PHYCFG_COLTST = (1 << 7), /* Enable collision test */ + ADM_PHYCFG_DPLX = (1 << 8), /* Enable full duplex */ + ADM_PHYCFG_ANEN_RST = (1 << 9), /* Restart auto negotiation (self clear) */ + ADM_PHYCFG_ISO = (1 << 10), /* Isolate PHY */ + ADM_PHYCFG_PDN = (1 << 11), /* Power down PHY */ + ADM_PHYCFG_ANEN = (1 << 12), /* Enable auto negotiation */ + ADM_PHYCFG_SPEED_100 = (1 << 13), /* Enable 100 Mbit/s */ + ADM_PHYCFG_LPBK = (1 << 14), /* Enable loopback operation */ + ADM_PHYCFG_RST = (1 << 15), /* Reset the port (self clear) */ + ADM_PHYCFG_INIT = ( + ADM_PHYCFG_RST | + ADM_PHYCFG_SPEED_100 | + ADM_PHYCFG_ANEN | + ADM_PHYCFG_ANEN_RST + ) +}; + +enum { + ADM_PORTCFG_FC = (1 << 0), /* Enable 802.x flow control */ + ADM_PORTCFG_AN = (1 << 1), /* Enable auto-negotiation */ + ADM_PORTCFG_SPEED_100 = (1 << 2), /* Enable 100 Mbit/s */ + ADM_PORTCFG_DPLX = (1 << 3), /* Enable full duplex */ + ADM_PORTCFG_OT = (1 << 4), /* Output tagged packets */ + ADM_PORTCFG_PD = (1 << 5), /* Port disable */ + ADM_PORTCFG_TV_PRIO = (1 << 6), /* 0 = VLAN based priority + * 1 = TOS based priority */ + ADM_PORTCFG_PPE = (1 << 7), /* Port based priority enable */ + ADM_PORTCFG_PP_S = (1 << 8), /* Port based priority, 2 bits */ + ADM_PORTCFG_PVID_BASE = (1 << 10), /* Primary VLAN id, 4 bits */ + ADM_PORTCFG_FSE = (1 << 14), /* Fx select enable */ + ADM_PORTCFG_CAM = (1 << 15), /* Crossover Auto MDIX */ + + ADM_PORTCFG_INIT = ( + ADM_PORTCFG_FC | + ADM_PORTCFG_AN | + ADM_PORTCFG_SPEED_100 | + ADM_PORTCFG_DPLX | + ADM_PORTCFG_CAM + ), + ADM_PORTCFG_CPU = ( + ADM_PORTCFG_FC | + ADM_PORTCFG_SPEED_100 | + ADM_PORTCFG_OT | + ADM_PORTCFG_DPLX + ), +}; + +#define ADM_PORTCFG_PPID(n) ((n & 0x3) << 8) +#define ADM_PORTCFG_PVID(n) ((n & 0xf) << 10) +#define ADM_PORTCFG_PVID_MASK (0xf << 10) + +#define ADM_IFNTE_MASK (0x3f << 9) +#define ADM_VID_CHECK_MASK (0x3f << 6) + +#define ADM_P0_PVID_VAL(n) ((((n) & 0xff0) >> 4) << 0) +#define ADM_P1_PVID_VAL(n) ((((n) & 0xff0) >> 4) << 0) +#define ADM_P2_PVID_VAL(n) ((((n) & 0xff0) >> 4) << 0) +#define ADM_P3_PVID_VAL(n) ((((n) & 0xff0) >> 4) << 0) +#define ADM_P4_PVID_VAL(n) ((((n) & 0xff0) >> 4) << 8) +#define ADM_P5_PVID_VAL(n) ((((n) & 0xff0) >> 4) << 0) +#define ADM_P2_PVID_MASK 0xff + +#define ADM_OTBE(n) (((n) & 0x3f) << 8) +#define ADM_OTBE_MASK (0x3f << 8) + +/* ADM_SYSC0 */ +enum { + ADM_NTTE = (1 << 2), /* New Tag Transmit Enable */ + ADM_RVID1 = (1 << 8) /* Replace VLAN ID 1 */ +}; + +/* Tag Based VLAN in ADM_SYSC3 */ +#define ADM_MAC_CLONE BIT(4) +#define ADM_TBV BIT(5) + +static const u8 adm_portcfg[] = { + [0] = ADM_P0_CFG, + [1] = ADM_P1_CFG, + [2] = ADM_P2_CFG, + [3] = ADM_P3_CFG, + [4] = ADM_P4_CFG, + [5] = ADM_P5_CFG, +}; + +/* Fields in ADM_VLAN_FILT_L(x) */ +#define ADM_VLAN_FILT_FID(n) (((n) & 0xf) << 12) +#define ADM_VLAN_FILT_TAGGED(n) (((n) & 0x3f) << 6) +#define ADM_VLAN_FILT_MEMBER(n) (((n) & 0x3f) << 0) +#define ADM_VLAN_FILT_MEMBER_MASK 0x3f +/* Fields in ADM_VLAN_FILT_H(x) */ +#define ADM_VLAN_FILT_VALID (1 << 15) +#define ADM_VLAN_FILT_VID(n) (((n) & 0xfff) << 0) + +/* Convert ports to a form for ADM6996L VLAN map */ +#define ADM_VLAN_FILT(ports) ((ports & 0x01) | ((ports & 0x02) << 1) | \ + ((ports & 0x04) << 2) | ((ports & 0x08) << 3) | \ + ((ports & 0x10) << 3) | ((ports & 0x20) << 3)) + +/* Port status register */ +enum { + ADM_PS_LS = (1 << 0), /* Link status */ + ADM_PS_SS = (1 << 1), /* Speed status */ + ADM_PS_DS = (1 << 2), /* Duplex status */ + ADM_PS_FCS = (1 << 3) /* Flow control status */ +}; + +/* + * Split the register address in phy id and register + * it will get combined again by the mdio bus op + */ +#define PHYADDR(_reg) ((_reg >> 5) & 0xff), (_reg & 0x1f) + +#endif diff --git a/target/linux/generic/files/drivers/net/phy/ar8216.c b/target/linux/generic/files/drivers/net/phy/ar8216.c new file mode 100644 index 0000000..75db1f1 --- /dev/null +++ b/target/linux/generic/files/drivers/net/phy/ar8216.c @@ -0,0 +1,2197 @@ +/* + * ar8216.c: AR8216 switch driver + * + * Copyright (C) 2009 Felix Fietkau + * Copyright (C) 2011-2012 Gabor Juhos + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ar8216.h" + +extern const struct ar8xxx_chip ar8327_chip; +extern const struct ar8xxx_chip ar8337_chip; + +#define AR8XXX_MIB_WORK_DELAY 2000 /* msecs */ + +#define MIB_DESC(_s , _o, _n) \ + { \ + .size = (_s), \ + .offset = (_o), \ + .name = (_n), \ + } + +static const struct ar8xxx_mib_desc ar8216_mibs[] = { + MIB_DESC(1, AR8216_STATS_RXBROAD, "RxBroad"), + MIB_DESC(1, AR8216_STATS_RXPAUSE, "RxPause"), + MIB_DESC(1, AR8216_STATS_RXMULTI, "RxMulti"), + MIB_DESC(1, AR8216_STATS_RXFCSERR, "RxFcsErr"), + MIB_DESC(1, AR8216_STATS_RXALIGNERR, "RxAlignErr"), + MIB_DESC(1, AR8216_STATS_RXRUNT, "RxRunt"), + MIB_DESC(1, AR8216_STATS_RXFRAGMENT, "RxFragment"), + MIB_DESC(1, AR8216_STATS_RX64BYTE, "Rx64Byte"), + MIB_DESC(1, AR8216_STATS_RX128BYTE, "Rx128Byte"), + MIB_DESC(1, AR8216_STATS_RX256BYTE, "Rx256Byte"), + MIB_DESC(1, AR8216_STATS_RX512BYTE, "Rx512Byte"), + MIB_DESC(1, AR8216_STATS_RX1024BYTE, "Rx1024Byte"), + MIB_DESC(1, AR8216_STATS_RXMAXBYTE, "RxMaxByte"), + MIB_DESC(1, AR8216_STATS_RXTOOLONG, "RxTooLong"), + MIB_DESC(2, AR8216_STATS_RXGOODBYTE, "RxGoodByte"), + MIB_DESC(2, AR8216_STATS_RXBADBYTE, "RxBadByte"), + MIB_DESC(1, AR8216_STATS_RXOVERFLOW, "RxOverFlow"), + MIB_DESC(1, AR8216_STATS_FILTERED, "Filtered"), + MIB_DESC(1, AR8216_STATS_TXBROAD, "TxBroad"), + MIB_DESC(1, AR8216_STATS_TXPAUSE, "TxPause"), + MIB_DESC(1, AR8216_STATS_TXMULTI, "TxMulti"), + MIB_DESC(1, AR8216_STATS_TXUNDERRUN, "TxUnderRun"), + MIB_DESC(1, AR8216_STATS_TX64BYTE, "Tx64Byte"), + MIB_DESC(1, AR8216_STATS_TX128BYTE, "Tx128Byte"), + MIB_DESC(1, AR8216_STATS_TX256BYTE, "Tx256Byte"), + MIB_DESC(1, AR8216_STATS_TX512BYTE, "Tx512Byte"), + MIB_DESC(1, AR8216_STATS_TX1024BYTE, "Tx1024Byte"), + MIB_DESC(1, AR8216_STATS_TXMAXBYTE, "TxMaxByte"), + MIB_DESC(1, AR8216_STATS_TXOVERSIZE, "TxOverSize"), + MIB_DESC(2, AR8216_STATS_TXBYTE, "TxByte"), + MIB_DESC(1, AR8216_STATS_TXCOLLISION, "TxCollision"), + MIB_DESC(1, AR8216_STATS_TXABORTCOL, "TxAbortCol"), + MIB_DESC(1, AR8216_STATS_TXMULTICOL, "TxMultiCol"), + MIB_DESC(1, AR8216_STATS_TXSINGLECOL, "TxSingleCol"), + MIB_DESC(1, AR8216_STATS_TXEXCDEFER, "TxExcDefer"), + MIB_DESC(1, AR8216_STATS_TXDEFER, "TxDefer"), + MIB_DESC(1, AR8216_STATS_TXLATECOL, "TxLateCol"), +}; + +const struct ar8xxx_mib_desc ar8236_mibs[39] = { + MIB_DESC(1, AR8236_STATS_RXBROAD, "RxBroad"), + MIB_DESC(1, AR8236_STATS_RXPAUSE, "RxPause"), + MIB_DESC(1, AR8236_STATS_RXMULTI, "RxMulti"), + MIB_DESC(1, AR8236_STATS_RXFCSERR, "RxFcsErr"), + MIB_DESC(1, AR8236_STATS_RXALIGNERR, "RxAlignErr"), + MIB_DESC(1, AR8236_STATS_RXRUNT, "RxRunt"), + MIB_DESC(1, AR8236_STATS_RXFRAGMENT, "RxFragment"), + MIB_DESC(1, AR8236_STATS_RX64BYTE, "Rx64Byte"), + MIB_DESC(1, AR8236_STATS_RX128BYTE, "Rx128Byte"), + MIB_DESC(1, AR8236_STATS_RX256BYTE, "Rx256Byte"), + MIB_DESC(1, AR8236_STATS_RX512BYTE, "Rx512Byte"), + MIB_DESC(1, AR8236_STATS_RX1024BYTE, "Rx1024Byte"), + MIB_DESC(1, AR8236_STATS_RX1518BYTE, "Rx1518Byte"), + MIB_DESC(1, AR8236_STATS_RXMAXBYTE, "RxMaxByte"), + MIB_DESC(1, AR8236_STATS_RXTOOLONG, "RxTooLong"), + MIB_DESC(2, AR8236_STATS_RXGOODBYTE, "RxGoodByte"), + MIB_DESC(2, AR8236_STATS_RXBADBYTE, "RxBadByte"), + MIB_DESC(1, AR8236_STATS_RXOVERFLOW, "RxOverFlow"), + MIB_DESC(1, AR8236_STATS_FILTERED, "Filtered"), + MIB_DESC(1, AR8236_STATS_TXBROAD, "TxBroad"), + MIB_DESC(1, AR8236_STATS_TXPAUSE, "TxPause"), + MIB_DESC(1, AR8236_STATS_TXMULTI, "TxMulti"), + MIB_DESC(1, AR8236_STATS_TXUNDERRUN, "TxUnderRun"), + MIB_DESC(1, AR8236_STATS_TX64BYTE, "Tx64Byte"), + MIB_DESC(1, AR8236_STATS_TX128BYTE, "Tx128Byte"), + MIB_DESC(1, AR8236_STATS_TX256BYTE, "Tx256Byte"), + MIB_DESC(1, AR8236_STATS_TX512BYTE, "Tx512Byte"), + MIB_DESC(1, AR8236_STATS_TX1024BYTE, "Tx1024Byte"), + MIB_DESC(1, AR8236_STATS_TX1518BYTE, "Tx1518Byte"), + MIB_DESC(1, AR8236_STATS_TXMAXBYTE, "TxMaxByte"), + MIB_DESC(1, AR8236_STATS_TXOVERSIZE, "TxOverSize"), + MIB_DESC(2, AR8236_STATS_TXBYTE, "TxByte"), + MIB_DESC(1, AR8236_STATS_TXCOLLISION, "TxCollision"), + MIB_DESC(1, AR8236_STATS_TXABORTCOL, "TxAbortCol"), + MIB_DESC(1, AR8236_STATS_TXMULTICOL, "TxMultiCol"), + MIB_DESC(1, AR8236_STATS_TXSINGLECOL, "TxSingleCol"), + MIB_DESC(1, AR8236_STATS_TXEXCDEFER, "TxExcDefer"), + MIB_DESC(1, AR8236_STATS_TXDEFER, "TxDefer"), + MIB_DESC(1, AR8236_STATS_TXLATECOL, "TxLateCol"), +}; + +static DEFINE_MUTEX(ar8xxx_dev_list_lock); +static LIST_HEAD(ar8xxx_dev_list); + +/* inspired by phy_poll_reset in drivers/net/phy/phy_device.c */ +static int +ar8xxx_phy_poll_reset(struct mii_bus *bus) +{ + unsigned int sleep_msecs = 20; + int ret, elapsed, i; + + for (elapsed = sleep_msecs; elapsed <= 600; + elapsed += sleep_msecs) { + msleep(sleep_msecs); + for (i = 0; i < AR8XXX_NUM_PHYS; i++) { + ret = mdiobus_read(bus, i, MII_BMCR); + if (ret < 0) + return ret; + if (ret & BMCR_RESET) + break; + if (i == AR8XXX_NUM_PHYS - 1) { + usleep_range(1000, 2000); + return 0; + } + } + } + return -ETIMEDOUT; +} + +static int +ar8xxx_phy_check_aneg(struct phy_device *phydev) +{ + int ret; + + if (phydev->autoneg != AUTONEG_ENABLE) + return 0; + /* + * BMCR_ANENABLE might have been cleared + * by phy_init_hw in certain kernel versions + * therefore check for it + */ + ret = phy_read(phydev, MII_BMCR); + if (ret < 0) + return ret; + if (ret & BMCR_ANENABLE) + return 0; + + dev_info(&phydev->dev, "ANEG disabled, re-enabling ...\n"); + ret |= BMCR_ANENABLE | BMCR_ANRESTART; + return phy_write(phydev, MII_BMCR, ret); +} + +void +ar8xxx_phy_init(struct ar8xxx_priv *priv) +{ + int i; + struct mii_bus *bus; + + bus = priv->mii_bus; + for (i = 0; i < AR8XXX_NUM_PHYS; i++) { + if (priv->chip->phy_fixup) + priv->chip->phy_fixup(priv, i); + + /* initialize the port itself */ + mdiobus_write(bus, i, MII_ADVERTISE, + ADVERTISE_ALL | ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM); + if (ar8xxx_has_gige(priv)) + mdiobus_write(bus, i, MII_CTRL1000, ADVERTISE_1000FULL); + mdiobus_write(bus, i, MII_BMCR, BMCR_RESET | BMCR_ANENABLE); + } + + ar8xxx_phy_poll_reset(bus); +} + +u32 +ar8xxx_mii_read32(struct ar8xxx_priv *priv, int phy_id, int regnum) +{ + struct mii_bus *bus = priv->mii_bus; + u16 lo, hi; + + lo = bus->read(bus, phy_id, regnum); + hi = bus->read(bus, phy_id, regnum + 1); + + return (hi << 16) | lo; +} + +void +ar8xxx_mii_write32(struct ar8xxx_priv *priv, int phy_id, int regnum, u32 val) +{ + struct mii_bus *bus = priv->mii_bus; + u16 lo, hi; + + lo = val & 0xffff; + hi = (u16) (val >> 16); + + if (priv->chip->mii_lo_first) + { + bus->write(bus, phy_id, regnum, lo); + bus->write(bus, phy_id, regnum + 1, hi); + } else { + bus->write(bus, phy_id, regnum + 1, hi); + bus->write(bus, phy_id, regnum, lo); + } +} + +u32 +ar8xxx_read(struct ar8xxx_priv *priv, int reg) +{ + struct mii_bus *bus = priv->mii_bus; + u16 r1, r2, page; + u32 val; + + split_addr((u32) reg, &r1, &r2, &page); + + mutex_lock(&bus->mdio_lock); + + bus->write(bus, 0x18, 0, page); + wait_for_page_switch(); + val = ar8xxx_mii_read32(priv, 0x10 | r2, r1); + + mutex_unlock(&bus->mdio_lock); + + return val; +} + +void +ar8xxx_write(struct ar8xxx_priv *priv, int reg, u32 val) +{ + struct mii_bus *bus = priv->mii_bus; + u16 r1, r2, page; + + split_addr((u32) reg, &r1, &r2, &page); + + mutex_lock(&bus->mdio_lock); + + bus->write(bus, 0x18, 0, page); + wait_for_page_switch(); + ar8xxx_mii_write32(priv, 0x10 | r2, r1, val); + + mutex_unlock(&bus->mdio_lock); +} + +u32 +ar8xxx_rmw(struct ar8xxx_priv *priv, int reg, u32 mask, u32 val) +{ + struct mii_bus *bus = priv->mii_bus; + u16 r1, r2, page; + u32 ret; + + split_addr((u32) reg, &r1, &r2, &page); + + mutex_lock(&bus->mdio_lock); + + bus->write(bus, 0x18, 0, page); + wait_for_page_switch(); + + ret = ar8xxx_mii_read32(priv, 0x10 | r2, r1); + ret &= ~mask; + ret |= val; + ar8xxx_mii_write32(priv, 0x10 | r2, r1, ret); + + mutex_unlock(&bus->mdio_lock); + + return ret; +} + +void +ar8xxx_phy_dbg_write(struct ar8xxx_priv *priv, int phy_addr, + u16 dbg_addr, u16 dbg_data) +{ + struct mii_bus *bus = priv->mii_bus; + + mutex_lock(&bus->mdio_lock); + bus->write(bus, phy_addr, MII_ATH_DBG_ADDR, dbg_addr); + bus->write(bus, phy_addr, MII_ATH_DBG_DATA, dbg_data); + mutex_unlock(&bus->mdio_lock); +} + +void +ar8xxx_phy_mmd_write(struct ar8xxx_priv *priv, int phy_addr, u16 addr, u16 data) +{ + struct mii_bus *bus = priv->mii_bus; + + mutex_lock(&bus->mdio_lock); + bus->write(bus, phy_addr, MII_ATH_MMD_ADDR, addr); + bus->write(bus, phy_addr, MII_ATH_MMD_DATA, data); + mutex_unlock(&bus->mdio_lock); +} + +u16 +ar8xxx_phy_mmd_read(struct ar8xxx_priv *priv, int phy_addr, u16 addr) +{ + struct mii_bus *bus = priv->mii_bus; + u16 data; + + mutex_lock(&bus->mdio_lock); + bus->write(bus, phy_addr, MII_ATH_MMD_ADDR, addr); + data = bus->read(bus, phy_addr, MII_ATH_MMD_DATA); + mutex_unlock(&bus->mdio_lock); + + return data; +} + +static int +ar8xxx_reg_wait(struct ar8xxx_priv *priv, u32 reg, u32 mask, u32 val, + unsigned timeout) +{ + int i; + + for (i = 0; i < timeout; i++) { + u32 t; + + t = ar8xxx_read(priv, reg); + if ((t & mask) == val) + return 0; + + usleep_range(1000, 2000); + } + + return -ETIMEDOUT; +} + +static int +ar8xxx_mib_op(struct ar8xxx_priv *priv, u32 op) +{ + unsigned mib_func = priv->chip->mib_func; + int ret; + + lockdep_assert_held(&priv->mib_lock); + + /* Capture the hardware statistics for all ports */ + ar8xxx_rmw(priv, mib_func, AR8216_MIB_FUNC, (op << AR8216_MIB_FUNC_S)); + + /* Wait for the capturing to complete. */ + ret = ar8xxx_reg_wait(priv, mib_func, AR8216_MIB_BUSY, 0, 10); + if (ret) + goto out; + + ret = 0; + +out: + return ret; +} + +static int +ar8xxx_mib_capture(struct ar8xxx_priv *priv) +{ + return ar8xxx_mib_op(priv, AR8216_MIB_FUNC_CAPTURE); +} + +static int +ar8xxx_mib_flush(struct ar8xxx_priv *priv) +{ + return ar8xxx_mib_op(priv, AR8216_MIB_FUNC_FLUSH); +} + +static void +ar8xxx_mib_fetch_port_stat(struct ar8xxx_priv *priv, int port, bool flush) +{ + unsigned int base; + u64 *mib_stats; + int i; + + WARN_ON(port >= priv->dev.ports); + + lockdep_assert_held(&priv->mib_lock); + + base = priv->chip->reg_port_stats_start + + priv->chip->reg_port_stats_length * port; + + mib_stats = &priv->mib_stats[port * priv->chip->num_mibs]; + for (i = 0; i < priv->chip->num_mibs; i++) { + const struct ar8xxx_mib_desc *mib; + u64 t; + + mib = &priv->chip->mib_decs[i]; + t = ar8xxx_read(priv, base + mib->offset); + if (mib->size == 2) { + u64 hi; + + hi = ar8xxx_read(priv, base + mib->offset + 4); + t |= hi << 32; + } + + if (flush) + mib_stats[i] = 0; + else + mib_stats[i] += t; + } +} + +static void +ar8216_read_port_link(struct ar8xxx_priv *priv, int port, + struct switch_port_link *link) +{ + u32 status; + u32 speed; + + memset(link, '\0', sizeof(*link)); + + status = priv->chip->read_port_status(priv, port); + + link->aneg = !!(status & AR8216_PORT_STATUS_LINK_AUTO); + if (link->aneg) { + link->link = !!(status & AR8216_PORT_STATUS_LINK_UP); + } else { + link->link = true; + + if (priv->get_port_link) { + int err; + + err = priv->get_port_link(port); + if (err >= 0) + link->link = !!err; + } + } + + if (!link->link) + return; + + link->duplex = !!(status & AR8216_PORT_STATUS_DUPLEX); + link->tx_flow = !!(status & AR8216_PORT_STATUS_TXFLOW); + link->rx_flow = !!(status & AR8216_PORT_STATUS_RXFLOW); + + if (link->aneg && link->duplex && priv->chip->read_port_eee_status) + link->eee = priv->chip->read_port_eee_status(priv, port); + + speed = (status & AR8216_PORT_STATUS_SPEED) >> + AR8216_PORT_STATUS_SPEED_S; + + switch (speed) { + case AR8216_PORT_SPEED_10M: + link->speed = SWITCH_PORT_SPEED_10; + break; + case AR8216_PORT_SPEED_100M: + link->speed = SWITCH_PORT_SPEED_100; + break; + case AR8216_PORT_SPEED_1000M: + link->speed = SWITCH_PORT_SPEED_1000; + break; + default: + link->speed = SWITCH_PORT_SPEED_UNKNOWN; + break; + } +} + +static struct sk_buff * +ar8216_mangle_tx(struct net_device *dev, struct sk_buff *skb) +{ + struct ar8xxx_priv *priv = dev->phy_ptr; + unsigned char *buf; + + if (unlikely(!priv)) + goto error; + + if (!priv->vlan) + goto send; + + if (unlikely(skb_headroom(skb) < 2)) { + if (pskb_expand_head(skb, 2, 0, GFP_ATOMIC) < 0) + goto error; + } + + buf = skb_push(skb, 2); + buf[0] = 0x10; + buf[1] = 0x80; + +send: + return skb; + +error: + dev_kfree_skb_any(skb); + return NULL; +} + +static void +ar8216_mangle_rx(struct net_device *dev, struct sk_buff *skb) +{ + struct ar8xxx_priv *priv; + unsigned char *buf; + int port, vlan; + + priv = dev->phy_ptr; + if (!priv) + return; + + /* don't strip the header if vlan mode is disabled */ + if (!priv->vlan) + return; + + /* strip header, get vlan id */ + buf = skb->data; + skb_pull(skb, 2); + + /* check for vlan header presence */ + if ((buf[12 + 2] != 0x81) || (buf[13 + 2] != 0x00)) + return; + + port = buf[0] & 0xf; + + /* no need to fix up packets coming from a tagged source */ + if (priv->vlan_tagged & (1 << port)) + return; + + /* lookup port vid from local table, the switch passes an invalid vlan id */ + vlan = priv->vlan_id[priv->pvid[port]]; + + buf[14 + 2] &= 0xf0; + buf[14 + 2] |= vlan >> 8; + buf[15 + 2] = vlan & 0xff; +} + +int +ar8216_wait_bit(struct ar8xxx_priv *priv, int reg, u32 mask, u32 val) +{ + int timeout = 20; + u32 t = 0; + + while (1) { + t = ar8xxx_read(priv, reg); + if ((t & mask) == val) + return 0; + + if (timeout-- <= 0) + break; + + udelay(10); + } + + pr_err("ar8216: timeout on reg %08x: %08x & %08x != %08x\n", + (unsigned int) reg, t, mask, val); + return -ETIMEDOUT; +} + +static void +ar8216_vtu_op(struct ar8xxx_priv *priv, u32 op, u32 val) +{ + if (ar8216_wait_bit(priv, AR8216_REG_VTU, AR8216_VTU_ACTIVE, 0)) + return; + if ((op & AR8216_VTU_OP) == AR8216_VTU_OP_LOAD) { + val &= AR8216_VTUDATA_MEMBER; + val |= AR8216_VTUDATA_VALID; + ar8xxx_write(priv, AR8216_REG_VTU_DATA, val); + } + op |= AR8216_VTU_ACTIVE; + ar8xxx_write(priv, AR8216_REG_VTU, op); +} + +static void +ar8216_vtu_flush(struct ar8xxx_priv *priv) +{ + ar8216_vtu_op(priv, AR8216_VTU_OP_FLUSH, 0); +} + +static void +ar8216_vtu_load_vlan(struct ar8xxx_priv *priv, u32 vid, u32 port_mask) +{ + u32 op; + + op = AR8216_VTU_OP_LOAD | (vid << AR8216_VTU_VID_S); + ar8216_vtu_op(priv, op, port_mask); +} + +static int +ar8216_atu_flush(struct ar8xxx_priv *priv) +{ + int ret; + + ret = ar8216_wait_bit(priv, AR8216_REG_ATU_FUNC0, AR8216_ATU_ACTIVE, 0); + if (!ret) + ar8xxx_write(priv, AR8216_REG_ATU_FUNC0, AR8216_ATU_OP_FLUSH | + AR8216_ATU_ACTIVE); + + return ret; +} + +static int +ar8216_atu_flush_port(struct ar8xxx_priv *priv, int port) +{ + u32 t; + int ret; + + ret = ar8216_wait_bit(priv, AR8216_REG_ATU_FUNC0, AR8216_ATU_ACTIVE, 0); + if (!ret) { + t = (port << AR8216_ATU_PORT_NUM_S) | AR8216_ATU_OP_FLUSH_PORT; + t |= AR8216_ATU_ACTIVE; + ar8xxx_write(priv, AR8216_REG_ATU_FUNC0, t); + } + + return ret; +} + +static u32 +ar8216_read_port_status(struct ar8xxx_priv *priv, int port) +{ + return ar8xxx_read(priv, AR8216_REG_PORT_STATUS(port)); +} + +static void +ar8216_setup_port(struct ar8xxx_priv *priv, int port, u32 members) +{ + u32 header; + u32 egress, ingress; + u32 pvid; + + if (priv->vlan) { + pvid = priv->vlan_id[priv->pvid[port]]; + if (priv->vlan_tagged & (1 << port)) + egress = AR8216_OUT_ADD_VLAN; + else + egress = AR8216_OUT_STRIP_VLAN; + ingress = AR8216_IN_SECURE; + } else { + pvid = port; + egress = AR8216_OUT_KEEP; + ingress = AR8216_IN_PORT_ONLY; + } + + if (chip_is_ar8216(priv) && priv->vlan && port == AR8216_PORT_CPU) + header = AR8216_PORT_CTRL_HEADER; + else + header = 0; + + ar8xxx_rmw(priv, AR8216_REG_PORT_CTRL(port), + AR8216_PORT_CTRL_LEARN | AR8216_PORT_CTRL_VLAN_MODE | + AR8216_PORT_CTRL_SINGLE_VLAN | AR8216_PORT_CTRL_STATE | + AR8216_PORT_CTRL_HEADER | AR8216_PORT_CTRL_LEARN_LOCK, + AR8216_PORT_CTRL_LEARN | header | + (egress << AR8216_PORT_CTRL_VLAN_MODE_S) | + (AR8216_PORT_STATE_FORWARD << AR8216_PORT_CTRL_STATE_S)); + + ar8xxx_rmw(priv, AR8216_REG_PORT_VLAN(port), + AR8216_PORT_VLAN_DEST_PORTS | AR8216_PORT_VLAN_MODE | + AR8216_PORT_VLAN_DEFAULT_ID, + (members << AR8216_PORT_VLAN_DEST_PORTS_S) | + (ingress << AR8216_PORT_VLAN_MODE_S) | + (pvid << AR8216_PORT_VLAN_DEFAULT_ID_S)); +} + +static int +ar8216_hw_init(struct ar8xxx_priv *priv) +{ + if (priv->initialized) + return 0; + + ar8xxx_phy_init(priv); + + priv->initialized = true; + return 0; +} + +static void +ar8216_init_globals(struct ar8xxx_priv *priv) +{ + /* standard atheros magic */ + ar8xxx_write(priv, 0x38, 0xc000050e); + + ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CTRL, + AR8216_GCTRL_MTU, 1518 + 8 + 2); +} + +static void +ar8216_init_port(struct ar8xxx_priv *priv, int port) +{ + /* Enable port learning and tx */ + ar8xxx_write(priv, AR8216_REG_PORT_CTRL(port), + AR8216_PORT_CTRL_LEARN | + (4 << AR8216_PORT_CTRL_STATE_S)); + + ar8xxx_write(priv, AR8216_REG_PORT_VLAN(port), 0); + + if (port == AR8216_PORT_CPU) { + ar8xxx_write(priv, AR8216_REG_PORT_STATUS(port), + AR8216_PORT_STATUS_LINK_UP | + (ar8xxx_has_gige(priv) ? + AR8216_PORT_SPEED_1000M : AR8216_PORT_SPEED_100M) | + AR8216_PORT_STATUS_TXMAC | + AR8216_PORT_STATUS_RXMAC | + (chip_is_ar8316(priv) ? AR8216_PORT_STATUS_RXFLOW : 0) | + (chip_is_ar8316(priv) ? AR8216_PORT_STATUS_TXFLOW : 0) | + AR8216_PORT_STATUS_DUPLEX); + } else { + ar8xxx_write(priv, AR8216_REG_PORT_STATUS(port), + AR8216_PORT_STATUS_LINK_AUTO); + } +} + +static void +ar8216_wait_atu_ready(struct ar8xxx_priv *priv, u16 r2, u16 r1) +{ + int timeout = 20; + + while (ar8xxx_mii_read32(priv, r2, r1) & AR8216_ATU_ACTIVE && --timeout) + udelay(10); + + if (!timeout) + pr_err("ar8216: timeout waiting for atu to become ready\n"); +} + +static void ar8216_get_arl_entry(struct ar8xxx_priv *priv, + struct arl_entry *a, u32 *status, enum arl_op op) +{ + struct mii_bus *bus = priv->mii_bus; + u16 r2, page; + u16 r1_func0, r1_func1, r1_func2; + u32 t, val0, val1, val2; + int i; + + split_addr(AR8216_REG_ATU_FUNC0, &r1_func0, &r2, &page); + r2 |= 0x10; + + r1_func1 = (AR8216_REG_ATU_FUNC1 >> 1) & 0x1e; + r1_func2 = (AR8216_REG_ATU_FUNC2 >> 1) & 0x1e; + + switch (op) { + case AR8XXX_ARL_INITIALIZE: + /* all ATU registers are on the same page + * therefore set page only once + */ + bus->write(bus, 0x18, 0, page); + wait_for_page_switch(); + + ar8216_wait_atu_ready(priv, r2, r1_func0); + + ar8xxx_mii_write32(priv, r2, r1_func0, AR8216_ATU_OP_GET_NEXT); + ar8xxx_mii_write32(priv, r2, r1_func1, 0); + ar8xxx_mii_write32(priv, r2, r1_func2, 0); + break; + case AR8XXX_ARL_GET_NEXT: + t = ar8xxx_mii_read32(priv, r2, r1_func0); + t |= AR8216_ATU_ACTIVE; + ar8xxx_mii_write32(priv, r2, r1_func0, t); + ar8216_wait_atu_ready(priv, r2, r1_func0); + + val0 = ar8xxx_mii_read32(priv, r2, r1_func0); + val1 = ar8xxx_mii_read32(priv, r2, r1_func1); + val2 = ar8xxx_mii_read32(priv, r2, r1_func2); + + *status = (val2 & AR8216_ATU_STATUS) >> AR8216_ATU_STATUS_S; + if (!*status) + break; + + i = 0; + t = AR8216_ATU_PORT0; + while (!(val2 & t) && ++i < priv->dev.ports) + t <<= 1; + + a->port = i; + a->mac[0] = (val0 & AR8216_ATU_ADDR5) >> AR8216_ATU_ADDR5_S; + a->mac[1] = (val0 & AR8216_ATU_ADDR4) >> AR8216_ATU_ADDR4_S; + a->mac[2] = (val1 & AR8216_ATU_ADDR3) >> AR8216_ATU_ADDR3_S; + a->mac[3] = (val1 & AR8216_ATU_ADDR2) >> AR8216_ATU_ADDR2_S; + a->mac[4] = (val1 & AR8216_ATU_ADDR1) >> AR8216_ATU_ADDR1_S; + a->mac[5] = (val1 & AR8216_ATU_ADDR0) >> AR8216_ATU_ADDR0_S; + break; + } +} + +static void +ar8236_setup_port(struct ar8xxx_priv *priv, int port, u32 members) +{ + u32 egress, ingress; + u32 pvid; + + if (priv->vlan) { + pvid = priv->vlan_id[priv->pvid[port]]; + if (priv->vlan_tagged & (1 << port)) + egress = AR8216_OUT_ADD_VLAN; + else + egress = AR8216_OUT_STRIP_VLAN; + ingress = AR8216_IN_SECURE; + } else { + pvid = port; + egress = AR8216_OUT_KEEP; + ingress = AR8216_IN_PORT_ONLY; + } + + ar8xxx_rmw(priv, AR8216_REG_PORT_CTRL(port), + AR8216_PORT_CTRL_LEARN | AR8216_PORT_CTRL_VLAN_MODE | + AR8216_PORT_CTRL_SINGLE_VLAN | AR8216_PORT_CTRL_STATE | + AR8216_PORT_CTRL_HEADER | AR8216_PORT_CTRL_LEARN_LOCK, + AR8216_PORT_CTRL_LEARN | + (egress << AR8216_PORT_CTRL_VLAN_MODE_S) | + (AR8216_PORT_STATE_FORWARD << AR8216_PORT_CTRL_STATE_S)); + + ar8xxx_rmw(priv, AR8236_REG_PORT_VLAN(port), + AR8236_PORT_VLAN_DEFAULT_ID, + (pvid << AR8236_PORT_VLAN_DEFAULT_ID_S)); + + ar8xxx_rmw(priv, AR8236_REG_PORT_VLAN2(port), + AR8236_PORT_VLAN2_VLAN_MODE | + AR8236_PORT_VLAN2_MEMBER, + (ingress << AR8236_PORT_VLAN2_VLAN_MODE_S) | + (members << AR8236_PORT_VLAN2_MEMBER_S)); +} + +static void +ar8236_init_globals(struct ar8xxx_priv *priv) +{ + /* enable jumbo frames */ + ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CTRL, + AR8316_GCTRL_MTU, 9018 + 8 + 2); + + /* enable cpu port to receive arp frames */ + ar8xxx_reg_set(priv, AR8216_REG_ATU_CTRL, + AR8236_ATU_CTRL_RES); + + /* enable cpu port to receive multicast and broadcast frames */ + ar8xxx_reg_set(priv, AR8216_REG_FLOOD_MASK, + AR8236_FM_CPU_BROADCAST_EN | AR8236_FM_CPU_BCAST_FWD_EN); + + /* Enable MIB counters */ + ar8xxx_rmw(priv, AR8216_REG_MIB_FUNC, AR8216_MIB_FUNC | AR8236_MIB_EN, + (AR8216_MIB_FUNC_NO_OP << AR8216_MIB_FUNC_S) | + AR8236_MIB_EN); +} + +static int +ar8316_hw_init(struct ar8xxx_priv *priv) +{ + u32 val, newval; + + val = ar8xxx_read(priv, AR8316_REG_POSTRIP); + + if (priv->phy->interface == PHY_INTERFACE_MODE_RGMII) { + if (priv->port4_phy) { + /* value taken from Ubiquiti RouterStation Pro */ + newval = 0x81461bea; + pr_info("ar8316: Using port 4 as PHY\n"); + } else { + newval = 0x01261be2; + pr_info("ar8316: Using port 4 as switch port\n"); + } + } else if (priv->phy->interface == PHY_INTERFACE_MODE_GMII) { + /* value taken from AVM Fritz!Box 7390 sources */ + newval = 0x010e5b71; + } else { + /* no known value for phy interface */ + pr_err("ar8316: unsupported mii mode: %d.\n", + priv->phy->interface); + return -EINVAL; + } + + if (val == newval) + goto out; + + ar8xxx_write(priv, AR8316_REG_POSTRIP, newval); + + if (priv->port4_phy && + priv->phy->interface == PHY_INTERFACE_MODE_RGMII) { + /* work around for phy4 rgmii mode */ + ar8xxx_phy_dbg_write(priv, 4, 0x12, 0x480c); + /* rx delay */ + ar8xxx_phy_dbg_write(priv, 4, 0x0, 0x824e); + /* tx delay */ + ar8xxx_phy_dbg_write(priv, 4, 0x5, 0x3d47); + msleep(1000); + } + + ar8xxx_phy_init(priv); + +out: + priv->initialized = true; + return 0; +} + +static void +ar8316_init_globals(struct ar8xxx_priv *priv) +{ + /* standard atheros magic */ + ar8xxx_write(priv, 0x38, 0xc000050e); + + /* enable cpu port to receive multicast and broadcast frames */ + ar8xxx_write(priv, AR8216_REG_FLOOD_MASK, 0x003f003f); + + /* enable jumbo frames */ + ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CTRL, + AR8316_GCTRL_MTU, 9018 + 8 + 2); + + /* Enable MIB counters */ + ar8xxx_rmw(priv, AR8216_REG_MIB_FUNC, AR8216_MIB_FUNC | AR8236_MIB_EN, + (AR8216_MIB_FUNC_NO_OP << AR8216_MIB_FUNC_S) | + AR8236_MIB_EN); +} + +int +ar8xxx_sw_set_vlan(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + priv->vlan = !!val->value.i; + return 0; +} + +int +ar8xxx_sw_get_vlan(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + val->value.i = priv->vlan; + return 0; +} + + +int +ar8xxx_sw_set_pvid(struct switch_dev *dev, int port, int vlan) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + + /* make sure no invalid PVIDs get set */ + + if (vlan >= dev->vlans) + return -EINVAL; + + priv->pvid[port] = vlan; + return 0; +} + +int +ar8xxx_sw_get_pvid(struct switch_dev *dev, int port, int *vlan) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + *vlan = priv->pvid[port]; + return 0; +} + +static int +ar8xxx_sw_set_vid(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + priv->vlan_id[val->port_vlan] = val->value.i; + return 0; +} + +static int +ar8xxx_sw_get_vid(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + val->value.i = priv->vlan_id[val->port_vlan]; + return 0; +} + +int +ar8xxx_sw_get_port_link(struct switch_dev *dev, int port, + struct switch_port_link *link) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + + ar8216_read_port_link(priv, port, link); + return 0; +} + +static int +ar8xxx_sw_get_ports(struct switch_dev *dev, struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + u8 ports = priv->vlan_table[val->port_vlan]; + int i; + + val->len = 0; + for (i = 0; i < dev->ports; i++) { + struct switch_port *p; + + if (!(ports & (1 << i))) + continue; + + p = &val->value.ports[val->len++]; + p->id = i; + if (priv->vlan_tagged & (1 << i)) + p->flags = (1 << SWITCH_PORT_FLAG_TAGGED); + else + p->flags = 0; + } + return 0; +} + +static int +ar8xxx_sw_set_ports(struct switch_dev *dev, struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + u8 *vt = &priv->vlan_table[val->port_vlan]; + int i, j; + + *vt = 0; + for (i = 0; i < val->len; i++) { + struct switch_port *p = &val->value.ports[i]; + + if (p->flags & (1 << SWITCH_PORT_FLAG_TAGGED)) { + priv->vlan_tagged |= (1 << p->id); + } else { + priv->vlan_tagged &= ~(1 << p->id); + priv->pvid[p->id] = val->port_vlan; + + /* make sure that an untagged port does not + * appear in other vlans */ + for (j = 0; j < AR8X16_MAX_VLANS; j++) { + if (j == val->port_vlan) + continue; + priv->vlan_table[j] &= ~(1 << p->id); + } + } + + *vt |= 1 << p->id; + } + return 0; +} + +static void +ar8216_set_mirror_regs(struct ar8xxx_priv *priv) +{ + int port; + + /* reset all mirror registers */ + ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CPUPORT, + AR8216_GLOBAL_CPUPORT_MIRROR_PORT, + (0xF << AR8216_GLOBAL_CPUPORT_MIRROR_PORT_S)); + for (port = 0; port < AR8216_NUM_PORTS; port++) { + ar8xxx_reg_clear(priv, AR8216_REG_PORT_CTRL(port), + AR8216_PORT_CTRL_MIRROR_RX); + + ar8xxx_reg_clear(priv, AR8216_REG_PORT_CTRL(port), + AR8216_PORT_CTRL_MIRROR_TX); + } + + /* now enable mirroring if necessary */ + if (priv->source_port >= AR8216_NUM_PORTS || + priv->monitor_port >= AR8216_NUM_PORTS || + priv->source_port == priv->monitor_port) { + return; + } + + ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CPUPORT, + AR8216_GLOBAL_CPUPORT_MIRROR_PORT, + (priv->monitor_port << AR8216_GLOBAL_CPUPORT_MIRROR_PORT_S)); + + if (priv->mirror_rx) + ar8xxx_reg_set(priv, AR8216_REG_PORT_CTRL(priv->source_port), + AR8216_PORT_CTRL_MIRROR_RX); + + if (priv->mirror_tx) + ar8xxx_reg_set(priv, AR8216_REG_PORT_CTRL(priv->source_port), + AR8216_PORT_CTRL_MIRROR_TX); +} + +int +ar8xxx_sw_hw_apply(struct switch_dev *dev) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + u8 portmask[AR8X16_MAX_PORTS]; + int i, j; + + mutex_lock(&priv->reg_mutex); + /* flush all vlan translation unit entries */ + priv->chip->vtu_flush(priv); + + memset(portmask, 0, sizeof(portmask)); + if (!priv->init) { + /* calculate the port destination masks and load vlans + * into the vlan translation unit */ + for (j = 0; j < AR8X16_MAX_VLANS; j++) { + u8 vp = priv->vlan_table[j]; + + if (!vp) + continue; + + for (i = 0; i < dev->ports; i++) { + u8 mask = (1 << i); + if (vp & mask) + portmask[i] |= vp & ~mask; + } + + priv->chip->vtu_load_vlan(priv, priv->vlan_id[j], + priv->vlan_table[j]); + } + } else { + /* vlan disabled: + * isolate all ports, but connect them to the cpu port */ + for (i = 0; i < dev->ports; i++) { + if (i == AR8216_PORT_CPU) + continue; + + portmask[i] = 1 << AR8216_PORT_CPU; + portmask[AR8216_PORT_CPU] |= (1 << i); + } + } + + /* update the port destination mask registers and tag settings */ + for (i = 0; i < dev->ports; i++) { + priv->chip->setup_port(priv, i, portmask[i]); + } + + priv->chip->set_mirror_regs(priv); + + mutex_unlock(&priv->reg_mutex); + return 0; +} + +int +ar8xxx_sw_reset_switch(struct switch_dev *dev) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + const struct ar8xxx_chip *chip = priv->chip; + int i; + + mutex_lock(&priv->reg_mutex); + memset(&priv->vlan, 0, sizeof(struct ar8xxx_priv) - + offsetof(struct ar8xxx_priv, vlan)); + + for (i = 0; i < AR8X16_MAX_VLANS; i++) + priv->vlan_id[i] = i; + + /* Configure all ports */ + for (i = 0; i < dev->ports; i++) + chip->init_port(priv, i); + + priv->mirror_rx = false; + priv->mirror_tx = false; + priv->source_port = 0; + priv->monitor_port = 0; + + chip->init_globals(priv); + + mutex_unlock(&priv->reg_mutex); + + return chip->sw_hw_apply(dev); +} + +int +ar8xxx_sw_set_reset_mibs(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + unsigned int len; + int ret; + + if (!ar8xxx_has_mib_counters(priv)) + return -EOPNOTSUPP; + + mutex_lock(&priv->mib_lock); + + len = priv->dev.ports * priv->chip->num_mibs * + sizeof(*priv->mib_stats); + memset(priv->mib_stats, '\0', len); + ret = ar8xxx_mib_flush(priv); + if (ret) + goto unlock; + + ret = 0; + +unlock: + mutex_unlock(&priv->mib_lock); + return ret; +} + +int +ar8xxx_sw_set_mirror_rx_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + + mutex_lock(&priv->reg_mutex); + priv->mirror_rx = !!val->value.i; + priv->chip->set_mirror_regs(priv); + mutex_unlock(&priv->reg_mutex); + + return 0; +} + +int +ar8xxx_sw_get_mirror_rx_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + val->value.i = priv->mirror_rx; + return 0; +} + +int +ar8xxx_sw_set_mirror_tx_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + + mutex_lock(&priv->reg_mutex); + priv->mirror_tx = !!val->value.i; + priv->chip->set_mirror_regs(priv); + mutex_unlock(&priv->reg_mutex); + + return 0; +} + +int +ar8xxx_sw_get_mirror_tx_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + val->value.i = priv->mirror_tx; + return 0; +} + +int +ar8xxx_sw_set_mirror_monitor_port(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + + mutex_lock(&priv->reg_mutex); + priv->monitor_port = val->value.i; + priv->chip->set_mirror_regs(priv); + mutex_unlock(&priv->reg_mutex); + + return 0; +} + +int +ar8xxx_sw_get_mirror_monitor_port(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + val->value.i = priv->monitor_port; + return 0; +} + +int +ar8xxx_sw_set_mirror_source_port(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + + mutex_lock(&priv->reg_mutex); + priv->source_port = val->value.i; + priv->chip->set_mirror_regs(priv); + mutex_unlock(&priv->reg_mutex); + + return 0; +} + +int +ar8xxx_sw_get_mirror_source_port(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + val->value.i = priv->source_port; + return 0; +} + +int +ar8xxx_sw_set_port_reset_mib(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + int port; + int ret; + + if (!ar8xxx_has_mib_counters(priv)) + return -EOPNOTSUPP; + + port = val->port_vlan; + if (port >= dev->ports) + return -EINVAL; + + mutex_lock(&priv->mib_lock); + ret = ar8xxx_mib_capture(priv); + if (ret) + goto unlock; + + ar8xxx_mib_fetch_port_stat(priv, port, true); + + ret = 0; + +unlock: + mutex_unlock(&priv->mib_lock); + return ret; +} + +int +ar8xxx_sw_get_port_mib(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + const struct ar8xxx_chip *chip = priv->chip; + u64 *mib_stats; + int port; + int ret; + char *buf = priv->buf; + int i, len = 0; + + if (!ar8xxx_has_mib_counters(priv)) + return -EOPNOTSUPP; + + port = val->port_vlan; + if (port >= dev->ports) + return -EINVAL; + + mutex_lock(&priv->mib_lock); + ret = ar8xxx_mib_capture(priv); + if (ret) + goto unlock; + + ar8xxx_mib_fetch_port_stat(priv, port, false); + + len += snprintf(buf + len, sizeof(priv->buf) - len, + "Port %d MIB counters\n", + port); + + mib_stats = &priv->mib_stats[port * chip->num_mibs]; + for (i = 0; i < chip->num_mibs; i++) + len += snprintf(buf + len, sizeof(priv->buf) - len, + "%-12s: %llu\n", + chip->mib_decs[i].name, + mib_stats[i]); + + val->value.s = buf; + val->len = len; + + ret = 0; + +unlock: + mutex_unlock(&priv->mib_lock); + return ret; +} + +int +ar8xxx_sw_get_arl_table(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + struct mii_bus *bus = priv->mii_bus; + const struct ar8xxx_chip *chip = priv->chip; + char *buf = priv->arl_buf; + int i, j, k, len = 0; + struct arl_entry *a, *a1; + u32 status; + + if (!chip->get_arl_entry) + return -EOPNOTSUPP; + + mutex_lock(&priv->reg_mutex); + mutex_lock(&bus->mdio_lock); + + chip->get_arl_entry(priv, NULL, NULL, AR8XXX_ARL_INITIALIZE); + + for(i = 0; i < AR8XXX_NUM_ARL_RECORDS; ++i) { + a = &priv->arl_table[i]; + duplicate: + chip->get_arl_entry(priv, a, &status, AR8XXX_ARL_GET_NEXT); + + if (!status) + break; + + /* avoid duplicates + * ARL table can include multiple valid entries + * per MAC, just with differing status codes + */ + for (j = 0; j < i; ++j) { + a1 = &priv->arl_table[j]; + if (a->port == a1->port && !memcmp(a->mac, a1->mac, sizeof(a->mac))) + goto duplicate; + } + } + + mutex_unlock(&bus->mdio_lock); + + len += snprintf(buf + len, sizeof(priv->arl_buf) - len, + "address resolution table\n"); + + if (i == AR8XXX_NUM_ARL_RECORDS) + len += snprintf(buf + len, sizeof(priv->arl_buf) - len, + "Too many entries found, displaying the first %d only!\n", + AR8XXX_NUM_ARL_RECORDS); + + for (j = 0; j < priv->dev.ports; ++j) { + for (k = 0; k < i; ++k) { + a = &priv->arl_table[k]; + if (a->port != j) + continue; + len += snprintf(buf + len, sizeof(priv->arl_buf) - len, + "Port %d: MAC %02x:%02x:%02x:%02x:%02x:%02x\n", + j, + a->mac[5], a->mac[4], a->mac[3], + a->mac[2], a->mac[1], a->mac[0]); + } + } + + val->value.s = buf; + val->len = len; + + mutex_unlock(&priv->reg_mutex); + + return 0; +} + +int +ar8xxx_sw_set_flush_arl_table(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + int ret; + + mutex_lock(&priv->reg_mutex); + ret = priv->chip->atu_flush(priv); + mutex_unlock(&priv->reg_mutex); + + return ret; +} + +int +ar8xxx_sw_set_flush_port_arl_table(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + int port, ret; + + port = val->port_vlan; + if (port >= dev->ports) + return -EINVAL; + + mutex_lock(&priv->reg_mutex); + ret = priv->chip->atu_flush_port(priv, port); + mutex_unlock(&priv->reg_mutex); + + return ret; +} + +static const struct switch_attr ar8xxx_sw_attr_globals[] = { + { + .type = SWITCH_TYPE_INT, + .name = "enable_vlan", + .description = "Enable VLAN mode", + .set = ar8xxx_sw_set_vlan, + .get = ar8xxx_sw_get_vlan, + .max = 1 + }, + { + .type = SWITCH_TYPE_NOVAL, + .name = "reset_mibs", + .description = "Reset all MIB counters", + .set = ar8xxx_sw_set_reset_mibs, + }, + { + .type = SWITCH_TYPE_INT, + .name = "enable_mirror_rx", + .description = "Enable mirroring of RX packets", + .set = ar8xxx_sw_set_mirror_rx_enable, + .get = ar8xxx_sw_get_mirror_rx_enable, + .max = 1 + }, + { + .type = SWITCH_TYPE_INT, + .name = "enable_mirror_tx", + .description = "Enable mirroring of TX packets", + .set = ar8xxx_sw_set_mirror_tx_enable, + .get = ar8xxx_sw_get_mirror_tx_enable, + .max = 1 + }, + { + .type = SWITCH_TYPE_INT, + .name = "mirror_monitor_port", + .description = "Mirror monitor port", + .set = ar8xxx_sw_set_mirror_monitor_port, + .get = ar8xxx_sw_get_mirror_monitor_port, + .max = AR8216_NUM_PORTS - 1 + }, + { + .type = SWITCH_TYPE_INT, + .name = "mirror_source_port", + .description = "Mirror source port", + .set = ar8xxx_sw_set_mirror_source_port, + .get = ar8xxx_sw_get_mirror_source_port, + .max = AR8216_NUM_PORTS - 1 + }, + { + .type = SWITCH_TYPE_STRING, + .name = "arl_table", + .description = "Get ARL table", + .set = NULL, + .get = ar8xxx_sw_get_arl_table, + }, + { + .type = SWITCH_TYPE_NOVAL, + .name = "flush_arl_table", + .description = "Flush ARL table", + .set = ar8xxx_sw_set_flush_arl_table, + }, +}; + +const struct switch_attr ar8xxx_sw_attr_port[] = { + { + .type = SWITCH_TYPE_NOVAL, + .name = "reset_mib", + .description = "Reset single port MIB counters", + .set = ar8xxx_sw_set_port_reset_mib, + }, + { + .type = SWITCH_TYPE_STRING, + .name = "mib", + .description = "Get port's MIB counters", + .set = NULL, + .get = ar8xxx_sw_get_port_mib, + }, + { + .type = SWITCH_TYPE_NOVAL, + .name = "flush_arl_table", + .description = "Flush port's ARL table entries", + .set = ar8xxx_sw_set_flush_port_arl_table, + }, +}; + +const struct switch_attr ar8xxx_sw_attr_vlan[1] = { + { + .type = SWITCH_TYPE_INT, + .name = "vid", + .description = "VLAN ID (0-4094)", + .set = ar8xxx_sw_set_vid, + .get = ar8xxx_sw_get_vid, + .max = 4094, + }, +}; + +static const struct switch_dev_ops ar8xxx_sw_ops = { + .attr_global = { + .attr = ar8xxx_sw_attr_globals, + .n_attr = ARRAY_SIZE(ar8xxx_sw_attr_globals), + }, + .attr_port = { + .attr = ar8xxx_sw_attr_port, + .n_attr = ARRAY_SIZE(ar8xxx_sw_attr_port), + }, + .attr_vlan = { + .attr = ar8xxx_sw_attr_vlan, + .n_attr = ARRAY_SIZE(ar8xxx_sw_attr_vlan), + }, + .get_port_pvid = ar8xxx_sw_get_pvid, + .set_port_pvid = ar8xxx_sw_set_pvid, + .get_vlan_ports = ar8xxx_sw_get_ports, + .set_vlan_ports = ar8xxx_sw_set_ports, + .apply_config = ar8xxx_sw_hw_apply, + .reset_switch = ar8xxx_sw_reset_switch, + .get_port_link = ar8xxx_sw_get_port_link, +}; + +static const struct ar8xxx_chip ar8216_chip = { + .caps = AR8XXX_CAP_MIB_COUNTERS, + + .reg_port_stats_start = 0x19000, + .reg_port_stats_length = 0xa0, + + .name = "Atheros AR8216", + .ports = AR8216_NUM_PORTS, + .vlans = AR8216_NUM_VLANS, + .swops = &ar8xxx_sw_ops, + + .hw_init = ar8216_hw_init, + .init_globals = ar8216_init_globals, + .init_port = ar8216_init_port, + .setup_port = ar8216_setup_port, + .read_port_status = ar8216_read_port_status, + .atu_flush = ar8216_atu_flush, + .atu_flush_port = ar8216_atu_flush_port, + .vtu_flush = ar8216_vtu_flush, + .vtu_load_vlan = ar8216_vtu_load_vlan, + .set_mirror_regs = ar8216_set_mirror_regs, + .get_arl_entry = ar8216_get_arl_entry, + .sw_hw_apply = ar8xxx_sw_hw_apply, + + .num_mibs = ARRAY_SIZE(ar8216_mibs), + .mib_decs = ar8216_mibs, + .mib_func = AR8216_REG_MIB_FUNC +}; + +static const struct ar8xxx_chip ar8236_chip = { + .caps = AR8XXX_CAP_MIB_COUNTERS, + + .reg_port_stats_start = 0x20000, + .reg_port_stats_length = 0x100, + + .name = "Atheros AR8236", + .ports = AR8216_NUM_PORTS, + .vlans = AR8216_NUM_VLANS, + .swops = &ar8xxx_sw_ops, + + .hw_init = ar8216_hw_init, + .init_globals = ar8236_init_globals, + .init_port = ar8216_init_port, + .setup_port = ar8236_setup_port, + .read_port_status = ar8216_read_port_status, + .atu_flush = ar8216_atu_flush, + .atu_flush_port = ar8216_atu_flush_port, + .vtu_flush = ar8216_vtu_flush, + .vtu_load_vlan = ar8216_vtu_load_vlan, + .set_mirror_regs = ar8216_set_mirror_regs, + .get_arl_entry = ar8216_get_arl_entry, + .sw_hw_apply = ar8xxx_sw_hw_apply, + + .num_mibs = ARRAY_SIZE(ar8236_mibs), + .mib_decs = ar8236_mibs, + .mib_func = AR8216_REG_MIB_FUNC +}; + +static const struct ar8xxx_chip ar8316_chip = { + .caps = AR8XXX_CAP_GIGE | AR8XXX_CAP_MIB_COUNTERS, + + .reg_port_stats_start = 0x20000, + .reg_port_stats_length = 0x100, + + .name = "Atheros AR8316", + .ports = AR8216_NUM_PORTS, + .vlans = AR8X16_MAX_VLANS, + .swops = &ar8xxx_sw_ops, + + .hw_init = ar8316_hw_init, + .init_globals = ar8316_init_globals, + .init_port = ar8216_init_port, + .setup_port = ar8216_setup_port, + .read_port_status = ar8216_read_port_status, + .atu_flush = ar8216_atu_flush, + .atu_flush_port = ar8216_atu_flush_port, + .vtu_flush = ar8216_vtu_flush, + .vtu_load_vlan = ar8216_vtu_load_vlan, + .set_mirror_regs = ar8216_set_mirror_regs, + .get_arl_entry = ar8216_get_arl_entry, + .sw_hw_apply = ar8xxx_sw_hw_apply, + + .num_mibs = ARRAY_SIZE(ar8236_mibs), + .mib_decs = ar8236_mibs, + .mib_func = AR8216_REG_MIB_FUNC +}; + +static int +ar8xxx_id_chip(struct ar8xxx_priv *priv) +{ + u32 val; + u16 id; + int i; + + val = ar8xxx_read(priv, AR8216_REG_CTRL); + if (val == ~0) + return -ENODEV; + + id = val & (AR8216_CTRL_REVISION | AR8216_CTRL_VERSION); + for (i = 0; i < AR8X16_PROBE_RETRIES; i++) { + u16 t; + + val = ar8xxx_read(priv, AR8216_REG_CTRL); + if (val == ~0) + return -ENODEV; + + t = val & (AR8216_CTRL_REVISION | AR8216_CTRL_VERSION); + if (t != id) + return -ENODEV; + } + + priv->chip_ver = (id & AR8216_CTRL_VERSION) >> AR8216_CTRL_VERSION_S; + priv->chip_rev = (id & AR8216_CTRL_REVISION); + + switch (priv->chip_ver) { + case AR8XXX_VER_AR8216: + priv->chip = &ar8216_chip; + break; + case AR8XXX_VER_AR8236: + priv->chip = &ar8236_chip; + break; + case AR8XXX_VER_AR8316: + priv->chip = &ar8316_chip; + break; + case AR8XXX_VER_AR8327: + priv->chip = &ar8327_chip; + break; + case AR8XXX_VER_AR8337: + priv->chip = &ar8337_chip; + break; + default: + pr_err("ar8216: Unknown Atheros device [ver=%d, rev=%d]\n", + priv->chip_ver, priv->chip_rev); + + return -ENODEV; + } + + return 0; +} + +static void +ar8xxx_mib_work_func(struct work_struct *work) +{ + struct ar8xxx_priv *priv; + int err; + + priv = container_of(work, struct ar8xxx_priv, mib_work.work); + + mutex_lock(&priv->mib_lock); + + err = ar8xxx_mib_capture(priv); + if (err) + goto next_port; + + ar8xxx_mib_fetch_port_stat(priv, priv->mib_next_port, false); + +next_port: + priv->mib_next_port++; + if (priv->mib_next_port >= priv->dev.ports) + priv->mib_next_port = 0; + + mutex_unlock(&priv->mib_lock); + schedule_delayed_work(&priv->mib_work, + msecs_to_jiffies(AR8XXX_MIB_WORK_DELAY)); +} + +static int +ar8xxx_mib_init(struct ar8xxx_priv *priv) +{ + unsigned int len; + + if (!ar8xxx_has_mib_counters(priv)) + return 0; + + BUG_ON(!priv->chip->mib_decs || !priv->chip->num_mibs); + + len = priv->dev.ports * priv->chip->num_mibs * + sizeof(*priv->mib_stats); + priv->mib_stats = kzalloc(len, GFP_KERNEL); + + if (!priv->mib_stats) + return -ENOMEM; + + return 0; +} + +static void +ar8xxx_mib_start(struct ar8xxx_priv *priv) +{ + if (!ar8xxx_has_mib_counters(priv)) + return; + + schedule_delayed_work(&priv->mib_work, + msecs_to_jiffies(AR8XXX_MIB_WORK_DELAY)); +} + +static void +ar8xxx_mib_stop(struct ar8xxx_priv *priv) +{ + if (!ar8xxx_has_mib_counters(priv)) + return; + + cancel_delayed_work(&priv->mib_work); +} + +static struct ar8xxx_priv * +ar8xxx_create(void) +{ + struct ar8xxx_priv *priv; + + priv = kzalloc(sizeof(struct ar8xxx_priv), GFP_KERNEL); + if (priv == NULL) + return NULL; + + mutex_init(&priv->reg_mutex); + mutex_init(&priv->mib_lock); + INIT_DELAYED_WORK(&priv->mib_work, ar8xxx_mib_work_func); + + return priv; +} + +static void +ar8xxx_free(struct ar8xxx_priv *priv) +{ + if (priv->chip && priv->chip->cleanup) + priv->chip->cleanup(priv); + + kfree(priv->chip_data); + kfree(priv->mib_stats); + kfree(priv); +} + +static int +ar8xxx_probe_switch(struct ar8xxx_priv *priv) +{ + const struct ar8xxx_chip *chip; + struct switch_dev *swdev; + int ret; + + ret = ar8xxx_id_chip(priv); + if (ret) + return ret; + + chip = priv->chip; + + swdev = &priv->dev; + swdev->cpu_port = AR8216_PORT_CPU; + swdev->name = chip->name; + swdev->vlans = chip->vlans; + swdev->ports = chip->ports; + swdev->ops = chip->swops; + + ret = ar8xxx_mib_init(priv); + if (ret) + return ret; + + return 0; +} + +static int +ar8xxx_start(struct ar8xxx_priv *priv) +{ + int ret; + + priv->init = true; + + ret = priv->chip->hw_init(priv); + if (ret) + return ret; + + ret = ar8xxx_sw_reset_switch(&priv->dev); + if (ret) + return ret; + + priv->init = false; + + ar8xxx_mib_start(priv); + + return 0; +} + +static int +ar8xxx_phy_config_init(struct phy_device *phydev) +{ + struct ar8xxx_priv *priv = phydev->priv; + struct net_device *dev = phydev->attached_dev; + int ret; + + if (WARN_ON(!priv)) + return -ENODEV; + + if (priv->chip->config_at_probe) + return ar8xxx_phy_check_aneg(phydev); + + priv->phy = phydev; + + if (phydev->addr != 0) { + if (chip_is_ar8316(priv)) { + /* switch device has been initialized, reinit */ + priv->dev.ports = (AR8216_NUM_PORTS - 1); + priv->initialized = false; + priv->port4_phy = true; + ar8316_hw_init(priv); + return 0; + } + + return 0; + } + + ret = ar8xxx_start(priv); + if (ret) + return ret; + + /* VID fixup only needed on ar8216 */ + if (chip_is_ar8216(priv)) { + dev->phy_ptr = priv; + dev->priv_flags |= IFF_NO_IP_ALIGN; + dev->eth_mangle_rx = ar8216_mangle_rx; + dev->eth_mangle_tx = ar8216_mangle_tx; + } + + return 0; +} + +static bool +ar8xxx_check_link_states(struct ar8xxx_priv *priv) +{ + bool link_new, changed = false; + u32 status; + int i; + + mutex_lock(&priv->reg_mutex); + + for (i = 0; i < priv->dev.ports; i++) { + status = priv->chip->read_port_status(priv, i); + link_new = !!(status & AR8216_PORT_STATUS_LINK_UP); + if (link_new == priv->link_up[i]) + continue; + + priv->link_up[i] = link_new; + changed = true; + /* flush ARL entries for this port if it went down*/ + if (!link_new) + priv->chip->atu_flush_port(priv, i); + dev_info(&priv->phy->dev, "Port %d is %s\n", + i, link_new ? "up" : "down"); + } + + mutex_unlock(&priv->reg_mutex); + + return changed; +} + +static int +ar8xxx_phy_read_status(struct phy_device *phydev) +{ + struct ar8xxx_priv *priv = phydev->priv; + struct switch_port_link link; + + /* check for switch port link changes */ + if (phydev->state == PHY_CHANGELINK) + ar8xxx_check_link_states(priv); + + if (phydev->addr != 0) + return genphy_read_status(phydev); + + ar8216_read_port_link(priv, phydev->addr, &link); + phydev->link = !!link.link; + if (!phydev->link) + return 0; + + switch (link.speed) { + case SWITCH_PORT_SPEED_10: + phydev->speed = SPEED_10; + break; + case SWITCH_PORT_SPEED_100: + phydev->speed = SPEED_100; + break; + case SWITCH_PORT_SPEED_1000: + phydev->speed = SPEED_1000; + break; + default: + phydev->speed = 0; + } + phydev->duplex = link.duplex ? DUPLEX_FULL : DUPLEX_HALF; + + phydev->state = PHY_RUNNING; + netif_carrier_on(phydev->attached_dev); + phydev->adjust_link(phydev->attached_dev); + + return 0; +} + +static int +ar8xxx_phy_config_aneg(struct phy_device *phydev) +{ + if (phydev->addr == 0) + return 0; + + return genphy_config_aneg(phydev); +} + +static const u32 ar8xxx_phy_ids[] = { + 0x004dd033, + 0x004dd034, /* AR8327 */ + 0x004dd036, /* AR8337 */ + 0x004dd041, + 0x004dd042, + 0x004dd043, /* AR8236 */ +}; + +static bool +ar8xxx_phy_match(u32 phy_id) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(ar8xxx_phy_ids); i++) + if (phy_id == ar8xxx_phy_ids[i]) + return true; + + return false; +} + +static bool +ar8xxx_is_possible(struct mii_bus *bus) +{ + unsigned i; + + for (i = 0; i < 4; i++) { + u32 phy_id; + + phy_id = mdiobus_read(bus, i, MII_PHYSID1) << 16; + phy_id |= mdiobus_read(bus, i, MII_PHYSID2); + if (!ar8xxx_phy_match(phy_id)) { + pr_debug("ar8xxx: unknown PHY at %s:%02x id:%08x\n", + dev_name(&bus->dev), i, phy_id); + return false; + } + } + + return true; +} + +static int +ar8xxx_phy_probe(struct phy_device *phydev) +{ + struct ar8xxx_priv *priv; + struct switch_dev *swdev; + int ret; + + /* skip PHYs at unused adresses */ + if (phydev->addr != 0 && phydev->addr != 4) + return -ENODEV; + + if (!ar8xxx_is_possible(phydev->bus)) + return -ENODEV; + + mutex_lock(&ar8xxx_dev_list_lock); + list_for_each_entry(priv, &ar8xxx_dev_list, list) + if (priv->mii_bus == phydev->bus) + goto found; + + priv = ar8xxx_create(); + if (priv == NULL) { + ret = -ENOMEM; + goto unlock; + } + + priv->mii_bus = phydev->bus; + + ret = ar8xxx_probe_switch(priv); + if (ret) + goto free_priv; + + swdev = &priv->dev; + swdev->alias = dev_name(&priv->mii_bus->dev); + ret = register_switch(swdev, NULL); + if (ret) + goto free_priv; + + pr_info("%s: %s rev. %u switch registered on %s\n", + swdev->devname, swdev->name, priv->chip_rev, + dev_name(&priv->mii_bus->dev)); + +found: + priv->use_count++; + + if (phydev->addr == 0) { + if (ar8xxx_has_gige(priv)) { + phydev->supported = SUPPORTED_1000baseT_Full; + phydev->advertising = ADVERTISED_1000baseT_Full; + } else { + phydev->supported = SUPPORTED_100baseT_Full; + phydev->advertising = ADVERTISED_100baseT_Full; + } + + if (priv->chip->config_at_probe) { + priv->phy = phydev; + + ret = ar8xxx_start(priv); + if (ret) + goto err_unregister_switch; + } + } else { + if (ar8xxx_has_gige(priv)) { + phydev->supported |= SUPPORTED_1000baseT_Full; + phydev->advertising |= ADVERTISED_1000baseT_Full; + } + } + + phydev->priv = priv; + + list_add(&priv->list, &ar8xxx_dev_list); + + mutex_unlock(&ar8xxx_dev_list_lock); + + return 0; + +err_unregister_switch: + if (--priv->use_count) + goto unlock; + + unregister_switch(&priv->dev); + +free_priv: + ar8xxx_free(priv); +unlock: + mutex_unlock(&ar8xxx_dev_list_lock); + return ret; +} + +static void +ar8xxx_phy_detach(struct phy_device *phydev) +{ + struct net_device *dev = phydev->attached_dev; + + if (!dev) + return; + + dev->phy_ptr = NULL; + dev->priv_flags &= ~IFF_NO_IP_ALIGN; + dev->eth_mangle_rx = NULL; + dev->eth_mangle_tx = NULL; +} + +static void +ar8xxx_phy_remove(struct phy_device *phydev) +{ + struct ar8xxx_priv *priv = phydev->priv; + + if (WARN_ON(!priv)) + return; + + phydev->priv = NULL; + if (--priv->use_count > 0) + return; + + mutex_lock(&ar8xxx_dev_list_lock); + list_del(&priv->list); + mutex_unlock(&ar8xxx_dev_list_lock); + + unregister_switch(&priv->dev); + ar8xxx_mib_stop(priv); + ar8xxx_free(priv); +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0) +static int +ar8xxx_phy_soft_reset(struct phy_device *phydev) +{ + /* we don't need an extra reset */ + return 0; +} +#endif + +static struct phy_driver ar8xxx_phy_driver = { + .phy_id = 0x004d0000, + .name = "Atheros AR8216/AR8236/AR8316", + .phy_id_mask = 0xffff0000, + .features = PHY_BASIC_FEATURES, + .probe = ar8xxx_phy_probe, + .remove = ar8xxx_phy_remove, + .detach = ar8xxx_phy_detach, + .config_init = ar8xxx_phy_config_init, + .config_aneg = ar8xxx_phy_config_aneg, + .read_status = ar8xxx_phy_read_status, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0) + .soft_reset = ar8xxx_phy_soft_reset, +#endif + .driver = { .owner = THIS_MODULE }, +}; + +int __init +ar8xxx_init(void) +{ + return phy_driver_register(&ar8xxx_phy_driver); +} + +void __exit +ar8xxx_exit(void) +{ + phy_driver_unregister(&ar8xxx_phy_driver); +} + +module_init(ar8xxx_init); +module_exit(ar8xxx_exit); +MODULE_LICENSE("GPL"); + diff --git a/target/linux/generic/files/drivers/net/phy/ar8216.h b/target/linux/generic/files/drivers/net/phy/ar8216.h new file mode 100644 index 0000000..14fe928 --- /dev/null +++ b/target/linux/generic/files/drivers/net/phy/ar8216.h @@ -0,0 +1,628 @@ +/* + * ar8216.h: AR8216 switch driver + * + * Copyright (C) 2009 Felix Fietkau + * + * 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. + */ + +#ifndef __AR8216_H +#define __AR8216_H + +#define BITS(_s, _n) (((1UL << (_n)) - 1) << _s) + +#define AR8XXX_CAP_GIGE BIT(0) +#define AR8XXX_CAP_MIB_COUNTERS BIT(1) + +#define AR8XXX_NUM_PHYS 5 +#define AR8216_PORT_CPU 0 +#define AR8216_NUM_PORTS 6 +#define AR8216_NUM_VLANS 16 +#define AR8316_NUM_VLANS 4096 + +/* size of the vlan table */ +#define AR8X16_MAX_VLANS 128 +#define AR8X16_PROBE_RETRIES 10 +#define AR8X16_MAX_PORTS 8 + +/* Atheros specific MII registers */ +#define MII_ATH_MMD_ADDR 0x0d +#define MII_ATH_MMD_DATA 0x0e +#define MII_ATH_DBG_ADDR 0x1d +#define MII_ATH_DBG_DATA 0x1e + +#define AR8216_REG_CTRL 0x0000 +#define AR8216_CTRL_REVISION BITS(0, 8) +#define AR8216_CTRL_REVISION_S 0 +#define AR8216_CTRL_VERSION BITS(8, 8) +#define AR8216_CTRL_VERSION_S 8 +#define AR8216_CTRL_RESET BIT(31) + +#define AR8216_REG_FLOOD_MASK 0x002C +#define AR8216_FM_UNI_DEST_PORTS BITS(0, 6) +#define AR8216_FM_MULTI_DEST_PORTS BITS(16, 6) +#define AR8236_FM_CPU_BROADCAST_EN BIT(26) +#define AR8236_FM_CPU_BCAST_FWD_EN BIT(25) + +#define AR8216_REG_GLOBAL_CTRL 0x0030 +#define AR8216_GCTRL_MTU BITS(0, 11) +#define AR8236_GCTRL_MTU BITS(0, 14) +#define AR8316_GCTRL_MTU BITS(0, 14) + +#define AR8216_REG_VTU 0x0040 +#define AR8216_VTU_OP BITS(0, 3) +#define AR8216_VTU_OP_NOOP 0x0 +#define AR8216_VTU_OP_FLUSH 0x1 +#define AR8216_VTU_OP_LOAD 0x2 +#define AR8216_VTU_OP_PURGE 0x3 +#define AR8216_VTU_OP_REMOVE_PORT 0x4 +#define AR8216_VTU_ACTIVE BIT(3) +#define AR8216_VTU_FULL BIT(4) +#define AR8216_VTU_PORT BITS(8, 4) +#define AR8216_VTU_PORT_S 8 +#define AR8216_VTU_VID BITS(16, 12) +#define AR8216_VTU_VID_S 16 +#define AR8216_VTU_PRIO BITS(28, 3) +#define AR8216_VTU_PRIO_S 28 +#define AR8216_VTU_PRIO_EN BIT(31) + +#define AR8216_REG_VTU_DATA 0x0044 +#define AR8216_VTUDATA_MEMBER BITS(0, 10) +#define AR8236_VTUDATA_MEMBER BITS(0, 7) +#define AR8216_VTUDATA_VALID BIT(11) + +#define AR8216_REG_ATU_FUNC0 0x0050 +#define AR8216_ATU_OP BITS(0, 3) +#define AR8216_ATU_OP_NOOP 0x0 +#define AR8216_ATU_OP_FLUSH 0x1 +#define AR8216_ATU_OP_LOAD 0x2 +#define AR8216_ATU_OP_PURGE 0x3 +#define AR8216_ATU_OP_FLUSH_UNLOCKED 0x4 +#define AR8216_ATU_OP_FLUSH_PORT 0x5 +#define AR8216_ATU_OP_GET_NEXT 0x6 +#define AR8216_ATU_ACTIVE BIT(3) +#define AR8216_ATU_PORT_NUM BITS(8, 4) +#define AR8216_ATU_PORT_NUM_S 8 +#define AR8216_ATU_FULL_VIO BIT(12) +#define AR8216_ATU_ADDR5 BITS(16, 8) +#define AR8216_ATU_ADDR5_S 16 +#define AR8216_ATU_ADDR4 BITS(24, 8) +#define AR8216_ATU_ADDR4_S 24 + +#define AR8216_REG_ATU_FUNC1 0x0054 +#define AR8216_ATU_ADDR3 BITS(0, 8) +#define AR8216_ATU_ADDR3_S 0 +#define AR8216_ATU_ADDR2 BITS(8, 8) +#define AR8216_ATU_ADDR2_S 8 +#define AR8216_ATU_ADDR1 BITS(16, 8) +#define AR8216_ATU_ADDR1_S 16 +#define AR8216_ATU_ADDR0 BITS(24, 8) +#define AR8216_ATU_ADDR0_S 24 + +#define AR8216_REG_ATU_FUNC2 0x0058 +#define AR8216_ATU_PORTS BITS(0, 6) +#define AR8216_ATU_PORT0 BIT(0) +#define AR8216_ATU_PORT1 BIT(1) +#define AR8216_ATU_PORT2 BIT(2) +#define AR8216_ATU_PORT3 BIT(3) +#define AR8216_ATU_PORT4 BIT(4) +#define AR8216_ATU_PORT5 BIT(5) +#define AR8216_ATU_STATUS BITS(16, 4) +#define AR8216_ATU_STATUS_S 16 + +#define AR8216_REG_ATU_CTRL 0x005C +#define AR8216_ATU_CTRL_AGE_EN BIT(17) +#define AR8216_ATU_CTRL_AGE_TIME BITS(0, 16) +#define AR8216_ATU_CTRL_AGE_TIME_S 0 +#define AR8236_ATU_CTRL_RES BIT(20) + +#define AR8216_REG_MIB_FUNC 0x0080 +#define AR8216_MIB_TIMER BITS(0, 16) +#define AR8216_MIB_AT_HALF_EN BIT(16) +#define AR8216_MIB_BUSY BIT(17) +#define AR8216_MIB_FUNC BITS(24, 3) +#define AR8216_MIB_FUNC_S 24 +#define AR8216_MIB_FUNC_NO_OP 0x0 +#define AR8216_MIB_FUNC_FLUSH 0x1 +#define AR8216_MIB_FUNC_CAPTURE 0x3 +#define AR8236_MIB_EN BIT(30) + +#define AR8216_REG_GLOBAL_CPUPORT 0x0078 +#define AR8216_GLOBAL_CPUPORT_MIRROR_PORT BITS(4, 4) +#define AR8216_GLOBAL_CPUPORT_MIRROR_PORT_S 4 + +#define AR8216_PORT_OFFSET(_i) (0x0100 * (_i + 1)) +#define AR8216_REG_PORT_STATUS(_i) (AR8216_PORT_OFFSET(_i) + 0x0000) +#define AR8216_PORT_STATUS_SPEED BITS(0,2) +#define AR8216_PORT_STATUS_SPEED_S 0 +#define AR8216_PORT_STATUS_TXMAC BIT(2) +#define AR8216_PORT_STATUS_RXMAC BIT(3) +#define AR8216_PORT_STATUS_TXFLOW BIT(4) +#define AR8216_PORT_STATUS_RXFLOW BIT(5) +#define AR8216_PORT_STATUS_DUPLEX BIT(6) +#define AR8216_PORT_STATUS_LINK_UP BIT(8) +#define AR8216_PORT_STATUS_LINK_AUTO BIT(9) +#define AR8216_PORT_STATUS_LINK_PAUSE BIT(10) + +#define AR8216_REG_PORT_CTRL(_i) (AR8216_PORT_OFFSET(_i) + 0x0004) + +/* port forwarding state */ +#define AR8216_PORT_CTRL_STATE BITS(0, 3) +#define AR8216_PORT_CTRL_STATE_S 0 + +#define AR8216_PORT_CTRL_LEARN_LOCK BIT(7) + +/* egress 802.1q mode */ +#define AR8216_PORT_CTRL_VLAN_MODE BITS(8, 2) +#define AR8216_PORT_CTRL_VLAN_MODE_S 8 + +#define AR8216_PORT_CTRL_IGMP_SNOOP BIT(10) +#define AR8216_PORT_CTRL_HEADER BIT(11) +#define AR8216_PORT_CTRL_MAC_LOOP BIT(12) +#define AR8216_PORT_CTRL_SINGLE_VLAN BIT(13) +#define AR8216_PORT_CTRL_LEARN BIT(14) +#define AR8216_PORT_CTRL_MIRROR_TX BIT(16) +#define AR8216_PORT_CTRL_MIRROR_RX BIT(17) + +#define AR8216_REG_PORT_VLAN(_i) (AR8216_PORT_OFFSET(_i) + 0x0008) + +#define AR8216_PORT_VLAN_DEFAULT_ID BITS(0, 12) +#define AR8216_PORT_VLAN_DEFAULT_ID_S 0 + +#define AR8216_PORT_VLAN_DEST_PORTS BITS(16, 9) +#define AR8216_PORT_VLAN_DEST_PORTS_S 16 + +/* bit0 added to the priority field of egress frames */ +#define AR8216_PORT_VLAN_TX_PRIO BIT(27) + +/* port default priority */ +#define AR8216_PORT_VLAN_PRIORITY BITS(28, 2) +#define AR8216_PORT_VLAN_PRIORITY_S 28 + +/* ingress 802.1q mode */ +#define AR8216_PORT_VLAN_MODE BITS(30, 2) +#define AR8216_PORT_VLAN_MODE_S 30 + +#define AR8216_REG_PORT_RATE(_i) (AR8216_PORT_OFFSET(_i) + 0x000c) +#define AR8216_REG_PORT_PRIO(_i) (AR8216_PORT_OFFSET(_i) + 0x0010) + +#define AR8216_STATS_RXBROAD 0x00 +#define AR8216_STATS_RXPAUSE 0x04 +#define AR8216_STATS_RXMULTI 0x08 +#define AR8216_STATS_RXFCSERR 0x0c +#define AR8216_STATS_RXALIGNERR 0x10 +#define AR8216_STATS_RXRUNT 0x14 +#define AR8216_STATS_RXFRAGMENT 0x18 +#define AR8216_STATS_RX64BYTE 0x1c +#define AR8216_STATS_RX128BYTE 0x20 +#define AR8216_STATS_RX256BYTE 0x24 +#define AR8216_STATS_RX512BYTE 0x28 +#define AR8216_STATS_RX1024BYTE 0x2c +#define AR8216_STATS_RXMAXBYTE 0x30 +#define AR8216_STATS_RXTOOLONG 0x34 +#define AR8216_STATS_RXGOODBYTE 0x38 +#define AR8216_STATS_RXBADBYTE 0x40 +#define AR8216_STATS_RXOVERFLOW 0x48 +#define AR8216_STATS_FILTERED 0x4c +#define AR8216_STATS_TXBROAD 0x50 +#define AR8216_STATS_TXPAUSE 0x54 +#define AR8216_STATS_TXMULTI 0x58 +#define AR8216_STATS_TXUNDERRUN 0x5c +#define AR8216_STATS_TX64BYTE 0x60 +#define AR8216_STATS_TX128BYTE 0x64 +#define AR8216_STATS_TX256BYTE 0x68 +#define AR8216_STATS_TX512BYTE 0x6c +#define AR8216_STATS_TX1024BYTE 0x70 +#define AR8216_STATS_TXMAXBYTE 0x74 +#define AR8216_STATS_TXOVERSIZE 0x78 +#define AR8216_STATS_TXBYTE 0x7c +#define AR8216_STATS_TXCOLLISION 0x84 +#define AR8216_STATS_TXABORTCOL 0x88 +#define AR8216_STATS_TXMULTICOL 0x8c +#define AR8216_STATS_TXSINGLECOL 0x90 +#define AR8216_STATS_TXEXCDEFER 0x94 +#define AR8216_STATS_TXDEFER 0x98 +#define AR8216_STATS_TXLATECOL 0x9c + +#define AR8236_REG_PORT_VLAN(_i) (AR8216_PORT_OFFSET((_i)) + 0x0008) +#define AR8236_PORT_VLAN_DEFAULT_ID BITS(16, 12) +#define AR8236_PORT_VLAN_DEFAULT_ID_S 16 +#define AR8236_PORT_VLAN_PRIORITY BITS(29, 3) +#define AR8236_PORT_VLAN_PRIORITY_S 28 + +#define AR8236_REG_PORT_VLAN2(_i) (AR8216_PORT_OFFSET((_i)) + 0x000c) +#define AR8236_PORT_VLAN2_MEMBER BITS(16, 7) +#define AR8236_PORT_VLAN2_MEMBER_S 16 +#define AR8236_PORT_VLAN2_TX_PRIO BIT(23) +#define AR8236_PORT_VLAN2_VLAN_MODE BITS(30, 2) +#define AR8236_PORT_VLAN2_VLAN_MODE_S 30 + +#define AR8236_STATS_RXBROAD 0x00 +#define AR8236_STATS_RXPAUSE 0x04 +#define AR8236_STATS_RXMULTI 0x08 +#define AR8236_STATS_RXFCSERR 0x0c +#define AR8236_STATS_RXALIGNERR 0x10 +#define AR8236_STATS_RXRUNT 0x14 +#define AR8236_STATS_RXFRAGMENT 0x18 +#define AR8236_STATS_RX64BYTE 0x1c +#define AR8236_STATS_RX128BYTE 0x20 +#define AR8236_STATS_RX256BYTE 0x24 +#define AR8236_STATS_RX512BYTE 0x28 +#define AR8236_STATS_RX1024BYTE 0x2c +#define AR8236_STATS_RX1518BYTE 0x30 +#define AR8236_STATS_RXMAXBYTE 0x34 +#define AR8236_STATS_RXTOOLONG 0x38 +#define AR8236_STATS_RXGOODBYTE 0x3c +#define AR8236_STATS_RXBADBYTE 0x44 +#define AR8236_STATS_RXOVERFLOW 0x4c +#define AR8236_STATS_FILTERED 0x50 +#define AR8236_STATS_TXBROAD 0x54 +#define AR8236_STATS_TXPAUSE 0x58 +#define AR8236_STATS_TXMULTI 0x5c +#define AR8236_STATS_TXUNDERRUN 0x60 +#define AR8236_STATS_TX64BYTE 0x64 +#define AR8236_STATS_TX128BYTE 0x68 +#define AR8236_STATS_TX256BYTE 0x6c +#define AR8236_STATS_TX512BYTE 0x70 +#define AR8236_STATS_TX1024BYTE 0x74 +#define AR8236_STATS_TX1518BYTE 0x78 +#define AR8236_STATS_TXMAXBYTE 0x7c +#define AR8236_STATS_TXOVERSIZE 0x80 +#define AR8236_STATS_TXBYTE 0x84 +#define AR8236_STATS_TXCOLLISION 0x8c +#define AR8236_STATS_TXABORTCOL 0x90 +#define AR8236_STATS_TXMULTICOL 0x94 +#define AR8236_STATS_TXSINGLECOL 0x98 +#define AR8236_STATS_TXEXCDEFER 0x9c +#define AR8236_STATS_TXDEFER 0xa0 +#define AR8236_STATS_TXLATECOL 0xa4 + +#define AR8316_REG_POSTRIP 0x0008 +#define AR8316_POSTRIP_MAC0_GMII_EN BIT(0) +#define AR8316_POSTRIP_MAC0_RGMII_EN BIT(1) +#define AR8316_POSTRIP_PHY4_GMII_EN BIT(2) +#define AR8316_POSTRIP_PHY4_RGMII_EN BIT(3) +#define AR8316_POSTRIP_MAC0_MAC_MODE BIT(4) +#define AR8316_POSTRIP_RTL_MODE BIT(5) +#define AR8316_POSTRIP_RGMII_RXCLK_DELAY_EN BIT(6) +#define AR8316_POSTRIP_RGMII_TXCLK_DELAY_EN BIT(7) +#define AR8316_POSTRIP_SERDES_EN BIT(8) +#define AR8316_POSTRIP_SEL_ANA_RST BIT(9) +#define AR8316_POSTRIP_GATE_25M_EN BIT(10) +#define AR8316_POSTRIP_SEL_CLK25M BIT(11) +#define AR8316_POSTRIP_HIB_PULSE_HW BIT(12) +#define AR8316_POSTRIP_DBG_MODE_I BIT(13) +#define AR8316_POSTRIP_MAC5_MAC_MODE BIT(14) +#define AR8316_POSTRIP_MAC5_PHY_MODE BIT(15) +#define AR8316_POSTRIP_POWER_DOWN_HW BIT(16) +#define AR8316_POSTRIP_LPW_STATE_EN BIT(17) +#define AR8316_POSTRIP_MAN_EN BIT(18) +#define AR8316_POSTRIP_PHY_PLL_ON BIT(19) +#define AR8316_POSTRIP_LPW_EXIT BIT(20) +#define AR8316_POSTRIP_TXDELAY_S0 BIT(21) +#define AR8316_POSTRIP_TXDELAY_S1 BIT(22) +#define AR8316_POSTRIP_RXDELAY_S0 BIT(23) +#define AR8316_POSTRIP_LED_OPEN_EN BIT(24) +#define AR8316_POSTRIP_SPI_EN BIT(25) +#define AR8316_POSTRIP_RXDELAY_S1 BIT(26) +#define AR8316_POSTRIP_POWER_ON_SEL BIT(31) + +/* port speed */ +enum { + AR8216_PORT_SPEED_10M = 0, + AR8216_PORT_SPEED_100M = 1, + AR8216_PORT_SPEED_1000M = 2, + AR8216_PORT_SPEED_ERR = 3, +}; + +/* ingress 802.1q mode */ +enum { + AR8216_IN_PORT_ONLY = 0, + AR8216_IN_PORT_FALLBACK = 1, + AR8216_IN_VLAN_ONLY = 2, + AR8216_IN_SECURE = 3 +}; + +/* egress 802.1q mode */ +enum { + AR8216_OUT_KEEP = 0, + AR8216_OUT_STRIP_VLAN = 1, + AR8216_OUT_ADD_VLAN = 2 +}; + +/* port forwarding state */ +enum { + AR8216_PORT_STATE_DISABLED = 0, + AR8216_PORT_STATE_BLOCK = 1, + AR8216_PORT_STATE_LISTEN = 2, + AR8216_PORT_STATE_LEARN = 3, + AR8216_PORT_STATE_FORWARD = 4 +}; + +enum { + AR8XXX_VER_AR8216 = 0x01, + AR8XXX_VER_AR8236 = 0x03, + AR8XXX_VER_AR8316 = 0x10, + AR8XXX_VER_AR8327 = 0x12, + AR8XXX_VER_AR8337 = 0x13, +}; + +#define AR8XXX_NUM_ARL_RECORDS 100 + +enum arl_op { + AR8XXX_ARL_INITIALIZE, + AR8XXX_ARL_GET_NEXT +}; + +struct arl_entry { + u8 port; + u8 mac[6]; +}; + +struct ar8xxx_priv; + +struct ar8xxx_mib_desc { + unsigned int size; + unsigned int offset; + const char *name; +}; + +struct ar8xxx_chip { + unsigned long caps; + bool config_at_probe; + bool mii_lo_first; + + /* parameters to calculate REG_PORT_STATS_BASE */ + unsigned reg_port_stats_start; + unsigned reg_port_stats_length; + + int (*hw_init)(struct ar8xxx_priv *priv); + void (*cleanup)(struct ar8xxx_priv *priv); + + const char *name; + int vlans; + int ports; + const struct switch_dev_ops *swops; + + void (*init_globals)(struct ar8xxx_priv *priv); + void (*init_port)(struct ar8xxx_priv *priv, int port); + void (*setup_port)(struct ar8xxx_priv *priv, int port, u32 members); + u32 (*read_port_status)(struct ar8xxx_priv *priv, int port); + u32 (*read_port_eee_status)(struct ar8xxx_priv *priv, int port); + int (*atu_flush)(struct ar8xxx_priv *priv); + int (*atu_flush_port)(struct ar8xxx_priv *priv, int port); + void (*vtu_flush)(struct ar8xxx_priv *priv); + void (*vtu_load_vlan)(struct ar8xxx_priv *priv, u32 vid, u32 port_mask); + void (*phy_fixup)(struct ar8xxx_priv *priv, int phy); + void (*set_mirror_regs)(struct ar8xxx_priv *priv); + void (*get_arl_entry)(struct ar8xxx_priv *priv, struct arl_entry *a, + u32 *status, enum arl_op op); + int (*sw_hw_apply)(struct switch_dev *dev); + + const struct ar8xxx_mib_desc *mib_decs; + unsigned num_mibs; + unsigned mib_func; +}; + +struct ar8xxx_priv { + struct switch_dev dev; + struct mii_bus *mii_bus; + struct phy_device *phy; + + int (*get_port_link)(unsigned port); + + const struct net_device_ops *ndo_old; + struct net_device_ops ndo; + struct mutex reg_mutex; + u8 chip_ver; + u8 chip_rev; + const struct ar8xxx_chip *chip; + void *chip_data; + bool initialized; + bool port4_phy; + char buf[2048]; + struct arl_entry arl_table[AR8XXX_NUM_ARL_RECORDS]; + char arl_buf[AR8XXX_NUM_ARL_RECORDS * 32 + 256]; + bool link_up[AR8X16_MAX_PORTS]; + + bool init; + + struct mutex mib_lock; + struct delayed_work mib_work; + int mib_next_port; + u64 *mib_stats; + + struct list_head list; + unsigned int use_count; + + /* all fields below are cleared on reset */ + bool vlan; + u16 vlan_id[AR8X16_MAX_VLANS]; + u8 vlan_table[AR8X16_MAX_VLANS]; + u8 vlan_tagged; + u16 pvid[AR8X16_MAX_PORTS]; + + /* mirroring */ + bool mirror_rx; + bool mirror_tx; + int source_port; + int monitor_port; +}; + +u32 +ar8xxx_mii_read32(struct ar8xxx_priv *priv, int phy_id, int regnum); +void +ar8xxx_mii_write32(struct ar8xxx_priv *priv, int phy_id, int regnum, u32 val); +u32 +ar8xxx_read(struct ar8xxx_priv *priv, int reg); +void +ar8xxx_write(struct ar8xxx_priv *priv, int reg, u32 val); +u32 +ar8xxx_rmw(struct ar8xxx_priv *priv, int reg, u32 mask, u32 val); + +void +ar8xxx_phy_dbg_write(struct ar8xxx_priv *priv, int phy_addr, + u16 dbg_addr, u16 dbg_data); +void +ar8xxx_phy_mmd_write(struct ar8xxx_priv *priv, int phy_addr, u16 addr, u16 data); +u16 +ar8xxx_phy_mmd_read(struct ar8xxx_priv *priv, int phy_addr, u16 addr); +void +ar8xxx_phy_init(struct ar8xxx_priv *priv); +int +ar8xxx_sw_set_vlan(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val); +int +ar8xxx_sw_get_vlan(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val); +int +ar8xxx_sw_set_reset_mibs(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int +ar8xxx_sw_set_mirror_rx_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int +ar8xxx_sw_get_mirror_rx_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int +ar8xxx_sw_set_mirror_tx_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int +ar8xxx_sw_get_mirror_tx_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int +ar8xxx_sw_set_mirror_monitor_port(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int +ar8xxx_sw_get_mirror_monitor_port(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int +ar8xxx_sw_set_mirror_source_port(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int +ar8xxx_sw_get_mirror_source_port(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int +ar8xxx_sw_set_pvid(struct switch_dev *dev, int port, int vlan); +int +ar8xxx_sw_get_pvid(struct switch_dev *dev, int port, int *vlan); +int +ar8xxx_sw_hw_apply(struct switch_dev *dev); +int +ar8xxx_sw_reset_switch(struct switch_dev *dev); +int +ar8xxx_sw_get_port_link(struct switch_dev *dev, int port, + struct switch_port_link *link); +int +ar8xxx_sw_set_port_reset_mib(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int +ar8xxx_sw_get_port_mib(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int +ar8xxx_sw_get_arl_table(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int +ar8xxx_sw_set_flush_arl_table(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int +ar8xxx_sw_set_flush_port_arl_table(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int +ar8216_wait_bit(struct ar8xxx_priv *priv, int reg, u32 mask, u32 val); + +static inline struct ar8xxx_priv * +swdev_to_ar8xxx(struct switch_dev *swdev) +{ + return container_of(swdev, struct ar8xxx_priv, dev); +} + +static inline bool ar8xxx_has_gige(struct ar8xxx_priv *priv) +{ + return priv->chip->caps & AR8XXX_CAP_GIGE; +} + +static inline bool ar8xxx_has_mib_counters(struct ar8xxx_priv *priv) +{ + return priv->chip->caps & AR8XXX_CAP_MIB_COUNTERS; +} + +static inline bool chip_is_ar8216(struct ar8xxx_priv *priv) +{ + return priv->chip_ver == AR8XXX_VER_AR8216; +} + +static inline bool chip_is_ar8236(struct ar8xxx_priv *priv) +{ + return priv->chip_ver == AR8XXX_VER_AR8236; +} + +static inline bool chip_is_ar8316(struct ar8xxx_priv *priv) +{ + return priv->chip_ver == AR8XXX_VER_AR8316; +} + +static inline bool chip_is_ar8327(struct ar8xxx_priv *priv) +{ + return priv->chip_ver == AR8XXX_VER_AR8327; +} + +static inline bool chip_is_ar8337(struct ar8xxx_priv *priv) +{ + return priv->chip_ver == AR8XXX_VER_AR8337; +} + +static inline void +ar8xxx_reg_set(struct ar8xxx_priv *priv, int reg, u32 val) +{ + ar8xxx_rmw(priv, reg, 0, val); +} + +static inline void +ar8xxx_reg_clear(struct ar8xxx_priv *priv, int reg, u32 val) +{ + ar8xxx_rmw(priv, reg, val, 0); +} + +static inline void +split_addr(u32 regaddr, u16 *r1, u16 *r2, u16 *page) +{ + regaddr >>= 1; + *r1 = regaddr & 0x1e; + + regaddr >>= 5; + *r2 = regaddr & 0x7; + + regaddr >>= 3; + *page = regaddr & 0x1ff; +} + +static inline void +wait_for_page_switch(void) +{ + udelay(5); +} + +#endif diff --git a/target/linux/generic/files/drivers/net/phy/ar8327.c b/target/linux/generic/files/drivers/net/phy/ar8327.c new file mode 100644 index 0000000..1802b9e --- /dev/null +++ b/target/linux/generic/files/drivers/net/phy/ar8327.c @@ -0,0 +1,1268 @@ +/* + * ar8327.c: AR8216 switch driver + * + * Copyright (C) 2009 Felix Fietkau + * Copyright (C) 2011-2012 Gabor Juhos + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ar8216.h" +#include "ar8327.h" + +extern const struct ar8xxx_mib_desc ar8236_mibs[39]; +extern const struct switch_attr ar8xxx_sw_attr_vlan[1]; + +static u32 +ar8327_get_pad_cfg(struct ar8327_pad_cfg *cfg) +{ + u32 t; + + if (!cfg) + return 0; + + t = 0; + switch (cfg->mode) { + case AR8327_PAD_NC: + break; + + case AR8327_PAD_MAC2MAC_MII: + t = AR8327_PAD_MAC_MII_EN; + if (cfg->rxclk_sel) + t |= AR8327_PAD_MAC_MII_RXCLK_SEL; + if (cfg->txclk_sel) + t |= AR8327_PAD_MAC_MII_TXCLK_SEL; + break; + + case AR8327_PAD_MAC2MAC_GMII: + t = AR8327_PAD_MAC_GMII_EN; + if (cfg->rxclk_sel) + t |= AR8327_PAD_MAC_GMII_RXCLK_SEL; + if (cfg->txclk_sel) + t |= AR8327_PAD_MAC_GMII_TXCLK_SEL; + break; + + case AR8327_PAD_MAC_SGMII: + t = AR8327_PAD_SGMII_EN; + + /* + * WAR for the QUalcomm Atheros AP136 board. + * It seems that RGMII TX/RX delay settings needs to be + * applied for SGMII mode as well, The ethernet is not + * reliable without this. + */ + t |= cfg->txclk_delay_sel << AR8327_PAD_RGMII_TXCLK_DELAY_SEL_S; + t |= cfg->rxclk_delay_sel << AR8327_PAD_RGMII_RXCLK_DELAY_SEL_S; + if (cfg->rxclk_delay_en) + t |= AR8327_PAD_RGMII_RXCLK_DELAY_EN; + if (cfg->txclk_delay_en) + t |= AR8327_PAD_RGMII_TXCLK_DELAY_EN; + + if (cfg->sgmii_delay_en) + t |= AR8327_PAD_SGMII_DELAY_EN; + + break; + + case AR8327_PAD_MAC2PHY_MII: + t = AR8327_PAD_PHY_MII_EN; + if (cfg->rxclk_sel) + t |= AR8327_PAD_PHY_MII_RXCLK_SEL; + if (cfg->txclk_sel) + t |= AR8327_PAD_PHY_MII_TXCLK_SEL; + break; + + case AR8327_PAD_MAC2PHY_GMII: + t = AR8327_PAD_PHY_GMII_EN; + if (cfg->pipe_rxclk_sel) + t |= AR8327_PAD_PHY_GMII_PIPE_RXCLK_SEL; + if (cfg->rxclk_sel) + t |= AR8327_PAD_PHY_GMII_RXCLK_SEL; + if (cfg->txclk_sel) + t |= AR8327_PAD_PHY_GMII_TXCLK_SEL; + break; + + case AR8327_PAD_MAC_RGMII: + t = AR8327_PAD_RGMII_EN; + t |= cfg->txclk_delay_sel << AR8327_PAD_RGMII_TXCLK_DELAY_SEL_S; + t |= cfg->rxclk_delay_sel << AR8327_PAD_RGMII_RXCLK_DELAY_SEL_S; + if (cfg->rxclk_delay_en) + t |= AR8327_PAD_RGMII_RXCLK_DELAY_EN; + if (cfg->txclk_delay_en) + t |= AR8327_PAD_RGMII_TXCLK_DELAY_EN; + break; + + case AR8327_PAD_PHY_GMII: + t = AR8327_PAD_PHYX_GMII_EN; + break; + + case AR8327_PAD_PHY_RGMII: + t = AR8327_PAD_PHYX_RGMII_EN; + break; + + case AR8327_PAD_PHY_MII: + t = AR8327_PAD_PHYX_MII_EN; + break; + } + + if (cfg->mac06_exchange_en) + t |= AR8337_PAD_MAC06_EXCHANGE_EN; + + return t; +} + +static void +ar8327_phy_fixup(struct ar8xxx_priv *priv, int phy) +{ + switch (priv->chip_rev) { + case 1: + /* For 100M waveform */ + ar8xxx_phy_dbg_write(priv, phy, 0, 0x02ea); + /* Turn on Gigabit clock */ + ar8xxx_phy_dbg_write(priv, phy, 0x3d, 0x68a0); + break; + + case 2: + ar8xxx_phy_mmd_write(priv, phy, 0x7, 0x3c); + ar8xxx_phy_mmd_write(priv, phy, 0x4007, 0x0); + /* fallthrough */ + case 4: + ar8xxx_phy_mmd_write(priv, phy, 0x3, 0x800d); + ar8xxx_phy_mmd_write(priv, phy, 0x4003, 0x803f); + + ar8xxx_phy_dbg_write(priv, phy, 0x3d, 0x6860); + ar8xxx_phy_dbg_write(priv, phy, 0x5, 0x2c46); + ar8xxx_phy_dbg_write(priv, phy, 0x3c, 0x6000); + break; + } +} + +static u32 +ar8327_get_port_init_status(struct ar8327_port_cfg *cfg) +{ + u32 t; + + if (!cfg->force_link) + return AR8216_PORT_STATUS_LINK_AUTO; + + t = AR8216_PORT_STATUS_TXMAC | AR8216_PORT_STATUS_RXMAC; + t |= cfg->duplex ? AR8216_PORT_STATUS_DUPLEX : 0; + t |= cfg->rxpause ? AR8216_PORT_STATUS_RXFLOW : 0; + t |= cfg->txpause ? AR8216_PORT_STATUS_TXFLOW : 0; + + switch (cfg->speed) { + case AR8327_PORT_SPEED_10: + t |= AR8216_PORT_SPEED_10M; + break; + case AR8327_PORT_SPEED_100: + t |= AR8216_PORT_SPEED_100M; + break; + case AR8327_PORT_SPEED_1000: + t |= AR8216_PORT_SPEED_1000M; + break; + } + + return t; +} + +#define AR8327_LED_ENTRY(_num, _reg, _shift) \ + [_num] = { .reg = (_reg), .shift = (_shift) } + +static const struct ar8327_led_entry +ar8327_led_map[AR8327_NUM_LEDS] = { + AR8327_LED_ENTRY(AR8327_LED_PHY0_0, 0, 14), + AR8327_LED_ENTRY(AR8327_LED_PHY0_1, 1, 14), + AR8327_LED_ENTRY(AR8327_LED_PHY0_2, 2, 14), + + AR8327_LED_ENTRY(AR8327_LED_PHY1_0, 3, 8), + AR8327_LED_ENTRY(AR8327_LED_PHY1_1, 3, 10), + AR8327_LED_ENTRY(AR8327_LED_PHY1_2, 3, 12), + + AR8327_LED_ENTRY(AR8327_LED_PHY2_0, 3, 14), + AR8327_LED_ENTRY(AR8327_LED_PHY2_1, 3, 16), + AR8327_LED_ENTRY(AR8327_LED_PHY2_2, 3, 18), + + AR8327_LED_ENTRY(AR8327_LED_PHY3_0, 3, 20), + AR8327_LED_ENTRY(AR8327_LED_PHY3_1, 3, 22), + AR8327_LED_ENTRY(AR8327_LED_PHY3_2, 3, 24), + + AR8327_LED_ENTRY(AR8327_LED_PHY4_0, 0, 30), + AR8327_LED_ENTRY(AR8327_LED_PHY4_1, 1, 30), + AR8327_LED_ENTRY(AR8327_LED_PHY4_2, 2, 30), +}; + +static void +ar8327_set_led_pattern(struct ar8xxx_priv *priv, unsigned int led_num, + enum ar8327_led_pattern pattern) +{ + const struct ar8327_led_entry *entry; + + entry = &ar8327_led_map[led_num]; + ar8xxx_rmw(priv, AR8327_REG_LED_CTRL(entry->reg), + (3 << entry->shift), pattern << entry->shift); +} + +static void +ar8327_led_work_func(struct work_struct *work) +{ + struct ar8327_led *aled; + u8 pattern; + + aled = container_of(work, struct ar8327_led, led_work); + + spin_lock(&aled->lock); + pattern = aled->pattern; + spin_unlock(&aled->lock); + + ar8327_set_led_pattern(aled->sw_priv, aled->led_num, + pattern); +} + +static void +ar8327_led_schedule_change(struct ar8327_led *aled, u8 pattern) +{ + if (aled->pattern == pattern) + return; + + aled->pattern = pattern; + schedule_work(&aled->led_work); +} + +static inline struct ar8327_led * +led_cdev_to_ar8327_led(struct led_classdev *led_cdev) +{ + return container_of(led_cdev, struct ar8327_led, cdev); +} + +static int +ar8327_led_blink_set(struct led_classdev *led_cdev, + unsigned long *delay_on, + unsigned long *delay_off) +{ + struct ar8327_led *aled = led_cdev_to_ar8327_led(led_cdev); + + if (*delay_on == 0 && *delay_off == 0) { + *delay_on = 125; + *delay_off = 125; + } + + if (*delay_on != 125 || *delay_off != 125) { + /* + * The hardware only supports blinking at 4Hz. Fall back + * to software implementation in other cases. + */ + return -EINVAL; + } + + spin_lock(&aled->lock); + + aled->enable_hw_mode = false; + ar8327_led_schedule_change(aled, AR8327_LED_PATTERN_BLINK); + + spin_unlock(&aled->lock); + + return 0; +} + +static void +ar8327_led_set_brightness(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct ar8327_led *aled = led_cdev_to_ar8327_led(led_cdev); + u8 pattern; + bool active; + + active = (brightness != LED_OFF); + active ^= aled->active_low; + + pattern = (active) ? AR8327_LED_PATTERN_ON : + AR8327_LED_PATTERN_OFF; + + spin_lock(&aled->lock); + + aled->enable_hw_mode = false; + ar8327_led_schedule_change(aled, pattern); + + spin_unlock(&aled->lock); +} + +static ssize_t +ar8327_led_enable_hw_mode_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct ar8327_led *aled = led_cdev_to_ar8327_led(led_cdev); + ssize_t ret = 0; + + spin_lock(&aled->lock); + ret += sprintf(buf, "%d\n", aled->enable_hw_mode); + spin_unlock(&aled->lock); + + return ret; +} + +static ssize_t +ar8327_led_enable_hw_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct ar8327_led *aled = led_cdev_to_ar8327_led(led_cdev); + u8 pattern; + u8 value; + int ret; + + ret = kstrtou8(buf, 10, &value); + if (ret < 0) + return -EINVAL; + + spin_lock(&aled->lock); + + aled->enable_hw_mode = !!value; + if (aled->enable_hw_mode) + pattern = AR8327_LED_PATTERN_RULE; + else + pattern = AR8327_LED_PATTERN_OFF; + + ar8327_led_schedule_change(aled, pattern); + + spin_unlock(&aled->lock); + + return size; +} + +static DEVICE_ATTR(enable_hw_mode, S_IRUGO | S_IWUSR, + ar8327_led_enable_hw_mode_show, + ar8327_led_enable_hw_mode_store); + +static int +ar8327_led_register(struct ar8327_led *aled) +{ + int ret; + + ret = led_classdev_register(NULL, &aled->cdev); + if (ret < 0) + return ret; + + if (aled->mode == AR8327_LED_MODE_HW) { + ret = device_create_file(aled->cdev.dev, + &dev_attr_enable_hw_mode); + if (ret) + goto err_unregister; + } + + return 0; + +err_unregister: + led_classdev_unregister(&aled->cdev); + return ret; +} + +static void +ar8327_led_unregister(struct ar8327_led *aled) +{ + if (aled->mode == AR8327_LED_MODE_HW) + device_remove_file(aled->cdev.dev, &dev_attr_enable_hw_mode); + + led_classdev_unregister(&aled->cdev); + cancel_work_sync(&aled->led_work); +} + +static int +ar8327_led_create(struct ar8xxx_priv *priv, + const struct ar8327_led_info *led_info) +{ + struct ar8327_data *data = priv->chip_data; + struct ar8327_led *aled; + int ret; + + if (!IS_ENABLED(CONFIG_AR8216_PHY_LEDS)) + return 0; + + if (!led_info->name) + return -EINVAL; + + if (led_info->led_num >= AR8327_NUM_LEDS) + return -EINVAL; + + aled = kzalloc(sizeof(*aled) + strlen(led_info->name) + 1, + GFP_KERNEL); + if (!aled) + return -ENOMEM; + + aled->sw_priv = priv; + aled->led_num = led_info->led_num; + aled->active_low = led_info->active_low; + aled->mode = led_info->mode; + + if (aled->mode == AR8327_LED_MODE_HW) + aled->enable_hw_mode = true; + + aled->name = (char *)(aled + 1); + strcpy(aled->name, led_info->name); + + aled->cdev.name = aled->name; + aled->cdev.brightness_set = ar8327_led_set_brightness; + aled->cdev.blink_set = ar8327_led_blink_set; + aled->cdev.default_trigger = led_info->default_trigger; + + spin_lock_init(&aled->lock); + mutex_init(&aled->mutex); + INIT_WORK(&aled->led_work, ar8327_led_work_func); + + ret = ar8327_led_register(aled); + if (ret) + goto err_free; + + data->leds[data->num_leds++] = aled; + + return 0; + +err_free: + kfree(aled); + return ret; +} + +static void +ar8327_led_destroy(struct ar8327_led *aled) +{ + ar8327_led_unregister(aled); + kfree(aled); +} + +static void +ar8327_leds_init(struct ar8xxx_priv *priv) +{ + struct ar8327_data *data = priv->chip_data; + unsigned i; + + if (!IS_ENABLED(CONFIG_AR8216_PHY_LEDS)) + return; + + for (i = 0; i < data->num_leds; i++) { + struct ar8327_led *aled; + + aled = data->leds[i]; + + if (aled->enable_hw_mode) + aled->pattern = AR8327_LED_PATTERN_RULE; + else + aled->pattern = AR8327_LED_PATTERN_OFF; + + ar8327_set_led_pattern(priv, aled->led_num, aled->pattern); + } +} + +static void +ar8327_leds_cleanup(struct ar8xxx_priv *priv) +{ + struct ar8327_data *data = priv->chip_data; + unsigned i; + + if (!IS_ENABLED(CONFIG_AR8216_PHY_LEDS)) + return; + + for (i = 0; i < data->num_leds; i++) { + struct ar8327_led *aled; + + aled = data->leds[i]; + ar8327_led_destroy(aled); + } + + kfree(data->leds); +} + +static int +ar8327_hw_config_pdata(struct ar8xxx_priv *priv, + struct ar8327_platform_data *pdata) +{ + struct ar8327_led_cfg *led_cfg; + struct ar8327_data *data = priv->chip_data; + u32 pos, new_pos; + u32 t; + + if (!pdata) + return -EINVAL; + + priv->get_port_link = pdata->get_port_link; + + data->port0_status = ar8327_get_port_init_status(&pdata->port0_cfg); + data->port6_status = ar8327_get_port_init_status(&pdata->port6_cfg); + + t = ar8327_get_pad_cfg(pdata->pad0_cfg); + ar8xxx_write(priv, AR8327_REG_PAD0_MODE, t); + t = ar8327_get_pad_cfg(pdata->pad5_cfg); + ar8xxx_write(priv, AR8327_REG_PAD5_MODE, t); + t = ar8327_get_pad_cfg(pdata->pad6_cfg); + ar8xxx_write(priv, AR8327_REG_PAD6_MODE, t); + + pos = ar8xxx_read(priv, AR8327_REG_POWER_ON_STRIP); + new_pos = pos; + + led_cfg = pdata->led_cfg; + if (led_cfg) { + if (led_cfg->open_drain) + new_pos |= AR8327_POWER_ON_STRIP_LED_OPEN_EN; + else + new_pos &= ~AR8327_POWER_ON_STRIP_LED_OPEN_EN; + + ar8xxx_write(priv, AR8327_REG_LED_CTRL0, led_cfg->led_ctrl0); + ar8xxx_write(priv, AR8327_REG_LED_CTRL1, led_cfg->led_ctrl1); + ar8xxx_write(priv, AR8327_REG_LED_CTRL2, led_cfg->led_ctrl2); + ar8xxx_write(priv, AR8327_REG_LED_CTRL3, led_cfg->led_ctrl3); + + if (new_pos != pos) + new_pos |= AR8327_POWER_ON_STRIP_POWER_ON_SEL; + } + + if (pdata->sgmii_cfg) { + t = pdata->sgmii_cfg->sgmii_ctrl; + if (priv->chip_rev == 1) + t |= AR8327_SGMII_CTRL_EN_PLL | + AR8327_SGMII_CTRL_EN_RX | + AR8327_SGMII_CTRL_EN_TX; + else + t &= ~(AR8327_SGMII_CTRL_EN_PLL | + AR8327_SGMII_CTRL_EN_RX | + AR8327_SGMII_CTRL_EN_TX); + + ar8xxx_write(priv, AR8327_REG_SGMII_CTRL, t); + + if (pdata->sgmii_cfg->serdes_aen) + new_pos &= ~AR8327_POWER_ON_STRIP_SERDES_AEN; + else + new_pos |= AR8327_POWER_ON_STRIP_SERDES_AEN; + } + + ar8xxx_write(priv, AR8327_REG_POWER_ON_STRIP, new_pos); + + if (pdata->leds && pdata->num_leds) { + int i; + + data->leds = kzalloc(pdata->num_leds * sizeof(void *), + GFP_KERNEL); + if (!data->leds) + return -ENOMEM; + + for (i = 0; i < pdata->num_leds; i++) + ar8327_led_create(priv, &pdata->leds[i]); + } + + return 0; +} + +#ifdef CONFIG_OF +static int +ar8327_hw_config_of(struct ar8xxx_priv *priv, struct device_node *np) +{ + struct ar8327_data *data = priv->chip_data; + const __be32 *paddr; + int len; + int i; + + paddr = of_get_property(np, "qca,ar8327-initvals", &len); + if (!paddr || len < (2 * sizeof(*paddr))) + return -EINVAL; + + len /= sizeof(*paddr); + + for (i = 0; i < len - 1; i += 2) { + u32 reg; + u32 val; + + reg = be32_to_cpup(paddr + i); + val = be32_to_cpup(paddr + i + 1); + + switch (reg) { + case AR8327_REG_PORT_STATUS(0): + data->port0_status = val; + break; + case AR8327_REG_PORT_STATUS(6): + data->port6_status = val; + break; + default: + ar8xxx_write(priv, reg, val); + break; + } + } + + return 0; +} +#else +static inline int +ar8327_hw_config_of(struct ar8xxx_priv *priv, struct device_node *np) +{ + return -EINVAL; +} +#endif + +static int +ar8327_hw_init(struct ar8xxx_priv *priv) +{ + int ret; + + priv->chip_data = kzalloc(sizeof(struct ar8327_data), GFP_KERNEL); + if (!priv->chip_data) + return -ENOMEM; + + if (priv->phy->dev.of_node) + ret = ar8327_hw_config_of(priv, priv->phy->dev.of_node); + else + ret = ar8327_hw_config_pdata(priv, + priv->phy->dev.platform_data); + + if (ret) + return ret; + + ar8327_leds_init(priv); + + ar8xxx_phy_init(priv); + + return 0; +} + +static void +ar8327_cleanup(struct ar8xxx_priv *priv) +{ + ar8327_leds_cleanup(priv); +} + +static void +ar8327_init_globals(struct ar8xxx_priv *priv) +{ + struct ar8327_data *data = priv->chip_data; + u32 t; + int i; + + /* enable CPU port and disable mirror port */ + t = AR8327_FWD_CTRL0_CPU_PORT_EN | + AR8327_FWD_CTRL0_MIRROR_PORT; + ar8xxx_write(priv, AR8327_REG_FWD_CTRL0, t); + + /* forward multicast and broadcast frames to CPU */ + t = (AR8327_PORTS_ALL << AR8327_FWD_CTRL1_UC_FLOOD_S) | + (AR8327_PORTS_ALL << AR8327_FWD_CTRL1_MC_FLOOD_S) | + (AR8327_PORTS_ALL << AR8327_FWD_CTRL1_BC_FLOOD_S); + ar8xxx_write(priv, AR8327_REG_FWD_CTRL1, t); + + /* enable jumbo frames */ + ar8xxx_rmw(priv, AR8327_REG_MAX_FRAME_SIZE, + AR8327_MAX_FRAME_SIZE_MTU, 9018 + 8 + 2); + + /* Enable MIB counters */ + ar8xxx_reg_set(priv, AR8327_REG_MODULE_EN, + AR8327_MODULE_EN_MIB); + + /* Disable EEE on all phy's due to stability issues */ + for (i = 0; i < AR8XXX_NUM_PHYS; i++) + data->eee[i] = false; +} + +static void +ar8327_init_port(struct ar8xxx_priv *priv, int port) +{ + struct ar8327_data *data = priv->chip_data; + u32 t; + + if (port == AR8216_PORT_CPU) + t = data->port0_status; + else if (port == 6) + t = data->port6_status; + else + t = AR8216_PORT_STATUS_LINK_AUTO; + + ar8xxx_write(priv, AR8327_REG_PORT_STATUS(port), t); + ar8xxx_write(priv, AR8327_REG_PORT_HEADER(port), 0); + + t = 1 << AR8327_PORT_VLAN0_DEF_SVID_S; + t |= 1 << AR8327_PORT_VLAN0_DEF_CVID_S; + ar8xxx_write(priv, AR8327_REG_PORT_VLAN0(port), t); + + t = AR8327_PORT_VLAN1_OUT_MODE_UNTOUCH << AR8327_PORT_VLAN1_OUT_MODE_S; + ar8xxx_write(priv, AR8327_REG_PORT_VLAN1(port), t); + + t = AR8327_PORT_LOOKUP_LEARN; + t |= AR8216_PORT_STATE_FORWARD << AR8327_PORT_LOOKUP_STATE_S; + ar8xxx_write(priv, AR8327_REG_PORT_LOOKUP(port), t); +} + +static u32 +ar8327_read_port_status(struct ar8xxx_priv *priv, int port) +{ + u32 t; + + t = ar8xxx_read(priv, AR8327_REG_PORT_STATUS(port)); + /* map the flow control autoneg result bits to the flow control bits + * used in forced mode to allow ar8216_read_port_link detect + * flow control properly if autoneg is used + */ + if (t & AR8216_PORT_STATUS_LINK_UP && + t & AR8216_PORT_STATUS_LINK_AUTO) { + t &= ~(AR8216_PORT_STATUS_TXFLOW | AR8216_PORT_STATUS_RXFLOW); + if (t & AR8327_PORT_STATUS_TXFLOW_AUTO) + t |= AR8216_PORT_STATUS_TXFLOW; + if (t & AR8327_PORT_STATUS_RXFLOW_AUTO) + t |= AR8216_PORT_STATUS_RXFLOW; + } + + return t; +} + +static u32 +ar8327_read_port_eee_status(struct ar8xxx_priv *priv, int port) +{ + int phy; + u16 t; + + if (port >= priv->dev.ports) + return 0; + + if (port == 0 || port == 6) + return 0; + + phy = port - 1; + + /* EEE Ability Auto-negotiation Result */ + ar8xxx_phy_mmd_write(priv, phy, 0x7, 0x8000); + t = ar8xxx_phy_mmd_read(priv, phy, 0x4007); + + return mmd_eee_adv_to_ethtool_adv_t(t); +} + +static int +ar8327_atu_flush(struct ar8xxx_priv *priv) +{ + int ret; + + ret = ar8216_wait_bit(priv, AR8327_REG_ATU_FUNC, + AR8327_ATU_FUNC_BUSY, 0); + if (!ret) + ar8xxx_write(priv, AR8327_REG_ATU_FUNC, + AR8327_ATU_FUNC_OP_FLUSH | + AR8327_ATU_FUNC_BUSY); + + return ret; +} + +static int +ar8327_atu_flush_port(struct ar8xxx_priv *priv, int port) +{ + u32 t; + int ret; + + ret = ar8216_wait_bit(priv, AR8327_REG_ATU_FUNC, + AR8327_ATU_FUNC_BUSY, 0); + if (!ret) { + t = (port << AR8327_ATU_PORT_NUM_S); + t |= AR8327_ATU_FUNC_OP_FLUSH_PORT; + t |= AR8327_ATU_FUNC_BUSY; + ar8xxx_write(priv, AR8327_REG_ATU_FUNC, t); + } + + return ret; +} + +static void +ar8327_vtu_op(struct ar8xxx_priv *priv, u32 op, u32 val) +{ + if (ar8216_wait_bit(priv, AR8327_REG_VTU_FUNC1, + AR8327_VTU_FUNC1_BUSY, 0)) + return; + + if ((op & AR8327_VTU_FUNC1_OP) == AR8327_VTU_FUNC1_OP_LOAD) + ar8xxx_write(priv, AR8327_REG_VTU_FUNC0, val); + + op |= AR8327_VTU_FUNC1_BUSY; + ar8xxx_write(priv, AR8327_REG_VTU_FUNC1, op); +} + +static void +ar8327_vtu_flush(struct ar8xxx_priv *priv) +{ + ar8327_vtu_op(priv, AR8327_VTU_FUNC1_OP_FLUSH, 0); +} + +static void +ar8327_vtu_load_vlan(struct ar8xxx_priv *priv, u32 vid, u32 port_mask) +{ + u32 op; + u32 val; + int i; + + op = AR8327_VTU_FUNC1_OP_LOAD | (vid << AR8327_VTU_FUNC1_VID_S); + val = AR8327_VTU_FUNC0_VALID | AR8327_VTU_FUNC0_IVL; + for (i = 0; i < AR8327_NUM_PORTS; i++) { + u32 mode; + + if ((port_mask & BIT(i)) == 0) + mode = AR8327_VTU_FUNC0_EG_MODE_NOT; + else if (priv->vlan == 0) + mode = AR8327_VTU_FUNC0_EG_MODE_KEEP; + else if ((priv->vlan_tagged & BIT(i)) || (priv->vlan_id[priv->pvid[i]] != vid)) + mode = AR8327_VTU_FUNC0_EG_MODE_TAG; + else + mode = AR8327_VTU_FUNC0_EG_MODE_UNTAG; + + val |= mode << AR8327_VTU_FUNC0_EG_MODE_S(i); + } + ar8327_vtu_op(priv, op, val); +} + +static void +ar8327_setup_port(struct ar8xxx_priv *priv, int port, u32 members) +{ + u32 t; + u32 egress, ingress; + u32 pvid = priv->vlan_id[priv->pvid[port]]; + + if (priv->vlan) { + egress = AR8327_PORT_VLAN1_OUT_MODE_UNMOD; + ingress = AR8216_IN_SECURE; + } else { + egress = AR8327_PORT_VLAN1_OUT_MODE_UNTOUCH; + ingress = AR8216_IN_PORT_ONLY; + } + + t = pvid << AR8327_PORT_VLAN0_DEF_SVID_S; + t |= pvid << AR8327_PORT_VLAN0_DEF_CVID_S; + ar8xxx_write(priv, AR8327_REG_PORT_VLAN0(port), t); + + t = AR8327_PORT_VLAN1_PORT_VLAN_PROP; + t |= egress << AR8327_PORT_VLAN1_OUT_MODE_S; + ar8xxx_write(priv, AR8327_REG_PORT_VLAN1(port), t); + + t = members; + t |= AR8327_PORT_LOOKUP_LEARN; + t |= ingress << AR8327_PORT_LOOKUP_IN_MODE_S; + t |= AR8216_PORT_STATE_FORWARD << AR8327_PORT_LOOKUP_STATE_S; + ar8xxx_write(priv, AR8327_REG_PORT_LOOKUP(port), t); +} + +static int +ar8327_sw_get_ports(struct switch_dev *dev, struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + u8 ports = priv->vlan_table[val->port_vlan]; + int i; + + val->len = 0; + for (i = 0; i < dev->ports; i++) { + struct switch_port *p; + + if (!(ports & (1 << i))) + continue; + + p = &val->value.ports[val->len++]; + p->id = i; + if ((priv->vlan_tagged & (1 << i)) || (priv->pvid[i] != val->port_vlan)) + p->flags = (1 << SWITCH_PORT_FLAG_TAGGED); + else + p->flags = 0; + } + return 0; +} + +static int +ar8327_sw_set_ports(struct switch_dev *dev, struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + u8 *vt = &priv->vlan_table[val->port_vlan]; + int i; + + *vt = 0; + for (i = 0; i < val->len; i++) { + struct switch_port *p = &val->value.ports[i]; + + if (p->flags & (1 << SWITCH_PORT_FLAG_TAGGED)) { + if (val->port_vlan == priv->pvid[p->id]) { + priv->vlan_tagged |= (1 << p->id); + } + } else { + priv->vlan_tagged &= ~(1 << p->id); + priv->pvid[p->id] = val->port_vlan; + } + + *vt |= 1 << p->id; + } + return 0; +} + +static void +ar8327_set_mirror_regs(struct ar8xxx_priv *priv) +{ + int port; + + /* reset all mirror registers */ + ar8xxx_rmw(priv, AR8327_REG_FWD_CTRL0, + AR8327_FWD_CTRL0_MIRROR_PORT, + (0xF << AR8327_FWD_CTRL0_MIRROR_PORT_S)); + for (port = 0; port < AR8327_NUM_PORTS; port++) { + ar8xxx_reg_clear(priv, AR8327_REG_PORT_LOOKUP(port), + AR8327_PORT_LOOKUP_ING_MIRROR_EN); + + ar8xxx_reg_clear(priv, AR8327_REG_PORT_HOL_CTRL1(port), + AR8327_PORT_HOL_CTRL1_EG_MIRROR_EN); + } + + /* now enable mirroring if necessary */ + if (priv->source_port >= AR8327_NUM_PORTS || + priv->monitor_port >= AR8327_NUM_PORTS || + priv->source_port == priv->monitor_port) { + return; + } + + ar8xxx_rmw(priv, AR8327_REG_FWD_CTRL0, + AR8327_FWD_CTRL0_MIRROR_PORT, + (priv->monitor_port << AR8327_FWD_CTRL0_MIRROR_PORT_S)); + + if (priv->mirror_rx) + ar8xxx_reg_set(priv, AR8327_REG_PORT_LOOKUP(priv->source_port), + AR8327_PORT_LOOKUP_ING_MIRROR_EN); + + if (priv->mirror_tx) + ar8xxx_reg_set(priv, AR8327_REG_PORT_HOL_CTRL1(priv->source_port), + AR8327_PORT_HOL_CTRL1_EG_MIRROR_EN); +} + +static int +ar8327_sw_set_eee(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + struct ar8327_data *data = priv->chip_data; + int port = val->port_vlan; + int phy; + + if (port >= dev->ports) + return -EINVAL; + if (port == 0 || port == 6) + return -EOPNOTSUPP; + + phy = port - 1; + + data->eee[phy] = !!(val->value.i); + + return 0; +} + +static int +ar8327_sw_get_eee(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + const struct ar8327_data *data = priv->chip_data; + int port = val->port_vlan; + int phy; + + if (port >= dev->ports) + return -EINVAL; + if (port == 0 || port == 6) + return -EOPNOTSUPP; + + phy = port - 1; + + val->value.i = data->eee[phy]; + + return 0; +} + +static void +ar8327_wait_atu_ready(struct ar8xxx_priv *priv, u16 r2, u16 r1) +{ + int timeout = 20; + + while (ar8xxx_mii_read32(priv, r2, r1) & AR8327_ATU_FUNC_BUSY && --timeout) + udelay(10); + + if (!timeout) + pr_err("ar8327: timeout waiting for atu to become ready\n"); +} + +static void ar8327_get_arl_entry(struct ar8xxx_priv *priv, + struct arl_entry *a, u32 *status, enum arl_op op) +{ + struct mii_bus *bus = priv->mii_bus; + u16 r2, page; + u16 r1_data0, r1_data1, r1_data2, r1_func; + u32 t, val0, val1, val2; + int i; + + split_addr(AR8327_REG_ATU_DATA0, &r1_data0, &r2, &page); + r2 |= 0x10; + + r1_data1 = (AR8327_REG_ATU_DATA1 >> 1) & 0x1e; + r1_data2 = (AR8327_REG_ATU_DATA2 >> 1) & 0x1e; + r1_func = (AR8327_REG_ATU_FUNC >> 1) & 0x1e; + + switch (op) { + case AR8XXX_ARL_INITIALIZE: + /* all ATU registers are on the same page + * therefore set page only once + */ + bus->write(bus, 0x18, 0, page); + wait_for_page_switch(); + + ar8327_wait_atu_ready(priv, r2, r1_func); + + ar8xxx_mii_write32(priv, r2, r1_data0, 0); + ar8xxx_mii_write32(priv, r2, r1_data1, 0); + ar8xxx_mii_write32(priv, r2, r1_data2, 0); + break; + case AR8XXX_ARL_GET_NEXT: + ar8xxx_mii_write32(priv, r2, r1_func, + AR8327_ATU_FUNC_OP_GET_NEXT | + AR8327_ATU_FUNC_BUSY); + ar8327_wait_atu_ready(priv, r2, r1_func); + + val0 = ar8xxx_mii_read32(priv, r2, r1_data0); + val1 = ar8xxx_mii_read32(priv, r2, r1_data1); + val2 = ar8xxx_mii_read32(priv, r2, r1_data2); + + *status = val2 & AR8327_ATU_STATUS; + if (!*status) + break; + + i = 0; + t = AR8327_ATU_PORT0; + while (!(val1 & t) && ++i < AR8327_NUM_PORTS) + t <<= 1; + + a->port = i; + a->mac[0] = (val0 & AR8327_ATU_ADDR0) >> AR8327_ATU_ADDR0_S; + a->mac[1] = (val0 & AR8327_ATU_ADDR1) >> AR8327_ATU_ADDR1_S; + a->mac[2] = (val0 & AR8327_ATU_ADDR2) >> AR8327_ATU_ADDR2_S; + a->mac[3] = (val0 & AR8327_ATU_ADDR3) >> AR8327_ATU_ADDR3_S; + a->mac[4] = (val1 & AR8327_ATU_ADDR4) >> AR8327_ATU_ADDR4_S; + a->mac[5] = (val1 & AR8327_ATU_ADDR5) >> AR8327_ATU_ADDR5_S; + break; + } +} + +static int +ar8327_sw_hw_apply(struct switch_dev *dev) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + const struct ar8327_data *data = priv->chip_data; + int ret, i; + + ret = ar8xxx_sw_hw_apply(dev); + if (ret) + return ret; + + for (i=0; i < AR8XXX_NUM_PHYS; i++) { + if (data->eee[i]) + ar8xxx_reg_clear(priv, AR8327_REG_EEE_CTRL, + AR8327_EEE_CTRL_DISABLE_PHY(i)); + else + ar8xxx_reg_set(priv, AR8327_REG_EEE_CTRL, + AR8327_EEE_CTRL_DISABLE_PHY(i)); + } + + return 0; +} + +static const struct switch_attr ar8327_sw_attr_globals[] = { + { + .type = SWITCH_TYPE_INT, + .name = "enable_vlan", + .description = "Enable VLAN mode", + .set = ar8xxx_sw_set_vlan, + .get = ar8xxx_sw_get_vlan, + .max = 1 + }, + { + .type = SWITCH_TYPE_NOVAL, + .name = "reset_mibs", + .description = "Reset all MIB counters", + .set = ar8xxx_sw_set_reset_mibs, + }, + { + .type = SWITCH_TYPE_INT, + .name = "enable_mirror_rx", + .description = "Enable mirroring of RX packets", + .set = ar8xxx_sw_set_mirror_rx_enable, + .get = ar8xxx_sw_get_mirror_rx_enable, + .max = 1 + }, + { + .type = SWITCH_TYPE_INT, + .name = "enable_mirror_tx", + .description = "Enable mirroring of TX packets", + .set = ar8xxx_sw_set_mirror_tx_enable, + .get = ar8xxx_sw_get_mirror_tx_enable, + .max = 1 + }, + { + .type = SWITCH_TYPE_INT, + .name = "mirror_monitor_port", + .description = "Mirror monitor port", + .set = ar8xxx_sw_set_mirror_monitor_port, + .get = ar8xxx_sw_get_mirror_monitor_port, + .max = AR8327_NUM_PORTS - 1 + }, + { + .type = SWITCH_TYPE_INT, + .name = "mirror_source_port", + .description = "Mirror source port", + .set = ar8xxx_sw_set_mirror_source_port, + .get = ar8xxx_sw_get_mirror_source_port, + .max = AR8327_NUM_PORTS - 1 + }, + { + .type = SWITCH_TYPE_STRING, + .name = "arl_table", + .description = "Get ARL table", + .set = NULL, + .get = ar8xxx_sw_get_arl_table, + }, + { + .type = SWITCH_TYPE_NOVAL, + .name = "flush_arl_table", + .description = "Flush ARL table", + .set = ar8xxx_sw_set_flush_arl_table, + }, +}; + +static const struct switch_attr ar8327_sw_attr_port[] = { + { + .type = SWITCH_TYPE_NOVAL, + .name = "reset_mib", + .description = "Reset single port MIB counters", + .set = ar8xxx_sw_set_port_reset_mib, + }, + { + .type = SWITCH_TYPE_STRING, + .name = "mib", + .description = "Get port's MIB counters", + .set = NULL, + .get = ar8xxx_sw_get_port_mib, + }, + { + .type = SWITCH_TYPE_INT, + .name = "enable_eee", + .description = "Enable EEE PHY sleep mode", + .set = ar8327_sw_set_eee, + .get = ar8327_sw_get_eee, + .max = 1, + }, + { + .type = SWITCH_TYPE_NOVAL, + .name = "flush_arl_table", + .description = "Flush port's ARL table entries", + .set = ar8xxx_sw_set_flush_port_arl_table, + }, +}; + +static const struct switch_dev_ops ar8327_sw_ops = { + .attr_global = { + .attr = ar8327_sw_attr_globals, + .n_attr = ARRAY_SIZE(ar8327_sw_attr_globals), + }, + .attr_port = { + .attr = ar8327_sw_attr_port, + .n_attr = ARRAY_SIZE(ar8327_sw_attr_port), + }, + .attr_vlan = { + .attr = ar8xxx_sw_attr_vlan, + .n_attr = ARRAY_SIZE(ar8xxx_sw_attr_vlan), + }, + .get_port_pvid = ar8xxx_sw_get_pvid, + .set_port_pvid = ar8xxx_sw_set_pvid, + .get_vlan_ports = ar8327_sw_get_ports, + .set_vlan_ports = ar8327_sw_set_ports, + .apply_config = ar8327_sw_hw_apply, + .reset_switch = ar8xxx_sw_reset_switch, + .get_port_link = ar8xxx_sw_get_port_link, +}; + +const struct ar8xxx_chip ar8327_chip = { + .caps = AR8XXX_CAP_GIGE | AR8XXX_CAP_MIB_COUNTERS, + .config_at_probe = true, + .mii_lo_first = true, + + .name = "Atheros AR8327", + .ports = AR8327_NUM_PORTS, + .vlans = AR8X16_MAX_VLANS, + .swops = &ar8327_sw_ops, + + .reg_port_stats_start = 0x1000, + .reg_port_stats_length = 0x100, + + .hw_init = ar8327_hw_init, + .cleanup = ar8327_cleanup, + .init_globals = ar8327_init_globals, + .init_port = ar8327_init_port, + .setup_port = ar8327_setup_port, + .read_port_status = ar8327_read_port_status, + .read_port_eee_status = ar8327_read_port_eee_status, + .atu_flush = ar8327_atu_flush, + .atu_flush_port = ar8327_atu_flush_port, + .vtu_flush = ar8327_vtu_flush, + .vtu_load_vlan = ar8327_vtu_load_vlan, + .phy_fixup = ar8327_phy_fixup, + .set_mirror_regs = ar8327_set_mirror_regs, + .get_arl_entry = ar8327_get_arl_entry, + .sw_hw_apply = ar8327_sw_hw_apply, + + .num_mibs = ARRAY_SIZE(ar8236_mibs), + .mib_decs = ar8236_mibs, + .mib_func = AR8327_REG_MIB_FUNC +}; + +const struct ar8xxx_chip ar8337_chip = { + .caps = AR8XXX_CAP_GIGE | AR8XXX_CAP_MIB_COUNTERS, + .config_at_probe = true, + .mii_lo_first = true, + + .name = "Atheros AR8337", + .ports = AR8327_NUM_PORTS, + .vlans = AR8X16_MAX_VLANS, + .swops = &ar8327_sw_ops, + + .reg_port_stats_start = 0x1000, + .reg_port_stats_length = 0x100, + + .hw_init = ar8327_hw_init, + .cleanup = ar8327_cleanup, + .init_globals = ar8327_init_globals, + .init_port = ar8327_init_port, + .setup_port = ar8327_setup_port, + .read_port_status = ar8327_read_port_status, + .read_port_eee_status = ar8327_read_port_eee_status, + .atu_flush = ar8327_atu_flush, + .atu_flush_port = ar8327_atu_flush_port, + .vtu_flush = ar8327_vtu_flush, + .vtu_load_vlan = ar8327_vtu_load_vlan, + .phy_fixup = ar8327_phy_fixup, + .set_mirror_regs = ar8327_set_mirror_regs, + .get_arl_entry = ar8327_get_arl_entry, + .sw_hw_apply = ar8327_sw_hw_apply, + + .num_mibs = ARRAY_SIZE(ar8236_mibs), + .mib_decs = ar8236_mibs, + .mib_func = AR8327_REG_MIB_FUNC +}; + diff --git a/target/linux/generic/files/drivers/net/phy/ar8327.h b/target/linux/generic/files/drivers/net/phy/ar8327.h new file mode 100644 index 0000000..8d1fb3b --- /dev/null +++ b/target/linux/generic/files/drivers/net/phy/ar8327.h @@ -0,0 +1,252 @@ +/* + * ar8327.h: AR8216 switch driver + * + * Copyright (C) 2009 Felix Fietkau + * + * 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. + */ + +#ifndef __AR8327_H +#define __AR8327_H + +#define AR8327_NUM_PORTS 7 +#define AR8327_NUM_LEDS 15 +#define AR8327_PORTS_ALL 0x7f +#define AR8327_NUM_LED_CTRL_REGS 4 + +#define AR8327_REG_MASK 0x000 + +#define AR8327_REG_PAD0_MODE 0x004 +#define AR8327_REG_PAD5_MODE 0x008 +#define AR8327_REG_PAD6_MODE 0x00c +#define AR8327_PAD_MAC_MII_RXCLK_SEL BIT(0) +#define AR8327_PAD_MAC_MII_TXCLK_SEL BIT(1) +#define AR8327_PAD_MAC_MII_EN BIT(2) +#define AR8327_PAD_MAC_GMII_RXCLK_SEL BIT(4) +#define AR8327_PAD_MAC_GMII_TXCLK_SEL BIT(5) +#define AR8327_PAD_MAC_GMII_EN BIT(6) +#define AR8327_PAD_SGMII_EN BIT(7) +#define AR8327_PAD_PHY_MII_RXCLK_SEL BIT(8) +#define AR8327_PAD_PHY_MII_TXCLK_SEL BIT(9) +#define AR8327_PAD_PHY_MII_EN BIT(10) +#define AR8327_PAD_PHY_GMII_PIPE_RXCLK_SEL BIT(11) +#define AR8327_PAD_PHY_GMII_RXCLK_SEL BIT(12) +#define AR8327_PAD_PHY_GMII_TXCLK_SEL BIT(13) +#define AR8327_PAD_PHY_GMII_EN BIT(14) +#define AR8327_PAD_PHYX_GMII_EN BIT(16) +#define AR8327_PAD_PHYX_RGMII_EN BIT(17) +#define AR8327_PAD_PHYX_MII_EN BIT(18) +#define AR8327_PAD_SGMII_DELAY_EN BIT(19) +#define AR8327_PAD_RGMII_RXCLK_DELAY_SEL BITS(20, 2) +#define AR8327_PAD_RGMII_RXCLK_DELAY_SEL_S 20 +#define AR8327_PAD_RGMII_TXCLK_DELAY_SEL BITS(22, 2) +#define AR8327_PAD_RGMII_TXCLK_DELAY_SEL_S 22 +#define AR8327_PAD_RGMII_RXCLK_DELAY_EN BIT(24) +#define AR8327_PAD_RGMII_TXCLK_DELAY_EN BIT(25) +#define AR8327_PAD_RGMII_EN BIT(26) + +#define AR8327_REG_POWER_ON_STRIP 0x010 +#define AR8327_POWER_ON_STRIP_POWER_ON_SEL BIT(31) +#define AR8327_POWER_ON_STRIP_LED_OPEN_EN BIT(24) +#define AR8327_POWER_ON_STRIP_SERDES_AEN BIT(7) + +#define AR8327_REG_INT_STATUS0 0x020 +#define AR8327_INT0_VT_DONE BIT(20) + +#define AR8327_REG_INT_STATUS1 0x024 +#define AR8327_REG_INT_MASK0 0x028 +#define AR8327_REG_INT_MASK1 0x02c + +#define AR8327_REG_MODULE_EN 0x030 +#define AR8327_MODULE_EN_MIB BIT(0) + +#define AR8327_REG_MIB_FUNC 0x034 +#define AR8327_MIB_CPU_KEEP BIT(20) + +#define AR8327_REG_SERVICE_TAG 0x048 +#define AR8327_REG_LED_CTRL(_i) (0x050 + (_i) * 4) +#define AR8327_REG_LED_CTRL0 0x050 +#define AR8327_REG_LED_CTRL1 0x054 +#define AR8327_REG_LED_CTRL2 0x058 +#define AR8327_REG_LED_CTRL3 0x05c +#define AR8327_REG_MAC_ADDR0 0x060 +#define AR8327_REG_MAC_ADDR1 0x064 + +#define AR8327_REG_MAX_FRAME_SIZE 0x078 +#define AR8327_MAX_FRAME_SIZE_MTU BITS(0, 14) + +#define AR8327_REG_PORT_STATUS(_i) (0x07c + (_i) * 4) +#define AR8327_PORT_STATUS_TXFLOW_AUTO BIT(10) +#define AR8327_PORT_STATUS_RXFLOW_AUTO BIT(11) + +#define AR8327_REG_HEADER_CTRL 0x098 +#define AR8327_REG_PORT_HEADER(_i) (0x09c + (_i) * 4) + +#define AR8327_REG_SGMII_CTRL 0x0e0 +#define AR8327_SGMII_CTRL_EN_PLL BIT(1) +#define AR8327_SGMII_CTRL_EN_RX BIT(2) +#define AR8327_SGMII_CTRL_EN_TX BIT(3) + +#define AR8327_REG_EEE_CTRL 0x100 +#define AR8327_EEE_CTRL_DISABLE_PHY(_i) BIT(4 + (_i) * 2) + +#define AR8327_REG_PORT_VLAN0(_i) (0x420 + (_i) * 0x8) +#define AR8327_PORT_VLAN0_DEF_SVID BITS(0, 12) +#define AR8327_PORT_VLAN0_DEF_SVID_S 0 +#define AR8327_PORT_VLAN0_DEF_CVID BITS(16, 12) +#define AR8327_PORT_VLAN0_DEF_CVID_S 16 + +#define AR8327_REG_PORT_VLAN1(_i) (0x424 + (_i) * 0x8) +#define AR8327_PORT_VLAN1_PORT_VLAN_PROP BIT(6) +#define AR8327_PORT_VLAN1_OUT_MODE BITS(12, 2) +#define AR8327_PORT_VLAN1_OUT_MODE_S 12 +#define AR8327_PORT_VLAN1_OUT_MODE_UNMOD 0 +#define AR8327_PORT_VLAN1_OUT_MODE_UNTAG 1 +#define AR8327_PORT_VLAN1_OUT_MODE_TAG 2 +#define AR8327_PORT_VLAN1_OUT_MODE_UNTOUCH 3 + +#define AR8327_REG_ATU_DATA0 0x600 +#define AR8327_ATU_ADDR0 BITS(0, 8) +#define AR8327_ATU_ADDR0_S 0 +#define AR8327_ATU_ADDR1 BITS(8, 8) +#define AR8327_ATU_ADDR1_S 8 +#define AR8327_ATU_ADDR2 BITS(16, 8) +#define AR8327_ATU_ADDR2_S 16 +#define AR8327_ATU_ADDR3 BITS(24, 8) +#define AR8327_ATU_ADDR3_S 24 +#define AR8327_REG_ATU_DATA1 0x604 +#define AR8327_ATU_ADDR4 BITS(0, 8) +#define AR8327_ATU_ADDR4_S 0 +#define AR8327_ATU_ADDR5 BITS(8, 8) +#define AR8327_ATU_ADDR5_S 8 +#define AR8327_ATU_PORTS BITS(16, 7) +#define AR8327_ATU_PORT0 BIT(16) +#define AR8327_ATU_PORT1 BIT(17) +#define AR8327_ATU_PORT2 BIT(18) +#define AR8327_ATU_PORT3 BIT(19) +#define AR8327_ATU_PORT4 BIT(20) +#define AR8327_ATU_PORT5 BIT(21) +#define AR8327_ATU_PORT6 BIT(22) +#define AR8327_REG_ATU_DATA2 0x608 +#define AR8327_ATU_STATUS BITS(0, 4) + +#define AR8327_REG_ATU_FUNC 0x60c +#define AR8327_ATU_FUNC_OP BITS(0, 4) +#define AR8327_ATU_FUNC_OP_NOOP 0x0 +#define AR8327_ATU_FUNC_OP_FLUSH 0x1 +#define AR8327_ATU_FUNC_OP_LOAD 0x2 +#define AR8327_ATU_FUNC_OP_PURGE 0x3 +#define AR8327_ATU_FUNC_OP_FLUSH_UNLOCKED 0x4 +#define AR8327_ATU_FUNC_OP_FLUSH_PORT 0x5 +#define AR8327_ATU_FUNC_OP_GET_NEXT 0x6 +#define AR8327_ATU_FUNC_OP_SEARCH_MAC 0x7 +#define AR8327_ATU_FUNC_OP_CHANGE_TRUNK 0x8 +#define AR8327_ATU_PORT_NUM BITS(8, 4) +#define AR8327_ATU_PORT_NUM_S 8 +#define AR8327_ATU_FUNC_BUSY BIT(31) + +#define AR8327_REG_VTU_FUNC0 0x0610 +#define AR8327_VTU_FUNC0_EG_MODE BITS(4, 14) +#define AR8327_VTU_FUNC0_EG_MODE_S(_i) (4 + (_i) * 2) +#define AR8327_VTU_FUNC0_EG_MODE_KEEP 0 +#define AR8327_VTU_FUNC0_EG_MODE_UNTAG 1 +#define AR8327_VTU_FUNC0_EG_MODE_TAG 2 +#define AR8327_VTU_FUNC0_EG_MODE_NOT 3 +#define AR8327_VTU_FUNC0_IVL BIT(19) +#define AR8327_VTU_FUNC0_VALID BIT(20) + +#define AR8327_REG_VTU_FUNC1 0x0614 +#define AR8327_VTU_FUNC1_OP BITS(0, 3) +#define AR8327_VTU_FUNC1_OP_NOOP 0 +#define AR8327_VTU_FUNC1_OP_FLUSH 1 +#define AR8327_VTU_FUNC1_OP_LOAD 2 +#define AR8327_VTU_FUNC1_OP_PURGE 3 +#define AR8327_VTU_FUNC1_OP_REMOVE_PORT 4 +#define AR8327_VTU_FUNC1_OP_GET_NEXT 5 +#define AR8327_VTU_FUNC1_OP_GET_ONE 6 +#define AR8327_VTU_FUNC1_FULL BIT(4) +#define AR8327_VTU_FUNC1_PORT BIT(8, 4) +#define AR8327_VTU_FUNC1_PORT_S 8 +#define AR8327_VTU_FUNC1_VID BIT(16, 12) +#define AR8327_VTU_FUNC1_VID_S 16 +#define AR8327_VTU_FUNC1_BUSY BIT(31) + +#define AR8327_REG_FWD_CTRL0 0x620 +#define AR8327_FWD_CTRL0_CPU_PORT_EN BIT(10) +#define AR8327_FWD_CTRL0_MIRROR_PORT BITS(4, 4) +#define AR8327_FWD_CTRL0_MIRROR_PORT_S 4 + +#define AR8327_REG_FWD_CTRL1 0x624 +#define AR8327_FWD_CTRL1_UC_FLOOD BITS(0, 7) +#define AR8327_FWD_CTRL1_UC_FLOOD_S 0 +#define AR8327_FWD_CTRL1_MC_FLOOD BITS(8, 7) +#define AR8327_FWD_CTRL1_MC_FLOOD_S 8 +#define AR8327_FWD_CTRL1_BC_FLOOD BITS(16, 7) +#define AR8327_FWD_CTRL1_BC_FLOOD_S 16 +#define AR8327_FWD_CTRL1_IGMP BITS(24, 7) +#define AR8327_FWD_CTRL1_IGMP_S 24 + +#define AR8327_REG_PORT_LOOKUP(_i) (0x660 + (_i) * 0xc) +#define AR8327_PORT_LOOKUP_MEMBER BITS(0, 7) +#define AR8327_PORT_LOOKUP_IN_MODE BITS(8, 2) +#define AR8327_PORT_LOOKUP_IN_MODE_S 8 +#define AR8327_PORT_LOOKUP_STATE BITS(16, 3) +#define AR8327_PORT_LOOKUP_STATE_S 16 +#define AR8327_PORT_LOOKUP_LEARN BIT(20) +#define AR8327_PORT_LOOKUP_ING_MIRROR_EN BIT(25) + +#define AR8327_REG_PORT_PRIO(_i) (0x664 + (_i) * 0xc) + +#define AR8327_REG_PORT_HOL_CTRL1(_i) (0x974 + (_i) * 0x8) +#define AR8327_PORT_HOL_CTRL1_EG_MIRROR_EN BIT(16) + +#define AR8337_PAD_MAC06_EXCHANGE_EN BIT(31) + +enum ar8327_led_pattern { + AR8327_LED_PATTERN_OFF = 0, + AR8327_LED_PATTERN_BLINK, + AR8327_LED_PATTERN_ON, + AR8327_LED_PATTERN_RULE, +}; + +struct ar8327_led_entry { + unsigned reg; + unsigned shift; +}; + +struct ar8327_led { + struct led_classdev cdev; + struct ar8xxx_priv *sw_priv; + + char *name; + bool active_low; + u8 led_num; + enum ar8327_led_mode mode; + + struct mutex mutex; + spinlock_t lock; + struct work_struct led_work; + bool enable_hw_mode; + enum ar8327_led_pattern pattern; +}; + +struct ar8327_data { + u32 port0_status; + u32 port6_status; + + struct ar8327_led **leds; + unsigned int num_leds; + + /* all fields below are cleared on reset */ + bool eee[AR8XXX_NUM_PHYS]; +}; + +#endif diff --git a/target/linux/generic/files/drivers/net/phy/b53/Kconfig b/target/linux/generic/files/drivers/net/phy/b53/Kconfig new file mode 100644 index 0000000..67e053e --- /dev/null +++ b/target/linux/generic/files/drivers/net/phy/b53/Kconfig @@ -0,0 +1,37 @@ +menuconfig B53 + tristate "Broadcom bcm53xx managed switch support" + depends on SWCONFIG + help + This driver adds support for Broadcom managed switch chips. It supports + BCM5325E, BCM5365, BCM539x, BCM53115 and BCM53125 as well as BCM63XX + integrated switches. + +config B53_SPI_DRIVER + tristate "B53 SPI connected switch driver" + depends on B53 && SPI + help + Select to enable support for registering switches configured through SPI. + +config B53_PHY_DRIVER + tristate "B53 MDIO connected switch driver" + depends on B53 + select B53_PHY_FIXUP + help + Select to enable support for registering switches configured through MDIO. + +config B53_MMAP_DRIVER + tristate "B53 MMAP connected switch driver" + depends on B53 + help + Select to enable support for memory-mapped switches like the BCM63XX + integrated switches. + +config B53_SRAB_DRIVER + tristate "B53 SRAB connected switch driver" + depends on B53 + help + Select to enable support for memory-mapped Switch Register Access + Bridge Registers (SRAB) like it is found on the BCM53010 + +config B53_PHY_FIXUP + bool diff --git a/target/linux/generic/files/drivers/net/phy/b53/Makefile b/target/linux/generic/files/drivers/net/phy/b53/Makefile new file mode 100644 index 0000000..7cc39c7 --- /dev/null +++ b/target/linux/generic/files/drivers/net/phy/b53/Makefile @@ -0,0 +1,10 @@ +obj-$(CONFIG_B53) += b53_common.o + +obj-$(CONFIG_B53_PHY_FIXUP) += b53_phy_fixup.o + +obj-$(CONFIG_B53_MMAP_DRIVER) += b53_mmap.o +obj-$(CONFIG_B53_SRAB_DRIVER) += b53_srab.o +obj-$(CONFIG_B53_PHY_DRIVER) += b53_mdio.o +obj-$(CONFIG_B53_SPI_DRIVER) += b53_spi.o + +ccflags-y += -Werror diff --git a/target/linux/generic/files/drivers/net/phy/b53/b53_common.c b/target/linux/generic/files/drivers/net/phy/b53/b53_common.c new file mode 100644 index 0000000..859d8d1 --- /dev/null +++ b/target/linux/generic/files/drivers/net/phy/b53/b53_common.c @@ -0,0 +1,1457 @@ +/* + * B53 switch driver main logic + * + * Copyright (C) 2011-2013 Jonas Gorski + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include + +#include "b53_regs.h" +#include "b53_priv.h" + +/* buffer size needed for displaying all MIBs with max'd values */ +#define B53_BUF_SIZE 1188 + +struct b53_mib_desc { + u8 size; + u8 offset; + const char *name; +}; + + +/* BCM5365 MIB counters */ +static const struct b53_mib_desc b53_mibs_65[] = { + { 8, 0x00, "TxOctets" }, + { 4, 0x08, "TxDropPkts" }, + { 4, 0x10, "TxBroadcastPkts" }, + { 4, 0x14, "TxMulticastPkts" }, + { 4, 0x18, "TxUnicastPkts" }, + { 4, 0x1c, "TxCollisions" }, + { 4, 0x20, "TxSingleCollision" }, + { 4, 0x24, "TxMultipleCollision" }, + { 4, 0x28, "TxDeferredTransmit" }, + { 4, 0x2c, "TxLateCollision" }, + { 4, 0x30, "TxExcessiveCollision" }, + { 4, 0x38, "TxPausePkts" }, + { 8, 0x44, "RxOctets" }, + { 4, 0x4c, "RxUndersizePkts" }, + { 4, 0x50, "RxPausePkts" }, + { 4, 0x54, "Pkts64Octets" }, + { 4, 0x58, "Pkts65to127Octets" }, + { 4, 0x5c, "Pkts128to255Octets" }, + { 4, 0x60, "Pkts256to511Octets" }, + { 4, 0x64, "Pkts512to1023Octets" }, + { 4, 0x68, "Pkts1024to1522Octets" }, + { 4, 0x6c, "RxOversizePkts" }, + { 4, 0x70, "RxJabbers" }, + { 4, 0x74, "RxAlignmentErrors" }, + { 4, 0x78, "RxFCSErrors" }, + { 8, 0x7c, "RxGoodOctets" }, + { 4, 0x84, "RxDropPkts" }, + { 4, 0x88, "RxUnicastPkts" }, + { 4, 0x8c, "RxMulticastPkts" }, + { 4, 0x90, "RxBroadcastPkts" }, + { 4, 0x94, "RxSAChanges" }, + { 4, 0x98, "RxFragments" }, + { }, +}; + +/* BCM63xx MIB counters */ +static const struct b53_mib_desc b53_mibs_63xx[] = { + { 8, 0x00, "TxOctets" }, + { 4, 0x08, "TxDropPkts" }, + { 4, 0x0c, "TxQoSPkts" }, + { 4, 0x10, "TxBroadcastPkts" }, + { 4, 0x14, "TxMulticastPkts" }, + { 4, 0x18, "TxUnicastPkts" }, + { 4, 0x1c, "TxCollisions" }, + { 4, 0x20, "TxSingleCollision" }, + { 4, 0x24, "TxMultipleCollision" }, + { 4, 0x28, "TxDeferredTransmit" }, + { 4, 0x2c, "TxLateCollision" }, + { 4, 0x30, "TxExcessiveCollision" }, + { 4, 0x38, "TxPausePkts" }, + { 8, 0x3c, "TxQoSOctets" }, + { 8, 0x44, "RxOctets" }, + { 4, 0x4c, "RxUndersizePkts" }, + { 4, 0x50, "RxPausePkts" }, + { 4, 0x54, "Pkts64Octets" }, + { 4, 0x58, "Pkts65to127Octets" }, + { 4, 0x5c, "Pkts128to255Octets" }, + { 4, 0x60, "Pkts256to511Octets" }, + { 4, 0x64, "Pkts512to1023Octets" }, + { 4, 0x68, "Pkts1024to1522Octets" }, + { 4, 0x6c, "RxOversizePkts" }, + { 4, 0x70, "RxJabbers" }, + { 4, 0x74, "RxAlignmentErrors" }, + { 4, 0x78, "RxFCSErrors" }, + { 8, 0x7c, "RxGoodOctets" }, + { 4, 0x84, "RxDropPkts" }, + { 4, 0x88, "RxUnicastPkts" }, + { 4, 0x8c, "RxMulticastPkts" }, + { 4, 0x90, "RxBroadcastPkts" }, + { 4, 0x94, "RxSAChanges" }, + { 4, 0x98, "RxFragments" }, + { 4, 0xa0, "RxSymbolErrors" }, + { 4, 0xa4, "RxQoSPkts" }, + { 8, 0xa8, "RxQoSOctets" }, + { 4, 0xb0, "Pkts1523to2047Octets" }, + { 4, 0xb4, "Pkts2048to4095Octets" }, + { 4, 0xb8, "Pkts4096to8191Octets" }, + { 4, 0xbc, "Pkts8192to9728Octets" }, + { 4, 0xc0, "RxDiscarded" }, + { } +}; + +/* MIB counters */ +static const struct b53_mib_desc b53_mibs[] = { + { 8, 0x00, "TxOctets" }, + { 4, 0x08, "TxDropPkts" }, + { 4, 0x10, "TxBroadcastPkts" }, + { 4, 0x14, "TxMulticastPkts" }, + { 4, 0x18, "TxUnicastPkts" }, + { 4, 0x1c, "TxCollisions" }, + { 4, 0x20, "TxSingleCollision" }, + { 4, 0x24, "TxMultipleCollision" }, + { 4, 0x28, "TxDeferredTransmit" }, + { 4, 0x2c, "TxLateCollision" }, + { 4, 0x30, "TxExcessiveCollision" }, + { 4, 0x38, "TxPausePkts" }, + { 8, 0x50, "RxOctets" }, + { 4, 0x58, "RxUndersizePkts" }, + { 4, 0x5c, "RxPausePkts" }, + { 4, 0x60, "Pkts64Octets" }, + { 4, 0x64, "Pkts65to127Octets" }, + { 4, 0x68, "Pkts128to255Octets" }, + { 4, 0x6c, "Pkts256to511Octets" }, + { 4, 0x70, "Pkts512to1023Octets" }, + { 4, 0x74, "Pkts1024to1522Octets" }, + { 4, 0x78, "RxOversizePkts" }, + { 4, 0x7c, "RxJabbers" }, + { 4, 0x80, "RxAlignmentErrors" }, + { 4, 0x84, "RxFCSErrors" }, + { 8, 0x88, "RxGoodOctets" }, + { 4, 0x90, "RxDropPkts" }, + { 4, 0x94, "RxUnicastPkts" }, + { 4, 0x98, "RxMulticastPkts" }, + { 4, 0x9c, "RxBroadcastPkts" }, + { 4, 0xa0, "RxSAChanges" }, + { 4, 0xa4, "RxFragments" }, + { 4, 0xa8, "RxJumboPkts" }, + { 4, 0xac, "RxSymbolErrors" }, + { 4, 0xc0, "RxDiscarded" }, + { } +}; + +static int b53_do_vlan_op(struct b53_device *dev, u8 op) +{ + unsigned int i; + + b53_write8(dev, B53_ARLIO_PAGE, dev->vta_regs[0], VTA_START_CMD | op); + + for (i = 0; i < 10; i++) { + u8 vta; + + b53_read8(dev, B53_ARLIO_PAGE, dev->vta_regs[0], &vta); + if (!(vta & VTA_START_CMD)) + return 0; + + usleep_range(100, 200); + } + + return -EIO; +} + +static void b53_set_vlan_entry(struct b53_device *dev, u16 vid, u16 members, + u16 untag) +{ + if (is5325(dev)) { + u32 entry = 0; + + if (members) { + entry = ((untag & VA_UNTAG_MASK_25) << VA_UNTAG_S_25) | + members; + if (dev->core_rev >= 3) + entry |= VA_VALID_25_R4 | vid << VA_VID_HIGH_S; + else + entry |= VA_VALID_25; + } + + b53_write32(dev, B53_VLAN_PAGE, B53_VLAN_WRITE_25, entry); + b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_TABLE_ACCESS_25, vid | + VTA_RW_STATE_WR | VTA_RW_OP_EN); + } else if (is5365(dev)) { + u16 entry = 0; + + if (members) + entry = ((untag & VA_UNTAG_MASK_65) << VA_UNTAG_S_65) | + members | VA_VALID_65; + + b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_WRITE_65, entry); + b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_TABLE_ACCESS_65, vid | + VTA_RW_STATE_WR | VTA_RW_OP_EN); + } else { + b53_write16(dev, B53_ARLIO_PAGE, dev->vta_regs[1], vid); + b53_write32(dev, B53_ARLIO_PAGE, dev->vta_regs[2], + (untag << VTE_UNTAG_S) | members); + + b53_do_vlan_op(dev, VTA_CMD_WRITE); + } +} + +void b53_set_forwarding(struct b53_device *dev, int enable) +{ + u8 mgmt; + + b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &mgmt); + + if (enable) + mgmt |= SM_SW_FWD_EN; + else + mgmt &= ~SM_SW_FWD_EN; + + b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, mgmt); +} + +static void b53_enable_vlan(struct b53_device *dev, int enable) +{ + u8 mgmt, vc0, vc1, vc4 = 0, vc5; + + b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &mgmt); + b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL0, &vc0); + b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL1, &vc1); + + if (is5325(dev) || is5365(dev)) { + b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4_25, &vc4); + b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5_25, &vc5); + } else if (is63xx(dev)) { + b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4_63XX, &vc4); + b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5_63XX, &vc5); + } else { + b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4, &vc4); + b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5, &vc5); + } + + mgmt &= ~SM_SW_FWD_MODE; + + if (enable) { + vc0 |= VC0_VLAN_EN | VC0_VID_CHK_EN | VC0_VID_HASH_VID; + vc1 |= VC1_RX_MCST_UNTAG_EN | VC1_RX_MCST_FWD_EN; + vc4 &= ~VC4_ING_VID_CHECK_MASK; + vc4 |= VC4_ING_VID_VIO_DROP << VC4_ING_VID_CHECK_S; + vc5 |= VC5_DROP_VTABLE_MISS; + + if (is5325(dev)) + vc0 &= ~VC0_RESERVED_1; + + if (is5325(dev) || is5365(dev)) + vc1 |= VC1_RX_MCST_TAG_EN; + + if (!is5325(dev) && !is5365(dev)) { + if (dev->allow_vid_4095) + vc5 |= VC5_VID_FFF_EN; + else + vc5 &= ~VC5_VID_FFF_EN; + } + } else { + vc0 &= ~(VC0_VLAN_EN | VC0_VID_CHK_EN | VC0_VID_HASH_VID); + vc1 &= ~(VC1_RX_MCST_UNTAG_EN | VC1_RX_MCST_FWD_EN); + vc4 &= ~VC4_ING_VID_CHECK_MASK; + vc5 &= ~VC5_DROP_VTABLE_MISS; + + if (is5325(dev) || is5365(dev)) + vc4 |= VC4_ING_VID_VIO_FWD << VC4_ING_VID_CHECK_S; + else + vc4 |= VC4_ING_VID_VIO_TO_IMP << VC4_ING_VID_CHECK_S; + + if (is5325(dev) || is5365(dev)) + vc1 &= ~VC1_RX_MCST_TAG_EN; + + if (!is5325(dev) && !is5365(dev)) + vc5 &= ~VC5_VID_FFF_EN; + } + + b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL0, vc0); + b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL1, vc1); + + if (is5325(dev) || is5365(dev)) { + /* enable the high 8 bit vid check on 5325 */ + if (is5325(dev) && enable) + b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL3, + VC3_HIGH_8BIT_EN); + else + b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL3, 0); + + b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4_25, vc4); + b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5_25, vc5); + } else if (is63xx(dev)) { + b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_CTRL3_63XX, 0); + b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4_63XX, vc4); + b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5_63XX, vc5); + } else { + b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_CTRL3, 0); + b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4, vc4); + b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5, vc5); + } + + b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, mgmt); +} + +static int b53_set_jumbo(struct b53_device *dev, int enable, int allow_10_100) +{ + u32 port_mask = 0; + u16 max_size = JMS_MIN_SIZE; + + if (is5325(dev) || is5365(dev)) + return -EINVAL; + + if (enable) { + port_mask = dev->enabled_ports; + max_size = JMS_MAX_SIZE; + if (allow_10_100) + port_mask |= JPM_10_100_JUMBO_EN; + } + + b53_write32(dev, B53_JUMBO_PAGE, dev->jumbo_pm_reg, port_mask); + return b53_write16(dev, B53_JUMBO_PAGE, dev->jumbo_size_reg, max_size); +} + +static int b53_flush_arl(struct b53_device *dev) +{ + unsigned int i; + + b53_write8(dev, B53_CTRL_PAGE, B53_FAST_AGE_CTRL, + FAST_AGE_DONE | FAST_AGE_DYNAMIC | FAST_AGE_STATIC); + + for (i = 0; i < 10; i++) { + u8 fast_age_ctrl; + + b53_read8(dev, B53_CTRL_PAGE, B53_FAST_AGE_CTRL, + &fast_age_ctrl); + + if (!(fast_age_ctrl & FAST_AGE_DONE)) + return 0; + + mdelay(1); + } + + pr_warn("time out while flushing ARL\n"); + + return -EINVAL; +} + +static void b53_enable_ports(struct b53_device *dev) +{ + unsigned i; + + b53_for_each_port(dev, i) { + u8 port_ctrl; + u16 pvlan_mask; + + /* + * prevent leaking packets between wan and lan in unmanaged + * mode through port vlans. + */ + if (dev->enable_vlan || is_cpu_port(dev, i)) + pvlan_mask = 0x1ff; + else if (is531x5(dev) || is5301x(dev)) + /* BCM53115 may use a different port as cpu port */ + pvlan_mask = BIT(dev->sw_dev.cpu_port); + else + pvlan_mask = BIT(B53_CPU_PORT); + + /* BCM5325 CPU port is at 8 */ + if ((is5325(dev) || is5365(dev)) && i == B53_CPU_PORT_25) + i = B53_CPU_PORT; + + if (dev->chip_id == BCM5398_DEVICE_ID && (i == 6 || i == 7)) + /* disable unused ports 6 & 7 */ + port_ctrl = PORT_CTRL_RX_DISABLE | PORT_CTRL_TX_DISABLE; + else if (i == B53_CPU_PORT) + port_ctrl = PORT_CTRL_RX_BCST_EN | + PORT_CTRL_RX_MCST_EN | + PORT_CTRL_RX_UCST_EN; + else + port_ctrl = 0; + + b53_write16(dev, B53_PVLAN_PAGE, B53_PVLAN_PORT_MASK(i), + pvlan_mask); + + /* port state is handled by bcm63xx_enet driver */ + if (!is63xx(dev) && !(is5301x(dev) && i == 6)) + b53_write8(dev, B53_CTRL_PAGE, B53_PORT_CTRL(i), + port_ctrl); + } +} + +static void b53_enable_mib(struct b53_device *dev) +{ + u8 gc; + + b53_read8(dev, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, &gc); + + gc &= ~(GC_RESET_MIB | GC_MIB_AC_EN); + + b53_write8(dev, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, gc); +} + +static int b53_apply(struct b53_device *dev) +{ + int i; + + /* clear all vlan entries */ + if (is5325(dev) || is5365(dev)) { + for (i = 1; i < dev->sw_dev.vlans; i++) + b53_set_vlan_entry(dev, i, 0, 0); + } else { + b53_do_vlan_op(dev, VTA_CMD_CLEAR); + } + + b53_enable_vlan(dev, dev->enable_vlan); + + /* fill VLAN table */ + if (dev->enable_vlan) { + for (i = 0; i < dev->sw_dev.vlans; i++) { + struct b53_vlan *vlan = &dev->vlans[i]; + + if (!vlan->members) + continue; + + b53_set_vlan_entry(dev, i, vlan->members, vlan->untag); + } + + b53_for_each_port(dev, i) + b53_write16(dev, B53_VLAN_PAGE, + B53_VLAN_PORT_DEF_TAG(i), + dev->ports[i].pvid); + } else { + b53_for_each_port(dev, i) + b53_write16(dev, B53_VLAN_PAGE, + B53_VLAN_PORT_DEF_TAG(i), 1); + + } + + b53_enable_ports(dev); + + if (!is5325(dev) && !is5365(dev)) + b53_set_jumbo(dev, dev->enable_jumbo, 1); + + return 0; +} + +static void b53_switch_reset_gpio(struct b53_device *dev) +{ + int gpio = dev->reset_gpio; + + if (gpio < 0) + return; + + /* + * Reset sequence: RESET low(50ms)->high(20ms) + */ + gpio_set_value(gpio, 0); + mdelay(50); + + gpio_set_value(gpio, 1); + mdelay(20); + + dev->current_page = 0xff; +} + +static int b53_switch_reset(struct b53_device *dev) +{ + u8 cpu_port = dev->sw_dev.cpu_port; + u8 mgmt; + + b53_switch_reset_gpio(dev); + + if (is539x(dev)) { + b53_write8(dev, B53_CTRL_PAGE, B53_SOFTRESET, 0x83); + b53_write8(dev, B53_CTRL_PAGE, B53_SOFTRESET, 0x00); + } + + b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &mgmt); + + if (!(mgmt & SM_SW_FWD_EN)) { + mgmt &= ~SM_SW_FWD_MODE; + mgmt |= SM_SW_FWD_EN; + + b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, mgmt); + b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &mgmt); + + if (!(mgmt & SM_SW_FWD_EN)) { + pr_err("Failed to enable switch!\n"); + return -EINVAL; + } + } + + /* enable all ports */ + b53_enable_ports(dev); + + /* configure MII port if necessary */ + if (is5325(dev)) { + u8 mii_port_override; + + b53_read8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL, + &mii_port_override); + /* reverse mii needs to be enabled */ + if (!(mii_port_override & PORT_OVERRIDE_RV_MII_25)) { + b53_write8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL, + mii_port_override | PORT_OVERRIDE_RV_MII_25); + b53_read8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL, + &mii_port_override); + + if (!(mii_port_override & PORT_OVERRIDE_RV_MII_25)) { + pr_err("Failed to enable reverse MII mode\n"); + return -EINVAL; + } + } + } else if (is531x5(dev) && cpu_port == B53_CPU_PORT) { + u8 mii_port_override; + + b53_read8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL, + &mii_port_override); + b53_write8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL, + mii_port_override | PORT_OVERRIDE_EN | + PORT_OVERRIDE_LINK); + } else if (is5301x(dev)) { + if (cpu_port == 8) { + u8 mii_port_override; + + b53_read8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL, + &mii_port_override); + mii_port_override |= PORT_OVERRIDE_LINK | + PORT_OVERRIDE_RX_FLOW | + PORT_OVERRIDE_TX_FLOW | + PORT_OVERRIDE_SPEED_2000M | + PORT_OVERRIDE_EN; + b53_write8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL, + mii_port_override); + + /* TODO: Ports 5 & 7 require some extra handling */ + } else { + u8 po_reg = B53_GMII_PORT_OVERRIDE_CTRL(cpu_port); + u8 gmii_po; + + b53_read8(dev, B53_CTRL_PAGE, po_reg, &gmii_po); + gmii_po |= GMII_PO_LINK | + GMII_PO_RX_FLOW | + GMII_PO_TX_FLOW | + GMII_PO_EN | + GMII_PO_SPEED_2000M; + b53_write8(dev, B53_CTRL_PAGE, po_reg, gmii_po); + } + } + + b53_enable_mib(dev); + + return b53_flush_arl(dev); +} + +/* + * Swconfig glue functions + */ + +static int b53_global_get_vlan_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct b53_device *priv = sw_to_b53(dev); + + val->value.i = priv->enable_vlan; + + return 0; +} + +static int b53_global_set_vlan_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct b53_device *priv = sw_to_b53(dev); + + priv->enable_vlan = val->value.i; + + return 0; +} + +static int b53_global_get_jumbo_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct b53_device *priv = sw_to_b53(dev); + + val->value.i = priv->enable_jumbo; + + return 0; +} + +static int b53_global_set_jumbo_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct b53_device *priv = sw_to_b53(dev); + + priv->enable_jumbo = val->value.i; + + return 0; +} + +static int b53_global_get_4095_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct b53_device *priv = sw_to_b53(dev); + + val->value.i = priv->allow_vid_4095; + + return 0; +} + +static int b53_global_set_4095_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct b53_device *priv = sw_to_b53(dev); + + priv->allow_vid_4095 = val->value.i; + + return 0; +} + +static int b53_global_get_ports(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct b53_device *priv = sw_to_b53(dev); + + val->len = snprintf(priv->buf, B53_BUF_SIZE, "0x%04x", + priv->enabled_ports); + val->value.s = priv->buf; + + return 0; +} + +static int b53_port_get_pvid(struct switch_dev *dev, int port, int *val) +{ + struct b53_device *priv = sw_to_b53(dev); + + *val = priv->ports[port].pvid; + + return 0; +} + +static int b53_port_set_pvid(struct switch_dev *dev, int port, int val) +{ + struct b53_device *priv = sw_to_b53(dev); + + if (val > 15 && is5325(priv)) + return -EINVAL; + if (val == 4095 && !priv->allow_vid_4095) + return -EINVAL; + + priv->ports[port].pvid = val; + + return 0; +} + +static int b53_vlan_get_ports(struct switch_dev *dev, struct switch_val *val) +{ + struct b53_device *priv = sw_to_b53(dev); + struct switch_port *port = &val->value.ports[0]; + struct b53_vlan *vlan = &priv->vlans[val->port_vlan]; + int i; + + val->len = 0; + + if (!vlan->members) + return 0; + + for (i = 0; i < dev->ports; i++) { + if (!(vlan->members & BIT(i))) + continue; + + + if (!(vlan->untag & BIT(i))) + port->flags = BIT(SWITCH_PORT_FLAG_TAGGED); + else + port->flags = 0; + + port->id = i; + val->len++; + port++; + } + + return 0; +} + +static int b53_vlan_set_ports(struct switch_dev *dev, struct switch_val *val) +{ + struct b53_device *priv = sw_to_b53(dev); + struct switch_port *port; + struct b53_vlan *vlan = &priv->vlans[val->port_vlan]; + int i; + + /* only BCM5325 and BCM5365 supports VID 0 */ + if (val->port_vlan == 0 && !is5325(priv) && !is5365(priv)) + return -EINVAL; + + /* VLAN 4095 needs special handling */ + if (val->port_vlan == 4095 && !priv->allow_vid_4095) + return -EINVAL; + + port = &val->value.ports[0]; + vlan->members = 0; + vlan->untag = 0; + for (i = 0; i < val->len; i++, port++) { + vlan->members |= BIT(port->id); + + if (!(port->flags & BIT(SWITCH_PORT_FLAG_TAGGED))) { + vlan->untag |= BIT(port->id); + priv->ports[port->id].pvid = val->port_vlan; + }; + } + + /* ignore disabled ports */ + vlan->members &= priv->enabled_ports; + vlan->untag &= priv->enabled_ports; + + return 0; +} + +static int b53_port_get_link(struct switch_dev *dev, int port, + struct switch_port_link *link) +{ + struct b53_device *priv = sw_to_b53(dev); + + if (is_cpu_port(priv, port)) { + link->link = 1; + link->duplex = 1; + link->speed = is5325(priv) || is5365(priv) ? + SWITCH_PORT_SPEED_100 : SWITCH_PORT_SPEED_1000; + link->aneg = 0; + } else if (priv->enabled_ports & BIT(port)) { + u32 speed; + u16 lnk, duplex; + + b53_read16(priv, B53_STAT_PAGE, B53_LINK_STAT, &lnk); + b53_read16(priv, B53_STAT_PAGE, priv->duplex_reg, &duplex); + + lnk = (lnk >> port) & 1; + duplex = (duplex >> port) & 1; + + if (is5325(priv) || is5365(priv)) { + u16 tmp; + + b53_read16(priv, B53_STAT_PAGE, B53_SPEED_STAT, &tmp); + speed = SPEED_PORT_FE(tmp, port); + } else { + b53_read32(priv, B53_STAT_PAGE, B53_SPEED_STAT, &speed); + speed = SPEED_PORT_GE(speed, port); + } + + link->link = lnk; + if (lnk) { + link->duplex = duplex; + switch (speed) { + case SPEED_STAT_10M: + link->speed = SWITCH_PORT_SPEED_10; + break; + case SPEED_STAT_100M: + link->speed = SWITCH_PORT_SPEED_100; + break; + case SPEED_STAT_1000M: + link->speed = SWITCH_PORT_SPEED_1000; + break; + } + } + + link->aneg = 1; + } else { + link->link = 0; + } + + return 0; + +} + +static int b53_global_reset_switch(struct switch_dev *dev) +{ + struct b53_device *priv = sw_to_b53(dev); + + /* reset vlans */ + priv->enable_vlan = 0; + priv->enable_jumbo = 0; + priv->allow_vid_4095 = 0; + + memset(priv->vlans, 0, sizeof(*priv->vlans) * dev->vlans); + memset(priv->ports, 0, sizeof(*priv->ports) * dev->ports); + + return b53_switch_reset(priv); +} + +static int b53_global_apply_config(struct switch_dev *dev) +{ + struct b53_device *priv = sw_to_b53(dev); + + /* disable switching */ + b53_set_forwarding(priv, 0); + + b53_apply(priv); + + /* enable switching */ + b53_set_forwarding(priv, 1); + + return 0; +} + + +static int b53_global_reset_mib(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct b53_device *priv = sw_to_b53(dev); + u8 gc; + + b53_read8(priv, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, &gc); + + b53_write8(priv, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, gc | GC_RESET_MIB); + mdelay(1); + b53_write8(priv, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, gc & ~GC_RESET_MIB); + mdelay(1); + + return 0; +} + +static int b53_port_get_mib(struct switch_dev *sw_dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct b53_device *dev = sw_to_b53(sw_dev); + const struct b53_mib_desc *mibs; + int port = val->port_vlan; + int len = 0; + + if (!(BIT(port) & dev->enabled_ports)) + return -1; + + if (is5365(dev)) { + if (port == 5) + port = 8; + + mibs = b53_mibs_65; + } else if (is63xx(dev)) { + mibs = b53_mibs_63xx; + } else { + mibs = b53_mibs; + } + + dev->buf[0] = 0; + + for (; mibs->size > 0; mibs++) { + u64 val; + + if (mibs->size == 8) { + b53_read64(dev, B53_MIB_PAGE(port), mibs->offset, &val); + } else { + u32 val32; + + b53_read32(dev, B53_MIB_PAGE(port), mibs->offset, + &val32); + val = val32; + } + + len += snprintf(dev->buf + len, B53_BUF_SIZE - len, + "%-20s: %llu\n", mibs->name, val); + } + + val->len = len; + val->value.s = dev->buf; + + return 0; +} + +static struct switch_attr b53_global_ops_25[] = { + { + .type = SWITCH_TYPE_INT, + .name = "enable_vlan", + .description = "Enable VLAN mode", + .set = b53_global_set_vlan_enable, + .get = b53_global_get_vlan_enable, + .max = 1, + }, + { + .type = SWITCH_TYPE_STRING, + .name = "ports", + .description = "Available ports (as bitmask)", + .get = b53_global_get_ports, + }, +}; + +static struct switch_attr b53_global_ops_65[] = { + { + .type = SWITCH_TYPE_INT, + .name = "enable_vlan", + .description = "Enable VLAN mode", + .set = b53_global_set_vlan_enable, + .get = b53_global_get_vlan_enable, + .max = 1, + }, + { + .type = SWITCH_TYPE_STRING, + .name = "ports", + .description = "Available ports (as bitmask)", + .get = b53_global_get_ports, + }, + { + .type = SWITCH_TYPE_INT, + .name = "reset_mib", + .description = "Reset MIB counters", + .set = b53_global_reset_mib, + }, +}; + +static struct switch_attr b53_global_ops[] = { + { + .type = SWITCH_TYPE_INT, + .name = "enable_vlan", + .description = "Enable VLAN mode", + .set = b53_global_set_vlan_enable, + .get = b53_global_get_vlan_enable, + .max = 1, + }, + { + .type = SWITCH_TYPE_STRING, + .name = "ports", + .description = "Available Ports (as bitmask)", + .get = b53_global_get_ports, + }, + { + .type = SWITCH_TYPE_INT, + .name = "reset_mib", + .description = "Reset MIB counters", + .set = b53_global_reset_mib, + }, + { + .type = SWITCH_TYPE_INT, + .name = "enable_jumbo", + .description = "Enable Jumbo Frames", + .set = b53_global_set_jumbo_enable, + .get = b53_global_get_jumbo_enable, + .max = 1, + }, + { + .type = SWITCH_TYPE_INT, + .name = "allow_vid_4095", + .description = "Allow VID 4095", + .set = b53_global_set_4095_enable, + .get = b53_global_get_4095_enable, + .max = 1, + }, +}; + +static struct switch_attr b53_port_ops[] = { + { + .type = SWITCH_TYPE_STRING, + .name = "mib", + .description = "Get port's MIB counters", + .get = b53_port_get_mib, + }, +}; + +static struct switch_attr b53_no_ops[] = { +}; + +static const struct switch_dev_ops b53_switch_ops_25 = { + .attr_global = { + .attr = b53_global_ops_25, + .n_attr = ARRAY_SIZE(b53_global_ops_25), + }, + .attr_port = { + .attr = b53_no_ops, + .n_attr = ARRAY_SIZE(b53_no_ops), + }, + .attr_vlan = { + .attr = b53_no_ops, + .n_attr = ARRAY_SIZE(b53_no_ops), + }, + + .get_vlan_ports = b53_vlan_get_ports, + .set_vlan_ports = b53_vlan_set_ports, + .get_port_pvid = b53_port_get_pvid, + .set_port_pvid = b53_port_set_pvid, + .apply_config = b53_global_apply_config, + .reset_switch = b53_global_reset_switch, + .get_port_link = b53_port_get_link, +}; + +static const struct switch_dev_ops b53_switch_ops_65 = { + .attr_global = { + .attr = b53_global_ops_65, + .n_attr = ARRAY_SIZE(b53_global_ops_65), + }, + .attr_port = { + .attr = b53_port_ops, + .n_attr = ARRAY_SIZE(b53_port_ops), + }, + .attr_vlan = { + .attr = b53_no_ops, + .n_attr = ARRAY_SIZE(b53_no_ops), + }, + + .get_vlan_ports = b53_vlan_get_ports, + .set_vlan_ports = b53_vlan_set_ports, + .get_port_pvid = b53_port_get_pvid, + .set_port_pvid = b53_port_set_pvid, + .apply_config = b53_global_apply_config, + .reset_switch = b53_global_reset_switch, + .get_port_link = b53_port_get_link, +}; + +static const struct switch_dev_ops b53_switch_ops = { + .attr_global = { + .attr = b53_global_ops, + .n_attr = ARRAY_SIZE(b53_global_ops), + }, + .attr_port = { + .attr = b53_port_ops, + .n_attr = ARRAY_SIZE(b53_port_ops), + }, + .attr_vlan = { + .attr = b53_no_ops, + .n_attr = ARRAY_SIZE(b53_no_ops), + }, + + .get_vlan_ports = b53_vlan_get_ports, + .set_vlan_ports = b53_vlan_set_ports, + .get_port_pvid = b53_port_get_pvid, + .set_port_pvid = b53_port_set_pvid, + .apply_config = b53_global_apply_config, + .reset_switch = b53_global_reset_switch, + .get_port_link = b53_port_get_link, +}; + +struct b53_chip_data { + u32 chip_id; + const char *dev_name; + const char *alias; + u16 vlans; + u16 enabled_ports; + u8 cpu_port; + u8 vta_regs[3]; + u8 duplex_reg; + u8 jumbo_pm_reg; + u8 jumbo_size_reg; + const struct switch_dev_ops *sw_ops; +}; + +#define B53_VTA_REGS \ + { B53_VT_ACCESS, B53_VT_INDEX, B53_VT_ENTRY } +#define B53_VTA_REGS_9798 \ + { B53_VT_ACCESS_9798, B53_VT_INDEX_9798, B53_VT_ENTRY_9798 } +#define B53_VTA_REGS_63XX \ + { B53_VT_ACCESS_63XX, B53_VT_INDEX_63XX, B53_VT_ENTRY_63XX } + +static const struct b53_chip_data b53_switch_chips[] = { + { + .chip_id = BCM5325_DEVICE_ID, + .dev_name = "BCM5325", + .alias = "bcm5325", + .vlans = 16, + .enabled_ports = 0x1f, + .cpu_port = B53_CPU_PORT_25, + .duplex_reg = B53_DUPLEX_STAT_FE, + .sw_ops = &b53_switch_ops_25, + }, + { + .chip_id = BCM5365_DEVICE_ID, + .dev_name = "BCM5365", + .alias = "bcm5365", + .vlans = 256, + .enabled_ports = 0x1f, + .cpu_port = B53_CPU_PORT_25, + .duplex_reg = B53_DUPLEX_STAT_FE, + .sw_ops = &b53_switch_ops_65, + }, + { + .chip_id = BCM5395_DEVICE_ID, + .dev_name = "BCM5395", + .alias = "bcm5395", + .vlans = 4096, + .enabled_ports = 0x1f, + .cpu_port = B53_CPU_PORT, + .vta_regs = B53_VTA_REGS, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + .sw_ops = &b53_switch_ops, + }, + { + .chip_id = BCM5397_DEVICE_ID, + .dev_name = "BCM5397", + .alias = "bcm5397", + .vlans = 4096, + .enabled_ports = 0x1f, + .cpu_port = B53_CPU_PORT, + .vta_regs = B53_VTA_REGS_9798, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + .sw_ops = &b53_switch_ops, + }, + { + .chip_id = BCM5398_DEVICE_ID, + .dev_name = "BCM5398", + .alias = "bcm5398", + .vlans = 4096, + .enabled_ports = 0x7f, + .cpu_port = B53_CPU_PORT, + .vta_regs = B53_VTA_REGS_9798, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + .sw_ops = &b53_switch_ops, + }, + { + .chip_id = BCM53115_DEVICE_ID, + .dev_name = "BCM53115", + .alias = "bcm53115", + .vlans = 4096, + .enabled_ports = 0x1f, + .vta_regs = B53_VTA_REGS, + .cpu_port = B53_CPU_PORT, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + .sw_ops = &b53_switch_ops, + }, + { + .chip_id = BCM53125_DEVICE_ID, + .dev_name = "BCM53125", + .alias = "bcm53125", + .vlans = 4096, + .enabled_ports = 0x1f, + .cpu_port = B53_CPU_PORT, + .vta_regs = B53_VTA_REGS, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + .sw_ops = &b53_switch_ops, + }, + { + .chip_id = BCM53128_DEVICE_ID, + .dev_name = "BCM53128", + .alias = "bcm53128", + .vlans = 4096, + .enabled_ports = 0x1ff, + .cpu_port = B53_CPU_PORT, + .vta_regs = B53_VTA_REGS, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + .sw_ops = &b53_switch_ops, + }, + { + .chip_id = BCM63XX_DEVICE_ID, + .dev_name = "BCM63xx", + .alias = "bcm63xx", + .vlans = 4096, + .enabled_ports = 0, /* pdata must provide them */ + .cpu_port = B53_CPU_PORT, + .vta_regs = B53_VTA_REGS_63XX, + .duplex_reg = B53_DUPLEX_STAT_63XX, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK_63XX, + .jumbo_size_reg = B53_JUMBO_MAX_SIZE_63XX, + .sw_ops = &b53_switch_ops, + }, + { + .chip_id = BCM53010_DEVICE_ID, + .dev_name = "BCM53010", + .alias = "bcm53011", + .vlans = 4096, + .enabled_ports = 0x1f, + .cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */ + .vta_regs = B53_VTA_REGS, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + .sw_ops = &b53_switch_ops, + }, + { + .chip_id = BCM53011_DEVICE_ID, + .dev_name = "BCM53011", + .alias = "bcm53011", + .vlans = 4096, + .enabled_ports = 0x1bf, + .cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */ + .vta_regs = B53_VTA_REGS, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + .sw_ops = &b53_switch_ops, + }, + { + .chip_id = BCM53012_DEVICE_ID, + .dev_name = "BCM53012", + .alias = "bcm53011", + .vlans = 4096, + .enabled_ports = 0x1bf, + .cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */ + .vta_regs = B53_VTA_REGS, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + .sw_ops = &b53_switch_ops, + }, + { + .chip_id = BCM53018_DEVICE_ID, + .dev_name = "BCM53018", + .alias = "bcm53018", + .vlans = 4096, + .enabled_ports = 0x1f, + .cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */ + .vta_regs = B53_VTA_REGS, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + .sw_ops = &b53_switch_ops, + }, + { + .chip_id = BCM53019_DEVICE_ID, + .dev_name = "BCM53019", + .alias = "bcm53019", + .vlans = 4096, + .enabled_ports = 0x1f, + .cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */ + .vta_regs = B53_VTA_REGS, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + .sw_ops = &b53_switch_ops, + }, +}; + +static int b53_switch_init(struct b53_device *dev) +{ + struct switch_dev *sw_dev = &dev->sw_dev; + unsigned i; + int ret; + + for (i = 0; i < ARRAY_SIZE(b53_switch_chips); i++) { + const struct b53_chip_data *chip = &b53_switch_chips[i]; + + if (chip->chip_id == dev->chip_id) { + sw_dev->name = chip->dev_name; + if (!sw_dev->alias) + sw_dev->alias = chip->alias; + if (!dev->enabled_ports) + dev->enabled_ports = chip->enabled_ports; + dev->duplex_reg = chip->duplex_reg; + dev->vta_regs[0] = chip->vta_regs[0]; + dev->vta_regs[1] = chip->vta_regs[1]; + dev->vta_regs[2] = chip->vta_regs[2]; + dev->jumbo_pm_reg = chip->jumbo_pm_reg; + sw_dev->ops = chip->sw_ops; + sw_dev->cpu_port = chip->cpu_port; + sw_dev->vlans = chip->vlans; + break; + } + } + + if (!sw_dev->name) + return -EINVAL; + + /* check which BCM5325x version we have */ + if (is5325(dev)) { + u8 vc4; + + b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4_25, &vc4); + + /* check reserved bits */ + switch (vc4 & 3) { + case 1: + /* BCM5325E */ + break; + case 3: + /* BCM5325F - do not use port 4 */ + dev->enabled_ports &= ~BIT(4); + break; + default: +/* On the BCM47XX SoCs this is the supported internal switch.*/ +#ifndef CONFIG_BCM47XX + /* BCM5325M */ + return -EINVAL; +#else + break; +#endif + } + } else if (dev->chip_id == BCM53115_DEVICE_ID) { + u64 strap_value; + + b53_read48(dev, B53_STAT_PAGE, B53_STRAP_VALUE, &strap_value); + /* use second IMP port if GMII is enabled */ + if (strap_value & SV_GMII_CTRL_115) + sw_dev->cpu_port = 5; + } + + /* cpu port is always last */ + sw_dev->ports = sw_dev->cpu_port + 1; + dev->enabled_ports |= BIT(sw_dev->cpu_port); + + dev->ports = devm_kzalloc(dev->dev, + sizeof(struct b53_port) * sw_dev->ports, + GFP_KERNEL); + if (!dev->ports) + return -ENOMEM; + + dev->vlans = devm_kzalloc(dev->dev, + sizeof(struct b53_vlan) * sw_dev->vlans, + GFP_KERNEL); + if (!dev->vlans) + return -ENOMEM; + + dev->buf = devm_kzalloc(dev->dev, B53_BUF_SIZE, GFP_KERNEL); + if (!dev->buf) + return -ENOMEM; + + dev->reset_gpio = b53_switch_get_reset_gpio(dev); + if (dev->reset_gpio >= 0) { + ret = devm_gpio_request_one(dev->dev, dev->reset_gpio, + GPIOF_OUT_INIT_HIGH, "robo_reset"); + if (ret) + return ret; + } + + return b53_switch_reset(dev); +} + +struct b53_device *b53_switch_alloc(struct device *base, struct b53_io_ops *ops, + void *priv) +{ + struct b53_device *dev; + + dev = devm_kzalloc(base, sizeof(*dev), GFP_KERNEL); + if (!dev) + return NULL; + + dev->dev = base; + dev->ops = ops; + dev->priv = priv; + mutex_init(&dev->reg_mutex); + + return dev; +} +EXPORT_SYMBOL(b53_switch_alloc); + +int b53_switch_detect(struct b53_device *dev) +{ + u32 id32; + u16 tmp; + u8 id8; + int ret; + + ret = b53_read8(dev, B53_MGMT_PAGE, B53_DEVICE_ID, &id8); + if (ret) + return ret; + + switch (id8) { + case 0: + /* + * BCM5325 and BCM5365 do not have this register so reads + * return 0. But the read operation did succeed, so assume + * this is one of them. + * + * Next check if we can write to the 5325's VTA register; for + * 5365 it is read only. + */ + + b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_TABLE_ACCESS_25, 0xf); + b53_read16(dev, B53_VLAN_PAGE, B53_VLAN_TABLE_ACCESS_25, &tmp); + + if (tmp == 0xf) + dev->chip_id = BCM5325_DEVICE_ID; + else + dev->chip_id = BCM5365_DEVICE_ID; + break; + case BCM5395_DEVICE_ID: + case BCM5397_DEVICE_ID: + case BCM5398_DEVICE_ID: + dev->chip_id = id8; + break; + default: + ret = b53_read32(dev, B53_MGMT_PAGE, B53_DEVICE_ID, &id32); + if (ret) + return ret; + + switch (id32) { + case BCM53115_DEVICE_ID: + case BCM53125_DEVICE_ID: + case BCM53128_DEVICE_ID: + case BCM53010_DEVICE_ID: + case BCM53011_DEVICE_ID: + case BCM53012_DEVICE_ID: + case BCM53018_DEVICE_ID: + case BCM53019_DEVICE_ID: + dev->chip_id = id32; + break; + default: + pr_err("unsupported switch detected (BCM53%02x/BCM%x)\n", + id8, id32); + return -ENODEV; + } + } + + if (dev->chip_id == BCM5325_DEVICE_ID) + return b53_read8(dev, B53_STAT_PAGE, B53_REV_ID_25, + &dev->core_rev); + else + return b53_read8(dev, B53_MGMT_PAGE, B53_REV_ID, + &dev->core_rev); +} +EXPORT_SYMBOL(b53_switch_detect); + +int b53_switch_register(struct b53_device *dev) +{ + int ret; + + if (dev->pdata) { + dev->chip_id = dev->pdata->chip_id; + dev->enabled_ports = dev->pdata->enabled_ports; + dev->sw_dev.alias = dev->pdata->alias; + } + + if (!dev->chip_id && b53_switch_detect(dev)) + return -EINVAL; + + ret = b53_switch_init(dev); + if (ret) + return ret; + + pr_info("found switch: %s, rev %i\n", dev->sw_dev.name, dev->core_rev); + + return register_switch(&dev->sw_dev, NULL); +} +EXPORT_SYMBOL(b53_switch_register); + +MODULE_AUTHOR("Jonas Gorski "); +MODULE_DESCRIPTION("B53 switch library"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/target/linux/generic/files/drivers/net/phy/b53/b53_mdio.c b/target/linux/generic/files/drivers/net/phy/b53/b53_mdio.c new file mode 100644 index 0000000..3c25f0e --- /dev/null +++ b/target/linux/generic/files/drivers/net/phy/b53/b53_mdio.c @@ -0,0 +1,425 @@ +/* + * B53 register access through MII registers + * + * Copyright (C) 2011-2013 Jonas Gorski + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include + +#include "b53_priv.h" + +#define B53_PSEUDO_PHY 0x1e /* Register Access Pseudo PHY */ + +/* MII registers */ +#define REG_MII_PAGE 0x10 /* MII Page register */ +#define REG_MII_ADDR 0x11 /* MII Address register */ +#define REG_MII_DATA0 0x18 /* MII Data register 0 */ +#define REG_MII_DATA1 0x19 /* MII Data register 1 */ +#define REG_MII_DATA2 0x1a /* MII Data register 2 */ +#define REG_MII_DATA3 0x1b /* MII Data register 3 */ + +#define REG_MII_PAGE_ENABLE BIT(0) +#define REG_MII_ADDR_WRITE BIT(0) +#define REG_MII_ADDR_READ BIT(1) + +static int b53_mdio_op(struct b53_device *dev, u8 page, u8 reg, u16 op) +{ + int i; + u16 v; + int ret; + struct mii_bus *bus = dev->priv; + + if (dev->current_page != page) { + /* set page number */ + v = (page << 8) | REG_MII_PAGE_ENABLE; + ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_PAGE, v); + if (ret) + return ret; + dev->current_page = page; + } + + /* set register address */ + v = (reg << 8) | op; + ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_ADDR, v); + if (ret) + return ret; + + /* check if operation completed */ + for (i = 0; i < 5; ++i) { + v = mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_ADDR); + if (!(v & (REG_MII_ADDR_WRITE | REG_MII_ADDR_READ))) + break; + usleep_range(10, 100); + } + + if (WARN_ON(i == 5)) + return -EIO; + + return 0; +} + +static int b53_mdio_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val) +{ + struct mii_bus *bus = dev->priv; + int ret; + + ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ); + if (ret) + return ret; + + *val = mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_DATA0) & 0xff; + + return 0; +} + +static int b53_mdio_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val) +{ + struct mii_bus *bus = dev->priv; + int ret; + + ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ); + if (ret) + return ret; + + *val = mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_DATA0); + + return 0; +} + +static int b53_mdio_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val) +{ + struct mii_bus *bus = dev->priv; + int ret; + + ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ); + if (ret) + return ret; + + *val = mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_DATA0); + *val |= mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_DATA1) << 16; + + return 0; +} + +static int b53_mdio_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val) +{ + struct mii_bus *bus = dev->priv; + u64 temp = 0; + int i; + int ret; + + ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ); + if (ret) + return ret; + + for (i = 2; i >= 0; i--) { + temp <<= 16; + temp |= mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_DATA0 + i); + } + + *val = temp; + + return 0; +} + +static int b53_mdio_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val) +{ + struct mii_bus *bus = dev->priv; + u64 temp = 0; + int i; + int ret; + + ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ); + if (ret) + return ret; + + for (i = 3; i >= 0; i--) { + temp <<= 16; + temp |= mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_DATA0 + i); + } + + *val = temp; + + return 0; +} + +static int b53_mdio_write8(struct b53_device *dev, u8 page, u8 reg, u8 value) +{ + struct mii_bus *bus = dev->priv; + int ret; + + ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_DATA0, value); + if (ret) + return ret; + + return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE); +} + +static int b53_mdio_write16(struct b53_device *dev, u8 page, u8 reg, + u16 value) +{ + struct mii_bus *bus = dev->priv; + int ret; + + ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_DATA0, value); + if (ret) + return ret; + + return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE); +} + +static int b53_mdio_write32(struct b53_device *dev, u8 page, u8 reg, + u32 value) +{ + struct mii_bus *bus = dev->priv; + unsigned int i; + u32 temp = value; + + for (i = 0; i < 2; i++) { + int ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_DATA0 + i, + temp & 0xffff); + if (ret) + return ret; + temp >>= 16; + } + + return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE); + +} + +static int b53_mdio_write48(struct b53_device *dev, u8 page, u8 reg, + u64 value) +{ + struct mii_bus *bus = dev->priv; + unsigned i; + u64 temp = value; + + for (i = 0; i < 3; i++) { + int ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_DATA0 + i, + temp & 0xffff); + if (ret) + return ret; + temp >>= 16; + } + + return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE); + +} + +static int b53_mdio_write64(struct b53_device *dev, u8 page, u8 reg, + u64 value) +{ + struct mii_bus *bus = dev->priv; + unsigned i; + u64 temp = value; + + for (i = 0; i < 4; i++) { + int ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_DATA0 + i, + temp & 0xffff); + if (ret) + return ret; + temp >>= 16; + } + + return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE); +} + +static struct b53_io_ops b53_mdio_ops = { + .read8 = b53_mdio_read8, + .read16 = b53_mdio_read16, + .read32 = b53_mdio_read32, + .read48 = b53_mdio_read48, + .read64 = b53_mdio_read64, + .write8 = b53_mdio_write8, + .write16 = b53_mdio_write16, + .write32 = b53_mdio_write32, + .write48 = b53_mdio_write48, + .write64 = b53_mdio_write64, +}; + +static int b53_phy_probe(struct phy_device *phydev) +{ + struct b53_device dev; + int ret; + + /* allow the generic phy driver to take over */ + if (phydev->addr != B53_PSEUDO_PHY && phydev->addr != 0) + return -ENODEV; + + dev.current_page = 0xff; + dev.priv = phydev->bus; + dev.ops = &b53_mdio_ops; + dev.pdata = NULL; + mutex_init(&dev.reg_mutex); + + ret = b53_switch_detect(&dev); + if (ret) + return ret; + + if (is5325(&dev) || is5365(&dev)) + phydev->supported = SUPPORTED_100baseT_Full; + else + phydev->supported = SUPPORTED_1000baseT_Full; + + phydev->advertising = phydev->supported; + + return 0; +} + +static int b53_phy_config_init(struct phy_device *phydev) +{ + struct b53_device *dev; + int ret; + + dev = b53_switch_alloc(&phydev->dev, &b53_mdio_ops, phydev->bus); + if (!dev) + return -ENOMEM; + + /* we don't use page 0xff, so force a page set */ + dev->current_page = 0xff; + /* force the ethX as alias */ + dev->sw_dev.alias = phydev->attached_dev->name; + + ret = b53_switch_register(dev); + if (ret) { + dev_err(dev->dev, "failed to register switch: %i\n", ret); + return ret; + } + + phydev->priv = dev; + + return 0; +} + +static void b53_phy_remove(struct phy_device *phydev) +{ + struct b53_device *priv = phydev->priv; + + if (!priv) + return; + + b53_switch_remove(priv); + + phydev->priv = NULL; +} + +static int b53_phy_config_aneg(struct phy_device *phydev) +{ + return 0; +} + +static int b53_phy_read_status(struct phy_device *phydev) +{ + struct b53_device *priv = phydev->priv; + + if (is5325(priv) || is5365(priv)) + phydev->speed = 100; + else + phydev->speed = 1000; + + phydev->duplex = DUPLEX_FULL; + phydev->link = 1; + phydev->state = PHY_RUNNING; + + netif_carrier_on(phydev->attached_dev); + phydev->adjust_link(phydev->attached_dev); + + return 0; +} + +/* BCM5325, BCM539x */ +static struct phy_driver b53_phy_driver_id1 = { + .phy_id = 0x0143bc00, + .name = "Broadcom B53 (1)", + .phy_id_mask = 0x1ffffc00, + .features = 0, + .probe = b53_phy_probe, + .remove = b53_phy_remove, + .config_aneg = b53_phy_config_aneg, + .config_init = b53_phy_config_init, + .read_status = b53_phy_read_status, + .driver = { + .owner = THIS_MODULE, + }, +}; + +/* BCM53125, BCM53128 */ +static struct phy_driver b53_phy_driver_id2 = { + .phy_id = 0x03625c00, + .name = "Broadcom B53 (2)", + .phy_id_mask = 0x1ffffc00, + .features = 0, + .probe = b53_phy_probe, + .remove = b53_phy_remove, + .config_aneg = b53_phy_config_aneg, + .config_init = b53_phy_config_init, + .read_status = b53_phy_read_status, + .driver = { + .owner = THIS_MODULE, + }, +}; + +/* BCM5365 */ +static struct phy_driver b53_phy_driver_id3 = { + .phy_id = 0x00406000, + .name = "Broadcom B53 (3)", + .phy_id_mask = 0x1ffffc00, + .features = 0, + .probe = b53_phy_probe, + .remove = b53_phy_remove, + .config_aneg = b53_phy_config_aneg, + .config_init = b53_phy_config_init, + .read_status = b53_phy_read_status, + .driver = { + .owner = THIS_MODULE, + }, +}; + +int __init b53_phy_driver_register(void) +{ + int ret; + + ret = phy_driver_register(&b53_phy_driver_id1); + if (ret) + return ret; + + ret = phy_driver_register(&b53_phy_driver_id2); + if (ret) + goto err1; + + ret = phy_driver_register(&b53_phy_driver_id3); + if (!ret) + return 0; + + phy_driver_unregister(&b53_phy_driver_id2); +err1: + phy_driver_unregister(&b53_phy_driver_id1); + return ret; +} + +void __exit b53_phy_driver_unregister(void) +{ + phy_driver_unregister(&b53_phy_driver_id3); + phy_driver_unregister(&b53_phy_driver_id2); + phy_driver_unregister(&b53_phy_driver_id1); +} + +module_init(b53_phy_driver_register); +module_exit(b53_phy_driver_unregister); + +MODULE_DESCRIPTION("B53 MDIO access driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/target/linux/generic/files/drivers/net/phy/b53/b53_mmap.c b/target/linux/generic/files/drivers/net/phy/b53/b53_mmap.c new file mode 100644 index 0000000..ab1895e --- /dev/null +++ b/target/linux/generic/files/drivers/net/phy/b53/b53_mmap.c @@ -0,0 +1,241 @@ +/* + * B53 register access through memory mapped registers + * + * Copyright (C) 2012-2013 Jonas Gorski + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include + +#include "b53_priv.h" + +static int b53_mmap_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val) +{ + u8 __iomem *regs = dev->priv; + + *val = readb(regs + (page << 8) + reg); + + return 0; +} + +static int b53_mmap_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val) +{ + u8 __iomem *regs = dev->priv; + + if (WARN_ON(reg % 2)) + return -EINVAL; + + if (dev->pdata && dev->pdata->big_endian) + *val = readw_be(regs + (page << 8) + reg); + else + *val = readw(regs + (page << 8) + reg); + + return 0; +} + +static int b53_mmap_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val) +{ + u8 __iomem *regs = dev->priv; + + if (WARN_ON(reg % 4)) + return -EINVAL; + + if (dev->pdata && dev->pdata->big_endian) + *val = readl_be(regs + (page << 8) + reg); + else + *val = readl(regs + (page << 8) + reg); + + return 0; +} + +static int b53_mmap_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val) +{ + if (WARN_ON(reg % 2)) + return -EINVAL; + + if (reg % 4) { + u16 lo; + u32 hi; + + b53_mmap_read16(dev, page, reg, &lo); + b53_mmap_read32(dev, page, reg + 2, &hi); + + *val = ((u64)hi << 16) | lo; + } else { + u32 lo; + u16 hi; + + b53_mmap_read32(dev, page, reg, &lo); + b53_mmap_read16(dev, page, reg + 4, &hi); + + *val = ((u64)hi << 32) | lo; + } + + return 0; +} + +static int b53_mmap_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val) +{ + u32 hi, lo; + + if (WARN_ON(reg % 4)) + return -EINVAL; + + b53_mmap_read32(dev, page, reg, &lo); + b53_mmap_read32(dev, page, reg + 4, &hi); + + *val = ((u64)hi << 32) | lo; + + return 0; +} + +static int b53_mmap_write8(struct b53_device *dev, u8 page, u8 reg, u8 value) +{ + u8 __iomem *regs = dev->priv; + + writeb(value, regs + (page << 8) + reg); + + return 0; +} + +static int b53_mmap_write16(struct b53_device *dev, u8 page, u8 reg, + u16 value) +{ + u8 __iomem *regs = dev->priv; + + if (WARN_ON(reg % 2)) + return -EINVAL; + + if (dev->pdata && dev->pdata->big_endian) + writew_be(value, regs + (page << 8) + reg); + else + writew(value, regs + (page << 8) + reg); + + return 0; +} + +static int b53_mmap_write32(struct b53_device *dev, u8 page, u8 reg, + u32 value) +{ + u8 __iomem *regs = dev->priv; + + if (WARN_ON(reg % 4)) + return -EINVAL; + + if (dev->pdata && dev->pdata->big_endian) + writel_be(value, regs + (page << 8) + reg); + else + writel(value, regs + (page << 8) + reg); + + return 0; +} + +static int b53_mmap_write48(struct b53_device *dev, u8 page, u8 reg, + u64 value) +{ + if (WARN_ON(reg % 2)) + return -EINVAL; + + if (reg % 4) { + u32 hi = (u32)(value >> 16); + u16 lo = (u16)value; + + b53_mmap_write16(dev, page, reg, lo); + b53_mmap_write32(dev, page, reg + 2, hi); + } else { + u16 hi = (u16)(value >> 32); + u32 lo = (u32)value; + + b53_mmap_write32(dev, page, reg, lo); + b53_mmap_write16(dev, page, reg + 4, hi); + } + + return 0; +} + +static int b53_mmap_write64(struct b53_device *dev, u8 page, u8 reg, + u64 value) +{ + u32 hi, lo; + + hi = (u32)(value >> 32); + lo = (u32)value; + + if (WARN_ON(reg % 4)) + return -EINVAL; + + b53_mmap_write32(dev, page, reg, lo); + b53_mmap_write32(dev, page, reg + 4, hi); + + return 0; +} + +static struct b53_io_ops b53_mmap_ops = { + .read8 = b53_mmap_read8, + .read16 = b53_mmap_read16, + .read32 = b53_mmap_read32, + .read48 = b53_mmap_read48, + .read64 = b53_mmap_read64, + .write8 = b53_mmap_write8, + .write16 = b53_mmap_write16, + .write32 = b53_mmap_write32, + .write48 = b53_mmap_write48, + .write64 = b53_mmap_write64, +}; + +static int b53_mmap_probe(struct platform_device *pdev) +{ + struct b53_platform_data *pdata = pdev->dev.platform_data; + struct b53_device *dev; + + if (!pdata) + return -EINVAL; + + dev = b53_switch_alloc(&pdev->dev, &b53_mmap_ops, pdata->regs); + if (!dev) + return -ENOMEM; + + if (pdata) + dev->pdata = pdata; + + platform_set_drvdata(pdev, dev); + + return b53_switch_register(dev); +} + +static int b53_mmap_remove(struct platform_device *pdev) +{ + struct b53_device *dev = platform_get_drvdata(pdev); + + if (dev) + b53_switch_remove(dev); + + return 0; +} + +static struct platform_driver b53_mmap_driver = { + .probe = b53_mmap_probe, + .remove = b53_mmap_remove, + .driver = { + .name = "b53-switch", + }, +}; + +module_platform_driver(b53_mmap_driver); +MODULE_AUTHOR("Jonas Gorski "); +MODULE_DESCRIPTION("B53 MMAP access driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/target/linux/generic/files/drivers/net/phy/b53/b53_phy_fixup.c b/target/linux/generic/files/drivers/net/phy/b53/b53_phy_fixup.c new file mode 100644 index 0000000..72d1373 --- /dev/null +++ b/target/linux/generic/files/drivers/net/phy/b53/b53_phy_fixup.c @@ -0,0 +1,55 @@ +/* + * B53 PHY Fixup call + * + * Copyright (C) 2013 Jonas Gorski + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include + +#define B53_PSEUDO_PHY 0x1e /* Register Access Pseudo PHY */ + +#define B53_BRCM_OUI_1 0x0143bc00 +#define B53_BRCM_OUI_2 0x03625c00 +#define B53_BRCM_OUI_3 0x00406000 + +static int b53_phy_fixup(struct phy_device *dev) +{ + u32 phy_id; + struct mii_bus *bus = dev->bus; + + if (dev->addr != B53_PSEUDO_PHY) + return 0; + + /* read the first port's id */ + phy_id = mdiobus_read(bus, 0, 2) << 16; + phy_id |= mdiobus_read(bus, 0, 3); + + if ((phy_id & 0xfffffc00) == B53_BRCM_OUI_1 || + (phy_id & 0xfffffc00) == B53_BRCM_OUI_2 || + (phy_id & 0xfffffc00) == B53_BRCM_OUI_3) { + dev->phy_id = phy_id; + } + + return 0; +} + +int __init b53_phy_fixup_register(void) +{ + return phy_register_fixup_for_id(PHY_ANY_ID, b53_phy_fixup); +} + +subsys_initcall(b53_phy_fixup_register); diff --git a/target/linux/generic/files/drivers/net/phy/b53/b53_priv.h b/target/linux/generic/files/drivers/net/phy/b53/b53_priv.h new file mode 100644 index 0000000..0c4c394 --- /dev/null +++ b/target/linux/generic/files/drivers/net/phy/b53/b53_priv.h @@ -0,0 +1,329 @@ +/* + * B53 common definitions + * + * Copyright (C) 2011-2013 Jonas Gorski + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __B53_PRIV_H +#define __B53_PRIV_H + +#include +#include +#include + +struct b53_device; + +struct b53_io_ops { + int (*read8)(struct b53_device *dev, u8 page, u8 reg, u8 *value); + int (*read16)(struct b53_device *dev, u8 page, u8 reg, u16 *value); + int (*read32)(struct b53_device *dev, u8 page, u8 reg, u32 *value); + int (*read48)(struct b53_device *dev, u8 page, u8 reg, u64 *value); + int (*read64)(struct b53_device *dev, u8 page, u8 reg, u64 *value); + int (*write8)(struct b53_device *dev, u8 page, u8 reg, u8 value); + int (*write16)(struct b53_device *dev, u8 page, u8 reg, u16 value); + int (*write32)(struct b53_device *dev, u8 page, u8 reg, u32 value); + int (*write48)(struct b53_device *dev, u8 page, u8 reg, u64 value); + int (*write64)(struct b53_device *dev, u8 page, u8 reg, u64 value); +}; + +enum { + BCM5325_DEVICE_ID = 0x25, + BCM5365_DEVICE_ID = 0x65, + BCM5395_DEVICE_ID = 0x95, + BCM5397_DEVICE_ID = 0x97, + BCM5398_DEVICE_ID = 0x98, + BCM53115_DEVICE_ID = 0x53115, + BCM53125_DEVICE_ID = 0x53125, + BCM53128_DEVICE_ID = 0x53128, + BCM63XX_DEVICE_ID = 0x6300, + BCM53010_DEVICE_ID = 0x53010, + BCM53011_DEVICE_ID = 0x53011, + BCM53012_DEVICE_ID = 0x53012, + BCM53018_DEVICE_ID = 0x53018, + BCM53019_DEVICE_ID = 0x53019, +}; + +#define B53_N_PORTS 9 +#define B53_N_PORTS_25 6 + +struct b53_vlan { + unsigned int members:B53_N_PORTS; + unsigned int untag:B53_N_PORTS; +}; + +struct b53_port { + unsigned int pvid:12; +}; + +struct b53_device { + struct switch_dev sw_dev; + struct b53_platform_data *pdata; + + struct mutex reg_mutex; + const struct b53_io_ops *ops; + + /* chip specific data */ + u32 chip_id; + u8 core_rev; + u8 vta_regs[3]; + u8 duplex_reg; + u8 jumbo_pm_reg; + u8 jumbo_size_reg; + int reset_gpio; + + /* used ports mask */ + u16 enabled_ports; + + /* connect specific data */ + u8 current_page; + struct device *dev; + void *priv; + + /* run time configuration */ + unsigned enable_vlan:1; + unsigned enable_jumbo:1; + unsigned allow_vid_4095:1; + + struct b53_port *ports; + struct b53_vlan *vlans; + + char *buf; +}; + +#define b53_for_each_port(dev, i) \ + for (i = 0; i < B53_N_PORTS; i++) \ + if (dev->enabled_ports & BIT(i)) + + + +static inline int is5325(struct b53_device *dev) +{ + return dev->chip_id == BCM5325_DEVICE_ID; +} + +static inline int is5365(struct b53_device *dev) +{ +#ifdef CONFIG_BCM47XX + return dev->chip_id == BCM5365_DEVICE_ID; +#else + return 0; +#endif +} + +static inline int is5397_98(struct b53_device *dev) +{ + return dev->chip_id == BCM5397_DEVICE_ID || + dev->chip_id == BCM5398_DEVICE_ID; +} + +static inline int is539x(struct b53_device *dev) +{ + return dev->chip_id == BCM5395_DEVICE_ID || + dev->chip_id == BCM5397_DEVICE_ID || + dev->chip_id == BCM5398_DEVICE_ID; +} + +static inline int is531x5(struct b53_device *dev) +{ + return dev->chip_id == BCM53115_DEVICE_ID || + dev->chip_id == BCM53125_DEVICE_ID || + dev->chip_id == BCM53128_DEVICE_ID; +} + +static inline int is63xx(struct b53_device *dev) +{ +#ifdef CONFIG_BCM63XX + return dev->chip_id == BCM63XX_DEVICE_ID; +#else + return 0; +#endif +} + +static inline int is5301x(struct b53_device *dev) +{ + return dev->chip_id == BCM53010_DEVICE_ID || + dev->chip_id == BCM53011_DEVICE_ID || + dev->chip_id == BCM53012_DEVICE_ID || + dev->chip_id == BCM53018_DEVICE_ID || + dev->chip_id == BCM53019_DEVICE_ID; +} + +#define B53_CPU_PORT_25 5 +#define B53_CPU_PORT 8 + +static inline int is_cpu_port(struct b53_device *dev, int port) +{ + return dev->sw_dev.cpu_port == port; +} + +static inline struct b53_device *sw_to_b53(struct switch_dev *sw) +{ + return container_of(sw, struct b53_device, sw_dev); +} + +struct b53_device *b53_switch_alloc(struct device *base, struct b53_io_ops *ops, + void *priv); + +int b53_switch_detect(struct b53_device *dev); + +int b53_switch_register(struct b53_device *dev); + +static inline void b53_switch_remove(struct b53_device *dev) +{ + unregister_switch(&dev->sw_dev); +} + +static inline int b53_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val) +{ + int ret; + + mutex_lock(&dev->reg_mutex); + ret = dev->ops->read8(dev, page, reg, val); + mutex_unlock(&dev->reg_mutex); + + return ret; +} + +static inline int b53_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val) +{ + int ret; + + mutex_lock(&dev->reg_mutex); + ret = dev->ops->read16(dev, page, reg, val); + mutex_unlock(&dev->reg_mutex); + + return ret; +} + +static inline int b53_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val) +{ + int ret; + + mutex_lock(&dev->reg_mutex); + ret = dev->ops->read32(dev, page, reg, val); + mutex_unlock(&dev->reg_mutex); + + return ret; +} + +static inline int b53_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val) +{ + int ret; + + mutex_lock(&dev->reg_mutex); + ret = dev->ops->read48(dev, page, reg, val); + mutex_unlock(&dev->reg_mutex); + + return ret; +} + +static inline int b53_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val) +{ + int ret; + + mutex_lock(&dev->reg_mutex); + ret = dev->ops->read64(dev, page, reg, val); + mutex_unlock(&dev->reg_mutex); + + return ret; +} + +static inline int b53_write8(struct b53_device *dev, u8 page, u8 reg, u8 value) +{ + int ret; + + mutex_lock(&dev->reg_mutex); + ret = dev->ops->write8(dev, page, reg, value); + mutex_unlock(&dev->reg_mutex); + + return ret; +} + +static inline int b53_write16(struct b53_device *dev, u8 page, u8 reg, + u16 value) +{ + int ret; + + mutex_lock(&dev->reg_mutex); + ret = dev->ops->write16(dev, page, reg, value); + mutex_unlock(&dev->reg_mutex); + + return ret; +} + +static inline int b53_write32(struct b53_device *dev, u8 page, u8 reg, + u32 value) +{ + int ret; + + mutex_lock(&dev->reg_mutex); + ret = dev->ops->write32(dev, page, reg, value); + mutex_unlock(&dev->reg_mutex); + + return ret; +} + +static inline int b53_write48(struct b53_device *dev, u8 page, u8 reg, + u64 value) +{ + int ret; + + mutex_lock(&dev->reg_mutex); + ret = dev->ops->write48(dev, page, reg, value); + mutex_unlock(&dev->reg_mutex); + + return ret; +} + +static inline int b53_write64(struct b53_device *dev, u8 page, u8 reg, + u64 value) +{ + int ret; + + mutex_lock(&dev->reg_mutex); + ret = dev->ops->write64(dev, page, reg, value); + mutex_unlock(&dev->reg_mutex); + + return ret; +} + +#ifdef CONFIG_BCM47XX + +#include +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) +#include +#else +#include +#endif +#include +static inline int b53_switch_get_reset_gpio(struct b53_device *dev) +{ + enum bcm47xx_board board = bcm47xx_board_get(); + + switch (board) { + case BCM47XX_BOARD_LINKSYS_WRT300NV11: + case BCM47XX_BOARD_LINKSYS_WRT310NV1: + return 8; + default: + return bcm47xx_nvram_gpio_pin("robo_reset"); + } +} +#else +static inline int b53_switch_get_reset_gpio(struct b53_device *dev) +{ + return -ENOENT; +} +#endif +#endif diff --git a/target/linux/generic/files/drivers/net/phy/b53/b53_regs.h b/target/linux/generic/files/drivers/net/phy/b53/b53_regs.h new file mode 100644 index 0000000..144e1c8 --- /dev/null +++ b/target/linux/generic/files/drivers/net/phy/b53/b53_regs.h @@ -0,0 +1,347 @@ +/* + * B53 register definitions + * + * Copyright (C) 2004 Broadcom Corporation + * Copyright (C) 2011-2013 Jonas Gorski + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __B53_REGS_H +#define __B53_REGS_H + +/* Management Port (SMP) Page offsets */ +#define B53_CTRL_PAGE 0x00 /* Control */ +#define B53_STAT_PAGE 0x01 /* Status */ +#define B53_MGMT_PAGE 0x02 /* Management Mode */ +#define B53_MIB_AC_PAGE 0x03 /* MIB Autocast */ +#define B53_ARLCTRL_PAGE 0x04 /* ARL Control */ +#define B53_ARLIO_PAGE 0x05 /* ARL Access */ +#define B53_FRAMEBUF_PAGE 0x06 /* Management frame access */ +#define B53_MEM_ACCESS_PAGE 0x08 /* Memory access */ + +/* PHY Registers */ +#define B53_PORT_MII_PAGE(i) (0x10 + (i)) /* Port i MII Registers */ +#define B53_IM_PORT_PAGE 0x18 /* Inverse MII Port (to EMAC) */ +#define B53_ALL_PORT_PAGE 0x19 /* All ports MII (broadcast) */ + +/* MIB registers */ +#define B53_MIB_PAGE(i) (0x20 + (i)) + +/* Quality of Service (QoS) Registers */ +#define B53_QOS_PAGE 0x30 + +/* Port VLAN Page */ +#define B53_PVLAN_PAGE 0x31 + +/* VLAN Registers */ +#define B53_VLAN_PAGE 0x34 + +/* Jumbo Frame Registers */ +#define B53_JUMBO_PAGE 0x40 + +/* CFP Configuration Registers Page */ +#define B53_CFP_PAGE 0xa1 + +/************************************************************************* + * Control Page registers + *************************************************************************/ + +/* Port Control Register (8 bit) */ +#define B53_PORT_CTRL(i) (0x00 + (i)) +#define PORT_CTRL_RX_DISABLE BIT(0) +#define PORT_CTRL_TX_DISABLE BIT(1) +#define PORT_CTRL_RX_BCST_EN BIT(2) /* Broadcast RX (P8 only) */ +#define PORT_CTRL_RX_MCST_EN BIT(3) /* Multicast RX (P8 only) */ +#define PORT_CTRL_RX_UCST_EN BIT(4) /* Unicast RX (P8 only) */ +#define PORT_CTRL_STP_STATE_S 5 +#define PORT_CTRL_STP_STATE_MASK (0x7 << PORT_CTRL_STP_STATE_S) + +/* SMP Control Register (8 bit) */ +#define B53_SMP_CTRL 0x0a + +/* Switch Mode Control Register (8 bit) */ +#define B53_SWITCH_MODE 0x0b +#define SM_SW_FWD_MODE BIT(0) /* 1 = Managed Mode */ +#define SM_SW_FWD_EN BIT(1) /* Forwarding Enable */ + +/* IMP Port state override register (8 bit) */ +#define B53_PORT_OVERRIDE_CTRL 0x0e +#define PORT_OVERRIDE_LINK BIT(0) +#define PORT_OVERRIDE_FULL_DUPLEX BIT(1) /* 0 = Half Duplex */ +#define PORT_OVERRIDE_SPEED_S 2 +#define PORT_OVERRIDE_SPEED_10M (0 << PORT_OVERRIDE_SPEED_S) +#define PORT_OVERRIDE_SPEED_100M (1 << PORT_OVERRIDE_SPEED_S) +#define PORT_OVERRIDE_SPEED_1000M (2 << PORT_OVERRIDE_SPEED_S) +#define PORT_OVERRIDE_RV_MII_25 BIT(4) /* BCM5325 only */ +#define PORT_OVERRIDE_RX_FLOW BIT(4) +#define PORT_OVERRIDE_TX_FLOW BIT(5) +#define PORT_OVERRIDE_SPEED_2000M BIT(6) /* BCM5301X only, requires setting 1000M */ +#define PORT_OVERRIDE_EN BIT(7) /* Use the register contents */ + +/* Power-down mode control */ +#define B53_PD_MODE_CTRL_25 0x0f + +/* IP Multicast control (8 bit) */ +#define B53_IP_MULTICAST_CTRL 0x21 +#define B53_IPMC_FWD_EN BIT(1) +#define B53_UC_FWD_EN BIT(6) +#define B53_MC_FWD_EN BIT(7) + +/* (16 bit) */ +#define B53_UC_FLOOD_MASK 0x32 +#define B53_MC_FLOOD_MASK 0x34 +#define B53_IPMC_FLOOD_MASK 0x36 + +/* + * Override Ports 0-7 State on devices with xMII interfaces (8 bit) + * + * For port 8 still use B53_PORT_OVERRIDE_CTRL + * Please note that not all ports are available on every hardware, e.g. BCM5301X + * don't include overriding port 6, BCM63xx also have some limitations. + */ +#define B53_GMII_PORT_OVERRIDE_CTRL(i) (0x58 + (i)) +#define GMII_PO_LINK BIT(0) +#define GMII_PO_FULL_DUPLEX BIT(1) /* 0 = Half Duplex */ +#define GMII_PO_SPEED_S 2 +#define GMII_PO_SPEED_10M (0 << GMII_PO_SPEED_S) +#define GMII_PO_SPEED_100M (1 << GMII_PO_SPEED_S) +#define GMII_PO_SPEED_1000M (2 << GMII_PO_SPEED_S) +#define GMII_PO_RX_FLOW BIT(4) +#define GMII_PO_TX_FLOW BIT(5) +#define GMII_PO_EN BIT(6) /* Use the register contents */ +#define GMII_PO_SPEED_2000M BIT(7) /* BCM5301X only, requires setting 1000M */ + +/* Software reset register (8 bit) */ +#define B53_SOFTRESET 0x79 + +/* Fast Aging Control register (8 bit) */ +#define B53_FAST_AGE_CTRL 0x88 +#define FAST_AGE_STATIC BIT(0) +#define FAST_AGE_DYNAMIC BIT(1) +#define FAST_AGE_PORT BIT(2) +#define FAST_AGE_VLAN BIT(3) +#define FAST_AGE_STP BIT(4) +#define FAST_AGE_MC BIT(5) +#define FAST_AGE_DONE BIT(7) + +/************************************************************************* + * Status Page registers + *************************************************************************/ + +/* Link Status Summary Register (16bit) */ +#define B53_LINK_STAT 0x00 + +/* Link Status Change Register (16 bit) */ +#define B53_LINK_STAT_CHANGE 0x02 + +/* Port Speed Summary Register (16 bit for FE, 32 bit for GE) */ +#define B53_SPEED_STAT 0x04 +#define SPEED_PORT_FE(reg, port) (((reg) >> (port)) & 1) +#define SPEED_PORT_GE(reg, port) (((reg) >> 2 * (port)) & 3) +#define SPEED_STAT_10M 0 +#define SPEED_STAT_100M 1 +#define SPEED_STAT_1000M 2 + +/* Duplex Status Summary (16 bit) */ +#define B53_DUPLEX_STAT_FE 0x06 +#define B53_DUPLEX_STAT_GE 0x08 +#define B53_DUPLEX_STAT_63XX 0x0c + +/* Revision ID register for BCM5325 */ +#define B53_REV_ID_25 0x50 + +/* Strap Value (48 bit) */ +#define B53_STRAP_VALUE 0x70 +#define SV_GMII_CTRL_115 BIT(27) + +/************************************************************************* + * Management Mode Page Registers + *************************************************************************/ + +/* Global Management Config Register (8 bit) */ +#define B53_GLOBAL_CONFIG 0x00 +#define GC_RESET_MIB 0x01 +#define GC_RX_BPDU_EN 0x02 +#define GC_MIB_AC_HDR_EN 0x10 +#define GC_MIB_AC_EN 0x20 +#define GC_FRM_MGMT_PORT_M 0xC0 +#define GC_FRM_MGMT_PORT_04 0x00 +#define GC_FRM_MGMT_PORT_MII 0x80 + +/* Broadcom Header control register (8 bit) */ +#define B53_BRCM_HDR 0x03 +#define BRCM_HDR_EN BIT(0) /* Enable tagging on IMP port */ + +/* Device ID register (8 or 32 bit) */ +#define B53_DEVICE_ID 0x30 + +/* Revision ID register (8 bit) */ +#define B53_REV_ID 0x40 + +/************************************************************************* + * ARL Access Page Registers + *************************************************************************/ + +/* VLAN Table Access Register (8 bit) */ +#define B53_VT_ACCESS 0x80 +#define B53_VT_ACCESS_9798 0x60 /* for BCM5397/BCM5398 */ +#define B53_VT_ACCESS_63XX 0x60 /* for BCM6328/62/68 */ +#define VTA_CMD_WRITE 0 +#define VTA_CMD_READ 1 +#define VTA_CMD_CLEAR 2 +#define VTA_START_CMD BIT(7) + +/* VLAN Table Index Register (16 bit) */ +#define B53_VT_INDEX 0x81 +#define B53_VT_INDEX_9798 0x61 +#define B53_VT_INDEX_63XX 0x62 + +/* VLAN Table Entry Register (32 bit) */ +#define B53_VT_ENTRY 0x83 +#define B53_VT_ENTRY_9798 0x63 +#define B53_VT_ENTRY_63XX 0x64 +#define VTE_MEMBERS 0x1ff +#define VTE_UNTAG_S 9 +#define VTE_UNTAG (0x1ff << 9) + +/************************************************************************* + * Port VLAN Registers + *************************************************************************/ + +/* Port VLAN mask (16 bit) IMP port is always 8, also on 5325 & co */ +#define B53_PVLAN_PORT_MASK(i) ((i) * 2) + +/************************************************************************* + * 802.1Q Page Registers + *************************************************************************/ + +/* Global QoS Control (8 bit) */ +#define B53_QOS_GLOBAL_CTL 0x00 + +/* Enable 802.1Q for individual Ports (16 bit) */ +#define B53_802_1P_EN 0x04 + +/************************************************************************* + * VLAN Page Registers + *************************************************************************/ + +/* VLAN Control 0 (8 bit) */ +#define B53_VLAN_CTRL0 0x00 +#define VC0_8021PF_CTRL_MASK 0x3 +#define VC0_8021PF_CTRL_NONE 0x0 +#define VC0_8021PF_CTRL_CHANGE_PRI 0x1 +#define VC0_8021PF_CTRL_CHANGE_VID 0x2 +#define VC0_8021PF_CTRL_CHANGE_BOTH 0x3 +#define VC0_8021QF_CTRL_MASK 0xc +#define VC0_8021QF_CTRL_CHANGE_PRI 0x1 +#define VC0_8021QF_CTRL_CHANGE_VID 0x2 +#define VC0_8021QF_CTRL_CHANGE_BOTH 0x3 +#define VC0_RESERVED_1 BIT(1) +#define VC0_DROP_VID_MISS BIT(4) +#define VC0_VID_HASH_VID BIT(5) +#define VC0_VID_CHK_EN BIT(6) /* Use VID,DA or VID,SA */ +#define VC0_VLAN_EN BIT(7) /* 802.1Q VLAN Enabled */ + +/* VLAN Control 1 (8 bit) */ +#define B53_VLAN_CTRL1 0x01 +#define VC1_RX_MCST_TAG_EN BIT(1) +#define VC1_RX_MCST_FWD_EN BIT(2) +#define VC1_RX_MCST_UNTAG_EN BIT(3) + +/* VLAN Control 2 (8 bit) */ +#define B53_VLAN_CTRL2 0x02 + +/* VLAN Control 3 (8 bit when BCM5325, 16 bit else) */ +#define B53_VLAN_CTRL3 0x03 +#define B53_VLAN_CTRL3_63XX 0x04 +#define VC3_MAXSIZE_1532 BIT(6) /* 5325 only */ +#define VC3_HIGH_8BIT_EN BIT(7) /* 5325 only */ + +/* VLAN Control 4 (8 bit) */ +#define B53_VLAN_CTRL4 0x05 +#define B53_VLAN_CTRL4_25 0x04 +#define B53_VLAN_CTRL4_63XX 0x06 +#define VC4_ING_VID_CHECK_S 6 +#define VC4_ING_VID_CHECK_MASK (0x3 << VC4_ING_VID_CHECK_S) +#define VC4_ING_VID_VIO_FWD 0 /* forward, but do not learn */ +#define VC4_ING_VID_VIO_DROP 1 /* drop VID violations */ +#define VC4_NO_ING_VID_CHK 2 /* do not check */ +#define VC4_ING_VID_VIO_TO_IMP 3 /* redirect to MII port */ + +/* VLAN Control 5 (8 bit) */ +#define B53_VLAN_CTRL5 0x06 +#define B53_VLAN_CTRL5_25 0x05 +#define B53_VLAN_CTRL5_63XX 0x07 +#define VC5_VID_FFF_EN BIT(2) +#define VC5_DROP_VTABLE_MISS BIT(3) + +/* VLAN Control 6 (8 bit) */ +#define B53_VLAN_CTRL6 0x07 +#define B53_VLAN_CTRL6_63XX 0x08 + +/* VLAN Table Access Register (16 bit) */ +#define B53_VLAN_TABLE_ACCESS_25 0x06 /* BCM5325E/5350 */ +#define B53_VLAN_TABLE_ACCESS_65 0x08 /* BCM5365 */ +#define VTA_VID_LOW_MASK_25 0xf +#define VTA_VID_LOW_MASK_65 0xff +#define VTA_VID_HIGH_S_25 4 +#define VTA_VID_HIGH_S_65 8 +#define VTA_VID_HIGH_MASK_25 (0xff << VTA_VID_HIGH_S_25E) +#define VTA_VID_HIGH_MASK_65 (0xf << VTA_VID_HIGH_S_65) +#define VTA_RW_STATE BIT(12) +#define VTA_RW_STATE_RD 0 +#define VTA_RW_STATE_WR BIT(12) +#define VTA_RW_OP_EN BIT(13) + +/* VLAN Read/Write Registers for (16/32 bit) */ +#define B53_VLAN_WRITE_25 0x08 +#define B53_VLAN_WRITE_65 0x0a +#define B53_VLAN_READ 0x0c +#define VA_MEMBER_MASK 0x3f +#define VA_UNTAG_S_25 6 +#define VA_UNTAG_MASK_25 0x3f +#define VA_UNTAG_S_65 7 +#define VA_UNTAG_MASK_65 0x1f +#define VA_VID_HIGH_S 12 +#define VA_VID_HIGH_MASK (0xffff << VA_VID_HIGH_S) +#define VA_VALID_25 BIT(20) +#define VA_VALID_25_R4 BIT(24) +#define VA_VALID_65 BIT(14) + +/* VLAN Port Default Tag (16 bit) */ +#define B53_VLAN_PORT_DEF_TAG(i) (0x10 + 2 * (i)) + +/************************************************************************* + * Jumbo Frame Page Registers + *************************************************************************/ + +/* Jumbo Enable Port Mask (bit i == port i enabled) (32 bit) */ +#define B53_JUMBO_PORT_MASK 0x01 +#define B53_JUMBO_PORT_MASK_63XX 0x04 +#define JPM_10_100_JUMBO_EN BIT(24) /* GigE always enabled */ + +/* Good Frame Max Size without 802.1Q TAG (16 bit) */ +#define B53_JUMBO_MAX_SIZE 0x05 +#define B53_JUMBO_MAX_SIZE_63XX 0x08 +#define JMS_MIN_SIZE 1518 +#define JMS_MAX_SIZE 9724 + +/************************************************************************* + * CFP Configuration Page Registers + *************************************************************************/ + +/* CFP Control Register with ports map (8 bit) */ +#define B53_CFP_CTRL 0x00 + +#endif /* !__B53_REGS_H */ diff --git a/target/linux/generic/files/drivers/net/phy/b53/b53_spi.c b/target/linux/generic/files/drivers/net/phy/b53/b53_spi.c new file mode 100644 index 0000000..469a8dd --- /dev/null +++ b/target/linux/generic/files/drivers/net/phy/b53/b53_spi.c @@ -0,0 +1,330 @@ +/* + * B53 register access through SPI + * + * Copyright (C) 2011-2013 Jonas Gorski + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include +#include +#include +#include + +#include "b53_priv.h" + +#define B53_SPI_DATA 0xf0 + +#define B53_SPI_STATUS 0xfe +#define B53_SPI_CMD_SPIF BIT(7) +#define B53_SPI_CMD_RACK BIT(5) + +#define B53_SPI_CMD_READ 0x00 +#define B53_SPI_CMD_WRITE 0x01 +#define B53_SPI_CMD_NORMAL 0x60 +#define B53_SPI_CMD_FAST 0x10 + +#define B53_SPI_PAGE_SELECT 0xff + +static inline int b53_spi_read_reg(struct spi_device *spi, u8 reg, u8 *val, + unsigned len) +{ + u8 txbuf[2]; + + txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_READ; + txbuf[1] = reg; + + return spi_write_then_read(spi, txbuf, 2, val, len); +} + +static inline int b53_spi_clear_status(struct spi_device *spi) +{ + unsigned int i; + u8 rxbuf; + int ret; + + for (i = 0; i < 10; i++) { + ret = b53_spi_read_reg(spi, B53_SPI_STATUS, &rxbuf, 1); + if (ret) + return ret; + + if (!(rxbuf & B53_SPI_CMD_SPIF)) + break; + + mdelay(1); + } + + if (i == 10) + return -EIO; + + return 0; +} + +static inline int b53_spi_set_page(struct spi_device *spi, u8 page) +{ + u8 txbuf[3]; + + txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE; + txbuf[1] = B53_SPI_PAGE_SELECT; + txbuf[2] = page; + + return spi_write(spi, txbuf, sizeof(txbuf)); +} + +static inline int b53_prepare_reg_access(struct spi_device *spi, u8 page) +{ + int ret = b53_spi_clear_status(spi); + + if (ret) + return ret; + + return b53_spi_set_page(spi, page); +} + +static int b53_spi_prepare_reg_read(struct spi_device *spi, u8 reg) +{ + u8 rxbuf; + int retry_count; + int ret; + + ret = b53_spi_read_reg(spi, reg, &rxbuf, 1); + if (ret) + return ret; + + for (retry_count = 0; retry_count < 10; retry_count++) { + ret = b53_spi_read_reg(spi, B53_SPI_STATUS, &rxbuf, 1); + if (ret) + return ret; + + if (rxbuf & B53_SPI_CMD_RACK) + break; + + mdelay(1); + } + + if (retry_count == 10) + return -EIO; + + return 0; +} + +static int b53_spi_read(struct b53_device *dev, u8 page, u8 reg, u8 *data, + unsigned len) +{ + struct spi_device *spi = dev->priv; + int ret; + + ret = b53_prepare_reg_access(spi, page); + if (ret) + return ret; + + ret = b53_spi_prepare_reg_read(spi, reg); + if (ret) + return ret; + + return b53_spi_read_reg(spi, B53_SPI_DATA, data, len); +} + +static int b53_spi_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val) +{ + return b53_spi_read(dev, page, reg, val, 1); +} + +static int b53_spi_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val) +{ + int ret = b53_spi_read(dev, page, reg, (u8 *)val, 2); + + if (!ret) + *val = le16_to_cpu(*val); + + return ret; +} + +static int b53_spi_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val) +{ + int ret = b53_spi_read(dev, page, reg, (u8 *)val, 4); + + if (!ret) + *val = le32_to_cpu(*val); + + return ret; +} + +static int b53_spi_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val) +{ + int ret; + + *val = 0; + ret = b53_spi_read(dev, page, reg, (u8 *)val, 6); + if (!ret) + *val = le64_to_cpu(*val); + + return ret; +} + +static int b53_spi_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val) +{ + int ret = b53_spi_read(dev, page, reg, (u8 *)val, 8); + + if (!ret) + *val = le64_to_cpu(*val); + + return ret; +} + +static int b53_spi_write8(struct b53_device *dev, u8 page, u8 reg, u8 value) +{ + struct spi_device *spi = dev->priv; + int ret; + u8 txbuf[3]; + + ret = b53_prepare_reg_access(spi, page); + if (ret) + return ret; + + txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE; + txbuf[1] = reg; + txbuf[2] = value; + + return spi_write(spi, txbuf, sizeof(txbuf)); +} + +static int b53_spi_write16(struct b53_device *dev, u8 page, u8 reg, u16 value) +{ + struct spi_device *spi = dev->priv; + int ret; + u8 txbuf[4]; + + ret = b53_prepare_reg_access(spi, page); + if (ret) + return ret; + + txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE; + txbuf[1] = reg; + put_unaligned_le16(value, &txbuf[2]); + + return spi_write(spi, txbuf, sizeof(txbuf)); +} + +static int b53_spi_write32(struct b53_device *dev, u8 page, u8 reg, u32 value) +{ + struct spi_device *spi = dev->priv; + int ret; + u8 txbuf[6]; + + ret = b53_prepare_reg_access(spi, page); + if (ret) + return ret; + + txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE; + txbuf[1] = reg; + put_unaligned_le32(value, &txbuf[2]); + + return spi_write(spi, txbuf, sizeof(txbuf)); +} + +static int b53_spi_write48(struct b53_device *dev, u8 page, u8 reg, u64 value) +{ + struct spi_device *spi = dev->priv; + int ret; + u8 txbuf[10]; + + ret = b53_prepare_reg_access(spi, page); + if (ret) + return ret; + + txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE; + txbuf[1] = reg; + put_unaligned_le64(value, &txbuf[2]); + + return spi_write(spi, txbuf, sizeof(txbuf) - 2); +} + +static int b53_spi_write64(struct b53_device *dev, u8 page, u8 reg, u64 value) +{ + struct spi_device *spi = dev->priv; + int ret; + u8 txbuf[10]; + + ret = b53_prepare_reg_access(spi, page); + if (ret) + return ret; + + txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE; + txbuf[1] = reg; + put_unaligned_le64(value, &txbuf[2]); + + return spi_write(spi, txbuf, sizeof(txbuf)); +} + +static struct b53_io_ops b53_spi_ops = { + .read8 = b53_spi_read8, + .read16 = b53_spi_read16, + .read32 = b53_spi_read32, + .read48 = b53_spi_read48, + .read64 = b53_spi_read64, + .write8 = b53_spi_write8, + .write16 = b53_spi_write16, + .write32 = b53_spi_write32, + .write48 = b53_spi_write48, + .write64 = b53_spi_write64, +}; + +static int b53_spi_probe(struct spi_device *spi) +{ + struct b53_device *dev; + int ret; + + dev = b53_switch_alloc(&spi->dev, &b53_spi_ops, spi); + if (!dev) + return -ENOMEM; + + if (spi->dev.platform_data) + dev->pdata = spi->dev.platform_data; + + ret = b53_switch_register(dev); + if (ret) + return ret; + + spi_set_drvdata(spi, dev); + + return 0; +} + +static int b53_spi_remove(struct spi_device *spi) +{ + struct b53_device *dev = spi_get_drvdata(spi); + + if (dev) + b53_switch_remove(dev); + + return 0; +} + +static struct spi_driver b53_spi_driver = { + .driver = { + .name = "b53-switch", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + .probe = b53_spi_probe, + .remove = b53_spi_remove, +}; + +module_spi_driver(b53_spi_driver); + +MODULE_AUTHOR("Jonas Gorski "); +MODULE_DESCRIPTION("B53 SPI access driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/target/linux/generic/files/drivers/net/phy/b53/b53_srab.c b/target/linux/generic/files/drivers/net/phy/b53/b53_srab.c new file mode 100644 index 0000000..012daa3 --- /dev/null +++ b/target/linux/generic/files/drivers/net/phy/b53/b53_srab.c @@ -0,0 +1,378 @@ +/* + * B53 register access through Switch Register Access Bridge Registers + * + * Copyright (C) 2013 Hauke Mehrtens + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include + +#include "b53_priv.h" + +/* command and status register of the SRAB */ +#define B53_SRAB_CMDSTAT 0x2c +#define B53_SRAB_CMDSTAT_RST BIT(2) +#define B53_SRAB_CMDSTAT_WRITE BIT(1) +#define B53_SRAB_CMDSTAT_GORDYN BIT(0) +#define B53_SRAB_CMDSTAT_PAGE 24 +#define B53_SRAB_CMDSTAT_REG 16 + +/* high order word of write data to switch registe */ +#define B53_SRAB_WD_H 0x30 + +/* low order word of write data to switch registe */ +#define B53_SRAB_WD_L 0x34 + +/* high order word of read data from switch register */ +#define B53_SRAB_RD_H 0x38 + +/* low order word of read data from switch register */ +#define B53_SRAB_RD_L 0x3c + +/* command and status register of the SRAB */ +#define B53_SRAB_CTRLS 0x40 +#define B53_SRAB_CTRLS_RCAREQ BIT(3) +#define B53_SRAB_CTRLS_RCAGNT BIT(4) +#define B53_SRAB_CTRLS_SW_INIT_DONE BIT(6) + +/* the register captures interrupt pulses from the switch */ +#define B53_SRAB_INTR 0x44 + +static int b53_srab_request_grant(struct b53_device *dev) +{ + u8 __iomem *regs = dev->priv; + u32 ctrls; + int i; + + ctrls = readl(regs + B53_SRAB_CTRLS); + ctrls |= B53_SRAB_CTRLS_RCAREQ; + writel(ctrls, regs + B53_SRAB_CTRLS); + + for (i = 0; i < 20; i++) { + ctrls = readl(regs + B53_SRAB_CTRLS); + if (ctrls & B53_SRAB_CTRLS_RCAGNT) + break; + usleep_range(10, 100); + } + if (WARN_ON(i == 5)) + return -EIO; + + return 0; +} + +static void b53_srab_release_grant(struct b53_device *dev) +{ + u8 __iomem *regs = dev->priv; + u32 ctrls; + + ctrls = readl(regs + B53_SRAB_CTRLS); + ctrls &= ~B53_SRAB_CTRLS_RCAREQ; + writel(ctrls, regs + B53_SRAB_CTRLS); +} + +static int b53_srab_op(struct b53_device *dev, u8 page, u8 reg, u32 op) +{ + int i; + u32 cmdstat; + u8 __iomem *regs = dev->priv; + + /* set register address */ + cmdstat = (page << B53_SRAB_CMDSTAT_PAGE) | + (reg << B53_SRAB_CMDSTAT_REG) | + B53_SRAB_CMDSTAT_GORDYN | + op; + writel(cmdstat, regs + B53_SRAB_CMDSTAT); + + /* check if operation completed */ + for (i = 0; i < 5; ++i) { + cmdstat = readl(regs + B53_SRAB_CMDSTAT); + if (!(cmdstat & B53_SRAB_CMDSTAT_GORDYN)) + break; + usleep_range(10, 100); + } + + if (WARN_ON(i == 5)) + return -EIO; + + return 0; +} + +static int b53_srab_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val) +{ + u8 __iomem *regs = dev->priv; + int ret = 0; + + ret = b53_srab_request_grant(dev); + if (ret) + goto err; + + ret = b53_srab_op(dev, page, reg, 0); + if (ret) + goto err; + + *val = readl(regs + B53_SRAB_RD_L) & 0xff; + +err: + b53_srab_release_grant(dev); + + return ret; +} + +static int b53_srab_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val) +{ + u8 __iomem *regs = dev->priv; + int ret = 0; + + ret = b53_srab_request_grant(dev); + if (ret) + goto err; + + ret = b53_srab_op(dev, page, reg, 0); + if (ret) + goto err; + + *val = readl(regs + B53_SRAB_RD_L) & 0xffff; + +err: + b53_srab_release_grant(dev); + + return ret; +} + +static int b53_srab_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val) +{ + u8 __iomem *regs = dev->priv; + int ret = 0; + + ret = b53_srab_request_grant(dev); + if (ret) + goto err; + + ret = b53_srab_op(dev, page, reg, 0); + if (ret) + goto err; + + *val = readl(regs + B53_SRAB_RD_L); + +err: + b53_srab_release_grant(dev); + + return ret; +} + +static int b53_srab_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val) +{ + u8 __iomem *regs = dev->priv; + int ret = 0; + + ret = b53_srab_request_grant(dev); + if (ret) + goto err; + + ret = b53_srab_op(dev, page, reg, 0); + if (ret) + goto err; + + *val = readl(regs + B53_SRAB_RD_L); + *val += ((u64)readl(regs + B53_SRAB_RD_H) & 0xffff) << 32; + +err: + b53_srab_release_grant(dev); + + return ret; +} + +static int b53_srab_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val) +{ + u8 __iomem *regs = dev->priv; + int ret = 0; + + ret = b53_srab_request_grant(dev); + if (ret) + goto err; + + ret = b53_srab_op(dev, page, reg, 0); + if (ret) + goto err; + + *val = readl(regs + B53_SRAB_RD_L); + *val += (u64)readl(regs + B53_SRAB_RD_H) << 32; + +err: + b53_srab_release_grant(dev); + + return ret; +} + +static int b53_srab_write8(struct b53_device *dev, u8 page, u8 reg, u8 value) +{ + u8 __iomem *regs = dev->priv; + int ret = 0; + + ret = b53_srab_request_grant(dev); + if (ret) + goto err; + + writel(value, regs + B53_SRAB_WD_L); + + ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE); + +err: + b53_srab_release_grant(dev); + + return ret; +} + +static int b53_srab_write16(struct b53_device *dev, u8 page, u8 reg, + u16 value) +{ + u8 __iomem *regs = dev->priv; + int ret = 0; + + ret = b53_srab_request_grant(dev); + if (ret) + goto err; + + writel(value, regs + B53_SRAB_WD_L); + + ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE); + +err: + b53_srab_release_grant(dev); + + return ret; +} + +static int b53_srab_write32(struct b53_device *dev, u8 page, u8 reg, + u32 value) +{ + u8 __iomem *regs = dev->priv; + int ret = 0; + + ret = b53_srab_request_grant(dev); + if (ret) + goto err; + + writel(value, regs + B53_SRAB_WD_L); + + ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE); + +err: + b53_srab_release_grant(dev); + + return ret; + +} + +static int b53_srab_write48(struct b53_device *dev, u8 page, u8 reg, + u64 value) +{ + u8 __iomem *regs = dev->priv; + int ret = 0; + + ret = b53_srab_request_grant(dev); + if (ret) + goto err; + + writel((u32)value, regs + B53_SRAB_WD_L); + writel((u16)(value >> 32), regs + B53_SRAB_WD_H); + + ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE); + +err: + b53_srab_release_grant(dev); + + return ret; + +} + +static int b53_srab_write64(struct b53_device *dev, u8 page, u8 reg, + u64 value) +{ + u8 __iomem *regs = dev->priv; + int ret = 0; + + ret = b53_srab_request_grant(dev); + if (ret) + goto err; + + writel((u32)value, regs + B53_SRAB_WD_L); + writel((u32)(value >> 32), regs + B53_SRAB_WD_H); + + ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE); + +err: + b53_srab_release_grant(dev); + + return ret; +} + +static struct b53_io_ops b53_srab_ops = { + .read8 = b53_srab_read8, + .read16 = b53_srab_read16, + .read32 = b53_srab_read32, + .read48 = b53_srab_read48, + .read64 = b53_srab_read64, + .write8 = b53_srab_write8, + .write16 = b53_srab_write16, + .write32 = b53_srab_write32, + .write48 = b53_srab_write48, + .write64 = b53_srab_write64, +}; + +static int b53_srab_probe(struct platform_device *pdev) +{ + struct b53_platform_data *pdata = pdev->dev.platform_data; + struct b53_device *dev; + + if (!pdata) + return -EINVAL; + + dev = b53_switch_alloc(&pdev->dev, &b53_srab_ops, pdata->regs); + if (!dev) + return -ENOMEM; + + if (pdata) + dev->pdata = pdata; + + platform_set_drvdata(pdev, dev); + + return b53_switch_register(dev); +} + +static int b53_srab_remove(struct platform_device *pdev) +{ + struct b53_device *dev = platform_get_drvdata(pdev); + + if (dev) + b53_switch_remove(dev); + + return 0; +} + +static struct platform_driver b53_srab_driver = { + .probe = b53_srab_probe, + .remove = b53_srab_remove, + .driver = { + .name = "b53-srab-switch", + }, +}; + +module_platform_driver(b53_srab_driver); +MODULE_AUTHOR("Hauke Mehrtens "); +MODULE_DESCRIPTION("B53 Switch Register Access Bridge Registers (SRAB) access driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/target/linux/generic/files/drivers/net/phy/ip17xx.c b/target/linux/generic/files/drivers/net/phy/ip17xx.c new file mode 100644 index 0000000..c82c39e --- /dev/null +++ b/target/linux/generic/files/drivers/net/phy/ip17xx.c @@ -0,0 +1,1410 @@ +/* + * ip17xx.c: Swconfig configuration for IC+ IP17xx switch family + * + * Copyright (C) 2008 Patrick Horn + * Copyright (C) 2008, 2010 Martin Mares + * Copyright (C) 2009 Felix Fietkau + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_VLANS 16 +#define MAX_PORTS 9 +#undef DUMP_MII_IO + +typedef struct ip17xx_reg { + u16 p; // phy + u16 m; // mii +} reg; +typedef char bitnum; + +#define NOTSUPPORTED {-1,-1} + +#define REG_SUPP(x) (((x).m != ((u16)-1)) && ((x).p != (u16)-1)) + +struct ip17xx_state; + +/*********** CONSTANTS ***********/ +struct register_mappings { + char *NAME; + u16 MODEL_NO; // Compare to bits 4-9 of MII register 0,3. + bitnum NUM_PORTS; + bitnum CPU_PORT; + +/* The default VLAN for each port. + Default: 0x0001 for Ports 0,1,2,3 + 0x0002 for Ports 4,5 */ + reg VLAN_DEFAULT_TAG_REG[MAX_PORTS]; + +/* These ports are tagged. + Default: 0x00 */ + reg ADD_TAG_REG; + reg REMOVE_TAG_REG; + bitnum ADD_TAG_BIT[MAX_PORTS]; +/* These ports are untagged. + Default: 0x00 (i.e. do not alter any VLAN tags...) + Maybe set to 0 if user disables VLANs. */ + bitnum REMOVE_TAG_BIT[MAX_PORTS]; + +/* Port M and Port N are on the same VLAN. + Default: All ports on all VLANs. */ +// Use register {29, 19+N/2} + reg VLAN_LOOKUP_REG; +// Port 5 uses register {30, 18} but same as odd bits. + reg VLAN_LOOKUP_REG_5; // in a different register on IP175C. + bitnum VLAN_LOOKUP_EVEN_BIT[MAX_PORTS]; + bitnum VLAN_LOOKUP_ODD_BIT[MAX_PORTS]; + +/* This VLAN corresponds to which ports. + Default: 0x2f,0x30,0x3f,0x3f... */ + reg TAG_VLAN_MASK_REG; + bitnum TAG_VLAN_MASK_EVEN_BIT[MAX_PORTS]; + bitnum TAG_VLAN_MASK_ODD_BIT[MAX_PORTS]; + + int RESET_VAL; + reg RESET_REG; + + reg MODE_REG; + int MODE_VAL; + +/* General flags */ + reg ROUTER_CONTROL_REG; + reg VLAN_CONTROL_REG; + bitnum TAG_VLAN_BIT; + bitnum ROUTER_EN_BIT; + bitnum NUMLAN_GROUPS_MAX; + bitnum NUMLAN_GROUPS_BIT; + + reg MII_REGISTER_EN; + bitnum MII_REGISTER_EN_BIT; + + // set to 1 for 178C, 0 for 175C. + bitnum SIMPLE_VLAN_REGISTERS; // 175C has two vlans per register but 178C has only one. + + // Pointers to functions which manipulate hardware state + int (*update_state)(struct ip17xx_state *state); + int (*set_vlan_mode)(struct ip17xx_state *state); + int (*reset)(struct ip17xx_state *state); +}; + +static int ip175c_update_state(struct ip17xx_state *state); +static int ip175c_set_vlan_mode(struct ip17xx_state *state); +static int ip175c_reset(struct ip17xx_state *state); + +static const struct register_mappings IP178C = { + .NAME = "IP178C", + .MODEL_NO = 0x18, + .VLAN_DEFAULT_TAG_REG = { + {30,3},{30,4},{30,5},{30,6},{30,7},{30,8}, + {30,9},{30,10},{30,11}, + }, + + .ADD_TAG_REG = {30,12}, + .ADD_TAG_BIT = {0,1,2,3,4,5,6,7,8}, + .REMOVE_TAG_REG = {30,13}, + .REMOVE_TAG_BIT = {4,5,6,7,8,9,10,11,12}, + + .SIMPLE_VLAN_REGISTERS = 1, + + .VLAN_LOOKUP_REG = {31,0},// +N + .VLAN_LOOKUP_REG_5 = NOTSUPPORTED, // not used with SIMPLE_VLAN_REGISTERS + .VLAN_LOOKUP_EVEN_BIT = {0,1,2,3,4,5,6,7,8}, + .VLAN_LOOKUP_ODD_BIT = {0,1,2,3,4,5,6,7,8}, + + .TAG_VLAN_MASK_REG = {30,14}, // +N + .TAG_VLAN_MASK_EVEN_BIT = {0,1,2,3,4,5,6,7,8}, + .TAG_VLAN_MASK_ODD_BIT = {0,1,2,3,4,5,6,7,8}, + + .RESET_VAL = 0x55AA, + .RESET_REG = {30,0}, + .MODE_VAL = 0, + .MODE_REG = NOTSUPPORTED, + + .ROUTER_CONTROL_REG = {30,30}, + .ROUTER_EN_BIT = 11, + .NUMLAN_GROUPS_MAX = 8, + .NUMLAN_GROUPS_BIT = 8, // {0-2} + + .VLAN_CONTROL_REG = {30,13}, + .TAG_VLAN_BIT = 3, + + .CPU_PORT = 8, + .NUM_PORTS = 9, + + .MII_REGISTER_EN = NOTSUPPORTED, + + .update_state = ip175c_update_state, + .set_vlan_mode = ip175c_set_vlan_mode, + .reset = ip175c_reset, +}; + +static const struct register_mappings IP175C = { + .NAME = "IP175C", + .MODEL_NO = 0x18, + .VLAN_DEFAULT_TAG_REG = { + {29,24},{29,25},{29,26},{29,27},{29,28},{29,30}, + NOTSUPPORTED,NOTSUPPORTED,NOTSUPPORTED + }, + + .ADD_TAG_REG = {29,23}, + .REMOVE_TAG_REG = {29,23}, + .ADD_TAG_BIT = {11,12,13,14,15,1,-1,-1,-1}, + .REMOVE_TAG_BIT = {6,7,8,9,10,0,-1,-1,-1}, + + .SIMPLE_VLAN_REGISTERS = 0, + + .VLAN_LOOKUP_REG = {29,19},// +N/2 + .VLAN_LOOKUP_REG_5 = {30,18}, + .VLAN_LOOKUP_EVEN_BIT = {8,9,10,11,12,15,-1,-1,-1}, + .VLAN_LOOKUP_ODD_BIT = {0,1,2,3,4,7,-1,-1,-1}, + + .TAG_VLAN_MASK_REG = {30,1}, // +N/2 + .TAG_VLAN_MASK_EVEN_BIT = {0,1,2,3,4,5,-1,-1,-1}, + .TAG_VLAN_MASK_ODD_BIT = {8,9,10,11,12,13,-1,-1,-1}, + + .RESET_VAL = 0x175C, + .RESET_REG = {30,0}, + .MODE_VAL = 0x175C, + .MODE_REG = {29,31}, + + .ROUTER_CONTROL_REG = {30,9}, + .ROUTER_EN_BIT = 3, + .NUMLAN_GROUPS_MAX = 8, + .NUMLAN_GROUPS_BIT = 0, // {0-2} + + .VLAN_CONTROL_REG = {30,9}, + .TAG_VLAN_BIT = 7, + + .NUM_PORTS = 6, + .CPU_PORT = 5, + + .MII_REGISTER_EN = NOTSUPPORTED, + + .update_state = ip175c_update_state, + .set_vlan_mode = ip175c_set_vlan_mode, + .reset = ip175c_reset, +}; + +static const struct register_mappings IP175A = { + .NAME = "IP175A", + .MODEL_NO = 0x05, + .VLAN_DEFAULT_TAG_REG = { + {0,24},{0,25},{0,26},{0,27},{0,28},NOTSUPPORTED, + NOTSUPPORTED,NOTSUPPORTED,NOTSUPPORTED + }, + + .ADD_TAG_REG = {0,23}, + .REMOVE_TAG_REG = {0,23}, + .ADD_TAG_BIT = {11,12,13,14,15,-1,-1,-1,-1}, + .REMOVE_TAG_BIT = {6,7,8,9,10,-1,-1,-1,-1}, + + .SIMPLE_VLAN_REGISTERS = 0, + + // Only programmable via EEPROM + .VLAN_LOOKUP_REG = NOTSUPPORTED,// +N/2 + .VLAN_LOOKUP_REG_5 = NOTSUPPORTED, + .VLAN_LOOKUP_EVEN_BIT = {8,9,10,11,12,-1,-1,-1,-1}, + .VLAN_LOOKUP_ODD_BIT = {0,1,2,3,4,-1,-1,-1,-1}, + + .TAG_VLAN_MASK_REG = NOTSUPPORTED, // +N/2, + .TAG_VLAN_MASK_EVEN_BIT = {-1,-1,-1,-1,-1,-1,-1,-1,-1}, + .TAG_VLAN_MASK_ODD_BIT = {-1,-1,-1,-1,-1,-1,-1,-1,-1}, + + .RESET_VAL = -1, + .RESET_REG = NOTSUPPORTED, + .MODE_VAL = 0, + .MODE_REG = NOTSUPPORTED, + + .ROUTER_CONTROL_REG = NOTSUPPORTED, + .VLAN_CONTROL_REG = NOTSUPPORTED, + .TAG_VLAN_BIT = -1, + .ROUTER_EN_BIT = -1, + .NUMLAN_GROUPS_MAX = -1, + .NUMLAN_GROUPS_BIT = -1, // {0-2} + + .NUM_PORTS = 5, + .CPU_PORT = 4, + + .MII_REGISTER_EN = {0, 18}, + .MII_REGISTER_EN_BIT = 7, + + .update_state = ip175c_update_state, + .set_vlan_mode = ip175c_set_vlan_mode, + .reset = ip175c_reset, +}; + + +static int ip175d_update_state(struct ip17xx_state *state); +static int ip175d_set_vlan_mode(struct ip17xx_state *state); +static int ip175d_reset(struct ip17xx_state *state); + +static const struct register_mappings IP175D = { + .NAME = "IP175D", + .MODEL_NO = 0x18, + + // The IP175D has a completely different interface, so we leave most + // of the registers undefined and switch to different code paths. + + .VLAN_DEFAULT_TAG_REG = { + NOTSUPPORTED,NOTSUPPORTED,NOTSUPPORTED,NOTSUPPORTED, + NOTSUPPORTED,NOTSUPPORTED,NOTSUPPORTED,NOTSUPPORTED, + }, + + .ADD_TAG_REG = NOTSUPPORTED, + .REMOVE_TAG_REG = NOTSUPPORTED, + + .SIMPLE_VLAN_REGISTERS = 0, + + .VLAN_LOOKUP_REG = NOTSUPPORTED, + .VLAN_LOOKUP_REG_5 = NOTSUPPORTED, + .TAG_VLAN_MASK_REG = NOTSUPPORTED, + + .RESET_VAL = 0x175D, + .RESET_REG = {20,2}, + .MODE_REG = NOTSUPPORTED, + + .ROUTER_CONTROL_REG = NOTSUPPORTED, + .ROUTER_EN_BIT = -1, + .NUMLAN_GROUPS_BIT = -1, + + .VLAN_CONTROL_REG = NOTSUPPORTED, + .TAG_VLAN_BIT = -1, + + .NUM_PORTS = 6, + .CPU_PORT = 5, + + .MII_REGISTER_EN = NOTSUPPORTED, + + .update_state = ip175d_update_state, + .set_vlan_mode = ip175d_set_vlan_mode, + .reset = ip175d_reset, +}; + +struct ip17xx_state { + struct switch_dev dev; + struct mii_bus *mii_bus; + bool registered; + + int router_mode; // ROUTER_EN + int vlan_enabled; // TAG_VLAN_EN + struct port_state { + u16 pvid; + unsigned int shareports; + } ports[MAX_PORTS]; + unsigned int add_tag; + unsigned int remove_tag; + int num_vlans; + struct vlan_state { + unsigned int ports; + unsigned int tag; // VLAN tag (IP175D only) + } vlans[MAX_VLANS]; + const struct register_mappings *regs; + reg proc_mii; // phy/reg for the low level register access via swconfig + + char buf[80]; +}; + +#define get_state(_dev) container_of((_dev), struct ip17xx_state, dev) + +static int ip_phy_read(struct ip17xx_state *state, int port, int reg) +{ + int val = mdiobus_read(state->mii_bus, port, reg); + if (val < 0) + pr_warning("IP17xx: Unable to get MII register %d,%d: error %d\n", port, reg, -val); +#ifdef DUMP_MII_IO + else + pr_debug("IP17xx: Read MII(%d,%d) -> %04x\n", port, reg, val); +#endif + return val; +} + +static int ip_phy_write(struct ip17xx_state *state, int port, int reg, u16 val) +{ + int err; + +#ifdef DUMP_MII_IO + pr_debug("IP17xx: Write MII(%d,%d) <- %04x\n", port, reg, val); +#endif + err = mdiobus_write(state->mii_bus, port, reg, val); + if (err < 0) + pr_warning("IP17xx: Unable to write MII register %d,%d: error %d\n", port, reg, -err); + return err; +} + +static int ip_phy_write_masked(struct ip17xx_state *state, int port, int reg, unsigned int mask, unsigned int data) +{ + int val = ip_phy_read(state, port, reg); + if (val < 0) + return 0; + return ip_phy_write(state, port, reg, (val & ~mask) | data); +} + +static int getPhy(struct ip17xx_state *state, reg mii) +{ + if (!REG_SUPP(mii)) + return -EFAULT; + return ip_phy_read(state, mii.p, mii.m); +} + +static int setPhy(struct ip17xx_state *state, reg mii, u16 value) +{ + int err; + + if (!REG_SUPP(mii)) + return -EFAULT; + err = ip_phy_write(state, mii.p, mii.m, value); + if (err < 0) + return err; + mdelay(2); + getPhy(state, mii); + return 0; +} + + +/** + * These two macros are to simplify the mapping of logical bits to the bits in hardware. + * NOTE: these macros will return if there is an error! + */ + +#define GET_PORT_BITS(state, bits, addr, bit_lookup) \ + do { \ + int i, val = getPhy((state), (addr)); \ + if (val < 0) \ + return val; \ + (bits) = 0; \ + for (i = 0; i < MAX_PORTS; i++) { \ + if ((bit_lookup)[i] == -1) continue; \ + if (val & (1<<(bit_lookup)[i])) \ + (bits) |= (1<>i)<<(bit_lookup)[i]); \ + } \ + val = setPhy((state), (addr), val); \ + if (val < 0) \ + return val; \ + } while (0) + + +static int get_model(struct ip17xx_state *state) +{ + int id1, id2; + int oui_id, model_no, rev_no, chip_no; + + id1 = ip_phy_read(state, 0, 2); + id2 = ip_phy_read(state, 0, 3); + oui_id = (id1 << 6) | ((id2 >> 10) & 0x3f); + model_no = (id2 >> 4) & 0x3f; + rev_no = id2 & 0xf; + pr_debug("IP17xx: Identified oui=%06x model=%02x rev=%X\n", oui_id, model_no, rev_no); + + if (oui_id != 0x0090c3) // No other oui_id should have reached us anyway + return -ENODEV; + + if (model_no == IP175A.MODEL_NO) { + state->regs = &IP175A; + } else if (model_no == IP175C.MODEL_NO) { + /* + * Several models share the same model_no: + * 178C has more PHYs, so we try whether the device responds to a read from PHY5 + * 175D has a new chip ID register + * 175C has neither + */ + if (ip_phy_read(state, 5, 2) == 0x0243) { + state->regs = &IP178C; + } else { + chip_no = ip_phy_read(state, 20, 0); + pr_debug("IP17xx: Chip ID register reads %04x\n", chip_no); + if (chip_no == 0x175d) { + state->regs = &IP175D; + } else { + state->regs = &IP175C; + } + } + } else { + pr_warning("IP17xx: Found an unknown IC+ switch with model number %02x, revision %X.\n", model_no, rev_no); + return -EPERM; + } + return 0; +} + +/*** Low-level functions for the older models ***/ + +/** Only set vlan and router flags in the switch **/ +static int ip175c_set_flags(struct ip17xx_state *state) +{ + int val; + + if (!REG_SUPP(state->regs->ROUTER_CONTROL_REG)) { + return 0; + } + + val = getPhy(state, state->regs->ROUTER_CONTROL_REG); + if (val < 0) { + return val; + } + if (state->regs->ROUTER_EN_BIT >= 0) { + if (state->router_mode) { + val |= (1<regs->ROUTER_EN_BIT); + } else { + val &= (~(1<regs->ROUTER_EN_BIT)); + } + } + if (state->regs->TAG_VLAN_BIT >= 0) { + if (state->vlan_enabled) { + val |= (1<regs->TAG_VLAN_BIT); + } else { + val &= (~(1<regs->TAG_VLAN_BIT)); + } + } + if (state->regs->NUMLAN_GROUPS_BIT >= 0) { + val &= (~((state->regs->NUMLAN_GROUPS_MAX-1)<regs->NUMLAN_GROUPS_BIT)); + if (state->num_vlans > state->regs->NUMLAN_GROUPS_MAX) { + val |= state->regs->NUMLAN_GROUPS_MAX << state->regs->NUMLAN_GROUPS_BIT; + } else if (state->num_vlans >= 1) { + val |= (state->num_vlans-1) << state->regs->NUMLAN_GROUPS_BIT; + } + } + return setPhy(state, state->regs->ROUTER_CONTROL_REG, val); +} + +/** Set all VLAN and port state. Usually you should call "correct_vlan_state" first. **/ +static int ip175c_set_state(struct ip17xx_state *state) +{ + int j; + int i; + SET_PORT_BITS(state, state->add_tag, + state->regs->ADD_TAG_REG, state->regs->ADD_TAG_BIT); + SET_PORT_BITS(state, state->remove_tag, + state->regs->REMOVE_TAG_REG, state->regs->REMOVE_TAG_BIT); + + if (REG_SUPP(state->regs->VLAN_LOOKUP_REG)) { + for (j=0; jregs->NUM_PORTS; j++) { + reg addr; + const bitnum *bit_lookup = (j%2==0)? + state->regs->VLAN_LOOKUP_EVEN_BIT: + state->regs->VLAN_LOOKUP_ODD_BIT; + + addr = state->regs->VLAN_LOOKUP_REG; + if (state->regs->SIMPLE_VLAN_REGISTERS) { + addr.m += j; + } else { + switch (j) { + case 0: + case 1: + break; + case 2: + case 3: + addr.m+=1; + break; + case 4: + addr.m+=2; + break; + case 5: + addr = state->regs->VLAN_LOOKUP_REG_5; + break; + default: + addr.m = -1; // shouldn't get here, but... + break; + } + } + //printf("shareports for %d is %02X\n",j,state->ports[j].shareports); + if (REG_SUPP(addr)) { + SET_PORT_BITS(state, state->ports[j].shareports, addr, bit_lookup); + } + } + } + if (REG_SUPP(state->regs->TAG_VLAN_MASK_REG)) { + for (j=0; jregs->TAG_VLAN_MASK_REG; + const bitnum *bit_lookup = (j%2==0)? + state->regs->TAG_VLAN_MASK_EVEN_BIT: + state->regs->TAG_VLAN_MASK_ODD_BIT; + unsigned int vlan_mask; + if (state->regs->SIMPLE_VLAN_REGISTERS) { + addr.m += j; + } else { + addr.m += j/2; + } + vlan_mask = state->vlans[j].ports; + SET_PORT_BITS(state, vlan_mask, addr, bit_lookup); + } + } + + for (i=0; iregs->VLAN_DEFAULT_TAG_REG[i])) { + int err = setPhy(state, state->regs->VLAN_DEFAULT_TAG_REG[i], + state->ports[i].pvid); + if (err < 0) { + return err; + } + } + } + + return ip175c_set_flags(state); +} + +/** + * Uses only the VLAN port mask and the add tag mask to generate the other fields: + * which ports are part of the same VLAN, removing vlan tags, and VLAN tag ids. + */ +static void ip175c_correct_vlan_state(struct ip17xx_state *state) +{ + int i, j; + state->num_vlans = 0; + for (i=0; ivlans[i].ports != 0) { + state->num_vlans = i+1; // Hack -- we need to store the "set" vlans somewhere... + } + } + + for (i=0; iregs->NUM_PORTS; i++) { + unsigned int portmask = (1<vlan_enabled) { + // Share with everybody! + state->ports[i].shareports = (1<regs->NUM_PORTS)-1; + continue; + } + state->ports[i].shareports = portmask; + for (j=0; jvlans[j].ports & portmask) + state->ports[i].shareports |= state->vlans[j].ports; + } + } +} + +static int ip175c_update_state(struct ip17xx_state *state) +{ + ip175c_correct_vlan_state(state); + return ip175c_set_state(state); +} + +static int ip175c_set_vlan_mode(struct ip17xx_state *state) +{ + return ip175c_update_state(state); +} + +static int ip175c_reset(struct ip17xx_state *state) +{ + int err; + + if (REG_SUPP(state->regs->MODE_REG)) { + err = setPhy(state, state->regs->MODE_REG, state->regs->MODE_VAL); + if (err < 0) + return err; + err = getPhy(state, state->regs->MODE_REG); + if (err < 0) + return err; + } + + return ip175c_update_state(state); +} + +/*** Low-level functions for IP175D ***/ + +static int ip175d_update_state(struct ip17xx_state *state) +{ + unsigned int filter_mask = 0; + unsigned int ports[16], add[16], rem[16]; + int i, j; + int err = 0; + + for (i = 0; i < 16; i++) { + ports[i] = 0; + add[i] = 0; + rem[i] = 0; + if (!state->vlan_enabled) { + err |= ip_phy_write(state, 22, 14+i, i+1); // default tags + ports[i] = 0x3f; + continue; + } + if (!state->vlans[i].tag) { + // Reset the filter + err |= ip_phy_write(state, 22, 14+i, 0); // tag + continue; + } + filter_mask |= 1 << i; + err |= ip_phy_write(state, 22, 14+i, state->vlans[i].tag); + ports[i] = state->vlans[i].ports; + for (j = 0; j < 6; j++) { + if (ports[i] & (1 << j)) { + if (state->add_tag & (1 << j)) + add[i] |= 1 << j; + if (state->remove_tag & (1 << j)) + rem[i] |= 1 << j; + } + } + } + + // Port masks, tag adds and removals + for (i = 0; i < 8; i++) { + err |= ip_phy_write(state, 23, i, ports[2*i] | (ports[2*i+1] << 8)); + err |= ip_phy_write(state, 23, 8+i, add[2*i] | (add[2*i+1] << 8)); + err |= ip_phy_write(state, 23, 16+i, rem[2*i] | (rem[2*i+1] << 8)); + } + err |= ip_phy_write(state, 22, 10, filter_mask); + + // Default VLAN tag for each port + for (i = 0; i < 6; i++) + err |= ip_phy_write(state, 22, 4+i, state->vlans[state->ports[i].pvid].tag); + + return (err ? -EIO : 0); +} + +static int ip175d_set_vlan_mode(struct ip17xx_state *state) +{ + int i; + int err = 0; + + if (state->vlan_enabled) { + // VLAN classification rules: tag-based VLANs, use VID to classify, + // drop packets that cannot be classified. + err |= ip_phy_write_masked(state, 22, 0, 0x3fff, 0x003f); + + // Ingress rules: CFI=1 dropped, null VID is untagged, VID=1 passed, + // VID=0xfff discarded, admin both tagged and untagged, ingress + // filters enabled. + err |= ip_phy_write_masked(state, 22, 1, 0x0fff, 0x0c3f); + + // Egress rules: IGMP processing off, keep VLAN header off + err |= ip_phy_write_masked(state, 22, 2, 0x0fff, 0x0000); + } else { + // VLAN classification rules: everything off & clear table + err |= ip_phy_write_masked(state, 22, 0, 0xbfff, 0x8000); + + // Ingress and egress rules: set to defaults + err |= ip_phy_write_masked(state, 22, 1, 0x0fff, 0x0c3f); + err |= ip_phy_write_masked(state, 22, 2, 0x0fff, 0x0000); + } + + // Reset default VLAN for each port to 0 + for (i = 0; i < 6; i++) + state->ports[i].pvid = 0; + + err |= ip175d_update_state(state); + + return (err ? -EIO : 0); +} + +static int ip175d_reset(struct ip17xx_state *state) +{ + int err = 0; + + // Disable the special tagging mode + err |= ip_phy_write_masked(state, 21, 22, 0x0003, 0x0000); + + // Set 802.1q protocol type + err |= ip_phy_write(state, 22, 3, 0x8100); + + state->vlan_enabled = 0; + err |= ip175d_set_vlan_mode(state); + + return (err ? -EIO : 0); +} + +/*** High-level functions ***/ + +static int ip17xx_get_enable_vlan(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + struct ip17xx_state *state = get_state(dev); + + val->value.i = state->vlan_enabled; + return 0; +} + +static void ip17xx_reset_vlan_config(struct ip17xx_state *state) +{ + int i; + + state->remove_tag = (state->vlan_enabled ? ((1<regs->NUM_PORTS)-1) : 0x0000); + state->add_tag = 0x0000; + for (i = 0; i < MAX_VLANS; i++) { + state->vlans[i].ports = 0x0000; + state->vlans[i].tag = (i ? i : 16); + } + for (i = 0; i < MAX_PORTS; i++) + state->ports[i].pvid = 0; +} + +static int ip17xx_set_enable_vlan(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + struct ip17xx_state *state = get_state(dev); + int enable; + + enable = val->value.i; + if (state->vlan_enabled == enable) { + // Do not change any state. + return 0; + } + state->vlan_enabled = enable; + + // Otherwise, if we are switching state, set fields to a known default. + ip17xx_reset_vlan_config(state); + + return state->regs->set_vlan_mode(state); +} + +static int ip17xx_get_ports(struct switch_dev *dev, struct switch_val *val) +{ + struct ip17xx_state *state = get_state(dev); + int b; + int ind; + unsigned int ports; + + if (val->port_vlan >= dev->vlans || val->port_vlan < 0) + return -EINVAL; + + ports = state->vlans[val->port_vlan].ports; + b = 0; + ind = 0; + while (b < MAX_PORTS) { + if (ports&1) { + int istagged = ((state->add_tag >> b) & 1); + val->value.ports[ind].id = b; + val->value.ports[ind].flags = (istagged << SWITCH_PORT_FLAG_TAGGED); + ind++; + } + b++; + ports >>= 1; + } + val->len = ind; + + return 0; +} + +static int ip17xx_set_ports(struct switch_dev *dev, struct switch_val *val) +{ + struct ip17xx_state *state = get_state(dev); + int i; + + if (val->port_vlan >= dev->vlans || val->port_vlan < 0) + return -EINVAL; + + state->vlans[val->port_vlan].ports = 0; + for (i = 0; i < val->len; i++) { + unsigned int bitmask = (1<value.ports[i].id); + state->vlans[val->port_vlan].ports |= bitmask; + if (val->value.ports[i].flags & (1<add_tag |= bitmask; + state->remove_tag &= (~bitmask); + } else { + state->add_tag &= (~bitmask); + state->remove_tag |= bitmask; + } + } + + return state->regs->update_state(state); +} + +static int ip17xx_apply(struct switch_dev *dev) +{ + struct ip17xx_state *state = get_state(dev); + + if (REG_SUPP(state->regs->MII_REGISTER_EN)) { + int val = getPhy(state, state->regs->MII_REGISTER_EN); + if (val < 0) { + return val; + } + val |= (1<regs->MII_REGISTER_EN_BIT); + return setPhy(state, state->regs->MII_REGISTER_EN, val); + } + return 0; +} + +static int ip17xx_reset(struct switch_dev *dev) +{ + struct ip17xx_state *state = get_state(dev); + int i, err; + + if (REG_SUPP(state->regs->RESET_REG)) { + err = setPhy(state, state->regs->RESET_REG, state->regs->RESET_VAL); + if (err < 0) + return err; + err = getPhy(state, state->regs->RESET_REG); + + /* + * Data sheet specifies reset period to be 2 msec. + * (I don't see any mention of the 2ms delay in the IP178C spec, only + * in IP175C, but it can't hurt.) + */ + mdelay(2); + } + + /* reset switch ports */ + for (i = 0; i < state->regs->NUM_PORTS-1; i++) { + err = ip_phy_write(state, i, MII_BMCR, BMCR_RESET); + if (err < 0) + return err; + } + + state->router_mode = 0; + state->vlan_enabled = 0; + ip17xx_reset_vlan_config(state); + + return state->regs->reset(state); +} + +static int ip17xx_get_tagged(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + struct ip17xx_state *state = get_state(dev); + + if (state->add_tag & (1<port_vlan)) { + if (state->remove_tag & (1<port_vlan)) + val->value.i = 3; // shouldn't ever happen. + else + val->value.i = 1; + } else { + if (state->remove_tag & (1<port_vlan)) + val->value.i = 0; + else + val->value.i = 2; + } + return 0; +} + +static int ip17xx_set_tagged(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + struct ip17xx_state *state = get_state(dev); + + state->add_tag &= ~(1<port_vlan); + state->remove_tag &= ~(1<port_vlan); + + if (val->value.i == 0) + state->remove_tag |= (1<port_vlan); + if (val->value.i == 1) + state->add_tag |= (1<port_vlan); + + return state->regs->update_state(state); +} + +/** Get the current phy address */ +static int ip17xx_get_phy(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + struct ip17xx_state *state = get_state(dev); + + val->value.i = state->proc_mii.p; + return 0; +} + +/** Set a new phy address for low level access to registers */ +static int ip17xx_set_phy(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + struct ip17xx_state *state = get_state(dev); + int new_reg = val->value.i; + + if (new_reg < 0 || new_reg > 31) + state->proc_mii.p = (u16)-1; + else + state->proc_mii.p = (u16)new_reg; + return 0; +} + +/** Get the current register number */ +static int ip17xx_get_reg(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + struct ip17xx_state *state = get_state(dev); + + val->value.i = state->proc_mii.m; + return 0; +} + +/** Set a new register address for low level access to registers */ +static int ip17xx_set_reg(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + struct ip17xx_state *state = get_state(dev); + int new_reg = val->value.i; + + if (new_reg < 0 || new_reg > 31) + state->proc_mii.m = (u16)-1; + else + state->proc_mii.m = (u16)new_reg; + return 0; +} + +/** Get the register content of state->proc_mii */ +static int ip17xx_get_val(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + struct ip17xx_state *state = get_state(dev); + int retval = -EINVAL; + if (REG_SUPP(state->proc_mii)) + retval = getPhy(state, state->proc_mii); + + if (retval < 0) { + return retval; + } else { + val->value.i = retval; + return 0; + } +} + +/** Write a value to the register defined by phy/reg above */ +static int ip17xx_set_val(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + struct ip17xx_state *state = get_state(dev); + int myval, err = -EINVAL; + + myval = val->value.i; + if (myval <= 0xffff && myval >= 0 && REG_SUPP(state->proc_mii)) { + err = setPhy(state, state->proc_mii, (u16)myval); + } + return err; +} + +static int ip17xx_read_name(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + struct ip17xx_state *state = get_state(dev); + val->value.s = state->regs->NAME; // Just a const pointer, won't be freed by swconfig. + return 0; +} + +static int ip17xx_get_tag(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + struct ip17xx_state *state = get_state(dev); + int vlan = val->port_vlan; + + if (vlan < 0 || vlan >= MAX_VLANS) + return -EINVAL; + + val->value.i = state->vlans[vlan].tag; + return 0; +} + +static int ip17xx_set_tag(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + struct ip17xx_state *state = get_state(dev); + int vlan = val->port_vlan; + int tag = val->value.i; + + if (vlan < 0 || vlan >= MAX_VLANS) + return -EINVAL; + + if (tag < 0 || tag > 4095) + return -EINVAL; + + state->vlans[vlan].tag = tag; + return state->regs->update_state(state); +} + +static int ip17xx_set_port_speed(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + struct ip17xx_state *state = get_state(dev); + int nr = val->port_vlan; + int ctrl; + int autoneg; + int speed; + if (val->value.i == 100) { + speed = 1; + autoneg = 0; + } else if (val->value.i == 10) { + speed = 0; + autoneg = 0; + } else { + autoneg = 1; + speed = 1; + } + + /* Can't set speed for cpu port */ + if (nr == state->regs->CPU_PORT) + return -EINVAL; + + if (nr >= dev->ports || nr < 0) + return -EINVAL; + + ctrl = ip_phy_read(state, nr, 0); + if (ctrl < 0) + return -EIO; + + ctrl &= (~(1<<12)); + ctrl &= (~(1<<13)); + ctrl |= (autoneg<<12); + ctrl |= (speed<<13); + + return ip_phy_write(state, nr, 0, ctrl); +} + +static int ip17xx_get_port_speed(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + struct ip17xx_state *state = get_state(dev); + int nr = val->port_vlan; + int speed, status; + + if (nr == state->regs->CPU_PORT) { + val->value.i = 100; + return 0; + } + + if (nr >= dev->ports || nr < 0) + return -EINVAL; + + status = ip_phy_read(state, nr, 1); + speed = ip_phy_read(state, nr, 18); + if (status < 0 || speed < 0) + return -EIO; + + if (status & 4) + val->value.i = ((speed & (1<<11)) ? 100 : 10); + else + val->value.i = 0; + + return 0; +} + +static int ip17xx_get_port_status(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + struct ip17xx_state *state = get_state(dev); + int ctrl, speed, status; + int nr = val->port_vlan; + int len; + char *buf = state->buf; // fixed-length at 80. + + if (nr == state->regs->CPU_PORT) { + sprintf(buf, "up, 100 Mbps, cpu port"); + val->value.s = buf; + return 0; + } + + if (nr >= dev->ports || nr < 0) + return -EINVAL; + + ctrl = ip_phy_read(state, nr, 0); + status = ip_phy_read(state, nr, 1); + speed = ip_phy_read(state, nr, 18); + if (ctrl < 0 || status < 0 || speed < 0) + return -EIO; + + if (status & 4) + len = sprintf(buf, "up, %d Mbps, %s duplex", + ((speed & (1<<11)) ? 100 : 10), + ((speed & (1<<10)) ? "full" : "half")); + else + len = sprintf(buf, "down"); + + if (ctrl & (1<<12)) { + len += sprintf(buf+len, ", auto-negotiate"); + if (!(status & (1<<5))) + len += sprintf(buf+len, " (in progress)"); + } else { + len += sprintf(buf+len, ", fixed speed (%d)", + ((ctrl & (1<<13)) ? 100 : 10)); + } + + buf[len] = '\0'; + val->value.s = buf; + return 0; +} + +static int ip17xx_get_pvid(struct switch_dev *dev, int port, int *val) +{ + struct ip17xx_state *state = get_state(dev); + + *val = state->ports[port].pvid; + return 0; +} + +static int ip17xx_set_pvid(struct switch_dev *dev, int port, int val) +{ + struct ip17xx_state *state = get_state(dev); + + if (val < 0 || val >= MAX_VLANS) + return -EINVAL; + + state->ports[port].pvid = val; + return state->regs->update_state(state); +} + + +enum Ports { + IP17XX_PORT_STATUS, + IP17XX_PORT_LINK, + IP17XX_PORT_TAGGED, + IP17XX_PORT_PVID, +}; + +enum Globals { + IP17XX_ENABLE_VLAN, + IP17XX_GET_NAME, + IP17XX_REGISTER_PHY, + IP17XX_REGISTER_MII, + IP17XX_REGISTER_VALUE, + IP17XX_REGISTER_ERRNO, +}; + +enum Vlans { + IP17XX_VLAN_TAG, +}; + +static const struct switch_attr ip17xx_global[] = { + [IP17XX_ENABLE_VLAN] = { + .id = IP17XX_ENABLE_VLAN, + .type = SWITCH_TYPE_INT, + .name = "enable_vlan", + .description = "Flag to enable or disable VLANs and tagging", + .get = ip17xx_get_enable_vlan, + .set = ip17xx_set_enable_vlan, + }, + [IP17XX_GET_NAME] = { + .id = IP17XX_GET_NAME, + .type = SWITCH_TYPE_STRING, + .description = "Returns the type of IC+ chip.", + .name = "name", + .get = ip17xx_read_name, + .set = NULL, + }, + /* jal: added for low level debugging etc. */ + [IP17XX_REGISTER_PHY] = { + .id = IP17XX_REGISTER_PHY, + .type = SWITCH_TYPE_INT, + .description = "Direct register access: set PHY (0-4, or 29,30,31)", + .name = "phy", + .get = ip17xx_get_phy, + .set = ip17xx_set_phy, + }, + [IP17XX_REGISTER_MII] = { + .id = IP17XX_REGISTER_MII, + .type = SWITCH_TYPE_INT, + .description = "Direct register access: set MII register number (0-31)", + .name = "reg", + .get = ip17xx_get_reg, + .set = ip17xx_set_reg, + }, + [IP17XX_REGISTER_VALUE] = { + .id = IP17XX_REGISTER_VALUE, + .type = SWITCH_TYPE_INT, + .description = "Direct register access: read/write to register (0-65535)", + .name = "val", + .get = ip17xx_get_val, + .set = ip17xx_set_val, + }, +}; + +static const struct switch_attr ip17xx_vlan[] = { + [IP17XX_VLAN_TAG] = { + .id = IP17XX_VLAN_TAG, + .type = SWITCH_TYPE_INT, + .description = "VLAN ID (0-4095) [IP175D only]", + .name = "vid", + .get = ip17xx_get_tag, + .set = ip17xx_set_tag, + } +}; + +static const struct switch_attr ip17xx_port[] = { + [IP17XX_PORT_STATUS] = { + .id = IP17XX_PORT_STATUS, + .type = SWITCH_TYPE_STRING, + .description = "Returns Detailed port status", + .name = "status", + .get = ip17xx_get_port_status, + .set = NULL, + }, + [IP17XX_PORT_LINK] = { + .id = IP17XX_PORT_LINK, + .type = SWITCH_TYPE_INT, + .description = "Link speed. Can write 0 for auto-negotiate, or 10 or 100", + .name = "link", + .get = ip17xx_get_port_speed, + .set = ip17xx_set_port_speed, + }, + [IP17XX_PORT_TAGGED] = { + .id = IP17XX_PORT_LINK, + .type = SWITCH_TYPE_INT, + .description = "0 = untag, 1 = add tags, 2 = do not alter (This value is reset if vlans are altered)", + .name = "tagged", + .get = ip17xx_get_tagged, + .set = ip17xx_set_tagged, + }, +}; + +static const struct switch_dev_ops ip17xx_ops = { + .attr_global = { + .attr = ip17xx_global, + .n_attr = ARRAY_SIZE(ip17xx_global), + }, + .attr_port = { + .attr = ip17xx_port, + .n_attr = ARRAY_SIZE(ip17xx_port), + }, + .attr_vlan = { + .attr = ip17xx_vlan, + .n_attr = ARRAY_SIZE(ip17xx_vlan), + }, + + .get_port_pvid = ip17xx_get_pvid, + .set_port_pvid = ip17xx_set_pvid, + .get_vlan_ports = ip17xx_get_ports, + .set_vlan_ports = ip17xx_set_ports, + .apply_config = ip17xx_apply, + .reset_switch = ip17xx_reset, +}; + +static int ip17xx_probe(struct phy_device *pdev) +{ + struct ip17xx_state *state; + struct switch_dev *dev; + int err; + + /* We only attach to PHY 0, but use all available PHYs */ + if (pdev->addr != 0) + return -ENODEV; + + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (!state) + return -ENOMEM; + + dev = &state->dev; + + pdev->priv = state; + state->mii_bus = pdev->bus; + + err = get_model(state); + if (err < 0) + goto error; + + dev->vlans = MAX_VLANS; + dev->cpu_port = state->regs->CPU_PORT; + dev->ports = state->regs->NUM_PORTS; + dev->name = state->regs->NAME; + dev->ops = &ip17xx_ops; + + pr_info("IP17xx: Found %s at %s\n", dev->name, dev_name(&pdev->dev)); + return 0; + +error: + kfree(state); + return err; +} + +static int ip17xx_config_init(struct phy_device *pdev) +{ + struct ip17xx_state *state = pdev->priv; + struct net_device *dev = pdev->attached_dev; + int err; + + err = register_switch(&state->dev, dev); + if (err < 0) + return err; + + state->registered = true; + ip17xx_reset(&state->dev); + return 0; +} + +static void ip17xx_remove(struct phy_device *pdev) +{ + struct ip17xx_state *state = pdev->priv; + + if (state->registered) + unregister_switch(&state->dev); + kfree(state); +} + +static int ip17xx_config_aneg(struct phy_device *pdev) +{ + return 0; +} + +static int ip17xx_aneg_done(struct phy_device *pdev) +{ + return BMSR_ANEGCOMPLETE; +} + +static int ip17xx_update_link(struct phy_device *pdev) +{ + pdev->link = 1; + return 0; +} + +static int ip17xx_read_status(struct phy_device *pdev) +{ + pdev->speed = SPEED_100; + pdev->duplex = DUPLEX_FULL; + pdev->pause = pdev->asym_pause = 0; + pdev->link = 1; + + return 0; +} + +static struct phy_driver ip17xx_driver = { + .name = "IC+ IP17xx", + .phy_id = 0x02430c00, + .phy_id_mask = 0x0ffffc00, + .features = PHY_BASIC_FEATURES, + .probe = ip17xx_probe, + .remove = ip17xx_remove, + .config_init = ip17xx_config_init, + .config_aneg = ip17xx_config_aneg, + .aneg_done = ip17xx_aneg_done, + .update_link = ip17xx_update_link, + .read_status = ip17xx_read_status, + .driver = { .owner = THIS_MODULE }, +}; + +static struct phy_driver ip175a_driver = { + .name = "IC+ IP175A", + .phy_id = 0x02430c50, + .phy_id_mask = 0x0ffffff0, + .features = PHY_BASIC_FEATURES, + .probe = ip17xx_probe, + .remove = ip17xx_remove, + .config_init = ip17xx_config_init, + .config_aneg = ip17xx_config_aneg, + .aneg_done = ip17xx_aneg_done, + .update_link = ip17xx_update_link, + .read_status = ip17xx_read_status, + .driver = { .owner = THIS_MODULE }, +}; + + +int __init ip17xx_init(void) +{ + int ret; + + ret = phy_driver_register(&ip175a_driver); + if (ret < 0) + return ret; + + return phy_driver_register(&ip17xx_driver); +} + +void __exit ip17xx_exit(void) +{ + phy_driver_unregister(&ip17xx_driver); + phy_driver_unregister(&ip175a_driver); +} + +MODULE_AUTHOR("Patrick Horn "); +MODULE_AUTHOR("Felix Fietkau "); +MODULE_AUTHOR("Martin Mares "); +MODULE_LICENSE("GPL"); + +module_init(ip17xx_init); +module_exit(ip17xx_exit); diff --git a/target/linux/generic/files/drivers/net/phy/mvsw61xx.c b/target/linux/generic/files/drivers/net/phy/mvsw61xx.c new file mode 100644 index 0000000..f879056 --- /dev/null +++ b/target/linux/generic/files/drivers/net/phy/mvsw61xx.c @@ -0,0 +1,854 @@ +/* + * Marvell 88E61xx switch driver + * + * Copyright (c) 2014 Claudio Leite + * Copyright (c) 2014 Nikita Nazarenko + * + * Based on code (c) 2008 Felix Fietkau + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License v2 as published by the + * Free Software Foundation + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mvsw61xx.h" + +MODULE_DESCRIPTION("Marvell 88E61xx Switch driver"); +MODULE_AUTHOR("Claudio Leite "); +MODULE_AUTHOR("Nikita Nazarenko "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:mvsw61xx"); + +/* + * Register access is done through direct or indirect addressing, + * depending on how the switch is physically connected. + * + * Direct addressing: all port and global registers directly + * accessible via an address/register pair + * + * Indirect addressing: switch is mapped at a single address, + * port and global registers accessible via a single command/data + * register pair + */ + +static int +mvsw61xx_wait_mask_raw(struct mii_bus *bus, int addr, + int reg, u16 mask, u16 val) +{ + int i = 100; + u16 r; + + do { + r = bus->read(bus, addr, reg); + if ((r & mask) == val) + return 0; + } while (--i > 0); + + return -ETIMEDOUT; +} + +static u16 +r16(struct mii_bus *bus, bool indirect, int base_addr, int addr, int reg) +{ + u16 ind_addr; + + if (!indirect) + return bus->read(bus, addr, reg); + + /* Indirect read: First, make sure switch is free */ + mvsw61xx_wait_mask_raw(bus, base_addr, MV_INDIRECT_REG_CMD, + MV_INDIRECT_INPROGRESS, 0); + + /* Load address and request read */ + ind_addr = MV_INDIRECT_READ | (addr << MV_INDIRECT_ADDR_S) | reg; + bus->write(bus, base_addr, MV_INDIRECT_REG_CMD, + ind_addr); + + /* Wait until it's ready */ + mvsw61xx_wait_mask_raw(bus, base_addr, MV_INDIRECT_REG_CMD, + MV_INDIRECT_INPROGRESS, 0); + + /* Read the requested data */ + return bus->read(bus, base_addr, MV_INDIRECT_REG_DATA); +} + +static void +w16(struct mii_bus *bus, bool indirect, int base_addr, int addr, + int reg, u16 val) +{ + u16 ind_addr; + + if (!indirect) { + bus->write(bus, addr, reg, val); + return; + } + + /* Indirect write: First, make sure switch is free */ + mvsw61xx_wait_mask_raw(bus, base_addr, MV_INDIRECT_REG_CMD, + MV_INDIRECT_INPROGRESS, 0); + + /* Load the data to be written */ + bus->write(bus, base_addr, MV_INDIRECT_REG_DATA, val); + + /* Wait again for switch to be free */ + mvsw61xx_wait_mask_raw(bus, base_addr, MV_INDIRECT_REG_CMD, + MV_INDIRECT_INPROGRESS, 0); + + /* Load address, and issue write command */ + ind_addr = MV_INDIRECT_WRITE | (addr << MV_INDIRECT_ADDR_S) | reg; + bus->write(bus, base_addr, MV_INDIRECT_REG_CMD, + ind_addr); +} + +/* swconfig support */ + +static inline u16 +sr16(struct switch_dev *dev, int addr, int reg) +{ + struct mvsw61xx_state *state = get_state(dev); + + return r16(state->bus, state->is_indirect, state->base_addr, addr, reg); +} + +static inline void +sw16(struct switch_dev *dev, int addr, int reg, u16 val) +{ + struct mvsw61xx_state *state = get_state(dev); + + w16(state->bus, state->is_indirect, state->base_addr, addr, reg, val); +} + +static int +mvsw61xx_wait_mask_s(struct switch_dev *dev, int addr, + int reg, u16 mask, u16 val) +{ + int i = 100; + u16 r; + + do { + r = sr16(dev, addr, reg) & mask; + if (r == val) + return 0; + } while (--i > 0); + + return -ETIMEDOUT; +} + +static int +mvsw61xx_get_port_mask(struct switch_dev *dev, + const struct switch_attr *attr, struct switch_val *val) +{ + struct mvsw61xx_state *state = get_state(dev); + char *buf = state->buf; + int port, len, i; + u16 reg; + + port = val->port_vlan; + reg = sr16(dev, MV_PORTREG(VLANMAP, port)) & MV_PORTS_MASK; + + len = sprintf(buf, "0x%04x: ", reg); + + for (i = 0; i < MV_PORTS; i++) { + if (reg & (1 << i)) + len += sprintf(buf + len, "%d ", i); + else if (i == port) + len += sprintf(buf + len, "(%d) ", i); + } + + val->value.s = buf; + + return 0; +} + +static int +mvsw61xx_get_port_qmode(struct switch_dev *dev, + const struct switch_attr *attr, struct switch_val *val) +{ + struct mvsw61xx_state *state = get_state(dev); + + val->value.i = state->ports[val->port_vlan].qmode; + + return 0; +} + +static int +mvsw61xx_set_port_qmode(struct switch_dev *dev, + const struct switch_attr *attr, struct switch_val *val) +{ + struct mvsw61xx_state *state = get_state(dev); + + state->ports[val->port_vlan].qmode = val->value.i; + + return 0; +} + +static int +mvsw61xx_get_port_pvid(struct switch_dev *dev, int port, int *val) +{ + struct mvsw61xx_state *state = get_state(dev); + + *val = state->ports[port].pvid; + + return 0; +} + +static int +mvsw61xx_set_port_pvid(struct switch_dev *dev, int port, int val) +{ + struct mvsw61xx_state *state = get_state(dev); + + if (val < 0 || val >= MV_VLANS) + return -EINVAL; + + state->ports[port].pvid = (u16)val; + + return 0; +} + +static int +mvsw61xx_get_port_link(struct switch_dev *dev, int port, + struct switch_port_link *link) +{ + u16 status, speed; + + status = sr16(dev, MV_PORTREG(STATUS, port)); + + link->link = status & MV_PORT_STATUS_LINK; + if (!link->link) + return 0; + + link->duplex = status & MV_PORT_STATUS_FDX; + + speed = (status & MV_PORT_STATUS_SPEED_MASK) >> + MV_PORT_STATUS_SPEED_SHIFT; + + switch (speed) { + case MV_PORT_STATUS_SPEED_10: + link->speed = SWITCH_PORT_SPEED_10; + break; + case MV_PORT_STATUS_SPEED_100: + link->speed = SWITCH_PORT_SPEED_100; + break; + case MV_PORT_STATUS_SPEED_1000: + link->speed = SWITCH_PORT_SPEED_1000; + break; + } + + return 0; +} + +static int mvsw61xx_get_vlan_ports(struct switch_dev *dev, + struct switch_val *val) +{ + struct mvsw61xx_state *state = get_state(dev); + int i, j, mode, vno; + + vno = val->port_vlan; + + if (vno <= 0 || vno >= dev->vlans) + return -EINVAL; + + for (i = 0, j = 0; i < dev->ports; i++) { + if (state->vlans[vno].mask & (1 << i)) { + val->value.ports[j].id = i; + + mode = (state->vlans[vno].port_mode >> (i * 4)) & 0xf; + if (mode == MV_VTUCTL_EGRESS_TAGGED) + val->value.ports[j].flags = + (1 << SWITCH_PORT_FLAG_TAGGED); + else + val->value.ports[j].flags = 0; + + j++; + } + } + + val->len = j; + + return 0; +} + +static int mvsw61xx_set_vlan_ports(struct switch_dev *dev, + struct switch_val *val) +{ + struct mvsw61xx_state *state = get_state(dev); + int i, mode, pno, vno; + + vno = val->port_vlan; + + if (vno <= 0 || vno >= dev->vlans) + return -EINVAL; + + state->vlans[vno].mask = 0; + state->vlans[vno].port_mode = 0; + state->vlans[vno].port_sstate = 0; + + if(state->vlans[vno].vid == 0) + state->vlans[vno].vid = vno; + + for (i = 0; i < val->len; i++) { + pno = val->value.ports[i].id; + + state->vlans[vno].mask |= (1 << pno); + if (val->value.ports[i].flags & + (1 << SWITCH_PORT_FLAG_TAGGED)) + mode = MV_VTUCTL_EGRESS_TAGGED; + else + mode = MV_VTUCTL_EGRESS_UNTAGGED; + + state->vlans[vno].port_mode |= mode << (pno * 4); + state->vlans[vno].port_sstate |= + MV_STUCTL_STATE_FORWARDING << (pno * 4 + 2); + } + + /* + * DISCARD is nonzero, so it must be explicitly + * set on ports not in the VLAN. + */ + for (i = 0; i < dev->ports; i++) + if (!(state->vlans[vno].mask & (1 << i))) + state->vlans[vno].port_mode |= + MV_VTUCTL_DISCARD << (i * 4); + + return 0; +} + +static int mvsw61xx_get_vlan_port_based(struct switch_dev *dev, + const struct switch_attr *attr, struct switch_val *val) +{ + struct mvsw61xx_state *state = get_state(dev); + int vno = val->port_vlan; + + if (vno <= 0 || vno >= dev->vlans) + return -EINVAL; + + if (state->vlans[vno].port_based) + val->value.i = 1; + else + val->value.i = 0; + + return 0; +} + +static int mvsw61xx_set_vlan_port_based(struct switch_dev *dev, + const struct switch_attr *attr, struct switch_val *val) +{ + struct mvsw61xx_state *state = get_state(dev); + int vno = val->port_vlan; + + if (vno <= 0 || vno >= dev->vlans) + return -EINVAL; + + if (val->value.i == 1) + state->vlans[vno].port_based = true; + else + state->vlans[vno].port_based = false; + + return 0; +} + +static int mvsw61xx_get_vid(struct switch_dev *dev, + const struct switch_attr *attr, struct switch_val *val) +{ + struct mvsw61xx_state *state = get_state(dev); + int vno = val->port_vlan; + + if (vno <= 0 || vno >= dev->vlans) + return -EINVAL; + + val->value.i = state->vlans[vno].vid; + + return 0; +} + +static int mvsw61xx_set_vid(struct switch_dev *dev, + const struct switch_attr *attr, struct switch_val *val) +{ + struct mvsw61xx_state *state = get_state(dev); + int vno = val->port_vlan; + + if (vno <= 0 || vno >= dev->vlans) + return -EINVAL; + + state->vlans[vno].vid = val->value.i; + + return 0; +} + +static int mvsw61xx_get_enable_vlan(struct switch_dev *dev, + const struct switch_attr *attr, struct switch_val *val) +{ + struct mvsw61xx_state *state = get_state(dev); + + val->value.i = state->vlan_enabled; + + return 0; +} + +static int mvsw61xx_set_enable_vlan(struct switch_dev *dev, + const struct switch_attr *attr, struct switch_val *val) +{ + struct mvsw61xx_state *state = get_state(dev); + + state->vlan_enabled = val->value.i; + + return 0; +} + +static int mvsw61xx_vtu_program(struct switch_dev *dev) +{ + struct mvsw61xx_state *state = get_state(dev); + u16 v1, v2, s1, s2; + int i; + + /* Flush */ + mvsw61xx_wait_mask_s(dev, MV_GLOBALREG(VTU_OP), + MV_VTUOP_INPROGRESS, 0); + sw16(dev, MV_GLOBALREG(VTU_OP), + MV_VTUOP_INPROGRESS | MV_VTUOP_PURGE); + + /* Write VLAN table */ + for (i = 1; i < dev->vlans; i++) { + if (state->vlans[i].mask == 0 || + state->vlans[i].vid == 0 || + state->vlans[i].port_based == true) + continue; + + mvsw61xx_wait_mask_s(dev, MV_GLOBALREG(VTU_OP), + MV_VTUOP_INPROGRESS, 0); + + /* Write per-VLAN port state into STU */ + s1 = (u16) (state->vlans[i].port_sstate & 0xffff); + s2 = (u16) ((state->vlans[i].port_sstate >> 16) & 0xffff); + + sw16(dev, MV_GLOBALREG(VTU_VID), MV_VTU_VID_VALID); + sw16(dev, MV_GLOBALREG(VTU_SID), i); + sw16(dev, MV_GLOBALREG(VTU_DATA1), s1); + sw16(dev, MV_GLOBALREG(VTU_DATA2), s2); + sw16(dev, MV_GLOBALREG(VTU_DATA3), 0); + + sw16(dev, MV_GLOBALREG(VTU_OP), + MV_VTUOP_INPROGRESS | MV_VTUOP_STULOAD); + mvsw61xx_wait_mask_s(dev, MV_GLOBALREG(VTU_OP), + MV_VTUOP_INPROGRESS, 0); + + /* Write VLAN information into VTU */ + v1 = (u16) (state->vlans[i].port_mode & 0xffff); + v2 = (u16) ((state->vlans[i].port_mode >> 16) & 0xffff); + + sw16(dev, MV_GLOBALREG(VTU_VID), + MV_VTU_VID_VALID | state->vlans[i].vid); + sw16(dev, MV_GLOBALREG(VTU_SID), i); + sw16(dev, MV_GLOBALREG(VTU_FID), i); + sw16(dev, MV_GLOBALREG(VTU_DATA1), v1); + sw16(dev, MV_GLOBALREG(VTU_DATA2), v2); + sw16(dev, MV_GLOBALREG(VTU_DATA3), 0); + + sw16(dev, MV_GLOBALREG(VTU_OP), + MV_VTUOP_INPROGRESS | MV_VTUOP_LOAD); + mvsw61xx_wait_mask_s(dev, MV_GLOBALREG(VTU_OP), + MV_VTUOP_INPROGRESS, 0); + } + + return 0; +} + +static void mvsw61xx_vlan_port_config(struct switch_dev *dev, int vno) +{ + struct mvsw61xx_state *state = get_state(dev); + int i, mode; + + for (i = 0; i < dev->ports; i++) { + if (!(state->vlans[vno].mask & (1 << i))) + continue; + + mode = (state->vlans[vno].port_mode >> (i * 4)) & 0xf; + + if(mode != MV_VTUCTL_EGRESS_TAGGED) + state->ports[i].pvid = state->vlans[vno].vid; + + if (state->vlans[vno].port_based) { + state->ports[i].mask |= state->vlans[vno].mask; + state->ports[i].fdb = vno; + } + else + state->ports[i].qmode = MV_8021Q_MODE_SECURE; + } +} + +static int mvsw61xx_update_state(struct switch_dev *dev) +{ + struct mvsw61xx_state *state = get_state(dev); + int i; + u16 reg; + + if (!state->registered) + return -EINVAL; + + /* + * Set 802.1q-only mode if vlan_enabled is true. + * + * Without this, even if 802.1q is enabled for + * a port/VLAN, it still depends on the port-based + * VLAN mask being set. + * + * With this setting, port-based VLANs are still + * functional, provided the VID is not in the VTU. + */ + reg = sr16(dev, MV_GLOBAL2REG(SDET_POLARITY)); + + if (state->vlan_enabled) + reg |= MV_8021Q_VLAN_ONLY; + else + reg &= ~MV_8021Q_VLAN_ONLY; + + sw16(dev, MV_GLOBAL2REG(SDET_POLARITY), reg); + + /* + * Set port-based VLAN masks on each port + * based only on VLAN definitions known to + * the driver (i.e. in state). + * + * This means any pre-existing port mapping is + * wiped out once our driver is initialized. + */ + for (i = 0; i < dev->ports; i++) { + state->ports[i].mask = 0; + state->ports[i].qmode = MV_8021Q_MODE_DISABLE; + } + + for (i = 0; i < dev->vlans; i++) + mvsw61xx_vlan_port_config(dev, i); + + for (i = 0; i < dev->ports; i++) { + reg = sr16(dev, MV_PORTREG(VLANID, i)) & ~MV_PVID_MASK; + reg |= state->ports[i].pvid; + sw16(dev, MV_PORTREG(VLANID, i), reg); + + state->ports[i].mask &= ~(1 << i); + + /* set default forwarding DB number and port mask */ + reg = sr16(dev, MV_PORTREG(CONTROL1, i)) & ~MV_FDB_HI_MASK; + reg |= (state->ports[i].fdb >> MV_FDB_HI_SHIFT) & + MV_FDB_HI_MASK; + sw16(dev, MV_PORTREG(CONTROL1, i), reg); + + reg = ((state->ports[i].fdb & 0xf) << MV_FDB_LO_SHIFT) | + state->ports[i].mask; + sw16(dev, MV_PORTREG(VLANMAP, i), reg); + + reg = sr16(dev, MV_PORTREG(CONTROL2, i)) & + ~MV_8021Q_MODE_MASK; + reg |= state->ports[i].qmode << MV_8021Q_MODE_SHIFT; + sw16(dev, MV_PORTREG(CONTROL2, i), reg); + } + + mvsw61xx_vtu_program(dev); + + return 0; +} + +static int mvsw61xx_apply(struct switch_dev *dev) +{ + return mvsw61xx_update_state(dev); +} + +static int mvsw61xx_reset(struct switch_dev *dev) +{ + struct mvsw61xx_state *state = get_state(dev); + int i; + u16 reg; + + /* Disable all ports before reset */ + for (i = 0; i < dev->ports; i++) { + reg = sr16(dev, MV_PORTREG(CONTROL, i)) & + ~MV_PORTCTRL_FORWARDING; + sw16(dev, MV_PORTREG(CONTROL, i), reg); + } + + reg = sr16(dev, MV_GLOBALREG(CONTROL)) | MV_CONTROL_RESET; + + sw16(dev, MV_GLOBALREG(CONTROL), reg); + if (mvsw61xx_wait_mask_s(dev, MV_GLOBALREG(CONTROL), + MV_CONTROL_RESET, 0) < 0) + return -ETIMEDOUT; + + for (i = 0; i < dev->ports; i++) { + state->ports[i].fdb = 0; + state->ports[i].qmode = 0; + state->ports[i].mask = 0; + state->ports[i].pvid = 0; + + /* Force flow control off */ + reg = sr16(dev, MV_PORTREG(PHYCTL, i)) & ~MV_PHYCTL_FC_MASK; + reg |= MV_PHYCTL_FC_DISABLE; + sw16(dev, MV_PORTREG(PHYCTL, i), reg); + + /* Set port association vector */ + sw16(dev, MV_PORTREG(ASSOC, i), (1 << i)); + } + + for (i = 0; i < dev->vlans; i++) { + state->vlans[i].port_based = false; + state->vlans[i].mask = 0; + state->vlans[i].vid = 0; + state->vlans[i].port_mode = 0; + state->vlans[i].port_sstate = 0; + } + + state->vlan_enabled = 0; + + mvsw61xx_update_state(dev); + + /* Re-enable ports */ + for (i = 0; i < dev->ports; i++) { + reg = sr16(dev, MV_PORTREG(CONTROL, i)) | + MV_PORTCTRL_FORWARDING; + sw16(dev, MV_PORTREG(CONTROL, i), reg); + } + + return 0; +} + +enum { + MVSW61XX_ENABLE_VLAN, +}; + +enum { + MVSW61XX_VLAN_PORT_BASED, + MVSW61XX_VLAN_ID, +}; + +enum { + MVSW61XX_PORT_MASK, + MVSW61XX_PORT_QMODE, +}; + +static const struct switch_attr mvsw61xx_global[] = { + [MVSW61XX_ENABLE_VLAN] = { + .id = MVSW61XX_ENABLE_VLAN, + .type = SWITCH_TYPE_INT, + .name = "enable_vlan", + .description = "Enable 802.1q VLAN support", + .get = mvsw61xx_get_enable_vlan, + .set = mvsw61xx_set_enable_vlan, + }, +}; + +static const struct switch_attr mvsw61xx_vlan[] = { + [MVSW61XX_VLAN_PORT_BASED] = { + .id = MVSW61XX_VLAN_PORT_BASED, + .type = SWITCH_TYPE_INT, + .name = "port_based", + .description = "Use port-based (non-802.1q) VLAN only", + .get = mvsw61xx_get_vlan_port_based, + .set = mvsw61xx_set_vlan_port_based, + }, + [MVSW61XX_VLAN_ID] = { + .id = MVSW61XX_VLAN_ID, + .type = SWITCH_TYPE_INT, + .name = "vid", + .description = "Get/set VLAN ID", + .get = mvsw61xx_get_vid, + .set = mvsw61xx_set_vid, + }, +}; + +static const struct switch_attr mvsw61xx_port[] = { + [MVSW61XX_PORT_MASK] = { + .id = MVSW61XX_PORT_MASK, + .type = SWITCH_TYPE_STRING, + .description = "Port-based VLAN mask", + .name = "mask", + .get = mvsw61xx_get_port_mask, + .set = NULL, + }, + [MVSW61XX_PORT_QMODE] = { + .id = MVSW61XX_PORT_QMODE, + .type = SWITCH_TYPE_INT, + .description = "802.1q mode: 0=off/1=fallback/2=check/3=secure", + .name = "qmode", + .get = mvsw61xx_get_port_qmode, + .set = mvsw61xx_set_port_qmode, + }, +}; + +static const struct switch_dev_ops mvsw61xx_ops = { + .attr_global = { + .attr = mvsw61xx_global, + .n_attr = ARRAY_SIZE(mvsw61xx_global), + }, + .attr_vlan = { + .attr = mvsw61xx_vlan, + .n_attr = ARRAY_SIZE(mvsw61xx_vlan), + }, + .attr_port = { + .attr = mvsw61xx_port, + .n_attr = ARRAY_SIZE(mvsw61xx_port), + }, + .get_port_link = mvsw61xx_get_port_link, + .get_port_pvid = mvsw61xx_get_port_pvid, + .set_port_pvid = mvsw61xx_set_port_pvid, + .get_vlan_ports = mvsw61xx_get_vlan_ports, + .set_vlan_ports = mvsw61xx_set_vlan_ports, + .apply_config = mvsw61xx_apply, + .reset_switch = mvsw61xx_reset, +}; + +/* end swconfig stuff */ + +static int mvsw61xx_probe(struct platform_device *pdev) +{ + struct mvsw61xx_state *state; + struct device_node *np = pdev->dev.of_node; + struct device_node *mdio; + char *model_str; + u32 val; + int err; + + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (!state) + return -ENOMEM; + + mdio = of_parse_phandle(np, "mii-bus", 0); + if (!mdio) { + dev_err(&pdev->dev, "Couldn't get MII bus handle\n"); + err = -ENODEV; + goto out_err; + } + + state->bus = of_mdio_find_bus(mdio); + if (!state->bus) { + dev_err(&pdev->dev, "Couldn't find MII bus from handle\n"); + err = -ENODEV; + goto out_err; + } + + state->is_indirect = of_property_read_bool(np, "is-indirect"); + + if (state->is_indirect) { + if (of_property_read_u32(np, "reg", &val)) { + dev_err(&pdev->dev, "Switch address not specified\n"); + err = -ENODEV; + goto out_err; + } + + state->base_addr = val; + } else { + state->base_addr = MV_BASE; + } + + state->model = r16(state->bus, state->is_indirect, state->base_addr, + MV_PORTREG(IDENT, 0)) & MV_IDENT_MASK; + + switch(state->model) { + case MV_IDENT_VALUE_6171: + model_str = MV_IDENT_STR_6171; + break; + case MV_IDENT_VALUE_6172: + model_str = MV_IDENT_STR_6172; + break; + case MV_IDENT_VALUE_6176: + model_str = MV_IDENT_STR_6176; + break; + default: + dev_err(&pdev->dev, "No compatible switch found at 0x%02x\n", + state->base_addr); + err = -ENODEV; + goto out_err; + } + + platform_set_drvdata(pdev, state); + dev_info(&pdev->dev, "Found %s at %s:%02x\n", model_str, + state->bus->id, state->base_addr); + + dev_info(&pdev->dev, "Using %sdirect addressing\n", + (state->is_indirect ? "in" : "")); + + if (of_property_read_u32(np, "cpu-port-0", &val)) { + dev_err(&pdev->dev, "CPU port not set\n"); + err = -ENODEV; + goto out_err; + } + + state->cpu_port0 = val; + + if (!of_property_read_u32(np, "cpu-port-1", &val)) + state->cpu_port1 = val; + else + state->cpu_port1 = -1; + + state->dev.vlans = MV_VLANS; + state->dev.cpu_port = state->cpu_port0; + state->dev.ports = MV_PORTS; + state->dev.name = model_str; + state->dev.ops = &mvsw61xx_ops; + state->dev.alias = dev_name(&pdev->dev); + + err = register_switch(&state->dev, NULL); + if (err < 0) + goto out_err; + + state->registered = true; + + return 0; +out_err: + kfree(state); + return err; +} + +static int +mvsw61xx_remove(struct platform_device *pdev) +{ + struct mvsw61xx_state *state = platform_get_drvdata(pdev); + + if (state->registered) + unregister_switch(&state->dev); + + kfree(state); + + return 0; +} + +static const struct of_device_id mvsw61xx_match[] = { + { .compatible = "marvell,88e6171" }, + { .compatible = "marvell,88e6172" }, + { .compatible = "marvell,88e6176" }, + { } +}; +MODULE_DEVICE_TABLE(of, mvsw61xx_match); + +static struct platform_driver mvsw61xx_driver = { + .probe = mvsw61xx_probe, + .remove = mvsw61xx_remove, + .driver = { + .name = "mvsw61xx", + .of_match_table = of_match_ptr(mvsw61xx_match), + .owner = THIS_MODULE, + }, +}; + +static int __init mvsw61xx_module_init(void) +{ + return platform_driver_register(&mvsw61xx_driver); +} +late_initcall(mvsw61xx_module_init); + +static void __exit mvsw61xx_module_exit(void) +{ + platform_driver_unregister(&mvsw61xx_driver); +} +module_exit(mvsw61xx_module_exit); diff --git a/target/linux/generic/files/drivers/net/phy/mvsw61xx.h b/target/linux/generic/files/drivers/net/phy/mvsw61xx.h new file mode 100644 index 0000000..dbc6c92 --- /dev/null +++ b/target/linux/generic/files/drivers/net/phy/mvsw61xx.h @@ -0,0 +1,266 @@ +/* + * Marvell 88E61xx switch driver + * + * Copyright (c) 2014 Claudio Leite + * Copyright (c) 2014 Nikita Nazarenko + * + * Based on code (c) 2008 Felix Fietkau + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License v2 as published by the + * Free Software Foundation + */ + +#ifndef __MVSW61XX_H +#define __MVSW61XX_H + +#define MV_PORTS 7 +#define MV_PORTS_MASK ((1 << MV_PORTS) - 1) + +#define MV_BASE 0x10 + +#define MV_SWITCHPORT_BASE 0x10 +#define MV_SWITCHPORT(_n) (MV_SWITCHPORT_BASE + (_n)) +#define MV_SWITCHREGS (MV_BASE + 0xb) + +#define MV_VLANS 64 + +enum { + MV_PORT_STATUS = 0x00, + MV_PORT_PHYCTL = 0x01, + MV_PORT_JAMCTL = 0x02, + MV_PORT_IDENT = 0x03, + MV_PORT_CONTROL = 0x04, + MV_PORT_CONTROL1 = 0x05, + MV_PORT_VLANMAP = 0x06, + MV_PORT_VLANID = 0x07, + MV_PORT_CONTROL2 = 0x08, + MV_PORT_ASSOC = 0x0b, + MV_PORT_RX_DISCARD_LOW = 0x10, + MV_PORT_RX_DISCARD_HIGH = 0x11, + MV_PORT_IN_FILTERED = 0x12, + MV_PORT_OUT_ACCEPTED = 0x13, +}; +#define MV_PORTREG(_type, _port) MV_SWITCHPORT(_port), MV_PORT_##_type + +enum { + MV_PORT_STATUS_FDX = (1 << 10), + MV_PORT_STATUS_LINK = (1 << 11), +}; + +enum { + MV_PORT_STATUS_SPEED_10 = 0x00, + MV_PORT_STATUS_SPEED_100 = 0x01, + MV_PORT_STATUS_SPEED_1000 = 0x02, +}; +#define MV_PORT_STATUS_SPEED_SHIFT 8 +#define MV_PORT_STATUS_SPEED_MASK (3 << 8) + +enum { + MV_PORTCTRL_DISABLED = (0 << 0), + MV_PORTCTRL_BLOCKING = (1 << 0), + MV_PORTCTRL_LEARNING = (2 << 0), + MV_PORTCTRL_FORWARDING = (3 << 0), + MV_PORTCTRL_VLANTUN = (1 << 7), + MV_PORTCTRL_EGRESS = (1 << 12), +}; + +#define MV_PHYCTL_FC_MASK (3 << 6) + +enum { + MV_PHYCTL_FC_ENABLE = (3 << 6), + MV_PHYCTL_FC_DISABLE = (1 << 6), +}; + +enum { + MV_8021Q_EGRESS_UNMODIFIED = 0x00, + MV_8021Q_EGRESS_UNTAGGED = 0x01, + MV_8021Q_EGRESS_TAGGED = 0x02, + MV_8021Q_EGRESS_ADDTAG = 0x03, +}; + +#define MV_8021Q_MODE_SHIFT 10 +#define MV_8021Q_MODE_MASK (0x3 << MV_8021Q_MODE_SHIFT) + +enum { + MV_8021Q_MODE_DISABLE = 0x00, + MV_8021Q_MODE_FALLBACK = 0x01, + MV_8021Q_MODE_CHECK = 0x02, + MV_8021Q_MODE_SECURE = 0x03, +}; + +enum { + MV_8021Q_VLAN_ONLY = (1 << 15), +}; + +#define MV_PORTASSOC_MONITOR (1 << 15) + +enum { + MV_SWITCH_ATU_FID0 = 0x01, + MV_SWITCH_ATU_FID1 = 0x02, + MV_SWITCH_ATU_SID = 0x03, + MV_SWITCH_CTRL = 0x04, + MV_SWITCH_ATU_CTRL = 0x0a, + MV_SWITCH_ATU_OP = 0x0b, + MV_SWITCH_ATU_DATA = 0x0c, + MV_SWITCH_ATU_MAC0 = 0x0d, + MV_SWITCH_ATU_MAC1 = 0x0e, + MV_SWITCH_ATU_MAC2 = 0x0f, + MV_SWITCH_GLOBAL = 0x1b, + MV_SWITCH_GLOBAL2 = 0x1c, +}; +#define MV_SWITCHREG(_type) MV_SWITCHREGS, MV_SWITCH_##_type + +enum { + MV_SWITCHCTL_EEIE = (1 << 0), + MV_SWITCHCTL_PHYIE = (1 << 1), + MV_SWITCHCTL_ATUDONE = (1 << 2), + MV_SWITCHCTL_ATUIE = (1 << 3), + MV_SWITCHCTL_CTRMODE = (1 << 8), + MV_SWITCHCTL_RELOAD = (1 << 9), + MV_SWITCHCTL_MSIZE = (1 << 10), + MV_SWITCHCTL_DROP = (1 << 13), +}; + +enum { +#define MV_ATUCTL_AGETIME_MIN 16 +#define MV_ATUCTL_AGETIME_MAX 4080 +#define MV_ATUCTL_AGETIME(_n) ((((_n) / 16) & 0xff) << 4) + MV_ATUCTL_ATU_256 = (0 << 12), + MV_ATUCTL_ATU_512 = (1 << 12), + MV_ATUCTL_ATU_1K = (2 << 12), + MV_ATUCTL_ATUMASK = (3 << 12), + MV_ATUCTL_NO_LEARN = (1 << 14), + MV_ATUCTL_RESET = (1 << 15), +}; + +enum { +#define MV_ATUOP_DBNUM(_n) ((_n) & 0x0f) + MV_ATUOP_NOOP = (0 << 12), + MV_ATUOP_FLUSH_ALL = (1 << 12), + MV_ATUOP_FLUSH_U = (2 << 12), + MV_ATUOP_LOAD_DB = (3 << 12), + MV_ATUOP_GET_NEXT = (4 << 12), + MV_ATUOP_FLUSH_DB = (5 << 12), + MV_ATUOP_FLUSH_DB_UU = (6 << 12), + MV_ATUOP_INPROGRESS = (1 << 15), +}; + +enum { + MV_GLOBAL_STATUS = 0x00, + MV_GLOBAL_ATU_FID = 0x01, + MV_GLOBAL_VTU_FID = 0x02, + MV_GLOBAL_VTU_SID = 0x03, + MV_GLOBAL_CONTROL = 0x04, + MV_GLOBAL_VTU_OP = 0x05, + MV_GLOBAL_VTU_VID = 0x06, + MV_GLOBAL_VTU_DATA1 = 0x07, + MV_GLOBAL_VTU_DATA2 = 0x08, + MV_GLOBAL_VTU_DATA3 = 0x09, + MV_GLOBAL_CONTROL2 = 0x1c, +}; +#define MV_GLOBALREG(_type) MV_SWITCH_GLOBAL, MV_GLOBAL_##_type + +enum { + MV_GLOBAL2_SDET_POLARITY = 0x1d, +}; +#define MV_GLOBAL2REG(_type) MV_SWITCH_GLOBAL2, MV_GLOBAL2_##_type + +enum { + MV_VTU_VID_VALID = (1 << 12), +}; + +enum { + MV_VTUOP_PURGE = (1 << 12), + MV_VTUOP_LOAD = (3 << 12), + MV_VTUOP_INPROGRESS = (1 << 15), + MV_VTUOP_STULOAD = (5 << 12), + MV_VTUOP_VTU_GET_NEXT = (4 << 12), + MV_VTUOP_STU_GET_NEXT = (6 << 12), + MV_VTUOP_GET_VIOLATION = (7 << 12), +}; + +enum { + MV_CONTROL_RESET = (1 << 15), + MV_CONTROL_PPU_ENABLE = (1 << 14), +}; + +enum { + MV_VTUCTL_EGRESS_UNMODIFIED = (0 << 0), + MV_VTUCTL_EGRESS_UNTAGGED = (1 << 0), + MV_VTUCTL_EGRESS_TAGGED = (2 << 0), + MV_VTUCTL_DISCARD = (3 << 0), +}; + +enum { + MV_STUCTL_STATE_DISABLED = (0 << 0), + MV_STUCTL_STATE_BLOCKING = (1 << 0), + MV_STUCTL_STATE_LEARNING = (2 << 0), + MV_STUCTL_STATE_FORWARDING = (3 << 0), +}; + +enum { + MV_INDIRECT_REG_CMD = 0, + MV_INDIRECT_REG_DATA = 1, +}; + +enum { + MV_INDIRECT_INPROGRESS = 0x8000, + MV_INDIRECT_WRITE = 0x9400, + MV_INDIRECT_READ = 0x9800, +}; +#define MV_INDIRECT_ADDR_S 5 + +#define MV_IDENT_MASK 0xfff0 + +#define MV_IDENT_VALUE_6171 0x1710 +#define MV_IDENT_STR_6171 "MV88E6171" + +#define MV_IDENT_VALUE_6172 0x1720 +#define MV_IDENT_STR_6172 "MV88E6172" + +#define MV_IDENT_VALUE_6176 0x1760 +#define MV_IDENT_STR_6176 "MV88E6176" + +#define MV_PVID_MASK 0x0fff + +#define MV_FDB_HI_MASK 0x00ff +#define MV_FDB_LO_MASK 0xf000 +#define MV_FDB_HI_SHIFT 4 +#define MV_FDB_LO_SHIFT 12 + +struct mvsw61xx_state { + struct switch_dev dev; + struct mii_bus *bus; + int base_addr; + u16 model; + + bool registered; + bool is_indirect; + + int cpu_port0; + int cpu_port1; + + int vlan_enabled; + struct port_state { + u16 fdb; + u16 pvid; + u16 mask; + u8 qmode; + } ports[MV_PORTS]; + + struct vlan_state { + bool port_based; + + u16 mask; + u16 vid; + u32 port_mode; + u32 port_sstate; + } vlans[MV_VLANS]; + + char buf[128]; +}; + +#define get_state(_dev) container_of((_dev), struct mvsw61xx_state, dev) + +#endif diff --git a/target/linux/generic/files/drivers/net/phy/mvswitch.c b/target/linux/generic/files/drivers/net/phy/mvswitch.c new file mode 100644 index 0000000..af73ec2 --- /dev/null +++ b/target/linux/generic/files/drivers/net/phy/mvswitch.c @@ -0,0 +1,433 @@ +/* + * Marvell 88E6060 switch driver + * Copyright (c) 2008 Felix Fietkau + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License v2 as published by the + * Free Software Foundation + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "mvswitch.h" + +/* Undefine this to use trailer mode instead. + * I don't know if header mode works with all chips */ +#define HEADER_MODE 1 + +MODULE_DESCRIPTION("Marvell 88E6060 Switch driver"); +MODULE_AUTHOR("Felix Fietkau"); +MODULE_LICENSE("GPL"); + +#define MVSWITCH_MAGIC 0x88E6060 + +struct mvswitch_priv { + netdev_features_t orig_features; + u8 vlans[16]; +}; + +#define to_mvsw(_phy) ((struct mvswitch_priv *) (_phy)->priv) + +static inline u16 +r16(struct phy_device *phydev, int addr, int reg) +{ + return phydev->bus->read(phydev->bus, addr, reg); +} + +static inline void +w16(struct phy_device *phydev, int addr, int reg, u16 val) +{ + phydev->bus->write(phydev->bus, addr, reg, val); +} + + +static struct sk_buff * +mvswitch_mangle_tx(struct net_device *dev, struct sk_buff *skb) +{ + struct mvswitch_priv *priv; + char *buf = NULL; + u16 vid; + + priv = dev->phy_ptr; + if (unlikely(!priv)) + goto error; + + if (unlikely(skb->len < 16)) + goto error; + +#ifdef HEADER_MODE + if (__vlan_hwaccel_get_tag(skb, &vid)) + goto error; + + if (skb_cloned(skb) || (skb->len <= 62) || (skb_headroom(skb) < MV_HEADER_SIZE)) { + if (pskb_expand_head(skb, MV_HEADER_SIZE, (skb->len < 62 ? 62 - skb->len : 0), GFP_ATOMIC)) + goto error_expand; + if (skb->len < 62) + skb->len = 62; + } + buf = skb_push(skb, MV_HEADER_SIZE); +#else + if (__vlan_get_tag(skb, &vid)) + goto error; + + if (unlikely((vid > 15 || !priv->vlans[vid]))) + goto error; + + if (skb->len <= 64) { + if (pskb_expand_head(skb, 0, 64 + MV_TRAILER_SIZE - skb->len, GFP_ATOMIC)) + goto error_expand; + + buf = skb->data + 64; + skb->len = 64 + MV_TRAILER_SIZE; + } else { + if (skb_cloned(skb) || unlikely(skb_tailroom(skb) < 4)) { + if (pskb_expand_head(skb, 0, 4, GFP_ATOMIC)) + goto error_expand; + } + buf = skb_put(skb, 4); + } + + /* move the ethernet header 4 bytes forward, overwriting the vlan tag */ + memmove(skb->data + 4, skb->data, 12); + skb->data += 4; + skb->len -= 4; + skb->mac_header += 4; +#endif + + if (!buf) + goto error; + + +#ifdef HEADER_MODE + /* prepend the tag */ + *((__be16 *) buf) = cpu_to_be16( + ((vid << MV_HEADER_VLAN_S) & MV_HEADER_VLAN_M) | + ((priv->vlans[vid] << MV_HEADER_PORTS_S) & MV_HEADER_PORTS_M) + ); +#else + /* append the tag */ + *((__be32 *) buf) = cpu_to_be32(( + (MV_TRAILER_OVERRIDE << MV_TRAILER_FLAGS_S) | + ((priv->vlans[vid] & MV_TRAILER_PORTS_M) << MV_TRAILER_PORTS_S) + )); +#endif + + return skb; + +error_expand: + if (net_ratelimit()) + printk("%s: failed to expand/update skb for the switch\n", dev->name); + +error: + /* any errors? drop the packet! */ + dev_kfree_skb_any(skb); + return NULL; +} + +static void +mvswitch_mangle_rx(struct net_device *dev, struct sk_buff *skb) +{ + struct mvswitch_priv *priv; + unsigned char *buf; + int vlan = -1; + int i; + + priv = dev->phy_ptr; + if (WARN_ON_ONCE(!priv)) + return; + +#ifdef HEADER_MODE + buf = skb->data; + skb_pull(skb, MV_HEADER_SIZE); +#else + buf = skb->data + skb->len - MV_TRAILER_SIZE; + if (buf[0] != 0x80) + return; +#endif + + /* look for the vlan matching the incoming port */ + for (i = 0; i < ARRAY_SIZE(priv->vlans); i++) { + if ((1 << buf[1]) & priv->vlans[i]) + vlan = i; + } + + if (vlan == -1) + return; + + __vlan_hwaccel_put_tag(skb, vlan); +} + + +static int +mvswitch_wait_mask(struct phy_device *pdev, int addr, int reg, u16 mask, u16 val) +{ + int i = 100; + u16 r; + + do { + r = r16(pdev, addr, reg) & mask; + if (r == val) + return 0; + } while(--i > 0); + return -ETIMEDOUT; +} + +static int +mvswitch_config_init(struct phy_device *pdev) +{ + struct mvswitch_priv *priv = to_mvsw(pdev); + struct net_device *dev = pdev->attached_dev; + u8 vlmap = 0; + int i; + + if (!dev) + return -EINVAL; + + printk("%s: Marvell 88E6060 PHY driver attached.\n", dev->name); + pdev->supported = ADVERTISED_100baseT_Full; + pdev->advertising = ADVERTISED_100baseT_Full; + dev->phy_ptr = priv; + pdev->irq = PHY_POLL; +#ifdef HEADER_MODE + dev->flags |= IFF_PROMISC; +#endif + + /* initialize default vlans */ + for (i = 0; i < MV_PORTS; i++) + priv->vlans[(i == MV_WANPORT ? 2 : 1)] |= (1 << i); + + /* before entering reset, disable all ports */ + for (i = 0; i < MV_PORTS; i++) + w16(pdev, MV_PORTREG(CONTROL, i), 0x00); + + msleep(2); /* wait for the status change to settle in */ + + /* put the ATU in reset */ + w16(pdev, MV_SWITCHREG(ATU_CTRL), MV_ATUCTL_RESET); + + i = mvswitch_wait_mask(pdev, MV_SWITCHREG(ATU_CTRL), MV_ATUCTL_RESET, 0); + if (i < 0) { + printk("%s: Timeout waiting for the switch to reset.\n", dev->name); + return i; + } + + /* set the ATU flags */ + w16(pdev, MV_SWITCHREG(ATU_CTRL), + MV_ATUCTL_NO_LEARN | + MV_ATUCTL_ATU_1K | + MV_ATUCTL_AGETIME(MV_ATUCTL_AGETIME_MIN) /* minimum without disabling ageing */ + ); + + /* initialize the cpu port */ + w16(pdev, MV_PORTREG(CONTROL, MV_CPUPORT), +#ifdef HEADER_MODE + MV_PORTCTRL_HEADER | +#else + MV_PORTCTRL_RXTR | + MV_PORTCTRL_TXTR | +#endif + MV_PORTCTRL_ENABLED + ); + /* wait for the phy change to settle in */ + msleep(2); + for (i = 0; i < MV_PORTS; i++) { + u8 pvid = 0; + int j; + + vlmap = 0; + + /* look for the matching vlan */ + for (j = 0; j < ARRAY_SIZE(priv->vlans); j++) { + if (priv->vlans[j] & (1 << i)) { + vlmap = priv->vlans[j]; + pvid = j; + } + } + /* leave port unconfigured if it's not part of a vlan */ + if (!vlmap) + continue; + + /* add the cpu port to the allowed destinations list */ + vlmap |= (1 << MV_CPUPORT); + + /* take port out of its own vlan destination map */ + vlmap &= ~(1 << i); + + /* apply vlan settings */ + w16(pdev, MV_PORTREG(VLANMAP, i), + MV_PORTVLAN_PORTS(vlmap) | + MV_PORTVLAN_ID(i) + ); + + /* re-enable port */ + w16(pdev, MV_PORTREG(CONTROL, i), + MV_PORTCTRL_ENABLED + ); + } + + w16(pdev, MV_PORTREG(VLANMAP, MV_CPUPORT), + MV_PORTVLAN_ID(MV_CPUPORT) + ); + + /* set the port association vector */ + for (i = 0; i <= MV_PORTS; i++) { + w16(pdev, MV_PORTREG(ASSOC, i), + MV_PORTASSOC_PORTS(1 << i) + ); + } + + /* init switch control */ + w16(pdev, MV_SWITCHREG(CTRL), + MV_SWITCHCTL_MSIZE | + MV_SWITCHCTL_DROP + ); + + dev->eth_mangle_rx = mvswitch_mangle_rx; + dev->eth_mangle_tx = mvswitch_mangle_tx; + priv->orig_features = dev->features; + +#ifdef HEADER_MODE + dev->priv_flags |= IFF_NO_IP_ALIGN; + dev->features |= NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_TX; +#else + dev->features |= NETIF_F_HW_VLAN_RX; +#endif + + return 0; +} + +static int +mvswitch_read_status(struct phy_device *pdev) +{ + pdev->speed = SPEED_100; + pdev->duplex = DUPLEX_FULL; + pdev->link = 1; + + /* XXX ugly workaround: we can't force the switch + * to gracefully handle hosts moving from one port to another, + * so we have to regularly clear the ATU database */ + + /* wait for the ATU to become available */ + mvswitch_wait_mask(pdev, MV_SWITCHREG(ATU_OP), MV_ATUOP_INPROGRESS, 0); + + /* flush the ATU */ + w16(pdev, MV_SWITCHREG(ATU_OP), + MV_ATUOP_INPROGRESS | + MV_ATUOP_FLUSH_ALL + ); + + /* wait for operation to complete */ + mvswitch_wait_mask(pdev, MV_SWITCHREG(ATU_OP), MV_ATUOP_INPROGRESS, 0); + + return 0; +} + +static int +mvswitch_config_aneg(struct phy_device *phydev) +{ + return 0; +} + +static void +mvswitch_detach(struct phy_device *pdev) +{ + struct mvswitch_priv *priv = to_mvsw(pdev); + struct net_device *dev = pdev->attached_dev; + + if (!dev) + return; + + dev->phy_ptr = NULL; + dev->eth_mangle_rx = NULL; + dev->eth_mangle_tx = NULL; + dev->features = priv->orig_features; + dev->priv_flags &= ~IFF_NO_IP_ALIGN; +} + +static void +mvswitch_remove(struct phy_device *pdev) +{ + struct mvswitch_priv *priv = to_mvsw(pdev); + + kfree(priv); +} + +static int +mvswitch_probe(struct phy_device *pdev) +{ + struct mvswitch_priv *priv; + + priv = kzalloc(sizeof(struct mvswitch_priv), GFP_KERNEL); + if (priv == NULL) + return -ENOMEM; + + pdev->priv = priv; + + return 0; +} + +static int +mvswitch_fixup(struct phy_device *dev) +{ + u16 reg; + + if (dev->addr != 0x10) + return 0; + + reg = dev->bus->read(dev->bus, MV_PORTREG(IDENT, 0)) & MV_IDENT_MASK; + if (reg != MV_IDENT_VALUE) + return 0; + + dev->phy_id = MVSWITCH_MAGIC; + return 0; +} + + +static struct phy_driver mvswitch_driver = { + .name = "Marvell 88E6060", + .phy_id = MVSWITCH_MAGIC, + .phy_id_mask = 0xffffffff, + .features = PHY_BASIC_FEATURES, + .probe = &mvswitch_probe, + .remove = &mvswitch_remove, + .detach = &mvswitch_detach, + .config_init = &mvswitch_config_init, + .config_aneg = &mvswitch_config_aneg, + .read_status = &mvswitch_read_status, + .driver = { .owner = THIS_MODULE,}, +}; + +static int __init +mvswitch_init(void) +{ + phy_register_fixup_for_id(PHY_ANY_ID, mvswitch_fixup); + return phy_driver_register(&mvswitch_driver); +} + +static void __exit +mvswitch_exit(void) +{ + phy_driver_unregister(&mvswitch_driver); +} + +module_init(mvswitch_init); +module_exit(mvswitch_exit); diff --git a/target/linux/generic/files/drivers/net/phy/mvswitch.h b/target/linux/generic/files/drivers/net/phy/mvswitch.h new file mode 100644 index 0000000..1563eec --- /dev/null +++ b/target/linux/generic/files/drivers/net/phy/mvswitch.h @@ -0,0 +1,145 @@ +/* + * Marvell 88E6060 switch driver + * Copyright (c) 2008 Felix Fietkau + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License v2 as published by the + * Free Software Foundation + */ +#ifndef __MVSWITCH_H +#define __MVSWITCH_H + +#define MV_HEADER_SIZE 2 +#define MV_HEADER_PORTS_M 0x001f +#define MV_HEADER_PORTS_S 0 +#define MV_HEADER_VLAN_M 0xf000 +#define MV_HEADER_VLAN_S 12 + +#define MV_TRAILER_SIZE 4 +#define MV_TRAILER_PORTS_M 0x1f +#define MV_TRAILER_PORTS_S 16 +#define MV_TRAILER_FLAGS_S 24 +#define MV_TRAILER_OVERRIDE 0x80 + + +#define MV_PORTS 5 +#define MV_WANPORT 4 +#define MV_CPUPORT 5 + +#define MV_BASE 0x10 + +#define MV_PHYPORT_BASE (MV_BASE + 0x0) +#define MV_PHYPORT(_n) (MV_PHYPORT_BASE + (_n)) +#define MV_SWITCHPORT_BASE (MV_BASE + 0x8) +#define MV_SWITCHPORT(_n) (MV_SWITCHPORT_BASE + (_n)) +#define MV_SWITCHREGS (MV_BASE + 0xf) + +enum { + MV_PHY_CONTROL = 0x00, + MV_PHY_STATUS = 0x01, + MV_PHY_IDENT0 = 0x02, + MV_PHY_IDENT1 = 0x03, + MV_PHY_ANEG = 0x04, + MV_PHY_LINK_ABILITY = 0x05, + MV_PHY_ANEG_EXPAND = 0x06, + MV_PHY_XMIT_NEXTP = 0x07, + MV_PHY_LINK_NEXTP = 0x08, + MV_PHY_CONTROL1 = 0x10, + MV_PHY_STATUS1 = 0x11, + MV_PHY_INTR_EN = 0x12, + MV_PHY_INTR_STATUS = 0x13, + MV_PHY_INTR_PORT = 0x14, + MV_PHY_RECV_COUNTER = 0x16, + MV_PHY_LED_PARALLEL = 0x16, + MV_PHY_LED_STREAM = 0x17, + MV_PHY_LED_CTRL = 0x18, + MV_PHY_LED_OVERRIDE = 0x19, + MV_PHY_VCT_CTRL = 0x1a, + MV_PHY_VCT_STATUS = 0x1b, + MV_PHY_CONTROL2 = 0x1e +}; +#define MV_PHYREG(_type, _port) MV_PHYPORT(_port), MV_PHY_##_type + +enum { + MV_PORT_STATUS = 0x00, + MV_PORT_IDENT = 0x03, + MV_PORT_CONTROL = 0x04, + MV_PORT_VLANMAP = 0x06, + MV_PORT_ASSOC = 0x0b, + MV_PORT_RXCOUNT = 0x10, + MV_PORT_TXCOUNT = 0x11, +}; +#define MV_PORTREG(_type, _port) MV_SWITCHPORT(_port), MV_PORT_##_type + +enum { + MV_PORTCTRL_BLOCK = (1 << 0), + MV_PORTCTRL_LEARN = (2 << 0), + MV_PORTCTRL_ENABLED = (3 << 0), + MV_PORTCTRL_VLANTUN = (1 << 7), /* Enforce VLANs on packets */ + MV_PORTCTRL_RXTR = (1 << 8), /* Enable Marvell packet trailer for ingress */ + MV_PORTCTRL_HEADER = (1 << 11), /* Enable Marvell packet header mode for port */ + MV_PORTCTRL_TXTR = (1 << 14), /* Enable Marvell packet trailer for egress */ + MV_PORTCTRL_FORCEFL = (1 << 15), /* force flow control */ +}; + +#define MV_PORTVLAN_ID(_n) (((_n) & 0xf) << 12) +#define MV_PORTVLAN_PORTS(_n) ((_n) & 0x3f) + +#define MV_PORTASSOC_PORTS(_n) ((_n) & 0x1f) +#define MV_PORTASSOC_MONITOR (1 << 15) + +enum { + MV_SWITCH_MAC0 = 0x01, + MV_SWITCH_MAC1 = 0x02, + MV_SWITCH_MAC2 = 0x03, + MV_SWITCH_CTRL = 0x04, + MV_SWITCH_ATU_CTRL = 0x0a, + MV_SWITCH_ATU_OP = 0x0b, + MV_SWITCH_ATU_DATA = 0x0c, + MV_SWITCH_ATU_MAC0 = 0x0d, + MV_SWITCH_ATU_MAC1 = 0x0e, + MV_SWITCH_ATU_MAC2 = 0x0f, +}; +#define MV_SWITCHREG(_type) MV_SWITCHREGS, MV_SWITCH_##_type + +enum { + MV_SWITCHCTL_EEIE = (1 << 0), /* EEPROM interrupt enable */ + MV_SWITCHCTL_PHYIE = (1 << 1), /* PHY interrupt enable */ + MV_SWITCHCTL_ATUDONE= (1 << 2), /* ATU done interrupt enable */ + MV_SWITCHCTL_ATUIE = (1 << 3), /* ATU interrupt enable */ + MV_SWITCHCTL_CTRMODE= (1 << 8), /* statistics for rx and tx errors */ + MV_SWITCHCTL_RELOAD = (1 << 9), /* reload registers from eeprom */ + MV_SWITCHCTL_MSIZE = (1 << 10), /* increase maximum frame size */ + MV_SWITCHCTL_DROP = (1 << 13), /* discard frames with excessive collisions */ +}; + +enum { +#define MV_ATUCTL_AGETIME_MIN 16 +#define MV_ATUCTL_AGETIME_MAX 4080 +#define MV_ATUCTL_AGETIME(_n) ((((_n) / 16) & 0xff) << 4) + MV_ATUCTL_ATU_256 = (0 << 12), + MV_ATUCTL_ATU_512 = (1 << 12), + MV_ATUCTL_ATU_1K = (2 << 12), + MV_ATUCTL_ATUMASK = (3 << 12), + MV_ATUCTL_NO_LEARN = (1 << 14), + MV_ATUCTL_RESET = (1 << 15), +}; + +enum { +#define MV_ATUOP_DBNUM(_n) ((_n) & 0x0f) + + MV_ATUOP_NOOP = (0 << 12), + MV_ATUOP_FLUSH_ALL = (1 << 12), + MV_ATUOP_FLUSH_U = (2 << 12), + MV_ATUOP_LOAD_DB = (3 << 12), + MV_ATUOP_GET_NEXT = (4 << 12), + MV_ATUOP_FLUSH_DB = (5 << 12), + MV_ATUOP_FLUSH_DB_UU= (6 << 12), + + MV_ATUOP_INPROGRESS = (1 << 15), +}; + +#define MV_IDENT_MASK 0xfff0 +#define MV_IDENT_VALUE 0x0600 + +#endif diff --git a/target/linux/generic/files/drivers/net/phy/psb6970.c b/target/linux/generic/files/drivers/net/phy/psb6970.c new file mode 100644 index 0000000..2fcd299 --- /dev/null +++ b/target/linux/generic/files/drivers/net/phy/psb6970.c @@ -0,0 +1,438 @@ +/* + * Lantiq PSB6970 (Tantos) Switch driver + * + * Copyright (c) 2009,2010 Team Embedded. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License v2 as published by the + * Free Software Foundation. + * + * The switch programming done in this driver follows the + * "Ethernet Traffic Separation using VLAN" Application Note as + * published by Lantiq. + */ + +#include +#include +#include +#include + +#define PSB6970_MAX_VLANS 16 +#define PSB6970_NUM_PORTS 7 +#define PSB6970_DEFAULT_PORT_CPU 6 +#define PSB6970_IS_CPU_PORT(x) ((x) > 4) + +#define PHYADDR(_reg) ((_reg >> 5) & 0xff), (_reg & 0x1f) + +/* --- Identification --- */ +#define PSB6970_CI0 0x0100 +#define PSB6970_CI0_MASK 0x000f +#define PSB6970_CI1 0x0101 +#define PSB6970_CI1_VAL 0x2599 +#define PSB6970_CI1_MASK 0xffff + +/* --- VLAN filter table --- */ +#define PSB6970_VFxL(i) ((i)*2+0x10) /* VLAN Filter Low */ +#define PSB6970_VFxL_VV (1 << 15) /* VLAN_Valid */ + +#define PSB6970_VFxH(i) ((i)*2+0x11) /* VLAN Filter High */ +#define PSB6970_VFxH_TM_SHIFT 7 /* Tagged Member */ + +/* --- Port registers --- */ +#define PSB6970_EC(p) ((p)*0x20+2) /* Extended Control */ +#define PSB6970_EC_IFNTE (1 << 1) /* Input Force No Tag Enable */ + +#define PSB6970_PBVM(p) ((p)*0x20+3) /* Port Base VLAN Map */ +#define PSB6970_PBVM_VMCE (1 << 8) +#define PSB6970_PBVM_AOVTP (1 << 9) +#define PSB6970_PBVM_VSD (1 << 10) +#define PSB6970_PBVM_VC (1 << 11) /* VID Check with VID table */ +#define PSB6970_PBVM_TBVE (1 << 13) /* Tag-Based VLAN enable */ + +#define PSB6970_DVID(p) ((p)*0x20+4) /* Default VLAN ID & Priority */ + +struct psb6970_priv { + struct switch_dev dev; + struct phy_device *phy; + u16 (*read) (struct phy_device* phydev, int reg); + void (*write) (struct phy_device* phydev, int reg, u16 val); + struct mutex reg_mutex; + + /* all fields below are cleared on reset */ + bool vlan; + u16 vlan_id[PSB6970_MAX_VLANS]; + u8 vlan_table[PSB6970_MAX_VLANS]; + u8 vlan_tagged; + u16 pvid[PSB6970_NUM_PORTS]; +}; + +#define to_psb6970(_dev) container_of(_dev, struct psb6970_priv, dev) + +static u16 psb6970_mii_read(struct phy_device *phydev, int reg) +{ + return phydev->bus->read(phydev->bus, PHYADDR(reg)); +} + +static void psb6970_mii_write(struct phy_device *phydev, int reg, u16 val) +{ + phydev->bus->write(phydev->bus, PHYADDR(reg), val); +} + +static int +psb6970_set_vlan(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + struct psb6970_priv *priv = to_psb6970(dev); + priv->vlan = !!val->value.i; + return 0; +} + +static int +psb6970_get_vlan(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + struct psb6970_priv *priv = to_psb6970(dev); + val->value.i = priv->vlan; + return 0; +} + +static int psb6970_set_pvid(struct switch_dev *dev, int port, int vlan) +{ + struct psb6970_priv *priv = to_psb6970(dev); + + /* make sure no invalid PVIDs get set */ + if (vlan >= dev->vlans) + return -EINVAL; + + priv->pvid[port] = vlan; + return 0; +} + +static int psb6970_get_pvid(struct switch_dev *dev, int port, int *vlan) +{ + struct psb6970_priv *priv = to_psb6970(dev); + *vlan = priv->pvid[port]; + return 0; +} + +static int +psb6970_set_vid(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + struct psb6970_priv *priv = to_psb6970(dev); + priv->vlan_id[val->port_vlan] = val->value.i; + return 0; +} + +static int +psb6970_get_vid(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + struct psb6970_priv *priv = to_psb6970(dev); + val->value.i = priv->vlan_id[val->port_vlan]; + return 0; +} + +static struct switch_attr psb6970_globals[] = { + { + .type = SWITCH_TYPE_INT, + .name = "enable_vlan", + .description = "Enable VLAN mode", + .set = psb6970_set_vlan, + .get = psb6970_get_vlan, + .max = 1}, +}; + +static struct switch_attr psb6970_port[] = { +}; + +static struct switch_attr psb6970_vlan[] = { + { + .type = SWITCH_TYPE_INT, + .name = "vid", + .description = "VLAN ID (0-4094)", + .set = psb6970_set_vid, + .get = psb6970_get_vid, + .max = 4094, + }, +}; + +static int psb6970_get_ports(struct switch_dev *dev, struct switch_val *val) +{ + struct psb6970_priv *priv = to_psb6970(dev); + u8 ports = priv->vlan_table[val->port_vlan]; + int i; + + val->len = 0; + for (i = 0; i < PSB6970_NUM_PORTS; i++) { + struct switch_port *p; + + if (!(ports & (1 << i))) + continue; + + p = &val->value.ports[val->len++]; + p->id = i; + if (priv->vlan_tagged & (1 << i)) + p->flags = (1 << SWITCH_PORT_FLAG_TAGGED); + else + p->flags = 0; + } + return 0; +} + +static int psb6970_set_ports(struct switch_dev *dev, struct switch_val *val) +{ + struct psb6970_priv *priv = to_psb6970(dev); + u8 *vt = &priv->vlan_table[val->port_vlan]; + int i, j; + + *vt = 0; + for (i = 0; i < val->len; i++) { + struct switch_port *p = &val->value.ports[i]; + + if (p->flags & (1 << SWITCH_PORT_FLAG_TAGGED)) + priv->vlan_tagged |= (1 << p->id); + else { + priv->vlan_tagged &= ~(1 << p->id); + priv->pvid[p->id] = val->port_vlan; + + /* make sure that an untagged port does not + * appear in other vlans */ + for (j = 0; j < PSB6970_MAX_VLANS; j++) { + if (j == val->port_vlan) + continue; + priv->vlan_table[j] &= ~(1 << p->id); + } + } + + *vt |= 1 << p->id; + } + return 0; +} + +static int psb6970_hw_apply(struct switch_dev *dev) +{ + struct psb6970_priv *priv = to_psb6970(dev); + int i, j; + + mutex_lock(&priv->reg_mutex); + + if (priv->vlan) { + /* into the vlan translation unit */ + for (j = 0; j < PSB6970_MAX_VLANS; j++) { + u8 vp = priv->vlan_table[j]; + + if (vp) { + priv->write(priv->phy, PSB6970_VFxL(j), + PSB6970_VFxL_VV | priv->vlan_id[j]); + priv->write(priv->phy, PSB6970_VFxH(j), + ((vp & priv-> + vlan_tagged) << + PSB6970_VFxH_TM_SHIFT) | vp); + } else /* clear VLAN Valid flag for unused vlans */ + priv->write(priv->phy, PSB6970_VFxL(j), 0); + + } + } + + /* update the port destination mask registers and tag settings */ + for (i = 0; i < PSB6970_NUM_PORTS; i++) { + int dvid = 1, pbvm = 0x7f | PSB6970_PBVM_VSD, ec = 0; + + if (priv->vlan) { + ec = PSB6970_EC_IFNTE; + dvid = priv->vlan_id[priv->pvid[i]]; + pbvm |= PSB6970_PBVM_TBVE | PSB6970_PBVM_VMCE; + + if ((i << 1) & priv->vlan_tagged) + pbvm |= PSB6970_PBVM_AOVTP | PSB6970_PBVM_VC; + } + + priv->write(priv->phy, PSB6970_PBVM(i), pbvm); + + if (!PSB6970_IS_CPU_PORT(i)) { + priv->write(priv->phy, PSB6970_EC(i), ec); + priv->write(priv->phy, PSB6970_DVID(i), dvid); + } + } + + mutex_unlock(&priv->reg_mutex); + return 0; +} + +static int psb6970_reset_switch(struct switch_dev *dev) +{ + struct psb6970_priv *priv = to_psb6970(dev); + int i; + + mutex_lock(&priv->reg_mutex); + + memset(&priv->vlan, 0, sizeof(struct psb6970_priv) - + offsetof(struct psb6970_priv, vlan)); + + for (i = 0; i < PSB6970_MAX_VLANS; i++) + priv->vlan_id[i] = i; + + mutex_unlock(&priv->reg_mutex); + + return psb6970_hw_apply(dev); +} + +static const struct switch_dev_ops psb6970_ops = { + .attr_global = { + .attr = psb6970_globals, + .n_attr = ARRAY_SIZE(psb6970_globals), + }, + .attr_port = { + .attr = psb6970_port, + .n_attr = ARRAY_SIZE(psb6970_port), + }, + .attr_vlan = { + .attr = psb6970_vlan, + .n_attr = ARRAY_SIZE(psb6970_vlan), + }, + .get_port_pvid = psb6970_get_pvid, + .set_port_pvid = psb6970_set_pvid, + .get_vlan_ports = psb6970_get_ports, + .set_vlan_ports = psb6970_set_ports, + .apply_config = psb6970_hw_apply, + .reset_switch = psb6970_reset_switch, +}; + +static int psb6970_config_init(struct phy_device *pdev) +{ + struct psb6970_priv *priv; + struct net_device *dev = pdev->attached_dev; + struct switch_dev *swdev; + int ret; + + priv = kzalloc(sizeof(struct psb6970_priv), GFP_KERNEL); + if (priv == NULL) + return -ENOMEM; + + priv->phy = pdev; + + if (pdev->addr == 0) + printk(KERN_INFO "%s: psb6970 switch driver attached.\n", + pdev->attached_dev->name); + + if (pdev->addr != 0) { + kfree(priv); + return 0; + } + + pdev->supported = pdev->advertising = SUPPORTED_100baseT_Full; + + mutex_init(&priv->reg_mutex); + priv->read = psb6970_mii_read; + priv->write = psb6970_mii_write; + + pdev->priv = priv; + + swdev = &priv->dev; + swdev->cpu_port = PSB6970_DEFAULT_PORT_CPU; + swdev->ops = &psb6970_ops; + + swdev->name = "Lantiq PSB6970"; + swdev->vlans = PSB6970_MAX_VLANS; + swdev->ports = PSB6970_NUM_PORTS; + + if ((ret = register_switch(&priv->dev, pdev->attached_dev)) < 0) { + kfree(priv); + goto done; + } + + ret = psb6970_reset_switch(&priv->dev); + if (ret) { + kfree(priv); + goto done; + } + + dev->phy_ptr = priv; + +done: + return ret; +} + +static int psb6970_read_status(struct phy_device *phydev) +{ + phydev->speed = SPEED_100; + phydev->duplex = DUPLEX_FULL; + phydev->link = 1; + + phydev->state = PHY_RUNNING; + netif_carrier_on(phydev->attached_dev); + phydev->adjust_link(phydev->attached_dev); + + return 0; +} + +static int psb6970_config_aneg(struct phy_device *phydev) +{ + return 0; +} + +static int psb6970_probe(struct phy_device *pdev) +{ + return 0; +} + +static void psb6970_remove(struct phy_device *pdev) +{ + struct psb6970_priv *priv = pdev->priv; + + if (!priv) + return; + + if (pdev->addr == 0) + unregister_switch(&priv->dev); + kfree(priv); +} + +static int psb6970_fixup(struct phy_device *dev) +{ + struct mii_bus *bus = dev->bus; + u16 reg; + + /* look for the switch on the bus */ + reg = bus->read(bus, PHYADDR(PSB6970_CI1)) & PSB6970_CI1_MASK; + if (reg != PSB6970_CI1_VAL) + return 0; + + dev->phy_id = (reg << 16); + dev->phy_id |= bus->read(bus, PHYADDR(PSB6970_CI0)) & PSB6970_CI0_MASK; + + return 0; +} + +static struct phy_driver psb6970_driver = { + .name = "Lantiq PSB6970", + .phy_id = PSB6970_CI1_VAL << 16, + .phy_id_mask = 0xffff0000, + .features = PHY_BASIC_FEATURES, + .probe = psb6970_probe, + .remove = psb6970_remove, + .config_init = &psb6970_config_init, + .config_aneg = &psb6970_config_aneg, + .read_status = &psb6970_read_status, + .driver = {.owner = THIS_MODULE}, +}; + +int __init psb6970_init(void) +{ + phy_register_fixup_for_id(PHY_ANY_ID, psb6970_fixup); + return phy_driver_register(&psb6970_driver); +} + +module_init(psb6970_init); + +void __exit psb6970_exit(void) +{ + phy_driver_unregister(&psb6970_driver); +} + +module_exit(psb6970_exit); + +MODULE_DESCRIPTION("Lantiq PSB6970 Switch"); +MODULE_AUTHOR("Ithamar R. Adema "); +MODULE_LICENSE("GPL"); diff --git a/target/linux/generic/files/drivers/net/phy/rtl8306.c b/target/linux/generic/files/drivers/net/phy/rtl8306.c new file mode 100644 index 0000000..e280e93 --- /dev/null +++ b/target/linux/generic/files/drivers/net/phy/rtl8306.c @@ -0,0 +1,1060 @@ +/* + * rtl8306.c: RTL8306S switch driver + * + * Copyright (C) 2009 Felix Fietkau + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//#define DEBUG 1 + +/* Global (PHY0) */ +#define RTL8306_REG_PAGE 16 +#define RTL8306_REG_PAGE_LO (1 << 15) +#define RTL8306_REG_PAGE_HI (1 << 1) /* inverted */ + +#define RTL8306_NUM_VLANS 16 +#define RTL8306_NUM_PORTS 6 +#define RTL8306_PORT_CPU 5 +#define RTL8306_NUM_PAGES 4 +#define RTL8306_NUM_REGS 32 + +#define RTL_NAME_S "RTL8306S" +#define RTL_NAME_SD "RTL8306SD" +#define RTL_NAME_SDM "RTL8306SDM" +#define RTL_NAME_UNKNOWN "RTL8306(unknown)" + +#define RTL8306_MAGIC 0x8306 + +static LIST_HEAD(phydevs); + +struct rtl_priv { + struct list_head list; + struct switch_dev dev; + int page; + int type; + int do_cpu; + struct mii_bus *bus; + char hwname[sizeof(RTL_NAME_UNKNOWN)]; + bool fixup; +}; + +struct rtl_phyregs { + int nway; + int speed; + int duplex; +}; + +#define to_rtl(_dev) container_of(_dev, struct rtl_priv, dev) + +enum { + RTL_TYPE_S, + RTL_TYPE_SD, + RTL_TYPE_SDM, +}; + +struct rtl_reg { + int page; + int phy; + int reg; + int bits; + int shift; + int inverted; +}; + +#define RTL_VLAN_REGOFS(name) \ + (RTL_REG_VLAN1_##name - RTL_REG_VLAN0_##name) + +#define RTL_PORT_REGOFS(name) \ + (RTL_REG_PORT1_##name - RTL_REG_PORT0_##name) + +#define RTL_PORT_REG(id, reg) \ + (RTL_REG_PORT0_##reg + (id * RTL_PORT_REGOFS(reg))) + +#define RTL_VLAN_REG(id, reg) \ + (RTL_REG_VLAN0_##reg + (id * RTL_VLAN_REGOFS(reg))) + +#define RTL_GLOBAL_REGATTR(reg) \ + .id = RTL_REG_##reg, \ + .type = SWITCH_TYPE_INT, \ + .ofs = 0, \ + .set = rtl_attr_set_int, \ + .get = rtl_attr_get_int + +#define RTL_PORT_REGATTR(reg) \ + .id = RTL_REG_PORT0_##reg, \ + .type = SWITCH_TYPE_INT, \ + .ofs = RTL_PORT_REGOFS(reg), \ + .set = rtl_attr_set_port_int, \ + .get = rtl_attr_get_port_int + +#define RTL_VLAN_REGATTR(reg) \ + .id = RTL_REG_VLAN0_##reg, \ + .type = SWITCH_TYPE_INT, \ + .ofs = RTL_VLAN_REGOFS(reg), \ + .set = rtl_attr_set_vlan_int, \ + .get = rtl_attr_get_vlan_int + +enum rtl_regidx { + RTL_REG_CHIPID, + RTL_REG_CHIPVER, + RTL_REG_CHIPTYPE, + RTL_REG_CPUPORT, + + RTL_REG_EN_CPUPORT, + RTL_REG_EN_TAG_OUT, + RTL_REG_EN_TAG_CLR, + RTL_REG_EN_TAG_IN, + RTL_REG_TRAP_CPU, + RTL_REG_CPU_LINKUP, + RTL_REG_TRUNK_PORTSEL, + RTL_REG_EN_TRUNK, + RTL_REG_RESET, + + RTL_REG_VLAN_ENABLE, + RTL_REG_VLAN_FILTER, + RTL_REG_VLAN_TAG_ONLY, + RTL_REG_VLAN_TAG_AWARE, +#define RTL_VLAN_ENUM(id) \ + RTL_REG_VLAN##id##_VID, \ + RTL_REG_VLAN##id##_PORTMASK + RTL_VLAN_ENUM(0), + RTL_VLAN_ENUM(1), + RTL_VLAN_ENUM(2), + RTL_VLAN_ENUM(3), + RTL_VLAN_ENUM(4), + RTL_VLAN_ENUM(5), + RTL_VLAN_ENUM(6), + RTL_VLAN_ENUM(7), + RTL_VLAN_ENUM(8), + RTL_VLAN_ENUM(9), + RTL_VLAN_ENUM(10), + RTL_VLAN_ENUM(11), + RTL_VLAN_ENUM(12), + RTL_VLAN_ENUM(13), + RTL_VLAN_ENUM(14), + RTL_VLAN_ENUM(15), +#define RTL_PORT_ENUM(id) \ + RTL_REG_PORT##id##_PVID, \ + RTL_REG_PORT##id##_NULL_VID_REPLACE, \ + RTL_REG_PORT##id##_NON_PVID_DISCARD, \ + RTL_REG_PORT##id##_VID_INSERT, \ + RTL_REG_PORT##id##_TAG_INSERT, \ + RTL_REG_PORT##id##_LINK, \ + RTL_REG_PORT##id##_SPEED, \ + RTL_REG_PORT##id##_NWAY, \ + RTL_REG_PORT##id##_NRESTART, \ + RTL_REG_PORT##id##_DUPLEX, \ + RTL_REG_PORT##id##_RXEN, \ + RTL_REG_PORT##id##_TXEN + RTL_PORT_ENUM(0), + RTL_PORT_ENUM(1), + RTL_PORT_ENUM(2), + RTL_PORT_ENUM(3), + RTL_PORT_ENUM(4), + RTL_PORT_ENUM(5), +}; + +static const struct rtl_reg rtl_regs[] = { + [RTL_REG_CHIPID] = { 0, 4, 30, 16, 0, 0 }, + [RTL_REG_CHIPVER] = { 0, 4, 31, 8, 0, 0 }, + [RTL_REG_CHIPTYPE] = { 0, 4, 31, 2, 8, 0 }, + + /* CPU port number */ + [RTL_REG_CPUPORT] = { 2, 4, 21, 3, 0, 0 }, + /* Enable CPU port function */ + [RTL_REG_EN_CPUPORT] = { 3, 2, 21, 1, 15, 1 }, + /* Enable CPU port tag insertion */ + [RTL_REG_EN_TAG_OUT] = { 3, 2, 21, 1, 12, 0 }, + /* Enable CPU port tag removal */ + [RTL_REG_EN_TAG_CLR] = { 3, 2, 21, 1, 11, 0 }, + /* Enable CPU port tag checking */ + [RTL_REG_EN_TAG_IN] = { 0, 4, 21, 1, 7, 0 }, + [RTL_REG_EN_TRUNK] = { 0, 0, 19, 1, 11, 1 }, + [RTL_REG_TRUNK_PORTSEL] = { 0, 0, 16, 1, 6, 1 }, + [RTL_REG_RESET] = { 0, 0, 16, 1, 12, 0 }, + + [RTL_REG_TRAP_CPU] = { 3, 2, 22, 1, 6, 0 }, + [RTL_REG_CPU_LINKUP] = { 0, 6, 22, 1, 15, 0 }, + + [RTL_REG_VLAN_TAG_ONLY] = { 0, 0, 16, 1, 8, 1 }, + [RTL_REG_VLAN_FILTER] = { 0, 0, 16, 1, 9, 1 }, + [RTL_REG_VLAN_TAG_AWARE] = { 0, 0, 16, 1, 10, 1 }, + [RTL_REG_VLAN_ENABLE] = { 0, 0, 18, 1, 8, 1 }, + +#define RTL_VLAN_REGS(id, phy, page, regofs) \ + [RTL_REG_VLAN##id##_VID] = { page, phy, 25 + regofs, 12, 0, 0 }, \ + [RTL_REG_VLAN##id##_PORTMASK] = { page, phy, 24 + regofs, 6, 0, 0 } + RTL_VLAN_REGS( 0, 0, 0, 0), + RTL_VLAN_REGS( 1, 1, 0, 0), + RTL_VLAN_REGS( 2, 2, 0, 0), + RTL_VLAN_REGS( 3, 3, 0, 0), + RTL_VLAN_REGS( 4, 4, 0, 0), + RTL_VLAN_REGS( 5, 0, 1, 2), + RTL_VLAN_REGS( 6, 1, 1, 2), + RTL_VLAN_REGS( 7, 2, 1, 2), + RTL_VLAN_REGS( 8, 3, 1, 2), + RTL_VLAN_REGS( 9, 4, 1, 2), + RTL_VLAN_REGS(10, 0, 1, 4), + RTL_VLAN_REGS(11, 1, 1, 4), + RTL_VLAN_REGS(12, 2, 1, 4), + RTL_VLAN_REGS(13, 3, 1, 4), + RTL_VLAN_REGS(14, 4, 1, 4), + RTL_VLAN_REGS(15, 0, 1, 6), + +#define REG_PORT_SETTING(port, phy) \ + [RTL_REG_PORT##port##_SPEED] = { 0, phy, 0, 1, 13, 0 }, \ + [RTL_REG_PORT##port##_NWAY] = { 0, phy, 0, 1, 12, 0 }, \ + [RTL_REG_PORT##port##_NRESTART] = { 0, phy, 0, 1, 9, 0 }, \ + [RTL_REG_PORT##port##_DUPLEX] = { 0, phy, 0, 1, 8, 0 }, \ + [RTL_REG_PORT##port##_TXEN] = { 0, phy, 24, 1, 11, 0 }, \ + [RTL_REG_PORT##port##_RXEN] = { 0, phy, 24, 1, 10, 0 }, \ + [RTL_REG_PORT##port##_LINK] = { 0, phy, 1, 1, 2, 0 }, \ + [RTL_REG_PORT##port##_NULL_VID_REPLACE] = { 0, phy, 22, 1, 12, 0 }, \ + [RTL_REG_PORT##port##_NON_PVID_DISCARD] = { 0, phy, 22, 1, 11, 0 }, \ + [RTL_REG_PORT##port##_VID_INSERT] = { 0, phy, 22, 2, 9, 0 }, \ + [RTL_REG_PORT##port##_TAG_INSERT] = { 0, phy, 22, 2, 0, 0 } + + REG_PORT_SETTING(0, 0), + REG_PORT_SETTING(1, 1), + REG_PORT_SETTING(2, 2), + REG_PORT_SETTING(3, 3), + REG_PORT_SETTING(4, 4), + REG_PORT_SETTING(5, 6), + +#define REG_PORT_PVID(phy, page, regofs) \ + { page, phy, 24 + regofs, 4, 12, 0 } + [RTL_REG_PORT0_PVID] = REG_PORT_PVID(0, 0, 0), + [RTL_REG_PORT1_PVID] = REG_PORT_PVID(1, 0, 0), + [RTL_REG_PORT2_PVID] = REG_PORT_PVID(2, 0, 0), + [RTL_REG_PORT3_PVID] = REG_PORT_PVID(3, 0, 0), + [RTL_REG_PORT4_PVID] = REG_PORT_PVID(4, 0, 0), + [RTL_REG_PORT5_PVID] = REG_PORT_PVID(0, 1, 2), +}; + + +static inline void +rtl_set_page(struct rtl_priv *priv, unsigned int page) +{ + struct mii_bus *bus = priv->bus; + u16 pgsel; + + if (priv->fixup) + return; + + if (priv->page == page) + return; + + BUG_ON(page > RTL8306_NUM_PAGES); + pgsel = bus->read(bus, 0, RTL8306_REG_PAGE); + pgsel &= ~(RTL8306_REG_PAGE_LO | RTL8306_REG_PAGE_HI); + if (page & (1 << 0)) + pgsel |= RTL8306_REG_PAGE_LO; + if (!(page & (1 << 1))) /* bit is inverted */ + pgsel |= RTL8306_REG_PAGE_HI; + bus->write(bus, 0, RTL8306_REG_PAGE, pgsel); +} + +static inline int +rtl_w16(struct switch_dev *dev, unsigned int page, unsigned int phy, unsigned int reg, u16 val) +{ + struct rtl_priv *priv = to_rtl(dev); + struct mii_bus *bus = priv->bus; + + rtl_set_page(priv, page); + bus->write(bus, phy, reg, val); + bus->read(bus, phy, reg); /* flush */ + return 0; +} + +static inline int +rtl_r16(struct switch_dev *dev, unsigned int page, unsigned int phy, unsigned int reg) +{ + struct rtl_priv *priv = to_rtl(dev); + struct mii_bus *bus = priv->bus; + + rtl_set_page(priv, page); + return bus->read(bus, phy, reg); +} + +static inline u16 +rtl_rmw(struct switch_dev *dev, unsigned int page, unsigned int phy, unsigned int reg, u16 mask, u16 val) +{ + struct rtl_priv *priv = to_rtl(dev); + struct mii_bus *bus = priv->bus; + u16 r; + + rtl_set_page(priv, page); + r = bus->read(bus, phy, reg); + r &= ~mask; + r |= val; + bus->write(bus, phy, reg, r); + return bus->read(bus, phy, reg); /* flush */ +} + + +static inline int +rtl_get(struct switch_dev *dev, enum rtl_regidx s) +{ + const struct rtl_reg *r = &rtl_regs[s]; + u16 val; + + BUG_ON(s >= ARRAY_SIZE(rtl_regs)); + if (r->bits == 0) /* unimplemented */ + return 0; + + val = rtl_r16(dev, r->page, r->phy, r->reg); + + if (r->shift > 0) + val >>= r->shift; + + if (r->inverted) + val = ~val; + + val &= (1 << r->bits) - 1; + + return val; +} + +static int +rtl_set(struct switch_dev *dev, enum rtl_regidx s, unsigned int val) +{ + const struct rtl_reg *r = &rtl_regs[s]; + u16 mask = 0xffff; + + BUG_ON(s >= ARRAY_SIZE(rtl_regs)); + + if (r->bits == 0) /* unimplemented */ + return 0; + + if (r->shift > 0) + val <<= r->shift; + + if (r->inverted) + val = ~val; + + if (r->bits != 16) { + mask = (1 << r->bits) - 1; + mask <<= r->shift; + } + val &= mask; + return rtl_rmw(dev, r->page, r->phy, r->reg, mask, val); +} + +static void +rtl_phy_save(struct switch_dev *dev, int port, struct rtl_phyregs *regs) +{ + regs->nway = rtl_get(dev, RTL_PORT_REG(port, NWAY)); + regs->speed = rtl_get(dev, RTL_PORT_REG(port, SPEED)); + regs->duplex = rtl_get(dev, RTL_PORT_REG(port, DUPLEX)); +} + +static void +rtl_phy_restore(struct switch_dev *dev, int port, struct rtl_phyregs *regs) +{ + rtl_set(dev, RTL_PORT_REG(port, NWAY), regs->nway); + rtl_set(dev, RTL_PORT_REG(port, SPEED), regs->speed); + rtl_set(dev, RTL_PORT_REG(port, DUPLEX), regs->duplex); +} + +static void +rtl_port_set_enable(struct switch_dev *dev, int port, int enabled) +{ + rtl_set(dev, RTL_PORT_REG(port, RXEN), enabled); + rtl_set(dev, RTL_PORT_REG(port, TXEN), enabled); + + if ((port >= 5) || !enabled) + return; + + /* restart autonegotiation if enabled */ + rtl_set(dev, RTL_PORT_REG(port, NRESTART), 1); +} + +static int +rtl_hw_apply(struct switch_dev *dev) +{ + int i; + int trunk_en, trunk_psel; + struct rtl_phyregs port5; + + rtl_phy_save(dev, 5, &port5); + + /* disable rx/tx from PHYs */ + for (i = 0; i < RTL8306_NUM_PORTS - 1; i++) { + rtl_port_set_enable(dev, i, 0); + } + + /* save trunking status */ + trunk_en = rtl_get(dev, RTL_REG_EN_TRUNK); + trunk_psel = rtl_get(dev, RTL_REG_TRUNK_PORTSEL); + + /* trunk port 3 and 4 + * XXX: Big WTF, but RealTek seems to do it */ + rtl_set(dev, RTL_REG_EN_TRUNK, 1); + rtl_set(dev, RTL_REG_TRUNK_PORTSEL, 1); + + /* execute the software reset */ + rtl_set(dev, RTL_REG_RESET, 1); + + /* wait for the reset to complete, + * but don't wait for too long */ + for (i = 0; i < 10; i++) { + if (rtl_get(dev, RTL_REG_RESET) == 0) + break; + + msleep(1); + } + + /* enable rx/tx from PHYs */ + for (i = 0; i < RTL8306_NUM_PORTS - 1; i++) { + rtl_port_set_enable(dev, i, 1); + } + + /* restore trunking settings */ + rtl_set(dev, RTL_REG_EN_TRUNK, trunk_en); + rtl_set(dev, RTL_REG_TRUNK_PORTSEL, trunk_psel); + rtl_phy_restore(dev, 5, &port5); + + rtl_set(dev, RTL_REG_CPU_LINKUP, 1); + + return 0; +} + +static void +rtl_hw_init(struct switch_dev *dev) +{ + struct rtl_priv *priv = to_rtl(dev); + int cpu_mask = 1 << dev->cpu_port; + int i; + + rtl_set(dev, RTL_REG_VLAN_ENABLE, 0); + rtl_set(dev, RTL_REG_VLAN_FILTER, 0); + rtl_set(dev, RTL_REG_EN_TRUNK, 0); + rtl_set(dev, RTL_REG_TRUNK_PORTSEL, 0); + + /* initialize cpu port settings */ + if (priv->do_cpu) { + rtl_set(dev, RTL_REG_CPUPORT, dev->cpu_port); + rtl_set(dev, RTL_REG_EN_CPUPORT, 1); + } else { + rtl_set(dev, RTL_REG_CPUPORT, 7); + rtl_set(dev, RTL_REG_EN_CPUPORT, 0); + } + rtl_set(dev, RTL_REG_EN_TAG_OUT, 0); + rtl_set(dev, RTL_REG_EN_TAG_IN, 0); + rtl_set(dev, RTL_REG_EN_TAG_CLR, 0); + + /* reset all vlans */ + for (i = 0; i < RTL8306_NUM_VLANS; i++) { + rtl_set(dev, RTL_VLAN_REG(i, VID), i); + rtl_set(dev, RTL_VLAN_REG(i, PORTMASK), 0); + } + + /* default to port isolation */ + for (i = 0; i < RTL8306_NUM_PORTS; i++) { + unsigned long mask; + + if ((1 << i) == cpu_mask) + mask = ((1 << RTL8306_NUM_PORTS) - 1) & ~cpu_mask; /* all bits set */ + else + mask = cpu_mask | (1 << i); + + rtl_set(dev, RTL_VLAN_REG(i, PORTMASK), mask); + rtl_set(dev, RTL_PORT_REG(i, PVID), i); + rtl_set(dev, RTL_PORT_REG(i, NULL_VID_REPLACE), 1); + rtl_set(dev, RTL_PORT_REG(i, VID_INSERT), 1); + rtl_set(dev, RTL_PORT_REG(i, TAG_INSERT), 3); + } + rtl_hw_apply(dev); +} + +#ifdef DEBUG +static int +rtl_set_use_cpuport(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + struct rtl_priv *priv = to_rtl(dev); + priv->do_cpu = val->value.i; + rtl_hw_init(dev); + return 0; +} + +static int +rtl_get_use_cpuport(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + struct rtl_priv *priv = to_rtl(dev); + val->value.i = priv->do_cpu; + return 0; +} + +static int +rtl_set_cpuport(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + dev->cpu_port = val->value.i; + rtl_hw_init(dev); + return 0; +} + +static int +rtl_get_cpuport(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + val->value.i = dev->cpu_port; + return 0; +} +#endif + +static int +rtl_reset(struct switch_dev *dev) +{ + rtl_hw_init(dev); + return 0; +} + +static int +rtl_attr_set_int(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + int idx = attr->id + (val->port_vlan * attr->ofs); + struct rtl_phyregs port; + + if (attr->id >= ARRAY_SIZE(rtl_regs)) + return -EINVAL; + + if ((attr->max > 0) && (val->value.i > attr->max)) + return -EINVAL; + + /* access to phy register 22 on port 4/5 + * needs phy status save/restore */ + if ((val->port_vlan > 3) && + (rtl_regs[idx].reg == 22) && + (rtl_regs[idx].page == 0)) { + + rtl_phy_save(dev, val->port_vlan, &port); + rtl_set(dev, idx, val->value.i); + rtl_phy_restore(dev, val->port_vlan, &port); + } else { + rtl_set(dev, idx, val->value.i); + } + + return 0; +} + +static int +rtl_attr_get_int(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + int idx = attr->id + (val->port_vlan * attr->ofs); + + if (idx >= ARRAY_SIZE(rtl_regs)) + return -EINVAL; + + val->value.i = rtl_get(dev, idx); + return 0; +} + +static int +rtl_attr_set_port_int(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + if (val->port_vlan >= RTL8306_NUM_PORTS) + return -EINVAL; + + return rtl_attr_set_int(dev, attr, val); +} + +static int +rtl_attr_get_port_int(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + if (val->port_vlan >= RTL8306_NUM_PORTS) + return -EINVAL; + return rtl_attr_get_int(dev, attr, val); +} + +static int +rtl_get_port_link(struct switch_dev *dev, int port, struct switch_port_link *link) +{ + if (port >= RTL8306_NUM_PORTS) + return -EINVAL; + + link->link = rtl_get(dev, RTL_PORT_REG(port, LINK)); + if (!link->link) + return 0; + + link->duplex = rtl_get(dev, RTL_PORT_REG(port, DUPLEX)); + link->aneg = rtl_get(dev, RTL_PORT_REG(port, NWAY)); + + if (rtl_get(dev, RTL_PORT_REG(port, SPEED))) + link->speed = SWITCH_PORT_SPEED_100; + else + link->speed = SWITCH_PORT_SPEED_10; + + return 0; +} + +static int +rtl_attr_set_vlan_int(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + if (val->port_vlan >= dev->vlans) + return -EINVAL; + + return rtl_attr_set_int(dev, attr, val); +} + +static int +rtl_attr_get_vlan_int(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + if (val->port_vlan >= dev->vlans) + return -EINVAL; + + return rtl_attr_get_int(dev, attr, val); +} + +static int +rtl_get_ports(struct switch_dev *dev, struct switch_val *val) +{ + unsigned int i, mask; + + mask = rtl_get(dev, RTL_VLAN_REG(val->port_vlan, PORTMASK)); + for (i = 0; i < RTL8306_NUM_PORTS; i++) { + struct switch_port *port; + + if (!(mask & (1 << i))) + continue; + + port = &val->value.ports[val->len]; + port->id = i; + if (rtl_get(dev, RTL_PORT_REG(i, TAG_INSERT)) == 2 || i == dev->cpu_port) + port->flags = (1 << SWITCH_PORT_FLAG_TAGGED); + val->len++; + } + + return 0; +} + +static int +rtl_set_vlan(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + struct rtl_priv *priv = to_rtl(dev); + struct rtl_phyregs port; + int en = val->value.i; + int i; + + rtl_set(dev, RTL_REG_EN_TAG_OUT, en && priv->do_cpu); + rtl_set(dev, RTL_REG_EN_TAG_IN, en && priv->do_cpu); + rtl_set(dev, RTL_REG_EN_TAG_CLR, en && priv->do_cpu); + rtl_set(dev, RTL_REG_VLAN_TAG_AWARE, en); + if (en) + rtl_set(dev, RTL_REG_VLAN_FILTER, en); + + for (i = 0; i < RTL8306_NUM_PORTS; i++) { + if (i > 3) + rtl_phy_save(dev, val->port_vlan, &port); + rtl_set(dev, RTL_PORT_REG(i, NULL_VID_REPLACE), 1); + rtl_set(dev, RTL_PORT_REG(i, VID_INSERT), (en ? (i == dev->cpu_port ? 0 : 1) : 1)); + rtl_set(dev, RTL_PORT_REG(i, TAG_INSERT), (en ? (i == dev->cpu_port ? 2 : 1) : 3)); + if (i > 3) + rtl_phy_restore(dev, val->port_vlan, &port); + } + rtl_set(dev, RTL_REG_VLAN_ENABLE, en); + + return 0; +} + +static int +rtl_get_vlan(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + val->value.i = rtl_get(dev, RTL_REG_VLAN_ENABLE); + return 0; +} + +static int +rtl_set_ports(struct switch_dev *dev, struct switch_val *val) +{ + unsigned int mask = 0; + unsigned int oldmask; + int i; + + for(i = 0; i < val->len; i++) + { + struct switch_port *port = &val->value.ports[i]; + bool tagged = false; + + mask |= (1 << port->id); + + if (port->id == dev->cpu_port) + continue; + + if ((i == dev->cpu_port) || + (port->flags & (1 << SWITCH_PORT_FLAG_TAGGED))) + tagged = true; + + /* fix up PVIDs for added ports */ + if (!tagged) + rtl_set(dev, RTL_PORT_REG(port->id, PVID), val->port_vlan); + + rtl_set(dev, RTL_PORT_REG(port->id, NON_PVID_DISCARD), (tagged ? 0 : 1)); + rtl_set(dev, RTL_PORT_REG(port->id, VID_INSERT), (tagged ? 0 : 1)); + rtl_set(dev, RTL_PORT_REG(port->id, TAG_INSERT), (tagged ? 2 : 1)); + } + + oldmask = rtl_get(dev, RTL_VLAN_REG(val->port_vlan, PORTMASK)); + rtl_set(dev, RTL_VLAN_REG(val->port_vlan, PORTMASK), mask); + + /* fix up PVIDs for removed ports, default to last vlan */ + oldmask &= ~mask; + for (i = 0; i < RTL8306_NUM_PORTS; i++) { + if (!(oldmask & (1 << i))) + continue; + + if (i == dev->cpu_port) + continue; + + if (rtl_get(dev, RTL_PORT_REG(i, PVID)) == val->port_vlan) + rtl_set(dev, RTL_PORT_REG(i, PVID), dev->vlans - 1); + } + + return 0; +} + +static struct switch_attr rtl_globals[] = { + { + .type = SWITCH_TYPE_INT, + .name = "enable_vlan", + .description = "Enable VLAN mode", + .max = 1, + .set = rtl_set_vlan, + .get = rtl_get_vlan, + }, + { + RTL_GLOBAL_REGATTR(EN_TRUNK), + .name = "trunk", + .description = "Enable port trunking", + .max = 1, + }, + { + RTL_GLOBAL_REGATTR(TRUNK_PORTSEL), + .name = "trunk_sel", + .description = "Select ports for trunking (0: 0,1 - 1: 3,4)", + .max = 1, + }, +#ifdef DEBUG + { + RTL_GLOBAL_REGATTR(VLAN_FILTER), + .name = "vlan_filter", + .description = "Filter incoming packets for allowed VLANS", + .max = 1, + }, + { + .type = SWITCH_TYPE_INT, + .name = "cpuport", + .description = "CPU Port", + .set = rtl_set_cpuport, + .get = rtl_get_cpuport, + .max = RTL8306_NUM_PORTS, + }, + { + .type = SWITCH_TYPE_INT, + .name = "use_cpuport", + .description = "CPU Port handling flag", + .set = rtl_set_use_cpuport, + .get = rtl_get_use_cpuport, + .max = RTL8306_NUM_PORTS, + }, + { + RTL_GLOBAL_REGATTR(TRAP_CPU), + .name = "trap_cpu", + .description = "VLAN trap to CPU", + .max = 1, + }, + { + RTL_GLOBAL_REGATTR(VLAN_TAG_AWARE), + .name = "vlan_tag_aware", + .description = "Enable VLAN tag awareness", + .max = 1, + }, + { + RTL_GLOBAL_REGATTR(VLAN_TAG_ONLY), + .name = "tag_only", + .description = "Only accept tagged packets", + .max = 1, + }, +#endif +}; +static struct switch_attr rtl_port[] = { + { + RTL_PORT_REGATTR(PVID), + .name = "pvid", + .description = "Port VLAN ID", + .max = RTL8306_NUM_VLANS - 1, + }, +#ifdef DEBUG + { + RTL_PORT_REGATTR(NULL_VID_REPLACE), + .name = "null_vid", + .description = "NULL VID gets replaced by port default vid", + .max = 1, + }, + { + RTL_PORT_REGATTR(NON_PVID_DISCARD), + .name = "non_pvid_discard", + .description = "discard packets with VID != PVID", + .max = 1, + }, + { + RTL_PORT_REGATTR(VID_INSERT), + .name = "vid_insert_remove", + .description = "how should the switch insert and remove vids ?", + .max = 3, + }, + { + RTL_PORT_REGATTR(TAG_INSERT), + .name = "tag_insert", + .description = "tag insertion handling", + .max = 3, + }, +#endif +}; + +static struct switch_attr rtl_vlan[] = { + { + RTL_VLAN_REGATTR(VID), + .name = "vid", + .description = "VLAN ID (1-4095)", + .max = 4095, + }, +}; + +static const struct switch_dev_ops rtl8306_ops = { + .attr_global = { + .attr = rtl_globals, + .n_attr = ARRAY_SIZE(rtl_globals), + }, + .attr_port = { + .attr = rtl_port, + .n_attr = ARRAY_SIZE(rtl_port), + }, + .attr_vlan = { + .attr = rtl_vlan, + .n_attr = ARRAY_SIZE(rtl_vlan), + }, + + .get_vlan_ports = rtl_get_ports, + .set_vlan_ports = rtl_set_ports, + .apply_config = rtl_hw_apply, + .reset_switch = rtl_reset, + .get_port_link = rtl_get_port_link, +}; + +static int +rtl8306_config_init(struct phy_device *pdev) +{ + struct net_device *netdev = pdev->attached_dev; + struct rtl_priv *priv = pdev->priv; + struct switch_dev *dev = &priv->dev; + struct switch_val val; + unsigned int chipid, chipver, chiptype; + int err; + + /* Only init the switch for the primary PHY */ + if (pdev->addr != 0) + return 0; + + val.value.i = 1; + priv->dev.cpu_port = RTL8306_PORT_CPU; + priv->dev.ports = RTL8306_NUM_PORTS; + priv->dev.vlans = RTL8306_NUM_VLANS; + priv->dev.ops = &rtl8306_ops; + priv->do_cpu = 0; + priv->page = -1; + priv->bus = pdev->bus; + + chipid = rtl_get(dev, RTL_REG_CHIPID); + chipver = rtl_get(dev, RTL_REG_CHIPVER); + chiptype = rtl_get(dev, RTL_REG_CHIPTYPE); + switch(chiptype) { + case 0: + case 2: + strncpy(priv->hwname, RTL_NAME_S, sizeof(priv->hwname)); + priv->type = RTL_TYPE_S; + break; + case 1: + strncpy(priv->hwname, RTL_NAME_SD, sizeof(priv->hwname)); + priv->type = RTL_TYPE_SD; + break; + case 3: + strncpy(priv->hwname, RTL_NAME_SDM, sizeof(priv->hwname)); + priv->type = RTL_TYPE_SDM; + break; + default: + strncpy(priv->hwname, RTL_NAME_UNKNOWN, sizeof(priv->hwname)); + break; + } + + dev->name = priv->hwname; + rtl_hw_init(dev); + + printk(KERN_INFO "Registering %s switch with Chip ID: 0x%04x, version: 0x%04x\n", priv->hwname, chipid, chipver); + + err = register_switch(dev, netdev); + if (err < 0) { + kfree(priv); + return err; + } + + return 0; +} + + +static int +rtl8306_fixup(struct phy_device *pdev) +{ + struct rtl_priv priv; + u16 chipid; + + /* Attach to primary LAN port and WAN port */ + if (pdev->addr != 0 && pdev->addr != 4) + return 0; + + memset(&priv, 0, sizeof(priv)); + priv.fixup = true; + priv.page = -1; + priv.bus = pdev->bus; + chipid = rtl_get(&priv.dev, RTL_REG_CHIPID); + if (chipid == 0x5988) + pdev->phy_id = RTL8306_MAGIC; + + return 0; +} + +static int +rtl8306_probe(struct phy_device *pdev) +{ + struct rtl_priv *priv; + + list_for_each_entry(priv, &phydevs, list) { + /* + * share one rtl_priv instance between virtual phy + * devices on the same bus + */ + if (priv->bus == pdev->bus) + goto found; + } + priv = kzalloc(sizeof(struct rtl_priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->bus = pdev->bus; + +found: + pdev->priv = priv; + return 0; +} + +static void +rtl8306_remove(struct phy_device *pdev) +{ + struct rtl_priv *priv = pdev->priv; + unregister_switch(&priv->dev); + kfree(priv); +} + +static int +rtl8306_config_aneg(struct phy_device *pdev) +{ + struct rtl_priv *priv = pdev->priv; + + /* Only for WAN */ + if (pdev->addr == 0) + return 0; + + /* Restart autonegotiation */ + rtl_set(&priv->dev, RTL_PORT_REG(4, NWAY), 1); + rtl_set(&priv->dev, RTL_PORT_REG(4, NRESTART), 1); + + return 0; +} + +static int +rtl8306_read_status(struct phy_device *pdev) +{ + struct rtl_priv *priv = pdev->priv; + struct switch_dev *dev = &priv->dev; + + if (pdev->addr == 4) { + /* WAN */ + pdev->speed = rtl_get(dev, RTL_PORT_REG(4, SPEED)) ? SPEED_100 : SPEED_10; + pdev->duplex = rtl_get(dev, RTL_PORT_REG(4, DUPLEX)) ? DUPLEX_FULL : DUPLEX_HALF; + pdev->link = !!rtl_get(dev, RTL_PORT_REG(4, LINK)); + } else { + /* LAN */ + pdev->speed = SPEED_100; + pdev->duplex = DUPLEX_FULL; + pdev->link = 1; + } + + /* + * Bypass generic PHY status read, + * it doesn't work with this switch + */ + if (pdev->link) { + pdev->state = PHY_RUNNING; + netif_carrier_on(pdev->attached_dev); + pdev->adjust_link(pdev->attached_dev); + } else { + pdev->state = PHY_NOLINK; + netif_carrier_off(pdev->attached_dev); + pdev->adjust_link(pdev->attached_dev); + } + + return 0; +} + + +static struct phy_driver rtl8306_driver = { + .name = "Realtek RTL8306S", + .flags = PHY_HAS_MAGICANEG, + .phy_id = RTL8306_MAGIC, + .phy_id_mask = 0xffffffff, + .features = PHY_BASIC_FEATURES, + .probe = &rtl8306_probe, + .remove = &rtl8306_remove, + .config_init = &rtl8306_config_init, + .config_aneg = &rtl8306_config_aneg, + .read_status = &rtl8306_read_status, + .driver = { .owner = THIS_MODULE,}, +}; + + +static int __init +rtl_init(void) +{ + phy_register_fixup_for_id(PHY_ANY_ID, rtl8306_fixup); + return phy_driver_register(&rtl8306_driver); +} + +static void __exit +rtl_exit(void) +{ + phy_driver_unregister(&rtl8306_driver); +} + +module_init(rtl_init); +module_exit(rtl_exit); +MODULE_LICENSE("GPL"); + diff --git a/target/linux/generic/files/drivers/net/phy/rtl8366_smi.c b/target/linux/generic/files/drivers/net/phy/rtl8366_smi.c new file mode 100644 index 0000000..699234d --- /dev/null +++ b/target/linux/generic/files/drivers/net/phy/rtl8366_smi.c @@ -0,0 +1,1449 @@ +/* + * Realtek RTL8366 SMI interface driver + * + * Copyright (C) 2009-2010 Gabor Juhos + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_RTL8366_SMI_DEBUG_FS +#include +#endif + +#include "rtl8366_smi.h" + +#define RTL8366_SMI_ACK_RETRY_COUNT 5 + +#define RTL8366_SMI_HW_STOP_DELAY 25 /* msecs */ +#define RTL8366_SMI_HW_START_DELAY 100 /* msecs */ + +static inline void rtl8366_smi_clk_delay(struct rtl8366_smi *smi) +{ + ndelay(smi->clk_delay); +} + +static void rtl8366_smi_start(struct rtl8366_smi *smi) +{ + unsigned int sda = smi->gpio_sda; + unsigned int sck = smi->gpio_sck; + + /* + * Set GPIO pins to output mode, with initial state: + * SCK = 0, SDA = 1 + */ + gpio_direction_output(sck, 0); + gpio_direction_output(sda, 1); + rtl8366_smi_clk_delay(smi); + + /* CLK 1: 0 -> 1, 1 -> 0 */ + gpio_set_value(sck, 1); + rtl8366_smi_clk_delay(smi); + gpio_set_value(sck, 0); + rtl8366_smi_clk_delay(smi); + + /* CLK 2: */ + gpio_set_value(sck, 1); + rtl8366_smi_clk_delay(smi); + gpio_set_value(sda, 0); + rtl8366_smi_clk_delay(smi); + gpio_set_value(sck, 0); + rtl8366_smi_clk_delay(smi); + gpio_set_value(sda, 1); +} + +static void rtl8366_smi_stop(struct rtl8366_smi *smi) +{ + unsigned int sda = smi->gpio_sda; + unsigned int sck = smi->gpio_sck; + + rtl8366_smi_clk_delay(smi); + gpio_set_value(sda, 0); + gpio_set_value(sck, 1); + rtl8366_smi_clk_delay(smi); + gpio_set_value(sda, 1); + rtl8366_smi_clk_delay(smi); + gpio_set_value(sck, 1); + rtl8366_smi_clk_delay(smi); + gpio_set_value(sck, 0); + rtl8366_smi_clk_delay(smi); + gpio_set_value(sck, 1); + + /* add a click */ + rtl8366_smi_clk_delay(smi); + gpio_set_value(sck, 0); + rtl8366_smi_clk_delay(smi); + gpio_set_value(sck, 1); + + /* set GPIO pins to input mode */ + gpio_direction_input(sda); + gpio_direction_input(sck); +} + +static void rtl8366_smi_write_bits(struct rtl8366_smi *smi, u32 data, u32 len) +{ + unsigned int sda = smi->gpio_sda; + unsigned int sck = smi->gpio_sck; + + for (; len > 0; len--) { + rtl8366_smi_clk_delay(smi); + + /* prepare data */ + gpio_set_value(sda, !!(data & ( 1 << (len - 1)))); + rtl8366_smi_clk_delay(smi); + + /* clocking */ + gpio_set_value(sck, 1); + rtl8366_smi_clk_delay(smi); + gpio_set_value(sck, 0); + } +} + +static void rtl8366_smi_read_bits(struct rtl8366_smi *smi, u32 len, u32 *data) +{ + unsigned int sda = smi->gpio_sda; + unsigned int sck = smi->gpio_sck; + + gpio_direction_input(sda); + + for (*data = 0; len > 0; len--) { + u32 u; + + rtl8366_smi_clk_delay(smi); + + /* clocking */ + gpio_set_value(sck, 1); + rtl8366_smi_clk_delay(smi); + u = !!gpio_get_value(sda); + gpio_set_value(sck, 0); + + *data |= (u << (len - 1)); + } + + gpio_direction_output(sda, 0); +} + +static int rtl8366_smi_wait_for_ack(struct rtl8366_smi *smi) +{ + int retry_cnt; + + retry_cnt = 0; + do { + u32 ack; + + rtl8366_smi_read_bits(smi, 1, &ack); + if (ack == 0) + break; + + if (++retry_cnt > RTL8366_SMI_ACK_RETRY_COUNT) { + dev_err(smi->parent, "ACK timeout\n"); + return -ETIMEDOUT; + } + } while (1); + + return 0; +} + +static int rtl8366_smi_write_byte(struct rtl8366_smi *smi, u8 data) +{ + rtl8366_smi_write_bits(smi, data, 8); + return rtl8366_smi_wait_for_ack(smi); +} + +static int rtl8366_smi_write_byte_noack(struct rtl8366_smi *smi, u8 data) +{ + rtl8366_smi_write_bits(smi, data, 8); + return 0; +} + +static int rtl8366_smi_read_byte0(struct rtl8366_smi *smi, u8 *data) +{ + u32 t; + + /* read data */ + rtl8366_smi_read_bits(smi, 8, &t); + *data = (t & 0xff); + + /* send an ACK */ + rtl8366_smi_write_bits(smi, 0x00, 1); + + return 0; +} + +static int rtl8366_smi_read_byte1(struct rtl8366_smi *smi, u8 *data) +{ + u32 t; + + /* read data */ + rtl8366_smi_read_bits(smi, 8, &t); + *data = (t & 0xff); + + /* send an ACK */ + rtl8366_smi_write_bits(smi, 0x01, 1); + + return 0; +} + +int rtl8366_smi_read_reg(struct rtl8366_smi *smi, u32 addr, u32 *data) +{ + unsigned long flags; + u8 lo = 0; + u8 hi = 0; + int ret; + + spin_lock_irqsave(&smi->lock, flags); + + rtl8366_smi_start(smi); + + /* send READ command */ + ret = rtl8366_smi_write_byte(smi, smi->cmd_read); + if (ret) + goto out; + + /* set ADDR[7:0] */ + ret = rtl8366_smi_write_byte(smi, addr & 0xff); + if (ret) + goto out; + + /* set ADDR[15:8] */ + ret = rtl8366_smi_write_byte(smi, addr >> 8); + if (ret) + goto out; + + /* read DATA[7:0] */ + rtl8366_smi_read_byte0(smi, &lo); + /* read DATA[15:8] */ + rtl8366_smi_read_byte1(smi, &hi); + + *data = ((u32) lo) | (((u32) hi) << 8); + + ret = 0; + + out: + rtl8366_smi_stop(smi); + spin_unlock_irqrestore(&smi->lock, flags); + + return ret; +} +EXPORT_SYMBOL_GPL(rtl8366_smi_read_reg); + +static int __rtl8366_smi_write_reg(struct rtl8366_smi *smi, + u32 addr, u32 data, bool ack) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(&smi->lock, flags); + + rtl8366_smi_start(smi); + + /* send WRITE command */ + ret = rtl8366_smi_write_byte(smi, smi->cmd_write); + if (ret) + goto out; + + /* set ADDR[7:0] */ + ret = rtl8366_smi_write_byte(smi, addr & 0xff); + if (ret) + goto out; + + /* set ADDR[15:8] */ + ret = rtl8366_smi_write_byte(smi, addr >> 8); + if (ret) + goto out; + + /* write DATA[7:0] */ + ret = rtl8366_smi_write_byte(smi, data & 0xff); + if (ret) + goto out; + + /* write DATA[15:8] */ + if (ack) + ret = rtl8366_smi_write_byte(smi, data >> 8); + else + ret = rtl8366_smi_write_byte_noack(smi, data >> 8); + if (ret) + goto out; + + ret = 0; + + out: + rtl8366_smi_stop(smi); + spin_unlock_irqrestore(&smi->lock, flags); + + return ret; +} + +int rtl8366_smi_write_reg(struct rtl8366_smi *smi, u32 addr, u32 data) +{ + return __rtl8366_smi_write_reg(smi, addr, data, true); +} +EXPORT_SYMBOL_GPL(rtl8366_smi_write_reg); + +int rtl8366_smi_write_reg_noack(struct rtl8366_smi *smi, u32 addr, u32 data) +{ + return __rtl8366_smi_write_reg(smi, addr, data, false); +} +EXPORT_SYMBOL_GPL(rtl8366_smi_write_reg_noack); + +int rtl8366_smi_rmwr(struct rtl8366_smi *smi, u32 addr, u32 mask, u32 data) +{ + u32 t; + int err; + + err = rtl8366_smi_read_reg(smi, addr, &t); + if (err) + return err; + + err = rtl8366_smi_write_reg(smi, addr, (t & ~mask) | data); + return err; + +} +EXPORT_SYMBOL_GPL(rtl8366_smi_rmwr); + +static int rtl8366_reset(struct rtl8366_smi *smi) +{ + if (smi->hw_reset) { + smi->hw_reset(true); + msleep(RTL8366_SMI_HW_STOP_DELAY); + smi->hw_reset(false); + msleep(RTL8366_SMI_HW_START_DELAY); + return 0; + } + + return smi->ops->reset_chip(smi); +} + +static int rtl8366_mc_is_used(struct rtl8366_smi *smi, int mc_index, int *used) +{ + int err; + int i; + + *used = 0; + for (i = 0; i < smi->num_ports; i++) { + int index = 0; + + err = smi->ops->get_mc_index(smi, i, &index); + if (err) + return err; + + if (mc_index == index) { + *used = 1; + break; + } + } + + return 0; +} + +static int rtl8366_set_vlan(struct rtl8366_smi *smi, int vid, u32 member, + u32 untag, u32 fid) +{ + struct rtl8366_vlan_4k vlan4k; + int err; + int i; + + /* Update the 4K table */ + err = smi->ops->get_vlan_4k(smi, vid, &vlan4k); + if (err) + return err; + + vlan4k.member = member; + vlan4k.untag = untag; + vlan4k.fid = fid; + err = smi->ops->set_vlan_4k(smi, &vlan4k); + if (err) + return err; + + /* Try to find an existing MC entry for this VID */ + for (i = 0; i < smi->num_vlan_mc; i++) { + struct rtl8366_vlan_mc vlanmc; + + err = smi->ops->get_vlan_mc(smi, i, &vlanmc); + if (err) + return err; + + if (vid == vlanmc.vid) { + /* update the MC entry */ + vlanmc.member = member; + vlanmc.untag = untag; + vlanmc.fid = fid; + + err = smi->ops->set_vlan_mc(smi, i, &vlanmc); + break; + } + } + + return err; +} + +static int rtl8366_get_pvid(struct rtl8366_smi *smi, int port, int *val) +{ + struct rtl8366_vlan_mc vlanmc; + int err; + int index; + + err = smi->ops->get_mc_index(smi, port, &index); + if (err) + return err; + + err = smi->ops->get_vlan_mc(smi, index, &vlanmc); + if (err) + return err; + + *val = vlanmc.vid; + return 0; +} + +static int rtl8366_set_pvid(struct rtl8366_smi *smi, unsigned port, + unsigned vid) +{ + struct rtl8366_vlan_mc vlanmc; + struct rtl8366_vlan_4k vlan4k; + int err; + int i; + + /* Try to find an existing MC entry for this VID */ + for (i = 0; i < smi->num_vlan_mc; i++) { + err = smi->ops->get_vlan_mc(smi, i, &vlanmc); + if (err) + return err; + + if (vid == vlanmc.vid) { + err = smi->ops->set_vlan_mc(smi, i, &vlanmc); + if (err) + return err; + + err = smi->ops->set_mc_index(smi, port, i); + return err; + } + } + + /* We have no MC entry for this VID, try to find an empty one */ + for (i = 0; i < smi->num_vlan_mc; i++) { + err = smi->ops->get_vlan_mc(smi, i, &vlanmc); + if (err) + return err; + + if (vlanmc.vid == 0 && vlanmc.member == 0) { + /* Update the entry from the 4K table */ + err = smi->ops->get_vlan_4k(smi, vid, &vlan4k); + if (err) + return err; + + vlanmc.vid = vid; + vlanmc.member = vlan4k.member; + vlanmc.untag = vlan4k.untag; + vlanmc.fid = vlan4k.fid; + err = smi->ops->set_vlan_mc(smi, i, &vlanmc); + if (err) + return err; + + err = smi->ops->set_mc_index(smi, port, i); + return err; + } + } + + /* MC table is full, try to find an unused entry and replace it */ + for (i = 0; i < smi->num_vlan_mc; i++) { + int used; + + err = rtl8366_mc_is_used(smi, i, &used); + if (err) + return err; + + if (!used) { + /* Update the entry from the 4K table */ + err = smi->ops->get_vlan_4k(smi, vid, &vlan4k); + if (err) + return err; + + vlanmc.vid = vid; + vlanmc.member = vlan4k.member; + vlanmc.untag = vlan4k.untag; + vlanmc.fid = vlan4k.fid; + err = smi->ops->set_vlan_mc(smi, i, &vlanmc); + if (err) + return err; + + err = smi->ops->set_mc_index(smi, port, i); + return err; + } + } + + dev_err(smi->parent, + "all VLAN member configurations are in use\n"); + + return -ENOSPC; +} + +int rtl8366_enable_vlan(struct rtl8366_smi *smi, int enable) +{ + int err; + + err = smi->ops->enable_vlan(smi, enable); + if (err) + return err; + + smi->vlan_enabled = enable; + + if (!enable) { + smi->vlan4k_enabled = 0; + err = smi->ops->enable_vlan4k(smi, enable); + } + + return err; +} +EXPORT_SYMBOL_GPL(rtl8366_enable_vlan); + +static int rtl8366_enable_vlan4k(struct rtl8366_smi *smi, int enable) +{ + int err; + + if (enable) { + err = smi->ops->enable_vlan(smi, enable); + if (err) + return err; + + smi->vlan_enabled = enable; + } + + err = smi->ops->enable_vlan4k(smi, enable); + if (err) + return err; + + smi->vlan4k_enabled = enable; + return 0; +} + +int rtl8366_enable_all_ports(struct rtl8366_smi *smi, int enable) +{ + int port; + int err; + + for (port = 0; port < smi->num_ports; port++) { + err = smi->ops->enable_port(smi, port, enable); + if (err) + return err; + } + + return 0; +} +EXPORT_SYMBOL_GPL(rtl8366_enable_all_ports); + +int rtl8366_reset_vlan(struct rtl8366_smi *smi) +{ + struct rtl8366_vlan_mc vlanmc; + int err; + int i; + + rtl8366_enable_vlan(smi, 0); + rtl8366_enable_vlan4k(smi, 0); + + /* clear VLAN member configurations */ + vlanmc.vid = 0; + vlanmc.priority = 0; + vlanmc.member = 0; + vlanmc.untag = 0; + vlanmc.fid = 0; + for (i = 0; i < smi->num_vlan_mc; i++) { + err = smi->ops->set_vlan_mc(smi, i, &vlanmc); + if (err) + return err; + } + + return 0; +} +EXPORT_SYMBOL_GPL(rtl8366_reset_vlan); + +static int rtl8366_init_vlan(struct rtl8366_smi *smi) +{ + int port; + int err; + + err = rtl8366_reset_vlan(smi); + if (err) + return err; + + for (port = 0; port < smi->num_ports; port++) { + u32 mask; + + if (port == smi->cpu_port) + mask = (1 << smi->num_ports) - 1; + else + mask = (1 << port) | (1 << smi->cpu_port); + + err = rtl8366_set_vlan(smi, (port + 1), mask, mask, 0); + if (err) + return err; + + err = rtl8366_set_pvid(smi, port, (port + 1)); + if (err) + return err; + } + + return rtl8366_enable_vlan(smi, 1); +} + +#ifdef CONFIG_RTL8366_SMI_DEBUG_FS +int rtl8366_debugfs_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} +EXPORT_SYMBOL_GPL(rtl8366_debugfs_open); + +static ssize_t rtl8366_read_debugfs_vlan_mc(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct rtl8366_smi *smi = (struct rtl8366_smi *)file->private_data; + int i, len = 0; + char *buf = smi->buf; + + len += snprintf(buf + len, sizeof(smi->buf) - len, + "%2s %6s %4s %6s %6s %3s\n", + "id", "vid","prio", "member", "untag", "fid"); + + for (i = 0; i < smi->num_vlan_mc; ++i) { + struct rtl8366_vlan_mc vlanmc; + + smi->ops->get_vlan_mc(smi, i, &vlanmc); + + len += snprintf(buf + len, sizeof(smi->buf) - len, + "%2d %6d %4d 0x%04x 0x%04x %3d\n", + i, vlanmc.vid, vlanmc.priority, + vlanmc.member, vlanmc.untag, vlanmc.fid); + } + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +#define RTL8366_VLAN4K_PAGE_SIZE 64 +#define RTL8366_VLAN4K_NUM_PAGES (4096 / RTL8366_VLAN4K_PAGE_SIZE) + +static ssize_t rtl8366_read_debugfs_vlan_4k(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct rtl8366_smi *smi = (struct rtl8366_smi *)file->private_data; + int i, len = 0; + int offset; + char *buf = smi->buf; + + if (smi->dbg_vlan_4k_page >= RTL8366_VLAN4K_NUM_PAGES) { + len += snprintf(buf + len, sizeof(smi->buf) - len, + "invalid page: %u\n", smi->dbg_vlan_4k_page); + return simple_read_from_buffer(user_buf, count, ppos, buf, len); + } + + len += snprintf(buf + len, sizeof(smi->buf) - len, + "%4s %6s %6s %3s\n", + "vid", "member", "untag", "fid"); + + offset = RTL8366_VLAN4K_PAGE_SIZE * smi->dbg_vlan_4k_page; + for (i = 0; i < RTL8366_VLAN4K_PAGE_SIZE; i++) { + struct rtl8366_vlan_4k vlan4k; + + smi->ops->get_vlan_4k(smi, offset + i, &vlan4k); + + len += snprintf(buf + len, sizeof(smi->buf) - len, + "%4d 0x%04x 0x%04x %3d\n", + vlan4k.vid, vlan4k.member, + vlan4k.untag, vlan4k.fid); + } + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t rtl8366_read_debugfs_pvid(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct rtl8366_smi *smi = (struct rtl8366_smi *)file->private_data; + char *buf = smi->buf; + int len = 0; + int i; + + len += snprintf(buf + len, sizeof(smi->buf) - len, "%4s %4s\n", + "port", "pvid"); + + for (i = 0; i < smi->num_ports; i++) { + int pvid; + int err; + + err = rtl8366_get_pvid(smi, i, &pvid); + if (err) + len += snprintf(buf + len, sizeof(smi->buf) - len, + "%4d error\n", i); + else + len += snprintf(buf + len, sizeof(smi->buf) - len, + "%4d %4d\n", i, pvid); + } + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t rtl8366_read_debugfs_reg(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct rtl8366_smi *smi = (struct rtl8366_smi *)file->private_data; + u32 t, reg = smi->dbg_reg; + int err, len = 0; + char *buf = smi->buf; + + memset(buf, '\0', sizeof(smi->buf)); + + err = rtl8366_smi_read_reg(smi, reg, &t); + if (err) { + len += snprintf(buf, sizeof(smi->buf), + "Read failed (reg: 0x%04x)\n", reg); + return simple_read_from_buffer(user_buf, count, ppos, buf, len); + } + + len += snprintf(buf, sizeof(smi->buf), "reg = 0x%04x, val = 0x%04x\n", + reg, t); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t rtl8366_write_debugfs_reg(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct rtl8366_smi *smi = (struct rtl8366_smi *)file->private_data; + unsigned long data; + u32 reg = smi->dbg_reg; + int err; + size_t len; + char *buf = smi->buf; + + len = min(count, sizeof(smi->buf) - 1); + if (copy_from_user(buf, user_buf, len)) { + dev_err(smi->parent, "copy from user failed\n"); + return -EFAULT; + } + + buf[len] = '\0'; + if (len > 0 && buf[len - 1] == '\n') + buf[len - 1] = '\0'; + + + if (kstrtoul(buf, 16, &data)) { + dev_err(smi->parent, "Invalid reg value %s\n", buf); + } else { + err = rtl8366_smi_write_reg(smi, reg, data); + if (err) { + dev_err(smi->parent, + "writing reg 0x%04x val 0x%04lx failed\n", + reg, data); + } + } + + return count; +} + +static ssize_t rtl8366_read_debugfs_mibs(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct rtl8366_smi *smi = file->private_data; + int i, j, len = 0; + char *buf = smi->buf; + + len += snprintf(buf + len, sizeof(smi->buf) - len, "%-36s", + "Counter"); + + for (i = 0; i < smi->num_ports; i++) { + char port_buf[10]; + + snprintf(port_buf, sizeof(port_buf), "Port %d", i); + len += snprintf(buf + len, sizeof(smi->buf) - len, " %12s", + port_buf); + } + len += snprintf(buf + len, sizeof(smi->buf) - len, "\n"); + + for (i = 0; i < smi->num_mib_counters; i++) { + len += snprintf(buf + len, sizeof(smi->buf) - len, "%-36s ", + smi->mib_counters[i].name); + for (j = 0; j < smi->num_ports; j++) { + unsigned long long counter = 0; + + if (!smi->ops->get_mib_counter(smi, i, j, &counter)) + len += snprintf(buf + len, + sizeof(smi->buf) - len, + "%12llu ", counter); + else + len += snprintf(buf + len, + sizeof(smi->buf) - len, + "%12s ", "error"); + } + len += snprintf(buf + len, sizeof(smi->buf) - len, "\n"); + } + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static const struct file_operations fops_rtl8366_regs = { + .read = rtl8366_read_debugfs_reg, + .write = rtl8366_write_debugfs_reg, + .open = rtl8366_debugfs_open, + .owner = THIS_MODULE +}; + +static const struct file_operations fops_rtl8366_vlan_mc = { + .read = rtl8366_read_debugfs_vlan_mc, + .open = rtl8366_debugfs_open, + .owner = THIS_MODULE +}; + +static const struct file_operations fops_rtl8366_vlan_4k = { + .read = rtl8366_read_debugfs_vlan_4k, + .open = rtl8366_debugfs_open, + .owner = THIS_MODULE +}; + +static const struct file_operations fops_rtl8366_pvid = { + .read = rtl8366_read_debugfs_pvid, + .open = rtl8366_debugfs_open, + .owner = THIS_MODULE +}; + +static const struct file_operations fops_rtl8366_mibs = { + .read = rtl8366_read_debugfs_mibs, + .open = rtl8366_debugfs_open, + .owner = THIS_MODULE +}; + +static void rtl8366_debugfs_init(struct rtl8366_smi *smi) +{ + struct dentry *node; + struct dentry *root; + + if (!smi->debugfs_root) + smi->debugfs_root = debugfs_create_dir(dev_name(smi->parent), + NULL); + + if (!smi->debugfs_root) { + dev_err(smi->parent, "Unable to create debugfs dir\n"); + return; + } + root = smi->debugfs_root; + + node = debugfs_create_x16("reg", S_IRUGO | S_IWUSR, root, + &smi->dbg_reg); + if (!node) { + dev_err(smi->parent, "Creating debugfs file '%s' failed\n", + "reg"); + return; + } + + node = debugfs_create_file("val", S_IRUGO | S_IWUSR, root, smi, + &fops_rtl8366_regs); + if (!node) { + dev_err(smi->parent, "Creating debugfs file '%s' failed\n", + "val"); + return; + } + + node = debugfs_create_file("vlan_mc", S_IRUSR, root, smi, + &fops_rtl8366_vlan_mc); + if (!node) { + dev_err(smi->parent, "Creating debugfs file '%s' failed\n", + "vlan_mc"); + return; + } + + node = debugfs_create_u8("vlan_4k_page", S_IRUGO | S_IWUSR, root, + &smi->dbg_vlan_4k_page); + if (!node) { + dev_err(smi->parent, "Creating debugfs file '%s' failed\n", + "vlan_4k_page"); + return; + } + + node = debugfs_create_file("vlan_4k", S_IRUSR, root, smi, + &fops_rtl8366_vlan_4k); + if (!node) { + dev_err(smi->parent, "Creating debugfs file '%s' failed\n", + "vlan_4k"); + return; + } + + node = debugfs_create_file("pvid", S_IRUSR, root, smi, + &fops_rtl8366_pvid); + if (!node) { + dev_err(smi->parent, "Creating debugfs file '%s' failed\n", + "pvid"); + return; + } + + node = debugfs_create_file("mibs", S_IRUSR, smi->debugfs_root, smi, + &fops_rtl8366_mibs); + if (!node) + dev_err(smi->parent, "Creating debugfs file '%s' failed\n", + "mibs"); +} + +static void rtl8366_debugfs_remove(struct rtl8366_smi *smi) +{ + if (smi->debugfs_root) { + debugfs_remove_recursive(smi->debugfs_root); + smi->debugfs_root = NULL; + } +} +#else +static inline void rtl8366_debugfs_init(struct rtl8366_smi *smi) {} +static inline void rtl8366_debugfs_remove(struct rtl8366_smi *smi) {} +#endif /* CONFIG_RTL8366_SMI_DEBUG_FS */ + +static int rtl8366_smi_mii_init(struct rtl8366_smi *smi) +{ + int ret; + int i; + + smi->mii_bus = mdiobus_alloc(); + if (smi->mii_bus == NULL) { + ret = -ENOMEM; + goto err; + } + + smi->mii_bus->priv = (void *) smi; + smi->mii_bus->name = dev_name(smi->parent); + smi->mii_bus->read = smi->ops->mii_read; + smi->mii_bus->write = smi->ops->mii_write; + snprintf(smi->mii_bus->id, MII_BUS_ID_SIZE, "%s", + dev_name(smi->parent)); + smi->mii_bus->parent = smi->parent; + smi->mii_bus->phy_mask = ~(0x1f); + smi->mii_bus->irq = smi->mii_irq; + for (i = 0; i < PHY_MAX_ADDR; i++) + smi->mii_irq[i] = PHY_POLL; + + ret = mdiobus_register(smi->mii_bus); + if (ret) + goto err_free; + + return 0; + + err_free: + mdiobus_free(smi->mii_bus); + err: + return ret; +} + +static void rtl8366_smi_mii_cleanup(struct rtl8366_smi *smi) +{ + mdiobus_unregister(smi->mii_bus); + mdiobus_free(smi->mii_bus); +} + +int rtl8366_sw_reset_switch(struct switch_dev *dev) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + int err; + + err = rtl8366_reset(smi); + if (err) + return err; + + err = smi->ops->setup(smi); + if (err) + return err; + + err = rtl8366_reset_vlan(smi); + if (err) + return err; + + err = rtl8366_enable_vlan(smi, 1); + if (err) + return err; + + return rtl8366_enable_all_ports(smi, 1); +} +EXPORT_SYMBOL_GPL(rtl8366_sw_reset_switch); + +int rtl8366_sw_get_port_pvid(struct switch_dev *dev, int port, int *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + return rtl8366_get_pvid(smi, port, val); +} +EXPORT_SYMBOL_GPL(rtl8366_sw_get_port_pvid); + +int rtl8366_sw_set_port_pvid(struct switch_dev *dev, int port, int val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + return rtl8366_set_pvid(smi, port, val); +} +EXPORT_SYMBOL_GPL(rtl8366_sw_set_port_pvid); + +int rtl8366_sw_get_port_mib(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + int i, len = 0; + unsigned long long counter = 0; + char *buf = smi->buf; + + if (val->port_vlan >= smi->num_ports) + return -EINVAL; + + len += snprintf(buf + len, sizeof(smi->buf) - len, + "Port %d MIB counters\n", + val->port_vlan); + + for (i = 0; i < smi->num_mib_counters; ++i) { + len += snprintf(buf + len, sizeof(smi->buf) - len, + "%-36s: ", smi->mib_counters[i].name); + if (!smi->ops->get_mib_counter(smi, i, val->port_vlan, + &counter)) + len += snprintf(buf + len, sizeof(smi->buf) - len, + "%llu\n", counter); + else + len += snprintf(buf + len, sizeof(smi->buf) - len, + "%s\n", "error"); + } + + val->value.s = buf; + val->len = len; + return 0; +} +EXPORT_SYMBOL_GPL(rtl8366_sw_get_port_mib); + +int rtl8366_sw_get_vlan_info(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + int i; + u32 len = 0; + struct rtl8366_vlan_4k vlan4k; + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + char *buf = smi->buf; + int err; + + if (!smi->ops->is_vlan_valid(smi, val->port_vlan)) + return -EINVAL; + + memset(buf, '\0', sizeof(smi->buf)); + + err = smi->ops->get_vlan_4k(smi, val->port_vlan, &vlan4k); + if (err) + return err; + + len += snprintf(buf + len, sizeof(smi->buf) - len, + "VLAN %d: Ports: '", vlan4k.vid); + + for (i = 0; i < smi->num_ports; i++) { + if (!(vlan4k.member & (1 << i))) + continue; + + len += snprintf(buf + len, sizeof(smi->buf) - len, "%d%s", i, + (vlan4k.untag & (1 << i)) ? "" : "t"); + } + + len += snprintf(buf + len, sizeof(smi->buf) - len, + "', members=%04x, untag=%04x, fid=%u", + vlan4k.member, vlan4k.untag, vlan4k.fid); + + val->value.s = buf; + val->len = len; + + return 0; +} +EXPORT_SYMBOL_GPL(rtl8366_sw_get_vlan_info); + +int rtl8366_sw_get_vlan_ports(struct switch_dev *dev, struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + struct switch_port *port; + struct rtl8366_vlan_4k vlan4k; + int i; + + if (!smi->ops->is_vlan_valid(smi, val->port_vlan)) + return -EINVAL; + + smi->ops->get_vlan_4k(smi, val->port_vlan, &vlan4k); + + port = &val->value.ports[0]; + val->len = 0; + for (i = 0; i < smi->num_ports; i++) { + if (!(vlan4k.member & BIT(i))) + continue; + + port->id = i; + port->flags = (vlan4k.untag & BIT(i)) ? + 0 : BIT(SWITCH_PORT_FLAG_TAGGED); + val->len++; + port++; + } + return 0; +} +EXPORT_SYMBOL_GPL(rtl8366_sw_get_vlan_ports); + +int rtl8366_sw_set_vlan_ports(struct switch_dev *dev, struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + struct switch_port *port; + u32 member = 0; + u32 untag = 0; + int err; + int i; + + if (!smi->ops->is_vlan_valid(smi, val->port_vlan)) + return -EINVAL; + + port = &val->value.ports[0]; + for (i = 0; i < val->len; i++, port++) { + int pvid = 0; + member |= BIT(port->id); + + if (!(port->flags & BIT(SWITCH_PORT_FLAG_TAGGED))) + untag |= BIT(port->id); + + /* + * To ensure that we have a valid MC entry for this VLAN, + * initialize the port VLAN ID here. + */ + err = rtl8366_get_pvid(smi, port->id, &pvid); + if (err < 0) + return err; + if (pvid == 0) { + err = rtl8366_set_pvid(smi, port->id, val->port_vlan); + if (err < 0) + return err; + } + } + + return rtl8366_set_vlan(smi, val->port_vlan, member, untag, 0); +} +EXPORT_SYMBOL_GPL(rtl8366_sw_set_vlan_ports); + +int rtl8366_sw_get_vlan_fid(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_vlan_4k vlan4k; + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + int err; + + if (!smi->ops->is_vlan_valid(smi, val->port_vlan)) + return -EINVAL; + + err = smi->ops->get_vlan_4k(smi, val->port_vlan, &vlan4k); + if (err) + return err; + + val->value.i = vlan4k.fid; + + return 0; +} +EXPORT_SYMBOL_GPL(rtl8366_sw_get_vlan_fid); + +int rtl8366_sw_set_vlan_fid(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_vlan_4k vlan4k; + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + int err; + + if (!smi->ops->is_vlan_valid(smi, val->port_vlan)) + return -EINVAL; + + if (val->value.i < 0 || val->value.i > attr->max) + return -EINVAL; + + err = smi->ops->get_vlan_4k(smi, val->port_vlan, &vlan4k); + if (err) + return err; + + return rtl8366_set_vlan(smi, val->port_vlan, + vlan4k.member, + vlan4k.untag, + val->value.i); +} +EXPORT_SYMBOL_GPL(rtl8366_sw_set_vlan_fid); + +int rtl8366_sw_get_vlan_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + + if (attr->ofs > 2) + return -EINVAL; + + if (attr->ofs == 1) + val->value.i = smi->vlan_enabled; + else + val->value.i = smi->vlan4k_enabled; + + return 0; +} +EXPORT_SYMBOL_GPL(rtl8366_sw_get_vlan_enable); + +int rtl8366_sw_set_vlan_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + int err; + + if (attr->ofs > 2) + return -EINVAL; + + if (attr->ofs == 1) + err = rtl8366_enable_vlan(smi, val->value.i); + else + err = rtl8366_enable_vlan4k(smi, val->value.i); + + return err; +} +EXPORT_SYMBOL_GPL(rtl8366_sw_set_vlan_enable); + +struct rtl8366_smi *rtl8366_smi_alloc(struct device *parent) +{ + struct rtl8366_smi *smi; + + BUG_ON(!parent); + + smi = kzalloc(sizeof(*smi), GFP_KERNEL); + if (!smi) { + dev_err(parent, "no memory for private data\n"); + return NULL; + } + + smi->parent = parent; + return smi; +} +EXPORT_SYMBOL_GPL(rtl8366_smi_alloc); + +static int __rtl8366_smi_init(struct rtl8366_smi *smi, const char *name) +{ + int err; + + err = gpio_request(smi->gpio_sda, name); + if (err) { + printk(KERN_ERR "rtl8366_smi: gpio_request failed for %u, err=%d\n", + smi->gpio_sda, err); + goto err_out; + } + + err = gpio_request(smi->gpio_sck, name); + if (err) { + printk(KERN_ERR "rtl8366_smi: gpio_request failed for %u, err=%d\n", + smi->gpio_sck, err); + goto err_free_sda; + } + + spin_lock_init(&smi->lock); + + /* start the switch */ + if (smi->hw_reset) { + smi->hw_reset(false); + msleep(RTL8366_SMI_HW_START_DELAY); + } + + return 0; + + err_free_sda: + gpio_free(smi->gpio_sda); + err_out: + return err; +} + +static void __rtl8366_smi_cleanup(struct rtl8366_smi *smi) +{ + if (smi->hw_reset) + smi->hw_reset(true); + + gpio_free(smi->gpio_sck); + gpio_free(smi->gpio_sda); +} + +enum rtl8366_type rtl8366_smi_detect(struct rtl8366_platform_data *pdata) +{ + static struct rtl8366_smi smi; + enum rtl8366_type type = RTL8366_TYPE_UNKNOWN; + u32 reg = 0; + + memset(&smi, 0, sizeof(smi)); + smi.gpio_sda = pdata->gpio_sda; + smi.gpio_sck = pdata->gpio_sck; + smi.clk_delay = 10; + smi.cmd_read = 0xa9; + smi.cmd_write = 0xa8; + + if (__rtl8366_smi_init(&smi, "rtl8366")) + goto out; + + if (rtl8366_smi_read_reg(&smi, 0x5c, ®)) + goto cleanup; + + switch(reg) { + case 0x6027: + printk("Found an RTL8366S switch\n"); + type = RTL8366_TYPE_S; + break; + case 0x5937: + printk("Found an RTL8366RB switch\n"); + type = RTL8366_TYPE_RB; + break; + default: + printk("Found an Unknown RTL8366 switch (id=0x%04x)\n", reg); + break; + } + +cleanup: + __rtl8366_smi_cleanup(&smi); +out: + return type; +} + +int rtl8366_smi_init(struct rtl8366_smi *smi) +{ + int err; + + if (!smi->ops) + return -EINVAL; + + err = __rtl8366_smi_init(smi, dev_name(smi->parent)); + if (err) + goto err_out; + + dev_info(smi->parent, "using GPIO pins %u (SDA) and %u (SCK)\n", + smi->gpio_sda, smi->gpio_sck); + + err = smi->ops->detect(smi); + if (err) { + dev_err(smi->parent, "chip detection failed, err=%d\n", err); + goto err_free_sck; + } + + err = rtl8366_reset(smi); + if (err) + goto err_free_sck; + + err = smi->ops->setup(smi); + if (err) { + dev_err(smi->parent, "chip setup failed, err=%d\n", err); + goto err_free_sck; + } + + err = rtl8366_init_vlan(smi); + if (err) { + dev_err(smi->parent, "VLAN initialization failed, err=%d\n", + err); + goto err_free_sck; + } + + err = rtl8366_enable_all_ports(smi, 1); + if (err) + goto err_free_sck; + + err = rtl8366_smi_mii_init(smi); + if (err) + goto err_free_sck; + + rtl8366_debugfs_init(smi); + + return 0; + + err_free_sck: + __rtl8366_smi_cleanup(smi); + err_out: + return err; +} +EXPORT_SYMBOL_GPL(rtl8366_smi_init); + +void rtl8366_smi_cleanup(struct rtl8366_smi *smi) +{ + rtl8366_debugfs_remove(smi); + rtl8366_smi_mii_cleanup(smi); + __rtl8366_smi_cleanup(smi); +} +EXPORT_SYMBOL_GPL(rtl8366_smi_cleanup); + +#ifdef CONFIG_OF +int rtl8366_smi_probe_of(struct platform_device *pdev, struct rtl8366_smi *smi) +{ + int sck = of_get_named_gpio(pdev->dev.of_node, "gpio-sck", 0); + int sda = of_get_named_gpio(pdev->dev.of_node, "gpio-sda", 0); + + if (!gpio_is_valid(sck) || !gpio_is_valid(sda)) { + dev_err(&pdev->dev, "gpios missing in devictree\n"); + return -EINVAL; + } + + smi->gpio_sda = sda; + smi->gpio_sck = sck; + + return 0; +} +#else +static inline int rtl8366_smi_probe_of(struct platform_device *pdev, struct rtl8366_smi *smi) +{ + return -ENODEV; +} +#endif + +int rtl8366_smi_probe_plat(struct platform_device *pdev, struct rtl8366_smi *smi) +{ + struct rtl8366_platform_data *pdata = pdev->dev.platform_data; + + if (!pdev->dev.platform_data) { + dev_err(&pdev->dev, "no platform data specified\n"); + return -EINVAL; + } + + smi->gpio_sda = pdata->gpio_sda; + smi->gpio_sck = pdata->gpio_sck; + smi->hw_reset = pdata->hw_reset; + + return 0; +} + + +struct rtl8366_smi *rtl8366_smi_probe(struct platform_device *pdev) +{ + struct rtl8366_smi *smi; + int err; + + smi = rtl8366_smi_alloc(&pdev->dev); + if (!smi) + return NULL; + + if (pdev->dev.of_node) + err = rtl8366_smi_probe_of(pdev, smi); + else + err = rtl8366_smi_probe_plat(pdev, smi); + + if (err) + goto free_smi; + + return smi; + +free_smi: + kfree(smi); + return NULL; +} +EXPORT_SYMBOL_GPL(rtl8366_smi_probe); + +MODULE_DESCRIPTION("Realtek RTL8366 SMI interface driver"); +MODULE_AUTHOR("Gabor Juhos "); +MODULE_LICENSE("GPL v2"); diff --git a/target/linux/generic/files/drivers/net/phy/rtl8366_smi.h b/target/linux/generic/files/drivers/net/phy/rtl8366_smi.h new file mode 100644 index 0000000..bd41385 --- /dev/null +++ b/target/linux/generic/files/drivers/net/phy/rtl8366_smi.h @@ -0,0 +1,152 @@ +/* + * Realtek RTL8366 SMI interface driver defines + * + * Copyright (C) 2009-2010 Gabor Juhos + * + * 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. + */ + +#ifndef _RTL8366_SMI_H +#define _RTL8366_SMI_H + +#include +#include +#include + +struct rtl8366_smi_ops; +struct rtl8366_vlan_ops; +struct mii_bus; +struct dentry; +struct inode; +struct file; + +struct rtl8366_mib_counter { + unsigned base; + unsigned offset; + unsigned length; + const char *name; +}; + +struct rtl8366_smi { + struct device *parent; + unsigned int gpio_sda; + unsigned int gpio_sck; + void (*hw_reset)(bool active); + unsigned int clk_delay; /* ns */ + u8 cmd_read; + u8 cmd_write; + spinlock_t lock; + struct mii_bus *mii_bus; + int mii_irq[PHY_MAX_ADDR]; + struct switch_dev sw_dev; + + unsigned int cpu_port; + unsigned int num_ports; + unsigned int num_vlan_mc; + unsigned int num_mib_counters; + struct rtl8366_mib_counter *mib_counters; + + struct rtl8366_smi_ops *ops; + + int vlan_enabled; + int vlan4k_enabled; + + char buf[4096]; +#ifdef CONFIG_RTL8366_SMI_DEBUG_FS + struct dentry *debugfs_root; + u16 dbg_reg; + u8 dbg_vlan_4k_page; +#endif +}; + +struct rtl8366_vlan_mc { + u16 vid; + u16 untag; + u16 member; + u8 fid; + u8 priority; +}; + +struct rtl8366_vlan_4k { + u16 vid; + u16 untag; + u16 member; + u8 fid; +}; + +struct rtl8366_smi_ops { + int (*detect)(struct rtl8366_smi *smi); + int (*reset_chip)(struct rtl8366_smi *smi); + int (*setup)(struct rtl8366_smi *smi); + + int (*mii_read)(struct mii_bus *bus, int addr, int reg); + int (*mii_write)(struct mii_bus *bus, int addr, int reg, u16 val); + + int (*get_vlan_mc)(struct rtl8366_smi *smi, u32 index, + struct rtl8366_vlan_mc *vlanmc); + int (*set_vlan_mc)(struct rtl8366_smi *smi, u32 index, + const struct rtl8366_vlan_mc *vlanmc); + int (*get_vlan_4k)(struct rtl8366_smi *smi, u32 vid, + struct rtl8366_vlan_4k *vlan4k); + int (*set_vlan_4k)(struct rtl8366_smi *smi, + const struct rtl8366_vlan_4k *vlan4k); + int (*get_mc_index)(struct rtl8366_smi *smi, int port, int *val); + int (*set_mc_index)(struct rtl8366_smi *smi, int port, int index); + int (*get_mib_counter)(struct rtl8366_smi *smi, int counter, + int port, unsigned long long *val); + int (*is_vlan_valid)(struct rtl8366_smi *smi, unsigned vlan); + int (*enable_vlan)(struct rtl8366_smi *smi, int enable); + int (*enable_vlan4k)(struct rtl8366_smi *smi, int enable); + int (*enable_port)(struct rtl8366_smi *smi, int port, int enable); +}; + +struct rtl8366_smi *rtl8366_smi_alloc(struct device *parent); +int rtl8366_smi_init(struct rtl8366_smi *smi); +void rtl8366_smi_cleanup(struct rtl8366_smi *smi); +int rtl8366_smi_write_reg(struct rtl8366_smi *smi, u32 addr, u32 data); +int rtl8366_smi_write_reg_noack(struct rtl8366_smi *smi, u32 addr, u32 data); +int rtl8366_smi_read_reg(struct rtl8366_smi *smi, u32 addr, u32 *data); +int rtl8366_smi_rmwr(struct rtl8366_smi *smi, u32 addr, u32 mask, u32 data); + +int rtl8366_reset_vlan(struct rtl8366_smi *smi); +int rtl8366_enable_vlan(struct rtl8366_smi *smi, int enable); +int rtl8366_enable_all_ports(struct rtl8366_smi *smi, int enable); + +#ifdef CONFIG_RTL8366_SMI_DEBUG_FS +int rtl8366_debugfs_open(struct inode *inode, struct file *file); +#endif + +static inline struct rtl8366_smi *sw_to_rtl8366_smi(struct switch_dev *sw) +{ + return container_of(sw, struct rtl8366_smi, sw_dev); +} + +int rtl8366_sw_reset_switch(struct switch_dev *dev); +int rtl8366_sw_get_port_pvid(struct switch_dev *dev, int port, int *val); +int rtl8366_sw_set_port_pvid(struct switch_dev *dev, int port, int val); +int rtl8366_sw_get_port_mib(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int rtl8366_sw_get_vlan_info(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int rtl8366_sw_get_vlan_fid(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int rtl8366_sw_set_vlan_fid(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int rtl8366_sw_get_vlan_ports(struct switch_dev *dev, struct switch_val *val); +int rtl8366_sw_set_vlan_ports(struct switch_dev *dev, struct switch_val *val); +int rtl8366_sw_get_vlan_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int rtl8366_sw_set_vlan_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); + +struct rtl8366_smi* rtl8366_smi_probe(struct platform_device *pdev); + +#endif /* _RTL8366_SMI_H */ diff --git a/target/linux/generic/files/drivers/net/phy/rtl8366rb.c b/target/linux/generic/files/drivers/net/phy/rtl8366rb.c new file mode 100644 index 0000000..f4ec748 --- /dev/null +++ b/target/linux/generic/files/drivers/net/phy/rtl8366rb.c @@ -0,0 +1,1496 @@ +/* + * Platform driver for the Realtek RTL8366RB ethernet switch + * + * Copyright (C) 2009-2010 Gabor Juhos + * Copyright (C) 2010 Antti Seppälä + * Copyright (C) 2010 Roman Yeryomin + * Copyright (C) 2011 Colin Leitner + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rtl8366_smi.h" + +#define RTL8366RB_DRIVER_DESC "Realtek RTL8366RB ethernet switch driver" +#define RTL8366RB_DRIVER_VER "0.2.4" + +#define RTL8366RB_PHY_NO_MAX 4 +#define RTL8366RB_PHY_PAGE_MAX 7 +#define RTL8366RB_PHY_ADDR_MAX 31 + +/* Switch Global Configuration register */ +#define RTL8366RB_SGCR 0x0000 +#define RTL8366RB_SGCR_EN_BC_STORM_CTRL BIT(0) +#define RTL8366RB_SGCR_MAX_LENGTH(_x) (_x << 4) +#define RTL8366RB_SGCR_MAX_LENGTH_MASK RTL8366RB_SGCR_MAX_LENGTH(0x3) +#define RTL8366RB_SGCR_MAX_LENGTH_1522 RTL8366RB_SGCR_MAX_LENGTH(0x0) +#define RTL8366RB_SGCR_MAX_LENGTH_1536 RTL8366RB_SGCR_MAX_LENGTH(0x1) +#define RTL8366RB_SGCR_MAX_LENGTH_1552 RTL8366RB_SGCR_MAX_LENGTH(0x2) +#define RTL8366RB_SGCR_MAX_LENGTH_9216 RTL8366RB_SGCR_MAX_LENGTH(0x3) +#define RTL8366RB_SGCR_EN_VLAN BIT(13) +#define RTL8366RB_SGCR_EN_VLAN_4KTB BIT(14) + +/* Port Enable Control register */ +#define RTL8366RB_PECR 0x0001 + +/* Port Mirror Control Register */ +#define RTL8366RB_PMCR 0x0007 +#define RTL8366RB_PMCR_SOURCE_PORT(_x) (_x) +#define RTL8366RB_PMCR_SOURCE_PORT_MASK 0x000f +#define RTL8366RB_PMCR_MONITOR_PORT(_x) ((_x) << 4) +#define RTL8366RB_PMCR_MONITOR_PORT_MASK 0x00f0 +#define RTL8366RB_PMCR_MIRROR_RX BIT(8) +#define RTL8366RB_PMCR_MIRROR_TX BIT(9) +#define RTL8366RB_PMCR_MIRROR_SPC BIT(10) +#define RTL8366RB_PMCR_MIRROR_ISO BIT(11) + +/* Switch Security Control registers */ +#define RTL8366RB_SSCR0 0x0002 +#define RTL8366RB_SSCR1 0x0003 +#define RTL8366RB_SSCR2 0x0004 +#define RTL8366RB_SSCR2_DROP_UNKNOWN_DA BIT(0) + +#define RTL8366RB_RESET_CTRL_REG 0x0100 +#define RTL8366RB_CHIP_CTRL_RESET_HW 1 +#define RTL8366RB_CHIP_CTRL_RESET_SW (1 << 1) + +#define RTL8366RB_CHIP_VERSION_CTRL_REG 0x050A +#define RTL8366RB_CHIP_VERSION_MASK 0xf +#define RTL8366RB_CHIP_ID_REG 0x0509 +#define RTL8366RB_CHIP_ID_8366 0x5937 + +/* PHY registers control */ +#define RTL8366RB_PHY_ACCESS_CTRL_REG 0x8000 +#define RTL8366RB_PHY_ACCESS_DATA_REG 0x8002 + +#define RTL8366RB_PHY_CTRL_READ 1 +#define RTL8366RB_PHY_CTRL_WRITE 0 + +#define RTL8366RB_PHY_REG_MASK 0x1f +#define RTL8366RB_PHY_PAGE_OFFSET 5 +#define RTL8366RB_PHY_PAGE_MASK (0xf << 5) +#define RTL8366RB_PHY_NO_OFFSET 9 +#define RTL8366RB_PHY_NO_MASK (0x1f << 9) + +#define RTL8366RB_VLAN_INGRESS_CTRL2_REG 0x037f + +/* LED control registers */ +#define RTL8366RB_LED_BLINKRATE_REG 0x0430 +#define RTL8366RB_LED_BLINKRATE_BIT 0 +#define RTL8366RB_LED_BLINKRATE_MASK 0x0007 + +#define RTL8366RB_LED_CTRL_REG 0x0431 +#define RTL8366RB_LED_0_1_CTRL_REG 0x0432 +#define RTL8366RB_LED_2_3_CTRL_REG 0x0433 + +#define RTL8366RB_MIB_COUNT 33 +#define RTL8366RB_GLOBAL_MIB_COUNT 1 +#define RTL8366RB_MIB_COUNTER_PORT_OFFSET 0x0050 +#define RTL8366RB_MIB_COUNTER_BASE 0x1000 +#define RTL8366RB_MIB_CTRL_REG 0x13F0 +#define RTL8366RB_MIB_CTRL_USER_MASK 0x0FFC +#define RTL8366RB_MIB_CTRL_BUSY_MASK BIT(0) +#define RTL8366RB_MIB_CTRL_RESET_MASK BIT(1) +#define RTL8366RB_MIB_CTRL_PORT_RESET(_p) BIT(2 + (_p)) +#define RTL8366RB_MIB_CTRL_GLOBAL_RESET BIT(11) + +#define RTL8366RB_PORT_VLAN_CTRL_BASE 0x0063 +#define RTL8366RB_PORT_VLAN_CTRL_REG(_p) \ + (RTL8366RB_PORT_VLAN_CTRL_BASE + (_p) / 4) +#define RTL8366RB_PORT_VLAN_CTRL_MASK 0xf +#define RTL8366RB_PORT_VLAN_CTRL_SHIFT(_p) (4 * ((_p) % 4)) + + +#define RTL8366RB_VLAN_TABLE_READ_BASE 0x018C +#define RTL8366RB_VLAN_TABLE_WRITE_BASE 0x0185 + + +#define RTL8366RB_TABLE_ACCESS_CTRL_REG 0x0180 +#define RTL8366RB_TABLE_VLAN_READ_CTRL 0x0E01 +#define RTL8366RB_TABLE_VLAN_WRITE_CTRL 0x0F01 + +#define RTL8366RB_VLAN_MC_BASE(_x) (0x0020 + (_x) * 3) + + +#define RTL8366RB_PORT_LINK_STATUS_BASE 0x0014 +#define RTL8366RB_PORT_STATUS_SPEED_MASK 0x0003 +#define RTL8366RB_PORT_STATUS_DUPLEX_MASK 0x0004 +#define RTL8366RB_PORT_STATUS_LINK_MASK 0x0010 +#define RTL8366RB_PORT_STATUS_TXPAUSE_MASK 0x0020 +#define RTL8366RB_PORT_STATUS_RXPAUSE_MASK 0x0040 +#define RTL8366RB_PORT_STATUS_AN_MASK 0x0080 + + +#define RTL8366RB_PORT_NUM_CPU 5 +#define RTL8366RB_NUM_PORTS 6 +#define RTL8366RB_NUM_VLANS 16 +#define RTL8366RB_NUM_LEDGROUPS 4 +#define RTL8366RB_NUM_VIDS 4096 +#define RTL8366RB_PRIORITYMAX 7 +#define RTL8366RB_FIDMAX 7 + + +#define RTL8366RB_PORT_1 (1 << 0) /* In userspace port 0 */ +#define RTL8366RB_PORT_2 (1 << 1) /* In userspace port 1 */ +#define RTL8366RB_PORT_3 (1 << 2) /* In userspace port 2 */ +#define RTL8366RB_PORT_4 (1 << 3) /* In userspace port 3 */ +#define RTL8366RB_PORT_5 (1 << 4) /* In userspace port 4 */ + +#define RTL8366RB_PORT_CPU (1 << 5) /* CPU port */ + +#define RTL8366RB_PORT_ALL (RTL8366RB_PORT_1 | \ + RTL8366RB_PORT_2 | \ + RTL8366RB_PORT_3 | \ + RTL8366RB_PORT_4 | \ + RTL8366RB_PORT_5 | \ + RTL8366RB_PORT_CPU) + +#define RTL8366RB_PORT_ALL_BUT_CPU (RTL8366RB_PORT_1 | \ + RTL8366RB_PORT_2 | \ + RTL8366RB_PORT_3 | \ + RTL8366RB_PORT_4 | \ + RTL8366RB_PORT_5) + +#define RTL8366RB_PORT_ALL_EXTERNAL (RTL8366RB_PORT_1 | \ + RTL8366RB_PORT_2 | \ + RTL8366RB_PORT_3 | \ + RTL8366RB_PORT_4) + +#define RTL8366RB_PORT_ALL_INTERNAL RTL8366RB_PORT_CPU + +#define RTL8366RB_VLAN_VID_MASK 0xfff +#define RTL8366RB_VLAN_PRIORITY_SHIFT 12 +#define RTL8366RB_VLAN_PRIORITY_MASK 0x7 +#define RTL8366RB_VLAN_UNTAG_SHIFT 8 +#define RTL8366RB_VLAN_UNTAG_MASK 0xff +#define RTL8366RB_VLAN_MEMBER_MASK 0xff +#define RTL8366RB_VLAN_FID_MASK 0x7 + + +/* Port ingress bandwidth control */ +#define RTL8366RB_IB_BASE 0x0200 +#define RTL8366RB_IB_REG(pnum) (RTL8366RB_IB_BASE + pnum) +#define RTL8366RB_IB_BDTH_MASK 0x3fff +#define RTL8366RB_IB_PREIFG_OFFSET 14 +#define RTL8366RB_IB_PREIFG_MASK (1 << RTL8366RB_IB_PREIFG_OFFSET) + +/* Port egress bandwidth control */ +#define RTL8366RB_EB_BASE 0x02d1 +#define RTL8366RB_EB_REG(pnum) (RTL8366RB_EB_BASE + pnum) +#define RTL8366RB_EB_BDTH_MASK 0x3fff +#define RTL8366RB_EB_PREIFG_REG 0x02f8 +#define RTL8366RB_EB_PREIFG_OFFSET 9 +#define RTL8366RB_EB_PREIFG_MASK (1 << RTL8366RB_EB_PREIFG_OFFSET) + +#define RTL8366RB_BDTH_SW_MAX 1048512 +#define RTL8366RB_BDTH_UNIT 64 +#define RTL8366RB_BDTH_REG_DEFAULT 16383 + +/* QOS */ +#define RTL8366RB_QOS_BIT 15 +#define RTL8366RB_QOS_MASK (1 << RTL8366RB_QOS_BIT) +/* Include/Exclude Preamble and IFG (20 bytes). 0:Exclude, 1:Include. */ +#define RTL8366RB_QOS_DEFAULT_PREIFG 1 + + +static struct rtl8366_mib_counter rtl8366rb_mib_counters[] = { + { 0, 0, 4, "IfInOctets" }, + { 0, 4, 4, "EtherStatsOctets" }, + { 0, 8, 2, "EtherStatsUnderSizePkts" }, + { 0, 10, 2, "EtherFragments" }, + { 0, 12, 2, "EtherStatsPkts64Octets" }, + { 0, 14, 2, "EtherStatsPkts65to127Octets" }, + { 0, 16, 2, "EtherStatsPkts128to255Octets" }, + { 0, 18, 2, "EtherStatsPkts256to511Octets" }, + { 0, 20, 2, "EtherStatsPkts512to1023Octets" }, + { 0, 22, 2, "EtherStatsPkts1024to1518Octets" }, + { 0, 24, 2, "EtherOversizeStats" }, + { 0, 26, 2, "EtherStatsJabbers" }, + { 0, 28, 2, "IfInUcastPkts" }, + { 0, 30, 2, "EtherStatsMulticastPkts" }, + { 0, 32, 2, "EtherStatsBroadcastPkts" }, + { 0, 34, 2, "EtherStatsDropEvents" }, + { 0, 36, 2, "Dot3StatsFCSErrors" }, + { 0, 38, 2, "Dot3StatsSymbolErrors" }, + { 0, 40, 2, "Dot3InPauseFrames" }, + { 0, 42, 2, "Dot3ControlInUnknownOpcodes" }, + { 0, 44, 4, "IfOutOctets" }, + { 0, 48, 2, "Dot3StatsSingleCollisionFrames" }, + { 0, 50, 2, "Dot3StatMultipleCollisionFrames" }, + { 0, 52, 2, "Dot3sDeferredTransmissions" }, + { 0, 54, 2, "Dot3StatsLateCollisions" }, + { 0, 56, 2, "EtherStatsCollisions" }, + { 0, 58, 2, "Dot3StatsExcessiveCollisions" }, + { 0, 60, 2, "Dot3OutPauseFrames" }, + { 0, 62, 2, "Dot1dBasePortDelayExceededDiscards" }, + { 0, 64, 2, "Dot1dTpPortInDiscards" }, + { 0, 66, 2, "IfOutUcastPkts" }, + { 0, 68, 2, "IfOutMulticastPkts" }, + { 0, 70, 2, "IfOutBroadcastPkts" }, +}; + +#define REG_WR(_smi, _reg, _val) \ + do { \ + err = rtl8366_smi_write_reg(_smi, _reg, _val); \ + if (err) \ + return err; \ + } while (0) + +#define REG_RMW(_smi, _reg, _mask, _val) \ + do { \ + err = rtl8366_smi_rmwr(_smi, _reg, _mask, _val); \ + if (err) \ + return err; \ + } while (0) + +static int rtl8366rb_reset_chip(struct rtl8366_smi *smi) +{ + int timeout = 10; + u32 data; + + rtl8366_smi_write_reg_noack(smi, RTL8366RB_RESET_CTRL_REG, + RTL8366RB_CHIP_CTRL_RESET_HW); + do { + msleep(1); + if (rtl8366_smi_read_reg(smi, RTL8366RB_RESET_CTRL_REG, &data)) + return -EIO; + + if (!(data & RTL8366RB_CHIP_CTRL_RESET_HW)) + break; + } while (--timeout); + + if (!timeout) { + printk("Timeout waiting for the switch to reset\n"); + return -EIO; + } + + return 0; +} + +static int rtl8366rb_setup(struct rtl8366_smi *smi) +{ + int err; + + /* set maximum packet length to 1536 bytes */ + REG_RMW(smi, RTL8366RB_SGCR, RTL8366RB_SGCR_MAX_LENGTH_MASK, + RTL8366RB_SGCR_MAX_LENGTH_1536); + + /* enable learning for all ports */ + REG_WR(smi, RTL8366RB_SSCR0, 0); + + /* enable auto ageing for all ports */ + REG_WR(smi, RTL8366RB_SSCR1, 0); + + /* + * discard VLAN tagged packets if the port is not a member of + * the VLAN with which the packets is associated. + */ + REG_WR(smi, RTL8366RB_VLAN_INGRESS_CTRL2_REG, RTL8366RB_PORT_ALL); + + /* don't drop packets whose DA has not been learned */ + REG_RMW(smi, RTL8366RB_SSCR2, RTL8366RB_SSCR2_DROP_UNKNOWN_DA, 0); + + return 0; +} + +static int rtl8366rb_read_phy_reg(struct rtl8366_smi *smi, + u32 phy_no, u32 page, u32 addr, u32 *data) +{ + u32 reg; + int ret; + + if (phy_no > RTL8366RB_PHY_NO_MAX) + return -EINVAL; + + if (page > RTL8366RB_PHY_PAGE_MAX) + return -EINVAL; + + if (addr > RTL8366RB_PHY_ADDR_MAX) + return -EINVAL; + + ret = rtl8366_smi_write_reg(smi, RTL8366RB_PHY_ACCESS_CTRL_REG, + RTL8366RB_PHY_CTRL_READ); + if (ret) + return ret; + + reg = 0x8000 | (1 << (phy_no + RTL8366RB_PHY_NO_OFFSET)) | + ((page << RTL8366RB_PHY_PAGE_OFFSET) & RTL8366RB_PHY_PAGE_MASK) | + (addr & RTL8366RB_PHY_REG_MASK); + + ret = rtl8366_smi_write_reg(smi, reg, 0); + if (ret) + return ret; + + ret = rtl8366_smi_read_reg(smi, RTL8366RB_PHY_ACCESS_DATA_REG, data); + if (ret) + return ret; + + return 0; +} + +static int rtl8366rb_write_phy_reg(struct rtl8366_smi *smi, + u32 phy_no, u32 page, u32 addr, u32 data) +{ + u32 reg; + int ret; + + if (phy_no > RTL8366RB_PHY_NO_MAX) + return -EINVAL; + + if (page > RTL8366RB_PHY_PAGE_MAX) + return -EINVAL; + + if (addr > RTL8366RB_PHY_ADDR_MAX) + return -EINVAL; + + ret = rtl8366_smi_write_reg(smi, RTL8366RB_PHY_ACCESS_CTRL_REG, + RTL8366RB_PHY_CTRL_WRITE); + if (ret) + return ret; + + reg = 0x8000 | (1 << (phy_no + RTL8366RB_PHY_NO_OFFSET)) | + ((page << RTL8366RB_PHY_PAGE_OFFSET) & RTL8366RB_PHY_PAGE_MASK) | + (addr & RTL8366RB_PHY_REG_MASK); + + ret = rtl8366_smi_write_reg(smi, reg, data); + if (ret) + return ret; + + return 0; +} + +static int rtl8366rb_get_mib_counter(struct rtl8366_smi *smi, int counter, + int port, unsigned long long *val) +{ + int i; + int err; + u32 addr, data; + u64 mibvalue; + + if (port > RTL8366RB_NUM_PORTS || counter >= RTL8366RB_MIB_COUNT) + return -EINVAL; + + addr = RTL8366RB_MIB_COUNTER_BASE + + RTL8366RB_MIB_COUNTER_PORT_OFFSET * (port) + + rtl8366rb_mib_counters[counter].offset; + + /* + * Writing access counter address first + * then ASIC will prepare 64bits counter wait for being retrived + */ + data = 0; /* writing data will be discard by ASIC */ + err = rtl8366_smi_write_reg(smi, addr, data); + if (err) + return err; + + /* read MIB control register */ + err = rtl8366_smi_read_reg(smi, RTL8366RB_MIB_CTRL_REG, &data); + if (err) + return err; + + if (data & RTL8366RB_MIB_CTRL_BUSY_MASK) + return -EBUSY; + + if (data & RTL8366RB_MIB_CTRL_RESET_MASK) + return -EIO; + + mibvalue = 0; + for (i = rtl8366rb_mib_counters[counter].length; i > 0; i--) { + err = rtl8366_smi_read_reg(smi, addr + (i - 1), &data); + if (err) + return err; + + mibvalue = (mibvalue << 16) | (data & 0xFFFF); + } + + *val = mibvalue; + return 0; +} + +static int rtl8366rb_get_vlan_4k(struct rtl8366_smi *smi, u32 vid, + struct rtl8366_vlan_4k *vlan4k) +{ + u32 data[3]; + int err; + int i; + + memset(vlan4k, '\0', sizeof(struct rtl8366_vlan_4k)); + + if (vid >= RTL8366RB_NUM_VIDS) + return -EINVAL; + + /* write VID */ + err = rtl8366_smi_write_reg(smi, RTL8366RB_VLAN_TABLE_WRITE_BASE, + vid & RTL8366RB_VLAN_VID_MASK); + if (err) + return err; + + /* write table access control word */ + err = rtl8366_smi_write_reg(smi, RTL8366RB_TABLE_ACCESS_CTRL_REG, + RTL8366RB_TABLE_VLAN_READ_CTRL); + if (err) + return err; + + for (i = 0; i < 3; i++) { + err = rtl8366_smi_read_reg(smi, + RTL8366RB_VLAN_TABLE_READ_BASE + i, + &data[i]); + if (err) + return err; + } + + vlan4k->vid = vid; + vlan4k->untag = (data[1] >> RTL8366RB_VLAN_UNTAG_SHIFT) & + RTL8366RB_VLAN_UNTAG_MASK; + vlan4k->member = data[1] & RTL8366RB_VLAN_MEMBER_MASK; + vlan4k->fid = data[2] & RTL8366RB_VLAN_FID_MASK; + + return 0; +} + +static int rtl8366rb_set_vlan_4k(struct rtl8366_smi *smi, + const struct rtl8366_vlan_4k *vlan4k) +{ + u32 data[3]; + int err; + int i; + + if (vlan4k->vid >= RTL8366RB_NUM_VIDS || + vlan4k->member > RTL8366RB_VLAN_MEMBER_MASK || + vlan4k->untag > RTL8366RB_VLAN_UNTAG_MASK || + vlan4k->fid > RTL8366RB_FIDMAX) + return -EINVAL; + + data[0] = vlan4k->vid & RTL8366RB_VLAN_VID_MASK; + data[1] = (vlan4k->member & RTL8366RB_VLAN_MEMBER_MASK) | + ((vlan4k->untag & RTL8366RB_VLAN_UNTAG_MASK) << + RTL8366RB_VLAN_UNTAG_SHIFT); + data[2] = vlan4k->fid & RTL8366RB_VLAN_FID_MASK; + + for (i = 0; i < 3; i++) { + err = rtl8366_smi_write_reg(smi, + RTL8366RB_VLAN_TABLE_WRITE_BASE + i, + data[i]); + if (err) + return err; + } + + /* write table access control word */ + err = rtl8366_smi_write_reg(smi, RTL8366RB_TABLE_ACCESS_CTRL_REG, + RTL8366RB_TABLE_VLAN_WRITE_CTRL); + + return err; +} + +static int rtl8366rb_get_vlan_mc(struct rtl8366_smi *smi, u32 index, + struct rtl8366_vlan_mc *vlanmc) +{ + u32 data[3]; + int err; + int i; + + memset(vlanmc, '\0', sizeof(struct rtl8366_vlan_mc)); + + if (index >= RTL8366RB_NUM_VLANS) + return -EINVAL; + + for (i = 0; i < 3; i++) { + err = rtl8366_smi_read_reg(smi, + RTL8366RB_VLAN_MC_BASE(index) + i, + &data[i]); + if (err) + return err; + } + + vlanmc->vid = data[0] & RTL8366RB_VLAN_VID_MASK; + vlanmc->priority = (data[0] >> RTL8366RB_VLAN_PRIORITY_SHIFT) & + RTL8366RB_VLAN_PRIORITY_MASK; + vlanmc->untag = (data[1] >> RTL8366RB_VLAN_UNTAG_SHIFT) & + RTL8366RB_VLAN_UNTAG_MASK; + vlanmc->member = data[1] & RTL8366RB_VLAN_MEMBER_MASK; + vlanmc->fid = data[2] & RTL8366RB_VLAN_FID_MASK; + + return 0; +} + +static int rtl8366rb_set_vlan_mc(struct rtl8366_smi *smi, u32 index, + const struct rtl8366_vlan_mc *vlanmc) +{ + u32 data[3]; + int err; + int i; + + if (index >= RTL8366RB_NUM_VLANS || + vlanmc->vid >= RTL8366RB_NUM_VIDS || + vlanmc->priority > RTL8366RB_PRIORITYMAX || + vlanmc->member > RTL8366RB_VLAN_MEMBER_MASK || + vlanmc->untag > RTL8366RB_VLAN_UNTAG_MASK || + vlanmc->fid > RTL8366RB_FIDMAX) + return -EINVAL; + + data[0] = (vlanmc->vid & RTL8366RB_VLAN_VID_MASK) | + ((vlanmc->priority & RTL8366RB_VLAN_PRIORITY_MASK) << + RTL8366RB_VLAN_PRIORITY_SHIFT); + data[1] = (vlanmc->member & RTL8366RB_VLAN_MEMBER_MASK) | + ((vlanmc->untag & RTL8366RB_VLAN_UNTAG_MASK) << + RTL8366RB_VLAN_UNTAG_SHIFT); + data[2] = vlanmc->fid & RTL8366RB_VLAN_FID_MASK; + + for (i = 0; i < 3; i++) { + err = rtl8366_smi_write_reg(smi, + RTL8366RB_VLAN_MC_BASE(index) + i, + data[i]); + if (err) + return err; + } + + return 0; +} + +static int rtl8366rb_get_mc_index(struct rtl8366_smi *smi, int port, int *val) +{ + u32 data; + int err; + + if (port >= RTL8366RB_NUM_PORTS) + return -EINVAL; + + err = rtl8366_smi_read_reg(smi, RTL8366RB_PORT_VLAN_CTRL_REG(port), + &data); + if (err) + return err; + + *val = (data >> RTL8366RB_PORT_VLAN_CTRL_SHIFT(port)) & + RTL8366RB_PORT_VLAN_CTRL_MASK; + + return 0; + +} + +static int rtl8366rb_set_mc_index(struct rtl8366_smi *smi, int port, int index) +{ + if (port >= RTL8366RB_NUM_PORTS || index >= RTL8366RB_NUM_VLANS) + return -EINVAL; + + return rtl8366_smi_rmwr(smi, RTL8366RB_PORT_VLAN_CTRL_REG(port), + RTL8366RB_PORT_VLAN_CTRL_MASK << + RTL8366RB_PORT_VLAN_CTRL_SHIFT(port), + (index & RTL8366RB_PORT_VLAN_CTRL_MASK) << + RTL8366RB_PORT_VLAN_CTRL_SHIFT(port)); +} + +static int rtl8366rb_is_vlan_valid(struct rtl8366_smi *smi, unsigned vlan) +{ + unsigned max = RTL8366RB_NUM_VLANS; + + if (smi->vlan4k_enabled) + max = RTL8366RB_NUM_VIDS - 1; + + if (vlan == 0 || vlan >= max) + return 0; + + return 1; +} + +static int rtl8366rb_enable_vlan(struct rtl8366_smi *smi, int enable) +{ + return rtl8366_smi_rmwr(smi, RTL8366RB_SGCR, RTL8366RB_SGCR_EN_VLAN, + (enable) ? RTL8366RB_SGCR_EN_VLAN : 0); +} + +static int rtl8366rb_enable_vlan4k(struct rtl8366_smi *smi, int enable) +{ + return rtl8366_smi_rmwr(smi, RTL8366RB_SGCR, + RTL8366RB_SGCR_EN_VLAN_4KTB, + (enable) ? RTL8366RB_SGCR_EN_VLAN_4KTB : 0); +} + +static int rtl8366rb_enable_port(struct rtl8366_smi *smi, int port, int enable) +{ + return rtl8366_smi_rmwr(smi, RTL8366RB_PECR, (1 << port), + (enable) ? 0 : (1 << port)); +} + +static int rtl8366rb_sw_reset_mibs(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + + return rtl8366_smi_rmwr(smi, RTL8366RB_MIB_CTRL_REG, 0, + RTL8366RB_MIB_CTRL_GLOBAL_RESET); +} + +static int rtl8366rb_sw_get_blinkrate(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + rtl8366_smi_read_reg(smi, RTL8366RB_LED_BLINKRATE_REG, &data); + + val->value.i = (data & (RTL8366RB_LED_BLINKRATE_MASK)); + + return 0; +} + +static int rtl8366rb_sw_set_blinkrate(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + + if (val->value.i >= 6) + return -EINVAL; + + return rtl8366_smi_rmwr(smi, RTL8366RB_LED_BLINKRATE_REG, + RTL8366RB_LED_BLINKRATE_MASK, + val->value.i); +} + +static int rtl8366rb_sw_get_learning_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + rtl8366_smi_read_reg(smi, RTL8366RB_SSCR0, &data); + val->value.i = !data; + + return 0; +} + + +static int rtl8366rb_sw_set_learning_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 portmask = 0; + int err = 0; + + if (!val->value.i) + portmask = RTL8366RB_PORT_ALL; + + /* set learning for all ports */ + REG_WR(smi, RTL8366RB_SSCR0, portmask); + + /* set auto ageing for all ports */ + REG_WR(smi, RTL8366RB_SSCR1, portmask); + + return 0; +} + +static int rtl8366rb_sw_get_port_link(struct switch_dev *dev, + int port, + struct switch_port_link *link) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data = 0; + u32 speed; + + if (port >= RTL8366RB_NUM_PORTS) + return -EINVAL; + + rtl8366_smi_read_reg(smi, RTL8366RB_PORT_LINK_STATUS_BASE + (port / 2), + &data); + + if (port % 2) + data = data >> 8; + + link->link = !!(data & RTL8366RB_PORT_STATUS_LINK_MASK); + if (!link->link) + return 0; + + link->duplex = !!(data & RTL8366RB_PORT_STATUS_DUPLEX_MASK); + link->rx_flow = !!(data & RTL8366RB_PORT_STATUS_RXPAUSE_MASK); + link->tx_flow = !!(data & RTL8366RB_PORT_STATUS_TXPAUSE_MASK); + link->aneg = !!(data & RTL8366RB_PORT_STATUS_AN_MASK); + + speed = (data & RTL8366RB_PORT_STATUS_SPEED_MASK); + switch (speed) { + case 0: + link->speed = SWITCH_PORT_SPEED_10; + break; + case 1: + link->speed = SWITCH_PORT_SPEED_100; + break; + case 2: + link->speed = SWITCH_PORT_SPEED_1000; + break; + default: + link->speed = SWITCH_PORT_SPEED_UNKNOWN; + break; + } + + return 0; +} + +static int rtl8366rb_sw_set_port_led(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + u32 mask; + u32 reg; + + if (val->port_vlan >= RTL8366RB_NUM_PORTS) + return -EINVAL; + + if (val->port_vlan == RTL8366RB_PORT_NUM_CPU) { + reg = RTL8366RB_LED_BLINKRATE_REG; + mask = 0xF << 4; + data = val->value.i << 4; + } else { + reg = RTL8366RB_LED_CTRL_REG; + mask = 0xF << (val->port_vlan * 4), + data = val->value.i << (val->port_vlan * 4); + } + + return rtl8366_smi_rmwr(smi, reg, mask, data); +} + +static int rtl8366rb_sw_get_port_led(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data = 0; + + if (val->port_vlan >= RTL8366RB_NUM_LEDGROUPS) + return -EINVAL; + + rtl8366_smi_read_reg(smi, RTL8366RB_LED_CTRL_REG, &data); + val->value.i = (data >> (val->port_vlan * 4)) & 0x000F; + + return 0; +} + +static int rtl8366rb_sw_set_port_disable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 mask, data; + + if (val->port_vlan >= RTL8366RB_NUM_PORTS) + return -EINVAL; + + mask = 1 << val->port_vlan ; + if (val->value.i) + data = mask; + else + data = 0; + + return rtl8366_smi_rmwr(smi, RTL8366RB_PECR, mask, data); +} + +static int rtl8366rb_sw_get_port_disable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + if (val->port_vlan >= RTL8366RB_NUM_PORTS) + return -EINVAL; + + rtl8366_smi_read_reg(smi, RTL8366RB_PECR, &data); + if (data & (1 << val->port_vlan)) + val->value.i = 1; + else + val->value.i = 0; + + return 0; +} + +static int rtl8366rb_sw_set_port_rate_in(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + + if (val->port_vlan >= RTL8366RB_NUM_PORTS) + return -EINVAL; + + if (val->value.i > 0 && val->value.i < RTL8366RB_BDTH_SW_MAX) + val->value.i = (val->value.i - 1) / RTL8366RB_BDTH_UNIT; + else + val->value.i = RTL8366RB_BDTH_REG_DEFAULT; + + return rtl8366_smi_rmwr(smi, RTL8366RB_IB_REG(val->port_vlan), + RTL8366RB_IB_BDTH_MASK | RTL8366RB_IB_PREIFG_MASK, + val->value.i | + (RTL8366RB_QOS_DEFAULT_PREIFG << RTL8366RB_IB_PREIFG_OFFSET)); + +} + +static int rtl8366rb_sw_get_port_rate_in(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + if (val->port_vlan >= RTL8366RB_NUM_PORTS) + return -EINVAL; + + rtl8366_smi_read_reg(smi, RTL8366RB_IB_REG(val->port_vlan), &data); + data &= RTL8366RB_IB_BDTH_MASK; + if (data < RTL8366RB_IB_BDTH_MASK) + data += 1; + + val->value.i = (int)data * RTL8366RB_BDTH_UNIT; + + return 0; +} + +static int rtl8366rb_sw_set_port_rate_out(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + + if (val->port_vlan >= RTL8366RB_NUM_PORTS) + return -EINVAL; + + rtl8366_smi_rmwr(smi, RTL8366RB_EB_PREIFG_REG, + RTL8366RB_EB_PREIFG_MASK, + (RTL8366RB_QOS_DEFAULT_PREIFG << RTL8366RB_EB_PREIFG_OFFSET)); + + if (val->value.i > 0 && val->value.i < RTL8366RB_BDTH_SW_MAX) + val->value.i = (val->value.i - 1) / RTL8366RB_BDTH_UNIT; + else + val->value.i = RTL8366RB_BDTH_REG_DEFAULT; + + return rtl8366_smi_rmwr(smi, RTL8366RB_EB_REG(val->port_vlan), + RTL8366RB_EB_BDTH_MASK, val->value.i ); + +} + +static int rtl8366rb_sw_get_port_rate_out(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + if (val->port_vlan >= RTL8366RB_NUM_PORTS) + return -EINVAL; + + rtl8366_smi_read_reg(smi, RTL8366RB_EB_REG(val->port_vlan), &data); + data &= RTL8366RB_EB_BDTH_MASK; + if (data < RTL8366RB_EB_BDTH_MASK) + data += 1; + + val->value.i = (int)data * RTL8366RB_BDTH_UNIT; + + return 0; +} + +static int rtl8366rb_sw_set_qos_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + if (val->value.i) + data = RTL8366RB_QOS_MASK; + else + data = 0; + + return rtl8366_smi_rmwr(smi, RTL8366RB_SGCR, RTL8366RB_QOS_MASK, data); +} + +static int rtl8366rb_sw_get_qos_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + rtl8366_smi_read_reg(smi, RTL8366RB_SGCR, &data); + if (data & RTL8366RB_QOS_MASK) + val->value.i = 1; + else + val->value.i = 0; + + return 0; +} + +static int rtl8366rb_sw_set_mirror_rx_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + if (val->value.i) + data = RTL8366RB_PMCR_MIRROR_RX; + else + data = 0; + + return rtl8366_smi_rmwr(smi, RTL8366RB_PMCR, RTL8366RB_PMCR_MIRROR_RX, data); +} + +static int rtl8366rb_sw_get_mirror_rx_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + rtl8366_smi_read_reg(smi, RTL8366RB_PMCR, &data); + if (data & RTL8366RB_PMCR_MIRROR_RX) + val->value.i = 1; + else + val->value.i = 0; + + return 0; +} + +static int rtl8366rb_sw_set_mirror_tx_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + if (val->value.i) + data = RTL8366RB_PMCR_MIRROR_TX; + else + data = 0; + + return rtl8366_smi_rmwr(smi, RTL8366RB_PMCR, RTL8366RB_PMCR_MIRROR_TX, data); +} + +static int rtl8366rb_sw_get_mirror_tx_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + rtl8366_smi_read_reg(smi, RTL8366RB_PMCR, &data); + if (data & RTL8366RB_PMCR_MIRROR_TX) + val->value.i = 1; + else + val->value.i = 0; + + return 0; +} + +static int rtl8366rb_sw_set_monitor_isolation_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + if (val->value.i) + data = RTL8366RB_PMCR_MIRROR_ISO; + else + data = 0; + + return rtl8366_smi_rmwr(smi, RTL8366RB_PMCR, RTL8366RB_PMCR_MIRROR_ISO, data); +} + +static int rtl8366rb_sw_get_monitor_isolation_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + rtl8366_smi_read_reg(smi, RTL8366RB_PMCR, &data); + if (data & RTL8366RB_PMCR_MIRROR_ISO) + val->value.i = 1; + else + val->value.i = 0; + + return 0; +} + +static int rtl8366rb_sw_set_mirror_pause_frames_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + if (val->value.i) + data = RTL8366RB_PMCR_MIRROR_SPC; + else + data = 0; + + return rtl8366_smi_rmwr(smi, RTL8366RB_PMCR, RTL8366RB_PMCR_MIRROR_SPC, data); +} + +static int rtl8366rb_sw_get_mirror_pause_frames_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + rtl8366_smi_read_reg(smi, RTL8366RB_PMCR, &data); + if (data & RTL8366RB_PMCR_MIRROR_SPC) + val->value.i = 1; + else + val->value.i = 0; + + return 0; +} + +static int rtl8366rb_sw_set_mirror_monitor_port(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + data = RTL8366RB_PMCR_MONITOR_PORT(val->value.i); + + return rtl8366_smi_rmwr(smi, RTL8366RB_PMCR, RTL8366RB_PMCR_MONITOR_PORT_MASK, data); +} + +static int rtl8366rb_sw_get_mirror_monitor_port(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + rtl8366_smi_read_reg(smi, RTL8366RB_PMCR, &data); + val->value.i = (data & RTL8366RB_PMCR_MONITOR_PORT_MASK) >> 4; + + return 0; +} + +static int rtl8366rb_sw_set_mirror_source_port(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + data = RTL8366RB_PMCR_SOURCE_PORT(val->value.i); + + return rtl8366_smi_rmwr(smi, RTL8366RB_PMCR, RTL8366RB_PMCR_SOURCE_PORT_MASK, data); +} + +static int rtl8366rb_sw_get_mirror_source_port(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + rtl8366_smi_read_reg(smi, RTL8366RB_PMCR, &data); + val->value.i = data & RTL8366RB_PMCR_SOURCE_PORT_MASK; + + return 0; +} + +static int rtl8366rb_sw_reset_port_mibs(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + + if (val->port_vlan >= RTL8366RB_NUM_PORTS) + return -EINVAL; + + return rtl8366_smi_rmwr(smi, RTL8366RB_MIB_CTRL_REG, 0, + RTL8366RB_MIB_CTRL_PORT_RESET(val->port_vlan)); +} + +static struct switch_attr rtl8366rb_globals[] = { + { + .type = SWITCH_TYPE_INT, + .name = "enable_learning", + .description = "Enable learning, enable aging", + .set = rtl8366rb_sw_set_learning_enable, + .get = rtl8366rb_sw_get_learning_enable, + .max = 1 + }, { + .type = SWITCH_TYPE_INT, + .name = "enable_vlan", + .description = "Enable VLAN mode", + .set = rtl8366_sw_set_vlan_enable, + .get = rtl8366_sw_get_vlan_enable, + .max = 1, + .ofs = 1 + }, { + .type = SWITCH_TYPE_INT, + .name = "enable_vlan4k", + .description = "Enable VLAN 4K mode", + .set = rtl8366_sw_set_vlan_enable, + .get = rtl8366_sw_get_vlan_enable, + .max = 1, + .ofs = 2 + }, { + .type = SWITCH_TYPE_NOVAL, + .name = "reset_mibs", + .description = "Reset all MIB counters", + .set = rtl8366rb_sw_reset_mibs, + }, { + .type = SWITCH_TYPE_INT, + .name = "blinkrate", + .description = "Get/Set LED blinking rate (0 = 43ms, 1 = 84ms," + " 2 = 120ms, 3 = 170ms, 4 = 340ms, 5 = 670ms)", + .set = rtl8366rb_sw_set_blinkrate, + .get = rtl8366rb_sw_get_blinkrate, + .max = 5 + }, { + .type = SWITCH_TYPE_INT, + .name = "enable_qos", + .description = "Enable QOS", + .set = rtl8366rb_sw_set_qos_enable, + .get = rtl8366rb_sw_get_qos_enable, + .max = 1 + }, { + .type = SWITCH_TYPE_INT, + .name = "enable_mirror_rx", + .description = "Enable mirroring of RX packets", + .set = rtl8366rb_sw_set_mirror_rx_enable, + .get = rtl8366rb_sw_get_mirror_rx_enable, + .max = 1 + }, { + .type = SWITCH_TYPE_INT, + .name = "enable_mirror_tx", + .description = "Enable mirroring of TX packets", + .set = rtl8366rb_sw_set_mirror_tx_enable, + .get = rtl8366rb_sw_get_mirror_tx_enable, + .max = 1 + }, { + .type = SWITCH_TYPE_INT, + .name = "enable_monitor_isolation", + .description = "Enable isolation of monitor port (TX packets will be dropped)", + .set = rtl8366rb_sw_set_monitor_isolation_enable, + .get = rtl8366rb_sw_get_monitor_isolation_enable, + .max = 1 + }, { + .type = SWITCH_TYPE_INT, + .name = "enable_mirror_pause_frames", + .description = "Enable mirroring of RX pause frames", + .set = rtl8366rb_sw_set_mirror_pause_frames_enable, + .get = rtl8366rb_sw_get_mirror_pause_frames_enable, + .max = 1 + }, { + .type = SWITCH_TYPE_INT, + .name = "mirror_monitor_port", + .description = "Mirror monitor port", + .set = rtl8366rb_sw_set_mirror_monitor_port, + .get = rtl8366rb_sw_get_mirror_monitor_port, + .max = 5 + }, { + .type = SWITCH_TYPE_INT, + .name = "mirror_source_port", + .description = "Mirror source port", + .set = rtl8366rb_sw_set_mirror_source_port, + .get = rtl8366rb_sw_get_mirror_source_port, + .max = 5 + }, +}; + +static struct switch_attr rtl8366rb_port[] = { + { + .type = SWITCH_TYPE_NOVAL, + .name = "reset_mib", + .description = "Reset single port MIB counters", + .set = rtl8366rb_sw_reset_port_mibs, + }, { + .type = SWITCH_TYPE_STRING, + .name = "mib", + .description = "Get MIB counters for port", + .max = 33, + .set = NULL, + .get = rtl8366_sw_get_port_mib, + }, { + .type = SWITCH_TYPE_INT, + .name = "led", + .description = "Get/Set port group (0 - 3) led mode (0 - 15)", + .max = 15, + .set = rtl8366rb_sw_set_port_led, + .get = rtl8366rb_sw_get_port_led, + }, { + .type = SWITCH_TYPE_INT, + .name = "disable", + .description = "Get/Set port state (enabled or disabled)", + .max = 1, + .set = rtl8366rb_sw_set_port_disable, + .get = rtl8366rb_sw_get_port_disable, + }, { + .type = SWITCH_TYPE_INT, + .name = "rate_in", + .description = "Get/Set port ingress (incoming) bandwidth limit in kbps", + .max = RTL8366RB_BDTH_SW_MAX, + .set = rtl8366rb_sw_set_port_rate_in, + .get = rtl8366rb_sw_get_port_rate_in, + }, { + .type = SWITCH_TYPE_INT, + .name = "rate_out", + .description = "Get/Set port egress (outgoing) bandwidth limit in kbps", + .max = RTL8366RB_BDTH_SW_MAX, + .set = rtl8366rb_sw_set_port_rate_out, + .get = rtl8366rb_sw_get_port_rate_out, + }, +}; + +static struct switch_attr rtl8366rb_vlan[] = { + { + .type = SWITCH_TYPE_STRING, + .name = "info", + .description = "Get vlan information", + .max = 1, + .set = NULL, + .get = rtl8366_sw_get_vlan_info, + }, { + .type = SWITCH_TYPE_INT, + .name = "fid", + .description = "Get/Set vlan FID", + .max = RTL8366RB_FIDMAX, + .set = rtl8366_sw_set_vlan_fid, + .get = rtl8366_sw_get_vlan_fid, + }, +}; + +static const struct switch_dev_ops rtl8366_ops = { + .attr_global = { + .attr = rtl8366rb_globals, + .n_attr = ARRAY_SIZE(rtl8366rb_globals), + }, + .attr_port = { + .attr = rtl8366rb_port, + .n_attr = ARRAY_SIZE(rtl8366rb_port), + }, + .attr_vlan = { + .attr = rtl8366rb_vlan, + .n_attr = ARRAY_SIZE(rtl8366rb_vlan), + }, + + .get_vlan_ports = rtl8366_sw_get_vlan_ports, + .set_vlan_ports = rtl8366_sw_set_vlan_ports, + .get_port_pvid = rtl8366_sw_get_port_pvid, + .set_port_pvid = rtl8366_sw_set_port_pvid, + .reset_switch = rtl8366_sw_reset_switch, + .get_port_link = rtl8366rb_sw_get_port_link, +}; + +static int rtl8366rb_switch_init(struct rtl8366_smi *smi) +{ + struct switch_dev *dev = &smi->sw_dev; + int err; + + dev->name = "RTL8366RB"; + dev->cpu_port = RTL8366RB_PORT_NUM_CPU; + dev->ports = RTL8366RB_NUM_PORTS; + dev->vlans = RTL8366RB_NUM_VIDS; + dev->ops = &rtl8366_ops; + dev->alias = dev_name(smi->parent); + + err = register_switch(dev, NULL); + if (err) + dev_err(smi->parent, "switch registration failed\n"); + + return err; +} + +static void rtl8366rb_switch_cleanup(struct rtl8366_smi *smi) +{ + unregister_switch(&smi->sw_dev); +} + +static int rtl8366rb_mii_read(struct mii_bus *bus, int addr, int reg) +{ + struct rtl8366_smi *smi = bus->priv; + u32 val = 0; + int err; + + err = rtl8366rb_read_phy_reg(smi, addr, 0, reg, &val); + if (err) + return 0xffff; + + return val; +} + +static int rtl8366rb_mii_write(struct mii_bus *bus, int addr, int reg, u16 val) +{ + struct rtl8366_smi *smi = bus->priv; + u32 t; + int err; + + err = rtl8366rb_write_phy_reg(smi, addr, 0, reg, val); + /* flush write */ + (void) rtl8366rb_read_phy_reg(smi, addr, 0, reg, &t); + + return err; +} + +static int rtl8366rb_detect(struct rtl8366_smi *smi) +{ + u32 chip_id = 0; + u32 chip_ver = 0; + int ret; + + ret = rtl8366_smi_read_reg(smi, RTL8366RB_CHIP_ID_REG, &chip_id); + if (ret) { + dev_err(smi->parent, "unable to read chip id\n"); + return ret; + } + + switch (chip_id) { + case RTL8366RB_CHIP_ID_8366: + break; + default: + dev_err(smi->parent, "unknown chip id (%04x)\n", chip_id); + return -ENODEV; + } + + ret = rtl8366_smi_read_reg(smi, RTL8366RB_CHIP_VERSION_CTRL_REG, + &chip_ver); + if (ret) { + dev_err(smi->parent, "unable to read chip version\n"); + return ret; + } + + dev_info(smi->parent, "RTL%04x ver. %u chip found\n", + chip_id, chip_ver & RTL8366RB_CHIP_VERSION_MASK); + + return 0; +} + +static struct rtl8366_smi_ops rtl8366rb_smi_ops = { + .detect = rtl8366rb_detect, + .reset_chip = rtl8366rb_reset_chip, + .setup = rtl8366rb_setup, + + .mii_read = rtl8366rb_mii_read, + .mii_write = rtl8366rb_mii_write, + + .get_vlan_mc = rtl8366rb_get_vlan_mc, + .set_vlan_mc = rtl8366rb_set_vlan_mc, + .get_vlan_4k = rtl8366rb_get_vlan_4k, + .set_vlan_4k = rtl8366rb_set_vlan_4k, + .get_mc_index = rtl8366rb_get_mc_index, + .set_mc_index = rtl8366rb_set_mc_index, + .get_mib_counter = rtl8366rb_get_mib_counter, + .is_vlan_valid = rtl8366rb_is_vlan_valid, + .enable_vlan = rtl8366rb_enable_vlan, + .enable_vlan4k = rtl8366rb_enable_vlan4k, + .enable_port = rtl8366rb_enable_port, +}; + +static int rtl8366rb_probe(struct platform_device *pdev) +{ + static int rtl8366_smi_version_printed; + struct rtl8366_smi *smi; + int err; + + if (!rtl8366_smi_version_printed++) + printk(KERN_NOTICE RTL8366RB_DRIVER_DESC + " version " RTL8366RB_DRIVER_VER"\n"); + + smi = rtl8366_smi_probe(pdev); + if (!smi) + return -ENODEV; + + smi->clk_delay = 10; + smi->cmd_read = 0xa9; + smi->cmd_write = 0xa8; + smi->ops = &rtl8366rb_smi_ops; + smi->cpu_port = RTL8366RB_PORT_NUM_CPU; + smi->num_ports = RTL8366RB_NUM_PORTS; + smi->num_vlan_mc = RTL8366RB_NUM_VLANS; + smi->mib_counters = rtl8366rb_mib_counters; + smi->num_mib_counters = ARRAY_SIZE(rtl8366rb_mib_counters); + + err = rtl8366_smi_init(smi); + if (err) + goto err_free_smi; + + platform_set_drvdata(pdev, smi); + + err = rtl8366rb_switch_init(smi); + if (err) + goto err_clear_drvdata; + + return 0; + + err_clear_drvdata: + platform_set_drvdata(pdev, NULL); + rtl8366_smi_cleanup(smi); + err_free_smi: + kfree(smi); + return err; +} + +static int rtl8366rb_remove(struct platform_device *pdev) +{ + struct rtl8366_smi *smi = platform_get_drvdata(pdev); + + if (smi) { + rtl8366rb_switch_cleanup(smi); + platform_set_drvdata(pdev, NULL); + rtl8366_smi_cleanup(smi); + kfree(smi); + } + + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id rtl8366rb_match[] = { + { .compatible = "rtl8366rb" }, + {}, +}; +MODULE_DEVICE_TABLE(of, rtl8366rb_match); +#endif + +static struct platform_driver rtl8366rb_driver = { + .driver = { + .name = RTL8366RB_DRIVER_NAME, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(rtl8366rb_match), + }, + .probe = rtl8366rb_probe, + .remove = rtl8366rb_remove, +}; + +static int __init rtl8366rb_module_init(void) +{ + return platform_driver_register(&rtl8366rb_driver); +} +module_init(rtl8366rb_module_init); + +static void __exit rtl8366rb_module_exit(void) +{ + platform_driver_unregister(&rtl8366rb_driver); +} +module_exit(rtl8366rb_module_exit); + +MODULE_DESCRIPTION(RTL8366RB_DRIVER_DESC); +MODULE_VERSION(RTL8366RB_DRIVER_VER); +MODULE_AUTHOR("Gabor Juhos "); +MODULE_AUTHOR("Antti Seppälä "); +MODULE_AUTHOR("Roman Yeryomin "); +MODULE_AUTHOR("Colin Leitner "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" RTL8366RB_DRIVER_NAME); diff --git a/target/linux/generic/files/drivers/net/phy/rtl8366s.c b/target/linux/generic/files/drivers/net/phy/rtl8366s.c new file mode 100644 index 0000000..3dc2a87 --- /dev/null +++ b/target/linux/generic/files/drivers/net/phy/rtl8366s.c @@ -0,0 +1,1148 @@ +/* + * Platform driver for the Realtek RTL8366S ethernet switch + * + * Copyright (C) 2009-2010 Gabor Juhos + * Copyright (C) 2010 Antti Seppälä + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rtl8366_smi.h" + +#define RTL8366S_DRIVER_DESC "Realtek RTL8366S ethernet switch driver" +#define RTL8366S_DRIVER_VER "0.2.2" + +#define RTL8366S_PHY_NO_MAX 4 +#define RTL8366S_PHY_PAGE_MAX 7 +#define RTL8366S_PHY_ADDR_MAX 31 + +/* Switch Global Configuration register */ +#define RTL8366S_SGCR 0x0000 +#define RTL8366S_SGCR_EN_BC_STORM_CTRL BIT(0) +#define RTL8366S_SGCR_MAX_LENGTH(_x) (_x << 4) +#define RTL8366S_SGCR_MAX_LENGTH_MASK RTL8366S_SGCR_MAX_LENGTH(0x3) +#define RTL8366S_SGCR_MAX_LENGTH_1522 RTL8366S_SGCR_MAX_LENGTH(0x0) +#define RTL8366S_SGCR_MAX_LENGTH_1536 RTL8366S_SGCR_MAX_LENGTH(0x1) +#define RTL8366S_SGCR_MAX_LENGTH_1552 RTL8366S_SGCR_MAX_LENGTH(0x2) +#define RTL8366S_SGCR_MAX_LENGTH_16000 RTL8366S_SGCR_MAX_LENGTH(0x3) +#define RTL8366S_SGCR_EN_VLAN BIT(13) + +/* Port Enable Control register */ +#define RTL8366S_PECR 0x0001 + +/* Switch Security Control registers */ +#define RTL8366S_SSCR0 0x0002 +#define RTL8366S_SSCR1 0x0003 +#define RTL8366S_SSCR2 0x0004 +#define RTL8366S_SSCR2_DROP_UNKNOWN_DA BIT(0) + +#define RTL8366S_RESET_CTRL_REG 0x0100 +#define RTL8366S_CHIP_CTRL_RESET_HW 1 +#define RTL8366S_CHIP_CTRL_RESET_SW (1 << 1) + +#define RTL8366S_CHIP_VERSION_CTRL_REG 0x0104 +#define RTL8366S_CHIP_VERSION_MASK 0xf +#define RTL8366S_CHIP_ID_REG 0x0105 +#define RTL8366S_CHIP_ID_8366 0x8366 + +/* PHY registers control */ +#define RTL8366S_PHY_ACCESS_CTRL_REG 0x8028 +#define RTL8366S_PHY_ACCESS_DATA_REG 0x8029 + +#define RTL8366S_PHY_CTRL_READ 1 +#define RTL8366S_PHY_CTRL_WRITE 0 + +#define RTL8366S_PHY_REG_MASK 0x1f +#define RTL8366S_PHY_PAGE_OFFSET 5 +#define RTL8366S_PHY_PAGE_MASK (0x7 << 5) +#define RTL8366S_PHY_NO_OFFSET 9 +#define RTL8366S_PHY_NO_MASK (0x1f << 9) + +/* LED control registers */ +#define RTL8366S_LED_BLINKRATE_REG 0x0420 +#define RTL8366S_LED_BLINKRATE_BIT 0 +#define RTL8366S_LED_BLINKRATE_MASK 0x0007 + +#define RTL8366S_LED_CTRL_REG 0x0421 +#define RTL8366S_LED_0_1_CTRL_REG 0x0422 +#define RTL8366S_LED_2_3_CTRL_REG 0x0423 + +#define RTL8366S_MIB_COUNT 33 +#define RTL8366S_GLOBAL_MIB_COUNT 1 +#define RTL8366S_MIB_COUNTER_PORT_OFFSET 0x0040 +#define RTL8366S_MIB_COUNTER_BASE 0x1000 +#define RTL8366S_MIB_COUNTER_PORT_OFFSET2 0x0008 +#define RTL8366S_MIB_COUNTER_BASE2 0x1180 +#define RTL8366S_MIB_CTRL_REG 0x11F0 +#define RTL8366S_MIB_CTRL_USER_MASK 0x01FF +#define RTL8366S_MIB_CTRL_BUSY_MASK 0x0001 +#define RTL8366S_MIB_CTRL_RESET_MASK 0x0002 + +#define RTL8366S_MIB_CTRL_GLOBAL_RESET_MASK 0x0004 +#define RTL8366S_MIB_CTRL_PORT_RESET_BIT 0x0003 +#define RTL8366S_MIB_CTRL_PORT_RESET_MASK 0x01FC + + +#define RTL8366S_PORT_VLAN_CTRL_BASE 0x0058 +#define RTL8366S_PORT_VLAN_CTRL_REG(_p) \ + (RTL8366S_PORT_VLAN_CTRL_BASE + (_p) / 4) +#define RTL8366S_PORT_VLAN_CTRL_MASK 0xf +#define RTL8366S_PORT_VLAN_CTRL_SHIFT(_p) (4 * ((_p) % 4)) + + +#define RTL8366S_VLAN_TABLE_READ_BASE 0x018B +#define RTL8366S_VLAN_TABLE_WRITE_BASE 0x0185 + +#define RTL8366S_VLAN_TB_CTRL_REG 0x010F + +#define RTL8366S_TABLE_ACCESS_CTRL_REG 0x0180 +#define RTL8366S_TABLE_VLAN_READ_CTRL 0x0E01 +#define RTL8366S_TABLE_VLAN_WRITE_CTRL 0x0F01 + +#define RTL8366S_VLAN_MC_BASE(_x) (0x0016 + (_x) * 2) + +#define RTL8366S_VLAN_MEMBERINGRESS_REG 0x0379 + +#define RTL8366S_PORT_LINK_STATUS_BASE 0x0060 +#define RTL8366S_PORT_STATUS_SPEED_MASK 0x0003 +#define RTL8366S_PORT_STATUS_DUPLEX_MASK 0x0004 +#define RTL8366S_PORT_STATUS_LINK_MASK 0x0010 +#define RTL8366S_PORT_STATUS_TXPAUSE_MASK 0x0020 +#define RTL8366S_PORT_STATUS_RXPAUSE_MASK 0x0040 +#define RTL8366S_PORT_STATUS_AN_MASK 0x0080 + + +#define RTL8366S_PORT_NUM_CPU 5 +#define RTL8366S_NUM_PORTS 6 +#define RTL8366S_NUM_VLANS 16 +#define RTL8366S_NUM_LEDGROUPS 4 +#define RTL8366S_NUM_VIDS 4096 +#define RTL8366S_PRIORITYMAX 7 +#define RTL8366S_FIDMAX 7 + + +#define RTL8366S_PORT_1 (1 << 0) /* In userspace port 0 */ +#define RTL8366S_PORT_2 (1 << 1) /* In userspace port 1 */ +#define RTL8366S_PORT_3 (1 << 2) /* In userspace port 2 */ +#define RTL8366S_PORT_4 (1 << 3) /* In userspace port 3 */ + +#define RTL8366S_PORT_UNKNOWN (1 << 4) /* No known connection */ +#define RTL8366S_PORT_CPU (1 << 5) /* CPU port */ + +#define RTL8366S_PORT_ALL (RTL8366S_PORT_1 | \ + RTL8366S_PORT_2 | \ + RTL8366S_PORT_3 | \ + RTL8366S_PORT_4 | \ + RTL8366S_PORT_UNKNOWN | \ + RTL8366S_PORT_CPU) + +#define RTL8366S_PORT_ALL_BUT_CPU (RTL8366S_PORT_1 | \ + RTL8366S_PORT_2 | \ + RTL8366S_PORT_3 | \ + RTL8366S_PORT_4 | \ + RTL8366S_PORT_UNKNOWN) + +#define RTL8366S_PORT_ALL_EXTERNAL (RTL8366S_PORT_1 | \ + RTL8366S_PORT_2 | \ + RTL8366S_PORT_3 | \ + RTL8366S_PORT_4) + +#define RTL8366S_PORT_ALL_INTERNAL (RTL8366S_PORT_UNKNOWN | \ + RTL8366S_PORT_CPU) + +#define RTL8366S_VLAN_VID_MASK 0xfff +#define RTL8366S_VLAN_PRIORITY_SHIFT 12 +#define RTL8366S_VLAN_PRIORITY_MASK 0x7 +#define RTL8366S_VLAN_MEMBER_MASK 0x3f +#define RTL8366S_VLAN_UNTAG_SHIFT 6 +#define RTL8366S_VLAN_UNTAG_MASK 0x3f +#define RTL8366S_VLAN_FID_SHIFT 12 +#define RTL8366S_VLAN_FID_MASK 0x7 + +static struct rtl8366_mib_counter rtl8366s_mib_counters[] = { + { 0, 0, 4, "IfInOctets" }, + { 0, 4, 4, "EtherStatsOctets" }, + { 0, 8, 2, "EtherStatsUnderSizePkts" }, + { 0, 10, 2, "EtherFragments" }, + { 0, 12, 2, "EtherStatsPkts64Octets" }, + { 0, 14, 2, "EtherStatsPkts65to127Octets" }, + { 0, 16, 2, "EtherStatsPkts128to255Octets" }, + { 0, 18, 2, "EtherStatsPkts256to511Octets" }, + { 0, 20, 2, "EtherStatsPkts512to1023Octets" }, + { 0, 22, 2, "EtherStatsPkts1024to1518Octets" }, + { 0, 24, 2, "EtherOversizeStats" }, + { 0, 26, 2, "EtherStatsJabbers" }, + { 0, 28, 2, "IfInUcastPkts" }, + { 0, 30, 2, "EtherStatsMulticastPkts" }, + { 0, 32, 2, "EtherStatsBroadcastPkts" }, + { 0, 34, 2, "EtherStatsDropEvents" }, + { 0, 36, 2, "Dot3StatsFCSErrors" }, + { 0, 38, 2, "Dot3StatsSymbolErrors" }, + { 0, 40, 2, "Dot3InPauseFrames" }, + { 0, 42, 2, "Dot3ControlInUnknownOpcodes" }, + { 0, 44, 4, "IfOutOctets" }, + { 0, 48, 2, "Dot3StatsSingleCollisionFrames" }, + { 0, 50, 2, "Dot3StatMultipleCollisionFrames" }, + { 0, 52, 2, "Dot3sDeferredTransmissions" }, + { 0, 54, 2, "Dot3StatsLateCollisions" }, + { 0, 56, 2, "EtherStatsCollisions" }, + { 0, 58, 2, "Dot3StatsExcessiveCollisions" }, + { 0, 60, 2, "Dot3OutPauseFrames" }, + { 0, 62, 2, "Dot1dBasePortDelayExceededDiscards" }, + + /* + * The following counters are accessible at a different + * base address. + */ + { 1, 0, 2, "Dot1dTpPortInDiscards" }, + { 1, 2, 2, "IfOutUcastPkts" }, + { 1, 4, 2, "IfOutMulticastPkts" }, + { 1, 6, 2, "IfOutBroadcastPkts" }, +}; + +#define REG_WR(_smi, _reg, _val) \ + do { \ + err = rtl8366_smi_write_reg(_smi, _reg, _val); \ + if (err) \ + return err; \ + } while (0) + +#define REG_RMW(_smi, _reg, _mask, _val) \ + do { \ + err = rtl8366_smi_rmwr(_smi, _reg, _mask, _val); \ + if (err) \ + return err; \ + } while (0) + +static int rtl8366s_reset_chip(struct rtl8366_smi *smi) +{ + int timeout = 10; + u32 data; + + rtl8366_smi_write_reg_noack(smi, RTL8366S_RESET_CTRL_REG, + RTL8366S_CHIP_CTRL_RESET_HW); + do { + msleep(1); + if (rtl8366_smi_read_reg(smi, RTL8366S_RESET_CTRL_REG, &data)) + return -EIO; + + if (!(data & RTL8366S_CHIP_CTRL_RESET_HW)) + break; + } while (--timeout); + + if (!timeout) { + printk("Timeout waiting for the switch to reset\n"); + return -EIO; + } + + return 0; +} + +static int rtl8366s_setup(struct rtl8366_smi *smi) +{ + struct rtl8366_platform_data *pdata; + int err; + + pdata = smi->parent->platform_data; + if (pdata && pdata->num_initvals && pdata->initvals) { + unsigned i; + + dev_info(smi->parent, "applying initvals\n"); + for (i = 0; i < pdata->num_initvals; i++) + REG_WR(smi, pdata->initvals[i].reg, + pdata->initvals[i].val); + } + + /* set maximum packet length to 1536 bytes */ + REG_RMW(smi, RTL8366S_SGCR, RTL8366S_SGCR_MAX_LENGTH_MASK, + RTL8366S_SGCR_MAX_LENGTH_1536); + + /* enable learning for all ports */ + REG_WR(smi, RTL8366S_SSCR0, 0); + + /* enable auto ageing for all ports */ + REG_WR(smi, RTL8366S_SSCR1, 0); + + /* + * discard VLAN tagged packets if the port is not a member of + * the VLAN with which the packets is associated. + */ + REG_WR(smi, RTL8366S_VLAN_MEMBERINGRESS_REG, RTL8366S_PORT_ALL); + + /* don't drop packets whose DA has not been learned */ + REG_RMW(smi, RTL8366S_SSCR2, RTL8366S_SSCR2_DROP_UNKNOWN_DA, 0); + + return 0; +} + +static int rtl8366s_read_phy_reg(struct rtl8366_smi *smi, + u32 phy_no, u32 page, u32 addr, u32 *data) +{ + u32 reg; + int ret; + + if (phy_no > RTL8366S_PHY_NO_MAX) + return -EINVAL; + + if (page > RTL8366S_PHY_PAGE_MAX) + return -EINVAL; + + if (addr > RTL8366S_PHY_ADDR_MAX) + return -EINVAL; + + ret = rtl8366_smi_write_reg(smi, RTL8366S_PHY_ACCESS_CTRL_REG, + RTL8366S_PHY_CTRL_READ); + if (ret) + return ret; + + reg = 0x8000 | (1 << (phy_no + RTL8366S_PHY_NO_OFFSET)) | + ((page << RTL8366S_PHY_PAGE_OFFSET) & RTL8366S_PHY_PAGE_MASK) | + (addr & RTL8366S_PHY_REG_MASK); + + ret = rtl8366_smi_write_reg(smi, reg, 0); + if (ret) + return ret; + + ret = rtl8366_smi_read_reg(smi, RTL8366S_PHY_ACCESS_DATA_REG, data); + if (ret) + return ret; + + return 0; +} + +static int rtl8366s_write_phy_reg(struct rtl8366_smi *smi, + u32 phy_no, u32 page, u32 addr, u32 data) +{ + u32 reg; + int ret; + + if (phy_no > RTL8366S_PHY_NO_MAX) + return -EINVAL; + + if (page > RTL8366S_PHY_PAGE_MAX) + return -EINVAL; + + if (addr > RTL8366S_PHY_ADDR_MAX) + return -EINVAL; + + ret = rtl8366_smi_write_reg(smi, RTL8366S_PHY_ACCESS_CTRL_REG, + RTL8366S_PHY_CTRL_WRITE); + if (ret) + return ret; + + reg = 0x8000 | (1 << (phy_no + RTL8366S_PHY_NO_OFFSET)) | + ((page << RTL8366S_PHY_PAGE_OFFSET) & RTL8366S_PHY_PAGE_MASK) | + (addr & RTL8366S_PHY_REG_MASK); + + ret = rtl8366_smi_write_reg(smi, reg, data); + if (ret) + return ret; + + return 0; +} + +static int rtl8366_get_mib_counter(struct rtl8366_smi *smi, int counter, + int port, unsigned long long *val) +{ + int i; + int err; + u32 addr, data; + u64 mibvalue; + + if (port > RTL8366S_NUM_PORTS || counter >= RTL8366S_MIB_COUNT) + return -EINVAL; + + switch (rtl8366s_mib_counters[counter].base) { + case 0: + addr = RTL8366S_MIB_COUNTER_BASE + + RTL8366S_MIB_COUNTER_PORT_OFFSET * port; + break; + + case 1: + addr = RTL8366S_MIB_COUNTER_BASE2 + + RTL8366S_MIB_COUNTER_PORT_OFFSET2 * port; + break; + + default: + return -EINVAL; + } + + addr += rtl8366s_mib_counters[counter].offset; + + /* + * Writing access counter address first + * then ASIC will prepare 64bits counter wait for being retrived + */ + data = 0; /* writing data will be discard by ASIC */ + err = rtl8366_smi_write_reg(smi, addr, data); + if (err) + return err; + + /* read MIB control register */ + err = rtl8366_smi_read_reg(smi, RTL8366S_MIB_CTRL_REG, &data); + if (err) + return err; + + if (data & RTL8366S_MIB_CTRL_BUSY_MASK) + return -EBUSY; + + if (data & RTL8366S_MIB_CTRL_RESET_MASK) + return -EIO; + + mibvalue = 0; + for (i = rtl8366s_mib_counters[counter].length; i > 0; i--) { + err = rtl8366_smi_read_reg(smi, addr + (i - 1), &data); + if (err) + return err; + + mibvalue = (mibvalue << 16) | (data & 0xFFFF); + } + + *val = mibvalue; + return 0; +} + +static int rtl8366s_get_vlan_4k(struct rtl8366_smi *smi, u32 vid, + struct rtl8366_vlan_4k *vlan4k) +{ + u32 data[2]; + int err; + int i; + + memset(vlan4k, '\0', sizeof(struct rtl8366_vlan_4k)); + + if (vid >= RTL8366S_NUM_VIDS) + return -EINVAL; + + /* write VID */ + err = rtl8366_smi_write_reg(smi, RTL8366S_VLAN_TABLE_WRITE_BASE, + vid & RTL8366S_VLAN_VID_MASK); + if (err) + return err; + + /* write table access control word */ + err = rtl8366_smi_write_reg(smi, RTL8366S_TABLE_ACCESS_CTRL_REG, + RTL8366S_TABLE_VLAN_READ_CTRL); + if (err) + return err; + + for (i = 0; i < 2; i++) { + err = rtl8366_smi_read_reg(smi, + RTL8366S_VLAN_TABLE_READ_BASE + i, + &data[i]); + if (err) + return err; + } + + vlan4k->vid = vid; + vlan4k->untag = (data[1] >> RTL8366S_VLAN_UNTAG_SHIFT) & + RTL8366S_VLAN_UNTAG_MASK; + vlan4k->member = data[1] & RTL8366S_VLAN_MEMBER_MASK; + vlan4k->fid = (data[1] >> RTL8366S_VLAN_FID_SHIFT) & + RTL8366S_VLAN_FID_MASK; + + return 0; +} + +static int rtl8366s_set_vlan_4k(struct rtl8366_smi *smi, + const struct rtl8366_vlan_4k *vlan4k) +{ + u32 data[2]; + int err; + int i; + + if (vlan4k->vid >= RTL8366S_NUM_VIDS || + vlan4k->member > RTL8366S_VLAN_MEMBER_MASK || + vlan4k->untag > RTL8366S_VLAN_UNTAG_MASK || + vlan4k->fid > RTL8366S_FIDMAX) + return -EINVAL; + + data[0] = vlan4k->vid & RTL8366S_VLAN_VID_MASK; + data[1] = (vlan4k->member & RTL8366S_VLAN_MEMBER_MASK) | + ((vlan4k->untag & RTL8366S_VLAN_UNTAG_MASK) << + RTL8366S_VLAN_UNTAG_SHIFT) | + ((vlan4k->fid & RTL8366S_VLAN_FID_MASK) << + RTL8366S_VLAN_FID_SHIFT); + + for (i = 0; i < 2; i++) { + err = rtl8366_smi_write_reg(smi, + RTL8366S_VLAN_TABLE_WRITE_BASE + i, + data[i]); + if (err) + return err; + } + + /* write table access control word */ + err = rtl8366_smi_write_reg(smi, RTL8366S_TABLE_ACCESS_CTRL_REG, + RTL8366S_TABLE_VLAN_WRITE_CTRL); + + return err; +} + +static int rtl8366s_get_vlan_mc(struct rtl8366_smi *smi, u32 index, + struct rtl8366_vlan_mc *vlanmc) +{ + u32 data[2]; + int err; + int i; + + memset(vlanmc, '\0', sizeof(struct rtl8366_vlan_mc)); + + if (index >= RTL8366S_NUM_VLANS) + return -EINVAL; + + for (i = 0; i < 2; i++) { + err = rtl8366_smi_read_reg(smi, + RTL8366S_VLAN_MC_BASE(index) + i, + &data[i]); + if (err) + return err; + } + + vlanmc->vid = data[0] & RTL8366S_VLAN_VID_MASK; + vlanmc->priority = (data[0] >> RTL8366S_VLAN_PRIORITY_SHIFT) & + RTL8366S_VLAN_PRIORITY_MASK; + vlanmc->untag = (data[1] >> RTL8366S_VLAN_UNTAG_SHIFT) & + RTL8366S_VLAN_UNTAG_MASK; + vlanmc->member = data[1] & RTL8366S_VLAN_MEMBER_MASK; + vlanmc->fid = (data[1] >> RTL8366S_VLAN_FID_SHIFT) & + RTL8366S_VLAN_FID_MASK; + + return 0; +} + +static int rtl8366s_set_vlan_mc(struct rtl8366_smi *smi, u32 index, + const struct rtl8366_vlan_mc *vlanmc) +{ + u32 data[2]; + int err; + int i; + + if (index >= RTL8366S_NUM_VLANS || + vlanmc->vid >= RTL8366S_NUM_VIDS || + vlanmc->priority > RTL8366S_PRIORITYMAX || + vlanmc->member > RTL8366S_VLAN_MEMBER_MASK || + vlanmc->untag > RTL8366S_VLAN_UNTAG_MASK || + vlanmc->fid > RTL8366S_FIDMAX) + return -EINVAL; + + data[0] = (vlanmc->vid & RTL8366S_VLAN_VID_MASK) | + ((vlanmc->priority & RTL8366S_VLAN_PRIORITY_MASK) << + RTL8366S_VLAN_PRIORITY_SHIFT); + data[1] = (vlanmc->member & RTL8366S_VLAN_MEMBER_MASK) | + ((vlanmc->untag & RTL8366S_VLAN_UNTAG_MASK) << + RTL8366S_VLAN_UNTAG_SHIFT) | + ((vlanmc->fid & RTL8366S_VLAN_FID_MASK) << + RTL8366S_VLAN_FID_SHIFT); + + for (i = 0; i < 2; i++) { + err = rtl8366_smi_write_reg(smi, + RTL8366S_VLAN_MC_BASE(index) + i, + data[i]); + if (err) + return err; + } + + return 0; +} + +static int rtl8366s_get_mc_index(struct rtl8366_smi *smi, int port, int *val) +{ + u32 data; + int err; + + if (port >= RTL8366S_NUM_PORTS) + return -EINVAL; + + err = rtl8366_smi_read_reg(smi, RTL8366S_PORT_VLAN_CTRL_REG(port), + &data); + if (err) + return err; + + *val = (data >> RTL8366S_PORT_VLAN_CTRL_SHIFT(port)) & + RTL8366S_PORT_VLAN_CTRL_MASK; + + return 0; +} + +static int rtl8366s_set_mc_index(struct rtl8366_smi *smi, int port, int index) +{ + if (port >= RTL8366S_NUM_PORTS || index >= RTL8366S_NUM_VLANS) + return -EINVAL; + + return rtl8366_smi_rmwr(smi, RTL8366S_PORT_VLAN_CTRL_REG(port), + RTL8366S_PORT_VLAN_CTRL_MASK << + RTL8366S_PORT_VLAN_CTRL_SHIFT(port), + (index & RTL8366S_PORT_VLAN_CTRL_MASK) << + RTL8366S_PORT_VLAN_CTRL_SHIFT(port)); +} + +static int rtl8366s_enable_vlan(struct rtl8366_smi *smi, int enable) +{ + return rtl8366_smi_rmwr(smi, RTL8366S_SGCR, RTL8366S_SGCR_EN_VLAN, + (enable) ? RTL8366S_SGCR_EN_VLAN : 0); +} + +static int rtl8366s_enable_vlan4k(struct rtl8366_smi *smi, int enable) +{ + return rtl8366_smi_rmwr(smi, RTL8366S_VLAN_TB_CTRL_REG, + 1, (enable) ? 1 : 0); +} + +static int rtl8366s_is_vlan_valid(struct rtl8366_smi *smi, unsigned vlan) +{ + unsigned max = RTL8366S_NUM_VLANS; + + if (smi->vlan4k_enabled) + max = RTL8366S_NUM_VIDS - 1; + + if (vlan == 0 || vlan >= max) + return 0; + + return 1; +} + +static int rtl8366s_enable_port(struct rtl8366_smi *smi, int port, int enable) +{ + return rtl8366_smi_rmwr(smi, RTL8366S_PECR, (1 << port), + (enable) ? 0 : (1 << port)); +} + +static int rtl8366s_sw_reset_mibs(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + + return rtl8366_smi_rmwr(smi, RTL8366S_MIB_CTRL_REG, 0, (1 << 2)); +} + +static int rtl8366s_sw_get_blinkrate(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + rtl8366_smi_read_reg(smi, RTL8366S_LED_BLINKRATE_REG, &data); + + val->value.i = (data & (RTL8366S_LED_BLINKRATE_MASK)); + + return 0; +} + +static int rtl8366s_sw_set_blinkrate(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + + if (val->value.i >= 6) + return -EINVAL; + + return rtl8366_smi_rmwr(smi, RTL8366S_LED_BLINKRATE_REG, + RTL8366S_LED_BLINKRATE_MASK, + val->value.i); +} + +static int rtl8366s_sw_get_max_length(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + rtl8366_smi_read_reg(smi, RTL8366S_SGCR, &data); + + val->value.i = ((data & (RTL8366S_SGCR_MAX_LENGTH_MASK)) >> 4); + + return 0; +} + +static int rtl8366s_sw_set_max_length(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + char length_code; + + switch (val->value.i) { + case 0: + length_code = RTL8366S_SGCR_MAX_LENGTH_1522; + break; + case 1: + length_code = RTL8366S_SGCR_MAX_LENGTH_1536; + break; + case 2: + length_code = RTL8366S_SGCR_MAX_LENGTH_1552; + break; + case 3: + length_code = RTL8366S_SGCR_MAX_LENGTH_16000; + break; + default: + return -EINVAL; + } + + return rtl8366_smi_rmwr(smi, RTL8366S_SGCR, + RTL8366S_SGCR_MAX_LENGTH_MASK, + length_code); +} + +static int rtl8366s_sw_get_learning_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + rtl8366_smi_read_reg(smi,RTL8366S_SSCR0, &data); + val->value.i = !data; + + return 0; +} + + +static int rtl8366s_sw_set_learning_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 portmask = 0; + int err = 0; + + if (!val->value.i) + portmask = RTL8366S_PORT_ALL; + + /* set learning for all ports */ + REG_WR(smi, RTL8366S_SSCR0, portmask); + + /* set auto ageing for all ports */ + REG_WR(smi, RTL8366S_SSCR1, portmask); + + return 0; +} + +static int rtl8366s_sw_get_port_link(struct switch_dev *dev, + int port, + struct switch_port_link *link) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data = 0; + u32 speed; + + if (port >= RTL8366S_NUM_PORTS) + return -EINVAL; + + rtl8366_smi_read_reg(smi, RTL8366S_PORT_LINK_STATUS_BASE + (port / 2), + &data); + + if (port % 2) + data = data >> 8; + + link->link = !!(data & RTL8366S_PORT_STATUS_LINK_MASK); + if (!link->link) + return 0; + + link->duplex = !!(data & RTL8366S_PORT_STATUS_DUPLEX_MASK); + link->rx_flow = !!(data & RTL8366S_PORT_STATUS_RXPAUSE_MASK); + link->tx_flow = !!(data & RTL8366S_PORT_STATUS_TXPAUSE_MASK); + link->aneg = !!(data & RTL8366S_PORT_STATUS_AN_MASK); + + speed = (data & RTL8366S_PORT_STATUS_SPEED_MASK); + switch (speed) { + case 0: + link->speed = SWITCH_PORT_SPEED_10; + break; + case 1: + link->speed = SWITCH_PORT_SPEED_100; + break; + case 2: + link->speed = SWITCH_PORT_SPEED_1000; + break; + default: + link->speed = SWITCH_PORT_SPEED_UNKNOWN; + break; + } + + return 0; +} + +static int rtl8366s_sw_set_port_led(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + u32 mask; + u32 reg; + + if (val->port_vlan >= RTL8366S_NUM_PORTS || + (1 << val->port_vlan) == RTL8366S_PORT_UNKNOWN) + return -EINVAL; + + if (val->port_vlan == RTL8366S_PORT_NUM_CPU) { + reg = RTL8366S_LED_BLINKRATE_REG; + mask = 0xF << 4; + data = val->value.i << 4; + } else { + reg = RTL8366S_LED_CTRL_REG; + mask = 0xF << (val->port_vlan * 4), + data = val->value.i << (val->port_vlan * 4); + } + + return rtl8366_smi_rmwr(smi, reg, mask, data); +} + +static int rtl8366s_sw_get_port_led(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data = 0; + + if (val->port_vlan >= RTL8366S_NUM_LEDGROUPS) + return -EINVAL; + + rtl8366_smi_read_reg(smi, RTL8366S_LED_CTRL_REG, &data); + val->value.i = (data >> (val->port_vlan * 4)) & 0x000F; + + return 0; +} + +static int rtl8366s_sw_reset_port_mibs(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + + if (val->port_vlan >= RTL8366S_NUM_PORTS) + return -EINVAL; + + + return rtl8366_smi_rmwr(smi, RTL8366S_MIB_CTRL_REG, + 0, (1 << (val->port_vlan + 3))); +} + +static struct switch_attr rtl8366s_globals[] = { + { + .type = SWITCH_TYPE_INT, + .name = "enable_learning", + .description = "Enable learning, enable aging", + .set = rtl8366s_sw_set_learning_enable, + .get = rtl8366s_sw_get_learning_enable, + .max = 1, + }, { + .type = SWITCH_TYPE_INT, + .name = "enable_vlan", + .description = "Enable VLAN mode", + .set = rtl8366_sw_set_vlan_enable, + .get = rtl8366_sw_get_vlan_enable, + .max = 1, + .ofs = 1 + }, { + .type = SWITCH_TYPE_INT, + .name = "enable_vlan4k", + .description = "Enable VLAN 4K mode", + .set = rtl8366_sw_set_vlan_enable, + .get = rtl8366_sw_get_vlan_enable, + .max = 1, + .ofs = 2 + }, { + .type = SWITCH_TYPE_NOVAL, + .name = "reset_mibs", + .description = "Reset all MIB counters", + .set = rtl8366s_sw_reset_mibs, + }, { + .type = SWITCH_TYPE_INT, + .name = "blinkrate", + .description = "Get/Set LED blinking rate (0 = 43ms, 1 = 84ms," + " 2 = 120ms, 3 = 170ms, 4 = 340ms, 5 = 670ms)", + .set = rtl8366s_sw_set_blinkrate, + .get = rtl8366s_sw_get_blinkrate, + .max = 5 + }, { + .type = SWITCH_TYPE_INT, + .name = "max_length", + .description = "Get/Set the maximum length of valid packets" + " (0 = 1522, 1 = 1536, 2 = 1552, 3 = 16000 (9216?))", + .set = rtl8366s_sw_set_max_length, + .get = rtl8366s_sw_get_max_length, + .max = 3, + }, +}; + +static struct switch_attr rtl8366s_port[] = { + { + .type = SWITCH_TYPE_NOVAL, + .name = "reset_mib", + .description = "Reset single port MIB counters", + .set = rtl8366s_sw_reset_port_mibs, + }, { + .type = SWITCH_TYPE_STRING, + .name = "mib", + .description = "Get MIB counters for port", + .max = 33, + .set = NULL, + .get = rtl8366_sw_get_port_mib, + }, { + .type = SWITCH_TYPE_INT, + .name = "led", + .description = "Get/Set port group (0 - 3) led mode (0 - 15)", + .max = 15, + .set = rtl8366s_sw_set_port_led, + .get = rtl8366s_sw_get_port_led, + }, +}; + +static struct switch_attr rtl8366s_vlan[] = { + { + .type = SWITCH_TYPE_STRING, + .name = "info", + .description = "Get vlan information", + .max = 1, + .set = NULL, + .get = rtl8366_sw_get_vlan_info, + }, { + .type = SWITCH_TYPE_INT, + .name = "fid", + .description = "Get/Set vlan FID", + .max = RTL8366S_FIDMAX, + .set = rtl8366_sw_set_vlan_fid, + .get = rtl8366_sw_get_vlan_fid, + }, +}; + +static const struct switch_dev_ops rtl8366_ops = { + .attr_global = { + .attr = rtl8366s_globals, + .n_attr = ARRAY_SIZE(rtl8366s_globals), + }, + .attr_port = { + .attr = rtl8366s_port, + .n_attr = ARRAY_SIZE(rtl8366s_port), + }, + .attr_vlan = { + .attr = rtl8366s_vlan, + .n_attr = ARRAY_SIZE(rtl8366s_vlan), + }, + + .get_vlan_ports = rtl8366_sw_get_vlan_ports, + .set_vlan_ports = rtl8366_sw_set_vlan_ports, + .get_port_pvid = rtl8366_sw_get_port_pvid, + .set_port_pvid = rtl8366_sw_set_port_pvid, + .reset_switch = rtl8366_sw_reset_switch, + .get_port_link = rtl8366s_sw_get_port_link, +}; + +static int rtl8366s_switch_init(struct rtl8366_smi *smi) +{ + struct switch_dev *dev = &smi->sw_dev; + int err; + + dev->name = "RTL8366S"; + dev->cpu_port = RTL8366S_PORT_NUM_CPU; + dev->ports = RTL8366S_NUM_PORTS; + dev->vlans = RTL8366S_NUM_VIDS; + dev->ops = &rtl8366_ops; + dev->alias = dev_name(smi->parent); + + err = register_switch(dev, NULL); + if (err) + dev_err(smi->parent, "switch registration failed\n"); + + return err; +} + +static void rtl8366s_switch_cleanup(struct rtl8366_smi *smi) +{ + unregister_switch(&smi->sw_dev); +} + +static int rtl8366s_mii_read(struct mii_bus *bus, int addr, int reg) +{ + struct rtl8366_smi *smi = bus->priv; + u32 val = 0; + int err; + + err = rtl8366s_read_phy_reg(smi, addr, 0, reg, &val); + if (err) + return 0xffff; + + return val; +} + +static int rtl8366s_mii_write(struct mii_bus *bus, int addr, int reg, u16 val) +{ + struct rtl8366_smi *smi = bus->priv; + u32 t; + int err; + + err = rtl8366s_write_phy_reg(smi, addr, 0, reg, val); + /* flush write */ + (void) rtl8366s_read_phy_reg(smi, addr, 0, reg, &t); + + return err; +} + +static int rtl8366s_detect(struct rtl8366_smi *smi) +{ + u32 chip_id = 0; + u32 chip_ver = 0; + int ret; + + ret = rtl8366_smi_read_reg(smi, RTL8366S_CHIP_ID_REG, &chip_id); + if (ret) { + dev_err(smi->parent, "unable to read chip id\n"); + return ret; + } + + switch (chip_id) { + case RTL8366S_CHIP_ID_8366: + break; + default: + dev_err(smi->parent, "unknown chip id (%04x)\n", chip_id); + return -ENODEV; + } + + ret = rtl8366_smi_read_reg(smi, RTL8366S_CHIP_VERSION_CTRL_REG, + &chip_ver); + if (ret) { + dev_err(smi->parent, "unable to read chip version\n"); + return ret; + } + + dev_info(smi->parent, "RTL%04x ver. %u chip found\n", + chip_id, chip_ver & RTL8366S_CHIP_VERSION_MASK); + + return 0; +} + +static struct rtl8366_smi_ops rtl8366s_smi_ops = { + .detect = rtl8366s_detect, + .reset_chip = rtl8366s_reset_chip, + .setup = rtl8366s_setup, + + .mii_read = rtl8366s_mii_read, + .mii_write = rtl8366s_mii_write, + + .get_vlan_mc = rtl8366s_get_vlan_mc, + .set_vlan_mc = rtl8366s_set_vlan_mc, + .get_vlan_4k = rtl8366s_get_vlan_4k, + .set_vlan_4k = rtl8366s_set_vlan_4k, + .get_mc_index = rtl8366s_get_mc_index, + .set_mc_index = rtl8366s_set_mc_index, + .get_mib_counter = rtl8366_get_mib_counter, + .is_vlan_valid = rtl8366s_is_vlan_valid, + .enable_vlan = rtl8366s_enable_vlan, + .enable_vlan4k = rtl8366s_enable_vlan4k, + .enable_port = rtl8366s_enable_port, +}; + +static int rtl8366s_probe(struct platform_device *pdev) +{ + static int rtl8366_smi_version_printed; + struct rtl8366_smi *smi; + int err; + + if (!rtl8366_smi_version_printed++) + printk(KERN_NOTICE RTL8366S_DRIVER_DESC + " version " RTL8366S_DRIVER_VER"\n"); + + smi = rtl8366_smi_probe(pdev); + if (!smi) + return -ENODEV; + + smi->clk_delay = 10; + smi->cmd_read = 0xa9; + smi->cmd_write = 0xa8; + smi->ops = &rtl8366s_smi_ops; + smi->cpu_port = RTL8366S_PORT_NUM_CPU; + smi->num_ports = RTL8366S_NUM_PORTS; + smi->num_vlan_mc = RTL8366S_NUM_VLANS; + smi->mib_counters = rtl8366s_mib_counters; + smi->num_mib_counters = ARRAY_SIZE(rtl8366s_mib_counters); + + err = rtl8366_smi_init(smi); + if (err) + goto err_free_smi; + + platform_set_drvdata(pdev, smi); + + err = rtl8366s_switch_init(smi); + if (err) + goto err_clear_drvdata; + + return 0; + + err_clear_drvdata: + platform_set_drvdata(pdev, NULL); + rtl8366_smi_cleanup(smi); + err_free_smi: + kfree(smi); + return err; +} + +static int rtl8366s_remove(struct platform_device *pdev) +{ + struct rtl8366_smi *smi = platform_get_drvdata(pdev); + + if (smi) { + rtl8366s_switch_cleanup(smi); + platform_set_drvdata(pdev, NULL); + rtl8366_smi_cleanup(smi); + kfree(smi); + } + + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id rtl8366s_match[] = { + { .compatible = "realtek,rtl8366s" }, + {}, +}; +MODULE_DEVICE_TABLE(of, rtl8366s_match); +#endif + +static struct platform_driver rtl8366s_driver = { + .driver = { + .name = RTL8366S_DRIVER_NAME, + .owner = THIS_MODULE, +#ifdef CONFIG_OF + .of_match_table = of_match_ptr(rtl8366s_match), +#endif + }, + .probe = rtl8366s_probe, + .remove = rtl8366s_remove, +}; + +static int __init rtl8366s_module_init(void) +{ + return platform_driver_register(&rtl8366s_driver); +} +module_init(rtl8366s_module_init); + +static void __exit rtl8366s_module_exit(void) +{ + platform_driver_unregister(&rtl8366s_driver); +} +module_exit(rtl8366s_module_exit); + +MODULE_DESCRIPTION(RTL8366S_DRIVER_DESC); +MODULE_VERSION(RTL8366S_DRIVER_VER); +MODULE_AUTHOR("Gabor Juhos "); +MODULE_AUTHOR("Antti Seppälä "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" RTL8366S_DRIVER_NAME); diff --git a/target/linux/generic/files/drivers/net/phy/rtl8367.c b/target/linux/generic/files/drivers/net/phy/rtl8367.c new file mode 100644 index 0000000..4978a8c --- /dev/null +++ b/target/linux/generic/files/drivers/net/phy/rtl8367.c @@ -0,0 +1,1835 @@ +/* + * Platform driver for the Realtek RTL8367R/M ethernet switches + * + * Copyright (C) 2011 Gabor Juhos + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rtl8366_smi.h" + +#define RTL8367_RESET_DELAY 1000 /* msecs*/ + +#define RTL8367_PHY_ADDR_MAX 8 +#define RTL8367_PHY_REG_MAX 31 + +#define RTL8367_VID_MASK 0xffff +#define RTL8367_FID_MASK 0xfff +#define RTL8367_UNTAG_MASK 0xffff +#define RTL8367_MEMBER_MASK 0xffff + +#define RTL8367_PORT_CFG_REG(_p) (0x000e + 0x20 * (_p)) +#define RTL8367_PORT_CFG_EGRESS_MODE_SHIFT 4 +#define RTL8367_PORT_CFG_EGRESS_MODE_MASK 0x3 +#define RTL8367_PORT_CFG_EGRESS_MODE_ORIGINAL 0 +#define RTL8367_PORT_CFG_EGRESS_MODE_KEEP 1 +#define RTL8367_PORT_CFG_EGRESS_MODE_PRI 2 +#define RTL8367_PORT_CFG_EGRESS_MODE_REAL 3 + +#define RTL8367_BYPASS_LINE_RATE_REG 0x03f7 + +#define RTL8367_TA_CTRL_REG 0x0500 +#define RTL8367_TA_CTRL_STATUS BIT(12) +#define RTL8367_TA_CTRL_METHOD BIT(5) +#define RTL8367_TA_CTRL_CMD_SHIFT 4 +#define RTL8367_TA_CTRL_CMD_READ 0 +#define RTL8367_TA_CTRL_CMD_WRITE 1 +#define RTL8367_TA_CTRL_TABLE_SHIFT 0 +#define RTL8367_TA_CTRL_TABLE_ACLRULE 1 +#define RTL8367_TA_CTRL_TABLE_ACLACT 2 +#define RTL8367_TA_CTRL_TABLE_CVLAN 3 +#define RTL8367_TA_CTRL_TABLE_L2 4 +#define RTL8367_TA_CTRL_CVLAN_READ \ + ((RTL8367_TA_CTRL_CMD_READ << RTL8367_TA_CTRL_CMD_SHIFT) | \ + RTL8367_TA_CTRL_TABLE_CVLAN) +#define RTL8367_TA_CTRL_CVLAN_WRITE \ + ((RTL8367_TA_CTRL_CMD_WRITE << RTL8367_TA_CTRL_CMD_SHIFT) | \ + RTL8367_TA_CTRL_TABLE_CVLAN) + +#define RTL8367_TA_ADDR_REG 0x0501 +#define RTL8367_TA_ADDR_MASK 0x3fff + +#define RTL8367_TA_DATA_REG(_x) (0x0503 + (_x)) +#define RTL8367_TA_VLAN_DATA_SIZE 4 +#define RTL8367_TA_VLAN_VID_MASK RTL8367_VID_MASK +#define RTL8367_TA_VLAN_MEMBER_SHIFT 0 +#define RTL8367_TA_VLAN_MEMBER_MASK RTL8367_MEMBER_MASK +#define RTL8367_TA_VLAN_FID_SHIFT 0 +#define RTL8367_TA_VLAN_FID_MASK RTL8367_FID_MASK +#define RTL8367_TA_VLAN_UNTAG1_SHIFT 14 +#define RTL8367_TA_VLAN_UNTAG1_MASK 0x3 +#define RTL8367_TA_VLAN_UNTAG2_SHIFT 0 +#define RTL8367_TA_VLAN_UNTAG2_MASK 0x3fff + +#define RTL8367_VLAN_PVID_CTRL_REG(_p) (0x0700 + (_p) / 2) +#define RTL8367_VLAN_PVID_CTRL_MASK 0x1f +#define RTL8367_VLAN_PVID_CTRL_SHIFT(_p) (8 * ((_p) % 2)) + +#define RTL8367_VLAN_MC_BASE(_x) (0x0728 + (_x) * 4) +#define RTL8367_VLAN_MC_DATA_SIZE 4 +#define RTL8367_VLAN_MC_MEMBER_SHIFT 0 +#define RTL8367_VLAN_MC_MEMBER_MASK RTL8367_MEMBER_MASK +#define RTL8367_VLAN_MC_FID_SHIFT 0 +#define RTL8367_VLAN_MC_FID_MASK RTL8367_FID_MASK +#define RTL8367_VLAN_MC_EVID_SHIFT 0 +#define RTL8367_VLAN_MC_EVID_MASK RTL8367_VID_MASK + +#define RTL8367_VLAN_CTRL_REG 0x07a8 +#define RTL8367_VLAN_CTRL_ENABLE BIT(0) + +#define RTL8367_VLAN_INGRESS_REG 0x07a9 + +#define RTL8367_PORT_ISOLATION_REG(_p) (0x08a2 + (_p)) + +#define RTL8367_MIB_COUNTER_REG(_x) (0x1000 + (_x)) + +#define RTL8367_MIB_ADDRESS_REG 0x1004 + +#define RTL8367_MIB_CTRL_REG(_x) (0x1005 + (_x)) +#define RTL8367_MIB_CTRL_GLOBAL_RESET_MASK BIT(11) +#define RTL8367_MIB_CTRL_QM_RESET_MASK BIT(10) +#define RTL8367_MIB_CTRL_PORT_RESET_MASK(_p) BIT(2 + (_p)) +#define RTL8367_MIB_CTRL_RESET_MASK BIT(1) +#define RTL8367_MIB_CTRL_BUSY_MASK BIT(0) + +#define RTL8367_MIB_COUNT 36 +#define RTL8367_MIB_COUNTER_PORT_OFFSET 0x0050 + +#define RTL8367_SWC0_REG 0x1200 +#define RTL8367_SWC0_MAX_LENGTH_SHIFT 13 +#define RTL8367_SWC0_MAX_LENGTH(_x) ((_x) << 13) +#define RTL8367_SWC0_MAX_LENGTH_MASK RTL8367_SWC0_MAX_LENGTH(0x3) +#define RTL8367_SWC0_MAX_LENGTH_1522 RTL8367_SWC0_MAX_LENGTH(0) +#define RTL8367_SWC0_MAX_LENGTH_1536 RTL8367_SWC0_MAX_LENGTH(1) +#define RTL8367_SWC0_MAX_LENGTH_1552 RTL8367_SWC0_MAX_LENGTH(2) +#define RTL8367_SWC0_MAX_LENGTH_16000 RTL8367_SWC0_MAX_LENGTH(3) + +#define RTL8367_CHIP_NUMBER_REG 0x1300 + +#define RTL8367_CHIP_VER_REG 0x1301 +#define RTL8367_CHIP_VER_RLVID_SHIFT 12 +#define RTL8367_CHIP_VER_RLVID_MASK 0xf +#define RTL8367_CHIP_VER_MCID_SHIFT 8 +#define RTL8367_CHIP_VER_MCID_MASK 0xf +#define RTL8367_CHIP_VER_BOID_SHIFT 4 +#define RTL8367_CHIP_VER_BOID_MASK 0xf + +#define RTL8367_CHIP_MODE_REG 0x1302 +#define RTL8367_CHIP_MODE_MASK 0x7 + +#define RTL8367_CHIP_DEBUG0_REG 0x1303 +#define RTL8367_CHIP_DEBUG0_DUMMY0(_x) BIT(8 + (_x)) + +#define RTL8367_CHIP_DEBUG1_REG 0x1304 + +#define RTL8367_DIS_REG 0x1305 +#define RTL8367_DIS_SKIP_MII_RXER(_x) BIT(12 + (_x)) +#define RTL8367_DIS_RGMII_SHIFT(_x) (4 * (_x)) +#define RTL8367_DIS_RGMII_MASK 0x7 + +#define RTL8367_EXT_RGMXF_REG(_x) (0x1306 + (_x)) +#define RTL8367_EXT_RGMXF_DUMMY0_SHIFT 5 +#define RTL8367_EXT_RGMXF_DUMMY0_MASK 0x7ff +#define RTL8367_EXT_RGMXF_TXDELAY_SHIFT 3 +#define RTL8367_EXT_RGMXF_TXDELAY_MASK 1 +#define RTL8367_EXT_RGMXF_RXDELAY_MASK 0x7 + +#define RTL8367_DI_FORCE_REG(_x) (0x1310 + (_x)) +#define RTL8367_DI_FORCE_MODE BIT(12) +#define RTL8367_DI_FORCE_NWAY BIT(7) +#define RTL8367_DI_FORCE_TXPAUSE BIT(6) +#define RTL8367_DI_FORCE_RXPAUSE BIT(5) +#define RTL8367_DI_FORCE_LINK BIT(4) +#define RTL8367_DI_FORCE_DUPLEX BIT(2) +#define RTL8367_DI_FORCE_SPEED_MASK 3 +#define RTL8367_DI_FORCE_SPEED_10 0 +#define RTL8367_DI_FORCE_SPEED_100 1 +#define RTL8367_DI_FORCE_SPEED_1000 2 + +#define RTL8367_MAC_FORCE_REG(_x) (0x1312 + (_x)) + +#define RTL8367_CHIP_RESET_REG 0x1322 +#define RTL8367_CHIP_RESET_SW BIT(1) +#define RTL8367_CHIP_RESET_HW BIT(0) + +#define RTL8367_PORT_STATUS_REG(_p) (0x1352 + (_p)) +#define RTL8367_PORT_STATUS_NWAY BIT(7) +#define RTL8367_PORT_STATUS_TXPAUSE BIT(6) +#define RTL8367_PORT_STATUS_RXPAUSE BIT(5) +#define RTL8367_PORT_STATUS_LINK BIT(4) +#define RTL8367_PORT_STATUS_DUPLEX BIT(2) +#define RTL8367_PORT_STATUS_SPEED_MASK 0x0003 +#define RTL8367_PORT_STATUS_SPEED_10 0 +#define RTL8367_PORT_STATUS_SPEED_100 1 +#define RTL8367_PORT_STATUS_SPEED_1000 2 + +#define RTL8367_RTL_NO_REG 0x13c0 +#define RTL8367_RTL_NO_8367R 0x3670 +#define RTL8367_RTL_NO_8367M 0x3671 + +#define RTL8367_RTL_VER_REG 0x13c1 +#define RTL8367_RTL_VER_MASK 0xf + +#define RTL8367_RTL_MAGIC_ID_REG 0x13c2 +#define RTL8367_RTL_MAGIC_ID_VAL 0x0249 + +#define RTL8367_LED_SYS_CONFIG_REG 0x1b00 +#define RTL8367_LED_MODE_REG 0x1b02 +#define RTL8367_LED_MODE_RATE_M 0x7 +#define RTL8367_LED_MODE_RATE_S 1 + +#define RTL8367_LED_CONFIG_REG 0x1b03 +#define RTL8367_LED_CONFIG_DATA_S 12 +#define RTL8367_LED_CONFIG_DATA_M 0x3 +#define RTL8367_LED_CONFIG_SEL BIT(14) +#define RTL8367_LED_CONFIG_LED_CFG_M 0xf + +#define RTL8367_PARA_LED_IO_EN1_REG 0x1b24 +#define RTL8367_PARA_LED_IO_EN2_REG 0x1b25 +#define RTL8367_PARA_LED_IO_EN_PMASK 0xff + +#define RTL8367_IA_CTRL_REG 0x1f00 +#define RTL8367_IA_CTRL_RW(_x) ((_x) << 1) +#define RTL8367_IA_CTRL_RW_READ RTL8367_IA_CTRL_RW(0) +#define RTL8367_IA_CTRL_RW_WRITE RTL8367_IA_CTRL_RW(1) +#define RTL8367_IA_CTRL_CMD_MASK BIT(0) + +#define RTL8367_IA_STATUS_REG 0x1f01 +#define RTL8367_IA_STATUS_PHY_BUSY BIT(2) +#define RTL8367_IA_STATUS_SDS_BUSY BIT(1) +#define RTL8367_IA_STATUS_MDX_BUSY BIT(0) + +#define RTL8367_IA_ADDRESS_REG 0x1f02 + +#define RTL8367_IA_WRITE_DATA_REG 0x1f03 +#define RTL8367_IA_READ_DATA_REG 0x1f04 + +#define RTL8367_INTERNAL_PHY_REG(_a, _r) (0x2000 + 32 * (_a) + (_r)) + +#define RTL8367_CPU_PORT_NUM 9 +#define RTL8367_NUM_PORTS 10 +#define RTL8367_NUM_VLANS 32 +#define RTL8367_NUM_LEDGROUPS 4 +#define RTL8367_NUM_VIDS 4096 +#define RTL8367_PRIORITYMAX 7 +#define RTL8367_FIDMAX 7 + +#define RTL8367_PORT_0 BIT(0) +#define RTL8367_PORT_1 BIT(1) +#define RTL8367_PORT_2 BIT(2) +#define RTL8367_PORT_3 BIT(3) +#define RTL8367_PORT_4 BIT(4) +#define RTL8367_PORT_5 BIT(5) +#define RTL8367_PORT_6 BIT(6) +#define RTL8367_PORT_7 BIT(7) +#define RTL8367_PORT_E1 BIT(8) /* external port 1 */ +#define RTL8367_PORT_E0 BIT(9) /* external port 0 */ + +#define RTL8367_PORTS_ALL \ + (RTL8367_PORT_0 | RTL8367_PORT_1 | RTL8367_PORT_2 | \ + RTL8367_PORT_3 | RTL8367_PORT_4 | RTL8367_PORT_5 | \ + RTL8367_PORT_6 | RTL8367_PORT_7 | RTL8367_PORT_E1 | \ + RTL8367_PORT_E0) + +#define RTL8367_PORTS_ALL_BUT_CPU \ + (RTL8367_PORT_0 | RTL8367_PORT_1 | RTL8367_PORT_2 | \ + RTL8367_PORT_3 | RTL8367_PORT_4 | RTL8367_PORT_5 | \ + RTL8367_PORT_6 | RTL8367_PORT_7 | RTL8367_PORT_E1) + +struct rtl8367_initval { + u16 reg; + u16 val; +}; + +static struct rtl8366_mib_counter rtl8367_mib_counters[] = { + { 0, 0, 4, "IfInOctets" }, + { 0, 4, 2, "Dot3StatsFCSErrors" }, + { 0, 6, 2, "Dot3StatsSymbolErrors" }, + { 0, 8, 2, "Dot3InPauseFrames" }, + { 0, 10, 2, "Dot3ControlInUnknownOpcodes" }, + { 0, 12, 2, "EtherStatsFragments" }, + { 0, 14, 2, "EtherStatsJabbers" }, + { 0, 16, 2, "IfInUcastPkts" }, + { 0, 18, 2, "EtherStatsDropEvents" }, + { 0, 20, 4, "EtherStatsOctets" }, + + { 0, 24, 2, "EtherStatsUnderSizePkts" }, + { 0, 26, 2, "EtherOversizeStats" }, + { 0, 28, 2, "EtherStatsPkts64Octets" }, + { 0, 30, 2, "EtherStatsPkts65to127Octets" }, + { 0, 32, 2, "EtherStatsPkts128to255Octets" }, + { 0, 34, 2, "EtherStatsPkts256to511Octets" }, + { 0, 36, 2, "EtherStatsPkts512to1023Octets" }, + { 0, 38, 2, "EtherStatsPkts1024to1518Octets" }, + { 0, 40, 2, "EtherStatsMulticastPkts" }, + { 0, 42, 2, "EtherStatsBroadcastPkts" }, + + { 0, 44, 4, "IfOutOctets" }, + + { 0, 48, 2, "Dot3StatsSingleCollisionFrames" }, + { 0, 50, 2, "Dot3StatMultipleCollisionFrames" }, + { 0, 52, 2, "Dot3sDeferredTransmissions" }, + { 0, 54, 2, "Dot3StatsLateCollisions" }, + { 0, 56, 2, "EtherStatsCollisions" }, + { 0, 58, 2, "Dot3StatsExcessiveCollisions" }, + { 0, 60, 2, "Dot3OutPauseFrames" }, + { 0, 62, 2, "Dot1dBasePortDelayExceededDiscards" }, + { 0, 64, 2, "Dot1dTpPortInDiscards" }, + { 0, 66, 2, "IfOutUcastPkts" }, + { 0, 68, 2, "IfOutMulticastPkts" }, + { 0, 70, 2, "IfOutBroadcastPkts" }, + { 0, 72, 2, "OutOampduPkts" }, + { 0, 74, 2, "InOampduPkts" }, + { 0, 76, 2, "PktgenPkts" }, +}; + +#define REG_RD(_smi, _reg, _val) \ + do { \ + err = rtl8366_smi_read_reg(_smi, _reg, _val); \ + if (err) \ + return err; \ + } while (0) + +#define REG_WR(_smi, _reg, _val) \ + do { \ + err = rtl8366_smi_write_reg(_smi, _reg, _val); \ + if (err) \ + return err; \ + } while (0) + +#define REG_RMW(_smi, _reg, _mask, _val) \ + do { \ + err = rtl8366_smi_rmwr(_smi, _reg, _mask, _val); \ + if (err) \ + return err; \ + } while (0) + +static const struct rtl8367_initval rtl8367_initvals_0_0[] = { + {0x133f, 0x0030}, {0x133e, 0x000e}, {0x221f, 0x0000}, {0x2215, 0x1006}, + {0x221f, 0x0005}, {0x2200, 0x00c6}, {0x221f, 0x0007}, {0x221e, 0x0048}, + {0x2215, 0x6412}, {0x2216, 0x6412}, {0x2217, 0x6412}, {0x2218, 0x6412}, + {0x2219, 0x6412}, {0x221A, 0x6412}, {0x221f, 0x0001}, {0x220c, 0xdbf0}, + {0x2209, 0x2576}, {0x2207, 0x287E}, {0x220A, 0x68E5}, {0x221D, 0x3DA4}, + {0x221C, 0xE7F7}, {0x2214, 0x7F52}, {0x2218, 0x7FCE}, {0x2208, 0x04B7}, + {0x2206, 0x4072}, {0x2210, 0xF05E}, {0x221B, 0xB414}, {0x221F, 0x0003}, + {0x221A, 0x06A6}, {0x2210, 0xF05E}, {0x2213, 0x06EB}, {0x2212, 0xF4D2}, + {0x220E, 0xE120}, {0x2200, 0x7C00}, {0x2202, 0x5FD0}, {0x220D, 0x0207}, + {0x221f, 0x0002}, {0x2205, 0x0978}, {0x2202, 0x8C01}, {0x2207, 0x3620}, + {0x221C, 0x0001}, {0x2203, 0x0420}, {0x2204, 0x80C8}, {0x133e, 0x0ede}, + {0x221f, 0x0002}, {0x220c, 0x0073}, {0x220d, 0xEB65}, {0x220e, 0x51d1}, + {0x220f, 0x5dcb}, {0x2210, 0x3044}, {0x2211, 0x1800}, {0x2212, 0x7E00}, + {0x2213, 0x0000}, {0x133f, 0x0010}, {0x133e, 0x0ffe}, {0x207f, 0x0002}, + {0x2074, 0x3D22}, {0x2075, 0x2000}, {0x2076, 0x6040}, {0x2077, 0x0000}, + {0x2078, 0x0f0a}, {0x2079, 0x50AB}, {0x207a, 0x0000}, {0x207b, 0x0f0f}, + {0x205f, 0x0002}, {0x2054, 0xFF00}, {0x2055, 0x000A}, {0x2056, 0x000A}, + {0x2057, 0x0005}, {0x2058, 0x0005}, {0x2059, 0x0000}, {0x205A, 0x0005}, + {0x205B, 0x0005}, {0x205C, 0x0005}, {0x209f, 0x0002}, {0x2094, 0x00AA}, + {0x2095, 0x00AA}, {0x2096, 0x00AA}, {0x2097, 0x00AA}, {0x2098, 0x0055}, + {0x2099, 0x00AA}, {0x209A, 0x00AA}, {0x209B, 0x00AA}, {0x1363, 0x8354}, + {0x1270, 0x3333}, {0x1271, 0x3333}, {0x1272, 0x3333}, {0x1330, 0x00DB}, + {0x1203, 0xff00}, {0x1200, 0x7fc4}, {0x121d, 0x1006}, {0x121e, 0x03e8}, + {0x121f, 0x02b3}, {0x1220, 0x028f}, {0x1221, 0x029b}, {0x1222, 0x0277}, + {0x1223, 0x02b3}, {0x1224, 0x028f}, {0x1225, 0x029b}, {0x1226, 0x0277}, + {0x1227, 0x00c0}, {0x1228, 0x00b4}, {0x122f, 0x00c0}, {0x1230, 0x00b4}, + {0x1229, 0x0020}, {0x122a, 0x000c}, {0x1231, 0x0030}, {0x1232, 0x0024}, + {0x0219, 0x0032}, {0x0200, 0x03e8}, {0x0201, 0x03e8}, {0x0202, 0x03e8}, + {0x0203, 0x03e8}, {0x0204, 0x03e8}, {0x0205, 0x03e8}, {0x0206, 0x03e8}, + {0x0207, 0x03e8}, {0x0218, 0x0032}, {0x0208, 0x029b}, {0x0209, 0x029b}, + {0x020a, 0x029b}, {0x020b, 0x029b}, {0x020c, 0x029b}, {0x020d, 0x029b}, + {0x020e, 0x029b}, {0x020f, 0x029b}, {0x0210, 0x029b}, {0x0211, 0x029b}, + {0x0212, 0x029b}, {0x0213, 0x029b}, {0x0214, 0x029b}, {0x0215, 0x029b}, + {0x0216, 0x029b}, {0x0217, 0x029b}, {0x0900, 0x0000}, {0x0901, 0x0000}, + {0x0902, 0x0000}, {0x0903, 0x0000}, {0x0865, 0x3210}, {0x087b, 0x0000}, + {0x087c, 0xff00}, {0x087d, 0x0000}, {0x087e, 0x0000}, {0x0801, 0x0100}, + {0x0802, 0x0100}, {0x1700, 0x014C}, {0x0301, 0x00FF}, {0x12AA, 0x0096}, + {0x133f, 0x0030}, {0x133e, 0x000e}, {0x221f, 0x0005}, {0x2200, 0x00C4}, + {0x221f, 0x0000}, {0x2210, 0x05EF}, {0x2204, 0x05E1}, {0x2200, 0x1340}, + {0x133f, 0x0010}, {0x20A0, 0x1940}, {0x20C0, 0x1940}, {0x20E0, 0x1940}, +}; + +static const struct rtl8367_initval rtl8367_initvals_0_1[] = { + {0x133f, 0x0030}, {0x133e, 0x000e}, {0x221f, 0x0000}, {0x2215, 0x1006}, + {0x221f, 0x0005}, {0x2200, 0x00c6}, {0x221f, 0x0007}, {0x221e, 0x0048}, + {0x2215, 0x6412}, {0x2216, 0x6412}, {0x2217, 0x6412}, {0x2218, 0x6412}, + {0x2219, 0x6412}, {0x221A, 0x6412}, {0x221f, 0x0001}, {0x220c, 0xdbf0}, + {0x2209, 0x2576}, {0x2207, 0x287E}, {0x220A, 0x68E5}, {0x221D, 0x3DA4}, + {0x221C, 0xE7F7}, {0x2214, 0x7F52}, {0x2218, 0x7FCE}, {0x2208, 0x04B7}, + {0x2206, 0x4072}, {0x2210, 0xF05E}, {0x221B, 0xB414}, {0x221F, 0x0003}, + {0x221A, 0x06A6}, {0x2210, 0xF05E}, {0x2213, 0x06EB}, {0x2212, 0xF4D2}, + {0x220E, 0xE120}, {0x2200, 0x7C00}, {0x2202, 0x5FD0}, {0x220D, 0x0207}, + {0x221f, 0x0002}, {0x2205, 0x0978}, {0x2202, 0x8C01}, {0x2207, 0x3620}, + {0x221C, 0x0001}, {0x2203, 0x0420}, {0x2204, 0x80C8}, {0x133e, 0x0ede}, + {0x221f, 0x0002}, {0x220c, 0x0073}, {0x220d, 0xEB65}, {0x220e, 0x51d1}, + {0x220f, 0x5dcb}, {0x2210, 0x3044}, {0x2211, 0x1800}, {0x2212, 0x7E00}, + {0x2213, 0x0000}, {0x133f, 0x0010}, {0x133e, 0x0ffe}, {0x207f, 0x0002}, + {0x2074, 0x3D22}, {0x2075, 0x2000}, {0x2076, 0x6040}, {0x2077, 0x0000}, + {0x2078, 0x0f0a}, {0x2079, 0x50AB}, {0x207a, 0x0000}, {0x207b, 0x0f0f}, + {0x205f, 0x0002}, {0x2054, 0xFF00}, {0x2055, 0x000A}, {0x2056, 0x000A}, + {0x2057, 0x0005}, {0x2058, 0x0005}, {0x2059, 0x0000}, {0x205A, 0x0005}, + {0x205B, 0x0005}, {0x205C, 0x0005}, {0x209f, 0x0002}, {0x2094, 0x00AA}, + {0x2095, 0x00AA}, {0x2096, 0x00AA}, {0x2097, 0x00AA}, {0x2098, 0x0055}, + {0x2099, 0x00AA}, {0x209A, 0x00AA}, {0x209B, 0x00AA}, {0x1363, 0x8354}, + {0x1270, 0x3333}, {0x1271, 0x3333}, {0x1272, 0x3333}, {0x1330, 0x00DB}, + {0x1203, 0xff00}, {0x1200, 0x7fc4}, {0x121d, 0x1b06}, {0x121e, 0x07f0}, + {0x121f, 0x0438}, {0x1220, 0x040f}, {0x1221, 0x040f}, {0x1222, 0x03eb}, + {0x1223, 0x0438}, {0x1224, 0x040f}, {0x1225, 0x040f}, {0x1226, 0x03eb}, + {0x1227, 0x0144}, {0x1228, 0x0138}, {0x122f, 0x0144}, {0x1230, 0x0138}, + {0x1229, 0x0020}, {0x122a, 0x000c}, {0x1231, 0x0030}, {0x1232, 0x0024}, + {0x0219, 0x0032}, {0x0200, 0x07d0}, {0x0201, 0x07d0}, {0x0202, 0x07d0}, + {0x0203, 0x07d0}, {0x0204, 0x07d0}, {0x0205, 0x07d0}, {0x0206, 0x07d0}, + {0x0207, 0x07d0}, {0x0218, 0x0032}, {0x0208, 0x0190}, {0x0209, 0x0190}, + {0x020a, 0x0190}, {0x020b, 0x0190}, {0x020c, 0x0190}, {0x020d, 0x0190}, + {0x020e, 0x0190}, {0x020f, 0x0190}, {0x0210, 0x0190}, {0x0211, 0x0190}, + {0x0212, 0x0190}, {0x0213, 0x0190}, {0x0214, 0x0190}, {0x0215, 0x0190}, + {0x0216, 0x0190}, {0x0217, 0x0190}, {0x0900, 0x0000}, {0x0901, 0x0000}, + {0x0902, 0x0000}, {0x0903, 0x0000}, {0x0865, 0x3210}, {0x087b, 0x0000}, + {0x087c, 0xff00}, {0x087d, 0x0000}, {0x087e, 0x0000}, {0x0801, 0x0100}, + {0x0802, 0x0100}, {0x1700, 0x0125}, {0x0301, 0x00FF}, {0x12AA, 0x0096}, + {0x133f, 0x0030}, {0x133e, 0x000e}, {0x221f, 0x0005}, {0x2200, 0x00C4}, + {0x221f, 0x0000}, {0x2210, 0x05EF}, {0x2204, 0x05E1}, {0x2200, 0x1340}, + {0x133f, 0x0010}, +}; + +static const struct rtl8367_initval rtl8367_initvals_1_0[] = { + {0x1B24, 0x0000}, {0x1B25, 0x0000}, {0x1B26, 0x0000}, {0x1B27, 0x0000}, + {0x207F, 0x0002}, {0x2079, 0x0200}, {0x207F, 0x0000}, {0x133F, 0x0030}, + {0x133E, 0x000E}, {0x221F, 0x0005}, {0x2201, 0x0700}, {0x2205, 0x8B82}, + {0x2206, 0x05CB}, {0x221F, 0x0002}, {0x2204, 0x80C2}, {0x2205, 0x0938}, + {0x221F, 0x0003}, {0x2212, 0xC4D2}, {0x220D, 0x0207}, {0x221F, 0x0001}, + {0x2207, 0x267E}, {0x221C, 0xE5F7}, {0x221B, 0x0424}, {0x221F, 0x0007}, + {0x221E, 0x0040}, {0x2218, 0x0000}, {0x221F, 0x0007}, {0x221E, 0x002C}, + {0x2218, 0x008B}, {0x221F, 0x0005}, {0x2205, 0xFFF6}, {0x2206, 0x0080}, + {0x2205, 0x8000}, {0x2206, 0xF8E0}, {0x2206, 0xE000}, {0x2206, 0xE1E0}, + {0x2206, 0x01AC}, {0x2206, 0x2408}, {0x2206, 0xE08B}, {0x2206, 0x84F7}, + {0x2206, 0x20E4}, {0x2206, 0x8B84}, {0x2206, 0xFC05}, {0x2206, 0xF8FA}, + {0x2206, 0xEF69}, {0x2206, 0xE08B}, {0x2206, 0x86AC}, {0x2206, 0x201A}, + {0x2206, 0xBF80}, {0x2206, 0x59D0}, {0x2206, 0x2402}, {0x2206, 0x803D}, + {0x2206, 0xE0E0}, {0x2206, 0xE4E1}, {0x2206, 0xE0E5}, {0x2206, 0x5806}, + {0x2206, 0x68C0}, {0x2206, 0xD1D2}, {0x2206, 0xE4E0}, {0x2206, 0xE4E5}, + {0x2206, 0xE0E5}, {0x2206, 0xEF96}, {0x2206, 0xFEFC}, {0x2206, 0x05FB}, + {0x2206, 0x0BFB}, {0x2206, 0x58FF}, {0x2206, 0x9E11}, {0x2206, 0x06F0}, + {0x2206, 0x0C81}, {0x2206, 0x8AE0}, {0x2206, 0x0019}, {0x2206, 0x1B89}, + {0x2206, 0xCFEB}, {0x2206, 0x19EB}, {0x2206, 0x19B0}, {0x2206, 0xEFFF}, + {0x2206, 0x0BFF}, {0x2206, 0x0425}, {0x2206, 0x0807}, {0x2206, 0x2640}, + {0x2206, 0x7227}, {0x2206, 0x267E}, {0x2206, 0x2804}, {0x2206, 0xB729}, + {0x2206, 0x2576}, {0x2206, 0x2A68}, {0x2206, 0xE52B}, {0x2206, 0xAD00}, + {0x2206, 0x2CDB}, {0x2206, 0xF02D}, {0x2206, 0x67BB}, {0x2206, 0x2E7B}, + {0x2206, 0x0F2F}, {0x2206, 0x7365}, {0x2206, 0x31AC}, {0x2206, 0xCC32}, + {0x2206, 0x2300}, {0x2206, 0x332D}, {0x2206, 0x1734}, {0x2206, 0x7F52}, + {0x2206, 0x3510}, {0x2206, 0x0036}, {0x2206, 0x0600}, {0x2206, 0x370C}, + {0x2206, 0xC038}, {0x2206, 0x7FCE}, {0x2206, 0x3CE5}, {0x2206, 0xF73D}, + {0x2206, 0x3DA4}, {0x2206, 0x6530}, {0x2206, 0x3E67}, {0x2206, 0x0053}, + {0x2206, 0x69D2}, {0x2206, 0x0F6A}, {0x2206, 0x012C}, {0x2206, 0x6C2B}, + {0x2206, 0x136E}, {0x2206, 0xE100}, {0x2206, 0x6F12}, {0x2206, 0xF771}, + {0x2206, 0x006B}, {0x2206, 0x7306}, {0x2206, 0xEB74}, {0x2206, 0x94C7}, + {0x2206, 0x7698}, {0x2206, 0x0A77}, {0x2206, 0x5000}, {0x2206, 0x788A}, + {0x2206, 0x1579}, {0x2206, 0x7F6F}, {0x2206, 0x7A06}, {0x2206, 0xA600}, + {0x2205, 0x8B90}, {0x2206, 0x8000}, {0x2205, 0x8B92}, {0x2206, 0x8000}, + {0x2205, 0x8B94}, {0x2206, 0x8014}, {0x2208, 0xFFFA}, {0x2202, 0x3C65}, + {0x2205, 0xFFF6}, {0x2206, 0x00F7}, {0x221F, 0x0000}, {0x221F, 0x0007}, + {0x221E, 0x0042}, {0x2218, 0x0000}, {0x221E, 0x002D}, {0x2218, 0xF010}, + {0x221E, 0x0020}, {0x2215, 0x0000}, {0x221E, 0x0023}, {0x2216, 0x8000}, + {0x221F, 0x0000}, {0x133F, 0x0010}, {0x133E, 0x0FFE}, {0x1362, 0x0115}, + {0x1363, 0x0002}, {0x1363, 0x0000}, {0x1306, 0x000C}, {0x1307, 0x000C}, + {0x1303, 0x0067}, {0x1304, 0x4444}, {0x1203, 0xFF00}, {0x1200, 0x7FC4}, + {0x121D, 0x7D16}, {0x121E, 0x03E8}, {0x121F, 0x024E}, {0x1220, 0x0230}, + {0x1221, 0x0244}, {0x1222, 0x0226}, {0x1223, 0x024E}, {0x1224, 0x0230}, + {0x1225, 0x0244}, {0x1226, 0x0226}, {0x1227, 0x00C0}, {0x1228, 0x00B4}, + {0x122F, 0x00C0}, {0x1230, 0x00B4}, {0x0208, 0x03E8}, {0x0209, 0x03E8}, + {0x020A, 0x03E8}, {0x020B, 0x03E8}, {0x020C, 0x03E8}, {0x020D, 0x03E8}, + {0x020E, 0x03E8}, {0x020F, 0x03E8}, {0x0210, 0x03E8}, {0x0211, 0x03E8}, + {0x0212, 0x03E8}, {0x0213, 0x03E8}, {0x0214, 0x03E8}, {0x0215, 0x03E8}, + {0x0216, 0x03E8}, {0x0217, 0x03E8}, {0x0900, 0x0000}, {0x0901, 0x0000}, + {0x0902, 0x0000}, {0x0903, 0x0000}, {0x0865, 0x3210}, {0x087B, 0x0000}, + {0x087C, 0xFF00}, {0x087D, 0x0000}, {0x087E, 0x0000}, {0x0801, 0x0100}, + {0x0802, 0x0100}, {0x0A20, 0x2040}, {0x0A21, 0x2040}, {0x0A22, 0x2040}, + {0x0A23, 0x2040}, {0x0A24, 0x2040}, {0x0A28, 0x2040}, {0x0A29, 0x2040}, + {0x133F, 0x0030}, {0x133E, 0x000E}, {0x221F, 0x0000}, {0x2200, 0x1340}, + {0x221F, 0x0000}, {0x133F, 0x0010}, {0x133E, 0x0FFE}, {0x20A0, 0x1940}, + {0x20C0, 0x1940}, {0x20E0, 0x1940}, {0x130c, 0x0050}, +}; + +static const struct rtl8367_initval rtl8367_initvals_1_1[] = { + {0x1B24, 0x0000}, {0x1B25, 0x0000}, {0x1B26, 0x0000}, {0x1B27, 0x0000}, + {0x207F, 0x0002}, {0x2079, 0x0200}, {0x207F, 0x0000}, {0x133F, 0x0030}, + {0x133E, 0x000E}, {0x221F, 0x0005}, {0x2201, 0x0700}, {0x2205, 0x8B82}, + {0x2206, 0x05CB}, {0x221F, 0x0002}, {0x2204, 0x80C2}, {0x2205, 0x0938}, + {0x221F, 0x0003}, {0x2212, 0xC4D2}, {0x220D, 0x0207}, {0x221F, 0x0001}, + {0x2207, 0x267E}, {0x221C, 0xE5F7}, {0x221B, 0x0424}, {0x221F, 0x0007}, + {0x221E, 0x0040}, {0x2218, 0x0000}, {0x221F, 0x0007}, {0x221E, 0x002C}, + {0x2218, 0x008B}, {0x221F, 0x0005}, {0x2205, 0xFFF6}, {0x2206, 0x0080}, + {0x2205, 0x8000}, {0x2206, 0xF8E0}, {0x2206, 0xE000}, {0x2206, 0xE1E0}, + {0x2206, 0x01AC}, {0x2206, 0x2408}, {0x2206, 0xE08B}, {0x2206, 0x84F7}, + {0x2206, 0x20E4}, {0x2206, 0x8B84}, {0x2206, 0xFC05}, {0x2206, 0xF8FA}, + {0x2206, 0xEF69}, {0x2206, 0xE08B}, {0x2206, 0x86AC}, {0x2206, 0x201A}, + {0x2206, 0xBF80}, {0x2206, 0x59D0}, {0x2206, 0x2402}, {0x2206, 0x803D}, + {0x2206, 0xE0E0}, {0x2206, 0xE4E1}, {0x2206, 0xE0E5}, {0x2206, 0x5806}, + {0x2206, 0x68C0}, {0x2206, 0xD1D2}, {0x2206, 0xE4E0}, {0x2206, 0xE4E5}, + {0x2206, 0xE0E5}, {0x2206, 0xEF96}, {0x2206, 0xFEFC}, {0x2206, 0x05FB}, + {0x2206, 0x0BFB}, {0x2206, 0x58FF}, {0x2206, 0x9E11}, {0x2206, 0x06F0}, + {0x2206, 0x0C81}, {0x2206, 0x8AE0}, {0x2206, 0x0019}, {0x2206, 0x1B89}, + {0x2206, 0xCFEB}, {0x2206, 0x19EB}, {0x2206, 0x19B0}, {0x2206, 0xEFFF}, + {0x2206, 0x0BFF}, {0x2206, 0x0425}, {0x2206, 0x0807}, {0x2206, 0x2640}, + {0x2206, 0x7227}, {0x2206, 0x267E}, {0x2206, 0x2804}, {0x2206, 0xB729}, + {0x2206, 0x2576}, {0x2206, 0x2A68}, {0x2206, 0xE52B}, {0x2206, 0xAD00}, + {0x2206, 0x2CDB}, {0x2206, 0xF02D}, {0x2206, 0x67BB}, {0x2206, 0x2E7B}, + {0x2206, 0x0F2F}, {0x2206, 0x7365}, {0x2206, 0x31AC}, {0x2206, 0xCC32}, + {0x2206, 0x2300}, {0x2206, 0x332D}, {0x2206, 0x1734}, {0x2206, 0x7F52}, + {0x2206, 0x3510}, {0x2206, 0x0036}, {0x2206, 0x0600}, {0x2206, 0x370C}, + {0x2206, 0xC038}, {0x2206, 0x7FCE}, {0x2206, 0x3CE5}, {0x2206, 0xF73D}, + {0x2206, 0x3DA4}, {0x2206, 0x6530}, {0x2206, 0x3E67}, {0x2206, 0x0053}, + {0x2206, 0x69D2}, {0x2206, 0x0F6A}, {0x2206, 0x012C}, {0x2206, 0x6C2B}, + {0x2206, 0x136E}, {0x2206, 0xE100}, {0x2206, 0x6F12}, {0x2206, 0xF771}, + {0x2206, 0x006B}, {0x2206, 0x7306}, {0x2206, 0xEB74}, {0x2206, 0x94C7}, + {0x2206, 0x7698}, {0x2206, 0x0A77}, {0x2206, 0x5000}, {0x2206, 0x788A}, + {0x2206, 0x1579}, {0x2206, 0x7F6F}, {0x2206, 0x7A06}, {0x2206, 0xA600}, + {0x2205, 0x8B90}, {0x2206, 0x8000}, {0x2205, 0x8B92}, {0x2206, 0x8000}, + {0x2205, 0x8B94}, {0x2206, 0x8014}, {0x2208, 0xFFFA}, {0x2202, 0x3C65}, + {0x2205, 0xFFF6}, {0x2206, 0x00F7}, {0x221F, 0x0000}, {0x221F, 0x0007}, + {0x221E, 0x0042}, {0x2218, 0x0000}, {0x221E, 0x002D}, {0x2218, 0xF010}, + {0x221E, 0x0020}, {0x2215, 0x0000}, {0x221E, 0x0023}, {0x2216, 0x8000}, + {0x221F, 0x0000}, {0x133F, 0x0010}, {0x133E, 0x0FFE}, {0x1362, 0x0115}, + {0x1363, 0x0002}, {0x1363, 0x0000}, {0x1306, 0x000C}, {0x1307, 0x000C}, + {0x1303, 0x0067}, {0x1304, 0x4444}, {0x1203, 0xFF00}, {0x1200, 0x7FC4}, + {0x0900, 0x0000}, {0x0901, 0x0000}, {0x0902, 0x0000}, {0x0903, 0x0000}, + {0x0865, 0x3210}, {0x087B, 0x0000}, {0x087C, 0xFF00}, {0x087D, 0x0000}, + {0x087E, 0x0000}, {0x0801, 0x0100}, {0x0802, 0x0100}, {0x0A20, 0x2040}, + {0x0A21, 0x2040}, {0x0A22, 0x2040}, {0x0A23, 0x2040}, {0x0A24, 0x2040}, + {0x0A25, 0x2040}, {0x0A26, 0x2040}, {0x0A27, 0x2040}, {0x0A28, 0x2040}, + {0x0A29, 0x2040}, {0x133F, 0x0030}, {0x133E, 0x000E}, {0x221F, 0x0000}, + {0x2200, 0x1340}, {0x221F, 0x0000}, {0x133F, 0x0010}, {0x133E, 0x0FFE}, + {0x1B03, 0x0876}, +}; + +static const struct rtl8367_initval rtl8367_initvals_2_0[] = { + {0x1b24, 0x0000}, {0x1b25, 0x0000}, {0x1b26, 0x0000}, {0x1b27, 0x0000}, + {0x133f, 0x0030}, {0x133e, 0x000e}, {0x221f, 0x0007}, {0x221e, 0x0048}, + {0x2219, 0x4012}, {0x221f, 0x0003}, {0x2201, 0x3554}, {0x2202, 0x63e8}, + {0x2203, 0x99c2}, {0x2204, 0x0113}, {0x2205, 0x303e}, {0x220d, 0x0207}, + {0x220e, 0xe100}, {0x221f, 0x0007}, {0x221e, 0x0040}, {0x2218, 0x0000}, + {0x221f, 0x0007}, {0x221e, 0x002c}, {0x2218, 0x008b}, {0x221f, 0x0005}, + {0x2205, 0xfff6}, {0x2206, 0x0080}, {0x221f, 0x0005}, {0x2205, 0x8000}, + {0x2206, 0x0280}, {0x2206, 0x2bf7}, {0x2206, 0x00e0}, {0x2206, 0xfff7}, + {0x2206, 0xa080}, {0x2206, 0x02ae}, {0x2206, 0xf602}, {0x2206, 0x804e}, + {0x2206, 0x0201}, {0x2206, 0x5002}, {0x2206, 0x0163}, {0x2206, 0x0201}, + {0x2206, 0x79e0}, {0x2206, 0x8b8c}, {0x2206, 0xe18b}, {0x2206, 0x8d1e}, + {0x2206, 0x01e1}, {0x2206, 0x8b8e}, {0x2206, 0x1e01}, {0x2206, 0xa000}, + {0x2206, 0xe4ae}, {0x2206, 0xd8bf}, {0x2206, 0x8b88}, {0x2206, 0xec00}, + {0x2206, 0x19a9}, {0x2206, 0x8b90}, {0x2206, 0xf9ee}, {0x2206, 0xfff6}, + {0x2206, 0x00ee}, {0x2206, 0xfff7}, {0x2206, 0xfce0}, {0x2206, 0xe140}, + {0x2206, 0xe1e1}, {0x2206, 0x41f7}, {0x2206, 0x2ff6}, {0x2206, 0x28e4}, + {0x2206, 0xe140}, {0x2206, 0xe5e1}, {0x2206, 0x4104}, {0x2206, 0xf8fa}, + {0x2206, 0xef69}, {0x2206, 0xe08b}, {0x2206, 0x86ac}, {0x2206, 0x201a}, + {0x2206, 0xbf80}, {0x2206, 0x77d0}, {0x2206, 0x6c02}, {0x2206, 0x2978}, + {0x2206, 0xe0e0}, {0x2206, 0xe4e1}, {0x2206, 0xe0e5}, {0x2206, 0x5806}, + {0x2206, 0x68c0}, {0x2206, 0xd1d2}, {0x2206, 0xe4e0}, {0x2206, 0xe4e5}, + {0x2206, 0xe0e5}, {0x2206, 0xef96}, {0x2206, 0xfefc}, {0x2206, 0x0425}, + {0x2206, 0x0807}, {0x2206, 0x2640}, {0x2206, 0x7227}, {0x2206, 0x267e}, + {0x2206, 0x2804}, {0x2206, 0xb729}, {0x2206, 0x2576}, {0x2206, 0x2a68}, + {0x2206, 0xe52b}, {0x2206, 0xad00}, {0x2206, 0x2cdb}, {0x2206, 0xf02d}, + {0x2206, 0x67bb}, {0x2206, 0x2e7b}, {0x2206, 0x0f2f}, {0x2206, 0x7365}, + {0x2206, 0x31ac}, {0x2206, 0xcc32}, {0x2206, 0x2300}, {0x2206, 0x332d}, + {0x2206, 0x1734}, {0x2206, 0x7f52}, {0x2206, 0x3510}, {0x2206, 0x0036}, + {0x2206, 0x0600}, {0x2206, 0x370c}, {0x2206, 0xc038}, {0x2206, 0x7fce}, + {0x2206, 0x3ce5}, {0x2206, 0xf73d}, {0x2206, 0x3da4}, {0x2206, 0x6530}, + {0x2206, 0x3e67}, {0x2206, 0x0053}, {0x2206, 0x69d2}, {0x2206, 0x0f6a}, + {0x2206, 0x012c}, {0x2206, 0x6c2b}, {0x2206, 0x136e}, {0x2206, 0xe100}, + {0x2206, 0x6f12}, {0x2206, 0xf771}, {0x2206, 0x006b}, {0x2206, 0x7306}, + {0x2206, 0xeb74}, {0x2206, 0x94c7}, {0x2206, 0x7698}, {0x2206, 0x0a77}, + {0x2206, 0x5000}, {0x2206, 0x788a}, {0x2206, 0x1579}, {0x2206, 0x7f6f}, + {0x2206, 0x7a06}, {0x2206, 0xa600}, {0x2201, 0x0701}, {0x2200, 0x0405}, + {0x221f, 0x0000}, {0x2200, 0x1340}, {0x221f, 0x0000}, {0x133f, 0x0010}, + {0x133e, 0x0ffe}, {0x1203, 0xff00}, {0x1200, 0x7fc4}, {0x121d, 0x7D16}, + {0x121e, 0x03e8}, {0x121f, 0x024e}, {0x1220, 0x0230}, {0x1221, 0x0244}, + {0x1222, 0x0226}, {0x1223, 0x024e}, {0x1224, 0x0230}, {0x1225, 0x0244}, + {0x1226, 0x0226}, {0x1227, 0x00c0}, {0x1228, 0x00b4}, {0x122f, 0x00c0}, + {0x1230, 0x00b4}, {0x0208, 0x03e8}, {0x0209, 0x03e8}, {0x020a, 0x03e8}, + {0x020b, 0x03e8}, {0x020c, 0x03e8}, {0x020d, 0x03e8}, {0x020e, 0x03e8}, + {0x020f, 0x03e8}, {0x0210, 0x03e8}, {0x0211, 0x03e8}, {0x0212, 0x03e8}, + {0x0213, 0x03e8}, {0x0214, 0x03e8}, {0x0215, 0x03e8}, {0x0216, 0x03e8}, + {0x0217, 0x03e8}, {0x0900, 0x0000}, {0x0901, 0x0000}, {0x0902, 0x0000}, + {0x0903, 0x0000}, {0x0865, 0x3210}, {0x087b, 0x0000}, {0x087c, 0xff00}, + {0x087d, 0x0000}, {0x087e, 0x0000}, {0x0801, 0x0100}, {0x0802, 0x0100}, + {0x0A20, 0x2040}, {0x0A21, 0x2040}, {0x0A22, 0x2040}, {0x0A23, 0x2040}, + {0x0A24, 0x2040}, {0x0A28, 0x2040}, {0x0A29, 0x2040}, {0x20A0, 0x1940}, + {0x20C0, 0x1940}, {0x20E0, 0x1940}, {0x130c, 0x0050}, +}; + +static const struct rtl8367_initval rtl8367_initvals_2_1[] = { + {0x1b24, 0x0000}, {0x1b25, 0x0000}, {0x1b26, 0x0000}, {0x1b27, 0x0000}, + {0x133f, 0x0030}, {0x133e, 0x000e}, {0x221f, 0x0007}, {0x221e, 0x0048}, + {0x2219, 0x4012}, {0x221f, 0x0003}, {0x2201, 0x3554}, {0x2202, 0x63e8}, + {0x2203, 0x99c2}, {0x2204, 0x0113}, {0x2205, 0x303e}, {0x220d, 0x0207}, + {0x220e, 0xe100}, {0x221f, 0x0007}, {0x221e, 0x0040}, {0x2218, 0x0000}, + {0x221f, 0x0007}, {0x221e, 0x002c}, {0x2218, 0x008b}, {0x221f, 0x0005}, + {0x2205, 0xfff6}, {0x2206, 0x0080}, {0x221f, 0x0005}, {0x2205, 0x8000}, + {0x2206, 0x0280}, {0x2206, 0x2bf7}, {0x2206, 0x00e0}, {0x2206, 0xfff7}, + {0x2206, 0xa080}, {0x2206, 0x02ae}, {0x2206, 0xf602}, {0x2206, 0x804e}, + {0x2206, 0x0201}, {0x2206, 0x5002}, {0x2206, 0x0163}, {0x2206, 0x0201}, + {0x2206, 0x79e0}, {0x2206, 0x8b8c}, {0x2206, 0xe18b}, {0x2206, 0x8d1e}, + {0x2206, 0x01e1}, {0x2206, 0x8b8e}, {0x2206, 0x1e01}, {0x2206, 0xa000}, + {0x2206, 0xe4ae}, {0x2206, 0xd8bf}, {0x2206, 0x8b88}, {0x2206, 0xec00}, + {0x2206, 0x19a9}, {0x2206, 0x8b90}, {0x2206, 0xf9ee}, {0x2206, 0xfff6}, + {0x2206, 0x00ee}, {0x2206, 0xfff7}, {0x2206, 0xfce0}, {0x2206, 0xe140}, + {0x2206, 0xe1e1}, {0x2206, 0x41f7}, {0x2206, 0x2ff6}, {0x2206, 0x28e4}, + {0x2206, 0xe140}, {0x2206, 0xe5e1}, {0x2206, 0x4104}, {0x2206, 0xf8fa}, + {0x2206, 0xef69}, {0x2206, 0xe08b}, {0x2206, 0x86ac}, {0x2206, 0x201a}, + {0x2206, 0xbf80}, {0x2206, 0x77d0}, {0x2206, 0x6c02}, {0x2206, 0x2978}, + {0x2206, 0xe0e0}, {0x2206, 0xe4e1}, {0x2206, 0xe0e5}, {0x2206, 0x5806}, + {0x2206, 0x68c0}, {0x2206, 0xd1d2}, {0x2206, 0xe4e0}, {0x2206, 0xe4e5}, + {0x2206, 0xe0e5}, {0x2206, 0xef96}, {0x2206, 0xfefc}, {0x2206, 0x0425}, + {0x2206, 0x0807}, {0x2206, 0x2640}, {0x2206, 0x7227}, {0x2206, 0x267e}, + {0x2206, 0x2804}, {0x2206, 0xb729}, {0x2206, 0x2576}, {0x2206, 0x2a68}, + {0x2206, 0xe52b}, {0x2206, 0xad00}, {0x2206, 0x2cdb}, {0x2206, 0xf02d}, + {0x2206, 0x67bb}, {0x2206, 0x2e7b}, {0x2206, 0x0f2f}, {0x2206, 0x7365}, + {0x2206, 0x31ac}, {0x2206, 0xcc32}, {0x2206, 0x2300}, {0x2206, 0x332d}, + {0x2206, 0x1734}, {0x2206, 0x7f52}, {0x2206, 0x3510}, {0x2206, 0x0036}, + {0x2206, 0x0600}, {0x2206, 0x370c}, {0x2206, 0xc038}, {0x2206, 0x7fce}, + {0x2206, 0x3ce5}, {0x2206, 0xf73d}, {0x2206, 0x3da4}, {0x2206, 0x6530}, + {0x2206, 0x3e67}, {0x2206, 0x0053}, {0x2206, 0x69d2}, {0x2206, 0x0f6a}, + {0x2206, 0x012c}, {0x2206, 0x6c2b}, {0x2206, 0x136e}, {0x2206, 0xe100}, + {0x2206, 0x6f12}, {0x2206, 0xf771}, {0x2206, 0x006b}, {0x2206, 0x7306}, + {0x2206, 0xeb74}, {0x2206, 0x94c7}, {0x2206, 0x7698}, {0x2206, 0x0a77}, + {0x2206, 0x5000}, {0x2206, 0x788a}, {0x2206, 0x1579}, {0x2206, 0x7f6f}, + {0x2206, 0x7a06}, {0x2206, 0xa600}, {0x2201, 0x0701}, {0x2200, 0x0405}, + {0x221f, 0x0000}, {0x2200, 0x1340}, {0x221f, 0x0000}, {0x133f, 0x0010}, + {0x133e, 0x0ffe}, {0x1203, 0xff00}, {0x1200, 0x7fc4}, {0x0900, 0x0000}, + {0x0901, 0x0000}, {0x0902, 0x0000}, {0x0903, 0x0000}, {0x0865, 0x3210}, + {0x087b, 0x0000}, {0x087c, 0xff00}, {0x087d, 0x0000}, {0x087e, 0x0000}, + {0x0801, 0x0100}, {0x0802, 0x0100}, {0x0A20, 0x2040}, {0x0A21, 0x2040}, + {0x0A22, 0x2040}, {0x0A23, 0x2040}, {0x0A24, 0x2040}, {0x0A25, 0x2040}, + {0x0A26, 0x2040}, {0x0A27, 0x2040}, {0x0A28, 0x2040}, {0x0A29, 0x2040}, + {0x130c, 0x0050}, +}; + +static int rtl8367_write_initvals(struct rtl8366_smi *smi, + const struct rtl8367_initval *initvals, + int count) +{ + int err; + int i; + + for (i = 0; i < count; i++) + REG_WR(smi, initvals[i].reg, initvals[i].val); + + return 0; +} + +static int rtl8367_read_phy_reg(struct rtl8366_smi *smi, + u32 phy_addr, u32 phy_reg, u32 *val) +{ + int timeout; + u32 data; + int err; + + if (phy_addr > RTL8367_PHY_ADDR_MAX) + return -EINVAL; + + if (phy_reg > RTL8367_PHY_REG_MAX) + return -EINVAL; + + REG_RD(smi, RTL8367_IA_STATUS_REG, &data); + if (data & RTL8367_IA_STATUS_PHY_BUSY) + return -ETIMEDOUT; + + /* prepare address */ + REG_WR(smi, RTL8367_IA_ADDRESS_REG, + RTL8367_INTERNAL_PHY_REG(phy_addr, phy_reg)); + + /* send read command */ + REG_WR(smi, RTL8367_IA_CTRL_REG, + RTL8367_IA_CTRL_CMD_MASK | RTL8367_IA_CTRL_RW_READ); + + timeout = 5; + do { + REG_RD(smi, RTL8367_IA_STATUS_REG, &data); + if ((data & RTL8367_IA_STATUS_PHY_BUSY) == 0) + break; + + if (timeout--) { + dev_err(smi->parent, "phy read timed out\n"); + return -ETIMEDOUT; + } + + udelay(1); + } while (1); + + /* read data */ + REG_RD(smi, RTL8367_IA_READ_DATA_REG, val); + + dev_dbg(smi->parent, "phy_read: addr:%02x, reg:%02x, val:%04x\n", + phy_addr, phy_reg, *val); + return 0; +} + +static int rtl8367_write_phy_reg(struct rtl8366_smi *smi, + u32 phy_addr, u32 phy_reg, u32 val) +{ + int timeout; + u32 data; + int err; + + dev_dbg(smi->parent, "phy_write: addr:%02x, reg:%02x, val:%04x\n", + phy_addr, phy_reg, val); + + if (phy_addr > RTL8367_PHY_ADDR_MAX) + return -EINVAL; + + if (phy_reg > RTL8367_PHY_REG_MAX) + return -EINVAL; + + REG_RD(smi, RTL8367_IA_STATUS_REG, &data); + if (data & RTL8367_IA_STATUS_PHY_BUSY) + return -ETIMEDOUT; + + /* preapre data */ + REG_WR(smi, RTL8367_IA_WRITE_DATA_REG, val); + + /* prepare address */ + REG_WR(smi, RTL8367_IA_ADDRESS_REG, + RTL8367_INTERNAL_PHY_REG(phy_addr, phy_reg)); + + /* send write command */ + REG_WR(smi, RTL8367_IA_CTRL_REG, + RTL8367_IA_CTRL_CMD_MASK | RTL8367_IA_CTRL_RW_WRITE); + + timeout = 5; + do { + REG_RD(smi, RTL8367_IA_STATUS_REG, &data); + if ((data & RTL8367_IA_STATUS_PHY_BUSY) == 0) + break; + + if (timeout--) { + dev_err(smi->parent, "phy write timed out\n"); + return -ETIMEDOUT; + } + + udelay(1); + } while (1); + + return 0; +} + +static int rtl8367_init_regs0(struct rtl8366_smi *smi, unsigned mode) +{ + const struct rtl8367_initval *initvals; + int count; + int err; + + switch (mode) { + case 0: + initvals = rtl8367_initvals_0_0; + count = ARRAY_SIZE(rtl8367_initvals_0_0); + break; + + case 1: + case 2: + initvals = rtl8367_initvals_0_1; + count = ARRAY_SIZE(rtl8367_initvals_0_1); + break; + + default: + dev_err(smi->parent, "%s: unknow mode %u\n", __func__, mode); + return -ENODEV; + } + + err = rtl8367_write_initvals(smi, initvals, count); + if (err) + return err; + + /* TODO: complete this */ + + return 0; +} + +static int rtl8367_init_regs1(struct rtl8366_smi *smi, unsigned mode) +{ + const struct rtl8367_initval *initvals; + int count; + + switch (mode) { + case 0: + initvals = rtl8367_initvals_1_0; + count = ARRAY_SIZE(rtl8367_initvals_1_0); + break; + + case 1: + case 2: + initvals = rtl8367_initvals_1_1; + count = ARRAY_SIZE(rtl8367_initvals_1_1); + break; + + default: + dev_err(smi->parent, "%s: unknow mode %u\n", __func__, mode); + return -ENODEV; + } + + return rtl8367_write_initvals(smi, initvals, count); +} + +static int rtl8367_init_regs2(struct rtl8366_smi *smi, unsigned mode) +{ + const struct rtl8367_initval *initvals; + int count; + + switch (mode) { + case 0: + initvals = rtl8367_initvals_2_0; + count = ARRAY_SIZE(rtl8367_initvals_2_0); + break; + + case 1: + case 2: + initvals = rtl8367_initvals_2_1; + count = ARRAY_SIZE(rtl8367_initvals_2_1); + break; + + default: + dev_err(smi->parent, "%s: unknow mode %u\n", __func__, mode); + return -ENODEV; + } + + return rtl8367_write_initvals(smi, initvals, count); +} + +static int rtl8367_init_regs(struct rtl8366_smi *smi) +{ + u32 data; + u32 rlvid; + u32 mode; + int err; + + REG_WR(smi, RTL8367_RTL_MAGIC_ID_REG, RTL8367_RTL_MAGIC_ID_VAL); + + REG_RD(smi, RTL8367_CHIP_VER_REG, &data); + rlvid = (data >> RTL8367_CHIP_VER_RLVID_SHIFT) & + RTL8367_CHIP_VER_RLVID_MASK; + + REG_RD(smi, RTL8367_CHIP_MODE_REG, &data); + mode = data & RTL8367_CHIP_MODE_MASK; + + switch (rlvid) { + case 0: + err = rtl8367_init_regs0(smi, mode); + break; + + case 1: + err = rtl8367_write_phy_reg(smi, 0, 31, 5); + if (err) + break; + + err = rtl8367_write_phy_reg(smi, 0, 5, 0x3ffe); + if (err) + break; + + err = rtl8367_read_phy_reg(smi, 0, 6, &data); + if (err) + break; + + if (data == 0x94eb) { + err = rtl8367_init_regs1(smi, mode); + } else if (data == 0x2104) { + err = rtl8367_init_regs2(smi, mode); + } else { + dev_err(smi->parent, "unknow phy data %04x\n", data); + return -ENODEV; + } + + break; + + default: + dev_err(smi->parent, "unknow rlvid %u\n", rlvid); + err = -ENODEV; + break; + } + + return err; +} + +static int rtl8367_reset_chip(struct rtl8366_smi *smi) +{ + int timeout = 10; + int err; + u32 data; + + REG_WR(smi, RTL8367_CHIP_RESET_REG, RTL8367_CHIP_RESET_HW); + msleep(RTL8367_RESET_DELAY); + + do { + REG_RD(smi, RTL8367_CHIP_RESET_REG, &data); + if (!(data & RTL8367_CHIP_RESET_HW)) + break; + + msleep(1); + } while (--timeout); + + if (!timeout) { + dev_err(smi->parent, "chip reset timed out\n"); + return -ETIMEDOUT; + } + + return 0; +} + +static int rtl8367_extif_set_mode(struct rtl8366_smi *smi, int id, + enum rtl8367_extif_mode mode) +{ + int err; + + /* set port mode */ + switch (mode) { + case RTL8367_EXTIF_MODE_RGMII: + case RTL8367_EXTIF_MODE_RGMII_33V: + REG_WR(smi, RTL8367_CHIP_DEBUG0_REG, 0x0367); + REG_WR(smi, RTL8367_CHIP_DEBUG1_REG, 0x7777); + break; + + case RTL8367_EXTIF_MODE_TMII_MAC: + case RTL8367_EXTIF_MODE_TMII_PHY: + REG_RMW(smi, RTL8367_BYPASS_LINE_RATE_REG, + BIT((id + 1) % 2), BIT((id + 1) % 2)); + break; + + case RTL8367_EXTIF_MODE_GMII: + REG_RMW(smi, RTL8367_CHIP_DEBUG0_REG, + RTL8367_CHIP_DEBUG0_DUMMY0(id), + RTL8367_CHIP_DEBUG0_DUMMY0(id)); + REG_RMW(smi, RTL8367_EXT_RGMXF_REG(id), BIT(6), BIT(6)); + break; + + case RTL8367_EXTIF_MODE_MII_MAC: + case RTL8367_EXTIF_MODE_MII_PHY: + case RTL8367_EXTIF_MODE_DISABLED: + REG_RMW(smi, RTL8367_BYPASS_LINE_RATE_REG, + BIT((id + 1) % 2), 0); + REG_RMW(smi, RTL8367_EXT_RGMXF_REG(id), BIT(6), 0); + break; + + default: + dev_err(smi->parent, + "invalid mode for external interface %d\n", id); + return -EINVAL; + } + + REG_RMW(smi, RTL8367_DIS_REG, + RTL8367_DIS_RGMII_MASK << RTL8367_DIS_RGMII_SHIFT(id), + mode << RTL8367_DIS_RGMII_SHIFT(id)); + + return 0; +} + +static int rtl8367_extif_set_force(struct rtl8366_smi *smi, int id, + struct rtl8367_port_ability *pa) +{ + u32 mask; + u32 val; + int err; + + mask = (RTL8367_DI_FORCE_MODE | + RTL8367_DI_FORCE_NWAY | + RTL8367_DI_FORCE_TXPAUSE | + RTL8367_DI_FORCE_RXPAUSE | + RTL8367_DI_FORCE_LINK | + RTL8367_DI_FORCE_DUPLEX | + RTL8367_DI_FORCE_SPEED_MASK); + + val = pa->speed; + val |= pa->force_mode ? RTL8367_DI_FORCE_MODE : 0; + val |= pa->nway ? RTL8367_DI_FORCE_NWAY : 0; + val |= pa->txpause ? RTL8367_DI_FORCE_TXPAUSE : 0; + val |= pa->rxpause ? RTL8367_DI_FORCE_RXPAUSE : 0; + val |= pa->link ? RTL8367_DI_FORCE_LINK : 0; + val |= pa->duplex ? RTL8367_DI_FORCE_DUPLEX : 0; + + REG_RMW(smi, RTL8367_DI_FORCE_REG(id), mask, val); + + return 0; +} + +static int rtl8367_extif_set_rgmii_delay(struct rtl8366_smi *smi, int id, + unsigned txdelay, unsigned rxdelay) +{ + u32 mask; + u32 val; + int err; + + mask = (RTL8367_EXT_RGMXF_RXDELAY_MASK | + (RTL8367_EXT_RGMXF_TXDELAY_MASK << + RTL8367_EXT_RGMXF_TXDELAY_SHIFT)); + + val = rxdelay; + val |= txdelay << RTL8367_EXT_RGMXF_TXDELAY_SHIFT; + + REG_RMW(smi, RTL8367_EXT_RGMXF_REG(id), mask, val); + + return 0; +} + +static int rtl8367_extif_init(struct rtl8366_smi *smi, int id, + struct rtl8367_extif_config *cfg) +{ + enum rtl8367_extif_mode mode; + int err; + + mode = (cfg) ? cfg->mode : RTL8367_EXTIF_MODE_DISABLED; + + err = rtl8367_extif_set_mode(smi, id, mode); + if (err) + return err; + + if (mode != RTL8367_EXTIF_MODE_DISABLED) { + err = rtl8367_extif_set_force(smi, id, &cfg->ability); + if (err) + return err; + + err = rtl8367_extif_set_rgmii_delay(smi, id, cfg->txdelay, + cfg->rxdelay); + if (err) + return err; + } + + return 0; +} + +static int rtl8367_led_group_set_ports(struct rtl8366_smi *smi, + unsigned int group, u16 port_mask) +{ + u32 reg; + u32 s; + int err; + + port_mask &= RTL8367_PARA_LED_IO_EN_PMASK; + s = (group % 2) * 8; + reg = RTL8367_PARA_LED_IO_EN1_REG + (group / 2); + + REG_RMW(smi, reg, (RTL8367_PARA_LED_IO_EN_PMASK << s), port_mask << s); + + return 0; +} + +static int rtl8367_led_group_set_mode(struct rtl8366_smi *smi, + unsigned int mode) +{ + u16 mask; + u16 set; + int err; + + mode &= RTL8367_LED_CONFIG_DATA_M; + + mask = (RTL8367_LED_CONFIG_DATA_M << RTL8367_LED_CONFIG_DATA_S) | + RTL8367_LED_CONFIG_SEL; + set = (mode << RTL8367_LED_CONFIG_DATA_S) | RTL8367_LED_CONFIG_SEL; + + REG_RMW(smi, RTL8367_LED_CONFIG_REG, mask, set); + + return 0; +} + +static int rtl8367_led_group_set_config(struct rtl8366_smi *smi, + unsigned int led, unsigned int cfg) +{ + u16 mask; + u16 set; + int err; + + mask = (RTL8367_LED_CONFIG_LED_CFG_M << (led * 4)) | + RTL8367_LED_CONFIG_SEL; + set = (cfg & RTL8367_LED_CONFIG_LED_CFG_M) << (led * 4); + + REG_RMW(smi, RTL8367_LED_CONFIG_REG, mask, set); + return 0; +} + +static int rtl8367_led_op_select_parallel(struct rtl8366_smi *smi) +{ + int err; + + REG_WR(smi, RTL8367_LED_SYS_CONFIG_REG, 0x1472); + return 0; +} + +static int rtl8367_led_blinkrate_set(struct rtl8366_smi *smi, unsigned int rate) +{ + u16 mask; + u16 set; + int err; + + mask = RTL8367_LED_MODE_RATE_M << RTL8367_LED_MODE_RATE_S; + set = (rate & RTL8367_LED_MODE_RATE_M) << RTL8367_LED_MODE_RATE_S; + REG_RMW(smi, RTL8367_LED_MODE_REG, mask, set); + + return 0; +} + +#ifdef CONFIG_OF +static int rtl8367_extif_init_of(struct rtl8366_smi *smi, int id, + const char *name) +{ + struct rtl8367_extif_config *cfg; + const __be32 *prop; + int size; + int err; + + prop = of_get_property(smi->parent->of_node, name, &size); + if (!prop) + return rtl8367_extif_init(smi, id, NULL); + + if (size != (9 * sizeof(*prop))) { + dev_err(smi->parent, "%s property is invalid\n", name); + return -EINVAL; + } + + cfg = kzalloc(sizeof(struct rtl8367_extif_config), GFP_KERNEL); + if (!cfg) + return -ENOMEM; + + cfg->txdelay = be32_to_cpup(prop++); + cfg->rxdelay = be32_to_cpup(prop++); + cfg->mode = be32_to_cpup(prop++); + cfg->ability.force_mode = be32_to_cpup(prop++); + cfg->ability.txpause = be32_to_cpup(prop++); + cfg->ability.rxpause = be32_to_cpup(prop++); + cfg->ability.link = be32_to_cpup(prop++); + cfg->ability.duplex = be32_to_cpup(prop++); + cfg->ability.speed = be32_to_cpup(prop++); + + err = rtl8367_extif_init(smi, id, cfg); + kfree(cfg); + + return err; +} +#else +static int rtl8367_extif_init_of(struct rtl8366_smi *smi, int id, + const char *name) +{ + return -EINVAL; +} +#endif + +static int rtl8367_setup(struct rtl8366_smi *smi) +{ + struct rtl8367_platform_data *pdata; + int err; + int i; + + pdata = smi->parent->platform_data; + + err = rtl8367_init_regs(smi); + if (err) + return err; + + /* initialize external interfaces */ + if (smi->parent->of_node) { + err = rtl8367_extif_init_of(smi, 0, "realtek,extif0"); + if (err) + return err; + + err = rtl8367_extif_init_of(smi, 1, "realtek,extif1"); + if (err) + return err; + } else { + err = rtl8367_extif_init(smi, 0, pdata->extif0_cfg); + if (err) + return err; + + err = rtl8367_extif_init(smi, 1, pdata->extif1_cfg); + if (err) + return err; + } + + /* set maximum packet length to 1536 bytes */ + REG_RMW(smi, RTL8367_SWC0_REG, RTL8367_SWC0_MAX_LENGTH_MASK, + RTL8367_SWC0_MAX_LENGTH_1536); + + /* + * discard VLAN tagged packets if the port is not a member of + * the VLAN with which the packets is associated. + */ + REG_WR(smi, RTL8367_VLAN_INGRESS_REG, RTL8367_PORTS_ALL); + + /* + * Setup egress tag mode for each port. + */ + for (i = 0; i < RTL8367_NUM_PORTS; i++) + REG_RMW(smi, + RTL8367_PORT_CFG_REG(i), + RTL8367_PORT_CFG_EGRESS_MODE_MASK << + RTL8367_PORT_CFG_EGRESS_MODE_SHIFT, + RTL8367_PORT_CFG_EGRESS_MODE_ORIGINAL << + RTL8367_PORT_CFG_EGRESS_MODE_SHIFT); + + /* setup LEDs */ + err = rtl8367_led_group_set_ports(smi, 0, RTL8367_PORTS_ALL); + if (err) + return err; + + err = rtl8367_led_group_set_mode(smi, 0); + if (err) + return err; + + err = rtl8367_led_op_select_parallel(smi); + if (err) + return err; + + err = rtl8367_led_blinkrate_set(smi, 1); + if (err) + return err; + + err = rtl8367_led_group_set_config(smi, 0, 2); + if (err) + return err; + + return 0; +} + +static int rtl8367_get_mib_counter(struct rtl8366_smi *smi, int counter, + int port, unsigned long long *val) +{ + struct rtl8366_mib_counter *mib; + int offset; + int i; + int err; + u32 addr, data; + u64 mibvalue; + + if (port > RTL8367_NUM_PORTS || counter >= RTL8367_MIB_COUNT) + return -EINVAL; + + mib = &rtl8367_mib_counters[counter]; + addr = RTL8367_MIB_COUNTER_PORT_OFFSET * port + mib->offset; + + /* + * Writing access counter address first + * then ASIC will prepare 64bits counter wait for being retrived + */ + REG_WR(smi, RTL8367_MIB_ADDRESS_REG, addr >> 2); + + /* read MIB control register */ + REG_RD(smi, RTL8367_MIB_CTRL_REG(0), &data); + + if (data & RTL8367_MIB_CTRL_BUSY_MASK) + return -EBUSY; + + if (data & RTL8367_MIB_CTRL_RESET_MASK) + return -EIO; + + if (mib->length == 4) + offset = 3; + else + offset = (mib->offset + 1) % 4; + + mibvalue = 0; + for (i = 0; i < mib->length; i++) { + REG_RD(smi, RTL8367_MIB_COUNTER_REG(offset - i), &data); + mibvalue = (mibvalue << 16) | (data & 0xFFFF); + } + + *val = mibvalue; + return 0; +} + +static int rtl8367_get_vlan_4k(struct rtl8366_smi *smi, u32 vid, + struct rtl8366_vlan_4k *vlan4k) +{ + u32 data[RTL8367_TA_VLAN_DATA_SIZE]; + int err; + int i; + + memset(vlan4k, '\0', sizeof(struct rtl8366_vlan_4k)); + + if (vid >= RTL8367_NUM_VIDS) + return -EINVAL; + + /* write VID */ + REG_WR(smi, RTL8367_TA_ADDR_REG, vid); + + /* write table access control word */ + REG_WR(smi, RTL8367_TA_CTRL_REG, RTL8367_TA_CTRL_CVLAN_READ); + + for (i = 0; i < ARRAY_SIZE(data); i++) + REG_RD(smi, RTL8367_TA_DATA_REG(i), &data[i]); + + vlan4k->vid = vid; + vlan4k->member = (data[0] >> RTL8367_TA_VLAN_MEMBER_SHIFT) & + RTL8367_TA_VLAN_MEMBER_MASK; + vlan4k->fid = (data[1] >> RTL8367_TA_VLAN_FID_SHIFT) & + RTL8367_TA_VLAN_FID_MASK; + vlan4k->untag = (data[2] >> RTL8367_TA_VLAN_UNTAG1_SHIFT) & + RTL8367_TA_VLAN_UNTAG1_MASK; + vlan4k->untag |= ((data[3] >> RTL8367_TA_VLAN_UNTAG2_SHIFT) & + RTL8367_TA_VLAN_UNTAG2_MASK) << 2; + + return 0; +} + +static int rtl8367_set_vlan_4k(struct rtl8366_smi *smi, + const struct rtl8366_vlan_4k *vlan4k) +{ + u32 data[RTL8367_TA_VLAN_DATA_SIZE]; + int err; + int i; + + if (vlan4k->vid >= RTL8367_NUM_VIDS || + vlan4k->member > RTL8367_TA_VLAN_MEMBER_MASK || + vlan4k->untag > RTL8367_UNTAG_MASK || + vlan4k->fid > RTL8367_FIDMAX) + return -EINVAL; + + data[0] = (vlan4k->member & RTL8367_TA_VLAN_MEMBER_MASK) << + RTL8367_TA_VLAN_MEMBER_SHIFT; + data[1] = (vlan4k->fid & RTL8367_TA_VLAN_FID_MASK) << + RTL8367_TA_VLAN_FID_SHIFT; + data[2] = (vlan4k->untag & RTL8367_TA_VLAN_UNTAG1_MASK) << + RTL8367_TA_VLAN_UNTAG1_SHIFT; + data[3] = ((vlan4k->untag >> 2) & RTL8367_TA_VLAN_UNTAG2_MASK) << + RTL8367_TA_VLAN_UNTAG2_SHIFT; + + for (i = 0; i < ARRAY_SIZE(data); i++) + REG_WR(smi, RTL8367_TA_DATA_REG(i), data[i]); + + /* write VID */ + REG_WR(smi, RTL8367_TA_ADDR_REG, + vlan4k->vid & RTL8367_TA_VLAN_VID_MASK); + + /* write table access control word */ + REG_WR(smi, RTL8367_TA_CTRL_REG, RTL8367_TA_CTRL_CVLAN_WRITE); + + return 0; +} + +static int rtl8367_get_vlan_mc(struct rtl8366_smi *smi, u32 index, + struct rtl8366_vlan_mc *vlanmc) +{ + u32 data[RTL8367_VLAN_MC_DATA_SIZE]; + int err; + int i; + + memset(vlanmc, '\0', sizeof(struct rtl8366_vlan_mc)); + + if (index >= RTL8367_NUM_VLANS) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(data); i++) + REG_RD(smi, RTL8367_VLAN_MC_BASE(index) + i, &data[i]); + + vlanmc->member = (data[0] >> RTL8367_VLAN_MC_MEMBER_SHIFT) & + RTL8367_VLAN_MC_MEMBER_MASK; + vlanmc->fid = (data[1] >> RTL8367_VLAN_MC_FID_SHIFT) & + RTL8367_VLAN_MC_FID_MASK; + vlanmc->vid = (data[3] >> RTL8367_VLAN_MC_EVID_SHIFT) & + RTL8367_VLAN_MC_EVID_MASK; + + return 0; +} + +static int rtl8367_set_vlan_mc(struct rtl8366_smi *smi, u32 index, + const struct rtl8366_vlan_mc *vlanmc) +{ + u32 data[RTL8367_VLAN_MC_DATA_SIZE]; + int err; + int i; + + if (index >= RTL8367_NUM_VLANS || + vlanmc->vid >= RTL8367_NUM_VIDS || + vlanmc->priority > RTL8367_PRIORITYMAX || + vlanmc->member > RTL8367_VLAN_MC_MEMBER_MASK || + vlanmc->untag > RTL8367_UNTAG_MASK || + vlanmc->fid > RTL8367_FIDMAX) + return -EINVAL; + + data[0] = (vlanmc->member & RTL8367_VLAN_MC_MEMBER_MASK) << + RTL8367_VLAN_MC_MEMBER_SHIFT; + data[1] = (vlanmc->fid & RTL8367_VLAN_MC_FID_MASK) << + RTL8367_VLAN_MC_FID_SHIFT; + data[2] = 0; + data[3] = (vlanmc->vid & RTL8367_VLAN_MC_EVID_MASK) << + RTL8367_VLAN_MC_EVID_SHIFT; + + for (i = 0; i < ARRAY_SIZE(data); i++) + REG_WR(smi, RTL8367_VLAN_MC_BASE(index) + i, data[i]); + + return 0; +} + +static int rtl8367_get_mc_index(struct rtl8366_smi *smi, int port, int *val) +{ + u32 data; + int err; + + if (port >= RTL8367_NUM_PORTS) + return -EINVAL; + + REG_RD(smi, RTL8367_VLAN_PVID_CTRL_REG(port), &data); + + *val = (data >> RTL8367_VLAN_PVID_CTRL_SHIFT(port)) & + RTL8367_VLAN_PVID_CTRL_MASK; + + return 0; +} + +static int rtl8367_set_mc_index(struct rtl8366_smi *smi, int port, int index) +{ + if (port >= RTL8367_NUM_PORTS || index >= RTL8367_NUM_VLANS) + return -EINVAL; + + return rtl8366_smi_rmwr(smi, RTL8367_VLAN_PVID_CTRL_REG(port), + RTL8367_VLAN_PVID_CTRL_MASK << + RTL8367_VLAN_PVID_CTRL_SHIFT(port), + (index & RTL8367_VLAN_PVID_CTRL_MASK) << + RTL8367_VLAN_PVID_CTRL_SHIFT(port)); +} + +static int rtl8367_enable_vlan(struct rtl8366_smi *smi, int enable) +{ + return rtl8366_smi_rmwr(smi, RTL8367_VLAN_CTRL_REG, + RTL8367_VLAN_CTRL_ENABLE, + (enable) ? RTL8367_VLAN_CTRL_ENABLE : 0); +} + +static int rtl8367_enable_vlan4k(struct rtl8366_smi *smi, int enable) +{ + return 0; +} + +static int rtl8367_is_vlan_valid(struct rtl8366_smi *smi, unsigned vlan) +{ + unsigned max = RTL8367_NUM_VLANS; + + if (smi->vlan4k_enabled) + max = RTL8367_NUM_VIDS - 1; + + if (vlan == 0 || vlan >= max) + return 0; + + return 1; +} + +static int rtl8367_enable_port(struct rtl8366_smi *smi, int port, int enable) +{ + int err; + + REG_WR(smi, RTL8367_PORT_ISOLATION_REG(port), + (enable) ? RTL8367_PORTS_ALL : 0); + + return 0; +} + +static int rtl8367_sw_reset_mibs(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + + return rtl8366_smi_rmwr(smi, RTL8367_MIB_CTRL_REG(0), 0, + RTL8367_MIB_CTRL_GLOBAL_RESET_MASK); +} + +static int rtl8367_sw_get_port_link(struct switch_dev *dev, + int port, + struct switch_port_link *link) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data = 0; + u32 speed; + + if (port >= RTL8367_NUM_PORTS) + return -EINVAL; + + rtl8366_smi_read_reg(smi, RTL8367_PORT_STATUS_REG(port), &data); + + link->link = !!(data & RTL8367_PORT_STATUS_LINK); + if (!link->link) + return 0; + + link->duplex = !!(data & RTL8367_PORT_STATUS_DUPLEX); + link->rx_flow = !!(data & RTL8367_PORT_STATUS_RXPAUSE); + link->tx_flow = !!(data & RTL8367_PORT_STATUS_TXPAUSE); + link->aneg = !!(data & RTL8367_PORT_STATUS_NWAY); + + speed = (data & RTL8367_PORT_STATUS_SPEED_MASK); + switch (speed) { + case 0: + link->speed = SWITCH_PORT_SPEED_10; + break; + case 1: + link->speed = SWITCH_PORT_SPEED_100; + break; + case 2: + link->speed = SWITCH_PORT_SPEED_1000; + break; + default: + link->speed = SWITCH_PORT_SPEED_UNKNOWN; + break; + } + + return 0; +} + +static int rtl8367_sw_get_max_length(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + rtl8366_smi_read_reg(smi, RTL8367_SWC0_REG, &data); + val->value.i = (data & RTL8367_SWC0_MAX_LENGTH_MASK) >> + RTL8367_SWC0_MAX_LENGTH_SHIFT; + + return 0; +} + +static int rtl8367_sw_set_max_length(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 max_len; + + switch (val->value.i) { + case 0: + max_len = RTL8367_SWC0_MAX_LENGTH_1522; + break; + case 1: + max_len = RTL8367_SWC0_MAX_LENGTH_1536; + break; + case 2: + max_len = RTL8367_SWC0_MAX_LENGTH_1552; + break; + case 3: + max_len = RTL8367_SWC0_MAX_LENGTH_16000; + break; + default: + return -EINVAL; + } + + return rtl8366_smi_rmwr(smi, RTL8367_SWC0_REG, + RTL8367_SWC0_MAX_LENGTH_MASK, max_len); +} + + +static int rtl8367_sw_reset_port_mibs(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + int port; + + port = val->port_vlan; + if (port >= RTL8367_NUM_PORTS) + return -EINVAL; + + return rtl8366_smi_rmwr(smi, RTL8367_MIB_CTRL_REG(port / 8), 0, + RTL8367_MIB_CTRL_PORT_RESET_MASK(port % 8)); +} + +static struct switch_attr rtl8367_globals[] = { + { + .type = SWITCH_TYPE_INT, + .name = "enable_vlan", + .description = "Enable VLAN mode", + .set = rtl8366_sw_set_vlan_enable, + .get = rtl8366_sw_get_vlan_enable, + .max = 1, + .ofs = 1 + }, { + .type = SWITCH_TYPE_INT, + .name = "enable_vlan4k", + .description = "Enable VLAN 4K mode", + .set = rtl8366_sw_set_vlan_enable, + .get = rtl8366_sw_get_vlan_enable, + .max = 1, + .ofs = 2 + }, { + .type = SWITCH_TYPE_NOVAL, + .name = "reset_mibs", + .description = "Reset all MIB counters", + .set = rtl8367_sw_reset_mibs, + }, { + .type = SWITCH_TYPE_INT, + .name = "max_length", + .description = "Get/Set the maximum length of valid packets" + "(0:1522, 1:1536, 2:1552, 3:16000)", + .set = rtl8367_sw_set_max_length, + .get = rtl8367_sw_get_max_length, + .max = 3, + } +}; + +static struct switch_attr rtl8367_port[] = { + { + .type = SWITCH_TYPE_NOVAL, + .name = "reset_mib", + .description = "Reset single port MIB counters", + .set = rtl8367_sw_reset_port_mibs, + }, { + .type = SWITCH_TYPE_STRING, + .name = "mib", + .description = "Get MIB counters for port", + .max = 33, + .set = NULL, + .get = rtl8366_sw_get_port_mib, + }, +}; + +static struct switch_attr rtl8367_vlan[] = { + { + .type = SWITCH_TYPE_STRING, + .name = "info", + .description = "Get vlan information", + .max = 1, + .set = NULL, + .get = rtl8366_sw_get_vlan_info, + }, { + .type = SWITCH_TYPE_INT, + .name = "fid", + .description = "Get/Set vlan FID", + .max = RTL8367_FIDMAX, + .set = rtl8366_sw_set_vlan_fid, + .get = rtl8366_sw_get_vlan_fid, + }, +}; + +static const struct switch_dev_ops rtl8367_sw_ops = { + .attr_global = { + .attr = rtl8367_globals, + .n_attr = ARRAY_SIZE(rtl8367_globals), + }, + .attr_port = { + .attr = rtl8367_port, + .n_attr = ARRAY_SIZE(rtl8367_port), + }, + .attr_vlan = { + .attr = rtl8367_vlan, + .n_attr = ARRAY_SIZE(rtl8367_vlan), + }, + + .get_vlan_ports = rtl8366_sw_get_vlan_ports, + .set_vlan_ports = rtl8366_sw_set_vlan_ports, + .get_port_pvid = rtl8366_sw_get_port_pvid, + .set_port_pvid = rtl8366_sw_set_port_pvid, + .reset_switch = rtl8366_sw_reset_switch, + .get_port_link = rtl8367_sw_get_port_link, +}; + +static int rtl8367_switch_init(struct rtl8366_smi *smi) +{ + struct switch_dev *dev = &smi->sw_dev; + int err; + + dev->name = "RTL8367"; + dev->cpu_port = RTL8367_CPU_PORT_NUM; + dev->ports = RTL8367_NUM_PORTS; + dev->vlans = RTL8367_NUM_VIDS; + dev->ops = &rtl8367_sw_ops; + dev->alias = dev_name(smi->parent); + + err = register_switch(dev, NULL); + if (err) + dev_err(smi->parent, "switch registration failed\n"); + + return err; +} + +static void rtl8367_switch_cleanup(struct rtl8366_smi *smi) +{ + unregister_switch(&smi->sw_dev); +} + +static int rtl8367_mii_read(struct mii_bus *bus, int addr, int reg) +{ + struct rtl8366_smi *smi = bus->priv; + u32 val = 0; + int err; + + err = rtl8367_read_phy_reg(smi, addr, reg, &val); + if (err) + return 0xffff; + + return val; +} + +static int rtl8367_mii_write(struct mii_bus *bus, int addr, int reg, u16 val) +{ + struct rtl8366_smi *smi = bus->priv; + u32 t; + int err; + + err = rtl8367_write_phy_reg(smi, addr, reg, val); + if (err) + return err; + + /* flush write */ + (void) rtl8367_read_phy_reg(smi, addr, reg, &t); + + return err; +} + +static int rtl8367_detect(struct rtl8366_smi *smi) +{ + u32 rtl_no = 0; + u32 rtl_ver = 0; + char *chip_name; + int ret; + + ret = rtl8366_smi_read_reg(smi, RTL8367_RTL_NO_REG, &rtl_no); + if (ret) { + dev_err(smi->parent, "unable to read chip number\n"); + return ret; + } + + switch (rtl_no) { + case RTL8367_RTL_NO_8367R: + chip_name = "8367R"; + break; + case RTL8367_RTL_NO_8367M: + chip_name = "8367M"; + break; + default: + dev_err(smi->parent, "unknown chip number (%04x)\n", rtl_no); + return -ENODEV; + } + + ret = rtl8366_smi_read_reg(smi, RTL8367_RTL_VER_REG, &rtl_ver); + if (ret) { + dev_err(smi->parent, "unable to read chip version\n"); + return ret; + } + + dev_info(smi->parent, "RTL%s ver. %u chip found\n", + chip_name, rtl_ver & RTL8367_RTL_VER_MASK); + + return 0; +} + +static struct rtl8366_smi_ops rtl8367_smi_ops = { + .detect = rtl8367_detect, + .reset_chip = rtl8367_reset_chip, + .setup = rtl8367_setup, + + .mii_read = rtl8367_mii_read, + .mii_write = rtl8367_mii_write, + + .get_vlan_mc = rtl8367_get_vlan_mc, + .set_vlan_mc = rtl8367_set_vlan_mc, + .get_vlan_4k = rtl8367_get_vlan_4k, + .set_vlan_4k = rtl8367_set_vlan_4k, + .get_mc_index = rtl8367_get_mc_index, + .set_mc_index = rtl8367_set_mc_index, + .get_mib_counter = rtl8367_get_mib_counter, + .is_vlan_valid = rtl8367_is_vlan_valid, + .enable_vlan = rtl8367_enable_vlan, + .enable_vlan4k = rtl8367_enable_vlan4k, + .enable_port = rtl8367_enable_port, +}; + +static int rtl8367_probe(struct platform_device *pdev) +{ + struct rtl8366_smi *smi; + int err; + + smi = rtl8366_smi_probe(pdev); + if (!smi) + return -ENODEV; + + smi->clk_delay = 1500; + smi->cmd_read = 0xb9; + smi->cmd_write = 0xb8; + smi->ops = &rtl8367_smi_ops; + smi->cpu_port = RTL8367_CPU_PORT_NUM; + smi->num_ports = RTL8367_NUM_PORTS; + smi->num_vlan_mc = RTL8367_NUM_VLANS; + smi->mib_counters = rtl8367_mib_counters; + smi->num_mib_counters = ARRAY_SIZE(rtl8367_mib_counters); + + err = rtl8366_smi_init(smi); + if (err) + goto err_free_smi; + + platform_set_drvdata(pdev, smi); + + err = rtl8367_switch_init(smi); + if (err) + goto err_clear_drvdata; + + return 0; + + err_clear_drvdata: + platform_set_drvdata(pdev, NULL); + rtl8366_smi_cleanup(smi); + err_free_smi: + kfree(smi); + return err; +} + +static int rtl8367_remove(struct platform_device *pdev) +{ + struct rtl8366_smi *smi = platform_get_drvdata(pdev); + + if (smi) { + rtl8367_switch_cleanup(smi); + platform_set_drvdata(pdev, NULL); + rtl8366_smi_cleanup(smi); + kfree(smi); + } + + return 0; +} + +static void rtl8367_shutdown(struct platform_device *pdev) +{ + struct rtl8366_smi *smi = platform_get_drvdata(pdev); + + if (smi) + rtl8367_reset_chip(smi); +} + +#ifdef CONFIG_OF +static const struct of_device_id rtl8367_match[] = { + { .compatible = "realtek,rtl8367" }, + {}, +}; +MODULE_DEVICE_TABLE(of, rtl8367_match); +#endif + +static struct platform_driver rtl8367_driver = { + .driver = { + .name = RTL8367_DRIVER_NAME, + .owner = THIS_MODULE, +#ifdef CONFIG_OF + .of_match_table = of_match_ptr(rtl8367_match), +#endif + }, + .probe = rtl8367_probe, + .remove = rtl8367_remove, + .shutdown = rtl8367_shutdown, +}; + +static int __init rtl8367_module_init(void) +{ + return platform_driver_register(&rtl8367_driver); +} +module_init(rtl8367_module_init); + +static void __exit rtl8367_module_exit(void) +{ + platform_driver_unregister(&rtl8367_driver); +} +module_exit(rtl8367_module_exit); + +MODULE_DESCRIPTION(RTL8367_DRIVER_DESC); +MODULE_AUTHOR("Gabor Juhos "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" RTL8367_DRIVER_NAME); diff --git a/target/linux/generic/files/drivers/net/phy/rtl8367b.c b/target/linux/generic/files/drivers/net/phy/rtl8367b.c new file mode 100644 index 0000000..a82f696 --- /dev/null +++ b/target/linux/generic/files/drivers/net/phy/rtl8367b.c @@ -0,0 +1,1602 @@ +/* + * Platform driver for the Realtek RTL8367R-VB ethernet switches + * + * Copyright (C) 2012 Gabor Juhos + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rtl8366_smi.h" + +#define RTL8367B_RESET_DELAY 1000 /* msecs*/ + +#define RTL8367B_PHY_ADDR_MAX 8 +#define RTL8367B_PHY_REG_MAX 31 + +#define RTL8367B_VID_MASK 0x3fff +#define RTL8367B_FID_MASK 0xf +#define RTL8367B_UNTAG_MASK 0xff +#define RTL8367B_MEMBER_MASK 0xff + +#define RTL8367B_PORT_MISC_CFG_REG(_p) (0x000e + 0x20 * (_p)) +#define RTL8367B_PORT_MISC_CFG_EGRESS_MODE_SHIFT 4 +#define RTL8367B_PORT_MISC_CFG_EGRESS_MODE_MASK 0x3 +#define RTL8367B_PORT_MISC_CFG_EGRESS_MODE_ORIGINAL 0 +#define RTL8367B_PORT_MISC_CFG_EGRESS_MODE_KEEP 1 +#define RTL8367B_PORT_MISC_CFG_EGRESS_MODE_PRI 2 +#define RTL8367B_PORT_MISC_CFG_EGRESS_MODE_REAL 3 + +#define RTL8367B_BYPASS_LINE_RATE_REG 0x03f7 + +#define RTL8367B_TA_CTRL_REG 0x0500 /*GOOD*/ +#define RTL8367B_TA_CTRL_SPA_SHIFT 8 +#define RTL8367B_TA_CTRL_SPA_MASK 0x7 +#define RTL8367B_TA_CTRL_METHOD BIT(4)/*GOOD*/ +#define RTL8367B_TA_CTRL_CMD_SHIFT 3 +#define RTL8367B_TA_CTRL_CMD_READ 0 +#define RTL8367B_TA_CTRL_CMD_WRITE 1 +#define RTL8367B_TA_CTRL_TABLE_SHIFT 0 /*GOOD*/ +#define RTL8367B_TA_CTRL_TABLE_ACLRULE 1 +#define RTL8367B_TA_CTRL_TABLE_ACLACT 2 +#define RTL8367B_TA_CTRL_TABLE_CVLAN 3 +#define RTL8367B_TA_CTRL_TABLE_L2 4 +#define RTL8367B_TA_CTRL_CVLAN_READ \ + ((RTL8367B_TA_CTRL_CMD_READ << RTL8367B_TA_CTRL_CMD_SHIFT) | \ + RTL8367B_TA_CTRL_TABLE_CVLAN) +#define RTL8367B_TA_CTRL_CVLAN_WRITE \ + ((RTL8367B_TA_CTRL_CMD_WRITE << RTL8367B_TA_CTRL_CMD_SHIFT) | \ + RTL8367B_TA_CTRL_TABLE_CVLAN) + +#define RTL8367B_TA_ADDR_REG 0x0501/*GOOD*/ +#define RTL8367B_TA_ADDR_MASK 0x3fff/*GOOD*/ + +#define RTL8367B_TA_LUT_REG 0x0502/*GOOD*/ + +#define RTL8367B_TA_WRDATA_REG(_x) (0x0510 + (_x))/*GOOD*/ +#define RTL8367B_TA_VLAN_NUM_WORDS 2 +#define RTL8367B_TA_VLAN_VID_MASK RTL8367B_VID_MASK +#define RTL8367B_TA_VLAN0_MEMBER_SHIFT 0 +#define RTL8367B_TA_VLAN0_MEMBER_MASK RTL8367B_MEMBER_MASK +#define RTL8367B_TA_VLAN0_UNTAG_SHIFT 8 +#define RTL8367B_TA_VLAN0_UNTAG_MASK RTL8367B_MEMBER_MASK +#define RTL8367B_TA_VLAN1_FID_SHIFT 0 +#define RTL8367B_TA_VLAN1_FID_MASK RTL8367B_FID_MASK + +#define RTL8367B_TA_RDDATA_REG(_x) (0x0520 + (_x))/*GOOD*/ + +#define RTL8367B_VLAN_PVID_CTRL_REG(_p) (0x0700 + (_p) / 2) /*GOOD*/ +#define RTL8367B_VLAN_PVID_CTRL_MASK 0x1f /*GOOD*/ +#define RTL8367B_VLAN_PVID_CTRL_SHIFT(_p) (8 * ((_p) % 2)) /*GOOD*/ + +#define RTL8367B_VLAN_MC_BASE(_x) (0x0728 + (_x) * 4) /*GOOD*/ +#define RTL8367B_VLAN_MC_NUM_WORDS 4 /*GOOD*/ +#define RTL8367B_VLAN_MC0_MEMBER_SHIFT 0/*GOOD*/ +#define RTL8367B_VLAN_MC0_MEMBER_MASK RTL8367B_MEMBER_MASK/*GOOD*/ +#define RTL8367B_VLAN_MC1_FID_SHIFT 0/*GOOD*/ +#define RTL8367B_VLAN_MC1_FID_MASK RTL8367B_FID_MASK/*GOOD*/ +#define RTL8367B_VLAN_MC3_EVID_SHIFT 0/*GOOD*/ +#define RTL8367B_VLAN_MC3_EVID_MASK RTL8367B_VID_MASK/*GOOD*/ + +#define RTL8367B_VLAN_CTRL_REG 0x07a8 /*GOOD*/ +#define RTL8367B_VLAN_CTRL_ENABLE BIT(0) + +#define RTL8367B_VLAN_INGRESS_REG 0x07a9 /*GOOD*/ + +#define RTL8367B_PORT_ISOLATION_REG(_p) (0x08a2 + (_p)) /*GOOD*/ + +#define RTL8367B_MIB_COUNTER_REG(_x) (0x1000 + (_x)) /*GOOD*/ +#define RTL8367B_MIB_COUNTER_PORT_OFFSET 0x007c /*GOOD*/ + +#define RTL8367B_MIB_ADDRESS_REG 0x1004 /*GOOD*/ + +#define RTL8367B_MIB_CTRL0_REG(_x) (0x1005 + (_x)) /*GOOD*/ +#define RTL8367B_MIB_CTRL0_GLOBAL_RESET_MASK BIT(11) /*GOOD*/ +#define RTL8367B_MIB_CTRL0_QM_RESET_MASK BIT(10) /*GOOD*/ +#define RTL8367B_MIB_CTRL0_PORT_RESET_MASK(_p) BIT(2 + (_p)) /*GOOD*/ +#define RTL8367B_MIB_CTRL0_RESET_MASK BIT(1) /*GOOD*/ +#define RTL8367B_MIB_CTRL0_BUSY_MASK BIT(0) /*GOOD*/ + +#define RTL8367B_SWC0_REG 0x1200/*GOOD*/ +#define RTL8367B_SWC0_MAX_LENGTH_SHIFT 13/*GOOD*/ +#define RTL8367B_SWC0_MAX_LENGTH(_x) ((_x) << 13) /*GOOD*/ +#define RTL8367B_SWC0_MAX_LENGTH_MASK RTL8367B_SWC0_MAX_LENGTH(0x3) +#define RTL8367B_SWC0_MAX_LENGTH_1522 RTL8367B_SWC0_MAX_LENGTH(0) +#define RTL8367B_SWC0_MAX_LENGTH_1536 RTL8367B_SWC0_MAX_LENGTH(1) +#define RTL8367B_SWC0_MAX_LENGTH_1552 RTL8367B_SWC0_MAX_LENGTH(2) +#define RTL8367B_SWC0_MAX_LENGTH_16000 RTL8367B_SWC0_MAX_LENGTH(3) + +#define RTL8367B_CHIP_NUMBER_REG 0x1300/*GOOD*/ + +#define RTL8367B_CHIP_VER_REG 0x1301/*GOOD*/ +#define RTL8367B_CHIP_VER_RLVID_SHIFT 12/*GOOD*/ +#define RTL8367B_CHIP_VER_RLVID_MASK 0xf/*GOOD*/ +#define RTL8367B_CHIP_VER_MCID_SHIFT 8/*GOOD*/ +#define RTL8367B_CHIP_VER_MCID_MASK 0xf/*GOOD*/ +#define RTL8367B_CHIP_VER_BOID_SHIFT 4/*GOOD*/ +#define RTL8367B_CHIP_VER_BOID_MASK 0xf/*GOOD*/ +#define RTL8367B_CHIP_VER_AFE_SHIFT 0/*GOOD*/ +#define RTL8367B_CHIP_VER_AFE_MASK 0x1/*GOOD*/ + +#define RTL8367B_CHIP_MODE_REG 0x1302 +#define RTL8367B_CHIP_MODE_MASK 0x7 + +#define RTL8367B_CHIP_DEBUG0_REG 0x1303 +#define RTL8367B_CHIP_DEBUG0_DUMMY0(_x) BIT(8 + (_x)) + +#define RTL8367B_CHIP_DEBUG1_REG 0x1304 + +#define RTL8367B_DIS_REG 0x1305 +#define RTL8367B_DIS_SKIP_MII_RXER(_x) BIT(12 + (_x)) +#define RTL8367B_DIS_RGMII_SHIFT(_x) (4 * (_x)) +#define RTL8367B_DIS_RGMII_MASK 0x7 + +#define RTL8367B_EXT_RGMXF_REG(_x) (0x1306 + (_x)) +#define RTL8367B_EXT_RGMXF_DUMMY0_SHIFT 5 +#define RTL8367B_EXT_RGMXF_DUMMY0_MASK 0x7ff +#define RTL8367B_EXT_RGMXF_TXDELAY_SHIFT 3 +#define RTL8367B_EXT_RGMXF_TXDELAY_MASK 1 +#define RTL8367B_EXT_RGMXF_RXDELAY_MASK 0x7 + +#define RTL8367B_DI_FORCE_REG(_x) (0x1310 + (_x)) +#define RTL8367B_DI_FORCE_MODE BIT(12) +#define RTL8367B_DI_FORCE_NWAY BIT(7) +#define RTL8367B_DI_FORCE_TXPAUSE BIT(6) +#define RTL8367B_DI_FORCE_RXPAUSE BIT(5) +#define RTL8367B_DI_FORCE_LINK BIT(4) +#define RTL8367B_DI_FORCE_DUPLEX BIT(2) +#define RTL8367B_DI_FORCE_SPEED_MASK 3 +#define RTL8367B_DI_FORCE_SPEED_10 0 +#define RTL8367B_DI_FORCE_SPEED_100 1 +#define RTL8367B_DI_FORCE_SPEED_1000 2 + +#define RTL8367B_MAC_FORCE_REG(_x) (0x1312 + (_x)) + +#define RTL8367B_CHIP_RESET_REG 0x1322 /*GOOD*/ +#define RTL8367B_CHIP_RESET_SW BIT(1) /*GOOD*/ +#define RTL8367B_CHIP_RESET_HW BIT(0) /*GOOD*/ + +#define RTL8367B_PORT_STATUS_REG(_p) (0x1352 + (_p)) /*GOOD*/ +#define RTL8367B_PORT_STATUS_EN_1000_SPI BIT(11) /*GOOD*/ +#define RTL8367B_PORT_STATUS_EN_100_SPI BIT(10)/*GOOD*/ +#define RTL8367B_PORT_STATUS_NWAY_FAULT BIT(9)/*GOOD*/ +#define RTL8367B_PORT_STATUS_LINK_MASTER BIT(8)/*GOOD*/ +#define RTL8367B_PORT_STATUS_NWAY BIT(7)/*GOOD*/ +#define RTL8367B_PORT_STATUS_TXPAUSE BIT(6)/*GOOD*/ +#define RTL8367B_PORT_STATUS_RXPAUSE BIT(5)/*GOOD*/ +#define RTL8367B_PORT_STATUS_LINK BIT(4)/*GOOD*/ +#define RTL8367B_PORT_STATUS_DUPLEX BIT(2)/*GOOD*/ +#define RTL8367B_PORT_STATUS_SPEED_MASK 0x0003/*GOOD*/ +#define RTL8367B_PORT_STATUS_SPEED_10 0/*GOOD*/ +#define RTL8367B_PORT_STATUS_SPEED_100 1/*GOOD*/ +#define RTL8367B_PORT_STATUS_SPEED_1000 2/*GOOD*/ + +#define RTL8367B_RTL_MAGIC_ID_REG 0x13c2 +#define RTL8367B_RTL_MAGIC_ID_VAL 0x0249 + +#define RTL8367B_IA_CTRL_REG 0x1f00 +#define RTL8367B_IA_CTRL_RW(_x) ((_x) << 1) +#define RTL8367B_IA_CTRL_RW_READ RTL8367B_IA_CTRL_RW(0) +#define RTL8367B_IA_CTRL_RW_WRITE RTL8367B_IA_CTRL_RW(1) +#define RTL8367B_IA_CTRL_CMD_MASK BIT(0) + +#define RTL8367B_IA_STATUS_REG 0x1f01 +#define RTL8367B_IA_STATUS_PHY_BUSY BIT(2) +#define RTL8367B_IA_STATUS_SDS_BUSY BIT(1) +#define RTL8367B_IA_STATUS_MDX_BUSY BIT(0) + +#define RTL8367B_IA_ADDRESS_REG 0x1f02 +#define RTL8367B_IA_WRITE_DATA_REG 0x1f03 +#define RTL8367B_IA_READ_DATA_REG 0x1f04 + +#define RTL8367B_INTERNAL_PHY_REG(_a, _r) (0x2000 + 32 * (_a) + (_r)) + +#define RTL8367B_NUM_MIB_COUNTERS 58 + +#define RTL8367B_CPU_PORT_NUM 5 +#define RTL8367B_NUM_PORTS 8 +#define RTL8367B_NUM_VLANS 32 +#define RTL8367B_NUM_VIDS 4096 +#define RTL8367B_PRIORITYMAX 7 +#define RTL8367B_FIDMAX 7 + +#define RTL8367B_PORT_0 BIT(0) +#define RTL8367B_PORT_1 BIT(1) +#define RTL8367B_PORT_2 BIT(2) +#define RTL8367B_PORT_3 BIT(3) +#define RTL8367B_PORT_4 BIT(4) +#define RTL8367B_PORT_E0 BIT(5) /* External port 0 */ +#define RTL8367B_PORT_E1 BIT(6) /* External port 1 */ +#define RTL8367B_PORT_E2 BIT(7) /* External port 2 */ + +#define RTL8367B_PORTS_ALL \ + (RTL8367B_PORT_0 | RTL8367B_PORT_1 | RTL8367B_PORT_2 | \ + RTL8367B_PORT_3 | RTL8367B_PORT_4 | RTL8367B_PORT_E0 | \ + RTL8367B_PORT_E1 | RTL8367B_PORT_E2) + +#define RTL8367B_PORTS_ALL_BUT_CPU \ + (RTL8367B_PORT_0 | RTL8367B_PORT_1 | RTL8367B_PORT_2 | \ + RTL8367B_PORT_3 | RTL8367B_PORT_4 | RTL8367B_PORT_E1 | \ + RTL8367B_PORT_E2) + +struct rtl8367b_initval { + u16 reg; + u16 val; +}; + +static struct rtl8366_mib_counter +rtl8367b_mib_counters[RTL8367B_NUM_MIB_COUNTERS] = { + {0, 0, 4, "ifInOctets" }, + {0, 4, 2, "dot3StatsFCSErrors" }, + {0, 6, 2, "dot3StatsSymbolErrors" }, + {0, 8, 2, "dot3InPauseFrames" }, + {0, 10, 2, "dot3ControlInUnknownOpcodes" }, + {0, 12, 2, "etherStatsFragments" }, + {0, 14, 2, "etherStatsJabbers" }, + {0, 16, 2, "ifInUcastPkts" }, + {0, 18, 2, "etherStatsDropEvents" }, + {0, 20, 2, "ifInMulticastPkts" }, + {0, 22, 2, "ifInBroadcastPkts" }, + {0, 24, 2, "inMldChecksumError" }, + {0, 26, 2, "inIgmpChecksumError" }, + {0, 28, 2, "inMldSpecificQuery" }, + {0, 30, 2, "inMldGeneralQuery" }, + {0, 32, 2, "inIgmpSpecificQuery" }, + {0, 34, 2, "inIgmpGeneralQuery" }, + {0, 36, 2, "inMldLeaves" }, + {0, 38, 2, "inIgmpLeaves" }, + + {0, 40, 4, "etherStatsOctets" }, + {0, 44, 2, "etherStatsUnderSizePkts" }, + {0, 46, 2, "etherOversizeStats" }, + {0, 48, 2, "etherStatsPkts64Octets" }, + {0, 50, 2, "etherStatsPkts65to127Octets" }, + {0, 52, 2, "etherStatsPkts128to255Octets" }, + {0, 54, 2, "etherStatsPkts256to511Octets" }, + {0, 56, 2, "etherStatsPkts512to1023Octets" }, + {0, 58, 2, "etherStatsPkts1024to1518Octets" }, + + {0, 60, 4, "ifOutOctets" }, + {0, 64, 2, "dot3StatsSingleCollisionFrames" }, + {0, 66, 2, "dot3StatMultipleCollisionFrames" }, + {0, 68, 2, "dot3sDeferredTransmissions" }, + {0, 70, 2, "dot3StatsLateCollisions" }, + {0, 72, 2, "etherStatsCollisions" }, + {0, 74, 2, "dot3StatsExcessiveCollisions" }, + {0, 76, 2, "dot3OutPauseFrames" }, + {0, 78, 2, "ifOutDiscards" }, + {0, 80, 2, "dot1dTpPortInDiscards" }, + {0, 82, 2, "ifOutUcastPkts" }, + {0, 84, 2, "ifOutMulticastPkts" }, + {0, 86, 2, "ifOutBroadcastPkts" }, + {0, 88, 2, "outOampduPkts" }, + {0, 90, 2, "inOampduPkts" }, + {0, 92, 2, "inIgmpJoinsSuccess" }, + {0, 94, 2, "inIgmpJoinsFail" }, + {0, 96, 2, "inMldJoinsSuccess" }, + {0, 98, 2, "inMldJoinsFail" }, + {0, 100, 2, "inReportSuppressionDrop" }, + {0, 102, 2, "inLeaveSuppressionDrop" }, + {0, 104, 2, "outIgmpReports" }, + {0, 106, 2, "outIgmpLeaves" }, + {0, 108, 2, "outIgmpGeneralQuery" }, + {0, 110, 2, "outIgmpSpecificQuery" }, + {0, 112, 2, "outMldReports" }, + {0, 114, 2, "outMldLeaves" }, + {0, 116, 2, "outMldGeneralQuery" }, + {0, 118, 2, "outMldSpecificQuery" }, + {0, 120, 2, "inKnownMulticastPkts" }, +}; + +#define REG_RD(_smi, _reg, _val) \ + do { \ + err = rtl8366_smi_read_reg(_smi, _reg, _val); \ + if (err) \ + return err; \ + } while (0) + +#define REG_WR(_smi, _reg, _val) \ + do { \ + err = rtl8366_smi_write_reg(_smi, _reg, _val); \ + if (err) \ + return err; \ + } while (0) + +#define REG_RMW(_smi, _reg, _mask, _val) \ + do { \ + err = rtl8366_smi_rmwr(_smi, _reg, _mask, _val); \ + if (err) \ + return err; \ + } while (0) + +static const struct rtl8367b_initval rtl8367r_vb_initvals_0[] = { + {0x1B03, 0x0876}, {0x1200, 0x7FC4}, {0x0301, 0x0026}, {0x1722, 0x0E14}, + {0x205F, 0x0002}, {0x2059, 0x1A00}, {0x205F, 0x0000}, {0x207F, 0x0002}, + {0x2077, 0x0000}, {0x2078, 0x0000}, {0x2079, 0x0000}, {0x207A, 0x0000}, + {0x207B, 0x0000}, {0x207F, 0x0000}, {0x205F, 0x0002}, {0x2053, 0x0000}, + {0x2054, 0x0000}, {0x2055, 0x0000}, {0x2056, 0x0000}, {0x2057, 0x0000}, + {0x205F, 0x0000}, {0x12A4, 0x110A}, {0x12A6, 0x150A}, {0x13F1, 0x0013}, + {0x13F4, 0x0010}, {0x13F5, 0x0000}, {0x0018, 0x0F00}, {0x0038, 0x0F00}, + {0x0058, 0x0F00}, {0x0078, 0x0F00}, {0x0098, 0x0F00}, {0x12B6, 0x0C02}, + {0x12B7, 0x030F}, {0x12B8, 0x11FF}, {0x12BC, 0x0004}, {0x1362, 0x0115}, + {0x1363, 0x0002}, {0x1363, 0x0000}, {0x133F, 0x0030}, {0x133E, 0x000E}, + {0x221F, 0x0007}, {0x221E, 0x002D}, {0x2218, 0xF030}, {0x221F, 0x0007}, + {0x221E, 0x0023}, {0x2216, 0x0005}, {0x2215, 0x00B9}, {0x2219, 0x0044}, + {0x2215, 0x00BA}, {0x2219, 0x0020}, {0x2215, 0x00BB}, {0x2219, 0x00C1}, + {0x2215, 0x0148}, {0x2219, 0x0096}, {0x2215, 0x016E}, {0x2219, 0x0026}, + {0x2216, 0x0000}, {0x2216, 0x0000}, {0x221E, 0x002D}, {0x2218, 0xF010}, + {0x221F, 0x0007}, {0x221E, 0x0020}, {0x2215, 0x0D00}, {0x221F, 0x0000}, + {0x221F, 0x0000}, {0x2217, 0x2160}, {0x221F, 0x0001}, {0x2210, 0xF25E}, + {0x221F, 0x0007}, {0x221E, 0x0042}, {0x2215, 0x0F00}, {0x2215, 0x0F00}, + {0x2216, 0x7408}, {0x2215, 0x0E00}, {0x2215, 0x0F00}, {0x2215, 0x0F01}, + {0x2216, 0x4000}, {0x2215, 0x0E01}, {0x2215, 0x0F01}, {0x2215, 0x0F02}, + {0x2216, 0x9400}, {0x2215, 0x0E02}, {0x2215, 0x0F02}, {0x2215, 0x0F03}, + {0x2216, 0x7408}, {0x2215, 0x0E03}, {0x2215, 0x0F03}, {0x2215, 0x0F04}, + {0x2216, 0x4008}, {0x2215, 0x0E04}, {0x2215, 0x0F04}, {0x2215, 0x0F05}, + {0x2216, 0x9400}, {0x2215, 0x0E05}, {0x2215, 0x0F05}, {0x2215, 0x0F06}, + {0x2216, 0x0803}, {0x2215, 0x0E06}, {0x2215, 0x0F06}, {0x2215, 0x0D00}, + {0x2215, 0x0100}, {0x221F, 0x0001}, {0x2210, 0xF05E}, {0x221F, 0x0000}, + {0x2217, 0x2100}, {0x221F, 0x0000}, {0x220D, 0x0003}, {0x220E, 0x0015}, + {0x220D, 0x4003}, {0x220E, 0x0006}, {0x221F, 0x0000}, {0x2200, 0x1340}, + {0x133F, 0x0010}, {0x12A0, 0x0058}, {0x12A1, 0x0058}, {0x133E, 0x000E}, + {0x133F, 0x0030}, {0x221F, 0x0000}, {0x2210, 0x0166}, {0x221F, 0x0000}, + {0x133E, 0x000E}, {0x133F, 0x0010}, {0x133F, 0x0030}, {0x133E, 0x000E}, + {0x221F, 0x0005}, {0x2205, 0xFFF6}, {0x2206, 0x0080}, {0x2205, 0x8B6E}, + {0x2206, 0x0000}, {0x220F, 0x0100}, {0x2205, 0x8000}, {0x2206, 0x0280}, + {0x2206, 0x28F7}, {0x2206, 0x00E0}, {0x2206, 0xFFF7}, {0x2206, 0xA080}, + {0x2206, 0x02AE}, {0x2206, 0xF602}, {0x2206, 0x0153}, {0x2206, 0x0201}, + {0x2206, 0x6602}, {0x2206, 0x80B9}, {0x2206, 0xE08B}, {0x2206, 0x8CE1}, + {0x2206, 0x8B8D}, {0x2206, 0x1E01}, {0x2206, 0xE18B}, {0x2206, 0x8E1E}, + {0x2206, 0x01A0}, {0x2206, 0x00E7}, {0x2206, 0xAEDB}, {0x2206, 0xEEE0}, + {0x2206, 0x120E}, {0x2206, 0xEEE0}, {0x2206, 0x1300}, {0x2206, 0xEEE0}, + {0x2206, 0x2001}, {0x2206, 0xEEE0}, {0x2206, 0x2166}, {0x2206, 0xEEE0}, + {0x2206, 0xC463}, {0x2206, 0xEEE0}, {0x2206, 0xC5E8}, {0x2206, 0xEEE0}, + {0x2206, 0xC699}, {0x2206, 0xEEE0}, {0x2206, 0xC7C2}, {0x2206, 0xEEE0}, + {0x2206, 0xC801}, {0x2206, 0xEEE0}, {0x2206, 0xC913}, {0x2206, 0xEEE0}, + {0x2206, 0xCA30}, {0x2206, 0xEEE0}, {0x2206, 0xCB3E}, {0x2206, 0xEEE0}, + {0x2206, 0xDCE1}, {0x2206, 0xEEE0}, {0x2206, 0xDD00}, {0x2206, 0xEEE2}, + {0x2206, 0x0001}, {0x2206, 0xEEE2}, {0x2206, 0x0100}, {0x2206, 0xEEE4}, + {0x2206, 0x8860}, {0x2206, 0xEEE4}, {0x2206, 0x8902}, {0x2206, 0xEEE4}, + {0x2206, 0x8C00}, {0x2206, 0xEEE4}, {0x2206, 0x8D30}, {0x2206, 0xEEEA}, + {0x2206, 0x1480}, {0x2206, 0xEEEA}, {0x2206, 0x1503}, {0x2206, 0xEEEA}, + {0x2206, 0xC600}, {0x2206, 0xEEEA}, {0x2206, 0xC706}, {0x2206, 0xEE85}, + {0x2206, 0xEE00}, {0x2206, 0xEE85}, {0x2206, 0xEF00}, {0x2206, 0xEE8B}, + {0x2206, 0x6750}, {0x2206, 0xEE8B}, {0x2206, 0x6632}, {0x2206, 0xEE8A}, + {0x2206, 0xD448}, {0x2206, 0xEE8A}, {0x2206, 0xD548}, {0x2206, 0xEE8A}, + {0x2206, 0xD649}, {0x2206, 0xEE8A}, {0x2206, 0xD7F8}, {0x2206, 0xEE8B}, + {0x2206, 0x85E2}, {0x2206, 0xEE8B}, {0x2206, 0x8700}, {0x2206, 0xEEFF}, + {0x2206, 0xF600}, {0x2206, 0xEEFF}, {0x2206, 0xF7FC}, {0x2206, 0x04F8}, + {0x2206, 0xE08B}, {0x2206, 0x8EAD}, {0x2206, 0x2023}, {0x2206, 0xF620}, + {0x2206, 0xE48B}, {0x2206, 0x8E02}, {0x2206, 0x2877}, {0x2206, 0x0225}, + {0x2206, 0xC702}, {0x2206, 0x26A1}, {0x2206, 0x0281}, {0x2206, 0xB302}, + {0x2206, 0x8496}, {0x2206, 0x0202}, {0x2206, 0xA102}, {0x2206, 0x27F1}, + {0x2206, 0x0228}, {0x2206, 0xF902}, {0x2206, 0x2AA0}, {0x2206, 0x0282}, + {0x2206, 0xB8E0}, {0x2206, 0x8B8E}, {0x2206, 0xAD21}, {0x2206, 0x08F6}, + {0x2206, 0x21E4}, {0x2206, 0x8B8E}, {0x2206, 0x0202}, {0x2206, 0x80E0}, + {0x2206, 0x8B8E}, {0x2206, 0xAD22}, {0x2206, 0x05F6}, {0x2206, 0x22E4}, + {0x2206, 0x8B8E}, {0x2206, 0xE08B}, {0x2206, 0x8EAD}, {0x2206, 0x2305}, + {0x2206, 0xF623}, {0x2206, 0xE48B}, {0x2206, 0x8EE0}, {0x2206, 0x8B8E}, + {0x2206, 0xAD24}, {0x2206, 0x08F6}, {0x2206, 0x24E4}, {0x2206, 0x8B8E}, + {0x2206, 0x0227}, {0x2206, 0x6AE0}, {0x2206, 0x8B8E}, {0x2206, 0xAD25}, + {0x2206, 0x05F6}, {0x2206, 0x25E4}, {0x2206, 0x8B8E}, {0x2206, 0xE08B}, + {0x2206, 0x8EAD}, {0x2206, 0x260B}, {0x2206, 0xF626}, {0x2206, 0xE48B}, + {0x2206, 0x8E02}, {0x2206, 0x830D}, {0x2206, 0x021D}, {0x2206, 0x6BE0}, + {0x2206, 0x8B8E}, {0x2206, 0xAD27}, {0x2206, 0x05F6}, {0x2206, 0x27E4}, + {0x2206, 0x8B8E}, {0x2206, 0x0281}, {0x2206, 0x4402}, {0x2206, 0x045C}, + {0x2206, 0xFC04}, {0x2206, 0xF8E0}, {0x2206, 0x8B83}, {0x2206, 0xAD23}, + {0x2206, 0x30E0}, {0x2206, 0xE022}, {0x2206, 0xE1E0}, {0x2206, 0x2359}, + {0x2206, 0x02E0}, {0x2206, 0x85EF}, {0x2206, 0xE585}, {0x2206, 0xEFAC}, + {0x2206, 0x2907}, {0x2206, 0x1F01}, {0x2206, 0x9E51}, {0x2206, 0xAD29}, + {0x2206, 0x20E0}, {0x2206, 0x8B83}, {0x2206, 0xAD21}, {0x2206, 0x06E1}, + {0x2206, 0x8B84}, {0x2206, 0xAD28}, {0x2206, 0x42E0}, {0x2206, 0x8B85}, + {0x2206, 0xAD21}, {0x2206, 0x06E1}, {0x2206, 0x8B84}, {0x2206, 0xAD29}, + {0x2206, 0x36BF}, {0x2206, 0x34BF}, {0x2206, 0x022C}, {0x2206, 0x31AE}, + {0x2206, 0x2EE0}, {0x2206, 0x8B83}, {0x2206, 0xAD21}, {0x2206, 0x10E0}, + {0x2206, 0x8B84}, {0x2206, 0xF620}, {0x2206, 0xE48B}, {0x2206, 0x84EE}, + {0x2206, 0x8ADA}, {0x2206, 0x00EE}, {0x2206, 0x8ADB}, {0x2206, 0x00E0}, + {0x2206, 0x8B85}, {0x2206, 0xAD21}, {0x2206, 0x0CE0}, {0x2206, 0x8B84}, + {0x2206, 0xF621}, {0x2206, 0xE48B}, {0x2206, 0x84EE}, {0x2206, 0x8B72}, + {0x2206, 0xFFBF}, {0x2206, 0x34C2}, {0x2206, 0x022C}, {0x2206, 0x31FC}, + {0x2206, 0x04F8}, {0x2206, 0xFAEF}, {0x2206, 0x69E0}, {0x2206, 0x8B85}, + {0x2206, 0xAD21}, {0x2206, 0x42E0}, {0x2206, 0xE022}, {0x2206, 0xE1E0}, + {0x2206, 0x2358}, {0x2206, 0xC059}, {0x2206, 0x021E}, {0x2206, 0x01E1}, + {0x2206, 0x8B72}, {0x2206, 0x1F10}, {0x2206, 0x9E2F}, {0x2206, 0xE48B}, + {0x2206, 0x72AD}, {0x2206, 0x2123}, {0x2206, 0xE18B}, {0x2206, 0x84F7}, + {0x2206, 0x29E5}, {0x2206, 0x8B84}, {0x2206, 0xAC27}, {0x2206, 0x10AC}, + {0x2206, 0x2605}, {0x2206, 0x0205}, {0x2206, 0x23AE}, {0x2206, 0x1602}, + {0x2206, 0x0535}, {0x2206, 0x0282}, {0x2206, 0x30AE}, {0x2206, 0x0E02}, + {0x2206, 0x056A}, {0x2206, 0x0282}, {0x2206, 0x75AE}, {0x2206, 0x0602}, + {0x2206, 0x04DC}, {0x2206, 0x0282}, {0x2206, 0x04EF}, {0x2206, 0x96FE}, + {0x2206, 0xFC04}, {0x2206, 0xF8F9}, {0x2206, 0xE08B}, {0x2206, 0x87AD}, + {0x2206, 0x2321}, {0x2206, 0xE0EA}, {0x2206, 0x14E1}, {0x2206, 0xEA15}, + {0x2206, 0xAD26}, {0x2206, 0x18F6}, {0x2206, 0x27E4}, {0x2206, 0xEA14}, + {0x2206, 0xE5EA}, {0x2206, 0x15F6}, {0x2206, 0x26E4}, {0x2206, 0xEA14}, + {0x2206, 0xE5EA}, {0x2206, 0x15F7}, {0x2206, 0x27E4}, {0x2206, 0xEA14}, + {0x2206, 0xE5EA}, {0x2206, 0x15FD}, {0x2206, 0xFC04}, {0x2206, 0xF8F9}, + {0x2206, 0xE08B}, {0x2206, 0x87AD}, {0x2206, 0x233A}, {0x2206, 0xAD22}, + {0x2206, 0x37E0}, {0x2206, 0xE020}, {0x2206, 0xE1E0}, {0x2206, 0x21AC}, + {0x2206, 0x212E}, {0x2206, 0xE0EA}, {0x2206, 0x14E1}, {0x2206, 0xEA15}, + {0x2206, 0xF627}, {0x2206, 0xE4EA}, {0x2206, 0x14E5}, {0x2206, 0xEA15}, + {0x2206, 0xE2EA}, {0x2206, 0x12E3}, {0x2206, 0xEA13}, {0x2206, 0x5A8F}, + {0x2206, 0x6A20}, {0x2206, 0xE6EA}, {0x2206, 0x12E7}, {0x2206, 0xEA13}, + {0x2206, 0xF726}, {0x2206, 0xE4EA}, {0x2206, 0x14E5}, {0x2206, 0xEA15}, + {0x2206, 0xF727}, {0x2206, 0xE4EA}, {0x2206, 0x14E5}, {0x2206, 0xEA15}, + {0x2206, 0xFDFC}, {0x2206, 0x04F8}, {0x2206, 0xF9E0}, {0x2206, 0x8B87}, + {0x2206, 0xAD23}, {0x2206, 0x38AD}, {0x2206, 0x2135}, {0x2206, 0xE0E0}, + {0x2206, 0x20E1}, {0x2206, 0xE021}, {0x2206, 0xAC21}, {0x2206, 0x2CE0}, + {0x2206, 0xEA14}, {0x2206, 0xE1EA}, {0x2206, 0x15F6}, {0x2206, 0x27E4}, + {0x2206, 0xEA14}, {0x2206, 0xE5EA}, {0x2206, 0x15E2}, {0x2206, 0xEA12}, + {0x2206, 0xE3EA}, {0x2206, 0x135A}, {0x2206, 0x8FE6}, {0x2206, 0xEA12}, + {0x2206, 0xE7EA}, {0x2206, 0x13F7}, {0x2206, 0x26E4}, {0x2206, 0xEA14}, + {0x2206, 0xE5EA}, {0x2206, 0x15F7}, {0x2206, 0x27E4}, {0x2206, 0xEA14}, + {0x2206, 0xE5EA}, {0x2206, 0x15FD}, {0x2206, 0xFC04}, {0x2206, 0xF8FA}, + {0x2206, 0xEF69}, {0x2206, 0xE08B}, {0x2206, 0x86AD}, {0x2206, 0x2146}, + {0x2206, 0xE0E0}, {0x2206, 0x22E1}, {0x2206, 0xE023}, {0x2206, 0x58C0}, + {0x2206, 0x5902}, {0x2206, 0x1E01}, {0x2206, 0xE18B}, {0x2206, 0x651F}, + {0x2206, 0x109E}, {0x2206, 0x33E4}, {0x2206, 0x8B65}, {0x2206, 0xAD21}, + {0x2206, 0x22AD}, {0x2206, 0x272A}, {0x2206, 0xD400}, {0x2206, 0x01BF}, + {0x2206, 0x34F2}, {0x2206, 0x022C}, {0x2206, 0xA2BF}, {0x2206, 0x34F5}, + {0x2206, 0x022C}, {0x2206, 0xE0E0}, {0x2206, 0x8B67}, {0x2206, 0x1B10}, + {0x2206, 0xAA14}, {0x2206, 0xE18B}, {0x2206, 0x660D}, {0x2206, 0x1459}, + {0x2206, 0x0FAE}, {0x2206, 0x05E1}, {0x2206, 0x8B66}, {0x2206, 0x590F}, + {0x2206, 0xBF85}, {0x2206, 0x6102}, {0x2206, 0x2CA2}, {0x2206, 0xEF96}, + {0x2206, 0xFEFC}, {0x2206, 0x04F8}, {0x2206, 0xF9FA}, {0x2206, 0xFBEF}, + {0x2206, 0x79E2}, {0x2206, 0x8AD2}, {0x2206, 0xAC19}, {0x2206, 0x2DE0}, + {0x2206, 0xE036}, {0x2206, 0xE1E0}, {0x2206, 0x37EF}, {0x2206, 0x311F}, + {0x2206, 0x325B}, {0x2206, 0x019E}, {0x2206, 0x1F7A}, {0x2206, 0x0159}, + {0x2206, 0x019F}, {0x2206, 0x0ABF}, {0x2206, 0x348E}, {0x2206, 0x022C}, + {0x2206, 0x31F6}, {0x2206, 0x06AE}, {0x2206, 0x0FF6}, {0x2206, 0x0302}, + {0x2206, 0x0470}, {0x2206, 0xF703}, {0x2206, 0xF706}, {0x2206, 0xBF34}, + {0x2206, 0x9302}, {0x2206, 0x2C31}, {0x2206, 0xAC1A}, {0x2206, 0x25E0}, + {0x2206, 0xE022}, {0x2206, 0xE1E0}, {0x2206, 0x23EF}, {0x2206, 0x300D}, + {0x2206, 0x311F}, {0x2206, 0x325B}, {0x2206, 0x029E}, {0x2206, 0x157A}, + {0x2206, 0x0258}, {0x2206, 0xC4A0}, {0x2206, 0x0408}, {0x2206, 0xBF34}, + {0x2206, 0x9E02}, {0x2206, 0x2C31}, {0x2206, 0xAE06}, {0x2206, 0xBF34}, + {0x2206, 0x9C02}, {0x2206, 0x2C31}, {0x2206, 0xAC1B}, {0x2206, 0x4AE0}, + {0x2206, 0xE012}, {0x2206, 0xE1E0}, {0x2206, 0x13EF}, {0x2206, 0x300D}, + {0x2206, 0x331F}, {0x2206, 0x325B}, {0x2206, 0x1C9E}, {0x2206, 0x3AEF}, + {0x2206, 0x325B}, {0x2206, 0x1C9F}, {0x2206, 0x09BF}, {0x2206, 0x3498}, + {0x2206, 0x022C}, {0x2206, 0x3102}, {0x2206, 0x83C5}, {0x2206, 0x5A03}, + {0x2206, 0x0D03}, {0x2206, 0x581C}, {0x2206, 0x1E20}, {0x2206, 0x0207}, + {0x2206, 0xA0A0}, {0x2206, 0x000E}, {0x2206, 0x0284}, {0x2206, 0x17AD}, + {0x2206, 0x1817}, {0x2206, 0xBF34}, {0x2206, 0x9A02}, {0x2206, 0x2C31}, + {0x2206, 0xAE0F}, {0x2206, 0xBF34}, {0x2206, 0xC802}, {0x2206, 0x2C31}, + {0x2206, 0xBF34}, {0x2206, 0xC502}, {0x2206, 0x2C31}, {0x2206, 0x0284}, + {0x2206, 0x52E6}, {0x2206, 0x8AD2}, {0x2206, 0xEF97}, {0x2206, 0xFFFE}, + {0x2206, 0xFDFC}, {0x2206, 0x04F8}, {0x2206, 0xBF34}, {0x2206, 0xDA02}, + {0x2206, 0x2CE0}, {0x2206, 0xE58A}, {0x2206, 0xD3BF}, {0x2206, 0x34D4}, + {0x2206, 0x022C}, {0x2206, 0xE00C}, {0x2206, 0x1159}, {0x2206, 0x02E0}, + {0x2206, 0x8AD3}, {0x2206, 0x1E01}, {0x2206, 0xE48A}, {0x2206, 0xD3D1}, + {0x2206, 0x00BF}, {0x2206, 0x34DA}, {0x2206, 0x022C}, {0x2206, 0xA2D1}, + {0x2206, 0x01BF}, {0x2206, 0x34D4}, {0x2206, 0x022C}, {0x2206, 0xA2BF}, + {0x2206, 0x34CB}, {0x2206, 0x022C}, {0x2206, 0xE0E5}, {0x2206, 0x8ACE}, + {0x2206, 0xBF85}, {0x2206, 0x6702}, {0x2206, 0x2CE0}, {0x2206, 0xE58A}, + {0x2206, 0xCFBF}, {0x2206, 0x8564}, {0x2206, 0x022C}, {0x2206, 0xE0E5}, + {0x2206, 0x8AD0}, {0x2206, 0xBF85}, {0x2206, 0x6A02}, {0x2206, 0x2CE0}, + {0x2206, 0xE58A}, {0x2206, 0xD1FC}, {0x2206, 0x04F8}, {0x2206, 0xE18A}, + {0x2206, 0xD1BF}, {0x2206, 0x856A}, {0x2206, 0x022C}, {0x2206, 0xA2E1}, + {0x2206, 0x8AD0}, {0x2206, 0xBF85}, {0x2206, 0x6402}, {0x2206, 0x2CA2}, + {0x2206, 0xE18A}, {0x2206, 0xCFBF}, {0x2206, 0x8567}, {0x2206, 0x022C}, + {0x2206, 0xA2E1}, {0x2206, 0x8ACE}, {0x2206, 0xBF34}, {0x2206, 0xCB02}, + {0x2206, 0x2CA2}, {0x2206, 0xE18A}, {0x2206, 0xD3BF}, {0x2206, 0x34DA}, + {0x2206, 0x022C}, {0x2206, 0xA2E1}, {0x2206, 0x8AD3}, {0x2206, 0x0D11}, + {0x2206, 0xBF34}, {0x2206, 0xD402}, {0x2206, 0x2CA2}, {0x2206, 0xFC04}, + {0x2206, 0xF9A0}, {0x2206, 0x0405}, {0x2206, 0xE38A}, {0x2206, 0xD4AE}, + {0x2206, 0x13A0}, {0x2206, 0x0805}, {0x2206, 0xE38A}, {0x2206, 0xD5AE}, + {0x2206, 0x0BA0}, {0x2206, 0x0C05}, {0x2206, 0xE38A}, {0x2206, 0xD6AE}, + {0x2206, 0x03E3}, {0x2206, 0x8AD7}, {0x2206, 0xEF13}, {0x2206, 0xBF34}, + {0x2206, 0xCB02}, {0x2206, 0x2CA2}, {0x2206, 0xEF13}, {0x2206, 0x0D11}, + {0x2206, 0xBF85}, {0x2206, 0x6702}, {0x2206, 0x2CA2}, {0x2206, 0xEF13}, + {0x2206, 0x0D14}, {0x2206, 0xBF85}, {0x2206, 0x6402}, {0x2206, 0x2CA2}, + {0x2206, 0xEF13}, {0x2206, 0x0D17}, {0x2206, 0xBF85}, {0x2206, 0x6A02}, + {0x2206, 0x2CA2}, {0x2206, 0xFD04}, {0x2206, 0xF8E0}, {0x2206, 0x8B85}, + {0x2206, 0xAD27}, {0x2206, 0x2DE0}, {0x2206, 0xE036}, {0x2206, 0xE1E0}, + {0x2206, 0x37E1}, {0x2206, 0x8B73}, {0x2206, 0x1F10}, {0x2206, 0x9E20}, + {0x2206, 0xE48B}, {0x2206, 0x73AC}, {0x2206, 0x200B}, {0x2206, 0xAC21}, + {0x2206, 0x0DAC}, {0x2206, 0x250F}, {0x2206, 0xAC27}, {0x2206, 0x0EAE}, + {0x2206, 0x0F02}, {0x2206, 0x84CC}, {0x2206, 0xAE0A}, {0x2206, 0x0284}, + {0x2206, 0xD1AE}, {0x2206, 0x05AE}, {0x2206, 0x0302}, {0x2206, 0x84D8}, + {0x2206, 0xFC04}, {0x2206, 0xEE8B}, {0x2206, 0x6800}, {0x2206, 0x0402}, + {0x2206, 0x84E5}, {0x2206, 0x0285}, {0x2206, 0x2804}, {0x2206, 0x0285}, + {0x2206, 0x4904}, {0x2206, 0xEE8B}, {0x2206, 0x6800}, {0x2206, 0xEE8B}, + {0x2206, 0x6902}, {0x2206, 0x04F8}, {0x2206, 0xF9E0}, {0x2206, 0x8B85}, + {0x2206, 0xAD26}, {0x2206, 0x38D0}, {0x2206, 0x0B02}, {0x2206, 0x2B4D}, + {0x2206, 0x5882}, {0x2206, 0x7882}, {0x2206, 0x9F2D}, {0x2206, 0xE08B}, + {0x2206, 0x68E1}, {0x2206, 0x8B69}, {0x2206, 0x1F10}, {0x2206, 0x9EC8}, + {0x2206, 0x10E4}, {0x2206, 0x8B68}, {0x2206, 0xE0E0}, {0x2206, 0x00E1}, + {0x2206, 0xE001}, {0x2206, 0xF727}, {0x2206, 0xE4E0}, {0x2206, 0x00E5}, + {0x2206, 0xE001}, {0x2206, 0xE2E0}, {0x2206, 0x20E3}, {0x2206, 0xE021}, + {0x2206, 0xAD30}, {0x2206, 0xF7F6}, {0x2206, 0x27E4}, {0x2206, 0xE000}, + {0x2206, 0xE5E0}, {0x2206, 0x01FD}, {0x2206, 0xFC04}, {0x2206, 0xF8FA}, + {0x2206, 0xEF69}, {0x2206, 0xE08B}, {0x2206, 0x86AD}, {0x2206, 0x2212}, + {0x2206, 0xE0E0}, {0x2206, 0x14E1}, {0x2206, 0xE015}, {0x2206, 0xAD26}, + {0x2206, 0x9CE1}, {0x2206, 0x85E0}, {0x2206, 0xBF85}, {0x2206, 0x6D02}, + {0x2206, 0x2CA2}, {0x2206, 0xEF96}, {0x2206, 0xFEFC}, {0x2206, 0x04F8}, + {0x2206, 0xFAEF}, {0x2206, 0x69E0}, {0x2206, 0x8B86}, {0x2206, 0xAD22}, + {0x2206, 0x09E1}, {0x2206, 0x85E1}, {0x2206, 0xBF85}, {0x2206, 0x6D02}, + {0x2206, 0x2CA2}, {0x2206, 0xEF96}, {0x2206, 0xFEFC}, {0x2206, 0x0464}, + {0x2206, 0xE48C}, {0x2206, 0xFDE4}, {0x2206, 0x80CA}, {0x2206, 0xE480}, + {0x2206, 0x66E0}, {0x2206, 0x8E70}, {0x2206, 0xE076}, {0x2205, 0xE142}, + {0x2206, 0x0701}, {0x2205, 0xE140}, {0x2206, 0x0405}, {0x220F, 0x0000}, + {0x221F, 0x0000}, {0x2200, 0x1340}, {0x133E, 0x000E}, {0x133F, 0x0010}, + {0x13EB, 0x11BB} +}; + +static const struct rtl8367b_initval rtl8367r_vb_initvals_1[] = { + {0x1B03, 0x0876}, {0x1200, 0x7FC4}, {0x1305, 0xC000}, {0x121E, 0x03CA}, + {0x1233, 0x0352}, {0x1234, 0x0064}, {0x1237, 0x0096}, {0x1238, 0x0078}, + {0x1239, 0x0084}, {0x123A, 0x0030}, {0x205F, 0x0002}, {0x2059, 0x1A00}, + {0x205F, 0x0000}, {0x207F, 0x0002}, {0x2077, 0x0000}, {0x2078, 0x0000}, + {0x2079, 0x0000}, {0x207A, 0x0000}, {0x207B, 0x0000}, {0x207F, 0x0000}, + {0x205F, 0x0002}, {0x2053, 0x0000}, {0x2054, 0x0000}, {0x2055, 0x0000}, + {0x2056, 0x0000}, {0x2057, 0x0000}, {0x205F, 0x0000}, {0x133F, 0x0030}, + {0x133E, 0x000E}, {0x221F, 0x0005}, {0x2205, 0x8B86}, {0x2206, 0x800E}, + {0x221F, 0x0000}, {0x133F, 0x0010}, {0x12A3, 0x2200}, {0x6107, 0xE58B}, + {0x6103, 0xA970}, {0x0018, 0x0F00}, {0x0038, 0x0F00}, {0x0058, 0x0F00}, + {0x0078, 0x0F00}, {0x0098, 0x0F00}, {0x133F, 0x0030}, {0x133E, 0x000E}, + {0x221F, 0x0005}, {0x2205, 0x8B6E}, {0x2206, 0x0000}, {0x220F, 0x0100}, + {0x2205, 0xFFF6}, {0x2206, 0x0080}, {0x2205, 0x8000}, {0x2206, 0x0280}, + {0x2206, 0x2BF7}, {0x2206, 0x00E0}, {0x2206, 0xFFF7}, {0x2206, 0xA080}, + {0x2206, 0x02AE}, {0x2206, 0xF602}, {0x2206, 0x0153}, {0x2206, 0x0201}, + {0x2206, 0x6602}, {0x2206, 0x8044}, {0x2206, 0x0201}, {0x2206, 0x7CE0}, + {0x2206, 0x8B8C}, {0x2206, 0xE18B}, {0x2206, 0x8D1E}, {0x2206, 0x01E1}, + {0x2206, 0x8B8E}, {0x2206, 0x1E01}, {0x2206, 0xA000}, {0x2206, 0xE4AE}, + {0x2206, 0xD8EE}, {0x2206, 0x85C0}, {0x2206, 0x00EE}, {0x2206, 0x85C1}, + {0x2206, 0x00EE}, {0x2206, 0x8AFC}, {0x2206, 0x07EE}, {0x2206, 0x8AFD}, + {0x2206, 0x73EE}, {0x2206, 0xFFF6}, {0x2206, 0x00EE}, {0x2206, 0xFFF7}, + {0x2206, 0xFC04}, {0x2206, 0xF8E0}, {0x2206, 0x8B8E}, {0x2206, 0xAD20}, + {0x2206, 0x0302}, {0x2206, 0x8050}, {0x2206, 0xFC04}, {0x2206, 0xF8F9}, + {0x2206, 0xE08B}, {0x2206, 0x85AD}, {0x2206, 0x2548}, {0x2206, 0xE08A}, + {0x2206, 0xE4E1}, {0x2206, 0x8AE5}, {0x2206, 0x7C00}, {0x2206, 0x009E}, + {0x2206, 0x35EE}, {0x2206, 0x8AE4}, {0x2206, 0x00EE}, {0x2206, 0x8AE5}, + {0x2206, 0x00E0}, {0x2206, 0x8AFC}, {0x2206, 0xE18A}, {0x2206, 0xFDE2}, + {0x2206, 0x85C0}, {0x2206, 0xE385}, {0x2206, 0xC102}, {0x2206, 0x2DAC}, + {0x2206, 0xAD20}, {0x2206, 0x12EE}, {0x2206, 0x8AE4}, {0x2206, 0x03EE}, + {0x2206, 0x8AE5}, {0x2206, 0xB7EE}, {0x2206, 0x85C0}, {0x2206, 0x00EE}, + {0x2206, 0x85C1}, {0x2206, 0x00AE}, {0x2206, 0x1115}, {0x2206, 0xE685}, + {0x2206, 0xC0E7}, {0x2206, 0x85C1}, {0x2206, 0xAE08}, {0x2206, 0xEE85}, + {0x2206, 0xC000}, {0x2206, 0xEE85}, {0x2206, 0xC100}, {0x2206, 0xFDFC}, + {0x2206, 0x0400}, {0x2205, 0xE142}, {0x2206, 0x0701}, {0x2205, 0xE140}, + {0x2206, 0x0405}, {0x220F, 0x0000}, {0x221F, 0x0000}, {0x133E, 0x000E}, + {0x133F, 0x0010}, {0x13EB, 0x11BB}, {0x207F, 0x0002}, {0x2073, 0x1D22}, + {0x207F, 0x0000}, {0x133F, 0x0030}, {0x133E, 0x000E}, {0x2200, 0x1340}, + {0x133E, 0x000E}, {0x133F, 0x0010}, +}; + +static int rtl8367b_write_initvals(struct rtl8366_smi *smi, + const struct rtl8367b_initval *initvals, + int count) +{ + int err; + int i; + + for (i = 0; i < count; i++) + REG_WR(smi, initvals[i].reg, initvals[i].val); + + return 0; +} + +static int rtl8367b_read_phy_reg(struct rtl8366_smi *smi, + u32 phy_addr, u32 phy_reg, u32 *val) +{ + int timeout; + u32 data; + int err; + + if (phy_addr > RTL8367B_PHY_ADDR_MAX) + return -EINVAL; + + if (phy_reg > RTL8367B_PHY_REG_MAX) + return -EINVAL; + + REG_RD(smi, RTL8367B_IA_STATUS_REG, &data); + if (data & RTL8367B_IA_STATUS_PHY_BUSY) + return -ETIMEDOUT; + + /* prepare address */ + REG_WR(smi, RTL8367B_IA_ADDRESS_REG, + RTL8367B_INTERNAL_PHY_REG(phy_addr, phy_reg)); + + /* send read command */ + REG_WR(smi, RTL8367B_IA_CTRL_REG, + RTL8367B_IA_CTRL_CMD_MASK | RTL8367B_IA_CTRL_RW_READ); + + timeout = 5; + do { + REG_RD(smi, RTL8367B_IA_STATUS_REG, &data); + if ((data & RTL8367B_IA_STATUS_PHY_BUSY) == 0) + break; + + if (timeout--) { + dev_err(smi->parent, "phy read timed out\n"); + return -ETIMEDOUT; + } + + udelay(1); + } while (1); + + /* read data */ + REG_RD(smi, RTL8367B_IA_READ_DATA_REG, val); + + dev_dbg(smi->parent, "phy_read: addr:%02x, reg:%02x, val:%04x\n", + phy_addr, phy_reg, *val); + return 0; +} + +static int rtl8367b_write_phy_reg(struct rtl8366_smi *smi, + u32 phy_addr, u32 phy_reg, u32 val) +{ + int timeout; + u32 data; + int err; + + dev_dbg(smi->parent, "phy_write: addr:%02x, reg:%02x, val:%04x\n", + phy_addr, phy_reg, val); + + if (phy_addr > RTL8367B_PHY_ADDR_MAX) + return -EINVAL; + + if (phy_reg > RTL8367B_PHY_REG_MAX) + return -EINVAL; + + REG_RD(smi, RTL8367B_IA_STATUS_REG, &data); + if (data & RTL8367B_IA_STATUS_PHY_BUSY) + return -ETIMEDOUT; + + /* preapre data */ + REG_WR(smi, RTL8367B_IA_WRITE_DATA_REG, val); + + /* prepare address */ + REG_WR(smi, RTL8367B_IA_ADDRESS_REG, + RTL8367B_INTERNAL_PHY_REG(phy_addr, phy_reg)); + + /* send write command */ + REG_WR(smi, RTL8367B_IA_CTRL_REG, + RTL8367B_IA_CTRL_CMD_MASK | RTL8367B_IA_CTRL_RW_WRITE); + + timeout = 5; + do { + REG_RD(smi, RTL8367B_IA_STATUS_REG, &data); + if ((data & RTL8367B_IA_STATUS_PHY_BUSY) == 0) + break; + + if (timeout--) { + dev_err(smi->parent, "phy write timed out\n"); + return -ETIMEDOUT; + } + + udelay(1); + } while (1); + + return 0; +} + +static int rtl8367b_init_regs(struct rtl8366_smi *smi) +{ + const struct rtl8367b_initval *initvals; + u32 chip_ver; + u32 rlvid; + int count; + int err; + + REG_WR(smi, RTL8367B_RTL_MAGIC_ID_REG, RTL8367B_RTL_MAGIC_ID_VAL); + REG_RD(smi, RTL8367B_CHIP_VER_REG, &chip_ver); + + rlvid = (chip_ver >> RTL8367B_CHIP_VER_RLVID_SHIFT) & + RTL8367B_CHIP_VER_RLVID_MASK; + + switch (rlvid) { + case 0: + initvals = rtl8367r_vb_initvals_0; + count = ARRAY_SIZE(rtl8367r_vb_initvals_0); + break; + + case 1: + initvals = rtl8367r_vb_initvals_1; + count = ARRAY_SIZE(rtl8367r_vb_initvals_1); + break; + + default: + dev_err(smi->parent, "unknow rlvid %u\n", rlvid); + return -ENODEV; + } + + /* TODO: disable RLTP */ + + return rtl8367b_write_initvals(smi, initvals, count); +} + +static int rtl8367b_reset_chip(struct rtl8366_smi *smi) +{ + int timeout = 10; + int err; + u32 data; + + REG_WR(smi, RTL8367B_CHIP_RESET_REG, RTL8367B_CHIP_RESET_HW); + msleep(RTL8367B_RESET_DELAY); + + do { + REG_RD(smi, RTL8367B_CHIP_RESET_REG, &data); + if (!(data & RTL8367B_CHIP_RESET_HW)) + break; + + msleep(1); + } while (--timeout); + + if (!timeout) { + dev_err(smi->parent, "chip reset timed out\n"); + return -ETIMEDOUT; + } + + return 0; +} + +static int rtl8367b_extif_set_mode(struct rtl8366_smi *smi, int id, + enum rtl8367_extif_mode mode) +{ + int err; + + /* set port mode */ + switch (mode) { + case RTL8367_EXTIF_MODE_RGMII: + case RTL8367_EXTIF_MODE_RGMII_33V: + REG_WR(smi, RTL8367B_CHIP_DEBUG0_REG, 0x0367); + REG_WR(smi, RTL8367B_CHIP_DEBUG1_REG, 0x7777); + break; + + case RTL8367_EXTIF_MODE_TMII_MAC: + case RTL8367_EXTIF_MODE_TMII_PHY: + REG_RMW(smi, RTL8367B_BYPASS_LINE_RATE_REG, + BIT((id + 1) % 2), BIT((id + 1) % 2)); + break; + + case RTL8367_EXTIF_MODE_GMII: + REG_RMW(smi, RTL8367B_CHIP_DEBUG0_REG, + RTL8367B_CHIP_DEBUG0_DUMMY0(id), + RTL8367B_CHIP_DEBUG0_DUMMY0(id)); + REG_RMW(smi, RTL8367B_EXT_RGMXF_REG(id), BIT(6), BIT(6)); + break; + + case RTL8367_EXTIF_MODE_MII_MAC: + case RTL8367_EXTIF_MODE_MII_PHY: + case RTL8367_EXTIF_MODE_DISABLED: + REG_RMW(smi, RTL8367B_BYPASS_LINE_RATE_REG, + BIT((id + 1) % 2), 0); + REG_RMW(smi, RTL8367B_EXT_RGMXF_REG(id), BIT(6), 0); + break; + + default: + dev_err(smi->parent, + "invalid mode for external interface %d\n", id); + return -EINVAL; + } + + REG_RMW(smi, RTL8367B_DIS_REG, + RTL8367B_DIS_RGMII_MASK << RTL8367B_DIS_RGMII_SHIFT(id), + mode << RTL8367B_DIS_RGMII_SHIFT(id)); + + return 0; +} + +static int rtl8367b_extif_set_force(struct rtl8366_smi *smi, int id, + struct rtl8367_port_ability *pa) +{ + u32 mask; + u32 val; + int err; + + mask = (RTL8367B_DI_FORCE_MODE | + RTL8367B_DI_FORCE_NWAY | + RTL8367B_DI_FORCE_TXPAUSE | + RTL8367B_DI_FORCE_RXPAUSE | + RTL8367B_DI_FORCE_LINK | + RTL8367B_DI_FORCE_DUPLEX | + RTL8367B_DI_FORCE_SPEED_MASK); + + val = pa->speed; + val |= pa->force_mode ? RTL8367B_DI_FORCE_MODE : 0; + val |= pa->nway ? RTL8367B_DI_FORCE_NWAY : 0; + val |= pa->txpause ? RTL8367B_DI_FORCE_TXPAUSE : 0; + val |= pa->rxpause ? RTL8367B_DI_FORCE_RXPAUSE : 0; + val |= pa->link ? RTL8367B_DI_FORCE_LINK : 0; + val |= pa->duplex ? RTL8367B_DI_FORCE_DUPLEX : 0; + + REG_RMW(smi, RTL8367B_DI_FORCE_REG(id), mask, val); + + return 0; +} + +static int rtl8367b_extif_set_rgmii_delay(struct rtl8366_smi *smi, int id, + unsigned txdelay, unsigned rxdelay) +{ + u32 mask; + u32 val; + int err; + + mask = (RTL8367B_EXT_RGMXF_RXDELAY_MASK | + (RTL8367B_EXT_RGMXF_TXDELAY_MASK << + RTL8367B_EXT_RGMXF_TXDELAY_SHIFT)); + + val = rxdelay; + val |= txdelay << RTL8367B_EXT_RGMXF_TXDELAY_SHIFT; + + REG_RMW(smi, RTL8367B_EXT_RGMXF_REG(id), mask, val); + + return 0; +} + +static int rtl8367b_extif_init(struct rtl8366_smi *smi, int id, + struct rtl8367_extif_config *cfg) +{ + enum rtl8367_extif_mode mode; + int err; + + mode = (cfg) ? cfg->mode : RTL8367_EXTIF_MODE_DISABLED; + + err = rtl8367b_extif_set_mode(smi, id, mode); + if (err) + return err; + + if (mode != RTL8367_EXTIF_MODE_DISABLED) { + err = rtl8367b_extif_set_force(smi, id, &cfg->ability); + if (err) + return err; + + err = rtl8367b_extif_set_rgmii_delay(smi, id, cfg->txdelay, + cfg->rxdelay); + if (err) + return err; + } + + return 0; +} + +#ifdef CONFIG_OF +static int rtl8367b_extif_init_of(struct rtl8366_smi *smi, int id, + const char *name) +{ + struct rtl8367_extif_config *cfg; + const __be32 *prop; + int size; + int err; + + prop = of_get_property(smi->parent->of_node, name, &size); + if (!prop) + return rtl8367b_extif_init(smi, id, NULL); + + if (size != (9 * sizeof(*prop))) { + dev_err(smi->parent, "%s property is invalid\n", name); + return -EINVAL; + } + + cfg = kzalloc(sizeof(struct rtl8367_extif_config), GFP_KERNEL); + if (!cfg) + return -ENOMEM; + + cfg->txdelay = be32_to_cpup(prop++); + cfg->rxdelay = be32_to_cpup(prop++); + cfg->mode = be32_to_cpup(prop++); + cfg->ability.force_mode = be32_to_cpup(prop++); + cfg->ability.txpause = be32_to_cpup(prop++); + cfg->ability.rxpause = be32_to_cpup(prop++); + cfg->ability.link = be32_to_cpup(prop++); + cfg->ability.duplex = be32_to_cpup(prop++); + cfg->ability.speed = be32_to_cpup(prop++); + + err = rtl8367b_extif_init(smi, id, cfg); + kfree(cfg); + + return err; +} +#else +static int rtl8367b_extif_init_of(struct rtl8366_smi *smi, int id, + const char *name) +{ + return -EINVAL; +} +#endif + +static int rtl8367b_setup(struct rtl8366_smi *smi) +{ + struct rtl8367_platform_data *pdata; + int err; + int i; + + pdata = smi->parent->platform_data; + + err = rtl8367b_init_regs(smi); + if (err) + return err; + + /* initialize external interfaces */ + if (smi->parent->of_node) { + err = rtl8367b_extif_init_of(smi, 0, "realtek,extif0"); + if (err) + return err; + + err = rtl8367b_extif_init_of(smi, 1, "realtek,extif1"); + if (err) + return err; + } else { + err = rtl8367b_extif_init(smi, 0, pdata->extif0_cfg); + if (err) + return err; + + err = rtl8367b_extif_init(smi, 1, pdata->extif1_cfg); + if (err) + return err; + } + + /* set maximum packet length to 1536 bytes */ + REG_RMW(smi, RTL8367B_SWC0_REG, RTL8367B_SWC0_MAX_LENGTH_MASK, + RTL8367B_SWC0_MAX_LENGTH_1536); + + /* + * discard VLAN tagged packets if the port is not a member of + * the VLAN with which the packets is associated. + */ + REG_WR(smi, RTL8367B_VLAN_INGRESS_REG, RTL8367B_PORTS_ALL); + + /* + * Setup egress tag mode for each port. + */ + for (i = 0; i < RTL8367B_NUM_PORTS; i++) + REG_RMW(smi, + RTL8367B_PORT_MISC_CFG_REG(i), + RTL8367B_PORT_MISC_CFG_EGRESS_MODE_MASK << + RTL8367B_PORT_MISC_CFG_EGRESS_MODE_SHIFT, + RTL8367B_PORT_MISC_CFG_EGRESS_MODE_ORIGINAL << + RTL8367B_PORT_MISC_CFG_EGRESS_MODE_SHIFT); + + return 0; +} + +static int rtl8367b_get_mib_counter(struct rtl8366_smi *smi, int counter, + int port, unsigned long long *val) +{ + struct rtl8366_mib_counter *mib; + int offset; + int i; + int err; + u32 addr, data; + u64 mibvalue; + + if (port > RTL8367B_NUM_PORTS || + counter >= RTL8367B_NUM_MIB_COUNTERS) + return -EINVAL; + + mib = &rtl8367b_mib_counters[counter]; + addr = RTL8367B_MIB_COUNTER_PORT_OFFSET * port + mib->offset; + + /* + * Writing access counter address first + * then ASIC will prepare 64bits counter wait for being retrived + */ + REG_WR(smi, RTL8367B_MIB_ADDRESS_REG, addr >> 2); + + /* read MIB control register */ + REG_RD(smi, RTL8367B_MIB_CTRL0_REG(0), &data); + + if (data & RTL8367B_MIB_CTRL0_BUSY_MASK) + return -EBUSY; + + if (data & RTL8367B_MIB_CTRL0_RESET_MASK) + return -EIO; + + if (mib->length == 4) + offset = 3; + else + offset = (mib->offset + 1) % 4; + + mibvalue = 0; + for (i = 0; i < mib->length; i++) { + REG_RD(smi, RTL8367B_MIB_COUNTER_REG(offset - i), &data); + mibvalue = (mibvalue << 16) | (data & 0xFFFF); + } + + *val = mibvalue; + return 0; +} + +static int rtl8367b_get_vlan_4k(struct rtl8366_smi *smi, u32 vid, + struct rtl8366_vlan_4k *vlan4k) +{ + u32 data[RTL8367B_TA_VLAN_NUM_WORDS]; + int err; + int i; + + memset(vlan4k, '\0', sizeof(struct rtl8366_vlan_4k)); + + if (vid >= RTL8367B_NUM_VIDS) + return -EINVAL; + + /* write VID */ + REG_WR(smi, RTL8367B_TA_ADDR_REG, vid); + + /* write table access control word */ + REG_WR(smi, RTL8367B_TA_CTRL_REG, RTL8367B_TA_CTRL_CVLAN_READ); + + for (i = 0; i < ARRAY_SIZE(data); i++) + REG_RD(smi, RTL8367B_TA_RDDATA_REG(i), &data[i]); + + vlan4k->vid = vid; + vlan4k->member = (data[0] >> RTL8367B_TA_VLAN0_MEMBER_SHIFT) & + RTL8367B_TA_VLAN0_MEMBER_MASK; + vlan4k->untag = (data[0] >> RTL8367B_TA_VLAN0_UNTAG_SHIFT) & + RTL8367B_TA_VLAN0_UNTAG_MASK; + vlan4k->fid = (data[1] >> RTL8367B_TA_VLAN1_FID_SHIFT) & + RTL8367B_TA_VLAN1_FID_MASK; + + return 0; +} + +static int rtl8367b_set_vlan_4k(struct rtl8366_smi *smi, + const struct rtl8366_vlan_4k *vlan4k) +{ + u32 data[RTL8367B_TA_VLAN_NUM_WORDS]; + int err; + int i; + + if (vlan4k->vid >= RTL8367B_NUM_VIDS || + vlan4k->member > RTL8367B_TA_VLAN0_MEMBER_MASK || + vlan4k->untag > RTL8367B_UNTAG_MASK || + vlan4k->fid > RTL8367B_FIDMAX) + return -EINVAL; + + memset(data, 0, sizeof(data)); + + data[0] = (vlan4k->member & RTL8367B_TA_VLAN0_MEMBER_MASK) << + RTL8367B_TA_VLAN0_MEMBER_SHIFT; + data[0] |= (vlan4k->untag & RTL8367B_TA_VLAN0_UNTAG_MASK) << + RTL8367B_TA_VLAN0_UNTAG_SHIFT; + data[1] = (vlan4k->fid & RTL8367B_TA_VLAN1_FID_MASK) << + RTL8367B_TA_VLAN1_FID_SHIFT; + + for (i = 0; i < ARRAY_SIZE(data); i++) + REG_WR(smi, RTL8367B_TA_WRDATA_REG(i), data[i]); + + /* write VID */ + REG_WR(smi, RTL8367B_TA_ADDR_REG, + vlan4k->vid & RTL8367B_TA_VLAN_VID_MASK); + + /* write table access control word */ + REG_WR(smi, RTL8367B_TA_CTRL_REG, RTL8367B_TA_CTRL_CVLAN_WRITE); + + return 0; +} + +static int rtl8367b_get_vlan_mc(struct rtl8366_smi *smi, u32 index, + struct rtl8366_vlan_mc *vlanmc) +{ + u32 data[RTL8367B_VLAN_MC_NUM_WORDS]; + int err; + int i; + + memset(vlanmc, '\0', sizeof(struct rtl8366_vlan_mc)); + + if (index >= RTL8367B_NUM_VLANS) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(data); i++) + REG_RD(smi, RTL8367B_VLAN_MC_BASE(index) + i, &data[i]); + + vlanmc->member = (data[0] >> RTL8367B_VLAN_MC0_MEMBER_SHIFT) & + RTL8367B_VLAN_MC0_MEMBER_MASK; + vlanmc->fid = (data[1] >> RTL8367B_VLAN_MC1_FID_SHIFT) & + RTL8367B_VLAN_MC1_FID_MASK; + vlanmc->vid = (data[3] >> RTL8367B_VLAN_MC3_EVID_SHIFT) & + RTL8367B_VLAN_MC3_EVID_MASK; + + return 0; +} + +static int rtl8367b_set_vlan_mc(struct rtl8366_smi *smi, u32 index, + const struct rtl8366_vlan_mc *vlanmc) +{ + u32 data[RTL8367B_VLAN_MC_NUM_WORDS]; + int err; + int i; + + if (index >= RTL8367B_NUM_VLANS || + vlanmc->vid >= RTL8367B_NUM_VIDS || + vlanmc->priority > RTL8367B_PRIORITYMAX || + vlanmc->member > RTL8367B_VLAN_MC0_MEMBER_MASK || + vlanmc->untag > RTL8367B_UNTAG_MASK || + vlanmc->fid > RTL8367B_FIDMAX) + return -EINVAL; + + data[0] = (vlanmc->member & RTL8367B_VLAN_MC0_MEMBER_MASK) << + RTL8367B_VLAN_MC0_MEMBER_SHIFT; + data[1] = (vlanmc->fid & RTL8367B_VLAN_MC1_FID_MASK) << + RTL8367B_VLAN_MC1_FID_SHIFT; + data[2] = 0; + data[3] = (vlanmc->vid & RTL8367B_VLAN_MC3_EVID_MASK) << + RTL8367B_VLAN_MC3_EVID_SHIFT; + + for (i = 0; i < ARRAY_SIZE(data); i++) + REG_WR(smi, RTL8367B_VLAN_MC_BASE(index) + i, data[i]); + + return 0; +} + +static int rtl8367b_get_mc_index(struct rtl8366_smi *smi, int port, int *val) +{ + u32 data; + int err; + + if (port >= RTL8367B_NUM_PORTS) + return -EINVAL; + + REG_RD(smi, RTL8367B_VLAN_PVID_CTRL_REG(port), &data); + + *val = (data >> RTL8367B_VLAN_PVID_CTRL_SHIFT(port)) & + RTL8367B_VLAN_PVID_CTRL_MASK; + + return 0; +} + +static int rtl8367b_set_mc_index(struct rtl8366_smi *smi, int port, int index) +{ + if (port >= RTL8367B_NUM_PORTS || index >= RTL8367B_NUM_VLANS) + return -EINVAL; + + return rtl8366_smi_rmwr(smi, RTL8367B_VLAN_PVID_CTRL_REG(port), + RTL8367B_VLAN_PVID_CTRL_MASK << + RTL8367B_VLAN_PVID_CTRL_SHIFT(port), + (index & RTL8367B_VLAN_PVID_CTRL_MASK) << + RTL8367B_VLAN_PVID_CTRL_SHIFT(port)); +} + +static int rtl8367b_enable_vlan(struct rtl8366_smi *smi, int enable) +{ + return rtl8366_smi_rmwr(smi, RTL8367B_VLAN_CTRL_REG, + RTL8367B_VLAN_CTRL_ENABLE, + (enable) ? RTL8367B_VLAN_CTRL_ENABLE : 0); +} + +static int rtl8367b_enable_vlan4k(struct rtl8366_smi *smi, int enable) +{ + return 0; +} + +static int rtl8367b_is_vlan_valid(struct rtl8366_smi *smi, unsigned vlan) +{ + unsigned max = RTL8367B_NUM_VLANS; + + if (smi->vlan4k_enabled) + max = RTL8367B_NUM_VIDS - 1; + + if (vlan == 0 || vlan >= max) + return 0; + + return 1; +} + +static int rtl8367b_enable_port(struct rtl8366_smi *smi, int port, int enable) +{ + int err; + + REG_WR(smi, RTL8367B_PORT_ISOLATION_REG(port), + (enable) ? RTL8367B_PORTS_ALL : 0); + + return 0; +} + +static int rtl8367b_sw_reset_mibs(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + + return rtl8366_smi_rmwr(smi, RTL8367B_MIB_CTRL0_REG(0), 0, + RTL8367B_MIB_CTRL0_GLOBAL_RESET_MASK); +} + +static int rtl8367b_sw_get_port_link(struct switch_dev *dev, + int port, + struct switch_port_link *link) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data = 0; + u32 speed; + + if (port >= RTL8367B_NUM_PORTS) + return -EINVAL; + + rtl8366_smi_read_reg(smi, RTL8367B_PORT_STATUS_REG(port), &data); + + link->link = !!(data & RTL8367B_PORT_STATUS_LINK); + if (!link->link) + return 0; + + link->duplex = !!(data & RTL8367B_PORT_STATUS_DUPLEX); + link->rx_flow = !!(data & RTL8367B_PORT_STATUS_RXPAUSE); + link->tx_flow = !!(data & RTL8367B_PORT_STATUS_TXPAUSE); + link->aneg = !!(data & RTL8367B_PORT_STATUS_NWAY); + + speed = (data & RTL8367B_PORT_STATUS_SPEED_MASK); + switch (speed) { + case 0: + link->speed = SWITCH_PORT_SPEED_10; + break; + case 1: + link->speed = SWITCH_PORT_SPEED_100; + break; + case 2: + link->speed = SWITCH_PORT_SPEED_1000; + break; + default: + link->speed = SWITCH_PORT_SPEED_UNKNOWN; + break; + } + + return 0; +} + +static int rtl8367b_sw_get_max_length(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + rtl8366_smi_read_reg(smi, RTL8367B_SWC0_REG, &data); + val->value.i = (data & RTL8367B_SWC0_MAX_LENGTH_MASK) >> + RTL8367B_SWC0_MAX_LENGTH_SHIFT; + + return 0; +} + +static int rtl8367b_sw_set_max_length(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 max_len; + + switch (val->value.i) { + case 0: + max_len = RTL8367B_SWC0_MAX_LENGTH_1522; + break; + case 1: + max_len = RTL8367B_SWC0_MAX_LENGTH_1536; + break; + case 2: + max_len = RTL8367B_SWC0_MAX_LENGTH_1552; + break; + case 3: + max_len = RTL8367B_SWC0_MAX_LENGTH_16000; + break; + default: + return -EINVAL; + } + + return rtl8366_smi_rmwr(smi, RTL8367B_SWC0_REG, + RTL8367B_SWC0_MAX_LENGTH_MASK, max_len); +} + + +static int rtl8367b_sw_reset_port_mibs(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + int port; + + port = val->port_vlan; + if (port >= RTL8367B_NUM_PORTS) + return -EINVAL; + + return rtl8366_smi_rmwr(smi, RTL8367B_MIB_CTRL0_REG(port / 8), 0, + RTL8367B_MIB_CTRL0_PORT_RESET_MASK(port % 8)); +} + +static struct switch_attr rtl8367b_globals[] = { + { + .type = SWITCH_TYPE_INT, + .name = "enable_vlan", + .description = "Enable VLAN mode", + .set = rtl8366_sw_set_vlan_enable, + .get = rtl8366_sw_get_vlan_enable, + .max = 1, + .ofs = 1 + }, { + .type = SWITCH_TYPE_INT, + .name = "enable_vlan4k", + .description = "Enable VLAN 4K mode", + .set = rtl8366_sw_set_vlan_enable, + .get = rtl8366_sw_get_vlan_enable, + .max = 1, + .ofs = 2 + }, { + .type = SWITCH_TYPE_NOVAL, + .name = "reset_mibs", + .description = "Reset all MIB counters", + .set = rtl8367b_sw_reset_mibs, + }, { + .type = SWITCH_TYPE_INT, + .name = "max_length", + .description = "Get/Set the maximum length of valid packets" + "(0:1522, 1:1536, 2:1552, 3:16000)", + .set = rtl8367b_sw_set_max_length, + .get = rtl8367b_sw_get_max_length, + .max = 3, + } +}; + +static struct switch_attr rtl8367b_port[] = { + { + .type = SWITCH_TYPE_NOVAL, + .name = "reset_mib", + .description = "Reset single port MIB counters", + .set = rtl8367b_sw_reset_port_mibs, + }, { + .type = SWITCH_TYPE_STRING, + .name = "mib", + .description = "Get MIB counters for port", + .max = 33, + .set = NULL, + .get = rtl8366_sw_get_port_mib, + }, +}; + +static struct switch_attr rtl8367b_vlan[] = { + { + .type = SWITCH_TYPE_STRING, + .name = "info", + .description = "Get vlan information", + .max = 1, + .set = NULL, + .get = rtl8366_sw_get_vlan_info, + }, +}; + +static const struct switch_dev_ops rtl8367b_sw_ops = { + .attr_global = { + .attr = rtl8367b_globals, + .n_attr = ARRAY_SIZE(rtl8367b_globals), + }, + .attr_port = { + .attr = rtl8367b_port, + .n_attr = ARRAY_SIZE(rtl8367b_port), + }, + .attr_vlan = { + .attr = rtl8367b_vlan, + .n_attr = ARRAY_SIZE(rtl8367b_vlan), + }, + + .get_vlan_ports = rtl8366_sw_get_vlan_ports, + .set_vlan_ports = rtl8366_sw_set_vlan_ports, + .get_port_pvid = rtl8366_sw_get_port_pvid, + .set_port_pvid = rtl8366_sw_set_port_pvid, + .reset_switch = rtl8366_sw_reset_switch, + .get_port_link = rtl8367b_sw_get_port_link, +}; + +static int rtl8367b_switch_init(struct rtl8366_smi *smi) +{ + struct switch_dev *dev = &smi->sw_dev; + int err; + + dev->name = "RTL8367B"; + dev->cpu_port = RTL8367B_CPU_PORT_NUM; + dev->ports = RTL8367B_NUM_PORTS; + dev->vlans = RTL8367B_NUM_VIDS; + dev->ops = &rtl8367b_sw_ops; + dev->alias = dev_name(smi->parent); + + err = register_switch(dev, NULL); + if (err) + dev_err(smi->parent, "switch registration failed\n"); + + return err; +} + +static void rtl8367b_switch_cleanup(struct rtl8366_smi *smi) +{ + unregister_switch(&smi->sw_dev); +} + +static int rtl8367b_mii_read(struct mii_bus *bus, int addr, int reg) +{ + struct rtl8366_smi *smi = bus->priv; + u32 val = 0; + int err; + + err = rtl8367b_read_phy_reg(smi, addr, reg, &val); + if (err) + return 0xffff; + + return val; +} + +static int rtl8367b_mii_write(struct mii_bus *bus, int addr, int reg, u16 val) +{ + struct rtl8366_smi *smi = bus->priv; + u32 t; + int err; + + err = rtl8367b_write_phy_reg(smi, addr, reg, val); + if (err) + return err; + + /* flush write */ + (void) rtl8367b_read_phy_reg(smi, addr, reg, &t); + + return err; +} + +static int rtl8367b_detect(struct rtl8366_smi *smi) +{ + const char *chip_name; + u32 chip_num; + u32 chip_ver; + u32 chip_mode; + int ret; + + /* TODO: improve chip detection */ + rtl8366_smi_write_reg(smi, RTL8367B_RTL_MAGIC_ID_REG, + RTL8367B_RTL_MAGIC_ID_VAL); + + ret = rtl8366_smi_read_reg(smi, RTL8367B_CHIP_NUMBER_REG, &chip_num); + if (ret) { + dev_err(smi->parent, "unable to read %s register\n", + "chip number"); + return ret; + } + + ret = rtl8366_smi_read_reg(smi, RTL8367B_CHIP_VER_REG, &chip_ver); + if (ret) { + dev_err(smi->parent, "unable to read %s register\n", + "chip version"); + return ret; + } + + ret = rtl8366_smi_read_reg(smi, RTL8367B_CHIP_MODE_REG, &chip_mode); + if (ret) { + dev_err(smi->parent, "unable to read %s register\n", + "chip mode"); + return ret; + } + + switch (chip_ver) { + case 0x1000: + chip_name = "8367RB"; + break; + case 0x1010: + chip_name = "8367R-VB"; + break; + default: + dev_err(smi->parent, + "unknown chip num:%04x ver:%04x, mode:%04x\n", + chip_num, chip_ver, chip_mode); + return -ENODEV; + } + + dev_info(smi->parent, "RTL%s chip found\n", chip_name); + + return 0; +} + +static struct rtl8366_smi_ops rtl8367b_smi_ops = { + .detect = rtl8367b_detect, + .reset_chip = rtl8367b_reset_chip, + .setup = rtl8367b_setup, + + .mii_read = rtl8367b_mii_read, + .mii_write = rtl8367b_mii_write, + + .get_vlan_mc = rtl8367b_get_vlan_mc, + .set_vlan_mc = rtl8367b_set_vlan_mc, + .get_vlan_4k = rtl8367b_get_vlan_4k, + .set_vlan_4k = rtl8367b_set_vlan_4k, + .get_mc_index = rtl8367b_get_mc_index, + .set_mc_index = rtl8367b_set_mc_index, + .get_mib_counter = rtl8367b_get_mib_counter, + .is_vlan_valid = rtl8367b_is_vlan_valid, + .enable_vlan = rtl8367b_enable_vlan, + .enable_vlan4k = rtl8367b_enable_vlan4k, + .enable_port = rtl8367b_enable_port, +}; + +static int rtl8367b_probe(struct platform_device *pdev) +{ + struct rtl8366_smi *smi; + int err; + + smi = rtl8366_smi_probe(pdev); + if (!smi) + return -ENODEV; + + smi->clk_delay = 1500; + smi->cmd_read = 0xb9; + smi->cmd_write = 0xb8; + smi->ops = &rtl8367b_smi_ops; + smi->cpu_port = RTL8367B_CPU_PORT_NUM; + smi->num_ports = RTL8367B_NUM_PORTS; + smi->num_vlan_mc = RTL8367B_NUM_VLANS; + smi->mib_counters = rtl8367b_mib_counters; + smi->num_mib_counters = ARRAY_SIZE(rtl8367b_mib_counters); + + err = rtl8366_smi_init(smi); + if (err) + goto err_free_smi; + + platform_set_drvdata(pdev, smi); + + err = rtl8367b_switch_init(smi); + if (err) + goto err_clear_drvdata; + + return 0; + + err_clear_drvdata: + platform_set_drvdata(pdev, NULL); + rtl8366_smi_cleanup(smi); + err_free_smi: + kfree(smi); + return err; +} + +static int rtl8367b_remove(struct platform_device *pdev) +{ + struct rtl8366_smi *smi = platform_get_drvdata(pdev); + + if (smi) { + rtl8367b_switch_cleanup(smi); + platform_set_drvdata(pdev, NULL); + rtl8366_smi_cleanup(smi); + kfree(smi); + } + + return 0; +} + +static void rtl8367b_shutdown(struct platform_device *pdev) +{ + struct rtl8366_smi *smi = platform_get_drvdata(pdev); + + if (smi) + rtl8367b_reset_chip(smi); +} + +#ifdef CONFIG_OF +static const struct of_device_id rtl8367b_match[] = { + { .compatible = "realtek,rtl8367b" }, + { .compatible = "rtl8367b" }, + {}, +}; +MODULE_DEVICE_TABLE(of, rtl8367b_match); +#endif + +static struct platform_driver rtl8367b_driver = { + .driver = { + .name = RTL8367B_DRIVER_NAME, + .owner = THIS_MODULE, +#ifdef CONFIG_OF + .of_match_table = of_match_ptr(rtl8367b_match), +#endif + }, + .probe = rtl8367b_probe, + .remove = rtl8367b_remove, + .shutdown = rtl8367b_shutdown, +}; + +module_platform_driver(rtl8367b_driver); + +MODULE_DESCRIPTION(RTL8367B_DRIVER_DESC); +MODULE_AUTHOR("Gabor Juhos "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" RTL8367B_DRIVER_NAME); + diff --git a/target/linux/generic/files/drivers/net/phy/swconfig.c b/target/linux/generic/files/drivers/net/phy/swconfig.c new file mode 100644 index 0000000..6bb3be1 --- /dev/null +++ b/target/linux/generic/files/drivers/net/phy/swconfig.c @@ -0,0 +1,1153 @@ +/* + * swconfig.c: Switch configuration API + * + * Copyright (C) 2008 Felix Fietkau + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SWCONFIG_DEVNAME "switch%d" + +#include "swconfig_leds.c" + +MODULE_AUTHOR("Felix Fietkau "); +MODULE_LICENSE("GPL"); + +static int swdev_id; +static struct list_head swdevs; +static DEFINE_SPINLOCK(swdevs_lock); +struct swconfig_callback; + +struct swconfig_callback { + struct sk_buff *msg; + struct genlmsghdr *hdr; + struct genl_info *info; + int cmd; + + /* callback for filling in the message data */ + int (*fill)(struct swconfig_callback *cb, void *arg); + + /* callback for closing the message before sending it */ + int (*close)(struct swconfig_callback *cb, void *arg); + + struct nlattr *nest[4]; + int args[4]; +}; + +/* defaults */ + +static int +swconfig_get_vlan_ports(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + int ret; + if (val->port_vlan >= dev->vlans) + return -EINVAL; + + if (!dev->ops->get_vlan_ports) + return -EOPNOTSUPP; + + ret = dev->ops->get_vlan_ports(dev, val); + return ret; +} + +static int +swconfig_set_vlan_ports(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + struct switch_port *ports = val->value.ports; + const struct switch_dev_ops *ops = dev->ops; + int i; + + if (val->port_vlan >= dev->vlans) + return -EINVAL; + + /* validate ports */ + if (val->len > dev->ports) + return -EINVAL; + + if (!ops->set_vlan_ports) + return -EOPNOTSUPP; + + for (i = 0; i < val->len; i++) { + if (ports[i].id >= dev->ports) + return -EINVAL; + + if (ops->set_port_pvid && + !(ports[i].flags & (1 << SWITCH_PORT_FLAG_TAGGED))) + ops->set_port_pvid(dev, ports[i].id, val->port_vlan); + } + + return ops->set_vlan_ports(dev, val); +} + +static int +swconfig_set_pvid(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + if (val->port_vlan >= dev->ports) + return -EINVAL; + + if (!dev->ops->set_port_pvid) + return -EOPNOTSUPP; + + return dev->ops->set_port_pvid(dev, val->port_vlan, val->value.i); +} + +static int +swconfig_get_pvid(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + if (val->port_vlan >= dev->ports) + return -EINVAL; + + if (!dev->ops->get_port_pvid) + return -EOPNOTSUPP; + + return dev->ops->get_port_pvid(dev, val->port_vlan, &val->value.i); +} + +static const char * +swconfig_speed_str(enum switch_port_speed speed) +{ + switch (speed) { + case SWITCH_PORT_SPEED_10: + return "10baseT"; + case SWITCH_PORT_SPEED_100: + return "100baseT"; + case SWITCH_PORT_SPEED_1000: + return "1000baseT"; + default: + break; + } + + return "unknown"; +} + +static int +swconfig_get_link(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + struct switch_port_link link; + int len; + int ret; + + if (val->port_vlan >= dev->ports) + return -EINVAL; + + if (!dev->ops->get_port_link) + return -EOPNOTSUPP; + + memset(&link, 0, sizeof(link)); + ret = dev->ops->get_port_link(dev, val->port_vlan, &link); + if (ret) + return ret; + + memset(dev->buf, 0, sizeof(dev->buf)); + + if (link.link) + len = snprintf(dev->buf, sizeof(dev->buf), + "port:%d link:up speed:%s %s-duplex %s%s%s%s%s", + val->port_vlan, + swconfig_speed_str(link.speed), + link.duplex ? "full" : "half", + link.tx_flow ? "txflow " : "", + link.rx_flow ? "rxflow " : "", + link.eee & ADVERTISED_100baseT_Full ? "eee100 " : "", + link.eee & ADVERTISED_1000baseT_Full ? "eee1000 " : "", + link.aneg ? "auto" : ""); + else + len = snprintf(dev->buf, sizeof(dev->buf), "port:%d link:down", + val->port_vlan); + + val->value.s = dev->buf; + val->len = len; + + return 0; +} + +static int +swconfig_apply_config(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + /* don't complain if not supported by the switch driver */ + if (!dev->ops->apply_config) + return 0; + + return dev->ops->apply_config(dev); +} + +static int +swconfig_reset_switch(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + /* don't complain if not supported by the switch driver */ + if (!dev->ops->reset_switch) + return 0; + + return dev->ops->reset_switch(dev); +} + +enum global_defaults { + GLOBAL_APPLY, + GLOBAL_RESET, +}; + +enum vlan_defaults { + VLAN_PORTS, +}; + +enum port_defaults { + PORT_PVID, + PORT_LINK, +}; + +static struct switch_attr default_global[] = { + [GLOBAL_APPLY] = { + .type = SWITCH_TYPE_NOVAL, + .name = "apply", + .description = "Activate changes in the hardware", + .set = swconfig_apply_config, + }, + [GLOBAL_RESET] = { + .type = SWITCH_TYPE_NOVAL, + .name = "reset", + .description = "Reset the switch", + .set = swconfig_reset_switch, + } +}; + +static struct switch_attr default_port[] = { + [PORT_PVID] = { + .type = SWITCH_TYPE_INT, + .name = "pvid", + .description = "Primary VLAN ID", + .set = swconfig_set_pvid, + .get = swconfig_get_pvid, + }, + [PORT_LINK] = { + .type = SWITCH_TYPE_STRING, + .name = "link", + .description = "Get port link information", + .set = NULL, + .get = swconfig_get_link, + } +}; + +static struct switch_attr default_vlan[] = { + [VLAN_PORTS] = { + .type = SWITCH_TYPE_PORTS, + .name = "ports", + .description = "VLAN port mapping", + .set = swconfig_set_vlan_ports, + .get = swconfig_get_vlan_ports, + }, +}; + +static const struct switch_attr * +swconfig_find_attr_by_name(const struct switch_attrlist *alist, + const char *name) +{ + int i; + + for (i = 0; i < alist->n_attr; i++) + if (strcmp(name, alist->attr[i].name) == 0) + return &alist->attr[i]; + + return NULL; +} + +static void swconfig_defaults_init(struct switch_dev *dev) +{ + const struct switch_dev_ops *ops = dev->ops; + + dev->def_global = 0; + dev->def_vlan = 0; + dev->def_port = 0; + + if (ops->get_vlan_ports || ops->set_vlan_ports) + set_bit(VLAN_PORTS, &dev->def_vlan); + + if (ops->get_port_pvid || ops->set_port_pvid) + set_bit(PORT_PVID, &dev->def_port); + + if (ops->get_port_link && + !swconfig_find_attr_by_name(&ops->attr_port, "link")) + set_bit(PORT_LINK, &dev->def_port); + + /* always present, can be no-op */ + set_bit(GLOBAL_APPLY, &dev->def_global); + set_bit(GLOBAL_RESET, &dev->def_global); +} + + +static struct genl_family switch_fam = { + .id = GENL_ID_GENERATE, + .name = "switch", + .hdrsize = 0, + .version = 1, + .maxattr = SWITCH_ATTR_MAX, +}; + +static const struct nla_policy switch_policy[SWITCH_ATTR_MAX+1] = { + [SWITCH_ATTR_ID] = { .type = NLA_U32 }, + [SWITCH_ATTR_OP_ID] = { .type = NLA_U32 }, + [SWITCH_ATTR_OP_PORT] = { .type = NLA_U32 }, + [SWITCH_ATTR_OP_VLAN] = { .type = NLA_U32 }, + [SWITCH_ATTR_OP_VALUE_INT] = { .type = NLA_U32 }, + [SWITCH_ATTR_OP_VALUE_STR] = { .type = NLA_NUL_STRING }, + [SWITCH_ATTR_OP_VALUE_PORTS] = { .type = NLA_NESTED }, + [SWITCH_ATTR_TYPE] = { .type = NLA_U32 }, +}; + +static const struct nla_policy port_policy[SWITCH_PORT_ATTR_MAX+1] = { + [SWITCH_PORT_ID] = { .type = NLA_U32 }, + [SWITCH_PORT_FLAG_TAGGED] = { .type = NLA_FLAG }, +}; + +static inline void +swconfig_lock(void) +{ + spin_lock(&swdevs_lock); +} + +static inline void +swconfig_unlock(void) +{ + spin_unlock(&swdevs_lock); +} + +static struct switch_dev * +swconfig_get_dev(struct genl_info *info) +{ + struct switch_dev *dev = NULL; + struct switch_dev *p; + int id; + + if (!info->attrs[SWITCH_ATTR_ID]) + goto done; + + id = nla_get_u32(info->attrs[SWITCH_ATTR_ID]); + swconfig_lock(); + list_for_each_entry(p, &swdevs, dev_list) { + if (id != p->id) + continue; + + dev = p; + break; + } + if (dev) + mutex_lock(&dev->sw_mutex); + else + pr_debug("device %d not found\n", id); + swconfig_unlock(); +done: + return dev; +} + +static inline void +swconfig_put_dev(struct switch_dev *dev) +{ + mutex_unlock(&dev->sw_mutex); +} + +static int +swconfig_dump_attr(struct swconfig_callback *cb, void *arg) +{ + struct switch_attr *op = arg; + struct genl_info *info = cb->info; + struct sk_buff *msg = cb->msg; + int id = cb->args[0]; + void *hdr; + + hdr = genlmsg_put(msg, info->snd_portid, info->snd_seq, &switch_fam, + NLM_F_MULTI, SWITCH_CMD_NEW_ATTR); + if (IS_ERR(hdr)) + return -1; + + if (nla_put_u32(msg, SWITCH_ATTR_OP_ID, id)) + goto nla_put_failure; + if (nla_put_u32(msg, SWITCH_ATTR_OP_TYPE, op->type)) + goto nla_put_failure; + if (nla_put_string(msg, SWITCH_ATTR_OP_NAME, op->name)) + goto nla_put_failure; + if (op->description) + if (nla_put_string(msg, SWITCH_ATTR_OP_DESCRIPTION, + op->description)) + goto nla_put_failure; + + genlmsg_end(msg, hdr); + return msg->len; +nla_put_failure: + genlmsg_cancel(msg, hdr); + return -EMSGSIZE; +} + +/* spread multipart messages across multiple message buffers */ +static int +swconfig_send_multipart(struct swconfig_callback *cb, void *arg) +{ + struct genl_info *info = cb->info; + int restart = 0; + int err; + + do { + if (!cb->msg) { + cb->msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + if (cb->msg == NULL) + goto error; + } + + if (!(cb->fill(cb, arg) < 0)) + break; + + /* fill failed, check if this was already the second attempt */ + if (restart) + goto error; + + /* try again in a new message, send the current one */ + restart = 1; + if (cb->close) { + if (cb->close(cb, arg) < 0) + goto error; + } + err = genlmsg_reply(cb->msg, info); + cb->msg = NULL; + if (err < 0) + goto error; + + } while (restart); + + return 0; + +error: + if (cb->msg) + nlmsg_free(cb->msg); + return -1; +} + +static int +swconfig_list_attrs(struct sk_buff *skb, struct genl_info *info) +{ + struct genlmsghdr *hdr = nlmsg_data(info->nlhdr); + const struct switch_attrlist *alist; + struct switch_dev *dev; + struct swconfig_callback cb; + int err = -EINVAL; + int i; + + /* defaults */ + struct switch_attr *def_list; + unsigned long *def_active; + int n_def; + + dev = swconfig_get_dev(info); + if (!dev) + return -EINVAL; + + switch (hdr->cmd) { + case SWITCH_CMD_LIST_GLOBAL: + alist = &dev->ops->attr_global; + def_list = default_global; + def_active = &dev->def_global; + n_def = ARRAY_SIZE(default_global); + break; + case SWITCH_CMD_LIST_VLAN: + alist = &dev->ops->attr_vlan; + def_list = default_vlan; + def_active = &dev->def_vlan; + n_def = ARRAY_SIZE(default_vlan); + break; + case SWITCH_CMD_LIST_PORT: + alist = &dev->ops->attr_port; + def_list = default_port; + def_active = &dev->def_port; + n_def = ARRAY_SIZE(default_port); + break; + default: + WARN_ON(1); + goto out; + } + + memset(&cb, 0, sizeof(cb)); + cb.info = info; + cb.fill = swconfig_dump_attr; + for (i = 0; i < alist->n_attr; i++) { + if (alist->attr[i].disabled) + continue; + cb.args[0] = i; + err = swconfig_send_multipart(&cb, (void *) &alist->attr[i]); + if (err < 0) + goto error; + } + + /* defaults */ + for (i = 0; i < n_def; i++) { + if (!test_bit(i, def_active)) + continue; + cb.args[0] = SWITCH_ATTR_DEFAULTS_OFFSET + i; + err = swconfig_send_multipart(&cb, (void *) &def_list[i]); + if (err < 0) + goto error; + } + swconfig_put_dev(dev); + + if (!cb.msg) + return 0; + + return genlmsg_reply(cb.msg, info); + +error: + if (cb.msg) + nlmsg_free(cb.msg); +out: + swconfig_put_dev(dev); + return err; +} + +static const struct switch_attr * +swconfig_lookup_attr(struct switch_dev *dev, struct genl_info *info, + struct switch_val *val) +{ + struct genlmsghdr *hdr = nlmsg_data(info->nlhdr); + const struct switch_attrlist *alist; + const struct switch_attr *attr = NULL; + int attr_id; + + /* defaults */ + struct switch_attr *def_list; + unsigned long *def_active; + int n_def; + + if (!info->attrs[SWITCH_ATTR_OP_ID]) + goto done; + + switch (hdr->cmd) { + case SWITCH_CMD_SET_GLOBAL: + case SWITCH_CMD_GET_GLOBAL: + alist = &dev->ops->attr_global; + def_list = default_global; + def_active = &dev->def_global; + n_def = ARRAY_SIZE(default_global); + break; + case SWITCH_CMD_SET_VLAN: + case SWITCH_CMD_GET_VLAN: + alist = &dev->ops->attr_vlan; + def_list = default_vlan; + def_active = &dev->def_vlan; + n_def = ARRAY_SIZE(default_vlan); + if (!info->attrs[SWITCH_ATTR_OP_VLAN]) + goto done; + val->port_vlan = nla_get_u32(info->attrs[SWITCH_ATTR_OP_VLAN]); + if (val->port_vlan >= dev->vlans) + goto done; + break; + case SWITCH_CMD_SET_PORT: + case SWITCH_CMD_GET_PORT: + alist = &dev->ops->attr_port; + def_list = default_port; + def_active = &dev->def_port; + n_def = ARRAY_SIZE(default_port); + if (!info->attrs[SWITCH_ATTR_OP_PORT]) + goto done; + val->port_vlan = nla_get_u32(info->attrs[SWITCH_ATTR_OP_PORT]); + if (val->port_vlan >= dev->ports) + goto done; + break; + default: + WARN_ON(1); + goto done; + } + + if (!alist) + goto done; + + attr_id = nla_get_u32(info->attrs[SWITCH_ATTR_OP_ID]); + if (attr_id >= SWITCH_ATTR_DEFAULTS_OFFSET) { + attr_id -= SWITCH_ATTR_DEFAULTS_OFFSET; + if (attr_id >= n_def) + goto done; + if (!test_bit(attr_id, def_active)) + goto done; + attr = &def_list[attr_id]; + } else { + if (attr_id >= alist->n_attr) + goto done; + attr = &alist->attr[attr_id]; + } + + if (attr->disabled) + attr = NULL; + +done: + if (!attr) + pr_debug("attribute lookup failed\n"); + val->attr = attr; + return attr; +} + +static int +swconfig_parse_ports(struct sk_buff *msg, struct nlattr *head, + struct switch_val *val, int max) +{ + struct nlattr *nla; + int rem; + + val->len = 0; + nla_for_each_nested(nla, head, rem) { + struct nlattr *tb[SWITCH_PORT_ATTR_MAX+1]; + struct switch_port *port = &val->value.ports[val->len]; + + if (val->len >= max) + return -EINVAL; + + if (nla_parse_nested(tb, SWITCH_PORT_ATTR_MAX, nla, + port_policy)) + return -EINVAL; + + if (!tb[SWITCH_PORT_ID]) + return -EINVAL; + + port->id = nla_get_u32(tb[SWITCH_PORT_ID]); + if (tb[SWITCH_PORT_FLAG_TAGGED]) + port->flags |= (1 << SWITCH_PORT_FLAG_TAGGED); + val->len++; + } + + return 0; +} + +static int +swconfig_set_attr(struct sk_buff *skb, struct genl_info *info) +{ + const struct switch_attr *attr; + struct switch_dev *dev; + struct switch_val val; + int err = -EINVAL; + + dev = swconfig_get_dev(info); + if (!dev) + return -EINVAL; + + memset(&val, 0, sizeof(val)); + attr = swconfig_lookup_attr(dev, info, &val); + if (!attr || !attr->set) + goto error; + + val.attr = attr; + switch (attr->type) { + case SWITCH_TYPE_NOVAL: + break; + case SWITCH_TYPE_INT: + if (!info->attrs[SWITCH_ATTR_OP_VALUE_INT]) + goto error; + val.value.i = + nla_get_u32(info->attrs[SWITCH_ATTR_OP_VALUE_INT]); + break; + case SWITCH_TYPE_STRING: + if (!info->attrs[SWITCH_ATTR_OP_VALUE_STR]) + goto error; + val.value.s = + nla_data(info->attrs[SWITCH_ATTR_OP_VALUE_STR]); + break; + case SWITCH_TYPE_PORTS: + val.value.ports = dev->portbuf; + memset(dev->portbuf, 0, + sizeof(struct switch_port) * dev->ports); + + /* TODO: implement multipart? */ + if (info->attrs[SWITCH_ATTR_OP_VALUE_PORTS]) { + err = swconfig_parse_ports(skb, + info->attrs[SWITCH_ATTR_OP_VALUE_PORTS], + &val, dev->ports); + if (err < 0) + goto error; + } else { + val.len = 0; + err = 0; + } + break; + default: + goto error; + } + + err = attr->set(dev, attr, &val); +error: + swconfig_put_dev(dev); + return err; +} + +static int +swconfig_close_portlist(struct swconfig_callback *cb, void *arg) +{ + if (cb->nest[0]) + nla_nest_end(cb->msg, cb->nest[0]); + return 0; +} + +static int +swconfig_send_port(struct swconfig_callback *cb, void *arg) +{ + const struct switch_port *port = arg; + struct nlattr *p = NULL; + + if (!cb->nest[0]) { + cb->nest[0] = nla_nest_start(cb->msg, cb->cmd); + if (!cb->nest[0]) + return -1; + } + + p = nla_nest_start(cb->msg, SWITCH_ATTR_PORT); + if (!p) + goto error; + + if (nla_put_u32(cb->msg, SWITCH_PORT_ID, port->id)) + goto nla_put_failure; + if (port->flags & (1 << SWITCH_PORT_FLAG_TAGGED)) { + if (nla_put_flag(cb->msg, SWITCH_PORT_FLAG_TAGGED)) + goto nla_put_failure; + } + + nla_nest_end(cb->msg, p); + return 0; + +nla_put_failure: + nla_nest_cancel(cb->msg, p); +error: + nla_nest_cancel(cb->msg, cb->nest[0]); + return -1; +} + +static int +swconfig_send_ports(struct sk_buff **msg, struct genl_info *info, int attr, + const struct switch_val *val) +{ + struct swconfig_callback cb; + int err = 0; + int i; + + if (!val->value.ports) + return -EINVAL; + + memset(&cb, 0, sizeof(cb)); + cb.cmd = attr; + cb.msg = *msg; + cb.info = info; + cb.fill = swconfig_send_port; + cb.close = swconfig_close_portlist; + + cb.nest[0] = nla_nest_start(cb.msg, cb.cmd); + for (i = 0; i < val->len; i++) { + err = swconfig_send_multipart(&cb, &val->value.ports[i]); + if (err) + goto done; + } + err = val->len; + swconfig_close_portlist(&cb, NULL); + *msg = cb.msg; + +done: + return err; +} + +static int +swconfig_get_attr(struct sk_buff *skb, struct genl_info *info) +{ + struct genlmsghdr *hdr = nlmsg_data(info->nlhdr); + const struct switch_attr *attr; + struct switch_dev *dev; + struct sk_buff *msg = NULL; + struct switch_val val; + int err = -EINVAL; + int cmd = hdr->cmd; + + dev = swconfig_get_dev(info); + if (!dev) + return -EINVAL; + + memset(&val, 0, sizeof(val)); + attr = swconfig_lookup_attr(dev, info, &val); + if (!attr || !attr->get) + goto error; + + if (attr->type == SWITCH_TYPE_PORTS) { + val.value.ports = dev->portbuf; + memset(dev->portbuf, 0, + sizeof(struct switch_port) * dev->ports); + } + + err = attr->get(dev, attr, &val); + if (err) + goto error; + + msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + if (!msg) + goto error; + + hdr = genlmsg_put(msg, info->snd_portid, info->snd_seq, &switch_fam, + 0, cmd); + if (IS_ERR(hdr)) + goto nla_put_failure; + + switch (attr->type) { + case SWITCH_TYPE_INT: + if (nla_put_u32(msg, SWITCH_ATTR_OP_VALUE_INT, val.value.i)) + goto nla_put_failure; + break; + case SWITCH_TYPE_STRING: + if (nla_put_string(msg, SWITCH_ATTR_OP_VALUE_STR, val.value.s)) + goto nla_put_failure; + break; + case SWITCH_TYPE_PORTS: + err = swconfig_send_ports(&msg, info, + SWITCH_ATTR_OP_VALUE_PORTS, &val); + if (err < 0) + goto nla_put_failure; + break; + default: + pr_debug("invalid type in attribute\n"); + err = -EINVAL; + goto error; + } + genlmsg_end(msg, hdr); + err = msg->len; + if (err < 0) + goto nla_put_failure; + + swconfig_put_dev(dev); + return genlmsg_reply(msg, info); + +nla_put_failure: + if (msg) + nlmsg_free(msg); +error: + swconfig_put_dev(dev); + if (!err) + err = -ENOMEM; + return err; +} + +static int +swconfig_send_switch(struct sk_buff *msg, u32 pid, u32 seq, int flags, + const struct switch_dev *dev) +{ + struct nlattr *p = NULL, *m = NULL; + void *hdr; + int i; + + hdr = genlmsg_put(msg, pid, seq, &switch_fam, flags, + SWITCH_CMD_NEW_ATTR); + if (IS_ERR(hdr)) + return -1; + + if (nla_put_u32(msg, SWITCH_ATTR_ID, dev->id)) + goto nla_put_failure; + if (nla_put_string(msg, SWITCH_ATTR_DEV_NAME, dev->devname)) + goto nla_put_failure; + if (nla_put_string(msg, SWITCH_ATTR_ALIAS, dev->alias)) + goto nla_put_failure; + if (nla_put_string(msg, SWITCH_ATTR_NAME, dev->name)) + goto nla_put_failure; + if (nla_put_u32(msg, SWITCH_ATTR_VLANS, dev->vlans)) + goto nla_put_failure; + if (nla_put_u32(msg, SWITCH_ATTR_PORTS, dev->ports)) + goto nla_put_failure; + if (nla_put_u32(msg, SWITCH_ATTR_CPU_PORT, dev->cpu_port)) + goto nla_put_failure; + + m = nla_nest_start(msg, SWITCH_ATTR_PORTMAP); + if (!m) + goto nla_put_failure; + for (i = 0; i < dev->ports; i++) { + p = nla_nest_start(msg, SWITCH_ATTR_PORTS); + if (!p) + continue; + if (dev->portmap[i].s) { + if (nla_put_string(msg, SWITCH_PORTMAP_SEGMENT, + dev->portmap[i].s)) + goto nla_put_failure; + if (nla_put_u32(msg, SWITCH_PORTMAP_VIRT, + dev->portmap[i].virt)) + goto nla_put_failure; + } + nla_nest_end(msg, p); + } + nla_nest_end(msg, m); + genlmsg_end(msg, hdr); + return msg->len; +nla_put_failure: + genlmsg_cancel(msg, hdr); + return -EMSGSIZE; +} + +static int swconfig_dump_switches(struct sk_buff *skb, + struct netlink_callback *cb) +{ + struct switch_dev *dev; + int start = cb->args[0]; + int idx = 0; + + swconfig_lock(); + list_for_each_entry(dev, &swdevs, dev_list) { + if (++idx <= start) + continue; + if (swconfig_send_switch(skb, NETLINK_CB(cb->skb).portid, + cb->nlh->nlmsg_seq, NLM_F_MULTI, + dev) < 0) + break; + } + swconfig_unlock(); + cb->args[0] = idx; + + return skb->len; +} + +static int +swconfig_done(struct netlink_callback *cb) +{ + return 0; +} + +static struct genl_ops swconfig_ops[] = { + { + .cmd = SWITCH_CMD_LIST_GLOBAL, + .doit = swconfig_list_attrs, + .policy = switch_policy, + }, + { + .cmd = SWITCH_CMD_LIST_VLAN, + .doit = swconfig_list_attrs, + .policy = switch_policy, + }, + { + .cmd = SWITCH_CMD_LIST_PORT, + .doit = swconfig_list_attrs, + .policy = switch_policy, + }, + { + .cmd = SWITCH_CMD_GET_GLOBAL, + .doit = swconfig_get_attr, + .policy = switch_policy, + }, + { + .cmd = SWITCH_CMD_GET_VLAN, + .doit = swconfig_get_attr, + .policy = switch_policy, + }, + { + .cmd = SWITCH_CMD_GET_PORT, + .doit = swconfig_get_attr, + .policy = switch_policy, + }, + { + .cmd = SWITCH_CMD_SET_GLOBAL, + .doit = swconfig_set_attr, + .policy = switch_policy, + }, + { + .cmd = SWITCH_CMD_SET_VLAN, + .doit = swconfig_set_attr, + .policy = switch_policy, + }, + { + .cmd = SWITCH_CMD_SET_PORT, + .doit = swconfig_set_attr, + .policy = switch_policy, + }, + { + .cmd = SWITCH_CMD_GET_SWITCH, + .dumpit = swconfig_dump_switches, + .policy = switch_policy, + .done = swconfig_done, + } +}; + +#ifdef CONFIG_OF +void +of_switch_load_portmap(struct switch_dev *dev) +{ + struct device_node *port; + + if (!dev->of_node) + return; + + for_each_child_of_node(dev->of_node, port) { + const __be32 *prop; + const char *segment; + int size, phys; + + if (!of_device_is_compatible(port, "swconfig,port")) + continue; + + if (of_property_read_string(port, "swconfig,segment", &segment)) + continue; + + prop = of_get_property(port, "swconfig,portmap", &size); + if (!prop) + continue; + + if (size != (2 * sizeof(*prop))) { + pr_err("%s: failed to parse port mapping\n", + port->name); + continue; + } + + phys = be32_to_cpup(prop++); + if ((phys < 0) | (phys >= dev->ports)) { + pr_err("%s: physical port index out of range\n", + port->name); + continue; + } + + dev->portmap[phys].s = kstrdup(segment, GFP_KERNEL); + dev->portmap[phys].virt = be32_to_cpup(prop); + pr_debug("Found port: %s, physical: %d, virtual: %d\n", + segment, phys, dev->portmap[phys].virt); + } +} +#endif + +int +register_switch(struct switch_dev *dev, struct net_device *netdev) +{ + struct switch_dev *sdev; + const int max_switches = 8 * sizeof(unsigned long); + unsigned long in_use = 0; + int err; + int i; + + INIT_LIST_HEAD(&dev->dev_list); + if (netdev) { + dev->netdev = netdev; + if (!dev->alias) + dev->alias = netdev->name; + } + BUG_ON(!dev->alias); + + if (dev->ports > 0) { + dev->portbuf = kzalloc(sizeof(struct switch_port) * + dev->ports, GFP_KERNEL); + if (!dev->portbuf) + return -ENOMEM; + dev->portmap = kzalloc(sizeof(struct switch_portmap) * + dev->ports, GFP_KERNEL); + if (!dev->portmap) { + kfree(dev->portbuf); + return -ENOMEM; + } + } + swconfig_defaults_init(dev); + mutex_init(&dev->sw_mutex); + swconfig_lock(); + dev->id = ++swdev_id; + + list_for_each_entry(sdev, &swdevs, dev_list) { + if (!sscanf(sdev->devname, SWCONFIG_DEVNAME, &i)) + continue; + if (i < 0 || i > max_switches) + continue; + + set_bit(i, &in_use); + } + i = find_first_zero_bit(&in_use, max_switches); + + if (i == max_switches) { + swconfig_unlock(); + return -ENFILE; + } + +#ifdef CONFIG_OF + if (dev->ports) + of_switch_load_portmap(dev); +#endif + + /* fill device name */ + snprintf(dev->devname, IFNAMSIZ, SWCONFIG_DEVNAME, i); + + list_add_tail(&dev->dev_list, &swdevs); + swconfig_unlock(); + + err = swconfig_create_led_trigger(dev); + if (err) + return err; + + return 0; +} +EXPORT_SYMBOL_GPL(register_switch); + +void +unregister_switch(struct switch_dev *dev) +{ + swconfig_destroy_led_trigger(dev); + kfree(dev->portbuf); + mutex_lock(&dev->sw_mutex); + swconfig_lock(); + list_del(&dev->dev_list); + swconfig_unlock(); + mutex_unlock(&dev->sw_mutex); +} +EXPORT_SYMBOL_GPL(unregister_switch); + + +static int __init +swconfig_init(void) +{ + int err; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,13,0)) + int i; +#endif + + INIT_LIST_HEAD(&swdevs); + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,13,0)) + err = genl_register_family(&switch_fam); + if (err) + return err; + + for (i = 0; i < ARRAY_SIZE(swconfig_ops); i++) { + err = genl_register_ops(&switch_fam, &swconfig_ops[i]); + if (err) + goto unregister; + } + return 0; + +unregister: + genl_unregister_family(&switch_fam); + return err; +#else + err = genl_register_family_with_ops(&switch_fam, swconfig_ops); + if (err) + return err; + return 0; +#endif +} + +static void __exit +swconfig_exit(void) +{ + genl_unregister_family(&switch_fam); +} + +module_init(swconfig_init); +module_exit(swconfig_exit); + diff --git a/target/linux/generic/files/drivers/net/phy/swconfig_leds.c b/target/linux/generic/files/drivers/net/phy/swconfig_leds.c new file mode 100644 index 0000000..abd7bed --- /dev/null +++ b/target/linux/generic/files/drivers/net/phy/swconfig_leds.c @@ -0,0 +1,354 @@ +/* + * swconfig_led.c: LED trigger support for the switch configuration API + * + * Copyright (C) 2011 Gabor Juhos + * + * 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. + * + */ + +#ifdef CONFIG_SWCONFIG_LEDS + +#include +#include +#include +#include + +#define SWCONFIG_LED_TIMER_INTERVAL (HZ / 10) +#define SWCONFIG_LED_NUM_PORTS 32 + +struct switch_led_trigger { + struct led_trigger trig; + struct switch_dev *swdev; + + struct delayed_work sw_led_work; + u32 port_mask; + u32 port_link; + unsigned long port_traffic[SWCONFIG_LED_NUM_PORTS]; +}; + +struct swconfig_trig_data { + struct led_classdev *led_cdev; + struct switch_dev *swdev; + + rwlock_t lock; + u32 port_mask; + + bool prev_link; + unsigned long prev_traffic; + enum led_brightness prev_brightness; +}; + +static void +swconfig_trig_set_brightness(struct swconfig_trig_data *trig_data, + enum led_brightness brightness) +{ + led_set_brightness(trig_data->led_cdev, brightness); + trig_data->prev_brightness = brightness; +} + +static void +swconfig_trig_update_port_mask(struct led_trigger *trigger) +{ + struct list_head *entry; + struct switch_led_trigger *sw_trig; + u32 port_mask; + + if (!trigger) + return; + + sw_trig = (void *) trigger; + + port_mask = 0; + read_lock(&trigger->leddev_list_lock); + list_for_each(entry, &trigger->led_cdevs) { + struct led_classdev *led_cdev; + struct swconfig_trig_data *trig_data; + + led_cdev = list_entry(entry, struct led_classdev, trig_list); + trig_data = led_cdev->trigger_data; + if (trig_data) { + read_lock(&trig_data->lock); + port_mask |= trig_data->port_mask; + read_unlock(&trig_data->lock); + } + } + read_unlock(&trigger->leddev_list_lock); + + sw_trig->port_mask = port_mask; + + if (port_mask) + schedule_delayed_work(&sw_trig->sw_led_work, + SWCONFIG_LED_TIMER_INTERVAL); + else + cancel_delayed_work_sync(&sw_trig->sw_led_work); +} + +static ssize_t +swconfig_trig_port_mask_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t size) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct swconfig_trig_data *trig_data = led_cdev->trigger_data; + unsigned long port_mask; + ssize_t ret = -EINVAL; + char *after; + size_t count; + + port_mask = simple_strtoul(buf, &after, 16); + count = after - buf; + + if (*after && isspace(*after)) + count++; + + if (count == size) { + bool changed; + + write_lock(&trig_data->lock); + + changed = (trig_data->port_mask != port_mask); + if (changed) { + trig_data->port_mask = port_mask; + if (port_mask == 0) + swconfig_trig_set_brightness(trig_data, LED_OFF); + } + + write_unlock(&trig_data->lock); + + if (changed) + swconfig_trig_update_port_mask(led_cdev->trigger); + + ret = count; + } + + return ret; +} + +static ssize_t +swconfig_trig_port_mask_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct swconfig_trig_data *trig_data = led_cdev->trigger_data; + + read_lock(&trig_data->lock); + sprintf(buf, "%#x\n", trig_data->port_mask); + read_unlock(&trig_data->lock); + + return strlen(buf) + 1; +} + +static DEVICE_ATTR(port_mask, 0644, swconfig_trig_port_mask_show, + swconfig_trig_port_mask_store); + +static void +swconfig_trig_activate(struct led_classdev *led_cdev) +{ + struct switch_led_trigger *sw_trig; + struct swconfig_trig_data *trig_data; + int err; + + if (led_cdev->trigger->activate != swconfig_trig_activate) + return; + + trig_data = kzalloc(sizeof(struct swconfig_trig_data), GFP_KERNEL); + if (!trig_data) + return; + + sw_trig = (void *) led_cdev->trigger; + + rwlock_init(&trig_data->lock); + trig_data->led_cdev = led_cdev; + trig_data->swdev = sw_trig->swdev; + led_cdev->trigger_data = trig_data; + + err = device_create_file(led_cdev->dev, &dev_attr_port_mask); + if (err) + goto err_free; + + return; + +err_free: + led_cdev->trigger_data = NULL; + kfree(trig_data); +} + +static void +swconfig_trig_deactivate(struct led_classdev *led_cdev) +{ + struct swconfig_trig_data *trig_data; + + swconfig_trig_update_port_mask(led_cdev->trigger); + + trig_data = (void *) led_cdev->trigger_data; + if (trig_data) { + device_remove_file(led_cdev->dev, &dev_attr_port_mask); + kfree(trig_data); + } +} + +static void +swconfig_trig_led_event(struct switch_led_trigger *sw_trig, + struct led_classdev *led_cdev) +{ + struct swconfig_trig_data *trig_data; + u32 port_mask; + bool link; + + trig_data = led_cdev->trigger_data; + if (!trig_data) + return; + + read_lock(&trig_data->lock); + port_mask = trig_data->port_mask; + read_unlock(&trig_data->lock); + + link = !!(sw_trig->port_link & port_mask); + if (!link) { + if (link != trig_data->prev_link) + swconfig_trig_set_brightness(trig_data, LED_OFF); + } else { + unsigned long traffic; + int i; + + traffic = 0; + for (i = 0; i < SWCONFIG_LED_NUM_PORTS; i++) { + if (port_mask & (1 << i)) + traffic += sw_trig->port_traffic[i]; + } + + if (trig_data->prev_brightness != LED_FULL) + swconfig_trig_set_brightness(trig_data, LED_FULL); + else if (traffic != trig_data->prev_traffic) + swconfig_trig_set_brightness(trig_data, LED_OFF); + + trig_data->prev_traffic = traffic; + } + + trig_data->prev_link = link; +} + +static void +swconfig_trig_update_leds(struct switch_led_trigger *sw_trig) +{ + struct list_head *entry; + struct led_trigger *trigger; + + trigger = &sw_trig->trig; + read_lock(&trigger->leddev_list_lock); + list_for_each(entry, &trigger->led_cdevs) { + struct led_classdev *led_cdev; + + led_cdev = list_entry(entry, struct led_classdev, trig_list); + swconfig_trig_led_event(sw_trig, led_cdev); + } + read_unlock(&trigger->leddev_list_lock); +} + +static void +swconfig_led_work_func(struct work_struct *work) +{ + struct switch_led_trigger *sw_trig; + struct switch_dev *swdev; + u32 port_mask; + u32 link; + int i; + + sw_trig = container_of(work, struct switch_led_trigger, + sw_led_work.work); + + port_mask = sw_trig->port_mask; + swdev = sw_trig->swdev; + + link = 0; + for (i = 0; i < SWCONFIG_LED_NUM_PORTS; i++) { + u32 port_bit; + + port_bit = BIT(i); + if ((port_mask & port_bit) == 0) + continue; + + if (swdev->ops->get_port_link) { + struct switch_port_link port_link; + + memset(&port_link, '\0', sizeof(port_link)); + swdev->ops->get_port_link(swdev, i, &port_link); + + if (port_link.link) + link |= port_bit; + } + + if (swdev->ops->get_port_stats) { + struct switch_port_stats port_stats; + + memset(&port_stats, '\0', sizeof(port_stats)); + swdev->ops->get_port_stats(swdev, i, &port_stats); + sw_trig->port_traffic[i] = port_stats.tx_bytes + + port_stats.rx_bytes; + } + } + + sw_trig->port_link = link; + + swconfig_trig_update_leds(sw_trig); + + schedule_delayed_work(&sw_trig->sw_led_work, + SWCONFIG_LED_TIMER_INTERVAL); +} + +static int +swconfig_create_led_trigger(struct switch_dev *swdev) +{ + struct switch_led_trigger *sw_trig; + int err; + + if (!swdev->ops->get_port_link) + return 0; + + sw_trig = kzalloc(sizeof(struct switch_led_trigger), GFP_KERNEL); + if (!sw_trig) + return -ENOMEM; + + sw_trig->swdev = swdev; + sw_trig->trig.name = swdev->devname; + sw_trig->trig.activate = swconfig_trig_activate; + sw_trig->trig.deactivate = swconfig_trig_deactivate; + + INIT_DELAYED_WORK(&sw_trig->sw_led_work, swconfig_led_work_func); + + err = led_trigger_register(&sw_trig->trig); + if (err) + goto err_free; + + swdev->led_trigger = sw_trig; + + return 0; + +err_free: + kfree(sw_trig); + return err; +} + +static void +swconfig_destroy_led_trigger(struct switch_dev *swdev) +{ + struct switch_led_trigger *sw_trig; + + sw_trig = swdev->led_trigger; + if (sw_trig) { + cancel_delayed_work_sync(&sw_trig->sw_led_work); + led_trigger_unregister(&sw_trig->trig); + kfree(sw_trig); + } +} + +#else /* SWCONFIG_LEDS */ +static inline int +swconfig_create_led_trigger(struct switch_dev *swdev) { return 0; } + +static inline void +swconfig_destroy_led_trigger(struct switch_dev *swdev) { } +#endif /* CONFIG_SWCONFIG_LEDS */ diff --git a/target/linux/generic/files/fs/yaffs2/Kconfig b/target/linux/generic/files/fs/yaffs2/Kconfig new file mode 100644 index 0000000..408570f --- /dev/null +++ b/target/linux/generic/files/fs/yaffs2/Kconfig @@ -0,0 +1,171 @@ +# +# yaffs file system configurations +# + +config YAFFS_FS + tristate "yaffs2 file system support" + default n + depends on MTD_BLOCK + select YAFFS_YAFFS1 + select YAFFS_YAFFS2 + help + yaffs2, or Yet Another Flash File System, is a file system + optimised for NAND Flash chips. + + To compile the yaffs2 file system support as a module, choose M + here: the module will be called yaffs2. + + If unsure, say N. + + Further information on yaffs2 is available at + . + +config YAFFS_YAFFS1 + bool "512 byte / page devices" + depends on YAFFS_FS + default y + help + Enable yaffs1 support -- yaffs for 512 byte / page devices + + Not needed for 2K-page devices. + + If unsure, say Y. + +config YAFFS_9BYTE_TAGS + bool "Use older-style on-NAND data format with pageStatus byte" + depends on YAFFS_YAFFS1 + default n + help + + Older-style on-NAND data format has a "pageStatus" byte to record + chunk/page state. This byte is zero when the page is discarded. + Choose this option if you have existing on-NAND data using this + format that you need to continue to support. New data written + also uses the older-style format. Note: Use of this option + generally requires that MTD's oob layout be adjusted to use the + older-style format. See notes on tags formats and MTD versions + in yaffs_mtdif1.c. + + If unsure, say N. + +config YAFFS_DOES_ECC + bool "Lets yaffs do its own ECC" + depends on YAFFS_FS && YAFFS_YAFFS1 && !YAFFS_9BYTE_TAGS + default n + help + This enables yaffs to use its own ECC functions instead of using + the ones from the generic MTD-NAND driver. + + If unsure, say N. + +config YAFFS_ECC_WRONG_ORDER + bool "Use the same ecc byte order as Steven Hill's nand_ecc.c" + depends on YAFFS_FS && YAFFS_DOES_ECC && !YAFFS_9BYTE_TAGS + default n + help + This makes yaffs_ecc.c use the same ecc byte order as Steven + Hill's nand_ecc.c. If not set, then you get the same ecc byte + order as SmartMedia. + + If unsure, say N. + +config YAFFS_YAFFS2 + bool "2048 byte (or larger) / page devices" + depends on YAFFS_FS + default y + help + Enable yaffs2 support -- yaffs for >= 2K bytes per page devices + + If unsure, say Y. + +config YAFFS_AUTO_YAFFS2 + bool "Autoselect yaffs2 format" + depends on YAFFS_YAFFS2 + default y + help + Without this, you need to explicitely use yaffs2 as the file + system type. With this, you can say "yaffs" and yaffs or yaffs2 + will be used depending on the device page size (yaffs on + 512-byte page devices, yaffs2 on 2K page devices). + + If unsure, say Y. + +config YAFFS_DISABLE_TAGS_ECC + bool "Disable yaffs from doing ECC on tags by default" + depends on YAFFS_FS && YAFFS_YAFFS2 + default n + help + This defaults yaffs to using its own ECC calculations on tags instead of + just relying on the MTD. + This behavior can also be overridden with tags_ecc_on and + tags_ecc_off mount options. + + If unsure, say N. + +config YAFFS_ALWAYS_CHECK_CHUNK_ERASED + bool "Force chunk erase check" + depends on YAFFS_FS + default n + help + Normally yaffs only checks chunks before writing until an erased + chunk is found. This helps to detect any partially written + chunks that might have happened due to power loss. + + Enabling this forces on the test that chunks are erased in flash + before writing to them. This takes more time but is potentially + a bit more secure. + + Suggest setting Y during development and ironing out driver + issues etc. Suggest setting to N if you want faster writing. + + If unsure, say Y. + +config YAFFS_EMPTY_LOST_AND_FOUND + bool "Empty lost and found on boot" + depends on YAFFS_FS + default n + help + If this is enabled then the contents of lost and found is + automatically dumped at mount. + + If unsure, say N. + +config YAFFS_DISABLE_BLOCK_REFRESHING + bool "Disable yaffs2 block refreshing" + depends on YAFFS_FS + default n + help + If this is set, then block refreshing is disabled. + Block refreshing infrequently refreshes the oldest block in + a yaffs2 file system. This mechanism helps to refresh flash to + mitigate against data loss. This is particularly useful for MLC. + + If unsure, say N. + +config YAFFS_DISABLE_BACKGROUND + bool "Disable yaffs2 background processing" + depends on YAFFS_FS + default n + help + If this is set, then background processing is disabled. + Background processing makes many foreground activities faster. + + If unsure, say N. + +config YAFFS_DISABLE_BAD_BLOCK_MARKING + bool "Disable yaffs2 bad block marking" + depends on YAFFS_FS + default n + help + Useful during early flash bring up to prevent problems causing + lots of bad block marking. + + If unsure, say N. + +config YAFFS_XATTR + bool "Enable yaffs2 xattr support" + depends on YAFFS_FS + default y + help + If this is set then yaffs2 will provide xattr support. + If unsure, say Y. diff --git a/target/linux/generic/files/fs/yaffs2/Makefile b/target/linux/generic/files/fs/yaffs2/Makefile new file mode 100644 index 0000000..f9a9fb1 --- /dev/null +++ b/target/linux/generic/files/fs/yaffs2/Makefile @@ -0,0 +1,18 @@ +# +# Makefile for the linux YAFFS filesystem routines. +# + +obj-$(CONFIG_YAFFS_FS) += yaffs.o + +yaffs-y := yaffs_ecc.o yaffs_vfs.o yaffs_guts.o yaffs_checkptrw.o +yaffs-y += yaffs_packedtags1.o yaffs_packedtags2.o yaffs_nand.o +yaffs-y += yaffs_tagscompat.o yaffs_tagsmarshall.o +yaffs-y += yaffs_mtdif.o +yaffs-y += yaffs_nameval.o yaffs_attribs.o +yaffs-y += yaffs_allocator.o +yaffs-y += yaffs_yaffs1.o +yaffs-y += yaffs_yaffs2.o +yaffs-y += yaffs_bitmap.o +yaffs-y += yaffs_summary.o +yaffs-y += yaffs_verify.o + diff --git a/target/linux/generic/files/fs/yaffs2/NOTE.openwrt b/target/linux/generic/files/fs/yaffs2/NOTE.openwrt new file mode 100644 index 0000000..e84fbe6 --- /dev/null +++ b/target/linux/generic/files/fs/yaffs2/NOTE.openwrt @@ -0,0 +1,4 @@ +The yaffs2 source has been fetched from the yaffs2 GIT tree. + +URL: git://www.aleph1.co.uk/yaffs2 +Version: 583dbd9cc2668870cb013f051ba59f7d3e513dae (2015-06-02) diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_allocator.c b/target/linux/generic/files/fs/yaffs2/yaffs_allocator.c new file mode 100644 index 0000000..c8f2861 --- /dev/null +++ b/target/linux/generic/files/fs/yaffs2/yaffs_allocator.c @@ -0,0 +1,357 @@ +/* + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning + * + * 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. + */ + +#include "yaffs_allocator.h" +#include "yaffs_guts.h" +#include "yaffs_trace.h" +#include "yportenv.h" + +/* + * Each entry in yaffs_tnode_list and yaffs_obj_list hold blocks + * of approx 100 objects that are themn allocated singly. + * This is basically a simplified slab allocator. + * + * We don't use the Linux slab allocator because slab does not allow + * us to dump all the objects in one hit when we do a umount and tear + * down all the tnodes and objects. slab requires that we first free + * the individual objects. + * + * Once yaffs has been mainlined I shall try to motivate for a change + * to slab to provide the extra features we need here. + */ + +struct yaffs_tnode_list { + struct yaffs_tnode_list *next; + struct yaffs_tnode *tnodes; +}; + +struct yaffs_obj_list { + struct yaffs_obj_list *next; + struct yaffs_obj *objects; +}; + +struct yaffs_allocator { + int n_tnodes_created; + struct yaffs_tnode *free_tnodes; + int n_free_tnodes; + struct yaffs_tnode_list *alloc_tnode_list; + + int n_obj_created; + struct list_head free_objs; + int n_free_objects; + + struct yaffs_obj_list *allocated_obj_list; +}; + +static void yaffs_deinit_raw_tnodes(struct yaffs_dev *dev) +{ + struct yaffs_allocator *allocator = + (struct yaffs_allocator *)dev->allocator; + struct yaffs_tnode_list *tmp; + + if (!allocator) { + BUG(); + return; + } + + while (allocator->alloc_tnode_list) { + tmp = allocator->alloc_tnode_list->next; + + kfree(allocator->alloc_tnode_list->tnodes); + kfree(allocator->alloc_tnode_list); + allocator->alloc_tnode_list = tmp; + } + + allocator->free_tnodes = NULL; + allocator->n_free_tnodes = 0; + allocator->n_tnodes_created = 0; +} + +static void yaffs_init_raw_tnodes(struct yaffs_dev *dev) +{ + struct yaffs_allocator *allocator = dev->allocator; + + if (!allocator) { + BUG(); + return; + } + + allocator->alloc_tnode_list = NULL; + allocator->free_tnodes = NULL; + allocator->n_free_tnodes = 0; + allocator->n_tnodes_created = 0; +} + +static int yaffs_create_tnodes(struct yaffs_dev *dev, int n_tnodes) +{ + struct yaffs_allocator *allocator = + (struct yaffs_allocator *)dev->allocator; + int i; + struct yaffs_tnode *new_tnodes; + u8 *mem; + struct yaffs_tnode *curr; + struct yaffs_tnode *next; + struct yaffs_tnode_list *tnl; + + if (!allocator) { + BUG(); + return YAFFS_FAIL; + } + + if (n_tnodes < 1) + return YAFFS_OK; + + /* make these things */ + new_tnodes = kmalloc(n_tnodes * dev->tnode_size, GFP_NOFS); + mem = (u8 *) new_tnodes; + + if (!new_tnodes) { + yaffs_trace(YAFFS_TRACE_ERROR, + "yaffs: Could not allocate Tnodes"); + return YAFFS_FAIL; + } + + /* New hookup for wide tnodes */ + for (i = 0; i < n_tnodes - 1; i++) { + curr = (struct yaffs_tnode *)&mem[i * dev->tnode_size]; + next = (struct yaffs_tnode *)&mem[(i + 1) * dev->tnode_size]; + curr->internal[0] = next; + } + + curr = (struct yaffs_tnode *)&mem[(n_tnodes - 1) * dev->tnode_size]; + curr->internal[0] = allocator->free_tnodes; + allocator->free_tnodes = (struct yaffs_tnode *)mem; + + allocator->n_free_tnodes += n_tnodes; + allocator->n_tnodes_created += n_tnodes; + + /* Now add this bunch of tnodes to a list for freeing up. + * NB If we can't add this to the management list it isn't fatal + * but it just means we can't free this bunch of tnodes later. + */ + tnl = kmalloc(sizeof(struct yaffs_tnode_list), GFP_NOFS); + if (!tnl) { + yaffs_trace(YAFFS_TRACE_ERROR, + "Could not add tnodes to management list"); + return YAFFS_FAIL; + } else { + tnl->tnodes = new_tnodes; + tnl->next = allocator->alloc_tnode_list; + allocator->alloc_tnode_list = tnl; + } + + yaffs_trace(YAFFS_TRACE_ALLOCATE, "Tnodes added"); + + return YAFFS_OK; +} + +struct yaffs_tnode *yaffs_alloc_raw_tnode(struct yaffs_dev *dev) +{ + struct yaffs_allocator *allocator = + (struct yaffs_allocator *)dev->allocator; + struct yaffs_tnode *tn = NULL; + + if (!allocator) { + BUG(); + return NULL; + } + + /* If there are none left make more */ + if (!allocator->free_tnodes) + yaffs_create_tnodes(dev, YAFFS_ALLOCATION_NTNODES); + + if (allocator->free_tnodes) { + tn = allocator->free_tnodes; + allocator->free_tnodes = allocator->free_tnodes->internal[0]; + allocator->n_free_tnodes--; + } + + return tn; +} + +/* FreeTnode frees up a tnode and puts it back on the free list */ +void yaffs_free_raw_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn) +{ + struct yaffs_allocator *allocator = dev->allocator; + + if (!allocator) { + BUG(); + return; + } + + if (tn) { + tn->internal[0] = allocator->free_tnodes; + allocator->free_tnodes = tn; + allocator->n_free_tnodes++; + } + dev->checkpoint_blocks_required = 0; /* force recalculation */ +} + +/*--------------- yaffs_obj alloaction ------------------------ + * + * Free yaffs_objs are stored in a list using obj->siblings. + * The blocks of allocated objects are stored in a linked list. + */ + +static void yaffs_init_raw_objs(struct yaffs_dev *dev) +{ + struct yaffs_allocator *allocator = dev->allocator; + + if (!allocator) { + BUG(); + return; + } + + allocator->allocated_obj_list = NULL; + INIT_LIST_HEAD(&allocator->free_objs); + allocator->n_free_objects = 0; +} + +static void yaffs_deinit_raw_objs(struct yaffs_dev *dev) +{ + struct yaffs_allocator *allocator = dev->allocator; + struct yaffs_obj_list *tmp; + + if (!allocator) { + BUG(); + return; + } + + while (allocator->allocated_obj_list) { + tmp = allocator->allocated_obj_list->next; + kfree(allocator->allocated_obj_list->objects); + kfree(allocator->allocated_obj_list); + allocator->allocated_obj_list = tmp; + } + + INIT_LIST_HEAD(&allocator->free_objs); + allocator->n_free_objects = 0; + allocator->n_obj_created = 0; +} + +static int yaffs_create_free_objs(struct yaffs_dev *dev, int n_obj) +{ + struct yaffs_allocator *allocator = dev->allocator; + int i; + struct yaffs_obj *new_objs; + struct yaffs_obj_list *list; + + if (!allocator) { + BUG(); + return YAFFS_FAIL; + } + + if (n_obj < 1) + return YAFFS_OK; + + /* make these things */ + new_objs = kmalloc(n_obj * sizeof(struct yaffs_obj), GFP_NOFS); + list = kmalloc(sizeof(struct yaffs_obj_list), GFP_NOFS); + + if (!new_objs || !list) { + kfree(new_objs); + new_objs = NULL; + kfree(list); + list = NULL; + yaffs_trace(YAFFS_TRACE_ALLOCATE, + "Could not allocate more objects"); + return YAFFS_FAIL; + } + + /* Hook them into the free list */ + for (i = 0; i < n_obj; i++) + list_add(&new_objs[i].siblings, &allocator->free_objs); + + allocator->n_free_objects += n_obj; + allocator->n_obj_created += n_obj; + + /* Now add this bunch of Objects to a list for freeing up. */ + + list->objects = new_objs; + list->next = allocator->allocated_obj_list; + allocator->allocated_obj_list = list; + + return YAFFS_OK; +} + +struct yaffs_obj *yaffs_alloc_raw_obj(struct yaffs_dev *dev) +{ + struct yaffs_obj *obj = NULL; + struct list_head *lh; + struct yaffs_allocator *allocator = dev->allocator; + + if (!allocator) { + BUG(); + return obj; + } + + /* If there are none left make more */ + if (list_empty(&allocator->free_objs)) + yaffs_create_free_objs(dev, YAFFS_ALLOCATION_NOBJECTS); + + if (!list_empty(&allocator->free_objs)) { + lh = allocator->free_objs.next; + obj = list_entry(lh, struct yaffs_obj, siblings); + list_del_init(lh); + allocator->n_free_objects--; + } + + return obj; +} + +void yaffs_free_raw_obj(struct yaffs_dev *dev, struct yaffs_obj *obj) +{ + + struct yaffs_allocator *allocator = dev->allocator; + + if (!allocator) { + BUG(); + return; + } + + /* Link into the free list. */ + list_add(&obj->siblings, &allocator->free_objs); + allocator->n_free_objects++; +} + +void yaffs_deinit_raw_tnodes_and_objs(struct yaffs_dev *dev) +{ + + if (!dev->allocator) { + BUG(); + return; + } + + yaffs_deinit_raw_tnodes(dev); + yaffs_deinit_raw_objs(dev); + kfree(dev->allocator); + dev->allocator = NULL; +} + +void yaffs_init_raw_tnodes_and_objs(struct yaffs_dev *dev) +{ + struct yaffs_allocator *allocator; + + if (dev->allocator) { + BUG(); + return; + } + + allocator = kmalloc(sizeof(struct yaffs_allocator), GFP_NOFS); + if (allocator) { + dev->allocator = allocator; + yaffs_init_raw_tnodes(dev); + yaffs_init_raw_objs(dev); + } +} + diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_allocator.h b/target/linux/generic/files/fs/yaffs2/yaffs_allocator.h new file mode 100644 index 0000000..a8cc322 --- /dev/null +++ b/target/linux/generic/files/fs/yaffs2/yaffs_allocator.h @@ -0,0 +1,30 @@ +/* + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + */ + +#ifndef __YAFFS_ALLOCATOR_H__ +#define __YAFFS_ALLOCATOR_H__ + +#include "yaffs_guts.h" + +void yaffs_init_raw_tnodes_and_objs(struct yaffs_dev *dev); +void yaffs_deinit_raw_tnodes_and_objs(struct yaffs_dev *dev); + +struct yaffs_tnode *yaffs_alloc_raw_tnode(struct yaffs_dev *dev); +void yaffs_free_raw_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn); + +struct yaffs_obj *yaffs_alloc_raw_obj(struct yaffs_dev *dev); +void yaffs_free_raw_obj(struct yaffs_dev *dev, struct yaffs_obj *obj); + +#endif diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_attribs.c b/target/linux/generic/files/fs/yaffs2/yaffs_attribs.c new file mode 100644 index 0000000..711941f --- /dev/null +++ b/target/linux/generic/files/fs/yaffs2/yaffs_attribs.c @@ -0,0 +1,132 @@ +/* + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning + * + * 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. + */ + +#include "yaffs_guts.h" +#include "yaffs_attribs.h" + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)) +#define IATTR_UID ia_uid +#define IATTR_GID ia_gid +#else +#define IATTR_UID ia_uid.val +#define IATTR_GID ia_gid.val +#endif + +void yaffs_load_attribs(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh) +{ + obj->yst_uid = oh->yst_uid; + obj->yst_gid = oh->yst_gid; + obj->yst_atime = oh->yst_atime; + obj->yst_mtime = oh->yst_mtime; + obj->yst_ctime = oh->yst_ctime; + obj->yst_rdev = oh->yst_rdev; +} + +void yaffs_load_attribs_oh(struct yaffs_obj_hdr *oh, struct yaffs_obj *obj) +{ + oh->yst_uid = obj->yst_uid; + oh->yst_gid = obj->yst_gid; + oh->yst_atime = obj->yst_atime; + oh->yst_mtime = obj->yst_mtime; + oh->yst_ctime = obj->yst_ctime; + oh->yst_rdev = obj->yst_rdev; + +} + +void yaffs_load_current_time(struct yaffs_obj *obj, int do_a, int do_c) +{ + obj->yst_mtime = Y_CURRENT_TIME; + if (do_a) + obj->yst_atime = obj->yst_mtime; + if (do_c) + obj->yst_ctime = obj->yst_mtime; +} + +void yaffs_attribs_init(struct yaffs_obj *obj, u32 gid, u32 uid, u32 rdev) +{ + yaffs_load_current_time(obj, 1, 1); + obj->yst_rdev = rdev; + obj->yst_uid = uid; + obj->yst_gid = gid; +} + +static loff_t yaffs_get_file_size(struct yaffs_obj *obj) +{ + YCHAR *alias = NULL; + obj = yaffs_get_equivalent_obj(obj); + + switch (obj->variant_type) { + case YAFFS_OBJECT_TYPE_FILE: + return obj->variant.file_variant.file_size; + case YAFFS_OBJECT_TYPE_SYMLINK: + alias = obj->variant.symlink_variant.alias; + if (!alias) + return 0; + return strnlen(alias, YAFFS_MAX_ALIAS_LENGTH); + default: + return 0; + } +} + +int yaffs_set_attribs(struct yaffs_obj *obj, struct iattr *attr) +{ + unsigned int valid = attr->ia_valid; + + if (valid & ATTR_MODE) + obj->yst_mode = attr->ia_mode; + if (valid & ATTR_UID) + obj->yst_uid = attr->IATTR_UID; + if (valid & ATTR_GID) + obj->yst_gid = attr->IATTR_GID; + + if (valid & ATTR_ATIME) + obj->yst_atime = Y_TIME_CONVERT(attr->ia_atime); + if (valid & ATTR_CTIME) + obj->yst_ctime = Y_TIME_CONVERT(attr->ia_ctime); + if (valid & ATTR_MTIME) + obj->yst_mtime = Y_TIME_CONVERT(attr->ia_mtime); + + if (valid & ATTR_SIZE) + yaffs_resize_file(obj, attr->ia_size); + + yaffs_update_oh(obj, NULL, 1, 0, 0, NULL); + + return YAFFS_OK; + +} + +int yaffs_get_attribs(struct yaffs_obj *obj, struct iattr *attr) +{ + unsigned int valid = 0; + + attr->ia_mode = obj->yst_mode; + valid |= ATTR_MODE; + attr->IATTR_UID = obj->yst_uid; + valid |= ATTR_UID; + attr->IATTR_GID = obj->yst_gid; + valid |= ATTR_GID; + + Y_TIME_CONVERT(attr->ia_atime) = obj->yst_atime; + valid |= ATTR_ATIME; + Y_TIME_CONVERT(attr->ia_ctime) = obj->yst_ctime; + valid |= ATTR_CTIME; + Y_TIME_CONVERT(attr->ia_mtime) = obj->yst_mtime; + valid |= ATTR_MTIME; + + attr->ia_size = yaffs_get_file_size(obj); + valid |= ATTR_SIZE; + + attr->ia_valid = valid; + + return YAFFS_OK; +} diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_attribs.h b/target/linux/generic/files/fs/yaffs2/yaffs_attribs.h new file mode 100644 index 0000000..5b21b08 --- /dev/null +++ b/target/linux/generic/files/fs/yaffs2/yaffs_attribs.h @@ -0,0 +1,28 @@ +/* + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + */ + +#ifndef __YAFFS_ATTRIBS_H__ +#define __YAFFS_ATTRIBS_H__ + +#include "yaffs_guts.h" + +void yaffs_load_attribs(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh); +void yaffs_load_attribs_oh(struct yaffs_obj_hdr *oh, struct yaffs_obj *obj); +void yaffs_attribs_init(struct yaffs_obj *obj, u32 gid, u32 uid, u32 rdev); +void yaffs_load_current_time(struct yaffs_obj *obj, int do_a, int do_c); +int yaffs_set_attribs(struct yaffs_obj *obj, struct iattr *attr); +int yaffs_get_attribs(struct yaffs_obj *obj, struct iattr *attr); + +#endif diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_bitmap.c b/target/linux/generic/files/fs/yaffs2/yaffs_bitmap.c new file mode 100644 index 0000000..4440e93 --- /dev/null +++ b/target/linux/generic/files/fs/yaffs2/yaffs_bitmap.c @@ -0,0 +1,97 @@ +/* + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning + * + * 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. + */ + +#include "yaffs_bitmap.h" +#include "yaffs_trace.h" +/* + * Chunk bitmap manipulations + */ + +static inline u8 *yaffs_block_bits(struct yaffs_dev *dev, int blk) +{ + if (blk < dev->internal_start_block || blk > dev->internal_end_block) { + yaffs_trace(YAFFS_TRACE_ERROR, + "BlockBits block %d is not valid", + blk); + BUG(); + } + return dev->chunk_bits + + (dev->chunk_bit_stride * (blk - dev->internal_start_block)); +} + +void yaffs_verify_chunk_bit_id(struct yaffs_dev *dev, int blk, int chunk) +{ + if (blk < dev->internal_start_block || blk > dev->internal_end_block || + chunk < 0 || chunk >= dev->param.chunks_per_block) { + yaffs_trace(YAFFS_TRACE_ERROR, + "Chunk Id (%d:%d) invalid", + blk, chunk); + BUG(); + } +} + +void yaffs_clear_chunk_bits(struct yaffs_dev *dev, int blk) +{ + u8 *blk_bits = yaffs_block_bits(dev, blk); + + memset(blk_bits, 0, dev->chunk_bit_stride); +} + +void yaffs_clear_chunk_bit(struct yaffs_dev *dev, int blk, int chunk) +{ + u8 *blk_bits = yaffs_block_bits(dev, blk); + + yaffs_verify_chunk_bit_id(dev, blk, chunk); + blk_bits[chunk / 8] &= ~(1 << (chunk & 7)); +} + +void yaffs_set_chunk_bit(struct yaffs_dev *dev, int blk, int chunk) +{ + u8 *blk_bits = yaffs_block_bits(dev, blk); + + yaffs_verify_chunk_bit_id(dev, blk, chunk); + blk_bits[chunk / 8] |= (1 << (chunk & 7)); +} + +int yaffs_check_chunk_bit(struct yaffs_dev *dev, int blk, int chunk) +{ + u8 *blk_bits = yaffs_block_bits(dev, blk); + + yaffs_verify_chunk_bit_id(dev, blk, chunk); + return (blk_bits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0; +} + +int yaffs_still_some_chunks(struct yaffs_dev *dev, int blk) +{ + u8 *blk_bits = yaffs_block_bits(dev, blk); + int i; + + for (i = 0; i < dev->chunk_bit_stride; i++) { + if (*blk_bits) + return 1; + blk_bits++; + } + return 0; +} + +int yaffs_count_chunk_bits(struct yaffs_dev *dev, int blk) +{ + u8 *blk_bits = yaffs_block_bits(dev, blk); + int i; + int n = 0; + + for (i = 0; i < dev->chunk_bit_stride; i++, blk_bits++) + n += hweight8(*blk_bits); + + return n; +} diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_bitmap.h b/target/linux/generic/files/fs/yaffs2/yaffs_bitmap.h new file mode 100644 index 0000000..e26b37d --- /dev/null +++ b/target/linux/generic/files/fs/yaffs2/yaffs_bitmap.h @@ -0,0 +1,33 @@ +/* + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + */ + +/* + * Chunk bitmap manipulations + */ + +#ifndef __YAFFS_BITMAP_H__ +#define __YAFFS_BITMAP_H__ + +#include "yaffs_guts.h" + +void yaffs_verify_chunk_bit_id(struct yaffs_dev *dev, int blk, int chunk); +void yaffs_clear_chunk_bits(struct yaffs_dev *dev, int blk); +void yaffs_clear_chunk_bit(struct yaffs_dev *dev, int blk, int chunk); +void yaffs_set_chunk_bit(struct yaffs_dev *dev, int blk, int chunk); +int yaffs_check_chunk_bit(struct yaffs_dev *dev, int blk, int chunk); +int yaffs_still_some_chunks(struct yaffs_dev *dev, int blk); +int yaffs_count_chunk_bits(struct yaffs_dev *dev, int blk); + +#endif diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_checkptrw.c b/target/linux/generic/files/fs/yaffs2/yaffs_checkptrw.c new file mode 100644 index 0000000..16ee1e0 --- /dev/null +++ b/target/linux/generic/files/fs/yaffs2/yaffs_checkptrw.c @@ -0,0 +1,466 @@ +/* + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning + * + * 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. + */ + +#include "yaffs_checkptrw.h" +#include "yaffs_getblockinfo.h" + +struct yaffs_checkpt_chunk_hdr { + int version; + int seq; + u32 sum; + u32 xor; +} ; + + +static int apply_chunk_offset(struct yaffs_dev *dev, int chunk) +{ + return chunk - dev->chunk_offset; +} + +static int apply_block_offset(struct yaffs_dev *dev, int block) +{ + return block - dev->block_offset; +} + +static void yaffs2_checkpt_init_chunk_hdr(struct yaffs_dev *dev) +{ + struct yaffs_checkpt_chunk_hdr hdr; + + hdr.version = YAFFS_CHECKPOINT_VERSION; + hdr.seq = dev->checkpt_page_seq; + hdr.sum = dev->checkpt_sum; + hdr.xor = dev->checkpt_xor; + + dev->checkpt_byte_offs = sizeof(hdr); + + memcpy(dev->checkpt_buffer, &hdr, sizeof(hdr)); +} + +static int yaffs2_checkpt_check_chunk_hdr(struct yaffs_dev *dev) +{ + struct yaffs_checkpt_chunk_hdr hdr; + + memcpy(&hdr, dev->checkpt_buffer, sizeof(hdr)); + + dev->checkpt_byte_offs = sizeof(hdr); + + return hdr.version == YAFFS_CHECKPOINT_VERSION && + hdr.seq == dev->checkpt_page_seq && + hdr.sum == dev->checkpt_sum && + hdr.xor == dev->checkpt_xor; +} + +static int yaffs2_checkpt_space_ok(struct yaffs_dev *dev) +{ + int blocks_avail = dev->n_erased_blocks - dev->param.n_reserved_blocks; + + yaffs_trace(YAFFS_TRACE_CHECKPOINT, + "checkpt blocks_avail = %d", blocks_avail); + + return (blocks_avail <= 0) ? 0 : 1; +} + +static int yaffs_checkpt_erase(struct yaffs_dev *dev) +{ + int i; + + if (!dev->drv.drv_erase_fn) + return 0; + yaffs_trace(YAFFS_TRACE_CHECKPOINT, + "checking blocks %d to %d", + dev->internal_start_block, dev->internal_end_block); + + for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) { + struct yaffs_block_info *bi = yaffs_get_block_info(dev, i); + int offset_i = apply_block_offset(dev, i); + int result; + + if (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT) { + yaffs_trace(YAFFS_TRACE_CHECKPOINT, + "erasing checkpt block %d", i); + + dev->n_erasures++; + + result = dev->drv.drv_erase_fn(dev, offset_i); + if(result) { + bi->block_state = YAFFS_BLOCK_STATE_EMPTY; + dev->n_erased_blocks++; + dev->n_free_chunks += + dev->param.chunks_per_block; + } else { + dev->drv.drv_mark_bad_fn(dev, offset_i); + bi->block_state = YAFFS_BLOCK_STATE_DEAD; + } + } + } + + dev->blocks_in_checkpt = 0; + + return 1; +} + +static void yaffs2_checkpt_find_erased_block(struct yaffs_dev *dev) +{ + int i; + int blocks_avail = dev->n_erased_blocks - dev->param.n_reserved_blocks; + + yaffs_trace(YAFFS_TRACE_CHECKPOINT, + "allocating checkpt block: erased %d reserved %d avail %d next %d ", + dev->n_erased_blocks, dev->param.n_reserved_blocks, + blocks_avail, dev->checkpt_next_block); + + if (dev->checkpt_next_block >= 0 && + dev->checkpt_next_block <= dev->internal_end_block && + blocks_avail > 0) { + + for (i = dev->checkpt_next_block; i <= dev->internal_end_block; + i++) { + struct yaffs_block_info *bi; + + bi = yaffs_get_block_info(dev, i); + if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) { + dev->checkpt_next_block = i + 1; + dev->checkpt_cur_block = i; + yaffs_trace(YAFFS_TRACE_CHECKPOINT, + "allocating checkpt block %d", i); + return; + } + } + } + yaffs_trace(YAFFS_TRACE_CHECKPOINT, "out of checkpt blocks"); + + dev->checkpt_next_block = -1; + dev->checkpt_cur_block = -1; +} + +static void yaffs2_checkpt_find_block(struct yaffs_dev *dev) +{ + int i; + struct yaffs_ext_tags tags; + + yaffs_trace(YAFFS_TRACE_CHECKPOINT, + "find next checkpt block: start: blocks %d next %d", + dev->blocks_in_checkpt, dev->checkpt_next_block); + + if (dev->blocks_in_checkpt < dev->checkpt_max_blocks) + for (i = dev->checkpt_next_block; i <= dev->internal_end_block; + i++) { + int chunk = i * dev->param.chunks_per_block; + enum yaffs_block_state state; + u32 seq; + + dev->tagger.read_chunk_tags_fn(dev, + apply_chunk_offset(dev, chunk), + NULL, &tags); + yaffs_trace(YAFFS_TRACE_CHECKPOINT, + "find next checkpt block: search: block %d state %d oid %d seq %d eccr %d", + i, (int) state, + tags.obj_id, tags.seq_number, + tags.ecc_result); + + if (tags.seq_number != YAFFS_SEQUENCE_CHECKPOINT_DATA) + continue; + + dev->tagger.query_block_fn(dev, + apply_block_offset(dev, i), + &state, &seq); + if (state == YAFFS_BLOCK_STATE_DEAD) + continue; + + /* Right kind of block */ + dev->checkpt_next_block = tags.obj_id; + dev->checkpt_cur_block = i; + dev->checkpt_block_list[dev->blocks_in_checkpt] = i; + dev->blocks_in_checkpt++; + yaffs_trace(YAFFS_TRACE_CHECKPOINT, + "found checkpt block %d", i); + return; + } + + yaffs_trace(YAFFS_TRACE_CHECKPOINT, "found no more checkpt blocks"); + + dev->checkpt_next_block = -1; + dev->checkpt_cur_block = -1; +} + +int yaffs2_checkpt_open(struct yaffs_dev *dev, int writing) +{ + int i; + + dev->checkpt_open_write = writing; + + /* Got the functions we need? */ + if (!dev->tagger.write_chunk_tags_fn || + !dev->tagger.read_chunk_tags_fn || + !dev->drv.drv_erase_fn || + !dev->drv.drv_mark_bad_fn) + return 0; + + if (writing && !yaffs2_checkpt_space_ok(dev)) + return 0; + + if (!dev->checkpt_buffer) + dev->checkpt_buffer = + kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS); + if (!dev->checkpt_buffer) + return 0; + + dev->checkpt_page_seq = 0; + dev->checkpt_byte_count = 0; + dev->checkpt_sum = 0; + dev->checkpt_xor = 0; + dev->checkpt_cur_block = -1; + dev->checkpt_cur_chunk = -1; + dev->checkpt_next_block = dev->internal_start_block; + + if (writing) { + memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk); + yaffs2_checkpt_init_chunk_hdr(dev); + return yaffs_checkpt_erase(dev); + } + + /* Opening for a read */ + /* Set to a value that will kick off a read */ + dev->checkpt_byte_offs = dev->data_bytes_per_chunk; + /* A checkpoint block list of 1 checkpoint block per 16 block is + * (hopefully) going to be way more than we need */ + dev->blocks_in_checkpt = 0; + dev->checkpt_max_blocks = + (dev->internal_end_block - dev->internal_start_block) / 16 + 2; + if (!dev->checkpt_block_list) + dev->checkpt_block_list = + kmalloc(sizeof(int) * dev->checkpt_max_blocks, GFP_NOFS); + + if (!dev->checkpt_block_list) + return 0; + + for (i = 0; i < dev->checkpt_max_blocks; i++) + dev->checkpt_block_list[i] = -1; + + return 1; +} + +int yaffs2_get_checkpt_sum(struct yaffs_dev *dev, u32 * sum) +{ + u32 composite_sum; + + composite_sum = (dev->checkpt_sum << 8) | (dev->checkpt_xor & 0xff); + *sum = composite_sum; + return 1; +} + +static int yaffs2_checkpt_flush_buffer(struct yaffs_dev *dev) +{ + int chunk; + int offset_chunk; + struct yaffs_ext_tags tags; + + if (dev->checkpt_cur_block < 0) { + yaffs2_checkpt_find_erased_block(dev); + dev->checkpt_cur_chunk = 0; + } + + if (dev->checkpt_cur_block < 0) + return 0; + + tags.is_deleted = 0; + tags.obj_id = dev->checkpt_next_block; /* Hint to next place to look */ + tags.chunk_id = dev->checkpt_page_seq + 1; + tags.seq_number = YAFFS_SEQUENCE_CHECKPOINT_DATA; + tags.n_bytes = dev->data_bytes_per_chunk; + if (dev->checkpt_cur_chunk == 0) { + /* First chunk we write for the block? Set block state to + checkpoint */ + struct yaffs_block_info *bi = + yaffs_get_block_info(dev, dev->checkpt_cur_block); + bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT; + dev->blocks_in_checkpt++; + } + + chunk = + dev->checkpt_cur_block * dev->param.chunks_per_block + + dev->checkpt_cur_chunk; + + yaffs_trace(YAFFS_TRACE_CHECKPOINT, + "checkpoint wite buffer nand %d(%d:%d) objid %d chId %d", + chunk, dev->checkpt_cur_block, dev->checkpt_cur_chunk, + tags.obj_id, tags.chunk_id); + + offset_chunk = apply_chunk_offset(dev, chunk); + + dev->n_page_writes++; + + dev->tagger.write_chunk_tags_fn(dev, offset_chunk, + dev->checkpt_buffer, &tags); + dev->checkpt_page_seq++; + dev->checkpt_cur_chunk++; + if (dev->checkpt_cur_chunk >= dev->param.chunks_per_block) { + dev->checkpt_cur_chunk = 0; + dev->checkpt_cur_block = -1; + } + memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk); + + yaffs2_checkpt_init_chunk_hdr(dev); + + + return 1; +} + +int yaffs2_checkpt_wr(struct yaffs_dev *dev, const void *data, int n_bytes) +{ + int i = 0; + int ok = 1; + u8 *data_bytes = (u8 *) data; + + if (!dev->checkpt_buffer) + return 0; + + if (!dev->checkpt_open_write) + return -1; + + while (i < n_bytes && ok) { + dev->checkpt_buffer[dev->checkpt_byte_offs] = *data_bytes; + dev->checkpt_sum += *data_bytes; + dev->checkpt_xor ^= *data_bytes; + + dev->checkpt_byte_offs++; + i++; + data_bytes++; + dev->checkpt_byte_count++; + + if (dev->checkpt_byte_offs < 0 || + dev->checkpt_byte_offs >= dev->data_bytes_per_chunk) + ok = yaffs2_checkpt_flush_buffer(dev); + } + + return i; +} + +int yaffs2_checkpt_rd(struct yaffs_dev *dev, void *data, int n_bytes) +{ + int i = 0; + struct yaffs_ext_tags tags; + int chunk; + int offset_chunk; + u8 *data_bytes = (u8 *) data; + + if (!dev->checkpt_buffer) + return 0; + + if (dev->checkpt_open_write) + return -1; + + while (i < n_bytes) { + + if (dev->checkpt_byte_offs < 0 || + dev->checkpt_byte_offs >= dev->data_bytes_per_chunk) { + + if (dev->checkpt_cur_block < 0) { + yaffs2_checkpt_find_block(dev); + dev->checkpt_cur_chunk = 0; + } + + /* Bail out if we can't find a checpoint block */ + if (dev->checkpt_cur_block < 0) + break; + + chunk = dev->checkpt_cur_block * + dev->param.chunks_per_block + + dev->checkpt_cur_chunk; + + offset_chunk = apply_chunk_offset(dev, chunk); + dev->n_page_reads++; + + /* Read in the next chunk */ + dev->tagger.read_chunk_tags_fn(dev, + offset_chunk, + dev->checkpt_buffer, + &tags); + + /* Bail out if the chunk is corrupted. */ + if (tags.chunk_id != (dev->checkpt_page_seq + 1) || + tags.ecc_result > YAFFS_ECC_RESULT_FIXED || + tags.seq_number != YAFFS_SEQUENCE_CHECKPOINT_DATA) + break; + + /* Bail out if it is not a checkpoint chunk. */ + if(!yaffs2_checkpt_check_chunk_hdr(dev)) + break; + + dev->checkpt_page_seq++; + dev->checkpt_cur_chunk++; + + if (dev->checkpt_cur_chunk >= + dev->param.chunks_per_block) + dev->checkpt_cur_block = -1; + + } + + *data_bytes = dev->checkpt_buffer[dev->checkpt_byte_offs]; + dev->checkpt_sum += *data_bytes; + dev->checkpt_xor ^= *data_bytes; + dev->checkpt_byte_offs++; + i++; + data_bytes++; + dev->checkpt_byte_count++; + } + + return i; /* Number of bytes read */ +} + +int yaffs_checkpt_close(struct yaffs_dev *dev) +{ + int i; + + if (dev->checkpt_open_write) { + if (dev->checkpt_byte_offs != + sizeof(sizeof(struct yaffs_checkpt_chunk_hdr))) + yaffs2_checkpt_flush_buffer(dev); + } else if (dev->checkpt_block_list) { + for (i = 0; + i < dev->blocks_in_checkpt && + dev->checkpt_block_list[i] >= 0; i++) { + int blk = dev->checkpt_block_list[i]; + struct yaffs_block_info *bi = NULL; + + if (dev->internal_start_block <= blk && + blk <= dev->internal_end_block) + bi = yaffs_get_block_info(dev, blk); + if (bi && bi->block_state == YAFFS_BLOCK_STATE_EMPTY) + bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT; + } + } + + dev->n_free_chunks -= + dev->blocks_in_checkpt * dev->param.chunks_per_block; + dev->n_erased_blocks -= dev->blocks_in_checkpt; + + yaffs_trace(YAFFS_TRACE_CHECKPOINT, "checkpoint byte count %d", + dev->checkpt_byte_count); + + if (dev->checkpt_buffer) + return 1; + else + return 0; +} + +int yaffs2_checkpt_invalidate_stream(struct yaffs_dev *dev) +{ + /* Erase the checkpoint data */ + + yaffs_trace(YAFFS_TRACE_CHECKPOINT, + "checkpoint invalidate of %d blocks", + dev->blocks_in_checkpt); + + return yaffs_checkpt_erase(dev); +} diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_checkptrw.h b/target/linux/generic/files/fs/yaffs2/yaffs_checkptrw.h new file mode 100644 index 0000000..cdbaba7 --- /dev/null +++ b/target/linux/generic/files/fs/yaffs2/yaffs_checkptrw.h @@ -0,0 +1,33 @@ +/* + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + */ + +#ifndef __YAFFS_CHECKPTRW_H__ +#define __YAFFS_CHECKPTRW_H__ + +#include "yaffs_guts.h" + +int yaffs2_checkpt_open(struct yaffs_dev *dev, int writing); + +int yaffs2_checkpt_wr(struct yaffs_dev *dev, const void *data, int n_bytes); + +int yaffs2_checkpt_rd(struct yaffs_dev *dev, void *data, int n_bytes); + +int yaffs2_get_checkpt_sum(struct yaffs_dev *dev, u32 * sum); + +int yaffs_checkpt_close(struct yaffs_dev *dev); + +int yaffs2_checkpt_invalidate_stream(struct yaffs_dev *dev); + +#endif diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_ecc.c b/target/linux/generic/files/fs/yaffs2/yaffs_ecc.c new file mode 100644 index 0000000..9294107 --- /dev/null +++ b/target/linux/generic/files/fs/yaffs2/yaffs_ecc.c @@ -0,0 +1,281 @@ +/* + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning + * + * 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 code implements the ECC algorithm used in SmartMedia. + * + * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes. + * The two unused bit are set to 1. + * The ECC can correct single bit errors in a 256-byte page of data. Thus, two + * such ECC blocks are used on a 512-byte NAND page. + * + */ + +#include "yportenv.h" + +#include "yaffs_ecc.h" + +/* Table generated by gen-ecc.c + * Using a table means we do not have to calculate p1..p4 and p1'..p4' + * for each byte of data. These are instead provided in a table in bits7..2. + * Bit 0 of each entry indicates whether the entry has an odd or even parity, + * and therefore this bytes influence on the line parity. + */ + +static const unsigned char column_parity_table[] = { + 0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69, + 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00, + 0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc, + 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95, + 0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0, + 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99, + 0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65, + 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c, + 0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc, + 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5, + 0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59, + 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30, + 0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55, + 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c, + 0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0, + 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9, + 0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0, + 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9, + 0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55, + 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c, + 0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59, + 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30, + 0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc, + 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5, + 0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65, + 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c, + 0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0, + 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99, + 0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc, + 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95, + 0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69, + 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00, +}; + + +/* Calculate the ECC for a 256-byte block of data */ +void yaffs_ecc_calc(const unsigned char *data, unsigned char *ecc) +{ + unsigned int i; + unsigned char col_parity = 0; + unsigned char line_parity = 0; + unsigned char line_parity_prime = 0; + unsigned char t; + unsigned char b; + + for (i = 0; i < 256; i++) { + b = column_parity_table[*data++]; + col_parity ^= b; + + if (b & 0x01) { /* odd number of bits in the byte */ + line_parity ^= i; + line_parity_prime ^= ~i; + } + } + + ecc[2] = (~col_parity) | 0x03; + + t = 0; + if (line_parity & 0x80) + t |= 0x80; + if (line_parity_prime & 0x80) + t |= 0x40; + if (line_parity & 0x40) + t |= 0x20; + if (line_parity_prime & 0x40) + t |= 0x10; + if (line_parity & 0x20) + t |= 0x08; + if (line_parity_prime & 0x20) + t |= 0x04; + if (line_parity & 0x10) + t |= 0x02; + if (line_parity_prime & 0x10) + t |= 0x01; + ecc[1] = ~t; + + t = 0; + if (line_parity & 0x08) + t |= 0x80; + if (line_parity_prime & 0x08) + t |= 0x40; + if (line_parity & 0x04) + t |= 0x20; + if (line_parity_prime & 0x04) + t |= 0x10; + if (line_parity & 0x02) + t |= 0x08; + if (line_parity_prime & 0x02) + t |= 0x04; + if (line_parity & 0x01) + t |= 0x02; + if (line_parity_prime & 0x01) + t |= 0x01; + ecc[0] = ~t; + +} + +/* Correct the ECC on a 256 byte block of data */ + +int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc, + const unsigned char *test_ecc) +{ + unsigned char d0, d1, d2; /* deltas */ + + d0 = read_ecc[0] ^ test_ecc[0]; + d1 = read_ecc[1] ^ test_ecc[1]; + d2 = read_ecc[2] ^ test_ecc[2]; + + if ((d0 | d1 | d2) == 0) + return 0; /* no error */ + + if (((d0 ^ (d0 >> 1)) & 0x55) == 0x55 && + ((d1 ^ (d1 >> 1)) & 0x55) == 0x55 && + ((d2 ^ (d2 >> 1)) & 0x54) == 0x54) { + /* Single bit (recoverable) error in data */ + + unsigned byte; + unsigned bit; + + bit = byte = 0; + + if (d1 & 0x80) + byte |= 0x80; + if (d1 & 0x20) + byte |= 0x40; + if (d1 & 0x08) + byte |= 0x20; + if (d1 & 0x02) + byte |= 0x10; + if (d0 & 0x80) + byte |= 0x08; + if (d0 & 0x20) + byte |= 0x04; + if (d0 & 0x08) + byte |= 0x02; + if (d0 & 0x02) + byte |= 0x01; + + if (d2 & 0x80) + bit |= 0x04; + if (d2 & 0x20) + bit |= 0x02; + if (d2 & 0x08) + bit |= 0x01; + + data[byte] ^= (1 << bit); + + return 1; /* Corrected the error */ + } + + if ((hweight8(d0) + hweight8(d1) + hweight8(d2)) == 1) { + /* Reccoverable error in ecc */ + + read_ecc[0] = test_ecc[0]; + read_ecc[1] = test_ecc[1]; + read_ecc[2] = test_ecc[2]; + + return 1; /* Corrected the error */ + } + + /* Unrecoverable error */ + + return -1; + +} + +/* + * ECCxxxOther does ECC calcs on arbitrary n bytes of data + */ +void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes, + struct yaffs_ecc_other *ecc_other) +{ + unsigned int i; + unsigned char col_parity = 0; + unsigned line_parity = 0; + unsigned line_parity_prime = 0; + unsigned char b; + + for (i = 0; i < n_bytes; i++) { + b = column_parity_table[*data++]; + col_parity ^= b; + + if (b & 0x01) { + /* odd number of bits in the byte */ + line_parity ^= i; + line_parity_prime ^= ~i; + } + + } + + ecc_other->col_parity = (col_parity >> 2) & 0x3f; + ecc_other->line_parity = line_parity; + ecc_other->line_parity_prime = line_parity_prime; +} + +int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes, + struct yaffs_ecc_other *read_ecc, + const struct yaffs_ecc_other *test_ecc) +{ + unsigned char delta_col; /* column parity delta */ + unsigned delta_line; /* line parity delta */ + unsigned delta_line_prime; /* line parity delta */ + unsigned bit; + + delta_col = read_ecc->col_parity ^ test_ecc->col_parity; + delta_line = read_ecc->line_parity ^ test_ecc->line_parity; + delta_line_prime = + read_ecc->line_parity_prime ^ test_ecc->line_parity_prime; + + if ((delta_col | delta_line | delta_line_prime) == 0) + return 0; /* no error */ + + if (delta_line == ~delta_line_prime && + (((delta_col ^ (delta_col >> 1)) & 0x15) == 0x15)) { + /* Single bit (recoverable) error in data */ + + bit = 0; + + if (delta_col & 0x20) + bit |= 0x04; + if (delta_col & 0x08) + bit |= 0x02; + if (delta_col & 0x02) + bit |= 0x01; + + if (delta_line >= n_bytes) + return -1; + + data[delta_line] ^= (1 << bit); + + return 1; /* corrected */ + } + + if ((hweight32(delta_line) + + hweight32(delta_line_prime) + + hweight8(delta_col)) == 1) { + /* Reccoverable error in ecc */ + + *read_ecc = *test_ecc; + return 1; /* corrected */ + } + + /* Unrecoverable error */ + + return -1; +} diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_ecc.h b/target/linux/generic/files/fs/yaffs2/yaffs_ecc.h new file mode 100644 index 0000000..17d47bd --- /dev/null +++ b/target/linux/generic/files/fs/yaffs2/yaffs_ecc.h @@ -0,0 +1,44 @@ +/* + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + */ + +/* + * This code implements the ECC algorithm used in SmartMedia. + * + * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes. + * The two unused bit are set to 1. + * The ECC can correct single bit errors in a 256-byte page of data. + * Thus, two such ECC blocks are used on a 512-byte NAND page. + * + */ + +#ifndef __YAFFS_ECC_H__ +#define __YAFFS_ECC_H__ + +struct yaffs_ecc_other { + unsigned char col_parity; + unsigned line_parity; + unsigned line_parity_prime; +}; + +void yaffs_ecc_calc(const unsigned char *data, unsigned char *ecc); +int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc, + const unsigned char *test_ecc); + +void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes, + struct yaffs_ecc_other *ecc); +int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes, + struct yaffs_ecc_other *read_ecc, + const struct yaffs_ecc_other *test_ecc); +#endif diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_getblockinfo.h b/target/linux/generic/files/fs/yaffs2/yaffs_getblockinfo.h new file mode 100644 index 0000000..8fd0802 --- /dev/null +++ b/target/linux/generic/files/fs/yaffs2/yaffs_getblockinfo.h @@ -0,0 +1,35 @@ +/* + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + */ + +#ifndef __YAFFS_GETBLOCKINFO_H__ +#define __YAFFS_GETBLOCKINFO_H__ + +#include "yaffs_guts.h" +#include "yaffs_trace.h" + +/* Function to manipulate block info */ +static inline struct yaffs_block_info *yaffs_get_block_info(struct yaffs_dev + *dev, int blk) +{ + if (blk < dev->internal_start_block || blk > dev->internal_end_block) { + yaffs_trace(YAFFS_TRACE_ERROR, + "**>> yaffs: get_block_info block %d is not valid", + blk); + BUG(); + } + return &dev->block_info[blk - dev->internal_start_block]; +} + +#endif diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_guts.c b/target/linux/generic/files/fs/yaffs2/yaffs_guts.c new file mode 100644 index 0000000..89fb2a9 --- /dev/null +++ b/target/linux/generic/files/fs/yaffs2/yaffs_guts.c @@ -0,0 +1,5140 @@ +/* + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning + * + * 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. + */ + +#include "yportenv.h" +#include "yaffs_trace.h" + +#include "yaffs_guts.h" +#include "yaffs_getblockinfo.h" +#include "yaffs_tagscompat.h" +#include "yaffs_tagsmarshall.h" +#include "yaffs_nand.h" +#include "yaffs_yaffs1.h" +#include "yaffs_yaffs2.h" +#include "yaffs_bitmap.h" +#include "yaffs_verify.h" +#include "yaffs_nand.h" +#include "yaffs_packedtags2.h" +#include "yaffs_nameval.h" +#include "yaffs_allocator.h" +#include "yaffs_attribs.h" +#include "yaffs_summary.h" + +/* Note YAFFS_GC_GOOD_ENOUGH must be <= YAFFS_GC_PASSIVE_THRESHOLD */ +#define YAFFS_GC_GOOD_ENOUGH 2 +#define YAFFS_GC_PASSIVE_THRESHOLD 4 + +#include "yaffs_ecc.h" + +/* Forward declarations */ + +static int yaffs_wr_data_obj(struct yaffs_obj *in, int inode_chunk, + const u8 *buffer, int n_bytes, int use_reserve); + +static void yaffs_fix_null_name(struct yaffs_obj *obj, YCHAR *name, + int buffer_size); + +/* Function to calculate chunk and offset */ + +void yaffs_addr_to_chunk(struct yaffs_dev *dev, loff_t addr, + int *chunk_out, u32 *offset_out) +{ + int chunk; + u32 offset; + + chunk = (u32) (addr >> dev->chunk_shift); + + if (dev->chunk_div == 1) { + /* easy power of 2 case */ + offset = (u32) (addr & dev->chunk_mask); + } else { + /* Non power-of-2 case */ + + loff_t chunk_base; + + chunk /= dev->chunk_div; + + chunk_base = ((loff_t) chunk) * dev->data_bytes_per_chunk; + offset = (u32) (addr - chunk_base); + } + + *chunk_out = chunk; + *offset_out = offset; +} + +/* Function to return the number of shifts for a power of 2 greater than or + * equal to the given number + * Note we don't try to cater for all possible numbers and this does not have to + * be hellishly efficient. + */ + +static inline u32 calc_shifts_ceiling(u32 x) +{ + int extra_bits; + int shifts; + + shifts = extra_bits = 0; + + while (x > 1) { + if (x & 1) + extra_bits++; + x >>= 1; + shifts++; + } + + if (extra_bits) + shifts++; + + return shifts; +} + +/* Function to return the number of shifts to get a 1 in bit 0 + */ + +static inline u32 calc_shifts(u32 x) +{ + u32 shifts; + + shifts = 0; + + if (!x) + return 0; + + while (!(x & 1)) { + x >>= 1; + shifts++; + } + + return shifts; +} + +/* + * Temporary buffer manipulations. + */ + +static int yaffs_init_tmp_buffers(struct yaffs_dev *dev) +{ + int i; + u8 *buf = (u8 *) 1; + + memset(dev->temp_buffer, 0, sizeof(dev->temp_buffer)); + + for (i = 0; buf && i < YAFFS_N_TEMP_BUFFERS; i++) { + dev->temp_buffer[i].in_use = 0; + buf = kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS); + dev->temp_buffer[i].buffer = buf; + } + + return buf ? YAFFS_OK : YAFFS_FAIL; +} + +u8 *yaffs_get_temp_buffer(struct yaffs_dev * dev) +{ + int i; + + dev->temp_in_use++; + if (dev->temp_in_use > dev->max_temp) + dev->max_temp = dev->temp_in_use; + + for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) { + if (dev->temp_buffer[i].in_use == 0) { + dev->temp_buffer[i].in_use = 1; + return dev->temp_buffer[i].buffer; + } + } + + yaffs_trace(YAFFS_TRACE_BUFFERS, "Out of temp buffers"); + /* + * If we got here then we have to allocate an unmanaged one + * This is not good. + */ + + dev->unmanaged_buffer_allocs++; + return kmalloc(dev->data_bytes_per_chunk, GFP_NOFS); + +} + +void yaffs_release_temp_buffer(struct yaffs_dev *dev, u8 *buffer) +{ + int i; + + dev->temp_in_use--; + + for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) { + if (dev->temp_buffer[i].buffer == buffer) { + dev->temp_buffer[i].in_use = 0; + return; + } + } + + if (buffer) { + /* assume it is an unmanaged one. */ + yaffs_trace(YAFFS_TRACE_BUFFERS, + "Releasing unmanaged temp buffer"); + kfree(buffer); + dev->unmanaged_buffer_deallocs++; + } + +} + +/* + * Functions for robustisizing TODO + * + */ + +static void yaffs_handle_chunk_wr_ok(struct yaffs_dev *dev, int nand_chunk, + const u8 *data, + const struct yaffs_ext_tags *tags) +{ + (void) dev; + (void) nand_chunk; + (void) data; + (void) tags; +} + +static void yaffs_handle_chunk_update(struct yaffs_dev *dev, int nand_chunk, + const struct yaffs_ext_tags *tags) +{ + (void) dev; + (void) nand_chunk; + (void) tags; +} + +void yaffs_handle_chunk_error(struct yaffs_dev *dev, + struct yaffs_block_info *bi) +{ + if (!bi->gc_prioritise) { + bi->gc_prioritise = 1; + dev->has_pending_prioritised_gc = 1; + bi->chunk_error_strikes++; + + if (bi->chunk_error_strikes > 3) { + bi->needs_retiring = 1; /* Too many stikes, so retire */ + yaffs_trace(YAFFS_TRACE_ALWAYS, + "yaffs: Block struck out"); + + } + } +} + +static void yaffs_handle_chunk_wr_error(struct yaffs_dev *dev, int nand_chunk, + int erased_ok) +{ + int flash_block = nand_chunk / dev->param.chunks_per_block; + struct yaffs_block_info *bi = yaffs_get_block_info(dev, flash_block); + + yaffs_handle_chunk_error(dev, bi); + + if (erased_ok) { + /* Was an actual write failure, + * so mark the block for retirement.*/ + bi->needs_retiring = 1; + yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS, + "**>> Block %d needs retiring", flash_block); + } + + /* Delete the chunk */ + yaffs_chunk_del(dev, nand_chunk, 1, __LINE__); + yaffs_skip_rest_of_block(dev); +} + +/* + * Verification code + */ + +/* + * Simple hash function. Needs to have a reasonable spread + */ + +static inline int yaffs_hash_fn(int n) +{ + if (n < 0) + n = -n; + return n % YAFFS_NOBJECT_BUCKETS; +} + +/* + * Access functions to useful fake objects. + * Note that root might have a presence in NAND if permissions are set. + */ + +struct yaffs_obj *yaffs_root(struct yaffs_dev *dev) +{ + return dev->root_dir; +} + +struct yaffs_obj *yaffs_lost_n_found(struct yaffs_dev *dev) +{ + return dev->lost_n_found; +} + +/* + * Erased NAND checking functions + */ + +int yaffs_check_ff(u8 *buffer, int n_bytes) +{ + /* Horrible, slow implementation */ + while (n_bytes--) { + if (*buffer != 0xff) + return 0; + buffer++; + } + return 1; +} + +static int yaffs_check_chunk_erased(struct yaffs_dev *dev, int nand_chunk) +{ + int retval = YAFFS_OK; + u8 *data = yaffs_get_temp_buffer(dev); + struct yaffs_ext_tags tags; + int result; + + result = yaffs_rd_chunk_tags_nand(dev, nand_chunk, data, &tags); + + if (tags.ecc_result > YAFFS_ECC_RESULT_NO_ERROR) + retval = YAFFS_FAIL; + + if (!yaffs_check_ff(data, dev->data_bytes_per_chunk) || + tags.chunk_used) { + yaffs_trace(YAFFS_TRACE_NANDACCESS, + "Chunk %d not erased", nand_chunk); + retval = YAFFS_FAIL; + } + + yaffs_release_temp_buffer(dev, data); + + return retval; + +} + +static int yaffs_verify_chunk_written(struct yaffs_dev *dev, + int nand_chunk, + const u8 *data, + struct yaffs_ext_tags *tags) +{ + int retval = YAFFS_OK; + struct yaffs_ext_tags temp_tags; + u8 *buffer = yaffs_get_temp_buffer(dev); + int result; + + result = yaffs_rd_chunk_tags_nand(dev, nand_chunk, buffer, &temp_tags); + if (memcmp(buffer, data, dev->data_bytes_per_chunk) || + temp_tags.obj_id != tags->obj_id || + temp_tags.chunk_id != tags->chunk_id || + temp_tags.n_bytes != tags->n_bytes) + retval = YAFFS_FAIL; + + yaffs_release_temp_buffer(dev, buffer); + + return retval; +} + + +int yaffs_check_alloc_available(struct yaffs_dev *dev, int n_chunks) +{ + int reserved_chunks; + int reserved_blocks = dev->param.n_reserved_blocks; + int checkpt_blocks; + + checkpt_blocks = yaffs_calc_checkpt_blocks_required(dev); + + reserved_chunks = + (reserved_blocks + checkpt_blocks) * dev->param.chunks_per_block; + + return (dev->n_free_chunks > (reserved_chunks + n_chunks)); +} + +static int yaffs_find_alloc_block(struct yaffs_dev *dev) +{ + int i; + struct yaffs_block_info *bi; + + if (dev->n_erased_blocks < 1) { + /* Hoosterman we've got a problem. + * Can't get space to gc + */ + yaffs_trace(YAFFS_TRACE_ERROR, + "yaffs tragedy: no more erased blocks"); + + return -1; + } + + /* Find an empty block. */ + + for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) { + dev->alloc_block_finder++; + if (dev->alloc_block_finder < dev->internal_start_block + || dev->alloc_block_finder > dev->internal_end_block) { + dev->alloc_block_finder = dev->internal_start_block; + } + + bi = yaffs_get_block_info(dev, dev->alloc_block_finder); + + if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) { + bi->block_state = YAFFS_BLOCK_STATE_ALLOCATING; + dev->seq_number++; + bi->seq_number = dev->seq_number; + dev->n_erased_blocks--; + yaffs_trace(YAFFS_TRACE_ALLOCATE, + "Allocated block %d, seq %d, %d left" , + dev->alloc_block_finder, dev->seq_number, + dev->n_erased_blocks); + return dev->alloc_block_finder; + } + } + + yaffs_trace(YAFFS_TRACE_ALWAYS, + "yaffs tragedy: no more erased blocks, but there should have been %d", + dev->n_erased_blocks); + + return -1; +} + +static int yaffs_alloc_chunk(struct yaffs_dev *dev, int use_reserver, + struct yaffs_block_info **block_ptr) +{ + int ret_val; + struct yaffs_block_info *bi; + + if (dev->alloc_block < 0) { + /* Get next block to allocate off */ + dev->alloc_block = yaffs_find_alloc_block(dev); + dev->alloc_page = 0; + } + + if (!use_reserver && !yaffs_check_alloc_available(dev, 1)) { + /* No space unless we're allowed to use the reserve. */ + return -1; + } + + if (dev->n_erased_blocks < dev->param.n_reserved_blocks + && dev->alloc_page == 0) + yaffs_trace(YAFFS_TRACE_ALLOCATE, "Allocating reserve"); + + /* Next page please.... */ + if (dev->alloc_block >= 0) { + bi = yaffs_get_block_info(dev, dev->alloc_block); + + ret_val = (dev->alloc_block * dev->param.chunks_per_block) + + dev->alloc_page; + bi->pages_in_use++; + yaffs_set_chunk_bit(dev, dev->alloc_block, dev->alloc_page); + + dev->alloc_page++; + + dev->n_free_chunks--; + + /* If the block is full set the state to full */ + if (dev->alloc_page >= dev->param.chunks_per_block) { + bi->block_state = YAFFS_BLOCK_STATE_FULL; + dev->alloc_block = -1; + } + + if (block_ptr) + *block_ptr = bi; + + return ret_val; + } + + yaffs_trace(YAFFS_TRACE_ERROR, + "!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!"); + + return -1; +} + +static int yaffs_get_erased_chunks(struct yaffs_dev *dev) +{ + int n; + + n = dev->n_erased_blocks * dev->param.chunks_per_block; + + if (dev->alloc_block > 0) + n += (dev->param.chunks_per_block - dev->alloc_page); + + return n; + +} + +/* + * yaffs_skip_rest_of_block() skips over the rest of the allocation block + * if we don't want to write to it. + */ +void yaffs_skip_rest_of_block(struct yaffs_dev *dev) +{ + struct yaffs_block_info *bi; + + if (dev->alloc_block > 0) { + bi = yaffs_get_block_info(dev, dev->alloc_block); + if (bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING) { + bi->block_state = YAFFS_BLOCK_STATE_FULL; + dev->alloc_block = -1; + } + } +} + +static int yaffs_write_new_chunk(struct yaffs_dev *dev, + const u8 *data, + struct yaffs_ext_tags *tags, int use_reserver) +{ + int attempts = 0; + int write_ok = 0; + int chunk; + + yaffs2_checkpt_invalidate(dev); + + do { + struct yaffs_block_info *bi = 0; + int erased_ok = 0; + + chunk = yaffs_alloc_chunk(dev, use_reserver, &bi); + if (chunk < 0) { + /* no space */ + break; + } + + /* First check this chunk is erased, if it needs + * checking. The checking policy (unless forced + * always on) is as follows: + * + * Check the first page we try to write in a block. + * If the check passes then we don't need to check any + * more. If the check fails, we check again... + * If the block has been erased, we don't need to check. + * + * However, if the block has been prioritised for gc, + * then we think there might be something odd about + * this block and stop using it. + * + * Rationale: We should only ever see chunks that have + * not been erased if there was a partially written + * chunk due to power loss. This checking policy should + * catch that case with very few checks and thus save a + * lot of checks that are most likely not needed. + * + * Mods to the above + * If an erase check fails or the write fails we skip the + * rest of the block. + */ + + /* let's give it a try */ + attempts++; + + if (dev->param.always_check_erased) + bi->skip_erased_check = 0; + + if (!bi->skip_erased_check) { + erased_ok = yaffs_check_chunk_erased(dev, chunk); + if (erased_ok != YAFFS_OK) { + yaffs_trace(YAFFS_TRACE_ERROR, + "**>> yaffs chunk %d was not erased", + chunk); + + /* If not erased, delete this one, + * skip rest of block and + * try another chunk */ + yaffs_chunk_del(dev, chunk, 1, __LINE__); + yaffs_skip_rest_of_block(dev); + continue; + } + } + + write_ok = yaffs_wr_chunk_tags_nand(dev, chunk, data, tags); + + if (!bi->skip_erased_check) + write_ok = + yaffs_verify_chunk_written(dev, chunk, data, tags); + + if (write_ok != YAFFS_OK) { + /* Clean up aborted write, skip to next block and + * try another chunk */ + yaffs_handle_chunk_wr_error(dev, chunk, erased_ok); + continue; + } + + bi->skip_erased_check = 1; + + /* Copy the data into the robustification buffer */ + yaffs_handle_chunk_wr_ok(dev, chunk, data, tags); + + } while (write_ok != YAFFS_OK && + (yaffs_wr_attempts <= 0 || attempts <= yaffs_wr_attempts)); + + if (!write_ok) + chunk = -1; + + if (attempts > 1) { + yaffs_trace(YAFFS_TRACE_ERROR, + "**>> yaffs write required %d attempts", + attempts); + dev->n_retried_writes += (attempts - 1); + } + + return chunk; +} + +/* + * Block retiring for handling a broken block. + */ + +static void yaffs_retire_block(struct yaffs_dev *dev, int flash_block) +{ + struct yaffs_block_info *bi = yaffs_get_block_info(dev, flash_block); + + yaffs2_checkpt_invalidate(dev); + + yaffs2_clear_oldest_dirty_seq(dev, bi); + + if (yaffs_mark_bad(dev, flash_block) != YAFFS_OK) { + if (yaffs_erase_block(dev, flash_block) != YAFFS_OK) { + yaffs_trace(YAFFS_TRACE_ALWAYS, + "yaffs: Failed to mark bad and erase block %d", + flash_block); + } else { + struct yaffs_ext_tags tags; + int chunk_id = + flash_block * dev->param.chunks_per_block; + + u8 *buffer = yaffs_get_temp_buffer(dev); + + memset(buffer, 0xff, dev->data_bytes_per_chunk); + memset(&tags, 0, sizeof(tags)); + tags.seq_number = YAFFS_SEQUENCE_BAD_BLOCK; + if (dev->tagger.write_chunk_tags_fn(dev, chunk_id - + dev->chunk_offset, + buffer, + &tags) != YAFFS_OK) + yaffs_trace(YAFFS_TRACE_ALWAYS, + "yaffs: Failed to write bad block marker to block %d", + flash_block); + + yaffs_release_temp_buffer(dev, buffer); + } + } + + bi->block_state = YAFFS_BLOCK_STATE_DEAD; + bi->gc_prioritise = 0; + bi->needs_retiring = 0; + + dev->n_retired_blocks++; +} + +/*---------------- Name handling functions ------------*/ + +static void yaffs_load_name_from_oh(struct yaffs_dev *dev, YCHAR *name, + const YCHAR *oh_name, int buff_size) +{ +#ifdef CONFIG_YAFFS_AUTO_UNICODE + if (dev->param.auto_unicode) { + if (*oh_name) { + /* It is an ASCII name, do an ASCII to + * unicode conversion */ + const char *ascii_oh_name = (const char *)oh_name; + int n = buff_size - 1; + while (n > 0 && *ascii_oh_name) { + *name = *ascii_oh_name; + name++; + ascii_oh_name++; + n--; + } + } else { + strncpy(name, oh_name + 1, buff_size - 1); + } + } else { +#else + (void) dev; + { +#endif + strncpy(name, oh_name, buff_size - 1); + } +} + +static void yaffs_load_oh_from_name(struct yaffs_dev *dev, YCHAR *oh_name, + const YCHAR *name) +{ +#ifdef CONFIG_YAFFS_AUTO_UNICODE + + int is_ascii; + const YCHAR *w; + + if (dev->param.auto_unicode) { + + is_ascii = 1; + w = name; + + /* Figure out if the name will fit in ascii character set */ + while (is_ascii && *w) { + if ((*w) & 0xff00) + is_ascii = 0; + w++; + } + + if (is_ascii) { + /* It is an ASCII name, so convert unicode to ascii */ + char *ascii_oh_name = (char *)oh_name; + int n = YAFFS_MAX_NAME_LENGTH - 1; + while (n > 0 && *name) { + *ascii_oh_name = *name; + name++; + ascii_oh_name++; + n--; + } + } else { + /* Unicode name, so save starting at the second YCHAR */ + *oh_name = 0; + strncpy(oh_name + 1, name, YAFFS_MAX_NAME_LENGTH - 2); + } + } else { +#else + dev = dev; + { +#endif + strncpy(oh_name, name, YAFFS_MAX_NAME_LENGTH - 1); + } +} + +static u16 yaffs_calc_name_sum(const YCHAR *name) +{ + u16 sum = 0; + u16 i = 1; + + if (!name) + return 0; + + while ((*name) && i < (YAFFS_MAX_NAME_LENGTH / 2)) { + + /* 0x1f mask is case insensitive */ + sum += ((*name) & 0x1f) * i; + i++; + name++; + } + return sum; +} + + +void yaffs_set_obj_name(struct yaffs_obj *obj, const YCHAR * name) +{ + memset(obj->short_name, 0, sizeof(obj->short_name)); + + if (name && !name[0]) { + yaffs_fix_null_name(obj, obj->short_name, + YAFFS_SHORT_NAME_LENGTH); + name = obj->short_name; + } else if (name && + strnlen(name, YAFFS_SHORT_NAME_LENGTH + 1) <= + YAFFS_SHORT_NAME_LENGTH) { + strcpy(obj->short_name, name); + } + + obj->sum = yaffs_calc_name_sum(name); +} + +void yaffs_set_obj_name_from_oh(struct yaffs_obj *obj, + const struct yaffs_obj_hdr *oh) +{ +#ifdef CONFIG_YAFFS_AUTO_UNICODE + YCHAR tmp_name[YAFFS_MAX_NAME_LENGTH + 1]; + memset(tmp_name, 0, sizeof(tmp_name)); + yaffs_load_name_from_oh(obj->my_dev, tmp_name, oh->name, + YAFFS_MAX_NAME_LENGTH + 1); + yaffs_set_obj_name(obj, tmp_name); +#else + yaffs_set_obj_name(obj, oh->name); +#endif +} + +loff_t yaffs_max_file_size(struct yaffs_dev *dev) +{ + if(sizeof(loff_t) < 8) + return YAFFS_MAX_FILE_SIZE_32; + else + return ((loff_t) YAFFS_MAX_CHUNK_ID) * dev->data_bytes_per_chunk; +} + +/*-------------------- TNODES ------------------- + + * List of spare tnodes + * The list is hooked together using the first pointer + * in the tnode. + */ + +struct yaffs_tnode *yaffs_get_tnode(struct yaffs_dev *dev) +{ + struct yaffs_tnode *tn = yaffs_alloc_raw_tnode(dev); + + if (tn) { + memset(tn, 0, dev->tnode_size); + dev->n_tnodes++; + } + + dev->checkpoint_blocks_required = 0; /* force recalculation */ + + return tn; +} + +/* FreeTnode frees up a tnode and puts it back on the free list */ +static void yaffs_free_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn) +{ + yaffs_free_raw_tnode(dev, tn); + dev->n_tnodes--; + dev->checkpoint_blocks_required = 0; /* force recalculation */ +} + +static void yaffs_deinit_tnodes_and_objs(struct yaffs_dev *dev) +{ + yaffs_deinit_raw_tnodes_and_objs(dev); + dev->n_obj = 0; + dev->n_tnodes = 0; +} + +static void yaffs_load_tnode_0(struct yaffs_dev *dev, struct yaffs_tnode *tn, + unsigned pos, unsigned val) +{ + u32 *map = (u32 *) tn; + u32 bit_in_map; + u32 bit_in_word; + u32 word_in_map; + u32 mask; + + pos &= YAFFS_TNODES_LEVEL0_MASK; + val >>= dev->chunk_grp_bits; + + bit_in_map = pos * dev->tnode_width; + word_in_map = bit_in_map / 32; + bit_in_word = bit_in_map & (32 - 1); + + mask = dev->tnode_mask << bit_in_word; + + map[word_in_map] &= ~mask; + map[word_in_map] |= (mask & (val << bit_in_word)); + + if (dev->tnode_width > (32 - bit_in_word)) { + bit_in_word = (32 - bit_in_word); + word_in_map++; + mask = + dev->tnode_mask >> bit_in_word; + map[word_in_map] &= ~mask; + map[word_in_map] |= (mask & (val >> bit_in_word)); + } +} + +u32 yaffs_get_group_base(struct yaffs_dev *dev, struct yaffs_tnode *tn, + unsigned pos) +{ + u32 *map = (u32 *) tn; + u32 bit_in_map; + u32 bit_in_word; + u32 word_in_map; + u32 val; + + pos &= YAFFS_TNODES_LEVEL0_MASK; + + bit_in_map = pos * dev->tnode_width; + word_in_map = bit_in_map / 32; + bit_in_word = bit_in_map & (32 - 1); + + val = map[word_in_map] >> bit_in_word; + + if (dev->tnode_width > (32 - bit_in_word)) { + bit_in_word = (32 - bit_in_word); + word_in_map++; + val |= (map[word_in_map] << bit_in_word); + } + + val &= dev->tnode_mask; + val <<= dev->chunk_grp_bits; + + return val; +} + +/* ------------------- End of individual tnode manipulation -----------------*/ + +/* ---------Functions to manipulate the look-up tree (made up of tnodes) ------ + * The look up tree is represented by the top tnode and the number of top_level + * in the tree. 0 means only the level 0 tnode is in the tree. + */ + +/* FindLevel0Tnode finds the level 0 tnode, if one exists. */ +struct yaffs_tnode *yaffs_find_tnode_0(struct yaffs_dev *dev, + struct yaffs_file_var *file_struct, + u32 chunk_id) +{ + struct yaffs_tnode *tn = file_struct->top; + u32 i; + int required_depth; + int level = file_struct->top_level; + + (void) dev; + + /* Check sane level and chunk Id */ + if (level < 0 || level > YAFFS_TNODES_MAX_LEVEL) + return NULL; + + if (chunk_id > YAFFS_MAX_CHUNK_ID) + return NULL; + + /* First check we're tall enough (ie enough top_level) */ + + i = chunk_id >> YAFFS_TNODES_LEVEL0_BITS; + required_depth = 0; + while (i) { + i >>= YAFFS_TNODES_INTERNAL_BITS; + required_depth++; + } + + if (required_depth > file_struct->top_level) + return NULL; /* Not tall enough, so we can't find it */ + + /* Traverse down to level 0 */ + while (level > 0 && tn) { + tn = tn->internal[(chunk_id >> + (YAFFS_TNODES_LEVEL0_BITS + + (level - 1) * + YAFFS_TNODES_INTERNAL_BITS)) & + YAFFS_TNODES_INTERNAL_MASK]; + level--; + } + + return tn; +} + +/* add_find_tnode_0 finds the level 0 tnode if it exists, + * otherwise first expands the tree. + * This happens in two steps: + * 1. If the tree isn't tall enough, then make it taller. + * 2. Scan down the tree towards the level 0 tnode adding tnodes if required. + * + * Used when modifying the tree. + * + * If the tn argument is NULL, then a fresh tnode will be added otherwise the + * specified tn will be plugged into the ttree. + */ + +struct yaffs_tnode *yaffs_add_find_tnode_0(struct yaffs_dev *dev, + struct yaffs_file_var *file_struct, + u32 chunk_id, + struct yaffs_tnode *passed_tn) +{ + int required_depth; + int i; + int l; + struct yaffs_tnode *tn; + u32 x; + + /* Check sane level and page Id */ + if (file_struct->top_level < 0 || + file_struct->top_level > YAFFS_TNODES_MAX_LEVEL) + return NULL; + + if (chunk_id > YAFFS_MAX_CHUNK_ID) + return NULL; + + /* First check we're tall enough (ie enough top_level) */ + + x = chunk_id >> YAFFS_TNODES_LEVEL0_BITS; + required_depth = 0; + while (x) { + x >>= YAFFS_TNODES_INTERNAL_BITS; + required_depth++; + } + + if (required_depth > file_struct->top_level) { + /* Not tall enough, gotta make the tree taller */ + for (i = file_struct->top_level; i < required_depth; i++) { + + tn = yaffs_get_tnode(dev); + + if (tn) { + tn->internal[0] = file_struct->top; + file_struct->top = tn; + file_struct->top_level++; + } else { + yaffs_trace(YAFFS_TRACE_ERROR, + "yaffs: no more tnodes"); + return NULL; + } + } + } + + /* Traverse down to level 0, adding anything we need */ + + l = file_struct->top_level; + tn = file_struct->top; + + if (l > 0) { + while (l > 0 && tn) { + x = (chunk_id >> + (YAFFS_TNODES_LEVEL0_BITS + + (l - 1) * YAFFS_TNODES_INTERNAL_BITS)) & + YAFFS_TNODES_INTERNAL_MASK; + + if ((l > 1) && !tn->internal[x]) { + /* Add missing non-level-zero tnode */ + tn->internal[x] = yaffs_get_tnode(dev); + if (!tn->internal[x]) + return NULL; + } else if (l == 1) { + /* Looking from level 1 at level 0 */ + if (passed_tn) { + /* If we already have one, release it */ + if (tn->internal[x]) + yaffs_free_tnode(dev, + tn->internal[x]); + tn->internal[x] = passed_tn; + + } else if (!tn->internal[x]) { + /* Don't have one, none passed in */ + tn->internal[x] = yaffs_get_tnode(dev); + if (!tn->internal[x]) + return NULL; + } + } + + tn = tn->internal[x]; + l--; + } + } else { + /* top is level 0 */ + if (passed_tn) { + memcpy(tn, passed_tn, + (dev->tnode_width * YAFFS_NTNODES_LEVEL0) / 8); + yaffs_free_tnode(dev, passed_tn); + } + } + + return tn; +} + +static int yaffs_tags_match(const struct yaffs_ext_tags *tags, int obj_id, + int chunk_obj) +{ + return (tags->chunk_id == chunk_obj && + tags->obj_id == obj_id && + !tags->is_deleted) ? 1 : 0; + +} + +static int yaffs_find_chunk_in_group(struct yaffs_dev *dev, int the_chunk, + struct yaffs_ext_tags *tags, int obj_id, + int inode_chunk) +{ + int j; + + for (j = 0; the_chunk && j < dev->chunk_grp_size; j++) { + if (yaffs_check_chunk_bit + (dev, the_chunk / dev->param.chunks_per_block, + the_chunk % dev->param.chunks_per_block)) { + + if (dev->chunk_grp_size == 1) + return the_chunk; + else { + yaffs_rd_chunk_tags_nand(dev, the_chunk, NULL, + tags); + if (yaffs_tags_match(tags, + obj_id, inode_chunk)) { + /* found it; */ + return the_chunk; + } + } + } + the_chunk++; + } + return -1; +} + +int yaffs_find_chunk_in_file(struct yaffs_obj *in, int inode_chunk, + struct yaffs_ext_tags *tags) +{ + /*Get the Tnode, then get the level 0 offset chunk offset */ + struct yaffs_tnode *tn; + int the_chunk = -1; + struct yaffs_ext_tags local_tags; + int ret_val = -1; + struct yaffs_dev *dev = in->my_dev; + + if (!tags) { + /* Passed a NULL, so use our own tags space */ + tags = &local_tags; + } + + tn = yaffs_find_tnode_0(dev, &in->variant.file_variant, inode_chunk); + + if (!tn) + return ret_val; + + the_chunk = yaffs_get_group_base(dev, tn, inode_chunk); + + ret_val = yaffs_find_chunk_in_group(dev, the_chunk, tags, in->obj_id, + inode_chunk); + return ret_val; +} + +static int yaffs_find_del_file_chunk(struct yaffs_obj *in, int inode_chunk, + struct yaffs_ext_tags *tags) +{ + /* Get the Tnode, then get the level 0 offset chunk offset */ + struct yaffs_tnode *tn; + int the_chunk = -1; + struct yaffs_ext_tags local_tags; + struct yaffs_dev *dev = in->my_dev; + int ret_val = -1; + + if (!tags) { + /* Passed a NULL, so use our own tags space */ + tags = &local_tags; + } + + tn = yaffs_find_tnode_0(dev, &in->variant.file_variant, inode_chunk); + + if (!tn) + return ret_val; + + the_chunk = yaffs_get_group_base(dev, tn, inode_chunk); + + ret_val = yaffs_find_chunk_in_group(dev, the_chunk, tags, in->obj_id, + inode_chunk); + + /* Delete the entry in the filestructure (if found) */ + if (ret_val != -1) + yaffs_load_tnode_0(dev, tn, inode_chunk, 0); + + return ret_val; +} + +int yaffs_put_chunk_in_file(struct yaffs_obj *in, int inode_chunk, + int nand_chunk, int in_scan) +{ + /* NB in_scan is zero unless scanning. + * For forward scanning, in_scan is > 0; + * for backward scanning in_scan is < 0 + * + * nand_chunk = 0 is a dummy insert to make sure the tnodes are there. + */ + + struct yaffs_tnode *tn; + struct yaffs_dev *dev = in->my_dev; + int existing_cunk; + struct yaffs_ext_tags existing_tags; + struct yaffs_ext_tags new_tags; + unsigned existing_serial, new_serial; + + if (in->variant_type != YAFFS_OBJECT_TYPE_FILE) { + /* Just ignore an attempt at putting a chunk into a non-file + * during scanning. + * If it is not during Scanning then something went wrong! + */ + if (!in_scan) { + yaffs_trace(YAFFS_TRACE_ERROR, + "yaffs tragedy:attempt to put data chunk into a non-file" + ); + BUG(); + } + + yaffs_chunk_del(dev, nand_chunk, 1, __LINE__); + return YAFFS_OK; + } + + tn = yaffs_add_find_tnode_0(dev, + &in->variant.file_variant, + inode_chunk, NULL); + if (!tn) + return YAFFS_FAIL; + + if (!nand_chunk) + /* Dummy insert, bail now */ + return YAFFS_OK; + + existing_cunk = yaffs_get_group_base(dev, tn, inode_chunk); + + if (in_scan != 0) { + /* If we're scanning then we need to test for duplicates + * NB This does not need to be efficient since it should only + * happen when the power fails during a write, then only one + * chunk should ever be affected. + * + * Correction for YAFFS2: This could happen quite a lot and we + * need to think about efficiency! TODO + * Update: For backward scanning we don't need to re-read tags + * so this is quite cheap. + */ + + if (existing_cunk > 0) { + /* NB Right now existing chunk will not be real + * chunk_id if the chunk group size > 1 + * thus we have to do a FindChunkInFile to get the + * real chunk id. + * + * We have a duplicate now we need to decide which + * one to use: + * + * Backwards scanning YAFFS2: The old one is what + * we use, dump the new one. + * YAFFS1: Get both sets of tags and compare serial + * numbers. + */ + + if (in_scan > 0) { + /* Only do this for forward scanning */ + yaffs_rd_chunk_tags_nand(dev, + nand_chunk, + NULL, &new_tags); + + /* Do a proper find */ + existing_cunk = + yaffs_find_chunk_in_file(in, inode_chunk, + &existing_tags); + } + + if (existing_cunk <= 0) { + /*Hoosterman - how did this happen? */ + + yaffs_trace(YAFFS_TRACE_ERROR, + "yaffs tragedy: existing chunk < 0 in scan" + ); + + } + + /* NB The deleted flags should be false, otherwise + * the chunks will not be loaded during a scan + */ + + if (in_scan > 0) { + new_serial = new_tags.serial_number; + existing_serial = existing_tags.serial_number; + } + + if ((in_scan > 0) && + (existing_cunk <= 0 || + ((existing_serial + 1) & 3) == new_serial)) { + /* Forward scanning. + * Use new + * Delete the old one and drop through to + * update the tnode + */ + yaffs_chunk_del(dev, existing_cunk, 1, + __LINE__); + } else { + /* Backward scanning or we want to use the + * existing one + * Delete the new one and return early so that + * the tnode isn't changed + */ + yaffs_chunk_del(dev, nand_chunk, 1, __LINE__); + return YAFFS_OK; + } + } + + } + + if (existing_cunk == 0) + in->n_data_chunks++; + + yaffs_load_tnode_0(dev, tn, inode_chunk, nand_chunk); + + return YAFFS_OK; +} + +static void yaffs_soft_del_chunk(struct yaffs_dev *dev, int chunk) +{ + struct yaffs_block_info *the_block; + unsigned block_no; + + yaffs_trace(YAFFS_TRACE_DELETION, "soft delete chunk %d", chunk); + + block_no = chunk / dev->param.chunks_per_block; + the_block = yaffs_get_block_info(dev, block_no); + if (the_block) { + the_block->soft_del_pages++; + dev->n_free_chunks++; + yaffs2_update_oldest_dirty_seq(dev, block_no, the_block); + } +} + +/* SoftDeleteWorker scans backwards through the tnode tree and soft deletes all + * the chunks in the file. + * All soft deleting does is increment the block's softdelete count and pulls + * the chunk out of the tnode. + * Thus, essentially this is the same as DeleteWorker except that the chunks + * are soft deleted. + */ + +static int yaffs_soft_del_worker(struct yaffs_obj *in, struct yaffs_tnode *tn, + u32 level, int chunk_offset) +{ + int i; + int the_chunk; + int all_done = 1; + struct yaffs_dev *dev = in->my_dev; + + if (!tn) + return 1; + + if (level > 0) { + for (i = YAFFS_NTNODES_INTERNAL - 1; + all_done && i >= 0; + i--) { + if (tn->internal[i]) { + all_done = + yaffs_soft_del_worker(in, + tn->internal[i], + level - 1, + (chunk_offset << + YAFFS_TNODES_INTERNAL_BITS) + + i); + if (all_done) { + yaffs_free_tnode(dev, + tn->internal[i]); + tn->internal[i] = NULL; + } else { + /* Can this happen? */ + } + } + } + return (all_done) ? 1 : 0; + } + + /* level 0 */ + for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0; i--) { + the_chunk = yaffs_get_group_base(dev, tn, i); + if (the_chunk) { + yaffs_soft_del_chunk(dev, the_chunk); + yaffs_load_tnode_0(dev, tn, i, 0); + } + } + return 1; +} + +static void yaffs_remove_obj_from_dir(struct yaffs_obj *obj) +{ + struct yaffs_dev *dev = obj->my_dev; + struct yaffs_obj *parent; + + yaffs_verify_obj_in_dir(obj); + parent = obj->parent; + + yaffs_verify_dir(parent); + + if (dev && dev->param.remove_obj_fn) + dev->param.remove_obj_fn(obj); + + list_del_init(&obj->siblings); + obj->parent = NULL; + + yaffs_verify_dir(parent); +} + +void yaffs_add_obj_to_dir(struct yaffs_obj *directory, struct yaffs_obj *obj) +{ + if (!directory) { + yaffs_trace(YAFFS_TRACE_ALWAYS, + "tragedy: Trying to add an object to a null pointer directory" + ); + BUG(); + return; + } + if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { + yaffs_trace(YAFFS_TRACE_ALWAYS, + "tragedy: Trying to add an object to a non-directory" + ); + BUG(); + } + + if (obj->siblings.prev == NULL) { + /* Not initialised */ + BUG(); + } + + yaffs_verify_dir(directory); + + yaffs_remove_obj_from_dir(obj); + + /* Now add it */ + list_add(&obj->siblings, &directory->variant.dir_variant.children); + obj->parent = directory; + + if (directory == obj->my_dev->unlinked_dir + || directory == obj->my_dev->del_dir) { + obj->unlinked = 1; + obj->my_dev->n_unlinked_files++; + obj->rename_allowed = 0; + } + + yaffs_verify_dir(directory); + yaffs_verify_obj_in_dir(obj); +} + +static int yaffs_change_obj_name(struct yaffs_obj *obj, + struct yaffs_obj *new_dir, + const YCHAR *new_name, int force, int shadows) +{ + int unlink_op; + int del_op; + struct yaffs_obj *existing_target; + + if (new_dir == NULL) + new_dir = obj->parent; /* use the old directory */ + + if (new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { + yaffs_trace(YAFFS_TRACE_ALWAYS, + "tragedy: yaffs_change_obj_name: new_dir is not a directory" + ); + BUG(); + } + + unlink_op = (new_dir == obj->my_dev->unlinked_dir); + del_op = (new_dir == obj->my_dev->del_dir); + + existing_target = yaffs_find_by_name(new_dir, new_name); + + /* If the object is a file going into the unlinked directory, + * then it is OK to just stuff it in since duplicate names are OK. + * else only proceed if the new name does not exist and we're putting + * it into a directory. + */ + if (!(unlink_op || del_op || force || + shadows > 0 || !existing_target) || + new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) + return YAFFS_FAIL; + + yaffs_set_obj_name(obj, new_name); + obj->dirty = 1; + yaffs_add_obj_to_dir(new_dir, obj); + + if (unlink_op) + obj->unlinked = 1; + + /* If it is a deletion then we mark it as a shrink for gc */ + if (yaffs_update_oh(obj, new_name, 0, del_op, shadows, NULL) >= 0) + return YAFFS_OK; + + return YAFFS_FAIL; +} + +/*------------------------ Short Operations Cache ------------------------------ + * In many situations where there is no high level buffering a lot of + * reads might be short sequential reads, and a lot of writes may be short + * sequential writes. eg. scanning/writing a jpeg file. + * In these cases, a short read/write cache can provide a huge perfomance + * benefit with dumb-as-a-rock code. + * In Linux, the page cache provides read buffering and the short op cache + * provides write buffering. + * + * There are a small number (~10) of cache chunks per device so that we don't + * need a very intelligent search. + */ + +static int yaffs_obj_cache_dirty(struct yaffs_obj *obj) +{ + struct yaffs_dev *dev = obj->my_dev; + int i; + struct yaffs_cache *cache; + int n_caches = obj->my_dev->param.n_caches; + + for (i = 0; i < n_caches; i++) { + cache = &dev->cache[i]; + if (cache->object == obj && cache->dirty) + return 1; + } + + return 0; +} + +static void yaffs_flush_single_cache(struct yaffs_cache *cache, int discard) +{ + + if (!cache || cache->locked) + return; + + /* Write it out and free it up if need be.*/ + if (cache->dirty) { + yaffs_wr_data_obj(cache->object, + cache->chunk_id, + cache->data, + cache->n_bytes, + 1); + + cache->dirty = 0; + } + + if (discard) + cache->object = NULL; +} + +static void yaffs_flush_file_cache(struct yaffs_obj *obj, int discard) +{ + struct yaffs_dev *dev = obj->my_dev; + int i; + struct yaffs_cache *cache; + int n_caches = obj->my_dev->param.n_caches; + + if (n_caches < 1) + return; + + + /* Find the chunks for this object and flush them. */ + for (i = 0; i < n_caches; i++) { + cache = &dev->cache[i]; + if (cache->object == obj) + yaffs_flush_single_cache(cache, discard); + } + +} + + +void yaffs_flush_whole_cache(struct yaffs_dev *dev, int discard) +{ + struct yaffs_obj *obj; + int n_caches = dev->param.n_caches; + int i; + + /* Find a dirty object in the cache and flush it... + * until there are no further dirty objects. + */ + do { + obj = NULL; + for (i = 0; i < n_caches && !obj; i++) { + if (dev->cache[i].object && dev->cache[i].dirty) + obj = dev->cache[i].object; + } + if (obj) + yaffs_flush_file_cache(obj, discard); + } while (obj); + +} + +/* Grab us an unused cache chunk for use. + * First look for an empty one. + * Then look for the least recently used non-dirty one. + * Then look for the least recently used dirty one...., flush and look again. + */ +static struct yaffs_cache *yaffs_grab_chunk_worker(struct yaffs_dev *dev) +{ + int i; + + if (dev->param.n_caches > 0) { + for (i = 0; i < dev->param.n_caches; i++) { + if (!dev->cache[i].object) + return &dev->cache[i]; + } + } + + return NULL; +} + +static struct yaffs_cache *yaffs_grab_chunk_cache(struct yaffs_dev *dev) +{ + struct yaffs_cache *cache; + int usage; + int i; + + if (dev->param.n_caches < 1) + return NULL; + + /* First look for an unused cache */ + + cache = yaffs_grab_chunk_worker(dev); + + if (cache) + return cache; + + /* + * Thery were all in use. + * Find the LRU cache and flush it if it is dirty. + */ + + usage = -1; + cache = NULL; + + for (i = 0; i < dev->param.n_caches; i++) { + if (dev->cache[i].object && + !dev->cache[i].locked && + (dev->cache[i].last_use < usage || !cache)) { + usage = dev->cache[i].last_use; + cache = &dev->cache[i]; + } + } + +#if 1 + yaffs_flush_single_cache(cache, 1); +#else + yaffs_flush_file_cache(cache->object, 1); + cache = yaffs_grab_chunk_worker(dev); +#endif + + return cache; +} + +/* Find a cached chunk */ +static struct yaffs_cache *yaffs_find_chunk_cache(const struct yaffs_obj *obj, + int chunk_id) +{ + struct yaffs_dev *dev = obj->my_dev; + int i; + + if (dev->param.n_caches < 1) + return NULL; + + for (i = 0; i < dev->param.n_caches; i++) { + if (dev->cache[i].object == obj && + dev->cache[i].chunk_id == chunk_id) { + dev->cache_hits++; + + return &dev->cache[i]; + } + } + return NULL; +} + +/* Mark the chunk for the least recently used algorithym */ +static void yaffs_use_cache(struct yaffs_dev *dev, struct yaffs_cache *cache, + int is_write) +{ + int i; + + if (dev->param.n_caches < 1) + return; + + if (dev->cache_last_use < 0 || + dev->cache_last_use > 100000000) { + /* Reset the cache usages */ + for (i = 1; i < dev->param.n_caches; i++) + dev->cache[i].last_use = 0; + + dev->cache_last_use = 0; + } + dev->cache_last_use++; + cache->last_use = dev->cache_last_use; + + if (is_write) + cache->dirty = 1; +} + +/* Invalidate a single cache page. + * Do this when a whole page gets written, + * ie the short cache for this page is no longer valid. + */ +static void yaffs_invalidate_chunk_cache(struct yaffs_obj *object, int chunk_id) +{ + struct yaffs_cache *cache; + + if (object->my_dev->param.n_caches > 0) { + cache = yaffs_find_chunk_cache(object, chunk_id); + + if (cache) + cache->object = NULL; + } +} + +/* Invalidate all the cache pages associated with this object + * Do this whenever ther file is deleted or resized. + */ +static void yaffs_invalidate_whole_cache(struct yaffs_obj *in) +{ + int i; + struct yaffs_dev *dev = in->my_dev; + + if (dev->param.n_caches > 0) { + /* Invalidate it. */ + for (i = 0; i < dev->param.n_caches; i++) { + if (dev->cache[i].object == in) + dev->cache[i].object = NULL; + } + } +} + +static void yaffs_unhash_obj(struct yaffs_obj *obj) +{ + int bucket; + struct yaffs_dev *dev = obj->my_dev; + + /* If it is still linked into the bucket list, free from the list */ + if (!list_empty(&obj->hash_link)) { + list_del_init(&obj->hash_link); + bucket = yaffs_hash_fn(obj->obj_id); + dev->obj_bucket[bucket].count--; + } +} + +/* FreeObject frees up a Object and puts it back on the free list */ +static void yaffs_free_obj(struct yaffs_obj *obj) +{ + struct yaffs_dev *dev; + + if (!obj) { + BUG(); + return; + } + dev = obj->my_dev; + yaffs_trace(YAFFS_TRACE_OS, "FreeObject %p inode %p", + obj, obj->my_inode); + if (obj->parent) + BUG(); + if (!list_empty(&obj->siblings)) + BUG(); + + if (obj->my_inode) { + /* We're still hooked up to a cached inode. + * Don't delete now, but mark for later deletion + */ + obj->defered_free = 1; + return; + } + + yaffs_unhash_obj(obj); + + yaffs_free_raw_obj(dev, obj); + dev->n_obj--; + dev->checkpoint_blocks_required = 0; /* force recalculation */ +} + +void yaffs_handle_defered_free(struct yaffs_obj *obj) +{ + if (obj->defered_free) + yaffs_free_obj(obj); +} + +static int yaffs_generic_obj_del(struct yaffs_obj *in) +{ + /* Iinvalidate the file's data in the cache, without flushing. */ + yaffs_invalidate_whole_cache(in); + + if (in->my_dev->param.is_yaffs2 && in->parent != in->my_dev->del_dir) { + /* Move to unlinked directory so we have a deletion record */ + yaffs_change_obj_name(in, in->my_dev->del_dir, _Y("deleted"), 0, + 0); + } + + yaffs_remove_obj_from_dir(in); + yaffs_chunk_del(in->my_dev, in->hdr_chunk, 1, __LINE__); + in->hdr_chunk = 0; + + yaffs_free_obj(in); + return YAFFS_OK; + +} + +static void yaffs_soft_del_file(struct yaffs_obj *obj) +{ + if (!obj->deleted || + obj->variant_type != YAFFS_OBJECT_TYPE_FILE || + obj->soft_del) + return; + + if (obj->n_data_chunks <= 0) { + /* Empty file with no duplicate object headers, + * just delete it immediately */ + yaffs_free_tnode(obj->my_dev, obj->variant.file_variant.top); + obj->variant.file_variant.top = NULL; + yaffs_trace(YAFFS_TRACE_TRACING, + "yaffs: Deleting empty file %d", + obj->obj_id); + yaffs_generic_obj_del(obj); + } else { + yaffs_soft_del_worker(obj, + obj->variant.file_variant.top, + obj->variant. + file_variant.top_level, 0); + obj->soft_del = 1; + } +} + +/* Pruning removes any part of the file structure tree that is beyond the + * bounds of the file (ie that does not point to chunks). + * + * A file should only get pruned when its size is reduced. + * + * Before pruning, the chunks must be pulled from the tree and the + * level 0 tnode entries must be zeroed out. + * Could also use this for file deletion, but that's probably better handled + * by a special case. + * + * This function is recursive. For levels > 0 the function is called again on + * any sub-tree. For level == 0 we just check if the sub-tree has data. + * If there is no data in a subtree then it is pruned. + */ + +static struct yaffs_tnode *yaffs_prune_worker(struct yaffs_dev *dev, + struct yaffs_tnode *tn, u32 level, + int del0) +{ + int i; + int has_data; + + if (!tn) + return tn; + + has_data = 0; + + if (level > 0) { + for (i = 0; i < YAFFS_NTNODES_INTERNAL; i++) { + if (tn->internal[i]) { + tn->internal[i] = + yaffs_prune_worker(dev, + tn->internal[i], + level - 1, + (i == 0) ? del0 : 1); + } + + if (tn->internal[i]) + has_data++; + } + } else { + int tnode_size_u32 = dev->tnode_size / sizeof(u32); + u32 *map = (u32 *) tn; + + for (i = 0; !has_data && i < tnode_size_u32; i++) { + if (map[i]) + has_data++; + } + } + + if (has_data == 0 && del0) { + /* Free and return NULL */ + yaffs_free_tnode(dev, tn); + tn = NULL; + } + return tn; +} + +static int yaffs_prune_tree(struct yaffs_dev *dev, + struct yaffs_file_var *file_struct) +{ + int i; + int has_data; + int done = 0; + struct yaffs_tnode *tn; + + if (file_struct->top_level < 1) + return YAFFS_OK; + + file_struct->top = + yaffs_prune_worker(dev, file_struct->top, file_struct->top_level, 0); + + /* Now we have a tree with all the non-zero branches NULL but + * the height is the same as it was. + * Let's see if we can trim internal tnodes to shorten the tree. + * We can do this if only the 0th element in the tnode is in use + * (ie all the non-zero are NULL) + */ + + while (file_struct->top_level && !done) { + tn = file_struct->top; + + has_data = 0; + for (i = 1; i < YAFFS_NTNODES_INTERNAL; i++) { + if (tn->internal[i]) + has_data++; + } + + if (!has_data) { + file_struct->top = tn->internal[0]; + file_struct->top_level--; + yaffs_free_tnode(dev, tn); + } else { + done = 1; + } + } + + return YAFFS_OK; +} + +/*-------------------- End of File Structure functions.-------------------*/ + +/* alloc_empty_obj gets us a clean Object.*/ +static struct yaffs_obj *yaffs_alloc_empty_obj(struct yaffs_dev *dev) +{ + struct yaffs_obj *obj = yaffs_alloc_raw_obj(dev); + + if (!obj) + return obj; + + dev->n_obj++; + + /* Now sweeten it up... */ + + memset(obj, 0, sizeof(struct yaffs_obj)); + obj->being_created = 1; + + obj->my_dev = dev; + obj->hdr_chunk = 0; + obj->variant_type = YAFFS_OBJECT_TYPE_UNKNOWN; + INIT_LIST_HEAD(&(obj->hard_links)); + INIT_LIST_HEAD(&(obj->hash_link)); + INIT_LIST_HEAD(&obj->siblings); + + /* Now make the directory sane */ + if (dev->root_dir) { + obj->parent = dev->root_dir; + list_add(&(obj->siblings), + &dev->root_dir->variant.dir_variant.children); + } + + /* Add it to the lost and found directory. + * NB Can't put root or lost-n-found in lost-n-found so + * check if lost-n-found exists first + */ + if (dev->lost_n_found) + yaffs_add_obj_to_dir(dev->lost_n_found, obj); + + obj->being_created = 0; + + dev->checkpoint_blocks_required = 0; /* force recalculation */ + + return obj; +} + +static int yaffs_find_nice_bucket(struct yaffs_dev *dev) +{ + int i; + int l = 999; + int lowest = 999999; + + /* Search for the shortest list or one that + * isn't too long. + */ + + for (i = 0; i < 10 && lowest > 4; i++) { + dev->bucket_finder++; + dev->bucket_finder %= YAFFS_NOBJECT_BUCKETS; + if (dev->obj_bucket[dev->bucket_finder].count < lowest) { + lowest = dev->obj_bucket[dev->bucket_finder].count; + l = dev->bucket_finder; + } + } + + return l; +} + +static int yaffs_new_obj_id(struct yaffs_dev *dev) +{ + int bucket = yaffs_find_nice_bucket(dev); + int found = 0; + struct list_head *i; + u32 n = (u32) bucket; + + /* + * Now find an object value that has not already been taken + * by scanning the list, incrementing each time by number of buckets. + */ + while (!found) { + found = 1; + n += YAFFS_NOBJECT_BUCKETS; + list_for_each(i, &dev->obj_bucket[bucket].list) { + /* Check if this value is already taken. */ + if (i && list_entry(i, struct yaffs_obj, + hash_link)->obj_id == n) + found = 0; + } + } + return n; +} + +static void yaffs_hash_obj(struct yaffs_obj *in) +{ + int bucket = yaffs_hash_fn(in->obj_id); + struct yaffs_dev *dev = in->my_dev; + + list_add(&in->hash_link, &dev->obj_bucket[bucket].list); + dev->obj_bucket[bucket].count++; +} + +struct yaffs_obj *yaffs_find_by_number(struct yaffs_dev *dev, u32 number) +{ + int bucket = yaffs_hash_fn(number); + struct list_head *i; + struct yaffs_obj *in; + + list_for_each(i, &dev->obj_bucket[bucket].list) { + /* Look if it is in the list */ + in = list_entry(i, struct yaffs_obj, hash_link); + if (in->obj_id == number) { + /* Don't show if it is defered free */ + if (in->defered_free) + return NULL; + return in; + } + } + + return NULL; +} + +static struct yaffs_obj *yaffs_new_obj(struct yaffs_dev *dev, int number, + enum yaffs_obj_type type) +{ + struct yaffs_obj *the_obj = NULL; + struct yaffs_tnode *tn = NULL; + + if (number < 0) + number = yaffs_new_obj_id(dev); + + if (type == YAFFS_OBJECT_TYPE_FILE) { + tn = yaffs_get_tnode(dev); + if (!tn) + return NULL; + } + + the_obj = yaffs_alloc_empty_obj(dev); + if (!the_obj) { + if (tn) + yaffs_free_tnode(dev, tn); + return NULL; + } + + the_obj->fake = 0; + the_obj->rename_allowed = 1; + the_obj->unlink_allowed = 1; + the_obj->obj_id = number; + yaffs_hash_obj(the_obj); + the_obj->variant_type = type; + yaffs_load_current_time(the_obj, 1, 1); + + switch (type) { + case YAFFS_OBJECT_TYPE_FILE: + the_obj->variant.file_variant.file_size = 0; + the_obj->variant.file_variant.scanned_size = 0; + the_obj->variant.file_variant.shrink_size = + yaffs_max_file_size(dev); + the_obj->variant.file_variant.top_level = 0; + the_obj->variant.file_variant.top = tn; + break; + case YAFFS_OBJECT_TYPE_DIRECTORY: + INIT_LIST_HEAD(&the_obj->variant.dir_variant.children); + INIT_LIST_HEAD(&the_obj->variant.dir_variant.dirty); + break; + case YAFFS_OBJECT_TYPE_SYMLINK: + case YAFFS_OBJECT_TYPE_HARDLINK: + case YAFFS_OBJECT_TYPE_SPECIAL: + /* No action required */ + break; + case YAFFS_OBJECT_TYPE_UNKNOWN: + /* todo this should not happen */ + break; + } + return the_obj; +} + +static struct yaffs_obj *yaffs_create_fake_dir(struct yaffs_dev *dev, + int number, u32 mode) +{ + + struct yaffs_obj *obj = + yaffs_new_obj(dev, number, YAFFS_OBJECT_TYPE_DIRECTORY); + + if (!obj) + return NULL; + + obj->fake = 1; /* it is fake so it might not use NAND */ + obj->rename_allowed = 0; + obj->unlink_allowed = 0; + obj->deleted = 0; + obj->unlinked = 0; + obj->yst_mode = mode; + obj->my_dev = dev; + obj->hdr_chunk = 0; /* Not a valid chunk. */ + return obj; + +} + + +static void yaffs_init_tnodes_and_objs(struct yaffs_dev *dev) +{ + int i; + + dev->n_obj = 0; + dev->n_tnodes = 0; + yaffs_init_raw_tnodes_and_objs(dev); + + for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) { + INIT_LIST_HEAD(&dev->obj_bucket[i].list); + dev->obj_bucket[i].count = 0; + } +} + +struct yaffs_obj *yaffs_find_or_create_by_number(struct yaffs_dev *dev, + int number, + enum yaffs_obj_type type) +{ + struct yaffs_obj *the_obj = NULL; + + if (number > 0) + the_obj = yaffs_find_by_number(dev, number); + + if (!the_obj) + the_obj = yaffs_new_obj(dev, number, type); + + return the_obj; + +} + +YCHAR *yaffs_clone_str(const YCHAR *str) +{ + YCHAR *new_str = NULL; + int len; + + if (!str) + str = _Y(""); + + len = strnlen(str, YAFFS_MAX_ALIAS_LENGTH); + new_str = kmalloc((len + 1) * sizeof(YCHAR), GFP_NOFS); + if (new_str) { + strncpy(new_str, str, len); + new_str[len] = 0; + } + return new_str; + +} +/* + *yaffs_update_parent() handles fixing a directories mtime and ctime when a new + * link (ie. name) is created or deleted in the directory. + * + * ie. + * create dir/a : update dir's mtime/ctime + * rm dir/a: update dir's mtime/ctime + * modify dir/a: don't update dir's mtimme/ctime + * + * This can be handled immediately or defered. Defering helps reduce the number + * of updates when many files in a directory are changed within a brief period. + * + * If the directory updating is defered then yaffs_update_dirty_dirs must be + * called periodically. + */ + +static void yaffs_update_parent(struct yaffs_obj *obj) +{ + struct yaffs_dev *dev; + + if (!obj) + return; + dev = obj->my_dev; + obj->dirty = 1; + yaffs_load_current_time(obj, 0, 1); + if (dev->param.defered_dir_update) { + struct list_head *link = &obj->variant.dir_variant.dirty; + + if (list_empty(link)) { + list_add(link, &dev->dirty_dirs); + yaffs_trace(YAFFS_TRACE_BACKGROUND, + "Added object %d to dirty directories", + obj->obj_id); + } + + } else { + yaffs_update_oh(obj, NULL, 0, 0, 0, NULL); + } +} + +void yaffs_update_dirty_dirs(struct yaffs_dev *dev) +{ + struct list_head *link; + struct yaffs_obj *obj; + struct yaffs_dir_var *d_s; + union yaffs_obj_var *o_v; + + yaffs_trace(YAFFS_TRACE_BACKGROUND, "Update dirty directories"); + + while (!list_empty(&dev->dirty_dirs)) { + link = dev->dirty_dirs.next; + list_del_init(link); + + d_s = list_entry(link, struct yaffs_dir_var, dirty); + o_v = list_entry(d_s, union yaffs_obj_var, dir_variant); + obj = list_entry(o_v, struct yaffs_obj, variant); + + yaffs_trace(YAFFS_TRACE_BACKGROUND, "Update directory %d", + obj->obj_id); + + if (obj->dirty) + yaffs_update_oh(obj, NULL, 0, 0, 0, NULL); + } +} + +/* + * Mknod (create) a new object. + * equiv_obj only has meaning for a hard link; + * alias_str only has meaning for a symlink. + * rdev only has meaning for devices (a subset of special objects) + */ + +static struct yaffs_obj *yaffs_create_obj(enum yaffs_obj_type type, + struct yaffs_obj *parent, + const YCHAR *name, + u32 mode, + u32 uid, + u32 gid, + struct yaffs_obj *equiv_obj, + const YCHAR *alias_str, u32 rdev) +{ + struct yaffs_obj *in; + YCHAR *str = NULL; + struct yaffs_dev *dev = parent->my_dev; + + /* Check if the entry exists. + * If it does then fail the call since we don't want a dup. */ + if (yaffs_find_by_name(parent, name)) + return NULL; + + if (type == YAFFS_OBJECT_TYPE_SYMLINK) { + str = yaffs_clone_str(alias_str); + if (!str) + return NULL; + } + + in = yaffs_new_obj(dev, -1, type); + + if (!in) { + kfree(str); + return NULL; + } + + in->hdr_chunk = 0; + in->valid = 1; + in->variant_type = type; + + in->yst_mode = mode; + + yaffs_attribs_init(in, gid, uid, rdev); + + in->n_data_chunks = 0; + + yaffs_set_obj_name(in, name); + in->dirty = 1; + + yaffs_add_obj_to_dir(parent, in); + + in->my_dev = parent->my_dev; + + switch (type) { + case YAFFS_OBJECT_TYPE_SYMLINK: + in->variant.symlink_variant.alias = str; + break; + case YAFFS_OBJECT_TYPE_HARDLINK: + in->variant.hardlink_variant.equiv_obj = equiv_obj; + in->variant.hardlink_variant.equiv_id = equiv_obj->obj_id; + list_add(&in->hard_links, &equiv_obj->hard_links); + break; + case YAFFS_OBJECT_TYPE_FILE: + case YAFFS_OBJECT_TYPE_DIRECTORY: + case YAFFS_OBJECT_TYPE_SPECIAL: + case YAFFS_OBJECT_TYPE_UNKNOWN: + /* do nothing */ + break; + } + + if (yaffs_update_oh(in, name, 0, 0, 0, NULL) < 0) { + /* Could not create the object header, fail */ + yaffs_del_obj(in); + in = NULL; + } + + if (in) + yaffs_update_parent(parent); + + return in; +} + +struct yaffs_obj *yaffs_create_file(struct yaffs_obj *parent, + const YCHAR *name, u32 mode, u32 uid, + u32 gid) +{ + return yaffs_create_obj(YAFFS_OBJECT_TYPE_FILE, parent, name, mode, + uid, gid, NULL, NULL, 0); +} + +struct yaffs_obj *yaffs_create_dir(struct yaffs_obj *parent, const YCHAR *name, + u32 mode, u32 uid, u32 gid) +{ + return yaffs_create_obj(YAFFS_OBJECT_TYPE_DIRECTORY, parent, name, + mode, uid, gid, NULL, NULL, 0); +} + +struct yaffs_obj *yaffs_create_special(struct yaffs_obj *parent, + const YCHAR *name, u32 mode, u32 uid, + u32 gid, u32 rdev) +{ + return yaffs_create_obj(YAFFS_OBJECT_TYPE_SPECIAL, parent, name, mode, + uid, gid, NULL, NULL, rdev); +} + +struct yaffs_obj *yaffs_create_symlink(struct yaffs_obj *parent, + const YCHAR *name, u32 mode, u32 uid, + u32 gid, const YCHAR *alias) +{ + return yaffs_create_obj(YAFFS_OBJECT_TYPE_SYMLINK, parent, name, mode, + uid, gid, NULL, alias, 0); +} + +/* yaffs_link_obj returns the object id of the equivalent object.*/ +struct yaffs_obj *yaffs_link_obj(struct yaffs_obj *parent, const YCHAR * name, + struct yaffs_obj *equiv_obj) +{ + /* Get the real object in case we were fed a hard link obj */ + equiv_obj = yaffs_get_equivalent_obj(equiv_obj); + + if (yaffs_create_obj(YAFFS_OBJECT_TYPE_HARDLINK, + parent, name, 0, 0, 0, + equiv_obj, NULL, 0)) + return equiv_obj; + + return NULL; + +} + + + +/*---------------------- Block Management and Page Allocation -------------*/ + +static void yaffs_deinit_blocks(struct yaffs_dev *dev) +{ + if (dev->block_info_alt && dev->block_info) + vfree(dev->block_info); + else + kfree(dev->block_info); + + dev->block_info_alt = 0; + + dev->block_info = NULL; + + if (dev->chunk_bits_alt && dev->chunk_bits) + vfree(dev->chunk_bits); + else + kfree(dev->chunk_bits); + dev->chunk_bits_alt = 0; + dev->chunk_bits = NULL; +} + +static int yaffs_init_blocks(struct yaffs_dev *dev) +{ + int n_blocks = dev->internal_end_block - dev->internal_start_block + 1; + + dev->block_info = NULL; + dev->chunk_bits = NULL; + dev->alloc_block = -1; /* force it to get a new one */ + + /* If the first allocation strategy fails, thry the alternate one */ + dev->block_info = + kmalloc(n_blocks * sizeof(struct yaffs_block_info), GFP_NOFS); + if (!dev->block_info) { + dev->block_info = + vmalloc(n_blocks * sizeof(struct yaffs_block_info)); + dev->block_info_alt = 1; + } else { + dev->block_info_alt = 0; + } + + if (!dev->block_info) + goto alloc_error; + + /* Set up dynamic blockinfo stuff. Round up bytes. */ + dev->chunk_bit_stride = (dev->param.chunks_per_block + 7) / 8; + dev->chunk_bits = + kmalloc(dev->chunk_bit_stride * n_blocks, GFP_NOFS); + if (!dev->chunk_bits) { + dev->chunk_bits = + vmalloc(dev->chunk_bit_stride * n_blocks); + dev->chunk_bits_alt = 1; + } else { + dev->chunk_bits_alt = 0; + } + if (!dev->chunk_bits) + goto alloc_error; + + + memset(dev->block_info, 0, n_blocks * sizeof(struct yaffs_block_info)); + memset(dev->chunk_bits, 0, dev->chunk_bit_stride * n_blocks); + return YAFFS_OK; + +alloc_error: + yaffs_deinit_blocks(dev); + return YAFFS_FAIL; +} + + +void yaffs_block_became_dirty(struct yaffs_dev *dev, int block_no) +{ + struct yaffs_block_info *bi = yaffs_get_block_info(dev, block_no); + int erased_ok = 0; + int i; + + /* If the block is still healthy erase it and mark as clean. + * If the block has had a data failure, then retire it. + */ + + yaffs_trace(YAFFS_TRACE_GC | YAFFS_TRACE_ERASE, + "yaffs_block_became_dirty block %d state %d %s", + block_no, bi->block_state, + (bi->needs_retiring) ? "needs retiring" : ""); + + yaffs2_clear_oldest_dirty_seq(dev, bi); + + bi->block_state = YAFFS_BLOCK_STATE_DIRTY; + + /* If this is the block being garbage collected then stop gc'ing */ + if (block_no == dev->gc_block) + dev->gc_block = 0; + + /* If this block is currently the best candidate for gc + * then drop as a candidate */ + if (block_no == dev->gc_dirtiest) { + dev->gc_dirtiest = 0; + dev->gc_pages_in_use = 0; + } + + if (!bi->needs_retiring) { + yaffs2_checkpt_invalidate(dev); + erased_ok = yaffs_erase_block(dev, block_no); + if (!erased_ok) { + dev->n_erase_failures++; + yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS, + "**>> Erasure failed %d", block_no); + } + } + + /* Verify erasure if needed */ + if (erased_ok && + ((yaffs_trace_mask & YAFFS_TRACE_ERASE) || + !yaffs_skip_verification(dev))) { + for (i = 0; i < dev->param.chunks_per_block; i++) { + if (!yaffs_check_chunk_erased(dev, + block_no * dev->param.chunks_per_block + i)) { + yaffs_trace(YAFFS_TRACE_ERROR, + ">>Block %d erasure supposedly OK, but chunk %d not erased", + block_no, i); + } + } + } + + if (!erased_ok) { + /* We lost a block of free space */ + dev->n_free_chunks -= dev->param.chunks_per_block; + yaffs_retire_block(dev, block_no); + yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS, + "**>> Block %d retired", block_no); + return; + } + + /* Clean it up... */ + bi->block_state = YAFFS_BLOCK_STATE_EMPTY; + bi->seq_number = 0; + dev->n_erased_blocks++; + bi->pages_in_use = 0; + bi->soft_del_pages = 0; + bi->has_shrink_hdr = 0; + bi->skip_erased_check = 1; /* Clean, so no need to check */ + bi->gc_prioritise = 0; + bi->has_summary = 0; + + yaffs_clear_chunk_bits(dev, block_no); + + yaffs_trace(YAFFS_TRACE_ERASE, "Erased block %d", block_no); +} + +static inline int yaffs_gc_process_chunk(struct yaffs_dev *dev, + struct yaffs_block_info *bi, + int old_chunk, u8 *buffer) +{ + int new_chunk; + int mark_flash = 1; + struct yaffs_ext_tags tags; + struct yaffs_obj *object; + int matching_chunk; + int ret_val = YAFFS_OK; + + memset(&tags, 0, sizeof(tags)); + yaffs_rd_chunk_tags_nand(dev, old_chunk, + buffer, &tags); + object = yaffs_find_by_number(dev, tags.obj_id); + + yaffs_trace(YAFFS_TRACE_GC_DETAIL, + "Collecting chunk in block %d, %d %d %d ", + dev->gc_chunk, tags.obj_id, + tags.chunk_id, tags.n_bytes); + + if (object && !yaffs_skip_verification(dev)) { + if (tags.chunk_id == 0) + matching_chunk = + object->hdr_chunk; + else if (object->soft_del) + /* Defeat the test */ + matching_chunk = old_chunk; + else + matching_chunk = + yaffs_find_chunk_in_file + (object, tags.chunk_id, + NULL); + + if (old_chunk != matching_chunk) + yaffs_trace(YAFFS_TRACE_ERROR, + "gc: page in gc mismatch: %d %d %d %d", + old_chunk, + matching_chunk, + tags.obj_id, + tags.chunk_id); + } + + if (!object) { + yaffs_trace(YAFFS_TRACE_ERROR, + "page %d in gc has no object: %d %d %d ", + old_chunk, + tags.obj_id, tags.chunk_id, + tags.n_bytes); + } + + if (object && + object->deleted && + object->soft_del && tags.chunk_id != 0) { + /* Data chunk in a soft deleted file, + * throw it away. + * It's a soft deleted data chunk, + * No need to copy this, just forget + * about it and fix up the object. + */ + + /* Free chunks already includes + * softdeleted chunks, how ever this + * chunk is going to soon be really + * deleted which will increment free + * chunks. We have to decrement free + * chunks so this works out properly. + */ + dev->n_free_chunks--; + bi->soft_del_pages--; + + object->n_data_chunks--; + if (object->n_data_chunks <= 0) { + /* remeber to clean up obj */ + dev->gc_cleanup_list[dev->n_clean_ups] = tags.obj_id; + dev->n_clean_ups++; + } + mark_flash = 0; + } else if (object) { + /* It's either a data chunk in a live + * file or an ObjectHeader, so we're + * interested in it. + * NB Need to keep the ObjectHeaders of + * deleted files until the whole file + * has been deleted off + */ + tags.serial_number++; + dev->n_gc_copies++; + + if (tags.chunk_id == 0) { + /* It is an object Id, + * We need to nuke the + * shrinkheader flags since its + * work is done. + * Also need to clean up + * shadowing. + */ + struct yaffs_obj_hdr *oh; + oh = (struct yaffs_obj_hdr *) buffer; + + oh->is_shrink = 0; + tags.extra_is_shrink = 0; + oh->shadows_obj = 0; + oh->inband_shadowed_obj_id = 0; + tags.extra_shadows = 0; + + /* Update file size */ + if (object->variant_type == YAFFS_OBJECT_TYPE_FILE) { + yaffs_oh_size_load(oh, + object->variant.file_variant.file_size); + tags.extra_file_size = + object->variant.file_variant.file_size; + } + + yaffs_verify_oh(object, oh, &tags, 1); + new_chunk = + yaffs_write_new_chunk(dev, (u8 *) oh, &tags, 1); + } else { + new_chunk = + yaffs_write_new_chunk(dev, buffer, &tags, 1); + } + + if (new_chunk < 0) { + ret_val = YAFFS_FAIL; + } else { + + /* Now fix up the Tnodes etc. */ + + if (tags.chunk_id == 0) { + /* It's a header */ + object->hdr_chunk = new_chunk; + object->serial = tags.serial_number; + } else { + /* It's a data chunk */ + yaffs_put_chunk_in_file(object, tags.chunk_id, + new_chunk, 0); + } + } + } + if (ret_val == YAFFS_OK) + yaffs_chunk_del(dev, old_chunk, mark_flash, __LINE__); + return ret_val; +} + +static int yaffs_gc_block(struct yaffs_dev *dev, int block, int whole_block) +{ + int old_chunk; + int ret_val = YAFFS_OK; + int i; + int is_checkpt_block; + int max_copies; + int chunks_before = yaffs_get_erased_chunks(dev); + int chunks_after; + struct yaffs_block_info *bi = yaffs_get_block_info(dev, block); + + is_checkpt_block = (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT); + + yaffs_trace(YAFFS_TRACE_TRACING, + "Collecting block %d, in use %d, shrink %d, whole_block %d", + block, bi->pages_in_use, bi->has_shrink_hdr, + whole_block); + + /*yaffs_verify_free_chunks(dev); */ + + if (bi->block_state == YAFFS_BLOCK_STATE_FULL) + bi->block_state = YAFFS_BLOCK_STATE_COLLECTING; + + bi->has_shrink_hdr = 0; /* clear the flag so that the block can erase */ + + dev->gc_disable = 1; + + yaffs_summary_gc(dev, block); + + if (is_checkpt_block || !yaffs_still_some_chunks(dev, block)) { + yaffs_trace(YAFFS_TRACE_TRACING, + "Collecting block %d that has no chunks in use", + block); + yaffs_block_became_dirty(dev, block); + } else { + + u8 *buffer = yaffs_get_temp_buffer(dev); + + yaffs_verify_blk(dev, bi, block); + + max_copies = (whole_block) ? dev->param.chunks_per_block : 5; + old_chunk = block * dev->param.chunks_per_block + dev->gc_chunk; + + for (/* init already done */ ; + ret_val == YAFFS_OK && + dev->gc_chunk < dev->param.chunks_per_block && + (bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) && + max_copies > 0; + dev->gc_chunk++, old_chunk++) { + if (yaffs_check_chunk_bit(dev, block, dev->gc_chunk)) { + /* Page is in use and might need to be copied */ + max_copies--; + ret_val = yaffs_gc_process_chunk(dev, bi, + old_chunk, buffer); + } + } + yaffs_release_temp_buffer(dev, buffer); + } + + yaffs_verify_collected_blk(dev, bi, block); + + if (bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) { + /* + * The gc did not complete. Set block state back to FULL + * because checkpointing does not restore gc. + */ + bi->block_state = YAFFS_BLOCK_STATE_FULL; + } else { + /* The gc completed. */ + /* Do any required cleanups */ + for (i = 0; i < dev->n_clean_ups; i++) { + /* Time to delete the file too */ + struct yaffs_obj *object = + yaffs_find_by_number(dev, dev->gc_cleanup_list[i]); + if (object) { + yaffs_free_tnode(dev, + object->variant.file_variant.top); + object->variant.file_variant.top = NULL; + yaffs_trace(YAFFS_TRACE_GC, + "yaffs: About to finally delete object %d", + object->obj_id); + yaffs_generic_obj_del(object); + object->my_dev->n_deleted_files--; + } + + } + chunks_after = yaffs_get_erased_chunks(dev); + if (chunks_before >= chunks_after) + yaffs_trace(YAFFS_TRACE_GC, + "gc did not increase free chunks before %d after %d", + chunks_before, chunks_after); + dev->gc_block = 0; + dev->gc_chunk = 0; + dev->n_clean_ups = 0; + } + + dev->gc_disable = 0; + + return ret_val; +} + +/* + * find_gc_block() selects the dirtiest block (or close enough) + * for garbage collection. + */ + +static unsigned yaffs_find_gc_block(struct yaffs_dev *dev, + int aggressive, int background) +{ + int i; + int iterations; + unsigned selected = 0; + int prioritised = 0; + int prioritised_exist = 0; + struct yaffs_block_info *bi; + int threshold; + + /* First let's see if we need to grab a prioritised block */ + if (dev->has_pending_prioritised_gc && !aggressive) { + dev->gc_dirtiest = 0; + bi = dev->block_info; + for (i = dev->internal_start_block; + i <= dev->internal_end_block && !selected; i++) { + + if (bi->gc_prioritise) { + prioritised_exist = 1; + if (bi->block_state == YAFFS_BLOCK_STATE_FULL && + yaffs_block_ok_for_gc(dev, bi)) { + selected = i; + prioritised = 1; + } + } + bi++; + } + + /* + * If there is a prioritised block and none was selected then + * this happened because there is at least one old dirty block + * gumming up the works. Let's gc the oldest dirty block. + */ + + if (prioritised_exist && + !selected && dev->oldest_dirty_block > 0) + selected = dev->oldest_dirty_block; + + if (!prioritised_exist) /* None found, so we can clear this */ + dev->has_pending_prioritised_gc = 0; + } + + /* If we're doing aggressive GC then we are happy to take a less-dirty + * block, and search harder. + * else (leasurely gc), then we only bother to do this if the + * block has only a few pages in use. + */ + + if (!selected) { + int pages_used; + int n_blocks = + dev->internal_end_block - dev->internal_start_block + 1; + if (aggressive) { + threshold = dev->param.chunks_per_block; + iterations = n_blocks; + } else { + int max_threshold; + + if (background) + max_threshold = dev->param.chunks_per_block / 2; + else + max_threshold = dev->param.chunks_per_block / 8; + + if (max_threshold < YAFFS_GC_PASSIVE_THRESHOLD) + max_threshold = YAFFS_GC_PASSIVE_THRESHOLD; + + threshold = background ? (dev->gc_not_done + 2) * 2 : 0; + if (threshold < YAFFS_GC_PASSIVE_THRESHOLD) + threshold = YAFFS_GC_PASSIVE_THRESHOLD; + if (threshold > max_threshold) + threshold = max_threshold; + + iterations = n_blocks / 16 + 1; + if (iterations > 100) + iterations = 100; + } + + for (i = 0; + i < iterations && + (dev->gc_dirtiest < 1 || + dev->gc_pages_in_use > YAFFS_GC_GOOD_ENOUGH); + i++) { + dev->gc_block_finder++; + if (dev->gc_block_finder < dev->internal_start_block || + dev->gc_block_finder > dev->internal_end_block) + dev->gc_block_finder = + dev->internal_start_block; + + bi = yaffs_get_block_info(dev, dev->gc_block_finder); + + pages_used = bi->pages_in_use - bi->soft_del_pages; + + if (bi->block_state == YAFFS_BLOCK_STATE_FULL && + pages_used < dev->param.chunks_per_block && + (dev->gc_dirtiest < 1 || + pages_used < dev->gc_pages_in_use) && + yaffs_block_ok_for_gc(dev, bi)) { + dev->gc_dirtiest = dev->gc_block_finder; + dev->gc_pages_in_use = pages_used; + } + } + + if (dev->gc_dirtiest > 0 && dev->gc_pages_in_use <= threshold) + selected = dev->gc_dirtiest; + } + + /* + * If nothing has been selected for a while, try the oldest dirty + * because that's gumming up the works. + */ + + if (!selected && dev->param.is_yaffs2 && + dev->gc_not_done >= (background ? 10 : 20)) { + yaffs2_find_oldest_dirty_seq(dev); + if (dev->oldest_dirty_block > 0) { + selected = dev->oldest_dirty_block; + dev->gc_dirtiest = selected; + dev->oldest_dirty_gc_count++; + bi = yaffs_get_block_info(dev, selected); + dev->gc_pages_in_use = + bi->pages_in_use - bi->soft_del_pages; + } else { + dev->gc_not_done = 0; + } + } + + if (selected) { + yaffs_trace(YAFFS_TRACE_GC, + "GC Selected block %d with %d free, prioritised:%d", + selected, + dev->param.chunks_per_block - dev->gc_pages_in_use, + prioritised); + + dev->n_gc_blocks++; + if (background) + dev->bg_gcs++; + + dev->gc_dirtiest = 0; + dev->gc_pages_in_use = 0; + dev->gc_not_done = 0; + if (dev->refresh_skip > 0) + dev->refresh_skip--; + } else { + dev->gc_not_done++; + yaffs_trace(YAFFS_TRACE_GC, + "GC none: finder %d skip %d threshold %d dirtiest %d using %d oldest %d%s", + dev->gc_block_finder, dev->gc_not_done, threshold, + dev->gc_dirtiest, dev->gc_pages_in_use, + dev->oldest_dirty_block, background ? " bg" : ""); + } + + return selected; +} + +/* New garbage collector + * If we're very low on erased blocks then we do aggressive garbage collection + * otherwise we do "leasurely" garbage collection. + * Aggressive gc looks further (whole array) and will accept less dirty blocks. + * Passive gc only inspects smaller areas and only accepts more dirty blocks. + * + * The idea is to help clear out space in a more spread-out manner. + * Dunno if it really does anything useful. + */ +static int yaffs_check_gc(struct yaffs_dev *dev, int background) +{ + int aggressive = 0; + int gc_ok = YAFFS_OK; + int max_tries = 0; + int min_erased; + int erased_chunks; + int checkpt_block_adjust; + + if (dev->param.gc_control_fn && + (dev->param.gc_control_fn(dev) & 1) == 0) + return YAFFS_OK; + + if (dev->gc_disable) + /* Bail out so we don't get recursive gc */ + return YAFFS_OK; + + /* This loop should pass the first time. + * Only loops here if the collection does not increase space. + */ + + do { + max_tries++; + + checkpt_block_adjust = yaffs_calc_checkpt_blocks_required(dev); + + min_erased = + dev->param.n_reserved_blocks + checkpt_block_adjust + 1; + erased_chunks = + dev->n_erased_blocks * dev->param.chunks_per_block; + + /* If we need a block soon then do aggressive gc. */ + if (dev->n_erased_blocks < min_erased) + aggressive = 1; + else { + if (!background + && erased_chunks > (dev->n_free_chunks / 4)) + break; + + if (dev->gc_skip > 20) + dev->gc_skip = 20; + if (erased_chunks < dev->n_free_chunks / 2 || + dev->gc_skip < 1 || background) + aggressive = 0; + else { + dev->gc_skip--; + break; + } + } + + dev->gc_skip = 5; + + /* If we don't already have a block being gc'd then see if we + * should start another */ + + if (dev->gc_block < 1 && !aggressive) { + dev->gc_block = yaffs2_find_refresh_block(dev); + dev->gc_chunk = 0; + dev->n_clean_ups = 0; + } + if (dev->gc_block < 1) { + dev->gc_block = + yaffs_find_gc_block(dev, aggressive, background); + dev->gc_chunk = 0; + dev->n_clean_ups = 0; + } + + if (dev->gc_block > 0) { + dev->all_gcs++; + if (!aggressive) + dev->passive_gc_count++; + + yaffs_trace(YAFFS_TRACE_GC, + "yaffs: GC n_erased_blocks %d aggressive %d", + dev->n_erased_blocks, aggressive); + + gc_ok = yaffs_gc_block(dev, dev->gc_block, aggressive); + } + + if (dev->n_erased_blocks < (dev->param.n_reserved_blocks) && + dev->gc_block > 0) { + yaffs_trace(YAFFS_TRACE_GC, + "yaffs: GC !!!no reclaim!!! n_erased_blocks %d after try %d block %d", + dev->n_erased_blocks, max_tries, + dev->gc_block); + } + } while ((dev->n_erased_blocks < dev->param.n_reserved_blocks) && + (dev->gc_block > 0) && (max_tries < 2)); + + return aggressive ? gc_ok : YAFFS_OK; +} + +/* + * yaffs_bg_gc() + * Garbage collects. Intended to be called from a background thread. + * Returns non-zero if at least half the free chunks are erased. + */ +int yaffs_bg_gc(struct yaffs_dev *dev, unsigned urgency) +{ + int erased_chunks = dev->n_erased_blocks * dev->param.chunks_per_block; + + yaffs_trace(YAFFS_TRACE_BACKGROUND, "Background gc %u", urgency); + + yaffs_check_gc(dev, 1); + return erased_chunks > dev->n_free_chunks / 2; +} + +/*-------------------- Data file manipulation -----------------*/ + +static int yaffs_rd_data_obj(struct yaffs_obj *in, int inode_chunk, u8 * buffer) +{ + int nand_chunk = yaffs_find_chunk_in_file(in, inode_chunk, NULL); + + if (nand_chunk >= 0) + return yaffs_rd_chunk_tags_nand(in->my_dev, nand_chunk, + buffer, NULL); + else { + yaffs_trace(YAFFS_TRACE_NANDACCESS, + "Chunk %d not found zero instead", + nand_chunk); + /* get sane (zero) data if you read a hole */ + memset(buffer, 0, in->my_dev->data_bytes_per_chunk); + return 0; + } + +} + +void yaffs_chunk_del(struct yaffs_dev *dev, int chunk_id, int mark_flash, + int lyn) +{ + int block; + int page; + struct yaffs_ext_tags tags; + struct yaffs_block_info *bi; + + if (chunk_id <= 0) + return; + + dev->n_deletions++; + block = chunk_id / dev->param.chunks_per_block; + page = chunk_id % dev->param.chunks_per_block; + + if (!yaffs_check_chunk_bit(dev, block, page)) + yaffs_trace(YAFFS_TRACE_VERIFY, + "Deleting invalid chunk %d", chunk_id); + + bi = yaffs_get_block_info(dev, block); + + yaffs2_update_oldest_dirty_seq(dev, block, bi); + + yaffs_trace(YAFFS_TRACE_DELETION, + "line %d delete of chunk %d", + lyn, chunk_id); + + if (!dev->param.is_yaffs2 && mark_flash && + bi->block_state != YAFFS_BLOCK_STATE_COLLECTING) { + + memset(&tags, 0, sizeof(tags)); + tags.is_deleted = 1; + yaffs_wr_chunk_tags_nand(dev, chunk_id, NULL, &tags); + yaffs_handle_chunk_update(dev, chunk_id, &tags); + } else { + dev->n_unmarked_deletions++; + } + + /* Pull out of the management area. + * If the whole block became dirty, this will kick off an erasure. + */ + if (bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING || + bi->block_state == YAFFS_BLOCK_STATE_FULL || + bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN || + bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) { + dev->n_free_chunks++; + yaffs_clear_chunk_bit(dev, block, page); + bi->pages_in_use--; + + if (bi->pages_in_use == 0 && + !bi->has_shrink_hdr && + bi->block_state != YAFFS_BLOCK_STATE_ALLOCATING && + bi->block_state != YAFFS_BLOCK_STATE_NEEDS_SCAN) { + yaffs_block_became_dirty(dev, block); + } + } +} + +static int yaffs_wr_data_obj(struct yaffs_obj *in, int inode_chunk, + const u8 *buffer, int n_bytes, int use_reserve) +{ + /* Find old chunk Need to do this to get serial number + * Write new one and patch into tree. + * Invalidate old tags. + */ + + int prev_chunk_id; + struct yaffs_ext_tags prev_tags; + int new_chunk_id; + struct yaffs_ext_tags new_tags; + struct yaffs_dev *dev = in->my_dev; + + yaffs_check_gc(dev, 0); + + /* Get the previous chunk at this location in the file if it exists. + * If it does not exist then put a zero into the tree. This creates + * the tnode now, rather than later when it is harder to clean up. + */ + prev_chunk_id = yaffs_find_chunk_in_file(in, inode_chunk, &prev_tags); + if (prev_chunk_id < 1 && + !yaffs_put_chunk_in_file(in, inode_chunk, 0, 0)) + return 0; + + /* Set up new tags */ + memset(&new_tags, 0, sizeof(new_tags)); + + new_tags.chunk_id = inode_chunk; + new_tags.obj_id = in->obj_id; + new_tags.serial_number = + (prev_chunk_id > 0) ? prev_tags.serial_number + 1 : 1; + new_tags.n_bytes = n_bytes; + + if (n_bytes < 1 || n_bytes > dev->param.total_bytes_per_chunk) { + yaffs_trace(YAFFS_TRACE_ERROR, + "Writing %d bytes to chunk!!!!!!!!!", + n_bytes); + BUG(); + } + + new_chunk_id = + yaffs_write_new_chunk(dev, buffer, &new_tags, use_reserve); + + if (new_chunk_id > 0) { + yaffs_put_chunk_in_file(in, inode_chunk, new_chunk_id, 0); + + if (prev_chunk_id > 0) + yaffs_chunk_del(dev, prev_chunk_id, 1, __LINE__); + + yaffs_verify_file_sane(in); + } + return new_chunk_id; + +} + + + +static int yaffs_do_xattrib_mod(struct yaffs_obj *obj, int set, + const YCHAR *name, const void *value, int size, + int flags) +{ + struct yaffs_xattr_mod xmod; + int result; + + xmod.set = set; + xmod.name = name; + xmod.data = value; + xmod.size = size; + xmod.flags = flags; + xmod.result = -ENOSPC; + + result = yaffs_update_oh(obj, NULL, 0, 0, 0, &xmod); + + if (result > 0) + return xmod.result; + else + return -ENOSPC; +} + +static int yaffs_apply_xattrib_mod(struct yaffs_obj *obj, char *buffer, + struct yaffs_xattr_mod *xmod) +{ + int retval = 0; + int x_offs = sizeof(struct yaffs_obj_hdr); + struct yaffs_dev *dev = obj->my_dev; + int x_size = dev->data_bytes_per_chunk - sizeof(struct yaffs_obj_hdr); + char *x_buffer = buffer + x_offs; + + if (xmod->set) + retval = + nval_set(x_buffer, x_size, xmod->name, xmod->data, + xmod->size, xmod->flags); + else + retval = nval_del(x_buffer, x_size, xmod->name); + + obj->has_xattr = nval_hasvalues(x_buffer, x_size); + obj->xattr_known = 1; + xmod->result = retval; + + return retval; +} + +static int yaffs_do_xattrib_fetch(struct yaffs_obj *obj, const YCHAR *name, + void *value, int size) +{ + char *buffer = NULL; + int result; + struct yaffs_ext_tags tags; + struct yaffs_dev *dev = obj->my_dev; + int x_offs = sizeof(struct yaffs_obj_hdr); + int x_size = dev->data_bytes_per_chunk - sizeof(struct yaffs_obj_hdr); + char *x_buffer; + int retval = 0; + + if (obj->hdr_chunk < 1) + return -ENODATA; + + /* If we know that the object has no xattribs then don't do all the + * reading and parsing. + */ + if (obj->xattr_known && !obj->has_xattr) { + if (name) + return -ENODATA; + else + return 0; + } + + buffer = (char *)yaffs_get_temp_buffer(dev); + if (!buffer) + return -ENOMEM; + + result = + yaffs_rd_chunk_tags_nand(dev, obj->hdr_chunk, (u8 *) buffer, &tags); + + if (result != YAFFS_OK) + retval = -ENOENT; + else { + x_buffer = buffer + x_offs; + + if (!obj->xattr_known) { + obj->has_xattr = nval_hasvalues(x_buffer, x_size); + obj->xattr_known = 1; + } + + if (name) + retval = nval_get(x_buffer, x_size, name, value, size); + else + retval = nval_list(x_buffer, x_size, value, size); + } + yaffs_release_temp_buffer(dev, (u8 *) buffer); + return retval; +} + +int yaffs_set_xattrib(struct yaffs_obj *obj, const YCHAR * name, + const void *value, int size, int flags) +{ + return yaffs_do_xattrib_mod(obj, 1, name, value, size, flags); +} + +int yaffs_remove_xattrib(struct yaffs_obj *obj, const YCHAR * name) +{ + return yaffs_do_xattrib_mod(obj, 0, name, NULL, 0, 0); +} + +int yaffs_get_xattrib(struct yaffs_obj *obj, const YCHAR * name, void *value, + int size) +{ + return yaffs_do_xattrib_fetch(obj, name, value, size); +} + +int yaffs_list_xattrib(struct yaffs_obj *obj, char *buffer, int size) +{ + return yaffs_do_xattrib_fetch(obj, NULL, buffer, size); +} + +static void yaffs_check_obj_details_loaded(struct yaffs_obj *in) +{ + u8 *buf; + struct yaffs_obj_hdr *oh; + struct yaffs_dev *dev; + struct yaffs_ext_tags tags; + int result; + int alloc_failed = 0; + + if (!in || !in->lazy_loaded || in->hdr_chunk < 1) + return; + + dev = in->my_dev; + in->lazy_loaded = 0; + buf = yaffs_get_temp_buffer(dev); + + result = yaffs_rd_chunk_tags_nand(dev, in->hdr_chunk, buf, &tags); + oh = (struct yaffs_obj_hdr *)buf; + + in->yst_mode = oh->yst_mode; + yaffs_load_attribs(in, oh); + yaffs_set_obj_name_from_oh(in, oh); + + if (in->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) { + in->variant.symlink_variant.alias = + yaffs_clone_str(oh->alias); + if (!in->variant.symlink_variant.alias) + alloc_failed = 1; /* Not returned */ + } + yaffs_release_temp_buffer(dev, buf); +} + +/* UpdateObjectHeader updates the header on NAND for an object. + * If name is not NULL, then that new name is used. + */ +int yaffs_update_oh(struct yaffs_obj *in, const YCHAR *name, int force, + int is_shrink, int shadows, struct yaffs_xattr_mod *xmod) +{ + + struct yaffs_block_info *bi; + struct yaffs_dev *dev = in->my_dev; + int prev_chunk_id; + int ret_val = 0; + int result = 0; + int new_chunk_id; + struct yaffs_ext_tags new_tags; + struct yaffs_ext_tags old_tags; + const YCHAR *alias = NULL; + u8 *buffer = NULL; + YCHAR old_name[YAFFS_MAX_NAME_LENGTH + 1]; + struct yaffs_obj_hdr *oh = NULL; + loff_t file_size = 0; + + strcpy(old_name, _Y("silly old name")); + + if (in->fake && in != dev->root_dir && !force && !xmod) + return ret_val; + + yaffs_check_gc(dev, 0); + yaffs_check_obj_details_loaded(in); + + buffer = yaffs_get_temp_buffer(in->my_dev); + oh = (struct yaffs_obj_hdr *)buffer; + + prev_chunk_id = in->hdr_chunk; + + if (prev_chunk_id > 0) { + result = yaffs_rd_chunk_tags_nand(dev, prev_chunk_id, + buffer, &old_tags); + + yaffs_verify_oh(in, oh, &old_tags, 0); + memcpy(old_name, oh->name, sizeof(oh->name)); + memset(buffer, 0xff, sizeof(struct yaffs_obj_hdr)); + } else { + memset(buffer, 0xff, dev->data_bytes_per_chunk); + } + + oh->type = in->variant_type; + oh->yst_mode = in->yst_mode; + oh->shadows_obj = oh->inband_shadowed_obj_id = shadows; + + yaffs_load_attribs_oh(oh, in); + + if (in->parent) + oh->parent_obj_id = in->parent->obj_id; + else + oh->parent_obj_id = 0; + + if (name && *name) { + memset(oh->name, 0, sizeof(oh->name)); + yaffs_load_oh_from_name(dev, oh->name, name); + } else if (prev_chunk_id > 0) { + memcpy(oh->name, old_name, sizeof(oh->name)); + } else { + memset(oh->name, 0, sizeof(oh->name)); + } + + oh->is_shrink = is_shrink; + + switch (in->variant_type) { + case YAFFS_OBJECT_TYPE_UNKNOWN: + /* Should not happen */ + break; + case YAFFS_OBJECT_TYPE_FILE: + if (oh->parent_obj_id != YAFFS_OBJECTID_DELETED && + oh->parent_obj_id != YAFFS_OBJECTID_UNLINKED) + file_size = in->variant.file_variant.file_size; + yaffs_oh_size_load(oh, file_size); + break; + case YAFFS_OBJECT_TYPE_HARDLINK: + oh->equiv_id = in->variant.hardlink_variant.equiv_id; + break; + case YAFFS_OBJECT_TYPE_SPECIAL: + /* Do nothing */ + break; + case YAFFS_OBJECT_TYPE_DIRECTORY: + /* Do nothing */ + break; + case YAFFS_OBJECT_TYPE_SYMLINK: + alias = in->variant.symlink_variant.alias; + if (!alias) + alias = _Y("no alias"); + strncpy(oh->alias, alias, YAFFS_MAX_ALIAS_LENGTH); + oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0; + break; + } + + /* process any xattrib modifications */ + if (xmod) + yaffs_apply_xattrib_mod(in, (char *)buffer, xmod); + + /* Tags */ + memset(&new_tags, 0, sizeof(new_tags)); + in->serial++; + new_tags.chunk_id = 0; + new_tags.obj_id = in->obj_id; + new_tags.serial_number = in->serial; + + /* Add extra info for file header */ + new_tags.extra_available = 1; + new_tags.extra_parent_id = oh->parent_obj_id; + new_tags.extra_file_size = file_size; + new_tags.extra_is_shrink = oh->is_shrink; + new_tags.extra_equiv_id = oh->equiv_id; + new_tags.extra_shadows = (oh->shadows_obj > 0) ? 1 : 0; + new_tags.extra_obj_type = in->variant_type; + yaffs_verify_oh(in, oh, &new_tags, 1); + + /* Create new chunk in NAND */ + new_chunk_id = + yaffs_write_new_chunk(dev, buffer, &new_tags, + (prev_chunk_id > 0) ? 1 : 0); + + if (buffer) + yaffs_release_temp_buffer(dev, buffer); + + if (new_chunk_id < 0) + return new_chunk_id; + + in->hdr_chunk = new_chunk_id; + + if (prev_chunk_id > 0) + yaffs_chunk_del(dev, prev_chunk_id, 1, __LINE__); + + if (!yaffs_obj_cache_dirty(in)) + in->dirty = 0; + + /* If this was a shrink, then mark the block + * that the chunk lives on */ + if (is_shrink) { + bi = yaffs_get_block_info(in->my_dev, + new_chunk_id / + in->my_dev->param.chunks_per_block); + bi->has_shrink_hdr = 1; + } + + + return new_chunk_id; +} + +/*--------------------- File read/write ------------------------ + * Read and write have very similar structures. + * In general the read/write has three parts to it + * An incomplete chunk to start with (if the read/write is not chunk-aligned) + * Some complete chunks + * An incomplete chunk to end off with + * + * Curve-balls: the first chunk might also be the last chunk. + */ + +int yaffs_file_rd(struct yaffs_obj *in, u8 * buffer, loff_t offset, int n_bytes) +{ + int chunk; + u32 start; + int n_copy; + int n = n_bytes; + int n_done = 0; + struct yaffs_cache *cache; + struct yaffs_dev *dev; + + dev = in->my_dev; + + while (n > 0) { + yaffs_addr_to_chunk(dev, offset, &chunk, &start); + chunk++; + + /* OK now check for the curveball where the start and end are in + * the same chunk. + */ + if ((start + n) < dev->data_bytes_per_chunk) + n_copy = n; + else + n_copy = dev->data_bytes_per_chunk - start; + + cache = yaffs_find_chunk_cache(in, chunk); + + /* If the chunk is already in the cache or it is less than + * a whole chunk or we're using inband tags then use the cache + * (if there is caching) else bypass the cache. + */ + if (cache || n_copy != dev->data_bytes_per_chunk || + dev->param.inband_tags) { + if (dev->param.n_caches > 0) { + + /* If we can't find the data in the cache, + * then load it up. */ + + if (!cache) { + cache = + yaffs_grab_chunk_cache(in->my_dev); + cache->object = in; + cache->chunk_id = chunk; + cache->dirty = 0; + cache->locked = 0; + yaffs_rd_data_obj(in, chunk, + cache->data); + cache->n_bytes = 0; + } + + yaffs_use_cache(dev, cache, 0); + + cache->locked = 1; + + memcpy(buffer, &cache->data[start], n_copy); + + cache->locked = 0; + } else { + /* Read into the local buffer then copy.. */ + + u8 *local_buffer = + yaffs_get_temp_buffer(dev); + yaffs_rd_data_obj(in, chunk, local_buffer); + + memcpy(buffer, &local_buffer[start], n_copy); + + yaffs_release_temp_buffer(dev, local_buffer); + } + } else { + /* A full chunk. Read directly into the buffer. */ + yaffs_rd_data_obj(in, chunk, buffer); + } + n -= n_copy; + offset += n_copy; + buffer += n_copy; + n_done += n_copy; + } + return n_done; +} + +int yaffs_do_file_wr(struct yaffs_obj *in, const u8 *buffer, loff_t offset, + int n_bytes, int write_through) +{ + + int chunk; + u32 start; + int n_copy; + int n = n_bytes; + int n_done = 0; + int n_writeback; + loff_t start_write = offset; + int chunk_written = 0; + u32 n_bytes_read; + loff_t chunk_start; + struct yaffs_dev *dev; + + dev = in->my_dev; + + while (n > 0 && chunk_written >= 0) { + yaffs_addr_to_chunk(dev, offset, &chunk, &start); + + if (((loff_t)chunk) * + dev->data_bytes_per_chunk + start != offset || + start >= dev->data_bytes_per_chunk) { + yaffs_trace(YAFFS_TRACE_ERROR, + "AddrToChunk of offset %lld gives chunk %d start %d", + offset, chunk, start); + } + chunk++; /* File pos to chunk in file offset */ + + /* OK now check for the curveball where the start and end are in + * the same chunk. + */ + + if ((start + n) < dev->data_bytes_per_chunk) { + n_copy = n; + + /* Now calculate how many bytes to write back.... + * If we're overwriting and not writing to then end of + * file then we need to write back as much as was there + * before. + */ + + chunk_start = (((loff_t)(chunk - 1)) * + dev->data_bytes_per_chunk); + + if (chunk_start > in->variant.file_variant.file_size) + n_bytes_read = 0; /* Past end of file */ + else + n_bytes_read = + in->variant.file_variant.file_size - + chunk_start; + + if (n_bytes_read > dev->data_bytes_per_chunk) + n_bytes_read = dev->data_bytes_per_chunk; + + n_writeback = + (n_bytes_read > + (start + n)) ? n_bytes_read : (start + n); + + if (n_writeback < 0 || + n_writeback > dev->data_bytes_per_chunk) + BUG(); + + } else { + n_copy = dev->data_bytes_per_chunk - start; + n_writeback = dev->data_bytes_per_chunk; + } + + if (n_copy != dev->data_bytes_per_chunk || + !dev->param.cache_bypass_aligned || + dev->param.inband_tags) { + /* An incomplete start or end chunk (or maybe both + * start and end chunk), or we're using inband tags, + * or we're forcing writes through the cache, + * so we want to use the cache buffers. + */ + if (dev->param.n_caches > 0) { + struct yaffs_cache *cache; + + /* If we can't find the data in the cache, then + * load the cache */ + cache = yaffs_find_chunk_cache(in, chunk); + + if (!cache && + yaffs_check_alloc_available(dev, 1)) { + cache = yaffs_grab_chunk_cache(dev); + cache->object = in; + cache->chunk_id = chunk; + cache->dirty = 0; + cache->locked = 0; + yaffs_rd_data_obj(in, chunk, + cache->data); + } else if (cache && + !cache->dirty && + !yaffs_check_alloc_available(dev, + 1)) { + /* Drop the cache if it was a read cache + * item and no space check has been made + * for it. + */ + cache = NULL; + } + + if (cache) { + yaffs_use_cache(dev, cache, 1); + cache->locked = 1; + + memcpy(&cache->data[start], buffer, + n_copy); + + cache->locked = 0; + cache->n_bytes = n_writeback; + + if (write_through) { + chunk_written = + yaffs_wr_data_obj + (cache->object, + cache->chunk_id, + cache->data, + cache->n_bytes, 1); + cache->dirty = 0; + } + } else { + chunk_written = -1; /* fail write */ + } + } else { + /* An incomplete start or end chunk (or maybe + * both start and end chunk). Read into the + * local buffer then copy over and write back. + */ + + u8 *local_buffer = yaffs_get_temp_buffer(dev); + + yaffs_rd_data_obj(in, chunk, local_buffer); + memcpy(&local_buffer[start], buffer, n_copy); + + chunk_written = + yaffs_wr_data_obj(in, chunk, + local_buffer, + n_writeback, 0); + + yaffs_release_temp_buffer(dev, local_buffer); + } + } else { + /* A full chunk. Write directly from the buffer. */ + + chunk_written = + yaffs_wr_data_obj(in, chunk, buffer, + dev->data_bytes_per_chunk, 0); + + /* Since we've overwritten the cached data, + * we better invalidate it. */ + yaffs_invalidate_chunk_cache(in, chunk); + } + + if (chunk_written >= 0) { + n -= n_copy; + offset += n_copy; + buffer += n_copy; + n_done += n_copy; + } + } + + /* Update file object */ + + if ((start_write + n_done) > in->variant.file_variant.file_size) + in->variant.file_variant.file_size = (start_write + n_done); + + in->dirty = 1; + return n_done; +} + +int yaffs_wr_file(struct yaffs_obj *in, const u8 *buffer, loff_t offset, + int n_bytes, int write_through) +{ + yaffs2_handle_hole(in, offset); + return yaffs_do_file_wr(in, buffer, offset, n_bytes, write_through); +} + +/* ---------------------- File resizing stuff ------------------ */ + +static void yaffs_prune_chunks(struct yaffs_obj *in, loff_t new_size) +{ + + struct yaffs_dev *dev = in->my_dev; + loff_t old_size = in->variant.file_variant.file_size; + int i; + int chunk_id; + u32 dummy; + int last_del; + int start_del; + + if (old_size > 0) + yaffs_addr_to_chunk(dev, old_size - 1, &last_del, &dummy); + else + last_del = 0; + + yaffs_addr_to_chunk(dev, new_size + dev->data_bytes_per_chunk - 1, + &start_del, &dummy); + last_del++; + start_del++; + + /* Delete backwards so that we don't end up with holes if + * power is lost part-way through the operation. + */ + for (i = last_del; i >= start_del; i--) { + /* NB this could be optimised somewhat, + * eg. could retrieve the tags and write them without + * using yaffs_chunk_del + */ + + chunk_id = yaffs_find_del_file_chunk(in, i, NULL); + + if (chunk_id < 1) + continue; + + if (chunk_id < + (dev->internal_start_block * dev->param.chunks_per_block) || + chunk_id >= + ((dev->internal_end_block + 1) * + dev->param.chunks_per_block)) { + yaffs_trace(YAFFS_TRACE_ALWAYS, + "Found daft chunk_id %d for %d", + chunk_id, i); + } else { + in->n_data_chunks--; + yaffs_chunk_del(dev, chunk_id, 1, __LINE__); + } + } +} + +void yaffs_resize_file_down(struct yaffs_obj *obj, loff_t new_size) +{ + int new_full; + u32 new_partial; + struct yaffs_dev *dev = obj->my_dev; + + yaffs_addr_to_chunk(dev, new_size, &new_full, &new_partial); + + yaffs_prune_chunks(obj, new_size); + + if (new_partial != 0) { + int last_chunk = 1 + new_full; + u8 *local_buffer = yaffs_get_temp_buffer(dev); + + /* Rewrite the last chunk with its new size and zero pad */ + yaffs_rd_data_obj(obj, last_chunk, local_buffer); + memset(local_buffer + new_partial, 0, + dev->data_bytes_per_chunk - new_partial); + + yaffs_wr_data_obj(obj, last_chunk, local_buffer, + new_partial, 1); + + yaffs_release_temp_buffer(dev, local_buffer); + } + + obj->variant.file_variant.file_size = new_size; + + yaffs_prune_tree(dev, &obj->variant.file_variant); +} + +int yaffs_resize_file(struct yaffs_obj *in, loff_t new_size) +{ + struct yaffs_dev *dev = in->my_dev; + loff_t old_size = in->variant.file_variant.file_size; + + yaffs_flush_file_cache(in, 1); + yaffs_invalidate_whole_cache(in); + + yaffs_check_gc(dev, 0); + + if (in->variant_type != YAFFS_OBJECT_TYPE_FILE) + return YAFFS_FAIL; + + if (new_size == old_size) + return YAFFS_OK; + + if (new_size > old_size) { + yaffs2_handle_hole(in, new_size); + in->variant.file_variant.file_size = new_size; + } else { + /* new_size < old_size */ + yaffs_resize_file_down(in, new_size); + } + + /* Write a new object header to reflect the resize. + * show we've shrunk the file, if need be + * Do this only if the file is not in the deleted directories + * and is not shadowed. + */ + if (in->parent && + !in->is_shadowed && + in->parent->obj_id != YAFFS_OBJECTID_UNLINKED && + in->parent->obj_id != YAFFS_OBJECTID_DELETED) + yaffs_update_oh(in, NULL, 0, 0, 0, NULL); + + return YAFFS_OK; +} + +int yaffs_flush_file(struct yaffs_obj *in, + int update_time, + int data_sync, + int discard_cache) +{ + if (!in->dirty) + return YAFFS_OK; + + yaffs_flush_file_cache(in, discard_cache); + + if (data_sync) + return YAFFS_OK; + + if (update_time) + yaffs_load_current_time(in, 0, 0); + + return (yaffs_update_oh(in, NULL, 0, 0, 0, NULL) >= 0) ? + YAFFS_OK : YAFFS_FAIL; +} + + +/* yaffs_del_file deletes the whole file data + * and the inode associated with the file. + * It does not delete the links associated with the file. + */ +static int yaffs_unlink_file_if_needed(struct yaffs_obj *in) +{ + int ret_val; + int del_now = 0; + struct yaffs_dev *dev = in->my_dev; + + if (!in->my_inode) + del_now = 1; + + if (del_now) { + ret_val = + yaffs_change_obj_name(in, in->my_dev->del_dir, + _Y("deleted"), 0, 0); + yaffs_trace(YAFFS_TRACE_TRACING, + "yaffs: immediate deletion of file %d", + in->obj_id); + in->deleted = 1; + in->my_dev->n_deleted_files++; + if (dev->param.disable_soft_del || dev->param.is_yaffs2) + yaffs_resize_file(in, 0); + yaffs_soft_del_file(in); + } else { + ret_val = + yaffs_change_obj_name(in, in->my_dev->unlinked_dir, + _Y("unlinked"), 0, 0); + } + return ret_val; +} + +static int yaffs_del_file(struct yaffs_obj *in) +{ + int ret_val = YAFFS_OK; + int deleted; /* Need to cache value on stack if in is freed */ + struct yaffs_dev *dev = in->my_dev; + + if (dev->param.disable_soft_del || dev->param.is_yaffs2) + yaffs_resize_file(in, 0); + + if (in->n_data_chunks > 0) { + /* Use soft deletion if there is data in the file. + * That won't be the case if it has been resized to zero. + */ + if (!in->unlinked) + ret_val = yaffs_unlink_file_if_needed(in); + + deleted = in->deleted; + + if (ret_val == YAFFS_OK && in->unlinked && !in->deleted) { + in->deleted = 1; + deleted = 1; + in->my_dev->n_deleted_files++; + yaffs_soft_del_file(in); + } + return deleted ? YAFFS_OK : YAFFS_FAIL; + } else { + /* The file has no data chunks so we toss it immediately */ + yaffs_free_tnode(in->my_dev, in->variant.file_variant.top); + in->variant.file_variant.top = NULL; + yaffs_generic_obj_del(in); + + return YAFFS_OK; + } +} + +int yaffs_is_non_empty_dir(struct yaffs_obj *obj) +{ + return (obj && + obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) && + !(list_empty(&obj->variant.dir_variant.children)); +} + +static int yaffs_del_dir(struct yaffs_obj *obj) +{ + /* First check that the directory is empty. */ + if (yaffs_is_non_empty_dir(obj)) + return YAFFS_FAIL; + + return yaffs_generic_obj_del(obj); +} + +static int yaffs_del_symlink(struct yaffs_obj *in) +{ + kfree(in->variant.symlink_variant.alias); + in->variant.symlink_variant.alias = NULL; + + return yaffs_generic_obj_del(in); +} + +static int yaffs_del_link(struct yaffs_obj *in) +{ + /* remove this hardlink from the list associated with the equivalent + * object + */ + list_del_init(&in->hard_links); + return yaffs_generic_obj_del(in); +} + +int yaffs_del_obj(struct yaffs_obj *obj) +{ + int ret_val = -1; + + switch (obj->variant_type) { + case YAFFS_OBJECT_TYPE_FILE: + ret_val = yaffs_del_file(obj); + break; + case YAFFS_OBJECT_TYPE_DIRECTORY: + if (!list_empty(&obj->variant.dir_variant.dirty)) { + yaffs_trace(YAFFS_TRACE_BACKGROUND, + "Remove object %d from dirty directories", + obj->obj_id); + list_del_init(&obj->variant.dir_variant.dirty); + } + return yaffs_del_dir(obj); + break; + case YAFFS_OBJECT_TYPE_SYMLINK: + ret_val = yaffs_del_symlink(obj); + break; + case YAFFS_OBJECT_TYPE_HARDLINK: + ret_val = yaffs_del_link(obj); + break; + case YAFFS_OBJECT_TYPE_SPECIAL: + ret_val = yaffs_generic_obj_del(obj); + break; + case YAFFS_OBJECT_TYPE_UNKNOWN: + ret_val = 0; + break; /* should not happen. */ + } + return ret_val; +} + + +static void yaffs_empty_dir_to_dir(struct yaffs_obj *from_dir, + struct yaffs_obj *to_dir) +{ + struct yaffs_obj *obj; + struct list_head *lh; + struct list_head *n; + + list_for_each_safe(lh, n, &from_dir->variant.dir_variant.children) { + obj = list_entry(lh, struct yaffs_obj, siblings); + yaffs_add_obj_to_dir(to_dir, obj); + } +} + +struct yaffs_obj *yaffs_retype_obj(struct yaffs_obj *obj, + enum yaffs_obj_type type) +{ + /* Tear down the old variant */ + switch (obj->variant_type) { + case YAFFS_OBJECT_TYPE_FILE: + /* Nuke file data */ + yaffs_resize_file(obj, 0); + yaffs_free_tnode(obj->my_dev, obj->variant.file_variant.top); + obj->variant.file_variant.top = NULL; + break; + case YAFFS_OBJECT_TYPE_DIRECTORY: + /* Put the children in lost and found. */ + yaffs_empty_dir_to_dir(obj, obj->my_dev->lost_n_found); + if (!list_empty(&obj->variant.dir_variant.dirty)) + list_del_init(&obj->variant.dir_variant.dirty); + break; + case YAFFS_OBJECT_TYPE_SYMLINK: + /* Nuke symplink data */ + kfree(obj->variant.symlink_variant.alias); + obj->variant.symlink_variant.alias = NULL; + break; + case YAFFS_OBJECT_TYPE_HARDLINK: + list_del_init(&obj->hard_links); + break; + default: + break; + } + + memset(&obj->variant, 0, sizeof(obj->variant)); + + /*Set up new variant if the memset is not enough. */ + switch (type) { + case YAFFS_OBJECT_TYPE_DIRECTORY: + INIT_LIST_HEAD(&obj->variant.dir_variant.children); + INIT_LIST_HEAD(&obj->variant.dir_variant.dirty); + break; + case YAFFS_OBJECT_TYPE_FILE: + case YAFFS_OBJECT_TYPE_SYMLINK: + case YAFFS_OBJECT_TYPE_HARDLINK: + default: + break; + } + + obj->variant_type = type; + + return obj; + +} + +static int yaffs_unlink_worker(struct yaffs_obj *obj) +{ + int del_now = 0; + + if (!obj) + return YAFFS_FAIL; + + if (!obj->my_inode) + del_now = 1; + + yaffs_update_parent(obj->parent); + + if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) { + return yaffs_del_link(obj); + } else if (!list_empty(&obj->hard_links)) { + /* Curve ball: We're unlinking an object that has a hardlink. + * + * This problem arises because we are not strictly following + * The Linux link/inode model. + * + * We can't really delete the object. + * Instead, we do the following: + * - Select a hardlink. + * - Unhook it from the hard links + * - Move it from its parent directory so that the rename works. + * - Rename the object to the hardlink's name. + * - Delete the hardlink + */ + + struct yaffs_obj *hl; + struct yaffs_obj *parent; + int ret_val; + YCHAR name[YAFFS_MAX_NAME_LENGTH + 1]; + + hl = list_entry(obj->hard_links.next, struct yaffs_obj, + hard_links); + + yaffs_get_obj_name(hl, name, YAFFS_MAX_NAME_LENGTH + 1); + parent = hl->parent; + + list_del_init(&hl->hard_links); + + yaffs_add_obj_to_dir(obj->my_dev->unlinked_dir, hl); + + ret_val = yaffs_change_obj_name(obj, parent, name, 0, 0); + + if (ret_val == YAFFS_OK) + ret_val = yaffs_generic_obj_del(hl); + + return ret_val; + + } else if (del_now) { + switch (obj->variant_type) { + case YAFFS_OBJECT_TYPE_FILE: + return yaffs_del_file(obj); + break; + case YAFFS_OBJECT_TYPE_DIRECTORY: + list_del_init(&obj->variant.dir_variant.dirty); + return yaffs_del_dir(obj); + break; + case YAFFS_OBJECT_TYPE_SYMLINK: + return yaffs_del_symlink(obj); + break; + case YAFFS_OBJECT_TYPE_SPECIAL: + return yaffs_generic_obj_del(obj); + break; + case YAFFS_OBJECT_TYPE_HARDLINK: + case YAFFS_OBJECT_TYPE_UNKNOWN: + default: + return YAFFS_FAIL; + } + } else if (yaffs_is_non_empty_dir(obj)) { + return YAFFS_FAIL; + } else { + return yaffs_change_obj_name(obj, obj->my_dev->unlinked_dir, + _Y("unlinked"), 0, 0); + } +} + +static int yaffs_unlink_obj(struct yaffs_obj *obj) +{ + if (obj && obj->unlink_allowed) + return yaffs_unlink_worker(obj); + + return YAFFS_FAIL; +} + +int yaffs_unlinker(struct yaffs_obj *dir, const YCHAR *name) +{ + struct yaffs_obj *obj; + + obj = yaffs_find_by_name(dir, name); + return yaffs_unlink_obj(obj); +} + +/* Note: + * If old_name is NULL then we take old_dir as the object to be renamed. + */ +int yaffs_rename_obj(struct yaffs_obj *old_dir, const YCHAR *old_name, + struct yaffs_obj *new_dir, const YCHAR *new_name) +{ + struct yaffs_obj *obj = NULL; + struct yaffs_obj *existing_target = NULL; + int force = 0; + int result; + struct yaffs_dev *dev; + + if (!old_dir || old_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { + BUG(); + return YAFFS_FAIL; + } + if (!new_dir || new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { + BUG(); + return YAFFS_FAIL; + } + + dev = old_dir->my_dev; + +#ifdef CONFIG_YAFFS_CASE_INSENSITIVE + /* Special case for case insemsitive systems. + * While look-up is case insensitive, the name isn't. + * Therefore we might want to change x.txt to X.txt + */ + if (old_dir == new_dir && + old_name && new_name && + strcmp(old_name, new_name) == 0) + force = 1; +#endif + + if (strnlen(new_name, YAFFS_MAX_NAME_LENGTH + 1) > + YAFFS_MAX_NAME_LENGTH) + /* ENAMETOOLONG */ + return YAFFS_FAIL; + + if (old_name) + obj = yaffs_find_by_name(old_dir, old_name); + else{ + obj = old_dir; + old_dir = obj->parent; + } + + if (obj && obj->rename_allowed) { + /* Now handle an existing target, if there is one */ + existing_target = yaffs_find_by_name(new_dir, new_name); + if (yaffs_is_non_empty_dir(existing_target)) { + return YAFFS_FAIL; /* ENOTEMPTY */ + } else if (existing_target && existing_target != obj) { + /* Nuke the target first, using shadowing, + * but only if it isn't the same object. + * + * Note we must disable gc here otherwise it can mess + * up the shadowing. + * + */ + dev->gc_disable = 1; + yaffs_change_obj_name(obj, new_dir, new_name, force, + existing_target->obj_id); + existing_target->is_shadowed = 1; + yaffs_unlink_obj(existing_target); + dev->gc_disable = 0; + } + + result = yaffs_change_obj_name(obj, new_dir, new_name, 1, 0); + + yaffs_update_parent(old_dir); + if (new_dir != old_dir) + yaffs_update_parent(new_dir); + + return result; + } + return YAFFS_FAIL; +} + +/*----------------------- Initialisation Scanning ---------------------- */ + +void yaffs_handle_shadowed_obj(struct yaffs_dev *dev, int obj_id, + int backward_scanning) +{ + struct yaffs_obj *obj; + + if (backward_scanning) { + /* Handle YAFFS2 case (backward scanning) + * If the shadowed object exists then ignore. + */ + obj = yaffs_find_by_number(dev, obj_id); + if (obj) + return; + } + + /* Let's create it (if it does not exist) assuming it is a file so that + * it can do shrinking etc. + * We put it in unlinked dir to be cleaned up after the scanning + */ + obj = + yaffs_find_or_create_by_number(dev, obj_id, YAFFS_OBJECT_TYPE_FILE); + if (!obj) + return; + obj->is_shadowed = 1; + yaffs_add_obj_to_dir(dev->unlinked_dir, obj); + obj->variant.file_variant.shrink_size = 0; + obj->valid = 1; /* So that we don't read any other info. */ +} + +void yaffs_link_fixup(struct yaffs_dev *dev, struct list_head *hard_list) +{ + struct list_head *lh; + struct list_head *save; + struct yaffs_obj *hl; + struct yaffs_obj *in; + + list_for_each_safe(lh, save, hard_list) { + hl = list_entry(lh, struct yaffs_obj, hard_links); + in = yaffs_find_by_number(dev, + hl->variant.hardlink_variant.equiv_id); + + if (in) { + /* Add the hardlink pointers */ + hl->variant.hardlink_variant.equiv_obj = in; + list_add(&hl->hard_links, &in->hard_links); + } else { + /* Todo Need to report/handle this better. + * Got a problem... hardlink to a non-existant object + */ + hl->variant.hardlink_variant.equiv_obj = NULL; + INIT_LIST_HEAD(&hl->hard_links); + } + } +} + +static void yaffs_strip_deleted_objs(struct yaffs_dev *dev) +{ + /* + * Sort out state of unlinked and deleted objects after scanning. + */ + struct list_head *i; + struct list_head *n; + struct yaffs_obj *l; + + if (dev->read_only) + return; + + /* Soft delete all the unlinked files */ + list_for_each_safe(i, n, + &dev->unlinked_dir->variant.dir_variant.children) { + l = list_entry(i, struct yaffs_obj, siblings); + yaffs_del_obj(l); + } + + list_for_each_safe(i, n, &dev->del_dir->variant.dir_variant.children) { + l = list_entry(i, struct yaffs_obj, siblings); + yaffs_del_obj(l); + } +} + +/* + * This code iterates through all the objects making sure that they are rooted. + * Any unrooted objects are re-rooted in lost+found. + * An object needs to be in one of: + * - Directly under deleted, unlinked + * - Directly or indirectly under root. + * + * Note: + * This code assumes that we don't ever change the current relationships + * between directories: + * root_dir->parent == unlinked_dir->parent == del_dir->parent == NULL + * lost-n-found->parent == root_dir + * + * This fixes the problem where directories might have inadvertently been + * deleted leaving the object "hanging" without being rooted in the + * directory tree. + */ + +static int yaffs_has_null_parent(struct yaffs_dev *dev, struct yaffs_obj *obj) +{ + return (obj == dev->del_dir || + obj == dev->unlinked_dir || obj == dev->root_dir); +} + +static void yaffs_fix_hanging_objs(struct yaffs_dev *dev) +{ + struct yaffs_obj *obj; + struct yaffs_obj *parent; + int i; + struct list_head *lh; + struct list_head *n; + int depth_limit; + int hanging; + + if (dev->read_only) + return; + + /* Iterate through the objects in each hash entry, + * looking at each object. + * Make sure it is rooted. + */ + + for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) { + list_for_each_safe(lh, n, &dev->obj_bucket[i].list) { + obj = list_entry(lh, struct yaffs_obj, hash_link); + parent = obj->parent; + + if (yaffs_has_null_parent(dev, obj)) { + /* These directories are not hanging */ + hanging = 0; + } else if (!parent || + parent->variant_type != + YAFFS_OBJECT_TYPE_DIRECTORY) { + hanging = 1; + } else if (yaffs_has_null_parent(dev, parent)) { + hanging = 0; + } else { + /* + * Need to follow the parent chain to + * see if it is hanging. + */ + hanging = 0; + depth_limit = 100; + + while (parent != dev->root_dir && + parent->parent && + parent->parent->variant_type == + YAFFS_OBJECT_TYPE_DIRECTORY && + depth_limit > 0) { + parent = parent->parent; + depth_limit--; + } + if (parent != dev->root_dir) + hanging = 1; + } + if (hanging) { + yaffs_trace(YAFFS_TRACE_SCAN, + "Hanging object %d moved to lost and found", + obj->obj_id); + yaffs_add_obj_to_dir(dev->lost_n_found, obj); + } + } + } +} + +/* + * Delete directory contents for cleaning up lost and found. + */ +static void yaffs_del_dir_contents(struct yaffs_obj *dir) +{ + struct yaffs_obj *obj; + struct list_head *lh; + struct list_head *n; + + if (dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) + BUG(); + + list_for_each_safe(lh, n, &dir->variant.dir_variant.children) { + obj = list_entry(lh, struct yaffs_obj, siblings); + if (obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) + yaffs_del_dir_contents(obj); + yaffs_trace(YAFFS_TRACE_SCAN, + "Deleting lost_found object %d", + obj->obj_id); + yaffs_unlink_obj(obj); + } +} + +static void yaffs_empty_l_n_f(struct yaffs_dev *dev) +{ + yaffs_del_dir_contents(dev->lost_n_found); +} + + +struct yaffs_obj *yaffs_find_by_name(struct yaffs_obj *directory, + const YCHAR *name) +{ + int sum; + struct list_head *i; + YCHAR buffer[YAFFS_MAX_NAME_LENGTH + 1]; + struct yaffs_obj *l; + + if (!name) + return NULL; + + if (!directory) { + yaffs_trace(YAFFS_TRACE_ALWAYS, + "tragedy: yaffs_find_by_name: null pointer directory" + ); + BUG(); + return NULL; + } + if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { + yaffs_trace(YAFFS_TRACE_ALWAYS, + "tragedy: yaffs_find_by_name: non-directory" + ); + BUG(); + } + + sum = yaffs_calc_name_sum(name); + + list_for_each(i, &directory->variant.dir_variant.children) { + l = list_entry(i, struct yaffs_obj, siblings); + + if (l->parent != directory) + BUG(); + + yaffs_check_obj_details_loaded(l); + + /* Special case for lost-n-found */ + if (l->obj_id == YAFFS_OBJECTID_LOSTNFOUND) { + if (!strcmp(name, YAFFS_LOSTNFOUND_NAME)) + return l; + } else if (l->sum == sum || l->hdr_chunk <= 0) { + /* LostnFound chunk called Objxxx + * Do a real check + */ + yaffs_get_obj_name(l, buffer, + YAFFS_MAX_NAME_LENGTH + 1); + if (!strncmp(name, buffer, YAFFS_MAX_NAME_LENGTH)) + return l; + } + } + return NULL; +} + +/* GetEquivalentObject dereferences any hard links to get to the + * actual object. + */ + +struct yaffs_obj *yaffs_get_equivalent_obj(struct yaffs_obj *obj) +{ + if (obj && obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) { + obj = obj->variant.hardlink_variant.equiv_obj; + yaffs_check_obj_details_loaded(obj); + } + return obj; +} + +/* + * A note or two on object names. + * * If the object name is missing, we then make one up in the form objnnn + * + * * ASCII names are stored in the object header's name field from byte zero + * * Unicode names are historically stored starting from byte zero. + * + * Then there are automatic Unicode names... + * The purpose of these is to save names in a way that can be read as + * ASCII or Unicode names as appropriate, thus allowing a Unicode and ASCII + * system to share files. + * + * These automatic unicode are stored slightly differently... + * - If the name can fit in the ASCII character space then they are saved as + * ascii names as per above. + * - If the name needs Unicode then the name is saved in Unicode + * starting at oh->name[1]. + + */ +static void yaffs_fix_null_name(struct yaffs_obj *obj, YCHAR *name, + int buffer_size) +{ + /* Create an object name if we could not find one. */ + if (strnlen(name, YAFFS_MAX_NAME_LENGTH) == 0) { + YCHAR local_name[20]; + YCHAR num_string[20]; + YCHAR *x = &num_string[19]; + unsigned v = obj->obj_id; + num_string[19] = 0; + while (v > 0) { + x--; + *x = '0' + (v % 10); + v /= 10; + } + /* make up a name */ + strcpy(local_name, YAFFS_LOSTNFOUND_PREFIX); + strcat(local_name, x); + strncpy(name, local_name, buffer_size - 1); + } +} + +int yaffs_get_obj_name(struct yaffs_obj *obj, YCHAR *name, int buffer_size) +{ + memset(name, 0, buffer_size * sizeof(YCHAR)); + yaffs_check_obj_details_loaded(obj); + if (obj->obj_id == YAFFS_OBJECTID_LOSTNFOUND) { + strncpy(name, YAFFS_LOSTNFOUND_NAME, buffer_size - 1); + } else if (obj->short_name[0]) { + strcpy(name, obj->short_name); + } else if (obj->hdr_chunk > 0) { + int result; + u8 *buffer = yaffs_get_temp_buffer(obj->my_dev); + + struct yaffs_obj_hdr *oh = (struct yaffs_obj_hdr *)buffer; + + memset(buffer, 0, obj->my_dev->data_bytes_per_chunk); + + if (obj->hdr_chunk > 0) { + result = yaffs_rd_chunk_tags_nand(obj->my_dev, + obj->hdr_chunk, + buffer, NULL); + } + yaffs_load_name_from_oh(obj->my_dev, name, oh->name, + buffer_size); + + yaffs_release_temp_buffer(obj->my_dev, buffer); + } + + yaffs_fix_null_name(obj, name, buffer_size); + + return strnlen(name, YAFFS_MAX_NAME_LENGTH); +} + +loff_t yaffs_get_obj_length(struct yaffs_obj *obj) +{ + /* Dereference any hard linking */ + obj = yaffs_get_equivalent_obj(obj); + + if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE) + return obj->variant.file_variant.file_size; + if (obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) { + if (!obj->variant.symlink_variant.alias) + return 0; + return strnlen(obj->variant.symlink_variant.alias, + YAFFS_MAX_ALIAS_LENGTH); + } else { + /* Only a directory should drop through to here */ + return obj->my_dev->data_bytes_per_chunk; + } +} + +int yaffs_get_obj_link_count(struct yaffs_obj *obj) +{ + int count = 0; + struct list_head *i; + + if (!obj->unlinked) + count++; /* the object itself */ + + list_for_each(i, &obj->hard_links) + count++; /* add the hard links; */ + + return count; +} + +int yaffs_get_obj_inode(struct yaffs_obj *obj) +{ + obj = yaffs_get_equivalent_obj(obj); + + return obj->obj_id; +} + +unsigned yaffs_get_obj_type(struct yaffs_obj *obj) +{ + obj = yaffs_get_equivalent_obj(obj); + + switch (obj->variant_type) { + case YAFFS_OBJECT_TYPE_FILE: + return DT_REG; + break; + case YAFFS_OBJECT_TYPE_DIRECTORY: + return DT_DIR; + break; + case YAFFS_OBJECT_TYPE_SYMLINK: + return DT_LNK; + break; + case YAFFS_OBJECT_TYPE_HARDLINK: + return DT_REG; + break; + case YAFFS_OBJECT_TYPE_SPECIAL: + if (S_ISFIFO(obj->yst_mode)) + return DT_FIFO; + if (S_ISCHR(obj->yst_mode)) + return DT_CHR; + if (S_ISBLK(obj->yst_mode)) + return DT_BLK; + if (S_ISSOCK(obj->yst_mode)) + return DT_SOCK; + return DT_REG; + break; + default: + return DT_REG; + break; + } +} + +YCHAR *yaffs_get_symlink_alias(struct yaffs_obj *obj) +{ + obj = yaffs_get_equivalent_obj(obj); + if (obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) + return yaffs_clone_str(obj->variant.symlink_variant.alias); + else + return yaffs_clone_str(_Y("")); +} + +/*--------------------------- Initialisation code -------------------------- */ + +static int yaffs_check_dev_fns(struct yaffs_dev *dev) +{ + struct yaffs_driver *drv = &dev->drv; + struct yaffs_tags_handler *tagger = &dev->tagger; + + /* Common functions, gotta have */ + if (!drv->drv_read_chunk_fn || + !drv->drv_write_chunk_fn || + !drv->drv_erase_fn) + return 0; + + if (dev->param.is_yaffs2 && + (!drv->drv_mark_bad_fn || !drv->drv_check_bad_fn)) + return 0; + + /* Install the default tags marshalling functions if needed. */ + yaffs_tags_compat_install(dev); + yaffs_tags_marshall_install(dev); + + /* Check we now have the marshalling functions required. */ + if (!tagger->write_chunk_tags_fn || + !tagger->read_chunk_tags_fn || + !tagger->query_block_fn || + !tagger->mark_bad_fn) + return 0; + + return 1; +} + +static int yaffs_create_initial_dir(struct yaffs_dev *dev) +{ + /* Initialise the unlinked, deleted, root and lost+found directories */ + dev->lost_n_found = dev->root_dir = NULL; + dev->unlinked_dir = dev->del_dir = NULL; + dev->unlinked_dir = + yaffs_create_fake_dir(dev, YAFFS_OBJECTID_UNLINKED, S_IFDIR); + dev->del_dir = + yaffs_create_fake_dir(dev, YAFFS_OBJECTID_DELETED, S_IFDIR); + dev->root_dir = + yaffs_create_fake_dir(dev, YAFFS_OBJECTID_ROOT, + YAFFS_ROOT_MODE | S_IFDIR); + dev->lost_n_found = + yaffs_create_fake_dir(dev, YAFFS_OBJECTID_LOSTNFOUND, + YAFFS_LOSTNFOUND_MODE | S_IFDIR); + + if (dev->lost_n_found && dev->root_dir && dev->unlinked_dir + && dev->del_dir) { + yaffs_add_obj_to_dir(dev->root_dir, dev->lost_n_found); + return YAFFS_OK; + } + return YAFFS_FAIL; +} + +/* Low level init. + * Typically only used by yaffs_guts_initialise, but also used by the + * Low level yaffs driver tests. + */ + +int yaffs_guts_ll_init(struct yaffs_dev *dev) +{ + + + yaffs_trace(YAFFS_TRACE_TRACING, "yaffs: yaffs_ll_init()"); + + if (!dev) { + yaffs_trace(YAFFS_TRACE_ALWAYS, + "yaffs: Need a device" + ); + return YAFFS_FAIL; + } + + if (dev->ll_init) + return YAFFS_OK; + + dev->internal_start_block = dev->param.start_block; + dev->internal_end_block = dev->param.end_block; + dev->block_offset = 0; + dev->chunk_offset = 0; + dev->n_free_chunks = 0; + + dev->gc_block = 0; + + if (dev->param.start_block == 0) { + dev->internal_start_block = dev->param.start_block + 1; + dev->internal_end_block = dev->param.end_block + 1; + dev->block_offset = 1; + dev->chunk_offset = dev->param.chunks_per_block; + } + + /* Check geometry parameters. */ + + if ((!dev->param.inband_tags && dev->param.is_yaffs2 && + dev->param.total_bytes_per_chunk < 1024) || + (!dev->param.is_yaffs2 && + dev->param.total_bytes_per_chunk < 512) || + (dev->param.inband_tags && !dev->param.is_yaffs2) || + dev->param.chunks_per_block < 2 || + dev->param.n_reserved_blocks < 2 || + dev->internal_start_block <= 0 || + dev->internal_end_block <= 0 || + dev->internal_end_block <= + (dev->internal_start_block + dev->param.n_reserved_blocks + 2) + ) { + /* otherwise it is too small */ + yaffs_trace(YAFFS_TRACE_ALWAYS, + "NAND geometry problems: chunk size %d, type is yaffs%s, inband_tags %d ", + dev->param.total_bytes_per_chunk, + dev->param.is_yaffs2 ? "2" : "", + dev->param.inband_tags); + return YAFFS_FAIL; + } + + /* Sort out space for inband tags, if required */ + if (dev->param.inband_tags) + dev->data_bytes_per_chunk = + dev->param.total_bytes_per_chunk - + sizeof(struct yaffs_packed_tags2_tags_only); + else + dev->data_bytes_per_chunk = dev->param.total_bytes_per_chunk; + + /* Got the right mix of functions? */ + if (!yaffs_check_dev_fns(dev)) { + /* Function missing */ + yaffs_trace(YAFFS_TRACE_ALWAYS, + "device function(s) missing or wrong"); + + return YAFFS_FAIL; + } + + if (yaffs_init_nand(dev) != YAFFS_OK) { + yaffs_trace(YAFFS_TRACE_ALWAYS, "InitialiseNAND failed"); + return YAFFS_FAIL; + } + + return YAFFS_OK; +} + + +int yaffs_guts_format_dev(struct yaffs_dev *dev) +{ + int i; + enum yaffs_block_state state; + u32 dummy; + + if(yaffs_guts_ll_init(dev) != YAFFS_OK) + return YAFFS_FAIL; + + if(dev->is_mounted) + return YAFFS_FAIL; + + for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) { + yaffs_query_init_block_state(dev, i, &state, &dummy); + if (state != YAFFS_BLOCK_STATE_DEAD) + yaffs_erase_block(dev, i); + } + + return YAFFS_OK; +} + + +int yaffs_guts_initialise(struct yaffs_dev *dev) +{ + int init_failed = 0; + unsigned x; + int bits; + + if(yaffs_guts_ll_init(dev) != YAFFS_OK) + return YAFFS_FAIL; + + if (dev->is_mounted) { + yaffs_trace(YAFFS_TRACE_ALWAYS, "device already mounted"); + return YAFFS_FAIL; + } + + dev->is_mounted = 1; + + /* OK now calculate a few things for the device */ + + /* + * Calculate all the chunk size manipulation numbers: + */ + x = dev->data_bytes_per_chunk; + /* We always use dev->chunk_shift and dev->chunk_div */ + dev->chunk_shift = calc_shifts(x); + x >>= dev->chunk_shift; + dev->chunk_div = x; + /* We only use chunk mask if chunk_div is 1 */ + dev->chunk_mask = (1 << dev->chunk_shift) - 1; + + /* + * Calculate chunk_grp_bits. + * We need to find the next power of 2 > than internal_end_block + */ + + x = dev->param.chunks_per_block * (dev->internal_end_block + 1); + + bits = calc_shifts_ceiling(x); + + /* Set up tnode width if wide tnodes are enabled. */ + if (!dev->param.wide_tnodes_disabled) { + /* bits must be even so that we end up with 32-bit words */ + if (bits & 1) + bits++; + if (bits < 16) + dev->tnode_width = 16; + else + dev->tnode_width = bits; + } else { + dev->tnode_width = 16; + } + + dev->tnode_mask = (1 << dev->tnode_width) - 1; + + /* Level0 Tnodes are 16 bits or wider (if wide tnodes are enabled), + * so if the bitwidth of the + * chunk range we're using is greater than 16 we need + * to figure out chunk shift and chunk_grp_size + */ + + if (bits <= dev->tnode_width) + dev->chunk_grp_bits = 0; + else + dev->chunk_grp_bits = bits - dev->tnode_width; + + dev->tnode_size = (dev->tnode_width * YAFFS_NTNODES_LEVEL0) / 8; + if (dev->tnode_size < sizeof(struct yaffs_tnode)) + dev->tnode_size = sizeof(struct yaffs_tnode); + + dev->chunk_grp_size = 1 << dev->chunk_grp_bits; + + if (dev->param.chunks_per_block < dev->chunk_grp_size) { + /* We have a problem because the soft delete won't work if + * the chunk group size > chunks per block. + * This can be remedied by using larger "virtual blocks". + */ + yaffs_trace(YAFFS_TRACE_ALWAYS, "chunk group too large"); + + return YAFFS_FAIL; + } + + /* Finished verifying the device, continue with initialisation */ + + /* More device initialisation */ + dev->all_gcs = 0; + dev->passive_gc_count = 0; + dev->oldest_dirty_gc_count = 0; + dev->bg_gcs = 0; + dev->gc_block_finder = 0; + dev->buffered_block = -1; + dev->doing_buffered_block_rewrite = 0; + dev->n_deleted_files = 0; + dev->n_bg_deletions = 0; + dev->n_unlinked_files = 0; + dev->n_ecc_fixed = 0; + dev->n_ecc_unfixed = 0; + dev->n_tags_ecc_fixed = 0; + dev->n_tags_ecc_unfixed = 0; + dev->n_erase_failures = 0; + dev->n_erased_blocks = 0; + dev->gc_disable = 0; + dev->has_pending_prioritised_gc = 1; + /* Assume the worst for now, will get fixed on first GC */ + INIT_LIST_HEAD(&dev->dirty_dirs); + dev->oldest_dirty_seq = 0; + dev->oldest_dirty_block = 0; + + /* Initialise temporary buffers and caches. */ + if (!yaffs_init_tmp_buffers(dev)) + init_failed = 1; + + dev->cache = NULL; + dev->gc_cleanup_list = NULL; + + if (!init_failed && dev->param.n_caches > 0) { + int i; + void *buf; + int cache_bytes = + dev->param.n_caches * sizeof(struct yaffs_cache); + + if (dev->param.n_caches > YAFFS_MAX_SHORT_OP_CACHES) + dev->param.n_caches = YAFFS_MAX_SHORT_OP_CACHES; + + dev->cache = kmalloc(cache_bytes, GFP_NOFS); + + buf = (u8 *) dev->cache; + + if (dev->cache) + memset(dev->cache, 0, cache_bytes); + + for (i = 0; i < dev->param.n_caches && buf; i++) { + dev->cache[i].object = NULL; + dev->cache[i].last_use = 0; + dev->cache[i].dirty = 0; + dev->cache[i].data = buf = + kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS); + } + if (!buf) + init_failed = 1; + + dev->cache_last_use = 0; + } + + dev->cache_hits = 0; + + if (!init_failed) { + dev->gc_cleanup_list = + kmalloc(dev->param.chunks_per_block * sizeof(u32), + GFP_NOFS); + if (!dev->gc_cleanup_list) + init_failed = 1; + } + + if (dev->param.is_yaffs2) + dev->param.use_header_file_size = 1; + + if (!init_failed && !yaffs_init_blocks(dev)) + init_failed = 1; + + yaffs_init_tnodes_and_objs(dev); + + if (!init_failed && !yaffs_create_initial_dir(dev)) + init_failed = 1; + + if (!init_failed && dev->param.is_yaffs2 && + !dev->param.disable_summary && + !yaffs_summary_init(dev)) + init_failed = 1; + + if (!init_failed) { + /* Now scan the flash. */ + if (dev->param.is_yaffs2) { + if (yaffs2_checkpt_restore(dev)) { + yaffs_check_obj_details_loaded(dev->root_dir); + yaffs_trace(YAFFS_TRACE_CHECKPOINT | + YAFFS_TRACE_MOUNT, + "yaffs: restored from checkpoint" + ); + } else { + + /* Clean up the mess caused by an aborted + * checkpoint load then scan backwards. + */ + yaffs_deinit_blocks(dev); + + yaffs_deinit_tnodes_and_objs(dev); + + dev->n_erased_blocks = 0; + dev->n_free_chunks = 0; + dev->alloc_block = -1; + dev->alloc_page = -1; + dev->n_deleted_files = 0; + dev->n_unlinked_files = 0; + dev->n_bg_deletions = 0; + + if (!init_failed && !yaffs_init_blocks(dev)) + init_failed = 1; + + yaffs_init_tnodes_and_objs(dev); + + if (!init_failed + && !yaffs_create_initial_dir(dev)) + init_failed = 1; + + if (!init_failed && !yaffs2_scan_backwards(dev)) + init_failed = 1; + } + } else if (!yaffs1_scan(dev)) { + init_failed = 1; + } + + yaffs_strip_deleted_objs(dev); + yaffs_fix_hanging_objs(dev); + if (dev->param.empty_lost_n_found) + yaffs_empty_l_n_f(dev); + } + + if (init_failed) { + /* Clean up the mess */ + yaffs_trace(YAFFS_TRACE_TRACING, + "yaffs: yaffs_guts_initialise() aborted."); + + yaffs_deinitialise(dev); + return YAFFS_FAIL; + } + + /* Zero out stats */ + dev->n_page_reads = 0; + dev->n_page_writes = 0; + dev->n_erasures = 0; + dev->n_gc_copies = 0; + dev->n_retried_writes = 0; + + dev->n_retired_blocks = 0; + + yaffs_verify_free_chunks(dev); + yaffs_verify_blocks(dev); + + /* Clean up any aborted checkpoint data */ + if (!dev->is_checkpointed && dev->blocks_in_checkpt > 0) + yaffs2_checkpt_invalidate(dev); + + yaffs_trace(YAFFS_TRACE_TRACING, + "yaffs: yaffs_guts_initialise() done."); + return YAFFS_OK; +} + +void yaffs_deinitialise(struct yaffs_dev *dev) +{ + if (dev->is_mounted) { + int i; + + yaffs_deinit_blocks(dev); + yaffs_deinit_tnodes_and_objs(dev); + yaffs_summary_deinit(dev); + + if (dev->param.n_caches > 0 && dev->cache) { + + for (i = 0; i < dev->param.n_caches; i++) { + kfree(dev->cache[i].data); + dev->cache[i].data = NULL; + } + + kfree(dev->cache); + dev->cache = NULL; + } + + kfree(dev->gc_cleanup_list); + + for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) { + kfree(dev->temp_buffer[i].buffer); + dev->temp_buffer[i].buffer = NULL; + } + + kfree(dev->checkpt_buffer); + dev->checkpt_buffer = NULL; + kfree(dev->checkpt_block_list); + dev->checkpt_block_list = NULL; + + dev->is_mounted = 0; + + yaffs_deinit_nand(dev); + } +} + +int yaffs_count_free_chunks(struct yaffs_dev *dev) +{ + int n_free = 0; + int b; + struct yaffs_block_info *blk; + + blk = dev->block_info; + for (b = dev->internal_start_block; b <= dev->internal_end_block; b++) { + switch (blk->block_state) { + case YAFFS_BLOCK_STATE_EMPTY: + case YAFFS_BLOCK_STATE_ALLOCATING: + case YAFFS_BLOCK_STATE_COLLECTING: + case YAFFS_BLOCK_STATE_FULL: + n_free += + (dev->param.chunks_per_block - blk->pages_in_use + + blk->soft_del_pages); + break; + default: + break; + } + blk++; + } + return n_free; +} + +int yaffs_get_n_free_chunks(struct yaffs_dev *dev) +{ + /* This is what we report to the outside world */ + int n_free; + int n_dirty_caches; + int blocks_for_checkpt; + int i; + + n_free = dev->n_free_chunks; + n_free += dev->n_deleted_files; + + /* Now count and subtract the number of dirty chunks in the cache. */ + + for (n_dirty_caches = 0, i = 0; i < dev->param.n_caches; i++) { + if (dev->cache[i].dirty) + n_dirty_caches++; + } + + n_free -= n_dirty_caches; + + n_free -= + ((dev->param.n_reserved_blocks + 1) * dev->param.chunks_per_block); + + /* Now figure checkpoint space and report that... */ + blocks_for_checkpt = yaffs_calc_checkpt_blocks_required(dev); + + n_free -= (blocks_for_checkpt * dev->param.chunks_per_block); + + if (n_free < 0) + n_free = 0; + + return n_free; +} + + + +/* + * Marshalling functions to get loff_t file sizes into and out of + * object headers. + */ +void yaffs_oh_size_load(struct yaffs_obj_hdr *oh, loff_t fsize) +{ + oh->file_size_low = (fsize & 0xFFFFFFFF); + oh->file_size_high = ((fsize >> 32) & 0xFFFFFFFF); +} + +loff_t yaffs_oh_to_size(struct yaffs_obj_hdr *oh) +{ + loff_t retval; + + if (sizeof(loff_t) >= 8 && ~(oh->file_size_high)) + retval = (((loff_t) oh->file_size_high) << 32) | + (((loff_t) oh->file_size_low) & 0xFFFFFFFF); + else + retval = (loff_t) oh->file_size_low; + + return retval; +} + + +void yaffs_count_blocks_by_state(struct yaffs_dev *dev, int bs[10]) +{ + int i; + struct yaffs_block_info *bi; + int s; + + for(i = 0; i < 10; i++) + bs[i] = 0; + + for(i = dev->internal_start_block; i <= dev->internal_end_block; i++) { + bi = yaffs_get_block_info(dev, i); + s = bi->block_state; + if(s > YAFFS_BLOCK_STATE_DEAD || s < YAFFS_BLOCK_STATE_UNKNOWN) + bs[0]++; + else + bs[s]++; + } +} diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_guts.h b/target/linux/generic/files/fs/yaffs2/yaffs_guts.h new file mode 100644 index 0000000..231f8ac --- /dev/null +++ b/target/linux/generic/files/fs/yaffs2/yaffs_guts.h @@ -0,0 +1,1010 @@ +/* + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + */ + +#ifndef __YAFFS_GUTS_H__ +#define __YAFFS_GUTS_H__ + +#include "yportenv.h" + +#define YAFFS_OK 1 +#define YAFFS_FAIL 0 + +/* Give us a Y=0x59, + * Give us an A=0x41, + * Give us an FF=0xff + * Give us an S=0x53 + * And what have we got... + */ +#define YAFFS_MAGIC 0x5941ff53 + +/* + * Tnodes form a tree with the tnodes in "levels" + * Levels greater than 0 hold 8 slots which point to other tnodes. + * Those at level 0 hold 16 slots which point to chunks in NAND. + * + * A maximum level of 8 thust supports files of size up to: + * + * 2^(3*MAX_LEVEL+4) + * + * Thus a max level of 8 supports files with up to 2^^28 chunks which gives + * a maximum file size of around 512Gbytees with 2k chunks. + */ +#define YAFFS_NTNODES_LEVEL0 16 +#define YAFFS_TNODES_LEVEL0_BITS 4 +#define YAFFS_TNODES_LEVEL0_MASK 0xf + +#define YAFFS_NTNODES_INTERNAL (YAFFS_NTNODES_LEVEL0 / 2) +#define YAFFS_TNODES_INTERNAL_BITS (YAFFS_TNODES_LEVEL0_BITS - 1) +#define YAFFS_TNODES_INTERNAL_MASK 0x7 +#define YAFFS_TNODES_MAX_LEVEL 8 +#define YAFFS_TNODES_MAX_BITS (YAFFS_TNODES_LEVEL0_BITS + \ + YAFFS_TNODES_INTERNAL_BITS * \ + YAFFS_TNODES_MAX_LEVEL) +#define YAFFS_MAX_CHUNK_ID ((1 << YAFFS_TNODES_MAX_BITS) - 1) + +#define YAFFS_MAX_FILE_SIZE_32 0x7fffffff + +/* Constants for YAFFS1 mode */ +#define YAFFS_BYTES_PER_SPARE 16 +#define YAFFS_BYTES_PER_CHUNK 512 +#define YAFFS_CHUNK_SIZE_SHIFT 9 +#define YAFFS_CHUNKS_PER_BLOCK 32 +#define YAFFS_BYTES_PER_BLOCK (YAFFS_CHUNKS_PER_BLOCK*YAFFS_BYTES_PER_CHUNK) + +#define YAFFS_MIN_YAFFS2_CHUNK_SIZE 1024 +#define YAFFS_MIN_YAFFS2_SPARE_SIZE 32 + + + +#define YAFFS_ALLOCATION_NOBJECTS 100 +#define YAFFS_ALLOCATION_NTNODES 100 +#define YAFFS_ALLOCATION_NLINKS 100 + +#define YAFFS_NOBJECT_BUCKETS 256 + +#define YAFFS_OBJECT_SPACE 0x40000 +#define YAFFS_MAX_OBJECT_ID (YAFFS_OBJECT_SPACE - 1) + +/* Binary data version stamps */ +#define YAFFS_SUMMARY_VERSION 1 +#define YAFFS_CHECKPOINT_VERSION 7 + +#ifdef CONFIG_YAFFS_UNICODE +#define YAFFS_MAX_NAME_LENGTH 127 +#define YAFFS_MAX_ALIAS_LENGTH 79 +#else +#define YAFFS_MAX_NAME_LENGTH 255 +#define YAFFS_MAX_ALIAS_LENGTH 159 +#endif + +#define YAFFS_SHORT_NAME_LENGTH 15 + +/* Some special object ids for pseudo objects */ +#define YAFFS_OBJECTID_ROOT 1 +#define YAFFS_OBJECTID_LOSTNFOUND 2 +#define YAFFS_OBJECTID_UNLINKED 3 +#define YAFFS_OBJECTID_DELETED 4 + +/* Fake object Id for summary data */ +#define YAFFS_OBJECTID_SUMMARY 0x10 + +/* Pseudo object ids for checkpointing */ +#define YAFFS_OBJECTID_CHECKPOINT_DATA 0x20 +#define YAFFS_SEQUENCE_CHECKPOINT_DATA 0x21 + +#define YAFFS_MAX_SHORT_OP_CACHES 20 + +#define YAFFS_N_TEMP_BUFFERS 6 + +/* We limit the number attempts at sucessfully saving a chunk of data. + * Small-page devices have 32 pages per block; large-page devices have 64. + * Default to something in the order of 5 to 10 blocks worth of chunks. + */ +#define YAFFS_WR_ATTEMPTS (5*64) + +/* Sequence numbers are used in YAFFS2 to determine block allocation order. + * The range is limited slightly to help distinguish bad numbers from good. + * This also allows us to perhaps in the future use special numbers for + * special purposes. + * EFFFFF00 allows the allocation of 8 blocks/second (~1Mbytes) for 15 years, + * and is a larger number than the lifetime of a 2GB device. + */ +#define YAFFS_LOWEST_SEQUENCE_NUMBER 0x00001000 +#define YAFFS_HIGHEST_SEQUENCE_NUMBER 0xefffff00 + +/* Special sequence number for bad block that failed to be marked bad */ +#define YAFFS_SEQUENCE_BAD_BLOCK 0xffff0000 + +/* ChunkCache is used for short read/write operations.*/ +struct yaffs_cache { + struct yaffs_obj *object; + int chunk_id; + int last_use; + int dirty; + int n_bytes; /* Only valid if the cache is dirty */ + int locked; /* Can't push out or flush while locked. */ + u8 *data; +}; + +/* yaffs1 tags structures in RAM + * NB This uses bitfield. Bitfields should not straddle a u32 boundary + * otherwise the structure size will get blown out. + */ + +struct yaffs_tags { + u32 chunk_id:20; + u32 serial_number:2; + u32 n_bytes_lsb:10; + u32 obj_id:18; + u32 ecc:12; + u32 n_bytes_msb:2; +}; + +union yaffs_tags_union { + struct yaffs_tags as_tags; + u8 as_bytes[8]; +}; + + +/* Stuff used for extended tags in YAFFS2 */ + +enum yaffs_ecc_result { + YAFFS_ECC_RESULT_UNKNOWN, + YAFFS_ECC_RESULT_NO_ERROR, + YAFFS_ECC_RESULT_FIXED, + YAFFS_ECC_RESULT_UNFIXED +}; + +enum yaffs_obj_type { + YAFFS_OBJECT_TYPE_UNKNOWN, + YAFFS_OBJECT_TYPE_FILE, + YAFFS_OBJECT_TYPE_SYMLINK, + YAFFS_OBJECT_TYPE_DIRECTORY, + YAFFS_OBJECT_TYPE_HARDLINK, + YAFFS_OBJECT_TYPE_SPECIAL +}; + +#define YAFFS_OBJECT_TYPE_MAX YAFFS_OBJECT_TYPE_SPECIAL + +struct yaffs_ext_tags { + unsigned chunk_used; /* Status of the chunk: used or unused */ + unsigned obj_id; /* If 0 this is not used */ + unsigned chunk_id; /* If 0 this is a header, else a data chunk */ + unsigned n_bytes; /* Only valid for data chunks */ + + /* The following stuff only has meaning when we read */ + enum yaffs_ecc_result ecc_result; + unsigned block_bad; + + /* YAFFS 1 stuff */ + unsigned is_deleted; /* The chunk is marked deleted */ + unsigned serial_number; /* Yaffs1 2-bit serial number */ + + /* YAFFS2 stuff */ + unsigned seq_number; /* The sequence number of this block */ + + /* Extra info if this is an object header (YAFFS2 only) */ + + unsigned extra_available; /* Extra info available if not zero */ + unsigned extra_parent_id; /* The parent object */ + unsigned extra_is_shrink; /* Is it a shrink header? */ + unsigned extra_shadows; /* Does this shadow another object? */ + + enum yaffs_obj_type extra_obj_type; /* What object type? */ + + loff_t extra_file_size; /* Length if it is a file */ + unsigned extra_equiv_id; /* Equivalent object for a hard link */ +}; + +/* Spare structure for YAFFS1 */ +struct yaffs_spare { + u8 tb0; + u8 tb1; + u8 tb2; + u8 tb3; + u8 page_status; /* set to 0 to delete the chunk */ + u8 block_status; + u8 tb4; + u8 tb5; + u8 ecc1[3]; + u8 tb6; + u8 tb7; + u8 ecc2[3]; +}; + +/*Special structure for passing through to mtd */ +struct yaffs_nand_spare { + struct yaffs_spare spare; + int eccres1; + int eccres2; +}; + +/* Block data in RAM */ + +enum yaffs_block_state { + YAFFS_BLOCK_STATE_UNKNOWN = 0, + + YAFFS_BLOCK_STATE_SCANNING, + /* Being scanned */ + + YAFFS_BLOCK_STATE_NEEDS_SCAN, + /* The block might have something on it (ie it is allocating or full, + * perhaps empty) but it needs to be scanned to determine its true + * state. + * This state is only valid during scanning. + * NB We tolerate empty because the pre-scanner might be incapable of + * deciding + * However, if this state is returned on a YAFFS2 device, + * then we expect a sequence number + */ + + YAFFS_BLOCK_STATE_EMPTY, + /* This block is empty */ + + YAFFS_BLOCK_STATE_ALLOCATING, + /* This block is partially allocated. + * At least one page holds valid data. + * This is the one currently being used for page + * allocation. Should never be more than one of these. + * If a block is only partially allocated at mount it is treated as + * full. + */ + + YAFFS_BLOCK_STATE_FULL, + /* All the pages in this block have been allocated. + * If a block was only partially allocated when mounted we treat + * it as fully allocated. + */ + + YAFFS_BLOCK_STATE_DIRTY, + /* The block was full and now all chunks have been deleted. + * Erase me, reuse me. + */ + + YAFFS_BLOCK_STATE_CHECKPOINT, + /* This block is assigned to holding checkpoint data. */ + + YAFFS_BLOCK_STATE_COLLECTING, + /* This block is being garbage collected */ + + YAFFS_BLOCK_STATE_DEAD + /* This block has failed and is not in use */ +}; + +#define YAFFS_NUMBER_OF_BLOCK_STATES (YAFFS_BLOCK_STATE_DEAD + 1) + +struct yaffs_block_info { + + s32 soft_del_pages:10; /* number of soft deleted pages */ + s32 pages_in_use:10; /* number of pages in use */ + u32 block_state:4; /* One of the above block states. */ + /* NB use unsigned because enum is sometimes + * an int */ + u32 needs_retiring:1; /* Data has failed on this block, */ + /*need to get valid data off and retire*/ + u32 skip_erased_check:1;/* Skip the erased check on this block */ + u32 gc_prioritise:1; /* An ECC check or blank check has failed. + Block should be prioritised for GC */ + u32 chunk_error_strikes:3; /* How many times we've had ecc etc + failures on this block and tried to reuse it */ + u32 has_summary:1; /* The block has a summary */ + + u32 has_shrink_hdr:1; /* This block has at least one shrink header */ + u32 seq_number; /* block sequence number for yaffs2 */ + +}; + +/* -------------------------- Object structure -------------------------------*/ +/* This is the object structure as stored on NAND */ + +struct yaffs_obj_hdr { + enum yaffs_obj_type type; + + /* Apply to everything */ + int parent_obj_id; + u16 sum_no_longer_used; /* checksum of name. No longer used */ + YCHAR name[YAFFS_MAX_NAME_LENGTH + 1]; + + /* The following apply to all object types except for hard links */ + u32 yst_mode; /* protection */ + + u32 yst_uid; + u32 yst_gid; + u32 yst_atime; + u32 yst_mtime; + u32 yst_ctime; + + /* File size applies to files only */ + u32 file_size_low; + + /* Equivalent object id applies to hard links only. */ + int equiv_id; + + /* Alias is for symlinks only. */ + YCHAR alias[YAFFS_MAX_ALIAS_LENGTH + 1]; + + u32 yst_rdev; /* stuff for block and char devices (major/min) */ + + u32 win_ctime[2]; + u32 win_atime[2]; + u32 win_mtime[2]; + + u32 inband_shadowed_obj_id; + u32 inband_is_shrink; + + u32 file_size_high; + u32 reserved[1]; + int shadows_obj; /* This object header shadows the + specified object if > 0 */ + + /* is_shrink applies to object headers written when wemake a hole. */ + u32 is_shrink; + +}; + +/*--------------------------- Tnode -------------------------- */ + +struct yaffs_tnode { + struct yaffs_tnode *internal[YAFFS_NTNODES_INTERNAL]; +}; + +/*------------------------ Object -----------------------------*/ +/* An object can be one of: + * - a directory (no data, has children links + * - a regular file (data.... not prunes :->). + * - a symlink [symbolic link] (the alias). + * - a hard link + */ + +struct yaffs_file_var { + loff_t file_size; + loff_t scanned_size; + loff_t shrink_size; + int top_level; + struct yaffs_tnode *top; +}; + +struct yaffs_dir_var { + struct list_head children; /* list of child links */ + struct list_head dirty; /* Entry for list of dirty directories */ +}; + +struct yaffs_symlink_var { + YCHAR *alias; +}; + +struct yaffs_hardlink_var { + struct yaffs_obj *equiv_obj; + u32 equiv_id; +}; + +union yaffs_obj_var { + struct yaffs_file_var file_variant; + struct yaffs_dir_var dir_variant; + struct yaffs_symlink_var symlink_variant; + struct yaffs_hardlink_var hardlink_variant; +}; + +struct yaffs_obj { + u8 deleted:1; /* This should only apply to unlinked files. */ + u8 soft_del:1; /* it has also been soft deleted */ + u8 unlinked:1; /* An unlinked file.*/ + u8 fake:1; /* A fake object has no presence on NAND. */ + u8 rename_allowed:1; /* Some objects cannot be renamed. */ + u8 unlink_allowed:1; + u8 dirty:1; /* the object needs to be written to flash */ + u8 valid:1; /* When the file system is being loaded up, this + * object might be created before the data + * is available + * ie. file data chunks encountered before + * the header. + */ + u8 lazy_loaded:1; /* This object has been lazy loaded and + * is missing some detail */ + + u8 defered_free:1; /* Object is removed from NAND, but is + * still in the inode cache. + * Free of object is defered. + * until the inode is released. + */ + u8 being_created:1; /* This object is still being created + * so skip some verification checks. */ + u8 is_shadowed:1; /* This object is shadowed on the way + * to being renamed. */ + + u8 xattr_known:1; /* We know if this has object has xattribs + * or not. */ + u8 has_xattr:1; /* This object has xattribs. + * Only valid if xattr_known. */ + + u8 serial; /* serial number of chunk in NAND.*/ + u16 sum; /* sum of the name to speed searching */ + + struct yaffs_dev *my_dev; /* The device I'm on */ + + struct list_head hash_link; /* list of objects in hash bucket */ + + struct list_head hard_links; /* hard linked object chain*/ + + /* directory structure stuff */ + /* also used for linking up the free list */ + struct yaffs_obj *parent; + struct list_head siblings; + + /* Where's my object header in NAND? */ + int hdr_chunk; + + int n_data_chunks; /* Number of data chunks for this file. */ + + u32 obj_id; /* the object id value */ + + u32 yst_mode; + + YCHAR short_name[YAFFS_SHORT_NAME_LENGTH + 1]; + +#ifdef CONFIG_YAFFS_WINCE + u32 win_ctime[2]; + u32 win_mtime[2]; + u32 win_atime[2]; +#else + u32 yst_uid; + u32 yst_gid; + u32 yst_atime; + u32 yst_mtime; + u32 yst_ctime; +#endif + + u32 yst_rdev; + + void *my_inode; + + enum yaffs_obj_type variant_type; + + union yaffs_obj_var variant; + +}; + +struct yaffs_obj_bucket { + struct list_head list; + int count; +}; + +/* yaffs_checkpt_obj holds the definition of an object as dumped + * by checkpointing. + */ + +struct yaffs_checkpt_obj { + int struct_type; + u32 obj_id; + u32 parent_id; + int hdr_chunk; + enum yaffs_obj_type variant_type:3; + u8 deleted:1; + u8 soft_del:1; + u8 unlinked:1; + u8 fake:1; + u8 rename_allowed:1; + u8 unlink_allowed:1; + u8 serial; + int n_data_chunks; + loff_t size_or_equiv_obj; +}; + +/*--------------------- Temporary buffers ---------------- + * + * These are chunk-sized working buffers. Each device has a few. + */ + +struct yaffs_buffer { + u8 *buffer; + int in_use; +}; + +/*----------------- Device ---------------------------------*/ + +struct yaffs_param { + const YCHAR *name; + + /* + * Entry parameters set up way early. Yaffs sets up the rest. + * The structure should be zeroed out before use so that unused + * and default values are zero. + */ + + int inband_tags; /* Use unband tags */ + u32 total_bytes_per_chunk; /* Should be >= 512, does not need to + be a power of 2 */ + int chunks_per_block; /* does not need to be a power of 2 */ + int spare_bytes_per_chunk; /* spare area size */ + int start_block; /* Start block we're allowed to use */ + int end_block; /* End block we're allowed to use */ + int n_reserved_blocks; /* Tuneable so that we can reduce + * reserved blocks on NOR and RAM. */ + + int n_caches; /* If <= 0, then short op caching is disabled, + * else the number of short op caches. + */ + int cache_bypass_aligned; /* If non-zero then bypass the cache for + * aligned writes. + */ + + int use_nand_ecc; /* Flag to decide whether or not to use + * NAND driver ECC on data (yaffs1) */ + int tags_9bytes; /* Use 9 byte tags */ + int no_tags_ecc; /* Flag to decide whether or not to do ECC + * on packed tags (yaffs2) */ + + int is_yaffs2; /* Use yaffs2 mode on this device */ + + int empty_lost_n_found; /* Auto-empty lost+found directory on mount */ + + int refresh_period; /* How often to check for a block refresh */ + + /* Checkpoint control. Can be set before or after initialisation */ + u8 skip_checkpt_rd; + u8 skip_checkpt_wr; + + int enable_xattr; /* Enable xattribs */ + + int max_objects; /* + * Set to limit the number of objects created. + * 0 = no limit. + */ + + /* The remove_obj_fn function must be supplied by OS flavours that + * need it. + * yaffs direct uses it to implement the faster readdir. + * Linux uses it to protect the directory during unlocking. + */ + void (*remove_obj_fn) (struct yaffs_obj *obj); + + /* Callback to mark the superblock dirty */ + void (*sb_dirty_fn) (struct yaffs_dev *dev); + + /* Callback to control garbage collection. */ + unsigned (*gc_control_fn) (struct yaffs_dev *dev); + + /* Debug control flags. Don't use unless you know what you're doing */ + int use_header_file_size; /* Flag to determine if we should use + * file sizes from the header */ + int disable_lazy_load; /* Disable lazy loading on this device */ + int wide_tnodes_disabled; /* Set to disable wide tnodes */ + int disable_soft_del; /* yaffs 1 only: Set to disable the use of + * softdeletion. */ + + int defered_dir_update; /* Set to defer directory updates */ + +#ifdef CONFIG_YAFFS_AUTO_UNICODE + int auto_unicode; +#endif + int always_check_erased; /* Force chunk erased check always on */ + + int disable_summary; + int disable_bad_block_marking; + +}; + +struct yaffs_driver { + int (*drv_write_chunk_fn) (struct yaffs_dev *dev, int nand_chunk, + const u8 *data, int data_len, + const u8 *oob, int oob_len); + int (*drv_read_chunk_fn) (struct yaffs_dev *dev, int nand_chunk, + u8 *data, int data_len, + u8 *oob, int oob_len, + enum yaffs_ecc_result *ecc_result); + int (*drv_erase_fn) (struct yaffs_dev *dev, int block_no); + int (*drv_mark_bad_fn) (struct yaffs_dev *dev, int block_no); + int (*drv_check_bad_fn) (struct yaffs_dev *dev, int block_no); + int (*drv_initialise_fn) (struct yaffs_dev *dev); + int (*drv_deinitialise_fn) (struct yaffs_dev *dev); +}; + +struct yaffs_tags_handler { + int (*write_chunk_tags_fn) (struct yaffs_dev *dev, + int nand_chunk, const u8 *data, + const struct yaffs_ext_tags *tags); + int (*read_chunk_tags_fn) (struct yaffs_dev *dev, + int nand_chunk, u8 *data, + struct yaffs_ext_tags *tags); + + int (*query_block_fn) (struct yaffs_dev *dev, int block_no, + enum yaffs_block_state *state, + u32 *seq_number); + int (*mark_bad_fn) (struct yaffs_dev *dev, int block_no); +}; + +struct yaffs_dev { + struct yaffs_param param; + struct yaffs_driver drv; + struct yaffs_tags_handler tagger; + + /* Context storage. Holds extra OS specific data for this device */ + + void *os_context; + void *driver_context; + + struct list_head dev_list; + + int ll_init; + /* Runtime parameters. Set up by YAFFS. */ + int data_bytes_per_chunk; + + /* Non-wide tnode stuff */ + u16 chunk_grp_bits; /* Number of bits that need to be resolved if + * the tnodes are not wide enough. + */ + u16 chunk_grp_size; /* == 2^^chunk_grp_bits */ + + /* Stuff to support wide tnodes */ + u32 tnode_width; + u32 tnode_mask; + u32 tnode_size; + + /* Stuff for figuring out file offset to chunk conversions */ + u32 chunk_shift; /* Shift value */ + u32 chunk_div; /* Divisor after shifting: 1 for 2^n sizes */ + u32 chunk_mask; /* Mask to use for power-of-2 case */ + + int is_mounted; + int read_only; + int is_checkpointed; + + /* Stuff to support block offsetting to support start block zero */ + int internal_start_block; + int internal_end_block; + int block_offset; + int chunk_offset; + + /* Runtime checkpointing stuff */ + int checkpt_page_seq; /* running sequence number of checkpt pages */ + int checkpt_byte_count; + int checkpt_byte_offs; + u8 *checkpt_buffer; + int checkpt_open_write; + int blocks_in_checkpt; + int checkpt_cur_chunk; + int checkpt_cur_block; + int checkpt_next_block; + int *checkpt_block_list; + int checkpt_max_blocks; + u32 checkpt_sum; + u32 checkpt_xor; + + int checkpoint_blocks_required; /* Number of blocks needed to store + * current checkpoint set */ + + /* Block Info */ + struct yaffs_block_info *block_info; + u8 *chunk_bits; /* bitmap of chunks in use */ + u8 block_info_alt:1; /* allocated using alternative alloc */ + u8 chunk_bits_alt:1; /* allocated using alternative alloc */ + int chunk_bit_stride; /* Number of bytes of chunk_bits per block. + * Must be consistent with chunks_per_block. + */ + + int n_erased_blocks; + int alloc_block; /* Current block being allocated off */ + u32 alloc_page; + int alloc_block_finder; /* Used to search for next allocation block */ + + /* Object and Tnode memory management */ + void *allocator; + int n_obj; + int n_tnodes; + + int n_hardlinks; + + struct yaffs_obj_bucket obj_bucket[YAFFS_NOBJECT_BUCKETS]; + u32 bucket_finder; + + int n_free_chunks; + + /* Garbage collection control */ + u32 *gc_cleanup_list; /* objects to delete at the end of a GC. */ + u32 n_clean_ups; + + unsigned has_pending_prioritised_gc; /* We think this device might + have pending prioritised gcs */ + unsigned gc_disable; + unsigned gc_block_finder; + unsigned gc_dirtiest; + unsigned gc_pages_in_use; + unsigned gc_not_done; + unsigned gc_block; + unsigned gc_chunk; + unsigned gc_skip; + struct yaffs_summary_tags *gc_sum_tags; + + /* Special directories */ + struct yaffs_obj *root_dir; + struct yaffs_obj *lost_n_found; + + int buffered_block; /* Which block is buffered here? */ + int doing_buffered_block_rewrite; + + struct yaffs_cache *cache; + int cache_last_use; + + /* Stuff for background deletion and unlinked files. */ + struct yaffs_obj *unlinked_dir; /* Directory where unlinked and deleted + files live. */ + struct yaffs_obj *del_dir; /* Directory where deleted objects are + sent to disappear. */ + struct yaffs_obj *unlinked_deletion; /* Current file being + background deleted. */ + int n_deleted_files; /* Count of files awaiting deletion; */ + int n_unlinked_files; /* Count of unlinked files. */ + int n_bg_deletions; /* Count of background deletions. */ + + /* Temporary buffer management */ + struct yaffs_buffer temp_buffer[YAFFS_N_TEMP_BUFFERS]; + int max_temp; + int temp_in_use; + int unmanaged_buffer_allocs; + int unmanaged_buffer_deallocs; + + /* yaffs2 runtime stuff */ + unsigned seq_number; /* Sequence number of currently + allocating block */ + unsigned oldest_dirty_seq; + unsigned oldest_dirty_block; + + /* Block refreshing */ + int refresh_skip; /* A skip down counter. + * Refresh happens when this gets to zero. */ + + /* Dirty directory handling */ + struct list_head dirty_dirs; /* List of dirty directories */ + + /* Summary */ + int chunks_per_summary; + struct yaffs_summary_tags *sum_tags; + + /* Statistics */ + u32 n_page_writes; + u32 n_page_reads; + u32 n_erasures; + u32 n_bad_queries; + u32 n_bad_markings; + u32 n_erase_failures; + u32 n_gc_copies; + u32 all_gcs; + u32 passive_gc_count; + u32 oldest_dirty_gc_count; + u32 n_gc_blocks; + u32 bg_gcs; + u32 n_retried_writes; + u32 n_retired_blocks; + u32 n_ecc_fixed; + u32 n_ecc_unfixed; + u32 n_tags_ecc_fixed; + u32 n_tags_ecc_unfixed; + u32 n_deletions; + u32 n_unmarked_deletions; + u32 refresh_count; + u32 cache_hits; + u32 tags_used; + u32 summary_used; + +}; + +/* The CheckpointDevice structure holds the device information that changes + *at runtime and must be preserved over unmount/mount cycles. + */ +struct yaffs_checkpt_dev { + int struct_type; + int n_erased_blocks; + int alloc_block; /* Current block being allocated off */ + u32 alloc_page; + int n_free_chunks; + + int n_deleted_files; /* Count of files awaiting deletion; */ + int n_unlinked_files; /* Count of unlinked files. */ + int n_bg_deletions; /* Count of background deletions. */ + + /* yaffs2 runtime stuff */ + unsigned seq_number; /* Sequence number of currently + * allocating block */ + +}; + +struct yaffs_checkpt_validity { + int struct_type; + u32 magic; + u32 version; + u32 head; +}; + +struct yaffs_shadow_fixer { + int obj_id; + int shadowed_id; + struct yaffs_shadow_fixer *next; +}; + +/* Structure for doing xattr modifications */ +struct yaffs_xattr_mod { + int set; /* If 0 then this is a deletion */ + const YCHAR *name; + const void *data; + int size; + int flags; + int result; +}; + +/*----------------------- YAFFS Functions -----------------------*/ + +int yaffs_guts_initialise(struct yaffs_dev *dev); +void yaffs_deinitialise(struct yaffs_dev *dev); + +int yaffs_get_n_free_chunks(struct yaffs_dev *dev); + +int yaffs_rename_obj(struct yaffs_obj *old_dir, const YCHAR * old_name, + struct yaffs_obj *new_dir, const YCHAR * new_name); + +int yaffs_unlinker(struct yaffs_obj *dir, const YCHAR * name); +int yaffs_del_obj(struct yaffs_obj *obj); +struct yaffs_obj *yaffs_retype_obj(struct yaffs_obj *obj, + enum yaffs_obj_type type); + + +int yaffs_get_obj_name(struct yaffs_obj *obj, YCHAR * name, int buffer_size); +loff_t yaffs_get_obj_length(struct yaffs_obj *obj); +int yaffs_get_obj_inode(struct yaffs_obj *obj); +unsigned yaffs_get_obj_type(struct yaffs_obj *obj); +int yaffs_get_obj_link_count(struct yaffs_obj *obj); + +/* File operations */ +int yaffs_file_rd(struct yaffs_obj *obj, u8 * buffer, loff_t offset, + int n_bytes); +int yaffs_wr_file(struct yaffs_obj *obj, const u8 * buffer, loff_t offset, + int n_bytes, int write_trhrough); +int yaffs_resize_file(struct yaffs_obj *obj, loff_t new_size); + +struct yaffs_obj *yaffs_create_file(struct yaffs_obj *parent, + const YCHAR *name, u32 mode, u32 uid, + u32 gid); + +int yaffs_flush_file(struct yaffs_obj *in, + int update_time, + int data_sync, + int discard_cache); + +/* Flushing and checkpointing */ +void yaffs_flush_whole_cache(struct yaffs_dev *dev, int discard); + +int yaffs_checkpoint_save(struct yaffs_dev *dev); +int yaffs_checkpoint_restore(struct yaffs_dev *dev); + +/* Directory operations */ +struct yaffs_obj *yaffs_create_dir(struct yaffs_obj *parent, const YCHAR *name, + u32 mode, u32 uid, u32 gid); +struct yaffs_obj *yaffs_find_by_name(struct yaffs_obj *the_dir, + const YCHAR *name); +struct yaffs_obj *yaffs_find_by_number(struct yaffs_dev *dev, u32 number); + +/* Link operations */ +struct yaffs_obj *yaffs_link_obj(struct yaffs_obj *parent, const YCHAR *name, + struct yaffs_obj *equiv_obj); + +struct yaffs_obj *yaffs_get_equivalent_obj(struct yaffs_obj *obj); + +/* Symlink operations */ +struct yaffs_obj *yaffs_create_symlink(struct yaffs_obj *parent, + const YCHAR *name, u32 mode, u32 uid, + u32 gid, const YCHAR *alias); +YCHAR *yaffs_get_symlink_alias(struct yaffs_obj *obj); + +/* Special inodes (fifos, sockets and devices) */ +struct yaffs_obj *yaffs_create_special(struct yaffs_obj *parent, + const YCHAR *name, u32 mode, u32 uid, + u32 gid, u32 rdev); + +int yaffs_set_xattrib(struct yaffs_obj *obj, const YCHAR *name, + const void *value, int size, int flags); +int yaffs_get_xattrib(struct yaffs_obj *obj, const YCHAR *name, void *value, + int size); +int yaffs_list_xattrib(struct yaffs_obj *obj, char *buffer, int size); +int yaffs_remove_xattrib(struct yaffs_obj *obj, const YCHAR *name); + +/* Special directories */ +struct yaffs_obj *yaffs_root(struct yaffs_dev *dev); +struct yaffs_obj *yaffs_lost_n_found(struct yaffs_dev *dev); + +void yaffs_handle_defered_free(struct yaffs_obj *obj); + +void yaffs_update_dirty_dirs(struct yaffs_dev *dev); + +int yaffs_bg_gc(struct yaffs_dev *dev, unsigned urgency); + +/* Debug dump */ +int yaffs_dump_obj(struct yaffs_obj *obj); + +void yaffs_guts_test(struct yaffs_dev *dev); +int yaffs_guts_ll_init(struct yaffs_dev *dev); + + +/* A few useful functions to be used within the core files*/ +void yaffs_chunk_del(struct yaffs_dev *dev, int chunk_id, int mark_flash, + int lyn); +int yaffs_check_ff(u8 *buffer, int n_bytes); +void yaffs_handle_chunk_error(struct yaffs_dev *dev, + struct yaffs_block_info *bi); + +u8 *yaffs_get_temp_buffer(struct yaffs_dev *dev); +void yaffs_release_temp_buffer(struct yaffs_dev *dev, u8 *buffer); + +struct yaffs_obj *yaffs_find_or_create_by_number(struct yaffs_dev *dev, + int number, + enum yaffs_obj_type type); +int yaffs_put_chunk_in_file(struct yaffs_obj *in, int inode_chunk, + int nand_chunk, int in_scan); +void yaffs_set_obj_name(struct yaffs_obj *obj, const YCHAR *name); +void yaffs_set_obj_name_from_oh(struct yaffs_obj *obj, + const struct yaffs_obj_hdr *oh); +void yaffs_add_obj_to_dir(struct yaffs_obj *directory, struct yaffs_obj *obj); +YCHAR *yaffs_clone_str(const YCHAR *str); +void yaffs_link_fixup(struct yaffs_dev *dev, struct list_head *hard_list); +void yaffs_block_became_dirty(struct yaffs_dev *dev, int block_no); +int yaffs_update_oh(struct yaffs_obj *in, const YCHAR *name, + int force, int is_shrink, int shadows, + struct yaffs_xattr_mod *xop); +void yaffs_handle_shadowed_obj(struct yaffs_dev *dev, int obj_id, + int backward_scanning); +int yaffs_check_alloc_available(struct yaffs_dev *dev, int n_chunks); +struct yaffs_tnode *yaffs_get_tnode(struct yaffs_dev *dev); +struct yaffs_tnode *yaffs_add_find_tnode_0(struct yaffs_dev *dev, + struct yaffs_file_var *file_struct, + u32 chunk_id, + struct yaffs_tnode *passed_tn); + +int yaffs_do_file_wr(struct yaffs_obj *in, const u8 *buffer, loff_t offset, + int n_bytes, int write_trhrough); +void yaffs_resize_file_down(struct yaffs_obj *obj, loff_t new_size); +void yaffs_skip_rest_of_block(struct yaffs_dev *dev); + +int yaffs_count_free_chunks(struct yaffs_dev *dev); + +struct yaffs_tnode *yaffs_find_tnode_0(struct yaffs_dev *dev, + struct yaffs_file_var *file_struct, + u32 chunk_id); + +u32 yaffs_get_group_base(struct yaffs_dev *dev, struct yaffs_tnode *tn, + unsigned pos); + +int yaffs_is_non_empty_dir(struct yaffs_obj *obj); + +int yaffs_guts_format_dev(struct yaffs_dev *dev); + +void yaffs_addr_to_chunk(struct yaffs_dev *dev, loff_t addr, + int *chunk_out, u32 *offset_out); +/* + * Marshalling functions to get loff_t file sizes into aand out of + * object headers. + */ +void yaffs_oh_size_load(struct yaffs_obj_hdr *oh, loff_t fsize); +loff_t yaffs_oh_to_size(struct yaffs_obj_hdr *oh); +loff_t yaffs_max_file_size(struct yaffs_dev *dev); + +/* + * Debug function to count number of blocks in each state + * NB Needs to be called with correct number of integers + */ + +void yaffs_count_blocks_by_state(struct yaffs_dev *dev, int bs[10]); + +int yaffs_find_chunk_in_file(struct yaffs_obj *in, int inode_chunk, + struct yaffs_ext_tags *tags); + +#endif diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_linux.h b/target/linux/generic/files/fs/yaffs2/yaffs_linux.h new file mode 100644 index 0000000..c20ab14 --- /dev/null +++ b/target/linux/generic/files/fs/yaffs2/yaffs_linux.h @@ -0,0 +1,48 @@ +/* + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + */ + +#ifndef __YAFFS_LINUX_H__ +#define __YAFFS_LINUX_H__ + +#include "yportenv.h" + +struct yaffs_linux_context { + struct list_head context_list; /* List of these we have mounted */ + struct yaffs_dev *dev; + struct super_block *super; + struct task_struct *bg_thread; /* Background thread for this device */ + int bg_running; + struct mutex gross_lock; /* Gross locking mutex*/ + u8 *spare_buffer; /* For mtdif2 use. Don't know the buffer size + * at compile time so we have to allocate it. + */ + struct list_head search_contexts; + struct task_struct *readdir_process; + unsigned mount_id; + int dirty; +}; + +#define yaffs_dev_to_lc(dev) ((struct yaffs_linux_context *)((dev)->os_context)) +#define yaffs_dev_to_mtd(dev) ((struct mtd_info *)((dev)->driver_context)) + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) +#define WRITE_SIZE_STR "writesize" +#define WRITE_SIZE(mtd) ((mtd)->writesize) +#else +#define WRITE_SIZE_STR "oobblock" +#define WRITE_SIZE(mtd) ((mtd)->oobblock) +#endif + +#endif diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_mtdif.c b/target/linux/generic/files/fs/yaffs2/yaffs_mtdif.c new file mode 100644 index 0000000..7c01461 --- /dev/null +++ b/target/linux/generic/files/fs/yaffs2/yaffs_mtdif.c @@ -0,0 +1,310 @@ +/* + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning + * + * 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. + */ + +#include "yportenv.h" + +#include "yaffs_mtdif.h" + +#include "linux/mtd/mtd.h" +#include "linux/types.h" +#include "linux/time.h" +#include "linux/mtd/nand.h" +#include "linux/kernel.h" +#include "linux/version.h" +#include "linux/types.h" +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) +#include "uapi/linux/major.h" +#endif + +#include "yaffs_trace.h" +#include "yaffs_guts.h" +#include "yaffs_linux.h" + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) +#define MTD_OPS_AUTO_OOB MTD_OOB_AUTO +#endif + + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)) +#define mtd_erase(m, ei) (m)->erase(m, ei) +#define mtd_write_oob(m, addr, pops) (m)->write_oob(m, addr, pops) +#define mtd_read_oob(m, addr, pops) (m)->read_oob(m, addr, pops) +#define mtd_block_isbad(m, offs) (m)->block_isbad(m, offs) +#define mtd_block_markbad(m, offs) (m)->block_markbad(m, offs) +#endif + + + +int nandmtd_erase_block(struct yaffs_dev *dev, int block_no) +{ + struct mtd_info *mtd = yaffs_dev_to_mtd(dev); + u32 addr = + ((loff_t) block_no) * dev->param.total_bytes_per_chunk * + dev->param.chunks_per_block; + struct erase_info ei; + int retval = 0; + + ei.mtd = mtd; + ei.addr = addr; + ei.len = dev->param.total_bytes_per_chunk * dev->param.chunks_per_block; + ei.time = 1000; + ei.retries = 2; + ei.callback = NULL; + ei.priv = (u_long) dev; + + retval = mtd_erase(mtd, &ei); + + if (retval == 0) + return YAFFS_OK; + + return YAFFS_FAIL; +} + + +static int yaffs_mtd_write(struct yaffs_dev *dev, int nand_chunk, + const u8 *data, int data_len, + const u8 *oob, int oob_len) +{ + struct mtd_info *mtd = yaffs_dev_to_mtd(dev); + loff_t addr; + struct mtd_oob_ops ops; + int retval; + + yaffs_trace(YAFFS_TRACE_MTD, + "yaffs_mtd_write(%p, %d, %p, %d, %p, %d)\n", + dev, nand_chunk, data, data_len, oob, oob_len); + + if (!data || !data_len) { + data = NULL; + data_len = 0; + } + + if (!oob || !oob_len) { + oob = NULL; + oob_len = 0; + } + + addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk; + memset(&ops, 0, sizeof(ops)); + ops.mode = MTD_OPS_AUTO_OOB; + ops.len = (data) ? data_len : 0; + ops.ooblen = oob_len; + ops.datbuf = (u8 *)data; + ops.oobbuf = (u8 *)oob; + + retval = mtd_write_oob(mtd, addr, &ops); + if (retval) { + yaffs_trace(YAFFS_TRACE_MTD, + "write_oob failed, chunk %d, mtd error %d", + nand_chunk, retval); + } + return retval ? YAFFS_FAIL : YAFFS_OK; +} + +static int yaffs_mtd_read(struct yaffs_dev *dev, int nand_chunk, + u8 *data, int data_len, + u8 *oob, int oob_len, + enum yaffs_ecc_result *ecc_result) +{ + struct mtd_info *mtd = yaffs_dev_to_mtd(dev); + loff_t addr; + struct mtd_oob_ops ops; + int retval; + + addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk; + memset(&ops, 0, sizeof(ops)); + ops.mode = MTD_OPS_AUTO_OOB; + ops.len = (data) ? data_len : 0; + ops.ooblen = oob_len; + ops.datbuf = data; + ops.oobbuf = oob; + +#if (MTD_VERSION_CODE < MTD_VERSION(2, 6, 20)) + /* In MTD 2.6.18 to 2.6.19 nand_base.c:nand_do_read_oob() has a bug; + * help it out with ops.len = ops.ooblen when ops.datbuf == NULL. + */ + ops.len = (ops.datbuf) ? ops.len : ops.ooblen; +#endif + /* Read page and oob using MTD. + * Check status and determine ECC result. + */ + retval = mtd_read_oob(mtd, addr, &ops); + if (retval) + yaffs_trace(YAFFS_TRACE_MTD, + "read_oob failed, chunk %d, mtd error %d", + nand_chunk, retval); + + switch (retval) { + case 0: + /* no error */ + if(ecc_result) + *ecc_result = YAFFS_ECC_RESULT_NO_ERROR; + break; + + case -EUCLEAN: + /* MTD's ECC fixed the data */ + if(ecc_result) + *ecc_result = YAFFS_ECC_RESULT_FIXED; + dev->n_ecc_fixed++; + break; + + case -EBADMSG: + default: + /* MTD's ECC could not fix the data */ + dev->n_ecc_unfixed++; + if(ecc_result) + *ecc_result = YAFFS_ECC_RESULT_UNFIXED; + return YAFFS_FAIL; + } + + return YAFFS_OK; +} + +static int yaffs_mtd_erase(struct yaffs_dev *dev, int block_no) +{ + struct mtd_info *mtd = yaffs_dev_to_mtd(dev); + + loff_t addr; + struct erase_info ei; + int retval = 0; + u32 block_size; + + block_size = dev->param.total_bytes_per_chunk * + dev->param.chunks_per_block; + addr = ((loff_t) block_no) * block_size; + + ei.mtd = mtd; + ei.addr = addr; + ei.len = block_size; + ei.time = 1000; + ei.retries = 2; + ei.callback = NULL; + ei.priv = (u_long) dev; + + retval = mtd_erase(mtd, &ei); + + if (retval == 0) + return YAFFS_OK; + + return YAFFS_FAIL; +} + +static int yaffs_mtd_mark_bad(struct yaffs_dev *dev, int block_no) +{ + struct mtd_info *mtd = yaffs_dev_to_mtd(dev); + int blocksize = dev->param.chunks_per_block * dev->param.total_bytes_per_chunk; + int retval; + + yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad", block_no); + + retval = mtd_block_markbad(mtd, (loff_t) blocksize * block_no); + return (retval) ? YAFFS_FAIL : YAFFS_OK; +} + +static int yaffs_mtd_check_bad(struct yaffs_dev *dev, int block_no) +{ + struct mtd_info *mtd = yaffs_dev_to_mtd(dev); + int blocksize = dev->param.chunks_per_block * dev->param.total_bytes_per_chunk; + int retval; + + yaffs_trace(YAFFS_TRACE_MTD, "checking block %d bad", block_no); + + retval = mtd_block_isbad(mtd, (loff_t) blocksize * block_no); + return (retval) ? YAFFS_FAIL : YAFFS_OK; +} + +static int yaffs_mtd_initialise(struct yaffs_dev *dev) +{ + return YAFFS_OK; +} + +static int yaffs_mtd_deinitialise(struct yaffs_dev *dev) +{ + return YAFFS_OK; +} + + +void yaffs_mtd_drv_install(struct yaffs_dev *dev) +{ + struct yaffs_driver *drv = &dev->drv; + + drv->drv_write_chunk_fn = yaffs_mtd_write; + drv->drv_read_chunk_fn = yaffs_mtd_read; + drv->drv_erase_fn = yaffs_mtd_erase; + drv->drv_mark_bad_fn = yaffs_mtd_mark_bad; + drv->drv_check_bad_fn = yaffs_mtd_check_bad; + drv->drv_initialise_fn = yaffs_mtd_initialise; + drv->drv_deinitialise_fn = yaffs_mtd_deinitialise; +} + + +struct mtd_info * yaffs_get_mtd_device(dev_t sdev) +{ + struct mtd_info *mtd; + + mtd = yaffs_get_mtd_device(sdev); + + /* Check it's an mtd device..... */ + if (MAJOR(sdev) != MTD_BLOCK_MAJOR) + return NULL; /* This isn't an mtd device */ + + /* Check it's NAND */ + if (mtd->type != MTD_NANDFLASH) { + yaffs_trace(YAFFS_TRACE_ALWAYS, + "yaffs: MTD device is not NAND it's type %d", + mtd->type); + return NULL; + } + + yaffs_trace(YAFFS_TRACE_OS, " %s %d", WRITE_SIZE_STR, WRITE_SIZE(mtd)); + yaffs_trace(YAFFS_TRACE_OS, " oobsize %d", mtd->oobsize); + yaffs_trace(YAFFS_TRACE_OS, " erasesize %d", mtd->erasesize); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) + yaffs_trace(YAFFS_TRACE_OS, " size %u", mtd->size); +#else + yaffs_trace(YAFFS_TRACE_OS, " size %lld", mtd->size); +#endif + + return mtd; +} + +int yaffs_verify_mtd(struct mtd_info *mtd, int yaffs_version, int inband_tags) +{ + if (yaffs_version == 2) { + if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE || + mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) && + !inband_tags) { + yaffs_trace(YAFFS_TRACE_ALWAYS, + "MTD device does not have the right page sizes" + ); + return -1; + } + } else { + if (WRITE_SIZE(mtd) < YAFFS_BYTES_PER_CHUNK || + mtd->oobsize != YAFFS_BYTES_PER_SPARE) { + yaffs_trace(YAFFS_TRACE_ALWAYS, + "MTD device does not support have the right page sizes" + ); + return -1; + } + } + + return 0; +} + + +void yaffs_put_mtd_device(struct mtd_info *mtd) +{ + if(mtd) + put_mtd_device(mtd); +} diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_mtdif.h b/target/linux/generic/files/fs/yaffs2/yaffs_mtdif.h new file mode 100644 index 0000000..9cff224 --- /dev/null +++ b/target/linux/generic/files/fs/yaffs2/yaffs_mtdif.h @@ -0,0 +1,25 @@ +/* + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + */ + +#ifndef __YAFFS_MTDIF_H__ +#define __YAFFS_MTDIF_H__ + +#include "yaffs_guts.h" + +void yaffs_mtd_drv_install(struct yaffs_dev *dev); +struct mtd_info * yaffs_get_mtd_device(dev_t sdev); +void yaffs_put_mtd_device(struct mtd_info *mtd); +int yaffs_verify_mtd(struct mtd_info *mtd, int yaffs_version, int inband_tags); +#endif diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_nameval.c b/target/linux/generic/files/fs/yaffs2/yaffs_nameval.c new file mode 100644 index 0000000..4bdf4ed --- /dev/null +++ b/target/linux/generic/files/fs/yaffs2/yaffs_nameval.c @@ -0,0 +1,208 @@ +/* + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning + * + * 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 simple implementation of a name-value store assumes a small number of +* values and fits into a small finite buffer. + * + * Each attribute is stored as a record: + * sizeof(int) bytes record size. + * strnlen+1 bytes name null terminated. + * nbytes value. + * ---------- + * total size stored in record size + * + * This code has not been tested with unicode yet. + */ + +#include "yaffs_nameval.h" + +#include "yportenv.h" + +static int nval_find(const char *xb, int xb_size, const YCHAR *name, + int *exist_size) +{ + int pos = 0; + int size; + + memcpy(&size, xb, sizeof(int)); + while (size > 0 && (size < xb_size) && (pos + size < xb_size)) { + if (!strncmp((YCHAR *) (xb + pos + sizeof(int)), + name, size)) { + if (exist_size) + *exist_size = size; + return pos; + } + pos += size; + if (pos < xb_size - sizeof(int)) + memcpy(&size, xb + pos, sizeof(int)); + else + size = 0; + } + if (exist_size) + *exist_size = 0; + return -ENODATA; +} + +static int nval_used(const char *xb, int xb_size) +{ + int pos = 0; + int size; + + memcpy(&size, xb + pos, sizeof(int)); + while (size > 0 && (size < xb_size) && (pos + size < xb_size)) { + pos += size; + if (pos < xb_size - sizeof(int)) + memcpy(&size, xb + pos, sizeof(int)); + else + size = 0; + } + return pos; +} + +int nval_del(char *xb, int xb_size, const YCHAR *name) +{ + int pos = nval_find(xb, xb_size, name, NULL); + int size; + + if (pos < 0 || pos >= xb_size) + return -ENODATA; + + /* Find size, shift rest over this record, + * then zero out the rest of buffer */ + memcpy(&size, xb + pos, sizeof(int)); + memcpy(xb + pos, xb + pos + size, xb_size - (pos + size)); + memset(xb + (xb_size - size), 0, size); + return 0; +} + +int nval_set(char *xb, int xb_size, const YCHAR *name, const char *buf, + int bsize, int flags) +{ + int pos; + int namelen = strnlen(name, xb_size); + int reclen; + int size_exist = 0; + int space; + int start; + + pos = nval_find(xb, xb_size, name, &size_exist); + + if (flags & XATTR_CREATE && pos >= 0) + return -EEXIST; + if (flags & XATTR_REPLACE && pos < 0) + return -ENODATA; + + start = nval_used(xb, xb_size); + space = xb_size - start + size_exist; + + reclen = (sizeof(int) + namelen + 1 + bsize); + + if (reclen > space) + return -ENOSPC; + + if (pos >= 0) { + nval_del(xb, xb_size, name); + start = nval_used(xb, xb_size); + } + + pos = start; + + memcpy(xb + pos, &reclen, sizeof(int)); + pos += sizeof(int); + strncpy((YCHAR *) (xb + pos), name, reclen); + pos += (namelen + 1); + memcpy(xb + pos, buf, bsize); + return 0; +} + +int nval_get(const char *xb, int xb_size, const YCHAR * name, char *buf, + int bsize) +{ + int pos = nval_find(xb, xb_size, name, NULL); + int size; + + if (pos >= 0 && pos < xb_size) { + + memcpy(&size, xb + pos, sizeof(int)); + pos += sizeof(int); /* advance past record length */ + size -= sizeof(int); + + /* Advance over name string */ + while (xb[pos] && size > 0 && pos < xb_size) { + pos++; + size--; + } + /*Advance over NUL */ + pos++; + size--; + + /* If bsize is zero then this is a size query. + * Return the size, but don't copy. + */ + if (!bsize) + return size; + + if (size <= bsize) { + memcpy(buf, xb + pos, size); + return size; + } + } + if (pos >= 0) + return -ERANGE; + + return -ENODATA; +} + +int nval_list(const char *xb, int xb_size, char *buf, int bsize) +{ + int pos = 0; + int size; + int name_len; + int ncopied = 0; + int filled = 0; + + memcpy(&size, xb + pos, sizeof(int)); + while (size > sizeof(int) && + size <= xb_size && + (pos + size) < xb_size && + !filled) { + pos += sizeof(int); + size -= sizeof(int); + name_len = strnlen((YCHAR *) (xb + pos), size); + if (ncopied + name_len + 1 < bsize) { + memcpy(buf, xb + pos, name_len * sizeof(YCHAR)); + buf += name_len; + *buf = '\0'; + buf++; + if (sizeof(YCHAR) > 1) { + *buf = '\0'; + buf++; + } + ncopied += (name_len + 1); + } else { + filled = 1; + } + pos += size; + if (pos < xb_size - sizeof(int)) + memcpy(&size, xb + pos, sizeof(int)); + else + size = 0; + } + return ncopied; +} + +int nval_hasvalues(const char *xb, int xb_size) +{ + return nval_used(xb, xb_size) > 0; +} diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_nameval.h b/target/linux/generic/files/fs/yaffs2/yaffs_nameval.h new file mode 100644 index 0000000..951e64f --- /dev/null +++ b/target/linux/generic/files/fs/yaffs2/yaffs_nameval.h @@ -0,0 +1,28 @@ +/* + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + */ + +#ifndef __NAMEVAL_H__ +#define __NAMEVAL_H__ + +#include "yportenv.h" + +int nval_del(char *xb, int xb_size, const YCHAR * name); +int nval_set(char *xb, int xb_size, const YCHAR * name, const char *buf, + int bsize, int flags); +int nval_get(const char *xb, int xb_size, const YCHAR * name, char *buf, + int bsize); +int nval_list(const char *xb, int xb_size, char *buf, int bsize); +int nval_hasvalues(const char *xb, int xb_size); +#endif diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_nand.c b/target/linux/generic/files/fs/yaffs2/yaffs_nand.c new file mode 100644 index 0000000..0d8499b --- /dev/null +++ b/target/linux/generic/files/fs/yaffs2/yaffs_nand.c @@ -0,0 +1,122 @@ +/* + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning + * + * 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. + */ + +#include "yaffs_nand.h" +#include "yaffs_tagscompat.h" + +#include "yaffs_getblockinfo.h" +#include "yaffs_summary.h" + +static int apply_chunk_offset(struct yaffs_dev *dev, int chunk) +{ + return chunk - dev->chunk_offset; +} + +int yaffs_rd_chunk_tags_nand(struct yaffs_dev *dev, int nand_chunk, + u8 *buffer, struct yaffs_ext_tags *tags) +{ + int result; + struct yaffs_ext_tags local_tags; + int flash_chunk = apply_chunk_offset(dev, nand_chunk); + + dev->n_page_reads++; + + /* If there are no tags provided use local tags. */ + if (!tags) + tags = &local_tags; + + result = dev->tagger.read_chunk_tags_fn(dev, flash_chunk, buffer, tags); + if (tags && tags->ecc_result > YAFFS_ECC_RESULT_NO_ERROR) { + + struct yaffs_block_info *bi; + bi = yaffs_get_block_info(dev, + nand_chunk / + dev->param.chunks_per_block); + yaffs_handle_chunk_error(dev, bi); + } + return result; +} + +int yaffs_wr_chunk_tags_nand(struct yaffs_dev *dev, + int nand_chunk, + const u8 *buffer, struct yaffs_ext_tags *tags) +{ + int result; + int flash_chunk = apply_chunk_offset(dev, nand_chunk); + + dev->n_page_writes++; + + if (!tags) { + yaffs_trace(YAFFS_TRACE_ERROR, "Writing with no tags"); + BUG(); + return YAFFS_FAIL; + } + + tags->seq_number = dev->seq_number; + tags->chunk_used = 1; + yaffs_trace(YAFFS_TRACE_WRITE, + "Writing chunk %d tags %d %d", + nand_chunk, tags->obj_id, tags->chunk_id); + + result = dev->tagger.write_chunk_tags_fn(dev, flash_chunk, + buffer, tags); + + yaffs_summary_add(dev, tags, nand_chunk); + + return result; +} + +int yaffs_mark_bad(struct yaffs_dev *dev, int block_no) +{ + block_no -= dev->block_offset; + dev->n_bad_markings++; + + if (dev->param.disable_bad_block_marking) + return YAFFS_OK; + + return dev->tagger.mark_bad_fn(dev, block_no); +} + + +int yaffs_query_init_block_state(struct yaffs_dev *dev, + int block_no, + enum yaffs_block_state *state, + u32 *seq_number) +{ + block_no -= dev->block_offset; + return dev->tagger.query_block_fn(dev, block_no, state, seq_number); +} + +int yaffs_erase_block(struct yaffs_dev *dev, int block_no) +{ + int result; + + block_no -= dev->block_offset; + dev->n_erasures++; + result = dev->drv.drv_erase_fn(dev, block_no); + return result; +} + +int yaffs_init_nand(struct yaffs_dev *dev) +{ + if (dev->drv.drv_initialise_fn) + return dev->drv.drv_initialise_fn(dev); + return YAFFS_OK; +} + +int yaffs_deinit_nand(struct yaffs_dev *dev) +{ + if (dev->drv.drv_deinitialise_fn) + return dev->drv.drv_deinitialise_fn(dev); + return YAFFS_OK; +} diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_nand.h b/target/linux/generic/files/fs/yaffs2/yaffs_nand.h new file mode 100644 index 0000000..804e97a --- /dev/null +++ b/target/linux/generic/files/fs/yaffs2/yaffs_nand.h @@ -0,0 +1,39 @@ +/* + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + */ + +#ifndef __YAFFS_NAND_H__ +#define __YAFFS_NAND_H__ +#include "yaffs_guts.h" + +int yaffs_rd_chunk_tags_nand(struct yaffs_dev *dev, int nand_chunk, + u8 *buffer, struct yaffs_ext_tags *tags); + +int yaffs_wr_chunk_tags_nand(struct yaffs_dev *dev, + int nand_chunk, + const u8 *buffer, struct yaffs_ext_tags *tags); + +int yaffs_mark_bad(struct yaffs_dev *dev, int block_no); + +int yaffs_query_init_block_state(struct yaffs_dev *dev, + int block_no, + enum yaffs_block_state *state, + unsigned *seq_number); + +int yaffs_erase_block(struct yaffs_dev *dev, int flash_block); + +int yaffs_init_nand(struct yaffs_dev *dev); +int yaffs_deinit_nand(struct yaffs_dev *dev); + +#endif diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_packedtags1.c b/target/linux/generic/files/fs/yaffs2/yaffs_packedtags1.c new file mode 100644 index 0000000..dd9a331 --- /dev/null +++ b/target/linux/generic/files/fs/yaffs2/yaffs_packedtags1.c @@ -0,0 +1,56 @@ +/* + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning + * + * 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. + */ + +#include "yaffs_packedtags1.h" +#include "yportenv.h" + +static const u8 all_ff[20] = { + 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff +}; + +void yaffs_pack_tags1(struct yaffs_packed_tags1 *pt, + const struct yaffs_ext_tags *t) +{ + pt->chunk_id = t->chunk_id; + pt->serial_number = t->serial_number; + pt->n_bytes = t->n_bytes; + pt->obj_id = t->obj_id; + pt->ecc = 0; + pt->deleted = (t->is_deleted) ? 0 : 1; + pt->unused_stuff = 0; + pt->should_be_ff = 0xffffffff; +} + +void yaffs_unpack_tags1(struct yaffs_ext_tags *t, + const struct yaffs_packed_tags1 *pt) +{ + + if (memcmp(all_ff, pt, sizeof(struct yaffs_packed_tags1))) { + t->block_bad = 0; + if (pt->should_be_ff != 0xffffffff) + t->block_bad = 1; + t->chunk_used = 1; + t->obj_id = pt->obj_id; + t->chunk_id = pt->chunk_id; + t->n_bytes = pt->n_bytes; + t->ecc_result = YAFFS_ECC_RESULT_NO_ERROR; + t->is_deleted = (pt->deleted) ? 0 : 1; + t->serial_number = pt->serial_number; + } else { + memset(t, 0, sizeof(struct yaffs_ext_tags)); + } +} diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_packedtags1.h b/target/linux/generic/files/fs/yaffs2/yaffs_packedtags1.h new file mode 100644 index 0000000..3015d58 --- /dev/null +++ b/target/linux/generic/files/fs/yaffs2/yaffs_packedtags1.h @@ -0,0 +1,39 @@ +/* + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + */ + +/* This is used to pack YAFFS1 tags, not YAFFS2 tags. */ + +#ifndef __YAFFS_PACKEDTAGS1_H__ +#define __YAFFS_PACKEDTAGS1_H__ + +#include "yaffs_guts.h" + +struct yaffs_packed_tags1 { + u32 chunk_id:20; + u32 serial_number:2; + u32 n_bytes:10; + u32 obj_id:18; + u32 ecc:12; + u32 deleted:1; + u32 unused_stuff:1; + unsigned should_be_ff; + +}; + +void yaffs_pack_tags1(struct yaffs_packed_tags1 *pt, + const struct yaffs_ext_tags *t); +void yaffs_unpack_tags1(struct yaffs_ext_tags *t, + const struct yaffs_packed_tags1 *pt); +#endif diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_packedtags2.c b/target/linux/generic/files/fs/yaffs2/yaffs_packedtags2.c new file mode 100644 index 0000000..e1d18cc --- /dev/null +++ b/target/linux/generic/files/fs/yaffs2/yaffs_packedtags2.c @@ -0,0 +1,197 @@ +/* + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning + * + * 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. + */ + +#include "yaffs_packedtags2.h" +#include "yportenv.h" +#include "yaffs_trace.h" + +/* This code packs a set of extended tags into a binary structure for + * NAND storage + */ + +/* Some of the information is "extra" struff which can be packed in to + * speed scanning + * This is defined by having the EXTRA_HEADER_INFO_FLAG set. + */ + +/* Extra flags applied to chunk_id */ + +#define EXTRA_HEADER_INFO_FLAG 0x80000000 +#define EXTRA_SHRINK_FLAG 0x40000000 +#define EXTRA_SHADOWS_FLAG 0x20000000 +#define EXTRA_SPARE_FLAGS 0x10000000 + +#define ALL_EXTRA_FLAGS 0xf0000000 + +/* Also, the top 4 bits of the object Id are set to the object type. */ +#define EXTRA_OBJECT_TYPE_SHIFT (28) +#define EXTRA_OBJECT_TYPE_MASK ((0x0f) << EXTRA_OBJECT_TYPE_SHIFT) + +static void yaffs_dump_packed_tags2_tags_only( + const struct yaffs_packed_tags2_tags_only *ptt) +{ + yaffs_trace(YAFFS_TRACE_MTD, + "packed tags obj %d chunk %d byte %d seq %d", + ptt->obj_id, ptt->chunk_id, ptt->n_bytes, ptt->seq_number); +} + +static void yaffs_dump_packed_tags2(const struct yaffs_packed_tags2 *pt) +{ + yaffs_dump_packed_tags2_tags_only(&pt->t); +} + +static void yaffs_dump_tags2(const struct yaffs_ext_tags *t) +{ + yaffs_trace(YAFFS_TRACE_MTD, + "ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte %d del %d ser %d seq %d", + t->ecc_result, t->block_bad, t->chunk_used, t->obj_id, + t->chunk_id, t->n_bytes, t->is_deleted, t->serial_number, + t->seq_number); + +} + +static int yaffs_check_tags_extra_packable(const struct yaffs_ext_tags *t) +{ + if (t->chunk_id != 0 || !t->extra_available) + return 0; + + /* Check if the file size is too long to store */ + if (t->extra_obj_type == YAFFS_OBJECT_TYPE_FILE && + (t->extra_file_size >> 31) != 0) + return 0; + return 1; +} + +void yaffs_pack_tags2_tags_only(struct yaffs_packed_tags2_tags_only *ptt, + const struct yaffs_ext_tags *t) +{ + ptt->chunk_id = t->chunk_id; + ptt->seq_number = t->seq_number; + ptt->n_bytes = t->n_bytes; + ptt->obj_id = t->obj_id; + + /* Only store extra tags for object headers. + * If it is a file then only store if the file size is short\ + * enough to fit. + */ + if (yaffs_check_tags_extra_packable(t)) { + /* Store the extra header info instead */ + /* We save the parent object in the chunk_id */ + ptt->chunk_id = EXTRA_HEADER_INFO_FLAG | t->extra_parent_id; + if (t->extra_is_shrink) + ptt->chunk_id |= EXTRA_SHRINK_FLAG; + if (t->extra_shadows) + ptt->chunk_id |= EXTRA_SHADOWS_FLAG; + + ptt->obj_id &= ~EXTRA_OBJECT_TYPE_MASK; + ptt->obj_id |= (t->extra_obj_type << EXTRA_OBJECT_TYPE_SHIFT); + + if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK) + ptt->n_bytes = t->extra_equiv_id; + else if (t->extra_obj_type == YAFFS_OBJECT_TYPE_FILE) + ptt->n_bytes = (unsigned) t->extra_file_size; + else + ptt->n_bytes = 0; + } + + yaffs_dump_packed_tags2_tags_only(ptt); + yaffs_dump_tags2(t); +} + +void yaffs_pack_tags2(struct yaffs_packed_tags2 *pt, + const struct yaffs_ext_tags *t, int tags_ecc) +{ + yaffs_pack_tags2_tags_only(&pt->t, t); + + if (tags_ecc) + yaffs_ecc_calc_other((unsigned char *)&pt->t, + sizeof(struct yaffs_packed_tags2_tags_only), + &pt->ecc); +} + +void yaffs_unpack_tags2_tags_only(struct yaffs_ext_tags *t, + struct yaffs_packed_tags2_tags_only *ptt) +{ + memset(t, 0, sizeof(struct yaffs_ext_tags)); + + if (ptt->seq_number == 0xffffffff) + return; + + t->block_bad = 0; + t->chunk_used = 1; + t->obj_id = ptt->obj_id; + t->chunk_id = ptt->chunk_id; + t->n_bytes = ptt->n_bytes; + t->is_deleted = 0; + t->serial_number = 0; + t->seq_number = ptt->seq_number; + + /* Do extra header info stuff */ + if (ptt->chunk_id & EXTRA_HEADER_INFO_FLAG) { + t->chunk_id = 0; + t->n_bytes = 0; + + t->extra_available = 1; + t->extra_parent_id = ptt->chunk_id & (~(ALL_EXTRA_FLAGS)); + t->extra_is_shrink = ptt->chunk_id & EXTRA_SHRINK_FLAG ? 1 : 0; + t->extra_shadows = ptt->chunk_id & EXTRA_SHADOWS_FLAG ? 1 : 0; + t->extra_obj_type = ptt->obj_id >> EXTRA_OBJECT_TYPE_SHIFT; + t->obj_id &= ~EXTRA_OBJECT_TYPE_MASK; + + if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK) + t->extra_equiv_id = ptt->n_bytes; + else + t->extra_file_size = ptt->n_bytes; + } + yaffs_dump_packed_tags2_tags_only(ptt); + yaffs_dump_tags2(t); +} + +void yaffs_unpack_tags2(struct yaffs_ext_tags *t, struct yaffs_packed_tags2 *pt, + int tags_ecc) +{ + enum yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_NO_ERROR; + + if (pt->t.seq_number != 0xffffffff && tags_ecc) { + /* Chunk is in use and we need to do ECC */ + + struct yaffs_ecc_other ecc; + int result; + yaffs_ecc_calc_other((unsigned char *)&pt->t, + sizeof(struct yaffs_packed_tags2_tags_only), + &ecc); + result = + yaffs_ecc_correct_other((unsigned char *)&pt->t, + sizeof(struct yaffs_packed_tags2_tags_only), + &pt->ecc, &ecc); + switch (result) { + case 0: + ecc_result = YAFFS_ECC_RESULT_NO_ERROR; + break; + case 1: + ecc_result = YAFFS_ECC_RESULT_FIXED; + break; + case -1: + ecc_result = YAFFS_ECC_RESULT_UNFIXED; + break; + default: + ecc_result = YAFFS_ECC_RESULT_UNKNOWN; + } + } + yaffs_unpack_tags2_tags_only(t, &pt->t); + + t->ecc_result = ecc_result; + + yaffs_dump_packed_tags2(pt); + yaffs_dump_tags2(t); +} diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_packedtags2.h b/target/linux/generic/files/fs/yaffs2/yaffs_packedtags2.h new file mode 100644 index 0000000..675e719 --- /dev/null +++ b/target/linux/generic/files/fs/yaffs2/yaffs_packedtags2.h @@ -0,0 +1,47 @@ +/* + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + */ + +/* This is used to pack YAFFS2 tags, not YAFFS1tags. */ + +#ifndef __YAFFS_PACKEDTAGS2_H__ +#define __YAFFS_PACKEDTAGS2_H__ + +#include "yaffs_guts.h" +#include "yaffs_ecc.h" + +struct yaffs_packed_tags2_tags_only { + unsigned seq_number; + unsigned obj_id; + unsigned chunk_id; + unsigned n_bytes; +}; + +struct yaffs_packed_tags2 { + struct yaffs_packed_tags2_tags_only t; + struct yaffs_ecc_other ecc; +}; + +/* Full packed tags with ECC, used for oob tags */ +void yaffs_pack_tags2(struct yaffs_packed_tags2 *pt, + const struct yaffs_ext_tags *t, int tags_ecc); +void yaffs_unpack_tags2(struct yaffs_ext_tags *t, struct yaffs_packed_tags2 *pt, + int tags_ecc); + +/* Only the tags part (no ECC for use with inband tags */ +void yaffs_pack_tags2_tags_only(struct yaffs_packed_tags2_tags_only *pt, + const struct yaffs_ext_tags *t); +void yaffs_unpack_tags2_tags_only(struct yaffs_ext_tags *t, + struct yaffs_packed_tags2_tags_only *pt); +#endif diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_summary.c b/target/linux/generic/files/fs/yaffs2/yaffs_summary.c new file mode 100644 index 0000000..3c9e723 --- /dev/null +++ b/target/linux/generic/files/fs/yaffs2/yaffs_summary.c @@ -0,0 +1,312 @@ +/* + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning + * + * 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. + */ + +/* Summaries write the useful part of the tags for the chunks in a block into an + * an array which is written to the last n chunks of the block. + * Reading the summaries gives all the tags for the block in one read. Much + * faster. + * + * Chunks holding summaries are marked with tags making it look like + * they are part of a fake file. + * + * The summary could also be used during gc. + * + */ + +#include "yaffs_summary.h" +#include "yaffs_packedtags2.h" +#include "yaffs_nand.h" +#include "yaffs_getblockinfo.h" +#include "yaffs_bitmap.h" + +/* + * The summary is built up in an array of summary tags. + * This gets written to the last one or two (maybe more) chunks in a block. + * A summary header is written as the first part of each chunk of summary data. + * The summary header must match or the summary is rejected. + */ + +/* Summary tags don't need the sequence number because that is redundant. */ +struct yaffs_summary_tags { + unsigned obj_id; + unsigned chunk_id; + unsigned n_bytes; +}; + +/* Summary header */ +struct yaffs_summary_header { + unsigned version; /* Must match current version */ + unsigned block; /* Must be this block */ + unsigned seq; /* Must be this sequence number */ + unsigned sum; /* Just add up all the bytes in the tags */ +}; + + +static void yaffs_summary_clear(struct yaffs_dev *dev) +{ + if (!dev->sum_tags) + return; + memset(dev->sum_tags, 0, dev->chunks_per_summary * + sizeof(struct yaffs_summary_tags)); +} + + +void yaffs_summary_deinit(struct yaffs_dev *dev) +{ + kfree(dev->sum_tags); + dev->sum_tags = NULL; + kfree(dev->gc_sum_tags); + dev->gc_sum_tags = NULL; + dev->chunks_per_summary = 0; +} + +int yaffs_summary_init(struct yaffs_dev *dev) +{ + int sum_bytes; + int chunks_used; /* Number of chunks used by summary */ + int sum_tags_bytes; + + sum_bytes = dev->param.chunks_per_block * + sizeof(struct yaffs_summary_tags); + + chunks_used = (sum_bytes + dev->data_bytes_per_chunk - 1)/ + (dev->data_bytes_per_chunk - + sizeof(struct yaffs_summary_header)); + + dev->chunks_per_summary = dev->param.chunks_per_block - chunks_used; + sum_tags_bytes = sizeof(struct yaffs_summary_tags) * + dev->chunks_per_summary; + dev->sum_tags = kmalloc(sum_tags_bytes, GFP_NOFS); + dev->gc_sum_tags = kmalloc(sum_tags_bytes, GFP_NOFS); + if (!dev->sum_tags || !dev->gc_sum_tags) { + yaffs_summary_deinit(dev); + return YAFFS_FAIL; + } + + yaffs_summary_clear(dev); + + return YAFFS_OK; +} + +static unsigned yaffs_summary_sum(struct yaffs_dev *dev) +{ + u8 *sum_buffer = (u8 *)dev->sum_tags; + int i; + unsigned sum = 0; + + i = sizeof(struct yaffs_summary_tags) * + dev->chunks_per_summary; + while (i > 0) { + sum += *sum_buffer; + sum_buffer++; + i--; + } + + return sum; +} + +static int yaffs_summary_write(struct yaffs_dev *dev, int blk) +{ + struct yaffs_ext_tags tags; + u8 *buffer; + u8 *sum_buffer = (u8 *)dev->sum_tags; + int n_bytes; + int chunk_in_nand; + int chunk_in_block; + int result; + int this_tx; + struct yaffs_summary_header hdr; + int sum_bytes_per_chunk = dev->data_bytes_per_chunk - sizeof(hdr); + struct yaffs_block_info *bi = yaffs_get_block_info(dev, blk); + + buffer = yaffs_get_temp_buffer(dev); + n_bytes = sizeof(struct yaffs_summary_tags) * + dev->chunks_per_summary; + memset(&tags, 0, sizeof(struct yaffs_ext_tags)); + tags.obj_id = YAFFS_OBJECTID_SUMMARY; + tags.chunk_id = 1; + chunk_in_block = dev->chunks_per_summary; + chunk_in_nand = dev->alloc_block * dev->param.chunks_per_block + + dev->chunks_per_summary; + hdr.version = YAFFS_SUMMARY_VERSION; + hdr.block = blk; + hdr.seq = bi->seq_number; + hdr.sum = yaffs_summary_sum(dev); + + do { + this_tx = n_bytes; + if (this_tx > sum_bytes_per_chunk) + this_tx = sum_bytes_per_chunk; + memcpy(buffer, &hdr, sizeof(hdr)); + memcpy(buffer + sizeof(hdr), sum_buffer, this_tx); + tags.n_bytes = this_tx + sizeof(hdr); + result = yaffs_wr_chunk_tags_nand(dev, chunk_in_nand, + buffer, &tags); + + if (result != YAFFS_OK) + break; + yaffs_set_chunk_bit(dev, blk, chunk_in_block); + bi->pages_in_use++; + dev->n_free_chunks--; + + n_bytes -= this_tx; + sum_buffer += this_tx; + chunk_in_nand++; + chunk_in_block++; + tags.chunk_id++; + } while (result == YAFFS_OK && n_bytes > 0); + yaffs_release_temp_buffer(dev, buffer); + + + if (result == YAFFS_OK) + bi->has_summary = 1; + + + return result; +} + +int yaffs_summary_read(struct yaffs_dev *dev, + struct yaffs_summary_tags *st, + int blk) +{ + struct yaffs_ext_tags tags; + u8 *buffer; + u8 *sum_buffer = (u8 *)st; + int n_bytes; + int chunk_id; + int chunk_in_nand; + int chunk_in_block; + int result; + int this_tx; + struct yaffs_summary_header hdr; + struct yaffs_block_info *bi = yaffs_get_block_info(dev, blk); + int sum_bytes_per_chunk = dev->data_bytes_per_chunk - sizeof(hdr); + int sum_tags_bytes; + + sum_tags_bytes = sizeof(struct yaffs_summary_tags) * + dev->chunks_per_summary; + buffer = yaffs_get_temp_buffer(dev); + n_bytes = sizeof(struct yaffs_summary_tags) * dev->chunks_per_summary; + chunk_in_block = dev->chunks_per_summary; + chunk_in_nand = blk * dev->param.chunks_per_block + + dev->chunks_per_summary; + chunk_id = 1; + do { + this_tx = n_bytes; + if (this_tx > sum_bytes_per_chunk) + this_tx = sum_bytes_per_chunk; + result = yaffs_rd_chunk_tags_nand(dev, chunk_in_nand, + buffer, &tags); + + if (tags.chunk_id != chunk_id || + tags.obj_id != YAFFS_OBJECTID_SUMMARY || + tags.chunk_used == 0 || + tags.ecc_result > YAFFS_ECC_RESULT_FIXED || + tags.n_bytes != (this_tx + sizeof(hdr))) + result = YAFFS_FAIL; + if (result != YAFFS_OK) + break; + + if (st == dev->sum_tags) { + /* If we're scanning then update the block info */ + yaffs_set_chunk_bit(dev, blk, chunk_in_block); + bi->pages_in_use++; + } + memcpy(&hdr, buffer, sizeof(hdr)); + memcpy(sum_buffer, buffer + sizeof(hdr), this_tx); + n_bytes -= this_tx; + sum_buffer += this_tx; + chunk_in_nand++; + chunk_in_block++; + chunk_id++; + } while (result == YAFFS_OK && n_bytes > 0); + yaffs_release_temp_buffer(dev, buffer); + + if (result == YAFFS_OK) { + /* Verify header */ + if (hdr.version != YAFFS_SUMMARY_VERSION || + hdr.seq != bi->seq_number || + hdr.sum != yaffs_summary_sum(dev)) + result = YAFFS_FAIL; + } + + if (st == dev->sum_tags && result == YAFFS_OK) + bi->has_summary = 1; + + return result; +} + +int yaffs_summary_add(struct yaffs_dev *dev, + struct yaffs_ext_tags *tags, + int chunk_in_nand) +{ + struct yaffs_packed_tags2_tags_only tags_only; + struct yaffs_summary_tags *sum_tags; + int block_in_nand = chunk_in_nand / dev->param.chunks_per_block; + int chunk_in_block = chunk_in_nand % dev->param.chunks_per_block; + + if (!dev->sum_tags) + return YAFFS_OK; + + if (chunk_in_block >= 0 && chunk_in_block < dev->chunks_per_summary) { + yaffs_pack_tags2_tags_only(&tags_only, tags); + sum_tags = &dev->sum_tags[chunk_in_block]; + sum_tags->chunk_id = tags_only.chunk_id; + sum_tags->n_bytes = tags_only.n_bytes; + sum_tags->obj_id = tags_only.obj_id; + + if (chunk_in_block == dev->chunks_per_summary - 1) { + /* Time to write out the summary */ + yaffs_summary_write(dev, block_in_nand); + yaffs_summary_clear(dev); + yaffs_skip_rest_of_block(dev); + } + } + return YAFFS_OK; +} + +int yaffs_summary_fetch(struct yaffs_dev *dev, + struct yaffs_ext_tags *tags, + int chunk_in_block) +{ + struct yaffs_packed_tags2_tags_only tags_only; + struct yaffs_summary_tags *sum_tags; + if (chunk_in_block >= 0 && chunk_in_block < dev->chunks_per_summary) { + sum_tags = &dev->sum_tags[chunk_in_block]; + tags_only.chunk_id = sum_tags->chunk_id; + tags_only.n_bytes = sum_tags->n_bytes; + tags_only.obj_id = sum_tags->obj_id; + yaffs_unpack_tags2_tags_only(tags, &tags_only); + return YAFFS_OK; + } + return YAFFS_FAIL; +} + +void yaffs_summary_gc(struct yaffs_dev *dev, int blk) +{ + struct yaffs_block_info *bi = yaffs_get_block_info(dev, blk); + int i; + + if (!bi->has_summary) + return; + + for (i = dev->chunks_per_summary; + i < dev->param.chunks_per_block; + i++) { + if (yaffs_check_chunk_bit(dev, blk, i)) { + yaffs_clear_chunk_bit(dev, blk, i); + bi->pages_in_use--; + dev->n_free_chunks++; + } + } +} diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_summary.h b/target/linux/generic/files/fs/yaffs2/yaffs_summary.h new file mode 100644 index 0000000..be141d0 --- /dev/null +++ b/target/linux/generic/files/fs/yaffs2/yaffs_summary.h @@ -0,0 +1,37 @@ +/* + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + */ + +#ifndef __YAFFS_SUMMARY_H__ +#define __YAFFS_SUMMARY_H__ + +#include "yaffs_packedtags2.h" + + +int yaffs_summary_init(struct yaffs_dev *dev); +void yaffs_summary_deinit(struct yaffs_dev *dev); + +int yaffs_summary_add(struct yaffs_dev *dev, + struct yaffs_ext_tags *tags, + int chunk_in_block); +int yaffs_summary_fetch(struct yaffs_dev *dev, + struct yaffs_ext_tags *tags, + int chunk_in_block); +int yaffs_summary_read(struct yaffs_dev *dev, + struct yaffs_summary_tags *st, + int blk); +void yaffs_summary_gc(struct yaffs_dev *dev, int blk); + + +#endif diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_tagscompat.c b/target/linux/generic/files/fs/yaffs2/yaffs_tagscompat.c new file mode 100644 index 0000000..092430b --- /dev/null +++ b/target/linux/generic/files/fs/yaffs2/yaffs_tagscompat.c @@ -0,0 +1,381 @@ +/* + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning + * + * 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. + */ + +#include "yaffs_guts.h" +#include "yaffs_tagscompat.h" +#include "yaffs_ecc.h" +#include "yaffs_getblockinfo.h" +#include "yaffs_trace.h" + +static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk); + + +/********** Tags ECC calculations *********/ + + +void yaffs_calc_tags_ecc(struct yaffs_tags *tags) +{ + /* Calculate an ecc */ + unsigned char *b = ((union yaffs_tags_union *)tags)->as_bytes; + unsigned i, j; + unsigned ecc = 0; + unsigned bit = 0; + + tags->ecc = 0; + + for (i = 0; i < 8; i++) { + for (j = 1; j & 0xff; j <<= 1) { + bit++; + if (b[i] & j) + ecc ^= bit; + } + } + tags->ecc = ecc; +} + +int yaffs_check_tags_ecc(struct yaffs_tags *tags) +{ + unsigned ecc = tags->ecc; + + yaffs_calc_tags_ecc(tags); + + ecc ^= tags->ecc; + + if (ecc && ecc <= 64) { + /* TODO: Handle the failure better. Retire? */ + unsigned char *b = ((union yaffs_tags_union *)tags)->as_bytes; + + ecc--; + + b[ecc / 8] ^= (1 << (ecc & 7)); + + /* Now recvalc the ecc */ + yaffs_calc_tags_ecc(tags); + + return 1; /* recovered error */ + } else if (ecc) { + /* Wierd ecc failure value */ + /* TODO Need to do somethiong here */ + return -1; /* unrecovered error */ + } + return 0; +} + +/********** Tags **********/ + +static void yaffs_load_tags_to_spare(struct yaffs_spare *spare_ptr, + struct yaffs_tags *tags_ptr) +{ + union yaffs_tags_union *tu = (union yaffs_tags_union *)tags_ptr; + + yaffs_calc_tags_ecc(tags_ptr); + + spare_ptr->tb0 = tu->as_bytes[0]; + spare_ptr->tb1 = tu->as_bytes[1]; + spare_ptr->tb2 = tu->as_bytes[2]; + spare_ptr->tb3 = tu->as_bytes[3]; + spare_ptr->tb4 = tu->as_bytes[4]; + spare_ptr->tb5 = tu->as_bytes[5]; + spare_ptr->tb6 = tu->as_bytes[6]; + spare_ptr->tb7 = tu->as_bytes[7]; +} + +static void yaffs_get_tags_from_spare(struct yaffs_dev *dev, + struct yaffs_spare *spare_ptr, + struct yaffs_tags *tags_ptr) +{ + union yaffs_tags_union *tu = (union yaffs_tags_union *)tags_ptr; + int result; + + tu->as_bytes[0] = spare_ptr->tb0; + tu->as_bytes[1] = spare_ptr->tb1; + tu->as_bytes[2] = spare_ptr->tb2; + tu->as_bytes[3] = spare_ptr->tb3; + tu->as_bytes[4] = spare_ptr->tb4; + tu->as_bytes[5] = spare_ptr->tb5; + tu->as_bytes[6] = spare_ptr->tb6; + tu->as_bytes[7] = spare_ptr->tb7; + + result = yaffs_check_tags_ecc(tags_ptr); + if (result > 0) + dev->n_tags_ecc_fixed++; + else if (result < 0) + dev->n_tags_ecc_unfixed++; +} + +static void yaffs_spare_init(struct yaffs_spare *spare) +{ + memset(spare, 0xff, sizeof(struct yaffs_spare)); +} + +static int yaffs_wr_nand(struct yaffs_dev *dev, + int nand_chunk, const u8 *data, + struct yaffs_spare *spare) +{ + int data_size = dev->data_bytes_per_chunk; + + return dev->drv.drv_write_chunk_fn(dev, nand_chunk, + data, data_size, + (u8 *) spare, sizeof(*spare)); +} + +static int yaffs_rd_chunk_nand(struct yaffs_dev *dev, + int nand_chunk, + u8 *data, + struct yaffs_spare *spare, + enum yaffs_ecc_result *ecc_result, + int correct_errors) +{ + int ret_val; + struct yaffs_spare local_spare; + int data_size; + int spare_size; + int ecc_result1, ecc_result2; + u8 calc_ecc[3]; + + if (!spare) { + /* If we don't have a real spare, then we use a local one. */ + /* Need this for the calculation of the ecc */ + spare = &local_spare; + } + data_size = dev->data_bytes_per_chunk; + spare_size = sizeof(struct yaffs_spare); + + if (dev->param.use_nand_ecc) + return dev->drv.drv_read_chunk_fn(dev, nand_chunk, + data, data_size, + (u8 *) spare, spare_size, + ecc_result); + + + /* Handle the ECC at this level. */ + + ret_val = dev->drv.drv_read_chunk_fn(dev, nand_chunk, + data, data_size, + (u8 *)spare, spare_size, + NULL); + if (!data || !correct_errors) + return ret_val; + + /* Do ECC correction if needed. */ + yaffs_ecc_calc(data, calc_ecc); + ecc_result1 = yaffs_ecc_correct(data, spare->ecc1, calc_ecc); + yaffs_ecc_calc(&data[256], calc_ecc); + ecc_result2 = yaffs_ecc_correct(&data[256], spare->ecc2, calc_ecc); + + if (ecc_result1 > 0) { + yaffs_trace(YAFFS_TRACE_ERROR, + "**>>yaffs ecc error fix performed on chunk %d:0", + nand_chunk); + dev->n_ecc_fixed++; + } else if (ecc_result1 < 0) { + yaffs_trace(YAFFS_TRACE_ERROR, + "**>>yaffs ecc error unfixed on chunk %d:0", + nand_chunk); + dev->n_ecc_unfixed++; + } + + if (ecc_result2 > 0) { + yaffs_trace(YAFFS_TRACE_ERROR, + "**>>yaffs ecc error fix performed on chunk %d:1", + nand_chunk); + dev->n_ecc_fixed++; + } else if (ecc_result2 < 0) { + yaffs_trace(YAFFS_TRACE_ERROR, + "**>>yaffs ecc error unfixed on chunk %d:1", + nand_chunk); + dev->n_ecc_unfixed++; + } + + if (ecc_result1 || ecc_result2) { + /* We had a data problem on this page */ + yaffs_handle_rd_data_error(dev, nand_chunk); + } + + if (ecc_result1 < 0 || ecc_result2 < 0) + *ecc_result = YAFFS_ECC_RESULT_UNFIXED; + else if (ecc_result1 > 0 || ecc_result2 > 0) + *ecc_result = YAFFS_ECC_RESULT_FIXED; + else + *ecc_result = YAFFS_ECC_RESULT_NO_ERROR; + + return ret_val; +} + +/* + * Functions for robustisizing + */ + +static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk) +{ + int flash_block = nand_chunk / dev->param.chunks_per_block; + + /* Mark the block for retirement */ + yaffs_get_block_info(dev, flash_block + dev->block_offset)-> + needs_retiring = 1; + yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS, + "**>>Block %d marked for retirement", + flash_block); + + /* TODO: + * Just do a garbage collection on the affected block + * then retire the block + * NB recursion + */ +} + +static int yaffs_tags_compat_wr(struct yaffs_dev *dev, + int nand_chunk, + const u8 *data, const struct yaffs_ext_tags *ext_tags) +{ + struct yaffs_spare spare; + struct yaffs_tags tags; + + yaffs_spare_init(&spare); + + if (ext_tags->is_deleted) + spare.page_status = 0; + else { + tags.obj_id = ext_tags->obj_id; + tags.chunk_id = ext_tags->chunk_id; + + tags.n_bytes_lsb = ext_tags->n_bytes & (1024 - 1); + + if (dev->data_bytes_per_chunk >= 1024) + tags.n_bytes_msb = (ext_tags->n_bytes >> 10) & 3; + else + tags.n_bytes_msb = 3; + + tags.serial_number = ext_tags->serial_number; + + if (!dev->param.use_nand_ecc && data) { + yaffs_ecc_calc(data, spare.ecc1); + yaffs_ecc_calc(&data[256], spare.ecc2); + } + + yaffs_load_tags_to_spare(&spare, &tags); + } + return yaffs_wr_nand(dev, nand_chunk, data, &spare); +} + +static int yaffs_tags_compat_rd(struct yaffs_dev *dev, + int nand_chunk, + u8 *data, struct yaffs_ext_tags *ext_tags) +{ + struct yaffs_spare spare; + struct yaffs_tags tags; + enum yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_UNKNOWN; + static struct yaffs_spare spare_ff; + static int init; + int deleted; + + if (!init) { + memset(&spare_ff, 0xff, sizeof(spare_ff)); + init = 1; + } + + if (!yaffs_rd_chunk_nand(dev, nand_chunk, + data, &spare, &ecc_result, 1)) + return YAFFS_FAIL; + + /* ext_tags may be NULL */ + if (!ext_tags) + return YAFFS_OK; + + deleted = (hweight8(spare.page_status) < 7) ? 1 : 0; + + ext_tags->is_deleted = deleted; + ext_tags->ecc_result = ecc_result; + ext_tags->block_bad = 0; /* We're reading it */ + /* therefore it is not a bad block */ + ext_tags->chunk_used = + memcmp(&spare_ff, &spare, sizeof(spare_ff)) ? 1 : 0; + + if (ext_tags->chunk_used) { + yaffs_get_tags_from_spare(dev, &spare, &tags); + ext_tags->obj_id = tags.obj_id; + ext_tags->chunk_id = tags.chunk_id; + ext_tags->n_bytes = tags.n_bytes_lsb; + + if (dev->data_bytes_per_chunk >= 1024) + ext_tags->n_bytes |= + (((unsigned)tags.n_bytes_msb) << 10); + + ext_tags->serial_number = tags.serial_number; + } + + return YAFFS_OK; +} + +static int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int flash_block) +{ + struct yaffs_spare spare; + + memset(&spare, 0xff, sizeof(struct yaffs_spare)); + + spare.block_status = 'Y'; + + yaffs_wr_nand(dev, flash_block * dev->param.chunks_per_block, NULL, + &spare); + yaffs_wr_nand(dev, flash_block * dev->param.chunks_per_block + 1, + NULL, &spare); + + return YAFFS_OK; +} + +static int yaffs_tags_compat_query_block(struct yaffs_dev *dev, + int block_no, + enum yaffs_block_state *state, + u32 *seq_number) +{ + struct yaffs_spare spare0, spare1; + static struct yaffs_spare spare_ff; + static int init; + enum yaffs_ecc_result dummy; + + if (!init) { + memset(&spare_ff, 0xff, sizeof(spare_ff)); + init = 1; + } + + *seq_number = 0; + + /* Look for bad block markers in the first two chunks */ + yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block, + NULL, &spare0, &dummy, 0); + yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block + 1, + NULL, &spare1, &dummy, 0); + + if (hweight8(spare0.block_status & spare1.block_status) < 7) + *state = YAFFS_BLOCK_STATE_DEAD; + else if (memcmp(&spare_ff, &spare0, sizeof(spare_ff)) == 0) + *state = YAFFS_BLOCK_STATE_EMPTY; + else + *state = YAFFS_BLOCK_STATE_NEEDS_SCAN; + + return YAFFS_OK; +} + +void yaffs_tags_compat_install(struct yaffs_dev *dev) +{ + if(dev->param.is_yaffs2) + return; + if(!dev->tagger.write_chunk_tags_fn) + dev->tagger.write_chunk_tags_fn = yaffs_tags_compat_wr; + if(!dev->tagger.read_chunk_tags_fn) + dev->tagger.read_chunk_tags_fn = yaffs_tags_compat_rd; + if(!dev->tagger.query_block_fn) + dev->tagger.query_block_fn = yaffs_tags_compat_query_block; + if(!dev->tagger.mark_bad_fn) + dev->tagger.mark_bad_fn = yaffs_tags_compat_mark_bad; +} diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_tagscompat.h b/target/linux/generic/files/fs/yaffs2/yaffs_tagscompat.h new file mode 100644 index 0000000..92d298a --- /dev/null +++ b/target/linux/generic/files/fs/yaffs2/yaffs_tagscompat.h @@ -0,0 +1,44 @@ +/* + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + */ + +#ifndef __YAFFS_TAGSCOMPAT_H__ +#define __YAFFS_TAGSCOMPAT_H__ + + +#include "yaffs_guts.h" + +#if 0 + + +int yaffs_tags_compat_wr(struct yaffs_dev *dev, + int nand_chunk, + const u8 *data, const struct yaffs_ext_tags *tags); +int yaffs_tags_compat_rd(struct yaffs_dev *dev, + int nand_chunk, + u8 *data, struct yaffs_ext_tags *tags); +int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int block_no); +int yaffs_tags_compat_query_block(struct yaffs_dev *dev, + int block_no, + enum yaffs_block_state *state, + u32 *seq_number); + +#endif + + +void yaffs_tags_compat_install(struct yaffs_dev *dev); +void yaffs_calc_tags_ecc(struct yaffs_tags *tags); +int yaffs_check_tags_ecc(struct yaffs_tags *tags); + +#endif diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_tagsmarshall.c b/target/linux/generic/files/fs/yaffs2/yaffs_tagsmarshall.c new file mode 100644 index 0000000..44a83b1 --- /dev/null +++ b/target/linux/generic/files/fs/yaffs2/yaffs_tagsmarshall.c @@ -0,0 +1,199 @@ +/* + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning + * + * 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. + */ + +#include "yaffs_guts.h" +#include "yaffs_trace.h" +#include "yaffs_packedtags2.h" + +static int yaffs_tags_marshall_write(struct yaffs_dev *dev, + int nand_chunk, const u8 *data, + const struct yaffs_ext_tags *tags) +{ + struct yaffs_packed_tags2 pt; + int retval; + + int packed_tags_size = + dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt); + void *packed_tags_ptr = + dev->param.no_tags_ecc ? (void *)&pt.t : (void *)&pt; + + yaffs_trace(YAFFS_TRACE_MTD, + "yaffs_tags_marshall_write chunk %d data %p tags %p", + nand_chunk, data, tags); + + /* For yaffs2 writing there must be both data and tags. + * If we're using inband tags, then the tags are stuffed into + * the end of the data buffer. + */ + if (!data || !tags) + BUG(); + else if (dev->param.inband_tags) { + struct yaffs_packed_tags2_tags_only *pt2tp; + pt2tp = + (struct yaffs_packed_tags2_tags_only *)(data + + dev-> + data_bytes_per_chunk); + yaffs_pack_tags2_tags_only(pt2tp, tags); + } else { + yaffs_pack_tags2(&pt, tags, !dev->param.no_tags_ecc); + } + + retval = dev->drv.drv_write_chunk_fn(dev, nand_chunk, + data, dev->param.total_bytes_per_chunk, + (dev->param.inband_tags) ? NULL : packed_tags_ptr, + (dev->param.inband_tags) ? 0 : packed_tags_size); + + return retval; +} + +static int yaffs_tags_marshall_read(struct yaffs_dev *dev, + int nand_chunk, u8 *data, + struct yaffs_ext_tags *tags) +{ + int retval = 0; + int local_data = 0; + u8 spare_buffer[100]; + enum yaffs_ecc_result ecc_result; + + struct yaffs_packed_tags2 pt; + + int packed_tags_size = + dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt); + void *packed_tags_ptr = + dev->param.no_tags_ecc ? (void *)&pt.t : (void *)&pt; + + yaffs_trace(YAFFS_TRACE_MTD, + "yaffs_tags_marshall_read chunk %d data %p tags %p", + nand_chunk, data, tags); + + if (dev->param.inband_tags) { + if (!data) { + local_data = 1; + data = yaffs_get_temp_buffer(dev); + } + } + + if (dev->param.inband_tags || (data && !tags)) + retval = dev->drv.drv_read_chunk_fn(dev, nand_chunk, + data, dev->param.total_bytes_per_chunk, + NULL, 0, + &ecc_result); + else if (tags) + retval = dev->drv.drv_read_chunk_fn(dev, nand_chunk, + data, dev->param.total_bytes_per_chunk, + spare_buffer, packed_tags_size, + &ecc_result); + else + BUG(); + + + if (dev->param.inband_tags) { + if (tags) { + struct yaffs_packed_tags2_tags_only *pt2tp; + pt2tp = + (struct yaffs_packed_tags2_tags_only *) + &data[dev->data_bytes_per_chunk]; + yaffs_unpack_tags2_tags_only(tags, pt2tp); + } + } else if (tags) { + memcpy(packed_tags_ptr, spare_buffer, packed_tags_size); + yaffs_unpack_tags2(tags, &pt, !dev->param.no_tags_ecc); + } + + if (local_data) + yaffs_release_temp_buffer(dev, data); + + if (tags && ecc_result == YAFFS_ECC_RESULT_UNFIXED) { + tags->ecc_result = YAFFS_ECC_RESULT_UNFIXED; + dev->n_ecc_unfixed++; + } + + if (tags && ecc_result == -YAFFS_ECC_RESULT_FIXED) { + if (tags->ecc_result <= YAFFS_ECC_RESULT_NO_ERROR) + tags->ecc_result = YAFFS_ECC_RESULT_FIXED; + dev->n_ecc_fixed++; + } + + if (ecc_result < YAFFS_ECC_RESULT_UNFIXED) + return YAFFS_OK; + else + return YAFFS_FAIL; +} + +static int yaffs_tags_marshall_query_block(struct yaffs_dev *dev, int block_no, + enum yaffs_block_state *state, + u32 *seq_number) +{ + int retval; + + yaffs_trace(YAFFS_TRACE_MTD, "yaffs_tags_marshall_query_block %d", + block_no); + + retval = dev->drv.drv_check_bad_fn(dev, block_no); + + if (retval== YAFFS_FAIL) { + yaffs_trace(YAFFS_TRACE_MTD, "block is bad"); + + *state = YAFFS_BLOCK_STATE_DEAD; + *seq_number = 0; + } else { + struct yaffs_ext_tags t; + + yaffs_tags_marshall_read(dev, + block_no * dev->param.chunks_per_block, + NULL, &t); + + if (t.chunk_used) { + *seq_number = t.seq_number; + *state = YAFFS_BLOCK_STATE_NEEDS_SCAN; + } else { + *seq_number = 0; + *state = YAFFS_BLOCK_STATE_EMPTY; + } + } + + yaffs_trace(YAFFS_TRACE_MTD, + "block query returns seq %d state %d", + *seq_number, *state); + + if (retval == 0) + return YAFFS_OK; + else + return YAFFS_FAIL; +} + +static int yaffs_tags_marshall_mark_bad(struct yaffs_dev *dev, int block_no) +{ + return dev->drv.drv_mark_bad_fn(dev, block_no); + +} + + +void yaffs_tags_marshall_install(struct yaffs_dev *dev) +{ + if (!dev->param.is_yaffs2) + return; + + if (!dev->tagger.write_chunk_tags_fn) + dev->tagger.write_chunk_tags_fn = yaffs_tags_marshall_write; + + if (!dev->tagger.read_chunk_tags_fn) + dev->tagger.read_chunk_tags_fn = yaffs_tags_marshall_read; + + if (!dev->tagger.query_block_fn) + dev->tagger.query_block_fn = yaffs_tags_marshall_query_block; + + if (!dev->tagger.mark_bad_fn) + dev->tagger.mark_bad_fn = yaffs_tags_marshall_mark_bad; + +} diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_tagsmarshall.h b/target/linux/generic/files/fs/yaffs2/yaffs_tagsmarshall.h new file mode 100644 index 0000000..bf3e68a --- /dev/null +++ b/target/linux/generic/files/fs/yaffs2/yaffs_tagsmarshall.h @@ -0,0 +1,22 @@ +/* + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + */ + +#ifndef __YAFFS_TAGSMARSHALL_H__ +#define __YAFFS_TAGSMARSHALL_H__ + +#include "yaffs_guts.h" +void yaffs_tags_marshall_install(struct yaffs_dev *dev); + +#endif diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_trace.h b/target/linux/generic/files/fs/yaffs2/yaffs_trace.h new file mode 100644 index 0000000..fd26054 --- /dev/null +++ b/target/linux/generic/files/fs/yaffs2/yaffs_trace.h @@ -0,0 +1,57 @@ +/* + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + */ + +#ifndef __YTRACE_H__ +#define __YTRACE_H__ + +extern unsigned int yaffs_trace_mask; +extern unsigned int yaffs_wr_attempts; + +/* + * Tracing flags. + * The flags masked in YAFFS_TRACE_ALWAYS are always traced. + */ + +#define YAFFS_TRACE_OS 0x00000002 +#define YAFFS_TRACE_ALLOCATE 0x00000004 +#define YAFFS_TRACE_SCAN 0x00000008 +#define YAFFS_TRACE_BAD_BLOCKS 0x00000010 +#define YAFFS_TRACE_ERASE 0x00000020 +#define YAFFS_TRACE_GC 0x00000040 +#define YAFFS_TRACE_WRITE 0x00000080 +#define YAFFS_TRACE_TRACING 0x00000100 +#define YAFFS_TRACE_DELETION 0x00000200 +#define YAFFS_TRACE_BUFFERS 0x00000400 +#define YAFFS_TRACE_NANDACCESS 0x00000800 +#define YAFFS_TRACE_GC_DETAIL 0x00001000 +#define YAFFS_TRACE_SCAN_DEBUG 0x00002000 +#define YAFFS_TRACE_MTD 0x00004000 +#define YAFFS_TRACE_CHECKPOINT 0x00008000 + +#define YAFFS_TRACE_VERIFY 0x00010000 +#define YAFFS_TRACE_VERIFY_NAND 0x00020000 +#define YAFFS_TRACE_VERIFY_FULL 0x00040000 +#define YAFFS_TRACE_VERIFY_ALL 0x000f0000 + +#define YAFFS_TRACE_SYNC 0x00100000 +#define YAFFS_TRACE_BACKGROUND 0x00200000 +#define YAFFS_TRACE_LOCK 0x00400000 +#define YAFFS_TRACE_MOUNT 0x00800000 + +#define YAFFS_TRACE_ERROR 0x40000000 +#define YAFFS_TRACE_BUG 0x80000000 +#define YAFFS_TRACE_ALWAYS 0xf0000000 + +#endif diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_verify.c b/target/linux/generic/files/fs/yaffs2/yaffs_verify.c new file mode 100644 index 0000000..e8f2f0a --- /dev/null +++ b/target/linux/generic/files/fs/yaffs2/yaffs_verify.c @@ -0,0 +1,529 @@ +/* + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning + * + * 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. + */ + +#include "yaffs_verify.h" +#include "yaffs_trace.h" +#include "yaffs_bitmap.h" +#include "yaffs_getblockinfo.h" +#include "yaffs_nand.h" + +int yaffs_skip_verification(struct yaffs_dev *dev) +{ + (void) dev; + return !(yaffs_trace_mask & + (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL)); +} + +static int yaffs_skip_full_verification(struct yaffs_dev *dev) +{ + (void) dev; + return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY_FULL)); +} + +static int yaffs_skip_nand_verification(struct yaffs_dev *dev) +{ + (void) dev; + return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY_NAND)); +} + +static const char * const block_state_name[] = { + "Unknown", + "Needs scan", + "Scanning", + "Empty", + "Allocating", + "Full", + "Dirty", + "Checkpoint", + "Collecting", + "Dead" +}; + +void yaffs_verify_blk(struct yaffs_dev *dev, struct yaffs_block_info *bi, int n) +{ + int actually_used; + int in_use; + + if (yaffs_skip_verification(dev)) + return; + + /* Report illegal runtime states */ + if (bi->block_state >= YAFFS_NUMBER_OF_BLOCK_STATES) + yaffs_trace(YAFFS_TRACE_VERIFY, + "Block %d has undefined state %d", + n, bi->block_state); + + switch (bi->block_state) { + case YAFFS_BLOCK_STATE_UNKNOWN: + case YAFFS_BLOCK_STATE_SCANNING: + case YAFFS_BLOCK_STATE_NEEDS_SCAN: + yaffs_trace(YAFFS_TRACE_VERIFY, + "Block %d has bad run-state %s", + n, block_state_name[bi->block_state]); + } + + /* Check pages in use and soft deletions are legal */ + + actually_used = bi->pages_in_use - bi->soft_del_pages; + + if (bi->pages_in_use < 0 || + bi->pages_in_use > dev->param.chunks_per_block || + bi->soft_del_pages < 0 || + bi->soft_del_pages > dev->param.chunks_per_block || + actually_used < 0 || actually_used > dev->param.chunks_per_block) + yaffs_trace(YAFFS_TRACE_VERIFY, + "Block %d has illegal values pages_in_used %d soft_del_pages %d", + n, bi->pages_in_use, bi->soft_del_pages); + + /* Check chunk bitmap legal */ + in_use = yaffs_count_chunk_bits(dev, n); + if (in_use != bi->pages_in_use) + yaffs_trace(YAFFS_TRACE_VERIFY, + "Block %d has inconsistent values pages_in_use %d counted chunk bits %d", + n, bi->pages_in_use, in_use); +} + +void yaffs_verify_collected_blk(struct yaffs_dev *dev, + struct yaffs_block_info *bi, int n) +{ + yaffs_verify_blk(dev, bi, n); + + /* After collection the block should be in the erased state */ + + if (bi->block_state != YAFFS_BLOCK_STATE_COLLECTING && + bi->block_state != YAFFS_BLOCK_STATE_EMPTY) { + yaffs_trace(YAFFS_TRACE_ERROR, + "Block %d is in state %d after gc, should be erased", + n, bi->block_state); + } +} + +void yaffs_verify_blocks(struct yaffs_dev *dev) +{ + int i; + int state_count[YAFFS_NUMBER_OF_BLOCK_STATES]; + int illegal_states = 0; + + if (yaffs_skip_verification(dev)) + return; + + memset(state_count, 0, sizeof(state_count)); + + for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) { + struct yaffs_block_info *bi = yaffs_get_block_info(dev, i); + yaffs_verify_blk(dev, bi, i); + + if (bi->block_state < YAFFS_NUMBER_OF_BLOCK_STATES) + state_count[bi->block_state]++; + else + illegal_states++; + } + + yaffs_trace(YAFFS_TRACE_VERIFY, "Block summary"); + + yaffs_trace(YAFFS_TRACE_VERIFY, + "%d blocks have illegal states", + illegal_states); + if (state_count[YAFFS_BLOCK_STATE_ALLOCATING] > 1) + yaffs_trace(YAFFS_TRACE_VERIFY, + "Too many allocating blocks"); + + for (i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++) + yaffs_trace(YAFFS_TRACE_VERIFY, + "%s %d blocks", + block_state_name[i], state_count[i]); + + if (dev->blocks_in_checkpt != state_count[YAFFS_BLOCK_STATE_CHECKPOINT]) + yaffs_trace(YAFFS_TRACE_VERIFY, + "Checkpoint block count wrong dev %d count %d", + dev->blocks_in_checkpt, + state_count[YAFFS_BLOCK_STATE_CHECKPOINT]); + + if (dev->n_erased_blocks != state_count[YAFFS_BLOCK_STATE_EMPTY]) + yaffs_trace(YAFFS_TRACE_VERIFY, + "Erased block count wrong dev %d count %d", + dev->n_erased_blocks, + state_count[YAFFS_BLOCK_STATE_EMPTY]); + + if (state_count[YAFFS_BLOCK_STATE_COLLECTING] > 1) + yaffs_trace(YAFFS_TRACE_VERIFY, + "Too many collecting blocks %d (max is 1)", + state_count[YAFFS_BLOCK_STATE_COLLECTING]); +} + +/* + * Verify the object header. oh must be valid, but obj and tags may be NULL in + * which case those tests will not be performed. + */ +void yaffs_verify_oh(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh, + struct yaffs_ext_tags *tags, int parent_check) +{ + if (obj && yaffs_skip_verification(obj->my_dev)) + return; + + if (!(tags && obj && oh)) { + yaffs_trace(YAFFS_TRACE_VERIFY, + "Verifying object header tags %p obj %p oh %p", + tags, obj, oh); + return; + } + + if (oh->type <= YAFFS_OBJECT_TYPE_UNKNOWN || + oh->type > YAFFS_OBJECT_TYPE_MAX) + yaffs_trace(YAFFS_TRACE_VERIFY, + "Obj %d header type is illegal value 0x%x", + tags->obj_id, oh->type); + + if (tags->obj_id != obj->obj_id) + yaffs_trace(YAFFS_TRACE_VERIFY, + "Obj %d header mismatch obj_id %d", + tags->obj_id, obj->obj_id); + + /* + * Check that the object's parent ids match if parent_check requested. + * + * Tests do not apply to the root object. + */ + + if (parent_check && tags->obj_id > 1 && !obj->parent) + yaffs_trace(YAFFS_TRACE_VERIFY, + "Obj %d header mismatch parent_id %d obj->parent is NULL", + tags->obj_id, oh->parent_obj_id); + + if (parent_check && obj->parent && + oh->parent_obj_id != obj->parent->obj_id && + (oh->parent_obj_id != YAFFS_OBJECTID_UNLINKED || + obj->parent->obj_id != YAFFS_OBJECTID_DELETED)) + yaffs_trace(YAFFS_TRACE_VERIFY, + "Obj %d header mismatch parent_id %d parent_obj_id %d", + tags->obj_id, oh->parent_obj_id, + obj->parent->obj_id); + + if (tags->obj_id > 1 && oh->name[0] == 0) /* Null name */ + yaffs_trace(YAFFS_TRACE_VERIFY, + "Obj %d header name is NULL", + obj->obj_id); + + if (tags->obj_id > 1 && ((u8) (oh->name[0])) == 0xff) /* Junk name */ + yaffs_trace(YAFFS_TRACE_VERIFY, + "Obj %d header name is 0xff", + obj->obj_id); +} + +void yaffs_verify_file(struct yaffs_obj *obj) +{ + u32 x; + int required_depth; + int actual_depth; + int last_chunk; + u32 offset_in_chunk; + u32 the_chunk; + + u32 i; + struct yaffs_dev *dev; + struct yaffs_ext_tags tags; + struct yaffs_tnode *tn; + u32 obj_id; + + if (!obj) + return; + + if (yaffs_skip_verification(obj->my_dev)) + return; + + dev = obj->my_dev; + obj_id = obj->obj_id; + + + /* Check file size is consistent with tnode depth */ + yaffs_addr_to_chunk(dev, obj->variant.file_variant.file_size, + &last_chunk, &offset_in_chunk); + last_chunk++; + x = last_chunk >> YAFFS_TNODES_LEVEL0_BITS; + required_depth = 0; + while (x > 0) { + x >>= YAFFS_TNODES_INTERNAL_BITS; + required_depth++; + } + + actual_depth = obj->variant.file_variant.top_level; + + /* Check that the chunks in the tnode tree are all correct. + * We do this by scanning through the tnode tree and + * checking the tags for every chunk match. + */ + + if (yaffs_skip_nand_verification(dev)) + return; + + for (i = 1; i <= last_chunk; i++) { + tn = yaffs_find_tnode_0(dev, &obj->variant.file_variant, i); + + if (!tn) + continue; + + the_chunk = yaffs_get_group_base(dev, tn, i); + if (the_chunk > 0) { + yaffs_rd_chunk_tags_nand(dev, the_chunk, NULL, + &tags); + if (tags.obj_id != obj_id || tags.chunk_id != i) + yaffs_trace(YAFFS_TRACE_VERIFY, + "Object %d chunk_id %d NAND mismatch chunk %d tags (%d:%d)", + obj_id, i, the_chunk, + tags.obj_id, tags.chunk_id); + } + } +} + +void yaffs_verify_link(struct yaffs_obj *obj) +{ + if (obj && yaffs_skip_verification(obj->my_dev)) + return; + + /* Verify sane equivalent object */ +} + +void yaffs_verify_symlink(struct yaffs_obj *obj) +{ + if (obj && yaffs_skip_verification(obj->my_dev)) + return; + + /* Verify symlink string */ +} + +void yaffs_verify_special(struct yaffs_obj *obj) +{ + if (obj && yaffs_skip_verification(obj->my_dev)) + return; +} + +void yaffs_verify_obj(struct yaffs_obj *obj) +{ + struct yaffs_dev *dev; + u32 chunk_min; + u32 chunk_max; + u32 chunk_id_ok; + u32 chunk_in_range; + u32 chunk_wrongly_deleted; + u32 chunk_valid; + + if (!obj) + return; + + if (obj->being_created) + return; + + dev = obj->my_dev; + + if (yaffs_skip_verification(dev)) + return; + + /* Check sane object header chunk */ + + chunk_min = dev->internal_start_block * dev->param.chunks_per_block; + chunk_max = + (dev->internal_end_block + 1) * dev->param.chunks_per_block - 1; + + chunk_in_range = (((unsigned)(obj->hdr_chunk)) >= chunk_min && + ((unsigned)(obj->hdr_chunk)) <= chunk_max); + chunk_id_ok = chunk_in_range || (obj->hdr_chunk == 0); + chunk_valid = chunk_in_range && + yaffs_check_chunk_bit(dev, + obj->hdr_chunk / dev->param.chunks_per_block, + obj->hdr_chunk % dev->param.chunks_per_block); + chunk_wrongly_deleted = chunk_in_range && !chunk_valid; + + if (!obj->fake && (!chunk_id_ok || chunk_wrongly_deleted)) + yaffs_trace(YAFFS_TRACE_VERIFY, + "Obj %d has chunk_id %d %s %s", + obj->obj_id, obj->hdr_chunk, + chunk_id_ok ? "" : ",out of range", + chunk_wrongly_deleted ? ",marked as deleted" : ""); + + if (chunk_valid && !yaffs_skip_nand_verification(dev)) { + struct yaffs_ext_tags tags; + struct yaffs_obj_hdr *oh; + u8 *buffer = yaffs_get_temp_buffer(dev); + + oh = (struct yaffs_obj_hdr *)buffer; + + yaffs_rd_chunk_tags_nand(dev, obj->hdr_chunk, buffer, &tags); + + yaffs_verify_oh(obj, oh, &tags, 1); + + yaffs_release_temp_buffer(dev, buffer); + } + + /* Verify it has a parent */ + if (obj && !obj->fake && (!obj->parent || obj->parent->my_dev != dev)) { + yaffs_trace(YAFFS_TRACE_VERIFY, + "Obj %d has parent pointer %p which does not look like an object", + obj->obj_id, obj->parent); + } + + /* Verify parent is a directory */ + if (obj->parent && + obj->parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { + yaffs_trace(YAFFS_TRACE_VERIFY, + "Obj %d's parent is not a directory (type %d)", + obj->obj_id, obj->parent->variant_type); + } + + switch (obj->variant_type) { + case YAFFS_OBJECT_TYPE_FILE: + yaffs_verify_file(obj); + break; + case YAFFS_OBJECT_TYPE_SYMLINK: + yaffs_verify_symlink(obj); + break; + case YAFFS_OBJECT_TYPE_DIRECTORY: + yaffs_verify_dir(obj); + break; + case YAFFS_OBJECT_TYPE_HARDLINK: + yaffs_verify_link(obj); + break; + case YAFFS_OBJECT_TYPE_SPECIAL: + yaffs_verify_special(obj); + break; + case YAFFS_OBJECT_TYPE_UNKNOWN: + default: + yaffs_trace(YAFFS_TRACE_VERIFY, + "Obj %d has illegaltype %d", + obj->obj_id, obj->variant_type); + break; + } +} + +void yaffs_verify_objects(struct yaffs_dev *dev) +{ + struct yaffs_obj *obj; + int i; + struct list_head *lh; + + if (yaffs_skip_verification(dev)) + return; + + /* Iterate through the objects in each hash entry */ + + for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) { + list_for_each(lh, &dev->obj_bucket[i].list) { + obj = list_entry(lh, struct yaffs_obj, hash_link); + yaffs_verify_obj(obj); + } + } +} + +void yaffs_verify_obj_in_dir(struct yaffs_obj *obj) +{ + struct list_head *lh; + struct yaffs_obj *list_obj; + int count = 0; + + if (!obj) { + yaffs_trace(YAFFS_TRACE_ALWAYS, "No object to verify"); + BUG(); + return; + } + + if (yaffs_skip_verification(obj->my_dev)) + return; + + if (!obj->parent) { + yaffs_trace(YAFFS_TRACE_ALWAYS, "Object does not have parent"); + BUG(); + return; + } + + if (obj->parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { + yaffs_trace(YAFFS_TRACE_ALWAYS, "Parent is not directory"); + BUG(); + } + + /* Iterate through the objects in each hash entry */ + + list_for_each(lh, &obj->parent->variant.dir_variant.children) { + list_obj = list_entry(lh, struct yaffs_obj, siblings); + yaffs_verify_obj(list_obj); + if (obj == list_obj) + count++; + } + + if (count != 1) { + yaffs_trace(YAFFS_TRACE_ALWAYS, + "Object in directory %d times", + count); + BUG(); + } +} + +void yaffs_verify_dir(struct yaffs_obj *directory) +{ + struct list_head *lh; + struct yaffs_obj *list_obj; + + if (!directory) { + BUG(); + return; + } + + if (yaffs_skip_full_verification(directory->my_dev)) + return; + + if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { + yaffs_trace(YAFFS_TRACE_ALWAYS, + "Directory has wrong type: %d", + directory->variant_type); + BUG(); + } + + /* Iterate through the objects in each hash entry */ + + list_for_each(lh, &directory->variant.dir_variant.children) { + list_obj = list_entry(lh, struct yaffs_obj, siblings); + if (list_obj->parent != directory) { + yaffs_trace(YAFFS_TRACE_ALWAYS, + "Object in directory list has wrong parent %p", + list_obj->parent); + BUG(); + } + yaffs_verify_obj_in_dir(list_obj); + } +} + +static int yaffs_free_verification_failures; + +void yaffs_verify_free_chunks(struct yaffs_dev *dev) +{ + int counted; + int difference; + + if (yaffs_skip_verification(dev)) + return; + + counted = yaffs_count_free_chunks(dev); + + difference = dev->n_free_chunks - counted; + + if (difference) { + yaffs_trace(YAFFS_TRACE_ALWAYS, + "Freechunks verification failure %d %d %d", + dev->n_free_chunks, counted, difference); + yaffs_free_verification_failures++; + } +} + +int yaffs_verify_file_sane(struct yaffs_obj *in) +{ + (void) in; + return YAFFS_OK; +} diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_verify.h b/target/linux/generic/files/fs/yaffs2/yaffs_verify.h new file mode 100644 index 0000000..4f4af8d --- /dev/null +++ b/target/linux/generic/files/fs/yaffs2/yaffs_verify.h @@ -0,0 +1,43 @@ +/* + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + */ + +#ifndef __YAFFS_VERIFY_H__ +#define __YAFFS_VERIFY_H__ + +#include "yaffs_guts.h" + +void yaffs_verify_blk(struct yaffs_dev *dev, struct yaffs_block_info *bi, + int n); +void yaffs_verify_collected_blk(struct yaffs_dev *dev, + struct yaffs_block_info *bi, int n); +void yaffs_verify_blocks(struct yaffs_dev *dev); + +void yaffs_verify_oh(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh, + struct yaffs_ext_tags *tags, int parent_check); +void yaffs_verify_file(struct yaffs_obj *obj); +void yaffs_verify_link(struct yaffs_obj *obj); +void yaffs_verify_symlink(struct yaffs_obj *obj); +void yaffs_verify_special(struct yaffs_obj *obj); +void yaffs_verify_obj(struct yaffs_obj *obj); +void yaffs_verify_objects(struct yaffs_dev *dev); +void yaffs_verify_obj_in_dir(struct yaffs_obj *obj); +void yaffs_verify_dir(struct yaffs_obj *directory); +void yaffs_verify_free_chunks(struct yaffs_dev *dev); + +int yaffs_verify_file_sane(struct yaffs_obj *obj); + +int yaffs_skip_verification(struct yaffs_dev *dev); + +#endif diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_vfs.c b/target/linux/generic/files/fs/yaffs2/yaffs_vfs.c new file mode 100644 index 0000000..864a5dc --- /dev/null +++ b/target/linux/generic/files/fs/yaffs2/yaffs_vfs.c @@ -0,0 +1,3665 @@ +/* + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning + * Acknowledgements: + * Luc van OostenRyck for numerous patches. + * Nick Bane for numerous patches. + * Nick Bane for 2.5/2.6 integration. + * Andras Toth for mknod rdev issue. + * Michael Fischer for finding the problem with inode inconsistency. + * Some code bodily lifted from JFFS + * + * 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 is the file system front-end to YAFFS that hooks it up to + * the VFS. + * + * Special notes: + * >> 2.4: sb->u.generic_sbp points to the struct yaffs_dev associated with + * this superblock + * >> 2.6: sb->s_fs_info points to the struct yaffs_dev associated with this + * superblock + * >> inode->u.generic_ip points to the associated struct yaffs_obj. + */ + +/* + * There are two variants of the VFS glue code. This variant should compile + * for any version of Linux. + */ +#include + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)) +#define YAFFS_COMPILE_BACKGROUND +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23)) +#define YAFFS_COMPILE_FREEZER +#endif +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)) +#define YAFFS_COMPILE_EXPORTFS +#endif + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 35)) +#define YAFFS_USE_SETATTR_COPY +#define YAFFS_USE_TRUNCATE_SETSIZE +#endif +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 35)) +#define YAFFS_HAS_EVICT_INODE +#endif + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)) +#define YAFFS_NEW_FOLLOW_LINK 1 +#else +#define YAFFS_NEW_FOLLOW_LINK 0 +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) +#define YAFFS_HAS_WRITE_SUPER +#endif + + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)) +#include +#endif + +#include +#include +#include +#include +#include +#include +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39)) +#include +#endif +#include +#include +#include +#include +#include + +#if (YAFFS_NEW_FOLLOW_LINK == 1) +#include +#endif + +#ifdef YAFFS_COMPILE_EXPORTFS +#include +#endif + +#ifdef YAFFS_COMPILE_BACKGROUND +#include +#include +#endif +#ifdef YAFFS_COMPILE_FREEZER +#include +#endif + +#include + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) + +#include + +#define UnlockPage(p) unlock_page(p) +#define Page_Uptodate(page) test_bit(PG_uptodate, &(page)->flags) + +/* FIXME: use sb->s_id instead ? */ +#define yaffs_devname(sb, buf) bdevname(sb->s_bdev, buf) + +#else + +#include +#define BDEVNAME_SIZE 0 +#define yaffs_devname(sb, buf) kdevname(sb->s_dev) + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)) +/* added NCB 26/5/2006 for 2.4.25-vrs2-tcl1 kernel */ +#define __user +#endif + +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)) +#define YPROC_ROOT (&proc_root) +#else +#define YPROC_ROOT NULL +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)) +#define Y_INIT_TIMER(a) init_timer(a) +#else +#define Y_INIT_TIMER(a) init_timer_on_stack(a) +#endif + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 27)) +#define YAFFS_USE_WRITE_BEGIN_END 1 +#else +#define YAFFS_USE_WRITE_BEGIN_END 0 +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) +#define YAFFS_SUPER_HAS_DIRTY +#endif + + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) +#define set_nlink(inode, count) do { (inode)->i_nlink = (count); } while(0) +#endif + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 28)) +static uint32_t YCALCBLOCKS(uint64_t partition_size, uint32_t block_size) +{ + uint64_t result = partition_size; + do_div(result, block_size); + return (uint32_t) result; +} +#else +#define YCALCBLOCKS(s, b) ((s)/(b)) +#endif + +#include +#include + +#include "yportenv.h" +#include "yaffs_trace.h" +#include "yaffs_guts.h" +#include "yaffs_attribs.h" + +#include "yaffs_linux.h" + +#include "yaffs_mtdif.h" +#include "yaffs_packedtags2.h" +#include "yaffs_getblockinfo.h" + +unsigned int yaffs_trace_mask = + YAFFS_TRACE_BAD_BLOCKS | + YAFFS_TRACE_ALWAYS | + 0; + +unsigned int yaffs_wr_attempts = YAFFS_WR_ATTEMPTS; +unsigned int yaffs_auto_checkpoint = 1; +unsigned int yaffs_gc_control = 1; +unsigned int yaffs_bg_enable = 1; +unsigned int yaffs_auto_select = 1; +/* Module Parameters */ +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) +module_param(yaffs_trace_mask, uint, 0644); +module_param(yaffs_wr_attempts, uint, 0644); +module_param(yaffs_auto_checkpoint, uint, 0644); +module_param(yaffs_gc_control, uint, 0644); +module_param(yaffs_bg_enable, uint, 0644); +#else +MODULE_PARM(yaffs_trace_mask, "i"); +MODULE_PARM(yaffs_wr_attempts, "i"); +MODULE_PARM(yaffs_auto_checkpoint, "i"); +MODULE_PARM(yaffs_gc_control, "i"); +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)) +/* use iget and read_inode */ +#define Y_IGET(sb, inum) iget((sb), (inum)) + +#else +/* Call local equivalent */ +#define YAFFS_USE_OWN_IGET +#define Y_IGET(sb, inum) yaffs_iget((sb), (inum)) + +#endif + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18)) +#define yaffs_inode_to_obj_lv(iptr) ((iptr)->i_private) +#else +#define yaffs_inode_to_obj_lv(iptr) ((iptr)->u.generic_ip) +#endif + +#define yaffs_inode_to_obj(iptr) \ + ((struct yaffs_obj *)(yaffs_inode_to_obj_lv(iptr))) +#define yaffs_dentry_to_obj(dptr) yaffs_inode_to_obj((dptr)->d_inode) + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) +#define yaffs_super_to_dev(sb) ((struct yaffs_dev *)sb->s_fs_info) +#else +#define yaffs_super_to_dev(sb) ((struct yaffs_dev *)sb->u.generic_sbp) +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)) +#define Y_CLEAR_INODE(i) clear_inode(i) +#else +#define Y_CLEAR_INODE(i) end_writeback(i) +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)) +#define YAFFS_USE_DIR_ITERATE +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,12,0)) +#define YAFFS_NEW_PROCFS +#include +#endif + + +#define update_dir_time(dir) do {\ + (dir)->i_ctime = (dir)->i_mtime = CURRENT_TIME; \ + } while (0) + +static void yaffs_fill_inode_from_obj(struct inode *inode, + struct yaffs_obj *obj); + + +static void yaffs_gross_lock(struct yaffs_dev *dev) +{ + yaffs_trace(YAFFS_TRACE_LOCK, "yaffs locking %p", current); + mutex_lock(&(yaffs_dev_to_lc(dev)->gross_lock)); + yaffs_trace(YAFFS_TRACE_LOCK, "yaffs locked %p", current); +} + +static void yaffs_gross_unlock(struct yaffs_dev *dev) +{ + yaffs_trace(YAFFS_TRACE_LOCK, "yaffs unlocking %p", current); + mutex_unlock(&(yaffs_dev_to_lc(dev)->gross_lock)); +} + + +static int yaffs_readpage_nolock(struct file *f, struct page *pg) +{ + /* Lifted from jffs2 */ + + struct yaffs_obj *obj; + unsigned char *pg_buf; + int ret; + loff_t pos = ((loff_t) pg->index) << PAGE_CACHE_SHIFT; + struct yaffs_dev *dev; + + yaffs_trace(YAFFS_TRACE_OS, + "yaffs_readpage_nolock at %lld, size %08x", + (long long)pos, + (unsigned)PAGE_CACHE_SIZE); + + obj = yaffs_dentry_to_obj(f->f_dentry); + + dev = obj->my_dev; + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) + BUG_ON(!PageLocked(pg)); +#else + if (!PageLocked(pg)) + PAGE_BUG(pg); +#endif + + pg_buf = kmap(pg); + /* FIXME: Can kmap fail? */ + + yaffs_gross_lock(dev); + + ret = yaffs_file_rd(obj, pg_buf, pos, PAGE_CACHE_SIZE); + + yaffs_gross_unlock(dev); + + if (ret >= 0) + ret = 0; + + if (ret) { + ClearPageUptodate(pg); + SetPageError(pg); + } else { + SetPageUptodate(pg); + ClearPageError(pg); + } + + flush_dcache_page(pg); + kunmap(pg); + + yaffs_trace(YAFFS_TRACE_OS, "yaffs_readpage_nolock done"); + return ret; +} + +static int yaffs_readpage_unlock(struct file *f, struct page *pg) +{ + int ret = yaffs_readpage_nolock(f, pg); + UnlockPage(pg); + return ret; +} + +static int yaffs_readpage(struct file *f, struct page *pg) +{ + int ret; + + yaffs_trace(YAFFS_TRACE_OS, "yaffs_readpage"); + ret = yaffs_readpage_unlock(f, pg); + yaffs_trace(YAFFS_TRACE_OS, "yaffs_readpage done"); + return ret; +} + + +static void yaffs_set_super_dirty_val(struct yaffs_dev *dev, int val) +{ + struct yaffs_linux_context *lc = yaffs_dev_to_lc(dev); + + if (lc) + lc->dirty = val; + +# ifdef YAFFS_SUPER_HAS_DIRTY + { + struct super_block *sb = lc->super; + + if (sb) + sb->s_dirt = val; + } +#endif + +} + +static void yaffs_set_super_dirty(struct yaffs_dev *dev) +{ + yaffs_set_super_dirty_val(dev, 1); +} + +static void yaffs_clear_super_dirty(struct yaffs_dev *dev) +{ + yaffs_set_super_dirty_val(dev, 0); +} + +static int yaffs_check_super_dirty(struct yaffs_dev *dev) +{ + struct yaffs_linux_context *lc = yaffs_dev_to_lc(dev); + + if (lc && lc->dirty) + return 1; + +# ifdef YAFFS_SUPER_HAS_DIRTY + { + struct super_block *sb = lc->super; + + if (sb && sb->s_dirt) + return 1; + } +#endif + return 0; + +} + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) +static int yaffs_writepage(struct page *page, struct writeback_control *wbc) +#else +static int yaffs_writepage(struct page *page) +#endif +{ + struct yaffs_dev *dev; + struct address_space *mapping = page->mapping; + struct inode *inode; + unsigned long end_index; + char *buffer; + struct yaffs_obj *obj; + int n_written = 0; + unsigned n_bytes; + loff_t i_size; + + if (!mapping) + BUG(); + inode = mapping->host; + if (!inode) + BUG(); + i_size = i_size_read(inode); + + end_index = i_size >> PAGE_CACHE_SHIFT; + + if (page->index < end_index) + n_bytes = PAGE_CACHE_SIZE; + else { + n_bytes = i_size & (PAGE_CACHE_SIZE - 1); + + if (page->index > end_index || !n_bytes) { + yaffs_trace(YAFFS_TRACE_OS, + "yaffs_writepage at %lld, inode size = %lld!!", + ((loff_t)page->index) << PAGE_CACHE_SHIFT, + inode->i_size); + yaffs_trace(YAFFS_TRACE_OS, + " -> don't care!!"); + + zero_user_segment(page, 0, PAGE_CACHE_SIZE); + set_page_writeback(page); + unlock_page(page); + end_page_writeback(page); + return 0; + } + } + + if (n_bytes != PAGE_CACHE_SIZE) + zero_user_segment(page, n_bytes, PAGE_CACHE_SIZE); + + get_page(page); + + buffer = kmap(page); + + obj = yaffs_inode_to_obj(inode); + dev = obj->my_dev; + yaffs_gross_lock(dev); + + yaffs_trace(YAFFS_TRACE_OS, + "yaffs_writepage at %lld, size %08x", + ((loff_t)page->index) << PAGE_CACHE_SHIFT, n_bytes); + yaffs_trace(YAFFS_TRACE_OS, + "writepag0: obj = %lld, ino = %lld", + obj->variant.file_variant.file_size, inode->i_size); + + n_written = yaffs_wr_file(obj, buffer, + ((loff_t)page->index) << PAGE_CACHE_SHIFT, n_bytes, 0); + + yaffs_set_super_dirty(dev); + + yaffs_trace(YAFFS_TRACE_OS, + "writepag1: obj = %lld, ino = %lld", + obj->variant.file_variant.file_size, inode->i_size); + + yaffs_gross_unlock(dev); + + kunmap(page); + set_page_writeback(page); + unlock_page(page); + end_page_writeback(page); + put_page(page); + + return (n_written == n_bytes) ? 0 : -ENOSPC; +} + +/* Space holding and freeing is done to ensure we have space available for write_begin/end */ +/* For now we just assume few parallel writes and check against a small number. */ +/* Todo: need to do this with a counter to handle parallel reads better */ + +static ssize_t yaffs_hold_space(struct file *f) +{ + struct yaffs_obj *obj; + struct yaffs_dev *dev; + + int n_free_chunks; + + obj = yaffs_dentry_to_obj(f->f_dentry); + + dev = obj->my_dev; + + yaffs_gross_lock(dev); + + n_free_chunks = yaffs_get_n_free_chunks(dev); + + yaffs_gross_unlock(dev); + + return (n_free_chunks > 20) ? 1 : 0; +} + +static void yaffs_release_space(struct file *f) +{ + struct yaffs_obj *obj; + struct yaffs_dev *dev; + + obj = yaffs_dentry_to_obj(f->f_dentry); + + dev = obj->my_dev; + + yaffs_gross_lock(dev); + + yaffs_gross_unlock(dev); +} + +#if (YAFFS_USE_WRITE_BEGIN_END > 0) +static int yaffs_write_begin(struct file *filp, struct address_space *mapping, + loff_t pos, unsigned len, unsigned flags, + struct page **pagep, void **fsdata) +{ + struct page *pg = NULL; + pgoff_t index = pos >> PAGE_CACHE_SHIFT; + + int ret = 0; + int space_held = 0; + + /* Get a page */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28) + pg = grab_cache_page_write_begin(mapping, index, flags); +#else + pg = __grab_cache_page(mapping, index); +#endif + + *pagep = pg; + if (!pg) { + ret = -ENOMEM; + goto out; + } + yaffs_trace(YAFFS_TRACE_OS, + "start yaffs_write_begin index %d(%x) uptodate %d", + (int)index, (int)index, Page_Uptodate(pg) ? 1 : 0); + + /* Get fs space */ + space_held = yaffs_hold_space(filp); + + if (!space_held) { + ret = -ENOSPC; + goto out; + } + + /* Update page if required */ + + if (!Page_Uptodate(pg)) + ret = yaffs_readpage_nolock(filp, pg); + + if (ret) + goto out; + + /* Happy path return */ + yaffs_trace(YAFFS_TRACE_OS, "end yaffs_write_begin - ok"); + + return 0; + +out: + yaffs_trace(YAFFS_TRACE_OS, + "end yaffs_write_begin fail returning %d", ret); + if (space_held) + yaffs_release_space(filp); + if (pg) { + unlock_page(pg); + page_cache_release(pg); + } + return ret; +} + +#else + +static int yaffs_prepare_write(struct file *f, struct page *pg, + unsigned offset, unsigned to) +{ + yaffs_trace(YAFFS_TRACE_OS, "yaffs_prepair_write"); + + if (!Page_Uptodate(pg)) + return yaffs_readpage_nolock(f, pg); + return 0; +} +#endif + + +static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n, + loff_t * pos) +{ + struct yaffs_obj *obj; + int n_written; + loff_t ipos; + struct inode *inode; + struct yaffs_dev *dev; + + obj = yaffs_dentry_to_obj(f->f_dentry); + + if (!obj) { + yaffs_trace(YAFFS_TRACE_OS, + "yaffs_file_write: hey obj is null!"); + return -EINVAL; + } + + dev = obj->my_dev; + + yaffs_gross_lock(dev); + + inode = f->f_dentry->d_inode; + + if (!S_ISBLK(inode->i_mode) && f->f_flags & O_APPEND) + ipos = inode->i_size; + else + ipos = *pos; + + yaffs_trace(YAFFS_TRACE_OS, + "yaffs_file_write about to write writing %u(%x) bytes to object %d at %lld", + (unsigned)n, (unsigned)n, obj->obj_id, ipos); + + n_written = yaffs_wr_file(obj, buf, ipos, n, 0); + + yaffs_set_super_dirty(dev); + + yaffs_trace(YAFFS_TRACE_OS, + "yaffs_file_write: %d(%x) bytes written", + (unsigned)n, (unsigned)n); + + if (n_written > 0) { + ipos += n_written; + *pos = ipos; + if (ipos > inode->i_size) { + inode->i_size = ipos; + inode->i_blocks = (ipos + 511) >> 9; + + yaffs_trace(YAFFS_TRACE_OS, + "yaffs_file_write size updated to %lld bytes, %d blocks", + ipos, (int)(inode->i_blocks)); + } + + } + yaffs_gross_unlock(dev); + return (n_written == 0) && (n > 0) ? -ENOSPC : n_written; +} + + +#if (YAFFS_USE_WRITE_BEGIN_END > 0) +static int yaffs_write_end(struct file *filp, struct address_space *mapping, + loff_t pos, unsigned len, unsigned copied, + struct page *pg, void *fsdadata) +{ + int ret = 0; + void *addr, *kva; + uint32_t offset_into_page = pos & (PAGE_CACHE_SIZE - 1); + + kva = kmap(pg); + addr = kva + offset_into_page; + + yaffs_trace(YAFFS_TRACE_OS, + "yaffs_write_end addr %p pos %lld n_bytes %d", + addr, pos, copied); + + ret = yaffs_file_write(filp, addr, copied, &pos); + + if (ret != copied) { + yaffs_trace(YAFFS_TRACE_OS, + "yaffs_write_end not same size ret %d copied %d", + ret, copied); + SetPageError(pg); + } + + kunmap(pg); + + yaffs_release_space(filp); + unlock_page(pg); + page_cache_release(pg); + return ret; +} +#else + +static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset, + unsigned to) +{ + void *addr, *kva; + + loff_t pos = (((loff_t) pg->index) << PAGE_CACHE_SHIFT) + offset; + int n_bytes = to - offset; + int n_written; + + kva = kmap(pg); + addr = kva + offset; + + yaffs_trace(YAFFS_TRACE_OS, + "yaffs_commit_write addr %p pos %lld n_bytes %d", + addr, pos, n_bytes); + + n_written = yaffs_file_write(f, addr, n_bytes, &pos); + + if (n_written != n_bytes) { + yaffs_trace(YAFFS_TRACE_OS, + "yaffs_commit_write not same size n_written %d n_bytes %d", + n_written, n_bytes); + SetPageError(pg); + } + kunmap(pg); + + yaffs_trace(YAFFS_TRACE_OS, + "yaffs_commit_write returning %d", + n_written == n_bytes ? 0 : n_written); + + return n_written == n_bytes ? 0 : n_written; +} +#endif + +static struct address_space_operations yaffs_file_address_operations = { + .readpage = yaffs_readpage, + .writepage = yaffs_writepage, +#if (YAFFS_USE_WRITE_BEGIN_END > 0) + .write_begin = yaffs_write_begin, + .write_end = yaffs_write_end, +#else + .prepare_write = yaffs_prepare_write, + .commit_write = yaffs_commit_write, +#endif +}; + + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) +static int yaffs_file_flush(struct file *file, fl_owner_t id) +#else +static int yaffs_file_flush(struct file *file) +#endif +{ + struct yaffs_obj *obj = yaffs_dentry_to_obj(file->f_dentry); + + struct yaffs_dev *dev = obj->my_dev; + + yaffs_trace(YAFFS_TRACE_OS, + "yaffs_file_flush object %d (%s)", + obj->obj_id, + obj->dirty ? "dirty" : "clean"); + + yaffs_gross_lock(dev); + + yaffs_flush_file(obj, 1, 0, 0); + + yaffs_gross_unlock(dev); + + return 0; +} + + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) +static int yaffs_sync_object(struct file *file, loff_t start, loff_t end, int datasync) +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34)) +static int yaffs_sync_object(struct file *file, int datasync) +#else +static int yaffs_sync_object(struct file *file, struct dentry *dentry, + int datasync) +#endif +{ + struct yaffs_obj *obj; + struct yaffs_dev *dev; +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34)) + struct dentry *dentry = file->f_path.dentry; +#endif + + obj = yaffs_dentry_to_obj(dentry); + + dev = obj->my_dev; + + yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC, + "yaffs_sync_object"); + yaffs_gross_lock(dev); + yaffs_flush_file(obj, 1, datasync, 0); + yaffs_gross_unlock(dev); + return 0; +} + + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22)) +static const struct file_operations yaffs_file_operations = { + .read = do_sync_read, + .write = do_sync_write, + .aio_read = generic_file_aio_read, + .aio_write = generic_file_aio_write, + .mmap = generic_file_mmap, + .flush = yaffs_file_flush, + .fsync = yaffs_sync_object, + .splice_read = generic_file_splice_read, + .splice_write = generic_file_splice_write, + .llseek = generic_file_llseek, +}; + +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18)) + +static const struct file_operations yaffs_file_operations = { + .read = do_sync_read, + .write = do_sync_write, + .aio_read = generic_file_aio_read, + .aio_write = generic_file_aio_write, + .mmap = generic_file_mmap, + .flush = yaffs_file_flush, + .fsync = yaffs_sync_object, + .sendfile = generic_file_sendfile, +}; + +#else + +static const struct file_operations yaffs_file_operations = { + .read = generic_file_read, + .write = generic_file_write, + .mmap = generic_file_mmap, + .flush = yaffs_file_flush, + .fsync = yaffs_sync_object, +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) + .sendfile = generic_file_sendfile, +#endif +}; +#endif + + + + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)) +static void zero_user_segment(struct page *page, unsigned start, unsigned end) +{ + void *kaddr = kmap_atomic(page, KM_USER0); + memset(kaddr + start, 0, end - start); + kunmap_atomic(kaddr, KM_USER0); + flush_dcache_page(page); +} +#endif + + +static int yaffs_vfs_setsize(struct inode *inode, loff_t newsize) +{ +#ifdef YAFFS_USE_TRUNCATE_SETSIZE + truncate_setsize(inode, newsize); + return 0; +#else + truncate_inode_pages(&inode->i_data, newsize); + return 0; +#endif + +} + + +static int yaffs_vfs_setattr(struct inode *inode, struct iattr *attr) +{ +#ifdef YAFFS_USE_SETATTR_COPY + setattr_copy(inode, attr); + return 0; +#else + return inode_setattr(inode, attr); +#endif + +} + +static int yaffs_setattr(struct dentry *dentry, struct iattr *attr) +{ + struct inode *inode = dentry->d_inode; + int error = 0; + struct yaffs_dev *dev; + + yaffs_trace(YAFFS_TRACE_OS, + "yaffs_setattr of object %d", + yaffs_inode_to_obj(inode)->obj_id); +#if 0 + /* Fail if a requested resize >= 2GB */ + if (attr->ia_valid & ATTR_SIZE && (attr->ia_size >> 31)) + error = -EINVAL; +#endif + + if (error == 0) + error = inode_change_ok(inode, attr); + if (error == 0) { + int result; + if (!error) { + error = yaffs_vfs_setattr(inode, attr); + yaffs_trace(YAFFS_TRACE_OS, "inode_setattr called"); + if (attr->ia_valid & ATTR_SIZE) { + yaffs_vfs_setsize(inode, attr->ia_size); + inode->i_blocks = (inode->i_size + 511) >> 9; + } + } + dev = yaffs_inode_to_obj(inode)->my_dev; + if (attr->ia_valid & ATTR_SIZE) { + yaffs_trace(YAFFS_TRACE_OS, + "resize to %d(%x)", + (int)(attr->ia_size), + (int)(attr->ia_size)); + } + yaffs_gross_lock(dev); + result = yaffs_set_attribs(yaffs_inode_to_obj(inode), attr); + if (result == YAFFS_OK) { + error = 0; + } else { + error = -EPERM; + } + yaffs_gross_unlock(dev); + + } + + yaffs_trace(YAFFS_TRACE_OS, "yaffs_setattr done returning %d", error); + + return error; +} + +static int yaffs_setxattr(struct dentry *dentry, const char *name, + const void *value, size_t size, int flags) +{ + struct inode *inode = dentry->d_inode; + int error = 0; + struct yaffs_dev *dev; + struct yaffs_obj *obj = yaffs_inode_to_obj(inode); + + yaffs_trace(YAFFS_TRACE_OS, "yaffs_setxattr of object %d", obj->obj_id); + + if (error == 0) { + int result; + dev = obj->my_dev; + yaffs_gross_lock(dev); + result = yaffs_set_xattrib(obj, name, value, size, flags); + if (result == YAFFS_OK) + error = 0; + else if (result < 0) + error = result; + yaffs_gross_unlock(dev); + + } + yaffs_trace(YAFFS_TRACE_OS, "yaffs_setxattr done returning %d", error); + + return error; +} + +static ssize_t yaffs_getxattr(struct dentry * dentry, const char *name, + void *buff, size_t size) +{ + struct inode *inode = dentry->d_inode; + int error = 0; + struct yaffs_dev *dev; + struct yaffs_obj *obj = yaffs_inode_to_obj(inode); + + yaffs_trace(YAFFS_TRACE_OS, + "yaffs_getxattr \"%s\" from object %d", + name, obj->obj_id); + + if (error == 0) { + dev = obj->my_dev; + yaffs_gross_lock(dev); + error = yaffs_get_xattrib(obj, name, buff, size); + yaffs_gross_unlock(dev); + + } + yaffs_trace(YAFFS_TRACE_OS, "yaffs_getxattr done returning %d", error); + + return error; +} + +static int yaffs_removexattr(struct dentry *dentry, const char *name) +{ + struct inode *inode = dentry->d_inode; + int error = 0; + struct yaffs_dev *dev; + struct yaffs_obj *obj = yaffs_inode_to_obj(inode); + + yaffs_trace(YAFFS_TRACE_OS, + "yaffs_removexattr of object %d", obj->obj_id); + + if (error == 0) { + int result; + dev = obj->my_dev; + yaffs_gross_lock(dev); + result = yaffs_remove_xattrib(obj, name); + if (result == YAFFS_OK) + error = 0; + else if (result < 0) + error = result; + yaffs_gross_unlock(dev); + + } + yaffs_trace(YAFFS_TRACE_OS, + "yaffs_removexattr done returning %d", error); + + return error; +} + +static ssize_t yaffs_listxattr(struct dentry * dentry, char *buff, size_t size) +{ + struct inode *inode = dentry->d_inode; + int error = 0; + struct yaffs_dev *dev; + struct yaffs_obj *obj = yaffs_inode_to_obj(inode); + + yaffs_trace(YAFFS_TRACE_OS, + "yaffs_listxattr of object %d", obj->obj_id); + + if (error == 0) { + dev = obj->my_dev; + yaffs_gross_lock(dev); + error = yaffs_list_xattrib(obj, buff, size); + yaffs_gross_unlock(dev); + + } + yaffs_trace(YAFFS_TRACE_OS, + "yaffs_listxattr done returning %d", error); + + return error; +} + + +static const struct inode_operations yaffs_file_inode_operations = { + .setattr = yaffs_setattr, + .setxattr = yaffs_setxattr, + .getxattr = yaffs_getxattr, + .listxattr = yaffs_listxattr, + .removexattr = yaffs_removexattr, +}; + + +static int yaffs_readlink(struct dentry *dentry, char __user * buffer, + int buflen) +{ + unsigned char *alias; + int ret; + + struct yaffs_dev *dev = yaffs_dentry_to_obj(dentry)->my_dev; + + yaffs_gross_lock(dev); + + alias = yaffs_get_symlink_alias(yaffs_dentry_to_obj(dentry)); + + yaffs_gross_unlock(dev); + + if (!alias) + return -ENOMEM; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 15, 0) + ret = vfs_readlink(dentry, buffer, buflen, alias); +#else + ret = readlink_copy(buffer, buflen, alias); +#endif + kfree(alias); + return ret; +} + +#if (YAFFS_NEW_FOLLOW_LINK == 1) +static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd) +{ + void *ret; +#else +static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd) +{ + int ret +#endif + unsigned char *alias; + int ret_int = 0; + struct yaffs_dev *dev = yaffs_dentry_to_obj(dentry)->my_dev; + + yaffs_gross_lock(dev); + + alias = yaffs_get_symlink_alias(yaffs_dentry_to_obj(dentry)); + yaffs_gross_unlock(dev); + + if (!alias) { + ret_int = -ENOMEM; + goto out; + } +#if (YAFFS_NEW_FOLLOW_LINK == 1) + nd_set_link(nd, alias); + ret = alias; +out: + if (ret_int) + ret = ERR_PTR(ret_int); + return ret; +#else + ret = vfs_follow_link(nd, alias); + kfree(alias); +out: + if (ret_int) + ret = ret_int; + return ret; +#endif +} + + +#ifdef YAFFS_HAS_PUT_INODE + +/* For now put inode is just for debugging + * Put inode is called when the inode **structure** is put. + */ +static void yaffs_put_inode(struct inode *inode) +{ + yaffs_trace(YAFFS_TRACE_OS, + "yaffs_put_inode: ino %d, count %d"), + (int)inode->i_ino, atomic_read(&inode->i_count); + +} +#endif + +#if (YAFFS_NEW_FOLLOW_LINK == 1) +void yaffs_put_link(struct dentry *dentry, struct nameidata *nd, void *alias) +{ + kfree(alias); +} +#endif + +static const struct inode_operations yaffs_symlink_inode_operations = { + .readlink = yaffs_readlink, + .follow_link = yaffs_follow_link, +#if (YAFFS_NEW_FOLLOW_LINK == 1) + .put_link = yaffs_put_link, +#endif + .setattr = yaffs_setattr, + .setxattr = yaffs_setxattr, + .getxattr = yaffs_getxattr, + .listxattr = yaffs_listxattr, + .removexattr = yaffs_removexattr, +}; + +#ifdef YAFFS_USE_OWN_IGET + +static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino) +{ + struct inode *inode; + struct yaffs_obj *obj; + struct yaffs_dev *dev = yaffs_super_to_dev(sb); + + yaffs_trace(YAFFS_TRACE_OS, "yaffs_iget for %lu", ino); + + inode = iget_locked(sb, ino); + if (!inode) + return ERR_PTR(-ENOMEM); + if (!(inode->i_state & I_NEW)) + return inode; + + /* NB This is called as a side effect of other functions, but + * we had to release the lock to prevent deadlocks, so + * need to lock again. + */ + + yaffs_gross_lock(dev); + + obj = yaffs_find_by_number(dev, inode->i_ino); + + yaffs_fill_inode_from_obj(inode, obj); + + yaffs_gross_unlock(dev); + + unlock_new_inode(inode); + return inode; +} + +#else + +static void yaffs_read_inode(struct inode *inode) +{ + /* NB This is called as a side effect of other functions, but + * we had to release the lock to prevent deadlocks, so + * need to lock again. + */ + + struct yaffs_obj *obj; + struct yaffs_dev *dev = yaffs_super_to_dev(inode->i_sb); + + yaffs_trace(YAFFS_TRACE_OS, + "yaffs_read_inode for %d", (int)inode->i_ino); + + if (current != yaffs_dev_to_lc(dev)->readdir_process) + yaffs_gross_lock(dev); + + obj = yaffs_find_by_number(dev, inode->i_ino); + + yaffs_fill_inode_from_obj(inode, obj); + + if (current != yaffs_dev_to_lc(dev)->readdir_process) + yaffs_gross_unlock(dev); +} + +#endif + + + +struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev, + struct yaffs_obj *obj) +{ + struct inode *inode; + + if (!sb) { + yaffs_trace(YAFFS_TRACE_OS, + "yaffs_get_inode for NULL super_block!!"); + return NULL; + + } + + if (!obj) { + yaffs_trace(YAFFS_TRACE_OS, + "yaffs_get_inode for NULL object!!"); + return NULL; + + } + + yaffs_trace(YAFFS_TRACE_OS, + "yaffs_get_inode for object %d", obj->obj_id); + + inode = Y_IGET(sb, obj->obj_id); + if (IS_ERR(inode)) + return NULL; + + /* NB Side effect: iget calls back to yaffs_read_inode(). */ + /* iget also increments the inode's i_count */ + /* NB You can't be holding gross_lock or deadlock will happen! */ + + return inode; +} + + + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) +#define YCRED(x) x +#else +#define YCRED(x) (x->cred) +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0) +#define YPROC_uid(p) (YCRED(p)->fsuid) +#define YPROC_gid(p) (YCRED(p)->fsgid) +#define EXTRACT_gid(x) x +#define EXTRACT_uid(x) x +#define MAKE_gid(x) x +#define MAKE_uid(x) x +#else +#define YPROC_uid(p) from_kuid(&init_user_ns, YCRED(p)->fsuid) +#define YPROC_gid(p) from_kgid(&init_user_ns, YCRED(p)->fsgid) +#define EXTRACT_gid(x) from_kgid(&init_user_ns, x) +#define EXTRACT_uid(x) from_kuid(&init_user_ns, x) +#define MAKE_gid(x) make_kgid(&init_user_ns, x) +#define MAKE_uid(x) make_kuid(&init_user_ns, x) +#endif + + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) +static int yaffs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, + dev_t rdev) +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) +static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode, + dev_t rdev) +#else +static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode, + int rdev) +#endif +{ + struct inode *inode; + + struct yaffs_obj *obj = NULL; + struct yaffs_dev *dev; + + struct yaffs_obj *parent = yaffs_inode_to_obj(dir); + + int error = -ENOSPC; + uid_t uid = YPROC_uid(current); + gid_t gid = + (dir->i_mode & S_ISGID) ? EXTRACT_gid(dir->i_gid) : YPROC_gid(current); + + if ((dir->i_mode & S_ISGID) && S_ISDIR(mode)) + mode |= S_ISGID; + + if (parent) { + yaffs_trace(YAFFS_TRACE_OS, + "yaffs_mknod: parent object %d type %d", + parent->obj_id, parent->variant_type); + } else { + yaffs_trace(YAFFS_TRACE_OS, + "yaffs_mknod: could not get parent object"); + return -EPERM; + } + + yaffs_trace(YAFFS_TRACE_OS, + "yaffs_mknod: making oject for %s, mode %x dev %x", + dentry->d_name.name, mode, rdev); + + dev = parent->my_dev; + + yaffs_gross_lock(dev); + + switch (mode & S_IFMT) { + default: + /* Special (socket, fifo, device...) */ + yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making special"); +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) + obj = + yaffs_create_special(parent, dentry->d_name.name, mode, uid, + gid, old_encode_dev(rdev)); +#else + obj = + yaffs_create_special(parent, dentry->d_name.name, mode, uid, + gid, rdev); +#endif + break; + case S_IFREG: /* file */ + yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making file"); + obj = yaffs_create_file(parent, dentry->d_name.name, mode, uid, + gid); + break; + case S_IFDIR: /* directory */ + yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making directory"); + obj = yaffs_create_dir(parent, dentry->d_name.name, mode, + uid, gid); + break; + case S_IFLNK: /* symlink */ + yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making symlink"); + obj = NULL; /* Do we ever get here? */ + break; + } + + /* Can not call yaffs_get_inode() with gross lock held */ + yaffs_gross_unlock(dev); + + if (obj) { + inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj); + d_instantiate(dentry, inode); + update_dir_time(dir); + yaffs_trace(YAFFS_TRACE_OS, + "yaffs_mknod created object %d count = %d", + obj->obj_id, atomic_read(&inode->i_count)); + error = 0; + yaffs_fill_inode_from_obj(dir, parent); + } else { + yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod failed making object"); + error = -ENOMEM; + } + + return error; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) +static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) +#else +static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode) +#endif +{ + int ret_val; + yaffs_trace(YAFFS_TRACE_OS, "yaffs_mkdir"); + ret_val = yaffs_mknod(dir, dentry, mode | S_IFDIR, 0); + return ret_val; +} + + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) +static int yaffs_create(struct inode *dir, struct dentry *dentry, umode_t mode, + bool dummy) +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) +static int yaffs_create(struct inode *dir, struct dentry *dentry, umode_t mode, + struct nameidata *n) +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) +static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode, + struct nameidata *n) +#else +static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode) +#endif +{ + yaffs_trace(YAFFS_TRACE_OS, "yaffs_create"); + return yaffs_mknod(dir, dentry, mode | S_IFREG, 0); +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) +static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry, + unsigned int dummy) +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) +static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry, + struct nameidata *n) +#else +static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry) +#endif +{ + struct yaffs_obj *obj; + struct inode *inode = NULL; /* NCB 2.5/2.6 needs NULL here */ + + struct yaffs_dev *dev = yaffs_inode_to_obj(dir)->my_dev; + + if (current != yaffs_dev_to_lc(dev)->readdir_process) + yaffs_gross_lock(dev); + + yaffs_trace(YAFFS_TRACE_OS, "yaffs_lookup for %d:%s", + yaffs_inode_to_obj(dir)->obj_id, dentry->d_name.name); + + obj = yaffs_find_by_name(yaffs_inode_to_obj(dir), dentry->d_name.name); + + obj = yaffs_get_equivalent_obj(obj); /* in case it was a hardlink */ + + /* Can't hold gross lock when calling yaffs_get_inode() */ + if (current != yaffs_dev_to_lc(dev)->readdir_process) + yaffs_gross_unlock(dev); + + if (obj) { + yaffs_trace(YAFFS_TRACE_OS, + "yaffs_lookup found %d", obj->obj_id); + + inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj); + } else { + yaffs_trace(YAFFS_TRACE_OS, "yaffs_lookup not found"); + + } + +/* added NCB for 2.5/6 compatability - forces add even if inode is + * NULL which creates dentry hash */ + d_add(dentry, inode); + + return NULL; +} + +/* + * Create a link... + */ +static int yaffs_link(struct dentry *old_dentry, struct inode *dir, + struct dentry *dentry) +{ + struct inode *inode = old_dentry->d_inode; + struct yaffs_obj *obj = NULL; + struct yaffs_obj *link = NULL; + struct yaffs_dev *dev; + + yaffs_trace(YAFFS_TRACE_OS, "yaffs_link"); + + obj = yaffs_inode_to_obj(inode); + dev = obj->my_dev; + + yaffs_gross_lock(dev); + + if (!S_ISDIR(inode->i_mode)) /* Don't link directories */ + link = + yaffs_link_obj(yaffs_inode_to_obj(dir), dentry->d_name.name, + obj); + + if (link) { + set_nlink(old_dentry->d_inode, yaffs_get_obj_link_count(obj)); + d_instantiate(dentry, old_dentry->d_inode); + atomic_inc(&old_dentry->d_inode->i_count); + yaffs_trace(YAFFS_TRACE_OS, + "yaffs_link link count %d i_count %d", + old_dentry->d_inode->i_nlink, + atomic_read(&old_dentry->d_inode->i_count)); + } + + yaffs_gross_unlock(dev); + + if (link) { + update_dir_time(dir); + return 0; + } + + return -EPERM; +} + +static int yaffs_symlink(struct inode *dir, struct dentry *dentry, + const char *symname) +{ + struct yaffs_obj *obj; + struct yaffs_dev *dev; + uid_t uid = YPROC_uid(current); + gid_t gid = + (dir->i_mode & S_ISGID) ? EXTRACT_gid(dir->i_gid) : YPROC_gid(current); + + yaffs_trace(YAFFS_TRACE_OS, "yaffs_symlink"); + + if (strnlen(dentry->d_name.name, YAFFS_MAX_NAME_LENGTH + 1) > + YAFFS_MAX_NAME_LENGTH) + return -ENAMETOOLONG; + + if (strnlen(symname, YAFFS_MAX_ALIAS_LENGTH + 1) > + YAFFS_MAX_ALIAS_LENGTH) + return -ENAMETOOLONG; + + dev = yaffs_inode_to_obj(dir)->my_dev; + yaffs_gross_lock(dev); + obj = yaffs_create_symlink(yaffs_inode_to_obj(dir), dentry->d_name.name, + S_IFLNK | S_IRWXUGO, uid, gid, symname); + yaffs_gross_unlock(dev); + + if (obj) { + struct inode *inode; + + inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj); + d_instantiate(dentry, inode); + update_dir_time(dir); + yaffs_trace(YAFFS_TRACE_OS, "symlink created OK"); + return 0; + } else { + yaffs_trace(YAFFS_TRACE_OS, "symlink not created"); + } + + return -ENOMEM; +} + +/* + * The VFS layer already does all the dentry stuff for rename. + * + * NB: POSIX says you can rename an object over an old object of the same name + */ +static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry) +{ + struct yaffs_dev *dev; + int ret_val = YAFFS_FAIL; + struct yaffs_obj *target; + + yaffs_trace(YAFFS_TRACE_OS, "yaffs_rename"); + dev = yaffs_inode_to_obj(old_dir)->my_dev; + + yaffs_gross_lock(dev); + + /* Check if the target is an existing directory that is not empty. */ + target = yaffs_find_by_name(yaffs_inode_to_obj(new_dir), + new_dentry->d_name.name); + + if (target && target->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY && + !list_empty(&target->variant.dir_variant.children)) { + + yaffs_trace(YAFFS_TRACE_OS, "target is non-empty dir"); + + ret_val = YAFFS_FAIL; + } else { + /* Now does unlinking internally using shadowing mechanism */ + yaffs_trace(YAFFS_TRACE_OS, "calling yaffs_rename_obj"); + + ret_val = yaffs_rename_obj(yaffs_inode_to_obj(old_dir), + old_dentry->d_name.name, + yaffs_inode_to_obj(new_dir), + new_dentry->d_name.name); + } + yaffs_gross_unlock(dev); + + if (ret_val == YAFFS_OK) { + if (target) + inode_dec_link_count(new_dentry->d_inode); + + update_dir_time(old_dir); + if (old_dir != new_dir) + update_dir_time(new_dir); + return 0; + } else { + return -ENOTEMPTY; + } +} + + + + +static int yaffs_unlink(struct inode *dir, struct dentry *dentry) +{ + int ret_val; + + struct yaffs_dev *dev; + struct yaffs_obj *obj; + + yaffs_trace(YAFFS_TRACE_OS, "yaffs_unlink %d:%s", + (int)(dir->i_ino), dentry->d_name.name); + obj = yaffs_inode_to_obj(dir); + dev = obj->my_dev; + + yaffs_gross_lock(dev); + + ret_val = yaffs_unlinker(obj, dentry->d_name.name); + + if (ret_val == YAFFS_OK) { + inode_dec_link_count(dentry->d_inode); + dir->i_version++; + yaffs_gross_unlock(dev); + update_dir_time(dir); + return 0; + } + yaffs_gross_unlock(dev); + return -ENOTEMPTY; +} + + + +static const struct inode_operations yaffs_dir_inode_operations = { + .create = yaffs_create, + .lookup = yaffs_lookup, + .link = yaffs_link, + .unlink = yaffs_unlink, + .symlink = yaffs_symlink, + .mkdir = yaffs_mkdir, + .rmdir = yaffs_unlink, + .mknod = yaffs_mknod, + .rename = yaffs_rename, + .setattr = yaffs_setattr, + .setxattr = yaffs_setxattr, + .getxattr = yaffs_getxattr, + .listxattr = yaffs_listxattr, + .removexattr = yaffs_removexattr, +}; + +/*-----------------------------------------------------------------*/ +/* Directory search context allows us to unlock access to yaffs during + * filldir without causing problems with the directory being modified. + * This is similar to the tried and tested mechanism used in yaffs direct. + * + * A search context iterates along a doubly linked list of siblings in the + * directory. If the iterating object is deleted then this would corrupt + * the list iteration, likely causing a crash. The search context avoids + * this by using the remove_obj_fn to move the search context to the + * next object before the object is deleted. + * + * Many readdirs (and thus seach conexts) may be alive simulateously so + * each struct yaffs_dev has a list of these. + * + * A seach context lives for the duration of a readdir. + * + * All these functions must be called while yaffs is locked. + */ + +struct yaffs_search_context { + struct yaffs_dev *dev; + struct yaffs_obj *dir_obj; + struct yaffs_obj *next_return; + struct list_head others; +}; + +/* + * yaffs_new_search() creates a new search context, initialises it and + * adds it to the device's search context list. + * + * Called at start of readdir. + */ +static struct yaffs_search_context *yaffs_new_search(struct yaffs_obj *dir) +{ + struct yaffs_dev *dev = dir->my_dev; + struct yaffs_search_context *sc = + kmalloc(sizeof(struct yaffs_search_context), GFP_NOFS); + if (sc) { + sc->dir_obj = dir; + sc->dev = dev; + if (list_empty(&sc->dir_obj->variant.dir_variant.children)) + sc->next_return = NULL; + else + sc->next_return = + list_entry(dir->variant.dir_variant.children.next, + struct yaffs_obj, siblings); + INIT_LIST_HEAD(&sc->others); + list_add(&sc->others, &(yaffs_dev_to_lc(dev)->search_contexts)); + } + return sc; +} + +/* + * yaffs_search_end() disposes of a search context and cleans up. + */ +static void yaffs_search_end(struct yaffs_search_context *sc) +{ + if (sc) { + list_del(&sc->others); + kfree(sc); + } +} + +/* + * yaffs_search_advance() moves a search context to the next object. + * Called when the search iterates or when an object removal causes + * the search context to be moved to the next object. + */ +static void yaffs_search_advance(struct yaffs_search_context *sc) +{ + if (!sc) + return; + + if (sc->next_return == NULL || + list_empty(&sc->dir_obj->variant.dir_variant.children)) + sc->next_return = NULL; + else { + struct list_head *next = sc->next_return->siblings.next; + + if (next == &sc->dir_obj->variant.dir_variant.children) + sc->next_return = NULL; /* end of list */ + else + sc->next_return = + list_entry(next, struct yaffs_obj, siblings); + } +} + +/* + * yaffs_remove_obj_callback() is called when an object is unlinked. + * We check open search contexts and advance any which are currently + * on the object being iterated. + */ +static void yaffs_remove_obj_callback(struct yaffs_obj *obj) +{ + + struct list_head *i; + struct yaffs_search_context *sc; + struct list_head *search_contexts = + &(yaffs_dev_to_lc(obj->my_dev)->search_contexts); + + /* Iterate through the directory search contexts. + * If any are currently on the object being removed, then advance + * the search context to the next object to prevent a hanging pointer. + */ + list_for_each(i, search_contexts) { + sc = list_entry(i, struct yaffs_search_context, others); + if (sc->next_return == obj) + yaffs_search_advance(sc); + } + +} + + +/*-----------------------------------------------------------------*/ + +#ifdef YAFFS_USE_DIR_ITERATE +static int yaffs_iterate(struct file *f, struct dir_context *dc) +{ + struct yaffs_obj *obj; + struct yaffs_dev *dev; + struct yaffs_search_context *sc; + unsigned long curoffs; + struct yaffs_obj *l; + int ret_val = 0; + + char name[YAFFS_MAX_NAME_LENGTH + 1]; + + obj = yaffs_dentry_to_obj(f->f_dentry); + dev = obj->my_dev; + + yaffs_gross_lock(dev); + + yaffs_dev_to_lc(dev)->readdir_process = current; + + sc = yaffs_new_search(obj); + if (!sc) { + ret_val = -ENOMEM; + goto out; + } + + if (!dir_emit_dots(f, dc)) + return 0; + + curoffs = 1; + + while (sc->next_return) { + curoffs++; + l = sc->next_return; + if (curoffs >= dc->pos) { + int this_inode = yaffs_get_obj_inode(l); + int this_type = yaffs_get_obj_type(l); + + yaffs_get_obj_name(l, name, YAFFS_MAX_NAME_LENGTH + 1); + yaffs_trace(YAFFS_TRACE_OS, + "yaffs_readdir: %s inode %d", + name, yaffs_get_obj_inode(l)); + + yaffs_gross_unlock(dev); + + if (!dir_emit(dc, + name, + strlen(name), + this_inode, + this_type)) { + yaffs_gross_lock(dev); + goto out; + } + + yaffs_gross_lock(dev); + + dc->pos++; + f->f_pos++; + } + yaffs_search_advance(sc); + } + +out: + yaffs_search_end(sc); + yaffs_dev_to_lc(dev)->readdir_process = NULL; + yaffs_gross_unlock(dev); + + return ret_val; +} + +#else + +static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir) +{ + struct yaffs_obj *obj; + struct yaffs_dev *dev; + struct yaffs_search_context *sc; + struct inode *inode = f->f_dentry->d_inode; + unsigned long offset, curoffs; + struct yaffs_obj *l; + int ret_val = 0; + + char name[YAFFS_MAX_NAME_LENGTH + 1]; + + obj = yaffs_dentry_to_obj(f->f_dentry); + dev = obj->my_dev; + + yaffs_gross_lock(dev); + + yaffs_dev_to_lc(dev)->readdir_process = current; + + offset = f->f_pos; + + sc = yaffs_new_search(obj); + if (!sc) { + ret_val = -ENOMEM; + goto out; + } + + yaffs_trace(YAFFS_TRACE_OS, + "yaffs_readdir: starting at %d", (int)offset); + + if (offset == 0) { + yaffs_trace(YAFFS_TRACE_OS, + "yaffs_readdir: entry . ino %d", + (int)inode->i_ino); + yaffs_gross_unlock(dev); + if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR) < 0) { + yaffs_gross_lock(dev); + goto out; + } + yaffs_gross_lock(dev); + offset++; + f->f_pos++; + } + if (offset == 1) { + yaffs_trace(YAFFS_TRACE_OS, + "yaffs_readdir: entry .. ino %d", + (int)f->f_dentry->d_parent->d_inode->i_ino); + yaffs_gross_unlock(dev); + if (filldir(dirent, "..", 2, offset, + f->f_dentry->d_parent->d_inode->i_ino, + DT_DIR) < 0) { + yaffs_gross_lock(dev); + goto out; + } + yaffs_gross_lock(dev); + offset++; + f->f_pos++; + } + + curoffs = 1; + + /* If the directory has changed since the open or last call to + readdir, rewind to after the 2 canned entries. */ + if (f->f_version != inode->i_version) { + offset = 2; + f->f_pos = offset; + f->f_version = inode->i_version; + } + + while (sc->next_return) { + curoffs++; + l = sc->next_return; + if (curoffs >= offset) { + int this_inode = yaffs_get_obj_inode(l); + int this_type = yaffs_get_obj_type(l); + + yaffs_get_obj_name(l, name, YAFFS_MAX_NAME_LENGTH + 1); + yaffs_trace(YAFFS_TRACE_OS, + "yaffs_readdir: %s inode %d", + name, yaffs_get_obj_inode(l)); + + yaffs_gross_unlock(dev); + + if (filldir(dirent, + name, + strlen(name), + offset, this_inode, this_type) < 0) { + yaffs_gross_lock(dev); + goto out; + } + + yaffs_gross_lock(dev); + + offset++; + f->f_pos++; + } + yaffs_search_advance(sc); + } + +out: + yaffs_search_end(sc); + yaffs_dev_to_lc(dev)->readdir_process = NULL; + yaffs_gross_unlock(dev); + + return ret_val; +} + +#endif + +static const struct file_operations yaffs_dir_operations = { + .read = generic_read_dir, +#ifdef YAFFS_USE_DIR_ITERATE + .iterate = yaffs_iterate, +#else + .readdir = yaffs_readdir, +#endif + .fsync = yaffs_sync_object, + .llseek = generic_file_llseek, +}; + +static void yaffs_fill_inode_from_obj(struct inode *inode, + struct yaffs_obj *obj) +{ + if (inode && obj) { + + /* Check mode against the variant type and attempt to repair if broken. */ + u32 mode = obj->yst_mode; + switch (obj->variant_type) { + case YAFFS_OBJECT_TYPE_FILE: + if (!S_ISREG(mode)) { + obj->yst_mode &= ~S_IFMT; + obj->yst_mode |= S_IFREG; + } + + break; + case YAFFS_OBJECT_TYPE_SYMLINK: + if (!S_ISLNK(mode)) { + obj->yst_mode &= ~S_IFMT; + obj->yst_mode |= S_IFLNK; + } + + break; + case YAFFS_OBJECT_TYPE_DIRECTORY: + if (!S_ISDIR(mode)) { + obj->yst_mode &= ~S_IFMT; + obj->yst_mode |= S_IFDIR; + } + + break; + case YAFFS_OBJECT_TYPE_UNKNOWN: + case YAFFS_OBJECT_TYPE_HARDLINK: + case YAFFS_OBJECT_TYPE_SPECIAL: + default: + /* TODO? */ + break; + } + + inode->i_flags |= S_NOATIME; + + inode->i_ino = obj->obj_id; + inode->i_mode = obj->yst_mode; + inode->i_uid = MAKE_uid(obj->yst_uid); + inode->i_gid = MAKE_gid(obj->yst_gid); +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)) + inode->i_blksize = inode->i_sb->s_blocksize; +#endif +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) + + inode->i_rdev = old_decode_dev(obj->yst_rdev); + inode->i_atime.tv_sec = (time_t) (obj->yst_atime); + inode->i_atime.tv_nsec = 0; + inode->i_mtime.tv_sec = (time_t) obj->yst_mtime; + inode->i_mtime.tv_nsec = 0; + inode->i_ctime.tv_sec = (time_t) obj->yst_ctime; + inode->i_ctime.tv_nsec = 0; +#else + inode->i_rdev = obj->yst_rdev; + inode->i_atime = obj->yst_atime; + inode->i_mtime = obj->yst_mtime; + inode->i_ctime = obj->yst_ctime; +#endif + inode->i_size = yaffs_get_obj_length(obj); + inode->i_blocks = (inode->i_size + 511) >> 9; + + set_nlink(inode, yaffs_get_obj_link_count(obj)); + + yaffs_trace(YAFFS_TRACE_OS, + "yaffs_fill_inode mode %x uid %d gid %d size %lld count %d", + inode->i_mode, obj->yst_uid, obj->yst_gid, + inode->i_size, atomic_read(&inode->i_count)); + + switch (obj->yst_mode & S_IFMT) { + default: /* fifo, device or socket */ +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) + init_special_inode(inode, obj->yst_mode, + old_decode_dev(obj->yst_rdev)); +#else + init_special_inode(inode, obj->yst_mode, + (dev_t) (obj->yst_rdev)); +#endif + break; + case S_IFREG: /* file */ + inode->i_op = &yaffs_file_inode_operations; + inode->i_fop = &yaffs_file_operations; + inode->i_mapping->a_ops = + &yaffs_file_address_operations; + break; + case S_IFDIR: /* directory */ + inode->i_op = &yaffs_dir_inode_operations; + inode->i_fop = &yaffs_dir_operations; + break; + case S_IFLNK: /* symlink */ + inode->i_op = &yaffs_symlink_inode_operations; + break; + } + + yaffs_inode_to_obj_lv(inode) = obj; + + obj->my_inode = inode; + + } else { + yaffs_trace(YAFFS_TRACE_OS, + "yaffs_fill_inode invalid parameters"); + } + +} + + + +/* + * yaffs background thread functions . + * yaffs_bg_thread_fn() the thread function + * yaffs_bg_start() launches the background thread. + * yaffs_bg_stop() cleans up the background thread. + * + * NB: + * The thread should only run after the yaffs is initialised + * The thread should be stopped before yaffs is unmounted. + * The thread should not do any writing while the fs is in read only. + */ + +static unsigned yaffs_bg_gc_urgency(struct yaffs_dev *dev) +{ + unsigned erased_chunks = + dev->n_erased_blocks * dev->param.chunks_per_block; + struct yaffs_linux_context *context = yaffs_dev_to_lc(dev); + unsigned scattered = 0; /* Free chunks not in an erased block */ + + if (erased_chunks < dev->n_free_chunks) + scattered = (dev->n_free_chunks - erased_chunks); + + if (!context->bg_running) + return 0; + else if (scattered < (dev->param.chunks_per_block * 2)) + return 0; + else if (erased_chunks > dev->n_free_chunks / 2) + return 0; + else if (erased_chunks > dev->n_free_chunks / 4) + return 1; + else + return 2; +} + +#ifdef YAFFS_COMPILE_BACKGROUND + +void yaffs_background_waker(unsigned long data) +{ + wake_up_process((struct task_struct *)data); +} + +static int yaffs_bg_thread_fn(void *data) +{ + struct yaffs_dev *dev = (struct yaffs_dev *)data; + struct yaffs_linux_context *context = yaffs_dev_to_lc(dev); + unsigned long now = jiffies; + unsigned long next_dir_update = now; + unsigned long next_gc = now; + unsigned long expires; + unsigned int urgency; + + int gc_result; + struct timer_list timer; + + yaffs_trace(YAFFS_TRACE_BACKGROUND, + "yaffs_background starting for dev %p", (void *)dev); + +#ifdef YAFFS_COMPILE_FREEZER + set_freezable(); +#endif + while (context->bg_running) { + yaffs_trace(YAFFS_TRACE_BACKGROUND, "yaffs_background"); + + if (kthread_should_stop()) + break; + +#ifdef YAFFS_COMPILE_FREEZER + if (try_to_freeze()) + continue; +#endif + yaffs_gross_lock(dev); + + now = jiffies; + + if (time_after(now, next_dir_update) && yaffs_bg_enable) { + yaffs_update_dirty_dirs(dev); + next_dir_update = now + HZ; + } + + if (time_after(now, next_gc) && yaffs_bg_enable) { + if (!dev->is_checkpointed) { + urgency = yaffs_bg_gc_urgency(dev); + gc_result = yaffs_bg_gc(dev, urgency); + if (urgency > 1) + next_gc = now + HZ / 20 + 1; + else if (urgency > 0) + next_gc = now + HZ / 10 + 1; + else + next_gc = now + HZ * 2; + } else { + /* + * gc not running so set to next_dir_update + * to cut down on wake ups + */ + next_gc = next_dir_update; + } + } + yaffs_gross_unlock(dev); +#if 1 + expires = next_dir_update; + if (time_before(next_gc, expires)) + expires = next_gc; + if (time_before(expires, now)) + expires = now + HZ; + + Y_INIT_TIMER(&timer); + timer.expires = expires + 1; + timer.data = (unsigned long)current; + timer.function = yaffs_background_waker; + + set_current_state(TASK_INTERRUPTIBLE); + add_timer(&timer); + schedule(); + del_timer_sync(&timer); +#else + msleep(10); +#endif + } + + return 0; +} + +static int yaffs_bg_start(struct yaffs_dev *dev) +{ + int retval = 0; + struct yaffs_linux_context *context = yaffs_dev_to_lc(dev); + + if (dev->read_only) + return -1; + + context->bg_running = 1; + + context->bg_thread = kthread_run(yaffs_bg_thread_fn, + (void *)dev, "yaffs-bg-%d", + context->mount_id); + + if (IS_ERR(context->bg_thread)) { + retval = PTR_ERR(context->bg_thread); + context->bg_thread = NULL; + context->bg_running = 0; + } + return retval; +} + +static void yaffs_bg_stop(struct yaffs_dev *dev) +{ + struct yaffs_linux_context *ctxt = yaffs_dev_to_lc(dev); + + ctxt->bg_running = 0; + + if (ctxt->bg_thread) { + kthread_stop(ctxt->bg_thread); + ctxt->bg_thread = NULL; + } +} +#else +static int yaffs_bg_thread_fn(void *data) +{ + return 0; +} + +static int yaffs_bg_start(struct yaffs_dev *dev) +{ + return 0; +} + +static void yaffs_bg_stop(struct yaffs_dev *dev) +{ +} +#endif + + +static void yaffs_flush_inodes(struct super_block *sb) +{ + struct inode *iptr; + struct yaffs_obj *obj; + + list_for_each_entry(iptr, &sb->s_inodes, i_sb_list) { + obj = yaffs_inode_to_obj(iptr); + if (obj) { + yaffs_trace(YAFFS_TRACE_OS, + "flushing obj %d", + obj->obj_id); + yaffs_flush_file(obj, 1, 0, 0); + } + } +} + +static void yaffs_flush_super(struct super_block *sb, int do_checkpoint) +{ + struct yaffs_dev *dev = yaffs_super_to_dev(sb); + if (!dev) + return; + + yaffs_flush_inodes(sb); + yaffs_update_dirty_dirs(dev); + yaffs_flush_whole_cache(dev, 1); + if (do_checkpoint) + yaffs_checkpoint_save(dev); +} + +static LIST_HEAD(yaffs_context_list); +struct mutex yaffs_context_lock; + +static void yaffs_put_super(struct super_block *sb) +{ + struct yaffs_dev *dev = yaffs_super_to_dev(sb); + struct mtd_info *mtd = yaffs_dev_to_mtd(dev); + + yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_ALWAYS, + "yaffs_put_super"); + + yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND, + "Shutting down yaffs background thread"); + yaffs_bg_stop(dev); + yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND, + "yaffs background thread shut down"); + + yaffs_gross_lock(dev); + + yaffs_flush_super(sb, 1); + + yaffs_deinitialise(dev); + + yaffs_gross_unlock(dev); + + mutex_lock(&yaffs_context_lock); + list_del_init(&(yaffs_dev_to_lc(dev)->context_list)); + mutex_unlock(&yaffs_context_lock); + + if (yaffs_dev_to_lc(dev)->spare_buffer) { + kfree(yaffs_dev_to_lc(dev)->spare_buffer); + yaffs_dev_to_lc(dev)->spare_buffer = NULL; + } + + kfree(dev); + + yaffs_put_mtd_device(mtd); + + yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_ALWAYS, + "yaffs_put_super done"); +} + + +static unsigned yaffs_gc_control_callback(struct yaffs_dev *dev) +{ + return yaffs_gc_control; +} + + +#ifdef YAFFS_COMPILE_EXPORTFS + +static struct inode *yaffs2_nfs_get_inode(struct super_block *sb, uint64_t ino, + uint32_t generation) +{ + return Y_IGET(sb, ino); +} + +static struct dentry *yaffs2_fh_to_dentry(struct super_block *sb, + struct fid *fid, int fh_len, + int fh_type) +{ + return generic_fh_to_dentry(sb, fid, fh_len, fh_type, + yaffs2_nfs_get_inode); +} + +static struct dentry *yaffs2_fh_to_parent(struct super_block *sb, + struct fid *fid, int fh_len, + int fh_type) +{ + return generic_fh_to_parent(sb, fid, fh_len, fh_type, + yaffs2_nfs_get_inode); +} + +struct dentry *yaffs2_get_parent(struct dentry *dentry) +{ + + struct super_block *sb = dentry->d_inode->i_sb; + struct dentry *parent = ERR_PTR(-ENOENT); + struct inode *inode; + unsigned long parent_ino; + struct yaffs_obj *d_obj; + struct yaffs_obj *parent_obj; + + d_obj = yaffs_inode_to_obj(dentry->d_inode); + + if (d_obj) { + parent_obj = d_obj->parent; + if (parent_obj) { + parent_ino = yaffs_get_obj_inode(parent_obj); + inode = Y_IGET(sb, parent_ino); + + if (IS_ERR(inode)) { + parent = ERR_CAST(inode); + } else { + parent = d_obtain_alias(inode); + if (!IS_ERR(parent)) { + parent = ERR_PTR(-ENOMEM); + iput(inode); + } + } + } + } + + return parent; +} + +/* Just declare a zero structure as a NULL value implies + * using the default functions of exportfs. + */ + +static struct export_operations yaffs_export_ops = { + .fh_to_dentry = yaffs2_fh_to_dentry, + .fh_to_parent = yaffs2_fh_to_parent, + .get_parent = yaffs2_get_parent, +}; + +#endif + +static void yaffs_unstitch_obj(struct inode *inode, struct yaffs_obj *obj) +{ + /* Clear the association between the inode and + * the struct yaffs_obj. + */ + obj->my_inode = NULL; + yaffs_inode_to_obj_lv(inode) = NULL; + + /* If the object freeing was deferred, then the real + * free happens now. + * This should fix the inode inconsistency problem. + */ + yaffs_handle_defered_free(obj); +} + +#ifdef YAFFS_HAS_EVICT_INODE +/* yaffs_evict_inode combines into one operation what was previously done in + * yaffs_clear_inode() and yaffs_delete_inode() + * + */ +static void yaffs_evict_inode(struct inode *inode) +{ + struct yaffs_obj *obj; + struct yaffs_dev *dev; + int deleteme = 0; + + obj = yaffs_inode_to_obj(inode); + + yaffs_trace(YAFFS_TRACE_OS, + "yaffs_evict_inode: ino %d, count %d %s", + (int)inode->i_ino, atomic_read(&inode->i_count), + obj ? "object exists" : "null object"); + + if (!inode->i_nlink && !is_bad_inode(inode)) + deleteme = 1; + truncate_inode_pages(&inode->i_data, 0); + Y_CLEAR_INODE(inode); + + if (deleteme && obj) { + dev = obj->my_dev; + yaffs_gross_lock(dev); + yaffs_del_obj(obj); + yaffs_gross_unlock(dev); + } + if (obj) { + dev = obj->my_dev; + yaffs_gross_lock(dev); + yaffs_unstitch_obj(inode, obj); + yaffs_gross_unlock(dev); + } +} +#else + +/* clear is called to tell the fs to release any per-inode data it holds. + * The object might still exist on disk and is just being thrown out of the cache + * or else the object has actually been deleted and we're being called via + * the chain + * yaffs_delete_inode() -> clear_inode()->yaffs_clear_inode() + */ + +static void yaffs_clear_inode(struct inode *inode) +{ + struct yaffs_obj *obj; + struct yaffs_dev *dev; + + obj = yaffs_inode_to_obj(inode); + + yaffs_trace(YAFFS_TRACE_OS, + "yaffs_clear_inode: ino %d, count %d %s", + (int)inode->i_ino, atomic_read(&inode->i_count), + obj ? "object exists" : "null object"); + + if (obj) { + dev = obj->my_dev; + yaffs_gross_lock(dev); + yaffs_unstitch_obj(inode, obj); + yaffs_gross_unlock(dev); + } + +} + +/* delete is called when the link count is zero and the inode + * is put (ie. nobody wants to know about it anymore, time to + * delete the file). + * NB Must call clear_inode() + */ +static void yaffs_delete_inode(struct inode *inode) +{ + struct yaffs_obj *obj = yaffs_inode_to_obj(inode); + struct yaffs_dev *dev; + + yaffs_trace(YAFFS_TRACE_OS, + "yaffs_delete_inode: ino %d, count %d %s", + (int)inode->i_ino, atomic_read(&inode->i_count), + obj ? "object exists" : "null object"); + + if (obj) { + dev = obj->my_dev; + yaffs_gross_lock(dev); + yaffs_del_obj(obj); + yaffs_gross_unlock(dev); + } +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)) + truncate_inode_pages(&inode->i_data, 0); +#endif + clear_inode(inode); +} +#endif + + + + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) +static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf) +{ + struct yaffs_dev *dev = yaffs_dentry_to_obj(dentry)->my_dev; + struct super_block *sb = dentry->d_sb; +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) +static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf) +{ + struct yaffs_dev *dev = yaffs_super_to_dev(sb); +#else +static int yaffs_statfs(struct super_block *sb, struct statfs *buf) +{ + struct yaffs_dev *dev = yaffs_super_to_dev(sb); +#endif + + yaffs_trace(YAFFS_TRACE_OS, "yaffs_statfs"); + + yaffs_gross_lock(dev); + + buf->f_type = YAFFS_MAGIC; + buf->f_bsize = sb->s_blocksize; + buf->f_namelen = 255; + + if (dev->data_bytes_per_chunk & (dev->data_bytes_per_chunk - 1)) { + /* Do this if chunk size is not a power of 2 */ + + uint64_t bytes_in_dev; + uint64_t bytes_free; + + bytes_in_dev = + ((uint64_t) + ((dev->param.end_block - dev->param.start_block + + 1))) * ((uint64_t) (dev->param.chunks_per_block * + dev->data_bytes_per_chunk)); + + do_div(bytes_in_dev, sb->s_blocksize); /* bytes_in_dev becomes the number of blocks */ + buf->f_blocks = bytes_in_dev; + + bytes_free = ((uint64_t) (yaffs_get_n_free_chunks(dev))) * + ((uint64_t) (dev->data_bytes_per_chunk)); + + do_div(bytes_free, sb->s_blocksize); + + buf->f_bfree = bytes_free; + + } else if (sb->s_blocksize > dev->data_bytes_per_chunk) { + + buf->f_blocks = + (dev->param.end_block - dev->param.start_block + 1) * + dev->param.chunks_per_block / + (sb->s_blocksize / dev->data_bytes_per_chunk); + buf->f_bfree = + yaffs_get_n_free_chunks(dev) / + (sb->s_blocksize / dev->data_bytes_per_chunk); + } else { + buf->f_blocks = + (dev->param.end_block - dev->param.start_block + 1) * + dev->param.chunks_per_block * + (dev->data_bytes_per_chunk / sb->s_blocksize); + + buf->f_bfree = + yaffs_get_n_free_chunks(dev) * + (dev->data_bytes_per_chunk / sb->s_blocksize); + } + + buf->f_files = 0; + buf->f_ffree = 0; + buf->f_bavail = buf->f_bfree; + + yaffs_gross_unlock(dev); + return 0; +} + + + +static int yaffs_do_sync_fs(struct super_block *sb, int request_checkpoint) +{ + + struct yaffs_dev *dev = yaffs_super_to_dev(sb); + unsigned int oneshot_checkpoint = (yaffs_auto_checkpoint & 4); + unsigned gc_urgent = yaffs_bg_gc_urgency(dev); + int do_checkpoint; + int dirty = yaffs_check_super_dirty(dev); + + yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND, + "yaffs_do_sync_fs: gc-urgency %d %s %s%s", + gc_urgent, + dirty ? "dirty" : "clean", + request_checkpoint ? "checkpoint requested" : "no checkpoint", + oneshot_checkpoint ? " one-shot" : ""); + + yaffs_gross_lock(dev); + do_checkpoint = ((request_checkpoint && !gc_urgent) || + oneshot_checkpoint) && !dev->is_checkpointed; + + if (dirty || do_checkpoint) { + yaffs_flush_super(sb, !dev->is_checkpointed && do_checkpoint); + yaffs_clear_super_dirty(dev); + if (oneshot_checkpoint) + yaffs_auto_checkpoint &= ~4; + } + yaffs_gross_unlock(dev); + + return 0; +} + + +#ifdef YAFFS_HAS_WRITE_SUPER +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) +static void yaffs_write_super(struct super_block *sb) +#else +static int yaffs_write_super(struct super_block *sb) +#endif +{ + unsigned request_checkpoint = (yaffs_auto_checkpoint >= 2); + + yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND, + "yaffs_write_super %s", + request_checkpoint ? " checkpt" : ""); + + yaffs_do_sync_fs(sb, request_checkpoint); + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18)) + return 0; +#endif +} +#endif + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) +static int yaffs_sync_fs(struct super_block *sb, int wait) +#else +static int yaffs_sync_fs(struct super_block *sb) +#endif +{ + unsigned request_checkpoint = (yaffs_auto_checkpoint >= 1); + + yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC, + "yaffs_sync_fs%s", request_checkpoint ? " checkpt" : ""); + + yaffs_do_sync_fs(sb, request_checkpoint); + + return 0; +} + +/* the function only is used to change dev->read_only when this file system + * is remounted. + */ +static int yaffs_remount_fs(struct super_block *sb, int *flags, char *data) +{ + int read_only = 0; + struct mtd_info *mtd; + struct yaffs_dev *dev = 0; + + /* Get the device */ + mtd = get_mtd_device(NULL, MINOR(sb->s_dev)); + if (!mtd) { + yaffs_trace(YAFFS_TRACE_ALWAYS, + "MTD device #%u doesn't appear to exist", + MINOR(sb->s_dev)); + return 1; + } + + /* Check it's NAND */ + if (mtd->type != MTD_NANDFLASH) { + yaffs_trace(YAFFS_TRACE_ALWAYS, + "MTD device is not NAND it's type %d", + mtd->type); + return 1; + } + + read_only = ((*flags & MS_RDONLY) != 0); + if (!read_only && !(mtd->flags & MTD_WRITEABLE)) { + read_only = 1; + printk(KERN_INFO + "yaffs: mtd is read only, setting superblock read only"); + *flags |= MS_RDONLY; + } + + dev = sb->s_fs_info; + dev->read_only = read_only; + + return 0; +} + +static const struct super_operations yaffs_super_ops = { + .statfs = yaffs_statfs, + +#ifndef YAFFS_USE_OWN_IGET + .read_inode = yaffs_read_inode, +#endif +#ifdef YAFFS_HAS_PUT_INODE + .put_inode = yaffs_put_inode, +#endif + .put_super = yaffs_put_super, +#ifdef YAFFS_HAS_EVICT_INODE + .evict_inode = yaffs_evict_inode, +#else + .delete_inode = yaffs_delete_inode, + .clear_inode = yaffs_clear_inode, +#endif + .sync_fs = yaffs_sync_fs, +#ifdef YAFFS_HAS_WRITE_SUPER + .write_super = yaffs_write_super, +#endif + .remount_fs = yaffs_remount_fs, +}; + +struct yaffs_options { + int inband_tags; + int skip_checkpoint_read; + int skip_checkpoint_write; + int no_cache; + int tags_ecc_on; + int tags_ecc_overridden; + int lazy_loading_enabled; + int lazy_loading_overridden; + int empty_lost_and_found; + int empty_lost_and_found_overridden; + int disable_summary; +}; + +#define MAX_OPT_LEN 30 +static int yaffs_parse_options(struct yaffs_options *options, + const char *options_str) +{ + char cur_opt[MAX_OPT_LEN + 1]; + int p; + int error = 0; + + /* Parse through the options which is a comma seperated list */ + + while (options_str && *options_str && !error) { + memset(cur_opt, 0, MAX_OPT_LEN + 1); + p = 0; + + while (*options_str == ',') + options_str++; + + while (*options_str && *options_str != ',') { + if (p < MAX_OPT_LEN) { + cur_opt[p] = *options_str; + p++; + } + options_str++; + } + + if (!strcmp(cur_opt, "inband-tags")) { + options->inband_tags = 1; + } else if (!strcmp(cur_opt, "tags-ecc-off")) { + options->tags_ecc_on = 0; + options->tags_ecc_overridden = 1; + } else if (!strcmp(cur_opt, "tags-ecc-on")) { + options->tags_ecc_on = 1; + options->tags_ecc_overridden = 1; + } else if (!strcmp(cur_opt, "lazy-loading-off")) { + options->lazy_loading_enabled = 0; + options->lazy_loading_overridden = 1; + } else if (!strcmp(cur_opt, "lazy-loading-on")) { + options->lazy_loading_enabled = 1; + options->lazy_loading_overridden = 1; + } else if (!strcmp(cur_opt, "disable-summary")) { + options->disable_summary = 1; + } else if (!strcmp(cur_opt, "empty-lost-and-found-off")) { + options->empty_lost_and_found = 0; + options->empty_lost_and_found_overridden = 1; + } else if (!strcmp(cur_opt, "empty-lost-and-found-on")) { + options->empty_lost_and_found = 1; + options->empty_lost_and_found_overridden = 1; + } else if (!strcmp(cur_opt, "no-cache")) { + options->no_cache = 1; + } else if (!strcmp(cur_opt, "no-checkpoint-read")) { + options->skip_checkpoint_read = 1; + } else if (!strcmp(cur_opt, "no-checkpoint-write")) { + options->skip_checkpoint_write = 1; + } else if (!strcmp(cur_opt, "no-checkpoint")) { + options->skip_checkpoint_read = 1; + options->skip_checkpoint_write = 1; + } else { + printk(KERN_INFO "yaffs: Bad mount option \"%s\"\n", + cur_opt); + error = 1; + } + } + + return error; +} + + +static struct dentry *yaffs_make_root(struct inode *inode) +{ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)) + struct dentry *root = d_alloc_root(inode); + + if (!root) + iput(inode); + + return root; +#else + return d_make_root(inode); +#endif +} + + + + +static struct super_block *yaffs_internal_read_super(int yaffs_version, + struct super_block *sb, + void *data, int silent) +{ + int n_blocks; + struct inode *inode = NULL; + struct dentry *root; + struct yaffs_dev *dev = 0; + char devname_buf[BDEVNAME_SIZE + 1]; + struct mtd_info *mtd; + int err; + char *data_str = (char *)data; + struct yaffs_linux_context *context = NULL; + struct yaffs_param *param; + + int read_only = 0; + int inband_tags = 0; + + struct yaffs_options options; + + unsigned mount_id; + int found; + struct yaffs_linux_context *context_iterator; + struct list_head *l; + + if (!sb) { + printk(KERN_INFO "yaffs: sb is NULL\n"); + return NULL; + } + + sb->s_magic = YAFFS_MAGIC; + sb->s_op = &yaffs_super_ops; + sb->s_flags |= MS_NOATIME; + + read_only = ((sb->s_flags & MS_RDONLY) != 0); + +#ifdef YAFFS_COMPILE_EXPORTFS + sb->s_export_op = &yaffs_export_ops; +#endif + + if (!sb->s_dev) + printk(KERN_INFO "yaffs: sb->s_dev is NULL\n"); + else if (!yaffs_devname(sb, devname_buf)) + printk(KERN_INFO "yaffs: devname is NULL\n"); + else + printk(KERN_INFO "yaffs: dev is %d name is \"%s\" %s\n", + sb->s_dev, + yaffs_devname(sb, devname_buf), read_only ? "ro" : "rw"); + + if (!data_str) + data_str = ""; + + printk(KERN_INFO "yaffs: passed flags \"%s\"\n", data_str); + + memset(&options, 0, sizeof(options)); + + if (yaffs_parse_options(&options, data_str)) { + /* Option parsing failed */ + return NULL; + } + + sb->s_blocksize = PAGE_CACHE_SIZE; + sb->s_blocksize_bits = PAGE_CACHE_SHIFT; + + yaffs_trace(YAFFS_TRACE_OS, + "yaffs_read_super: Using yaffs%d", yaffs_version); + yaffs_trace(YAFFS_TRACE_OS, + "yaffs_read_super: block size %d", (int)(sb->s_blocksize)); + + yaffs_trace(YAFFS_TRACE_ALWAYS, + "yaffs: Attempting MTD mount of %u.%u,\"%s\"", + MAJOR(sb->s_dev), MINOR(sb->s_dev), + yaffs_devname(sb, devname_buf)); + + /* Get the device */ + mtd = get_mtd_device(NULL, MINOR(sb->s_dev)); + if (IS_ERR(mtd)) { + yaffs_trace(YAFFS_TRACE_ALWAYS, + "yaffs: MTD device %u either not valid or unavailable", + MINOR(sb->s_dev)); + return NULL; + } + + if (yaffs_auto_select && yaffs_version == 1 && WRITE_SIZE(mtd) >= 2048) { + yaffs_trace(YAFFS_TRACE_ALWAYS, "auto selecting yaffs2"); + yaffs_version = 2; + } + + /* Added NCB 26/5/2006 for completeness */ + if (yaffs_version == 2 && !options.inband_tags + && WRITE_SIZE(mtd) == 512) { + yaffs_trace(YAFFS_TRACE_ALWAYS, "auto selecting yaffs1"); + yaffs_version = 1; + } + + if (mtd->oobavail < sizeof(struct yaffs_packed_tags2) || + options.inband_tags) + inband_tags = 1; + + if(yaffs_verify_mtd(mtd, yaffs_version, inband_tags) < 0) + return NULL; + + /* OK, so if we got here, we have an MTD that's NAND and looks + * like it has the right capabilities + * Set the struct yaffs_dev up for mtd + */ + + if (!read_only && !(mtd->flags & MTD_WRITEABLE)) { + read_only = 1; + printk(KERN_INFO + "yaffs: mtd is read only, setting superblock read only\n" + ); + sb->s_flags |= MS_RDONLY; + } + + dev = kmalloc(sizeof(struct yaffs_dev), GFP_KERNEL); + context = kmalloc(sizeof(struct yaffs_linux_context), GFP_KERNEL); + + if (!dev || !context) { + kfree(dev); + kfree(context); + dev = NULL; + context = NULL; + + /* Deep shit could not allocate device structure */ + yaffs_trace(YAFFS_TRACE_ALWAYS, + "yaffs_read_super: Failed trying to allocate struct yaffs_dev." + ); + return NULL; + } + memset(dev, 0, sizeof(struct yaffs_dev)); + param = &(dev->param); + + memset(context, 0, sizeof(struct yaffs_linux_context)); + dev->os_context = context; + INIT_LIST_HEAD(&(context->context_list)); + context->dev = dev; + context->super = sb; + + dev->read_only = read_only; + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) + sb->s_fs_info = dev; +#else + sb->u.generic_sbp = dev; +#endif + + + dev->driver_context = mtd; + param->name = mtd->name; + + /* Set up the memory size parameters.... */ + + + param->n_reserved_blocks = 5; + param->n_caches = (options.no_cache) ? 0 : 10; + param->inband_tags = inband_tags; + + param->enable_xattr = 1; + if (options.lazy_loading_overridden) + param->disable_lazy_load = !options.lazy_loading_enabled; + + param->defered_dir_update = 1; + + if (options.tags_ecc_overridden) + param->no_tags_ecc = !options.tags_ecc_on; + + param->empty_lost_n_found = 1; + param->refresh_period = 500; + param->disable_summary = options.disable_summary; + + +#ifdef CONFIG_YAFFS_DISABLE_BAD_BLOCK_MARKING + param->disable_bad_block_marking = 1; +#endif + if (options.empty_lost_and_found_overridden) + param->empty_lost_n_found = options.empty_lost_and_found; + + /* ... and the functions. */ + if (yaffs_version == 2) { + param->is_yaffs2 = 1; +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) + param->total_bytes_per_chunk = mtd->writesize; + param->chunks_per_block = mtd->erasesize / mtd->writesize; +#else + param->total_bytes_per_chunk = mtd->oobblock; + param->chunks_per_block = mtd->erasesize / mtd->oobblock; +#endif + n_blocks = YCALCBLOCKS(mtd->size, mtd->erasesize); + + param->start_block = 0; + param->end_block = n_blocks - 1; + } else { + param->is_yaffs2 = 0; + n_blocks = YCALCBLOCKS(mtd->size, + YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK); + + param->chunks_per_block = YAFFS_CHUNKS_PER_BLOCK; + param->total_bytes_per_chunk = YAFFS_BYTES_PER_CHUNK; + } + + param->start_block = 0; + param->end_block = n_blocks - 1; + + yaffs_mtd_drv_install(dev); + + param->sb_dirty_fn = yaffs_set_super_dirty; + param->gc_control_fn = yaffs_gc_control_callback; + + yaffs_dev_to_lc(dev)->super = sb; + + param->use_nand_ecc = 1; + + param->skip_checkpt_rd = options.skip_checkpoint_read; + param->skip_checkpt_wr = options.skip_checkpoint_write; + + mutex_lock(&yaffs_context_lock); + /* Get a mount id */ + found = 0; + for (mount_id = 0; !found; mount_id++) { + found = 1; + list_for_each(l, &yaffs_context_list) { + context_iterator = + list_entry(l, struct yaffs_linux_context, + context_list); + if (context_iterator->mount_id == mount_id) + found = 0; + } + } + context->mount_id = mount_id; + + list_add_tail(&(yaffs_dev_to_lc(dev)->context_list), + &yaffs_context_list); + mutex_unlock(&yaffs_context_lock); + + /* Directory search handling... */ + INIT_LIST_HEAD(&(yaffs_dev_to_lc(dev)->search_contexts)); + param->remove_obj_fn = yaffs_remove_obj_callback; + + mutex_init(&(yaffs_dev_to_lc(dev)->gross_lock)); + + yaffs_gross_lock(dev); + + err = yaffs_guts_initialise(dev); + + yaffs_trace(YAFFS_TRACE_OS, + "yaffs_read_super: guts initialised %s", + (err == YAFFS_OK) ? "OK" : "FAILED"); + + if (err == YAFFS_OK) + yaffs_bg_start(dev); + + if (!context->bg_thread) + param->defered_dir_update = 0; + + sb->s_maxbytes = yaffs_max_file_size(dev); + + /* Release lock before yaffs_get_inode() */ + yaffs_gross_unlock(dev); + + /* Create root inode */ + if (err == YAFFS_OK) + inode = yaffs_get_inode(sb, S_IFDIR | 0755, 0, yaffs_root(dev)); + + if (!inode) + return NULL; + + inode->i_op = &yaffs_dir_inode_operations; + inode->i_fop = &yaffs_dir_operations; + + yaffs_trace(YAFFS_TRACE_OS, "yaffs_read_super: got root inode"); + + root = yaffs_make_root(inode); + + if (!root) + return NULL; + + sb->s_root = root; + if(!dev->is_checkpointed) + yaffs_set_super_dirty(dev); + + yaffs_trace(YAFFS_TRACE_ALWAYS, + "yaffs_read_super: is_checkpointed %d", + dev->is_checkpointed); + + yaffs_trace(YAFFS_TRACE_OS, "yaffs_read_super: done"); + return sb; +} + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) +static int yaffs_internal_read_super_mtd(struct super_block *sb, void *data, + int silent) +{ + return yaffs_internal_read_super(1, sb, data, silent) ? 0 : -EINVAL; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) +static struct dentry *yaffs_mount(struct file_system_type *fs_type, int flags, + const char *dev_name, void *data) +{ + return mount_bdev(fs_type, flags, dev_name, data, yaffs_internal_read_super_mtd); +} +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) +static int yaffs_read_super(struct file_system_type *fs, + int flags, const char *dev_name, + void *data, struct vfsmount *mnt) +{ + + return get_sb_bdev(fs, flags, dev_name, data, + yaffs_internal_read_super_mtd, mnt); +} +#else +static struct super_block *yaffs_read_super(struct file_system_type *fs, + int flags, const char *dev_name, + void *data) +{ + + return get_sb_bdev(fs, flags, dev_name, data, + yaffs_internal_read_super_mtd); +} +#endif + +static struct file_system_type yaffs_fs_type = { + .owner = THIS_MODULE, + .name = "yaffs", +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) + .mount = yaffs_mount, +#else + .get_sb = yaffs_read_super, +#endif + .kill_sb = kill_block_super, + .fs_flags = FS_REQUIRES_DEV, +}; +#else +static struct super_block *yaffs_read_super(struct super_block *sb, void *data, + int silent) +{ + return yaffs_internal_read_super(1, sb, data, silent); +} + +static DECLARE_FSTYPE(yaffs_fs_type, "yaffs", yaffs_read_super, + FS_REQUIRES_DEV); +#endif + + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) +static int yaffs2_internal_read_super_mtd(struct super_block *sb, void *data, + int silent) +{ + return yaffs_internal_read_super(2, sb, data, silent) ? 0 : -EINVAL; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) +static struct dentry *yaffs2_mount(struct file_system_type *fs_type, int flags, + const char *dev_name, void *data) +{ + return mount_bdev(fs_type, flags, dev_name, data, yaffs2_internal_read_super_mtd); +} +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) +static int yaffs2_read_super(struct file_system_type *fs, + int flags, const char *dev_name, void *data, + struct vfsmount *mnt) +{ + return get_sb_bdev(fs, flags, dev_name, data, + yaffs2_internal_read_super_mtd, mnt); +} +#else +static struct super_block *yaffs2_read_super(struct file_system_type *fs, + int flags, const char *dev_name, + void *data) +{ + + return get_sb_bdev(fs, flags, dev_name, data, + yaffs2_internal_read_super_mtd); +} +#endif + +static struct file_system_type yaffs2_fs_type = { + .owner = THIS_MODULE, + .name = "yaffs2", +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) + .mount = yaffs2_mount, +#else + .get_sb = yaffs2_read_super, +#endif + .kill_sb = kill_block_super, + .fs_flags = FS_REQUIRES_DEV, +}; +#else +static struct super_block *yaffs2_read_super(struct super_block *sb, + void *data, int silent) +{ + return yaffs_internal_read_super(2, sb, data, silent); +} + +static DECLARE_FSTYPE(yaffs2_fs_type, "yaffs2", yaffs2_read_super, + FS_REQUIRES_DEV); +#endif + + +static struct proc_dir_entry *my_proc_entry; + +static char *yaffs_dump_dev_part0(char *buf, struct yaffs_dev *dev) +{ + struct yaffs_param *param = &dev->param; + int bs[10]; + + yaffs_count_blocks_by_state(dev,bs); + + buf += sprintf(buf, "start_block.......... %d\n", param->start_block); + buf += sprintf(buf, "end_block............ %d\n", param->end_block); + buf += sprintf(buf, "total_bytes_per_chunk %d\n", + param->total_bytes_per_chunk); + buf += sprintf(buf, "use_nand_ecc......... %d\n", param->use_nand_ecc); + buf += sprintf(buf, "no_tags_ecc.......... %d\n", param->no_tags_ecc); + buf += sprintf(buf, "is_yaffs2............ %d\n", param->is_yaffs2); + buf += sprintf(buf, "inband_tags.......... %d\n", param->inband_tags); + buf += sprintf(buf, "empty_lost_n_found... %d\n", + param->empty_lost_n_found); + buf += sprintf(buf, "disable_lazy_load.... %d\n", + param->disable_lazy_load); + buf += sprintf(buf, "disable_bad_block_mrk %d\n", + param->disable_bad_block_marking); + buf += sprintf(buf, "refresh_period....... %d\n", + param->refresh_period); + buf += sprintf(buf, "n_caches............. %d\n", param->n_caches); + buf += sprintf(buf, "n_reserved_blocks.... %d\n", + param->n_reserved_blocks); + buf += sprintf(buf, "always_check_erased.. %d\n", + param->always_check_erased); + buf += sprintf(buf, "\n"); + buf += sprintf(buf, "block count by state\n"); + buf += sprintf(buf, "0:%d 1:%d 2:%d 3:%d 4:%d\n", + bs[0], bs[1], bs[2], bs[3], bs[4]); + buf += sprintf(buf, "5:%d 6:%d 7:%d 8:%d 9:%d\n", + bs[5], bs[6], bs[7], bs[8], bs[9]); + + return buf; +} + +static char *yaffs_dump_dev_part1(char *buf, struct yaffs_dev *dev) +{ + buf += sprintf(buf, "max file size....... %lld\n", + (long long) yaffs_max_file_size(dev)); + buf += sprintf(buf, "data_bytes_per_chunk. %d\n", + dev->data_bytes_per_chunk); + buf += sprintf(buf, "chunk_grp_bits....... %d\n", dev->chunk_grp_bits); + buf += sprintf(buf, "chunk_grp_size....... %d\n", dev->chunk_grp_size); + buf += sprintf(buf, "n_erased_blocks...... %d\n", dev->n_erased_blocks); + buf += sprintf(buf, "blocks_in_checkpt.... %d\n", + dev->blocks_in_checkpt); + buf += sprintf(buf, "\n"); + buf += sprintf(buf, "n_tnodes............. %d\n", dev->n_tnodes); + buf += sprintf(buf, "n_obj................ %d\n", dev->n_obj); + buf += sprintf(buf, "n_free_chunks........ %d\n", dev->n_free_chunks); + buf += sprintf(buf, "\n"); + buf += sprintf(buf, "n_page_writes........ %u\n", dev->n_page_writes); + buf += sprintf(buf, "n_page_reads......... %u\n", dev->n_page_reads); + buf += sprintf(buf, "n_erasures........... %u\n", dev->n_erasures); + buf += sprintf(buf, "n_gc_copies.......... %u\n", dev->n_gc_copies); + buf += sprintf(buf, "all_gcs.............. %u\n", dev->all_gcs); + buf += sprintf(buf, "passive_gc_count..... %u\n", + dev->passive_gc_count); + buf += sprintf(buf, "oldest_dirty_gc_count %u\n", + dev->oldest_dirty_gc_count); + buf += sprintf(buf, "n_gc_blocks.......... %u\n", dev->n_gc_blocks); + buf += sprintf(buf, "bg_gcs............... %u\n", dev->bg_gcs); + buf += sprintf(buf, "n_retried_writes..... %u\n", + dev->n_retried_writes); + buf += sprintf(buf, "n_retired_blocks..... %u\n", + dev->n_retired_blocks); + buf += sprintf(buf, "n_ecc_fixed.......... %u\n", dev->n_ecc_fixed); + buf += sprintf(buf, "n_ecc_unfixed........ %u\n", dev->n_ecc_unfixed); + buf += sprintf(buf, "n_tags_ecc_fixed..... %u\n", + dev->n_tags_ecc_fixed); + buf += sprintf(buf, "n_tags_ecc_unfixed... %u\n", + dev->n_tags_ecc_unfixed); + buf += sprintf(buf, "cache_hits........... %u\n", dev->cache_hits); + buf += sprintf(buf, "n_deleted_files...... %u\n", dev->n_deleted_files); + buf += sprintf(buf, "n_unlinked_files..... %u\n", + dev->n_unlinked_files); + buf += sprintf(buf, "refresh_count........ %u\n", dev->refresh_count); + buf += sprintf(buf, "n_bg_deletions....... %u\n", dev->n_bg_deletions); + buf += sprintf(buf, "tags_used............ %u\n", dev->tags_used); + buf += sprintf(buf, "summary_used......... %u\n", dev->summary_used); + + return buf; +} + +static int yaffs_proc_read(char *page, + char **start, + off_t offset, int count, int *eof, void *data) +{ + struct list_head *item; + char *buf = page; + int step = offset; + int n = 0; + + /* Get proc_file_read() to step 'offset' by one on each sucessive call. + * We use 'offset' (*ppos) to indicate where we are in dev_list. + * This also assumes the user has posted a read buffer large + * enough to hold the complete output; but that's life in /proc. + */ + + *(int *)start = 1; + + /* Print header first */ + if (step == 0) + buf += + sprintf(buf, + "Multi-version YAFFS." + "\n"); + else if (step == 1) + buf += sprintf(buf, "\n"); + else { + step -= 2; + + mutex_lock(&yaffs_context_lock); + + /* Locate and print the Nth entry. Order N-squared but N is small. */ + list_for_each(item, &yaffs_context_list) { + struct yaffs_linux_context *dc = + list_entry(item, struct yaffs_linux_context, + context_list); + struct yaffs_dev *dev = dc->dev; + + if (n < (step & ~1)) { + n += 2; + continue; + } + if ((step & 1) == 0) { + buf += + sprintf(buf, "\nDevice %d \"%s\"\n", n, + dev->param.name); + buf = yaffs_dump_dev_part0(buf, dev); + } else { + buf = yaffs_dump_dev_part1(buf, dev); + } + + break; + } + mutex_unlock(&yaffs_context_lock); + } + + return buf - page < count ? buf - page : count; +} + +/** + * Set the verbosity of the warnings and error messages. + * + * Note that the names can only be a..z or _ with the current code. + */ + +static struct { + char *mask_name; + unsigned mask_bitfield; +} mask_flags[] = { + {"allocate", YAFFS_TRACE_ALLOCATE}, + {"always", YAFFS_TRACE_ALWAYS}, + {"background", YAFFS_TRACE_BACKGROUND}, + {"bad_blocks", YAFFS_TRACE_BAD_BLOCKS}, + {"buffers", YAFFS_TRACE_BUFFERS}, + {"bug", YAFFS_TRACE_BUG}, + {"checkpt", YAFFS_TRACE_CHECKPOINT}, + {"deletion", YAFFS_TRACE_DELETION}, + {"erase", YAFFS_TRACE_ERASE}, + {"error", YAFFS_TRACE_ERROR}, + {"gc_detail", YAFFS_TRACE_GC_DETAIL}, + {"gc", YAFFS_TRACE_GC}, + {"lock", YAFFS_TRACE_LOCK}, + {"mtd", YAFFS_TRACE_MTD}, + {"nandaccess", YAFFS_TRACE_NANDACCESS}, + {"os", YAFFS_TRACE_OS}, + {"scan_debug", YAFFS_TRACE_SCAN_DEBUG}, + {"scan", YAFFS_TRACE_SCAN}, + {"mount", YAFFS_TRACE_MOUNT}, + {"tracing", YAFFS_TRACE_TRACING}, + {"sync", YAFFS_TRACE_SYNC}, + {"write", YAFFS_TRACE_WRITE}, + {"verify", YAFFS_TRACE_VERIFY}, + {"verify_nand", YAFFS_TRACE_VERIFY_NAND}, + {"verify_full", YAFFS_TRACE_VERIFY_FULL}, + {"verify_all", YAFFS_TRACE_VERIFY_ALL}, + {"all", 0xffffffff}, + {"none", 0}, + {NULL, 0}, +}; + +#define MAX_MASK_NAME_LENGTH 40 +static int yaffs_proc_write_trace_options(struct file *file, const char *buf, + unsigned long count) +{ + unsigned rg = 0, mask_bitfield; + char *end; + char *mask_name; + const char *x; + char substring[MAX_MASK_NAME_LENGTH + 1]; + int i; + int done = 0; + int add, len = 0; + int pos = 0; + + rg = yaffs_trace_mask; + + while (!done && (pos < count)) { + done = 1; + while ((pos < count) && isspace(buf[pos])) + pos++; + + switch (buf[pos]) { + case '+': + case '-': + case '=': + add = buf[pos]; + pos++; + break; + + default: + add = ' '; + break; + } + mask_name = NULL; + + mask_bitfield = simple_strtoul(buf + pos, &end, 0); + + if (end > buf + pos) { + mask_name = "numeral"; + len = end - (buf + pos); + pos += len; + done = 0; + } else { + for (x = buf + pos, i = 0; + (*x == '_' || (*x >= 'a' && *x <= 'z')) && + i < MAX_MASK_NAME_LENGTH; x++, i++, pos++) + substring[i] = *x; + substring[i] = '\0'; + + for (i = 0; mask_flags[i].mask_name != NULL; i++) { + if (strcmp(substring, mask_flags[i].mask_name) + == 0) { + mask_name = mask_flags[i].mask_name; + mask_bitfield = + mask_flags[i].mask_bitfield; + done = 0; + break; + } + } + } + + if (mask_name != NULL) { + done = 0; + switch (add) { + case '-': + rg &= ~mask_bitfield; + break; + case '+': + rg |= mask_bitfield; + break; + case '=': + rg = mask_bitfield; + break; + default: + rg |= mask_bitfield; + break; + } + } + } + + yaffs_trace_mask = rg | YAFFS_TRACE_ALWAYS; + + printk(KERN_DEBUG "new trace = 0x%08X\n", yaffs_trace_mask); + + if (rg & YAFFS_TRACE_ALWAYS) { + for (i = 0; mask_flags[i].mask_name != NULL; i++) { + char flag; + flag = ((rg & mask_flags[i].mask_bitfield) == + mask_flags[i].mask_bitfield) ? '+' : '-'; + printk(KERN_DEBUG "%c%s\n", flag, + mask_flags[i].mask_name); + } + } + + return count; +} + +/* Debug strings are of the form: + * .bnnn print info on block n + * .cobjn,chunkn print nand chunk id for objn:chunkn + */ + +static int yaffs_proc_debug_write(struct file *file, const char *buf, + unsigned long count) +{ + + char str[100]; + char *p0; + char *p1; + long p1_val; + long p0_val; + char cmd; + struct list_head *item; + + memset(str, 0, sizeof(str)); + memcpy(str, buf, min((size_t)count, sizeof(str) -1)); + + cmd = str[1]; + + p0 = str + 2; + + p1 = p0; + + while (*p1 && *p1 != ',') { + p1++; + } + *p1 = '\0'; + p1++; + + p0_val = simple_strtol(p0, NULL, 0); + p1_val = simple_strtol(p1, NULL, 0); + + + mutex_lock(&yaffs_context_lock); + + /* Locate and print the Nth entry. Order N-squared but N is small. */ + list_for_each(item, &yaffs_context_list) { + struct yaffs_linux_context *dc = + list_entry(item, struct yaffs_linux_context, + context_list); + struct yaffs_dev *dev = dc->dev; + + if (cmd == 'b') { + struct yaffs_block_info *bi; + + bi = yaffs_get_block_info(dev,p0_val); + + if(bi) { + printk("Block %d: state %d, retire %d, use %d, seq %d\n", + (int)p0_val, bi->block_state, + bi->needs_retiring, bi->pages_in_use, + bi->seq_number); + } + } else if (cmd == 'c') { + struct yaffs_obj *obj; + int nand_chunk; + + obj = yaffs_find_by_number(dev, p0_val); + if (!obj) + printk("No obj %d\n", (int)p0_val); + else { + if(p1_val == 0) + nand_chunk = obj->hdr_chunk; + else + nand_chunk = + yaffs_find_chunk_in_file(obj, + p1_val, NULL); + printk("Nand chunk for %d:%d is %d\n", + (int)p0_val, (int)p1_val, nand_chunk); + } + } + } + + mutex_unlock(&yaffs_context_lock); + + return count; +} + + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)) +static int yaffs_proc_write(struct file *file, const char *buf, + unsigned long count, void *ppos) +#else +static ssize_t yaffs_proc_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +#endif +{ + if (buf[0] == '.') + return yaffs_proc_debug_write(file, buf, count); + return yaffs_proc_write_trace_options(file, buf, count); +} + +/* Stuff to handle installation of file systems */ +struct file_system_to_install { + struct file_system_type *fst; + int installed; +}; + +static struct file_system_to_install fs_to_install[] = { + {&yaffs_fs_type, 0}, + {&yaffs2_fs_type, 0}, + {NULL, 0} +}; + + +#ifdef YAFFS_NEW_PROCFS +static int yaffs_proc_show(struct seq_file *m, void *v) +{ + /* FIXME: Unify in a better way? */ + char buffer[512]; + char *start; + int len; + + len = yaffs_proc_read(buffer, &start, 0, sizeof(buffer), NULL, NULL); + seq_puts(m, buffer); + return 0; +} + +static int yaffs_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, yaffs_proc_show, NULL); +} + +static struct file_operations procfs_ops = { + .owner = THIS_MODULE, + .open = yaffs_proc_open, + .read = seq_read, + .write = yaffs_proc_write, +}; + +static int yaffs_procfs_init(void) +{ + /* Install the proc_fs entries */ + my_proc_entry = proc_create("yaffs", + S_IRUGO | S_IFREG, + YPROC_ROOT, + &procfs_ops); + + if (my_proc_entry) { + return 0; + } else { + return -ENOMEM; + } +} + +#else + + +static int yaffs_procfs_init(void) +{ + /* Install the proc_fs entries */ + my_proc_entry = create_proc_entry("yaffs", + S_IRUGO | S_IFREG, YPROC_ROOT); + + if (my_proc_entry) { + my_proc_entry->write_proc = yaffs_proc_write; + my_proc_entry->read_proc = yaffs_proc_read; + my_proc_entry->data = NULL; + return 0; + } else { + return -ENOMEM; + } +} + +#endif + + +static int __init init_yaffs_fs(void) +{ + int error = 0; + struct file_system_to_install *fsinst; + + yaffs_trace(YAFFS_TRACE_ALWAYS, + "yaffs Installing."); + + mutex_init(&yaffs_context_lock); + + error = yaffs_procfs_init(); + if (error) + return error; + + /* Now add the file system entries */ + + fsinst = fs_to_install; + + while (fsinst->fst && !error) { + error = register_filesystem(fsinst->fst); + if (!error) + fsinst->installed = 1; + fsinst++; + } + + /* Any errors? uninstall */ + if (error) { + fsinst = fs_to_install; + + while (fsinst->fst) { + if (fsinst->installed) { + unregister_filesystem(fsinst->fst); + fsinst->installed = 0; + } + fsinst++; + } + } + + return error; +} + +static void __exit exit_yaffs_fs(void) +{ + + struct file_system_to_install *fsinst; + + yaffs_trace(YAFFS_TRACE_ALWAYS, + "yaffs removing."); + + remove_proc_entry("yaffs", YPROC_ROOT); + + fsinst = fs_to_install; + + while (fsinst->fst) { + if (fsinst->installed) { + unregister_filesystem(fsinst->fst); + fsinst->installed = 0; + } + fsinst++; + } +} + +module_init(init_yaffs_fs) + module_exit(exit_yaffs_fs) + + MODULE_DESCRIPTION("YAFFS2 - a NAND specific flash file system"); +MODULE_AUTHOR("Charles Manning, Aleph One Ltd., 2002-2011"); +MODULE_LICENSE("GPL"); diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_yaffs1.c b/target/linux/generic/files/fs/yaffs2/yaffs_yaffs1.c new file mode 100644 index 0000000..d277e20 --- /dev/null +++ b/target/linux/generic/files/fs/yaffs2/yaffs_yaffs1.c @@ -0,0 +1,422 @@ +/* + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning + * + * 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. + */ + +#include "yaffs_yaffs1.h" +#include "yportenv.h" +#include "yaffs_trace.h" +#include "yaffs_bitmap.h" +#include "yaffs_getblockinfo.h" +#include "yaffs_nand.h" +#include "yaffs_attribs.h" + +int yaffs1_scan(struct yaffs_dev *dev) +{ + struct yaffs_ext_tags tags; + int blk; + int result; + int chunk; + int c; + int deleted; + enum yaffs_block_state state; + LIST_HEAD(hard_list); + struct yaffs_block_info *bi; + u32 seq_number; + struct yaffs_obj_hdr *oh; + struct yaffs_obj *in; + struct yaffs_obj *parent; + int alloc_failed = 0; + struct yaffs_shadow_fixer *shadow_fixers = NULL; + u8 *chunk_data; + + yaffs_trace(YAFFS_TRACE_SCAN, + "yaffs1_scan starts intstartblk %d intendblk %d...", + dev->internal_start_block, dev->internal_end_block); + + chunk_data = yaffs_get_temp_buffer(dev); + + dev->seq_number = YAFFS_LOWEST_SEQUENCE_NUMBER; + + /* Scan all the blocks to determine their state */ + bi = dev->block_info; + for (blk = dev->internal_start_block; blk <= dev->internal_end_block; + blk++) { + yaffs_clear_chunk_bits(dev, blk); + bi->pages_in_use = 0; + bi->soft_del_pages = 0; + + yaffs_query_init_block_state(dev, blk, &state, &seq_number); + + bi->block_state = state; + bi->seq_number = seq_number; + + if (bi->seq_number == YAFFS_SEQUENCE_BAD_BLOCK) + bi->block_state = state = YAFFS_BLOCK_STATE_DEAD; + + yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, + "Block scanning block %d state %d seq %d", + blk, state, seq_number); + + if (state == YAFFS_BLOCK_STATE_DEAD) { + yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, + "block %d is bad", blk); + } else if (state == YAFFS_BLOCK_STATE_EMPTY) { + yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, "Block empty "); + dev->n_erased_blocks++; + dev->n_free_chunks += dev->param.chunks_per_block; + } + bi++; + } + + /* For each block.... */ + for (blk = dev->internal_start_block; + !alloc_failed && blk <= dev->internal_end_block; blk++) { + + cond_resched(); + + bi = yaffs_get_block_info(dev, blk); + state = bi->block_state; + + deleted = 0; + + /* For each chunk in each block that needs scanning.... */ + for (c = 0; + !alloc_failed && c < dev->param.chunks_per_block && + state == YAFFS_BLOCK_STATE_NEEDS_SCAN; c++) { + /* Read the tags and decide what to do */ + chunk = blk * dev->param.chunks_per_block + c; + + result = yaffs_rd_chunk_tags_nand(dev, chunk, NULL, + &tags); + + /* Let's have a good look at this chunk... */ + + if (tags.ecc_result == YAFFS_ECC_RESULT_UNFIXED || + tags.is_deleted) { + /* YAFFS1 only... + * A deleted chunk + */ + deleted++; + dev->n_free_chunks++; + } else if (!tags.chunk_used) { + /* An unassigned chunk in the block + * This means that either the block is empty or + * this is the one being allocated from + */ + + if (c == 0) { + /* We're looking at the first chunk in + *the block so the block is unused */ + state = YAFFS_BLOCK_STATE_EMPTY; + dev->n_erased_blocks++; + } else { + /* this is the block being allocated */ + yaffs_trace(YAFFS_TRACE_SCAN, + " Allocating from %d %d", + blk, c); + state = YAFFS_BLOCK_STATE_ALLOCATING; + dev->alloc_block = blk; + dev->alloc_page = c; + dev->alloc_block_finder = blk; + + } + + dev->n_free_chunks += + (dev->param.chunks_per_block - c); + } else if (tags.chunk_id > 0) { + /* chunk_id > 0 so it is a data chunk... */ + unsigned int endpos; + + yaffs_set_chunk_bit(dev, blk, c); + bi->pages_in_use++; + + in = yaffs_find_or_create_by_number(dev, + tags.obj_id, + YAFFS_OBJECT_TYPE_FILE); + /* PutChunkIntoFile checks for a clash + * (two data chunks with the same chunk_id). + */ + + if (!in) + alloc_failed = 1; + + if (in) { + if (!yaffs_put_chunk_in_file + (in, tags.chunk_id, chunk, 1)) + alloc_failed = 1; + } + + endpos = + (tags.chunk_id - 1) * + dev->data_bytes_per_chunk + + tags.n_bytes; + if (in && + in->variant_type == + YAFFS_OBJECT_TYPE_FILE && + in->variant.file_variant.scanned_size < + endpos) { + in->variant.file_variant.scanned_size = + endpos; + if (!dev->param.use_header_file_size) { + in->variant. + file_variant.file_size = + in->variant. + file_variant.scanned_size; + } + + } + } else { + /* chunk_id == 0, so it is an ObjectHeader. + * Make the object + */ + yaffs_set_chunk_bit(dev, blk, c); + bi->pages_in_use++; + + result = yaffs_rd_chunk_tags_nand(dev, chunk, + chunk_data, + NULL); + + oh = (struct yaffs_obj_hdr *)chunk_data; + + in = yaffs_find_by_number(dev, tags.obj_id); + if (in && in->variant_type != oh->type) { + /* This should not happen, but somehow + * Wev'e ended up with an obj_id that + * has been reused but not yet deleted, + * and worse still it has changed type. + * Delete the old object. + */ + + yaffs_del_obj(in); + in = NULL; + } + + in = yaffs_find_or_create_by_number(dev, + tags.obj_id, + oh->type); + + if (!in) + alloc_failed = 1; + + if (in && oh->shadows_obj > 0) { + + struct yaffs_shadow_fixer *fixer; + fixer = + kmalloc(sizeof + (struct yaffs_shadow_fixer), + GFP_NOFS); + if (fixer) { + fixer->next = shadow_fixers; + shadow_fixers = fixer; + fixer->obj_id = tags.obj_id; + fixer->shadowed_id = + oh->shadows_obj; + yaffs_trace(YAFFS_TRACE_SCAN, + " Shadow fixer: %d shadows %d", + fixer->obj_id, + fixer->shadowed_id); + + } + + } + + if (in && in->valid) { + /* We have already filled this one. + * We have a duplicate and need to + * resolve it. */ + + unsigned existing_serial = in->serial; + unsigned new_serial = + tags.serial_number; + + if (((existing_serial + 1) & 3) == + new_serial) { + /* Use new one - destroy the + * exisiting one */ + yaffs_chunk_del(dev, + in->hdr_chunk, + 1, __LINE__); + in->valid = 0; + } else { + /* Use existing - destroy + * this one. */ + yaffs_chunk_del(dev, chunk, 1, + __LINE__); + } + } + + if (in && !in->valid && + (tags.obj_id == YAFFS_OBJECTID_ROOT || + tags.obj_id == + YAFFS_OBJECTID_LOSTNFOUND)) { + /* We only load some info, don't fiddle + * with directory structure */ + in->valid = 1; + in->variant_type = oh->type; + + in->yst_mode = oh->yst_mode; + yaffs_load_attribs(in, oh); + in->hdr_chunk = chunk; + in->serial = tags.serial_number; + + } else if (in && !in->valid) { + /* we need to load this info */ + + in->valid = 1; + in->variant_type = oh->type; + + in->yst_mode = oh->yst_mode; + yaffs_load_attribs(in, oh); + in->hdr_chunk = chunk; + in->serial = tags.serial_number; + + yaffs_set_obj_name_from_oh(in, oh); + in->dirty = 0; + + /* directory stuff... + * hook up to parent + */ + + parent = + yaffs_find_or_create_by_number + (dev, oh->parent_obj_id, + YAFFS_OBJECT_TYPE_DIRECTORY); + if (!parent) + alloc_failed = 1; + if (parent && parent->variant_type == + YAFFS_OBJECT_TYPE_UNKNOWN) { + /* Set up as a directory */ + parent->variant_type = + YAFFS_OBJECT_TYPE_DIRECTORY; + INIT_LIST_HEAD(&parent-> + variant.dir_variant. + children); + } else if (!parent || + parent->variant_type != + YAFFS_OBJECT_TYPE_DIRECTORY) { + /* Hoosterman, a problem.... + * We're trying to use a + * non-directory as a directory + */ + + yaffs_trace(YAFFS_TRACE_ERROR, + "yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found." + ); + parent = dev->lost_n_found; + } + + yaffs_add_obj_to_dir(parent, in); + + switch (in->variant_type) { + case YAFFS_OBJECT_TYPE_UNKNOWN: + /* Todo got a problem */ + break; + case YAFFS_OBJECT_TYPE_FILE: + if (dev->param. + use_header_file_size) + in->variant. + file_variant.file_size + = yaffs_oh_to_size(oh); + break; + case YAFFS_OBJECT_TYPE_HARDLINK: + in->variant. + hardlink_variant.equiv_id = + oh->equiv_id; + list_add(&in->hard_links, + &hard_list); + break; + case YAFFS_OBJECT_TYPE_DIRECTORY: + /* Do nothing */ + break; + case YAFFS_OBJECT_TYPE_SPECIAL: + /* Do nothing */ + break; + case YAFFS_OBJECT_TYPE_SYMLINK: + in->variant.symlink_variant. + alias = + yaffs_clone_str(oh->alias); + if (!in->variant. + symlink_variant.alias) + alloc_failed = 1; + break; + } + } + } + } + + if (state == YAFFS_BLOCK_STATE_NEEDS_SCAN) { + /* If we got this far while scanning, + * then the block is fully allocated. */ + state = YAFFS_BLOCK_STATE_FULL; + } + + if (state == YAFFS_BLOCK_STATE_ALLOCATING) { + /* If the block was partially allocated then + * treat it as fully allocated. */ + state = YAFFS_BLOCK_STATE_FULL; + dev->alloc_block = -1; + } + + bi->block_state = state; + + /* Now let's see if it was dirty */ + if (bi->pages_in_use == 0 && + !bi->has_shrink_hdr && + bi->block_state == YAFFS_BLOCK_STATE_FULL) + yaffs_block_became_dirty(dev, blk); + } + + /* Ok, we've done all the scanning. + * Fix up the hard link chains. + * We should now have scanned all the objects, now it's time to add + * these hardlinks. + */ + + yaffs_link_fixup(dev, &hard_list); + + /* + * Fix up any shadowed objects. + * There should not be more than one of these. + */ + { + struct yaffs_shadow_fixer *fixer; + struct yaffs_obj *obj; + + while (shadow_fixers) { + fixer = shadow_fixers; + shadow_fixers = fixer->next; + /* Complete the rename transaction by deleting the + * shadowed object then setting the object header + to unshadowed. + */ + obj = yaffs_find_by_number(dev, fixer->shadowed_id); + if (obj) + yaffs_del_obj(obj); + + obj = yaffs_find_by_number(dev, fixer->obj_id); + + if (obj) + yaffs_update_oh(obj, NULL, 1, 0, 0, NULL); + + kfree(fixer); + } + } + + yaffs_release_temp_buffer(dev, chunk_data); + + if (alloc_failed) + return YAFFS_FAIL; + + yaffs_trace(YAFFS_TRACE_SCAN, "yaffs1_scan ends"); + + return YAFFS_OK; +} diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_yaffs1.h b/target/linux/generic/files/fs/yaffs2/yaffs_yaffs1.h new file mode 100644 index 0000000..97e2fdd --- /dev/null +++ b/target/linux/generic/files/fs/yaffs2/yaffs_yaffs1.h @@ -0,0 +1,22 @@ +/* + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + */ + +#ifndef __YAFFS_YAFFS1_H__ +#define __YAFFS_YAFFS1_H__ + +#include "yaffs_guts.h" +int yaffs1_scan(struct yaffs_dev *dev); + +#endif diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_yaffs2.c b/target/linux/generic/files/fs/yaffs2/yaffs_yaffs2.c new file mode 100644 index 0000000..9fb7c94 --- /dev/null +++ b/target/linux/generic/files/fs/yaffs2/yaffs_yaffs2.c @@ -0,0 +1,1532 @@ +/* + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning + * + * 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. + */ + +#include "yaffs_guts.h" +#include "yaffs_trace.h" +#include "yaffs_yaffs2.h" +#include "yaffs_checkptrw.h" +#include "yaffs_bitmap.h" +#include "yaffs_nand.h" +#include "yaffs_getblockinfo.h" +#include "yaffs_verify.h" +#include "yaffs_attribs.h" +#include "yaffs_summary.h" + +/* + * Checkpoints are really no benefit on very small partitions. + * + * To save space on small partitions don't bother with checkpoints unless + * the partition is at least this big. + */ +#define YAFFS_CHECKPOINT_MIN_BLOCKS 60 +#define YAFFS_SMALL_HOLE_THRESHOLD 4 + +/* + * Oldest Dirty Sequence Number handling. + */ + +/* yaffs_calc_oldest_dirty_seq() + * yaffs2_find_oldest_dirty_seq() + * Calculate the oldest dirty sequence number if we don't know it. + */ +void yaffs_calc_oldest_dirty_seq(struct yaffs_dev *dev) +{ + int i; + unsigned seq; + unsigned block_no = 0; + struct yaffs_block_info *b; + + if (!dev->param.is_yaffs2) + return; + + /* Find the oldest dirty sequence number. */ + seq = dev->seq_number + 1; + b = dev->block_info; + for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) { + if (b->block_state == YAFFS_BLOCK_STATE_FULL && + (b->pages_in_use - b->soft_del_pages) < + dev->param.chunks_per_block && + b->seq_number < seq) { + seq = b->seq_number; + block_no = i; + } + b++; + } + + if (block_no) { + dev->oldest_dirty_seq = seq; + dev->oldest_dirty_block = block_no; + } +} + +void yaffs2_find_oldest_dirty_seq(struct yaffs_dev *dev) +{ + if (!dev->param.is_yaffs2) + return; + + if (!dev->oldest_dirty_seq) + yaffs_calc_oldest_dirty_seq(dev); +} + +/* + * yaffs_clear_oldest_dirty_seq() + * Called when a block is erased or marked bad. (ie. when its seq_number + * becomes invalid). If the value matches the oldest then we clear + * dev->oldest_dirty_seq to force its recomputation. + */ +void yaffs2_clear_oldest_dirty_seq(struct yaffs_dev *dev, + struct yaffs_block_info *bi) +{ + + if (!dev->param.is_yaffs2) + return; + + if (!bi || bi->seq_number == dev->oldest_dirty_seq) { + dev->oldest_dirty_seq = 0; + dev->oldest_dirty_block = 0; + } +} + +/* + * yaffs2_update_oldest_dirty_seq() + * Update the oldest dirty sequence number whenever we dirty a block. + * Only do this if the oldest_dirty_seq is actually being tracked. + */ +void yaffs2_update_oldest_dirty_seq(struct yaffs_dev *dev, unsigned block_no, + struct yaffs_block_info *bi) +{ + if (!dev->param.is_yaffs2) + return; + + if (dev->oldest_dirty_seq) { + if (dev->oldest_dirty_seq > bi->seq_number) { + dev->oldest_dirty_seq = bi->seq_number; + dev->oldest_dirty_block = block_no; + } + } +} + +int yaffs_block_ok_for_gc(struct yaffs_dev *dev, struct yaffs_block_info *bi) +{ + + if (!dev->param.is_yaffs2) + return 1; /* disqualification only applies to yaffs2. */ + + if (!bi->has_shrink_hdr) + return 1; /* can gc */ + + yaffs2_find_oldest_dirty_seq(dev); + + /* Can't do gc of this block if there are any blocks older than this + * one that have discarded pages. + */ + return (bi->seq_number <= dev->oldest_dirty_seq); +} + +/* + * yaffs2_find_refresh_block() + * periodically finds the oldest full block by sequence number for refreshing. + * Only for yaffs2. + */ +u32 yaffs2_find_refresh_block(struct yaffs_dev *dev) +{ + u32 b; + u32 oldest = 0; + u32 oldest_seq = 0; + struct yaffs_block_info *bi; + + if (!dev->param.is_yaffs2) + return oldest; + + /* + * If refresh period < 10 then refreshing is disabled. + */ + if (dev->param.refresh_period < 10) + return oldest; + + /* + * Fix broken values. + */ + if (dev->refresh_skip > dev->param.refresh_period) + dev->refresh_skip = dev->param.refresh_period; + + if (dev->refresh_skip > 0) + return oldest; + + /* + * Refresh skip is now zero. + * We'll do a refresh this time around.... + * Update the refresh skip and find the oldest block. + */ + dev->refresh_skip = dev->param.refresh_period; + dev->refresh_count++; + bi = dev->block_info; + for (b = dev->internal_start_block; b <= dev->internal_end_block; b++) { + + if (bi->block_state == YAFFS_BLOCK_STATE_FULL) { + + if (oldest < 1 || bi->seq_number < oldest_seq) { + oldest = b; + oldest_seq = bi->seq_number; + } + } + bi++; + } + + if (oldest > 0) { + yaffs_trace(YAFFS_TRACE_GC, + "GC refresh count %d selected block %d with seq_number %d", + dev->refresh_count, oldest, oldest_seq); + } + + return oldest; +} + +int yaffs2_checkpt_required(struct yaffs_dev *dev) +{ + int nblocks; + + if (!dev->param.is_yaffs2) + return 0; + + nblocks = dev->internal_end_block - dev->internal_start_block + 1; + + return !dev->param.skip_checkpt_wr && + !dev->read_only && (nblocks >= YAFFS_CHECKPOINT_MIN_BLOCKS); +} + +int yaffs_calc_checkpt_blocks_required(struct yaffs_dev *dev) +{ + int retval; + int n_bytes = 0; + int n_blocks; + int dev_blocks; + + if (!dev->param.is_yaffs2) + return 0; + + if (!dev->checkpoint_blocks_required && yaffs2_checkpt_required(dev)) { + /* Not a valid value so recalculate */ + dev_blocks = dev->param.end_block - dev->param.start_block + 1; + n_bytes += sizeof(struct yaffs_checkpt_validity); + n_bytes += sizeof(struct yaffs_checkpt_dev); + n_bytes += dev_blocks * sizeof(struct yaffs_block_info); + n_bytes += dev_blocks * dev->chunk_bit_stride; + n_bytes += + (sizeof(struct yaffs_checkpt_obj) + sizeof(u32)) * + dev->n_obj; + n_bytes += (dev->tnode_size + sizeof(u32)) * dev->n_tnodes; + n_bytes += sizeof(struct yaffs_checkpt_validity); + n_bytes += sizeof(u32); /* checksum */ + + /* Round up and add 2 blocks to allow for some bad blocks, + * so add 3 */ + + n_blocks = + (n_bytes / + (dev->data_bytes_per_chunk * + dev->param.chunks_per_block)) + 3; + + dev->checkpoint_blocks_required = n_blocks; + } + + retval = dev->checkpoint_blocks_required - dev->blocks_in_checkpt; + if (retval < 0) + retval = 0; + return retval; +} + +/*--------------------- Checkpointing --------------------*/ + +static int yaffs2_wr_checkpt_validity_marker(struct yaffs_dev *dev, int head) +{ + struct yaffs_checkpt_validity cp; + + memset(&cp, 0, sizeof(cp)); + + cp.struct_type = sizeof(cp); + cp.magic = YAFFS_MAGIC; + cp.version = YAFFS_CHECKPOINT_VERSION; + cp.head = (head) ? 1 : 0; + + return (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp)) ? 1 : 0; +} + +static int yaffs2_rd_checkpt_validity_marker(struct yaffs_dev *dev, int head) +{ + struct yaffs_checkpt_validity cp; + int ok; + + ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp)); + + if (ok) + ok = (cp.struct_type == sizeof(cp)) && + (cp.magic == YAFFS_MAGIC) && + (cp.version == YAFFS_CHECKPOINT_VERSION) && + (cp.head == ((head) ? 1 : 0)); + return ok ? 1 : 0; +} + +static void yaffs2_dev_to_checkpt_dev(struct yaffs_checkpt_dev *cp, + struct yaffs_dev *dev) +{ + cp->n_erased_blocks = dev->n_erased_blocks; + cp->alloc_block = dev->alloc_block; + cp->alloc_page = dev->alloc_page; + cp->n_free_chunks = dev->n_free_chunks; + + cp->n_deleted_files = dev->n_deleted_files; + cp->n_unlinked_files = dev->n_unlinked_files; + cp->n_bg_deletions = dev->n_bg_deletions; + cp->seq_number = dev->seq_number; + +} + +static void yaffs_checkpt_dev_to_dev(struct yaffs_dev *dev, + struct yaffs_checkpt_dev *cp) +{ + dev->n_erased_blocks = cp->n_erased_blocks; + dev->alloc_block = cp->alloc_block; + dev->alloc_page = cp->alloc_page; + dev->n_free_chunks = cp->n_free_chunks; + + dev->n_deleted_files = cp->n_deleted_files; + dev->n_unlinked_files = cp->n_unlinked_files; + dev->n_bg_deletions = cp->n_bg_deletions; + dev->seq_number = cp->seq_number; +} + +static int yaffs2_wr_checkpt_dev(struct yaffs_dev *dev) +{ + struct yaffs_checkpt_dev cp; + u32 n_bytes; + u32 n_blocks = dev->internal_end_block - dev->internal_start_block + 1; + int ok; + + /* Write device runtime values */ + yaffs2_dev_to_checkpt_dev(&cp, dev); + cp.struct_type = sizeof(cp); + + ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp)); + if (!ok) + return 0; + + /* Write block info */ + n_bytes = n_blocks * sizeof(struct yaffs_block_info); + ok = (yaffs2_checkpt_wr(dev, dev->block_info, n_bytes) == n_bytes); + if (!ok) + return 0; + + /* Write chunk bits */ + n_bytes = n_blocks * dev->chunk_bit_stride; + ok = (yaffs2_checkpt_wr(dev, dev->chunk_bits, n_bytes) == n_bytes); + + return ok ? 1 : 0; +} + +static int yaffs2_rd_checkpt_dev(struct yaffs_dev *dev) +{ + struct yaffs_checkpt_dev cp; + u32 n_bytes; + u32 n_blocks = + (dev->internal_end_block - dev->internal_start_block + 1); + int ok; + + ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp)); + if (!ok) + return 0; + + if (cp.struct_type != sizeof(cp)) + return 0; + + yaffs_checkpt_dev_to_dev(dev, &cp); + + n_bytes = n_blocks * sizeof(struct yaffs_block_info); + + ok = (yaffs2_checkpt_rd(dev, dev->block_info, n_bytes) == n_bytes); + + if (!ok) + return 0; + + n_bytes = n_blocks * dev->chunk_bit_stride; + + ok = (yaffs2_checkpt_rd(dev, dev->chunk_bits, n_bytes) == n_bytes); + + return ok ? 1 : 0; +} + +static void yaffs2_obj_checkpt_obj(struct yaffs_checkpt_obj *cp, + struct yaffs_obj *obj) +{ + cp->obj_id = obj->obj_id; + cp->parent_id = (obj->parent) ? obj->parent->obj_id : 0; + cp->hdr_chunk = obj->hdr_chunk; + cp->variant_type = obj->variant_type; + cp->deleted = obj->deleted; + cp->soft_del = obj->soft_del; + cp->unlinked = obj->unlinked; + cp->fake = obj->fake; + cp->rename_allowed = obj->rename_allowed; + cp->unlink_allowed = obj->unlink_allowed; + cp->serial = obj->serial; + cp->n_data_chunks = obj->n_data_chunks; + + if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE) + cp->size_or_equiv_obj = obj->variant.file_variant.file_size; + else if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) + cp->size_or_equiv_obj = obj->variant.hardlink_variant.equiv_id; +} + +static int yaffs2_checkpt_obj_to_obj(struct yaffs_obj *obj, + struct yaffs_checkpt_obj *cp) +{ + struct yaffs_obj *parent; + + if (obj->variant_type != cp->variant_type) { + yaffs_trace(YAFFS_TRACE_ERROR, + "Checkpoint read object %d type %d chunk %d does not match existing object type %d", + cp->obj_id, cp->variant_type, cp->hdr_chunk, + obj->variant_type); + return 0; + } + + obj->obj_id = cp->obj_id; + + if (cp->parent_id) + parent = yaffs_find_or_create_by_number(obj->my_dev, + cp->parent_id, + YAFFS_OBJECT_TYPE_DIRECTORY); + else + parent = NULL; + + if (parent) { + if (parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { + yaffs_trace(YAFFS_TRACE_ALWAYS, + "Checkpoint read object %d parent %d type %d chunk %d Parent type, %d, not directory", + cp->obj_id, cp->parent_id, + cp->variant_type, cp->hdr_chunk, + parent->variant_type); + return 0; + } + yaffs_add_obj_to_dir(parent, obj); + } + + obj->hdr_chunk = cp->hdr_chunk; + obj->variant_type = cp->variant_type; + obj->deleted = cp->deleted; + obj->soft_del = cp->soft_del; + obj->unlinked = cp->unlinked; + obj->fake = cp->fake; + obj->rename_allowed = cp->rename_allowed; + obj->unlink_allowed = cp->unlink_allowed; + obj->serial = cp->serial; + obj->n_data_chunks = cp->n_data_chunks; + + if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE) + obj->variant.file_variant.file_size = cp->size_or_equiv_obj; + else if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) + obj->variant.hardlink_variant.equiv_id = cp->size_or_equiv_obj; + + if (obj->hdr_chunk > 0) + obj->lazy_loaded = 1; + return 1; +} + +static int yaffs2_checkpt_tnode_worker(struct yaffs_obj *in, + struct yaffs_tnode *tn, u32 level, + int chunk_offset) +{ + int i; + struct yaffs_dev *dev = in->my_dev; + int ok = 1; + u32 base_offset; + + if (!tn) + return 1; + + if (level > 0) { + for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) { + if (!tn->internal[i]) + continue; + ok = yaffs2_checkpt_tnode_worker(in, + tn->internal[i], + level - 1, + (chunk_offset << + YAFFS_TNODES_INTERNAL_BITS) + i); + } + return ok; + } + + /* Level 0 tnode */ + base_offset = chunk_offset << YAFFS_TNODES_LEVEL0_BITS; + ok = (yaffs2_checkpt_wr(dev, &base_offset, sizeof(base_offset)) == + sizeof(base_offset)); + if (ok) + ok = (yaffs2_checkpt_wr(dev, tn, dev->tnode_size) == + dev->tnode_size); + + return ok; +} + +static int yaffs2_wr_checkpt_tnodes(struct yaffs_obj *obj) +{ + u32 end_marker = ~0; + int ok = 1; + + if (obj->variant_type != YAFFS_OBJECT_TYPE_FILE) + return ok; + + ok = yaffs2_checkpt_tnode_worker(obj, + obj->variant.file_variant.top, + obj->variant.file_variant. + top_level, 0); + if (ok) + ok = (yaffs2_checkpt_wr(obj->my_dev, &end_marker, + sizeof(end_marker)) == sizeof(end_marker)); + + return ok ? 1 : 0; +} + +static int yaffs2_rd_checkpt_tnodes(struct yaffs_obj *obj) +{ + u32 base_chunk; + int ok = 1; + struct yaffs_dev *dev = obj->my_dev; + struct yaffs_file_var *file_stuct_ptr = &obj->variant.file_variant; + struct yaffs_tnode *tn; + int nread = 0; + + ok = (yaffs2_checkpt_rd(dev, &base_chunk, sizeof(base_chunk)) == + sizeof(base_chunk)); + + while (ok && (~base_chunk)) { + nread++; + /* Read level 0 tnode */ + + tn = yaffs_get_tnode(dev); + if (tn) + ok = (yaffs2_checkpt_rd(dev, tn, dev->tnode_size) == + dev->tnode_size); + else + ok = 0; + + if (tn && ok) + ok = yaffs_add_find_tnode_0(dev, + file_stuct_ptr, + base_chunk, tn) ? 1 : 0; + + if (ok) + ok = (yaffs2_checkpt_rd + (dev, &base_chunk, + sizeof(base_chunk)) == sizeof(base_chunk)); + } + + yaffs_trace(YAFFS_TRACE_CHECKPOINT, + "Checkpoint read tnodes %d records, last %d. ok %d", + nread, base_chunk, ok); + + return ok ? 1 : 0; +} + +static int yaffs2_wr_checkpt_objs(struct yaffs_dev *dev) +{ + struct yaffs_obj *obj; + struct yaffs_checkpt_obj cp; + int i; + int ok = 1; + struct list_head *lh; + + /* Iterate through the objects in each hash entry, + * dumping them to the checkpointing stream. + */ + + for (i = 0; ok && i < YAFFS_NOBJECT_BUCKETS; i++) { + list_for_each(lh, &dev->obj_bucket[i].list) { + obj = list_entry(lh, struct yaffs_obj, hash_link); + if (!obj->defered_free) { + yaffs2_obj_checkpt_obj(&cp, obj); + cp.struct_type = sizeof(cp); + + yaffs_trace(YAFFS_TRACE_CHECKPOINT, + "Checkpoint write object %d parent %d type %d chunk %d obj addr %p", + cp.obj_id, cp.parent_id, + cp.variant_type, cp.hdr_chunk, obj); + + ok = (yaffs2_checkpt_wr(dev, &cp, + sizeof(cp)) == sizeof(cp)); + + if (ok && + obj->variant_type == + YAFFS_OBJECT_TYPE_FILE) + ok = yaffs2_wr_checkpt_tnodes(obj); + } + } + } + + /* Dump end of list */ + memset(&cp, 0xff, sizeof(struct yaffs_checkpt_obj)); + cp.struct_type = sizeof(cp); + + if (ok) + ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp)); + + return ok ? 1 : 0; +} + +static int yaffs2_rd_checkpt_objs(struct yaffs_dev *dev) +{ + struct yaffs_obj *obj; + struct yaffs_checkpt_obj cp; + int ok = 1; + int done = 0; + LIST_HEAD(hard_list); + + + while (ok && !done) { + ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp)); + if (cp.struct_type != sizeof(cp)) { + yaffs_trace(YAFFS_TRACE_CHECKPOINT, + "struct size %d instead of %d ok %d", + cp.struct_type, (int)sizeof(cp), ok); + ok = 0; + } + + yaffs_trace(YAFFS_TRACE_CHECKPOINT, + "Checkpoint read object %d parent %d type %d chunk %d ", + cp.obj_id, cp.parent_id, cp.variant_type, + cp.hdr_chunk); + + if (ok && cp.obj_id == ~0) { + done = 1; + } else if (ok) { + obj = + yaffs_find_or_create_by_number(dev, cp.obj_id, + cp.variant_type); + if (obj) { + ok = yaffs2_checkpt_obj_to_obj(obj, &cp); + if (!ok) + break; + if (obj->variant_type == + YAFFS_OBJECT_TYPE_FILE) { + ok = yaffs2_rd_checkpt_tnodes(obj); + } else if (obj->variant_type == + YAFFS_OBJECT_TYPE_HARDLINK) { + list_add(&obj->hard_links, &hard_list); + } + } else { + ok = 0; + } + } + } + + if (ok) + yaffs_link_fixup(dev, &hard_list); + + return ok ? 1 : 0; +} + +static int yaffs2_wr_checkpt_sum(struct yaffs_dev *dev) +{ + u32 checkpt_sum; + int ok; + + yaffs2_get_checkpt_sum(dev, &checkpt_sum); + + ok = (yaffs2_checkpt_wr(dev, &checkpt_sum, sizeof(checkpt_sum)) == + sizeof(checkpt_sum)); + + if (!ok) + return 0; + + return 1; +} + +static int yaffs2_rd_checkpt_sum(struct yaffs_dev *dev) +{ + u32 checkpt_sum0; + u32 checkpt_sum1; + int ok; + + yaffs2_get_checkpt_sum(dev, &checkpt_sum0); + + ok = (yaffs2_checkpt_rd(dev, &checkpt_sum1, sizeof(checkpt_sum1)) == + sizeof(checkpt_sum1)); + + if (!ok) + return 0; + + if (checkpt_sum0 != checkpt_sum1) + return 0; + + return 1; +} + +static int yaffs2_wr_checkpt_data(struct yaffs_dev *dev) +{ + int ok = 1; + + if (!yaffs2_checkpt_required(dev)) { + yaffs_trace(YAFFS_TRACE_CHECKPOINT, + "skipping checkpoint write"); + ok = 0; + } + + if (ok) + ok = yaffs2_checkpt_open(dev, 1); + + if (ok) { + yaffs_trace(YAFFS_TRACE_CHECKPOINT, + "write checkpoint validity"); + ok = yaffs2_wr_checkpt_validity_marker(dev, 1); + } + if (ok) { + yaffs_trace(YAFFS_TRACE_CHECKPOINT, + "write checkpoint device"); + ok = yaffs2_wr_checkpt_dev(dev); + } + if (ok) { + yaffs_trace(YAFFS_TRACE_CHECKPOINT, + "write checkpoint objects"); + ok = yaffs2_wr_checkpt_objs(dev); + } + if (ok) { + yaffs_trace(YAFFS_TRACE_CHECKPOINT, + "write checkpoint validity"); + ok = yaffs2_wr_checkpt_validity_marker(dev, 0); + } + + if (ok) + ok = yaffs2_wr_checkpt_sum(dev); + + if (!yaffs_checkpt_close(dev)) + ok = 0; + + if (ok) + dev->is_checkpointed = 1; + else + dev->is_checkpointed = 0; + + return dev->is_checkpointed; +} + +static int yaffs2_rd_checkpt_data(struct yaffs_dev *dev) +{ + int ok = 1; + + if (!dev->param.is_yaffs2) + ok = 0; + + if (ok && dev->param.skip_checkpt_rd) { + yaffs_trace(YAFFS_TRACE_CHECKPOINT, + "skipping checkpoint read"); + ok = 0; + } + + if (ok) + ok = yaffs2_checkpt_open(dev, 0); /* open for read */ + + if (ok) { + yaffs_trace(YAFFS_TRACE_CHECKPOINT, + "read checkpoint validity"); + ok = yaffs2_rd_checkpt_validity_marker(dev, 1); + } + if (ok) { + yaffs_trace(YAFFS_TRACE_CHECKPOINT, + "read checkpoint device"); + ok = yaffs2_rd_checkpt_dev(dev); + } + if (ok) { + yaffs_trace(YAFFS_TRACE_CHECKPOINT, + "read checkpoint objects"); + ok = yaffs2_rd_checkpt_objs(dev); + } + if (ok) { + yaffs_trace(YAFFS_TRACE_CHECKPOINT, + "read checkpoint validity"); + ok = yaffs2_rd_checkpt_validity_marker(dev, 0); + } + + if (ok) { + ok = yaffs2_rd_checkpt_sum(dev); + yaffs_trace(YAFFS_TRACE_CHECKPOINT, + "read checkpoint checksum %d", ok); + } + + if (!yaffs_checkpt_close(dev)) + ok = 0; + + if (ok) + dev->is_checkpointed = 1; + else + dev->is_checkpointed = 0; + + return ok ? 1 : 0; +} + +void yaffs2_checkpt_invalidate(struct yaffs_dev *dev) +{ + if (dev->is_checkpointed || dev->blocks_in_checkpt > 0) { + dev->is_checkpointed = 0; + yaffs2_checkpt_invalidate_stream(dev); + } + if (dev->param.sb_dirty_fn) + dev->param.sb_dirty_fn(dev); +} + +int yaffs_checkpoint_save(struct yaffs_dev *dev) +{ + yaffs_trace(YAFFS_TRACE_CHECKPOINT, + "save entry: is_checkpointed %d", + dev->is_checkpointed); + + yaffs_verify_objects(dev); + yaffs_verify_blocks(dev); + yaffs_verify_free_chunks(dev); + + if (!dev->is_checkpointed) { + yaffs2_checkpt_invalidate(dev); + yaffs2_wr_checkpt_data(dev); + } + + yaffs_trace(YAFFS_TRACE_CHECKPOINT | YAFFS_TRACE_MOUNT, + "save exit: is_checkpointed %d", + dev->is_checkpointed); + + return dev->is_checkpointed; +} + +int yaffs2_checkpt_restore(struct yaffs_dev *dev) +{ + int retval; + + yaffs_trace(YAFFS_TRACE_CHECKPOINT, + "restore entry: is_checkpointed %d", + dev->is_checkpointed); + + retval = yaffs2_rd_checkpt_data(dev); + + if (dev->is_checkpointed) { + yaffs_verify_objects(dev); + yaffs_verify_blocks(dev); + yaffs_verify_free_chunks(dev); + } + + yaffs_trace(YAFFS_TRACE_CHECKPOINT, + "restore exit: is_checkpointed %d", + dev->is_checkpointed); + + return retval; +} + +int yaffs2_handle_hole(struct yaffs_obj *obj, loff_t new_size) +{ + /* if new_size > old_file_size. + * We're going to be writing a hole. + * If the hole is small then write zeros otherwise write a start + * of hole marker. + */ + loff_t old_file_size; + loff_t increase; + int small_hole; + int result = YAFFS_OK; + struct yaffs_dev *dev = NULL; + u8 *local_buffer = NULL; + int small_increase_ok = 0; + + if (!obj) + return YAFFS_FAIL; + + if (obj->variant_type != YAFFS_OBJECT_TYPE_FILE) + return YAFFS_FAIL; + + dev = obj->my_dev; + + /* Bail out if not yaffs2 mode */ + if (!dev->param.is_yaffs2) + return YAFFS_OK; + + old_file_size = obj->variant.file_variant.file_size; + + if (new_size <= old_file_size) + return YAFFS_OK; + + increase = new_size - old_file_size; + + if (increase < YAFFS_SMALL_HOLE_THRESHOLD * dev->data_bytes_per_chunk && + yaffs_check_alloc_available(dev, YAFFS_SMALL_HOLE_THRESHOLD + 1)) + small_hole = 1; + else + small_hole = 0; + + if (small_hole) + local_buffer = yaffs_get_temp_buffer(dev); + + if (local_buffer) { + /* fill hole with zero bytes */ + loff_t pos = old_file_size; + int this_write; + int written; + memset(local_buffer, 0, dev->data_bytes_per_chunk); + small_increase_ok = 1; + + while (increase > 0 && small_increase_ok) { + this_write = increase; + if (this_write > dev->data_bytes_per_chunk) + this_write = dev->data_bytes_per_chunk; + written = + yaffs_do_file_wr(obj, local_buffer, pos, this_write, + 0); + if (written == this_write) { + pos += this_write; + increase -= this_write; + } else { + small_increase_ok = 0; + } + } + + yaffs_release_temp_buffer(dev, local_buffer); + + /* If out of space then reverse any chunks we've added */ + if (!small_increase_ok) + yaffs_resize_file_down(obj, old_file_size); + } + + if (!small_increase_ok && + obj->parent && + obj->parent->obj_id != YAFFS_OBJECTID_UNLINKED && + obj->parent->obj_id != YAFFS_OBJECTID_DELETED) { + /* Write a hole start header with the old file size */ + yaffs_update_oh(obj, NULL, 0, 1, 0, NULL); + } + + return result; +} + +struct yaffs_block_index { + int seq; + int block; +}; + +static int yaffs2_ybicmp(const void *a, const void *b) +{ + int aseq = ((struct yaffs_block_index *)a)->seq; + int bseq = ((struct yaffs_block_index *)b)->seq; + int ablock = ((struct yaffs_block_index *)a)->block; + int bblock = ((struct yaffs_block_index *)b)->block; + + if (aseq == bseq) + return ablock - bblock; + + return aseq - bseq; +} + +static inline int yaffs2_scan_chunk(struct yaffs_dev *dev, + struct yaffs_block_info *bi, + int blk, int chunk_in_block, + int *found_chunks, + u8 *chunk_data, + struct list_head *hard_list, + int summary_available) +{ + struct yaffs_obj_hdr *oh; + struct yaffs_obj *in; + struct yaffs_obj *parent; + int equiv_id; + loff_t file_size; + int is_shrink; + int is_unlinked; + struct yaffs_ext_tags tags; + int result; + int alloc_failed = 0; + int chunk = blk * dev->param.chunks_per_block + chunk_in_block; + struct yaffs_file_var *file_var; + struct yaffs_hardlink_var *hl_var; + struct yaffs_symlink_var *sl_var; + + if (summary_available) { + result = yaffs_summary_fetch(dev, &tags, chunk_in_block); + tags.seq_number = bi->seq_number; + } + + if (!summary_available || tags.obj_id == 0) { + result = yaffs_rd_chunk_tags_nand(dev, chunk, NULL, &tags); + dev->tags_used++; + } else { + dev->summary_used++; + } + + /* Let's have a good look at this chunk... */ + + if (!tags.chunk_used) { + /* An unassigned chunk in the block. + * If there are used chunks after this one, then + * it is a chunk that was skipped due to failing + * the erased check. Just skip it so that it can + * be deleted. + * But, more typically, We get here when this is + * an unallocated chunk and his means that + * either the block is empty or this is the one + * being allocated from + */ + + if (*found_chunks) { + /* This is a chunk that was skipped due + * to failing the erased check */ + } else if (chunk_in_block == 0) { + /* We're looking at the first chunk in + * the block so the block is unused */ + bi->block_state = YAFFS_BLOCK_STATE_EMPTY; + dev->n_erased_blocks++; + } else { + if (bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN || + bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING) { + if (dev->seq_number == bi->seq_number) { + /* Allocating from this block*/ + yaffs_trace(YAFFS_TRACE_SCAN, + " Allocating from %d %d", + blk, chunk_in_block); + + bi->block_state = + YAFFS_BLOCK_STATE_ALLOCATING; + dev->alloc_block = blk; + dev->alloc_page = chunk_in_block; + dev->alloc_block_finder = blk; + } else { + /* This is a partially written block + * that is not the current + * allocation block. + */ + yaffs_trace(YAFFS_TRACE_SCAN, + "Partially written block %d detected. gc will fix this.", + blk); + } + } + } + + dev->n_free_chunks++; + + } else if (tags.ecc_result == + YAFFS_ECC_RESULT_UNFIXED) { + yaffs_trace(YAFFS_TRACE_SCAN, + " Unfixed ECC in chunk(%d:%d), chunk ignored", + blk, chunk_in_block); + dev->n_free_chunks++; + } else if (tags.obj_id > YAFFS_MAX_OBJECT_ID || + tags.chunk_id > YAFFS_MAX_CHUNK_ID || + tags.obj_id == YAFFS_OBJECTID_SUMMARY || + (tags.chunk_id > 0 && + tags.n_bytes > dev->data_bytes_per_chunk) || + tags.seq_number != bi->seq_number) { + yaffs_trace(YAFFS_TRACE_SCAN, + "Chunk (%d:%d) with bad tags:obj = %d, chunk_id = %d, n_bytes = %d, ignored", + blk, chunk_in_block, tags.obj_id, + tags.chunk_id, tags.n_bytes); + dev->n_free_chunks++; + } else if (tags.chunk_id > 0) { + /* chunk_id > 0 so it is a data chunk... */ + loff_t endpos; + loff_t chunk_base = (tags.chunk_id - 1) * + dev->data_bytes_per_chunk; + + *found_chunks = 1; + + yaffs_set_chunk_bit(dev, blk, chunk_in_block); + bi->pages_in_use++; + + in = yaffs_find_or_create_by_number(dev, + tags.obj_id, + YAFFS_OBJECT_TYPE_FILE); + if (!in) + /* Out of memory */ + alloc_failed = 1; + + if (in && + in->variant_type == YAFFS_OBJECT_TYPE_FILE && + chunk_base < in->variant.file_variant.shrink_size) { + /* This has not been invalidated by + * a resize */ + if (!yaffs_put_chunk_in_file(in, tags.chunk_id, + chunk, -1)) + alloc_failed = 1; + + /* File size is calculated by looking at + * the data chunks if we have not + * seen an object header yet. + * Stop this practice once we find an + * object header. + */ + endpos = chunk_base + tags.n_bytes; + + if (!in->valid && + in->variant.file_variant.scanned_size < endpos) { + in->variant.file_variant. + scanned_size = endpos; + in->variant.file_variant. + file_size = endpos; + } + } else if (in) { + /* This chunk has been invalidated by a + * resize, or a past file deletion + * so delete the chunk*/ + yaffs_chunk_del(dev, chunk, 1, __LINE__); + } + } else { + /* chunk_id == 0, so it is an ObjectHeader. + * Thus, we read in the object header and make + * the object + */ + *found_chunks = 1; + + yaffs_set_chunk_bit(dev, blk, chunk_in_block); + bi->pages_in_use++; + + oh = NULL; + in = NULL; + + if (tags.extra_available) { + in = yaffs_find_or_create_by_number(dev, + tags.obj_id, + tags.extra_obj_type); + if (!in) + alloc_failed = 1; + } + + if (!in || + (!in->valid && dev->param.disable_lazy_load) || + tags.extra_shadows || + (!in->valid && (tags.obj_id == YAFFS_OBJECTID_ROOT || + tags.obj_id == YAFFS_OBJECTID_LOSTNFOUND))) { + + /* If we don't have valid info then we + * need to read the chunk + * TODO In future we can probably defer + * reading the chunk and living with + * invalid data until needed. + */ + + result = yaffs_rd_chunk_tags_nand(dev, + chunk, + chunk_data, + NULL); + + oh = (struct yaffs_obj_hdr *)chunk_data; + + if (dev->param.inband_tags) { + /* Fix up the header if they got + * corrupted by inband tags */ + oh->shadows_obj = + oh->inband_shadowed_obj_id; + oh->is_shrink = + oh->inband_is_shrink; + } + + if (!in) { + in = yaffs_find_or_create_by_number(dev, + tags.obj_id, oh->type); + if (!in) + alloc_failed = 1; + } + } + + if (!in) { + /* TODO Hoosterman we have a problem! */ + yaffs_trace(YAFFS_TRACE_ERROR, + "yaffs tragedy: Could not make object for object %d at chunk %d during scan", + tags.obj_id, chunk); + return YAFFS_FAIL; + } + + if (in->valid) { + /* We have already filled this one. + * We have a duplicate that will be + * discarded, but we first have to suck + * out resize info if it is a file. + */ + if ((in->variant_type == YAFFS_OBJECT_TYPE_FILE) && + ((oh && oh->type == YAFFS_OBJECT_TYPE_FILE) || + (tags.extra_available && + tags.extra_obj_type == YAFFS_OBJECT_TYPE_FILE) + )) { + loff_t this_size = (oh) ? + yaffs_oh_to_size(oh) : + tags.extra_file_size; + u32 parent_obj_id = (oh) ? + oh->parent_obj_id : + tags.extra_parent_id; + + is_shrink = (oh) ? + oh->is_shrink : + tags.extra_is_shrink; + + /* If it is deleted (unlinked + * at start also means deleted) + * we treat the file size as + * being zeroed at this point. + */ + if (parent_obj_id == YAFFS_OBJECTID_DELETED || + parent_obj_id == YAFFS_OBJECTID_UNLINKED) { + this_size = 0; + is_shrink = 1; + } + + if (is_shrink && + in->variant.file_variant.shrink_size > + this_size) + in->variant.file_variant.shrink_size = + this_size; + + if (is_shrink) + bi->has_shrink_hdr = 1; + } + /* Use existing - destroy this one. */ + yaffs_chunk_del(dev, chunk, 1, __LINE__); + } + + if (!in->valid && in->variant_type != + (oh ? oh->type : tags.extra_obj_type)) { + yaffs_trace(YAFFS_TRACE_ERROR, + "yaffs tragedy: Bad type, %d != %d, for object %d at chunk %d during scan", + oh ? oh->type : tags.extra_obj_type, + in->variant_type, tags.obj_id, + chunk); + in = yaffs_retype_obj(in, oh ? oh->type : tags.extra_obj_type); + } + + if (!in->valid && + (tags.obj_id == YAFFS_OBJECTID_ROOT || + tags.obj_id == YAFFS_OBJECTID_LOSTNFOUND)) { + /* We only load some info, don't fiddle + * with directory structure */ + in->valid = 1; + + if (oh) { + in->yst_mode = oh->yst_mode; + yaffs_load_attribs(in, oh); + in->lazy_loaded = 0; + } else { + in->lazy_loaded = 1; + } + in->hdr_chunk = chunk; + + } else if (!in->valid) { + /* we need to load this info */ + in->valid = 1; + in->hdr_chunk = chunk; + if (oh) { + in->variant_type = oh->type; + in->yst_mode = oh->yst_mode; + yaffs_load_attribs(in, oh); + + if (oh->shadows_obj > 0) + yaffs_handle_shadowed_obj(dev, + oh->shadows_obj, 1); + + yaffs_set_obj_name_from_oh(in, oh); + parent = yaffs_find_or_create_by_number(dev, + oh->parent_obj_id, + YAFFS_OBJECT_TYPE_DIRECTORY); + file_size = yaffs_oh_to_size(oh); + is_shrink = oh->is_shrink; + equiv_id = oh->equiv_id; + } else { + in->variant_type = tags.extra_obj_type; + parent = yaffs_find_or_create_by_number(dev, + tags.extra_parent_id, + YAFFS_OBJECT_TYPE_DIRECTORY); + file_size = tags.extra_file_size; + is_shrink = tags.extra_is_shrink; + equiv_id = tags.extra_equiv_id; + in->lazy_loaded = 1; + } + in->dirty = 0; + + if (!parent) + alloc_failed = 1; + + /* directory stuff... + * hook up to parent + */ + + if (parent && + parent->variant_type == YAFFS_OBJECT_TYPE_UNKNOWN) { + /* Set up as a directory */ + parent->variant_type = + YAFFS_OBJECT_TYPE_DIRECTORY; + INIT_LIST_HEAD(&parent-> + variant.dir_variant.children); + } else if (!parent || + parent->variant_type != + YAFFS_OBJECT_TYPE_DIRECTORY) { + /* Hoosterman, another problem.... + * Trying to use a non-directory as a directory + */ + + yaffs_trace(YAFFS_TRACE_ERROR, + "yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found." + ); + parent = dev->lost_n_found; + } + yaffs_add_obj_to_dir(parent, in); + + is_unlinked = (parent == dev->del_dir) || + (parent == dev->unlinked_dir); + + if (is_shrink) + /* Mark the block */ + bi->has_shrink_hdr = 1; + + /* Note re hardlinks. + * Since we might scan a hardlink before its equivalent + * object is scanned we put them all in a list. + * After scanning is complete, we should have all the + * objects, so we run through this list and fix up all + * the chains. + */ + + switch (in->variant_type) { + case YAFFS_OBJECT_TYPE_UNKNOWN: + /* Todo got a problem */ + break; + case YAFFS_OBJECT_TYPE_FILE: + file_var = &in->variant.file_variant; + if (file_var->scanned_size < file_size) { + /* This covers the case where the file + * size is greater than the data held. + * This will happen if the file is + * resized to be larger than its + * current data extents. + */ + file_var->file_size = file_size; + file_var->scanned_size = file_size; + } + + if (file_var->shrink_size > file_size) + file_var->shrink_size = file_size; + + break; + case YAFFS_OBJECT_TYPE_HARDLINK: + hl_var = &in->variant.hardlink_variant; + if (!is_unlinked) { + hl_var->equiv_id = equiv_id; + list_add(&in->hard_links, hard_list); + } + break; + case YAFFS_OBJECT_TYPE_DIRECTORY: + /* Do nothing */ + break; + case YAFFS_OBJECT_TYPE_SPECIAL: + /* Do nothing */ + break; + case YAFFS_OBJECT_TYPE_SYMLINK: + sl_var = &in->variant.symlink_variant; + if (oh) { + sl_var->alias = + yaffs_clone_str(oh->alias); + if (!sl_var->alias) + alloc_failed = 1; + } + break; + } + } + } + return alloc_failed ? YAFFS_FAIL : YAFFS_OK; +} + +int yaffs2_scan_backwards(struct yaffs_dev *dev) +{ + int blk; + int block_iter; + int start_iter; + int end_iter; + int n_to_scan = 0; + enum yaffs_block_state state; + int c; + LIST_HEAD(hard_list); + struct yaffs_block_info *bi; + u32 seq_number; + int n_blocks = dev->internal_end_block - dev->internal_start_block + 1; + u8 *chunk_data; + int found_chunks; + int alloc_failed = 0; + struct yaffs_block_index *block_index = NULL; + int alt_block_index = 0; + int summary_available; + + yaffs_trace(YAFFS_TRACE_SCAN, + "yaffs2_scan_backwards starts intstartblk %d intendblk %d...", + dev->internal_start_block, dev->internal_end_block); + + dev->seq_number = YAFFS_LOWEST_SEQUENCE_NUMBER; + + block_index = + kmalloc(n_blocks * sizeof(struct yaffs_block_index), GFP_NOFS); + + if (!block_index) { + block_index = + vmalloc(n_blocks * sizeof(struct yaffs_block_index)); + alt_block_index = 1; + } + + if (!block_index) { + yaffs_trace(YAFFS_TRACE_SCAN, + "yaffs2_scan_backwards() could not allocate block index!" + ); + return YAFFS_FAIL; + } + + dev->blocks_in_checkpt = 0; + + chunk_data = yaffs_get_temp_buffer(dev); + + /* Scan all the blocks to determine their state */ + bi = dev->block_info; + for (blk = dev->internal_start_block; blk <= dev->internal_end_block; + blk++) { + yaffs_clear_chunk_bits(dev, blk); + bi->pages_in_use = 0; + bi->soft_del_pages = 0; + + yaffs_query_init_block_state(dev, blk, &state, &seq_number); + + bi->block_state = state; + bi->seq_number = seq_number; + + if (bi->seq_number == YAFFS_SEQUENCE_CHECKPOINT_DATA) + bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT; + if (bi->seq_number == YAFFS_SEQUENCE_BAD_BLOCK) + bi->block_state = YAFFS_BLOCK_STATE_DEAD; + + yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, + "Block scanning block %d state %d seq %d", + blk, bi->block_state, seq_number); + + if (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT) { + dev->blocks_in_checkpt++; + + } else if (bi->block_state == YAFFS_BLOCK_STATE_DEAD) { + yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, + "block %d is bad", blk); + } else if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) { + yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, "Block empty "); + dev->n_erased_blocks++; + dev->n_free_chunks += dev->param.chunks_per_block; + } else if (bi->block_state == + YAFFS_BLOCK_STATE_NEEDS_SCAN) { + /* Determine the highest sequence number */ + if (seq_number >= YAFFS_LOWEST_SEQUENCE_NUMBER && + seq_number < YAFFS_HIGHEST_SEQUENCE_NUMBER) { + block_index[n_to_scan].seq = seq_number; + block_index[n_to_scan].block = blk; + n_to_scan++; + if (seq_number >= dev->seq_number) + dev->seq_number = seq_number; + } else { + /* TODO: Nasty sequence number! */ + yaffs_trace(YAFFS_TRACE_SCAN, + "Block scanning block %d has bad sequence number %d", + blk, seq_number); + } + } + bi++; + } + + yaffs_trace(YAFFS_TRACE_ALWAYS, "%d blocks to be sorted...", n_to_scan); + + cond_resched(); + + /* Sort the blocks by sequence number */ + sort(block_index, n_to_scan, sizeof(struct yaffs_block_index), + yaffs2_ybicmp, NULL); + + cond_resched(); + + yaffs_trace(YAFFS_TRACE_SCAN, "...done"); + + /* Now scan the blocks looking at the data. */ + start_iter = 0; + end_iter = n_to_scan - 1; + yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, "%d blocks to scan", n_to_scan); + + /* For each block.... backwards */ + for (block_iter = end_iter; + !alloc_failed && block_iter >= start_iter; + block_iter--) { + /* Cooperative multitasking! This loop can run for so + long that watchdog timers expire. */ + cond_resched(); + + /* get the block to scan in the correct order */ + blk = block_index[block_iter].block; + bi = yaffs_get_block_info(dev, blk); + + summary_available = yaffs_summary_read(dev, dev->sum_tags, blk); + + /* For each chunk in each block that needs scanning.... */ + found_chunks = 0; + if (summary_available) + c = dev->chunks_per_summary - 1; + else + c = dev->param.chunks_per_block - 1; + + for (/* c is already initialised */; + !alloc_failed && c >= 0 && + (bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN || + bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING); + c--) { + /* Scan backwards... + * Read the tags and decide what to do + */ + if (yaffs2_scan_chunk(dev, bi, blk, c, + &found_chunks, chunk_data, + &hard_list, summary_available) == + YAFFS_FAIL) + alloc_failed = 1; + } + + if (bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN) { + /* If we got this far while scanning, then the block + * is fully allocated. */ + bi->block_state = YAFFS_BLOCK_STATE_FULL; + } + + /* Now let's see if it was dirty */ + if (bi->pages_in_use == 0 && + !bi->has_shrink_hdr && + bi->block_state == YAFFS_BLOCK_STATE_FULL) { + yaffs_block_became_dirty(dev, blk); + } + } + + yaffs_skip_rest_of_block(dev); + + if (alt_block_index) + vfree(block_index); + else + kfree(block_index); + + /* Ok, we've done all the scanning. + * Fix up the hard link chains. + * We have scanned all the objects, now it's time to add these + * hardlinks. + */ + yaffs_link_fixup(dev, &hard_list); + + yaffs_release_temp_buffer(dev, chunk_data); + + if (alloc_failed) + return YAFFS_FAIL; + + yaffs_trace(YAFFS_TRACE_SCAN, "yaffs2_scan_backwards ends"); + + return YAFFS_OK; +} diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_yaffs2.h b/target/linux/generic/files/fs/yaffs2/yaffs_yaffs2.h new file mode 100644 index 0000000..2363bfd --- /dev/null +++ b/target/linux/generic/files/fs/yaffs2/yaffs_yaffs2.h @@ -0,0 +1,39 @@ +/* + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + */ + +#ifndef __YAFFS_YAFFS2_H__ +#define __YAFFS_YAFFS2_H__ + +#include "yaffs_guts.h" + +void yaffs_calc_oldest_dirty_seq(struct yaffs_dev *dev); +void yaffs2_find_oldest_dirty_seq(struct yaffs_dev *dev); +void yaffs2_clear_oldest_dirty_seq(struct yaffs_dev *dev, + struct yaffs_block_info *bi); +void yaffs2_update_oldest_dirty_seq(struct yaffs_dev *dev, unsigned block_no, + struct yaffs_block_info *bi); +int yaffs_block_ok_for_gc(struct yaffs_dev *dev, struct yaffs_block_info *bi); +u32 yaffs2_find_refresh_block(struct yaffs_dev *dev); +int yaffs2_checkpt_required(struct yaffs_dev *dev); +int yaffs_calc_checkpt_blocks_required(struct yaffs_dev *dev); + +void yaffs2_checkpt_invalidate(struct yaffs_dev *dev); +int yaffs2_checkpt_save(struct yaffs_dev *dev); +int yaffs2_checkpt_restore(struct yaffs_dev *dev); + +int yaffs2_handle_hole(struct yaffs_obj *obj, loff_t new_size); +int yaffs2_scan_backwards(struct yaffs_dev *dev); + +#endif diff --git a/target/linux/generic/files/fs/yaffs2/yportenv.h b/target/linux/generic/files/fs/yaffs2/yportenv.h new file mode 100644 index 0000000..8975af3 --- /dev/null +++ b/target/linux/generic/files/fs/yaffs2/yportenv.h @@ -0,0 +1,85 @@ +/* + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + */ + +#ifndef __YPORTENV_H__ +#define __YPORTENV_H__ + +/* + * Define the MTD version in terms of Linux Kernel versions + * This allows yaffs to be used independantly of the kernel + * as well as with it. + */ + +#define MTD_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c)) + +#ifdef YAFFS_OUT_OF_TREE +#include "moduleconfig.h" +#endif + +#include +#define MTD_VERSION_CODE LINUX_VERSION_CODE + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)) +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* These type wrappings are used to support Unicode names in WinCE. */ +#define YCHAR char +#define YUCHAR unsigned char +#define _Y(x) x + +#define YAFFS_LOSTNFOUND_NAME "lost+found" +#define YAFFS_LOSTNFOUND_PREFIX "obj" + + +#define YAFFS_ROOT_MODE 0755 +#define YAFFS_LOSTNFOUND_MODE 0700 + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) +#define Y_CURRENT_TIME CURRENT_TIME.tv_sec +#define Y_TIME_CONVERT(x) (x).tv_sec +#else +#define Y_CURRENT_TIME CURRENT_TIME +#define Y_TIME_CONVERT(x) (x) +#endif + +#define compile_time_assertion(assertion) \ + ({ int x = __builtin_choose_expr(assertion, 0, (void)0); (void) x; }) + + +#define yaffs_printf(msk, fmt, ...) \ + printk(KERN_DEBUG "yaffs: " fmt "\n", ##__VA_ARGS__) + +#define yaffs_trace(msk, fmt, ...) do { \ + if (yaffs_trace_mask & (msk)) \ + printk(KERN_DEBUG "yaffs: " fmt "\n", ##__VA_ARGS__); \ +} while (0) + + +#endif diff --git a/target/linux/generic/files/include/linux/ar8216_platform.h b/target/linux/generic/files/include/linux/ar8216_platform.h new file mode 100644 index 0000000..d70f11a --- /dev/null +++ b/target/linux/generic/files/include/linux/ar8216_platform.h @@ -0,0 +1,133 @@ +/* + * AR8216 switch driver platform data + * + * Copyright (C) 2012 Gabor Juhos + * + * 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. + */ + +#ifndef AR8216_PLATFORM_H +#define AR8216_PLATFORM_H + +enum ar8327_pad_mode { + AR8327_PAD_NC = 0, + AR8327_PAD_MAC2MAC_MII, + AR8327_PAD_MAC2MAC_GMII, + AR8327_PAD_MAC_SGMII, + AR8327_PAD_MAC2PHY_MII, + AR8327_PAD_MAC2PHY_GMII, + AR8327_PAD_MAC_RGMII, + AR8327_PAD_PHY_GMII, + AR8327_PAD_PHY_RGMII, + AR8327_PAD_PHY_MII, +}; + +enum ar8327_clk_delay_sel { + AR8327_CLK_DELAY_SEL0 = 0, + AR8327_CLK_DELAY_SEL1, + AR8327_CLK_DELAY_SEL2, + AR8327_CLK_DELAY_SEL3, +}; + +struct ar8327_pad_cfg { + enum ar8327_pad_mode mode; + bool rxclk_sel; + bool txclk_sel; + bool pipe_rxclk_sel; + bool txclk_delay_en; + bool rxclk_delay_en; + bool sgmii_delay_en; + enum ar8327_clk_delay_sel txclk_delay_sel; + enum ar8327_clk_delay_sel rxclk_delay_sel; + bool mac06_exchange_en; +}; + +enum ar8327_port_speed { + AR8327_PORT_SPEED_10 = 0, + AR8327_PORT_SPEED_100, + AR8327_PORT_SPEED_1000, +}; + +struct ar8327_port_cfg { + int force_link:1; + enum ar8327_port_speed speed; + int txpause:1; + int rxpause:1; + int duplex:1; +}; + +struct ar8327_sgmii_cfg { + u32 sgmii_ctrl; + bool serdes_aen; +}; + +struct ar8327_led_cfg { + u32 led_ctrl0; + u32 led_ctrl1; + u32 led_ctrl2; + u32 led_ctrl3; + bool open_drain; +}; + +enum ar8327_led_num { + AR8327_LED_PHY0_0 = 0, + AR8327_LED_PHY0_1, + AR8327_LED_PHY0_2, + AR8327_LED_PHY1_0, + AR8327_LED_PHY1_1, + AR8327_LED_PHY1_2, + AR8327_LED_PHY2_0, + AR8327_LED_PHY2_1, + AR8327_LED_PHY2_2, + AR8327_LED_PHY3_0, + AR8327_LED_PHY3_1, + AR8327_LED_PHY3_2, + AR8327_LED_PHY4_0, + AR8327_LED_PHY4_1, + AR8327_LED_PHY4_2, +}; + +enum ar8327_led_mode { + AR8327_LED_MODE_HW = 0, + AR8327_LED_MODE_SW, +}; + +struct ar8327_led_info { + const char *name; + const char *default_trigger; + bool active_low; + enum ar8327_led_num led_num; + enum ar8327_led_mode mode; +}; + +#define AR8327_LED_INFO(_led, _mode, _name) { \ + .name = (_name), \ + .led_num = AR8327_LED_ ## _led, \ + .mode = AR8327_LED_MODE_ ## _mode \ +} + +struct ar8327_platform_data { + struct ar8327_pad_cfg *pad0_cfg; + struct ar8327_pad_cfg *pad5_cfg; + struct ar8327_pad_cfg *pad6_cfg; + struct ar8327_sgmii_cfg *sgmii_cfg; + struct ar8327_port_cfg port0_cfg; + struct ar8327_port_cfg port6_cfg; + struct ar8327_led_cfg *led_cfg; + + int (*get_port_link)(unsigned port); + + unsigned num_leds; + const struct ar8327_led_info *leds; +}; + +#endif /* AR8216_PLATFORM_H */ + diff --git a/target/linux/generic/files/include/linux/ath5k_platform.h b/target/linux/generic/files/include/linux/ath5k_platform.h new file mode 100644 index 0000000..ec85224 --- /dev/null +++ b/target/linux/generic/files/include/linux/ath5k_platform.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2008 Atheros Communications Inc. + * Copyright (c) 2009 Gabor Juhos + * Copyright (c) 2009 Imre Kaloz + * Copyright (c) 2010 Daniel Golle + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _LINUX_ATH5K_PLATFORM_H +#define _LINUX_ATH5K_PLATFORM_H + +#define ATH5K_PLAT_EEP_MAX_WORDS 2048 + +struct ath5k_platform_data { + u16 *eeprom_data; + u8 *macaddr; +}; + +#endif /* _LINUX_ATH5K_PLATFORM_H */ diff --git a/target/linux/generic/files/include/linux/ath9k_platform.h b/target/linux/generic/files/include/linux/ath9k_platform.h new file mode 100644 index 0000000..9fa7016 --- /dev/null +++ b/target/linux/generic/files/include/linux/ath9k_platform.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2008 Atheros Communications Inc. + * Copyright (c) 2009 Gabor Juhos + * Copyright (c) 2009 Imre Kaloz + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _LINUX_ATH9K_PLATFORM_H +#define _LINUX_ATH9K_PLATFORM_H + +#define ATH9K_PLAT_EEP_MAX_WORDS 2048 + +struct ath9k_platform_data { + const char *eeprom_name; + + u16 eeprom_data[ATH9K_PLAT_EEP_MAX_WORDS]; + u8 *macaddr; + + int led_pin; + u32 gpio_mask; + u32 gpio_val; + + bool endian_check; + bool is_clk_25mhz; + bool tx_gain_buffalo; + bool disable_2ghz; + bool disable_5ghz; + + int (*get_mac_revision)(void); + int (*external_reset)(void); + + bool use_eeprom; + + int num_leds; + const struct gpio_led *leds; +}; + +#endif /* _LINUX_ATH9K_PLATFORM_H */ diff --git a/target/linux/generic/files/include/linux/myloader.h b/target/linux/generic/files/include/linux/myloader.h new file mode 100644 index 0000000..d89e415 --- /dev/null +++ b/target/linux/generic/files/include/linux/myloader.h @@ -0,0 +1,121 @@ +/* + * Compex's MyLoader specific definitions + * + * Copyright (C) 2006-2008 Gabor Juhos + * + * 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. + * + */ + +#ifndef _MYLOADER_H_ +#define _MYLOADER_H_ + +/* Myloader specific magic numbers */ +#define MYLO_MAGIC_SYS_PARAMS 0x20021107 +#define MYLO_MAGIC_PARTITIONS 0x20021103 +#define MYLO_MAGIC_BOARD_PARAMS 0x20021103 + +/* Vendor ID's (seems to be same as the PCI vendor ID's) */ +#define VENID_COMPEX 0x11F6 + +/* Devices based on the ADM5120 */ +#define DEVID_COMPEX_NP27G 0x0078 +#define DEVID_COMPEX_NP28G 0x044C +#define DEVID_COMPEX_NP28GHS 0x044E +#define DEVID_COMPEX_WP54Gv1C 0x0514 +#define DEVID_COMPEX_WP54G 0x0515 +#define DEVID_COMPEX_WP54AG 0x0546 +#define DEVID_COMPEX_WPP54AG 0x0550 +#define DEVID_COMPEX_WPP54G 0x0555 + +/* Devices based on the Atheros AR2317 */ +#define DEVID_COMPEX_NP25G 0x05E6 +#define DEVID_COMPEX_WPE53G 0x05DC + +/* Devices based on the Atheros AR71xx */ +#define DEVID_COMPEX_WP543 0x0640 +#define DEVID_COMPEX_WPE72 0x0672 + +/* Devices based on the IXP422 */ +#define DEVID_COMPEX_WP18 0x047E +#define DEVID_COMPEX_NP18A 0x0489 + +/* Other devices */ +#define DEVID_COMPEX_NP26G8M 0x03E8 +#define DEVID_COMPEX_NP26G16M 0x03E9 + +struct mylo_partition { + uint16_t flags; /* partition flags */ + uint16_t type; /* type of the partition */ + uint32_t addr; /* relative address of the partition from the + flash start */ + uint32_t size; /* size of the partition in bytes */ + uint32_t param; /* if this is the active partition, the + MyLoader load code to this address */ +}; + +#define PARTITION_FLAG_ACTIVE 0x8000 /* this is the active partition, + * MyLoader loads firmware from here */ +#define PARTITION_FLAG_ISRAM 0x2000 /* FIXME: this is a RAM partition? */ +#define PARTIIION_FLAG_RAMLOAD 0x1000 /* FIXME: load this partition into the RAM? */ +#define PARTITION_FLAG_PRELOAD 0x0800 /* the partition data preloaded to RAM + * before decompression */ +#define PARTITION_FLAG_LZMA 0x0100 /* partition data compressed by LZMA */ +#define PARTITION_FLAG_HAVEHDR 0x0002 /* the partition data have a header */ + +#define PARTITION_TYPE_FREE 0 +#define PARTITION_TYPE_USED 1 + +#define MYLO_MAX_PARTITIONS 8 /* maximum number of partitions in the + partition table */ + +struct mylo_partition_table { + uint32_t magic; /* must be MYLO_MAGIC_PARTITIONS */ + uint32_t res0; /* unknown/unused */ + uint32_t res1; /* unknown/unused */ + uint32_t res2; /* unknown/unused */ + struct mylo_partition partitions[MYLO_MAX_PARTITIONS]; +}; + +struct mylo_partition_header { + uint32_t len; /* length of the partition data */ + uint32_t crc; /* CRC value of the partition data */ +}; + +struct mylo_system_params { + uint32_t magic; /* must be MYLO_MAGIC_SYS_PARAMS */ + uint32_t res0; + uint32_t res1; + uint32_t mylo_ver; + uint16_t vid; /* Vendor ID */ + uint16_t did; /* Device ID */ + uint16_t svid; /* Sub Vendor ID */ + uint16_t sdid; /* Sub Device ID */ + uint32_t rev; /* device revision */ + uint32_t fwhi; + uint32_t fwlo; + uint32_t tftp_addr; + uint32_t prog_start; + uint32_t flash_size; /* size of boot FLASH in bytes */ + uint32_t dram_size; /* size of onboard RAM in bytes */ +}; + +struct mylo_eth_addr { + uint8_t mac[6]; + uint8_t csum[2]; +}; + +#define MYLO_ETHADDR_COUNT 8 /* maximum number of ethernet address + in the board parameters */ + +struct mylo_board_params { + uint32_t magic; /* must be MYLO_MAGIC_BOARD_PARAMS */ + uint32_t res0; + uint32_t res1; + uint32_t res2; + struct mylo_eth_addr addr[MYLO_ETHADDR_COUNT]; +}; + +#endif /* _MYLOADER_H_*/ diff --git a/target/linux/generic/files/include/linux/platform_data/adm6996-gpio.h b/target/linux/generic/files/include/linux/platform_data/adm6996-gpio.h new file mode 100644 index 0000000..e4fcfaf --- /dev/null +++ b/target/linux/generic/files/include/linux/platform_data/adm6996-gpio.h @@ -0,0 +1,30 @@ +/* + * ADM6996 GPIO platform data + * + * Copyright (C) 2013 Hauke Mehrtens + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License v2 as published by the + * Free Software Foundation + */ + +#ifndef __PLATFORM_ADM6996_GPIO_H +#define __PLATFORM_ADM6996_GPIO_H + +#include + +enum adm6996_model { + ADM6996FC = 1, + ADM6996M = 2, + ADM6996L = 3, +}; + +struct adm6996_gpio_platform_data { + u8 eecs; + u8 eesk; + u8 eedi; + u8 eerc; + enum adm6996_model model; +}; + +#endif diff --git a/target/linux/generic/files/include/linux/platform_data/b53.h b/target/linux/generic/files/include/linux/platform_data/b53.h new file mode 100644 index 0000000..7842741 --- /dev/null +++ b/target/linux/generic/files/include/linux/platform_data/b53.h @@ -0,0 +1,36 @@ +/* + * B53 platform data + * + * Copyright (C) 2013 Jonas Gorski + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __B53_H +#define __B53_H + +#include + +struct b53_platform_data { + u32 chip_id; + u16 enabled_ports; + + /* allow to specify an ethX alias */ + const char *alias; + + /* only used by MMAP'd driver */ + unsigned big_endian:1; + void __iomem *regs; +}; + +#endif diff --git a/target/linux/generic/files/include/linux/platform_data/brcmfmac-sdio.h b/target/linux/generic/files/include/linux/platform_data/brcmfmac-sdio.h new file mode 100644 index 0000000..1ade657 --- /dev/null +++ b/target/linux/generic/files/include/linux/platform_data/brcmfmac-sdio.h @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2013 Broadcom Corporation + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _LINUX_BRCMFMAC_PLATFORM_H +#define _LINUX_BRCMFMAC_PLATFORM_H + +/* + * Platform specific driver functions and data. Through the platform specific + * device data functions can be provided to help the brcmfmac driver to + * operate with the device in combination with the used platform. + * + * Use the platform data in the following (similar) way: + * + * +#include + + +static void brcmfmac_power_on(void) +{ +} + +static void brcmfmac_power_off(void) +{ +} + +static void brcmfmac_reset(void) +{ +} + +static struct brcmfmac_sdio_platform_data brcmfmac_sdio_pdata = { + .power_on = brcmfmac_power_on, + .power_off = brcmfmac_power_off, + .reset = brcmfmac_reset +}; + +static struct platform_device brcmfmac_device = { + .name = BRCMFMAC_SDIO_PDATA_NAME, + .id = PLATFORM_DEVID_NONE, + .dev.platform_data = &brcmfmac_sdio_pdata +}; + +void __init brcmfmac_init_pdata(void) +{ + brcmfmac_sdio_pdata.oob_irq_supported = true; + brcmfmac_sdio_pdata.oob_irq_nr = gpio_to_irq(GPIO_BRCMF_SDIO_OOB); + brcmfmac_sdio_pdata.oob_irq_flags = IORESOURCE_IRQ | + IORESOURCE_IRQ_HIGHLEVEL; + platform_device_register(&brcmfmac_device); +} + * + * + * Note: the brcmfmac can be loaded as module or be statically built-in into + * the kernel. If built-in then do note that it uses module_init (and + * module_exit) routines which equal device_initcall. So if you intend to + * create a module with the platform specific data for the brcmfmac and have + * it built-in to the kernel then use a higher initcall then device_initcall + * (see init.h). If this is not done then brcmfmac will load without problems + * but will not pickup the platform data. + * + * When the driver does not "detect" platform driver data then it will continue + * without reporting anything and just assume there is no data needed. Which is + * probably true for most platforms. + * + * Explanation of the platform_data fields: + * + * drive_strength: is the preferred drive_strength to be used for the SDIO + * pins. If 0 then a default value will be used. This is the target drive + * strength, the exact drive strength which will be used depends on the + * capabilities of the device. + * + * oob_irq_supported: does the board have support for OOB interrupts. SDIO + * in-band interrupts are relatively slow and for having less overhead on + * interrupt processing an out of band interrupt can be used. If the HW + * supports this then enable this by setting this field to true and configure + * the oob related fields. + * + * oob_irq_nr, oob_irq_flags: the OOB interrupt information. The values are + * used for registering the irq using request_irq function. + * + * power_on: This function is called by the brcmfmac when the module gets + * loaded. This can be particularly useful for low power devices. The platform + * spcific routine may for example decide to power up the complete device. + * If there is no use-case for this function then provide NULL. + * + * power_off: This function is called by the brcmfmac when the module gets + * unloaded. At this point the device can be powered down or otherwise be reset. + * So if an actual power_off is not supported but reset is then reset the device + * when this function gets called. This can be particularly useful for low power + * devices. If there is no use-case for this function (either power-down or + * reset) then provide NULL. + * + * reset: This function can get called if the device communication broke down. + * This functionality is particularly useful in case of SDIO type devices. It is + * possible to reset a dongle via sdio data interface, but it requires that + * this is fully functional. This function is chip/module specific and this + * function should return only after the complete reset has completed. + */ + +#define BRCMFMAC_SDIO_PDATA_NAME "brcmfmac_sdio" + +struct brcmfmac_sdio_platform_data { + unsigned int drive_strength; + bool oob_irq_supported; + unsigned int oob_irq_nr; + unsigned long oob_irq_flags; + void (*power_on)(void); + void (*power_off)(void); + void (*reset)(void); +}; + +#endif /* _LINUX_BRCMFMAC_PLATFORM_H */ diff --git a/target/linux/generic/files/include/linux/routerboot.h b/target/linux/generic/files/include/linux/routerboot.h new file mode 100644 index 0000000..3cda858 --- /dev/null +++ b/target/linux/generic/files/include/linux/routerboot.h @@ -0,0 +1,106 @@ +/* + * Mikrotik's RouterBOOT definitions + * + * Copyright (C) 2007-2008 Gabor Juhos + * + * 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. + * + */ + +#ifndef _ROUTERBOOT_H +#define _ROUTERBOOT_H + +#define RB_MAC_SIZE 6 + +/* + * Magic numbers + */ +#define RB_MAGIC_HARD 0x64726148 /* "Hard" */ +#define RB_MAGIC_SOFT 0x74666F53 /* "Soft" */ +#define RB_MAGIC_DAWN 0x6E776144 /* "Dawn" */ + +#define RB_ID_TERMINATOR 0 + +/* + * ID values for Hardware settings + */ +#define RB_ID_HARD_01 1 +#define RB_ID_HARD_02 2 +#define RB_ID_FLASH_INFO 3 +#define RB_ID_MAC_ADDRESS_PACK 4 +#define RB_ID_BOARD_NAME 5 +#define RB_ID_BIOS_VERSION 6 +#define RB_ID_HARD_07 7 +#define RB_ID_SDRAM_TIMINGS 8 +#define RB_ID_DEVICE_TIMINGS 9 +#define RB_ID_SOFTWARE_ID 10 +#define RB_ID_SERIAL_NUMBER 11 +#define RB_ID_HARD_12 12 +#define RB_ID_MEMORY_SIZE 13 +#define RB_ID_MAC_ADDRESS_COUNT 14 +#define RB_ID_HW_OPTIONS 21 +#define RB_ID_WLAN_DATA 22 + +/* + * ID values for Software settings + */ +#define RB_ID_UART_SPEED 1 +#define RB_ID_BOOT_DELAY 2 +#define RB_ID_BOOT_DEVICE 3 +#define RB_ID_BOOT_KEY 4 +#define RB_ID_CPU_MODE 5 +#define RB_ID_FW_VERSION 6 +#define RB_ID_SOFT_07 7 +#define RB_ID_SOFT_08 8 +#define RB_ID_BOOT_PROTOCOL 9 +#define RB_ID_SOFT_10 10 +#define RB_ID_SOFT_11 11 + +/* + * UART_SPEED values + */ +#define RB_UART_SPEED_115200 0 +#define RB_UART_SPEED_57600 1 +#define RB_UART_SPEED_38400 2 +#define RB_UART_SPEED_19200 3 +#define RB_UART_SPEED_9600 4 +#define RB_UART_SPEED_4800 5 +#define RB_UART_SPEED_2400 6 +#define RB_UART_SPEED_1200 7 + +/* + * BOOT_DELAY values + */ +#define RB_BOOT_DELAY_0SEC 0 +#define RB_BOOT_DELAY_1SEC 1 +#define RB_BOOT_DELAY_2SEC 2 + +/* + * BOOT_DEVICE values + */ +#define RB_BOOT_DEVICE_ETHER 0 +#define RB_BOOT_DEVICE_NANDETH 1 +#define RB_BOOT_DEVICE_ETHONCE 2 +#define RB_BOOT_DEVICE_NANDONLY 3 + +/* + * BOOT_KEY values + */ +#define RB_BOOT_KEY_ANY 0 +#define RB_BOOT_KEY_DEL 1 + +/* + * CPU_MODE values + */ +#define RB_CPU_MODE_POWERSAVE 0 +#define RB_CPU_MODE_REGULAR 1 + +/* + * BOOT_PROTOCOL values + */ +#define RB_BOOT_PROTOCOL_BOOTP 0 +#define RB_BOOT_PROTOCOL_DHCP 1 + +#endif /* _ROUTERBOOT_H */ diff --git a/target/linux/generic/files/include/linux/rt2x00_platform.h b/target/linux/generic/files/include/linux/rt2x00_platform.h new file mode 100644 index 0000000..80483ef --- /dev/null +++ b/target/linux/generic/files/include/linux/rt2x00_platform.h @@ -0,0 +1,24 @@ +/* + * Platform data definition for the rt2x00 driver + * + * Copyright (C) 2011 Gabor Juhos + * + * 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. + * + */ + +#ifndef _RT2X00_PLATFORM_H +#define _RT2X00_PLATFORM_H + +struct rt2x00_platform_data { + char *eeprom_file_name; + const u8 *mac_address; + + int disable_2ghz; + int disable_5ghz; + int clk_is_20mhz; +}; + +#endif /* _RT2X00_PLATFORM_H */ diff --git a/target/linux/generic/files/include/linux/rtl8366.h b/target/linux/generic/files/include/linux/rtl8366.h new file mode 100644 index 0000000..78daed2 --- /dev/null +++ b/target/linux/generic/files/include/linux/rtl8366.h @@ -0,0 +1,40 @@ +/* + * Platform data definition for the Realtek RTL8366RB/S ethernet switch driver + * + * Copyright (C) 2009-2010 Gabor Juhos + * + * 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. + */ + +#ifndef _RTL8366_H +#define _RTL8366_H + +#define RTL8366_DRIVER_NAME "rtl8366" +#define RTL8366S_DRIVER_NAME "rtl8366s" +#define RTL8366RB_DRIVER_NAME "rtl8366rb" + +enum rtl8366_type { + RTL8366_TYPE_UNKNOWN, + RTL8366_TYPE_S, + RTL8366_TYPE_RB, +}; + +struct rtl8366_initval { + unsigned reg; + u16 val; +}; + +struct rtl8366_platform_data { + unsigned gpio_sda; + unsigned gpio_sck; + void (*hw_reset)(bool active); + + unsigned num_initvals; + struct rtl8366_initval *initvals; +}; + +enum rtl8366_type rtl8366_smi_detect(struct rtl8366_platform_data *pdata); + +#endif /* _RTL8366_H */ diff --git a/target/linux/generic/files/include/linux/rtl8367.h b/target/linux/generic/files/include/linux/rtl8367.h new file mode 100644 index 0000000..855de6a --- /dev/null +++ b/target/linux/generic/files/include/linux/rtl8367.h @@ -0,0 +1,60 @@ +/* + * Platform data definition for the Realtek RTL8367 ethernet switch driver + * + * Copyright (C) 2011 Gabor Juhos + * + * 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. + */ + +#ifndef _RTL8367_H +#define _RTL8367_H + +#define RTL8367_DRIVER_NAME "rtl8367" +#define RTL8367B_DRIVER_NAME "rtl8367b" + +enum rtl8367_port_speed { + RTL8367_PORT_SPEED_10 = 0, + RTL8367_PORT_SPEED_100, + RTL8367_PORT_SPEED_1000, +}; + +struct rtl8367_port_ability { + int force_mode; + int nway; + int txpause; + int rxpause; + int link; + int duplex; + enum rtl8367_port_speed speed; +}; + +enum rtl8367_extif_mode { + RTL8367_EXTIF_MODE_DISABLED = 0, + RTL8367_EXTIF_MODE_RGMII, + RTL8367_EXTIF_MODE_MII_MAC, + RTL8367_EXTIF_MODE_MII_PHY, + RTL8367_EXTIF_MODE_TMII_MAC, + RTL8367_EXTIF_MODE_TMII_PHY, + RTL8367_EXTIF_MODE_GMII, + RTL8367_EXTIF_MODE_RGMII_33V, +}; + +struct rtl8367_extif_config { + unsigned int txdelay; + unsigned int rxdelay; + enum rtl8367_extif_mode mode; + struct rtl8367_port_ability ability; +}; + +struct rtl8367_platform_data { + unsigned gpio_sda; + unsigned gpio_sck; + void (*hw_reset)(bool active); + + struct rtl8367_extif_config *extif0_cfg; + struct rtl8367_extif_config *extif1_cfg; +}; + +#endif /* _RTL8367_H */ diff --git a/target/linux/generic/files/include/linux/switch.h b/target/linux/generic/files/include/linux/switch.h new file mode 100644 index 0000000..4291364 --- /dev/null +++ b/target/linux/generic/files/include/linux/switch.h @@ -0,0 +1,169 @@ +/* + * switch.h: Switch configuration API + * + * Copyright (C) 2008 Felix Fietkau + * + * 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. + */ +#ifndef _LINUX_SWITCH_H +#define _LINUX_SWITCH_H + +#include +#include + +struct switch_dev; +struct switch_op; +struct switch_val; +struct switch_attr; +struct switch_attrlist; +struct switch_led_trigger; + +int register_switch(struct switch_dev *dev, struct net_device *netdev); +void unregister_switch(struct switch_dev *dev); + +/** + * struct switch_attrlist - attribute list + * + * @n_attr: number of attributes + * @attr: pointer to the attributes array + */ +struct switch_attrlist { + int n_attr; + const struct switch_attr *attr; +}; + +enum switch_port_speed { + SWITCH_PORT_SPEED_UNKNOWN = 0, + SWITCH_PORT_SPEED_10 = 10, + SWITCH_PORT_SPEED_100 = 100, + SWITCH_PORT_SPEED_1000 = 1000, +}; + +struct switch_port_link { + bool link; + bool duplex; + bool aneg; + bool tx_flow; + bool rx_flow; + enum switch_port_speed speed; + /* in ethtool adv_t format */ + u32 eee; +}; + +struct switch_port_stats { + unsigned long tx_bytes; + unsigned long rx_bytes; +}; + +/** + * struct switch_dev_ops - switch driver operations + * + * @attr_global: global switch attribute list + * @attr_port: port attribute list + * @attr_vlan: vlan attribute list + * + * Callbacks: + * + * @get_vlan_ports: read the port list of a VLAN + * @set_vlan_ports: set the port list of a VLAN + * + * @get_port_pvid: get the primary VLAN ID of a port + * @set_port_pvid: set the primary VLAN ID of a port + * + * @apply_config: apply all changed settings to the switch + * @reset_switch: resetting the switch + */ +struct switch_dev_ops { + struct switch_attrlist attr_global, attr_port, attr_vlan; + + int (*get_vlan_ports)(struct switch_dev *dev, struct switch_val *val); + int (*set_vlan_ports)(struct switch_dev *dev, struct switch_val *val); + + int (*get_port_pvid)(struct switch_dev *dev, int port, int *val); + int (*set_port_pvid)(struct switch_dev *dev, int port, int val); + + int (*apply_config)(struct switch_dev *dev); + int (*reset_switch)(struct switch_dev *dev); + + int (*get_port_link)(struct switch_dev *dev, int port, + struct switch_port_link *link); + int (*get_port_stats)(struct switch_dev *dev, int port, + struct switch_port_stats *stats); +}; + +struct switch_dev { + struct device_node *of_node; + const struct switch_dev_ops *ops; + /* will be automatically filled */ + char devname[IFNAMSIZ]; + + const char *name; + /* NB: either alias or netdev must be set */ + const char *alias; + struct net_device *netdev; + + int ports; + int vlans; + int cpu_port; + + /* the following fields are internal for swconfig */ + int id; + struct list_head dev_list; + unsigned long def_global, def_port, def_vlan; + + struct mutex sw_mutex; + struct switch_port *portbuf; + struct switch_portmap *portmap; + + char buf[128]; + +#ifdef CONFIG_SWCONFIG_LEDS + struct switch_led_trigger *led_trigger; +#endif +}; + +struct switch_port { + u32 id; + u32 flags; +}; + +struct switch_portmap { + u32 virt; + const char *s; +}; + +struct switch_val { + const struct switch_attr *attr; + int port_vlan; + int len; + union { + const char *s; + u32 i; + struct switch_port *ports; + } value; +}; + +struct switch_attr { + int disabled; + int type; + const char *name; + const char *description; + + int (*set)(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val); + int (*get)(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val); + + /* for driver internal use */ + int id; + int ofs; + int max; +}; + +#endif /* _LINUX_SWITCH_H */ diff --git a/target/linux/generic/files/include/uapi/linux/switch.h b/target/linux/generic/files/include/uapi/linux/switch.h new file mode 100644 index 0000000..a59b239 --- /dev/null +++ b/target/linux/generic/files/include/uapi/linux/switch.h @@ -0,0 +1,103 @@ +/* + * switch.h: Switch configuration API + * + * Copyright (C) 2008 Felix Fietkau + * + * 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. + */ + +#ifndef _UAPI_LINUX_SWITCH_H +#define _UAPI_LINUX_SWITCH_H + +#include +#include +#include +#include +#ifndef __KERNEL__ +#include +#include +#include +#endif + +/* main attributes */ +enum { + SWITCH_ATTR_UNSPEC, + /* global */ + SWITCH_ATTR_TYPE, + /* device */ + SWITCH_ATTR_ID, + SWITCH_ATTR_DEV_NAME, + SWITCH_ATTR_ALIAS, + SWITCH_ATTR_NAME, + SWITCH_ATTR_VLANS, + SWITCH_ATTR_PORTS, + SWITCH_ATTR_PORTMAP, + SWITCH_ATTR_CPU_PORT, + /* attributes */ + SWITCH_ATTR_OP_ID, + SWITCH_ATTR_OP_TYPE, + SWITCH_ATTR_OP_NAME, + SWITCH_ATTR_OP_PORT, + SWITCH_ATTR_OP_VLAN, + SWITCH_ATTR_OP_VALUE_INT, + SWITCH_ATTR_OP_VALUE_STR, + SWITCH_ATTR_OP_VALUE_PORTS, + SWITCH_ATTR_OP_DESCRIPTION, + /* port lists */ + SWITCH_ATTR_PORT, + SWITCH_ATTR_MAX +}; + +enum { + /* port map */ + SWITCH_PORTMAP_PORTS, + SWITCH_PORTMAP_SEGMENT, + SWITCH_PORTMAP_VIRT, + SWITCH_PORTMAP_MAX +}; + +/* commands */ +enum { + SWITCH_CMD_UNSPEC, + SWITCH_CMD_GET_SWITCH, + SWITCH_CMD_NEW_ATTR, + SWITCH_CMD_LIST_GLOBAL, + SWITCH_CMD_GET_GLOBAL, + SWITCH_CMD_SET_GLOBAL, + SWITCH_CMD_LIST_PORT, + SWITCH_CMD_GET_PORT, + SWITCH_CMD_SET_PORT, + SWITCH_CMD_LIST_VLAN, + SWITCH_CMD_GET_VLAN, + SWITCH_CMD_SET_VLAN +}; + +/* data types */ +enum switch_val_type { + SWITCH_TYPE_UNSPEC, + SWITCH_TYPE_INT, + SWITCH_TYPE_STRING, + SWITCH_TYPE_PORTS, + SWITCH_TYPE_NOVAL, +}; + +/* port nested attributes */ +enum { + SWITCH_PORT_UNSPEC, + SWITCH_PORT_ID, + SWITCH_PORT_FLAG_TAGGED, + SWITCH_PORT_ATTR_MAX +}; + +#define SWITCH_ATTR_DEFAULTS_OFFSET 0x1000 + + +#endif /* _UAPI_LINUX_SWITCH_H */ diff --git a/target/linux/generic/image/Makefile b/target/linux/generic/image/Makefile new file mode 100644 index 0000000..e733e0a --- /dev/null +++ b/target/linux/generic/image/Makefile @@ -0,0 +1,12 @@ +# +# Copyright (C) 2006-2010 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# +include $(TOPDIR)/rules.mk +include $(INCLUDE_DIR)/image.mk + +# use default targets for everything + +$(eval $(call BuildImage)) diff --git a/target/linux/generic/image/initramfs-base-files.txt b/target/linux/generic/image/initramfs-base-files.txt new file mode 100644 index 0000000..eda5d0d --- /dev/null +++ b/target/linux/generic/image/initramfs-base-files.txt @@ -0,0 +1,9 @@ +nod /dev/console 600 0 0 c 5 1 +nod /dev/null 666 0 0 c 1 3 +nod /dev/zero 666 0 0 c 1 5 +nod /dev/tty 666 0 0 c 5 0 +nod /dev/tty0 660 0 0 c 4 0 +nod /dev/tty1 660 0 0 c 4 1 +nod /dev/random 666 0 0 c 1 8 +nod /dev/urandom 666 0 0 c 1 9 +dir /dev/pts 755 0 0 diff --git a/target/linux/generic/image/lzma-loader/Makefile b/target/linux/generic/image/lzma-loader/Makefile new file mode 100644 index 0000000..d75a446 --- /dev/null +++ b/target/linux/generic/image/lzma-loader/Makefile @@ -0,0 +1,46 @@ +# +# Copyright (C) 2006 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +include $(TOPDIR)/rules.mk + +PKG_NAME := loader +PKG_VERSION := 0.05 + +PKG_BUILD_DIR := $(KDIR)/$(PKG_NAME)-$(PKG_VERSION)$(LOADER_TYPE) + +$(PKG_BUILD_DIR)/.prepared: + mkdir $(PKG_BUILD_DIR) + $(CP) ./src/* $(PKG_BUILD_DIR)/ + touch $@ + +$(PKG_BUILD_DIR)/lzma.elf: $(PKG_BUILD_DIR)/.prepared $(PKG_BUILD_DIR)/vmlinux.lzma + PATH="$(TARGET_PATH)" $(MAKE) -C $(PKG_BUILD_DIR) \ + CC="$(TARGET_CC)" CROSS_COMPILE="$(TARGET_CROSS)" \ + RAMSIZE=$(RAMSIZE) \ + LOADADDR=$(LOADADDR) \ + KERNEL_ENTRY=$(KERNEL_ENTRY) \ + IMAGE_COPY=$(IMAGE_COPY) + + +$(PKG_BUILD_DIR)/vmlinux.lzma: $(KDIR)/vmlinux.lzma + $(CP) $< $@ + +$(KDIR)/loader$(LOADER_TYPE).elf: $(PKG_BUILD_DIR)/lzma.elf + $(CP) $< $@ + +$(KDIR)/loader$(LOADER_TYPE).bin: $(PKG_BUILD_DIR)/lzma.bin + $(CP) $< $@ + +download: +prepare: $(PKG_BUILD_DIR)/.prepared +compile: $(KDIR)/loader$(LOADER_TYPE).elf $(KDIR)/loader$(LOADER_TYPE).bin +install: + +clean: + rm -rf $(PKG_BUILD_DIR) + rm -f $(KDIR)/loader.elf + rm -f $(KDIR)/loader.bin diff --git a/target/linux/generic/image/lzma-loader/src/LzmaDecode.c b/target/linux/generic/image/lzma-loader/src/LzmaDecode.c new file mode 100644 index 0000000..c90a0d3 --- /dev/null +++ b/target/linux/generic/image/lzma-loader/src/LzmaDecode.c @@ -0,0 +1,590 @@ +/* + LzmaDecode.c + LZMA Decoder (optimized for Speed version) + + LZMA SDK 4.22 Copyright (c) 1999-2005 Igor Pavlov (2005-06-10) + http://www.7-zip.org/ + + LZMA SDK is licensed under two licenses: + 1) GNU Lesser General Public License (GNU LGPL) + 2) Common Public License (CPL) + It means that you can select one of these two licenses and + follow rules of that license. + + SPECIAL EXCEPTION: + Igor Pavlov, as the author of this Code, expressly permits you to + statically or dynamically link your Code (or bind by name) to the + interfaces of this file without subjecting your linked Code to the + terms of the CPL or GNU LGPL. Any modifications or additions + to this file, however, are subject to the LGPL or CPL terms. +*/ + +#include "LzmaDecode.h" + +#ifndef Byte +#define Byte unsigned char +#endif + +#define kNumTopBits 24 +#define kTopValue ((UInt32)1 << kNumTopBits) + +#define kNumBitModelTotalBits 11 +#define kBitModelTotal (1 << kNumBitModelTotalBits) +#define kNumMoveBits 5 + +#define RC_READ_BYTE (*Buffer++) + +#define RC_INIT2 Code = 0; Range = 0xFFFFFFFF; \ + { int i; for(i = 0; i < 5; i++) { RC_TEST; Code = (Code << 8) | RC_READ_BYTE; }} + +#ifdef _LZMA_IN_CB + +#define RC_TEST { if (Buffer == BufferLim) \ + { SizeT size; int result = InCallback->Read(InCallback, &Buffer, &size); if (result != LZMA_RESULT_OK) return result; \ + BufferLim = Buffer + size; if (size == 0) return LZMA_RESULT_DATA_ERROR; }} + +#define RC_INIT Buffer = BufferLim = 0; RC_INIT2 + +#else + +#define RC_TEST { if (Buffer == BufferLim) return LZMA_RESULT_DATA_ERROR; } + +#define RC_INIT(buffer, bufferSize) Buffer = buffer; BufferLim = buffer + bufferSize; RC_INIT2 + +#endif + +#define RC_NORMALIZE if (Range < kTopValue) { RC_TEST; Range <<= 8; Code = (Code << 8) | RC_READ_BYTE; } + +#define IfBit0(p) RC_NORMALIZE; bound = (Range >> kNumBitModelTotalBits) * *(p); if (Code < bound) +#define UpdateBit0(p) Range = bound; *(p) += (kBitModelTotal - *(p)) >> kNumMoveBits; +#define UpdateBit1(p) Range -= bound; Code -= bound; *(p) -= (*(p)) >> kNumMoveBits; + +#define RC_GET_BIT2(p, mi, A0, A1) IfBit0(p) \ + { UpdateBit0(p); mi <<= 1; A0; } else \ + { UpdateBit1(p); mi = (mi + mi) + 1; A1; } + +#define RC_GET_BIT(p, mi) RC_GET_BIT2(p, mi, ; , ;) + +#define RangeDecoderBitTreeDecode(probs, numLevels, res) \ + { int i = numLevels; res = 1; \ + do { CProb *p = probs + res; RC_GET_BIT(p, res) } while(--i != 0); \ + res -= (1 << numLevels); } + + +#define kNumPosBitsMax 4 +#define kNumPosStatesMax (1 << kNumPosBitsMax) + +#define kLenNumLowBits 3 +#define kLenNumLowSymbols (1 << kLenNumLowBits) +#define kLenNumMidBits 3 +#define kLenNumMidSymbols (1 << kLenNumMidBits) +#define kLenNumHighBits 8 +#define kLenNumHighSymbols (1 << kLenNumHighBits) + +#define LenChoice 0 +#define LenChoice2 (LenChoice + 1) +#define LenLow (LenChoice2 + 1) +#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits)) +#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits)) +#define kNumLenProbs (LenHigh + kLenNumHighSymbols) + + +#define kNumStates 12 +#define kNumLitStates 7 + +#define kStartPosModelIndex 4 +#define kEndPosModelIndex 14 +#define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) + +#define kNumPosSlotBits 6 +#define kNumLenToPosStates 4 + +#define kNumAlignBits 4 +#define kAlignTableSize (1 << kNumAlignBits) + +#define kMatchMinLen 2 + +#define IsMatch 0 +#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax)) +#define IsRepG0 (IsRep + kNumStates) +#define IsRepG1 (IsRepG0 + kNumStates) +#define IsRepG2 (IsRepG1 + kNumStates) +#define IsRep0Long (IsRepG2 + kNumStates) +#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax)) +#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits)) +#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex) +#define LenCoder (Align + kAlignTableSize) +#define RepLenCoder (LenCoder + kNumLenProbs) +#define Literal (RepLenCoder + kNumLenProbs) + +#if Literal != LZMA_BASE_SIZE +StopCompilingDueBUG +#endif + +#if 0 +int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size) +{ + unsigned char prop0; + if (size < LZMA_PROPERTIES_SIZE) + return LZMA_RESULT_DATA_ERROR; + prop0 = propsData[0]; + if (prop0 >= (9 * 5 * 5)) + return LZMA_RESULT_DATA_ERROR; + { + for (propsRes->pb = 0; prop0 >= (9 * 5); propsRes->pb++, prop0 -= (9 * 5)); + for (propsRes->lp = 0; prop0 >= 9; propsRes->lp++, prop0 -= 9); + propsRes->lc = prop0; + /* + unsigned char remainder = (unsigned char)(prop0 / 9); + propsRes->lc = prop0 % 9; + propsRes->pb = remainder / 5; + propsRes->lp = remainder % 5; + */ + } + + #ifdef _LZMA_OUT_READ + { + int i; + propsRes->DictionarySize = 0; + for (i = 0; i < 4; i++) + propsRes->DictionarySize += (UInt32)(propsData[1 + i]) << (i * 8); + if (propsRes->DictionarySize == 0) + propsRes->DictionarySize = 1; + } + #endif + return LZMA_RESULT_OK; +} +#endif + +#define kLzmaStreamWasFinishedId (-1) + +int LzmaDecode(CLzmaDecoderState *vs, + #ifdef _LZMA_IN_CB + ILzmaInCallback *InCallback, + #else + const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed, + #endif + unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed) +{ + CProb *p = vs->Probs; + SizeT nowPos = 0; + Byte previousByte = 0; + UInt32 posStateMask = (1 << (vs->Properties.pb)) - 1; + UInt32 literalPosMask = (1 << (vs->Properties.lp)) - 1; + int lc = vs->Properties.lc; + + #ifdef _LZMA_OUT_READ + + UInt32 Range = vs->Range; + UInt32 Code = vs->Code; + #ifdef _LZMA_IN_CB + const Byte *Buffer = vs->Buffer; + const Byte *BufferLim = vs->BufferLim; + #else + const Byte *Buffer = inStream; + const Byte *BufferLim = inStream + inSize; + #endif + int state = vs->State; + UInt32 rep0 = vs->Reps[0], rep1 = vs->Reps[1], rep2 = vs->Reps[2], rep3 = vs->Reps[3]; + int len = vs->RemainLen; + UInt32 globalPos = vs->GlobalPos; + UInt32 distanceLimit = vs->DistanceLimit; + + Byte *dictionary = vs->Dictionary; + UInt32 dictionarySize = vs->Properties.DictionarySize; + UInt32 dictionaryPos = vs->DictionaryPos; + + Byte tempDictionary[4]; + + #ifndef _LZMA_IN_CB + *inSizeProcessed = 0; + #endif + *outSizeProcessed = 0; + if (len == kLzmaStreamWasFinishedId) + return LZMA_RESULT_OK; + + if (dictionarySize == 0) + { + dictionary = tempDictionary; + dictionarySize = 1; + tempDictionary[0] = vs->TempDictionary[0]; + } + + if (len == kLzmaNeedInitId) + { + { + UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + vs->Properties.lp)); + UInt32 i; + for (i = 0; i < numProbs; i++) + p[i] = kBitModelTotal >> 1; + rep0 = rep1 = rep2 = rep3 = 1; + state = 0; + globalPos = 0; + distanceLimit = 0; + dictionaryPos = 0; + dictionary[dictionarySize - 1] = 0; + #ifdef _LZMA_IN_CB + RC_INIT; + #else + RC_INIT(inStream, inSize); + #endif + } + len = 0; + } + while(len != 0 && nowPos < outSize) + { + UInt32 pos = dictionaryPos - rep0; + if (pos >= dictionarySize) + pos += dictionarySize; + outStream[nowPos++] = dictionary[dictionaryPos] = dictionary[pos]; + if (++dictionaryPos == dictionarySize) + dictionaryPos = 0; + len--; + } + if (dictionaryPos == 0) + previousByte = dictionary[dictionarySize - 1]; + else + previousByte = dictionary[dictionaryPos - 1]; + + #else /* if !_LZMA_OUT_READ */ + + int state = 0; + UInt32 rep0 = 1, rep1 = 1, rep2 = 1, rep3 = 1; + int len = 0; + const Byte *Buffer; + const Byte *BufferLim; + UInt32 Range; + UInt32 Code; + + #ifndef _LZMA_IN_CB + *inSizeProcessed = 0; + #endif + *outSizeProcessed = 0; + + { + UInt32 i; + UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + vs->Properties.lp)); + for (i = 0; i < numProbs; i++) + p[i] = kBitModelTotal >> 1; + } + + #ifdef _LZMA_IN_CB + RC_INIT; + #else + RC_INIT(inStream, inSize); + #endif + + #endif /* _LZMA_OUT_READ */ + + while(nowPos < outSize) + { + CProb *prob; + UInt32 bound; + int posState = (int)( + (nowPos + #ifdef _LZMA_OUT_READ + + globalPos + #endif + ) + & posStateMask); + + prob = p + IsMatch + (state << kNumPosBitsMax) + posState; + IfBit0(prob) + { + int symbol = 1; + UpdateBit0(prob) + prob = p + Literal + (LZMA_LIT_SIZE * + ((( + (nowPos + #ifdef _LZMA_OUT_READ + + globalPos + #endif + ) + & literalPosMask) << lc) + (previousByte >> (8 - lc)))); + + if (state >= kNumLitStates) + { + int matchByte; + #ifdef _LZMA_OUT_READ + UInt32 pos = dictionaryPos - rep0; + if (pos >= dictionarySize) + pos += dictionarySize; + matchByte = dictionary[pos]; + #else + matchByte = outStream[nowPos - rep0]; + #endif + do + { + int bit; + CProb *probLit; + matchByte <<= 1; + bit = (matchByte & 0x100); + probLit = prob + 0x100 + bit + symbol; + RC_GET_BIT2(probLit, symbol, if (bit != 0) break, if (bit == 0) break) + } + while (symbol < 0x100); + } + while (symbol < 0x100) + { + CProb *probLit = prob + symbol; + RC_GET_BIT(probLit, symbol) + } + previousByte = (Byte)symbol; + + outStream[nowPos++] = previousByte; + #ifdef _LZMA_OUT_READ + if (distanceLimit < dictionarySize) + distanceLimit++; + + dictionary[dictionaryPos] = previousByte; + if (++dictionaryPos == dictionarySize) + dictionaryPos = 0; + #endif + if (state < 4) state = 0; + else if (state < 10) state -= 3; + else state -= 6; + } + else + { + UpdateBit1(prob); + prob = p + IsRep + state; + IfBit0(prob) + { + UpdateBit0(prob); + rep3 = rep2; + rep2 = rep1; + rep1 = rep0; + state = state < kNumLitStates ? 0 : 3; + prob = p + LenCoder; + } + else + { + UpdateBit1(prob); + prob = p + IsRepG0 + state; + IfBit0(prob) + { + UpdateBit0(prob); + prob = p + IsRep0Long + (state << kNumPosBitsMax) + posState; + IfBit0(prob) + { + #ifdef _LZMA_OUT_READ + UInt32 pos; + #endif + UpdateBit0(prob); + + #ifdef _LZMA_OUT_READ + if (distanceLimit == 0) + #else + if (nowPos == 0) + #endif + return LZMA_RESULT_DATA_ERROR; + + state = state < kNumLitStates ? 9 : 11; + #ifdef _LZMA_OUT_READ + pos = dictionaryPos - rep0; + if (pos >= dictionarySize) + pos += dictionarySize; + previousByte = dictionary[pos]; + dictionary[dictionaryPos] = previousByte; + if (++dictionaryPos == dictionarySize) + dictionaryPos = 0; + #else + previousByte = outStream[nowPos - rep0]; + #endif + outStream[nowPos++] = previousByte; + #ifdef _LZMA_OUT_READ + if (distanceLimit < dictionarySize) + distanceLimit++; + #endif + + continue; + } + else + { + UpdateBit1(prob); + } + } + else + { + UInt32 distance; + UpdateBit1(prob); + prob = p + IsRepG1 + state; + IfBit0(prob) + { + UpdateBit0(prob); + distance = rep1; + } + else + { + UpdateBit1(prob); + prob = p + IsRepG2 + state; + IfBit0(prob) + { + UpdateBit0(prob); + distance = rep2; + } + else + { + UpdateBit1(prob); + distance = rep3; + rep3 = rep2; + } + rep2 = rep1; + } + rep1 = rep0; + rep0 = distance; + } + state = state < kNumLitStates ? 8 : 11; + prob = p + RepLenCoder; + } + { + int numBits, offset; + CProb *probLen = prob + LenChoice; + IfBit0(probLen) + { + UpdateBit0(probLen); + probLen = prob + LenLow + (posState << kLenNumLowBits); + offset = 0; + numBits = kLenNumLowBits; + } + else + { + UpdateBit1(probLen); + probLen = prob + LenChoice2; + IfBit0(probLen) + { + UpdateBit0(probLen); + probLen = prob + LenMid + (posState << kLenNumMidBits); + offset = kLenNumLowSymbols; + numBits = kLenNumMidBits; + } + else + { + UpdateBit1(probLen); + probLen = prob + LenHigh; + offset = kLenNumLowSymbols + kLenNumMidSymbols; + numBits = kLenNumHighBits; + } + } + RangeDecoderBitTreeDecode(probLen, numBits, len); + len += offset; + } + + if (state < 4) + { + int posSlot; + state += kNumLitStates; + prob = p + PosSlot + + ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << + kNumPosSlotBits); + RangeDecoderBitTreeDecode(prob, kNumPosSlotBits, posSlot); + if (posSlot >= kStartPosModelIndex) + { + int numDirectBits = ((posSlot >> 1) - 1); + rep0 = (2 | ((UInt32)posSlot & 1)); + if (posSlot < kEndPosModelIndex) + { + rep0 <<= numDirectBits; + prob = p + SpecPos + rep0 - posSlot - 1; + } + else + { + numDirectBits -= kNumAlignBits; + do + { + RC_NORMALIZE + Range >>= 1; + rep0 <<= 1; + if (Code >= Range) + { + Code -= Range; + rep0 |= 1; + } + } + while (--numDirectBits != 0); + prob = p + Align; + rep0 <<= kNumAlignBits; + numDirectBits = kNumAlignBits; + } + { + int i = 1; + int mi = 1; + do + { + CProb *prob3 = prob + mi; + RC_GET_BIT2(prob3, mi, ; , rep0 |= i); + i <<= 1; + } + while(--numDirectBits != 0); + } + } + else + rep0 = posSlot; + if (++rep0 == (UInt32)(0)) + { + /* it's for stream version */ + len = kLzmaStreamWasFinishedId; + break; + } + } + + len += kMatchMinLen; + #ifdef _LZMA_OUT_READ + if (rep0 > distanceLimit) + #else + if (rep0 > nowPos) + #endif + return LZMA_RESULT_DATA_ERROR; + + #ifdef _LZMA_OUT_READ + if (dictionarySize - distanceLimit > (UInt32)len) + distanceLimit += len; + else + distanceLimit = dictionarySize; + #endif + + do + { + #ifdef _LZMA_OUT_READ + UInt32 pos = dictionaryPos - rep0; + if (pos >= dictionarySize) + pos += dictionarySize; + previousByte = dictionary[pos]; + dictionary[dictionaryPos] = previousByte; + if (++dictionaryPos == dictionarySize) + dictionaryPos = 0; + #else + previousByte = outStream[nowPos - rep0]; + #endif + len--; + outStream[nowPos++] = previousByte; + } + while(len != 0 && nowPos < outSize); + } + } + RC_NORMALIZE; + + #ifdef _LZMA_OUT_READ + vs->Range = Range; + vs->Code = Code; + vs->DictionaryPos = dictionaryPos; + vs->GlobalPos = globalPos + (UInt32)nowPos; + vs->DistanceLimit = distanceLimit; + vs->Reps[0] = rep0; + vs->Reps[1] = rep1; + vs->Reps[2] = rep2; + vs->Reps[3] = rep3; + vs->State = state; + vs->RemainLen = len; + vs->TempDictionary[0] = tempDictionary[0]; + #endif + + #ifdef _LZMA_IN_CB + vs->Buffer = Buffer; + vs->BufferLim = BufferLim; + #else + *inSizeProcessed = (SizeT)(Buffer - inStream); + #endif + *outSizeProcessed = nowPos; + return LZMA_RESULT_OK; +} diff --git a/target/linux/generic/image/lzma-loader/src/LzmaDecode.h b/target/linux/generic/image/lzma-loader/src/LzmaDecode.h new file mode 100644 index 0000000..213062a --- /dev/null +++ b/target/linux/generic/image/lzma-loader/src/LzmaDecode.h @@ -0,0 +1,131 @@ +/* + LzmaDecode.h + LZMA Decoder interface + + LZMA SDK 4.21 Copyright (c) 1999-2005 Igor Pavlov (2005-06-08) + http://www.7-zip.org/ + + LZMA SDK is licensed under two licenses: + 1) GNU Lesser General Public License (GNU LGPL) + 2) Common Public License (CPL) + It means that you can select one of these two licenses and + follow rules of that license. + + SPECIAL EXCEPTION: + Igor Pavlov, as the author of this code, expressly permits you to + statically or dynamically link your code (or bind by name) to the + interfaces of this file without subjecting your linked code to the + terms of the CPL or GNU LGPL. Any modifications or additions + to this file, however, are subject to the LGPL or CPL terms. +*/ + +#ifndef __LZMADECODE_H +#define __LZMADECODE_H + +/* #define _LZMA_IN_CB */ +/* Use callback for input data */ + +/* #define _LZMA_OUT_READ */ +/* Use read function for output data */ + +/* #define _LZMA_PROB32 */ +/* It can increase speed on some 32-bit CPUs, + but memory usage will be doubled in that case */ + +/* #define _LZMA_LOC_OPT */ +/* Enable local speed optimizations inside code */ + +/* #define _LZMA_SYSTEM_SIZE_T */ +/* Use system's size_t. You can use it to enable 64-bit sizes supporting*/ + +#ifndef UInt32 +#ifdef _LZMA_UINT32_IS_ULONG +#define UInt32 unsigned long +#else +#define UInt32 unsigned int +#endif +#endif + +#ifndef SizeT +#ifdef _LZMA_SYSTEM_SIZE_T +#include +#define SizeT size_t +#else +#define SizeT UInt32 +#endif +#endif + +#ifdef _LZMA_PROB32 +#define CProb UInt32 +#else +#define CProb unsigned short +#endif + +#define LZMA_RESULT_OK 0 +#define LZMA_RESULT_DATA_ERROR 1 + +#ifdef _LZMA_IN_CB +typedef struct _ILzmaInCallback +{ + int (*Read)(void *object, const unsigned char **buffer, SizeT *bufferSize); +} ILzmaInCallback; +#endif + +#define LZMA_BASE_SIZE 1846 +#define LZMA_LIT_SIZE 768 + +#define LZMA_PROPERTIES_SIZE 5 + +typedef struct _CLzmaProperties +{ + int lc; + int lp; + int pb; + #ifdef _LZMA_OUT_READ + UInt32 DictionarySize; + #endif +}CLzmaProperties; + +int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size); + +#define LzmaGetNumProbs(Properties) (LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((Properties)->lc + (Properties)->lp))) + +#define kLzmaNeedInitId (-2) + +typedef struct _CLzmaDecoderState +{ + CLzmaProperties Properties; + CProb *Probs; + + #ifdef _LZMA_IN_CB + const unsigned char *Buffer; + const unsigned char *BufferLim; + #endif + + #ifdef _LZMA_OUT_READ + unsigned char *Dictionary; + UInt32 Range; + UInt32 Code; + UInt32 DictionaryPos; + UInt32 GlobalPos; + UInt32 DistanceLimit; + UInt32 Reps[4]; + int State; + int RemainLen; + unsigned char TempDictionary[4]; + #endif +} CLzmaDecoderState; + +#ifdef _LZMA_OUT_READ +#define LzmaDecoderInit(vs) { (vs)->RemainLen = kLzmaNeedInitId; } +#endif + +int LzmaDecode(CLzmaDecoderState *vs, + #ifdef _LZMA_IN_CB + ILzmaInCallback *inCallback, + #else + const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed, + #endif + unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed); + +#endif diff --git a/target/linux/generic/image/lzma-loader/src/Makefile b/target/linux/generic/image/lzma-loader/src/Makefile new file mode 100644 index 0000000..910172c --- /dev/null +++ b/target/linux/generic/image/lzma-loader/src/Makefile @@ -0,0 +1,68 @@ +# +# Copyright (C) 2006 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# +RAMSTART = 0x80000000 +RAMSIZE = 0x00100000 # 1MB +LOADADDR = 0x80400000 # RAM start + 4M +KERNEL_ENTRY = 0x80001000 +IMAGE_COPY:=0 + +CROSS_COMPILE = mips-linux- + +OBJCOPY:= $(CROSS_COMPILE)objcopy -O binary -R .reginfo -R .note -R .comment -R .mdebug -S +CFLAGS := -fno-builtin -Os -G 0 -ffunction-sections -mno-abicalls -fno-pic -mabi=32 -march=mips32 -Wa,-32 -Wa,-march=mips32 -Wa,-mips32 -Wa,--trap -Wall -DRAMSTART=${RAMSTART} -DRAMSIZE=${RAMSIZE} -DKERNEL_ENTRY=${KERNEL_ENTRY} -D_LZMA_IN_CB +ifeq ($(IMAGE_COPY),1) +CFLAGS += -DLOADADDR=${LOADADDR} -DIMAGE_COPY=1 +endif + +.S.s: + $(CPP) $(CFLAGS) $< -o $*.s +.S.o: + $(CC) $(CFLAGS) -c $< -o $*.o +.c.o: + $(CC) $(CFLAGS) -c $< -o $*.o + +CC = $(CROSS_COMPILE)gcc +LD = $(CROSS_COMPILE)ld +OBJDUMP = $(CROSS_COMPILE)objdump + +O_FORMAT = $(shell $(OBJDUMP) -i | head -2 | grep elf32) + +# Drop some uninteresting sections in the kernel. +# This is only relevant for ELF kernels but doesn't hurt a.out +drop-sections = .reginfo .mdebug .comment +strip-flags = $(addprefix --remove-section=,$(drop-sections)) + +all : lzma.elf lzma.bin + +lzma.lds: lzma.lds.in + sed -e 's,@LOADADDR@,$(LOADADDR),g' -e 's,@ENTRY@,_start,g' $< >$@ + +kernel.o: vmlinux.lzma lzma.lds + $(LD) -r -b binary --oformat $(O_FORMAT) -o $@ $< + +lzma.bin: lzma.elf + $(OBJCOPY) $< $@ + +ifeq ($(IMAGE_COPY),1) +LOADER_ENTRY ?= $(KERNEL_ENTRY) +lzma.o: decompress.o LzmaDecode.o kernel.o + sed -e 's,@LOADADDR@,$(LOADADDR),g' -e 's,@ENTRY@,entry,g' lzma.lds.in >lzma-stage2.lds + $(LD) -static --no-warn-mismatch -e entry -Tlzma-stage2.lds -o temp-$@ $^ + $(OBJCOPY) temp-$@ lzma.tmp + @echo "SECTIONS { .data : { code_start = .; *(.data) code_stop = .; }}" > lzma-data.lds + $(LD) -no-warn-mismatch -T lzma-data.lds -r -o $@ -b binary lzma.tmp --oformat $(O_FORMAT) + +lzma.elf: start.o lzma.o + sed -e 's,@LOADADDR@,$(LOADER_ENTRY),g' lzma-copy.lds.in >lzma-copy.lds + $(LD) -s -Tlzma-copy.lds -o $@ $^ +else +lzma.elf: start.o decompress.o LzmaDecode.o kernel.o + $(LD) -s -Tlzma.lds -o $@ $^ +endif + +clean: + rm -f *.o lzma.elf lzma.bin *.tmp *.lds diff --git a/target/linux/generic/image/lzma-loader/src/decompress.c b/target/linux/generic/image/lzma-loader/src/decompress.c new file mode 100644 index 0000000..45ac509 --- /dev/null +++ b/target/linux/generic/image/lzma-loader/src/decompress.c @@ -0,0 +1,157 @@ +/* + * LZMA compressed kernel decompressor for bcm947xx boards + * + * Copyright (C) 2005 by Oleg I. Vdovikin + * + * 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 + * + * + * Please note, this was code based on the bunzip2 decompressor code + * by Manuel Novoa III (mjn3@codepoet.org), although the only thing left + * is an idea and part of original vendor code + * + * + * 12-Mar-2005 Mineharu Takahara + * pass actual output size to decoder (stream mode + * compressed input is not a requirement anymore) + * + * 24-Apr-2005 Oleg I. Vdovikin + * reordered functions using lds script, removed forward decl + * + * ??-Nov-2005 Mike Baker + * reorder the script as an lzma wrapper; do not depend on flash access + */ + +#include "LzmaDecode.h" + +#define KSEG0 0x80000000 +#define KSEG1 0xa0000000 + +#define KSEG1ADDR(a) ((((unsigned)(a)) & 0x1fffffffU) | KSEG1) + +#define Index_Invalidate_I 0x00 +#define Index_Writeback_Inv_D 0x01 + +#define cache_unroll(base,op) \ + __asm__ __volatile__( \ + ".set noreorder;\n" \ + ".set mips3;\n" \ + "cache %1, (%0);\n" \ + ".set mips0;\n" \ + ".set reorder\n" \ + : \ + : "r" (base), \ + "i" (op)); + + +static __inline__ void blast_icache(unsigned long size, unsigned long lsize) +{ + unsigned long start = KSEG0; + unsigned long end = (start + size); + + while(start < end) { + cache_unroll(start,Index_Invalidate_I); + start += lsize; + } +} + +static __inline__ void blast_dcache(unsigned long size, unsigned long lsize) +{ + unsigned long start = KSEG0; + unsigned long end = (start + size); + + while(start < end) { + cache_unroll(start,Index_Writeback_Inv_D); + start += lsize; + } +} + +unsigned char *data; + +static int read_byte(void *object, unsigned char **buffer, UInt32 *bufferSize) +{ + *bufferSize = 1; + *buffer = data; + ++data; + return LZMA_RESULT_OK; +} + +static __inline__ unsigned char get_byte(void) +{ + unsigned char *buffer; + UInt32 fake; + + return read_byte(0, &buffer, &fake), *buffer; +} + +/* This puts lzma workspace 128k below RAM end. + * That should be enough for both lzma and stack + */ +static char *buffer = (char *)(RAMSTART + RAMSIZE - 0x00020000); +extern char lzma_start[]; +extern char lzma_end[]; + +/* should be the first function */ +void entry(unsigned long icache_size, unsigned long icache_lsize, + unsigned long dcache_size, unsigned long dcache_lsize) +{ + unsigned int i; /* temp value */ + unsigned int osize; /* uncompressed size */ + volatile unsigned int arg0, arg1, arg2, arg3; + + /* restore argument registers */ + __asm__ __volatile__ ("ori %0, $12, 0":"=r"(arg0)); + __asm__ __volatile__ ("ori %0, $13, 0":"=r"(arg1)); + __asm__ __volatile__ ("ori %0, $14, 0":"=r"(arg2)); + __asm__ __volatile__ ("ori %0, $15, 0":"=r"(arg3)); + + ILzmaInCallback callback; + CLzmaDecoderState vs; + callback.Read = read_byte; + + data = lzma_start; + + /* lzma args */ + i = get_byte(); + vs.Properties.lc = i % 9, i = i / 9; + vs.Properties.lp = i % 5, vs.Properties.pb = i / 5; + + vs.Probs = (CProb *)buffer; + + /* skip rest of the LZMA coder property */ + for (i = 0; i < 4; i++) + get_byte(); + + /* read the lower half of uncompressed size in the header */ + osize = ((unsigned int)get_byte()) + + ((unsigned int)get_byte() << 8) + + ((unsigned int)get_byte() << 16) + + ((unsigned int)get_byte() << 24); + + /* skip rest of the header (upper half of uncompressed size) */ + for (i = 0; i < 4; i++) + get_byte(); + + /* decompress kernel */ + if ((i = LzmaDecode(&vs, &callback, + (unsigned char*)KERNEL_ENTRY, osize, &osize)) == LZMA_RESULT_OK) + { + blast_dcache(dcache_size, dcache_lsize); + blast_icache(icache_size, icache_lsize); + + /* Jump to load address */ + ((void (*)(int a0, int a1, int a2, int a3)) KERNEL_ENTRY)(arg0, arg1, arg2, arg3); + } +} diff --git a/target/linux/generic/image/lzma-loader/src/lzma-copy.lds.in b/target/linux/generic/image/lzma-loader/src/lzma-copy.lds.in new file mode 100644 index 0000000..fbc87ab --- /dev/null +++ b/target/linux/generic/image/lzma-loader/src/lzma-copy.lds.in @@ -0,0 +1,20 @@ +OUTPUT_ARCH(mips) +ENTRY(_start) +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = @LOADADDR@; + .text : + { + _ftext = . ; + *(.text) + *(.rodata) + } =0 + + .reginfo : { *(.reginfo) } + + .bss : + { + *(.bss) + } +} diff --git a/target/linux/generic/image/lzma-loader/src/lzma.lds.in b/target/linux/generic/image/lzma-loader/src/lzma.lds.in new file mode 100644 index 0000000..6021cec --- /dev/null +++ b/target/linux/generic/image/lzma-loader/src/lzma.lds.in @@ -0,0 +1,24 @@ +OUTPUT_ARCH(mips) +ENTRY(@ENTRY@) +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = @LOADADDR@; + .text : + { + _ftext = . ; + *(.text.entry) + *(.text) + *(.rodata) + lzma_start = .; + kernel.o + lzma_end = .; + } =0 + + .reginfo : { *(.reginfo) } + + .bss : + { + *(.bss) + } +} diff --git a/target/linux/generic/image/lzma-loader/src/print.c b/target/linux/generic/image/lzma-loader/src/print.c new file mode 100644 index 0000000..950687b --- /dev/null +++ b/target/linux/generic/image/lzma-loader/src/print.c @@ -0,0 +1,324 @@ +/* + * Copyright (C) 2001 MontaVista Software Inc. + * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net + * + * 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. + * + */ + +#include "print.h" + +/* macros */ +#define IsDigit(x) ( ((x) >= '0') && ((x) <= '9') ) +#define Ctod(x) ( (x) - '0') + +/* forward declaration */ +extern int PrintChar(char *, char, int, int); +extern int PrintString(char *, char *, int, int); +extern int PrintNum(char *, unsigned long, int, int, int, int, char, int); + +/* private variable */ +static const char theFatalMsg[] = "fatal error in lp_Print!"; + +/* -*- + * A low level printf() function. + */ +void +lp_Print(void (*output)(void *, char *, int), + void * arg, + char *fmt, + va_list ap) +{ + +#define OUTPUT(arg, s, l) \ + { if (((l) < 0) || ((l) > LP_MAX_BUF)) { \ + (*output)(arg, (char*)theFatalMsg, sizeof(theFatalMsg)-1); for(;;); \ + } else { \ + (*output)(arg, s, l); \ + } \ + } + + char buf[LP_MAX_BUF]; + + char c; + char *s; + long int num; + + int longFlag; + int negFlag; + int width; + int prec; + int ladjust; + char padc; + + int length; + + for(;;) { + { + /* scan for the next '%' */ + char *fmtStart = fmt; + while ( (*fmt != '\0') && (*fmt != '%')) { + fmt ++; + } + + /* flush the string found so far */ + OUTPUT(arg, fmtStart, fmt-fmtStart); + + /* are we hitting the end? */ + if (*fmt == '\0') break; + } + + /* we found a '%' */ + fmt ++; + + /* check for long */ + if (*fmt == 'l') { + longFlag = 1; + fmt ++; + } else { + longFlag = 0; + } + + /* check for other prefixes */ + width = 0; + prec = -1; + ladjust = 0; + padc = ' '; + + if (*fmt == '-') { + ladjust = 1; + fmt ++; + } + + if (*fmt == '0') { + padc = '0'; + fmt++; + } + + if (IsDigit(*fmt)) { + while (IsDigit(*fmt)) { + width = 10 * width + Ctod(*fmt++); + } + } + + if (*fmt == '.') { + fmt ++; + if (IsDigit(*fmt)) { + prec = 0; + while (IsDigit(*fmt)) { + prec = prec*10 + Ctod(*fmt++); + } + } + } + + + /* check format flag */ + negFlag = 0; + switch (*fmt) { + case 'b': + if (longFlag) { + num = va_arg(ap, long int); + } else { + num = va_arg(ap, int); + } + length = PrintNum(buf, num, 2, 0, width, ladjust, padc, 0); + OUTPUT(arg, buf, length); + break; + + case 'd': + case 'D': + if (longFlag) { + num = va_arg(ap, long int); + } else { + num = va_arg(ap, int); + } + if (num < 0) { + num = - num; + negFlag = 1; + } + length = PrintNum(buf, num, 10, negFlag, width, ladjust, padc, 0); + OUTPUT(arg, buf, length); + break; + + case 'o': + case 'O': + if (longFlag) { + num = va_arg(ap, long int); + } else { + num = va_arg(ap, int); + } + length = PrintNum(buf, num, 8, 0, width, ladjust, padc, 0); + OUTPUT(arg, buf, length); + break; + + case 'u': + case 'U': + if (longFlag) { + num = va_arg(ap, long int); + } else { + num = va_arg(ap, int); + } + length = PrintNum(buf, num, 10, 0, width, ladjust, padc, 0); + OUTPUT(arg, buf, length); + break; + + case 'x': + if (longFlag) { + num = va_arg(ap, long int); + } else { + num = va_arg(ap, int); + } + length = PrintNum(buf, num, 16, 0, width, ladjust, padc, 0); + OUTPUT(arg, buf, length); + break; + + case 'X': + if (longFlag) { + num = va_arg(ap, long int); + } else { + num = va_arg(ap, int); + } + length = PrintNum(buf, num, 16, 0, width, ladjust, padc, 1); + OUTPUT(arg, buf, length); + break; + + case 'c': + c = (char)va_arg(ap, int); + length = PrintChar(buf, c, width, ladjust); + OUTPUT(arg, buf, length); + break; + + case 's': + s = (char*)va_arg(ap, char *); + length = PrintString(buf, s, width, ladjust); + OUTPUT(arg, buf, length); + break; + + case '\0': + fmt --; + break; + + default: + /* output this char as it is */ + OUTPUT(arg, fmt, 1); + } /* switch (*fmt) */ + + fmt ++; + } /* for(;;) */ + + /* special termination call */ + OUTPUT(arg, "\0", 1); +} + + +/* --------------- local help functions --------------------- */ +int +PrintChar(char * buf, char c, int length, int ladjust) +{ + int i; + + if (length < 1) length = 1; + if (ladjust) { + *buf = c; + for (i=1; i< length; i++) buf[i] = ' '; + } else { + for (i=0; i< length-1; i++) buf[i] = ' '; + buf[length - 1] = c; + } + return length; +} + +int +PrintString(char * buf, char* s, int length, int ladjust) +{ + int i; + int len=0; + char* s1 = s; + while (*s1++) len++; + if (length < len) length = len; + + if (ladjust) { + for (i=0; i< len; i++) buf[i] = s[i]; + for (i=len; i< length; i++) buf[i] = ' '; + } else { + for (i=0; i< length-len; i++) buf[i] = ' '; + for (i=length-len; i < length; i++) buf[i] = s[i-length+len]; + } + return length; +} + +int +PrintNum(char * buf, unsigned long u, int base, int negFlag, + int length, int ladjust, char padc, int upcase) +{ + /* algorithm : + * 1. prints the number from left to right in reverse form. + * 2. fill the remaining spaces with padc if length is longer than + * the actual length + * TRICKY : if left adjusted, no "0" padding. + * if negtive, insert "0" padding between "0" and number. + * 3. if (!ladjust) we reverse the whole string including paddings + * 4. otherwise we only reverse the actual string representing the num. + */ + + int actualLength =0; + char *p = buf; + int i; + + do { + int tmp = u %base; + if (tmp <= 9) { + *p++ = '0' + tmp; + } else if (upcase) { + *p++ = 'A' + tmp - 10; + } else { + *p++ = 'a' + tmp - 10; + } + u /= base; + } while (u != 0); + + if (negFlag) { + *p++ = '-'; + } + + /* figure out actual length and adjust the maximum length */ + actualLength = p - buf; + if (length < actualLength) length = actualLength; + + /* add padding */ + if (ladjust) { + padc = ' '; + } + if (negFlag && !ladjust && (padc == '0')) { + for (i = actualLength-1; i< length-1; i++) buf[i] = padc; + buf[length -1] = '-'; + } else { + for (i = actualLength; i< length; i++) buf[i] = padc; + } + + + /* prepare to reverse the string */ + { + int begin = 0; + int end; + if (ladjust) { + end = actualLength - 1; + } else { + end = length -1; + } + + while (end > begin) { + char tmp = buf[begin]; + buf[begin] = buf[end]; + buf[end] = tmp; + begin ++; + end --; + } + } + + /* adjust the string pointer */ + return length; +} diff --git a/target/linux/generic/image/lzma-loader/src/print.h b/target/linux/generic/image/lzma-loader/src/print.h new file mode 100644 index 0000000..b051463 --- /dev/null +++ b/target/linux/generic/image/lzma-loader/src/print.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2001 MontaVista Software Inc. + * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net + * + * 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. + * + */ + +#ifndef _print_h_ +#define _print_h_ + +#include + +/* this is the maximum width for a variable */ +#define LP_MAX_BUF 80 + +/* -*- + * output function takes an void pointer which is passed in as the + * second argument in lp_Print(). This black-box argument gives output + * function a way to track state. + * + * The second argument in output function is a pointer to char buffer. + * The third argument specifies the number of chars to outputed. + * + * output function cannot assume the buffer is null-terminated after + * l number of chars. + */ +void lp_Print(void (*output)(void *, char *, int), + void * arg, + char *fmt, + va_list ap); + +#endif diff --git a/target/linux/generic/image/lzma-loader/src/printf.c b/target/linux/generic/image/lzma-loader/src/printf.c new file mode 100644 index 0000000..49bd50d --- /dev/null +++ b/target/linux/generic/image/lzma-loader/src/printf.c @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2001 MontaVista Software Inc. + * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net + * + * 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. + * + */ + +#include "printf.h" +#include "print.h" +#include "uart16550.h" + +static void myoutput(void *arg, char *s, int l) +{ + int i; + + // special termination call + if ((l==1) && (s[0] == '\0')) return; + + for (i=0; i< l; i++) { + Uart16550Put(s[i]); + if (s[i] == '\n') Uart16550Put('\r'); + } +} + +void printf(char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + lp_Print(myoutput, 0, fmt, ap); + va_end(ap); +} diff --git a/target/linux/generic/image/lzma-loader/src/printf.h b/target/linux/generic/image/lzma-loader/src/printf.h new file mode 100644 index 0000000..9b1c1df --- /dev/null +++ b/target/linux/generic/image/lzma-loader/src/printf.h @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2001 MontaVista Software Inc. + * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net + * + * 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. + * + */ + +#ifndef _printf_h_ +#define _printf_h_ + +#include +void printf(char *fmt, ...); + +#endif /* _printf_h_ */ diff --git a/target/linux/generic/image/lzma-loader/src/start.S b/target/linux/generic/image/lzma-loader/src/start.S new file mode 100644 index 0000000..8642933 --- /dev/null +++ b/target/linux/generic/image/lzma-loader/src/start.S @@ -0,0 +1,160 @@ +#include +#include + +#define KSEG0 0x80000000 + +#define C0_CONFIG $16 +#define C0_TAGLO $28 +#define C0_TAGHI $29 + +#define CONF1_DA_SHIFT 7 /* D$ associativity */ +#define CONF1_DA_MASK 0x00000380 +#define CONF1_DA_BASE 1 +#define CONF1_DL_SHIFT 10 /* D$ line size */ +#define CONF1_DL_MASK 0x00001c00 +#define CONF1_DL_BASE 2 +#define CONF1_DS_SHIFT 13 /* D$ sets/way */ +#define CONF1_DS_MASK 0x0000e000 +#define CONF1_DS_BASE 64 +#define CONF1_IA_SHIFT 16 /* I$ associativity */ +#define CONF1_IA_MASK 0x00070000 +#define CONF1_IA_BASE 1 +#define CONF1_IL_SHIFT 19 /* I$ line size */ +#define CONF1_IL_MASK 0x00380000 +#define CONF1_IL_BASE 2 +#define CONF1_IS_SHIFT 22 /* Instruction cache sets/way */ +#define CONF1_IS_MASK 0x01c00000 +#define CONF1_IS_BASE 64 + +#define Index_Invalidate_I 0x00 +#define Index_Writeback_Inv_D 0x01 + +LEAF(_start) + + .set mips32 + .set noreorder + + /* save argument registers */ + move t4, a0 + move t5, a1 + move t6, a2 + move t7, a3 + + /* set up stack */ + li sp, RAMSTART + RAMSIZE - 16 + +#ifdef IMAGE_COPY + /* Copy decompressor code to the right place */ + li t2, LOADADDR + add a0, t2, 0 + la a1, code_start + la a2, code_stop +$L1: + lw t0, 0(a1) + sw t0, 0(a0) + add a1, 4 + add a0, 4 + blt a1, a2, $L1 + nop +#endif + + /* At this point we need to invalidate dcache and */ + /* icache before jumping to new code */ + +1: /* Get cache sizes */ + mfc0 s0,C0_CONFIG,1 + + li s1,CONF1_DL_MASK + and s1,s0 + beq s1,zero,nodc + nop + + srl s1,CONF1_DL_SHIFT + li t0,CONF1_DL_BASE + sll s1,t0,s1 /* s1 has D$ cache line size */ + + li s2,CONF1_DA_MASK + and s2,s0 + srl s2,CONF1_DA_SHIFT + addiu s2,CONF1_DA_BASE /* s2 now has D$ associativity */ + + li t0,CONF1_DS_MASK + and t0,s0 + srl t0,CONF1_DS_SHIFT + li s3,CONF1_DS_BASE + sll s3,s3,t0 /* s3 has D$ sets per way */ + + multu s2,s3 /* sets/way * associativity */ + mflo t0 /* total cache lines */ + + multu s1,t0 /* D$ linesize * lines */ + mflo s2 /* s2 is now D$ size in bytes */ + + /* Initilize the D$: */ + mtc0 zero,C0_TAGLO + mtc0 zero,C0_TAGHI + + li t0,KSEG0 /* Just an address for the first $ line */ + addu t1,t0,s2 /* + size of cache == end */ + +1: cache Index_Writeback_Inv_D,0(t0) + bne t0,t1,1b + addu t0,s1 + +nodc: + /* Now we get to do it all again for the I$ */ + + move s3,zero /* just in case there is no icache */ + move s4,zero + + li t0,CONF1_IL_MASK + and t0,s0 + beq t0,zero,noic + nop + + srl t0,CONF1_IL_SHIFT + li s3,CONF1_IL_BASE + sll s3,t0 /* s3 has I$ cache line size */ + + li t0,CONF1_IA_MASK + and t0,s0 + srl t0,CONF1_IA_SHIFT + addiu s4,t0,CONF1_IA_BASE /* s4 now has I$ associativity */ + + li t0,CONF1_IS_MASK + and t0,s0 + srl t0,CONF1_IS_SHIFT + li s5,CONF1_IS_BASE + sll s5,t0 /* s5 has I$ sets per way */ + + multu s4,s5 /* sets/way * associativity */ + mflo t0 /* s4 is now total cache lines */ + + multu s3,t0 /* I$ linesize * lines */ + mflo s4 /* s4 is cache size in bytes */ + + /* Initilize the I$: */ + mtc0 zero,C0_TAGLO + mtc0 zero,C0_TAGHI + + li t0,KSEG0 /* Just an address for the first $ line */ + addu t1,t0,s4 /* + size of cache == end */ + +1: cache Index_Invalidate_I,0(t0) + bne t0,t1,1b + addu t0,s3 +noic: + /* jump to main */ + move a0,s3 /* icache line size */ + move a1,s4 /* icache size */ + move a2,s1 /* dcache line size */ +#ifdef IMAGE_COPY + jal t2 +#else + jal entry +#endif + move a3,s2 /* dcache size */ + + .set reorder +END(_start) + diff --git a/target/linux/generic/image/lzma-loader/src/uart16550.c b/target/linux/generic/image/lzma-loader/src/uart16550.c new file mode 100644 index 0000000..7df5727 --- /dev/null +++ b/target/linux/generic/image/lzma-loader/src/uart16550.c @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2001 MontaVista Software Inc. + * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net + * + * 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. + * + */ + + +#include "uart16550.h" + +/* === CONFIG === */ + +#define BASE 0xb8058000 +#define MAX_BAUD 1152000 +#define REG_OFFSET 4 + +/* === END OF CONFIG === */ + +/* register offset */ +#define OFS_RCV_BUFFER (0*REG_OFFSET) +#define OFS_TRANS_HOLD (0*REG_OFFSET) +#define OFS_SEND_BUFFER (0*REG_OFFSET) +#define OFS_INTR_ENABLE (1*REG_OFFSET) +#define OFS_INTR_ID (2*REG_OFFSET) +#define OFS_DATA_FORMAT (3*REG_OFFSET) +#define OFS_LINE_CONTROL (3*REG_OFFSET) +#define OFS_MODEM_CONTROL (4*REG_OFFSET) +#define OFS_RS232_OUTPUT (4*REG_OFFSET) +#define OFS_LINE_STATUS (5*REG_OFFSET) +#define OFS_MODEM_STATUS (6*REG_OFFSET) +#define OFS_RS232_INPUT (6*REG_OFFSET) +#define OFS_SCRATCH_PAD (7*REG_OFFSET) + +#define OFS_DIVISOR_LSB (0*REG_OFFSET) +#define OFS_DIVISOR_MSB (1*REG_OFFSET) + + +/* memory-mapped read/write of the port */ +#define UART16550_READ(y) (*((volatile uint32*)(BASE + y))) +#define UART16550_WRITE(y, z) ((*((volatile uint32*)(BASE + y))) = z) + +#define DEBUG_LED (*(unsigned short*)0xb7ffffc0) +#define OutputLED(x) (DEBUG_LED = x) + +void Uart16550Init(uint32 baud, uint8 data, uint8 parity, uint8 stop) +{ + /* disable interrupts */ + UART16550_WRITE(OFS_INTR_ENABLE, 0); + + /* set up buad rate */ + { + uint32 divisor; + + /* set DIAB bit */ + UART16550_WRITE(OFS_LINE_CONTROL, 0x80); + + /* set divisor */ + divisor = MAX_BAUD / baud; + UART16550_WRITE(OFS_DIVISOR_LSB, divisor & 0xff); + UART16550_WRITE(OFS_DIVISOR_MSB, (divisor & 0xff00)>>8); + + /* clear DIAB bit */ + UART16550_WRITE(OFS_LINE_CONTROL, 0x0); + } + + /* set data format */ + UART16550_WRITE(OFS_DATA_FORMAT, data | parity | stop); +} + +uint8 Uart16550GetPoll() +{ + while((UART16550_READ(OFS_LINE_STATUS) & 0x1) == 0); + return UART16550_READ(OFS_RCV_BUFFER); +} + + +void Uart16550Put(uint8 byte) +{ + while ((UART16550_READ(OFS_LINE_STATUS) &0x20) == 0); + UART16550_WRITE(OFS_SEND_BUFFER, byte); +} + diff --git a/target/linux/generic/image/lzma-loader/src/uart16550.h b/target/linux/generic/image/lzma-loader/src/uart16550.h new file mode 100644 index 0000000..b3fd6fd --- /dev/null +++ b/target/linux/generic/image/lzma-loader/src/uart16550.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2001 MontaVista Software Inc. + * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net + * + * 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. + * + */ + +#ifndef _uart16550_h_ +#define _uart16550_h_ + +typedef unsigned char uint8; +typedef unsigned int uint32; + +#define UART16550_BAUD_2400 2400 +#define UART16550_BAUD_4800 4800 +#define UART16550_BAUD_9600 9600 +#define UART16550_BAUD_19200 19200 +#define UART16550_BAUD_38400 38400 +#define UART16550_BAUD_57600 57600 +#define UART16550_BAUD_115200 115200 + +#define UART16550_PARITY_NONE 0 +#define UART16550_PARITY_ODD 0x08 +#define UART16550_PARITY_EVEN 0x18 +#define UART16550_PARITY_MARK 0x28 +#define UART16550_PARITY_SPACE 0x38 + +#define UART16550_DATA_5BIT 0x0 +#define UART16550_DATA_6BIT 0x1 +#define UART16550_DATA_7BIT 0x2 +#define UART16550_DATA_8BIT 0x3 + +#define UART16550_STOP_1BIT 0x0 +#define UART16550_STOP_2BIT 0x4 + +void Uart16550Init(uint32 baud, uint8 data, uint8 parity, uint8 stop); + +/* blocking call */ +uint8 Uart16550GetPoll(); + +void Uart16550Put(uint8 byte); + +#endif diff --git a/target/linux/generic/image/relocate/Makefile b/target/linux/generic/image/relocate/Makefile new file mode 100644 index 0000000..5f6ebeb --- /dev/null +++ b/target/linux/generic/image/relocate/Makefile @@ -0,0 +1,74 @@ +# +# Makefile for the kernel relocation stub for MIPS devices +# +# Copyright (C) 2011 Gabor Juhos +# Copyright (C) 2015 Felix Fietkau +# +# Some parts of this file was based on the OpenWrt specific lzma-loader +# for the BCM47xx and ADM5120 based boards: +# Copyright (C) 2004 Manuel Novoa III (mjn3@codepoet.org) +# Copyright (C) 2005 Mineharu Takahara +# Copyright (C) 2005 by Oleg I. Vdovikin +# +# 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. +# + +LOADADDR := +LZMA_TEXT_START := 0x81000000 +LOADER_DATA := +BOARD := +FLASH_OFFS := +FLASH_MAX := +PLATFORM := +CACHELINE_SIZE := 32 + +CC := $(CROSS_COMPILE)gcc +LD := $(CROSS_COMPILE)ld +OBJCOPY := $(CROSS_COMPILE)objcopy +OBJDUMP := $(CROSS_COMPILE)objdump + +BIN_FLAGS := -O binary -R .reginfo -R .note -R .comment -R .mdebug -S + +CFLAGS = -D__KERNEL__ -Wall -Wstrict-prototypes -Wno-trigraphs -Os \ + -fno-strict-aliasing -fno-common -fomit-frame-pointer -G 0 \ + -mno-abicalls -fno-pic -ffunction-sections -pipe -mlong-calls \ + -fno-common -ffreestanding -fhonour-copts \ + -mabi=32 -march=mips32r2 \ + -Wa,-32 -Wa,-march=mips32r2 -Wa,-mips32r2 -Wa,--trap \ + -DCONFIG_CACHELINE_SIZE=$(CACHELINE_SIZE) \ + -DKERNEL_ADDR=$(KERNEL_ADDR) + +ASFLAGS = $(CFLAGS) -D__ASSEMBLY__ + +LDFLAGS = -static --gc-sections -no-warn-mismatch +LDFLAGS += -e startup -T loader.lds -Ttext $(LZMA_TEXT_START) + +O_FORMAT = $(shell $(OBJDUMP) -i | head -2 | grep elf32) + +OBJECTS := head.o + +all: head.o loader.bin + +# Don't build dependencies, this may die if $(CC) isn't gcc +dep: + +install: + +%.o : %.c + $(CC) $(CFLAGS) -c -o $@ $< + +%.o : %.S + $(CC) $(ASFLAGS) -c -o $@ $< + +loader: $(OBJECTS) + $(LD) $(LDFLAGS) -o $@ $(OBJECTS) + +loader.bin: loader + $(OBJCOPY) $(BIN_FLAGS) $< $@ + +mrproper: clean + +clean: + rm -f loader *.elf *.bin *.o diff --git a/target/linux/generic/image/relocate/cacheops.h b/target/linux/generic/image/relocate/cacheops.h new file mode 100644 index 0000000..70bcad7 --- /dev/null +++ b/target/linux/generic/image/relocate/cacheops.h @@ -0,0 +1,85 @@ +/* + * Cache operations for the cache instruction. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * (C) Copyright 1996, 97, 99, 2002, 03 Ralf Baechle + * (C) Copyright 1999 Silicon Graphics, Inc. + */ +#ifndef __ASM_CACHEOPS_H +#define __ASM_CACHEOPS_H + +/* + * Cache Operations available on all MIPS processors with R4000-style caches + */ +#define Index_Invalidate_I 0x00 +#define Index_Writeback_Inv_D 0x01 +#define Index_Load_Tag_I 0x04 +#define Index_Load_Tag_D 0x05 +#define Index_Store_Tag_I 0x08 +#define Index_Store_Tag_D 0x09 +#if defined(CONFIG_CPU_LOONGSON2) +#define Hit_Invalidate_I 0x00 +#else +#define Hit_Invalidate_I 0x10 +#endif +#define Hit_Invalidate_D 0x11 +#define Hit_Writeback_Inv_D 0x15 + +/* + * R4000-specific cacheops + */ +#define Create_Dirty_Excl_D 0x0d +#define Fill 0x14 +#define Hit_Writeback_I 0x18 +#define Hit_Writeback_D 0x19 + +/* + * R4000SC and R4400SC-specific cacheops + */ +#define Index_Invalidate_SI 0x02 +#define Index_Writeback_Inv_SD 0x03 +#define Index_Load_Tag_SI 0x06 +#define Index_Load_Tag_SD 0x07 +#define Index_Store_Tag_SI 0x0A +#define Index_Store_Tag_SD 0x0B +#define Create_Dirty_Excl_SD 0x0f +#define Hit_Invalidate_SI 0x12 +#define Hit_Invalidate_SD 0x13 +#define Hit_Writeback_Inv_SD 0x17 +#define Hit_Writeback_SD 0x1b +#define Hit_Set_Virtual_SI 0x1e +#define Hit_Set_Virtual_SD 0x1f + +/* + * R5000-specific cacheops + */ +#define R5K_Page_Invalidate_S 0x17 + +/* + * RM7000-specific cacheops + */ +#define Page_Invalidate_T 0x16 + +/* + * R10000-specific cacheops + * + * Cacheops 0x02, 0x06, 0x0a, 0x0c-0x0e, 0x16, 0x1a and 0x1e are unused. + * Most of the _S cacheops are identical to the R4000SC _SD cacheops. + */ +#define Index_Writeback_Inv_S 0x03 +#define Index_Load_Tag_S 0x07 +#define Index_Store_Tag_S 0x0B +#define Hit_Invalidate_S 0x13 +#define Cache_Barrier 0x14 +#define Hit_Writeback_Inv_S 0x17 +#define Index_Load_Data_I 0x18 +#define Index_Load_Data_D 0x19 +#define Index_Load_Data_S 0x1b +#define Index_Store_Data_I 0x1c +#define Index_Store_Data_D 0x1d +#define Index_Store_Data_S 0x1f + +#endif /* __ASM_CACHEOPS_H */ diff --git a/target/linux/generic/image/relocate/cp0regdef.h b/target/linux/generic/image/relocate/cp0regdef.h new file mode 100644 index 0000000..c1188ad --- /dev/null +++ b/target/linux/generic/image/relocate/cp0regdef.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 1994, 1995, 1996, 1997, 2000, 2001 by Ralf Baechle + * + * Copyright (C) 2001, Monta Vista Software + * Author: jsun@mvista.com or jsun@junsun.net + */ +#ifndef _cp0regdef_h_ +#define _cp0regdef_h_ + +#define CP0_INDEX $0 +#define CP0_RANDOM $1 +#define CP0_ENTRYLO0 $2 +#define CP0_ENTRYLO1 $3 +#define CP0_CONTEXT $4 +#define CP0_PAGEMASK $5 +#define CP0_WIRED $6 +#define CP0_BADVADDR $8 +#define CP0_COUNT $9 +#define CP0_ENTRYHI $10 +#define CP0_COMPARE $11 +#define CP0_STATUS $12 +#define CP0_CAUSE $13 +#define CP0_EPC $14 +#define CP0_PRID $15 +#define CP0_CONFIG $16 +#define CP0_LLADDR $17 +#define CP0_WATCHLO $18 +#define CP0_WATCHHI $19 +#define CP0_XCONTEXT $20 +#define CP0_FRAMEMASK $21 +#define CP0_DIAGNOSTIC $22 +#define CP0_PERFORMANCE $25 +#define CP0_ECC $26 +#define CP0_CACHEERR $27 +#define CP0_TAGLO $28 +#define CP0_TAGHI $29 +#define CP0_ERROREPC $30 + +#endif diff --git a/target/linux/generic/image/relocate/head.S b/target/linux/generic/image/relocate/head.S new file mode 100644 index 0000000..3e5b374 --- /dev/null +++ b/target/linux/generic/image/relocate/head.S @@ -0,0 +1,159 @@ +/* + * Kernel relocation stub for MIPS devices + * + * Copyright (C) 2015 Felix Fietkau + * + * Based on: + * + * LZMA compressed kernel loader for Atheros AR7XXX/AR9XXX based boards + * + * Copyright (C) 2011 Gabor Juhos + * + * Some parts of this code was based on the OpenWrt specific lzma-loader + * for the BCM47xx and ADM5120 based boards: + * Copyright (C) 2004 Manuel Novoa III (mjn3@codepoet.org) + * Copyright (C) 2005 by Oleg I. Vdovikin + * + * 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. + */ + +#include +#include +#include "cp0regdef.h" +#include "cacheops.h" + +#define KSEG0 0x80000000 + + .macro ehb + sll zero, 3 + .endm + + .macro reset + li t0, 0xbe000034 + lw t1, 0(t0) + ori t1, 1 + sw t1, 0(t0) + .endm + + .text + +LEAF(startup) + .set noreorder + .set mips32 + + .fill 0x10000 + + mtc0 zero, CP0_WATCHLO # clear watch registers + mtc0 zero, CP0_WATCHHI + mtc0 zero, CP0_CAUSE # clear before writing status register + + mfc0 t0, CP0_STATUS + li t1, 0x1000001f + or t0, t1 + xori t0, 0x1f + mtc0 t0, CP0_STATUS + ehb + + mtc0 zero, CP0_COUNT + mtc0 zero, CP0_COMPARE + ehb + + la t0, __reloc_label # get linked address of label + bal __reloc_label # branch and link to label to + nop # get actual address +__reloc_label: + subu t0, ra, t0 # get reloc_delta + + /* Copy our code to the right place */ + la t1, _code_start # get linked address of _code_start + la t2, _code_end # get linked address of _code_end + + addu t4, t2, t0 # calculate actual address of _code_end + lw t5, 0(t4) # get extra data size + + add t2, t5 + add t2, 4 + + add t0, t1 # calculate actual address of _code_start + +__reloc_copy: + lw t3, 0(t0) + sw t3, 0(t1) + add t1, 4 + blt t1, t2, __reloc_copy + add t0, 4 + + /* flush cache */ + la t0, _code_start + la t1, _code_end + + li t2, ~(CONFIG_CACHELINE_SIZE - 1) + and t0, t2 + and t1, t2 + li t2, CONFIG_CACHELINE_SIZE + + b __flush_check + nop + +__flush_line: + cache Hit_Writeback_Inv_D, 0(t0) + cache Hit_Invalidate_I, 0(t0) + add t0, t2 + +__flush_check: + bne t0, t1, __flush_line + nop + + sync + + la t0, __reloc_back + j t0 + nop + +__reloc_back: + la t0, _code_end + add t0, 4 + + addu t1, t0, t5 + + li t2, KERNEL_ADDR + +__kernel_copy: + lw t3, 0(t0) + sw t3, 0(t2) + add t0, 4 + blt t0, t1, __kernel_copy + add t2, 4 + + /* flush cache */ + li t0, KERNEL_ADDR + addu t1, t0, t5 + + add t1, CONFIG_CACHELINE_SIZE - 1 + li t2, ~(CONFIG_CACHELINE_SIZE - 1) + and t0, t2 + and t1, t2 + li t2, CONFIG_CACHELINE_SIZE + + b __kernel_flush_check + nop + +__kernel_flush_line: + cache Hit_Writeback_Inv_D, 0(t0) + cache Hit_Invalidate_I, 0(t0) + add t0, t2 + +__kernel_flush_check: + bne t0, t1, __kernel_flush_line + nop + + sync + + li t0, KERNEL_ADDR + jr t0 + nop + + .set reorder +END(startup) diff --git a/target/linux/generic/image/relocate/loader.lds b/target/linux/generic/image/relocate/loader.lds new file mode 100644 index 0000000..98ca209 --- /dev/null +++ b/target/linux/generic/image/relocate/loader.lds @@ -0,0 +1,16 @@ +OUTPUT_ARCH(mips) +SECTIONS { + .text : { + _code_start = .; + *(.text) + *(.text.*) + *(.rodata) + *(.rodata.*) + *(.data) + *(.data.*) + } + + . = ALIGN(32); + + _code_end = .; +} diff --git a/target/linux/generic/patches-3.18/000-keep_initrafs_the_default.patch b/target/linux/generic/patches-3.18/000-keep_initrafs_the_default.patch new file mode 100644 index 0000000..d4164ca --- /dev/null +++ b/target/linux/generic/patches-3.18/000-keep_initrafs_the_default.patch @@ -0,0 +1,25 @@ +Upstream changed the default rootfs to tmpfs when none has been passed +to the kernel - this doesn't fit our purposes, so change it back. + +Signed-off-by: Imre Kaloz + +--- a/init/do_mounts.c ++++ b/init/do_mounts.c +@@ -623,6 +623,7 @@ int __init init_rootfs(void) + if (err) + return err; + ++#if 0 + if (IS_ENABLED(CONFIG_TMPFS) && !saved_root_name[0] && + (!root_fs_names || strstr(root_fs_names, "tmpfs"))) { + err = shmem_init(); +@@ -630,6 +631,9 @@ int __init init_rootfs(void) + } else { + err = init_ramfs_fs(); + } ++#else ++ err = init_ramfs_fs(); ++#endif + + if (err) + unregister_filesystem(&rootfs_fs_type); diff --git a/target/linux/generic/patches-3.18/020-ssb_update.patch b/target/linux/generic/patches-3.18/020-ssb_update.patch new file mode 100644 index 0000000..f94d160 --- /dev/null +++ b/target/linux/generic/patches-3.18/020-ssb_update.patch @@ -0,0 +1,134 @@ +--- a/drivers/ssb/pcihost_wrapper.c ++++ b/drivers/ssb/pcihost_wrapper.c +@@ -11,15 +11,17 @@ + * Licensed under the GNU/GPL. See COPYING for details. + */ + ++#include + #include + #include + #include + #include + + +-#ifdef CONFIG_PM +-static int ssb_pcihost_suspend(struct pci_dev *dev, pm_message_t state) ++#ifdef CONFIG_PM_SLEEP ++static int ssb_pcihost_suspend(struct device *d) + { ++ struct pci_dev *dev = to_pci_dev(d); + struct ssb_bus *ssb = pci_get_drvdata(dev); + int err; + +@@ -28,17 +30,23 @@ static int ssb_pcihost_suspend(struct pc + return err; + pci_save_state(dev); + pci_disable_device(dev); +- pci_set_power_state(dev, pci_choose_state(dev, state)); ++ ++ /* if there is a wakeup enabled child device on ssb bus, ++ enable pci wakeup posibility. */ ++ device_set_wakeup_enable(d, d->power.wakeup_path); ++ ++ pci_prepare_to_sleep(dev); + + return 0; + } + +-static int ssb_pcihost_resume(struct pci_dev *dev) ++static int ssb_pcihost_resume(struct device *d) + { ++ struct pci_dev *dev = to_pci_dev(d); + struct ssb_bus *ssb = pci_get_drvdata(dev); + int err; + +- pci_set_power_state(dev, PCI_D0); ++ pci_back_from_sleep(dev); + err = pci_enable_device(dev); + if (err) + return err; +@@ -49,10 +57,12 @@ static int ssb_pcihost_resume(struct pci + + return 0; + } +-#else /* CONFIG_PM */ +-# define ssb_pcihost_suspend NULL +-# define ssb_pcihost_resume NULL +-#endif /* CONFIG_PM */ ++ ++static const struct dev_pm_ops ssb_pcihost_pm_ops = { ++ SET_SYSTEM_SLEEP_PM_OPS(ssb_pcihost_suspend, ssb_pcihost_resume) ++}; ++ ++#endif /* CONFIG_PM_SLEEP */ + + static int ssb_pcihost_probe(struct pci_dev *dev, + const struct pci_device_id *id) +@@ -115,8 +125,9 @@ int ssb_pcihost_register(struct pci_driv + { + driver->probe = ssb_pcihost_probe; + driver->remove = ssb_pcihost_remove; +- driver->suspend = ssb_pcihost_suspend; +- driver->resume = ssb_pcihost_resume; ++#ifdef CONFIG_PM_SLEEP ++ driver->driver.pm = &ssb_pcihost_pm_ops; ++#endif + + return pci_register_driver(driver); + } +--- a/drivers/ssb/driver_pcicore.c ++++ b/drivers/ssb/driver_pcicore.c +@@ -357,6 +357,16 @@ static void ssb_pcicore_init_hostmode(st + pcicore_write32(pc, SSB_PCICORE_SBTOPCI2, + SSB_PCICORE_SBTOPCI_MEM | SSB_PCI_DMA); + ++ /* ++ * Accessing PCI config without a proper delay after devices reset (not ++ * GPIO reset) was causing reboots on WRT300N v1.0 (BCM4704). ++ * Tested delay 850 us lowered reboot chance to 50-80%, 1000 us fixed it ++ * completely. Flushing all writes was also tested but with no luck. ++ * The same problem was reported for WRT350N v1 (BCM4705), so we just ++ * sleep here unconditionally. ++ */ ++ usleep_range(1000, 2000); ++ + /* Enable PCI bridge BAR0 prefetch and burst */ + val = PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY; + ssb_extpci_write_config(pc, 0, 0, 0, PCI_COMMAND, &val, 2); +--- a/drivers/ssb/main.c ++++ b/drivers/ssb/main.c +@@ -90,25 +90,6 @@ found: + } + #endif /* CONFIG_SSB_PCMCIAHOST */ + +-#ifdef CONFIG_SSB_SDIOHOST +-struct ssb_bus *ssb_sdio_func_to_bus(struct sdio_func *func) +-{ +- struct ssb_bus *bus; +- +- ssb_buses_lock(); +- list_for_each_entry(bus, &buses, list) { +- if (bus->bustype == SSB_BUSTYPE_SDIO && +- bus->host_sdio == func) +- goto found; +- } +- bus = NULL; +-found: +- ssb_buses_unlock(); +- +- return bus; +-} +-#endif /* CONFIG_SSB_SDIOHOST */ +- + int ssb_for_each_bus_call(unsigned long data, + int (*func)(struct ssb_bus *bus, unsigned long data)) + { +@@ -1154,6 +1135,8 @@ static u32 ssb_tmslow_reject_bitmask(str + case SSB_IDLOW_SSBREV_25: /* TODO - find the proper REJECT bit */ + case SSB_IDLOW_SSBREV_27: /* same here */ + return SSB_TMSLOW_REJECT; /* this is a guess */ ++ case SSB_IDLOW_SSBREV: ++ break; + default: + WARN(1, KERN_INFO "ssb: Backplane Revision 0x%.8X\n", rev); + } diff --git a/target/linux/generic/patches-3.18/021-ssb_sprom.patch b/target/linux/generic/patches-3.18/021-ssb_sprom.patch new file mode 100644 index 0000000..52d8080 --- /dev/null +++ b/target/linux/generic/patches-3.18/021-ssb_sprom.patch @@ -0,0 +1,32 @@ +--- a/include/linux/ssb/ssb.h ++++ b/include/linux/ssb/ssb.h +@@ -29,10 +29,13 @@ struct ssb_sprom { + u8 il0mac[6] __aligned(sizeof(u16)); /* MAC address for 802.11b/g */ + u8 et0mac[6] __aligned(sizeof(u16)); /* MAC address for Ethernet */ + u8 et1mac[6] __aligned(sizeof(u16)); /* MAC address for 802.11a */ ++ u8 et2mac[6] __aligned(sizeof(u16)); /* MAC address for extra Ethernet */ + u8 et0phyaddr; /* MII address for enet0 */ + u8 et1phyaddr; /* MII address for enet1 */ ++ u8 et2phyaddr; /* MII address for enet2 */ + u8 et0mdcport; /* MDIO for enet0 */ + u8 et1mdcport; /* MDIO for enet1 */ ++ u8 et2mdcport; /* MDIO for enet2 */ + u16 dev_id; /* Device ID overriding e.g. PCI ID */ + u16 board_rev; /* Board revision number from SPROM. */ + u16 board_num; /* Board number from SPROM. */ +@@ -88,11 +91,14 @@ struct ssb_sprom { + u32 ofdm5glpo; /* 5.2GHz OFDM power offset */ + u32 ofdm5gpo; /* 5.3GHz OFDM power offset */ + u32 ofdm5ghpo; /* 5.8GHz OFDM power offset */ ++ u32 boardflags; ++ u32 boardflags2; ++ u32 boardflags3; ++ /* TODO: Switch all drivers to new u32 fields and drop below ones */ + u16 boardflags_lo; /* Board flags (bits 0-15) */ + u16 boardflags_hi; /* Board flags (bits 16-31) */ + u16 boardflags2_lo; /* Board flags (bits 32-47) */ + u16 boardflags2_hi; /* Board flags (bits 48-63) */ +- /* TODO store board flags in a single u64 */ + + struct ssb_sprom_core_pwr_info core_pwr_info[4]; + diff --git a/target/linux/generic/patches-3.18/025-bcma_backport.patch b/target/linux/generic/patches-3.18/025-bcma_backport.patch new file mode 100644 index 0000000..ca24e86 --- /dev/null +++ b/target/linux/generic/patches-3.18/025-bcma_backport.patch @@ -0,0 +1,286 @@ +--- a/drivers/bcma/bcma_private.h ++++ b/drivers/bcma/bcma_private.h +@@ -24,6 +24,7 @@ struct bcma_bus; + /* main.c */ + bool bcma_wait_value(struct bcma_device *core, u16 reg, u32 mask, u32 value, + int timeout); ++void bcma_prepare_core(struct bcma_bus *bus, struct bcma_device *core); + int bcma_bus_register(struct bcma_bus *bus); + void bcma_bus_unregister(struct bcma_bus *bus); + int __init bcma_bus_early_register(struct bcma_bus *bus, +--- a/drivers/bcma/driver_chipcommon.c ++++ b/drivers/bcma/driver_chipcommon.c +@@ -339,7 +339,7 @@ void bcma_chipco_serial_init(struct bcma + return; + } + +- irq = bcma_core_irq(cc->core); ++ irq = bcma_core_irq(cc->core, 0); + + /* Determine the registers of the UARTs */ + cc->nr_serial_ports = (cc->capabilities & BCMA_CC_CAP_NRUART); +--- a/drivers/bcma/driver_gpio.c ++++ b/drivers/bcma/driver_gpio.c +@@ -152,7 +152,7 @@ static int bcma_gpio_irq_domain_init(str + handle_simple_irq); + } + +- hwirq = bcma_core_irq(cc->core); ++ hwirq = bcma_core_irq(cc->core, 0); + err = request_irq(hwirq, bcma_gpio_irq_handler, IRQF_SHARED, "gpio", + cc); + if (err) +@@ -183,7 +183,7 @@ static void bcma_gpio_irq_domain_exit(st + return; + + bcma_cc_mask32(cc, BCMA_CC_IRQMASK, ~BCMA_CC_IRQ_GPIO); +- free_irq(bcma_core_irq(cc->core), cc); ++ free_irq(bcma_core_irq(cc->core, 0), cc); + for (gpio = 0; gpio < chip->ngpio; gpio++) { + int irq = irq_find_mapping(cc->irq_domain, gpio); + +--- a/drivers/bcma/driver_mips.c ++++ b/drivers/bcma/driver_mips.c +@@ -115,7 +115,7 @@ static u32 bcma_core_mips_irqflag(struct + * If disabled, 5 is returned. + * If not supported, 6 is returned. + */ +-static unsigned int bcma_core_mips_irq(struct bcma_device *dev) ++unsigned int bcma_core_mips_irq(struct bcma_device *dev) + { + struct bcma_device *mdev = dev->bus->drv_mips.core; + u32 irqflag; +@@ -133,13 +133,6 @@ static unsigned int bcma_core_mips_irq(s + return 5; + } + +-unsigned int bcma_core_irq(struct bcma_device *dev) +-{ +- unsigned int mips_irq = bcma_core_mips_irq(dev); +- return mips_irq <= 4 ? mips_irq + 2 : 0; +-} +-EXPORT_SYMBOL(bcma_core_irq); +- + static void bcma_core_mips_set_irq(struct bcma_device *dev, unsigned int irq) + { + unsigned int oldirq = bcma_core_mips_irq(dev); +@@ -423,7 +416,7 @@ void bcma_core_mips_init(struct bcma_drv + break; + default: + list_for_each_entry(core, &bus->cores, list) { +- core->irq = bcma_core_irq(core); ++ core->irq = bcma_core_irq(core, 0); + } + bcma_err(bus, + "Unknown device (0x%x) found, can not configure IRQs\n", +--- a/drivers/bcma/driver_pci_host.c ++++ b/drivers/bcma/driver_pci_host.c +@@ -593,7 +593,7 @@ int bcma_core_pci_plat_dev_init(struct p + pr_info("PCI: Fixing up device %s\n", pci_name(dev)); + + /* Fix up interrupt lines */ +- dev->irq = bcma_core_irq(pc_host->pdev->core); ++ dev->irq = bcma_core_irq(pc_host->pdev->core, 0); + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); + + readrq = pcie_get_readrq(dev); +@@ -617,6 +617,6 @@ int bcma_core_pci_pcibios_map_irq(const + + pc_host = container_of(dev->bus->ops, struct bcma_drv_pci_host, + pci_ops); +- return bcma_core_irq(pc_host->pdev->core); ++ return bcma_core_irq(pc_host->pdev->core, 0); + } + EXPORT_SYMBOL(bcma_core_pci_pcibios_map_irq); +--- a/drivers/bcma/main.c ++++ b/drivers/bcma/main.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + + MODULE_DESCRIPTION("Broadcom's specific AMBA driver"); + MODULE_LICENSE("GPL"); +@@ -153,6 +154,46 @@ static struct device_node *bcma_of_find_ + return NULL; + } + ++static int bcma_of_irq_parse(struct platform_device *parent, ++ struct bcma_device *core, ++ struct of_phandle_args *out_irq, int num) ++{ ++ __be32 laddr[1]; ++ int rc; ++ ++ if (core->dev.of_node) { ++ rc = of_irq_parse_one(core->dev.of_node, num, out_irq); ++ if (!rc) ++ return rc; ++ } ++ ++ out_irq->np = parent->dev.of_node; ++ out_irq->args_count = 1; ++ out_irq->args[0] = num; ++ ++ laddr[0] = cpu_to_be32(core->addr); ++ return of_irq_parse_raw(laddr, out_irq); ++} ++ ++static unsigned int bcma_of_get_irq(struct platform_device *parent, ++ struct bcma_device *core, int num) ++{ ++ struct of_phandle_args out_irq; ++ int ret; ++ ++ if (!parent || !parent->dev.of_node) ++ return 0; ++ ++ ret = bcma_of_irq_parse(parent, core, &out_irq, num); ++ if (ret) { ++ bcma_debug(core->bus, "bcma_of_get_irq() failed with rc=%d\n", ++ ret); ++ return 0; ++ } ++ ++ return irq_create_of_mapping(&out_irq); ++} ++ + static void bcma_of_fill_device(struct platform_device *parent, + struct bcma_device *core) + { +@@ -161,18 +202,47 @@ static void bcma_of_fill_device(struct p + node = bcma_of_find_child_device(parent, core); + if (node) + core->dev.of_node = node; ++ ++ core->irq = bcma_of_get_irq(parent, core, 0); + } + #else + static void bcma_of_fill_device(struct platform_device *parent, + struct bcma_device *core) + { + } ++static inline unsigned int bcma_of_get_irq(struct platform_device *parent, ++ struct bcma_device *core, int num) ++{ ++ return 0; ++} + #endif /* CONFIG_OF */ + +-static void bcma_register_core(struct bcma_bus *bus, struct bcma_device *core) ++unsigned int bcma_core_irq(struct bcma_device *core, int num) + { +- int err; ++ struct bcma_bus *bus = core->bus; ++ unsigned int mips_irq; ++ ++ switch (bus->hosttype) { ++ case BCMA_HOSTTYPE_PCI: ++ return bus->host_pci->irq; ++ case BCMA_HOSTTYPE_SOC: ++ if (bus->drv_mips.core && num == 0) { ++ mips_irq = bcma_core_mips_irq(core); ++ return mips_irq <= 4 ? mips_irq + 2 : 0; ++ } ++ if (bus->host_pdev) ++ return bcma_of_get_irq(bus->host_pdev, core, num); ++ return 0; ++ case BCMA_HOSTTYPE_SDIO: ++ return 0; ++ } + ++ return 0; ++} ++EXPORT_SYMBOL(bcma_core_irq); ++ ++void bcma_prepare_core(struct bcma_bus *bus, struct bcma_device *core) ++{ + core->dev.release = bcma_release_core_dev; + core->dev.bus = &bcma_bus_type; + dev_set_name(&core->dev, "bcma%d:%d", bus->num, core->core_index); +@@ -196,6 +266,11 @@ static void bcma_register_core(struct bc + case BCMA_HOSTTYPE_SDIO: + break; + } ++} ++ ++static void bcma_register_core(struct bcma_bus *bus, struct bcma_device *core) ++{ ++ int err; + + err = device_register(&core->dev); + if (err) { +--- a/drivers/bcma/scan.c ++++ b/drivers/bcma/scan.c +@@ -505,6 +505,7 @@ int bcma_bus_scan(struct bcma_bus *bus) + bus->nr_cores++; + other_core = bcma_find_core_reverse(bus, core->id.id); + core->core_unit = (other_core == NULL) ? 0 : other_core->core_unit + 1; ++ bcma_prepare_core(bus, core); + + bcma_info(bus, "Core %d found: %s (manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n", + core->core_index, bcma_device_name(&core->id), +--- a/include/linux/bcma/bcma.h ++++ b/include/linux/bcma/bcma.h +@@ -447,4 +447,6 @@ extern u32 bcma_chipco_pll_read(struct b + #define BCMA_DMA_TRANSLATION_DMA64_CMT 0x80000000 /* Client Mode Translation for 64-bit DMA */ + extern u32 bcma_core_dma_translation(struct bcma_device *core); + ++extern unsigned int bcma_core_irq(struct bcma_device *core, int num); ++ + #endif /* LINUX_BCMA_H_ */ +--- a/include/linux/bcma/bcma_driver_mips.h ++++ b/include/linux/bcma/bcma_driver_mips.h +@@ -43,12 +43,12 @@ struct bcma_drv_mips { + extern void bcma_core_mips_init(struct bcma_drv_mips *mcore); + extern void bcma_core_mips_early_init(struct bcma_drv_mips *mcore); + +-extern unsigned int bcma_core_irq(struct bcma_device *core); ++extern unsigned int bcma_core_mips_irq(struct bcma_device *dev); + #else + static inline void bcma_core_mips_init(struct bcma_drv_mips *mcore) { } + static inline void bcma_core_mips_early_init(struct bcma_drv_mips *mcore) { } + +-static inline unsigned int bcma_core_irq(struct bcma_device *core) ++static inline unsigned int bcma_core_mips_irq(struct bcma_device *dev) + { + return 0; + } +--- a/Documentation/devicetree/bindings/bus/bcma.txt ++++ b/Documentation/devicetree/bindings/bus/bcma.txt +@@ -8,6 +8,11 @@ Required properties: + + The cores on the AXI bus are automatically detected by bcma with the + memory ranges they are using and they get registered afterwards. ++Automatic detection of the IRQ number is not working on ++BCM47xx/BCM53xx ARM SoCs. To assign IRQ numbers to the cores, provide ++them manually through device tree. Use an interrupt-map to specify the ++IRQ used by the devices on the bus. The first address is just an index, ++because we do not have any special register. + + The top-level axi bus may contain children representing attached cores + (devices). This is needed since some hardware details can't be auto +@@ -22,6 +27,22 @@ Example: + ranges = <0x00000000 0x18000000 0x00100000>; + #address-cells = <1>; + #size-cells = <1>; ++ #interrupt-cells = <1>; ++ interrupt-map-mask = <0x000fffff 0xffff>; ++ interrupt-map = ++ /* Ethernet Controller 0 */ ++ <0x00024000 0 &gic GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>, ++ ++ /* Ethernet Controller 1 */ ++ <0x00025000 0 &gic GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>; ++ ++ /* PCIe Controller 0 */ ++ <0x00012000 0 &gic GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>, ++ <0x00012000 1 &gic GIC_SPI 127 IRQ_TYPE_LEVEL_HIGH>, ++ <0x00012000 2 &gic GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>, ++ <0x00012000 3 &gic GIC_SPI 129 IRQ_TYPE_LEVEL_HIGH>, ++ <0x00012000 4 &gic GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>, ++ <0x00012000 5 &gic GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>; + + chipcommon { + reg = <0x00000000 0x1000>; diff --git a/target/linux/generic/patches-3.18/026-bcma-from-3.20.patch b/target/linux/generic/patches-3.18/026-bcma-from-3.20.patch new file mode 100644 index 0000000..17c06b0 --- /dev/null +++ b/target/linux/generic/patches-3.18/026-bcma-from-3.20.patch @@ -0,0 +1,527 @@ +--- a/drivers/bcma/bcma_private.h ++++ b/drivers/bcma/bcma_private.h +@@ -25,22 +25,18 @@ struct bcma_bus; + bool bcma_wait_value(struct bcma_device *core, u16 reg, u32 mask, u32 value, + int timeout); + void bcma_prepare_core(struct bcma_bus *bus, struct bcma_device *core); ++void bcma_init_bus(struct bcma_bus *bus); + int bcma_bus_register(struct bcma_bus *bus); + void bcma_bus_unregister(struct bcma_bus *bus); +-int __init bcma_bus_early_register(struct bcma_bus *bus, +- struct bcma_device *core_cc, +- struct bcma_device *core_mips); ++int __init bcma_bus_early_register(struct bcma_bus *bus); + #ifdef CONFIG_PM + int bcma_bus_suspend(struct bcma_bus *bus); + int bcma_bus_resume(struct bcma_bus *bus); + #endif + + /* scan.c */ ++void bcma_detect_chip(struct bcma_bus *bus); + int bcma_bus_scan(struct bcma_bus *bus); +-int __init bcma_bus_scan_early(struct bcma_bus *bus, +- struct bcma_device_id *match, +- struct bcma_device *core); +-void bcma_init_bus(struct bcma_bus *bus); + + /* sprom.c */ + int bcma_sprom_get(struct bcma_bus *bus); +@@ -111,6 +107,14 @@ extern int bcma_chipco_watchdog_register + #ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE + bool bcma_core_pci_is_in_hostmode(struct bcma_drv_pci *pc); + void bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc); ++#else ++static inline bool bcma_core_pci_is_in_hostmode(struct bcma_drv_pci *pc) ++{ ++ return false; ++} ++static inline void bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc) ++{ ++} + #endif /* CONFIG_BCMA_DRIVER_PCI_HOSTMODE */ + + #ifdef CONFIG_BCMA_DRIVER_GPIO +--- a/drivers/bcma/driver_chipcommon.c ++++ b/drivers/bcma/driver_chipcommon.c +@@ -79,7 +79,9 @@ static int bcma_chipco_watchdog_ticks_pe + + if (cc->capabilities & BCMA_CC_CAP_PMU) { + if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) +- /* 4706 CC and PMU watchdogs are clocked at 1/4 of ALP clock */ ++ /* 4706 CC and PMU watchdogs are clocked at 1/4 of ALP ++ * clock ++ */ + return bcma_chipco_get_alp_clock(cc) / 4000; + else + /* based on 32KHz ILP clock */ +@@ -97,7 +99,8 @@ int bcma_chipco_watchdog_register(struct + wdt.driver_data = cc; + wdt.timer_set = bcma_chipco_watchdog_timer_set_wdt; + wdt.timer_set_ms = bcma_chipco_watchdog_timer_set_ms_wdt; +- wdt.max_timer_ms = bcma_chipco_watchdog_get_max_timer(cc) / cc->ticks_per_ms; ++ wdt.max_timer_ms = ++ bcma_chipco_watchdog_get_max_timer(cc) / cc->ticks_per_ms; + + pdev = platform_device_register_data(NULL, "bcm47xx-wdt", + cc->core->bus->num, &wdt, +@@ -175,7 +178,6 @@ void bcma_core_chipcommon_init(struct bc + u32 bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc, u32 ticks) + { + u32 maxt; +- enum bcma_clkmode clkmode; + + maxt = bcma_chipco_watchdog_get_max_timer(cc); + if (cc->capabilities & BCMA_CC_CAP_PMU) { +@@ -185,8 +187,13 @@ u32 bcma_chipco_watchdog_timer_set(struc + ticks = maxt; + bcma_cc_write32(cc, BCMA_CC_PMU_WATCHDOG, ticks); + } else { +- clkmode = ticks ? BCMA_CLKMODE_FAST : BCMA_CLKMODE_DYNAMIC; +- bcma_core_set_clockmode(cc->core, clkmode); ++ struct bcma_bus *bus = cc->core->bus; ++ ++ if (bus->chipinfo.id != BCMA_CHIP_ID_BCM4707 && ++ bus->chipinfo.id != BCMA_CHIP_ID_BCM53018) ++ bcma_core_set_clockmode(cc->core, ++ ticks ? BCMA_CLKMODE_FAST : BCMA_CLKMODE_DYNAMIC); ++ + if (ticks > maxt) + ticks = maxt; + /* instant NMI */ +@@ -335,7 +342,8 @@ void bcma_chipco_serial_init(struct bcma + | BCMA_CC_CORECTL_UARTCLKEN); + } + } else { +- bcma_err(cc->core->bus, "serial not supported on this device ccrev: 0x%x\n", ccrev); ++ bcma_err(cc->core->bus, "serial not supported on this device ccrev: 0x%x\n", ++ ccrev); + return; + } + +--- a/drivers/bcma/driver_pci.c ++++ b/drivers/bcma/driver_pci.c +@@ -145,6 +145,47 @@ static u16 bcma_pcie_mdio_writeread(stru + } + + /************************************************** ++ * Early init. ++ **************************************************/ ++ ++static void bcma_core_pci_fixcfg(struct bcma_drv_pci *pc) ++{ ++ struct bcma_device *core = pc->core; ++ u16 val16, core_index; ++ uint regoff; ++ ++ regoff = BCMA_CORE_PCI_SPROM(BCMA_CORE_PCI_SPROM_PI_OFFSET); ++ core_index = (u16)core->core_index; ++ ++ val16 = pcicore_read16(pc, regoff); ++ if (((val16 & BCMA_CORE_PCI_SPROM_PI_MASK) >> BCMA_CORE_PCI_SPROM_PI_SHIFT) ++ != core_index) { ++ val16 = (core_index << BCMA_CORE_PCI_SPROM_PI_SHIFT) | ++ (val16 & ~BCMA_CORE_PCI_SPROM_PI_MASK); ++ pcicore_write16(pc, regoff, val16); ++ } ++} ++ ++/* ++ * Apply some early fixes required before accessing SPROM. ++ * See also si_pci_fixcfg. ++ */ ++void bcma_core_pci_early_init(struct bcma_drv_pci *pc) ++{ ++ if (pc->early_setup_done) ++ return; ++ ++ pc->hostmode = bcma_core_pci_is_in_hostmode(pc); ++ if (pc->hostmode) ++ goto out; ++ ++ bcma_core_pci_fixcfg(pc); ++ ++out: ++ pc->early_setup_done = true; ++} ++ ++/************************************************** + * Workarounds. + **************************************************/ + +@@ -175,24 +216,6 @@ static void bcma_pcicore_serdes_workarou + tmp & ~BCMA_CORE_PCI_PLL_CTRL_FREQDET_EN); + } + +-static void bcma_core_pci_fixcfg(struct bcma_drv_pci *pc) +-{ +- struct bcma_device *core = pc->core; +- u16 val16, core_index; +- uint regoff; +- +- regoff = BCMA_CORE_PCI_SPROM(BCMA_CORE_PCI_SPROM_PI_OFFSET); +- core_index = (u16)core->core_index; +- +- val16 = pcicore_read16(pc, regoff); +- if (((val16 & BCMA_CORE_PCI_SPROM_PI_MASK) >> BCMA_CORE_PCI_SPROM_PI_SHIFT) +- != core_index) { +- val16 = (core_index << BCMA_CORE_PCI_SPROM_PI_SHIFT) | +- (val16 & ~BCMA_CORE_PCI_SPROM_PI_MASK); +- pcicore_write16(pc, regoff, val16); +- } +-} +- + /* Fix MISC config to allow coming out of L2/L3-Ready state w/o PRST */ + /* Needs to happen when coming out of 'standby'/'hibernate' */ + static void bcma_core_pci_config_fixup(struct bcma_drv_pci *pc) +@@ -216,7 +239,6 @@ static void bcma_core_pci_config_fixup(s + + static void bcma_core_pci_clientmode_init(struct bcma_drv_pci *pc) + { +- bcma_core_pci_fixcfg(pc); + bcma_pcicore_serdes_workaround(pc); + bcma_core_pci_config_fixup(pc); + } +@@ -226,13 +248,11 @@ void bcma_core_pci_init(struct bcma_drv_ + if (pc->setup_done) + return; + +-#ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE +- pc->hostmode = bcma_core_pci_is_in_hostmode(pc); ++ bcma_core_pci_early_init(pc); ++ + if (pc->hostmode) + bcma_core_pci_hostmode_init(pc); +-#endif /* CONFIG_BCMA_DRIVER_PCI_HOSTMODE */ +- +- if (!pc->hostmode) ++ else + bcma_core_pci_clientmode_init(pc); + } + +--- a/drivers/bcma/host_pci.c ++++ b/drivers/bcma/host_pci.c +@@ -13,10 +13,12 @@ + + static void bcma_host_pci_switch_core(struct bcma_device *core) + { ++ int win2 = core->bus->host_is_pcie2 ? ++ BCMA_PCIE2_BAR0_WIN2 : BCMA_PCI_BAR0_WIN2; ++ + pci_write_config_dword(core->bus->host_pci, BCMA_PCI_BAR0_WIN, + core->addr); +- pci_write_config_dword(core->bus->host_pci, BCMA_PCI_BAR0_WIN2, +- core->wrap); ++ pci_write_config_dword(core->bus->host_pci, win2, core->wrap); + core->bus->mapped_core = core; + bcma_debug(core->bus, "Switched to core: 0x%X\n", core->id.id); + } +--- a/drivers/bcma/host_soc.c ++++ b/drivers/bcma/host_soc.c +@@ -193,7 +193,7 @@ int __init bcma_host_soc_init(struct bcm + int err; + + /* Scan bus and initialize it */ +- err = bcma_bus_early_register(bus, &soc->core_cc, &soc->core_mips); ++ err = bcma_bus_early_register(bus); + if (err) + iounmap(bus->mmio); + +--- a/drivers/bcma/main.c ++++ b/drivers/bcma/main.c +@@ -268,6 +268,18 @@ void bcma_prepare_core(struct bcma_bus * + } + } + ++void bcma_init_bus(struct bcma_bus *bus) ++{ ++ mutex_lock(&bcma_buses_mutex); ++ bus->num = bcma_bus_next_num++; ++ mutex_unlock(&bcma_buses_mutex); ++ ++ INIT_LIST_HEAD(&bus->cores); ++ bus->nr_cores = 0; ++ ++ bcma_detect_chip(bus); ++} ++ + static void bcma_register_core(struct bcma_bus *bus, struct bcma_device *core) + { + int err; +@@ -356,12 +368,19 @@ static void bcma_unregister_cores(struct + struct bcma_device *core, *tmp; + + list_for_each_entry_safe(core, tmp, &bus->cores, list) { ++ if (!core->dev_registered) ++ continue; + list_del(&core->list); +- if (core->dev_registered) +- device_unregister(&core->dev); ++ device_unregister(&core->dev); + } + if (bus->hosttype == BCMA_HOSTTYPE_SOC) + platform_device_unregister(bus->drv_cc.watchdog); ++ ++ /* Now noone uses internally-handled cores, we can free them */ ++ list_for_each_entry_safe(core, tmp, &bus->cores, list) { ++ list_del(&core->list); ++ kfree(core); ++ } + } + + int bcma_bus_register(struct bcma_bus *bus) +@@ -369,10 +388,6 @@ int bcma_bus_register(struct bcma_bus *b + int err; + struct bcma_device *core; + +- mutex_lock(&bcma_buses_mutex); +- bus->num = bcma_bus_next_num++; +- mutex_unlock(&bcma_buses_mutex); +- + /* Scan for devices (cores) */ + err = bcma_bus_scan(bus); + if (err) { +@@ -387,6 +402,13 @@ int bcma_bus_register(struct bcma_bus *b + bcma_core_chipcommon_early_init(&bus->drv_cc); + } + ++ /* Early init PCIE core */ ++ core = bcma_find_core(bus, BCMA_CORE_PCIE); ++ if (core) { ++ bus->drv_pci[0].core = core; ++ bcma_core_pci_early_init(&bus->drv_pci[0]); ++ } ++ + /* Cores providing flash access go before SPROM init */ + list_for_each_entry(core, &bus->cores, list) { + if (bcma_is_core_needed_early(core->id.id)) +@@ -459,7 +481,6 @@ int bcma_bus_register(struct bcma_bus *b + + void bcma_bus_unregister(struct bcma_bus *bus) + { +- struct bcma_device *cores[3]; + int err; + + err = bcma_gpio_unregister(&bus->drv_cc); +@@ -470,46 +491,23 @@ void bcma_bus_unregister(struct bcma_bus + + bcma_core_chipcommon_b_free(&bus->drv_cc_b); + +- cores[0] = bcma_find_core(bus, BCMA_CORE_MIPS_74K); +- cores[1] = bcma_find_core(bus, BCMA_CORE_PCIE); +- cores[2] = bcma_find_core(bus, BCMA_CORE_4706_MAC_GBIT_COMMON); +- + bcma_unregister_cores(bus); +- +- kfree(cores[2]); +- kfree(cores[1]); +- kfree(cores[0]); + } + +-int __init bcma_bus_early_register(struct bcma_bus *bus, +- struct bcma_device *core_cc, +- struct bcma_device *core_mips) ++/* ++ * This is a special version of bus registration function designed for SoCs. ++ * It scans bus and performs basic initialization of main cores only. ++ * Please note it requires memory allocation, however it won't try to sleep. ++ */ ++int __init bcma_bus_early_register(struct bcma_bus *bus) + { + int err; + struct bcma_device *core; +- struct bcma_device_id match; +- +- match.manuf = BCMA_MANUF_BCM; +- match.id = bcma_cc_core_id(bus); +- match.class = BCMA_CL_SIM; +- match.rev = BCMA_ANY_REV; + +- /* Scan for chip common core */ +- err = bcma_bus_scan_early(bus, &match, core_cc); +- if (err) { +- bcma_err(bus, "Failed to scan for common core: %d\n", err); +- return -1; +- } +- +- match.manuf = BCMA_MANUF_MIPS; +- match.id = BCMA_CORE_MIPS_74K; +- match.class = BCMA_CL_SIM; +- match.rev = BCMA_ANY_REV; +- +- /* Scan for mips core */ +- err = bcma_bus_scan_early(bus, &match, core_mips); ++ /* Scan for devices (cores) */ ++ err = bcma_bus_scan(bus); + if (err) { +- bcma_err(bus, "Failed to scan for mips core: %d\n", err); ++ bcma_err(bus, "Failed to scan bus: %d\n", err); + return -1; + } + +--- a/drivers/bcma/scan.c ++++ b/drivers/bcma/scan.c +@@ -435,15 +435,12 @@ static int bcma_get_next_core(struct bcm + return 0; + } + +-void bcma_init_bus(struct bcma_bus *bus) ++void bcma_detect_chip(struct bcma_bus *bus) + { + s32 tmp; + struct bcma_chipinfo *chipinfo = &(bus->chipinfo); + char chip_id[8]; + +- INIT_LIST_HEAD(&bus->cores); +- bus->nr_cores = 0; +- + bcma_scan_switch_core(bus, BCMA_ADDR_BASE); + + tmp = bcma_scan_read32(bus, 0, BCMA_CC_ID); +@@ -464,6 +461,10 @@ int bcma_bus_scan(struct bcma_bus *bus) + + int err, core_num = 0; + ++ /* Skip if bus was already scanned (e.g. during early register) */ ++ if (bus->nr_cores) ++ return 0; ++ + erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM); + if (bus->hosttype == BCMA_HOSTTYPE_SOC) { + eromptr = ioremap_nocache(erombase, BCMA_CORE_SIZE); +@@ -519,64 +520,6 @@ int bcma_bus_scan(struct bcma_bus *bus) + out: + if (bus->hosttype == BCMA_HOSTTYPE_SOC) + iounmap(eromptr); +- +- return err; +-} +- +-int __init bcma_bus_scan_early(struct bcma_bus *bus, +- struct bcma_device_id *match, +- struct bcma_device *core) +-{ +- u32 erombase; +- u32 __iomem *eromptr, *eromend; +- +- int err = -ENODEV; +- int core_num = 0; +- +- erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM); +- if (bus->hosttype == BCMA_HOSTTYPE_SOC) { +- eromptr = ioremap_nocache(erombase, BCMA_CORE_SIZE); +- if (!eromptr) +- return -ENOMEM; +- } else { +- eromptr = bus->mmio; +- } +- +- eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32); +- +- bcma_scan_switch_core(bus, erombase); +- +- while (eromptr < eromend) { +- memset(core, 0, sizeof(*core)); +- INIT_LIST_HEAD(&core->list); +- core->bus = bus; +- +- err = bcma_get_next_core(bus, &eromptr, match, core_num, core); +- if (err == -ENODEV) { +- core_num++; +- continue; +- } else if (err == -ENXIO) +- continue; +- else if (err == -ESPIPE) +- break; +- else if (err < 0) +- goto out; +- +- core->core_index = core_num++; +- bus->nr_cores++; +- bcma_info(bus, "Core %d found: %s (manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n", +- core->core_index, bcma_device_name(&core->id), +- core->id.manuf, core->id.id, core->id.rev, +- core->id.class); +- +- list_add_tail(&core->list, &bus->cores); +- err = 0; +- break; +- } +- +-out: +- if (bus->hosttype == BCMA_HOSTTYPE_SOC) +- iounmap(eromptr); + + return err; + } +--- a/drivers/bcma/sprom.c ++++ b/drivers/bcma/sprom.c +@@ -579,7 +579,8 @@ int bcma_sprom_get(struct bcma_bus *bus) + u16 offset = BCMA_CC_SPROM; + u16 *sprom; + size_t sprom_sizes[] = { SSB_SPROMSIZE_WORDS_R4, +- SSB_SPROMSIZE_WORDS_R10, }; ++ SSB_SPROMSIZE_WORDS_R10, ++ SSB_SPROMSIZE_WORDS_R11, }; + int i, err = 0; + + if (!bus->drv_cc.core) +--- a/include/linux/bcma/bcma.h ++++ b/include/linux/bcma/bcma.h +@@ -318,6 +318,7 @@ struct bcma_bus { + const struct bcma_host_ops *ops; + + enum bcma_hosttype hosttype; ++ bool host_is_pcie2; /* Used for BCMA_HOSTTYPE_PCI only */ + union { + /* Pointer to the PCI bus (only for BCMA_HOSTTYPE_PCI) */ + struct pci_dev *host_pci; +--- a/include/linux/bcma/bcma_driver_pci.h ++++ b/include/linux/bcma/bcma_driver_pci.h +@@ -223,6 +223,7 @@ struct bcma_drv_pci_host { + + struct bcma_drv_pci { + struct bcma_device *core; ++ u8 early_setup_done:1; + u8 setup_done:1; + u8 hostmode:1; + +@@ -237,6 +238,7 @@ struct bcma_drv_pci { + #define pcicore_write16(pc, offset, val) bcma_write16((pc)->core, offset, val) + #define pcicore_write32(pc, offset, val) bcma_write32((pc)->core, offset, val) + ++extern void bcma_core_pci_early_init(struct bcma_drv_pci *pc); + extern void bcma_core_pci_init(struct bcma_drv_pci *pc); + extern int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, + struct bcma_device *core, bool enable); +--- a/include/linux/bcma/bcma_regs.h ++++ b/include/linux/bcma/bcma_regs.h +@@ -64,6 +64,8 @@ + #define BCMA_PCI_GPIO_XTAL 0x40 /* PCI config space GPIO 14 for Xtal powerup */ + #define BCMA_PCI_GPIO_PLL 0x80 /* PCI config space GPIO 15 for PLL powerdown */ + ++#define BCMA_PCIE2_BAR0_WIN2 0x70 ++ + /* SiliconBackplane Address Map. + * All regions may not exist on all chips. + */ +--- a/include/linux/bcma/bcma_soc.h ++++ b/include/linux/bcma/bcma_soc.h +@@ -5,8 +5,6 @@ + + struct bcma_soc { + struct bcma_bus bus; +- struct bcma_device core_cc; +- struct bcma_device core_mips; + }; + + int __init bcma_host_soc_register(struct bcma_soc *soc); +--- a/include/linux/ssb/ssb_regs.h ++++ b/include/linux/ssb/ssb_regs.h +@@ -173,6 +173,7 @@ + #define SSB_SPROMSIZE_BYTES_R123 (SSB_SPROMSIZE_WORDS_R123 * sizeof(u16)) + #define SSB_SPROMSIZE_BYTES_R4 (SSB_SPROMSIZE_WORDS_R4 * sizeof(u16)) + #define SSB_SPROMSIZE_WORDS_R10 230 ++#define SSB_SPROMSIZE_WORDS_R11 234 + #define SSB_SPROM_BASE1 0x1000 + #define SSB_SPROM_BASE31 0x0800 + #define SSB_SPROM_REVISION 0x007E diff --git a/target/linux/generic/patches-3.18/027-bcma-from-4.1.patch b/target/linux/generic/patches-3.18/027-bcma-from-4.1.patch new file mode 100644 index 0000000..1d751a0 --- /dev/null +++ b/target/linux/generic/patches-3.18/027-bcma-from-4.1.patch @@ -0,0 +1,680 @@ +--- a/drivers/bcma/bcma_private.h ++++ b/drivers/bcma/bcma_private.h +@@ -26,6 +26,7 @@ bool bcma_wait_value(struct bcma_device + int timeout); + void bcma_prepare_core(struct bcma_bus *bus, struct bcma_device *core); + void bcma_init_bus(struct bcma_bus *bus); ++void bcma_unregister_cores(struct bcma_bus *bus); + int bcma_bus_register(struct bcma_bus *bus); + void bcma_bus_unregister(struct bcma_bus *bus); + int __init bcma_bus_early_register(struct bcma_bus *bus); +@@ -42,6 +43,9 @@ int bcma_bus_scan(struct bcma_bus *bus); + int bcma_sprom_get(struct bcma_bus *bus); + + /* driver_chipcommon.c */ ++void bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc); ++void bcma_core_chipcommon_init(struct bcma_drv_cc *cc); ++void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable); + #ifdef CONFIG_BCMA_DRIVER_MIPS + void bcma_chipco_serial_init(struct bcma_drv_cc *cc); + extern struct platform_device bcma_pflash_dev; +@@ -52,6 +56,8 @@ int bcma_core_chipcommon_b_init(struct b + void bcma_core_chipcommon_b_free(struct bcma_drv_cc_b *ccb); + + /* driver_chipcommon_pmu.c */ ++void bcma_pmu_early_init(struct bcma_drv_cc *cc); ++void bcma_pmu_init(struct bcma_drv_cc *cc); + u32 bcma_pmu_get_alp_clock(struct bcma_drv_cc *cc); + u32 bcma_pmu_get_cpu_clock(struct bcma_drv_cc *cc); + +@@ -100,7 +106,35 @@ static inline void __exit bcma_host_soc_ + #endif /* CONFIG_BCMA_HOST_SOC && CONFIG_OF */ + + /* driver_pci.c */ ++#ifdef CONFIG_BCMA_DRIVER_PCI + u32 bcma_pcie_read(struct bcma_drv_pci *pc, u32 address); ++void bcma_core_pci_early_init(struct bcma_drv_pci *pc); ++void bcma_core_pci_init(struct bcma_drv_pci *pc); ++void bcma_core_pci_up(struct bcma_drv_pci *pc); ++void bcma_core_pci_down(struct bcma_drv_pci *pc); ++#else ++static inline void bcma_core_pci_early_init(struct bcma_drv_pci *pc) ++{ ++ WARN_ON(pc->core->bus->hosttype == BCMA_HOSTTYPE_PCI); ++} ++static inline void bcma_core_pci_init(struct bcma_drv_pci *pc) ++{ ++ /* Initialization is required for PCI hosted bus */ ++ WARN_ON(pc->core->bus->hosttype == BCMA_HOSTTYPE_PCI); ++} ++#endif ++ ++/* driver_pcie2.c */ ++#ifdef CONFIG_BCMA_DRIVER_PCI ++void bcma_core_pcie2_init(struct bcma_drv_pcie2 *pcie2); ++void bcma_core_pcie2_up(struct bcma_drv_pcie2 *pcie2); ++#else ++static inline void bcma_core_pcie2_init(struct bcma_drv_pcie2 *pcie2) ++{ ++ /* Initialization is required for PCI hosted bus */ ++ WARN_ON(pcie2->core->bus->hosttype == BCMA_HOSTTYPE_PCI); ++} ++#endif + + extern int bcma_chipco_watchdog_register(struct bcma_drv_cc *cc); + +@@ -117,6 +151,39 @@ static inline void bcma_core_pci_hostmod + } + #endif /* CONFIG_BCMA_DRIVER_PCI_HOSTMODE */ + ++/************************************************** ++ * driver_mips.c ++ **************************************************/ ++ ++#ifdef CONFIG_BCMA_DRIVER_MIPS ++unsigned int bcma_core_mips_irq(struct bcma_device *dev); ++void bcma_core_mips_early_init(struct bcma_drv_mips *mcore); ++void bcma_core_mips_init(struct bcma_drv_mips *mcore); ++#else ++static inline unsigned int bcma_core_mips_irq(struct bcma_device *dev) ++{ ++ return 0; ++} ++static inline void bcma_core_mips_early_init(struct bcma_drv_mips *mcore) ++{ ++} ++static inline void bcma_core_mips_init(struct bcma_drv_mips *mcore) ++{ ++} ++#endif ++ ++/************************************************** ++ * driver_gmac_cmn.c ++ **************************************************/ ++ ++#ifdef CONFIG_BCMA_DRIVER_GMAC_CMN ++void bcma_core_gmac_cmn_init(struct bcma_drv_gmac_cmn *gc); ++#else ++static inline void bcma_core_gmac_cmn_init(struct bcma_drv_gmac_cmn *gc) ++{ ++} ++#endif ++ + #ifdef CONFIG_BCMA_DRIVER_GPIO + /* driver_gpio.c */ + int bcma_gpio_init(struct bcma_drv_cc *cc); +--- a/drivers/bcma/driver_gpio.c ++++ b/drivers/bcma/driver_gpio.c +@@ -17,6 +17,8 @@ + + #include "bcma_private.h" + ++#define BCMA_GPIO_MAX_PINS 32 ++ + static inline struct bcma_drv_cc *bcma_gpio_get_cc(struct gpio_chip *chip) + { + return container_of(chip, struct bcma_drv_cc, gpio); +@@ -76,7 +78,7 @@ static void bcma_gpio_free(struct gpio_c + bcma_chipco_gpio_pullup(cc, 1 << gpio, 0); + } + +-#if IS_BUILTIN(CONFIG_BCM47XX) ++#if IS_BUILTIN(CONFIG_BCM47XX) || IS_BUILTIN(CONFIG_ARCH_BCM_5301X) + static int bcma_gpio_to_irq(struct gpio_chip *chip, unsigned gpio) + { + struct bcma_drv_cc *cc = bcma_gpio_get_cc(chip); +@@ -204,6 +206,7 @@ static void bcma_gpio_irq_domain_exit(st + + int bcma_gpio_init(struct bcma_drv_cc *cc) + { ++ struct bcma_bus *bus = cc->core->bus; + struct gpio_chip *chip = &cc->gpio; + int err; + +@@ -215,14 +218,14 @@ int bcma_gpio_init(struct bcma_drv_cc *c + chip->set = bcma_gpio_set_value; + chip->direction_input = bcma_gpio_direction_input; + chip->direction_output = bcma_gpio_direction_output; +-#if IS_BUILTIN(CONFIG_BCM47XX) ++#if IS_BUILTIN(CONFIG_BCM47XX) || IS_BUILTIN(CONFIG_ARCH_BCM_5301X) + chip->to_irq = bcma_gpio_to_irq; + #endif + #if IS_BUILTIN(CONFIG_OF) + if (cc->core->bus->hosttype == BCMA_HOSTTYPE_SOC) + chip->of_node = cc->core->dev.of_node; + #endif +- switch (cc->core->bus->chipinfo.id) { ++ switch (bus->chipinfo.id) { + case BCMA_CHIP_ID_BCM5357: + case BCMA_CHIP_ID_BCM53572: + chip->ngpio = 32; +@@ -231,13 +234,17 @@ int bcma_gpio_init(struct bcma_drv_cc *c + chip->ngpio = 16; + } + +- /* There is just one SoC in one device and its GPIO addresses should be +- * deterministic to address them more easily. The other buses could get +- * a random base number. */ +- if (cc->core->bus->hosttype == BCMA_HOSTTYPE_SOC) +- chip->base = 0; +- else +- chip->base = -1; ++ /* ++ * On MIPS we register GPIO devices (LEDs, buttons) using absolute GPIO ++ * pin numbers. We don't have Device Tree there and we can't really use ++ * relative (per chip) numbers. ++ * So let's use predictable base for BCM47XX and "random" for all other. ++ */ ++#if IS_BUILTIN(CONFIG_BCM47XX) ++ chip->base = bus->num * BCMA_GPIO_MAX_PINS; ++#else ++ chip->base = -1; ++#endif + + err = bcma_gpio_irq_domain_init(cc); + if (err) +--- a/drivers/bcma/driver_pci.c ++++ b/drivers/bcma/driver_pci.c +@@ -282,39 +282,6 @@ void bcma_core_pci_power_save(struct bcm + } + EXPORT_SYMBOL_GPL(bcma_core_pci_power_save); + +-int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core, +- bool enable) +-{ +- struct pci_dev *pdev; +- u32 coremask, tmp; +- int err = 0; +- +- if (!pc || core->bus->hosttype != BCMA_HOSTTYPE_PCI) { +- /* This bcma device is not on a PCI host-bus. So the IRQs are +- * not routed through the PCI core. +- * So we must not enable routing through the PCI core. */ +- goto out; +- } +- +- pdev = pc->core->bus->host_pci; +- +- err = pci_read_config_dword(pdev, BCMA_PCI_IRQMASK, &tmp); +- if (err) +- goto out; +- +- coremask = BIT(core->core_index) << 8; +- if (enable) +- tmp |= coremask; +- else +- tmp &= ~coremask; +- +- err = pci_write_config_dword(pdev, BCMA_PCI_IRQMASK, tmp); +- +-out: +- return err; +-} +-EXPORT_SYMBOL_GPL(bcma_core_pci_irq_ctl); +- + static void bcma_core_pci_extend_L1timer(struct bcma_drv_pci *pc, bool extend) + { + u32 w; +@@ -328,28 +295,12 @@ static void bcma_core_pci_extend_L1timer + bcma_pcie_read(pc, BCMA_CORE_PCI_DLLP_PMTHRESHREG); + } + +-void bcma_core_pci_up(struct bcma_bus *bus) ++void bcma_core_pci_up(struct bcma_drv_pci *pc) + { +- struct bcma_drv_pci *pc; +- +- if (bus->hosttype != BCMA_HOSTTYPE_PCI) +- return; +- +- pc = &bus->drv_pci[0]; +- + bcma_core_pci_extend_L1timer(pc, true); + } +-EXPORT_SYMBOL_GPL(bcma_core_pci_up); + +-void bcma_core_pci_down(struct bcma_bus *bus) ++void bcma_core_pci_down(struct bcma_drv_pci *pc) + { +- struct bcma_drv_pci *pc; +- +- if (bus->hosttype != BCMA_HOSTTYPE_PCI) +- return; +- +- pc = &bus->drv_pci[0]; +- + bcma_core_pci_extend_L1timer(pc, false); + } +-EXPORT_SYMBOL_GPL(bcma_core_pci_down); +--- a/drivers/bcma/driver_pci_host.c ++++ b/drivers/bcma/driver_pci_host.c +@@ -11,6 +11,7 @@ + + #include "bcma_private.h" + #include ++#include + #include + #include + #include +--- a/drivers/bcma/driver_pcie2.c ++++ b/drivers/bcma/driver_pcie2.c +@@ -10,6 +10,7 @@ + + #include "bcma_private.h" + #include ++#include + + /************************************************** + * R/W ops. +@@ -156,14 +157,23 @@ static void pciedev_reg_pm_clk_period(st + + void bcma_core_pcie2_init(struct bcma_drv_pcie2 *pcie2) + { +- struct bcma_chipinfo *ci = &pcie2->core->bus->chipinfo; ++ struct bcma_bus *bus = pcie2->core->bus; ++ struct bcma_chipinfo *ci = &bus->chipinfo; + u32 tmp; + + tmp = pcie2_read32(pcie2, BCMA_CORE_PCIE2_SPROM(54)); + if ((tmp & 0xe) >> 1 == 2) + bcma_core_pcie2_cfg_write(pcie2, 0x4e0, 0x17); + +- /* TODO: Do we need pcie_reqsize? */ ++ switch (bus->chipinfo.id) { ++ case BCMA_CHIP_ID_BCM4360: ++ case BCMA_CHIP_ID_BCM4352: ++ pcie2->reqsize = 1024; ++ break; ++ default: ++ pcie2->reqsize = 128; ++ break; ++ } + + if (ci->id == BCMA_CHIP_ID_BCM4360 && ci->rev > 3) + bcma_core_pcie2_war_delay_perst_enab(pcie2, true); +@@ -173,3 +183,18 @@ void bcma_core_pcie2_init(struct bcma_dr + pciedev_crwlpciegen2_180(pcie2); + pciedev_crwlpciegen2_182(pcie2); + } ++ ++/************************************************** ++ * Runtime ops. ++ **************************************************/ ++ ++void bcma_core_pcie2_up(struct bcma_drv_pcie2 *pcie2) ++{ ++ struct bcma_bus *bus = pcie2->core->bus; ++ struct pci_dev *dev = bus->host_pci; ++ int err; ++ ++ err = pcie_set_readrq(dev, pcie2->reqsize); ++ if (err) ++ bcma_err(bus, "Error setting PCI_EXP_DEVCTL_READRQ: %d\n", err); ++} +--- a/drivers/bcma/host_pci.c ++++ b/drivers/bcma/host_pci.c +@@ -213,16 +213,26 @@ static int bcma_host_pci_probe(struct pc + /* Initialize struct, detect chip */ + bcma_init_bus(bus); + ++ /* Scan bus to find out generation of PCIe core */ ++ err = bcma_bus_scan(bus); ++ if (err) ++ goto err_pci_unmap_mmio; ++ ++ if (bcma_find_core(bus, BCMA_CORE_PCIE2)) ++ bus->host_is_pcie2 = true; ++ + /* Register */ + err = bcma_bus_register(bus); + if (err) +- goto err_pci_unmap_mmio; ++ goto err_unregister_cores; + + pci_set_drvdata(dev, bus); + + out: + return err; + ++err_unregister_cores: ++ bcma_unregister_cores(bus); + err_pci_unmap_mmio: + pci_iounmap(dev, bus->mmio); + err_pci_release_regions: +@@ -283,9 +293,12 @@ static const struct pci_device_id bcma_p + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4357) }, + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4358) }, + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4359) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4360) }, + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4365) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43a0) }, + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43a9) }, + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43aa) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43b1) }, + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4727) }, + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 43227) }, /* 0xa8db, BCM43217 (sic!) */ + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 43228) }, /* 0xa8dc */ +@@ -310,3 +323,65 @@ void __exit bcma_host_pci_exit(void) + { + pci_unregister_driver(&bcma_pci_bridge_driver); + } ++ ++/************************************************** ++ * Runtime ops for drivers. ++ **************************************************/ ++ ++/* See also pcicore_up */ ++void bcma_host_pci_up(struct bcma_bus *bus) ++{ ++ if (bus->hosttype != BCMA_HOSTTYPE_PCI) ++ return; ++ ++ if (bus->host_is_pcie2) ++ bcma_core_pcie2_up(&bus->drv_pcie2); ++ else ++ bcma_core_pci_up(&bus->drv_pci[0]); ++} ++EXPORT_SYMBOL_GPL(bcma_host_pci_up); ++ ++/* See also pcicore_down */ ++void bcma_host_pci_down(struct bcma_bus *bus) ++{ ++ if (bus->hosttype != BCMA_HOSTTYPE_PCI) ++ return; ++ ++ if (!bus->host_is_pcie2) ++ bcma_core_pci_down(&bus->drv_pci[0]); ++} ++EXPORT_SYMBOL_GPL(bcma_host_pci_down); ++ ++/* See also si_pci_setup */ ++int bcma_host_pci_irq_ctl(struct bcma_bus *bus, struct bcma_device *core, ++ bool enable) ++{ ++ struct pci_dev *pdev; ++ u32 coremask, tmp; ++ int err = 0; ++ ++ if (bus->hosttype != BCMA_HOSTTYPE_PCI) { ++ /* This bcma device is not on a PCI host-bus. So the IRQs are ++ * not routed through the PCI core. ++ * So we must not enable routing through the PCI core. */ ++ goto out; ++ } ++ ++ pdev = bus->host_pci; ++ ++ err = pci_read_config_dword(pdev, BCMA_PCI_IRQMASK, &tmp); ++ if (err) ++ goto out; ++ ++ coremask = BIT(core->core_index) << 8; ++ if (enable) ++ tmp |= coremask; ++ else ++ tmp &= ~coremask; ++ ++ err = pci_write_config_dword(pdev, BCMA_PCI_IRQMASK, tmp); ++ ++out: ++ return err; ++} ++EXPORT_SYMBOL_GPL(bcma_host_pci_irq_ctl); +--- a/drivers/bcma/main.c ++++ b/drivers/bcma/main.c +@@ -363,7 +363,7 @@ static int bcma_register_devices(struct + return 0; + } + +-static void bcma_unregister_cores(struct bcma_bus *bus) ++void bcma_unregister_cores(struct bcma_bus *bus) + { + struct bcma_device *core, *tmp; + +--- a/drivers/net/wireless/b43/main.c ++++ b/drivers/net/wireless/b43/main.c +@@ -4770,7 +4770,7 @@ static void b43_wireless_core_exit(struc + switch (dev->dev->bus_type) { + #ifdef CONFIG_B43_BCMA + case B43_BUS_BCMA: +- bcma_core_pci_down(dev->dev->bdev->bus); ++ bcma_host_pci_down(dev->dev->bdev->bus); + break; + #endif + #ifdef CONFIG_B43_SSB +@@ -4817,9 +4817,9 @@ static int b43_wireless_core_init(struct + switch (dev->dev->bus_type) { + #ifdef CONFIG_B43_BCMA + case B43_BUS_BCMA: +- bcma_core_pci_irq_ctl(&dev->dev->bdev->bus->drv_pci[0], ++ bcma_host_pci_irq_ctl(dev->dev->bdev->bus, + dev->dev->bdev, true); +- bcma_core_pci_up(dev->dev->bdev->bus); ++ bcma_host_pci_up(dev->dev->bdev->bus); + break; + #endif + #ifdef CONFIG_B43_SSB +--- a/drivers/net/wireless/brcm80211/brcmsmac/main.c ++++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c +@@ -4669,7 +4669,7 @@ static int brcms_b_attach(struct brcms_c + brcms_c_coredisable(wlc_hw); + + /* Match driver "down" state */ +- bcma_core_pci_down(wlc_hw->d11core->bus); ++ bcma_host_pci_down(wlc_hw->d11core->bus); + + /* turn off pll and xtal to match driver "down" state */ + brcms_b_xtal(wlc_hw, OFF); +@@ -4960,7 +4960,7 @@ static int brcms_b_up_prep(struct brcms_ + * Configure pci/pcmcia here instead of in brcms_c_attach() + * to allow mfg hotswap: down, hotswap (chip power cycle), up. + */ +- bcma_core_pci_irq_ctl(&wlc_hw->d11core->bus->drv_pci[0], wlc_hw->d11core, ++ bcma_host_pci_irq_ctl(wlc_hw->d11core->bus, wlc_hw->d11core, + true); + + /* +@@ -4970,12 +4970,12 @@ static int brcms_b_up_prep(struct brcms_ + */ + if (brcms_b_radio_read_hwdisabled(wlc_hw)) { + /* put SB PCI in down state again */ +- bcma_core_pci_down(wlc_hw->d11core->bus); ++ bcma_host_pci_down(wlc_hw->d11core->bus); + brcms_b_xtal(wlc_hw, OFF); + return -ENOMEDIUM; + } + +- bcma_core_pci_up(wlc_hw->d11core->bus); ++ bcma_host_pci_up(wlc_hw->d11core->bus); + + /* reset the d11 core */ + brcms_b_corereset(wlc_hw, BRCMS_USE_COREFLAGS); +@@ -5172,7 +5172,7 @@ static int brcms_b_down_finish(struct br + + /* turn off primary xtal and pll */ + if (!wlc_hw->noreset) { +- bcma_core_pci_down(wlc_hw->d11core->bus); ++ bcma_host_pci_down(wlc_hw->d11core->bus); + brcms_b_xtal(wlc_hw, OFF); + } + } +--- a/include/linux/bcma/bcma.h ++++ b/include/linux/bcma/bcma.h +@@ -434,6 +434,27 @@ static inline struct bcma_device *bcma_f + return bcma_find_core_unit(bus, coreid, 0); + } + ++#ifdef CONFIG_BCMA_HOST_PCI ++extern void bcma_host_pci_up(struct bcma_bus *bus); ++extern void bcma_host_pci_down(struct bcma_bus *bus); ++extern int bcma_host_pci_irq_ctl(struct bcma_bus *bus, ++ struct bcma_device *core, bool enable); ++#else ++static inline void bcma_host_pci_up(struct bcma_bus *bus) ++{ ++} ++static inline void bcma_host_pci_down(struct bcma_bus *bus) ++{ ++} ++static inline int bcma_host_pci_irq_ctl(struct bcma_bus *bus, ++ struct bcma_device *core, bool enable) ++{ ++ if (bus->hosttype == BCMA_HOSTTYPE_PCI) ++ return -ENOTSUPP; ++ return 0; ++} ++#endif ++ + extern bool bcma_core_is_enabled(struct bcma_device *core); + extern void bcma_core_disable(struct bcma_device *core, u32 flags); + extern int bcma_core_enable(struct bcma_device *core, u32 flags); +--- a/include/linux/bcma/bcma_driver_pci.h ++++ b/include/linux/bcma/bcma_driver_pci.h +@@ -238,13 +238,13 @@ struct bcma_drv_pci { + #define pcicore_write16(pc, offset, val) bcma_write16((pc)->core, offset, val) + #define pcicore_write32(pc, offset, val) bcma_write32((pc)->core, offset, val) + +-extern void bcma_core_pci_early_init(struct bcma_drv_pci *pc); +-extern void bcma_core_pci_init(struct bcma_drv_pci *pc); +-extern int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, +- struct bcma_device *core, bool enable); +-extern void bcma_core_pci_up(struct bcma_bus *bus); +-extern void bcma_core_pci_down(struct bcma_bus *bus); ++#ifdef CONFIG_BCMA_DRIVER_PCI + extern void bcma_core_pci_power_save(struct bcma_bus *bus, bool up); ++#else ++static inline void bcma_core_pci_power_save(struct bcma_bus *bus, bool up) ++{ ++} ++#endif + + extern int bcma_core_pci_pcibios_map_irq(const struct pci_dev *dev); + extern int bcma_core_pci_plat_dev_init(struct pci_dev *dev); +--- a/include/linux/bcma/bcma_driver_pcie2.h ++++ b/include/linux/bcma/bcma_driver_pcie2.h +@@ -143,6 +143,8 @@ + + struct bcma_drv_pcie2 { + struct bcma_device *core; ++ ++ u16 reqsize; + }; + + #define pcie2_read16(pcie2, offset) bcma_read16((pcie2)->core, offset) +@@ -153,6 +155,4 @@ struct bcma_drv_pcie2 { + #define pcie2_set32(pcie2, offset, set) bcma_set32((pcie2)->core, offset, set) + #define pcie2_mask32(pcie2, offset, mask) bcma_mask32((pcie2)->core, offset, mask) + +-void bcma_core_pcie2_init(struct bcma_drv_pcie2 *pcie2); +- + #endif /* LINUX_BCMA_DRIVER_PCIE2_H_ */ +--- a/drivers/bcma/Kconfig ++++ b/drivers/bcma/Kconfig +@@ -26,6 +26,7 @@ config BCMA_HOST_PCI_POSSIBLE + config BCMA_HOST_PCI + bool "Support for BCMA on PCI-host bus" + depends on BCMA_HOST_PCI_POSSIBLE ++ select BCMA_DRIVER_PCI + default y + + config BCMA_DRIVER_PCI_HOSTMODE +@@ -44,6 +45,22 @@ config BCMA_HOST_SOC + + If unsure, say N + ++config BCMA_DRIVER_PCI ++ bool "BCMA Broadcom PCI core driver" ++ depends on BCMA && PCI ++ default y ++ help ++ BCMA bus may have many versions of PCIe core. This driver ++ supports: ++ 1) PCIe core working in clientmode ++ 2) PCIe Gen 2 clientmode core ++ ++ In general PCIe (Gen 2) clientmode core is required on PCIe ++ hosted buses. It's responsible for initialization and basic ++ hardware management. ++ This driver is also prerequisite for a hostmode PCIe core ++ support. ++ + config BCMA_DRIVER_MIPS + bool "BCMA Broadcom MIPS core driver" + depends on BCMA && MIPS +--- a/drivers/bcma/Makefile ++++ b/drivers/bcma/Makefile +@@ -3,8 +3,8 @@ bcma-y += driver_chipcommon.o driver + bcma-y += driver_chipcommon_b.o + bcma-$(CONFIG_BCMA_SFLASH) += driver_chipcommon_sflash.o + bcma-$(CONFIG_BCMA_NFLASH) += driver_chipcommon_nflash.o +-bcma-y += driver_pci.o +-bcma-y += driver_pcie2.o ++bcma-$(CONFIG_BCMA_DRIVER_PCI) += driver_pci.o ++bcma-$(CONFIG_BCMA_DRIVER_PCI) += driver_pcie2.o + bcma-$(CONFIG_BCMA_DRIVER_PCI_HOSTMODE) += driver_pci_host.o + bcma-$(CONFIG_BCMA_DRIVER_MIPS) += driver_mips.o + bcma-$(CONFIG_BCMA_DRIVER_GMAC_CMN) += driver_gmac_cmn.o +--- a/include/linux/bcma/bcma_driver_chipcommon.h ++++ b/include/linux/bcma/bcma_driver_chipcommon.h +@@ -663,14 +663,6 @@ struct bcma_drv_cc_b { + #define bcma_cc_maskset32(cc, offset, mask, set) \ + bcma_cc_write32(cc, offset, (bcma_cc_read32(cc, offset) & (mask)) | (set)) + +-extern void bcma_core_chipcommon_init(struct bcma_drv_cc *cc); +-extern void bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc); +- +-extern void bcma_chipco_suspend(struct bcma_drv_cc *cc); +-extern void bcma_chipco_resume(struct bcma_drv_cc *cc); +- +-void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable); +- + extern u32 bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc, u32 ticks); + + extern u32 bcma_chipco_get_alp_clock(struct bcma_drv_cc *cc); +@@ -690,9 +682,6 @@ u32 bcma_chipco_gpio_pullup(struct bcma_ + u32 bcma_chipco_gpio_pulldown(struct bcma_drv_cc *cc, u32 mask, u32 value); + + /* PMU support */ +-extern void bcma_pmu_init(struct bcma_drv_cc *cc); +-extern void bcma_pmu_early_init(struct bcma_drv_cc *cc); +- + extern void bcma_chipco_pll_write(struct bcma_drv_cc *cc, u32 offset, + u32 value); + extern void bcma_chipco_pll_maskset(struct bcma_drv_cc *cc, u32 offset, +--- a/include/linux/bcma/bcma_driver_gmac_cmn.h ++++ b/include/linux/bcma/bcma_driver_gmac_cmn.h +@@ -91,10 +91,4 @@ struct bcma_drv_gmac_cmn { + #define gmac_cmn_write16(gc, offset, val) bcma_write16((gc)->core, offset, val) + #define gmac_cmn_write32(gc, offset, val) bcma_write32((gc)->core, offset, val) + +-#ifdef CONFIG_BCMA_DRIVER_GMAC_CMN +-extern void bcma_core_gmac_cmn_init(struct bcma_drv_gmac_cmn *gc); +-#else +-static inline void bcma_core_gmac_cmn_init(struct bcma_drv_gmac_cmn *gc) { } +-#endif +- + #endif /* LINUX_BCMA_DRIVER_GMAC_CMN_H_ */ +--- a/include/linux/bcma/bcma_driver_mips.h ++++ b/include/linux/bcma/bcma_driver_mips.h +@@ -39,21 +39,6 @@ struct bcma_drv_mips { + u8 early_setup_done:1; + }; + +-#ifdef CONFIG_BCMA_DRIVER_MIPS +-extern void bcma_core_mips_init(struct bcma_drv_mips *mcore); +-extern void bcma_core_mips_early_init(struct bcma_drv_mips *mcore); +- +-extern unsigned int bcma_core_mips_irq(struct bcma_device *dev); +-#else +-static inline void bcma_core_mips_init(struct bcma_drv_mips *mcore) { } +-static inline void bcma_core_mips_early_init(struct bcma_drv_mips *mcore) { } +- +-static inline unsigned int bcma_core_mips_irq(struct bcma_device *dev) +-{ +- return 0; +-} +-#endif +- + extern u32 bcma_cpu_clock(struct bcma_drv_mips *mcore); + + #endif /* LINUX_BCMA_DRIVER_MIPS_H_ */ diff --git a/target/linux/generic/patches-3.18/028-bcma-from-4.2.patch b/target/linux/generic/patches-3.18/028-bcma-from-4.2.patch new file mode 100644 index 0000000..ba3df18 --- /dev/null +++ b/target/linux/generic/patches-3.18/028-bcma-from-4.2.patch @@ -0,0 +1,86 @@ +--- a/drivers/bcma/driver_gpio.c ++++ b/drivers/bcma/driver_gpio.c +@@ -226,6 +226,7 @@ int bcma_gpio_init(struct bcma_drv_cc *c + chip->of_node = cc->core->dev.of_node; + #endif + switch (bus->chipinfo.id) { ++ case BCMA_CHIP_ID_BCM4707: + case BCMA_CHIP_ID_BCM5357: + case BCMA_CHIP_ID_BCM53572: + chip->ngpio = 32; +@@ -235,16 +236,17 @@ int bcma_gpio_init(struct bcma_drv_cc *c + } + + /* +- * On MIPS we register GPIO devices (LEDs, buttons) using absolute GPIO +- * pin numbers. We don't have Device Tree there and we can't really use +- * relative (per chip) numbers. +- * So let's use predictable base for BCM47XX and "random" for all other. ++ * Register SoC GPIO devices with absolute GPIO pin base. ++ * On MIPS, we don't have Device Tree and we can't use relative (per chip) ++ * GPIO numbers. ++ * On some ARM devices, user space may want to access some system GPIO ++ * pins directly, which is easier to do with a predictable GPIO base. + */ +-#if IS_BUILTIN(CONFIG_BCM47XX) +- chip->base = bus->num * BCMA_GPIO_MAX_PINS; +-#else +- chip->base = -1; +-#endif ++ if (IS_BUILTIN(CONFIG_BCM47XX) || ++ cc->core->bus->hosttype == BCMA_HOSTTYPE_SOC) ++ chip->base = bus->num * BCMA_GPIO_MAX_PINS; ++ else ++ chip->base = -1; + + err = bcma_gpio_irq_domain_init(cc); + if (err) +--- a/drivers/bcma/Kconfig ++++ b/drivers/bcma/Kconfig +@@ -29,12 +29,6 @@ config BCMA_HOST_PCI + select BCMA_DRIVER_PCI + default y + +-config BCMA_DRIVER_PCI_HOSTMODE +- bool "Driver for PCI core working in hostmode" +- depends on BCMA && MIPS && BCMA_HOST_PCI +- help +- PCI core hostmode operation (external PCI bus). +- + config BCMA_HOST_SOC + bool "Support for BCMA in a SoC" + depends on BCMA +@@ -61,6 +55,12 @@ config BCMA_DRIVER_PCI + This driver is also prerequisite for a hostmode PCIe core + support. + ++config BCMA_DRIVER_PCI_HOSTMODE ++ bool "Driver for PCI core working in hostmode" ++ depends on BCMA && MIPS && BCMA_DRIVER_PCI ++ help ++ PCI core hostmode operation (external PCI bus). ++ + config BCMA_DRIVER_MIPS + bool "BCMA Broadcom MIPS core driver" + depends on BCMA && MIPS +--- a/include/linux/bcma/bcma_driver_pci.h ++++ b/include/linux/bcma/bcma_driver_pci.h +@@ -246,7 +246,18 @@ static inline void bcma_core_pci_power_s + } + #endif + ++#ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE + extern int bcma_core_pci_pcibios_map_irq(const struct pci_dev *dev); + extern int bcma_core_pci_plat_dev_init(struct pci_dev *dev); ++#else ++static inline int bcma_core_pci_pcibios_map_irq(const struct pci_dev *dev) ++{ ++ return -ENOTSUPP; ++} ++static inline int bcma_core_pci_plat_dev_init(struct pci_dev *dev) ++{ ++ return -ENOTSUPP; ++} ++#endif + + #endif /* LINUX_BCMA_DRIVER_PCI_H_ */ diff --git a/target/linux/generic/patches-3.18/030-nl80211-Allow-set-network-namespace-by-fd.patch b/target/linux/generic/patches-3.18/030-nl80211-Allow-set-network-namespace-by-fd.patch new file mode 100644 index 0000000..52a2391 --- /dev/null +++ b/target/linux/generic/patches-3.18/030-nl80211-Allow-set-network-namespace-by-fd.patch @@ -0,0 +1,21 @@ +From: Vadim Kochan +Date: Mon, 12 Jan 2015 16:34:05 +0200 +Subject: [PATCH] nl80211: Allow set network namespace by fd + +Added new NL80211_ATTR_NETNS_FD which allows to +set namespace via nl80211 by fd. + +Signed-off-by: Vadim Kochan +Signed-off-by: Johannes Berg +--- + +--- a/net/core/net_namespace.c ++++ b/net/core/net_namespace.c +@@ -361,6 +361,7 @@ struct net *get_net_ns_by_fd(int fd) + return ERR_PTR(-EINVAL); + } + #endif ++EXPORT_SYMBOL_GPL(get_net_ns_by_fd); + + struct net *get_net_ns_by_pid(pid_t pid) + { diff --git a/target/linux/generic/patches-3.18/040-mtd-bcm47xxpart-backports-from-3.19.patch b/target/linux/generic/patches-3.18/040-mtd-bcm47xxpart-backports-from-3.19.patch new file mode 100644 index 0000000..b2d53f9 --- /dev/null +++ b/target/linux/generic/patches-3.18/040-mtd-bcm47xxpart-backports-from-3.19.patch @@ -0,0 +1,50 @@ +--- a/drivers/mtd/bcm47xxpart.c ++++ b/drivers/mtd/bcm47xxpart.c +@@ -15,8 +15,12 @@ + #include + #include + +-/* 10 parts were found on sflash on Netgear WNDR4500 */ +-#define BCM47XXPART_MAX_PARTS 12 ++/* ++ * NAND flash on Netgear R6250 was verified to contain 15 partitions. ++ * This will result in allocating too big array for some old devices, but the ++ * memory will be freed soon anyway (see mtd_device_parse_register). ++ */ ++#define BCM47XXPART_MAX_PARTS 20 + + /* + * Amount of bytes we read when analyzing each block of flash memory. +@@ -168,18 +172,26 @@ static int bcm47xxpart_parse(struct mtd_ + i++; + } + +- bcm47xxpart_add_part(&parts[curr_part++], "linux", +- offset + trx->offset[i], 0); +- i++; ++ if (trx->offset[i]) { ++ bcm47xxpart_add_part(&parts[curr_part++], ++ "linux", ++ offset + trx->offset[i], ++ 0); ++ i++; ++ } + + /* + * Pure rootfs size is known and can be calculated as: + * trx->length - trx->offset[i]. We don't fill it as + * we want to have jffs2 (overlay) in the same mtd. + */ +- bcm47xxpart_add_part(&parts[curr_part++], "rootfs", +- offset + trx->offset[i], 0); +- i++; ++ if (trx->offset[i]) { ++ bcm47xxpart_add_part(&parts[curr_part++], ++ "rootfs", ++ offset + trx->offset[i], ++ 0); ++ i++; ++ } + + last_trx_part = curr_part - 1; + diff --git a/target/linux/generic/patches-3.18/041-mtd-bcm47xxpart-backports-from-3.20.patch b/target/linux/generic/patches-3.18/041-mtd-bcm47xxpart-backports-from-3.20.patch new file mode 100644 index 0000000..59180c2 --- /dev/null +++ b/target/linux/generic/patches-3.18/041-mtd-bcm47xxpart-backports-from-3.20.patch @@ -0,0 +1,95 @@ +--- a/drivers/mtd/bcm47xxpart.c ++++ b/drivers/mtd/bcm47xxpart.c +@@ -15,6 +15,8 @@ + #include + #include + ++#include ++ + /* + * NAND flash on Netgear R6250 was verified to contain 15 partitions. + * This will result in allocating too big array for some old devices, but the +@@ -39,7 +41,8 @@ + #define ML_MAGIC1 0x39685a42 + #define ML_MAGIC2 0x26594131 + #define TRX_MAGIC 0x30524448 +-#define SQSH_MAGIC 0x71736873 /* shsq */ ++#define SHSQ_MAGIC 0x71736873 /* shsq (weird ZTE H218N endianness) */ ++#define UBI_EC_MAGIC 0x23494255 /* UBI# */ + + struct trx_header { + uint32_t magic; +@@ -50,7 +53,7 @@ struct trx_header { + uint32_t offset[3]; + } __packed; + +-static void bcm47xxpart_add_part(struct mtd_partition *part, char *name, ++static void bcm47xxpart_add_part(struct mtd_partition *part, const char *name, + u64 offset, uint32_t mask_flags) + { + part->name = name; +@@ -58,6 +61,26 @@ static void bcm47xxpart_add_part(struct + part->mask_flags = mask_flags; + } + ++static const char *bcm47xxpart_trx_data_part_name(struct mtd_info *master, ++ size_t offset) ++{ ++ uint32_t buf; ++ size_t bytes_read; ++ ++ if (mtd_read(master, offset, sizeof(buf), &bytes_read, ++ (uint8_t *)&buf) < 0) { ++ pr_err("mtd_read error while parsing (offset: 0x%X)!\n", ++ offset); ++ goto out_default; ++ } ++ ++ if (buf == UBI_EC_MAGIC) ++ return "ubi"; ++ ++out_default: ++ return "rootfs"; ++} ++ + static int bcm47xxpart_parse(struct mtd_info *master, + struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +@@ -73,8 +96,12 @@ static int bcm47xxpart_parse(struct mtd_ + int last_trx_part = -1; + int possible_nvram_sizes[] = { 0x8000, 0xF000, 0x10000, }; + +- if (blocksize <= 0x10000) +- blocksize = 0x10000; ++ /* ++ * Some really old flashes (like AT45DB*) had smaller erasesize-s, but ++ * partitions were aligned to at least 0x1000 anyway. ++ */ ++ if (blocksize < 0x1000) ++ blocksize = 0x1000; + + /* Alloc */ + parts = kzalloc(sizeof(struct mtd_partition) * BCM47XXPART_MAX_PARTS, +@@ -186,8 +213,11 @@ static int bcm47xxpart_parse(struct mtd_ + * we want to have jffs2 (overlay) in the same mtd. + */ + if (trx->offset[i]) { ++ const char *name; ++ ++ name = bcm47xxpart_trx_data_part_name(master, offset + trx->offset[i]); + bcm47xxpart_add_part(&parts[curr_part++], +- "rootfs", ++ name, + offset + trx->offset[i], + 0); + i++; +@@ -205,7 +235,8 @@ static int bcm47xxpart_parse(struct mtd_ + } + + /* Squashfs on devices not using TRX */ +- if (buf[0x000 / 4] == SQSH_MAGIC) { ++ if (le32_to_cpu(buf[0x000 / 4]) == SQUASHFS_MAGIC || ++ buf[0x000 / 4] == SHSQ_MAGIC) { + bcm47xxpart_add_part(&parts[curr_part++], "rootfs", + offset, 0); + continue; diff --git a/target/linux/generic/patches-3.18/050-backport_netfilter_rtcache.patch b/target/linux/generic/patches-3.18/050-backport_netfilter_rtcache.patch new file mode 100644 index 0000000..9f23db6 --- /dev/null +++ b/target/linux/generic/patches-3.18/050-backport_netfilter_rtcache.patch @@ -0,0 +1,509 @@ +Subject: netfilter: conntrack: cache route for forwarded connections + +... to avoid per-packet FIB lookup if possible. + +The cached dst is re-used provided the input interface +is the same as that of the previous packet in the same direction. + +If not, the cached dst is invalidated. + +For ipv6 we also need to store sernum, else dst_check doesn't work, +pointed out by Eric Dumazet. + +This should speed up forwarding when conntrack is already in use +anyway, especially when using reverse path filtering -- active RPF +enforces two FIB lookups for each packet. + +Before the routing cache removal this didn't matter since RPF was performed +only when route cache didn't yield a result; but without route cache it +comes at higher price. + +Julian Anastasov suggested to add NETDEV_UNREGISTER handler to +avoid holding on to dsts of 'frozen' conntracks. + +Signed-off-by: Florian Westphal + +--- a/include/net/netfilter/nf_conntrack_extend.h ++++ b/include/net/netfilter/nf_conntrack_extend.h +@@ -30,6 +30,9 @@ enum nf_ct_ext_id { + #if IS_ENABLED(CONFIG_NETFILTER_SYNPROXY) + NF_CT_EXT_SYNPROXY, + #endif ++#if IS_ENABLED(CONFIG_NF_CONNTRACK_RTCACHE) ++ NF_CT_EXT_RTCACHE, ++#endif + NF_CT_EXT_NUM, + }; + +@@ -43,6 +46,7 @@ enum nf_ct_ext_id { + #define NF_CT_EXT_TIMEOUT_TYPE struct nf_conn_timeout + #define NF_CT_EXT_LABELS_TYPE struct nf_conn_labels + #define NF_CT_EXT_SYNPROXY_TYPE struct nf_conn_synproxy ++#define NF_CT_EXT_RTCACHE_TYPE struct nf_conn_rtcache + + /* Extensions: optional stuff which isn't permanently in struct. */ + struct nf_ct_ext { +--- /dev/null ++++ b/include/net/netfilter/nf_conntrack_rtcache.h +@@ -0,0 +1,34 @@ ++#include ++#include ++#include ++ ++struct dst_entry; ++ ++struct nf_conn_dst_cache { ++ struct dst_entry *dst; ++ int iif; ++#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6) ++ u32 cookie; ++#endif ++ ++}; ++ ++struct nf_conn_rtcache { ++ struct nf_conn_dst_cache cached_dst[IP_CT_DIR_MAX]; ++}; ++ ++static inline ++struct nf_conn_rtcache *nf_ct_rtcache_find(const struct nf_conn *ct) ++{ ++#if IS_ENABLED(CONFIG_NF_CONNTRACK_RTCACHE) ++ return nf_ct_ext_find(ct, NF_CT_EXT_RTCACHE); ++#else ++ return NULL; ++#endif ++} ++ ++static inline int nf_conn_rtcache_iif_get(const struct nf_conn_rtcache *rtc, ++ enum ip_conntrack_dir dir) ++{ ++ return rtc->cached_dst[dir].iif; ++} +--- a/net/netfilter/Kconfig ++++ b/net/netfilter/Kconfig +@@ -106,6 +106,18 @@ config NF_CONNTRACK_EVENTS + + If unsure, say `N'. + ++config NF_CONNTRACK_RTCACHE ++ tristate "Cache route entries in conntrack objects" ++ depends on NETFILTER_ADVANCED ++ depends on NF_CONNTRACK ++ help ++ If this option is enabled, the connection tracking code will ++ cache routing information for each connection that is being ++ forwarded, at a cost of 32 bytes per conntrack object. ++ ++ To compile it as a module, choose M here. If unsure, say N. ++ The module will be called nf_conntrack_rtcache. ++ + config NF_CONNTRACK_TIMEOUT + bool 'Connection tracking timeout' + depends on NETFILTER_ADVANCED +--- a/net/netfilter/Makefile ++++ b/net/netfilter/Makefile +@@ -18,6 +18,9 @@ obj-$(CONFIG_NETFILTER_NETLINK_LOG) += n + # connection tracking + obj-$(CONFIG_NF_CONNTRACK) += nf_conntrack.o + ++# optional conntrack route cache extension ++obj-$(CONFIG_NF_CONNTRACK_RTCACHE) += nf_conntrack_rtcache.o ++ + # SCTP protocol connection tracking + obj-$(CONFIG_NF_CT_PROTO_DCCP) += nf_conntrack_proto_dccp.o + obj-$(CONFIG_NF_CT_PROTO_GRE) += nf_conntrack_proto_gre.o +--- /dev/null ++++ b/net/netfilter/nf_conntrack_rtcache.c +@@ -0,0 +1,391 @@ ++/* route cache for netfilter. ++ * ++ * (C) 2014 Red Hat GmbH ++ * ++ * 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. ++ */ ++ ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++#include ++#include ++#include ++ ++#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6) ++#include ++#endif ++ ++static void __nf_conn_rtcache_destroy(struct nf_conn_rtcache *rtc, ++ enum ip_conntrack_dir dir) ++{ ++ struct dst_entry *dst = rtc->cached_dst[dir].dst; ++ ++ dst_release(dst); ++} ++ ++static void nf_conn_rtcache_destroy(struct nf_conn *ct) ++{ ++ struct nf_conn_rtcache *rtc = nf_ct_rtcache_find(ct); ++ ++ if (!rtc) ++ return; ++ ++ __nf_conn_rtcache_destroy(rtc, IP_CT_DIR_ORIGINAL); ++ __nf_conn_rtcache_destroy(rtc, IP_CT_DIR_REPLY); ++} ++ ++static void nf_ct_rtcache_ext_add(struct nf_conn *ct) ++{ ++ struct nf_conn_rtcache *rtc; ++ ++ rtc = nf_ct_ext_add(ct, NF_CT_EXT_RTCACHE, GFP_ATOMIC); ++ if (rtc) { ++ rtc->cached_dst[IP_CT_DIR_ORIGINAL].iif = -1; ++ rtc->cached_dst[IP_CT_DIR_ORIGINAL].dst = NULL; ++ rtc->cached_dst[IP_CT_DIR_REPLY].iif = -1; ++ rtc->cached_dst[IP_CT_DIR_REPLY].dst = NULL; ++ } ++} ++ ++static struct nf_conn_rtcache *nf_ct_rtcache_find_usable(struct nf_conn *ct) ++{ ++ if (nf_ct_is_untracked(ct)) ++ return NULL; ++ return nf_ct_rtcache_find(ct); ++} ++ ++static struct dst_entry * ++nf_conn_rtcache_dst_get(const struct nf_conn_rtcache *rtc, ++ enum ip_conntrack_dir dir) ++{ ++ return rtc->cached_dst[dir].dst; ++} ++ ++static u32 nf_rtcache_get_cookie(int pf, const struct dst_entry *dst) ++{ ++#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6) ++ if (pf == NFPROTO_IPV6) { ++ const struct rt6_info *rt = (const struct rt6_info *)dst; ++ ++ if (rt->rt6i_node) ++ return (u32)rt->rt6i_node->fn_sernum; ++ } ++#endif ++ return 0; ++} ++ ++static void nf_conn_rtcache_dst_set(int pf, ++ struct nf_conn_rtcache *rtc, ++ struct dst_entry *dst, ++ enum ip_conntrack_dir dir, int iif) ++{ ++ if (rtc->cached_dst[dir].iif != iif) ++ rtc->cached_dst[dir].iif = iif; ++ ++ if (rtc->cached_dst[dir].dst != dst) { ++ struct dst_entry *old; ++ ++ dst_hold(dst); ++ ++ old = xchg(&rtc->cached_dst[dir].dst, dst); ++ dst_release(old); ++ ++#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6) ++ if (pf == NFPROTO_IPV6) ++ rtc->cached_dst[dir].cookie = ++ nf_rtcache_get_cookie(pf, dst); ++#endif ++ } ++} ++ ++static void nf_conn_rtcache_dst_obsolete(struct nf_conn_rtcache *rtc, ++ enum ip_conntrack_dir dir) ++{ ++ struct dst_entry *old; ++ ++ pr_debug("Invalidate iif %d for dir %d on cache %p\n", ++ rtc->cached_dst[dir].iif, dir, rtc); ++ ++ old = xchg(&rtc->cached_dst[dir].dst, NULL); ++ dst_release(old); ++ rtc->cached_dst[dir].iif = -1; ++} ++ ++static unsigned int nf_rtcache_in(const struct nf_hook_ops *ops, ++ struct sk_buff *skb, ++ const struct net_device *in, ++ const struct net_device *out, ++ int (*okfn)(struct sk_buff *)) ++{ ++ struct nf_conn_rtcache *rtc; ++ enum ip_conntrack_info ctinfo; ++ enum ip_conntrack_dir dir; ++ struct dst_entry *dst; ++ struct nf_conn *ct; ++ int iif; ++ u32 cookie; ++ ++ if (skb_dst(skb) || skb->sk) ++ return NF_ACCEPT; ++ ++ ct = nf_ct_get(skb, &ctinfo); ++ if (!ct) ++ return NF_ACCEPT; ++ ++ rtc = nf_ct_rtcache_find_usable(ct); ++ if (!rtc) ++ return NF_ACCEPT; ++ ++ /* if iif changes, don't use cache and let ip stack ++ * do route lookup. ++ * ++ * If rp_filter is enabled it might toss skb, so ++ * we don't want to avoid these checks. ++ */ ++ dir = CTINFO2DIR(ctinfo); ++ iif = nf_conn_rtcache_iif_get(rtc, dir); ++ if (in->ifindex != iif) { ++ pr_debug("ct %p, iif %d, cached iif %d, skip cached entry\n", ++ ct, iif, in->ifindex); ++ return NF_ACCEPT; ++ } ++ dst = nf_conn_rtcache_dst_get(rtc, dir); ++ if (dst == NULL) ++ return NF_ACCEPT; ++ ++ cookie = nf_rtcache_get_cookie(ops->pf, dst); ++ ++ dst = dst_check(dst, cookie); ++ pr_debug("obtained dst %p for skb %p, cookie %d\n", dst, skb, cookie); ++ if (likely(dst)) ++ skb_dst_set_noref_force(skb, dst); ++ else ++ nf_conn_rtcache_dst_obsolete(rtc, dir); ++ ++ return NF_ACCEPT; ++} ++ ++static unsigned int nf_rtcache_forward(const struct nf_hook_ops *ops, ++ struct sk_buff *skb, ++ const struct net_device *in, ++ const struct net_device *out, ++ int (*okfn)(struct sk_buff *)) ++{ ++ struct nf_conn_rtcache *rtc; ++ enum ip_conntrack_info ctinfo; ++ enum ip_conntrack_dir dir; ++ struct nf_conn *ct; ++ struct dst_entry *dst = skb_dst(skb); ++ int iif; ++ ++ ct = nf_ct_get(skb, &ctinfo); ++ if (!ct) ++ return NF_ACCEPT; ++ ++ if (dst && dst_xfrm(dst)) ++ return NF_ACCEPT; ++ ++ if (!nf_ct_is_confirmed(ct)) { ++ if (WARN_ON(nf_ct_rtcache_find(ct))) ++ return NF_ACCEPT; ++ nf_ct_rtcache_ext_add(ct); ++ return NF_ACCEPT; ++ } ++ ++ rtc = nf_ct_rtcache_find_usable(ct); ++ if (!rtc) ++ return NF_ACCEPT; ++ ++ dir = CTINFO2DIR(ctinfo); ++ iif = nf_conn_rtcache_iif_get(rtc, dir); ++ pr_debug("ct %p, skb %p, dir %d, iif %d, cached iif %d\n", ++ ct, skb, dir, iif, in->ifindex); ++ if (likely(in->ifindex == iif)) ++ return NF_ACCEPT; ++ ++ nf_conn_rtcache_dst_set(ops->pf, rtc, skb_dst(skb), dir, in->ifindex); ++ return NF_ACCEPT; ++} ++ ++static int nf_rtcache_dst_remove(struct nf_conn *ct, void *data) ++{ ++ struct nf_conn_rtcache *rtc = nf_ct_rtcache_find(ct); ++ struct net_device *dev = data; ++ ++ if (!rtc) ++ return 0; ++ ++ if (dev->ifindex == rtc->cached_dst[IP_CT_DIR_ORIGINAL].iif || ++ dev->ifindex == rtc->cached_dst[IP_CT_DIR_REPLY].iif) { ++ nf_conn_rtcache_dst_obsolete(rtc, IP_CT_DIR_ORIGINAL); ++ nf_conn_rtcache_dst_obsolete(rtc, IP_CT_DIR_REPLY); ++ } ++ ++ return 0; ++} ++ ++static int nf_rtcache_netdev_event(struct notifier_block *this, ++ unsigned long event, void *ptr) ++{ ++ struct net_device *dev = netdev_notifier_info_to_dev(ptr); ++ struct net *net = dev_net(dev); ++ ++ if (event == NETDEV_DOWN) ++ nf_ct_iterate_cleanup(net, nf_rtcache_dst_remove, dev, 0, 0); ++ ++ return NOTIFY_DONE; ++} ++ ++static struct notifier_block nf_rtcache_notifier = { ++ .notifier_call = nf_rtcache_netdev_event, ++}; ++ ++static struct nf_hook_ops rtcache_ops[] = { ++ { ++ .hook = nf_rtcache_in, ++ .owner = THIS_MODULE, ++ .pf = NFPROTO_IPV4, ++ .hooknum = NF_INET_PRE_ROUTING, ++ .priority = NF_IP_PRI_LAST, ++ }, ++ { ++ .hook = nf_rtcache_forward, ++ .owner = THIS_MODULE, ++ .pf = NFPROTO_IPV4, ++ .hooknum = NF_INET_FORWARD, ++ .priority = NF_IP_PRI_LAST, ++ }, ++#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6) ++ { ++ .hook = nf_rtcache_in, ++ .owner = THIS_MODULE, ++ .pf = NFPROTO_IPV6, ++ .hooknum = NF_INET_PRE_ROUTING, ++ .priority = NF_IP_PRI_LAST, ++ }, ++ { ++ .hook = nf_rtcache_forward, ++ .owner = THIS_MODULE, ++ .pf = NFPROTO_IPV6, ++ .hooknum = NF_INET_FORWARD, ++ .priority = NF_IP_PRI_LAST, ++ }, ++#endif ++}; ++ ++static struct nf_ct_ext_type rtcache_extend __read_mostly = { ++ .len = sizeof(struct nf_conn_rtcache), ++ .align = __alignof__(struct nf_conn_rtcache), ++ .id = NF_CT_EXT_RTCACHE, ++ .destroy = nf_conn_rtcache_destroy, ++}; ++ ++static int __init nf_conntrack_rtcache_init(void) ++{ ++ int ret = nf_ct_extend_register(&rtcache_extend); ++ ++ if (ret < 0) { ++ pr_err("nf_conntrack_rtcache: Unable to register extension\n"); ++ return ret; ++ } ++ ++ ret = nf_register_hooks(rtcache_ops, ARRAY_SIZE(rtcache_ops)); ++ if (ret < 0) { ++ nf_ct_extend_unregister(&rtcache_extend); ++ return ret; ++ } ++ ++ ret = register_netdevice_notifier(&nf_rtcache_notifier); ++ if (ret) { ++ nf_unregister_hooks(rtcache_ops, ARRAY_SIZE(rtcache_ops)); ++ nf_ct_extend_unregister(&rtcache_extend); ++ } ++ ++ return ret; ++} ++ ++static int nf_rtcache_ext_remove(struct nf_conn *ct, void *data) ++{ ++ struct nf_conn_rtcache *rtc = nf_ct_rtcache_find(ct); ++ ++ return rtc != NULL; ++} ++ ++static bool __exit nf_conntrack_rtcache_wait_for_dying(struct net *net) ++{ ++ bool wait = false; ++ int cpu; ++ ++ for_each_possible_cpu(cpu) { ++ struct nf_conntrack_tuple_hash *h; ++ struct hlist_nulls_node *n; ++ struct nf_conn *ct; ++ struct ct_pcpu *pcpu = per_cpu_ptr(net->ct.pcpu_lists, cpu); ++ ++ rcu_read_lock(); ++ spin_lock_bh(&pcpu->lock); ++ ++ hlist_nulls_for_each_entry(h, n, &pcpu->dying, hnnode) { ++ ct = nf_ct_tuplehash_to_ctrack(h); ++ if (nf_ct_rtcache_find(ct) != NULL) { ++ wait = true; ++ break; ++ } ++ } ++ spin_unlock_bh(&pcpu->lock); ++ rcu_read_unlock(); ++ } ++ ++ return wait; ++} ++ ++static void __exit nf_conntrack_rtcache_fini(void) ++{ ++ struct net *net; ++ int count = 0; ++ ++ /* remove hooks so no new connections get rtcache extension */ ++ nf_unregister_hooks(rtcache_ops, ARRAY_SIZE(rtcache_ops)); ++ ++ synchronize_net(); ++ ++ unregister_netdevice_notifier(&nf_rtcache_notifier); ++ ++ rtnl_lock(); ++ ++ /* zap all conntracks with rtcache extension */ ++ for_each_net(net) ++ nf_ct_iterate_cleanup(net, nf_rtcache_ext_remove, NULL, 0, 0); ++ ++ for_each_net(net) { ++ /* .. and make sure they're gone from dying list, too */ ++ while (nf_conntrack_rtcache_wait_for_dying(net)) { ++ msleep(200); ++ WARN_ONCE(++count > 25, "Waiting for all rtcache conntracks to go away\n"); ++ } ++ } ++ ++ rtnl_unlock(); ++ synchronize_net(); ++ nf_ct_extend_unregister(&rtcache_extend); ++} ++module_init(nf_conntrack_rtcache_init); ++module_exit(nf_conntrack_rtcache_fini); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Florian Westphal "); ++MODULE_DESCRIPTION("Conntrack route cache extension"); diff --git a/target/linux/generic/patches-3.18/051-02-bridge-allow-setting-hash_max-multicast_router-if-in.patch b/target/linux/generic/patches-3.18/051-02-bridge-allow-setting-hash_max-multicast_router-if-in.patch new file mode 100644 index 0000000..f7f88f8 --- /dev/null +++ b/target/linux/generic/patches-3.18/051-02-bridge-allow-setting-hash_max-multicast_router-if-in.patch @@ -0,0 +1,99 @@ +From 6ae4ae8e512bd229f806c22f8a2cd751e4f987c2 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Linus=20L=C3=BCssing?= +Date: Sat, 23 May 2015 03:12:34 +0200 +Subject: [PATCH] bridge: allow setting hash_max + multicast_router if + interface is down +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Network managers like netifd (used in OpenWRT for instance) try to +configure interface options after creation but before setting the +interface up. + +Unfortunately the sysfs / bridge currently only allows to configure the +hash_max and multicast_router options when the bridge interface is up. +But since br_multicast_init() doesn't start any timers and only sets +default values and initializes timers it should be save to reconfigure +the default values after that, before things actually get active after +the bridge is set up. + +Signed-off-by: Linus Lüssing +Signed-off-by: David S. Miller +--- + net/bridge/br_multicast.c | 24 +++--------------------- + 1 file changed, 3 insertions(+), 21 deletions(-) + +--- a/net/bridge/br_multicast.c ++++ b/net/bridge/br_multicast.c +@@ -1948,11 +1948,9 @@ out: + + int br_multicast_set_router(struct net_bridge *br, unsigned long val) + { +- int err = -ENOENT; ++ int err = -EINVAL; + + spin_lock_bh(&br->multicast_lock); +- if (!netif_running(br->dev)) +- goto unlock; + + switch (val) { + case 0: +@@ -1963,13 +1961,8 @@ int br_multicast_set_router(struct net_b + br->multicast_router = val; + err = 0; + break; +- +- default: +- err = -EINVAL; +- break; + } + +-unlock: + spin_unlock_bh(&br->multicast_lock); + + return err; +@@ -1978,11 +1971,9 @@ unlock: + int br_multicast_set_port_router(struct net_bridge_port *p, unsigned long val) + { + struct net_bridge *br = p->br; +- int err = -ENOENT; ++ int err = -EINVAL; + + spin_lock(&br->multicast_lock); +- if (!netif_running(br->dev) || p->state == BR_STATE_DISABLED) +- goto unlock; + + switch (val) { + case 0: +@@ -2004,13 +1995,8 @@ int br_multicast_set_port_router(struct + + br_multicast_add_router(br, p); + break; +- +- default: +- err = -EINVAL; +- break; + } + +-unlock: + spin_unlock(&br->multicast_lock); + + return err; +@@ -2115,15 +2101,11 @@ unlock: + + int br_multicast_set_hash_max(struct net_bridge *br, unsigned long val) + { +- int err = -ENOENT; ++ int err = -EINVAL; + u32 old; + struct net_bridge_mdb_htable *mdb; + + spin_lock_bh(&br->multicast_lock); +- if (!netif_running(br->dev)) +- goto unlock; +- +- err = -EINVAL; + if (!is_power_of_2(val)) + goto unlock; + diff --git a/target/linux/generic/patches-3.18/060-mips_decompressor_memmove.patch b/target/linux/generic/patches-3.18/060-mips_decompressor_memmove.patch new file mode 100644 index 0000000..d215b80 --- /dev/null +++ b/target/linux/generic/patches-3.18/060-mips_decompressor_memmove.patch @@ -0,0 +1,22 @@ +--- a/arch/mips/boot/compressed/string.c ++++ b/arch/mips/boot/compressed/string.c +@@ -26,3 +26,19 @@ void *memset(void *s, int c, size_t n) + ss[i] = c; + return s; + } ++ ++void *memmove(void *__dest, __const void *__src, size_t count) ++{ ++ unsigned char *d = __dest; ++ const unsigned char *s = __src; ++ ++ if (__dest == __src) ++ return __dest; ++ ++ if (__dest < __src) ++ return memcpy(__dest, __src, count); ++ ++ while (count--) ++ d[count] = s[count]; ++ return __dest; ++} diff --git a/target/linux/generic/patches-3.18/070-bgmac-register-napi-before-the-device.patch b/target/linux/generic/patches-3.18/070-bgmac-register-napi-before-the-device.patch new file mode 100644 index 0000000..aa45860 --- /dev/null +++ b/target/linux/generic/patches-3.18/070-bgmac-register-napi-before-the-device.patch @@ -0,0 +1,44 @@ +From 6216642f200258708e47170ff14ba8ecb486f4f0 Mon Sep 17 00:00:00 2001 +From: Hauke Mehrtens +Date: Sun, 18 Jan 2015 19:49:58 +0100 +Subject: [PATCH] bgmac: register napi before the device + +napi should get registered before the netdev and not after. + +Signed-off-by: Hauke Mehrtens +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/broadcom/bgmac.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/drivers/net/ethernet/broadcom/bgmac.c ++++ b/drivers/net/ethernet/broadcom/bgmac.c +@@ -1515,6 +1515,8 @@ static int bgmac_probe(struct bcma_devic + if (core->bus->sprom.boardflags_lo & BGMAC_BFL_ENETADM) + bgmac_warn(bgmac, "Support for ADMtek ethernet switch not implemented\n"); + ++ netif_napi_add(net_dev, &bgmac->napi, bgmac_poll, BGMAC_WEIGHT); ++ + err = bgmac_mii_register(bgmac); + if (err) { + bgmac_err(bgmac, "Cannot register MDIO\n"); +@@ -1529,8 +1531,6 @@ static int bgmac_probe(struct bcma_devic + + netif_carrier_off(net_dev); + +- netif_napi_add(net_dev, &bgmac->napi, bgmac_poll, BGMAC_WEIGHT); +- + return 0; + + err_mii_unregister: +@@ -1549,9 +1549,9 @@ static void bgmac_remove(struct bcma_dev + { + struct bgmac *bgmac = bcma_get_drvdata(core); + +- netif_napi_del(&bgmac->napi); + unregister_netdev(bgmac->net_dev); + bgmac_mii_unregister(bgmac); ++ netif_napi_del(&bgmac->napi); + bgmac_dma_free(bgmac); + bcma_set_drvdata(core, NULL); + free_netdev(bgmac->net_dev); diff --git a/target/linux/generic/patches-3.18/071-bgmac-activate-irqs-only-if-there-is-nothing-to-poll.patch b/target/linux/generic/patches-3.18/071-bgmac-activate-irqs-only-if-there-is-nothing-to-poll.patch new file mode 100644 index 0000000..cc43d36 --- /dev/null +++ b/target/linux/generic/patches-3.18/071-bgmac-activate-irqs-only-if-there-is-nothing-to-poll.patch @@ -0,0 +1,30 @@ +From 43f159c60a99318b1ef7d1d7c16c4dfdd06bfd90 Mon Sep 17 00:00:00 2001 +From: Hauke Mehrtens +Date: Sun, 18 Jan 2015 19:49:59 +0100 +Subject: [PATCH] bgmac: activate irqs only if there is nothing to poll + +IRQs should only get activated when there is nothing to poll in the +queue any more and to after every poll. + +Signed-off-by: Hauke Mehrtens +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/broadcom/bgmac.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/drivers/net/ethernet/broadcom/bgmac.c ++++ b/drivers/net/ethernet/broadcom/bgmac.c +@@ -1167,10 +1167,10 @@ static int bgmac_poll(struct napi_struct + bgmac->int_status = 0; + } + +- if (handled < weight) ++ if (handled < weight) { + napi_complete(napi); +- +- bgmac_chip_intrs_on(bgmac); ++ bgmac_chip_intrs_on(bgmac); ++ } + + return handled; + } diff --git a/target/linux/generic/patches-3.18/072-bgmac-fix-device-initialization-on-Northstar-SoCs-co.patch b/target/linux/generic/patches-3.18/072-bgmac-fix-device-initialization-on-Northstar-SoCs-co.patch new file mode 100644 index 0000000..121d2f4 --- /dev/null +++ b/target/linux/generic/patches-3.18/072-bgmac-fix-device-initialization-on-Northstar-SoCs-co.patch @@ -0,0 +1,40 @@ +From 21697336d46b71dd031f29e426dda0b1e7f06cc0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Wed, 11 Feb 2015 18:06:34 +0100 +Subject: [PATCH] bgmac: fix device initialization on Northstar SoCs (condition + typo) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +On Northstar (Broadcom's ARM architecture) we need to manually enable +all cores. Code for that is already in place, but the condition for it +was wrong. + +Signed-off-by: Rafał Miłecki +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/broadcom/bgmac.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +--- a/drivers/net/ethernet/broadcom/bgmac.c ++++ b/drivers/net/ethernet/broadcom/bgmac.c +@@ -1412,6 +1412,7 @@ static void bgmac_mii_unregister(struct + /* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipattach */ + static int bgmac_probe(struct bcma_device *core) + { ++ struct bcma_chipinfo *ci = &core->bus->chipinfo; + struct net_device *net_dev; + struct bgmac *bgmac; + struct ssb_sprom *sprom = &core->bus->sprom; +@@ -1474,8 +1475,8 @@ static int bgmac_probe(struct bcma_devic + bgmac_chip_reset(bgmac); + + /* For Northstar, we have to take all GMAC core out of reset */ +- if (core->id.id == BCMA_CHIP_ID_BCM4707 || +- core->id.id == BCMA_CHIP_ID_BCM53018) { ++ if (ci->id == BCMA_CHIP_ID_BCM4707 || ++ ci->id == BCMA_CHIP_ID_BCM53018) { + struct bcma_device *ns_core; + int ns_gmac; + diff --git a/target/linux/generic/patches-3.18/073-bgmac-Clean-warning-messages.patch b/target/linux/generic/patches-3.18/073-bgmac-Clean-warning-messages.patch new file mode 100644 index 0000000..17fe5df --- /dev/null +++ b/target/linux/generic/patches-3.18/073-bgmac-Clean-warning-messages.patch @@ -0,0 +1,50 @@ +From 8edfe3b6fad28da191c8fa15e4e0d8f7335a0091 Mon Sep 17 00:00:00 2001 +From: Peter Senna Tschudin +Date: Sat, 7 Mar 2015 12:10:26 +0100 +Subject: [PATCH] bgmac: Clean warning messages +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +On my test environment the throughput of a file transfer drops +from 4.4MBps to 116KBps due the number of repeated warning +messages. This patch removes the warning messages as DMA works +correctly with addresses using 0xC0000000 bits. + +Signed-off-by: Peter Senna Tschudin +Acked-by: Rafał Miłecki +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/broadcom/bgmac.c | 7 ------- + 1 file changed, 7 deletions(-) + +--- a/drivers/net/ethernet/broadcom/bgmac.c ++++ b/drivers/net/ethernet/broadcom/bgmac.c +@@ -302,9 +302,6 @@ static int bgmac_dma_rx_skb_for_slot(str + slot->skb = skb; + slot->dma_addr = dma_addr; + +- if (slot->dma_addr & 0xC0000000) +- bgmac_warn(bgmac, "DMA address using 0xC0000000 bit(s), it may need translation trick\n"); +- + return 0; + } + +@@ -505,8 +502,6 @@ static int bgmac_dma_alloc(struct bgmac + ring->mmio_base); + goto err_dma_free; + } +- if (ring->dma_base & 0xC0000000) +- bgmac_warn(bgmac, "DMA address using 0xC0000000 bit(s), it may need translation trick\n"); + + ring->unaligned = bgmac_dma_unaligned(bgmac, ring, + BGMAC_DMA_RING_TX); +@@ -536,8 +531,6 @@ static int bgmac_dma_alloc(struct bgmac + err = -ENOMEM; + goto err_dma_free; + } +- if (ring->dma_base & 0xC0000000) +- bgmac_warn(bgmac, "DMA address using 0xC0000000 bit(s), it may need translation trick\n"); + + ring->unaligned = bgmac_dma_unaligned(bgmac, ring, + BGMAC_DMA_RING_RX); diff --git a/target/linux/generic/patches-3.18/074-bgmac-register-fixed-PHY-for-ARM-BCM470X-BCM5301X-ch.patch b/target/linux/generic/patches-3.18/074-bgmac-register-fixed-PHY-for-ARM-BCM470X-BCM5301X-ch.patch new file mode 100644 index 0000000..9f0baff --- /dev/null +++ b/target/linux/generic/patches-3.18/074-bgmac-register-fixed-PHY-for-ARM-BCM470X-BCM5301X-ch.patch @@ -0,0 +1,76 @@ +From c25b23b8a387e7d31f7a74af8e37b61e9e6ebb21 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Fri, 20 Mar 2015 23:14:31 +0100 +Subject: [PATCH] bgmac: register fixed PHY for ARM BCM470X / BCM5301X chipsets +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +On ARM SoCs with bgmac Ethernet hardware we don't have any normal PHY. +There is always a switch attached but it's not even controlled over MDIO +like in case of MIPS devices. +We need a fixed PHY to be able to send/receive packets from the switch. + +Signed-off-by: Rafał Miłecki +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/broadcom/bgmac.c | 34 ++++++++++++++++++++++++++++++++++ + 1 file changed, 34 insertions(+) + +--- a/drivers/net/ethernet/broadcom/bgmac.c ++++ b/drivers/net/ethernet/broadcom/bgmac.c +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -1330,13 +1331,46 @@ static void bgmac_adjust_link(struct net + } + } + ++static int bgmac_fixed_phy_register(struct bgmac *bgmac) ++{ ++ struct fixed_phy_status fphy_status = { ++ .link = 1, ++ .speed = SPEED_1000, ++ .duplex = DUPLEX_FULL, ++ }; ++ struct phy_device *phy_dev; ++ int err; ++ ++ phy_dev = fixed_phy_register(PHY_POLL, &fphy_status, NULL); ++ if (!phy_dev || IS_ERR(phy_dev)) { ++ bgmac_err(bgmac, "Failed to register fixed PHY device\n"); ++ return -ENODEV; ++ } ++ ++ err = phy_connect_direct(bgmac->net_dev, phy_dev, bgmac_adjust_link, ++ PHY_INTERFACE_MODE_MII); ++ if (err) { ++ bgmac_err(bgmac, "Connecting PHY failed\n"); ++ return err; ++ } ++ ++ bgmac->phy_dev = phy_dev; ++ ++ return err; ++} ++ + static int bgmac_mii_register(struct bgmac *bgmac) + { ++ struct bcma_chipinfo *ci = &bgmac->core->bus->chipinfo; + struct mii_bus *mii_bus; + struct phy_device *phy_dev; + char bus_id[MII_BUS_ID_SIZE + 3]; + int i, err = 0; + ++ if (ci->id == BCMA_CHIP_ID_BCM4707 || ++ ci->id == BCMA_CHIP_ID_BCM53018) ++ return bgmac_fixed_phy_register(bgmac); ++ + mii_bus = mdiobus_alloc(); + if (!mii_bus) + return -ENOMEM; diff --git a/target/linux/generic/patches-3.18/075-bgmac-allow-enabling-on-ARCH_BCM_5301X.patch b/target/linux/generic/patches-3.18/075-bgmac-allow-enabling-on-ARCH_BCM_5301X.patch new file mode 100644 index 0000000..4513667 --- /dev/null +++ b/target/linux/generic/patches-3.18/075-bgmac-allow-enabling-on-ARCH_BCM_5301X.patch @@ -0,0 +1,28 @@ +From fc300dc3733fdc328e6e10c7b8379b60c26cd648 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Fri, 20 Mar 2015 23:14:32 +0100 +Subject: [PATCH] bgmac: allow enabling on ARCH_BCM_5301X +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Home routers based on ARM SoCs like BCM4708 also have bcma bus with core +supported by bgmac. + +Signed-off-by: Rafał Miłecki +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/broadcom/Kconfig | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/ethernet/broadcom/Kconfig ++++ b/drivers/net/ethernet/broadcom/Kconfig +@@ -143,7 +143,7 @@ config BNX2X_SRIOV + + config BGMAC + tristate "BCMA bus GBit core support" +- depends on BCMA_HOST_SOC && HAS_DMA && BCM47XX ++ depends on BCMA_HOST_SOC && HAS_DMA && (BCM47XX || ARCH_BCM_5301X) + select PHYLIB + ---help--- + This driver supports GBit MAC and BCM4706 GBit MAC cores on BCMA bus. diff --git a/target/linux/generic/patches-3.18/076-net-phy-export-fixed_phy_register.patch b/target/linux/generic/patches-3.18/076-net-phy-export-fixed_phy_register.patch new file mode 100644 index 0000000..939016c --- /dev/null +++ b/target/linux/generic/patches-3.18/076-net-phy-export-fixed_phy_register.patch @@ -0,0 +1,30 @@ +From 37e9a6904520b525b542ecd67201164d06fdb95a Mon Sep 17 00:00:00 2001 +From: Mark Salter +Date: Thu, 11 Dec 2014 23:03:26 -0500 +Subject: [PATCH] net: phy: export fixed_phy_register() + +When building the bcmgenet driver as module, I get: + +ERROR: "fixed_phy_register" [drivers/net/ethernet/broadcom/genet/genet.ko] undefined! + +commit b0ba512e225d72 ("net: bcmgenet: enable driver to work without device +tree") which added a call to fixed_phy_register. But fixed_phy_register +needs to be exported if used from a module. + +Signed-off-by: Mark Salter +Acked-by: Florian Fainelli +Signed-off-by: David S. Miller +--- + drivers/net/phy/fixed.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/net/phy/fixed.c ++++ b/drivers/net/phy/fixed.c +@@ -274,6 +274,7 @@ struct phy_device *fixed_phy_register(un + + return phy; + } ++EXPORT_SYMBOL_GPL(fixed_phy_register); + + static int __init fixed_mdio_bus_init(void) + { diff --git a/target/linux/generic/patches-3.18/077-01-bgmac-fix-descriptor-frame-start-end-definitions.patch b/target/linux/generic/patches-3.18/077-01-bgmac-fix-descriptor-frame-start-end-definitions.patch new file mode 100644 index 0000000..fdfae3a --- /dev/null +++ b/target/linux/generic/patches-3.18/077-01-bgmac-fix-descriptor-frame-start-end-definitions.patch @@ -0,0 +1,24 @@ +From: Felix Fietkau +Date: Mon, 23 Mar 2015 02:40:06 +0100 +Subject: [PATCH] bgmac: fix descriptor frame start/end definitions + +The start-of-frame and end-of-frame bits were accidentally swapped. +In the current code it does not make any difference, since they are +always used together. + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/broadcom/bgmac.h ++++ b/drivers/net/ethernet/broadcom/bgmac.h +@@ -345,8 +345,8 @@ + + #define BGMAC_DESC_CTL0_EOT 0x10000000 /* End of ring */ + #define BGMAC_DESC_CTL0_IOC 0x20000000 /* IRQ on complete */ +-#define BGMAC_DESC_CTL0_SOF 0x40000000 /* Start of frame */ +-#define BGMAC_DESC_CTL0_EOF 0x80000000 /* End of frame */ ++#define BGMAC_DESC_CTL0_EOF 0x40000000 /* End of frame */ ++#define BGMAC_DESC_CTL0_SOF 0x80000000 /* Start of frame */ + #define BGMAC_DESC_CTL1_LEN 0x00001FFF + + #define BGMAC_PHY_NOREGS 0x1E diff --git a/target/linux/generic/patches-3.18/077-02-bgmac-implement-GRO-and-use-build_skb.patch b/target/linux/generic/patches-3.18/077-02-bgmac-implement-GRO-and-use-build_skb.patch new file mode 100644 index 0000000..2a2df60 --- /dev/null +++ b/target/linux/generic/patches-3.18/077-02-bgmac-implement-GRO-and-use-build_skb.patch @@ -0,0 +1,189 @@ +From: Felix Fietkau +Date: Mon, 23 Mar 2015 02:41:25 +0100 +Subject: [PATCH] bgmac: implement GRO and use build_skb + +This improves performance for routing and local rx + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/broadcom/bgmac.c ++++ b/drivers/net/ethernet/broadcom/bgmac.c +@@ -276,31 +276,31 @@ static int bgmac_dma_rx_skb_for_slot(str + struct bgmac_slot_info *slot) + { + struct device *dma_dev = bgmac->core->dma_dev; +- struct sk_buff *skb; + dma_addr_t dma_addr; + struct bgmac_rx_header *rx; ++ void *buf; + + /* Alloc skb */ +- skb = netdev_alloc_skb(bgmac->net_dev, BGMAC_RX_BUF_SIZE); +- if (!skb) ++ buf = netdev_alloc_frag(BGMAC_RX_ALLOC_SIZE); ++ if (!buf) + return -ENOMEM; + + /* Poison - if everything goes fine, hardware will overwrite it */ +- rx = (struct bgmac_rx_header *)skb->data; ++ rx = buf; + rx->len = cpu_to_le16(0xdead); + rx->flags = cpu_to_le16(0xbeef); + + /* Map skb for the DMA */ +- dma_addr = dma_map_single(dma_dev, skb->data, +- BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE); ++ dma_addr = dma_map_single(dma_dev, buf, BGMAC_RX_BUF_SIZE, ++ DMA_FROM_DEVICE); + if (dma_mapping_error(dma_dev, dma_addr)) { + bgmac_err(bgmac, "DMA mapping error\n"); +- dev_kfree_skb(skb); ++ put_page(virt_to_head_page(buf)); + return -ENOMEM; + } + + /* Update the slot */ +- slot->skb = skb; ++ slot->buf = buf; + slot->dma_addr = dma_addr; + + return 0; +@@ -343,8 +343,9 @@ static int bgmac_dma_rx_read(struct bgma + while (ring->start != ring->end) { + struct device *dma_dev = bgmac->core->dma_dev; + struct bgmac_slot_info *slot = &ring->slots[ring->start]; +- struct sk_buff *skb = slot->skb; +- struct bgmac_rx_header *rx; ++ struct bgmac_rx_header *rx = slot->buf; ++ struct sk_buff *skb; ++ void *buf = slot->buf; + u16 len, flags; + + /* Unmap buffer to make it accessible to the CPU */ +@@ -352,7 +353,6 @@ static int bgmac_dma_rx_read(struct bgma + BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE); + + /* Get info from the header */ +- rx = (struct bgmac_rx_header *)skb->data; + len = le16_to_cpu(rx->len); + flags = le16_to_cpu(rx->flags); + +@@ -393,12 +393,13 @@ static int bgmac_dma_rx_read(struct bgma + dma_unmap_single(dma_dev, old_dma_addr, + BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE); + ++ skb = build_skb(buf, BGMAC_RX_ALLOC_SIZE); + skb_put(skb, BGMAC_RX_FRAME_OFFSET + len); + skb_pull(skb, BGMAC_RX_FRAME_OFFSET); + + skb_checksum_none_assert(skb); + skb->protocol = eth_type_trans(skb, bgmac->net_dev); +- netif_receive_skb(skb); ++ napi_gro_receive(&bgmac->napi, skb); + handled++; + } while (0); + +@@ -434,12 +435,11 @@ static bool bgmac_dma_unaligned(struct b + return false; + } + +-static void bgmac_dma_ring_free(struct bgmac *bgmac, +- struct bgmac_dma_ring *ring) ++static void bgmac_dma_tx_ring_free(struct bgmac *bgmac, ++ struct bgmac_dma_ring *ring) + { + struct device *dma_dev = bgmac->core->dma_dev; + struct bgmac_slot_info *slot; +- int size; + int i; + + for (i = 0; i < ring->num_slots; i++) { +@@ -451,23 +451,55 @@ static void bgmac_dma_ring_free(struct b + dev_kfree_skb(slot->skb); + } + } ++} ++ ++static void bgmac_dma_rx_ring_free(struct bgmac *bgmac, ++ struct bgmac_dma_ring *ring) ++{ ++ struct device *dma_dev = bgmac->core->dma_dev; ++ struct bgmac_slot_info *slot; ++ int i; ++ ++ for (i = 0; i < ring->num_slots; i++) { ++ slot = &ring->slots[i]; ++ if (!slot->buf) ++ continue; + +- if (ring->cpu_base) { +- /* Free ring of descriptors */ +- size = ring->num_slots * sizeof(struct bgmac_dma_desc); +- dma_free_coherent(dma_dev, size, ring->cpu_base, +- ring->dma_base); ++ if (slot->dma_addr) ++ dma_unmap_single(dma_dev, slot->dma_addr, ++ BGMAC_RX_BUF_SIZE, ++ DMA_FROM_DEVICE); ++ put_page(virt_to_head_page(slot->buf)); + } + } + ++static void bgmac_dma_ring_desc_free(struct bgmac *bgmac, ++ struct bgmac_dma_ring *ring) ++{ ++ struct device *dma_dev = bgmac->core->dma_dev; ++ int size; ++ ++ if (!ring->cpu_base) ++ return; ++ ++ /* Free ring of descriptors */ ++ size = ring->num_slots * sizeof(struct bgmac_dma_desc); ++ dma_free_coherent(dma_dev, size, ring->cpu_base, ++ ring->dma_base); ++} ++ + static void bgmac_dma_free(struct bgmac *bgmac) + { + int i; + +- for (i = 0; i < BGMAC_MAX_TX_RINGS; i++) +- bgmac_dma_ring_free(bgmac, &bgmac->tx_ring[i]); +- for (i = 0; i < BGMAC_MAX_RX_RINGS; i++) +- bgmac_dma_ring_free(bgmac, &bgmac->rx_ring[i]); ++ for (i = 0; i < BGMAC_MAX_TX_RINGS; i++) { ++ bgmac_dma_tx_ring_free(bgmac, &bgmac->tx_ring[i]); ++ bgmac_dma_ring_desc_free(bgmac, &bgmac->tx_ring[i]); ++ } ++ for (i = 0; i < BGMAC_MAX_RX_RINGS; i++) { ++ bgmac_dma_rx_ring_free(bgmac, &bgmac->rx_ring[i]); ++ bgmac_dma_ring_desc_free(bgmac, &bgmac->rx_ring[i]); ++ } + } + + static int bgmac_dma_alloc(struct bgmac *bgmac) +--- a/drivers/net/ethernet/broadcom/bgmac.h ++++ b/drivers/net/ethernet/broadcom/bgmac.h +@@ -362,6 +362,8 @@ + #define BGMAC_RX_FRAME_OFFSET 30 /* There are 2 unused bytes between header and real data */ + #define BGMAC_RX_MAX_FRAME_SIZE 1536 /* Copied from b44/tg3 */ + #define BGMAC_RX_BUF_SIZE (BGMAC_RX_FRAME_OFFSET + BGMAC_RX_MAX_FRAME_SIZE) ++#define BGMAC_RX_ALLOC_SIZE (SKB_DATA_ALIGN(BGMAC_RX_BUF_SIZE) + \ ++ SKB_DATA_ALIGN(sizeof(struct skb_shared_info))) + + #define BGMAC_BFL_ENETROBO 0x0010 /* has ephy roboswitch spi */ + #define BGMAC_BFL_ENETADM 0x0080 /* has ADMtek switch */ +@@ -383,7 +385,10 @@ + #define ETHER_MAX_LEN 1518 + + struct bgmac_slot_info { +- struct sk_buff *skb; ++ union { ++ struct sk_buff *skb; ++ void *buf; ++ }; + dma_addr_t dma_addr; + }; + diff --git a/target/linux/generic/patches-3.18/077-03-bgmac-implement-scatter-gather-support.patch b/target/linux/generic/patches-3.18/077-03-bgmac-implement-scatter-gather-support.patch new file mode 100644 index 0000000..5cb21a5 --- /dev/null +++ b/target/linux/generic/patches-3.18/077-03-bgmac-implement-scatter-gather-support.patch @@ -0,0 +1,267 @@ +From: Felix Fietkau +Date: Mon, 23 Mar 2015 02:42:26 +0100 +Subject: [PATCH] bgmac: implement scatter/gather support + +Always use software checksumming, since the hardware does not have any +checksum offload support. +This significantly improves local TCP tx performance. + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/broadcom/bgmac.c ++++ b/drivers/net/ethernet/broadcom/bgmac.c +@@ -115,53 +115,91 @@ static void bgmac_dma_tx_enable(struct b + bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_TX_CTL, ctl); + } + ++static void ++bgmac_dma_tx_add_buf(struct bgmac *bgmac, struct bgmac_dma_ring *ring, ++ int i, int len, u32 ctl0) ++{ ++ struct bgmac_slot_info *slot; ++ struct bgmac_dma_desc *dma_desc; ++ u32 ctl1; ++ ++ if (i == ring->num_slots - 1) ++ ctl0 |= BGMAC_DESC_CTL0_EOT; ++ ++ ctl1 = len & BGMAC_DESC_CTL1_LEN; ++ ++ slot = &ring->slots[i]; ++ dma_desc = &ring->cpu_base[i]; ++ dma_desc->addr_low = cpu_to_le32(lower_32_bits(slot->dma_addr)); ++ dma_desc->addr_high = cpu_to_le32(upper_32_bits(slot->dma_addr)); ++ dma_desc->ctl0 = cpu_to_le32(ctl0); ++ dma_desc->ctl1 = cpu_to_le32(ctl1); ++} ++ + static netdev_tx_t bgmac_dma_tx_add(struct bgmac *bgmac, + struct bgmac_dma_ring *ring, + struct sk_buff *skb) + { + struct device *dma_dev = bgmac->core->dma_dev; + struct net_device *net_dev = bgmac->net_dev; +- struct bgmac_dma_desc *dma_desc; +- struct bgmac_slot_info *slot; +- u32 ctl0, ctl1; ++ struct bgmac_slot_info *slot = &ring->slots[ring->end]; + int free_slots; ++ int nr_frags; ++ u32 flags; ++ int index = ring->end; ++ int i; + + if (skb->len > BGMAC_DESC_CTL1_LEN) { + bgmac_err(bgmac, "Too long skb (%d)\n", skb->len); +- goto err_stop_drop; ++ goto err_drop; + } + ++ if (skb->ip_summed == CHECKSUM_PARTIAL) ++ skb_checksum_help(skb); ++ ++ nr_frags = skb_shinfo(skb)->nr_frags; ++ + if (ring->start <= ring->end) + free_slots = ring->start - ring->end + BGMAC_TX_RING_SLOTS; + else + free_slots = ring->start - ring->end; +- if (free_slots == 1) { ++ ++ if (free_slots <= nr_frags + 1) { + bgmac_err(bgmac, "TX ring is full, queue should be stopped!\n"); + netif_stop_queue(net_dev); + return NETDEV_TX_BUSY; + } + +- slot = &ring->slots[ring->end]; +- slot->skb = skb; +- slot->dma_addr = dma_map_single(dma_dev, skb->data, skb->len, ++ slot->dma_addr = dma_map_single(dma_dev, skb->data, skb_headlen(skb), + DMA_TO_DEVICE); +- if (dma_mapping_error(dma_dev, slot->dma_addr)) { +- bgmac_err(bgmac, "Mapping error of skb on ring 0x%X\n", +- ring->mmio_base); +- goto err_stop_drop; +- } ++ if (unlikely(dma_mapping_error(dma_dev, slot->dma_addr))) ++ goto err_dma_head; + +- ctl0 = BGMAC_DESC_CTL0_IOC | BGMAC_DESC_CTL0_SOF | BGMAC_DESC_CTL0_EOF; +- if (ring->end == ring->num_slots - 1) +- ctl0 |= BGMAC_DESC_CTL0_EOT; +- ctl1 = skb->len & BGMAC_DESC_CTL1_LEN; ++ flags = BGMAC_DESC_CTL0_SOF; ++ if (!nr_frags) ++ flags |= BGMAC_DESC_CTL0_EOF | BGMAC_DESC_CTL0_IOC; ++ ++ bgmac_dma_tx_add_buf(bgmac, ring, index, skb_headlen(skb), flags); ++ flags = 0; ++ ++ for (i = 0; i < nr_frags; i++) { ++ struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i]; ++ int len = skb_frag_size(frag); ++ ++ index = (index + 1) % BGMAC_TX_RING_SLOTS; ++ slot = &ring->slots[index]; ++ slot->dma_addr = skb_frag_dma_map(dma_dev, frag, 0, ++ len, DMA_TO_DEVICE); ++ if (unlikely(dma_mapping_error(dma_dev, slot->dma_addr))) ++ goto err_dma; + +- dma_desc = ring->cpu_base; +- dma_desc += ring->end; +- dma_desc->addr_low = cpu_to_le32(lower_32_bits(slot->dma_addr)); +- dma_desc->addr_high = cpu_to_le32(upper_32_bits(slot->dma_addr)); +- dma_desc->ctl0 = cpu_to_le32(ctl0); +- dma_desc->ctl1 = cpu_to_le32(ctl1); ++ if (i == nr_frags - 1) ++ flags |= BGMAC_DESC_CTL0_EOF | BGMAC_DESC_CTL0_IOC; ++ ++ bgmac_dma_tx_add_buf(bgmac, ring, index, len, flags); ++ } ++ ++ slot->skb = skb; + + netdev_sent_queue(net_dev, skb->len); + +@@ -170,20 +208,35 @@ static netdev_tx_t bgmac_dma_tx_add(stru + /* Increase ring->end to point empty slot. We tell hardware the first + * slot it should *not* read. + */ +- if (++ring->end >= BGMAC_TX_RING_SLOTS) +- ring->end = 0; ++ ring->end = (index + 1) % BGMAC_TX_RING_SLOTS; + bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_TX_INDEX, + ring->index_base + + ring->end * sizeof(struct bgmac_dma_desc)); + +- /* Always keep one slot free to allow detecting bugged calls. */ +- if (--free_slots == 1) ++ free_slots -= nr_frags + 1; ++ if (free_slots < 8) + netif_stop_queue(net_dev); + + return NETDEV_TX_OK; + +-err_stop_drop: +- netif_stop_queue(net_dev); ++err_dma: ++ dma_unmap_single(dma_dev, slot->dma_addr, skb_headlen(skb), ++ DMA_TO_DEVICE); ++ ++ while (i > 0) { ++ int index = (ring->end + i) % BGMAC_TX_RING_SLOTS; ++ struct bgmac_slot_info *slot = &ring->slots[index]; ++ u32 ctl1 = le32_to_cpu(ring->cpu_base[index].ctl1); ++ int len = ctl1 & BGMAC_DESC_CTL1_LEN; ++ ++ dma_unmap_page(dma_dev, slot->dma_addr, len, DMA_TO_DEVICE); ++ } ++ ++err_dma_head: ++ bgmac_err(bgmac, "Mapping error of skb on ring 0x%X\n", ++ ring->mmio_base); ++ ++err_drop: + dev_kfree_skb(skb); + return NETDEV_TX_OK; + } +@@ -205,32 +258,45 @@ static void bgmac_dma_tx_free(struct bgm + + while (ring->start != empty_slot) { + struct bgmac_slot_info *slot = &ring->slots[ring->start]; ++ u32 ctl1 = le32_to_cpu(ring->cpu_base[ring->start].ctl1); ++ int len = ctl1 & BGMAC_DESC_CTL1_LEN; + +- if (slot->skb) { ++ if (!slot->dma_addr) { ++ bgmac_err(bgmac, "Hardware reported transmission for empty TX ring slot %d! End of ring: %d\n", ++ ring->start, ring->end); ++ goto next; ++ } ++ ++ if (ctl1 & BGMAC_DESC_CTL0_SOF) + /* Unmap no longer used buffer */ +- dma_unmap_single(dma_dev, slot->dma_addr, +- slot->skb->len, DMA_TO_DEVICE); +- slot->dma_addr = 0; ++ dma_unmap_single(dma_dev, slot->dma_addr, len, ++ DMA_TO_DEVICE); ++ else ++ dma_unmap_page(dma_dev, slot->dma_addr, len, ++ DMA_TO_DEVICE); + ++ if (slot->skb) { + bytes_compl += slot->skb->len; + pkts_compl++; + + /* Free memory! :) */ + dev_kfree_skb(slot->skb); + slot->skb = NULL; +- } else { +- bgmac_err(bgmac, "Hardware reported transmission for empty TX ring slot %d! End of ring: %d\n", +- ring->start, ring->end); + } + ++next: ++ slot->dma_addr = 0; + if (++ring->start >= BGMAC_TX_RING_SLOTS) + ring->start = 0; + freed = true; + } + ++ if (!pkts_compl) ++ return; ++ + netdev_completed_queue(bgmac->net_dev, pkts_compl, bytes_compl); + +- if (freed && netif_queue_stopped(bgmac->net_dev)) ++ if (netif_queue_stopped(bgmac->net_dev)) + netif_wake_queue(bgmac->net_dev); + } + +@@ -439,17 +505,25 @@ static void bgmac_dma_tx_ring_free(struc + struct bgmac_dma_ring *ring) + { + struct device *dma_dev = bgmac->core->dma_dev; ++ struct bgmac_dma_desc *dma_desc = ring->cpu_base; + struct bgmac_slot_info *slot; + int i; + + for (i = 0; i < ring->num_slots; i++) { ++ int len = dma_desc[i].ctl1 & BGMAC_DESC_CTL1_LEN; ++ + slot = &ring->slots[i]; +- if (slot->skb) { +- if (slot->dma_addr) +- dma_unmap_single(dma_dev, slot->dma_addr, +- slot->skb->len, DMA_TO_DEVICE); +- dev_kfree_skb(slot->skb); +- } ++ dev_kfree_skb(slot->skb); ++ ++ if (!slot->dma_addr) ++ continue; ++ ++ if (slot->skb) ++ dma_unmap_single(dma_dev, slot->dma_addr, ++ len, DMA_TO_DEVICE); ++ else ++ dma_unmap_page(dma_dev, slot->dma_addr, ++ len, DMA_TO_DEVICE); + } + } + +@@ -1583,6 +1657,10 @@ static int bgmac_probe(struct bcma_devic + goto err_dma_free; + } + ++ net_dev->features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; ++ net_dev->hw_features = net_dev->features; ++ net_dev->vlan_features = net_dev->features; ++ + err = register_netdev(bgmac->net_dev); + if (err) { + bgmac_err(bgmac, "Cannot register net device\n"); diff --git a/target/linux/generic/patches-3.18/077-04-bgmac-simplify-tx-ring-index-handling.patch b/target/linux/generic/patches-3.18/077-04-bgmac-simplify-tx-ring-index-handling.patch new file mode 100644 index 0000000..241a308 --- /dev/null +++ b/target/linux/generic/patches-3.18/077-04-bgmac-simplify-tx-ring-index-handling.patch @@ -0,0 +1,125 @@ +From: Felix Fietkau +Date: Sun, 12 Apr 2015 09:58:56 +0200 +Subject: [PATCH] bgmac: simplify tx ring index handling + +Keep incrementing ring->start and ring->end instead of pointing it to +the actual ring slot entry. This simplifies the calculation of the +number of free slots. + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/broadcom/bgmac.c ++++ b/drivers/net/ethernet/broadcom/bgmac.c +@@ -142,11 +142,10 @@ static netdev_tx_t bgmac_dma_tx_add(stru + { + struct device *dma_dev = bgmac->core->dma_dev; + struct net_device *net_dev = bgmac->net_dev; +- struct bgmac_slot_info *slot = &ring->slots[ring->end]; +- int free_slots; ++ int index = ring->end % BGMAC_TX_RING_SLOTS; ++ struct bgmac_slot_info *slot = &ring->slots[index]; + int nr_frags; + u32 flags; +- int index = ring->end; + int i; + + if (skb->len > BGMAC_DESC_CTL1_LEN) { +@@ -159,12 +158,10 @@ static netdev_tx_t bgmac_dma_tx_add(stru + + nr_frags = skb_shinfo(skb)->nr_frags; + +- if (ring->start <= ring->end) +- free_slots = ring->start - ring->end + BGMAC_TX_RING_SLOTS; +- else +- free_slots = ring->start - ring->end; +- +- if (free_slots <= nr_frags + 1) { ++ /* ring->end - ring->start will return the number of valid slots, ++ * even when ring->end overflows ++ */ ++ if (ring->end - ring->start + nr_frags + 1 >= BGMAC_TX_RING_SLOTS) { + bgmac_err(bgmac, "TX ring is full, queue should be stopped!\n"); + netif_stop_queue(net_dev); + return NETDEV_TX_BUSY; +@@ -200,7 +197,7 @@ static netdev_tx_t bgmac_dma_tx_add(stru + } + + slot->skb = skb; +- ++ ring->end += nr_frags + 1; + netdev_sent_queue(net_dev, skb->len); + + wmb(); +@@ -208,13 +205,12 @@ static netdev_tx_t bgmac_dma_tx_add(stru + /* Increase ring->end to point empty slot. We tell hardware the first + * slot it should *not* read. + */ +- ring->end = (index + 1) % BGMAC_TX_RING_SLOTS; + bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_TX_INDEX, + ring->index_base + +- ring->end * sizeof(struct bgmac_dma_desc)); ++ (ring->end % BGMAC_TX_RING_SLOTS) * ++ sizeof(struct bgmac_dma_desc)); + +- free_slots -= nr_frags + 1; +- if (free_slots < 8) ++ if (ring->end - ring->start >= BGMAC_TX_RING_SLOTS - 8) + netif_stop_queue(net_dev); + + return NETDEV_TX_OK; +@@ -256,17 +252,17 @@ static void bgmac_dma_tx_free(struct bgm + empty_slot &= BGMAC_DMA_TX_STATDPTR; + empty_slot /= sizeof(struct bgmac_dma_desc); + +- while (ring->start != empty_slot) { +- struct bgmac_slot_info *slot = &ring->slots[ring->start]; +- u32 ctl1 = le32_to_cpu(ring->cpu_base[ring->start].ctl1); +- int len = ctl1 & BGMAC_DESC_CTL1_LEN; ++ while (ring->start != ring->end) { ++ int slot_idx = ring->start % BGMAC_TX_RING_SLOTS; ++ struct bgmac_slot_info *slot = &ring->slots[slot_idx]; ++ u32 ctl1; ++ int len; + +- if (!slot->dma_addr) { +- bgmac_err(bgmac, "Hardware reported transmission for empty TX ring slot %d! End of ring: %d\n", +- ring->start, ring->end); +- goto next; +- } ++ if (slot_idx == empty_slot) ++ break; + ++ ctl1 = le32_to_cpu(ring->cpu_base[slot_idx].ctl1); ++ len = ctl1 & BGMAC_DESC_CTL1_LEN; + if (ctl1 & BGMAC_DESC_CTL0_SOF) + /* Unmap no longer used buffer */ + dma_unmap_single(dma_dev, slot->dma_addr, len, +@@ -284,10 +280,8 @@ static void bgmac_dma_tx_free(struct bgm + slot->skb = NULL; + } + +-next: + slot->dma_addr = 0; +- if (++ring->start >= BGMAC_TX_RING_SLOTS) +- ring->start = 0; ++ ring->start++; + freed = true; + } + +--- a/drivers/net/ethernet/broadcom/bgmac.h ++++ b/drivers/net/ethernet/broadcom/bgmac.h +@@ -414,10 +414,10 @@ enum bgmac_dma_ring_type { + * empty. + */ + struct bgmac_dma_ring { +- u16 num_slots; +- u16 start; +- u16 end; ++ u32 start; ++ u32 end; + ++ u16 num_slots; + u16 mmio_base; + struct bgmac_dma_desc *cpu_base; + dma_addr_t dma_base; diff --git a/target/linux/generic/patches-3.18/077-05-bgmac-leave-interrupts-disabled-as-long-as-there-is-.patch b/target/linux/generic/patches-3.18/077-05-bgmac-leave-interrupts-disabled-as-long-as-there-is-.patch new file mode 100644 index 0000000..3bbe9ea --- /dev/null +++ b/target/linux/generic/patches-3.18/077-05-bgmac-leave-interrupts-disabled-as-long-as-there-is-.patch @@ -0,0 +1,87 @@ +From: Felix Fietkau +Date: Sun, 12 Apr 2015 10:08:04 +0200 +Subject: [PATCH] bgmac: leave interrupts disabled as long as there is work + to do + +Always poll rx and tx during NAPI poll instead of relying on the status +of the first interrupt. This prevents bgmac_poll from leaving unfinished +work around until the next IRQ. +In my tests this makes bridging/routing throughput under heavy load more +stable and ensures that no new IRQs arrive as long as bgmac_poll uses up +the entire budget. + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/broadcom/bgmac.c ++++ b/drivers/net/ethernet/broadcom/bgmac.c +@@ -1109,8 +1109,6 @@ static void bgmac_chip_reset(struct bgma + bgmac_phy_init(bgmac); + + netdev_reset_queue(bgmac->net_dev); +- +- bgmac->int_status = 0; + } + + static void bgmac_chip_intrs_on(struct bgmac *bgmac) +@@ -1225,14 +1223,13 @@ static irqreturn_t bgmac_interrupt(int i + if (!int_status) + return IRQ_NONE; + +- /* Ack */ +- bgmac_write(bgmac, BGMAC_INT_STATUS, int_status); ++ int_status &= ~(BGMAC_IS_TX0 | BGMAC_IS_RX); ++ if (int_status) ++ bgmac_err(bgmac, "Unknown IRQs: 0x%08X\n", int_status); + + /* Disable new interrupts until handling existing ones */ + bgmac_chip_intrs_off(bgmac); + +- bgmac->int_status = int_status; +- + napi_schedule(&bgmac->napi); + + return IRQ_HANDLED; +@@ -1241,25 +1238,17 @@ static irqreturn_t bgmac_interrupt(int i + static int bgmac_poll(struct napi_struct *napi, int weight) + { + struct bgmac *bgmac = container_of(napi, struct bgmac, napi); +- struct bgmac_dma_ring *ring; + int handled = 0; + +- if (bgmac->int_status & BGMAC_IS_TX0) { +- ring = &bgmac->tx_ring[0]; +- bgmac_dma_tx_free(bgmac, ring); +- bgmac->int_status &= ~BGMAC_IS_TX0; +- } ++ /* Ack */ ++ bgmac_write(bgmac, BGMAC_INT_STATUS, ~0); + +- if (bgmac->int_status & BGMAC_IS_RX) { +- ring = &bgmac->rx_ring[0]; +- handled += bgmac_dma_rx_read(bgmac, ring, weight); +- bgmac->int_status &= ~BGMAC_IS_RX; +- } ++ bgmac_dma_tx_free(bgmac, &bgmac->tx_ring[0]); ++ handled += bgmac_dma_rx_read(bgmac, &bgmac->rx_ring[0], weight); + +- if (bgmac->int_status) { +- bgmac_err(bgmac, "Unknown IRQs: 0x%08X\n", bgmac->int_status); +- bgmac->int_status = 0; +- } ++ /* Poll again if more events arrived in the meantime */ ++ if (bgmac_read(bgmac, BGMAC_INT_STATUS) & (BGMAC_IS_TX0 | BGMAC_IS_RX)) ++ return handled; + + if (handled < weight) { + napi_complete(napi); +--- a/drivers/net/ethernet/broadcom/bgmac.h ++++ b/drivers/net/ethernet/broadcom/bgmac.h +@@ -452,7 +452,6 @@ struct bgmac { + + /* Int */ + u32 int_mask; +- u32 int_status; + + /* Current MAC state */ + int mac_speed; diff --git a/target/linux/generic/patches-3.18/077-06-bgmac-set-received-skb-headroom-to-NET_SKB_PAD.patch b/target/linux/generic/patches-3.18/077-06-bgmac-set-received-skb-headroom-to-NET_SKB_PAD.patch new file mode 100644 index 0000000..2c490ef --- /dev/null +++ b/target/linux/generic/patches-3.18/077-06-bgmac-set-received-skb-headroom-to-NET_SKB_PAD.patch @@ -0,0 +1,66 @@ +From: Felix Fietkau +Date: Sun, 12 Apr 2015 10:13:28 +0200 +Subject: [PATCH] bgmac: set received skb headroom to NET_SKB_PAD + +A packet buffer offset of 30 bytes is inefficient, because the first 2 +bytes end up in a different cacheline. + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/broadcom/bgmac.c ++++ b/drivers/net/ethernet/broadcom/bgmac.c +@@ -346,13 +346,13 @@ static int bgmac_dma_rx_skb_for_slot(str + return -ENOMEM; + + /* Poison - if everything goes fine, hardware will overwrite it */ +- rx = buf; ++ rx = buf + BGMAC_RX_BUF_OFFSET; + rx->len = cpu_to_le16(0xdead); + rx->flags = cpu_to_le16(0xbeef); + + /* Map skb for the DMA */ +- dma_addr = dma_map_single(dma_dev, buf, BGMAC_RX_BUF_SIZE, +- DMA_FROM_DEVICE); ++ dma_addr = dma_map_single(dma_dev, buf + BGMAC_RX_BUF_OFFSET, ++ BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE); + if (dma_mapping_error(dma_dev, dma_addr)) { + bgmac_err(bgmac, "DMA mapping error\n"); + put_page(virt_to_head_page(buf)); +@@ -403,7 +403,7 @@ static int bgmac_dma_rx_read(struct bgma + while (ring->start != ring->end) { + struct device *dma_dev = bgmac->core->dma_dev; + struct bgmac_slot_info *slot = &ring->slots[ring->start]; +- struct bgmac_rx_header *rx = slot->buf; ++ struct bgmac_rx_header *rx = slot->buf + BGMAC_RX_BUF_OFFSET; + struct sk_buff *skb; + void *buf = slot->buf; + u16 len, flags; +@@ -454,8 +454,10 @@ static int bgmac_dma_rx_read(struct bgma + BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE); + + skb = build_skb(buf, BGMAC_RX_ALLOC_SIZE); +- skb_put(skb, BGMAC_RX_FRAME_OFFSET + len); +- skb_pull(skb, BGMAC_RX_FRAME_OFFSET); ++ skb_put(skb, BGMAC_RX_FRAME_OFFSET + ++ BGMAC_RX_BUF_OFFSET + len); ++ skb_pull(skb, BGMAC_RX_FRAME_OFFSET + ++ BGMAC_RX_BUF_OFFSET); + + skb_checksum_none_assert(skb); + skb->protocol = eth_type_trans(skb, bgmac->net_dev); +--- a/drivers/net/ethernet/broadcom/bgmac.h ++++ b/drivers/net/ethernet/broadcom/bgmac.h +@@ -360,9 +360,11 @@ + + #define BGMAC_RX_HEADER_LEN 28 /* Last 24 bytes are unused. Well... */ + #define BGMAC_RX_FRAME_OFFSET 30 /* There are 2 unused bytes between header and real data */ ++#define BGMAC_RX_BUF_OFFSET (NET_SKB_PAD + NET_IP_ALIGN - \ ++ BGMAC_RX_FRAME_OFFSET) + #define BGMAC_RX_MAX_FRAME_SIZE 1536 /* Copied from b44/tg3 */ + #define BGMAC_RX_BUF_SIZE (BGMAC_RX_FRAME_OFFSET + BGMAC_RX_MAX_FRAME_SIZE) +-#define BGMAC_RX_ALLOC_SIZE (SKB_DATA_ALIGN(BGMAC_RX_BUF_SIZE) + \ ++#define BGMAC_RX_ALLOC_SIZE (SKB_DATA_ALIGN(BGMAC_RX_BUF_SIZE + BGMAC_RX_BUF_OFFSET) + \ + SKB_DATA_ALIGN(sizeof(struct skb_shared_info))) + + #define BGMAC_BFL_ENETROBO 0x0010 /* has ephy roboswitch spi */ diff --git a/target/linux/generic/patches-3.18/077-07-bgmac-simplify-rx-DMA-error-handling.patch b/target/linux/generic/patches-3.18/077-07-bgmac-simplify-rx-DMA-error-handling.patch new file mode 100644 index 0000000..2ca9d10 --- /dev/null +++ b/target/linux/generic/patches-3.18/077-07-bgmac-simplify-rx-DMA-error-handling.patch @@ -0,0 +1,130 @@ +From: Felix Fietkau +Date: Sun, 12 Apr 2015 22:23:07 +0200 +Subject: [PATCH] bgmac: simplify/optimize rx DMA error handling + +Allocate a new buffer before processing the completed one. If allocation +fails, reuse the old buffer. + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/broadcom/bgmac.c ++++ b/drivers/net/ethernet/broadcom/bgmac.c +@@ -386,6 +386,19 @@ static void bgmac_dma_rx_setup_desc(stru + dma_desc->ctl1 = cpu_to_le32(ctl1); + } + ++static void bgmac_dma_rx_poison_buf(struct device *dma_dev, ++ struct bgmac_slot_info *slot) ++{ ++ struct bgmac_rx_header *rx = slot->buf + BGMAC_RX_BUF_OFFSET; ++ ++ dma_sync_single_for_cpu(dma_dev, slot->dma_addr, BGMAC_RX_BUF_SIZE, ++ DMA_FROM_DEVICE); ++ rx->len = cpu_to_le16(0xdead); ++ rx->flags = cpu_to_le16(0xbeef); ++ dma_sync_single_for_device(dma_dev, slot->dma_addr, BGMAC_RX_BUF_SIZE, ++ DMA_FROM_DEVICE); ++} ++ + static int bgmac_dma_rx_read(struct bgmac *bgmac, struct bgmac_dma_ring *ring, + int weight) + { +@@ -406,53 +419,35 @@ static int bgmac_dma_rx_read(struct bgma + struct bgmac_rx_header *rx = slot->buf + BGMAC_RX_BUF_OFFSET; + struct sk_buff *skb; + void *buf = slot->buf; ++ dma_addr_t dma_addr = slot->dma_addr; + u16 len, flags; + +- /* Unmap buffer to make it accessible to the CPU */ +- dma_sync_single_for_cpu(dma_dev, slot->dma_addr, +- BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE); +- +- /* Get info from the header */ +- len = le16_to_cpu(rx->len); +- flags = le16_to_cpu(rx->flags); +- + do { +- dma_addr_t old_dma_addr = slot->dma_addr; +- int err; ++ /* Prepare new skb as replacement */ ++ if (bgmac_dma_rx_skb_for_slot(bgmac, slot)) { ++ bgmac_dma_rx_poison_buf(dma_dev, slot); ++ break; ++ } ++ ++ /* Unmap buffer to make it accessible to the CPU */ ++ dma_unmap_single(dma_dev, dma_addr, ++ BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE); ++ ++ /* Get info from the header */ ++ len = le16_to_cpu(rx->len); ++ flags = le16_to_cpu(rx->flags); + + /* Check for poison and drop or pass the packet */ + if (len == 0xdead && flags == 0xbeef) { + bgmac_err(bgmac, "Found poisoned packet at slot %d, DMA issue!\n", + ring->start); +- dma_sync_single_for_device(dma_dev, +- slot->dma_addr, +- BGMAC_RX_BUF_SIZE, +- DMA_FROM_DEVICE); ++ put_page(virt_to_head_page(buf)); + break; + } + + /* Omit CRC. */ + len -= ETH_FCS_LEN; + +- /* Prepare new skb as replacement */ +- err = bgmac_dma_rx_skb_for_slot(bgmac, slot); +- if (err) { +- /* Poison the old skb */ +- rx->len = cpu_to_le16(0xdead); +- rx->flags = cpu_to_le16(0xbeef); +- +- dma_sync_single_for_device(dma_dev, +- slot->dma_addr, +- BGMAC_RX_BUF_SIZE, +- DMA_FROM_DEVICE); +- break; +- } +- bgmac_dma_rx_setup_desc(bgmac, ring, ring->start); +- +- /* Unmap old skb, we'll pass it to the netfif */ +- dma_unmap_single(dma_dev, old_dma_addr, +- BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE); +- + skb = build_skb(buf, BGMAC_RX_ALLOC_SIZE); + skb_put(skb, BGMAC_RX_FRAME_OFFSET + + BGMAC_RX_BUF_OFFSET + len); +@@ -465,6 +460,8 @@ static int bgmac_dma_rx_read(struct bgma + handled++; + } while (0); + ++ bgmac_dma_rx_setup_desc(bgmac, ring, ring->start); ++ + if (++ring->start >= BGMAC_RX_RING_SLOTS) + ring->start = 0; + +@@ -532,14 +529,14 @@ static void bgmac_dma_rx_ring_free(struc + + for (i = 0; i < ring->num_slots; i++) { + slot = &ring->slots[i]; +- if (!slot->buf) ++ if (!slot->dma_addr) + continue; + +- if (slot->dma_addr) +- dma_unmap_single(dma_dev, slot->dma_addr, +- BGMAC_RX_BUF_SIZE, +- DMA_FROM_DEVICE); ++ dma_unmap_single(dma_dev, slot->dma_addr, ++ BGMAC_RX_BUF_SIZE, ++ DMA_FROM_DEVICE); + put_page(virt_to_head_page(slot->buf)); ++ slot->dma_addr = 0; + } + } + diff --git a/target/linux/generic/patches-3.18/077-08-bgmac-add-check-for-oversized-packets.patch b/target/linux/generic/patches-3.18/077-08-bgmac-add-check-for-oversized-packets.patch new file mode 100644 index 0000000..705aa2d --- /dev/null +++ b/target/linux/generic/patches-3.18/077-08-bgmac-add-check-for-oversized-packets.patch @@ -0,0 +1,27 @@ +From: Felix Fietkau +Date: Sun, 12 Apr 2015 22:28:20 +0200 +Subject: [PATCH] bgmac: add check for oversized packets + +In very rare cases, the MAC can catch an internal buffer that is bigger +than it's supposed to be. Instead of crashing the kernel, simply pass +the buffer back to the hardware + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/broadcom/bgmac.c ++++ b/drivers/net/ethernet/broadcom/bgmac.c +@@ -445,6 +445,13 @@ static int bgmac_dma_rx_read(struct bgma + break; + } + ++ if (len > BGMAC_RX_ALLOC_SIZE) { ++ bgmac_err(bgmac, "Found oversized packet at slot %d, DMA issue!\n", ++ ring->start); ++ put_page(virt_to_head_page(buf)); ++ break; ++ } ++ + /* Omit CRC. */ + len -= ETH_FCS_LEN; + diff --git a/target/linux/generic/patches-3.18/077-09-bgmac-increase-rx-ring-size-from-511-to-512.patch b/target/linux/generic/patches-3.18/077-09-bgmac-increase-rx-ring-size-from-511-to-512.patch new file mode 100644 index 0000000..4888cc3 --- /dev/null +++ b/target/linux/generic/patches-3.18/077-09-bgmac-increase-rx-ring-size-from-511-to-512.patch @@ -0,0 +1,23 @@ +From: Felix Fietkau +Date: Sun, 12 Apr 2015 22:36:16 +0200 +Subject: [PATCH] bgmac: increase rx ring size from 511 to 512 + +Limiting it to 511 looks like a failed attempt at leaving one descriptor +empty to allow the hardware to stop processing a buffer that has not +been prepared yet. However, this doesn't work because this affects the +total ring size as well + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/broadcom/bgmac.h ++++ b/drivers/net/ethernet/broadcom/bgmac.h +@@ -356,7 +356,7 @@ + #define BGMAC_MAX_RX_RINGS 1 + + #define BGMAC_TX_RING_SLOTS 128 +-#define BGMAC_RX_RING_SLOTS 512 - 1 /* Why -1? Well, Broadcom does that... */ ++#define BGMAC_RX_RING_SLOTS 512 + + #define BGMAC_RX_HEADER_LEN 28 /* Last 24 bytes are unused. Well... */ + #define BGMAC_RX_FRAME_OFFSET 30 /* There are 2 unused bytes between header and real data */ diff --git a/target/linux/generic/patches-3.18/077-10-bgmac-simplify-dma-init-cleanup.patch b/target/linux/generic/patches-3.18/077-10-bgmac-simplify-dma-init-cleanup.patch new file mode 100644 index 0000000..f8d7921 --- /dev/null +++ b/target/linux/generic/patches-3.18/077-10-bgmac-simplify-dma-init-cleanup.patch @@ -0,0 +1,184 @@ +From: Felix Fietkau +Date: Sun, 12 Apr 2015 23:19:32 +0200 +Subject: [PATCH] bgmac: simplify dma init/cleanup + +Instead of allocating buffers at device init time and initializing +descriptors at device open, do both at the same time (during open). +Free all buffers when closing the device. + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/broadcom/bgmac.c ++++ b/drivers/net/ethernet/broadcom/bgmac.c +@@ -562,18 +562,26 @@ static void bgmac_dma_ring_desc_free(str + ring->dma_base); + } + +-static void bgmac_dma_free(struct bgmac *bgmac) ++static void bgmac_dma_cleanup(struct bgmac *bgmac) + { + int i; + +- for (i = 0; i < BGMAC_MAX_TX_RINGS; i++) { ++ for (i = 0; i < BGMAC_MAX_TX_RINGS; i++) + bgmac_dma_tx_ring_free(bgmac, &bgmac->tx_ring[i]); +- bgmac_dma_ring_desc_free(bgmac, &bgmac->tx_ring[i]); +- } +- for (i = 0; i < BGMAC_MAX_RX_RINGS; i++) { ++ ++ for (i = 0; i < BGMAC_MAX_RX_RINGS; i++) + bgmac_dma_rx_ring_free(bgmac, &bgmac->rx_ring[i]); ++} ++ ++static void bgmac_dma_free(struct bgmac *bgmac) ++{ ++ int i; ++ ++ for (i = 0; i < BGMAC_MAX_TX_RINGS; i++) ++ bgmac_dma_ring_desc_free(bgmac, &bgmac->tx_ring[i]); ++ ++ for (i = 0; i < BGMAC_MAX_RX_RINGS; i++) + bgmac_dma_ring_desc_free(bgmac, &bgmac->rx_ring[i]); +- } + } + + static int bgmac_dma_alloc(struct bgmac *bgmac) +@@ -621,8 +629,6 @@ static int bgmac_dma_alloc(struct bgmac + } + + for (i = 0; i < BGMAC_MAX_RX_RINGS; i++) { +- int j; +- + ring = &bgmac->rx_ring[i]; + ring->num_slots = BGMAC_RX_RING_SLOTS; + ring->mmio_base = ring_base[i]; +@@ -645,15 +651,6 @@ static int bgmac_dma_alloc(struct bgmac + ring->index_base = lower_32_bits(ring->dma_base); + else + ring->index_base = 0; +- +- /* Alloc RX slots */ +- for (j = 0; j < ring->num_slots; j++) { +- err = bgmac_dma_rx_skb_for_slot(bgmac, &ring->slots[j]); +- if (err) { +- bgmac_err(bgmac, "Can't allocate skb for slot in RX ring\n"); +- goto err_dma_free; +- } +- } + } + + return 0; +@@ -663,10 +660,10 @@ err_dma_free: + return -ENOMEM; + } + +-static void bgmac_dma_init(struct bgmac *bgmac) ++static int bgmac_dma_init(struct bgmac *bgmac) + { + struct bgmac_dma_ring *ring; +- int i; ++ int i, err; + + for (i = 0; i < BGMAC_MAX_TX_RINGS; i++) { + ring = &bgmac->tx_ring[i]; +@@ -698,8 +695,13 @@ static void bgmac_dma_init(struct bgmac + if (ring->unaligned) + bgmac_dma_rx_enable(bgmac, ring); + +- for (j = 0; j < ring->num_slots; j++) ++ for (j = 0; j < ring->num_slots; j++) { ++ err = bgmac_dma_rx_skb_for_slot(bgmac, &ring->slots[j]); ++ if (err) ++ goto error; ++ + bgmac_dma_rx_setup_desc(bgmac, ring, j); ++ } + + bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_RX_INDEX, + ring->index_base + +@@ -708,6 +710,12 @@ static void bgmac_dma_init(struct bgmac + ring->start = 0; + ring->end = 0; + } ++ ++ return 0; ++ ++error: ++ bgmac_dma_cleanup(bgmac); ++ return err; + } + + /************************************************** +@@ -1183,11 +1191,8 @@ static void bgmac_enable(struct bgmac *b + } + + /* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipinit */ +-static void bgmac_chip_init(struct bgmac *bgmac, bool full_init) ++static void bgmac_chip_init(struct bgmac *bgmac) + { +- struct bgmac_dma_ring *ring; +- int i; +- + /* 1 interrupt per received frame */ + bgmac_write(bgmac, BGMAC_INT_RECV_LAZY, 1 << BGMAC_IRL_FC_SHIFT); + +@@ -1205,16 +1210,7 @@ static void bgmac_chip_init(struct bgmac + + bgmac_write(bgmac, BGMAC_RXMAX_LENGTH, 32 + ETHER_MAX_LEN); + +- if (full_init) { +- bgmac_dma_init(bgmac); +- if (1) /* FIXME: is there any case we don't want IRQs? */ +- bgmac_chip_intrs_on(bgmac); +- } else { +- for (i = 0; i < BGMAC_MAX_RX_RINGS; i++) { +- ring = &bgmac->rx_ring[i]; +- bgmac_dma_rx_enable(bgmac, ring); +- } +- } ++ bgmac_chip_intrs_on(bgmac); + + bgmac_enable(bgmac); + } +@@ -1274,23 +1270,27 @@ static int bgmac_open(struct net_device + int err = 0; + + bgmac_chip_reset(bgmac); ++ ++ err = bgmac_dma_init(bgmac); ++ if (err) ++ return err; ++ + /* Specs say about reclaiming rings here, but we do that in DMA init */ +- bgmac_chip_init(bgmac, true); ++ bgmac_chip_init(bgmac); + + err = request_irq(bgmac->core->irq, bgmac_interrupt, IRQF_SHARED, + KBUILD_MODNAME, net_dev); + if (err < 0) { + bgmac_err(bgmac, "IRQ request error: %d!\n", err); +- goto err_out; ++ bgmac_dma_cleanup(bgmac); ++ return err; + } + napi_enable(&bgmac->napi); + + phy_start(bgmac->phy_dev); + + netif_carrier_on(net_dev); +- +-err_out: +- return err; ++ return 0; + } + + static int bgmac_stop(struct net_device *net_dev) +@@ -1306,6 +1306,7 @@ static int bgmac_stop(struct net_device + free_irq(bgmac->core->irq, net_dev); + + bgmac_chip_reset(bgmac); ++ bgmac_dma_cleanup(bgmac); + + return 0; + } diff --git a/target/linux/generic/patches-3.18/077-11-bgmac-fix-DMA-rx-corruption.patch b/target/linux/generic/patches-3.18/077-11-bgmac-fix-DMA-rx-corruption.patch new file mode 100644 index 0000000..2e670d8 --- /dev/null +++ b/target/linux/generic/patches-3.18/077-11-bgmac-fix-DMA-rx-corruption.patch @@ -0,0 +1,88 @@ +From: Felix Fietkau +Date: Sun, 12 Apr 2015 11:59:47 +0200 +Subject: [PATCH] bgmac: fix DMA rx corruption + +The driver needs to inform the hardware about the first invalid (not yet +filled) rx slot, by writing its DMA descriptor pointer offset to the +BGMAC_DMA_RX_INDEX register. + +This register was set to a value exceeding the rx ring size, effectively +allowing the hardware constant access to the full ring, regardless of +which slots are initialized. + +To fix this issue, always mark the last filled rx slot as invalid. + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/broadcom/bgmac.c ++++ b/drivers/net/ethernet/broadcom/bgmac.c +@@ -366,6 +366,16 @@ static int bgmac_dma_rx_skb_for_slot(str + return 0; + } + ++static void bgmac_dma_rx_update_index(struct bgmac *bgmac, ++ struct bgmac_dma_ring *ring) ++{ ++ wmb(); ++ ++ bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_RX_INDEX, ++ ring->index_base + ++ ring->end * sizeof(struct bgmac_dma_desc)); ++} ++ + static void bgmac_dma_rx_setup_desc(struct bgmac *bgmac, + struct bgmac_dma_ring *ring, int desc_idx) + { +@@ -384,6 +394,8 @@ static void bgmac_dma_rx_setup_desc(stru + dma_desc->addr_high = cpu_to_le32(upper_32_bits(ring->slots[desc_idx].dma_addr)); + dma_desc->ctl0 = cpu_to_le32(ctl0); + dma_desc->ctl1 = cpu_to_le32(ctl1); ++ ++ ring->end = desc_idx; + } + + static void bgmac_dma_rx_poison_buf(struct device *dma_dev, +@@ -411,9 +423,7 @@ static int bgmac_dma_rx_read(struct bgma + end_slot &= BGMAC_DMA_RX_STATDPTR; + end_slot /= sizeof(struct bgmac_dma_desc); + +- ring->end = end_slot; +- +- while (ring->start != ring->end) { ++ while (ring->start != end_slot) { + struct device *dma_dev = bgmac->core->dma_dev; + struct bgmac_slot_info *slot = &ring->slots[ring->start]; + struct bgmac_rx_header *rx = slot->buf + BGMAC_RX_BUF_OFFSET; +@@ -476,6 +486,8 @@ static int bgmac_dma_rx_read(struct bgma + break; + } + ++ bgmac_dma_rx_update_index(bgmac, ring); ++ + return handled; + } + +@@ -695,6 +707,8 @@ static int bgmac_dma_init(struct bgmac * + if (ring->unaligned) + bgmac_dma_rx_enable(bgmac, ring); + ++ ring->start = 0; ++ ring->end = 0; + for (j = 0; j < ring->num_slots; j++) { + err = bgmac_dma_rx_skb_for_slot(bgmac, &ring->slots[j]); + if (err) +@@ -703,12 +717,7 @@ static int bgmac_dma_init(struct bgmac * + bgmac_dma_rx_setup_desc(bgmac, ring, j); + } + +- bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_RX_INDEX, +- ring->index_base + +- ring->num_slots * sizeof(struct bgmac_dma_desc)); +- +- ring->start = 0; +- ring->end = 0; ++ bgmac_dma_rx_update_index(bgmac, ring); + } + + return 0; diff --git a/target/linux/generic/patches-3.18/077-12-bgmac-drop-ring-num_slots.patch b/target/linux/generic/patches-3.18/077-12-bgmac-drop-ring-num_slots.patch new file mode 100644 index 0000000..4cd2e3f --- /dev/null +++ b/target/linux/generic/patches-3.18/077-12-bgmac-drop-ring-num_slots.patch @@ -0,0 +1,132 @@ +From: Felix Fietkau +Date: Sun, 12 Apr 2015 23:28:38 +0200 +Subject: [PATCH] bgmac: drop ring->num_slots + +The ring size is always known at compile time, so make the code a bit +more efficient + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/broadcom/bgmac.c ++++ b/drivers/net/ethernet/broadcom/bgmac.c +@@ -123,7 +123,7 @@ bgmac_dma_tx_add_buf(struct bgmac *bgmac + struct bgmac_dma_desc *dma_desc; + u32 ctl1; + +- if (i == ring->num_slots - 1) ++ if (i == BGMAC_TX_RING_SLOTS - 1) + ctl0 |= BGMAC_DESC_CTL0_EOT; + + ctl1 = len & BGMAC_DESC_CTL1_LEN; +@@ -382,7 +382,7 @@ static void bgmac_dma_rx_setup_desc(stru + struct bgmac_dma_desc *dma_desc = ring->cpu_base + desc_idx; + u32 ctl0 = 0, ctl1 = 0; + +- if (desc_idx == ring->num_slots - 1) ++ if (desc_idx == BGMAC_RX_RING_SLOTS - 1) + ctl0 |= BGMAC_DESC_CTL0_EOT; + ctl1 |= BGMAC_RX_BUF_SIZE & BGMAC_DESC_CTL1_LEN; + /* Is there any BGMAC device that requires extension? */ +@@ -521,7 +521,7 @@ static void bgmac_dma_tx_ring_free(struc + struct bgmac_slot_info *slot; + int i; + +- for (i = 0; i < ring->num_slots; i++) { ++ for (i = 0; i < BGMAC_TX_RING_SLOTS; i++) { + int len = dma_desc[i].ctl1 & BGMAC_DESC_CTL1_LEN; + + slot = &ring->slots[i]; +@@ -546,7 +546,7 @@ static void bgmac_dma_rx_ring_free(struc + struct bgmac_slot_info *slot; + int i; + +- for (i = 0; i < ring->num_slots; i++) { ++ for (i = 0; i < BGMAC_RX_RING_SLOTS; i++) { + slot = &ring->slots[i]; + if (!slot->dma_addr) + continue; +@@ -560,7 +560,8 @@ static void bgmac_dma_rx_ring_free(struc + } + + static void bgmac_dma_ring_desc_free(struct bgmac *bgmac, +- struct bgmac_dma_ring *ring) ++ struct bgmac_dma_ring *ring, ++ int num_slots) + { + struct device *dma_dev = bgmac->core->dma_dev; + int size; +@@ -569,7 +570,7 @@ static void bgmac_dma_ring_desc_free(str + return; + + /* Free ring of descriptors */ +- size = ring->num_slots * sizeof(struct bgmac_dma_desc); ++ size = num_slots * sizeof(struct bgmac_dma_desc); + dma_free_coherent(dma_dev, size, ring->cpu_base, + ring->dma_base); + } +@@ -590,10 +591,12 @@ static void bgmac_dma_free(struct bgmac + int i; + + for (i = 0; i < BGMAC_MAX_TX_RINGS; i++) +- bgmac_dma_ring_desc_free(bgmac, &bgmac->tx_ring[i]); ++ bgmac_dma_ring_desc_free(bgmac, &bgmac->tx_ring[i], ++ BGMAC_TX_RING_SLOTS); + + for (i = 0; i < BGMAC_MAX_RX_RINGS; i++) +- bgmac_dma_ring_desc_free(bgmac, &bgmac->rx_ring[i]); ++ bgmac_dma_ring_desc_free(bgmac, &bgmac->rx_ring[i], ++ BGMAC_RX_RING_SLOTS); + } + + static int bgmac_dma_alloc(struct bgmac *bgmac) +@@ -616,11 +619,10 @@ static int bgmac_dma_alloc(struct bgmac + + for (i = 0; i < BGMAC_MAX_TX_RINGS; i++) { + ring = &bgmac->tx_ring[i]; +- ring->num_slots = BGMAC_TX_RING_SLOTS; + ring->mmio_base = ring_base[i]; + + /* Alloc ring of descriptors */ +- size = ring->num_slots * sizeof(struct bgmac_dma_desc); ++ size = BGMAC_TX_RING_SLOTS * sizeof(struct bgmac_dma_desc); + ring->cpu_base = dma_zalloc_coherent(dma_dev, size, + &ring->dma_base, + GFP_KERNEL); +@@ -642,11 +644,10 @@ static int bgmac_dma_alloc(struct bgmac + + for (i = 0; i < BGMAC_MAX_RX_RINGS; i++) { + ring = &bgmac->rx_ring[i]; +- ring->num_slots = BGMAC_RX_RING_SLOTS; + ring->mmio_base = ring_base[i]; + + /* Alloc ring of descriptors */ +- size = ring->num_slots * sizeof(struct bgmac_dma_desc); ++ size = BGMAC_RX_RING_SLOTS * sizeof(struct bgmac_dma_desc); + ring->cpu_base = dma_zalloc_coherent(dma_dev, size, + &ring->dma_base, + GFP_KERNEL); +@@ -709,7 +710,7 @@ static int bgmac_dma_init(struct bgmac * + + ring->start = 0; + ring->end = 0; +- for (j = 0; j < ring->num_slots; j++) { ++ for (j = 0; j < BGMAC_RX_RING_SLOTS; j++) { + err = bgmac_dma_rx_skb_for_slot(bgmac, &ring->slots[j]); + if (err) + goto error; +--- a/drivers/net/ethernet/broadcom/bgmac.h ++++ b/drivers/net/ethernet/broadcom/bgmac.h +@@ -419,11 +419,10 @@ struct bgmac_dma_ring { + u32 start; + u32 end; + +- u16 num_slots; +- u16 mmio_base; + struct bgmac_dma_desc *cpu_base; + dma_addr_t dma_base; + u32 index_base; /* Used for unaligned rings only, otherwise 0 */ ++ u16 mmio_base; + bool unaligned; + + struct bgmac_slot_info slots[BGMAC_RX_RING_SLOTS]; diff --git a/target/linux/generic/patches-3.18/077-13-bgmac-fix-MAC-soft-reset-bit-for-corerev-4.patch b/target/linux/generic/patches-3.18/077-13-bgmac-fix-MAC-soft-reset-bit-for-corerev-4.patch new file mode 100644 index 0000000..a3d9fd6 --- /dev/null +++ b/target/linux/generic/patches-3.18/077-13-bgmac-fix-MAC-soft-reset-bit-for-corerev-4.patch @@ -0,0 +1,24 @@ +From: Felix Fietkau +Date: Mon, 13 Apr 2015 15:54:04 +0200 +Subject: [PATCH] bgmac: fix MAC soft-reset bit for corerev > 4 + +Only core revisions older than 4 use BGMAC_CMDCFG_SR_REV0 + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/broadcom/bgmac.h ++++ b/drivers/net/ethernet/broadcom/bgmac.h +@@ -198,9 +198,9 @@ + #define BGMAC_CMDCFG_TAI 0x00000200 + #define BGMAC_CMDCFG_HD 0x00000400 /* Set if in half duplex mode */ + #define BGMAC_CMDCFG_HD_SHIFT 10 +-#define BGMAC_CMDCFG_SR_REV0 0x00000800 /* Set to reset mode, for other revs */ +-#define BGMAC_CMDCFG_SR_REV4 0x00002000 /* Set to reset mode, only for core rev 4 */ +-#define BGMAC_CMDCFG_SR(rev) ((rev == 4) ? BGMAC_CMDCFG_SR_REV4 : BGMAC_CMDCFG_SR_REV0) ++#define BGMAC_CMDCFG_SR_REV0 0x00000800 /* Set to reset mode, for core rev 0-3 */ ++#define BGMAC_CMDCFG_SR_REV4 0x00002000 /* Set to reset mode, for core rev >= 4 */ ++#define BGMAC_CMDCFG_SR(rev) ((rev >= 4) ? BGMAC_CMDCFG_SR_REV4 : BGMAC_CMDCFG_SR_REV0) + #define BGMAC_CMDCFG_ML 0x00008000 /* Set to activate mac loopback mode */ + #define BGMAC_CMDCFG_AE 0x00400000 + #define BGMAC_CMDCFG_CFE 0x00800000 diff --git a/target/linux/generic/patches-3.18/077-14-bgmac-reset-all-4-GMAC-cores-on-init.patch b/target/linux/generic/patches-3.18/077-14-bgmac-reset-all-4-GMAC-cores-on-init.patch new file mode 100644 index 0000000..2a913a6 --- /dev/null +++ b/target/linux/generic/patches-3.18/077-14-bgmac-reset-all-4-GMAC-cores-on-init.patch @@ -0,0 +1,28 @@ +From: Felix Fietkau +Date: Mon, 13 Apr 2015 15:56:26 +0200 +Subject: [PATCH] bgmac: reset all 4 GMAC cores on init + +On a BCM4709 based device, I found that GMAC cores may be enabled at +probe time, but only become usable after a full reset. +Disable cores before re-enabling them to ensure that they are properly +reset. + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/broadcom/bgmac.c ++++ b/drivers/net/ethernet/broadcom/bgmac.c +@@ -1623,8 +1623,11 @@ static int bgmac_probe(struct bcma_devic + ns_core = bcma_find_core_unit(core->bus, + BCMA_CORE_MAC_GBIT, + ns_gmac); +- if (ns_core && !bcma_core_is_enabled(ns_core)) +- bcma_core_enable(ns_core, 0); ++ if (!ns_core) ++ continue; ++ ++ bcma_core_disable(ns_core, 0); ++ bcma_core_enable(ns_core, 0); + } + } + diff --git a/target/linux/generic/patches-3.18/080-00-fib_trie-Fix-proc-net-fib_trie-when-CONFIG_IP_MULTIP.patch b/target/linux/generic/patches-3.18/080-00-fib_trie-Fix-proc-net-fib_trie-when-CONFIG_IP_MULTIP.patch new file mode 100644 index 0000000..5d99367 --- /dev/null +++ b/target/linux/generic/patches-3.18/080-00-fib_trie-Fix-proc-net-fib_trie-when-CONFIG_IP_MULTIP.patch @@ -0,0 +1,46 @@ +From: Alexander Duyck +Date: Tue, 2 Dec 2014 10:58:21 -0800 +Subject: [PATCH] fib_trie: Fix /proc/net/fib_trie when + CONFIG_IP_MULTIPLE_TABLES is not defined + +In recent testing I had disabled CONFIG_IP_MULTIPLE_TABLES and as a result +when I ran "cat /proc/net/fib_trie" the main trie was displayed multiple +times. I found that the problem line of code was in the function +fib_trie_seq_next. Specifically the line below caused the indexes to go in +the opposite direction of our traversal: + + h = tb->tb_id & (FIB_TABLE_HASHSZ - 1); + +This issue was that the RT tables are defined such that RT_TABLE_LOCAL is ID +255, while it is located at TABLE_LOCAL_INDEX of 0, and RT_TABLE_MAIN is 254 +with a TABLE_MAIN_INDEX of 1. This means that the above line will return 1 +for the local table and 0 for main. The result is that fib_trie_seq_next +will return NULL at the end of the local table, fib_trie_seq_start will +return the start of the main table, and then fib_trie_seq_next will loop on +main forever as h will always return 0. + +The fix for this is to reverse the ordering of the two tables. It has the +advantage of making it so that the tables now print in the same order +regardless of if multiple tables are enabled or not. In order to make the +definition consistent with the multiple tables case I simply masked the to +RT_TABLE_XXX values by (FIB_TABLE_HASHSZ - 1). This way the two table +layouts should always stay consistent. + +Fixes: 93456b6 ("[IPV4]: Unify access to the routing tables") +Signed-off-by: Alexander Duyck +Signed-off-by: David S. Miller +--- + +--- a/include/net/ip_fib.h ++++ b/include/net/ip_fib.h +@@ -201,8 +201,8 @@ void fib_free_table(struct fib_table *tb + + #ifndef CONFIG_IP_MULTIPLE_TABLES + +-#define TABLE_LOCAL_INDEX 0 +-#define TABLE_MAIN_INDEX 1 ++#define TABLE_LOCAL_INDEX (RT_TABLE_LOCAL & (FIB_TABLE_HASHSZ - 1)) ++#define TABLE_MAIN_INDEX (RT_TABLE_MAIN & (FIB_TABLE_HASHSZ - 1)) + + static inline struct fib_table *fib_get_table(struct net *net, u32 id) + { diff --git a/target/linux/generic/patches-3.18/080-01-fib_trie-Fix-trie-balancing-issue-if-new-node-pushes.patch b/target/linux/generic/patches-3.18/080-01-fib_trie-Fix-trie-balancing-issue-if-new-node-pushes.patch new file mode 100644 index 0000000..4e09f8a --- /dev/null +++ b/target/linux/generic/patches-3.18/080-01-fib_trie-Fix-trie-balancing-issue-if-new-node-pushes.patch @@ -0,0 +1,72 @@ +From: Alexander Duyck +Date: Wed, 10 Dec 2014 21:49:22 -0800 +Subject: [PATCH] fib_trie: Fix trie balancing issue if new node pushes down + existing node + +This patch addresses an issue with the level compression of the fib_trie. +Specifically in the case of adding a new leaf that triggers a new node to +be added that takes the place of the old node. The result is a trie where +the 1 child tnode is on one side and one leaf is on the other which gives +you a very deep trie. Below is the script I used to generate a trie on +dummy0 with a 10.X.X.X family of addresses. + + ip link add type dummy + ipval=184549374 + bit=2 + for i in `seq 1 23` + do + ifconfig dummy0:$bit $ipval/8 + ipval=`expr $ipval - $bit` + bit=`expr $bit \* 2` + done + cat /proc/net/fib_triestat + +Running the script before the patch: + + Local: + Aver depth: 10.82 + Max depth: 23 + Leaves: 29 + Prefixes: 30 + Internal nodes: 27 + 1: 26 2: 1 + Pointers: 56 + Null ptrs: 1 + Total size: 5 kB + +After applying the patch and repeating: + + Local: + Aver depth: 4.72 + Max depth: 9 + Leaves: 29 + Prefixes: 30 + Internal nodes: 12 + 1: 3 2: 2 3: 7 + Pointers: 70 + Null ptrs: 30 + Total size: 4 kB + +What this fix does is start the rebalance at the newly created tnode +instead of at the parent tnode. This way if there is a gap between the +parent and the new node it doesn't prevent the new tnode from being +coalesced with any pre-existing nodes that may have been pushed into one +of the new nodes child branches. + +Signed-off-by: Alexander Duyck +Signed-off-by: David S. Miller +--- + +--- a/net/ipv4/fib_trie.c ++++ b/net/ipv4/fib_trie.c +@@ -1143,8 +1143,9 @@ static struct list_head *fib_insert_node + put_child(tp, cindex, (struct rt_trie_node *)tn); + } else { + rcu_assign_pointer(t->trie, (struct rt_trie_node *)tn); +- tp = tn; + } ++ ++ tp = tn; + } + + if (tp && tp->pos + tp->bits > 32) diff --git a/target/linux/generic/patches-3.18/080-02-fib_trie-Update-usage-stats-to-be-percpu-instead-of-.patch b/target/linux/generic/patches-3.18/080-02-fib_trie-Update-usage-stats-to-be-percpu-instead-of-.patch new file mode 100644 index 0000000..2e6deb5 --- /dev/null +++ b/target/linux/generic/patches-3.18/080-02-fib_trie-Update-usage-stats-to-be-percpu-instead-of-.patch @@ -0,0 +1,200 @@ +From: Alexander Duyck +Date: Wed, 31 Dec 2014 10:55:29 -0800 +Subject: [PATCH] fib_trie: Update usage stats to be percpu instead of + global variables + +The trie usage stats were currently being shared by all threads that were +calling fib_table_lookup. As a result when multiple threads were +performing lookups simultaneously the trie would begin to cache bounce +between those threads. + +In order to prevent this I have updated the usage stats to use a set of +percpu variables. By doing this we should be able to avoid the cache +bouncing and still make use of these stats. + +Signed-off-by: Alexander Duyck +Signed-off-by: David S. Miller +--- + +--- a/net/ipv4/fib_frontend.c ++++ b/net/ipv4/fib_frontend.c +@@ -67,7 +67,7 @@ static int __net_init fib4_rules_init(st + return 0; + + fail: +- kfree(local_table); ++ fib_free_table(local_table); + return -ENOMEM; + } + #else +--- a/net/ipv4/fib_trie.c ++++ b/net/ipv4/fib_trie.c +@@ -153,7 +153,7 @@ struct trie_stat { + struct trie { + struct rt_trie_node __rcu *trie; + #ifdef CONFIG_IP_FIB_TRIE_STATS +- struct trie_use_stats stats; ++ struct trie_use_stats __percpu *stats; + #endif + }; + +@@ -631,7 +631,7 @@ static struct rt_trie_node *resize(struc + if (IS_ERR(tn)) { + tn = old_tn; + #ifdef CONFIG_IP_FIB_TRIE_STATS +- t->stats.resize_node_skipped++; ++ this_cpu_inc(t->stats->resize_node_skipped); + #endif + break; + } +@@ -658,7 +658,7 @@ static struct rt_trie_node *resize(struc + if (IS_ERR(tn)) { + tn = old_tn; + #ifdef CONFIG_IP_FIB_TRIE_STATS +- t->stats.resize_node_skipped++; ++ this_cpu_inc(t->stats->resize_node_skipped); + #endif + break; + } +@@ -1357,7 +1357,7 @@ static int check_leaf(struct fib_table * + err = fib_props[fa->fa_type].error; + if (err) { + #ifdef CONFIG_IP_FIB_TRIE_STATS +- t->stats.semantic_match_passed++; ++ this_cpu_inc(t->stats->semantic_match_passed); + #endif + return err; + } +@@ -1372,7 +1372,7 @@ static int check_leaf(struct fib_table * + continue; + + #ifdef CONFIG_IP_FIB_TRIE_STATS +- t->stats.semantic_match_passed++; ++ this_cpu_inc(t->stats->semantic_match_passed); + #endif + res->prefixlen = li->plen; + res->nh_sel = nhsel; +@@ -1388,7 +1388,7 @@ static int check_leaf(struct fib_table * + } + + #ifdef CONFIG_IP_FIB_TRIE_STATS +- t->stats.semantic_match_miss++; ++ this_cpu_inc(t->stats->semantic_match_miss); + #endif + } + +@@ -1399,6 +1399,9 @@ int fib_table_lookup(struct fib_table *t + struct fib_result *res, int fib_flags) + { + struct trie *t = (struct trie *) tb->tb_data; ++#ifdef CONFIG_IP_FIB_TRIE_STATS ++ struct trie_use_stats __percpu *stats = t->stats; ++#endif + int ret; + struct rt_trie_node *n; + struct tnode *pn; +@@ -1417,7 +1420,7 @@ int fib_table_lookup(struct fib_table *t + goto failed; + + #ifdef CONFIG_IP_FIB_TRIE_STATS +- t->stats.gets++; ++ this_cpu_inc(stats->gets); + #endif + + /* Just a leaf? */ +@@ -1441,7 +1444,7 @@ int fib_table_lookup(struct fib_table *t + + if (n == NULL) { + #ifdef CONFIG_IP_FIB_TRIE_STATS +- t->stats.null_node_hit++; ++ this_cpu_inc(stats->null_node_hit); + #endif + goto backtrace; + } +@@ -1576,7 +1579,7 @@ backtrace: + chopped_off = 0; + + #ifdef CONFIG_IP_FIB_TRIE_STATS +- t->stats.backtrack++; ++ this_cpu_inc(stats->backtrack); + #endif + goto backtrace; + } +@@ -1830,6 +1833,11 @@ int fib_table_flush(struct fib_table *tb + + void fib_free_table(struct fib_table *tb) + { ++#ifdef CONFIG_IP_FIB_TRIE_STATS ++ struct trie *t = (struct trie *)tb->tb_data; ++ ++ free_percpu(t->stats); ++#endif /* CONFIG_IP_FIB_TRIE_STATS */ + kfree(tb); + } + +@@ -1973,7 +1981,14 @@ struct fib_table *fib_trie_table(u32 id) + tb->tb_num_default = 0; + + t = (struct trie *) tb->tb_data; +- memset(t, 0, sizeof(*t)); ++ RCU_INIT_POINTER(t->trie, NULL); ++#ifdef CONFIG_IP_FIB_TRIE_STATS ++ t->stats = alloc_percpu(struct trie_use_stats); ++ if (!t->stats) { ++ kfree(tb); ++ tb = NULL; ++ } ++#endif + + return tb; + } +@@ -2139,18 +2154,31 @@ static void trie_show_stats(struct seq_f + + #ifdef CONFIG_IP_FIB_TRIE_STATS + static void trie_show_usage(struct seq_file *seq, +- const struct trie_use_stats *stats) ++ const struct trie_use_stats __percpu *stats) + { ++ struct trie_use_stats s = { 0 }; ++ int cpu; ++ ++ /* loop through all of the CPUs and gather up the stats */ ++ for_each_possible_cpu(cpu) { ++ const struct trie_use_stats *pcpu = per_cpu_ptr(stats, cpu); ++ ++ s.gets += pcpu->gets; ++ s.backtrack += pcpu->backtrack; ++ s.semantic_match_passed += pcpu->semantic_match_passed; ++ s.semantic_match_miss += pcpu->semantic_match_miss; ++ s.null_node_hit += pcpu->null_node_hit; ++ s.resize_node_skipped += pcpu->resize_node_skipped; ++ } ++ + seq_printf(seq, "\nCounters:\n---------\n"); +- seq_printf(seq, "gets = %u\n", stats->gets); +- seq_printf(seq, "backtracks = %u\n", stats->backtrack); ++ seq_printf(seq, "gets = %u\n", s.gets); ++ seq_printf(seq, "backtracks = %u\n", s.backtrack); + seq_printf(seq, "semantic match passed = %u\n", +- stats->semantic_match_passed); +- seq_printf(seq, "semantic match miss = %u\n", +- stats->semantic_match_miss); +- seq_printf(seq, "null node hit= %u\n", stats->null_node_hit); +- seq_printf(seq, "skipped node resize = %u\n\n", +- stats->resize_node_skipped); ++ s.semantic_match_passed); ++ seq_printf(seq, "semantic match miss = %u\n", s.semantic_match_miss); ++ seq_printf(seq, "null node hit= %u\n", s.null_node_hit); ++ seq_printf(seq, "skipped node resize = %u\n\n", s.resize_node_skipped); + } + #endif /* CONFIG_IP_FIB_TRIE_STATS */ + +@@ -2191,7 +2219,7 @@ static int fib_triestat_seq_show(struct + trie_collect_stats(t, &stat); + trie_show_stats(seq, &stat); + #ifdef CONFIG_IP_FIB_TRIE_STATS +- trie_show_usage(seq, &t->stats); ++ trie_show_usage(seq, t->stats); + #endif + } + } diff --git a/target/linux/generic/patches-3.18/080-03-fib_trie-Make-leaf-and-tnode-more-uniform.patch b/target/linux/generic/patches-3.18/080-03-fib_trie-Make-leaf-and-tnode-more-uniform.patch new file mode 100644 index 0000000..4c727cd --- /dev/null +++ b/target/linux/generic/patches-3.18/080-03-fib_trie-Make-leaf-and-tnode-more-uniform.patch @@ -0,0 +1,421 @@ +From: Alexander Duyck +Date: Wed, 31 Dec 2014 10:55:35 -0800 +Subject: [PATCH] fib_trie: Make leaf and tnode more uniform + +This change makes some fundamental changes to the way leaves and tnodes are +constructed. The big differences are: +1. Leaves now populate pos and bits indicating their full key size. +2. Trie nodes now mask out their lower bits to be consistent with the leaf +3. Both structures have been reordered so that rt_trie_node now consisists + of a much larger region including the pos, bits, and rcu portions of + the tnode structure. + +On 32b systems this will result in the leaf being 4B larger as the pos and +bits values were added to a hole created by the key as it was only 4B in +length. + +Signed-off-by: Alexander Duyck +Signed-off-by: David S. Miller +--- + +--- a/net/ipv4/fib_trie.c ++++ b/net/ipv4/fib_trie.c +@@ -87,24 +87,38 @@ + + typedef unsigned int t_key; + +-#define T_TNODE 0 +-#define T_LEAF 1 +-#define NODE_TYPE_MASK 0x1UL +-#define NODE_TYPE(node) ((node)->parent & NODE_TYPE_MASK) ++#define IS_TNODE(n) ((n)->bits) ++#define IS_LEAF(n) (!(n)->bits) + +-#define IS_TNODE(n) (!(n->parent & T_LEAF)) +-#define IS_LEAF(n) (n->parent & T_LEAF) ++struct tnode { ++ t_key key; ++ unsigned char bits; /* 2log(KEYLENGTH) bits needed */ ++ unsigned char pos; /* 2log(KEYLENGTH) bits needed */ ++ struct tnode __rcu *parent; ++ union { ++ struct rcu_head rcu; ++ struct tnode *tnode_free; ++ }; ++ unsigned int full_children; /* KEYLENGTH bits needed */ ++ unsigned int empty_children; /* KEYLENGTH bits needed */ ++ struct rt_trie_node __rcu *child[0]; ++}; + + struct rt_trie_node { +- unsigned long parent; + t_key key; ++ unsigned char bits; ++ unsigned char pos; ++ struct tnode __rcu *parent; ++ struct rcu_head rcu; + }; + + struct leaf { +- unsigned long parent; + t_key key; +- struct hlist_head list; ++ unsigned char bits; ++ unsigned char pos; ++ struct tnode __rcu *parent; + struct rcu_head rcu; ++ struct hlist_head list; + }; + + struct leaf_info { +@@ -115,20 +129,6 @@ struct leaf_info { + struct rcu_head rcu; + }; + +-struct tnode { +- unsigned long parent; +- t_key key; +- unsigned char pos; /* 2log(KEYLENGTH) bits needed */ +- unsigned char bits; /* 2log(KEYLENGTH) bits needed */ +- unsigned int full_children; /* KEYLENGTH bits needed */ +- unsigned int empty_children; /* KEYLENGTH bits needed */ +- union { +- struct rcu_head rcu; +- struct tnode *tnode_free; +- }; +- struct rt_trie_node __rcu *child[0]; +-}; +- + #ifdef CONFIG_IP_FIB_TRIE_STATS + struct trie_use_stats { + unsigned int gets; +@@ -176,38 +176,27 @@ static const int sync_pages = 128; + static struct kmem_cache *fn_alias_kmem __read_mostly; + static struct kmem_cache *trie_leaf_kmem __read_mostly; + +-/* +- * caller must hold RTNL +- */ +-static inline struct tnode *node_parent(const struct rt_trie_node *node) +-{ +- unsigned long parent; ++/* caller must hold RTNL */ ++#define node_parent(n) rtnl_dereference((n)->parent) + +- parent = rcu_dereference_index_check(node->parent, lockdep_rtnl_is_held()); ++/* caller must hold RCU read lock or RTNL */ ++#define node_parent_rcu(n) rcu_dereference_rtnl((n)->parent) + +- return (struct tnode *)(parent & ~NODE_TYPE_MASK); +-} +- +-/* +- * caller must hold RCU read lock or RTNL +- */ +-static inline struct tnode *node_parent_rcu(const struct rt_trie_node *node) ++/* wrapper for rcu_assign_pointer */ ++static inline void node_set_parent(struct rt_trie_node *node, struct tnode *ptr) + { +- unsigned long parent; +- +- parent = rcu_dereference_index_check(node->parent, rcu_read_lock_held() || +- lockdep_rtnl_is_held()); +- +- return (struct tnode *)(parent & ~NODE_TYPE_MASK); ++ if (node) ++ rcu_assign_pointer(node->parent, ptr); + } + +-/* Same as rcu_assign_pointer +- * but that macro() assumes that value is a pointer. ++#define NODE_INIT_PARENT(n, p) RCU_INIT_POINTER((n)->parent, p) ++ ++/* This provides us with the number of children in this node, in the case of a ++ * leaf this will return 0 meaning none of the children are accessible. + */ +-static inline void node_set_parent(struct rt_trie_node *node, struct tnode *ptr) ++static inline int tnode_child_length(const struct tnode *tn) + { +- smp_wmb(); +- node->parent = (unsigned long)ptr | NODE_TYPE(node); ++ return (1ul << tn->bits) & ~(1ul); + } + + /* +@@ -215,7 +204,7 @@ static inline void node_set_parent(struc + */ + static inline struct rt_trie_node *tnode_get_child(const struct tnode *tn, unsigned int i) + { +- BUG_ON(i >= 1U << tn->bits); ++ BUG_ON(i >= tnode_child_length(tn)); + + return rtnl_dereference(tn->child[i]); + } +@@ -225,16 +214,11 @@ static inline struct rt_trie_node *tnode + */ + static inline struct rt_trie_node *tnode_get_child_rcu(const struct tnode *tn, unsigned int i) + { +- BUG_ON(i >= 1U << tn->bits); ++ BUG_ON(i >= tnode_child_length(tn)); + + return rcu_dereference_rtnl(tn->child[i]); + } + +-static inline int tnode_child_length(const struct tnode *tn) +-{ +- return 1 << tn->bits; +-} +- + static inline t_key mask_pfx(t_key k, unsigned int l) + { + return (l == 0) ? 0 : k >> (KEYLENGTH-l) << (KEYLENGTH-l); +@@ -336,11 +320,6 @@ static inline int tkey_mismatch(t_key a, + + */ + +-static inline void check_tnode(const struct tnode *tn) +-{ +- WARN_ON(tn && tn->pos+tn->bits > 32); +-} +- + static const int halve_threshold = 25; + static const int inflate_threshold = 50; + static const int halve_threshold_root = 15; +@@ -426,11 +405,20 @@ static void tnode_free_flush(void) + } + } + +-static struct leaf *leaf_new(void) ++static struct leaf *leaf_new(t_key key) + { + struct leaf *l = kmem_cache_alloc(trie_leaf_kmem, GFP_KERNEL); + if (l) { +- l->parent = T_LEAF; ++ l->parent = NULL; ++ /* set key and pos to reflect full key value ++ * any trailing zeros in the key should be ignored ++ * as the nodes are searched ++ */ ++ l->key = key; ++ l->pos = KEYLENGTH; ++ /* set bits to 0 indicating we are not a tnode */ ++ l->bits = 0; ++ + INIT_HLIST_HEAD(&l->list); + } + return l; +@@ -451,12 +439,16 @@ static struct tnode *tnode_new(t_key key + { + size_t sz = sizeof(struct tnode) + (sizeof(struct rt_trie_node *) << bits); + struct tnode *tn = tnode_alloc(sz); ++ unsigned int shift = pos + bits; ++ ++ /* verify bits and pos their msb bits clear and values are valid */ ++ BUG_ON(!bits || (shift > KEYLENGTH)); + + if (tn) { +- tn->parent = T_TNODE; ++ tn->parent = NULL; + tn->pos = pos; + tn->bits = bits; +- tn->key = key; ++ tn->key = mask_pfx(key, pos); + tn->full_children = 0; + tn->empty_children = 1<pos == tn->pos + tn->bits; ++ return n && IS_TNODE(n) && (n->pos == (tn->pos + tn->bits)); + } + + static inline void put_child(struct tnode *tn, int i, +@@ -514,8 +503,7 @@ static void tnode_put_child_reorg(struct + else if (!wasfull && isfull) + tn->full_children++; + +- if (n) +- node_set_parent(n, tn); ++ node_set_parent(n, tn); + + rcu_assign_pointer(tn->child[i], n); + } +@@ -523,7 +511,7 @@ static void tnode_put_child_reorg(struct + #define MAX_WORK 10 + static struct rt_trie_node *resize(struct trie *t, struct tnode *tn) + { +- int i; ++ struct rt_trie_node *n = NULL; + struct tnode *old_tn; + int inflate_threshold_use; + int halve_threshold_use; +@@ -536,12 +524,11 @@ static struct rt_trie_node *resize(struc + tn, inflate_threshold, halve_threshold); + + /* No children */ +- if (tn->empty_children == tnode_child_length(tn)) { +- tnode_free_safe(tn); +- return NULL; +- } ++ if (tn->empty_children > (tnode_child_length(tn) - 1)) ++ goto no_children; ++ + /* One child */ +- if (tn->empty_children == tnode_child_length(tn) - 1) ++ if (tn->empty_children == (tnode_child_length(tn) - 1)) + goto one_child; + /* + * Double as long as the resulting node has a number of +@@ -607,11 +594,9 @@ static struct rt_trie_node *resize(struc + * + */ + +- check_tnode(tn); +- + /* Keep root node larger */ + +- if (!node_parent((struct rt_trie_node *)tn)) { ++ if (!node_parent(tn)) { + inflate_threshold_use = inflate_threshold_root; + halve_threshold_use = halve_threshold_root; + } else { +@@ -637,8 +622,6 @@ static struct rt_trie_node *resize(struc + } + } + +- check_tnode(tn); +- + /* Return if at least one inflate is run */ + if (max_work != MAX_WORK) + return (struct rt_trie_node *) tn; +@@ -666,21 +649,16 @@ static struct rt_trie_node *resize(struc + + + /* Only one child remains */ +- if (tn->empty_children == tnode_child_length(tn) - 1) { ++ if (tn->empty_children == (tnode_child_length(tn) - 1)) { ++ unsigned long i; + one_child: +- for (i = 0; i < tnode_child_length(tn); i++) { +- struct rt_trie_node *n; +- +- n = rtnl_dereference(tn->child[i]); +- if (!n) +- continue; +- +- /* compress one level */ +- +- node_set_parent(n, NULL); +- tnode_free_safe(tn); +- return n; +- } ++ for (i = tnode_child_length(tn); !n && i;) ++ n = tnode_get_child(tn, --i); ++no_children: ++ /* compress one level */ ++ node_set_parent(n, NULL); ++ tnode_free_safe(tn); ++ return n; + } + return (struct rt_trie_node *) tn; + } +@@ -760,8 +738,7 @@ static struct tnode *inflate(struct trie + + /* A leaf or an internal node with skipped bits */ + +- if (IS_LEAF(node) || ((struct tnode *) node)->pos > +- tn->pos + tn->bits - 1) { ++ if (IS_LEAF(node) || (node->pos > (tn->pos + tn->bits - 1))) { + put_child(tn, + tkey_extract_bits(node->key, oldtnode->pos, oldtnode->bits + 1), + node); +@@ -958,11 +935,9 @@ fib_find_node(struct trie *t, u32 key) + pos = 0; + n = rcu_dereference_rtnl(t->trie); + +- while (n != NULL && NODE_TYPE(n) == T_TNODE) { ++ while (n && IS_TNODE(n)) { + tn = (struct tnode *) n; + +- check_tnode(tn); +- + if (tkey_sub_equals(tn->key, pos, tn->pos-pos, key)) { + pos = tn->pos + tn->bits; + n = tnode_get_child_rcu(tn, +@@ -988,7 +963,7 @@ static void trie_rebalance(struct trie * + + key = tn->key; + +- while (tn != NULL && (tp = node_parent((struct rt_trie_node *)tn)) != NULL) { ++ while (tn != NULL && (tp = node_parent(tn)) != NULL) { + cindex = tkey_extract_bits(key, tp->pos, tp->bits); + wasfull = tnode_full(tp, tnode_get_child(tp, cindex)); + tn = (struct tnode *)resize(t, tn); +@@ -996,7 +971,7 @@ static void trie_rebalance(struct trie * + tnode_put_child_reorg(tp, cindex, + (struct rt_trie_node *)tn, wasfull); + +- tp = node_parent((struct rt_trie_node *) tn); ++ tp = node_parent(tn); + if (!tp) + rcu_assign_pointer(t->trie, (struct rt_trie_node *)tn); + +@@ -1048,11 +1023,9 @@ static struct list_head *fib_insert_node + * If it doesn't, we need to replace it with a T_TNODE. + */ + +- while (n != NULL && NODE_TYPE(n) == T_TNODE) { ++ while (n && IS_TNODE(n)) { + tn = (struct tnode *) n; + +- check_tnode(tn); +- + if (tkey_sub_equals(tn->key, pos, tn->pos-pos, key)) { + tp = tn; + pos = tn->pos + tn->bits; +@@ -1087,12 +1060,11 @@ static struct list_head *fib_insert_node + insert_leaf_info(&l->list, li); + goto done; + } +- l = leaf_new(); ++ l = leaf_new(key); + + if (!l) + return NULL; + +- l->key = key; + li = leaf_info_new(plen); + + if (!li) { +@@ -1569,7 +1541,7 @@ backtrace: + if (chopped_off <= pn->bits) { + cindex &= ~(1 << (chopped_off-1)); + } else { +- struct tnode *parent = node_parent_rcu((struct rt_trie_node *) pn); ++ struct tnode *parent = node_parent_rcu(pn); + if (!parent) + goto failed; + +@@ -1597,7 +1569,7 @@ EXPORT_SYMBOL_GPL(fib_table_lookup); + */ + static void trie_leaf_remove(struct trie *t, struct leaf *l) + { +- struct tnode *tp = node_parent((struct rt_trie_node *) l); ++ struct tnode *tp = node_parent(l); + + pr_debug("entering trie_leaf_remove(%p)\n", l); + +@@ -2374,7 +2346,7 @@ static int fib_trie_seq_show(struct seq_ + + if (IS_TNODE(n)) { + struct tnode *tn = (struct tnode *) n; +- __be32 prf = htonl(mask_pfx(tn->key, tn->pos)); ++ __be32 prf = htonl(tn->key); + + seq_indent(seq, iter->depth-1); + seq_printf(seq, " +-- %pI4/%d %d %d %d\n", diff --git a/target/linux/generic/patches-3.18/080-04-fib_trie-Merge-tnode_free-and-leaf_free-into-node_fr.patch b/target/linux/generic/patches-3.18/080-04-fib_trie-Merge-tnode_free-and-leaf_free-into-node_fr.patch new file mode 100644 index 0000000..3f8d030 --- /dev/null +++ b/target/linux/generic/patches-3.18/080-04-fib_trie-Merge-tnode_free-and-leaf_free-into-node_fr.patch @@ -0,0 +1,209 @@ +From: Alexander Duyck +Date: Wed, 31 Dec 2014 10:55:41 -0800 +Subject: [PATCH] fib_trie: Merge tnode_free and leaf_free into node_free + +Both the leaf and the tnode had an rcu_head in them, but they had them in +slightly different places. Since we now have them in the same spot and +know that any node with bits == 0 is a leaf and the rest are either vmalloc +or kmalloc tnodes depending on the value of bits it makes it easy to combine +the functions and reduce overhead. + +In addition I have taken advantage of the rcu_head pointer to go ahead and +put together a simple linked list instead of using the tnode pointer as +this way we can merge either type of structure for freeing. + +Signed-off-by: Alexander Duyck +Signed-off-by: David S. Miller +--- + +--- a/net/ipv4/fib_trie.c ++++ b/net/ipv4/fib_trie.c +@@ -95,15 +95,17 @@ struct tnode { + unsigned char bits; /* 2log(KEYLENGTH) bits needed */ + unsigned char pos; /* 2log(KEYLENGTH) bits needed */ + struct tnode __rcu *parent; +- union { +- struct rcu_head rcu; +- struct tnode *tnode_free; +- }; ++ struct rcu_head rcu; ++ /* everything above this comment must be the same as rt_trie_node */ + unsigned int full_children; /* KEYLENGTH bits needed */ + unsigned int empty_children; /* KEYLENGTH bits needed */ + struct rt_trie_node __rcu *child[0]; + }; + ++/* This struct represents the shared bits between tnode and leaf. If any ++ * ordering is changed here is must also be updated in tnode and leaf as ++ * well. ++ */ + struct rt_trie_node { + t_key key; + unsigned char bits; +@@ -118,6 +120,7 @@ struct leaf { + unsigned char pos; + struct tnode __rcu *parent; + struct rcu_head rcu; ++ /* everything above this comment must be the same as rt_trie_node */ + struct hlist_head list; + }; + +@@ -163,7 +166,7 @@ static struct rt_trie_node *resize(struc + static struct tnode *inflate(struct trie *t, struct tnode *tn); + static struct tnode *halve(struct trie *t, struct tnode *tn); + /* tnodes to free after resize(); protected by RTNL */ +-static struct tnode *tnode_free_head; ++static struct callback_head *tnode_free_head; + static size_t tnode_free_size; + + /* +@@ -336,17 +339,23 @@ static inline void alias_free_mem_rcu(st + call_rcu(&fa->rcu, __alias_free_mem); + } + +-static void __leaf_free_rcu(struct rcu_head *head) +-{ +- struct leaf *l = container_of(head, struct leaf, rcu); +- kmem_cache_free(trie_leaf_kmem, l); +-} ++#define TNODE_KMALLOC_MAX \ ++ ilog2((PAGE_SIZE - sizeof(struct tnode)) / sizeof(struct rt_trie_node *)) + +-static inline void free_leaf(struct leaf *l) ++static void __node_free_rcu(struct rcu_head *head) + { +- call_rcu(&l->rcu, __leaf_free_rcu); ++ struct rt_trie_node *n = container_of(head, struct rt_trie_node, rcu); ++ ++ if (IS_LEAF(n)) ++ kmem_cache_free(trie_leaf_kmem, n); ++ else if (n->bits <= TNODE_KMALLOC_MAX) ++ kfree(n); ++ else ++ vfree(n); + } + ++#define node_free(n) call_rcu(&n->rcu, __node_free_rcu) ++ + static inline void free_leaf_info(struct leaf_info *leaf) + { + kfree_rcu(leaf, rcu); +@@ -360,43 +369,24 @@ static struct tnode *tnode_alloc(size_t + return vzalloc(size); + } + +-static void __tnode_free_rcu(struct rcu_head *head) +-{ +- struct tnode *tn = container_of(head, struct tnode, rcu); +- size_t size = sizeof(struct tnode) + +- (sizeof(struct rt_trie_node *) << tn->bits); +- +- if (size <= PAGE_SIZE) +- kfree(tn); +- else +- vfree(tn); +-} +- +-static inline void tnode_free(struct tnode *tn) +-{ +- if (IS_LEAF(tn)) +- free_leaf((struct leaf *) tn); +- else +- call_rcu(&tn->rcu, __tnode_free_rcu); +-} +- + static void tnode_free_safe(struct tnode *tn) + { + BUG_ON(IS_LEAF(tn)); +- tn->tnode_free = tnode_free_head; +- tnode_free_head = tn; +- tnode_free_size += sizeof(struct tnode) + +- (sizeof(struct rt_trie_node *) << tn->bits); ++ tn->rcu.next = tnode_free_head; ++ tnode_free_head = &tn->rcu; + } + + static void tnode_free_flush(void) + { +- struct tnode *tn; ++ struct callback_head *head; ++ ++ while ((head = tnode_free_head)) { ++ struct tnode *tn = container_of(head, struct tnode, rcu); ++ ++ tnode_free_head = head->next; ++ tnode_free_size += offsetof(struct tnode, child[1 << tn->bits]); + +- while ((tn = tnode_free_head)) { +- tnode_free_head = tn->tnode_free; +- tn->tnode_free = NULL; +- tnode_free(tn); ++ node_free(tn); + } + + if (tnode_free_size >= PAGE_SIZE * sync_pages) { +@@ -437,7 +427,7 @@ static struct leaf_info *leaf_info_new(i + + static struct tnode *tnode_new(t_key key, int pos, int bits) + { +- size_t sz = sizeof(struct tnode) + (sizeof(struct rt_trie_node *) << bits); ++ size_t sz = offsetof(struct tnode, child[1 << bits]); + struct tnode *tn = tnode_alloc(sz); + unsigned int shift = pos + bits; + +@@ -666,15 +656,15 @@ no_children: + + static void tnode_clean_free(struct tnode *tn) + { ++ struct rt_trie_node *tofree; + int i; +- struct tnode *tofree; + + for (i = 0; i < tnode_child_length(tn); i++) { +- tofree = (struct tnode *)rtnl_dereference(tn->child[i]); ++ tofree = rtnl_dereference(tn->child[i]); + if (tofree) +- tnode_free(tofree); ++ node_free(tofree); + } +- tnode_free(tn); ++ node_free(tn); + } + + static struct tnode *inflate(struct trie *t, struct tnode *tn) +@@ -717,7 +707,7 @@ static struct tnode *inflate(struct trie + inode->bits - 1); + + if (!right) { +- tnode_free(left); ++ node_free(left); + goto nomem; + } + +@@ -1068,7 +1058,7 @@ static struct list_head *fib_insert_node + li = leaf_info_new(plen); + + if (!li) { +- free_leaf(l); ++ node_free(l); + return NULL; + } + +@@ -1100,7 +1090,7 @@ static struct list_head *fib_insert_node + + if (!tn) { + free_leaf_info(li); +- free_leaf(l); ++ node_free(l); + return NULL; + } + +@@ -1580,7 +1570,7 @@ static void trie_leaf_remove(struct trie + } else + RCU_INIT_POINTER(t->trie, NULL); + +- free_leaf(l); ++ node_free(l); + } + + /* diff --git a/target/linux/generic/patches-3.18/080-05-fib_trie-Merge-leaf-into-tnode.patch b/target/linux/generic/patches-3.18/080-05-fib_trie-Merge-leaf-into-tnode.patch new file mode 100644 index 0000000..a3393bf --- /dev/null +++ b/target/linux/generic/patches-3.18/080-05-fib_trie-Merge-leaf-into-tnode.patch @@ -0,0 +1,928 @@ +From: Alexander Duyck +Date: Wed, 31 Dec 2014 10:55:47 -0800 +Subject: [PATCH] fib_trie: Merge leaf into tnode + +This change makes it so that leaf and tnode are the same struct. As a +result there is no need for rt_trie_node anymore since everyting can be +merged into tnode. + +On 32b systems this results in the leaf being 4 bytes larger, however I +don't know if that is really an issue as this and an eariler patch that +added bits & pos have increased the size from 20 to 28. If I am not +mistaken slub/slab allocate on power of 2 sizes so 20 was likely being +rounded up to 32 anyway. + +Signed-off-by: Alexander Duyck +Signed-off-by: David S. Miller +--- + +--- a/net/ipv4/fib_trie.c ++++ b/net/ipv4/fib_trie.c +@@ -96,32 +96,16 @@ struct tnode { + unsigned char pos; /* 2log(KEYLENGTH) bits needed */ + struct tnode __rcu *parent; + struct rcu_head rcu; +- /* everything above this comment must be the same as rt_trie_node */ +- unsigned int full_children; /* KEYLENGTH bits needed */ +- unsigned int empty_children; /* KEYLENGTH bits needed */ +- struct rt_trie_node __rcu *child[0]; +-}; +- +-/* This struct represents the shared bits between tnode and leaf. If any +- * ordering is changed here is must also be updated in tnode and leaf as +- * well. +- */ +-struct rt_trie_node { +- t_key key; +- unsigned char bits; +- unsigned char pos; +- struct tnode __rcu *parent; +- struct rcu_head rcu; +-}; +- +-struct leaf { +- t_key key; +- unsigned char bits; +- unsigned char pos; +- struct tnode __rcu *parent; +- struct rcu_head rcu; +- /* everything above this comment must be the same as rt_trie_node */ +- struct hlist_head list; ++ union { ++ /* The fields in this struct are valid if bits > 0 (TNODE) */ ++ struct { ++ unsigned int full_children; /* KEYLENGTH bits needed */ ++ unsigned int empty_children; /* KEYLENGTH bits needed */ ++ struct tnode __rcu *child[0]; ++ }; ++ /* This list pointer if valid if bits == 0 (LEAF) */ ++ struct hlist_head list; ++ }; + }; + + struct leaf_info { +@@ -154,15 +138,15 @@ struct trie_stat { + }; + + struct trie { +- struct rt_trie_node __rcu *trie; ++ struct tnode __rcu *trie; + #ifdef CONFIG_IP_FIB_TRIE_STATS + struct trie_use_stats __percpu *stats; + #endif + }; + +-static void tnode_put_child_reorg(struct tnode *tn, int i, struct rt_trie_node *n, ++static void tnode_put_child_reorg(struct tnode *tn, int i, struct tnode *n, + int wasfull); +-static struct rt_trie_node *resize(struct trie *t, struct tnode *tn); ++static struct tnode *resize(struct trie *t, struct tnode *tn); + static struct tnode *inflate(struct trie *t, struct tnode *tn); + static struct tnode *halve(struct trie *t, struct tnode *tn); + /* tnodes to free after resize(); protected by RTNL */ +@@ -186,10 +170,10 @@ static struct kmem_cache *trie_leaf_kmem + #define node_parent_rcu(n) rcu_dereference_rtnl((n)->parent) + + /* wrapper for rcu_assign_pointer */ +-static inline void node_set_parent(struct rt_trie_node *node, struct tnode *ptr) ++static inline void node_set_parent(struct tnode *n, struct tnode *tp) + { +- if (node) +- rcu_assign_pointer(node->parent, ptr); ++ if (n) ++ rcu_assign_pointer(n->parent, tp); + } + + #define NODE_INIT_PARENT(n, p) RCU_INIT_POINTER((n)->parent, p) +@@ -205,7 +189,7 @@ static inline int tnode_child_length(con + /* + * caller must hold RTNL + */ +-static inline struct rt_trie_node *tnode_get_child(const struct tnode *tn, unsigned int i) ++static inline struct tnode *tnode_get_child(const struct tnode *tn, unsigned int i) + { + BUG_ON(i >= tnode_child_length(tn)); + +@@ -215,7 +199,7 @@ static inline struct rt_trie_node *tnode + /* + * caller must hold RCU read lock or RTNL + */ +-static inline struct rt_trie_node *tnode_get_child_rcu(const struct tnode *tn, unsigned int i) ++static inline struct tnode *tnode_get_child_rcu(const struct tnode *tn, unsigned int i) + { + BUG_ON(i >= tnode_child_length(tn)); + +@@ -340,11 +324,11 @@ static inline void alias_free_mem_rcu(st + } + + #define TNODE_KMALLOC_MAX \ +- ilog2((PAGE_SIZE - sizeof(struct tnode)) / sizeof(struct rt_trie_node *)) ++ ilog2((PAGE_SIZE - sizeof(struct tnode)) / sizeof(struct tnode *)) + + static void __node_free_rcu(struct rcu_head *head) + { +- struct rt_trie_node *n = container_of(head, struct rt_trie_node, rcu); ++ struct tnode *n = container_of(head, struct tnode, rcu); + + if (IS_LEAF(n)) + kmem_cache_free(trie_leaf_kmem, n); +@@ -395,9 +379,9 @@ static void tnode_free_flush(void) + } + } + +-static struct leaf *leaf_new(t_key key) ++static struct tnode *leaf_new(t_key key) + { +- struct leaf *l = kmem_cache_alloc(trie_leaf_kmem, GFP_KERNEL); ++ struct tnode *l = kmem_cache_alloc(trie_leaf_kmem, GFP_KERNEL); + if (l) { + l->parent = NULL; + /* set key and pos to reflect full key value +@@ -444,7 +428,7 @@ static struct tnode *tnode_new(t_key key + } + + pr_debug("AT %p s=%zu %zu\n", tn, sizeof(struct tnode), +- sizeof(struct rt_trie_node *) << bits); ++ sizeof(struct tnode *) << bits); + return tn; + } + +@@ -453,13 +437,13 @@ static struct tnode *tnode_new(t_key key + * and no bits are skipped. See discussion in dyntree paper p. 6 + */ + +-static inline int tnode_full(const struct tnode *tn, const struct rt_trie_node *n) ++static inline int tnode_full(const struct tnode *tn, const struct tnode *n) + { + return n && IS_TNODE(n) && (n->pos == (tn->pos + tn->bits)); + } + + static inline void put_child(struct tnode *tn, int i, +- struct rt_trie_node *n) ++ struct tnode *n) + { + tnode_put_child_reorg(tn, i, n, -1); + } +@@ -469,10 +453,10 @@ static inline void put_child(struct tnod + * Update the value of full_children and empty_children. + */ + +-static void tnode_put_child_reorg(struct tnode *tn, int i, struct rt_trie_node *n, ++static void tnode_put_child_reorg(struct tnode *tn, int i, struct tnode *n, + int wasfull) + { +- struct rt_trie_node *chi = rtnl_dereference(tn->child[i]); ++ struct tnode *chi = rtnl_dereference(tn->child[i]); + int isfull; + + BUG_ON(i >= 1<bits); +@@ -499,10 +483,9 @@ static void tnode_put_child_reorg(struct + } + + #define MAX_WORK 10 +-static struct rt_trie_node *resize(struct trie *t, struct tnode *tn) ++static struct tnode *resize(struct trie *t, struct tnode *tn) + { +- struct rt_trie_node *n = NULL; +- struct tnode *old_tn; ++ struct tnode *old_tn, *n = NULL; + int inflate_threshold_use; + int halve_threshold_use; + int max_work; +@@ -614,7 +597,7 @@ static struct rt_trie_node *resize(struc + + /* Return if at least one inflate is run */ + if (max_work != MAX_WORK) +- return (struct rt_trie_node *) tn; ++ return tn; + + /* + * Halve as long as the number of empty children in this +@@ -650,13 +633,13 @@ no_children: + tnode_free_safe(tn); + return n; + } +- return (struct rt_trie_node *) tn; ++ return tn; + } + + + static void tnode_clean_free(struct tnode *tn) + { +- struct rt_trie_node *tofree; ++ struct tnode *tofree; + int i; + + for (i = 0; i < tnode_child_length(tn); i++) { +@@ -667,10 +650,10 @@ static void tnode_clean_free(struct tnod + node_free(tn); + } + +-static struct tnode *inflate(struct trie *t, struct tnode *tn) ++static struct tnode *inflate(struct trie *t, struct tnode *oldtnode) + { +- struct tnode *oldtnode = tn; +- int olen = tnode_child_length(tn); ++ int olen = tnode_child_length(oldtnode); ++ struct tnode *tn; + int i; + + pr_debug("In inflate\n"); +@@ -690,11 +673,8 @@ static struct tnode *inflate(struct trie + for (i = 0; i < olen; i++) { + struct tnode *inode; + +- inode = (struct tnode *) tnode_get_child(oldtnode, i); +- if (inode && +- IS_TNODE(inode) && +- inode->pos == oldtnode->pos + oldtnode->bits && +- inode->bits > 1) { ++ inode = tnode_get_child(oldtnode, i); ++ if (tnode_full(oldtnode, inode) && inode->bits > 1) { + struct tnode *left, *right; + t_key m = ~0U << (KEYLENGTH - 1) >> inode->pos; + +@@ -711,33 +691,29 @@ static struct tnode *inflate(struct trie + goto nomem; + } + +- put_child(tn, 2*i, (struct rt_trie_node *) left); +- put_child(tn, 2*i+1, (struct rt_trie_node *) right); ++ put_child(tn, 2*i, left); ++ put_child(tn, 2*i+1, right); + } + } + + for (i = 0; i < olen; i++) { +- struct tnode *inode; +- struct rt_trie_node *node = tnode_get_child(oldtnode, i); ++ struct tnode *inode = tnode_get_child(oldtnode, i); + struct tnode *left, *right; + int size, j; + + /* An empty child */ +- if (node == NULL) ++ if (inode == NULL) + continue; + + /* A leaf or an internal node with skipped bits */ +- +- if (IS_LEAF(node) || (node->pos > (tn->pos + tn->bits - 1))) { ++ if (!tnode_full(oldtnode, inode)) { + put_child(tn, +- tkey_extract_bits(node->key, oldtnode->pos, oldtnode->bits + 1), +- node); ++ tkey_extract_bits(inode->key, tn->pos, tn->bits), ++ inode); + continue; + } + + /* An internal node with two children */ +- inode = (struct tnode *) node; +- + if (inode->bits == 1) { + put_child(tn, 2*i, rtnl_dereference(inode->child[0])); + put_child(tn, 2*i+1, rtnl_dereference(inode->child[1])); +@@ -769,12 +745,12 @@ static struct tnode *inflate(struct trie + * bit to zero. + */ + +- left = (struct tnode *) tnode_get_child(tn, 2*i); ++ left = tnode_get_child(tn, 2*i); + put_child(tn, 2*i, NULL); + + BUG_ON(!left); + +- right = (struct tnode *) tnode_get_child(tn, 2*i+1); ++ right = tnode_get_child(tn, 2*i+1); + put_child(tn, 2*i+1, NULL); + + BUG_ON(!right); +@@ -796,12 +772,11 @@ nomem: + return ERR_PTR(-ENOMEM); + } + +-static struct tnode *halve(struct trie *t, struct tnode *tn) ++static struct tnode *halve(struct trie *t, struct tnode *oldtnode) + { +- struct tnode *oldtnode = tn; +- struct rt_trie_node *left, *right; ++ int olen = tnode_child_length(oldtnode); ++ struct tnode *tn, *left, *right; + int i; +- int olen = tnode_child_length(tn); + + pr_debug("In halve\n"); + +@@ -830,7 +805,7 @@ static struct tnode *halve(struct trie * + if (!newn) + goto nomem; + +- put_child(tn, i/2, (struct rt_trie_node *)newn); ++ put_child(tn, i/2, newn); + } + + } +@@ -855,7 +830,7 @@ static struct tnode *halve(struct trie * + } + + /* Two nonempty children */ +- newBinNode = (struct tnode *) tnode_get_child(tn, i/2); ++ newBinNode = tnode_get_child(tn, i/2); + put_child(tn, i/2, NULL); + put_child(newBinNode, 0, left); + put_child(newBinNode, 1, right); +@@ -871,7 +846,7 @@ nomem: + /* readside must use rcu_read_lock currently dump routines + via get_fa_head and dump */ + +-static struct leaf_info *find_leaf_info(struct leaf *l, int plen) ++static struct leaf_info *find_leaf_info(struct tnode *l, int plen) + { + struct hlist_head *head = &l->list; + struct leaf_info *li; +@@ -883,7 +858,7 @@ static struct leaf_info *find_leaf_info( + return NULL; + } + +-static inline struct list_head *get_fa_head(struct leaf *l, int plen) ++static inline struct list_head *get_fa_head(struct tnode *l, int plen) + { + struct leaf_info *li = find_leaf_info(l, plen); + +@@ -915,32 +890,25 @@ static void insert_leaf_info(struct hlis + + /* rcu_read_lock needs to be hold by caller from readside */ + +-static struct leaf * +-fib_find_node(struct trie *t, u32 key) ++static struct tnode *fib_find_node(struct trie *t, u32 key) + { +- int pos; +- struct tnode *tn; +- struct rt_trie_node *n; +- +- pos = 0; +- n = rcu_dereference_rtnl(t->trie); ++ struct tnode *n = rcu_dereference_rtnl(t->trie); ++ int pos = 0; + + while (n && IS_TNODE(n)) { +- tn = (struct tnode *) n; +- +- if (tkey_sub_equals(tn->key, pos, tn->pos-pos, key)) { +- pos = tn->pos + tn->bits; +- n = tnode_get_child_rcu(tn, ++ if (tkey_sub_equals(n->key, pos, n->pos-pos, key)) { ++ pos = n->pos + n->bits; ++ n = tnode_get_child_rcu(n, + tkey_extract_bits(key, +- tn->pos, +- tn->bits)); ++ n->pos, ++ n->bits)); + } else + break; + } + /* Case we have found a leaf. Compare prefixes */ + + if (n != NULL && IS_LEAF(n) && tkey_equals(key, n->key)) +- return (struct leaf *)n; ++ return n; + + return NULL; + } +@@ -956,14 +924,13 @@ static void trie_rebalance(struct trie * + while (tn != NULL && (tp = node_parent(tn)) != NULL) { + cindex = tkey_extract_bits(key, tp->pos, tp->bits); + wasfull = tnode_full(tp, tnode_get_child(tp, cindex)); +- tn = (struct tnode *)resize(t, tn); ++ tn = resize(t, tn); + +- tnode_put_child_reorg(tp, cindex, +- (struct rt_trie_node *)tn, wasfull); ++ tnode_put_child_reorg(tp, cindex, tn, wasfull); + + tp = node_parent(tn); + if (!tp) +- rcu_assign_pointer(t->trie, (struct rt_trie_node *)tn); ++ rcu_assign_pointer(t->trie, tn); + + tnode_free_flush(); + if (!tp) +@@ -973,9 +940,9 @@ static void trie_rebalance(struct trie * + + /* Handle last (top) tnode */ + if (IS_TNODE(tn)) +- tn = (struct tnode *)resize(t, tn); ++ tn = resize(t, tn); + +- rcu_assign_pointer(t->trie, (struct rt_trie_node *)tn); ++ rcu_assign_pointer(t->trie, tn); + tnode_free_flush(); + } + +@@ -985,8 +952,8 @@ static struct list_head *fib_insert_node + { + int pos, newpos; + struct tnode *tp = NULL, *tn = NULL; +- struct rt_trie_node *n; +- struct leaf *l; ++ struct tnode *n; ++ struct tnode *l; + int missbit; + struct list_head *fa_head = NULL; + struct leaf_info *li; +@@ -1014,17 +981,15 @@ static struct list_head *fib_insert_node + */ + + while (n && IS_TNODE(n)) { +- tn = (struct tnode *) n; +- +- if (tkey_sub_equals(tn->key, pos, tn->pos-pos, key)) { +- tp = tn; +- pos = tn->pos + tn->bits; +- n = tnode_get_child(tn, ++ if (tkey_sub_equals(n->key, pos, n->pos-pos, key)) { ++ tp = n; ++ pos = n->pos + n->bits; ++ n = tnode_get_child(n, + tkey_extract_bits(key, +- tn->pos, +- tn->bits)); ++ n->pos, ++ n->bits)); + +- BUG_ON(n && node_parent(n) != tn); ++ BUG_ON(n && node_parent(n) != tp); + } else + break; + } +@@ -1040,14 +1005,13 @@ static struct list_head *fib_insert_node + /* Case 1: n is a leaf. Compare prefixes */ + + if (n != NULL && IS_LEAF(n) && tkey_equals(key, n->key)) { +- l = (struct leaf *) n; + li = leaf_info_new(plen); + + if (!li) + return NULL; + + fa_head = &li->falh; +- insert_leaf_info(&l->list, li); ++ insert_leaf_info(&n->list, li); + goto done; + } + l = leaf_new(key); +@@ -1068,10 +1032,10 @@ static struct list_head *fib_insert_node + if (t->trie && n == NULL) { + /* Case 2: n is NULL, and will just insert a new leaf */ + +- node_set_parent((struct rt_trie_node *)l, tp); ++ node_set_parent(l, tp); + + cindex = tkey_extract_bits(key, tp->pos, tp->bits); +- put_child(tp, cindex, (struct rt_trie_node *)l); ++ put_child(tp, cindex, l); + } else { + /* Case 3: n is a LEAF or a TNODE and the key doesn't match. */ + /* +@@ -1094,17 +1058,17 @@ static struct list_head *fib_insert_node + return NULL; + } + +- node_set_parent((struct rt_trie_node *)tn, tp); ++ node_set_parent(tn, tp); + + missbit = tkey_extract_bits(key, newpos, 1); +- put_child(tn, missbit, (struct rt_trie_node *)l); ++ put_child(tn, missbit, l); + put_child(tn, 1-missbit, n); + + if (tp) { + cindex = tkey_extract_bits(key, tp->pos, tp->bits); +- put_child(tp, cindex, (struct rt_trie_node *)tn); ++ put_child(tp, cindex, tn); + } else { +- rcu_assign_pointer(t->trie, (struct rt_trie_node *)tn); ++ rcu_assign_pointer(t->trie, tn); + } + + tp = tn; +@@ -1134,7 +1098,7 @@ int fib_table_insert(struct fib_table *t + u8 tos = cfg->fc_tos; + u32 key, mask; + int err; +- struct leaf *l; ++ struct tnode *l; + + if (plen > 32) + return -EINVAL; +@@ -1292,7 +1256,7 @@ err: + } + + /* should be called with rcu_read_lock */ +-static int check_leaf(struct fib_table *tb, struct trie *t, struct leaf *l, ++static int check_leaf(struct fib_table *tb, struct trie *t, struct tnode *l, + t_key key, const struct flowi4 *flp, + struct fib_result *res, int fib_flags) + { +@@ -1365,7 +1329,7 @@ int fib_table_lookup(struct fib_table *t + struct trie_use_stats __percpu *stats = t->stats; + #endif + int ret; +- struct rt_trie_node *n; ++ struct tnode *n; + struct tnode *pn; + unsigned int pos, bits; + t_key key = ntohl(flp->daddr); +@@ -1387,11 +1351,11 @@ int fib_table_lookup(struct fib_table *t + + /* Just a leaf? */ + if (IS_LEAF(n)) { +- ret = check_leaf(tb, t, (struct leaf *)n, key, flp, res, fib_flags); ++ ret = check_leaf(tb, t, n, key, flp, res, fib_flags); + goto found; + } + +- pn = (struct tnode *) n; ++ pn = n; + chopped_off = 0; + + while (pn) { +@@ -1412,13 +1376,13 @@ int fib_table_lookup(struct fib_table *t + } + + if (IS_LEAF(n)) { +- ret = check_leaf(tb, t, (struct leaf *)n, key, flp, res, fib_flags); ++ ret = check_leaf(tb, t, n, key, flp, res, fib_flags); + if (ret > 0) + goto backtrace; + goto found; + } + +- cn = (struct tnode *)n; ++ cn = n; + + /* + * It's a tnode, and we can do some extra checks here if we +@@ -1506,7 +1470,7 @@ int fib_table_lookup(struct fib_table *t + current_prefix_length = mp; + } + +- pn = (struct tnode *)n; /* Descend */ ++ pn = n; /* Descend */ + chopped_off = 0; + continue; + +@@ -1557,7 +1521,7 @@ EXPORT_SYMBOL_GPL(fib_table_lookup); + /* + * Remove the leaf and return parent. + */ +-static void trie_leaf_remove(struct trie *t, struct leaf *l) ++static void trie_leaf_remove(struct trie *t, struct tnode *l) + { + struct tnode *tp = node_parent(l); + +@@ -1584,7 +1548,7 @@ int fib_table_delete(struct fib_table *t + u8 tos = cfg->fc_tos; + struct fib_alias *fa, *fa_to_delete; + struct list_head *fa_head; +- struct leaf *l; ++ struct tnode *l; + struct leaf_info *li; + + if (plen > 32) +@@ -1682,7 +1646,7 @@ static int trie_flush_list(struct list_h + return found; + } + +-static int trie_flush_leaf(struct leaf *l) ++static int trie_flush_leaf(struct tnode *l) + { + int found = 0; + struct hlist_head *lih = &l->list; +@@ -1704,7 +1668,7 @@ static int trie_flush_leaf(struct leaf * + * Scan for the next right leaf starting at node p->child[idx] + * Since we have back pointer, no recursion necessary. + */ +-static struct leaf *leaf_walk_rcu(struct tnode *p, struct rt_trie_node *c) ++static struct tnode *leaf_walk_rcu(struct tnode *p, struct tnode *c) + { + do { + t_key idx; +@@ -1720,47 +1684,46 @@ static struct leaf *leaf_walk_rcu(struct + continue; + + if (IS_LEAF(c)) +- return (struct leaf *) c; ++ return c; + + /* Rescan start scanning in new node */ +- p = (struct tnode *) c; ++ p = c; + idx = 0; + } + + /* Node empty, walk back up to parent */ +- c = (struct rt_trie_node *) p; ++ c = p; + } while ((p = node_parent_rcu(c)) != NULL); + + return NULL; /* Root of trie */ + } + +-static struct leaf *trie_firstleaf(struct trie *t) ++static struct tnode *trie_firstleaf(struct trie *t) + { +- struct tnode *n = (struct tnode *)rcu_dereference_rtnl(t->trie); ++ struct tnode *n = rcu_dereference_rtnl(t->trie); + + if (!n) + return NULL; + + if (IS_LEAF(n)) /* trie is just a leaf */ +- return (struct leaf *) n; ++ return n; + + return leaf_walk_rcu(n, NULL); + } + +-static struct leaf *trie_nextleaf(struct leaf *l) ++static struct tnode *trie_nextleaf(struct tnode *l) + { +- struct rt_trie_node *c = (struct rt_trie_node *) l; +- struct tnode *p = node_parent_rcu(c); ++ struct tnode *p = node_parent_rcu(l); + + if (!p) + return NULL; /* trie with just one leaf */ + +- return leaf_walk_rcu(p, c); ++ return leaf_walk_rcu(p, l); + } + +-static struct leaf *trie_leafindex(struct trie *t, int index) ++static struct tnode *trie_leafindex(struct trie *t, int index) + { +- struct leaf *l = trie_firstleaf(t); ++ struct tnode *l = trie_firstleaf(t); + + while (l && index-- > 0) + l = trie_nextleaf(l); +@@ -1775,7 +1738,7 @@ static struct leaf *trie_leafindex(struc + int fib_table_flush(struct fib_table *tb) + { + struct trie *t = (struct trie *) tb->tb_data; +- struct leaf *l, *ll = NULL; ++ struct tnode *l, *ll = NULL; + int found = 0; + + for (l = trie_firstleaf(t); l; l = trie_nextleaf(l)) { +@@ -1840,7 +1803,7 @@ static int fn_trie_dump_fa(t_key key, in + return skb->len; + } + +-static int fn_trie_dump_leaf(struct leaf *l, struct fib_table *tb, ++static int fn_trie_dump_leaf(struct tnode *l, struct fib_table *tb, + struct sk_buff *skb, struct netlink_callback *cb) + { + struct leaf_info *li; +@@ -1876,7 +1839,7 @@ static int fn_trie_dump_leaf(struct leaf + int fib_table_dump(struct fib_table *tb, struct sk_buff *skb, + struct netlink_callback *cb) + { +- struct leaf *l; ++ struct tnode *l; + struct trie *t = (struct trie *) tb->tb_data; + t_key key = cb->args[2]; + int count = cb->args[3]; +@@ -1922,7 +1885,7 @@ void __init fib_trie_init(void) + 0, SLAB_PANIC, NULL); + + trie_leaf_kmem = kmem_cache_create("ip_fib_trie", +- max(sizeof(struct leaf), ++ max(sizeof(struct tnode), + sizeof(struct leaf_info)), + 0, SLAB_PANIC, NULL); + } +@@ -1965,7 +1928,7 @@ struct fib_trie_iter { + unsigned int depth; + }; + +-static struct rt_trie_node *fib_trie_get_next(struct fib_trie_iter *iter) ++static struct tnode *fib_trie_get_next(struct fib_trie_iter *iter) + { + struct tnode *tn = iter->tnode; + unsigned int cindex = iter->index; +@@ -1979,7 +1942,7 @@ static struct rt_trie_node *fib_trie_get + iter->tnode, iter->index, iter->depth); + rescan: + while (cindex < (1<bits)) { +- struct rt_trie_node *n = tnode_get_child_rcu(tn, cindex); ++ struct tnode *n = tnode_get_child_rcu(tn, cindex); + + if (n) { + if (IS_LEAF(n)) { +@@ -1987,7 +1950,7 @@ rescan: + iter->index = cindex + 1; + } else { + /* push down one level */ +- iter->tnode = (struct tnode *) n; ++ iter->tnode = n; + iter->index = 0; + ++iter->depth; + } +@@ -1998,7 +1961,7 @@ rescan: + } + + /* Current node exhausted, pop back up */ +- p = node_parent_rcu((struct rt_trie_node *)tn); ++ p = node_parent_rcu(tn); + if (p) { + cindex = tkey_extract_bits(tn->key, p->pos, p->bits)+1; + tn = p; +@@ -2010,10 +1973,10 @@ rescan: + return NULL; + } + +-static struct rt_trie_node *fib_trie_get_first(struct fib_trie_iter *iter, ++static struct tnode *fib_trie_get_first(struct fib_trie_iter *iter, + struct trie *t) + { +- struct rt_trie_node *n; ++ struct tnode *n; + + if (!t) + return NULL; +@@ -2023,7 +1986,7 @@ static struct rt_trie_node *fib_trie_get + return NULL; + + if (IS_TNODE(n)) { +- iter->tnode = (struct tnode *) n; ++ iter->tnode = n; + iter->index = 0; + iter->depth = 1; + } else { +@@ -2037,7 +2000,7 @@ static struct rt_trie_node *fib_trie_get + + static void trie_collect_stats(struct trie *t, struct trie_stat *s) + { +- struct rt_trie_node *n; ++ struct tnode *n; + struct fib_trie_iter iter; + + memset(s, 0, sizeof(*s)); +@@ -2045,7 +2008,6 @@ static void trie_collect_stats(struct tr + rcu_read_lock(); + for (n = fib_trie_get_first(&iter, t); n; n = fib_trie_get_next(&iter)) { + if (IS_LEAF(n)) { +- struct leaf *l = (struct leaf *)n; + struct leaf_info *li; + + s->leaves++; +@@ -2053,18 +2015,17 @@ static void trie_collect_stats(struct tr + if (iter.depth > s->maxdepth) + s->maxdepth = iter.depth; + +- hlist_for_each_entry_rcu(li, &l->list, hlist) ++ hlist_for_each_entry_rcu(li, &n->list, hlist) + ++s->prefixes; + } else { +- const struct tnode *tn = (const struct tnode *) n; + int i; + + s->tnodes++; +- if (tn->bits < MAX_STAT_DEPTH) +- s->nodesizes[tn->bits]++; ++ if (n->bits < MAX_STAT_DEPTH) ++ s->nodesizes[n->bits]++; + +- for (i = 0; i < (1<bits); i++) +- if (!tn->child[i]) ++ for (i = 0; i < tnode_child_length(n); i++) ++ if (!rcu_access_pointer(n->child[i])) + s->nullpointers++; + } + } +@@ -2088,7 +2049,7 @@ static void trie_show_stats(struct seq_f + seq_printf(seq, "\tMax depth: %u\n", stat->maxdepth); + + seq_printf(seq, "\tLeaves: %u\n", stat->leaves); +- bytes = sizeof(struct leaf) * stat->leaves; ++ bytes = sizeof(struct tnode) * stat->leaves; + + seq_printf(seq, "\tPrefixes: %u\n", stat->prefixes); + bytes += sizeof(struct leaf_info) * stat->prefixes; +@@ -2109,7 +2070,7 @@ static void trie_show_stats(struct seq_f + seq_putc(seq, '\n'); + seq_printf(seq, "\tPointers: %u\n", pointers); + +- bytes += sizeof(struct rt_trie_node *) * pointers; ++ bytes += sizeof(struct tnode *) * pointers; + seq_printf(seq, "Null ptrs: %u\n", stat->nullpointers); + seq_printf(seq, "Total size: %u kB\n", (bytes + 1023) / 1024); + } +@@ -2163,7 +2124,7 @@ static int fib_triestat_seq_show(struct + seq_printf(seq, + "Basic info: size of leaf:" + " %Zd bytes, size of tnode: %Zd bytes.\n", +- sizeof(struct leaf), sizeof(struct tnode)); ++ sizeof(struct tnode), sizeof(struct tnode)); + + for (h = 0; h < FIB_TABLE_HASHSZ; h++) { + struct hlist_head *head = &net->ipv4.fib_table_hash[h]; +@@ -2202,7 +2163,7 @@ static const struct file_operations fib_ + .release = single_release_net, + }; + +-static struct rt_trie_node *fib_trie_get_idx(struct seq_file *seq, loff_t pos) ++static struct tnode *fib_trie_get_idx(struct seq_file *seq, loff_t pos) + { + struct fib_trie_iter *iter = seq->private; + struct net *net = seq_file_net(seq); +@@ -2214,7 +2175,7 @@ static struct rt_trie_node *fib_trie_get + struct fib_table *tb; + + hlist_for_each_entry_rcu(tb, head, tb_hlist) { +- struct rt_trie_node *n; ++ struct tnode *n; + + for (n = fib_trie_get_first(iter, + (struct trie *) tb->tb_data); +@@ -2243,7 +2204,7 @@ static void *fib_trie_seq_next(struct se + struct fib_table *tb = iter->tb; + struct hlist_node *tb_node; + unsigned int h; +- struct rt_trie_node *n; ++ struct tnode *n; + + ++*pos; + /* next node in same table */ +@@ -2329,29 +2290,26 @@ static inline const char *rtn_type(char + static int fib_trie_seq_show(struct seq_file *seq, void *v) + { + const struct fib_trie_iter *iter = seq->private; +- struct rt_trie_node *n = v; ++ struct tnode *n = v; + + if (!node_parent_rcu(n)) + fib_table_print(seq, iter->tb); + + if (IS_TNODE(n)) { +- struct tnode *tn = (struct tnode *) n; +- __be32 prf = htonl(tn->key); ++ __be32 prf = htonl(n->key); + +- seq_indent(seq, iter->depth-1); ++ seq_indent(seq, iter->depth - 1); + seq_printf(seq, " +-- %pI4/%d %d %d %d\n", +- &prf, tn->pos, tn->bits, tn->full_children, +- tn->empty_children); +- ++ &prf, n->pos, n->bits, n->full_children, ++ n->empty_children); + } else { +- struct leaf *l = (struct leaf *) n; + struct leaf_info *li; +- __be32 val = htonl(l->key); ++ __be32 val = htonl(n->key); + + seq_indent(seq, iter->depth); + seq_printf(seq, " |-- %pI4\n", &val); + +- hlist_for_each_entry_rcu(li, &l->list, hlist) { ++ hlist_for_each_entry_rcu(li, &n->list, hlist) { + struct fib_alias *fa; + + list_for_each_entry_rcu(fa, &li->falh, fa_list) { +@@ -2401,9 +2359,9 @@ struct fib_route_iter { + t_key key; + }; + +-static struct leaf *fib_route_get_idx(struct fib_route_iter *iter, loff_t pos) ++static struct tnode *fib_route_get_idx(struct fib_route_iter *iter, loff_t pos) + { +- struct leaf *l = NULL; ++ struct tnode *l = NULL; + struct trie *t = iter->main_trie; + + /* use cache location of last found key */ +@@ -2448,7 +2406,7 @@ static void *fib_route_seq_start(struct + static void *fib_route_seq_next(struct seq_file *seq, void *v, loff_t *pos) + { + struct fib_route_iter *iter = seq->private; +- struct leaf *l = v; ++ struct tnode *l = v; + + ++*pos; + if (v == SEQ_START_TOKEN) { +@@ -2494,7 +2452,7 @@ static unsigned int fib_flag_trans(int t + */ + static int fib_route_seq_show(struct seq_file *seq, void *v) + { +- struct leaf *l = v; ++ struct tnode *l = v; + struct leaf_info *li; + + if (v == SEQ_START_TOKEN) { diff --git a/target/linux/generic/patches-3.18/080-06-fib_trie-Optimize-fib_table_lookup-to-avoid-wasting-.patch b/target/linux/generic/patches-3.18/080-06-fib_trie-Optimize-fib_table_lookup-to-avoid-wasting-.patch new file mode 100644 index 0000000..e844126 --- /dev/null +++ b/target/linux/generic/patches-3.18/080-06-fib_trie-Optimize-fib_table_lookup-to-avoid-wasting-.patch @@ -0,0 +1,343 @@ +From: Alexander Duyck +Date: Wed, 31 Dec 2014 10:55:54 -0800 +Subject: [PATCH] fib_trie: Optimize fib_table_lookup to avoid wasting + time on loops/variables + +This patch is meant to reduce the complexity of fib_table_lookup by reducing +the number of variables to the bare minimum while still keeping the same if +not improved functionality versus the original. + +Most of this change was started off by the desire to rid the function of +chopped_off and current_prefix_length as they actually added very little to +the function since they only applied when computing the cindex. I was able +to replace them mostly with just a check for the prefix match. As long as +the prefix between the key and the node being tested was the same we know +we can search the tnode fully versus just testing cindex 0. + +The second portion of the change ended up being a massive reordering. +Originally the calls to check_leaf were up near the start of the loop, and +the backtracing and descending into lower levels of tnodes was later. This +didn't make much sense as the structure of the tree means the leaves are +always the last thing to be tested. As such I reordered things so that we +instead have a loop that will delve into the tree and only exit when we +have either found a leaf or we have exhausted the tree. The advantage of +rearranging things like this is that we can fully inline check_leaf since +there is now only one reference to it in the function. + +Signed-off-by: Alexander Duyck +Signed-off-by: David S. Miller +--- + +--- a/net/ipv4/fib_trie.c ++++ b/net/ipv4/fib_trie.c +@@ -90,6 +90,9 @@ typedef unsigned int t_key; + #define IS_TNODE(n) ((n)->bits) + #define IS_LEAF(n) (!(n)->bits) + ++#define get_shift(_kv) (KEYLENGTH - (_kv)->pos - (_kv)->bits) ++#define get_index(_key, _kv) (((_key) ^ (_kv)->key) >> get_shift(_kv)) ++ + struct tnode { + t_key key; + unsigned char bits; /* 2log(KEYLENGTH) bits needed */ +@@ -1281,7 +1284,7 @@ static int check_leaf(struct fib_table * + continue; + fib_alias_accessed(fa); + err = fib_props[fa->fa_type].error; +- if (err) { ++ if (unlikely(err < 0)) { + #ifdef CONFIG_IP_FIB_TRIE_STATS + this_cpu_inc(t->stats->semantic_match_passed); + #endif +@@ -1303,7 +1306,7 @@ static int check_leaf(struct fib_table * + res->prefixlen = li->plen; + res->nh_sel = nhsel; + res->type = fa->fa_type; +- res->scope = fa->fa_info->fib_scope; ++ res->scope = fi->fib_scope; + res->fi = fi; + res->table = tb; + res->fa_head = &li->falh; +@@ -1321,23 +1324,24 @@ static int check_leaf(struct fib_table * + return 1; + } + ++static inline t_key prefix_mismatch(t_key key, struct tnode *n) ++{ ++ t_key prefix = n->key; ++ ++ return (key ^ prefix) & (prefix | -prefix); ++} ++ + int fib_table_lookup(struct fib_table *tb, const struct flowi4 *flp, + struct fib_result *res, int fib_flags) + { +- struct trie *t = (struct trie *) tb->tb_data; ++ struct trie *t = (struct trie *)tb->tb_data; + #ifdef CONFIG_IP_FIB_TRIE_STATS + struct trie_use_stats __percpu *stats = t->stats; + #endif +- int ret; +- struct tnode *n; +- struct tnode *pn; +- unsigned int pos, bits; +- t_key key = ntohl(flp->daddr); +- unsigned int chopped_off; +- t_key cindex = 0; +- unsigned int current_prefix_length = KEYLENGTH; +- struct tnode *cn; +- t_key pref_mismatch; ++ const t_key key = ntohl(flp->daddr); ++ struct tnode *n, *pn; ++ t_key cindex; ++ int ret = 1; + + rcu_read_lock(); + +@@ -1349,170 +1353,102 @@ int fib_table_lookup(struct fib_table *t + this_cpu_inc(stats->gets); + #endif + +- /* Just a leaf? */ +- if (IS_LEAF(n)) { +- ret = check_leaf(tb, t, n, key, flp, res, fib_flags); +- goto found; +- } +- + pn = n; +- chopped_off = 0; +- +- while (pn) { +- pos = pn->pos; +- bits = pn->bits; ++ cindex = 0; + +- if (!chopped_off) +- cindex = tkey_extract_bits(mask_pfx(key, current_prefix_length), +- pos, bits); +- +- n = tnode_get_child_rcu(pn, cindex); +- +- if (n == NULL) { +-#ifdef CONFIG_IP_FIB_TRIE_STATS +- this_cpu_inc(stats->null_node_hit); +-#endif +- goto backtrace; +- } ++ /* Step 1: Travel to the longest prefix match in the trie */ ++ for (;;) { ++ unsigned long index = get_index(key, n); ++ ++ /* This bit of code is a bit tricky but it combines multiple ++ * checks into a single check. The prefix consists of the ++ * prefix plus zeros for the "bits" in the prefix. The index ++ * is the difference between the key and this value. From ++ * this we can actually derive several pieces of data. ++ * if !(index >> bits) ++ * we know the value is child index ++ * else ++ * we have a mismatch in skip bits and failed ++ */ ++ if (index >> n->bits) ++ break; + +- if (IS_LEAF(n)) { +- ret = check_leaf(tb, t, n, key, flp, res, fib_flags); +- if (ret > 0) +- goto backtrace; ++ /* we have found a leaf. Prefixes have already been compared */ ++ if (IS_LEAF(n)) + goto found; +- } +- +- cn = n; + +- /* +- * It's a tnode, and we can do some extra checks here if we +- * like, to avoid descending into a dead-end branch. +- * This tnode is in the parent's child array at index +- * key[p_pos..p_pos+p_bits] but potentially with some bits +- * chopped off, so in reality the index may be just a +- * subprefix, padded with zero at the end. +- * We can also take a look at any skipped bits in this +- * tnode - everything up to p_pos is supposed to be ok, +- * and the non-chopped bits of the index (se previous +- * paragraph) are also guaranteed ok, but the rest is +- * considered unknown. +- * +- * The skipped bits are key[pos+bits..cn->pos]. +- */ +- +- /* If current_prefix_length < pos+bits, we are already doing +- * actual prefix matching, which means everything from +- * pos+(bits-chopped_off) onward must be zero along some +- * branch of this subtree - otherwise there is *no* valid +- * prefix present. Here we can only check the skipped +- * bits. Remember, since we have already indexed into the +- * parent's child array, we know that the bits we chopped of +- * *are* zero. ++ /* only record pn and cindex if we are going to be chopping ++ * bits later. Otherwise we are just wasting cycles. + */ +- +- /* NOTA BENE: Checking only skipped bits +- for the new node here */ +- +- if (current_prefix_length < pos+bits) { +- if (tkey_extract_bits(cn->key, current_prefix_length, +- cn->pos - current_prefix_length) +- || !(cn->child[0])) +- goto backtrace; ++ if (index) { ++ pn = n; ++ cindex = index; + } + +- /* +- * If chopped_off=0, the index is fully validated and we +- * only need to look at the skipped bits for this, the new, +- * tnode. What we actually want to do is to find out if +- * these skipped bits match our key perfectly, or if we will +- * have to count on finding a matching prefix further down, +- * because if we do, we would like to have some way of +- * verifying the existence of such a prefix at this point. +- */ +- +- /* The only thing we can do at this point is to verify that +- * any such matching prefix can indeed be a prefix to our +- * key, and if the bits in the node we are inspecting that +- * do not match our key are not ZERO, this cannot be true. +- * Thus, find out where there is a mismatch (before cn->pos) +- * and verify that all the mismatching bits are zero in the +- * new tnode's key. +- */ ++ n = rcu_dereference(n->child[index]); ++ if (unlikely(!n)) ++ goto backtrace; ++ } + +- /* +- * Note: We aren't very concerned about the piece of +- * the key that precede pn->pos+pn->bits, since these +- * have already been checked. The bits after cn->pos +- * aren't checked since these are by definition +- * "unknown" at this point. Thus, what we want to see +- * is if we are about to enter the "prefix matching" +- * state, and in that case verify that the skipped +- * bits that will prevail throughout this subtree are +- * zero, as they have to be if we are to find a +- * matching prefix. ++ /* Step 2: Sort out leaves and begin backtracing for longest prefix */ ++ for (;;) { ++ /* record the pointer where our next node pointer is stored */ ++ struct tnode __rcu **cptr = n->child; ++ ++ /* This test verifies that none of the bits that differ ++ * between the key and the prefix exist in the region of ++ * the lsb and higher in the prefix. + */ ++ if (unlikely(prefix_mismatch(key, n))) ++ goto backtrace; + +- pref_mismatch = mask_pfx(cn->key ^ key, cn->pos); ++ /* exit out and process leaf */ ++ if (unlikely(IS_LEAF(n))) ++ break; + +- /* +- * In short: If skipped bits in this node do not match +- * the search key, enter the "prefix matching" +- * state.directly. ++ /* Don't bother recording parent info. Since we are in ++ * prefix match mode we will have to come back to wherever ++ * we started this traversal anyway + */ +- if (pref_mismatch) { +- /* fls(x) = __fls(x) + 1 */ +- int mp = KEYLENGTH - __fls(pref_mismatch) - 1; +- +- if (tkey_extract_bits(cn->key, mp, cn->pos - mp) != 0) +- goto backtrace; +- +- if (current_prefix_length >= cn->pos) +- current_prefix_length = mp; +- } +- +- pn = n; /* Descend */ +- chopped_off = 0; +- continue; + ++ while ((n = rcu_dereference(*cptr)) == NULL) { + backtrace: +- chopped_off++; +- +- /* As zero don't change the child key (cindex) */ +- while ((chopped_off <= pn->bits) +- && !(cindex & (1<<(chopped_off-1)))) +- chopped_off++; +- +- /* Decrease current_... with bits chopped off */ +- if (current_prefix_length > pn->pos + pn->bits - chopped_off) +- current_prefix_length = pn->pos + pn->bits +- - chopped_off; +- +- /* +- * Either we do the actual chop off according or if we have +- * chopped off all bits in this tnode walk up to our parent. +- */ +- +- if (chopped_off <= pn->bits) { +- cindex &= ~(1 << (chopped_off-1)); +- } else { +- struct tnode *parent = node_parent_rcu(pn); +- if (!parent) +- goto failed; +- +- /* Get Child's index */ +- cindex = tkey_extract_bits(pn->key, parent->pos, parent->bits); +- pn = parent; +- chopped_off = 0; +- + #ifdef CONFIG_IP_FIB_TRIE_STATS +- this_cpu_inc(stats->backtrack); ++ if (!n) ++ this_cpu_inc(stats->null_node_hit); + #endif +- goto backtrace; ++ /* If we are at cindex 0 there are no more bits for ++ * us to strip at this level so we must ascend back ++ * up one level to see if there are any more bits to ++ * be stripped there. ++ */ ++ while (!cindex) { ++ t_key pkey = pn->key; ++ ++ pn = node_parent_rcu(pn); ++ if (unlikely(!pn)) ++ goto failed; ++#ifdef CONFIG_IP_FIB_TRIE_STATS ++ this_cpu_inc(stats->backtrack); ++#endif ++ /* Get Child's index */ ++ cindex = get_index(pkey, pn); ++ } ++ ++ /* strip the least significant bit from the cindex */ ++ cindex &= cindex - 1; ++ ++ /* grab pointer for next child node */ ++ cptr = &pn->child[cindex]; + } + } +-failed: +- ret = 1; ++ + found: ++ /* Step 3: Process the leaf, if that fails fall back to backtracing */ ++ ret = check_leaf(tb, t, n, key, flp, res, fib_flags); ++ if (unlikely(ret > 0)) ++ goto backtrace; ++failed: + rcu_read_unlock(); + return ret; + } diff --git a/target/linux/generic/patches-3.18/080-07-fib_trie-Optimize-fib_find_node.patch b/target/linux/generic/patches-3.18/080-07-fib_trie-Optimize-fib_find_node.patch new file mode 100644 index 0000000..0193f75 --- /dev/null +++ b/target/linux/generic/patches-3.18/080-07-fib_trie-Optimize-fib_find_node.patch @@ -0,0 +1,64 @@ +From: Alexander Duyck +Date: Wed, 31 Dec 2014 10:56:00 -0800 +Subject: [PATCH] fib_trie: Optimize fib_find_node + +This patch makes use of the same features I made use of for +fib_table_lookup to streamline fib_find_node. The resultant code should be +smaller and run faster than the original. + +Signed-off-by: Alexander Duyck +Signed-off-by: David S. Miller +--- + +--- a/net/ipv4/fib_trie.c ++++ b/net/ipv4/fib_trie.c +@@ -892,28 +892,34 @@ static void insert_leaf_info(struct hlis + } + + /* rcu_read_lock needs to be hold by caller from readside */ +- + static struct tnode *fib_find_node(struct trie *t, u32 key) + { + struct tnode *n = rcu_dereference_rtnl(t->trie); +- int pos = 0; + +- while (n && IS_TNODE(n)) { +- if (tkey_sub_equals(n->key, pos, n->pos-pos, key)) { +- pos = n->pos + n->bits; +- n = tnode_get_child_rcu(n, +- tkey_extract_bits(key, +- n->pos, +- n->bits)); +- } else ++ while (n) { ++ unsigned long index = get_index(key, n); ++ ++ /* This bit of code is a bit tricky but it combines multiple ++ * checks into a single check. The prefix consists of the ++ * prefix plus zeros for the bits in the cindex. The index ++ * is the difference between the key and this value. From ++ * this we can actually derive several pieces of data. ++ * if !(index >> bits) ++ * we know the value is cindex ++ * else ++ * we have a mismatch in skip bits and failed ++ */ ++ if (index >> n->bits) ++ return NULL; ++ ++ /* we have found a leaf. Prefixes have already been compared */ ++ if (IS_LEAF(n)) + break; +- } +- /* Case we have found a leaf. Compare prefixes */ + +- if (n != NULL && IS_LEAF(n) && tkey_equals(key, n->key)) +- return n; ++ n = rcu_dereference_rtnl(n->child[index]); ++ } + +- return NULL; ++ return n; + } + + static void trie_rebalance(struct trie *t, struct tnode *tn) diff --git a/target/linux/generic/patches-3.18/080-08-fib_trie-Optimize-fib_table_insert.patch b/target/linux/generic/patches-3.18/080-08-fib_trie-Optimize-fib_table_insert.patch new file mode 100644 index 0000000..b328d2c --- /dev/null +++ b/target/linux/generic/patches-3.18/080-08-fib_trie-Optimize-fib_table_insert.patch @@ -0,0 +1,276 @@ +From: Alexander Duyck +Date: Wed, 31 Dec 2014 10:56:06 -0800 +Subject: [PATCH] fib_trie: Optimize fib_table_insert + +This patch updates the fib_table_insert function to take advantage of the +changes made to improve the performance of fib_table_lookup. As a result +the code should be smaller and run faster then the original. + +Signed-off-by: Alexander Duyck +Signed-off-by: David S. Miller +--- + +--- a/net/ipv4/fib_trie.c ++++ b/net/ipv4/fib_trie.c +@@ -222,31 +222,6 @@ static inline t_key tkey_extract_bits(t_ + return 0; + } + +-static inline int tkey_equals(t_key a, t_key b) +-{ +- return a == b; +-} +- +-static inline int tkey_sub_equals(t_key a, int offset, int bits, t_key b) +-{ +- if (bits == 0 || offset >= KEYLENGTH) +- return 1; +- bits = bits > KEYLENGTH ? KEYLENGTH : bits; +- return ((a ^ b) << offset) >> (KEYLENGTH - bits) == 0; +-} +- +-static inline int tkey_mismatch(t_key a, int offset, t_key b) +-{ +- t_key diff = a ^ b; +- int i = offset; +- +- if (!diff) +- return 0; +- while ((diff << i) >> (KEYLENGTH-1) == 0) +- i++; +- return i; +-} +- + /* + To understand this stuff, an understanding of keys and all their bits is + necessary. Every node in the trie has a key associated with it, but not +@@ -485,6 +460,15 @@ static void tnode_put_child_reorg(struct + rcu_assign_pointer(tn->child[i], n); + } + ++static void put_child_root(struct tnode *tp, struct trie *t, ++ t_key key, struct tnode *n) ++{ ++ if (tp) ++ put_child(tp, get_index(key, tp), n); ++ else ++ rcu_assign_pointer(t->trie, n); ++} ++ + #define MAX_WORK 10 + static struct tnode *resize(struct trie *t, struct tnode *tn) + { +@@ -959,138 +943,100 @@ static void trie_rebalance(struct trie * + + static struct list_head *fib_insert_node(struct trie *t, u32 key, int plen) + { +- int pos, newpos; +- struct tnode *tp = NULL, *tn = NULL; +- struct tnode *n; +- struct tnode *l; +- int missbit; + struct list_head *fa_head = NULL; ++ struct tnode *l, *n, *tp = NULL; + struct leaf_info *li; +- t_key cindex; + +- pos = 0; ++ li = leaf_info_new(plen); ++ if (!li) ++ return NULL; ++ fa_head = &li->falh; ++ + n = rtnl_dereference(t->trie); + + /* If we point to NULL, stop. Either the tree is empty and we should + * just put a new leaf in if, or we have reached an empty child slot, + * and we should just put our new leaf in that. +- * If we point to a T_TNODE, check if it matches our key. Note that +- * a T_TNODE might be skipping any number of bits - its 'pos' need +- * not be the parent's 'pos'+'bits'! +- * +- * If it does match the current key, get pos/bits from it, extract +- * the index from our key, push the T_TNODE and walk the tree. +- * +- * If it doesn't, we have to replace it with a new T_TNODE. + * +- * If we point to a T_LEAF, it might or might not have the same key +- * as we do. If it does, just change the value, update the T_LEAF's +- * value, and return it. +- * If it doesn't, we need to replace it with a T_TNODE. ++ * If we hit a node with a key that does't match then we should stop ++ * and create a new tnode to replace that node and insert ourselves ++ * and the other node into the new tnode. + */ ++ while (n) { ++ unsigned long index = get_index(key, n); + +- while (n && IS_TNODE(n)) { +- if (tkey_sub_equals(n->key, pos, n->pos-pos, key)) { +- tp = n; +- pos = n->pos + n->bits; +- n = tnode_get_child(n, +- tkey_extract_bits(key, +- n->pos, +- n->bits)); +- +- BUG_ON(n && node_parent(n) != tp); +- } else ++ /* This bit of code is a bit tricky but it combines multiple ++ * checks into a single check. The prefix consists of the ++ * prefix plus zeros for the "bits" in the prefix. The index ++ * is the difference between the key and this value. From ++ * this we can actually derive several pieces of data. ++ * if !(index >> bits) ++ * we know the value is child index ++ * else ++ * we have a mismatch in skip bits and failed ++ */ ++ if (index >> n->bits) + break; +- } +- +- /* +- * n ----> NULL, LEAF or TNODE +- * +- * tp is n's (parent) ----> NULL or TNODE +- */ + +- BUG_ON(tp && IS_LEAF(tp)); +- +- /* Case 1: n is a leaf. Compare prefixes */ +- +- if (n != NULL && IS_LEAF(n) && tkey_equals(key, n->key)) { +- li = leaf_info_new(plen); +- +- if (!li) +- return NULL; ++ /* we have found a leaf. Prefixes have already been compared */ ++ if (IS_LEAF(n)) { ++ /* Case 1: n is a leaf, and prefixes match*/ ++ insert_leaf_info(&n->list, li); ++ return fa_head; ++ } + +- fa_head = &li->falh; +- insert_leaf_info(&n->list, li); +- goto done; ++ tp = n; ++ n = rcu_dereference_rtnl(n->child[index]); + } +- l = leaf_new(key); +- +- if (!l) +- return NULL; + +- li = leaf_info_new(plen); +- +- if (!li) { +- node_free(l); ++ l = leaf_new(key); ++ if (!l) { ++ free_leaf_info(li); + return NULL; + } + +- fa_head = &li->falh; + insert_leaf_info(&l->list, li); + +- if (t->trie && n == NULL) { +- /* Case 2: n is NULL, and will just insert a new leaf */ +- +- node_set_parent(l, tp); +- +- cindex = tkey_extract_bits(key, tp->pos, tp->bits); +- put_child(tp, cindex, l); +- } else { +- /* Case 3: n is a LEAF or a TNODE and the key doesn't match. */ +- /* +- * Add a new tnode here +- * first tnode need some special handling +- */ ++ /* Case 2: n is a LEAF or a TNODE and the key doesn't match. ++ * ++ * Add a new tnode here ++ * first tnode need some special handling ++ * leaves us in position for handling as case 3 ++ */ ++ if (n) { ++ struct tnode *tn; ++ int newpos; + +- if (n) { +- pos = tp ? tp->pos+tp->bits : 0; +- newpos = tkey_mismatch(key, pos, n->key); +- tn = tnode_new(n->key, newpos, 1); +- } else { +- newpos = 0; +- tn = tnode_new(key, newpos, 1); /* First tnode */ +- } ++ newpos = KEYLENGTH - __fls(n->key ^ key) - 1; + ++ tn = tnode_new(key, newpos, 1); + if (!tn) { + free_leaf_info(li); + node_free(l); + return NULL; + } + +- node_set_parent(tn, tp); +- +- missbit = tkey_extract_bits(key, newpos, 1); +- put_child(tn, missbit, l); +- put_child(tn, 1-missbit, n); +- +- if (tp) { +- cindex = tkey_extract_bits(key, tp->pos, tp->bits); +- put_child(tp, cindex, tn); +- } else { +- rcu_assign_pointer(t->trie, tn); +- } ++ /* initialize routes out of node */ ++ NODE_INIT_PARENT(tn, tp); ++ put_child(tn, get_index(key, tn) ^ 1, n); ++ ++ /* start adding routes into the node */ ++ put_child_root(tp, t, key, tn); ++ node_set_parent(n, tn); + ++ /* parent now has a NULL spot where the leaf can go */ + tp = tn; + } + +- if (tp && tp->pos + tp->bits > 32) +- pr_warn("fib_trie tp=%p pos=%d, bits=%d, key=%0x plen=%d\n", +- tp, tp->pos, tp->bits, key, plen); +- +- /* Rebalance the trie */ ++ /* Case 3: n is NULL, and will just insert a new leaf */ ++ if (tp) { ++ NODE_INIT_PARENT(l, tp); ++ put_child(tp, get_index(key, tp), l); ++ trie_rebalance(t, tp); ++ } else { ++ rcu_assign_pointer(t->trie, l); ++ } + +- trie_rebalance(t, tp); +-done: + return fa_head; + } + +@@ -1470,11 +1416,11 @@ static void trie_leaf_remove(struct trie + pr_debug("entering trie_leaf_remove(%p)\n", l); + + if (tp) { +- t_key cindex = tkey_extract_bits(l->key, tp->pos, tp->bits); +- put_child(tp, cindex, NULL); ++ put_child(tp, get_index(l->key, tp), NULL); + trie_rebalance(t, tp); +- } else ++ } else { + RCU_INIT_POINTER(t->trie, NULL); ++ } + + node_free(l); + } diff --git a/target/linux/generic/patches-3.18/080-09-fib_trie-Update-meaning-of-pos-to-represent-unchecke.patch b/target/linux/generic/patches-3.18/080-09-fib_trie-Update-meaning-of-pos-to-represent-unchecke.patch new file mode 100644 index 0000000..a0d3476 --- /dev/null +++ b/target/linux/generic/patches-3.18/080-09-fib_trie-Update-meaning-of-pos-to-represent-unchecke.patch @@ -0,0 +1,346 @@ +From: Alexander Duyck +Date: Wed, 31 Dec 2014 10:56:12 -0800 +Subject: [PATCH] fib_trie: Update meaning of pos to represent unchecked + bits + +This change moves the pos value to the other side of the "bits" field. By +doing this it actually simplifies a significant amount of code in the trie. + +For example when halving a tree we know that the bit lost exists at +oldnode->pos, and if we inflate the tree the new bit being add is at +tn->pos. Previously to find those bits you would have to subtract pos and +bits from the keylength or start with a value of (1 << 31) and then shift +that. + +There are a number of spots throughout the code that benefit from this. In +the case of the hot-path searches the main advantage is that we can drop 2 +or more operations from the search path as we no longer need to compute the +value for the index to be shifted by and can instead just use the raw pos +value. + +In addition the tkey_extract_bits is now defunct and can be replaced by +get_index since the two operations were doing the same thing, but now +get_index does it much more quickly as it is only an xor and shift versus a +pair of shifts and a subtraction. + +Signed-off-by: Alexander Duyck +Signed-off-by: David S. Miller +--- + +--- a/net/ipv4/fib_trie.c ++++ b/net/ipv4/fib_trie.c +@@ -90,8 +90,7 @@ typedef unsigned int t_key; + #define IS_TNODE(n) ((n)->bits) + #define IS_LEAF(n) (!(n)->bits) + +-#define get_shift(_kv) (KEYLENGTH - (_kv)->pos - (_kv)->bits) +-#define get_index(_key, _kv) (((_key) ^ (_kv)->key) >> get_shift(_kv)) ++#define get_index(_key, _kv) (((_key) ^ (_kv)->key) >> (_kv)->pos) + + struct tnode { + t_key key; +@@ -209,81 +208,64 @@ static inline struct tnode *tnode_get_ch + return rcu_dereference_rtnl(tn->child[i]); + } + +-static inline t_key mask_pfx(t_key k, unsigned int l) +-{ +- return (l == 0) ? 0 : k >> (KEYLENGTH-l) << (KEYLENGTH-l); +-} +- +-static inline t_key tkey_extract_bits(t_key a, unsigned int offset, unsigned int bits) +-{ +- if (offset < KEYLENGTH) +- return ((t_key)(a << offset)) >> (KEYLENGTH - bits); +- else +- return 0; +-} +- +-/* +- To understand this stuff, an understanding of keys and all their bits is +- necessary. Every node in the trie has a key associated with it, but not +- all of the bits in that key are significant. +- +- Consider a node 'n' and its parent 'tp'. +- +- If n is a leaf, every bit in its key is significant. Its presence is +- necessitated by path compression, since during a tree traversal (when +- searching for a leaf - unless we are doing an insertion) we will completely +- ignore all skipped bits we encounter. Thus we need to verify, at the end of +- a potentially successful search, that we have indeed been walking the +- correct key path. +- +- Note that we can never "miss" the correct key in the tree if present by +- following the wrong path. Path compression ensures that segments of the key +- that are the same for all keys with a given prefix are skipped, but the +- skipped part *is* identical for each node in the subtrie below the skipped +- bit! trie_insert() in this implementation takes care of that - note the +- call to tkey_sub_equals() in trie_insert(). +- +- if n is an internal node - a 'tnode' here, the various parts of its key +- have many different meanings. +- +- Example: +- _________________________________________________________________ +- | i | i | i | i | i | i | i | N | N | N | S | S | S | S | S | C | +- ----------------------------------------------------------------- +- 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 +- +- _________________________________________________________________ +- | C | C | C | u | u | u | u | u | u | u | u | u | u | u | u | u | +- ----------------------------------------------------------------- +- 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 +- +- tp->pos = 7 +- tp->bits = 3 +- n->pos = 15 +- n->bits = 4 +- +- First, let's just ignore the bits that come before the parent tp, that is +- the bits from 0 to (tp->pos-1). They are *known* but at this point we do +- not use them for anything. +- +- The bits from (tp->pos) to (tp->pos + tp->bits - 1) - "N", above - are the +- index into the parent's child array. That is, they will be used to find +- 'n' among tp's children. +- +- The bits from (tp->pos + tp->bits) to (n->pos - 1) - "S" - are skipped bits +- for the node n. +- +- All the bits we have seen so far are significant to the node n. The rest +- of the bits are really not needed or indeed known in n->key. +- +- The bits from (n->pos) to (n->pos + n->bits - 1) - "C" - are the index into +- n's child array, and will of course be different for each child. +- +- +- The rest of the bits, from (n->pos + n->bits) onward, are completely unknown +- at this point. +- +-*/ ++/* To understand this stuff, an understanding of keys and all their bits is ++ * necessary. Every node in the trie has a key associated with it, but not ++ * all of the bits in that key are significant. ++ * ++ * Consider a node 'n' and its parent 'tp'. ++ * ++ * If n is a leaf, every bit in its key is significant. Its presence is ++ * necessitated by path compression, since during a tree traversal (when ++ * searching for a leaf - unless we are doing an insertion) we will completely ++ * ignore all skipped bits we encounter. Thus we need to verify, at the end of ++ * a potentially successful search, that we have indeed been walking the ++ * correct key path. ++ * ++ * Note that we can never "miss" the correct key in the tree if present by ++ * following the wrong path. Path compression ensures that segments of the key ++ * that are the same for all keys with a given prefix are skipped, but the ++ * skipped part *is* identical for each node in the subtrie below the skipped ++ * bit! trie_insert() in this implementation takes care of that. ++ * ++ * if n is an internal node - a 'tnode' here, the various parts of its key ++ * have many different meanings. ++ * ++ * Example: ++ * _________________________________________________________________ ++ * | i | i | i | i | i | i | i | N | N | N | S | S | S | S | S | C | ++ * ----------------------------------------------------------------- ++ * 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 ++ * ++ * _________________________________________________________________ ++ * | C | C | C | u | u | u | u | u | u | u | u | u | u | u | u | u | ++ * ----------------------------------------------------------------- ++ * 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 ++ * ++ * tp->pos = 22 ++ * tp->bits = 3 ++ * n->pos = 13 ++ * n->bits = 4 ++ * ++ * First, let's just ignore the bits that come before the parent tp, that is ++ * the bits from (tp->pos + tp->bits) to 31. They are *known* but at this ++ * point we do not use them for anything. ++ * ++ * The bits from (tp->pos) to (tp->pos + tp->bits - 1) - "N", above - are the ++ * index into the parent's child array. That is, they will be used to find ++ * 'n' among tp's children. ++ * ++ * The bits from (n->pos + n->bits) to (tn->pos - 1) - "S" - are skipped bits ++ * for the node n. ++ * ++ * All the bits we have seen so far are significant to the node n. The rest ++ * of the bits are really not needed or indeed known in n->key. ++ * ++ * The bits from (n->pos) to (n->pos + n->bits - 1) - "C" - are the index into ++ * n's child array, and will of course be different for each child. ++ * ++ * The rest of the bits, from 0 to (n->pos + n->bits), are completely unknown ++ * at this point. ++ */ + + static const int halve_threshold = 25; + static const int inflate_threshold = 50; +@@ -367,7 +349,7 @@ static struct tnode *leaf_new(t_key key) + * as the nodes are searched + */ + l->key = key; +- l->pos = KEYLENGTH; ++ l->pos = 0; + /* set bits to 0 indicating we are not a tnode */ + l->bits = 0; + +@@ -400,7 +382,7 @@ static struct tnode *tnode_new(t_key key + tn->parent = NULL; + tn->pos = pos; + tn->bits = bits; +- tn->key = mask_pfx(key, pos); ++ tn->key = (shift < KEYLENGTH) ? (key >> shift) << shift : 0; + tn->full_children = 0; + tn->empty_children = 1<pos == (tn->pos + tn->bits)); ++ return n && ((n->pos + n->bits) == tn->pos) && IS_TNODE(n); + } + + static inline void put_child(struct tnode *tn, int i, +@@ -641,11 +621,12 @@ static struct tnode *inflate(struct trie + { + int olen = tnode_child_length(oldtnode); + struct tnode *tn; ++ t_key m; + int i; + + pr_debug("In inflate\n"); + +- tn = tnode_new(oldtnode->key, oldtnode->pos, oldtnode->bits + 1); ++ tn = tnode_new(oldtnode->key, oldtnode->pos - 1, oldtnode->bits + 1); + + if (!tn) + return ERR_PTR(-ENOMEM); +@@ -656,21 +637,18 @@ static struct tnode *inflate(struct trie + * fails. In case of failure we return the oldnode and inflate + * of tnode is ignored. + */ ++ for (i = 0, m = 1u << tn->pos; i < olen; i++) { ++ struct tnode *inode = tnode_get_child(oldtnode, i); + +- for (i = 0; i < olen; i++) { +- struct tnode *inode; +- +- inode = tnode_get_child(oldtnode, i); +- if (tnode_full(oldtnode, inode) && inode->bits > 1) { ++ if (tnode_full(oldtnode, inode) && (inode->bits > 1)) { + struct tnode *left, *right; +- t_key m = ~0U << (KEYLENGTH - 1) >> inode->pos; + +- left = tnode_new(inode->key&(~m), inode->pos + 1, ++ left = tnode_new(inode->key & ~m, inode->pos, + inode->bits - 1); + if (!left) + goto nomem; + +- right = tnode_new(inode->key|m, inode->pos + 1, ++ right = tnode_new(inode->key | m, inode->pos, + inode->bits - 1); + + if (!right) { +@@ -694,9 +672,7 @@ static struct tnode *inflate(struct trie + + /* A leaf or an internal node with skipped bits */ + if (!tnode_full(oldtnode, inode)) { +- put_child(tn, +- tkey_extract_bits(inode->key, tn->pos, tn->bits), +- inode); ++ put_child(tn, get_index(inode->key, tn), inode); + continue; + } + +@@ -767,7 +743,7 @@ static struct tnode *halve(struct trie * + + pr_debug("In halve\n"); + +- tn = tnode_new(oldtnode->key, oldtnode->pos, oldtnode->bits - 1); ++ tn = tnode_new(oldtnode->key, oldtnode->pos + 1, oldtnode->bits - 1); + + if (!tn) + return ERR_PTR(-ENOMEM); +@@ -787,7 +763,7 @@ static struct tnode *halve(struct trie * + if (left && right) { + struct tnode *newn; + +- newn = tnode_new(left->key, tn->pos + tn->bits, 1); ++ newn = tnode_new(left->key, oldtnode->pos, 1); + + if (!newn) + goto nomem; +@@ -915,7 +891,7 @@ static void trie_rebalance(struct trie * + key = tn->key; + + while (tn != NULL && (tp = node_parent(tn)) != NULL) { +- cindex = tkey_extract_bits(key, tp->pos, tp->bits); ++ cindex = get_index(key, tp); + wasfull = tnode_full(tp, tnode_get_child(tp, cindex)); + tn = resize(t, tn); + +@@ -1005,11 +981,8 @@ static struct list_head *fib_insert_node + */ + if (n) { + struct tnode *tn; +- int newpos; +- +- newpos = KEYLENGTH - __fls(n->key ^ key) - 1; + +- tn = tnode_new(key, newpos, 1); ++ tn = tnode_new(key, __fls(key ^ n->key), 1); + if (!tn) { + free_leaf_info(li); + node_free(l); +@@ -1559,12 +1532,7 @@ static int trie_flush_leaf(struct tnode + static struct tnode *leaf_walk_rcu(struct tnode *p, struct tnode *c) + { + do { +- t_key idx; +- +- if (c) +- idx = tkey_extract_bits(c->key, p->pos, p->bits) + 1; +- else +- idx = 0; ++ t_key idx = c ? idx = get_index(c->key, p) + 1 : 0; + + while (idx < 1u << p->bits) { + c = tnode_get_child_rcu(p, idx++); +@@ -1851,7 +1819,7 @@ rescan: + /* Current node exhausted, pop back up */ + p = node_parent_rcu(tn); + if (p) { +- cindex = tkey_extract_bits(tn->key, p->pos, p->bits)+1; ++ cindex = get_index(tn->key, p) + 1; + tn = p; + --iter->depth; + goto rescan; +@@ -2186,10 +2154,10 @@ static int fib_trie_seq_show(struct seq_ + if (IS_TNODE(n)) { + __be32 prf = htonl(n->key); + +- seq_indent(seq, iter->depth - 1); +- seq_printf(seq, " +-- %pI4/%d %d %d %d\n", +- &prf, n->pos, n->bits, n->full_children, +- n->empty_children); ++ seq_indent(seq, iter->depth-1); ++ seq_printf(seq, " +-- %pI4/%zu %u %u %u\n", ++ &prf, KEYLENGTH - n->pos - n->bits, n->bits, ++ n->full_children, n->empty_children); + } else { + struct leaf_info *li; + __be32 val = htonl(n->key); diff --git a/target/linux/generic/patches-3.18/080-10-fib_trie-Use-unsigned-long-for-anything-dealing-with.patch b/target/linux/generic/patches-3.18/080-10-fib_trie-Use-unsigned-long-for-anything-dealing-with.patch new file mode 100644 index 0000000..487a25f --- /dev/null +++ b/target/linux/generic/patches-3.18/080-10-fib_trie-Use-unsigned-long-for-anything-dealing-with.patch @@ -0,0 +1,186 @@ +From: Alexander Duyck +Date: Wed, 31 Dec 2014 10:56:18 -0800 +Subject: [PATCH] fib_trie: Use unsigned long for anything dealing with a + shift by bits + +This change makes it so that anything that can be shifted by, or compared +to a value shifted by bits is updated to be an unsigned long. This is +mostly a precaution against an insanely huge address space that somehow +starts coming close to the 2^32 root node size which would require +something like 1.5 billion addresses. + +I chose unsigned long instead of unsigned long long since I do not believe +it is possible to allocate a 32 bit tnode on a 32 bit system as the memory +consumed would be 16GB + 28B which exceeds the addressible space for any +one process. + +Signed-off-by: Alexander Duyck +Signed-off-by: David S. Miller +--- + +--- a/net/ipv4/fib_trie.c ++++ b/net/ipv4/fib_trie.c +@@ -146,8 +146,8 @@ struct trie { + #endif + }; + +-static void tnode_put_child_reorg(struct tnode *tn, int i, struct tnode *n, +- int wasfull); ++static void tnode_put_child_reorg(struct tnode *tn, unsigned long i, ++ struct tnode *n, int wasfull); + static struct tnode *resize(struct trie *t, struct tnode *tn); + static struct tnode *inflate(struct trie *t, struct tnode *tn); + static struct tnode *halve(struct trie *t, struct tnode *tn); +@@ -183,25 +183,23 @@ static inline void node_set_parent(struc + /* This provides us with the number of children in this node, in the case of a + * leaf this will return 0 meaning none of the children are accessible. + */ +-static inline int tnode_child_length(const struct tnode *tn) ++static inline unsigned long tnode_child_length(const struct tnode *tn) + { + return (1ul << tn->bits) & ~(1ul); + } + +-/* +- * caller must hold RTNL +- */ +-static inline struct tnode *tnode_get_child(const struct tnode *tn, unsigned int i) ++/* caller must hold RTNL */ ++static inline struct tnode *tnode_get_child(const struct tnode *tn, ++ unsigned long i) + { + BUG_ON(i >= tnode_child_length(tn)); + + return rtnl_dereference(tn->child[i]); + } + +-/* +- * caller must hold RCU read lock or RTNL +- */ +-static inline struct tnode *tnode_get_child_rcu(const struct tnode *tn, unsigned int i) ++/* caller must hold RCU read lock or RTNL */ ++static inline struct tnode *tnode_get_child_rcu(const struct tnode *tn, ++ unsigned long i) + { + BUG_ON(i >= tnode_child_length(tn)); + +@@ -400,7 +398,7 @@ static inline int tnode_full(const struc + return n && ((n->pos + n->bits) == tn->pos) && IS_TNODE(n); + } + +-static inline void put_child(struct tnode *tn, int i, ++static inline void put_child(struct tnode *tn, unsigned long i, + struct tnode *n) + { + tnode_put_child_reorg(tn, i, n, -1); +@@ -411,13 +409,13 @@ static inline void put_child(struct tnod + * Update the value of full_children and empty_children. + */ + +-static void tnode_put_child_reorg(struct tnode *tn, int i, struct tnode *n, +- int wasfull) ++static void tnode_put_child_reorg(struct tnode *tn, unsigned long i, ++ struct tnode *n, int wasfull) + { + struct tnode *chi = rtnl_dereference(tn->child[i]); + int isfull; + +- BUG_ON(i >= 1<bits); ++ BUG_ON(i >= tnode_child_length(tn)); + + /* update emptyChildren */ + if (n == NULL && chi != NULL) +@@ -607,10 +605,10 @@ no_children: + static void tnode_clean_free(struct tnode *tn) + { + struct tnode *tofree; +- int i; ++ unsigned long i; + + for (i = 0; i < tnode_child_length(tn); i++) { +- tofree = rtnl_dereference(tn->child[i]); ++ tofree = tnode_get_child(tn, i); + if (tofree) + node_free(tofree); + } +@@ -619,10 +617,10 @@ static void tnode_clean_free(struct tnod + + static struct tnode *inflate(struct trie *t, struct tnode *oldtnode) + { +- int olen = tnode_child_length(oldtnode); ++ unsigned long olen = tnode_child_length(oldtnode); + struct tnode *tn; ++ unsigned long i; + t_key m; +- int i; + + pr_debug("In inflate\n"); + +@@ -664,7 +662,7 @@ static struct tnode *inflate(struct trie + for (i = 0; i < olen; i++) { + struct tnode *inode = tnode_get_child(oldtnode, i); + struct tnode *left, *right; +- int size, j; ++ unsigned long size, j; + + /* An empty child */ + if (inode == NULL) +@@ -737,7 +735,7 @@ nomem: + + static struct tnode *halve(struct trie *t, struct tnode *oldtnode) + { +- int olen = tnode_child_length(oldtnode); ++ unsigned long olen = tnode_child_length(oldtnode); + struct tnode *tn, *left, *right; + int i; + +@@ -1532,9 +1530,9 @@ static int trie_flush_leaf(struct tnode + static struct tnode *leaf_walk_rcu(struct tnode *p, struct tnode *c) + { + do { +- t_key idx = c ? idx = get_index(c->key, p) + 1 : 0; ++ unsigned long idx = c ? idx = get_index(c->key, p) + 1 : 0; + +- while (idx < 1u << p->bits) { ++ while (idx < tnode_child_length(p)) { + c = tnode_get_child_rcu(p, idx++); + if (!c) + continue; +@@ -1786,8 +1784,8 @@ struct fib_trie_iter { + + static struct tnode *fib_trie_get_next(struct fib_trie_iter *iter) + { ++ unsigned long cindex = iter->index; + struct tnode *tn = iter->tnode; +- unsigned int cindex = iter->index; + struct tnode *p; + + /* A single entry routing table */ +@@ -1797,7 +1795,7 @@ static struct tnode *fib_trie_get_next(s + pr_debug("get_next iter={node=%p index=%d depth=%d}\n", + iter->tnode, iter->index, iter->depth); + rescan: +- while (cindex < (1<bits)) { ++ while (cindex < tnode_child_length(tn)) { + struct tnode *n = tnode_get_child_rcu(tn, cindex); + + if (n) { +@@ -1874,15 +1872,16 @@ static void trie_collect_stats(struct tr + hlist_for_each_entry_rcu(li, &n->list, hlist) + ++s->prefixes; + } else { +- int i; ++ unsigned long i; + + s->tnodes++; + if (n->bits < MAX_STAT_DEPTH) + s->nodesizes[n->bits]++; + +- for (i = 0; i < tnode_child_length(n); i++) ++ for (i = 0; i < tnode_child_length(n); i++) { + if (!rcu_access_pointer(n->child[i])) + s->nullpointers++; ++ } + } + } + rcu_read_unlock(); diff --git a/target/linux/generic/patches-3.18/080-11-fib_trie-Push-rcu_read_lock-unlock-to-callers.patch b/target/linux/generic/patches-3.18/080-11-fib_trie-Push-rcu_read_lock-unlock-to-callers.patch new file mode 100644 index 0000000..b36bcd8 --- /dev/null +++ b/target/linux/generic/patches-3.18/080-11-fib_trie-Push-rcu_read_lock-unlock-to-callers.patch @@ -0,0 +1,403 @@ +From: Alexander Duyck +Date: Wed, 31 Dec 2014 10:56:24 -0800 +Subject: [PATCH] fib_trie: Push rcu_read_lock/unlock to callers + +This change is to start cleaning up some of the rcu_read_lock/unlock +handling. I realized while reviewing the code there are several spots that +I don't believe are being handled correctly or are masking warnings by +locally calling rcu_read_lock/unlock instead of calling them at the correct +level. + +A common example is a call to fib_get_table followed by fib_table_lookup. +The rcu_read_lock/unlock ought to wrap both but there are several spots where +they were not wrapped. + +Signed-off-by: Alexander Duyck +Signed-off-by: David S. Miller +--- + +--- a/include/net/ip_fib.h ++++ b/include/net/ip_fib.h +@@ -222,16 +222,19 @@ static inline struct fib_table *fib_new_ + static inline int fib_lookup(struct net *net, const struct flowi4 *flp, + struct fib_result *res) + { +- struct fib_table *table; ++ int err = -ENETUNREACH; + +- table = fib_get_table(net, RT_TABLE_LOCAL); +- if (!fib_table_lookup(table, flp, res, FIB_LOOKUP_NOREF)) +- return 0; +- +- table = fib_get_table(net, RT_TABLE_MAIN); +- if (!fib_table_lookup(table, flp, res, FIB_LOOKUP_NOREF)) +- return 0; +- return -ENETUNREACH; ++ rcu_read_lock(); ++ ++ if (!fib_table_lookup(fib_get_table(net, RT_TABLE_LOCAL), flp, res, ++ FIB_LOOKUP_NOREF) || ++ !fib_table_lookup(fib_get_table(net, RT_TABLE_MAIN), flp, res, ++ FIB_LOOKUP_NOREF)) ++ err = 0; ++ ++ rcu_read_unlock(); ++ ++ return err; + } + + #else /* CONFIG_IP_MULTIPLE_TABLES */ +@@ -247,20 +250,25 @@ static inline int fib_lookup(struct net + struct fib_result *res) + { + if (!net->ipv4.fib_has_custom_rules) { ++ int err = -ENETUNREACH; ++ ++ rcu_read_lock(); ++ + res->tclassid = 0; +- if (net->ipv4.fib_local && +- !fib_table_lookup(net->ipv4.fib_local, flp, res, +- FIB_LOOKUP_NOREF)) +- return 0; +- if (net->ipv4.fib_main && +- !fib_table_lookup(net->ipv4.fib_main, flp, res, +- FIB_LOOKUP_NOREF)) +- return 0; +- if (net->ipv4.fib_default && +- !fib_table_lookup(net->ipv4.fib_default, flp, res, +- FIB_LOOKUP_NOREF)) +- return 0; +- return -ENETUNREACH; ++ if ((net->ipv4.fib_local && ++ !fib_table_lookup(net->ipv4.fib_local, flp, res, ++ FIB_LOOKUP_NOREF)) || ++ (net->ipv4.fib_main && ++ !fib_table_lookup(net->ipv4.fib_main, flp, res, ++ FIB_LOOKUP_NOREF)) || ++ (net->ipv4.fib_default && ++ !fib_table_lookup(net->ipv4.fib_default, flp, res, ++ FIB_LOOKUP_NOREF))) ++ err = 0; ++ ++ rcu_read_unlock(); ++ ++ return err; + } + return __fib_lookup(net, flp, res); + } +--- a/net/ipv4/fib_frontend.c ++++ b/net/ipv4/fib_frontend.c +@@ -109,6 +109,7 @@ struct fib_table *fib_new_table(struct n + return tb; + } + ++/* caller must hold either rtnl or rcu read lock */ + struct fib_table *fib_get_table(struct net *net, u32 id) + { + struct fib_table *tb; +@@ -119,15 +120,11 @@ struct fib_table *fib_get_table(struct n + id = RT_TABLE_MAIN; + h = id & (FIB_TABLE_HASHSZ - 1); + +- rcu_read_lock(); + head = &net->ipv4.fib_table_hash[h]; + hlist_for_each_entry_rcu(tb, head, tb_hlist) { +- if (tb->tb_id == id) { +- rcu_read_unlock(); ++ if (tb->tb_id == id) + return tb; +- } + } +- rcu_read_unlock(); + return NULL; + } + #endif /* CONFIG_IP_MULTIPLE_TABLES */ +@@ -167,16 +164,18 @@ static inline unsigned int __inet_dev_ad + if (ipv4_is_multicast(addr)) + return RTN_MULTICAST; + ++ rcu_read_lock(); ++ + local_table = fib_get_table(net, RT_TABLE_LOCAL); + if (local_table) { + ret = RTN_UNICAST; +- rcu_read_lock(); + if (!fib_table_lookup(local_table, &fl4, &res, FIB_LOOKUP_NOREF)) { + if (!dev || dev == res.fi->fib_dev) + ret = res.type; + } +- rcu_read_unlock(); + } ++ ++ rcu_read_unlock(); + return ret; + } + +@@ -919,7 +918,7 @@ void fib_del_ifaddr(struct in_ifaddr *if + #undef BRD1_OK + } + +-static void nl_fib_lookup(struct fib_result_nl *frn, struct fib_table *tb) ++static void nl_fib_lookup(struct net *net, struct fib_result_nl *frn) + { + + struct fib_result res; +@@ -929,6 +928,11 @@ static void nl_fib_lookup(struct fib_res + .flowi4_tos = frn->fl_tos, + .flowi4_scope = frn->fl_scope, + }; ++ struct fib_table *tb; ++ ++ rcu_read_lock(); ++ ++ tb = fib_get_table(net, frn->tb_id_in); + + frn->err = -ENOENT; + if (tb) { +@@ -945,6 +949,8 @@ static void nl_fib_lookup(struct fib_res + } + local_bh_enable(); + } ++ ++ rcu_read_unlock(); + } + + static void nl_fib_input(struct sk_buff *skb) +@@ -952,7 +958,6 @@ static void nl_fib_input(struct sk_buff + struct net *net; + struct fib_result_nl *frn; + struct nlmsghdr *nlh; +- struct fib_table *tb; + u32 portid; + + net = sock_net(skb->sk); +@@ -967,9 +972,7 @@ static void nl_fib_input(struct sk_buff + nlh = nlmsg_hdr(skb); + + frn = (struct fib_result_nl *) nlmsg_data(nlh); +- tb = fib_get_table(net, frn->tb_id_in); +- +- nl_fib_lookup(frn, tb); ++ nl_fib_lookup(net, frn); + + portid = NETLINK_CB(skb).portid; /* netlink portid */ + NETLINK_CB(skb).portid = 0; /* from kernel */ +--- a/net/ipv4/fib_rules.c ++++ b/net/ipv4/fib_rules.c +@@ -81,27 +81,25 @@ static int fib4_rule_action(struct fib_r + break; + + case FR_ACT_UNREACHABLE: +- err = -ENETUNREACH; +- goto errout; ++ return -ENETUNREACH; + + case FR_ACT_PROHIBIT: +- err = -EACCES; +- goto errout; ++ return -EACCES; + + case FR_ACT_BLACKHOLE: + default: +- err = -EINVAL; +- goto errout; ++ return -EINVAL; + } + ++ rcu_read_lock(); ++ + tbl = fib_get_table(rule->fr_net, rule->table); +- if (!tbl) +- goto errout; ++ if (tbl) ++ err = fib_table_lookup(tbl, &flp->u.ip4, ++ (struct fib_result *)arg->result, ++ arg->flags); + +- err = fib_table_lookup(tbl, &flp->u.ip4, (struct fib_result *) arg->result, arg->flags); +- if (err > 0) +- err = -EAGAIN; +-errout: ++ rcu_read_unlock(); + return err; + } + +--- a/net/ipv4/fib_trie.c ++++ b/net/ipv4/fib_trie.c +@@ -1181,72 +1181,6 @@ err: + return err; + } + +-/* should be called with rcu_read_lock */ +-static int check_leaf(struct fib_table *tb, struct trie *t, struct tnode *l, +- t_key key, const struct flowi4 *flp, +- struct fib_result *res, int fib_flags) +-{ +- struct leaf_info *li; +- struct hlist_head *hhead = &l->list; +- +- hlist_for_each_entry_rcu(li, hhead, hlist) { +- struct fib_alias *fa; +- +- if (l->key != (key & li->mask_plen)) +- continue; +- +- list_for_each_entry_rcu(fa, &li->falh, fa_list) { +- struct fib_info *fi = fa->fa_info; +- int nhsel, err; +- +- if (fa->fa_tos && fa->fa_tos != flp->flowi4_tos) +- continue; +- if (fi->fib_dead) +- continue; +- if (fa->fa_info->fib_scope < flp->flowi4_scope) +- continue; +- fib_alias_accessed(fa); +- err = fib_props[fa->fa_type].error; +- if (unlikely(err < 0)) { +-#ifdef CONFIG_IP_FIB_TRIE_STATS +- this_cpu_inc(t->stats->semantic_match_passed); +-#endif +- return err; +- } +- if (fi->fib_flags & RTNH_F_DEAD) +- continue; +- for (nhsel = 0; nhsel < fi->fib_nhs; nhsel++) { +- const struct fib_nh *nh = &fi->fib_nh[nhsel]; +- +- if (nh->nh_flags & RTNH_F_DEAD) +- continue; +- if (flp->flowi4_oif && flp->flowi4_oif != nh->nh_oif) +- continue; +- +-#ifdef CONFIG_IP_FIB_TRIE_STATS +- this_cpu_inc(t->stats->semantic_match_passed); +-#endif +- res->prefixlen = li->plen; +- res->nh_sel = nhsel; +- res->type = fa->fa_type; +- res->scope = fi->fib_scope; +- res->fi = fi; +- res->table = tb; +- res->fa_head = &li->falh; +- if (!(fib_flags & FIB_LOOKUP_NOREF)) +- atomic_inc(&fi->fib_clntref); +- return 0; +- } +- } +- +-#ifdef CONFIG_IP_FIB_TRIE_STATS +- this_cpu_inc(t->stats->semantic_match_miss); +-#endif +- } +- +- return 1; +-} +- + static inline t_key prefix_mismatch(t_key key, struct tnode *n) + { + t_key prefix = n->key; +@@ -1254,6 +1188,7 @@ static inline t_key prefix_mismatch(t_ke + return (key ^ prefix) & (prefix | -prefix); + } + ++/* should be called with rcu_read_lock */ + int fib_table_lookup(struct fib_table *tb, const struct flowi4 *flp, + struct fib_result *res, int fib_flags) + { +@@ -1263,14 +1198,12 @@ int fib_table_lookup(struct fib_table *t + #endif + const t_key key = ntohl(flp->daddr); + struct tnode *n, *pn; ++ struct leaf_info *li; + t_key cindex; +- int ret = 1; +- +- rcu_read_lock(); + + n = rcu_dereference(t->trie); + if (!n) +- goto failed; ++ return -EAGAIN; + + #ifdef CONFIG_IP_FIB_TRIE_STATS + this_cpu_inc(stats->gets); +@@ -1350,7 +1283,7 @@ backtrace: + + pn = node_parent_rcu(pn); + if (unlikely(!pn)) +- goto failed; ++ return -EAGAIN; + #ifdef CONFIG_IP_FIB_TRIE_STATS + this_cpu_inc(stats->backtrack); + #endif +@@ -1368,12 +1301,62 @@ backtrace: + + found: + /* Step 3: Process the leaf, if that fails fall back to backtracing */ +- ret = check_leaf(tb, t, n, key, flp, res, fib_flags); +- if (unlikely(ret > 0)) +- goto backtrace; +-failed: +- rcu_read_unlock(); +- return ret; ++ hlist_for_each_entry_rcu(li, &n->list, hlist) { ++ struct fib_alias *fa; ++ ++ if ((key ^ n->key) & li->mask_plen) ++ continue; ++ ++ list_for_each_entry_rcu(fa, &li->falh, fa_list) { ++ struct fib_info *fi = fa->fa_info; ++ int nhsel, err; ++ ++ if (fa->fa_tos && fa->fa_tos != flp->flowi4_tos) ++ continue; ++ if (fi->fib_dead) ++ continue; ++ if (fa->fa_info->fib_scope < flp->flowi4_scope) ++ continue; ++ fib_alias_accessed(fa); ++ err = fib_props[fa->fa_type].error; ++ if (unlikely(err < 0)) { ++#ifdef CONFIG_IP_FIB_TRIE_STATS ++ this_cpu_inc(stats->semantic_match_passed); ++#endif ++ return err; ++ } ++ if (fi->fib_flags & RTNH_F_DEAD) ++ continue; ++ for (nhsel = 0; nhsel < fi->fib_nhs; nhsel++) { ++ const struct fib_nh *nh = &fi->fib_nh[nhsel]; ++ ++ if (nh->nh_flags & RTNH_F_DEAD) ++ continue; ++ if (flp->flowi4_oif && flp->flowi4_oif != nh->nh_oif) ++ continue; ++ ++ if (!(fib_flags & FIB_LOOKUP_NOREF)) ++ atomic_inc(&fi->fib_clntref); ++ ++ res->prefixlen = li->plen; ++ res->nh_sel = nhsel; ++ res->type = fa->fa_type; ++ res->scope = fi->fib_scope; ++ res->fi = fi; ++ res->table = tb; ++ res->fa_head = &li->falh; ++#ifdef CONFIG_IP_FIB_TRIE_STATS ++ this_cpu_inc(stats->semantic_match_passed); ++#endif ++ return err; ++ } ++ } ++ ++#ifdef CONFIG_IP_FIB_TRIE_STATS ++ this_cpu_inc(stats->semantic_match_miss); ++#endif ++ } ++ goto backtrace; + } + EXPORT_SYMBOL_GPL(fib_table_lookup); + diff --git a/target/linux/generic/patches-3.18/080-12-fib_trie-Move-resize-to-after-inflate-halve.patch b/target/linux/generic/patches-3.18/080-12-fib_trie-Move-resize-to-after-inflate-halve.patch new file mode 100644 index 0000000..a373add --- /dev/null +++ b/target/linux/generic/patches-3.18/080-12-fib_trie-Move-resize-to-after-inflate-halve.patch @@ -0,0 +1,345 @@ +From: Alexander Duyck +Date: Wed, 31 Dec 2014 10:56:31 -0800 +Subject: [PATCH] fib_trie: Move resize to after inflate/halve + +This change consists of a cut/paste of resize to behind inflate and halve +so that I could remove the two function prototypes. + +Signed-off-by: Alexander Duyck +Signed-off-by: David S. Miller +--- + +--- a/net/ipv4/fib_trie.c ++++ b/net/ipv4/fib_trie.c +@@ -149,8 +149,6 @@ struct trie { + static void tnode_put_child_reorg(struct tnode *tn, unsigned long i, + struct tnode *n, int wasfull); + static struct tnode *resize(struct trie *t, struct tnode *tn); +-static struct tnode *inflate(struct trie *t, struct tnode *tn); +-static struct tnode *halve(struct trie *t, struct tnode *tn); + /* tnodes to free after resize(); protected by RTNL */ + static struct callback_head *tnode_free_head; + static size_t tnode_free_size; +@@ -447,161 +445,6 @@ static void put_child_root(struct tnode + rcu_assign_pointer(t->trie, n); + } + +-#define MAX_WORK 10 +-static struct tnode *resize(struct trie *t, struct tnode *tn) +-{ +- struct tnode *old_tn, *n = NULL; +- int inflate_threshold_use; +- int halve_threshold_use; +- int max_work; +- +- if (!tn) +- return NULL; +- +- pr_debug("In tnode_resize %p inflate_threshold=%d threshold=%d\n", +- tn, inflate_threshold, halve_threshold); +- +- /* No children */ +- if (tn->empty_children > (tnode_child_length(tn) - 1)) +- goto no_children; +- +- /* One child */ +- if (tn->empty_children == (tnode_child_length(tn) - 1)) +- goto one_child; +- /* +- * Double as long as the resulting node has a number of +- * nonempty nodes that are above the threshold. +- */ +- +- /* +- * From "Implementing a dynamic compressed trie" by Stefan Nilsson of +- * the Helsinki University of Technology and Matti Tikkanen of Nokia +- * Telecommunications, page 6: +- * "A node is doubled if the ratio of non-empty children to all +- * children in the *doubled* node is at least 'high'." +- * +- * 'high' in this instance is the variable 'inflate_threshold'. It +- * is expressed as a percentage, so we multiply it with +- * tnode_child_length() and instead of multiplying by 2 (since the +- * child array will be doubled by inflate()) and multiplying +- * the left-hand side by 100 (to handle the percentage thing) we +- * multiply the left-hand side by 50. +- * +- * The left-hand side may look a bit weird: tnode_child_length(tn) +- * - tn->empty_children is of course the number of non-null children +- * in the current node. tn->full_children is the number of "full" +- * children, that is non-null tnodes with a skip value of 0. +- * All of those will be doubled in the resulting inflated tnode, so +- * we just count them one extra time here. +- * +- * A clearer way to write this would be: +- * +- * to_be_doubled = tn->full_children; +- * not_to_be_doubled = tnode_child_length(tn) - tn->empty_children - +- * tn->full_children; +- * +- * new_child_length = tnode_child_length(tn) * 2; +- * +- * new_fill_factor = 100 * (not_to_be_doubled + 2*to_be_doubled) / +- * new_child_length; +- * if (new_fill_factor >= inflate_threshold) +- * +- * ...and so on, tho it would mess up the while () loop. +- * +- * anyway, +- * 100 * (not_to_be_doubled + 2*to_be_doubled) / new_child_length >= +- * inflate_threshold +- * +- * avoid a division: +- * 100 * (not_to_be_doubled + 2*to_be_doubled) >= +- * inflate_threshold * new_child_length +- * +- * expand not_to_be_doubled and to_be_doubled, and shorten: +- * 100 * (tnode_child_length(tn) - tn->empty_children + +- * tn->full_children) >= inflate_threshold * new_child_length +- * +- * expand new_child_length: +- * 100 * (tnode_child_length(tn) - tn->empty_children + +- * tn->full_children) >= +- * inflate_threshold * tnode_child_length(tn) * 2 +- * +- * shorten again: +- * 50 * (tn->full_children + tnode_child_length(tn) - +- * tn->empty_children) >= inflate_threshold * +- * tnode_child_length(tn) +- * +- */ +- +- /* Keep root node larger */ +- +- if (!node_parent(tn)) { +- inflate_threshold_use = inflate_threshold_root; +- halve_threshold_use = halve_threshold_root; +- } else { +- inflate_threshold_use = inflate_threshold; +- halve_threshold_use = halve_threshold; +- } +- +- max_work = MAX_WORK; +- while ((tn->full_children > 0 && max_work-- && +- 50 * (tn->full_children + tnode_child_length(tn) +- - tn->empty_children) +- >= inflate_threshold_use * tnode_child_length(tn))) { +- +- old_tn = tn; +- tn = inflate(t, tn); +- +- if (IS_ERR(tn)) { +- tn = old_tn; +-#ifdef CONFIG_IP_FIB_TRIE_STATS +- this_cpu_inc(t->stats->resize_node_skipped); +-#endif +- break; +- } +- } +- +- /* Return if at least one inflate is run */ +- if (max_work != MAX_WORK) +- return tn; +- +- /* +- * Halve as long as the number of empty children in this +- * node is above threshold. +- */ +- +- max_work = MAX_WORK; +- while (tn->bits > 1 && max_work-- && +- 100 * (tnode_child_length(tn) - tn->empty_children) < +- halve_threshold_use * tnode_child_length(tn)) { +- +- old_tn = tn; +- tn = halve(t, tn); +- if (IS_ERR(tn)) { +- tn = old_tn; +-#ifdef CONFIG_IP_FIB_TRIE_STATS +- this_cpu_inc(t->stats->resize_node_skipped); +-#endif +- break; +- } +- } +- +- +- /* Only one child remains */ +- if (tn->empty_children == (tnode_child_length(tn) - 1)) { +- unsigned long i; +-one_child: +- for (i = tnode_child_length(tn); !n && i;) +- n = tnode_get_child(tn, --i); +-no_children: +- /* compress one level */ +- node_set_parent(n, NULL); +- tnode_free_safe(tn); +- return n; +- } +- return tn; +-} +- +- + static void tnode_clean_free(struct tnode *tn) + { + struct tnode *tofree; +@@ -804,6 +647,160 @@ nomem: + return ERR_PTR(-ENOMEM); + } + ++#define MAX_WORK 10 ++static struct tnode *resize(struct trie *t, struct tnode *tn) ++{ ++ struct tnode *old_tn, *n = NULL; ++ int inflate_threshold_use; ++ int halve_threshold_use; ++ int max_work; ++ ++ if (!tn) ++ return NULL; ++ ++ pr_debug("In tnode_resize %p inflate_threshold=%d threshold=%d\n", ++ tn, inflate_threshold, halve_threshold); ++ ++ /* No children */ ++ if (tn->empty_children > (tnode_child_length(tn) - 1)) ++ goto no_children; ++ ++ /* One child */ ++ if (tn->empty_children == (tnode_child_length(tn) - 1)) ++ goto one_child; ++ /* ++ * Double as long as the resulting node has a number of ++ * nonempty nodes that are above the threshold. ++ */ ++ ++ /* ++ * From "Implementing a dynamic compressed trie" by Stefan Nilsson of ++ * the Helsinki University of Technology and Matti Tikkanen of Nokia ++ * Telecommunications, page 6: ++ * "A node is doubled if the ratio of non-empty children to all ++ * children in the *doubled* node is at least 'high'." ++ * ++ * 'high' in this instance is the variable 'inflate_threshold'. It ++ * is expressed as a percentage, so we multiply it with ++ * tnode_child_length() and instead of multiplying by 2 (since the ++ * child array will be doubled by inflate()) and multiplying ++ * the left-hand side by 100 (to handle the percentage thing) we ++ * multiply the left-hand side by 50. ++ * ++ * The left-hand side may look a bit weird: tnode_child_length(tn) ++ * - tn->empty_children is of course the number of non-null children ++ * in the current node. tn->full_children is the number of "full" ++ * children, that is non-null tnodes with a skip value of 0. ++ * All of those will be doubled in the resulting inflated tnode, so ++ * we just count them one extra time here. ++ * ++ * A clearer way to write this would be: ++ * ++ * to_be_doubled = tn->full_children; ++ * not_to_be_doubled = tnode_child_length(tn) - tn->empty_children - ++ * tn->full_children; ++ * ++ * new_child_length = tnode_child_length(tn) * 2; ++ * ++ * new_fill_factor = 100 * (not_to_be_doubled + 2*to_be_doubled) / ++ * new_child_length; ++ * if (new_fill_factor >= inflate_threshold) ++ * ++ * ...and so on, tho it would mess up the while () loop. ++ * ++ * anyway, ++ * 100 * (not_to_be_doubled + 2*to_be_doubled) / new_child_length >= ++ * inflate_threshold ++ * ++ * avoid a division: ++ * 100 * (not_to_be_doubled + 2*to_be_doubled) >= ++ * inflate_threshold * new_child_length ++ * ++ * expand not_to_be_doubled and to_be_doubled, and shorten: ++ * 100 * (tnode_child_length(tn) - tn->empty_children + ++ * tn->full_children) >= inflate_threshold * new_child_length ++ * ++ * expand new_child_length: ++ * 100 * (tnode_child_length(tn) - tn->empty_children + ++ * tn->full_children) >= ++ * inflate_threshold * tnode_child_length(tn) * 2 ++ * ++ * shorten again: ++ * 50 * (tn->full_children + tnode_child_length(tn) - ++ * tn->empty_children) >= inflate_threshold * ++ * tnode_child_length(tn) ++ * ++ */ ++ ++ /* Keep root node larger */ ++ ++ if (!node_parent(tn)) { ++ inflate_threshold_use = inflate_threshold_root; ++ halve_threshold_use = halve_threshold_root; ++ } else { ++ inflate_threshold_use = inflate_threshold; ++ halve_threshold_use = halve_threshold; ++ } ++ ++ max_work = MAX_WORK; ++ while ((tn->full_children > 0 && max_work-- && ++ 50 * (tn->full_children + tnode_child_length(tn) ++ - tn->empty_children) ++ >= inflate_threshold_use * tnode_child_length(tn))) { ++ ++ old_tn = tn; ++ tn = inflate(t, tn); ++ ++ if (IS_ERR(tn)) { ++ tn = old_tn; ++#ifdef CONFIG_IP_FIB_TRIE_STATS ++ this_cpu_inc(t->stats->resize_node_skipped); ++#endif ++ break; ++ } ++ } ++ ++ /* Return if at least one inflate is run */ ++ if (max_work != MAX_WORK) ++ return tn; ++ ++ /* ++ * Halve as long as the number of empty children in this ++ * node is above threshold. ++ */ ++ ++ max_work = MAX_WORK; ++ while (tn->bits > 1 && max_work-- && ++ 100 * (tnode_child_length(tn) - tn->empty_children) < ++ halve_threshold_use * tnode_child_length(tn)) { ++ ++ old_tn = tn; ++ tn = halve(t, tn); ++ if (IS_ERR(tn)) { ++ tn = old_tn; ++#ifdef CONFIG_IP_FIB_TRIE_STATS ++ this_cpu_inc(t->stats->resize_node_skipped); ++#endif ++ break; ++ } ++ } ++ ++ ++ /* Only one child remains */ ++ if (tn->empty_children == (tnode_child_length(tn) - 1)) { ++ unsigned long i; ++one_child: ++ for (i = tnode_child_length(tn); !n && i;) ++ n = tnode_get_child(tn, --i); ++no_children: ++ /* compress one level */ ++ node_set_parent(n, NULL); ++ tnode_free_safe(tn); ++ return n; ++ } ++ return tn; ++} ++ + /* readside must use rcu_read_lock currently dump routines + via get_fa_head and dump */ + diff --git a/target/linux/generic/patches-3.18/080-13-fib_trie-Add-functions-should_inflate-and-should_hal.patch b/target/linux/generic/patches-3.18/080-13-fib_trie-Add-functions-should_inflate-and-should_hal.patch new file mode 100644 index 0000000..c01d57a --- /dev/null +++ b/target/linux/generic/patches-3.18/080-13-fib_trie-Add-functions-should_inflate-and-should_hal.patch @@ -0,0 +1,250 @@ +From: Alexander Duyck +Date: Wed, 31 Dec 2014 10:56:37 -0800 +Subject: [PATCH] fib_trie: Add functions should_inflate and should_halve + +This change pulls the logic for if we should inflate/halve the nodes out +into separate functions. It also addresses what I believe is a bug where 1 +full node is all that is needed to keep a node from ever being halved. + +Simple script to reproduce the issue: + modprobe dummy; ifconfig dummy0 up + for i in `seq 0 255`; do ifconfig dummy0:$i 10.0.${i}.1/24 up; done + ifconfig dummy0:256 10.0.255.33/16 up + for i in `seq 0 254`; do ifconfig dummy0:$i down; done + +Results from /proc/net/fib_triestat +Before: + Local: + Aver depth: 3.00 + Max depth: 4 + Leaves: 17 + Prefixes: 18 + Internal nodes: 11 + 1: 8 2: 2 10: 1 + Pointers: 1048 + Null ptrs: 1021 + Total size: 11 kB +After: + Local: + Aver depth: 3.41 + Max depth: 5 + Leaves: 17 + Prefixes: 18 + Internal nodes: 12 + 1: 8 2: 3 3: 1 + Pointers: 36 + Null ptrs: 8 + Total size: 3 kB + +Signed-off-by: Alexander Duyck +Signed-off-by: David S. Miller +--- + +--- a/net/ipv4/fib_trie.c ++++ b/net/ipv4/fib_trie.c +@@ -647,12 +647,94 @@ nomem: + return ERR_PTR(-ENOMEM); + } + ++/* From "Implementing a dynamic compressed trie" by Stefan Nilsson of ++ * the Helsinki University of Technology and Matti Tikkanen of Nokia ++ * Telecommunications, page 6: ++ * "A node is doubled if the ratio of non-empty children to all ++ * children in the *doubled* node is at least 'high'." ++ * ++ * 'high' in this instance is the variable 'inflate_threshold'. It ++ * is expressed as a percentage, so we multiply it with ++ * tnode_child_length() and instead of multiplying by 2 (since the ++ * child array will be doubled by inflate()) and multiplying ++ * the left-hand side by 100 (to handle the percentage thing) we ++ * multiply the left-hand side by 50. ++ * ++ * The left-hand side may look a bit weird: tnode_child_length(tn) ++ * - tn->empty_children is of course the number of non-null children ++ * in the current node. tn->full_children is the number of "full" ++ * children, that is non-null tnodes with a skip value of 0. ++ * All of those will be doubled in the resulting inflated tnode, so ++ * we just count them one extra time here. ++ * ++ * A clearer way to write this would be: ++ * ++ * to_be_doubled = tn->full_children; ++ * not_to_be_doubled = tnode_child_length(tn) - tn->empty_children - ++ * tn->full_children; ++ * ++ * new_child_length = tnode_child_length(tn) * 2; ++ * ++ * new_fill_factor = 100 * (not_to_be_doubled + 2*to_be_doubled) / ++ * new_child_length; ++ * if (new_fill_factor >= inflate_threshold) ++ * ++ * ...and so on, tho it would mess up the while () loop. ++ * ++ * anyway, ++ * 100 * (not_to_be_doubled + 2*to_be_doubled) / new_child_length >= ++ * inflate_threshold ++ * ++ * avoid a division: ++ * 100 * (not_to_be_doubled + 2*to_be_doubled) >= ++ * inflate_threshold * new_child_length ++ * ++ * expand not_to_be_doubled and to_be_doubled, and shorten: ++ * 100 * (tnode_child_length(tn) - tn->empty_children + ++ * tn->full_children) >= inflate_threshold * new_child_length ++ * ++ * expand new_child_length: ++ * 100 * (tnode_child_length(tn) - tn->empty_children + ++ * tn->full_children) >= ++ * inflate_threshold * tnode_child_length(tn) * 2 ++ * ++ * shorten again: ++ * 50 * (tn->full_children + tnode_child_length(tn) - ++ * tn->empty_children) >= inflate_threshold * ++ * tnode_child_length(tn) ++ * ++ */ ++static bool should_inflate(const struct tnode *tn) ++{ ++ unsigned long used = tnode_child_length(tn); ++ unsigned long threshold = used; ++ ++ /* Keep root node larger */ ++ threshold *= node_parent(tn) ? inflate_threshold : ++ inflate_threshold_root; ++ used += tn->full_children; ++ used -= tn->empty_children; ++ ++ return tn->pos && ((50 * used) >= threshold); ++} ++ ++static bool should_halve(const struct tnode *tn) ++{ ++ unsigned long used = tnode_child_length(tn); ++ unsigned long threshold = used; ++ ++ /* Keep root node larger */ ++ threshold *= node_parent(tn) ? halve_threshold : ++ halve_threshold_root; ++ used -= tn->empty_children; ++ ++ return (tn->bits > 1) && ((100 * used) < threshold); ++} ++ + #define MAX_WORK 10 + static struct tnode *resize(struct trie *t, struct tnode *tn) + { + struct tnode *old_tn, *n = NULL; +- int inflate_threshold_use; +- int halve_threshold_use; + int max_work; + + if (!tn) +@@ -668,86 +750,12 @@ static struct tnode *resize(struct trie + /* One child */ + if (tn->empty_children == (tnode_child_length(tn) - 1)) + goto one_child; +- /* +- * Double as long as the resulting node has a number of +- * nonempty nodes that are above the threshold. +- */ + +- /* +- * From "Implementing a dynamic compressed trie" by Stefan Nilsson of +- * the Helsinki University of Technology and Matti Tikkanen of Nokia +- * Telecommunications, page 6: +- * "A node is doubled if the ratio of non-empty children to all +- * children in the *doubled* node is at least 'high'." +- * +- * 'high' in this instance is the variable 'inflate_threshold'. It +- * is expressed as a percentage, so we multiply it with +- * tnode_child_length() and instead of multiplying by 2 (since the +- * child array will be doubled by inflate()) and multiplying +- * the left-hand side by 100 (to handle the percentage thing) we +- * multiply the left-hand side by 50. +- * +- * The left-hand side may look a bit weird: tnode_child_length(tn) +- * - tn->empty_children is of course the number of non-null children +- * in the current node. tn->full_children is the number of "full" +- * children, that is non-null tnodes with a skip value of 0. +- * All of those will be doubled in the resulting inflated tnode, so +- * we just count them one extra time here. +- * +- * A clearer way to write this would be: +- * +- * to_be_doubled = tn->full_children; +- * not_to_be_doubled = tnode_child_length(tn) - tn->empty_children - +- * tn->full_children; +- * +- * new_child_length = tnode_child_length(tn) * 2; +- * +- * new_fill_factor = 100 * (not_to_be_doubled + 2*to_be_doubled) / +- * new_child_length; +- * if (new_fill_factor >= inflate_threshold) +- * +- * ...and so on, tho it would mess up the while () loop. +- * +- * anyway, +- * 100 * (not_to_be_doubled + 2*to_be_doubled) / new_child_length >= +- * inflate_threshold +- * +- * avoid a division: +- * 100 * (not_to_be_doubled + 2*to_be_doubled) >= +- * inflate_threshold * new_child_length +- * +- * expand not_to_be_doubled and to_be_doubled, and shorten: +- * 100 * (tnode_child_length(tn) - tn->empty_children + +- * tn->full_children) >= inflate_threshold * new_child_length +- * +- * expand new_child_length: +- * 100 * (tnode_child_length(tn) - tn->empty_children + +- * tn->full_children) >= +- * inflate_threshold * tnode_child_length(tn) * 2 +- * +- * shorten again: +- * 50 * (tn->full_children + tnode_child_length(tn) - +- * tn->empty_children) >= inflate_threshold * +- * tnode_child_length(tn) +- * ++ /* Double as long as the resulting node has a number of ++ * nonempty nodes that are above the threshold. + */ +- +- /* Keep root node larger */ +- +- if (!node_parent(tn)) { +- inflate_threshold_use = inflate_threshold_root; +- halve_threshold_use = halve_threshold_root; +- } else { +- inflate_threshold_use = inflate_threshold; +- halve_threshold_use = halve_threshold; +- } +- + max_work = MAX_WORK; +- while ((tn->full_children > 0 && max_work-- && +- 50 * (tn->full_children + tnode_child_length(tn) +- - tn->empty_children) +- >= inflate_threshold_use * tnode_child_length(tn))) { +- ++ while (should_inflate(tn) && max_work--) { + old_tn = tn; + tn = inflate(t, tn); + +@@ -764,16 +772,11 @@ static struct tnode *resize(struct trie + if (max_work != MAX_WORK) + return tn; + +- /* +- * Halve as long as the number of empty children in this ++ /* Halve as long as the number of empty children in this + * node is above threshold. + */ +- + max_work = MAX_WORK; +- while (tn->bits > 1 && max_work-- && +- 100 * (tnode_child_length(tn) - tn->empty_children) < +- halve_threshold_use * tnode_child_length(tn)) { +- ++ while (should_halve(tn) && max_work--) { + old_tn = tn; + tn = halve(t, tn); + if (IS_ERR(tn)) { diff --git a/target/linux/generic/patches-3.18/080-14-fib_trie-Push-assignment-of-child-to-parent-down-int.patch b/target/linux/generic/patches-3.18/080-14-fib_trie-Push-assignment-of-child-to-parent-down-int.patch new file mode 100644 index 0000000..8f26e32 --- /dev/null +++ b/target/linux/generic/patches-3.18/080-14-fib_trie-Push-assignment-of-child-to-parent-down-int.patch @@ -0,0 +1,336 @@ +From: Alexander Duyck +Date: Wed, 31 Dec 2014 10:56:43 -0800 +Subject: [PATCH] fib_trie: Push assignment of child to parent down into + inflate/halve + +This change makes it so that the assignment of the tnode to the parent is +handled directly within whatever function is currently handling the node be +it inflate, halve, or resize. By doing this we can avoid some of the need +to set NULL pointers in the tree while we are resizing the subnodes. + +Signed-off-by: Alexander Duyck +Signed-off-by: David S. Miller +--- + +--- a/net/ipv4/fib_trie.c ++++ b/net/ipv4/fib_trie.c +@@ -146,9 +146,7 @@ struct trie { + #endif + }; + +-static void tnode_put_child_reorg(struct tnode *tn, unsigned long i, +- struct tnode *n, int wasfull); +-static struct tnode *resize(struct trie *t, struct tnode *tn); ++static void resize(struct trie *t, struct tnode *tn); + /* tnodes to free after resize(); protected by RTNL */ + static struct callback_head *tnode_free_head; + static size_t tnode_free_size; +@@ -396,22 +394,13 @@ static inline int tnode_full(const struc + return n && ((n->pos + n->bits) == tn->pos) && IS_TNODE(n); + } + +-static inline void put_child(struct tnode *tn, unsigned long i, +- struct tnode *n) +-{ +- tnode_put_child_reorg(tn, i, n, -1); +-} +- +- /* +- * Add a child at position i overwriting the old value. +- * Update the value of full_children and empty_children. +- */ +- +-static void tnode_put_child_reorg(struct tnode *tn, unsigned long i, +- struct tnode *n, int wasfull) ++/* Add a child at position i overwriting the old value. ++ * Update the value of full_children and empty_children. ++ */ ++static void put_child(struct tnode *tn, unsigned long i, struct tnode *n) + { + struct tnode *chi = rtnl_dereference(tn->child[i]); +- int isfull; ++ int isfull, wasfull; + + BUG_ON(i >= tnode_child_length(tn)); + +@@ -422,10 +411,9 @@ static void tnode_put_child_reorg(struct + tn->empty_children--; + + /* update fullChildren */ +- if (wasfull == -1) +- wasfull = tnode_full(tn, chi); +- ++ wasfull = tnode_full(tn, chi); + isfull = tnode_full(tn, n); ++ + if (wasfull && !isfull) + tn->full_children--; + else if (!wasfull && isfull) +@@ -458,9 +446,10 @@ static void tnode_clean_free(struct tnod + node_free(tn); + } + +-static struct tnode *inflate(struct trie *t, struct tnode *oldtnode) ++static int inflate(struct trie *t, struct tnode *oldtnode) + { + unsigned long olen = tnode_child_length(oldtnode); ++ struct tnode *tp = node_parent(oldtnode); + struct tnode *tn; + unsigned long i; + t_key m; +@@ -468,9 +457,8 @@ static struct tnode *inflate(struct trie + pr_debug("In inflate\n"); + + tn = tnode_new(oldtnode->key, oldtnode->pos - 1, oldtnode->bits + 1); +- + if (!tn) +- return ERR_PTR(-ENOMEM); ++ return -ENOMEM; + + /* + * Preallocate and store tnodes before the actual work so we +@@ -564,30 +552,36 @@ static struct tnode *inflate(struct trie + put_child(left, j, rtnl_dereference(inode->child[j])); + put_child(right, j, rtnl_dereference(inode->child[j + size])); + } +- put_child(tn, 2*i, resize(t, left)); +- put_child(tn, 2*i+1, resize(t, right)); ++ ++ put_child(tn, 2 * i, left); ++ put_child(tn, 2 * i + 1, right); + + tnode_free_safe(inode); ++ ++ resize(t, left); ++ resize(t, right); + } ++ ++ put_child_root(tp, t, tn->key, tn); + tnode_free_safe(oldtnode); +- return tn; ++ return 0; + nomem: + tnode_clean_free(tn); +- return ERR_PTR(-ENOMEM); ++ return -ENOMEM; + } + +-static struct tnode *halve(struct trie *t, struct tnode *oldtnode) ++static int halve(struct trie *t, struct tnode *oldtnode) + { + unsigned long olen = tnode_child_length(oldtnode); ++ struct tnode *tp = node_parent(oldtnode); + struct tnode *tn, *left, *right; + int i; + + pr_debug("In halve\n"); + + tn = tnode_new(oldtnode->key, oldtnode->pos + 1, oldtnode->bits - 1); +- + if (!tn) +- return ERR_PTR(-ENOMEM); ++ return -ENOMEM; + + /* + * Preallocate and store tnodes before the actual work so we +@@ -606,8 +600,10 @@ static struct tnode *halve(struct trie * + + newn = tnode_new(left->key, oldtnode->pos, 1); + +- if (!newn) +- goto nomem; ++ if (!newn) { ++ tnode_clean_free(tn); ++ return -ENOMEM; ++ } + + put_child(tn, i/2, newn); + } +@@ -635,16 +631,18 @@ static struct tnode *halve(struct trie * + + /* Two nonempty children */ + newBinNode = tnode_get_child(tn, i/2); +- put_child(tn, i/2, NULL); + put_child(newBinNode, 0, left); + put_child(newBinNode, 1, right); +- put_child(tn, i/2, resize(t, newBinNode)); ++ ++ put_child(tn, i / 2, newBinNode); ++ ++ resize(t, newBinNode); + } ++ ++ put_child_root(tp, t, tn->key, tn); + tnode_free_safe(oldtnode); +- return tn; +-nomem: +- tnode_clean_free(tn); +- return ERR_PTR(-ENOMEM); ++ ++ return 0; + } + + /* From "Implementing a dynamic compressed trie" by Stefan Nilsson of +@@ -704,45 +702,48 @@ nomem: + * tnode_child_length(tn) + * + */ +-static bool should_inflate(const struct tnode *tn) ++static bool should_inflate(const struct tnode *tp, const struct tnode *tn) + { + unsigned long used = tnode_child_length(tn); + unsigned long threshold = used; + + /* Keep root node larger */ +- threshold *= node_parent(tn) ? inflate_threshold : +- inflate_threshold_root; ++ threshold *= tp ? inflate_threshold : inflate_threshold_root; + used += tn->full_children; + used -= tn->empty_children; + + return tn->pos && ((50 * used) >= threshold); + } + +-static bool should_halve(const struct tnode *tn) ++static bool should_halve(const struct tnode *tp, const struct tnode *tn) + { + unsigned long used = tnode_child_length(tn); + unsigned long threshold = used; + + /* Keep root node larger */ +- threshold *= node_parent(tn) ? halve_threshold : +- halve_threshold_root; ++ threshold *= tp ? halve_threshold : halve_threshold_root; + used -= tn->empty_children; + + return (tn->bits > 1) && ((100 * used) < threshold); + } + + #define MAX_WORK 10 +-static struct tnode *resize(struct trie *t, struct tnode *tn) ++static void resize(struct trie *t, struct tnode *tn) + { +- struct tnode *old_tn, *n = NULL; ++ struct tnode *tp = node_parent(tn), *n = NULL; ++ struct tnode __rcu **cptr; + int max_work; + +- if (!tn) +- return NULL; +- + pr_debug("In tnode_resize %p inflate_threshold=%d threshold=%d\n", + tn, inflate_threshold, halve_threshold); + ++ /* track the tnode via the pointer from the parent instead of ++ * doing it ourselves. This way we can let RCU fully do its ++ * thing without us interfering ++ */ ++ cptr = tp ? &tp->child[get_index(tn->key, tp)] : &t->trie; ++ BUG_ON(tn != rtnl_dereference(*cptr)); ++ + /* No children */ + if (tn->empty_children > (tnode_child_length(tn) - 1)) + goto no_children; +@@ -755,39 +756,35 @@ static struct tnode *resize(struct trie + * nonempty nodes that are above the threshold. + */ + max_work = MAX_WORK; +- while (should_inflate(tn) && max_work--) { +- old_tn = tn; +- tn = inflate(t, tn); +- +- if (IS_ERR(tn)) { +- tn = old_tn; ++ while (should_inflate(tp, tn) && max_work--) { ++ if (inflate(t, tn)) { + #ifdef CONFIG_IP_FIB_TRIE_STATS + this_cpu_inc(t->stats->resize_node_skipped); + #endif + break; + } ++ ++ tn = rtnl_dereference(*cptr); + } + + /* Return if at least one inflate is run */ + if (max_work != MAX_WORK) +- return tn; ++ return; + + /* Halve as long as the number of empty children in this + * node is above threshold. + */ + max_work = MAX_WORK; +- while (should_halve(tn) && max_work--) { +- old_tn = tn; +- tn = halve(t, tn); +- if (IS_ERR(tn)) { +- tn = old_tn; ++ while (should_halve(tp, tn) && max_work--) { ++ if (halve(t, tn)) { + #ifdef CONFIG_IP_FIB_TRIE_STATS + this_cpu_inc(t->stats->resize_node_skipped); + #endif + break; + } +- } + ++ tn = rtnl_dereference(*cptr); ++ } + + /* Only one child remains */ + if (tn->empty_children == (tnode_child_length(tn) - 1)) { +@@ -797,11 +794,12 @@ one_child: + n = tnode_get_child(tn, --i); + no_children: + /* compress one level */ +- node_set_parent(n, NULL); ++ put_child_root(tp, t, tn->key, n); ++ node_set_parent(n, tp); ++ ++ /* drop dead node */ + tnode_free_safe(tn); +- return n; + } +- return tn; + } + + /* readside must use rcu_read_lock currently dump routines +@@ -882,34 +880,19 @@ static struct tnode *fib_find_node(struc + + static void trie_rebalance(struct trie *t, struct tnode *tn) + { +- int wasfull; +- t_key cindex, key; + struct tnode *tp; + +- key = tn->key; +- +- while (tn != NULL && (tp = node_parent(tn)) != NULL) { +- cindex = get_index(key, tp); +- wasfull = tnode_full(tp, tnode_get_child(tp, cindex)); +- tn = resize(t, tn); +- +- tnode_put_child_reorg(tp, cindex, tn, wasfull); +- +- tp = node_parent(tn); +- if (!tp) +- rcu_assign_pointer(t->trie, tn); ++ while ((tp = node_parent(tn)) != NULL) { ++ resize(t, tn); + + tnode_free_flush(); +- if (!tp) +- break; + tn = tp; + } + + /* Handle last (top) tnode */ + if (IS_TNODE(tn)) +- tn = resize(t, tn); ++ resize(t, tn); + +- rcu_assign_pointer(t->trie, tn); + tnode_free_flush(); + } + diff --git a/target/linux/generic/patches-3.18/080-15-fib_trie-Push-tnode-flushing-down-to-inflate-halve.patch b/target/linux/generic/patches-3.18/080-15-fib_trie-Push-tnode-flushing-down-to-inflate-halve.patch new file mode 100644 index 0000000..51178a0 --- /dev/null +++ b/target/linux/generic/patches-3.18/080-15-fib_trie-Push-tnode-flushing-down-to-inflate-halve.patch @@ -0,0 +1,237 @@ +From: Alexander Duyck +Date: Wed, 31 Dec 2014 10:56:49 -0800 +Subject: [PATCH] fib_trie: Push tnode flushing down to inflate/halve + +This change pushes the tnode freeing down into the inflate and halve +functions. It makes more sense here as we have a better grasp of what is +going on and when a given cluster of nodes is ready to be freed. + +I believe this may address a bug in the freeing logic as well. For some +reason if the freelist got to a certain size we would call +synchronize_rcu(). I'm assuming that what they meant to do is call +synchronize_rcu() after they had handed off that much memory via +call_rcu(). As such that is what I have updated the behavior to be. + +Signed-off-by: Alexander Duyck +Signed-off-by: David S. Miller +--- + +--- a/net/ipv4/fib_trie.c ++++ b/net/ipv4/fib_trie.c +@@ -147,8 +147,6 @@ struct trie { + }; + + static void resize(struct trie *t, struct tnode *tn); +-/* tnodes to free after resize(); protected by RTNL */ +-static struct callback_head *tnode_free_head; + static size_t tnode_free_size; + + /* +@@ -307,32 +305,6 @@ static struct tnode *tnode_alloc(size_t + return vzalloc(size); + } + +-static void tnode_free_safe(struct tnode *tn) +-{ +- BUG_ON(IS_LEAF(tn)); +- tn->rcu.next = tnode_free_head; +- tnode_free_head = &tn->rcu; +-} +- +-static void tnode_free_flush(void) +-{ +- struct callback_head *head; +- +- while ((head = tnode_free_head)) { +- struct tnode *tn = container_of(head, struct tnode, rcu); +- +- tnode_free_head = head->next; +- tnode_free_size += offsetof(struct tnode, child[1 << tn->bits]); +- +- node_free(tn); +- } +- +- if (tnode_free_size >= PAGE_SIZE * sync_pages) { +- tnode_free_size = 0; +- synchronize_rcu(); +- } +-} +- + static struct tnode *leaf_new(t_key key) + { + struct tnode *l = kmem_cache_alloc(trie_leaf_kmem, GFP_KERNEL); +@@ -433,17 +405,33 @@ static void put_child_root(struct tnode + rcu_assign_pointer(t->trie, n); + } + +-static void tnode_clean_free(struct tnode *tn) ++static inline void tnode_free_init(struct tnode *tn) + { +- struct tnode *tofree; +- unsigned long i; ++ tn->rcu.next = NULL; ++} ++ ++static inline void tnode_free_append(struct tnode *tn, struct tnode *n) ++{ ++ n->rcu.next = tn->rcu.next; ++ tn->rcu.next = &n->rcu; ++} + +- for (i = 0; i < tnode_child_length(tn); i++) { +- tofree = tnode_get_child(tn, i); +- if (tofree) +- node_free(tofree); ++static void tnode_free(struct tnode *tn) ++{ ++ struct callback_head *head = &tn->rcu; ++ ++ while (head) { ++ head = head->next; ++ tnode_free_size += offsetof(struct tnode, child[1 << tn->bits]); ++ node_free(tn); ++ ++ tn = container_of(head, struct tnode, rcu); ++ } ++ ++ if (tnode_free_size >= PAGE_SIZE * sync_pages) { ++ tnode_free_size = 0; ++ synchronize_rcu(); + } +- node_free(tn); + } + + static int inflate(struct trie *t, struct tnode *oldtnode) +@@ -476,20 +464,23 @@ static int inflate(struct trie *t, struc + inode->bits - 1); + if (!left) + goto nomem; ++ tnode_free_append(tn, left); + + right = tnode_new(inode->key | m, inode->pos, + inode->bits - 1); + +- if (!right) { +- node_free(left); ++ if (!right) + goto nomem; +- } ++ tnode_free_append(tn, right); + + put_child(tn, 2*i, left); + put_child(tn, 2*i+1, right); + } + } + ++ /* prepare oldtnode to be freed */ ++ tnode_free_init(oldtnode); ++ + for (i = 0; i < olen; i++) { + struct tnode *inode = tnode_get_child(oldtnode, i); + struct tnode *left, *right; +@@ -505,12 +496,13 @@ static int inflate(struct trie *t, struc + continue; + } + ++ /* drop the node in the old tnode free list */ ++ tnode_free_append(oldtnode, inode); ++ + /* An internal node with two children */ + if (inode->bits == 1) { + put_child(tn, 2*i, rtnl_dereference(inode->child[0])); + put_child(tn, 2*i+1, rtnl_dereference(inode->child[1])); +- +- tnode_free_safe(inode); + continue; + } + +@@ -556,17 +548,19 @@ static int inflate(struct trie *t, struc + put_child(tn, 2 * i, left); + put_child(tn, 2 * i + 1, right); + +- tnode_free_safe(inode); +- ++ /* resize child nodes */ + resize(t, left); + resize(t, right); + } + + put_child_root(tp, t, tn->key, tn); +- tnode_free_safe(oldtnode); ++ ++ /* we completed without error, prepare to free old node */ ++ tnode_free(oldtnode); + return 0; + nomem: +- tnode_clean_free(tn); ++ /* all pointers should be clean so we are done */ ++ tnode_free(tn); + return -ENOMEM; + } + +@@ -599,17 +593,20 @@ static int halve(struct trie *t, struct + struct tnode *newn; + + newn = tnode_new(left->key, oldtnode->pos, 1); +- + if (!newn) { +- tnode_clean_free(tn); ++ tnode_free(tn); + return -ENOMEM; + } ++ tnode_free_append(tn, newn); + + put_child(tn, i/2, newn); + } + + } + ++ /* prepare oldtnode to be freed */ ++ tnode_free_init(oldtnode); ++ + for (i = 0; i < olen; i += 2) { + struct tnode *newBinNode; + +@@ -636,11 +633,14 @@ static int halve(struct trie *t, struct + + put_child(tn, i / 2, newBinNode); + ++ /* resize child node */ + resize(t, newBinNode); + } + + put_child_root(tp, t, tn->key, tn); +- tnode_free_safe(oldtnode); ++ ++ /* all pointers should be clean so we are done */ ++ tnode_free(oldtnode); + + return 0; + } +@@ -798,7 +798,8 @@ no_children: + node_set_parent(n, tp); + + /* drop dead node */ +- tnode_free_safe(tn); ++ tnode_free_init(tn); ++ tnode_free(tn); + } + } + +@@ -884,16 +885,12 @@ static void trie_rebalance(struct trie * + + while ((tp = node_parent(tn)) != NULL) { + resize(t, tn); +- +- tnode_free_flush(); + tn = tp; + } + + /* Handle last (top) tnode */ + if (IS_TNODE(tn)) + resize(t, tn); +- +- tnode_free_flush(); + } + + /* only used from updater-side */ diff --git a/target/linux/generic/patches-3.18/080-16-fib_trie-inflate-halve-nodes-in-a-more-RCU-friendly-.patch b/target/linux/generic/patches-3.18/080-16-fib_trie-inflate-halve-nodes-in-a-more-RCU-friendly-.patch new file mode 100644 index 0000000..d6b600c --- /dev/null +++ b/target/linux/generic/patches-3.18/080-16-fib_trie-inflate-halve-nodes-in-a-more-RCU-friendly-.patch @@ -0,0 +1,345 @@ +From: Alexander Duyck +Date: Wed, 31 Dec 2014 10:56:55 -0800 +Subject: [PATCH] fib_trie: inflate/halve nodes in a more RCU friendly + way + +This change pulls the node_set_parent functionality out of put_child_reorg +and instead leaves that to the function to take care of as well. By doing +this we can fully construct the new cluster of tnodes and all of the +pointers out of it before we start routing pointers into it. + +I am suspecting this will likely fix some concurency issues though I don't +have a good test to show as such. + +Signed-off-by: Alexander Duyck +Signed-off-by: David S. Miller +--- + +--- a/net/ipv4/fib_trie.c ++++ b/net/ipv4/fib_trie.c +@@ -391,8 +391,6 @@ static void put_child(struct tnode *tn, + else if (!wasfull && isfull) + tn->full_children++; + +- node_set_parent(n, tn); +- + rcu_assign_pointer(tn->child[i], n); + } + +@@ -436,10 +434,8 @@ static void tnode_free(struct tnode *tn) + + static int inflate(struct trie *t, struct tnode *oldtnode) + { +- unsigned long olen = tnode_child_length(oldtnode); +- struct tnode *tp = node_parent(oldtnode); +- struct tnode *tn; +- unsigned long i; ++ struct tnode *inode, *node0, *node1, *tn, *tp; ++ unsigned long i, j, k; + t_key m; + + pr_debug("In inflate\n"); +@@ -448,43 +444,13 @@ static int inflate(struct trie *t, struc + if (!tn) + return -ENOMEM; + +- /* +- * Preallocate and store tnodes before the actual work so we +- * don't get into an inconsistent state if memory allocation +- * fails. In case of failure we return the oldnode and inflate +- * of tnode is ignored. ++ /* Assemble all of the pointers in our cluster, in this case that ++ * represents all of the pointers out of our allocated nodes that ++ * point to existing tnodes and the links between our allocated ++ * nodes. + */ +- for (i = 0, m = 1u << tn->pos; i < olen; i++) { +- struct tnode *inode = tnode_get_child(oldtnode, i); +- +- if (tnode_full(oldtnode, inode) && (inode->bits > 1)) { +- struct tnode *left, *right; +- +- left = tnode_new(inode->key & ~m, inode->pos, +- inode->bits - 1); +- if (!left) +- goto nomem; +- tnode_free_append(tn, left); +- +- right = tnode_new(inode->key | m, inode->pos, +- inode->bits - 1); +- +- if (!right) +- goto nomem; +- tnode_free_append(tn, right); +- +- put_child(tn, 2*i, left); +- put_child(tn, 2*i+1, right); +- } +- } +- +- /* prepare oldtnode to be freed */ +- tnode_free_init(oldtnode); +- +- for (i = 0; i < olen; i++) { +- struct tnode *inode = tnode_get_child(oldtnode, i); +- struct tnode *left, *right; +- unsigned long size, j; ++ for (i = tnode_child_length(oldtnode), m = 1u << tn->pos; i;) { ++ inode = tnode_get_child(oldtnode, --i); + + /* An empty child */ + if (inode == NULL) +@@ -496,65 +462,99 @@ static int inflate(struct trie *t, struc + continue; + } + +- /* drop the node in the old tnode free list */ +- tnode_free_append(oldtnode, inode); +- + /* An internal node with two children */ + if (inode->bits == 1) { +- put_child(tn, 2*i, rtnl_dereference(inode->child[0])); +- put_child(tn, 2*i+1, rtnl_dereference(inode->child[1])); ++ put_child(tn, 2 * i + 1, tnode_get_child(inode, 1)); ++ put_child(tn, 2 * i, tnode_get_child(inode, 0)); + continue; + } + +- /* An internal node with more than two children */ +- + /* We will replace this node 'inode' with two new +- * ones, 'left' and 'right', each with half of the ++ * ones, 'node0' and 'node1', each with half of the + * original children. The two new nodes will have + * a position one bit further down the key and this + * means that the "significant" part of their keys + * (see the discussion near the top of this file) + * will differ by one bit, which will be "0" in +- * left's key and "1" in right's key. Since we are ++ * node0's key and "1" in node1's key. Since we are + * moving the key position by one step, the bit that + * we are moving away from - the bit at position +- * (inode->pos) - is the one that will differ between +- * left and right. So... we synthesize that bit in the +- * two new keys. +- * The mask 'm' below will be a single "one" bit at +- * the position (inode->pos) ++ * (tn->pos) - is the one that will differ between ++ * node0 and node1. So... we synthesize that bit in the ++ * two new keys. + */ ++ node1 = tnode_new(inode->key | m, inode->pos, inode->bits - 1); ++ if (!node1) ++ goto nomem; ++ tnode_free_append(tn, node1); ++ ++ node0 = tnode_new(inode->key & ~m, inode->pos, inode->bits - 1); ++ if (!node0) ++ goto nomem; ++ tnode_free_append(tn, node0); ++ ++ /* populate child pointers in new nodes */ ++ for (k = tnode_child_length(inode), j = k / 2; j;) { ++ put_child(node1, --j, tnode_get_child(inode, --k)); ++ put_child(node0, j, tnode_get_child(inode, j)); ++ put_child(node1, --j, tnode_get_child(inode, --k)); ++ put_child(node0, j, tnode_get_child(inode, j)); ++ } ++ ++ /* link new nodes to parent */ ++ NODE_INIT_PARENT(node1, tn); ++ NODE_INIT_PARENT(node0, tn); ++ ++ /* link parent to nodes */ ++ put_child(tn, 2 * i + 1, node1); ++ put_child(tn, 2 * i, node0); ++ } ++ ++ /* setup the parent pointer into and out of this node */ ++ tp = node_parent(oldtnode); ++ NODE_INIT_PARENT(tn, tp); ++ put_child_root(tp, t, tn->key, tn); + +- /* Use the old key, but set the new significant +- * bit to zero. +- */ ++ /* prepare oldtnode to be freed */ ++ tnode_free_init(oldtnode); + +- left = tnode_get_child(tn, 2*i); +- put_child(tn, 2*i, NULL); ++ /* update all child nodes parent pointers to route to us */ ++ for (i = tnode_child_length(oldtnode); i;) { ++ inode = tnode_get_child(oldtnode, --i); + +- BUG_ON(!left); ++ /* A leaf or an internal node with skipped bits */ ++ if (!tnode_full(oldtnode, inode)) { ++ node_set_parent(inode, tn); ++ continue; ++ } + +- right = tnode_get_child(tn, 2*i+1); +- put_child(tn, 2*i+1, NULL); ++ /* drop the node in the old tnode free list */ ++ tnode_free_append(oldtnode, inode); + +- BUG_ON(!right); ++ /* fetch new nodes */ ++ node1 = tnode_get_child(tn, 2 * i + 1); ++ node0 = tnode_get_child(tn, 2 * i); + +- size = tnode_child_length(left); +- for (j = 0; j < size; j++) { +- put_child(left, j, rtnl_dereference(inode->child[j])); +- put_child(right, j, rtnl_dereference(inode->child[j + size])); ++ /* bits == 1 then node0 and node1 represent inode's children */ ++ if (inode->bits == 1) { ++ node_set_parent(node1, tn); ++ node_set_parent(node0, tn); ++ continue; + } + +- put_child(tn, 2 * i, left); +- put_child(tn, 2 * i + 1, right); ++ /* update parent pointers in child node's children */ ++ for (k = tnode_child_length(inode), j = k / 2; j;) { ++ node_set_parent(tnode_get_child(inode, --k), node1); ++ node_set_parent(tnode_get_child(inode, --j), node0); ++ node_set_parent(tnode_get_child(inode, --k), node1); ++ node_set_parent(tnode_get_child(inode, --j), node0); ++ } + + /* resize child nodes */ +- resize(t, left); +- resize(t, right); ++ resize(t, node1); ++ resize(t, node0); + } + +- put_child_root(tp, t, tn->key, tn); +- + /* we completed without error, prepare to free old node */ + tnode_free(oldtnode); + return 0; +@@ -566,10 +566,8 @@ nomem: + + static int halve(struct trie *t, struct tnode *oldtnode) + { +- unsigned long olen = tnode_child_length(oldtnode); +- struct tnode *tp = node_parent(oldtnode); +- struct tnode *tn, *left, *right; +- int i; ++ struct tnode *tn, *tp, *inode, *node0, *node1; ++ unsigned long i; + + pr_debug("In halve\n"); + +@@ -577,68 +575,64 @@ static int halve(struct trie *t, struct + if (!tn) + return -ENOMEM; + +- /* +- * Preallocate and store tnodes before the actual work so we +- * don't get into an inconsistent state if memory allocation +- * fails. In case of failure we return the oldnode and halve +- * of tnode is ignored. ++ /* Assemble all of the pointers in our cluster, in this case that ++ * represents all of the pointers out of our allocated nodes that ++ * point to existing tnodes and the links between our allocated ++ * nodes. + */ ++ for (i = tnode_child_length(oldtnode); i;) { ++ node1 = tnode_get_child(oldtnode, --i); ++ node0 = tnode_get_child(oldtnode, --i); + +- for (i = 0; i < olen; i += 2) { +- left = tnode_get_child(oldtnode, i); +- right = tnode_get_child(oldtnode, i+1); ++ /* At least one of the children is empty */ ++ if (!node1 || !node0) { ++ put_child(tn, i / 2, node1 ? : node0); ++ continue; ++ } + + /* Two nonempty children */ +- if (left && right) { +- struct tnode *newn; +- +- newn = tnode_new(left->key, oldtnode->pos, 1); +- if (!newn) { +- tnode_free(tn); +- return -ENOMEM; +- } +- tnode_free_append(tn, newn); +- +- put_child(tn, i/2, newn); ++ inode = tnode_new(node0->key, oldtnode->pos, 1); ++ if (!inode) { ++ tnode_free(tn); ++ return -ENOMEM; + } ++ tnode_free_append(tn, inode); + ++ /* initialize pointers out of node */ ++ put_child(inode, 1, node1); ++ put_child(inode, 0, node0); ++ NODE_INIT_PARENT(inode, tn); ++ ++ /* link parent to node */ ++ put_child(tn, i / 2, inode); + } + ++ /* setup the parent pointer out of and back into this node */ ++ tp = node_parent(oldtnode); ++ NODE_INIT_PARENT(tn, tp); ++ put_child_root(tp, t, tn->key, tn); ++ + /* prepare oldtnode to be freed */ + tnode_free_init(oldtnode); + +- for (i = 0; i < olen; i += 2) { +- struct tnode *newBinNode; +- +- left = tnode_get_child(oldtnode, i); +- right = tnode_get_child(oldtnode, i+1); +- +- /* At least one of the children is empty */ +- if (left == NULL) { +- if (right == NULL) /* Both are empty */ +- continue; +- put_child(tn, i/2, right); +- continue; +- } +- +- if (right == NULL) { +- put_child(tn, i/2, left); ++ /* update all of the child parent pointers */ ++ for (i = tnode_child_length(tn); i;) { ++ inode = tnode_get_child(tn, --i); ++ ++ /* only new tnodes will be considered "full" nodes */ ++ if (!tnode_full(tn, inode)) { ++ node_set_parent(inode, tn); + continue; + } + + /* Two nonempty children */ +- newBinNode = tnode_get_child(tn, i/2); +- put_child(newBinNode, 0, left); +- put_child(newBinNode, 1, right); +- +- put_child(tn, i / 2, newBinNode); ++ node_set_parent(tnode_get_child(inode, 1), inode); ++ node_set_parent(tnode_get_child(inode, 0), inode); + + /* resize child node */ +- resize(t, newBinNode); ++ resize(t, inode); + } + +- put_child_root(tp, t, tn->key, tn); +- + /* all pointers should be clean so we are done */ + tnode_free(oldtnode); + diff --git a/target/linux/generic/patches-3.18/080-17-fib_trie-Remove-checks-for-index-tnode_child_length-.patch b/target/linux/generic/patches-3.18/080-17-fib_trie-Remove-checks-for-index-tnode_child_length-.patch new file mode 100644 index 0000000..8f7c671 --- /dev/null +++ b/target/linux/generic/patches-3.18/080-17-fib_trie-Remove-checks-for-index-tnode_child_length-.patch @@ -0,0 +1,95 @@ +From: Alexander Duyck +Date: Wed, 31 Dec 2014 10:57:02 -0800 +Subject: [PATCH] fib_trie: Remove checks for index >= tnode_child_length + from tnode_get_child + +For some reason the compiler doesn't seem to understand that when we are in +a loop that runs from tnode_child_length - 1 to 0 we don't expect the value +of tn->bits to change. As such every call to tnode_get_child was rerunning +tnode_chile_length which ended up consuming quite a bit of space in the +resultant assembly code. + +I have gone though and verified that in all cases where tnode_get_child +is used we are either winding though a fixed loop from tnode_child_length - +1 to 0, or are in a fastpath case where we are verifying the value by +either checking for any remaining bits after shifting index by bits and +testing for leaf, or by using tnode_child_length. + +size net/ipv4/fib_trie.o +Before: + text data bss dec hex filename + 15506 376 8 15890 3e12 net/ipv4/fib_trie.o + +After: + text data bss dec hex filename + 14827 376 8 15211 3b6b net/ipv4/fib_trie.o + +Signed-off-by: Alexander Duyck +Signed-off-by: David S. Miller +--- + +--- a/net/ipv4/fib_trie.c ++++ b/net/ipv4/fib_trie.c +@@ -186,8 +186,6 @@ static inline unsigned long tnode_child_ + static inline struct tnode *tnode_get_child(const struct tnode *tn, + unsigned long i) + { +- BUG_ON(i >= tnode_child_length(tn)); +- + return rtnl_dereference(tn->child[i]); + } + +@@ -195,8 +193,6 @@ static inline struct tnode *tnode_get_ch + static inline struct tnode *tnode_get_child_rcu(const struct tnode *tn, + unsigned long i) + { +- BUG_ON(i >= tnode_child_length(tn)); +- + return rcu_dereference_rtnl(tn->child[i]); + } + +@@ -371,7 +367,7 @@ static inline int tnode_full(const struc + */ + static void put_child(struct tnode *tn, unsigned long i, struct tnode *n) + { +- struct tnode *chi = rtnl_dereference(tn->child[i]); ++ struct tnode *chi = tnode_get_child(tn, i); + int isfull, wasfull; + + BUG_ON(i >= tnode_child_length(tn)); +@@ -867,7 +863,7 @@ static struct tnode *fib_find_node(struc + if (IS_LEAF(n)) + break; + +- n = rcu_dereference_rtnl(n->child[index]); ++ n = tnode_get_child_rcu(n, index); + } + + return n; +@@ -934,7 +930,7 @@ static struct list_head *fib_insert_node + } + + tp = n; +- n = rcu_dereference_rtnl(n->child[index]); ++ n = tnode_get_child_rcu(n, index); + } + + l = leaf_new(key); +@@ -1215,7 +1211,7 @@ int fib_table_lookup(struct fib_table *t + cindex = index; + } + +- n = rcu_dereference(n->child[index]); ++ n = tnode_get_child_rcu(n, index); + if (unlikely(!n)) + goto backtrace; + } +@@ -1835,7 +1831,7 @@ static void trie_collect_stats(struct tr + if (n->bits < MAX_STAT_DEPTH) + s->nodesizes[n->bits]++; + +- for (i = 0; i < tnode_child_length(n); i++) { ++ for (i = tnode_child_length(n); i--;) { + if (!rcu_access_pointer(n->child[i])) + s->nullpointers++; + } diff --git a/target/linux/generic/patches-3.18/080-18-fib_trie-Add-tracking-value-for-suffix-length.patch b/target/linux/generic/patches-3.18/080-18-fib_trie-Add-tracking-value-for-suffix-length.patch new file mode 100644 index 0000000..6a4a45e --- /dev/null +++ b/target/linux/generic/patches-3.18/080-18-fib_trie-Add-tracking-value-for-suffix-length.patch @@ -0,0 +1,234 @@ +From: Alexander Duyck +Date: Wed, 31 Dec 2014 10:57:08 -0800 +Subject: [PATCH] fib_trie: Add tracking value for suffix length + +This change adds a tracking value for the maximum suffix length of all +prefixes stored in any given tnode. With this value we can determine if we +need to backtrace or not based on if the suffix is greater than the pos +value. + +By doing this we can reduce the CPU overhead for lookups in the local table +as many of the prefixes there are 32b long and have a suffix length of 0 +meaning we can immediately backtrace to the root node without needing to +test any of the nodes between it and where we ended up. + +Signed-off-by: Alexander Duyck +Signed-off-by: David S. Miller +--- + +--- a/net/ipv4/fib_trie.c ++++ b/net/ipv4/fib_trie.c +@@ -96,6 +96,7 @@ struct tnode { + t_key key; + unsigned char bits; /* 2log(KEYLENGTH) bits needed */ + unsigned char pos; /* 2log(KEYLENGTH) bits needed */ ++ unsigned char slen; + struct tnode __rcu *parent; + struct rcu_head rcu; + union { +@@ -311,6 +312,7 @@ static struct tnode *leaf_new(t_key key) + * as the nodes are searched + */ + l->key = key; ++ l->slen = 0; + l->pos = 0; + /* set bits to 0 indicating we are not a tnode */ + l->bits = 0; +@@ -342,6 +344,7 @@ static struct tnode *tnode_new(t_key key + + if (tn) { + tn->parent = NULL; ++ tn->slen = pos; + tn->pos = pos; + tn->bits = bits; + tn->key = (shift < KEYLENGTH) ? (key >> shift) << shift : 0; +@@ -387,6 +390,9 @@ static void put_child(struct tnode *tn, + else if (!wasfull && isfull) + tn->full_children++; + ++ if (n && (tn->slen < n->slen)) ++ tn->slen = n->slen; ++ + rcu_assign_pointer(tn->child[i], n); + } + +@@ -635,6 +641,41 @@ static int halve(struct trie *t, struct + return 0; + } + ++static unsigned char update_suffix(struct tnode *tn) ++{ ++ unsigned char slen = tn->pos; ++ unsigned long stride, i; ++ ++ /* search though the list of children looking for nodes that might ++ * have a suffix greater than the one we currently have. This is ++ * why we start with a stride of 2 since a stride of 1 would ++ * represent the nodes with suffix length equal to tn->pos ++ */ ++ for (i = 0, stride = 0x2ul ; i < tnode_child_length(tn); i += stride) { ++ struct tnode *n = tnode_get_child(tn, i); ++ ++ if (!n || (n->slen <= slen)) ++ continue; ++ ++ /* update stride and slen based on new value */ ++ stride <<= (n->slen - slen); ++ slen = n->slen; ++ i &= ~(stride - 1); ++ ++ /* if slen covers all but the last bit we can stop here ++ * there will be nothing longer than that since only node ++ * 0 and 1 << (bits - 1) could have that as their suffix ++ * length. ++ */ ++ if ((slen + 1) >= (tn->pos + tn->bits)) ++ break; ++ } ++ ++ tn->slen = slen; ++ ++ return slen; ++} ++ + /* From "Implementing a dynamic compressed trie" by Stefan Nilsson of + * the Helsinki University of Technology and Matti Tikkanen of Nokia + * Telecommunications, page 6: +@@ -790,6 +831,19 @@ no_children: + /* drop dead node */ + tnode_free_init(tn); + tnode_free(tn); ++ return; ++ } ++ ++ /* Return if at least one deflate was run */ ++ if (max_work != MAX_WORK) ++ return; ++ ++ /* push the suffix length to the parent node */ ++ if (tn->slen > tn->pos) { ++ unsigned char slen = update_suffix(tn); ++ ++ if (tp && (slen > tp->slen)) ++ tp->slen = slen; + } + } + +@@ -818,8 +872,58 @@ static inline struct list_head *get_fa_h + return &li->falh; + } + +-static void insert_leaf_info(struct hlist_head *head, struct leaf_info *new) ++static void leaf_pull_suffix(struct tnode *l) ++{ ++ struct tnode *tp = node_parent(l); ++ ++ while (tp && (tp->slen > tp->pos) && (tp->slen > l->slen)) { ++ if (update_suffix(tp) > l->slen) ++ break; ++ tp = node_parent(tp); ++ } ++} ++ ++static void leaf_push_suffix(struct tnode *l) ++{ ++ struct tnode *tn = node_parent(l); ++ ++ /* if this is a new leaf then tn will be NULL and we can sort ++ * out parent suffix lengths as a part of trie_rebalance ++ */ ++ while (tn && (tn->slen < l->slen)) { ++ tn->slen = l->slen; ++ tn = node_parent(tn); ++ } ++} ++ ++static void remove_leaf_info(struct tnode *l, struct leaf_info *old) ++{ ++ struct hlist_node *prev; ++ ++ /* record the location of the pointer to this object */ ++ prev = rtnl_dereference(hlist_pprev_rcu(&old->hlist)); ++ ++ /* remove the leaf info from the list */ ++ hlist_del_rcu(&old->hlist); ++ ++ /* if we emptied the list this leaf will be freed and we can sort ++ * out parent suffix lengths as a part of trie_rebalance ++ */ ++ if (hlist_empty(&l->list)) ++ return; ++ ++ /* if we removed the tail then we need to update slen */ ++ if (!rcu_access_pointer(hlist_next_rcu(prev))) { ++ struct leaf_info *li = hlist_entry(prev, typeof(*li), hlist); ++ ++ l->slen = KEYLENGTH - li->plen; ++ leaf_pull_suffix(l); ++ } ++} ++ ++static void insert_leaf_info(struct tnode *l, struct leaf_info *new) + { ++ struct hlist_head *head = &l->list; + struct leaf_info *li = NULL, *last = NULL; + + if (hlist_empty(head)) { +@@ -836,6 +940,12 @@ static void insert_leaf_info(struct hlis + else + hlist_add_before_rcu(&new->hlist, &li->hlist); + } ++ ++ /* if we added to the tail node then we need to update slen */ ++ if (!rcu_access_pointer(hlist_next_rcu(&new->hlist))) { ++ l->slen = KEYLENGTH - new->plen; ++ leaf_push_suffix(l); ++ } + } + + /* rcu_read_lock needs to be hold by caller from readside */ +@@ -925,7 +1035,7 @@ static struct list_head *fib_insert_node + /* we have found a leaf. Prefixes have already been compared */ + if (IS_LEAF(n)) { + /* Case 1: n is a leaf, and prefixes match*/ +- insert_leaf_info(&n->list, li); ++ insert_leaf_info(n, li); + return fa_head; + } + +@@ -939,7 +1049,7 @@ static struct list_head *fib_insert_node + return NULL; + } + +- insert_leaf_info(&l->list, li); ++ insert_leaf_info(l, li); + + /* Case 2: n is a LEAF or a TNODE and the key doesn't match. + * +@@ -1206,7 +1316,7 @@ int fib_table_lookup(struct fib_table *t + /* only record pn and cindex if we are going to be chopping + * bits later. Otherwise we are just wasting cycles. + */ +- if (index) { ++ if (n->slen > n->pos) { + pn = n; + cindex = index; + } +@@ -1225,7 +1335,7 @@ int fib_table_lookup(struct fib_table *t + * between the key and the prefix exist in the region of + * the lsb and higher in the prefix. + */ +- if (unlikely(prefix_mismatch(key, n))) ++ if (unlikely(prefix_mismatch(key, n)) || (n->slen == n->pos)) + goto backtrace; + + /* exit out and process leaf */ +@@ -1425,7 +1535,7 @@ int fib_table_delete(struct fib_table *t + tb->tb_num_default--; + + if (list_empty(fa_head)) { +- hlist_del_rcu(&li->hlist); ++ remove_leaf_info(l, li); + free_leaf_info(li); + } + diff --git a/target/linux/generic/patches-3.18/080-19-fib_trie-Use-index-0ul-n-bits-instead-of-index-n-bit.patch b/target/linux/generic/patches-3.18/080-19-fib_trie-Use-index-0ul-n-bits-instead-of-index-n-bit.patch new file mode 100644 index 0000000..d5fc112 --- /dev/null +++ b/target/linux/generic/patches-3.18/080-19-fib_trie-Use-index-0ul-n-bits-instead-of-index-n-bit.patch @@ -0,0 +1,52 @@ +From: Alexander Duyck +Date: Thu, 22 Jan 2015 15:51:08 -0800 +Subject: [PATCH] fib_trie: Use index & (~0ul << n->bits) instead of index >> + n->bits + +In doing performance testing and analysis of the changes I recently found +that by shifting the index I had created an unnecessary dependency. + +I have updated the code so that we instead shift a mask by bits and then +just test against that as that should save us about 2 CPU cycles since we +can generate the mask while the key and pos are being processed. + +Signed-off-by: Alexander Duyck +Signed-off-by: David S. Miller +--- + +--- a/net/ipv4/fib_trie.c ++++ b/net/ipv4/fib_trie.c +@@ -961,12 +961,12 @@ static struct tnode *fib_find_node(struc + * prefix plus zeros for the bits in the cindex. The index + * is the difference between the key and this value. From + * this we can actually derive several pieces of data. +- * if !(index >> bits) +- * we know the value is cindex +- * else ++ * if (index & (~0ul << bits)) + * we have a mismatch in skip bits and failed ++ * else ++ * we know the value is cindex + */ +- if (index >> n->bits) ++ if (index & (~0ul << n->bits)) + return NULL; + + /* we have found a leaf. Prefixes have already been compared */ +@@ -1301,12 +1301,12 @@ int fib_table_lookup(struct fib_table *t + * prefix plus zeros for the "bits" in the prefix. The index + * is the difference between the key and this value. From + * this we can actually derive several pieces of data. +- * if !(index >> bits) +- * we know the value is child index +- * else ++ * if (index & (~0ul << bits)) + * we have a mismatch in skip bits and failed ++ * else ++ * we know the value is cindex + */ +- if (index >> n->bits) ++ if (index & (~0ul << n->bits)) + break; + + /* we have found a leaf. Prefixes have already been compared */ diff --git a/target/linux/generic/patches-3.18/080-20-fib_trie-Fix-RCU-bug-and-merge-similar-bits-of-infla.patch b/target/linux/generic/patches-3.18/080-20-fib_trie-Fix-RCU-bug-and-merge-similar-bits-of-infla.patch new file mode 100644 index 0000000..7e26127 --- /dev/null +++ b/target/linux/generic/patches-3.18/080-20-fib_trie-Fix-RCU-bug-and-merge-similar-bits-of-infla.patch @@ -0,0 +1,267 @@ +From: Alexander Duyck +Date: Thu, 22 Jan 2015 15:51:14 -0800 +Subject: [PATCH] fib_trie: Fix RCU bug and merge similar bits of inflate/halve + +This patch addresses two issues. + +The first issue is the fact that I believe I had the RCU freeing sequence +slightly out of order. As a result we could get into an issue if a caller +went into a child of a child of the new node, then backtraced into the to be +freed parent, and then attempted to access a child of a child that may have +been consumed in a resize of one of the new nodes children. To resolve this I +have moved the resize after we have freed the oldtnode. The only side effect +of this is that we will now be calling resize on more nodes in the case of +inflate due to the fact that we don't have a good way to test to see if a +full_tnode on the new node was there before or after the allocation. This +should have minimal impact however since the node should already be +correctly size so it is just the cost of calling should_inflate that we +will be taking on the node which is only a couple of cycles. + +The second issue is the fact that inflate and halve were essentially doing +the same thing after the new node was added to the trie replacing the old +one. As such it wasn't really necessary to keep the code in both functions +so I have split it out into two other functions, called replace and +update_children. + +Signed-off-by: Alexander Duyck +Signed-off-by: David S. Miller +--- + +--- a/net/ipv4/fib_trie.c ++++ b/net/ipv4/fib_trie.c +@@ -396,8 +396,30 @@ static void put_child(struct tnode *tn, + rcu_assign_pointer(tn->child[i], n); + } + +-static void put_child_root(struct tnode *tp, struct trie *t, +- t_key key, struct tnode *n) ++static void update_children(struct tnode *tn) ++{ ++ unsigned long i; ++ ++ /* update all of the child parent pointers */ ++ for (i = tnode_child_length(tn); i;) { ++ struct tnode *inode = tnode_get_child(tn, --i); ++ ++ if (!inode) ++ continue; ++ ++ /* Either update the children of a tnode that ++ * already belongs to us or update the child ++ * to point to ourselves. ++ */ ++ if (node_parent(inode) == tn) ++ update_children(inode); ++ else ++ node_set_parent(inode, tn); ++ } ++} ++ ++static inline void put_child_root(struct tnode *tp, struct trie *t, ++ t_key key, struct tnode *n) + { + if (tp) + put_child(tp, get_index(key, tp), n); +@@ -434,10 +456,35 @@ static void tnode_free(struct tnode *tn) + } + } + ++static void replace(struct trie *t, struct tnode *oldtnode, struct tnode *tn) ++{ ++ struct tnode *tp = node_parent(oldtnode); ++ unsigned long i; ++ ++ /* setup the parent pointer out of and back into this node */ ++ NODE_INIT_PARENT(tn, tp); ++ put_child_root(tp, t, tn->key, tn); ++ ++ /* update all of the child parent pointers */ ++ update_children(tn); ++ ++ /* all pointers should be clean so we are done */ ++ tnode_free(oldtnode); ++ ++ /* resize children now that oldtnode is freed */ ++ for (i = tnode_child_length(tn); i;) { ++ struct tnode *inode = tnode_get_child(tn, --i); ++ ++ /* resize child node */ ++ if (tnode_full(tn, inode)) ++ resize(t, inode); ++ } ++} ++ + static int inflate(struct trie *t, struct tnode *oldtnode) + { +- struct tnode *inode, *node0, *node1, *tn, *tp; +- unsigned long i, j, k; ++ struct tnode *tn; ++ unsigned long i; + t_key m; + + pr_debug("In inflate\n"); +@@ -446,13 +493,18 @@ static int inflate(struct trie *t, struc + if (!tn) + return -ENOMEM; + ++ /* prepare oldtnode to be freed */ ++ tnode_free_init(oldtnode); ++ + /* Assemble all of the pointers in our cluster, in this case that + * represents all of the pointers out of our allocated nodes that + * point to existing tnodes and the links between our allocated + * nodes. + */ + for (i = tnode_child_length(oldtnode), m = 1u << tn->pos; i;) { +- inode = tnode_get_child(oldtnode, --i); ++ struct tnode *inode = tnode_get_child(oldtnode, --i); ++ struct tnode *node0, *node1; ++ unsigned long j, k; + + /* An empty child */ + if (inode == NULL) +@@ -464,6 +516,9 @@ static int inflate(struct trie *t, struc + continue; + } + ++ /* drop the node in the old tnode free list */ ++ tnode_free_append(oldtnode, inode); ++ + /* An internal node with two children */ + if (inode->bits == 1) { + put_child(tn, 2 * i + 1, tnode_get_child(inode, 1)); +@@ -488,9 +543,9 @@ static int inflate(struct trie *t, struc + node1 = tnode_new(inode->key | m, inode->pos, inode->bits - 1); + if (!node1) + goto nomem; +- tnode_free_append(tn, node1); ++ node0 = tnode_new(inode->key, inode->pos, inode->bits - 1); + +- node0 = tnode_new(inode->key & ~m, inode->pos, inode->bits - 1); ++ tnode_free_append(tn, node1); + if (!node0) + goto nomem; + tnode_free_append(tn, node0); +@@ -512,53 +567,9 @@ static int inflate(struct trie *t, struc + put_child(tn, 2 * i, node0); + } + +- /* setup the parent pointer into and out of this node */ +- tp = node_parent(oldtnode); +- NODE_INIT_PARENT(tn, tp); +- put_child_root(tp, t, tn->key, tn); ++ /* setup the parent pointers into and out of this node */ ++ replace(t, oldtnode, tn); + +- /* prepare oldtnode to be freed */ +- tnode_free_init(oldtnode); +- +- /* update all child nodes parent pointers to route to us */ +- for (i = tnode_child_length(oldtnode); i;) { +- inode = tnode_get_child(oldtnode, --i); +- +- /* A leaf or an internal node with skipped bits */ +- if (!tnode_full(oldtnode, inode)) { +- node_set_parent(inode, tn); +- continue; +- } +- +- /* drop the node in the old tnode free list */ +- tnode_free_append(oldtnode, inode); +- +- /* fetch new nodes */ +- node1 = tnode_get_child(tn, 2 * i + 1); +- node0 = tnode_get_child(tn, 2 * i); +- +- /* bits == 1 then node0 and node1 represent inode's children */ +- if (inode->bits == 1) { +- node_set_parent(node1, tn); +- node_set_parent(node0, tn); +- continue; +- } +- +- /* update parent pointers in child node's children */ +- for (k = tnode_child_length(inode), j = k / 2; j;) { +- node_set_parent(tnode_get_child(inode, --k), node1); +- node_set_parent(tnode_get_child(inode, --j), node0); +- node_set_parent(tnode_get_child(inode, --k), node1); +- node_set_parent(tnode_get_child(inode, --j), node0); +- } +- +- /* resize child nodes */ +- resize(t, node1); +- resize(t, node0); +- } +- +- /* we completed without error, prepare to free old node */ +- tnode_free(oldtnode); + return 0; + nomem: + /* all pointers should be clean so we are done */ +@@ -568,7 +579,7 @@ nomem: + + static int halve(struct trie *t, struct tnode *oldtnode) + { +- struct tnode *tn, *tp, *inode, *node0, *node1; ++ struct tnode *tn; + unsigned long i; + + pr_debug("In halve\n"); +@@ -577,14 +588,18 @@ static int halve(struct trie *t, struct + if (!tn) + return -ENOMEM; + ++ /* prepare oldtnode to be freed */ ++ tnode_free_init(oldtnode); ++ + /* Assemble all of the pointers in our cluster, in this case that + * represents all of the pointers out of our allocated nodes that + * point to existing tnodes and the links between our allocated + * nodes. + */ + for (i = tnode_child_length(oldtnode); i;) { +- node1 = tnode_get_child(oldtnode, --i); +- node0 = tnode_get_child(oldtnode, --i); ++ struct tnode *node1 = tnode_get_child(oldtnode, --i); ++ struct tnode *node0 = tnode_get_child(oldtnode, --i); ++ struct tnode *inode; + + /* At least one of the children is empty */ + if (!node1 || !node0) { +@@ -609,34 +624,8 @@ static int halve(struct trie *t, struct + put_child(tn, i / 2, inode); + } + +- /* setup the parent pointer out of and back into this node */ +- tp = node_parent(oldtnode); +- NODE_INIT_PARENT(tn, tp); +- put_child_root(tp, t, tn->key, tn); +- +- /* prepare oldtnode to be freed */ +- tnode_free_init(oldtnode); +- +- /* update all of the child parent pointers */ +- for (i = tnode_child_length(tn); i;) { +- inode = tnode_get_child(tn, --i); +- +- /* only new tnodes will be considered "full" nodes */ +- if (!tnode_full(tn, inode)) { +- node_set_parent(inode, tn); +- continue; +- } +- +- /* Two nonempty children */ +- node_set_parent(tnode_get_child(inode, 1), inode); +- node_set_parent(tnode_get_child(inode, 0), inode); +- +- /* resize child node */ +- resize(t, inode); +- } +- +- /* all pointers should be clean so we are done */ +- tnode_free(oldtnode); ++ /* setup the parent pointers into and out of this node */ ++ replace(t, oldtnode, tn); + + return 0; + } diff --git a/target/linux/generic/patches-3.18/080-21-fib_trie-Fall-back-to-slen-update-on-inflate-halve-f.patch b/target/linux/generic/patches-3.18/080-21-fib_trie-Fall-back-to-slen-update-on-inflate-halve-f.patch new file mode 100644 index 0000000..058b33b --- /dev/null +++ b/target/linux/generic/patches-3.18/080-21-fib_trie-Fall-back-to-slen-update-on-inflate-halve-f.patch @@ -0,0 +1,61 @@ +From: Alexander Duyck +Date: Thu, 22 Jan 2015 15:51:20 -0800 +Subject: [PATCH] fib_trie: Fall back to slen update on inflate/halve failure + +This change corrects an issue where if inflate or halve fails we were +exiting the resize function without at least updating the slen for the +node. To correct this I have moved the update of max_size into the while +loop so that it is only decremented on a successful call to either inflate +or halve. + +Signed-off-by: Alexander Duyck +Signed-off-by: David S. Miller +--- + +--- a/net/ipv4/fib_trie.c ++++ b/net/ipv4/fib_trie.c +@@ -752,7 +752,7 @@ static void resize(struct trie *t, struc + { + struct tnode *tp = node_parent(tn), *n = NULL; + struct tnode __rcu **cptr; +- int max_work; ++ int max_work = MAX_WORK; + + pr_debug("In tnode_resize %p inflate_threshold=%d threshold=%d\n", + tn, inflate_threshold, halve_threshold); +@@ -775,8 +775,7 @@ static void resize(struct trie *t, struc + /* Double as long as the resulting node has a number of + * nonempty nodes that are above the threshold. + */ +- max_work = MAX_WORK; +- while (should_inflate(tp, tn) && max_work--) { ++ while (should_inflate(tp, tn) && max_work) { + if (inflate(t, tn)) { + #ifdef CONFIG_IP_FIB_TRIE_STATS + this_cpu_inc(t->stats->resize_node_skipped); +@@ -784,6 +783,7 @@ static void resize(struct trie *t, struc + break; + } + ++ max_work--; + tn = rtnl_dereference(*cptr); + } + +@@ -794,8 +794,7 @@ static void resize(struct trie *t, struc + /* Halve as long as the number of empty children in this + * node is above threshold. + */ +- max_work = MAX_WORK; +- while (should_halve(tp, tn) && max_work--) { ++ while (should_halve(tp, tn) && max_work) { + if (halve(t, tn)) { + #ifdef CONFIG_IP_FIB_TRIE_STATS + this_cpu_inc(t->stats->resize_node_skipped); +@@ -803,6 +802,7 @@ static void resize(struct trie *t, struc + break; + } + ++ max_work--; + tn = rtnl_dereference(*cptr); + } + diff --git a/target/linux/generic/patches-3.18/080-22-fib_trie-Add-collapse-and-should_collapse-to-resize.patch b/target/linux/generic/patches-3.18/080-22-fib_trie-Add-collapse-and-should_collapse-to-resize.patch new file mode 100644 index 0000000..19b7db7 --- /dev/null +++ b/target/linux/generic/patches-3.18/080-22-fib_trie-Add-collapse-and-should_collapse-to-resize.patch @@ -0,0 +1,206 @@ +From: Alexander Duyck +Date: Thu, 22 Jan 2015 15:51:26 -0800 +Subject: [PATCH] fib_trie: Add collapse() and should_collapse() to resize + +This patch really does two things. + +First it pulls the logic for determining if we should collapse one node out +of the tree and the actual code doing the collapse into a separate pair of +functions. This helps to make the changes to these areas more readable. + +Second it encodes the upper 32b of the empty_children value onto the +full_children value in the case of bits == KEYLENGTH. By doing this we are +able to handle the case of a 32b node where empty_children would appear to +be 0 when it was actually 1ul << 32. + +Signed-off-by: Alexander Duyck +Signed-off-by: David S. Miller +--- + +--- a/net/ipv4/fib_trie.c ++++ b/net/ipv4/fib_trie.c +@@ -83,7 +83,8 @@ + + #define MAX_STAT_DEPTH 32 + +-#define KEYLENGTH (8*sizeof(t_key)) ++#define KEYLENGTH (8*sizeof(t_key)) ++#define KEY_MAX ((t_key)~0) + + typedef unsigned int t_key; + +@@ -102,8 +103,8 @@ struct tnode { + union { + /* The fields in this struct are valid if bits > 0 (TNODE) */ + struct { +- unsigned int full_children; /* KEYLENGTH bits needed */ +- unsigned int empty_children; /* KEYLENGTH bits needed */ ++ t_key empty_children; /* KEYLENGTH bits needed */ ++ t_key full_children; /* KEYLENGTH bits needed */ + struct tnode __rcu *child[0]; + }; + /* This list pointer if valid if bits == 0 (LEAF) */ +@@ -302,6 +303,16 @@ static struct tnode *tnode_alloc(size_t + return vzalloc(size); + } + ++static inline void empty_child_inc(struct tnode *n) ++{ ++ ++n->empty_children ? : ++n->full_children; ++} ++ ++static inline void empty_child_dec(struct tnode *n) ++{ ++ n->empty_children-- ? : n->full_children--; ++} ++ + static struct tnode *leaf_new(t_key key) + { + struct tnode *l = kmem_cache_alloc(trie_leaf_kmem, GFP_KERNEL); +@@ -335,7 +346,7 @@ static struct leaf_info *leaf_info_new(i + + static struct tnode *tnode_new(t_key key, int pos, int bits) + { +- size_t sz = offsetof(struct tnode, child[1 << bits]); ++ size_t sz = offsetof(struct tnode, child[1ul << bits]); + struct tnode *tn = tnode_alloc(sz); + unsigned int shift = pos + bits; + +@@ -348,8 +359,10 @@ static struct tnode *tnode_new(t_key key + tn->pos = pos; + tn->bits = bits; + tn->key = (shift < KEYLENGTH) ? (key >> shift) << shift : 0; +- tn->full_children = 0; +- tn->empty_children = 1<full_children = 1; ++ else ++ tn->empty_children = 1ul << bits; + } + + pr_debug("AT %p s=%zu %zu\n", tn, sizeof(struct tnode), +@@ -375,11 +388,11 @@ static void put_child(struct tnode *tn, + + BUG_ON(i >= tnode_child_length(tn)); + +- /* update emptyChildren */ ++ /* update emptyChildren, overflow into fullChildren */ + if (n == NULL && chi != NULL) +- tn->empty_children++; +- else if (n != NULL && chi == NULL) +- tn->empty_children--; ++ empty_child_inc(tn); ++ if (n != NULL && chi == NULL) ++ empty_child_dec(tn); + + /* update fullChildren */ + wasfull = tnode_full(tn, chi); +@@ -630,6 +643,24 @@ static int halve(struct trie *t, struct + return 0; + } + ++static void collapse(struct trie *t, struct tnode *oldtnode) ++{ ++ struct tnode *n, *tp; ++ unsigned long i; ++ ++ /* scan the tnode looking for that one child that might still exist */ ++ for (n = NULL, i = tnode_child_length(oldtnode); !n && i;) ++ n = tnode_get_child(oldtnode, --i); ++ ++ /* compress one level */ ++ tp = node_parent(oldtnode); ++ put_child_root(tp, t, oldtnode->key, n); ++ node_set_parent(n, tp); ++ ++ /* drop dead node */ ++ node_free(oldtnode); ++} ++ + static unsigned char update_suffix(struct tnode *tn) + { + unsigned char slen = tn->pos; +@@ -729,10 +760,12 @@ static bool should_inflate(const struct + + /* Keep root node larger */ + threshold *= tp ? inflate_threshold : inflate_threshold_root; +- used += tn->full_children; + used -= tn->empty_children; ++ used += tn->full_children; + +- return tn->pos && ((50 * used) >= threshold); ++ /* if bits == KEYLENGTH then pos = 0, and will fail below */ ++ ++ return (used > 1) && tn->pos && ((50 * used) >= threshold); + } + + static bool should_halve(const struct tnode *tp, const struct tnode *tn) +@@ -744,13 +777,29 @@ static bool should_halve(const struct tn + threshold *= tp ? halve_threshold : halve_threshold_root; + used -= tn->empty_children; + +- return (tn->bits > 1) && ((100 * used) < threshold); ++ /* if bits == KEYLENGTH then used = 100% on wrap, and will fail below */ ++ ++ return (used > 1) && (tn->bits > 1) && ((100 * used) < threshold); ++} ++ ++static bool should_collapse(const struct tnode *tn) ++{ ++ unsigned long used = tnode_child_length(tn); ++ ++ used -= tn->empty_children; ++ ++ /* account for bits == KEYLENGTH case */ ++ if ((tn->bits == KEYLENGTH) && tn->full_children) ++ used -= KEY_MAX; ++ ++ /* One child or none, time to drop us from the trie */ ++ return used < 2; + } + + #define MAX_WORK 10 + static void resize(struct trie *t, struct tnode *tn) + { +- struct tnode *tp = node_parent(tn), *n = NULL; ++ struct tnode *tp = node_parent(tn); + struct tnode __rcu **cptr; + int max_work = MAX_WORK; + +@@ -764,14 +813,6 @@ static void resize(struct trie *t, struc + cptr = tp ? &tp->child[get_index(tn->key, tp)] : &t->trie; + BUG_ON(tn != rtnl_dereference(*cptr)); + +- /* No children */ +- if (tn->empty_children > (tnode_child_length(tn) - 1)) +- goto no_children; +- +- /* One child */ +- if (tn->empty_children == (tnode_child_length(tn) - 1)) +- goto one_child; +- + /* Double as long as the resulting node has a number of + * nonempty nodes that are above the threshold. + */ +@@ -807,19 +848,8 @@ static void resize(struct trie *t, struc + } + + /* Only one child remains */ +- if (tn->empty_children == (tnode_child_length(tn) - 1)) { +- unsigned long i; +-one_child: +- for (i = tnode_child_length(tn); !n && i;) +- n = tnode_get_child(tn, --i); +-no_children: +- /* compress one level */ +- put_child_root(tp, t, tn->key, n); +- node_set_parent(n, tp); +- +- /* drop dead node */ +- tnode_free_init(tn); +- tnode_free(tn); ++ if (should_collapse(tn)) { ++ collapse(t, tn); + return; + } + diff --git a/target/linux/generic/patches-3.18/080-23-fib_trie-Use-empty_children-instead-of-counting-empt.patch b/target/linux/generic/patches-3.18/080-23-fib_trie-Use-empty_children-instead-of-counting-empt.patch new file mode 100644 index 0000000..160fbe1 --- /dev/null +++ b/target/linux/generic/patches-3.18/080-23-fib_trie-Use-empty_children-instead-of-counting-empt.patch @@ -0,0 +1,34 @@ +From: Alexander Duyck +Date: Thu, 22 Jan 2015 15:51:33 -0800 +Subject: [PATCH] fib_trie: Use empty_children instead of counting empty nodes + in stats collection + +It doesn't make much sense to count the pointers ourselves when +empty_children already has a count for the number of NULL pointers stored +in the tnode. As such save ourselves the cycles and just use +empty_children. + +Signed-off-by: Alexander Duyck +Signed-off-by: David S. Miller +--- + +--- a/net/ipv4/fib_trie.c ++++ b/net/ipv4/fib_trie.c +@@ -1954,16 +1954,10 @@ static void trie_collect_stats(struct tr + hlist_for_each_entry_rcu(li, &n->list, hlist) + ++s->prefixes; + } else { +- unsigned long i; +- + s->tnodes++; + if (n->bits < MAX_STAT_DEPTH) + s->nodesizes[n->bits]++; +- +- for (i = tnode_child_length(n); i--;) { +- if (!rcu_access_pointer(n->child[i])) +- s->nullpointers++; +- } ++ s->nullpointers += n->empty_children; + } + } + rcu_read_unlock(); diff --git a/target/linux/generic/patches-3.18/080-24-fib_trie-Move-fib_find_alias-to-file-where-it-is-use.patch b/target/linux/generic/patches-3.18/080-24-fib_trie-Move-fib_find_alias-to-file-where-it-is-use.patch new file mode 100644 index 0000000..5eba700 --- /dev/null +++ b/target/linux/generic/patches-3.18/080-24-fib_trie-Move-fib_find_alias-to-file-where-it-is-use.patch @@ -0,0 +1,79 @@ +From: Alexander Duyck +Date: Thu, 22 Jan 2015 15:51:39 -0800 +Subject: [PATCH] fib_trie: Move fib_find_alias to file where it is used + +The function fib_find_alias is only accessed by functions in fib_trie.c as +such it makes sense to relocate it and cast it as static so that the +compiler can take advantage of optimizations it can do to it as a local +function. + +Signed-off-by: Alexander Duyck +Signed-off-by: David S. Miller +--- + +--- a/net/ipv4/fib_lookup.h ++++ b/net/ipv4/fib_lookup.h +@@ -32,7 +32,6 @@ int fib_dump_info(struct sk_buff *skb, u + unsigned int); + void rtmsg_fib(int event, __be32 key, struct fib_alias *fa, int dst_len, + u32 tb_id, const struct nl_info *info, unsigned int nlm_flags); +-struct fib_alias *fib_find_alias(struct list_head *fah, u8 tos, u32 prio); + + static inline void fib_result_assign(struct fib_result *res, + struct fib_info *fi) +--- a/net/ipv4/fib_semantics.c ++++ b/net/ipv4/fib_semantics.c +@@ -410,24 +410,6 @@ errout: + rtnl_set_sk_err(info->nl_net, RTNLGRP_IPV4_ROUTE, err); + } + +-/* Return the first fib alias matching TOS with +- * priority less than or equal to PRIO. +- */ +-struct fib_alias *fib_find_alias(struct list_head *fah, u8 tos, u32 prio) +-{ +- if (fah) { +- struct fib_alias *fa; +- list_for_each_entry(fa, fah, fa_list) { +- if (fa->fa_tos > tos) +- continue; +- if (fa->fa_info->fib_priority >= prio || +- fa->fa_tos < tos) +- return fa; +- } +- } +- return NULL; +-} +- + static int fib_detect_death(struct fib_info *fi, int order, + struct fib_info **last_resort, int *last_idx, + int dflt) +--- a/net/ipv4/fib_trie.c ++++ b/net/ipv4/fib_trie.c +@@ -998,6 +998,26 @@ static struct tnode *fib_find_node(struc + return n; + } + ++/* Return the first fib alias matching TOS with ++ * priority less than or equal to PRIO. ++ */ ++static struct fib_alias *fib_find_alias(struct list_head *fah, u8 tos, u32 prio) ++{ ++ struct fib_alias *fa; ++ ++ if (!fah) ++ return NULL; ++ ++ list_for_each_entry(fa, fah, fa_list) { ++ if (fa->fa_tos > tos) ++ continue; ++ if (fa->fa_info->fib_priority >= prio || fa->fa_tos < tos) ++ return fa; ++ } ++ ++ return NULL; ++} ++ + static void trie_rebalance(struct trie *t, struct tnode *tn) + { + struct tnode *tp; diff --git a/target/linux/generic/patches-3.18/080-25-fib_trie-Various-clean-ups-for-handling-slen.patch b/target/linux/generic/patches-3.18/080-25-fib_trie-Various-clean-ups-for-handling-slen.patch new file mode 100644 index 0000000..c7739d0 --- /dev/null +++ b/target/linux/generic/patches-3.18/080-25-fib_trie-Various-clean-ups-for-handling-slen.patch @@ -0,0 +1,116 @@ +From: Alexander Duyck +Date: Thu, 22 Jan 2015 15:51:45 -0800 +Subject: [PATCH] fib_trie: Various clean-ups for handling slen + +While doing further work on the fib_trie I noted a few items. + +First I was using calls that were far more complicated than they needed to +be for determining when to push/pull the suffix length. I have updated the +code to reflect the simplier logic. + +The second issue is that I realised we weren't necessarily handling the +case of a leaf_info struct surviving a flush. I have updated the logic so +that now we will call pull_suffix in the event of having a leaf info value +left in the leaf after flushing it. + +Signed-off-by: Alexander Duyck +Signed-off-by: David S. Miller +--- + +--- a/net/ipv4/fib_trie.c ++++ b/net/ipv4/fib_trie.c +@@ -917,27 +917,20 @@ static void leaf_push_suffix(struct tnod + + static void remove_leaf_info(struct tnode *l, struct leaf_info *old) + { +- struct hlist_node *prev; +- +- /* record the location of the pointer to this object */ +- prev = rtnl_dereference(hlist_pprev_rcu(&old->hlist)); ++ /* record the location of the previous list_info entry */ ++ struct hlist_node **pprev = old->hlist.pprev; ++ struct leaf_info *li = hlist_entry(pprev, typeof(*li), hlist.next); + + /* remove the leaf info from the list */ + hlist_del_rcu(&old->hlist); + +- /* if we emptied the list this leaf will be freed and we can sort +- * out parent suffix lengths as a part of trie_rebalance +- */ +- if (hlist_empty(&l->list)) ++ /* only access li if it is pointing at the last valid hlist_node */ ++ if (hlist_empty(&l->list) || (*pprev)) + return; + +- /* if we removed the tail then we need to update slen */ +- if (!rcu_access_pointer(hlist_next_rcu(prev))) { +- struct leaf_info *li = hlist_entry(prev, typeof(*li), hlist); +- +- l->slen = KEYLENGTH - li->plen; +- leaf_pull_suffix(l); +- } ++ /* update the trie with the latest suffix length */ ++ l->slen = KEYLENGTH - li->plen; ++ leaf_pull_suffix(l); + } + + static void insert_leaf_info(struct tnode *l, struct leaf_info *new) +@@ -961,7 +954,7 @@ static void insert_leaf_info(struct tnod + } + + /* if we added to the tail node then we need to update slen */ +- if (!rcu_access_pointer(hlist_next_rcu(&new->hlist))) { ++ if (l->slen < (KEYLENGTH - new->plen)) { + l->slen = KEYLENGTH - new->plen; + leaf_push_suffix(l); + } +@@ -1613,6 +1606,7 @@ static int trie_flush_leaf(struct tnode + struct hlist_head *lih = &l->list; + struct hlist_node *tmp; + struct leaf_info *li = NULL; ++ unsigned char plen = KEYLENGTH; + + hlist_for_each_entry_safe(li, tmp, lih, hlist) { + found += trie_flush_list(&li->falh); +@@ -1620,8 +1614,14 @@ static int trie_flush_leaf(struct tnode + if (list_empty(&li->falh)) { + hlist_del_rcu(&li->hlist); + free_leaf_info(li); ++ continue; + } ++ ++ plen = li->plen; + } ++ ++ l->slen = KEYLENGTH - plen; ++ + return found; + } + +@@ -1700,13 +1700,22 @@ int fib_table_flush(struct fib_table *tb + for (l = trie_firstleaf(t); l; l = trie_nextleaf(l)) { + found += trie_flush_leaf(l); + +- if (ll && hlist_empty(&ll->list)) +- trie_leaf_remove(t, ll); ++ if (ll) { ++ if (hlist_empty(&ll->list)) ++ trie_leaf_remove(t, ll); ++ else ++ leaf_pull_suffix(ll); ++ } ++ + ll = l; + } + +- if (ll && hlist_empty(&ll->list)) +- trie_leaf_remove(t, ll); ++ if (ll) { ++ if (hlist_empty(&ll->list)) ++ trie_leaf_remove(t, ll); ++ else ++ leaf_pull_suffix(ll); ++ } + + pr_debug("trie_flush found=%d\n", found); + return found; diff --git a/target/linux/generic/patches-3.18/081-pppoe-Use-workqueue-to-die-properly-when-a-PADT-is-r.patch b/target/linux/generic/patches-3.18/081-pppoe-Use-workqueue-to-die-properly-when-a-PADT-is-r.patch new file mode 100644 index 0000000..de85830 --- /dev/null +++ b/target/linux/generic/patches-3.18/081-pppoe-Use-workqueue-to-die-properly-when-a-PADT-is-r.patch @@ -0,0 +1,89 @@ +From: Simon Farnsworth +Date: Sun, 1 Mar 2015 10:54:39 +0000 +Subject: [PATCH] pppoe: Use workqueue to die properly when a PADT is received + +When a PADT frame is received, the socket may not be in a good state to +close down the PPP interface. The current implementation handles this by +simply blocking all further PPP traffic, and hoping that the lack of traffic +will trigger the user to investigate. + +Use schedule_work to get to a process context from which we clear down the +PPP interface, in a fashion analogous to hangup on a TTY-based PPP +interface. This causes pppd to disconnect immediately, and allows tools to +take immediate corrective action. + +Note that pppd's rp_pppoe.so plugin has code in it to disable the session +when it disconnects; however, as a consequence of this patch, the session is +already disabled before rp_pppoe.so is asked to disable the session. The +result is a harmless error message: + +Failed to disconnect PPPoE socket: 114 Operation already in progress + +This message is safe to ignore, as long as the error is 114 Operation +already in progress; in that specific case, it means that the PPPoE session +has already been disabled before pppd tried to disable it. + +Signed-off-by: Simon Farnsworth +Tested-by: Dan Williams +Tested-by: Christoph Schulz +Signed-off-by: David S. Miller +--- + +--- a/drivers/net/ppp/pppoe.c ++++ b/drivers/net/ppp/pppoe.c +@@ -455,6 +455,18 @@ out: + return NET_RX_DROP; + } + ++static void pppoe_unbind_sock_work(struct work_struct *work) ++{ ++ struct pppox_sock *po = container_of(work, struct pppox_sock, ++ proto.pppoe.padt_work); ++ struct sock *sk = sk_pppox(po); ++ ++ lock_sock(sk); ++ pppox_unbind_sock(sk); ++ release_sock(sk); ++ sock_put(sk); ++} ++ + /************************************************************************ + * + * Receive a PPPoE Discovery frame. +@@ -500,7 +512,8 @@ static int pppoe_disc_rcv(struct sk_buff + } + + bh_unlock_sock(sk); +- sock_put(sk); ++ if (!schedule_work(&po->proto.pppoe.padt_work)) ++ sock_put(sk); + } + + abort: +@@ -613,6 +626,8 @@ static int pppoe_connect(struct socket * + + lock_sock(sk); + ++ INIT_WORK(&po->proto.pppoe.padt_work, pppoe_unbind_sock_work); ++ + error = -EINVAL; + if (sp->sa_protocol != PX_PROTO_OE) + goto end; +--- a/include/linux/if_pppox.h ++++ b/include/linux/if_pppox.h +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + #include + + static inline struct pppoe_hdr *pppoe_hdr(const struct sk_buff *skb) +@@ -32,6 +33,7 @@ struct pppoe_opt { + struct pppoe_addr pa; /* what this socket is bound to*/ + struct sockaddr_pppox relay; /* what socket data will be + relayed to (PPPoE relaying) */ ++ struct work_struct padt_work;/* Work item for handling PADT */ + }; + + struct pptp_opt { diff --git a/target/linux/generic/patches-3.18/082-ipv6-ip6_fragment-fix-headroom-tests-and-skb-leak.patch b/target/linux/generic/patches-3.18/082-ipv6-ip6_fragment-fix-headroom-tests-and-skb-leak.patch new file mode 100644 index 0000000..7c833c4 --- /dev/null +++ b/target/linux/generic/patches-3.18/082-ipv6-ip6_fragment-fix-headroom-tests-and-skb-leak.patch @@ -0,0 +1,101 @@ +From: Florian Westphal +Date: Thu, 17 Sep 2015 11:24:48 +0100 +Subject: [PATCH] ipv6: ip6_fragment: fix headroom tests and skb leak + +David Woodhouse reports skb_under_panic when we try to push ethernet +header to fragmented ipv6 skbs: + + skbuff: skb_under_panic: text:c1277f1e len:1294 put:14 head:dec98000 + data:dec97ffc tail:0xdec9850a end:0xdec98f40 dev:br-lan +[..] +ip6_finish_output2+0x196/0x4da + +David further debugged this: + [..] offending fragments were arriving here with skb_headroom(skb)==10. + Which is reasonable, being the Solos ADSL card's header of 8 bytes + followed by 2 bytes of PPP frame type. + +The problem is that if netfilter ipv6 defragmentation is used, skb_cow() +in ip6_forward will only see reassembled skb. + +Therefore, headroom is overestimated by 8 bytes (we pulled fragment +header) and we don't check the skbs in the frag_list either. + +We can't do these checks in netfilter defrag since outdev isn't known yet. + +Furthermore, existing tests in ip6_fragment did not consider the fragment +or ipv6 header size when checking headroom of the fraglist skbs. + +While at it, also fix a skb leak on memory allocation -- ip6_fragment +must consume the skb. + +I tested this e1000 driver hacked to not allocate additional headroom +(we end up in slowpath, since LL_RESERVED_SPACE is 16). + +If 2 bytes of headroom are allocated, fastpath is taken (14 byte +ethernet header was pulled, so 16 byte headroom available in all +fragments). + +Reported-by: David Woodhouse +Diagnosed-by: David Woodhouse +Signed-off-by: Florian Westphal +Closes 20532 +--- + +--- a/net/ipv6/ip6_output.c ++++ b/net/ipv6/ip6_output.c +@@ -594,20 +594,22 @@ int ip6_fragment(struct sk_buff *skb, in + } + mtu -= hlen + sizeof(struct frag_hdr); + ++ hroom = LL_RESERVED_SPACE(rt->dst.dev); + if (skb_has_frag_list(skb)) { + int first_len = skb_pagelen(skb); + struct sk_buff *frag2; + + if (first_len - hlen > mtu || + ((first_len - hlen) & 7) || +- skb_cloned(skb)) ++ skb_cloned(skb) || ++ skb_headroom(skb) < (hroom + sizeof(struct frag_hdr))) + goto slow_path; + + skb_walk_frags(skb, frag) { + /* Correct geometry. */ + if (frag->len > mtu || + ((frag->len & 7) && frag->next) || +- skb_headroom(frag) < hlen) ++ skb_headroom(frag) < (hlen + hroom + sizeof(struct frag_hdr))) + goto slow_path_clean; + + /* Partially cloned skb? */ +@@ -624,8 +626,6 @@ int ip6_fragment(struct sk_buff *skb, in + + err = 0; + offset = 0; +- frag = skb_shinfo(skb)->frag_list; +- skb_frag_list_init(skb); + /* BUILD HEADER */ + + *prevhdr = NEXTHDR_FRAGMENT; +@@ -633,8 +633,11 @@ int ip6_fragment(struct sk_buff *skb, in + if (!tmp_hdr) { + IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), + IPSTATS_MIB_FRAGFAILS); +- return -ENOMEM; ++ err = -ENOMEM; ++ goto fail; + } ++ frag = skb_shinfo(skb)->frag_list; ++ skb_frag_list_init(skb); + + __skb_pull(skb, hlen); + fh = (struct frag_hdr *)__skb_push(skb, sizeof(struct frag_hdr)); +@@ -732,7 +735,6 @@ slow_path: + */ + + *prevhdr = NEXTHDR_FRAGMENT; +- hroom = LL_RESERVED_SPACE(rt->dst.dev); + troom = rt->dst.dev->needed_tailroom; + + /* diff --git a/target/linux/generic/patches-3.18/083-solos-pci-Increase-headroom-on-received-packets.patch b/target/linux/generic/patches-3.18/083-solos-pci-Increase-headroom-on-received-packets.patch new file mode 100644 index 0000000..7f9f926 --- /dev/null +++ b/target/linux/generic/patches-3.18/083-solos-pci-Increase-headroom-on-received-packets.patch @@ -0,0 +1,54 @@ +From: David Woodhouse +Date: Thu, 17 Sep 2015 11:19:53 +0100 +Subject: [PATCH] solos-pci: Increase headroom on received packets +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +A comment in include/linux/skbuff.h says that: + + * Various parts of the networking layer expect at least 32 bytes of + * headroom, you should not reduce this. + +This was demonstrated by a panic when handling fragmented IPv6 packets: +http://marc.info/?l=linux-netdev&m=144236093519172&w=2 + +It's not entirely clear if that comment is still valid — and if it is, +perhaps netif_rx() ought to be enforcing it with a warning. + +But either way, it is rather stupid from a performance point of view +for us to be receiving packets into a buffer which doesn't have enough +room to prepend an Ethernet header — it means that *every* incoming +packet is going to be need to be reallocated. So let's fix that. + +Signed-off-by: David Woodhouse +--- + +--- a/drivers/atm/solos-pci.c ++++ b/drivers/atm/solos-pci.c +@@ -805,7 +805,12 @@ static void solos_bh(unsigned long card_ + continue; + } + +- skb = alloc_skb(size + 1, GFP_ATOMIC); ++ /* Use netdev_alloc_skb() because it adds NET_SKB_PAD of ++ * headroom, and ensures we can route packets back out an ++ * Ethernet interface (for example) without having to ++ * reallocate. Adding NET_IP_ALIGN also ensures that both ++ * PPPoATM and PPPoEoBR2684 packets end up aligned. */ ++ skb = netdev_alloc_skb_ip_align(NULL, size + 1); + if (!skb) { + if (net_ratelimit()) + dev_warn(&card->dev->dev, "Failed to allocate sk_buff for RX\n"); +@@ -869,7 +874,10 @@ static void solos_bh(unsigned long card_ + /* Allocate RX skbs for any ports which need them */ + if (card->using_dma && card->atmdev[port] && + !card->rx_skb[port]) { +- struct sk_buff *skb = alloc_skb(RX_DMA_SIZE, GFP_ATOMIC); ++ /* Unlike the MMIO case (qv) we can't add NET_IP_ALIGN ++ * here; the FPGA can only DMA to addresses which are ++ * aligned to 4 bytes. */ ++ struct sk_buff *skb = dev_alloc_skb(RX_DMA_SIZE); + if (skb) { + SKB_CB(skb)->dma_addr = + pci_map_single(card->dev, skb->data, diff --git a/target/linux/generic/patches-3.18/090-overlayfs-fallback-to-readonly-when-full.patch b/target/linux/generic/patches-3.18/090-overlayfs-fallback-to-readonly-when-full.patch new file mode 100644 index 0000000..340a412 --- /dev/null +++ b/target/linux/generic/patches-3.18/090-overlayfs-fallback-to-readonly-when-full.patch @@ -0,0 +1,109 @@ +[linux-unionfs added to Cc] + +On Tue, May 19, 2015 at 09:51:20AM +0200, Bastian Bittorf wrote: +> Hi Miklos, +> +> sorry for writing directly to you, feel free to forward +> this to the appropriate mailinglist. +> +> we have a problem with mainline overlay filesystem on kernel 3.18: +> https://dev.openwrt.org/ticket/19564 +> +> 2 things are odd: +> when the working filesystem is full, overlays fails with: +> +> overlayfs: failed to create directory /overlay/work/work +> +> what is strange, that we call it with: +> +> mount(overlay, "/mnt", "overlay", MS_NOATIME, lowerdir) +> +> see here: +> http://nbd.name/gitweb.cgi?p=fstools.git;a=blob;f=libfstools/mount.c;h=81176ce399b4cd8e2d347c0008c13dec92407f55;hb=e6004000ff15d7bd32cf5663e8690fc94d7ec747#l125 +> +> do you have an idea whats wrong? +> 1) is it really needed, that we need space for creating dir "/overlay/work"? +> 2) why does overlay need "/overlay/work/work"? + +The work directory is needed for atomic copy-up and similar. It is not actually +necessary to mount a read-only overlay. Post 4.0 it is possible to mount the +overlay without workdir (but even then it won't happen automatically in case the +upper fs is full, so this should be fixed in the latest kernel too). + +Could you please try the following patch? If the workdir can't be created it +will fall back to mounting the overlay read-only. + +Thanks, +Miklos + +--- + fs/overlayfs/copy_up.c | 3 +++ + fs/overlayfs/dir.c | 9 +++++++++ + fs/overlayfs/super.c | 12 +++++++++--- + 3 files changed, 21 insertions(+), 3 deletions(-) + +--- a/fs/overlayfs/copy_up.c ++++ b/fs/overlayfs/copy_up.c +@@ -300,6 +300,9 @@ int ovl_copy_up_one(struct dentry *paren + struct cred *override_cred; + char *link = NULL; + ++ if (WARN_ON(!workdir)) ++ return -EROFS; ++ + ovl_path_upper(parent, &parentpath); + upperdir = parentpath.dentry; + +--- a/fs/overlayfs/dir.c ++++ b/fs/overlayfs/dir.c +@@ -222,6 +222,9 @@ static struct dentry *ovl_clear_empty(st + struct kstat stat; + int err; + ++ if (WARN_ON(!workdir)) ++ return ERR_PTR(-EROFS); ++ + err = ovl_lock_rename_workdir(workdir, upperdir); + if (err) + goto out; +@@ -322,6 +325,9 @@ static int ovl_create_over_whiteout(stru + struct dentry *newdentry; + int err; + ++ if (WARN_ON(!workdir)) ++ return -EROFS; ++ + err = ovl_lock_rename_workdir(workdir, upperdir); + if (err) + goto out; +@@ -506,6 +512,9 @@ static int ovl_remove_and_whiteout(struc + struct dentry *opaquedir = NULL; + int err; + ++ if (WARN_ON(!workdir)) ++ return -EROFS; ++ + if (is_dir) { + opaquedir = ovl_check_empty_and_clear(dentry); + err = PTR_ERR(opaquedir); +--- a/fs/overlayfs/super.c ++++ b/fs/overlayfs/super.c +@@ -740,9 +740,15 @@ static int ovl_fill_super(struct super_b + ufs->workdir = ovl_workdir_create(ufs->upper_mnt, workpath.dentry); + err = PTR_ERR(ufs->workdir); + if (IS_ERR(ufs->workdir)) { +- pr_err("overlayfs: failed to create directory %s/%s\n", +- ufs->config.workdir, OVL_WORKDIR_NAME); +- goto out_put_lower_mnt; ++ if (err == -ENOSPC || err == -EROFS) { ++ pr_warning("overlayfs: failed to create work directory (%s), mounting read-only\n", err == ENOSPC ? "ENOSPC" : "EROFS"); ++ sb->s_flags |= MS_RDONLY; ++ ufs->workdir = NULL; ++ } else { ++ pr_err("overlayfs: failed to create directory %s/%s\n", ++ ufs->config.workdir, OVL_WORKDIR_NAME); ++ goto out_put_lower_mnt; ++ } + } + + /* diff --git a/target/linux/generic/patches-3.18/091-mtd-spi-nor-add-support-Spansion_S25FL164K b/target/linux/generic/patches-3.18/091-mtd-spi-nor-add-support-Spansion_S25FL164K new file mode 100644 index 0000000..d9831f4 --- /dev/null +++ b/target/linux/generic/patches-3.18/091-mtd-spi-nor-add-support-Spansion_S25FL164K @@ -0,0 +1,10 @@ +--- a/drivers/mtd/spi-nor/spi-nor.c ++++ b/drivers/mtd/spi-nor/spi-nor.c +@@ -566,6 +566,7 @@ static const struct spi_device_id spi_no + { "s25fl008k", INFO(0xef4014, 0, 64 * 1024, 16, SECT_4K) }, + { "s25fl016k", INFO(0xef4015, 0, 64 * 1024, 32, SECT_4K) }, + { "s25fl064k", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) }, ++ { "s25fl164k", INFO(0x014017, 0, 64 * 1024, 128, SECT_4K) }, + + /* SST -- large erase sizes are "overlays", "sectors" are 4K */ + { "sst25vf040b", INFO(0xbf258d, 0, 64 * 1024, 8, SECT_4K | SST_WRITE) }, diff --git a/target/linux/generic/patches-3.18/092-01-spi-Check-to-see-if-the-device-is-processing-a-messa.patch b/target/linux/generic/patches-3.18/092-01-spi-Check-to-see-if-the-device-is-processing-a-messa.patch new file mode 100644 index 0000000..fa3ab6a --- /dev/null +++ b/target/linux/generic/patches-3.18/092-01-spi-Check-to-see-if-the-device-is-processing-a-messa.patch @@ -0,0 +1,47 @@ +From: Mark Brown +Date: Tue, 9 Dec 2014 19:46:56 +0000 +Subject: [PATCH] spi: Check to see if the device is processing a message + before we idle + +cur_msg is updated under the queue lock and holds the message we are +currently processing. Since currently we only ever do removals in the +pump kthread it doesn't matter in what order we do things but we want +to be able to push things out from the submitting thread so pull the +check to see if we're currently handling a message before we check to +see if the queue is idle. + +Signed-off-by: Mark Brown +--- + +--- a/drivers/spi/spi.c ++++ b/drivers/spi/spi.c +@@ -891,8 +891,16 @@ static void spi_pump_messages(struct kth + bool was_busy = false; + int ret; + +- /* Lock queue and check for queue work */ ++ /* Lock queue */ + spin_lock_irqsave(&master->queue_lock, flags); ++ ++ /* Make sure we are not already running a message */ ++ if (master->cur_msg) { ++ spin_unlock_irqrestore(&master->queue_lock, flags); ++ return; ++ } ++ ++ /* Check if the queue is idle */ + if (list_empty(&master->queue) || !master->running) { + if (!master->busy) { + spin_unlock_irqrestore(&master->queue_lock, flags); +@@ -916,11 +924,6 @@ static void spi_pump_messages(struct kth + return; + } + +- /* Make sure we are not already running a message */ +- if (master->cur_msg) { +- spin_unlock_irqrestore(&master->queue_lock, flags); +- return; +- } + /* Extract head of queue */ + master->cur_msg = + list_first_entry(&master->queue, struct spi_message, queue); diff --git a/target/linux/generic/patches-3.18/092-02-spi-Pump-transfers-inside-calling-context-for-spi_sy.patch b/target/linux/generic/patches-3.18/092-02-spi-Pump-transfers-inside-calling-context-for-spi_sy.patch new file mode 100644 index 0000000..ddfb060 --- /dev/null +++ b/target/linux/generic/patches-3.18/092-02-spi-Pump-transfers-inside-calling-context-for-spi_sy.patch @@ -0,0 +1,184 @@ +From: Mark Brown +Date: Tue, 9 Dec 2014 21:38:05 +0000 +Subject: [PATCH] spi: Pump transfers inside calling context for spi_sync() + +If we are using the standard SPI message pump (which all drivers should be +transitioning over to) then special case the message enqueue and instead of +starting the worker thread to push messages to the hardware do so in the +context of the caller if the controller is idle. This avoids a context +switch in the common case where the controller has a single user in a +single thread, for short PIO transfers there may be no need to context +switch away from the calling context to complete the transfer. + +The code is a bit more complex than is desirable in part due to the need +to handle drivers not using the standard queue and in part due to handling +the various combinations of bus locking and asynchronous submission in +interrupt context. + +It is still suboptimal since it will still wake the message pump for each +transfer in order to schedule idling of the hardware and if multiple +contexts are using the controller simultaneously a caller may end up +pumping a message for some random other thread rather than for itself, +and if the thread ends up deferring due to another context idling the +hardware then it will just busy wait. It can, however, have the benefit +of aggregating power up and down of the hardware when a caller performs +a series of transfers back to back without any need for the use of +spi_async(). + +Signed-off-by: Mark Brown +--- + +--- a/drivers/spi/spi.c ++++ b/drivers/spi/spi.c +@@ -882,6 +882,9 @@ EXPORT_SYMBOL_GPL(spi_finalize_current_t + * needs processing and if so call out to the driver to initialize hardware + * and transfer each message. + * ++ * Note that it is called both from the kthread itself and also from ++ * inside spi_sync(); the queue extraction handling at the top of the ++ * function should deal with this safely. + */ + static void spi_pump_messages(struct kthread_work *work) + { +@@ -900,6 +903,13 @@ static void spi_pump_messages(struct kth + return; + } + ++ /* If another context is idling the device then defer */ ++ if (master->idling) { ++ queue_kthread_work(&master->kworker, &master->pump_messages); ++ spin_unlock_irqrestore(&master->queue_lock, flags); ++ return; ++ } ++ + /* Check if the queue is idle */ + if (list_empty(&master->queue) || !master->running) { + if (!master->busy) { +@@ -907,7 +917,9 @@ static void spi_pump_messages(struct kth + return; + } + master->busy = false; ++ master->idling = true; + spin_unlock_irqrestore(&master->queue_lock, flags); ++ + kfree(master->dummy_rx); + master->dummy_rx = NULL; + kfree(master->dummy_tx); +@@ -921,6 +933,10 @@ static void spi_pump_messages(struct kth + pm_runtime_put_autosuspend(master->dev.parent); + } + trace_spi_master_idle(master); ++ ++ spin_lock_irqsave(&master->queue_lock, flags); ++ master->idling = false; ++ spin_unlock_irqrestore(&master->queue_lock, flags); + return; + } + +@@ -1166,12 +1182,9 @@ static int spi_destroy_queue(struct spi_ + return 0; + } + +-/** +- * spi_queued_transfer - transfer function for queued transfers +- * @spi: spi device which is requesting transfer +- * @msg: spi message which is to handled is queued to driver queue +- */ +-static int spi_queued_transfer(struct spi_device *spi, struct spi_message *msg) ++static int __spi_queued_transfer(struct spi_device *spi, ++ struct spi_message *msg, ++ bool need_pump) + { + struct spi_master *master = spi->master; + unsigned long flags; +@@ -1186,13 +1199,23 @@ static int spi_queued_transfer(struct sp + msg->status = -EINPROGRESS; + + list_add_tail(&msg->queue, &master->queue); +- if (!master->busy) ++ if (!master->busy && need_pump) + queue_kthread_work(&master->kworker, &master->pump_messages); + + spin_unlock_irqrestore(&master->queue_lock, flags); + return 0; + } + ++/** ++ * spi_queued_transfer - transfer function for queued transfers ++ * @spi: spi device which is requesting transfer ++ * @msg: spi message which is to handled is queued to driver queue ++ */ ++static int spi_queued_transfer(struct spi_device *spi, struct spi_message *msg) ++{ ++ return __spi_queued_transfer(spi, msg, true); ++} ++ + static int spi_master_initialize_queue(struct spi_master *master) + { + int ret; +@@ -2105,19 +2128,46 @@ static int __spi_sync(struct spi_device + DECLARE_COMPLETION_ONSTACK(done); + int status; + struct spi_master *master = spi->master; ++ unsigned long flags; ++ ++ status = __spi_validate(spi, message); ++ if (status != 0) ++ return status; + + message->complete = spi_complete; + message->context = &done; ++ message->spi = spi; + + if (!bus_locked) + mutex_lock(&master->bus_lock_mutex); + +- status = spi_async_locked(spi, message); ++ /* If we're not using the legacy transfer method then we will ++ * try to transfer in the calling context so special case. ++ * This code would be less tricky if we could remove the ++ * support for driver implemented message queues. ++ */ ++ if (master->transfer == spi_queued_transfer) { ++ spin_lock_irqsave(&master->bus_lock_spinlock, flags); ++ ++ trace_spi_message_submit(message); ++ ++ status = __spi_queued_transfer(spi, message, false); ++ ++ spin_unlock_irqrestore(&master->bus_lock_spinlock, flags); ++ } else { ++ status = spi_async_locked(spi, message); ++ } + + if (!bus_locked) + mutex_unlock(&master->bus_lock_mutex); + + if (status == 0) { ++ /* Push out the messages in the calling context if we ++ * can. ++ */ ++ if (master->transfer == spi_queued_transfer) ++ spi_pump_messages(&master->pump_messages); ++ + wait_for_completion(&done); + status = message->status; + } +--- a/include/linux/spi/spi.h ++++ b/include/linux/spi/spi.h +@@ -260,6 +260,7 @@ static inline void spi_unregister_driver + * @pump_messages: work struct for scheduling work to the message pump + * @queue_lock: spinlock to syncronise access to message queue + * @queue: message queue ++ * @idling: the device is entering idle state + * @cur_msg: the currently in-flight message + * @cur_msg_prepared: spi_prepare_message was called for the currently + * in-flight message +@@ -425,6 +426,7 @@ struct spi_master { + spinlock_t queue_lock; + struct list_head queue; + struct spi_message *cur_msg; ++ bool idling; + bool busy; + bool running; + bool rt; diff --git a/target/linux/generic/patches-3.18/092-03-spi-Only-idle-the-message-pump-in-the-worker-kthread.patch b/target/linux/generic/patches-3.18/092-03-spi-Only-idle-the-message-pump-in-the-worker-kthread.patch new file mode 100644 index 0000000..e8cbe61 --- /dev/null +++ b/target/linux/generic/patches-3.18/092-03-spi-Only-idle-the-message-pump-in-the-worker-kthread.patch @@ -0,0 +1,83 @@ +From: Mark Brown +Date: Wed, 10 Dec 2014 13:46:33 +0000 +Subject: [PATCH] spi: Only idle the message pump in the worker kthread + +In order to avoid the situation where the kthread is waiting for another +context to make the hardware idle let the message pump know if it's being +called from the worker thread context and if it isn't then defer to the +worker thread instead of idling the hardware immediately. This will ensure +that if this situation happens we block rather than busy waiting. + +Signed-off-by: Mark Brown +--- + +--- a/drivers/spi/spi.c ++++ b/drivers/spi/spi.c +@@ -875,8 +875,9 @@ void spi_finalize_current_transfer(struc + EXPORT_SYMBOL_GPL(spi_finalize_current_transfer); + + /** +- * spi_pump_messages - kthread work function which processes spi message queue +- * @work: pointer to kthread work struct contained in the master struct ++ * __spi_pump_messages - function which processes spi message queue ++ * @master: master to process queue for ++ * @in_kthread: true if we are in the context of the message pump thread + * + * This function checks if there is any spi message in the queue that + * needs processing and if so call out to the driver to initialize hardware +@@ -886,10 +887,8 @@ EXPORT_SYMBOL_GPL(spi_finalize_current_t + * inside spi_sync(); the queue extraction handling at the top of the + * function should deal with this safely. + */ +-static void spi_pump_messages(struct kthread_work *work) ++static void __spi_pump_messages(struct spi_master *master, bool in_kthread) + { +- struct spi_master *master = +- container_of(work, struct spi_master, pump_messages); + unsigned long flags; + bool was_busy = false; + int ret; +@@ -916,6 +915,15 @@ static void spi_pump_messages(struct kth + spin_unlock_irqrestore(&master->queue_lock, flags); + return; + } ++ ++ /* Only do teardown in the thread */ ++ if (!in_kthread) { ++ queue_kthread_work(&master->kworker, ++ &master->pump_messages); ++ spin_unlock_irqrestore(&master->queue_lock, flags); ++ return; ++ } ++ + master->busy = false; + master->idling = true; + spin_unlock_irqrestore(&master->queue_lock, flags); +@@ -1004,6 +1012,18 @@ static void spi_pump_messages(struct kth + } + } + ++/** ++ * spi_pump_messages - kthread work function which processes spi message queue ++ * @work: pointer to kthread work struct contained in the master struct ++ */ ++static void spi_pump_messages(struct kthread_work *work) ++{ ++ struct spi_master *master = ++ container_of(work, struct spi_master, pump_messages); ++ ++ __spi_pump_messages(master, true); ++} ++ + static int spi_init_queue(struct spi_master *master) + { + struct sched_param param = { .sched_priority = MAX_RT_PRIO - 1 }; +@@ -2166,7 +2186,7 @@ static int __spi_sync(struct spi_device + * can. + */ + if (master->transfer == spi_queued_transfer) +- spi_pump_messages(&master->pump_messages); ++ __spi_pump_messages(master, false); + + wait_for_completion(&done); + status = message->status; diff --git a/target/linux/generic/patches-3.18/095-api-fix-compatibility-of-linux-in.h-with-netinet-in..patch b/target/linux/generic/patches-3.18/095-api-fix-compatibility-of-linux-in.h-with-netinet-in..patch new file mode 100644 index 0000000..4c5cd59 --- /dev/null +++ b/target/linux/generic/patches-3.18/095-api-fix-compatibility-of-linux-in.h-with-netinet-in..patch @@ -0,0 +1,146 @@ +From 279c6c7fa64f5763e6b9f05e7ab3840092e702e7 Mon Sep 17 00:00:00 2001 +From: Stephen Hemminger +Date: Mon, 29 Jun 2015 14:57:48 -1000 +Subject: [PATCH] api: fix compatibility of linux/in.h with netinet/in.h + +u +This fixes breakage to iproute2 build with recent kernel headers +caused by: + commit a263653ed798216c0069922d7b5237ca49436007 + Author: Pablo Neira Ayuso + Date: Wed Jun 17 10:28:27 2015 -0500 + + netfilter: don't pull include/linux/netfilter.h from netns headers + +The issue is that definitions in linux/in.h overlap with those +in netinet/in.h. This patch solves this by introducing the same +mechanism as was used to solve the same problem with linux/in6.h + +Signed-off-by: Stephen Hemminger +Signed-off-by: David S. Miller +--- + include/uapi/linux/in.h | 16 +++++++++++++--- + include/uapi/linux/libc-compat.h | 22 ++++++++++++++++++++++ + 2 files changed, 35 insertions(+), 3 deletions(-) + +--- a/include/uapi/linux/in.h ++++ b/include/uapi/linux/in.h +@@ -19,8 +19,10 @@ + #define _UAPI_LINUX_IN_H + + #include ++#include + #include + ++#if __UAPI_DEF_IN_IPPROTO + /* Standard well-defined IP protocols. */ + enum { + IPPROTO_IP = 0, /* Dummy protocol for TCP */ +@@ -73,12 +75,14 @@ enum { + #define IPPROTO_RAW IPPROTO_RAW + IPPROTO_MAX + }; ++#endif + +- ++#if __UAPI_DEF_IN_ADDR + /* Internet address. */ + struct in_addr { + __be32 s_addr; + }; ++#endif + + #define IP_TOS 1 + #define IP_TTL 2 +@@ -154,6 +158,7 @@ struct in_addr { + + /* Request struct for multicast socket ops */ + ++#if __UAPI_DEF_IP_MREQ + struct ip_mreq { + struct in_addr imr_multiaddr; /* IP multicast address of group */ + struct in_addr imr_interface; /* local IP address of interface */ +@@ -205,14 +210,18 @@ struct group_filter { + #define GROUP_FILTER_SIZE(numsrc) \ + (sizeof(struct group_filter) - sizeof(struct __kernel_sockaddr_storage) \ + + (numsrc) * sizeof(struct __kernel_sockaddr_storage)) ++#endif + ++#if __UAPI_DEF_IN_PKTINFO + struct in_pktinfo { + int ipi_ifindex; + struct in_addr ipi_spec_dst; + struct in_addr ipi_addr; + }; ++#endif + + /* Structure describing an Internet (IP) socket address. */ ++#if __UAPI_DEF_SOCKADDR_IN + #define __SOCK_SIZE__ 16 /* sizeof(struct sockaddr) */ + struct sockaddr_in { + __kernel_sa_family_t sin_family; /* Address family */ +@@ -224,8 +233,9 @@ struct sockaddr_in { + sizeof(unsigned short int) - sizeof(struct in_addr)]; + }; + #define sin_zero __pad /* for BSD UNIX comp. -FvK */ ++#endif + +- ++#if __UAPI_DEF_IN_CLASS + /* + * Definitions of the bits in an Internet address integer. + * On subnets, host and network parts are found according +@@ -276,7 +286,7 @@ struct sockaddr_in { + #define INADDR_ALLHOSTS_GROUP 0xe0000001U /* 224.0.0.1 */ + #define INADDR_ALLRTRS_GROUP 0xe0000002U /* 224.0.0.2 */ + #define INADDR_MAX_LOCAL_GROUP 0xe00000ffU /* 224.0.0.255 */ +- ++#endif + + /* contains the htonl type stuff.. */ + #include +--- a/include/uapi/linux/libc-compat.h ++++ b/include/uapi/linux/libc-compat.h +@@ -56,6 +56,13 @@ + + /* GLIBC headers included first so don't define anything + * that would already be defined. */ ++#define __UAPI_DEF_IN_ADDR 0 ++#define __UAPI_DEF_IN_IPPROTO 0 ++#define __UAPI_DEF_IN_PKTINFO 0 ++#define __UAPI_DEF_IP_MREQ 0 ++#define __UAPI_DEF_SOCKADDR_IN 0 ++#define __UAPI_DEF_IN_CLASS 0 ++ + #define __UAPI_DEF_IN6_ADDR 0 + /* The exception is the in6_addr macros which must be defined + * if the glibc code didn't define them. This guard matches +@@ -76,6 +83,13 @@ + /* Linux headers included first, and we must define everything + * we need. The expectation is that glibc will check the + * __UAPI_DEF_* defines and adjust appropriately. */ ++#define __UAPI_DEF_IN_ADDR 1 ++#define __UAPI_DEF_IN_IPPROTO 1 ++#define __UAPI_DEF_IN_PKTINFO 1 ++#define __UAPI_DEF_IP_MREQ 1 ++#define __UAPI_DEF_SOCKADDR_IN 1 ++#define __UAPI_DEF_IN_CLASS 1 ++ + #define __UAPI_DEF_IN6_ADDR 1 + /* We unconditionally define the in6_addr macros and glibc must + * coordinate. */ +@@ -99,6 +113,14 @@ + * that we need. */ + #else /* !defined(__GLIBC__) */ + ++/* Definitions for in.h */ ++#define __UAPI_DEF_IN_ADDR 1 ++#define __UAPI_DEF_IN_IPPROTO 1 ++#define __UAPI_DEF_IN_PKTINFO 1 ++#define __UAPI_DEF_IP_MREQ 1 ++#define __UAPI_DEF_SOCKADDR_IN 1 ++#define __UAPI_DEF_IN_CLASS 1 ++ + /* Definitions for in6.h */ + #define __UAPI_DEF_IN6_ADDR 1 + #define __UAPI_DEF_IN6_ADDR_ALT 1 diff --git a/target/linux/generic/patches-3.18/099-module_arch_freeing_init-new-hook-for-archs-before-m.patch b/target/linux/generic/patches-3.18/099-module_arch_freeing_init-new-hook-for-archs-before-m.patch new file mode 100644 index 0000000..d00f751 --- /dev/null +++ b/target/linux/generic/patches-3.18/099-module_arch_freeing_init-new-hook-for-archs-before-m.patch @@ -0,0 +1,182 @@ +From: Rusty Russell +Date: Tue, 20 Jan 2015 09:07:04 +1030 +Subject: [PATCH] module_arch_freeing_init(): new hook for archs before module->module_init freed. + +Archs have been abusing module_free() to clean up their arch-specific +allocations. Since module_free() is also (ab)used by BPF and trace code, +let's keep it to simple allocations, and provide a hook called before +that. + +This means that avr32, ia64, parisc and s390 no longer need to implement +their own module_free() at all. avr32 doesn't need module_finalize() +either. + +Signed-off-by: Rusty Russell +Cc: Chris Metcalf +Cc: Haavard Skinnemoen +Cc: Hans-Christian Egtvedt +Cc: Tony Luck +Cc: Fenghua Yu +Cc: "James E.J. Bottomley" +Cc: Helge Deller +Cc: Martin Schwidefsky +Cc: Heiko Carstens +Cc: linux-kernel@vger.kernel.org +Cc: linux-ia64@vger.kernel.org +Cc: linux-parisc@vger.kernel.org +Cc: linux-s390@vger.kernel.org + +Origin: backport, https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=d453cded05ee219b77815ea194dc36efa5398bca +--- + arch/avr32/kernel/module.c | 13 +------------ + arch/ia64/kernel/module.c | 6 ++---- + arch/parisc/kernel/module.c | 6 +----- + arch/s390/kernel/module.c | 10 +++------- + arch/tile/kernel/module.c | 2 +- + include/linux/moduleloader.h | 2 ++ + kernel/module.c | 7 +++++++ + 7 files changed, 17 insertions(+), 29 deletions(-) + +--- a/arch/avr32/kernel/module.c ++++ b/arch/avr32/kernel/module.c +@@ -19,12 +19,10 @@ + #include + #include + +-void module_free(struct module *mod, void *module_region) ++void module_arch_freeing_init(struct module *mod) + { + vfree(mod->arch.syminfo); + mod->arch.syminfo = NULL; +- +- vfree(module_region); + } + + static inline int check_rela(Elf32_Rela *rela, struct module *module, +@@ -291,12 +289,3 @@ int apply_relocate_add(Elf32_Shdr *sechd + + return ret; + } +- +-int module_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, +- struct module *module) +-{ +- vfree(module->arch.syminfo); +- module->arch.syminfo = NULL; +- +- return 0; +-} +--- a/arch/ia64/kernel/module.c ++++ b/arch/ia64/kernel/module.c +@@ -305,14 +305,12 @@ plt_target (struct plt_entry *plt) + #endif /* !USE_BRL */ + + void +-module_free (struct module *mod, void *module_region) ++module_arch_freeing_init (struct module *mod) + { +- if (mod && mod->arch.init_unw_table && +- module_region == mod->module_init) { ++ if (mod->arch.init_unw_table) { + unw_remove_unwind_table(mod->arch.init_unw_table); + mod->arch.init_unw_table = NULL; + } +- vfree(module_region); + } + + /* Have we already seen one of these relocations? */ +--- a/arch/parisc/kernel/module.c ++++ b/arch/parisc/kernel/module.c +@@ -298,14 +298,10 @@ static inline unsigned long count_stubs( + } + #endif + +- +-/* Free memory returned from module_alloc */ +-void module_free(struct module *mod, void *module_region) ++void module_arch_freeing_init(struct module *mod) + { + kfree(mod->arch.section); + mod->arch.section = NULL; +- +- vfree(module_region); + } + + /* Additional bytes needed in front of individual sections */ +--- a/arch/s390/kernel/module.c ++++ b/arch/s390/kernel/module.c +@@ -55,14 +55,10 @@ void *module_alloc(unsigned long size) + } + #endif + +-/* Free memory returned from module_alloc */ +-void module_free(struct module *mod, void *module_region) ++void module_arch_freeing_init(struct module *mod) + { +- if (mod) { +- vfree(mod->arch.syminfo); +- mod->arch.syminfo = NULL; +- } +- vfree(module_region); ++ vfree(mod->arch.syminfo); ++ mod->arch.syminfo = NULL; + } + + static void check_rela(Elf_Rela *rela, struct module *me) +--- a/arch/tile/kernel/module.c ++++ b/arch/tile/kernel/module.c +@@ -83,7 +83,7 @@ void module_free(struct module *mod, voi + 0, 0, 0, NULL, NULL, 0); + + /* +- * FIXME: If module_region == mod->module_init, trim exception ++ * FIXME: Add module_arch_freeing_init to trim exception + * table entries. + */ + } +--- a/include/linux/moduleloader.h ++++ b/include/linux/moduleloader.h +@@ -82,4 +82,6 @@ int module_finalize(const Elf_Ehdr *hdr, + /* Any cleanup needed when module leaves. */ + void module_arch_cleanup(struct module *mod); + ++/* Any cleanup before freeing mod->module_init */ ++void module_arch_freeing_init(struct module *mod); + #endif +--- a/kernel/module.c ++++ b/kernel/module.c +@@ -1833,6 +1833,10 @@ void __weak module_arch_cleanup(struct m + { + } + ++void __weak module_arch_freeing_init(struct module *mod) ++{ ++} ++ + /* Free a module, remove from lists, etc. */ + static void free_module(struct module *mod) + { +@@ -1865,6 +1869,7 @@ static void free_module(struct module *m + + /* This may be NULL, but that's OK */ + unset_module_init_ro_nx(mod); ++ module_arch_freeing_init(mod); + module_free(mod, mod->module_init); + kfree(mod->args); + percpu_modfree(mod); +@@ -2954,6 +2959,7 @@ static struct module *layout_and_allocat + static void module_deallocate(struct module *mod, struct load_info *info) + { + percpu_modfree(mod); ++ module_arch_freeing_init(mod); + module_free(mod, mod->module_init); + module_free(mod, mod->module_core); + } +@@ -3077,6 +3083,7 @@ static int do_init_module(struct module + mod->strtab = mod->core_strtab; + #endif + unset_module_init_ro_nx(mod); ++ module_arch_freeing_init(mod); + module_free(mod, mod->module_init); + mod->module_init = NULL; + mod->init_size = 0; diff --git a/target/linux/generic/patches-3.18/100-pppoe-drop-pppoe-device-in-pppoe_unbind_sock_work.patch b/target/linux/generic/patches-3.18/100-pppoe-drop-pppoe-device-in-pppoe_unbind_sock_work.patch new file mode 100644 index 0000000..c461b3e --- /dev/null +++ b/target/linux/generic/patches-3.18/100-pppoe-drop-pppoe-device-in-pppoe_unbind_sock_work.patch @@ -0,0 +1,27 @@ +From: Felix Fietkau +Date: Sat, 9 May 2015 23:03:47 +0200 +Subject: [PATCH] pppoe: drop pppoe device in pppoe_unbind_sock_work + +After receiving a PADT and the socket is closed, user space will no +longer drop the reference to the pppoe device. +This leads to errors like this: + +[ 488.570000] unregister_netdevice: waiting for eth0.2 to become free. Usage count = 2 + +Fixes: 287f3a943fe ("pppoe: Use workqueue to die properly when a PADT is received") +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ppp/pppoe.c ++++ b/drivers/net/ppp/pppoe.c +@@ -462,6 +462,10 @@ static void pppoe_unbind_sock_work(struc + struct sock *sk = sk_pppox(po); + + lock_sock(sk); ++ if (po->pppoe_dev) { ++ dev_put(po->pppoe_dev); ++ po->pppoe_dev = NULL; ++ } + pppox_unbind_sock(sk); + release_sock(sk); + sock_put(sk); diff --git a/target/linux/generic/patches-3.18/101-pppoe-fix-disconnect-crash.patch b/target/linux/generic/patches-3.18/101-pppoe-fix-disconnect-crash.patch new file mode 100644 index 0000000..f2e6e45 --- /dev/null +++ b/target/linux/generic/patches-3.18/101-pppoe-fix-disconnect-crash.patch @@ -0,0 +1,16 @@ +Fix crash with actions performed on the underlying interface (MAC address, +MTU or link state update). This triggers pppoe_flush_dev(), which cleans up +the device without announcing it in sk->sk_state. + +Patch by Guillaume Nault (pulled from netdev@vger) + +--- a/drivers/net/ppp/pppoe.c ++++ b/drivers/net/ppp/pppoe.c +@@ -313,7 +313,6 @@ static void pppoe_flush_dev(struct net_d + if (po->pppoe_dev == dev && + sk->sk_state & (PPPOX_CONNECTED | PPPOX_BOUND | PPPOX_ZOMBIE)) { + pppox_unbind_sock(sk); +- sk->sk_state = PPPOX_ZOMBIE; + sk->sk_state_change(sk); + po->pppoe_dev = NULL; + dev_put(dev); diff --git a/target/linux/generic/patches-3.18/102-ehci_hcd_ignore_oc.patch b/target/linux/generic/patches-3.18/102-ehci_hcd_ignore_oc.patch new file mode 100644 index 0000000..a564559 --- /dev/null +++ b/target/linux/generic/patches-3.18/102-ehci_hcd_ignore_oc.patch @@ -0,0 +1,82 @@ +From 1e311820ec3055e3f08e687de6564692a7cec675 Mon Sep 17 00:00:00 2001 +From: Florian Fainelli +Date: Mon, 28 Jan 2013 20:06:29 +0100 +Subject: [PATCH 11/12] USB: EHCI: add ignore_oc flag to disable overcurrent + checking + +This patch adds an ignore_oc flag which can be set by EHCI controller +not supporting or wanting to disable overcurrent checking. The EHCI +platform data in include/linux/usb/ehci_pdriver.h is also augmented to +take advantage of this new flag. + +Signed-off-by: Florian Fainelli +--- + drivers/usb/host/ehci-hcd.c | 2 +- + drivers/usb/host/ehci-hub.c | 4 ++-- + drivers/usb/host/ehci-platform.c | 1 + + drivers/usb/host/ehci.h | 1 + + include/linux/usb/ehci_pdriver.h | 1 + + 5 files changed, 6 insertions(+), 3 deletions(-) + +--- a/drivers/usb/host/ehci-hcd.c ++++ b/drivers/usb/host/ehci-hcd.c +@@ -633,7 +633,7 @@ static int ehci_run (struct usb_hcd *hcd + "USB %x.%x started, EHCI %x.%02x%s\n", + ((ehci->sbrn & 0xf0)>>4), (ehci->sbrn & 0x0f), + temp >> 8, temp & 0xff, +- ignore_oc ? ", overcurrent ignored" : ""); ++ (ignore_oc || ehci->ignore_oc) ? ", overcurrent ignored" : ""); + + ehci_writel(ehci, INTR_MASK, + &ehci->regs->intr_enable); /* Turn On Interrupts */ +--- a/drivers/usb/host/ehci-hub.c ++++ b/drivers/usb/host/ehci-hub.c +@@ -635,7 +635,7 @@ ehci_hub_status_data (struct usb_hcd *hc + * always set, seem to clear PORT_OCC and PORT_CSC when writing to + * PORT_POWER; that's surprising, but maybe within-spec. + */ +- if (!ignore_oc) ++ if (!ignore_oc && !ehci->ignore_oc) + mask = PORT_CSC | PORT_PEC | PORT_OCC; + else + mask = PORT_CSC | PORT_PEC; +@@ -995,7 +995,7 @@ int ehci_hub_control( + if (temp & PORT_PEC) + status |= USB_PORT_STAT_C_ENABLE << 16; + +- if ((temp & PORT_OCC) && !ignore_oc){ ++ if ((temp & PORT_OCC) && (!ignore_oc && !ehci->ignore_oc)){ + status |= USB_PORT_STAT_C_OVERCURRENT << 16; + + /* +--- a/drivers/usb/host/ehci-platform.c ++++ b/drivers/usb/host/ehci-platform.c +@@ -226,6 +226,8 @@ static int ehci_platform_probe(struct pl + ehci->big_endian_desc = 1; + if (pdata->big_endian_mmio) + ehci->big_endian_mmio = 1; ++ if (pdata->ignore_oc) ++ ehci->ignore_oc = 1; + + #ifndef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO + if (ehci->big_endian_mmio) { +--- a/drivers/usb/host/ehci.h ++++ b/drivers/usb/host/ehci.h +@@ -226,6 +226,7 @@ struct ehci_hcd { /* one per controlle + unsigned frame_index_bug:1; /* MosChip (AKA NetMos) */ + unsigned need_oc_pp_cycle:1; /* MPC834X port power */ + unsigned imx28_write_fix:1; /* For Freescale i.MX28 */ ++ unsigned ignore_oc:1; + + /* required for usb32 quirk */ + #define OHCI_CTRL_HCFS (3 << 6) +--- a/include/linux/usb/ehci_pdriver.h ++++ b/include/linux/usb/ehci_pdriver.h +@@ -45,6 +45,7 @@ struct usb_ehci_pdata { + unsigned big_endian_desc:1; + unsigned big_endian_mmio:1; + unsigned no_io_watchdog:1; ++ unsigned ignore_oc:1; + + /* Turn on all power and clocks */ + int (*power_on)(struct platform_device *pdev); diff --git a/target/linux/generic/patches-3.18/110-jffs2-use-.rename2-and-add-RENAME_WHITEOUT-support.patch b/target/linux/generic/patches-3.18/110-jffs2-use-.rename2-and-add-RENAME_WHITEOUT-support.patch new file mode 100644 index 0000000..4ffa3c2 --- /dev/null +++ b/target/linux/generic/patches-3.18/110-jffs2-use-.rename2-and-add-RENAME_WHITEOUT-support.patch @@ -0,0 +1,86 @@ +From: Felix Fietkau +Date: Fri, 10 Apr 2015 13:35:29 +0200 +Subject: [PATCH] jffs2: use .rename2 and add RENAME_WHITEOUT support + +It is required for renames on overlayfs + +Signed-off-by: Felix Fietkau +--- + +--- a/fs/jffs2/dir.c ++++ b/fs/jffs2/dir.c +@@ -35,7 +35,7 @@ static int jffs2_mkdir (struct inode *,s + static int jffs2_rmdir (struct inode *,struct dentry *); + static int jffs2_mknod (struct inode *,struct dentry *,umode_t,dev_t); + static int jffs2_rename (struct inode *, struct dentry *, +- struct inode *, struct dentry *); ++ struct inode *, struct dentry *, unsigned int); + + const struct file_operations jffs2_dir_operations = + { +@@ -57,7 +57,7 @@ const struct inode_operations jffs2_dir_ + .mkdir = jffs2_mkdir, + .rmdir = jffs2_rmdir, + .mknod = jffs2_mknod, +- .rename = jffs2_rename, ++ .rename2 = jffs2_rename, + .get_acl = jffs2_get_acl, + .set_acl = jffs2_set_acl, + .setattr = jffs2_setattr, +@@ -756,8 +756,27 @@ static int jffs2_mknod (struct inode *di + return ret; + } + ++static int jffs2_whiteout(struct inode *old_dir, struct dentry *old_dentry) ++{ ++ struct dentry *wh; ++ int err; ++ ++ wh = d_alloc(old_dentry->d_parent, &old_dentry->d_name); ++ if (!wh) ++ return -ENOMEM; ++ ++ err = jffs2_mknod(old_dir, wh, S_IFCHR | WHITEOUT_MODE, ++ WHITEOUT_DEV); ++ if (err) ++ return err; ++ ++ d_rehash(wh); ++ return 0; ++} ++ + static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry, +- struct inode *new_dir_i, struct dentry *new_dentry) ++ struct inode *new_dir_i, struct dentry *new_dentry, ++ unsigned int flags) + { + int ret; + struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dir_i->i_sb); +@@ -765,6 +784,9 @@ static int jffs2_rename (struct inode *o + uint8_t type; + uint32_t now; + ++ if (flags & ~RENAME_WHITEOUT) ++ return -EINVAL; ++ + /* The VFS will check for us and prevent trying to rename a + * file over a directory and vice versa, but if it's a directory, + * the VFS can't check whether the victim is empty. The filesystem +@@ -828,9 +850,14 @@ static int jffs2_rename (struct inode *o + if (S_ISDIR(old_dentry->d_inode->i_mode) && !victim_f) + inc_nlink(new_dir_i); + +- /* Unlink the original */ +- ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i), +- old_dentry->d_name.name, old_dentry->d_name.len, NULL, now); ++ if (flags & RENAME_WHITEOUT) ++ /* Replace with whiteout */ ++ ret = jffs2_whiteout(old_dir_i, old_dentry); ++ else ++ /* Unlink the original */ ++ ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i), ++ old_dentry->d_name.name, ++ old_dentry->d_name.len, NULL, now); + + /* We don't touch inode->i_nlink */ + diff --git a/target/linux/generic/patches-3.18/111-jffs2-add-RENAME_EXCHANGE-support.patch b/target/linux/generic/patches-3.18/111-jffs2-add-RENAME_EXCHANGE-support.patch new file mode 100644 index 0000000..df208da --- /dev/null +++ b/target/linux/generic/patches-3.18/111-jffs2-add-RENAME_EXCHANGE-support.patch @@ -0,0 +1,58 @@ +From: Felix Fietkau +Date: Sat, 25 Apr 2015 12:41:32 +0200 +Subject: [PATCH] jffs2: add RENAME_EXCHANGE support + +Signed-off-by: Felix Fietkau +--- + +--- a/fs/jffs2/dir.c ++++ b/fs/jffs2/dir.c +@@ -784,7 +784,7 @@ static int jffs2_rename (struct inode *o + uint8_t type; + uint32_t now; + +- if (flags & ~RENAME_WHITEOUT) ++ if (flags & ~(RENAME_WHITEOUT | RENAME_EXCHANGE)) + return -EINVAL; + + /* The VFS will check for us and prevent trying to rename a +@@ -792,7 +792,7 @@ static int jffs2_rename (struct inode *o + * the VFS can't check whether the victim is empty. The filesystem + * needs to do that for itself. + */ +- if (new_dentry->d_inode) { ++ if (new_dentry->d_inode && !(flags & RENAME_EXCHANGE)) { + victim_f = JFFS2_INODE_INFO(new_dentry->d_inode); + if (S_ISDIR(new_dentry->d_inode->i_mode)) { + struct jffs2_full_dirent *fd; +@@ -827,7 +827,7 @@ static int jffs2_rename (struct inode *o + if (ret) + return ret; + +- if (victim_f) { ++ if (victim_f && !(flags & RENAME_EXCHANGE)) { + /* There was a victim. Kill it off nicely */ + if (S_ISDIR(new_dentry->d_inode->i_mode)) + clear_nlink(new_dentry->d_inode); +@@ -853,6 +853,12 @@ static int jffs2_rename (struct inode *o + if (flags & RENAME_WHITEOUT) + /* Replace with whiteout */ + ret = jffs2_whiteout(old_dir_i, old_dentry); ++ else if (flags & RENAME_EXCHANGE) ++ /* Replace the original */ ++ ret = jffs2_do_link(c, JFFS2_INODE_INFO(old_dir_i), ++ new_dentry->d_inode->i_ino, type, ++ old_dentry->d_name.name, old_dentry->d_name.len, ++ now); + else + /* Unlink the original */ + ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i), +@@ -879,7 +885,7 @@ static int jffs2_rename (struct inode *o + return ret; + } + +- if (S_ISDIR(old_dentry->d_inode->i_mode)) ++ if (S_ISDIR(old_dentry->d_inode->i_mode) && !(flags & RENAME_EXCHANGE)) + drop_nlink(old_dir_i); + + new_dir_i->i_mtime = new_dir_i->i_ctime = old_dir_i->i_mtime = old_dir_i->i_ctime = ITIME(now); diff --git a/target/linux/generic/patches-3.18/120-bridge_allow_receiption_on_disabled_port.patch b/target/linux/generic/patches-3.18/120-bridge_allow_receiption_on_disabled_port.patch new file mode 100644 index 0000000..d80ef18 --- /dev/null +++ b/target/linux/generic/patches-3.18/120-bridge_allow_receiption_on_disabled_port.patch @@ -0,0 +1,54 @@ +From: Stephen Hemminger +Subject: bridge: allow receiption on disabled port + +When an ethernet device is enslaved to a bridge, and the bridge STP +detects loss of carrier (or operational state down), then normally +packet receiption is blocked. + +This breaks control applications like WPA which maybe expecting to +receive packets to negotiate to bring link up. The bridge needs to +block forwarding packets from these disabled ports, but there is no +hard requirement to not allow local packet delivery. + +Signed-off-by: Stephen Hemminger +Signed-off-by: Felix Fietkau + +--- a/net/bridge/br_input.c ++++ b/net/bridge/br_input.c +@@ -146,11 +146,13 @@ EXPORT_SYMBOL_GPL(br_handle_frame_finish + static int br_handle_local_finish(struct sk_buff *skb) + { + struct net_bridge_port *p = br_port_get_rcu(skb->dev); +- u16 vid = 0; ++ if (p->state != BR_STATE_DISABLED) { ++ u16 vid = 0; + +- /* check if vlan is allowed, to avoid spoofing */ +- if (p->flags & BR_LEARNING && br_should_learn(p, skb, &vid)) +- br_fdb_update(p->br, p, eth_hdr(skb)->h_source, vid, false); ++ /* check if vlan is allowed, to avoid spoofing */ ++ if (p->flags & BR_LEARNING && br_should_learn(p, skb, &vid)) ++ br_fdb_update(p->br, p, eth_hdr(skb)->h_source, vid, false); ++ } + return 0; /* process further */ + } + +@@ -224,6 +226,18 @@ rx_handler_result_t br_handle_frame(stru + + forward: + switch (p->state) { ++ case BR_STATE_DISABLED: ++ if (ether_addr_equal(p->br->dev->dev_addr, dest)) ++ skb->pkt_type = PACKET_HOST; ++ ++ if (NF_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL, ++ br_handle_local_finish)) ++ break; ++ ++ BR_INPUT_SKB_CB(skb)->brdev = p->br->dev; ++ br_pass_frame_up(skb); ++ break; ++ + case BR_STATE_FORWARDING: + rhook = rcu_dereference(br_should_route_hook); + if (rhook) { diff --git a/target/linux/generic/patches-3.18/132-mips_inline_dma_ops.patch b/target/linux/generic/patches-3.18/132-mips_inline_dma_ops.patch new file mode 100644 index 0000000..8795bde --- /dev/null +++ b/target/linux/generic/patches-3.18/132-mips_inline_dma_ops.patch @@ -0,0 +1,688 @@ +From 2c58080407554e1bac8fd50d23cb02420524caed Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Mon, 12 Aug 2013 12:50:22 +0200 +Subject: [PATCH] MIPS: partially inline dma ops + +Several DMA ops are no-op on many platforms, and the indirection through +the mips_dma_map_ops function table is causing the compiler to emit +unnecessary code. + +Inlining visibly improves network performance in my tests (on a 24Kc +based system), and also slightly reduces code size of a few drivers. + +Signed-off-by: Felix Fietkau +--- + arch/mips/Kconfig | 4 + + arch/mips/include/asm/dma-mapping.h | 360 +++++++++++++++++++++++++++++++++++- + arch/mips/mm/dma-default.c | 163 ++-------------- + 3 files changed, 373 insertions(+), 154 deletions(-) + +--- a/arch/mips/Kconfig ++++ b/arch/mips/Kconfig +@@ -1450,6 +1450,7 @@ config CPU_CAVIUM_OCTEON + select CPU_SUPPORTS_HUGEPAGES + select USB_EHCI_BIG_ENDIAN_MMIO + select MIPS_L1_CACHE_SHIFT_7 ++ select SYS_HAS_DMA_OPS + help + The Cavium Octeon processor is a highly integrated chip containing + many ethernet hardware widgets for networking tasks. The processor +@@ -1705,6 +1706,9 @@ config MIPS_MALTA_PM + bool + default y + ++config SYS_HAS_DMA_OPS ++ bool ++ + # + # CPU may reorder R->R, R->W, W->R, W->W + # Reordering beyond LL and SC is handled in WEAK_REORDERING_BEYOND_LLSC +--- a/arch/mips/include/asm/dma-mapping.h ++++ b/arch/mips/include/asm/dma-mapping.h +@@ -1,9 +1,16 @@ + #ifndef _ASM_DMA_MAPPING_H + #define _ASM_DMA_MAPPING_H + ++#include ++#include ++#include ++#include ++#include ++ + #include + #include + #include ++#include + #include + + #ifndef CONFIG_SGI_IP27 /* Kludge to fix 2.6.39 build for IP27 */ +@@ -12,12 +19,48 @@ + + extern struct dma_map_ops *mips_dma_map_ops; + ++void __dma_sync(struct page *page, unsigned long offset, size_t size, ++ enum dma_data_direction direction); ++void *mips_dma_alloc_coherent(struct device *dev, size_t size, ++ dma_addr_t *dma_handle, gfp_t gfp, ++ struct dma_attrs *attrs); ++void mips_dma_free_coherent(struct device *dev, size_t size, void *vaddr, ++ dma_addr_t dma_handle, struct dma_attrs *attrs); ++ + static inline struct dma_map_ops *get_dma_ops(struct device *dev) + { ++#ifdef CONFIG_SYS_HAS_DMA_OPS + if (dev && dev->archdata.dma_ops) + return dev->archdata.dma_ops; + else + return mips_dma_map_ops; ++#else ++ return NULL; ++#endif ++} ++ ++/* ++ * Warning on the terminology - Linux calls an uncached area coherent; ++ * MIPS terminology calls memory areas with hardware maintained coherency ++ * coherent. ++ */ ++ ++static inline int cpu_needs_post_dma_flush(struct device *dev) ++{ ++#ifndef CONFIG_SYS_HAS_CPU_R10000 ++ return 0; ++#endif ++ return !plat_device_is_coherent(dev) && ++ (boot_cpu_type() == CPU_R10000 || ++ boot_cpu_type() == CPU_R12000 || ++ boot_cpu_type() == CPU_BMIPS5000); ++} ++ ++static inline struct page *dma_addr_to_page(struct device *dev, ++ dma_addr_t dma_addr) ++{ ++ return pfn_to_page( ++ plat_dma_addr_to_phys(dev, dma_addr) >> PAGE_SHIFT); + } + + static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) +@@ -30,12 +73,304 @@ static inline bool dma_capable(struct de + + static inline void dma_mark_clean(void *addr, size_t size) {} + +-#include ++static inline dma_addr_t dma_map_single_attrs(struct device *dev, void *ptr, ++ size_t size, ++ enum dma_data_direction dir, ++ struct dma_attrs *attrs) ++{ ++ struct dma_map_ops *ops = get_dma_ops(dev); ++ unsigned long offset = (unsigned long)ptr & ~PAGE_MASK; ++ struct page *page = virt_to_page(ptr); ++ dma_addr_t addr; ++ ++ kmemcheck_mark_initialized(ptr, size); ++ BUG_ON(!valid_dma_direction(dir)); ++ if (ops) { ++ addr = ops->map_page(dev, page, offset, size, dir, attrs); ++ } else { ++ if (!plat_device_is_coherent(dev)) ++ __dma_sync(page, offset, size, dir); ++ ++ addr = plat_map_dma_mem_page(dev, page) + offset; ++ } ++ debug_dma_map_page(dev, page, offset, size, dir, addr, true); ++ return addr; ++} ++ ++static inline void dma_unmap_single_attrs(struct device *dev, dma_addr_t addr, ++ size_t size, ++ enum dma_data_direction dir, ++ struct dma_attrs *attrs) ++{ ++ struct dma_map_ops *ops = get_dma_ops(dev); ++ ++ BUG_ON(!valid_dma_direction(dir)); ++ if (ops) { ++ ops->unmap_page(dev, addr, size, dir, attrs); ++ } else { ++ if (cpu_needs_post_dma_flush(dev)) ++ __dma_sync(dma_addr_to_page(dev, addr), ++ addr & ~PAGE_MASK, size, dir); ++ ++ plat_unmap_dma_mem(dev, addr, size, dir); ++ } ++ debug_dma_unmap_page(dev, addr, size, dir, true); ++} ++ ++static inline int dma_map_sg_attrs(struct device *dev, struct scatterlist *sg, ++ int nents, enum dma_data_direction dir, ++ struct dma_attrs *attrs) ++{ ++ struct dma_map_ops *ops = get_dma_ops(dev); ++ int i, ents; ++ struct scatterlist *s; ++ ++ for_each_sg(sg, s, nents, i) ++ kmemcheck_mark_initialized(sg_virt(s), s->length); ++ BUG_ON(!valid_dma_direction(dir)); ++ if (ops) { ++ ents = ops->map_sg(dev, sg, nents, dir, attrs); ++ } else { ++ for_each_sg(sg, s, nents, i) { ++ struct page *page = sg_page(s); ++ ++ if (!plat_device_is_coherent(dev)) ++ __dma_sync(page, s->offset, s->length, dir); ++#ifdef CONFIG_NEED_SG_DMA_LENGTH ++ s->dma_length = s->length; ++#endif ++ s->dma_address = ++ plat_map_dma_mem_page(dev, page) + s->offset; ++ } ++ ents = nents; ++ } ++ debug_dma_map_sg(dev, sg, nents, ents, dir); ++ ++ return ents; ++} ++ ++static inline void dma_unmap_sg_attrs(struct device *dev, struct scatterlist *sg, ++ int nents, enum dma_data_direction dir, ++ struct dma_attrs *attrs) ++{ ++ struct dma_map_ops *ops = get_dma_ops(dev); ++ struct scatterlist *s; ++ int i; ++ ++ BUG_ON(!valid_dma_direction(dir)); ++ debug_dma_unmap_sg(dev, sg, nents, dir); ++ if (ops) { ++ ops->unmap_sg(dev, sg, nents, dir, attrs); ++ return; ++ } ++ ++ for_each_sg(sg, s, nents, i) { ++ if (!plat_device_is_coherent(dev) && dir != DMA_TO_DEVICE) ++ __dma_sync(sg_page(s), s->offset, s->length, dir); ++ plat_unmap_dma_mem(dev, s->dma_address, s->length, dir); ++ } ++} ++ ++static inline dma_addr_t dma_map_page(struct device *dev, struct page *page, ++ size_t offset, size_t size, ++ enum dma_data_direction dir) ++{ ++ struct dma_map_ops *ops = get_dma_ops(dev); ++ dma_addr_t addr; ++ ++ kmemcheck_mark_initialized(page_address(page) + offset, size); ++ BUG_ON(!valid_dma_direction(dir)); ++ if (ops) { ++ addr = ops->map_page(dev, page, offset, size, dir, NULL); ++ } else { ++ if (!plat_device_is_coherent(dev)) ++ __dma_sync(page, offset, size, dir); ++ ++ addr = plat_map_dma_mem_page(dev, page) + offset; ++ } ++ debug_dma_map_page(dev, page, offset, size, dir, addr, false); ++ ++ return addr; ++} ++ ++static inline void dma_unmap_page(struct device *dev, dma_addr_t addr, ++ size_t size, enum dma_data_direction dir) ++{ ++ struct dma_map_ops *ops = get_dma_ops(dev); ++ ++ BUG_ON(!valid_dma_direction(dir)); ++ if (ops) { ++ ops->unmap_page(dev, addr, size, dir, NULL); ++ } else { ++ if (cpu_needs_post_dma_flush(dev)) ++ __dma_sync(dma_addr_to_page(dev, addr), ++ addr & ~PAGE_MASK, size, dir); ++ ++ plat_unmap_dma_mem(dev, addr, size, dir); ++ } ++ debug_dma_unmap_page(dev, addr, size, dir, false); ++} ++ ++static inline void dma_sync_single_for_cpu(struct device *dev, dma_addr_t addr, ++ size_t size, ++ enum dma_data_direction dir) ++{ ++ struct dma_map_ops *ops = get_dma_ops(dev); ++ ++ BUG_ON(!valid_dma_direction(dir)); ++ if (ops) ++ ops->sync_single_for_cpu(dev, addr, size, dir); ++ else if (cpu_needs_post_dma_flush(dev)) ++ __dma_sync(dma_addr_to_page(dev, addr), ++ addr & ~PAGE_MASK, size, dir); ++ debug_dma_sync_single_for_cpu(dev, addr, size, dir); ++} ++ ++static inline void dma_sync_single_for_device(struct device *dev, ++ dma_addr_t addr, size_t size, ++ enum dma_data_direction dir) ++{ ++ struct dma_map_ops *ops = get_dma_ops(dev); ++ ++ BUG_ON(!valid_dma_direction(dir)); ++ if (ops) ++ ops->sync_single_for_device(dev, addr, size, dir); ++ else if (!plat_device_is_coherent(dev)) ++ __dma_sync(dma_addr_to_page(dev, addr), ++ addr & ~PAGE_MASK, size, dir); ++ debug_dma_sync_single_for_device(dev, addr, size, dir); ++} ++ ++static inline void dma_sync_single_range_for_cpu(struct device *dev, ++ dma_addr_t addr, ++ unsigned long offset, ++ size_t size, ++ enum dma_data_direction dir) ++{ ++ const struct dma_map_ops *ops = get_dma_ops(dev); ++ ++ BUG_ON(!valid_dma_direction(dir)); ++ if (ops) ++ ops->sync_single_for_cpu(dev, addr + offset, size, dir); ++ else if (cpu_needs_post_dma_flush(dev)) ++ __dma_sync(dma_addr_to_page(dev, addr + offset), ++ (addr + offset) & ~PAGE_MASK, size, dir); ++ debug_dma_sync_single_range_for_cpu(dev, addr, offset, size, dir); ++} ++ ++static inline void dma_sync_single_range_for_device(struct device *dev, ++ dma_addr_t addr, ++ unsigned long offset, ++ size_t size, ++ enum dma_data_direction dir) ++{ ++ const struct dma_map_ops *ops = get_dma_ops(dev); ++ ++ BUG_ON(!valid_dma_direction(dir)); ++ if (ops) ++ ops->sync_single_for_device(dev, addr + offset, size, dir); ++ else if (!plat_device_is_coherent(dev)) ++ __dma_sync(dma_addr_to_page(dev, addr + offset), ++ (addr + offset) & ~PAGE_MASK, size, dir); ++ debug_dma_sync_single_range_for_device(dev, addr, offset, size, dir); ++} ++ ++static inline void ++dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, ++ int nelems, enum dma_data_direction dir) ++{ ++ struct dma_map_ops *ops = get_dma_ops(dev); ++ struct scatterlist *s; ++ int i; ++ ++ BUG_ON(!valid_dma_direction(dir)); ++ if (ops) ++ ops->sync_sg_for_cpu(dev, sg, nelems, dir); ++ else if (cpu_needs_post_dma_flush(dev)) { ++ for_each_sg(sg, s, nelems, i) ++ __dma_sync(sg_page(s), s->offset, s->length, dir); ++ } ++ debug_dma_sync_sg_for_cpu(dev, sg, nelems, dir); ++} ++ ++static inline void ++dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, ++ int nelems, enum dma_data_direction dir) ++{ ++ struct dma_map_ops *ops = get_dma_ops(dev); ++ struct scatterlist *s; ++ int i; ++ ++ BUG_ON(!valid_dma_direction(dir)); ++ if (ops) ++ ops->sync_sg_for_device(dev, sg, nelems, dir); ++ else if (!plat_device_is_coherent(dev)) { ++ for_each_sg(sg, s, nelems, i) ++ __dma_sync(sg_page(s), s->offset, s->length, dir); ++ } ++ debug_dma_sync_sg_for_device(dev, sg, nelems, dir); ++ ++} ++ ++#define dma_map_single(d, a, s, r) dma_map_single_attrs(d, a, s, r, NULL) ++#define dma_unmap_single(d, a, s, r) dma_unmap_single_attrs(d, a, s, r, NULL) ++#define dma_map_sg(d, s, n, r) dma_map_sg_attrs(d, s, n, r, NULL) ++#define dma_unmap_sg(d, s, n, r) dma_unmap_sg_attrs(d, s, n, r, NULL) ++ ++extern int dma_common_mmap(struct device *dev, struct vm_area_struct *vma, ++ void *cpu_addr, dma_addr_t dma_addr, size_t size); ++ ++/** ++ * dma_mmap_attrs - map a coherent DMA allocation into user space ++ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices ++ * @vma: vm_area_struct describing requested user mapping ++ * @cpu_addr: kernel CPU-view address returned from dma_alloc_attrs ++ * @handle: device-view address returned from dma_alloc_attrs ++ * @size: size of memory originally requested in dma_alloc_attrs ++ * @attrs: attributes of mapping properties requested in dma_alloc_attrs ++ * ++ * Map a coherent DMA buffer previously allocated by dma_alloc_attrs ++ * into user space. The coherent DMA buffer must not be freed by the ++ * driver until the user space mapping has been released. ++ */ ++static inline int ++dma_mmap_attrs(struct device *dev, struct vm_area_struct *vma, void *cpu_addr, ++ dma_addr_t dma_addr, size_t size, struct dma_attrs *attrs) ++{ ++ struct dma_map_ops *ops = get_dma_ops(dev); ++ BUG_ON(!ops); ++ if (ops && ops->mmap) ++ return ops->mmap(dev, vma, cpu_addr, dma_addr, size, attrs); ++ return dma_common_mmap(dev, vma, cpu_addr, dma_addr, size); ++} ++ ++#define dma_mmap_coherent(d, v, c, h, s) dma_mmap_attrs(d, v, c, h, s, NULL) ++ ++int ++dma_common_get_sgtable(struct device *dev, struct sg_table *sgt, ++ void *cpu_addr, dma_addr_t dma_addr, size_t size); ++ ++static inline int ++dma_get_sgtable_attrs(struct device *dev, struct sg_table *sgt, void *cpu_addr, ++ dma_addr_t dma_addr, size_t size, struct dma_attrs *attrs) ++{ ++ struct dma_map_ops *ops = get_dma_ops(dev); ++ BUG_ON(!ops); ++ if (ops && ops->get_sgtable) ++ return ops->get_sgtable(dev, sgt, cpu_addr, dma_addr, size, ++ attrs); ++ return dma_common_get_sgtable(dev, sgt, cpu_addr, dma_addr, size); ++} ++ ++#define dma_get_sgtable(d, t, v, h, s) dma_get_sgtable_attrs(d, t, v, h, s, NULL) ++ + + static inline int dma_supported(struct device *dev, u64 mask) + { + struct dma_map_ops *ops = get_dma_ops(dev); +- return ops->dma_supported(dev, mask); ++ if (ops) ++ return ops->dma_supported(dev, mask); ++ return plat_dma_supported(dev, mask); + } + + static inline int dma_mapping_error(struct device *dev, u64 mask) +@@ -43,7 +378,9 @@ static inline int dma_mapping_error(stru + struct dma_map_ops *ops = get_dma_ops(dev); + + debug_dma_mapping_error(dev, mask); +- return ops->mapping_error(dev, mask); ++ if (ops) ++ return ops->mapping_error(dev, mask); ++ return 0; + } + + static inline int +@@ -54,7 +391,7 @@ dma_set_mask(struct device *dev, u64 mas + if(!dev->dma_mask || !dma_supported(dev, mask)) + return -EIO; + +- if (ops->set_dma_mask) ++ if (ops && ops->set_dma_mask) + return ops->set_dma_mask(dev, mask); + + *dev->dma_mask = mask; +@@ -74,7 +411,11 @@ static inline void *dma_alloc_attrs(stru + void *ret; + struct dma_map_ops *ops = get_dma_ops(dev); + +- ret = ops->alloc(dev, size, dma_handle, gfp, attrs); ++ if (ops) ++ ret = ops->alloc(dev, size, dma_handle, gfp, attrs); ++ else ++ ret = mips_dma_alloc_coherent(dev, size, dma_handle, gfp, ++ attrs); + + debug_dma_alloc_coherent(dev, size, *dma_handle, ret); + +@@ -89,7 +430,10 @@ static inline void dma_free_attrs(struct + { + struct dma_map_ops *ops = get_dma_ops(dev); + +- ops->free(dev, size, vaddr, dma_handle, attrs); ++ if (ops) ++ ops->free(dev, size, vaddr, dma_handle, attrs); ++ else ++ mips_dma_free_coherent(dev, size, vaddr, dma_handle, attrs); + + debug_dma_free_coherent(dev, size, vaddr, dma_handle); + } +--- a/arch/mips/mm/dma-default.c ++++ b/arch/mips/mm/dma-default.c +@@ -26,7 +26,7 @@ + + #ifdef CONFIG_DMA_MAYBE_COHERENT + int coherentio = 0; /* User defined DMA coherency from command line. */ +-EXPORT_SYMBOL_GPL(coherentio); ++EXPORT_SYMBOL(coherentio); + int hw_coherentio = 0; /* Actual hardware supported DMA coherency setting. */ + + static int __init setcoherentio(char *str) +@@ -46,30 +46,6 @@ static int __init setnocoherentio(char * + early_param("nocoherentio", setnocoherentio); + #endif + +-static inline struct page *dma_addr_to_page(struct device *dev, +- dma_addr_t dma_addr) +-{ +- return pfn_to_page( +- plat_dma_addr_to_phys(dev, dma_addr) >> PAGE_SHIFT); +-} +- +-/* +- * The affected CPUs below in 'cpu_needs_post_dma_flush()' can +- * speculatively fill random cachelines with stale data at any time, +- * requiring an extra flush post-DMA. +- * +- * Warning on the terminology - Linux calls an uncached area coherent; +- * MIPS terminology calls memory areas with hardware maintained coherency +- * coherent. +- */ +-static inline int cpu_needs_post_dma_flush(struct device *dev) +-{ +- return !plat_device_is_coherent(dev) && +- (boot_cpu_type() == CPU_R10000 || +- boot_cpu_type() == CPU_R12000 || +- boot_cpu_type() == CPU_BMIPS5000); +-} +- + static gfp_t massage_gfp_flags(const struct device *dev, gfp_t gfp) + { + gfp_t dma_flag; +@@ -125,8 +101,9 @@ void *dma_alloc_noncoherent(struct devic + } + EXPORT_SYMBOL(dma_alloc_noncoherent); + +-static void *mips_dma_alloc_coherent(struct device *dev, size_t size, +- dma_addr_t * dma_handle, gfp_t gfp, struct dma_attrs *attrs) ++void *mips_dma_alloc_coherent(struct device *dev, size_t size, ++ dma_addr_t *dma_handle, gfp_t gfp, ++ struct dma_attrs *attrs) + { + void *ret; + struct page *page = NULL; +@@ -157,6 +134,7 @@ static void *mips_dma_alloc_coherent(str + + return ret; + } ++EXPORT_SYMBOL(mips_dma_alloc_coherent); + + + void dma_free_noncoherent(struct device *dev, size_t size, void *vaddr, +@@ -167,8 +145,8 @@ void dma_free_noncoherent(struct device + } + EXPORT_SYMBOL(dma_free_noncoherent); + +-static void mips_dma_free_coherent(struct device *dev, size_t size, void *vaddr, +- dma_addr_t dma_handle, struct dma_attrs *attrs) ++void mips_dma_free_coherent(struct device *dev, size_t size, void *vaddr, ++ dma_addr_t dma_handle, struct dma_attrs *attrs) + { + unsigned long addr = (unsigned long) vaddr; + int order = get_order(size); +@@ -188,6 +166,7 @@ static void mips_dma_free_coherent(struc + if (!dma_release_from_contiguous(dev, page, count)) + __free_pages(page, get_order(size)); + } ++EXPORT_SYMBOL(mips_dma_free_coherent); + + static inline void __dma_sync_virtual(void *addr, size_t size, + enum dma_data_direction direction) +@@ -216,8 +195,8 @@ static inline void __dma_sync_virtual(vo + * If highmem is not configured then the bulk of this loop gets + * optimized out. + */ +-static inline void __dma_sync(struct page *page, +- unsigned long offset, size_t size, enum dma_data_direction direction) ++void __dma_sync(struct page *page, unsigned long offset, size_t size, ++ enum dma_data_direction direction) + { + size_t left = size; + +@@ -246,108 +225,7 @@ static inline void __dma_sync(struct pag + left -= len; + } while (left); + } +- +-static void mips_dma_unmap_page(struct device *dev, dma_addr_t dma_addr, +- size_t size, enum dma_data_direction direction, struct dma_attrs *attrs) +-{ +- if (cpu_needs_post_dma_flush(dev)) +- __dma_sync(dma_addr_to_page(dev, dma_addr), +- dma_addr & ~PAGE_MASK, size, direction); +- +- plat_unmap_dma_mem(dev, dma_addr, size, direction); +-} +- +-static int mips_dma_map_sg(struct device *dev, struct scatterlist *sg, +- int nents, enum dma_data_direction direction, struct dma_attrs *attrs) +-{ +- int i; +- +- for (i = 0; i < nents; i++, sg++) { +- if (!plat_device_is_coherent(dev)) +- __dma_sync(sg_page(sg), sg->offset, sg->length, +- direction); +-#ifdef CONFIG_NEED_SG_DMA_LENGTH +- sg->dma_length = sg->length; +-#endif +- sg->dma_address = plat_map_dma_mem_page(dev, sg_page(sg)) + +- sg->offset; +- } +- +- return nents; +-} +- +-static dma_addr_t mips_dma_map_page(struct device *dev, struct page *page, +- unsigned long offset, size_t size, enum dma_data_direction direction, +- struct dma_attrs *attrs) +-{ +- if (!plat_device_is_coherent(dev)) +- __dma_sync(page, offset, size, direction); +- +- return plat_map_dma_mem_page(dev, page) + offset; +-} +- +-static void mips_dma_unmap_sg(struct device *dev, struct scatterlist *sg, +- int nhwentries, enum dma_data_direction direction, +- struct dma_attrs *attrs) +-{ +- int i; +- +- for (i = 0; i < nhwentries; i++, sg++) { +- if (!plat_device_is_coherent(dev) && +- direction != DMA_TO_DEVICE) +- __dma_sync(sg_page(sg), sg->offset, sg->length, +- direction); +- plat_unmap_dma_mem(dev, sg->dma_address, sg->length, direction); +- } +-} +- +-static void mips_dma_sync_single_for_cpu(struct device *dev, +- dma_addr_t dma_handle, size_t size, enum dma_data_direction direction) +-{ +- if (cpu_needs_post_dma_flush(dev)) +- __dma_sync(dma_addr_to_page(dev, dma_handle), +- dma_handle & ~PAGE_MASK, size, direction); +-} +- +-static void mips_dma_sync_single_for_device(struct device *dev, +- dma_addr_t dma_handle, size_t size, enum dma_data_direction direction) +-{ +- if (!plat_device_is_coherent(dev)) +- __dma_sync(dma_addr_to_page(dev, dma_handle), +- dma_handle & ~PAGE_MASK, size, direction); +-} +- +-static void mips_dma_sync_sg_for_cpu(struct device *dev, +- struct scatterlist *sg, int nelems, enum dma_data_direction direction) +-{ +- int i; +- +- if (cpu_needs_post_dma_flush(dev)) +- for (i = 0; i < nelems; i++, sg++) +- __dma_sync(sg_page(sg), sg->offset, sg->length, +- direction); +-} +- +-static void mips_dma_sync_sg_for_device(struct device *dev, +- struct scatterlist *sg, int nelems, enum dma_data_direction direction) +-{ +- int i; +- +- if (!plat_device_is_coherent(dev)) +- for (i = 0; i < nelems; i++, sg++) +- __dma_sync(sg_page(sg), sg->offset, sg->length, +- direction); +-} +- +-int mips_dma_mapping_error(struct device *dev, dma_addr_t dma_addr) +-{ +- return 0; +-} +- +-int mips_dma_supported(struct device *dev, u64 mask) +-{ +- return plat_dma_supported(dev, mask); +-} ++EXPORT_SYMBOL(__dma_sync); + + void dma_cache_sync(struct device *dev, void *vaddr, size_t size, + enum dma_data_direction direction) +@@ -360,23 +238,10 @@ void dma_cache_sync(struct device *dev, + + EXPORT_SYMBOL(dma_cache_sync); + +-static struct dma_map_ops mips_default_dma_map_ops = { +- .alloc = mips_dma_alloc_coherent, +- .free = mips_dma_free_coherent, +- .map_page = mips_dma_map_page, +- .unmap_page = mips_dma_unmap_page, +- .map_sg = mips_dma_map_sg, +- .unmap_sg = mips_dma_unmap_sg, +- .sync_single_for_cpu = mips_dma_sync_single_for_cpu, +- .sync_single_for_device = mips_dma_sync_single_for_device, +- .sync_sg_for_cpu = mips_dma_sync_sg_for_cpu, +- .sync_sg_for_device = mips_dma_sync_sg_for_device, +- .mapping_error = mips_dma_mapping_error, +- .dma_supported = mips_dma_supported +-}; +- +-struct dma_map_ops *mips_dma_map_ops = &mips_default_dma_map_ops; ++#ifdef CONFIG_SYS_HAS_DMA_OPS ++struct dma_map_ops *mips_dma_map_ops = NULL; + EXPORT_SYMBOL(mips_dma_map_ops); ++#endif + + #define PREALLOC_DMA_DEBUG_ENTRIES (1 << 16) + diff --git a/target/linux/generic/patches-3.18/140-mtd-part-add-generic-parsing-of-linux-part-probe.patch b/target/linux/generic/patches-3.18/140-mtd-part-add-generic-parsing-of-linux-part-probe.patch new file mode 100644 index 0000000..bd34f96 --- /dev/null +++ b/target/linux/generic/patches-3.18/140-mtd-part-add-generic-parsing-of-linux-part-probe.patch @@ -0,0 +1,175 @@ +From 173b0add0cff6558f950c0cb1eacfb729d482711 Mon Sep 17 00:00:00 2001 +From: Hauke Mehrtens +Date: Sun, 17 May 2015 18:48:38 +0200 +Subject: [PATCH 4/8] mtd: part: add generic parsing of linux,part-probe + +This moves the linux,part-probe device tree parsing code from +physmap_of.c to mtdpart.c. Now all drivers can use this feature by just +providing a reference to their device tree node in struct +mtd_part_parser_data. + +Signed-off-by: Hauke Mehrtens +--- + Documentation/devicetree/bindings/mtd/nand.txt | 16 ++++++++++ + drivers/mtd/maps/physmap_of.c | 40 +----------------------- + drivers/mtd/mtdpart.c | 43 ++++++++++++++++++++++++++ + 3 files changed, 60 insertions(+), 39 deletions(-) + +--- a/Documentation/devicetree/bindings/mtd/nand.txt ++++ b/Documentation/devicetree/bindings/mtd/nand.txt +@@ -12,6 +12,22 @@ + - nand-ecc-step-size: integer representing the number of data bytes + that are covered by a single ECC step. + ++- linux,part-probe: list of name as strings of the partition parser ++ which should be used to parse the partition table. ++ They will be tried in the specified ordering and ++ the next one will be used if the previous one ++ failed. ++ ++ Example: linux,part-probe = "cmdlinepart", "ofpart"; ++ ++ This is also the default value, which will be used ++ if this attribute is not specified. It could be ++ that the flash driver in use overwrote the default ++ value and uses some other default. ++ ++ Possible values are: bcm47xxpart, afs, ar7part, ++ ofoldpart, ofpart, bcm63xxpart, RedBoot, cmdlinepart ++ + The ECC strength and ECC step size properties define the correction capability + of a controller. Together, they say a controller can correct "{strength} bit + errors per {size} bytes". +--- a/drivers/mtd/maps/physmap_of.c ++++ b/drivers/mtd/maps/physmap_of.c +@@ -114,45 +114,9 @@ static struct mtd_info *obsolete_probe(s + static const char * const part_probe_types_def[] = { + "cmdlinepart", "RedBoot", "ofpart", "ofoldpart", NULL }; + +-static const char * const *of_get_probes(struct device_node *dp) +-{ +- const char *cp; +- int cplen; +- unsigned int l; +- unsigned int count; +- const char **res; +- +- cp = of_get_property(dp, "linux,part-probe", &cplen); +- if (cp == NULL) +- return part_probe_types_def; +- +- count = 0; +- for (l = 0; l != cplen; l++) +- if (cp[l] == 0) +- count++; +- +- res = kzalloc((count + 1)*sizeof(*res), GFP_KERNEL); +- count = 0; +- while (cplen > 0) { +- res[count] = cp; +- l = strlen(cp) + 1; +- cp += l; +- cplen -= l; +- count++; +- } +- return res; +-} +- +-static void of_free_probes(const char * const *probes) +-{ +- if (probes != part_probe_types_def) +- kfree(probes); +-} +- + static struct of_device_id of_flash_match[]; + static int of_flash_probe(struct platform_device *dev) + { +- const char * const *part_probe_types; + const struct of_device_id *match; + struct device_node *dp = dev->dev.of_node; + struct resource res; +@@ -302,10 +266,8 @@ static int of_flash_probe(struct platfor + goto err_out; + + ppdata.of_node = dp; +- part_probe_types = of_get_probes(dp); +- mtd_device_parse_register(info->cmtd, part_probe_types, &ppdata, ++ mtd_device_parse_register(info->cmtd, part_probe_types_def, &ppdata, + NULL, 0); +- of_free_probes(part_probe_types); + + kfree(mtd_list); + +--- a/drivers/mtd/mtdpart.c ++++ b/drivers/mtd/mtdpart.c +@@ -29,6 +29,7 @@ + #include + #include + #include ++#include + #include + + #include "mtdcore.h" +@@ -702,6 +703,40 @@ void deregister_mtd_parser(struct mtd_pa + EXPORT_SYMBOL_GPL(deregister_mtd_parser); + + /* ++ * Parses the linux,part-probe device tree property. ++ * When a non null value is returned it has to be freed with kfree() by ++ * the caller. ++ */ ++static const char * const *of_get_probes(struct device_node *dp) ++{ ++ const char *cp; ++ int cplen; ++ unsigned int l; ++ unsigned int count; ++ const char **res; ++ ++ cp = of_get_property(dp, "linux,part-probe", &cplen); ++ if (cp == NULL) ++ return NULL; ++ ++ count = 0; ++ for (l = 0; l != cplen; l++) ++ if (cp[l] == 0) ++ count++; ++ ++ res = kzalloc((count + 1) * sizeof(*res), GFP_KERNEL); ++ count = 0; ++ while (cplen > 0) { ++ res[count] = cp; ++ l = strlen(cp) + 1; ++ cp += l; ++ cplen -= l; ++ count++; ++ } ++ return res; ++} ++ ++/* + * Do not forget to update 'parse_mtd_partitions()' kerneldoc comment if you + * are changing this array! + */ +@@ -737,6 +772,13 @@ int parse_mtd_partitions(struct mtd_info + { + struct mtd_part_parser *parser; + int ret = 0; ++ const char *const *types_of = NULL; ++ ++ if (data && data->of_node) { ++ types_of = of_get_probes(data->of_node); ++ if (types_of != NULL) ++ types = types_of; ++ } + + if (!types) + types = default_mtd_part_types; +@@ -755,6 +797,7 @@ int parse_mtd_partitions(struct mtd_info + break; + } + } ++ kfree(types_of); + return ret; + } + diff --git a/target/linux/generic/patches-3.18/180-usb-xhci-make-USB_XHCI_PLATFORM-selectable.patch b/target/linux/generic/patches-3.18/180-usb-xhci-make-USB_XHCI_PLATFORM-selectable.patch new file mode 100644 index 0000000..a17e398 --- /dev/null +++ b/target/linux/generic/patches-3.18/180-usb-xhci-make-USB_XHCI_PLATFORM-selectable.patch @@ -0,0 +1,41 @@ +From 9612e686b235dc9e33c8dfb5e6d2ff2b2140fb9d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Tue, 16 Jun 2015 21:01:30 +0200 +Subject: [PATCH V2] usb: xhci: make USB_XHCI_PLATFORM selectable +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Right now xhci-plat-hcd can be built when using one of platform specific +drivers only (mvebu/rcar). There shouldn't be such limitation as some +platforms may not require any quirks and may want to just use a generic +driver ("generic-xhci" / "xhci-hcd"). + +Signed-off-by: Rafał Miłecki +--- +Greg/Mathias: I'm not sure if it's more like USB subsystem stuff or xHCI +Could you decide which one of you could pick that, please? + +V2: Drop useless "default n", thanks Sergei :) +--- + drivers/usb/host/Kconfig | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +--- a/drivers/usb/host/Kconfig ++++ b/drivers/usb/host/Kconfig +@@ -32,7 +32,14 @@ config USB_XHCI_PCI + default y + + config USB_XHCI_PLATFORM +- tristate ++ tristate "Generic xHCI driver for a platform device" ++ ---help--- ++ Adds an xHCI host driver for a generic platform device, which ++ provides a memory space and an irq. ++ It is also a prerequisite for platform specific drivers that ++ implement some extra quirks. ++ ++ If unsure, say N. + + config USB_XHCI_MVEBU + tristate "xHCI support for Marvell Armada 375/38x" diff --git a/target/linux/generic/patches-3.18/190-cdc_ncm_add_support_for_moving_ndp_to_end_of_ncm_frame.patch b/target/linux/generic/patches-3.18/190-cdc_ncm_add_support_for_moving_ndp_to_end_of_ncm_frame.patch new file mode 100644 index 0000000..09cbe0c --- /dev/null +++ b/target/linux/generic/patches-3.18/190-cdc_ncm_add_support_for_moving_ndp_to_end_of_ncm_frame.patch @@ -0,0 +1,228 @@ +From 4a0e3e989d66bb7204b163d9cfaa7fa96d0f2023 Mon Sep 17 00:00:00 2001 +From: Enrico Mioso +Date: Wed, 8 Jul 2015 13:05:57 +0200 +Subject: [PATCH] cdc_ncm: Add support for moving NDP to end of NCM frame + +NCM specs are not actually mandating a specific position in the frame for +the NDP (Network Datagram Pointer). However, some Huawei devices will +ignore our aggregates if it is not placed after the datagrams it points +to. Add support for doing just this, in a per-device configurable way. +While at it, update NCM subdrivers, disabling this functionality in all of +them, except in huawei_cdc_ncm where it is enabled instead. +We aren't making any distinction between different Huawei NCM devices, +based on what the vendor driver does. Standard NCM devices are left +unaffected: if they are compliant, they should be always usable, still +stay on the safe side. + +This change has been tested and working with a Huawei E3131 device (which +works regardless of NDP position), a Huawei E3531 (also working both +ways) and an E3372 (which mandates NDP to be after indexed datagrams). + +V1->V2: +- corrected wrong NDP acronym definition +- fixed possible NULL pointer dereference +- patch cleanup +V2->V3: +- Properly account for the NDP size when writing new packets to SKB + +Signed-off-by: Enrico Mioso +Signed-off-by: David S. Miller +--- + drivers/net/usb/cdc_mbim.c | 2 +- + drivers/net/usb/cdc_ncm.c | 61 ++++++++++++++++++++++++++++++++++++---- + drivers/net/usb/huawei_cdc_ncm.c | 7 +++-- + include/linux/usb/cdc_ncm.h | 7 ++++- + 4 files changed, 67 insertions(+), 10 deletions(-) + +--- a/drivers/net/usb/cdc_mbim.c ++++ b/drivers/net/usb/cdc_mbim.c +@@ -158,7 +158,7 @@ static int cdc_mbim_bind(struct usbnet * + if (!cdc_ncm_comm_intf_is_mbim(intf->cur_altsetting)) + goto err; + +- ret = cdc_ncm_bind_common(dev, intf, data_altsetting); ++ ret = cdc_ncm_bind_common(dev, intf, data_altsetting, 0); + if (ret) + goto err; + +--- a/drivers/net/usb/cdc_ncm.c ++++ b/drivers/net/usb/cdc_ncm.c +@@ -684,10 +684,12 @@ static void cdc_ncm_free(struct cdc_ncm_ + ctx->tx_curr_skb = NULL; + } + ++ kfree(ctx->delayed_ndp16); ++ + kfree(ctx); + } + +-int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_altsetting) ++int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_altsetting, int drvflags) + { + const struct usb_cdc_union_desc *union_desc = NULL; + struct cdc_ncm_ctx *ctx; +@@ -855,6 +857,17 @@ advance: + /* finish setting up the device specific data */ + cdc_ncm_setup(dev); + ++ /* Device-specific flags */ ++ ctx->drvflags = drvflags; ++ ++ /* Allocate the delayed NDP if needed. */ ++ if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END) { ++ ctx->delayed_ndp16 = kzalloc(ctx->max_ndp_size, GFP_KERNEL); ++ if (!ctx->delayed_ndp16) ++ goto error2; ++ dev_info(&intf->dev, "NDP will be placed at end of frame for this device."); ++ } ++ + /* override ethtool_ops */ + dev->net->ethtool_ops = &cdc_ncm_ethtool_ops; + +@@ -954,8 +967,11 @@ static int cdc_ncm_bind(struct usbnet *d + if (cdc_ncm_select_altsetting(intf) != CDC_NCM_COMM_ALTSETTING_NCM) + return -ENODEV; + +- /* The NCM data altsetting is fixed */ +- ret = cdc_ncm_bind_common(dev, intf, CDC_NCM_DATA_ALTSETTING_NCM); ++ /* The NCM data altsetting is fixed, so we hard-coded it. ++ * Additionally, generic NCM devices are assumed to accept arbitrarily ++ * placed NDP. ++ */ ++ ret = cdc_ncm_bind_common(dev, intf, CDC_NCM_DATA_ALTSETTING_NCM, 0); + + /* + * We should get an event when network connection is "connected" or +@@ -986,6 +1002,14 @@ static struct usb_cdc_ncm_ndp16 *cdc_ncm + struct usb_cdc_ncm_nth16 *nth16 = (void *)skb->data; + size_t ndpoffset = le16_to_cpu(nth16->wNdpIndex); + ++ /* If NDP should be moved to the end of the NCM package, we can't follow the ++ * NTH16 header as we would normally do. NDP isn't written to the SKB yet, and ++ * the wNdpIndex field in the header is actually not consistent with reality. It will be later. ++ */ ++ if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END) ++ if (ctx->delayed_ndp16->dwSignature == sign) ++ return ctx->delayed_ndp16; ++ + /* follow the chain of NDPs, looking for a match */ + while (ndpoffset) { + ndp16 = (struct usb_cdc_ncm_ndp16 *)(skb->data + ndpoffset); +@@ -995,7 +1019,8 @@ static struct usb_cdc_ncm_ndp16 *cdc_ncm + } + + /* align new NDP */ +- cdc_ncm_align_tail(skb, ctx->tx_ndp_modulus, 0, ctx->tx_max); ++ if (!(ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END)) ++ cdc_ncm_align_tail(skb, ctx->tx_ndp_modulus, 0, ctx->tx_max); + + /* verify that there is room for the NDP and the datagram (reserve) */ + if ((ctx->tx_max - skb->len - reserve) < ctx->max_ndp_size) +@@ -1008,7 +1033,11 @@ static struct usb_cdc_ncm_ndp16 *cdc_ncm + nth16->wNdpIndex = cpu_to_le16(skb->len); + + /* push a new empty NDP */ +- ndp16 = (struct usb_cdc_ncm_ndp16 *)memset(skb_put(skb, ctx->max_ndp_size), 0, ctx->max_ndp_size); ++ if (!(ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END)) ++ ndp16 = (struct usb_cdc_ncm_ndp16 *)memset(skb_put(skb, ctx->max_ndp_size), 0, ctx->max_ndp_size); ++ else ++ ndp16 = ctx->delayed_ndp16; ++ + ndp16->dwSignature = sign; + ndp16->wLength = cpu_to_le16(sizeof(struct usb_cdc_ncm_ndp16) + sizeof(struct usb_cdc_ncm_dpe16)); + return ndp16; +@@ -1023,6 +1052,15 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev + struct sk_buff *skb_out; + u16 n = 0, index, ndplen; + u8 ready2send = 0; ++ u32 delayed_ndp_size; ++ ++ /* When our NDP gets written in cdc_ncm_ndp(), then skb_out->len gets updated ++ * accordingly. Otherwise, we should check here. ++ */ ++ if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END) ++ delayed_ndp_size = ctx->max_ndp_size; ++ else ++ delayed_ndp_size = 0; + + /* if there is a remaining skb, it gets priority */ + if (skb != NULL) { +@@ -1077,7 +1115,7 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev + cdc_ncm_align_tail(skb_out, ctx->tx_modulus, ctx->tx_remainder, ctx->tx_max); + + /* check if we had enough room left for both NDP and frame */ +- if (!ndp16 || skb_out->len + skb->len > ctx->tx_max) { ++ if (!ndp16 || skb_out->len + skb->len + delayed_ndp_size > ctx->tx_max) { + if (n == 0) { + /* won't fit, MTU problem? */ + dev_kfree_skb_any(skb); +@@ -1150,6 +1188,17 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev + /* variables will be reset at next call */ + } + ++ /* If requested, put NDP at end of frame. */ ++ if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END) { ++ nth16 = (struct usb_cdc_ncm_nth16 *)skb_out->data; ++ cdc_ncm_align_tail(skb_out, ctx->tx_ndp_modulus, 0, ctx->tx_max); ++ nth16->wNdpIndex = cpu_to_le16(skb_out->len); ++ memcpy(skb_put(skb_out, ctx->max_ndp_size), ctx->delayed_ndp16, ctx->max_ndp_size); ++ ++ /* Zero out delayed NDP - signature checking will naturally fail. */ ++ ndp16 = memset(ctx->delayed_ndp16, 0, ctx->max_ndp_size); ++ } ++ + /* If collected data size is less or equal ctx->min_tx_pkt + * bytes, we send buffers as it is. If we get more data, it + * would be more efficient for USB HS mobile device with DMA +--- a/drivers/net/usb/huawei_cdc_ncm.c ++++ b/drivers/net/usb/huawei_cdc_ncm.c +@@ -73,11 +73,14 @@ static int huawei_cdc_ncm_bind(struct us + struct usb_driver *subdriver = ERR_PTR(-ENODEV); + int ret = -ENODEV; + struct huawei_cdc_ncm_state *drvstate = (void *)&usbnet_dev->data; ++ int drvflags = 0; + + /* altsetting should always be 1 for NCM devices - so we hard-coded +- * it here ++ * it here. Some huawei devices will need the NDP part of the NCM package to ++ * be at the end of the frame. + */ +- ret = cdc_ncm_bind_common(usbnet_dev, intf, 1); ++ drvflags |= CDC_NCM_FLAG_NDP_TO_END; ++ ret = cdc_ncm_bind_common(usbnet_dev, intf, 1, drvflags); + if (ret) + goto err; + +--- a/include/linux/usb/cdc_ncm.h ++++ b/include/linux/usb/cdc_ncm.h +@@ -80,6 +80,9 @@ + #define CDC_NCM_TIMER_INTERVAL_MIN 5UL + #define CDC_NCM_TIMER_INTERVAL_MAX (U32_MAX / NSEC_PER_USEC) + ++/* Driver flags */ ++#define CDC_NCM_FLAG_NDP_TO_END 0x02 /* NDP is placed at end of frame */ ++ + #define cdc_ncm_comm_intf_is_mbim(x) ((x)->desc.bInterfaceSubClass == USB_CDC_SUBCLASS_MBIM && \ + (x)->desc.bInterfaceProtocol == USB_CDC_PROTO_NONE) + #define cdc_ncm_data_intf_is_mbim(x) ((x)->desc.bInterfaceProtocol == USB_CDC_MBIM_PROTO_NTB) +@@ -103,9 +106,11 @@ struct cdc_ncm_ctx { + + spinlock_t mtx; + atomic_t stop; ++ int drvflags; + + u32 timer_interval; + u32 max_ndp_size; ++ struct usb_cdc_ncm_ndp16 *delayed_ndp16; + + u32 tx_timer_pending; + u32 tx_curr_frame_num; +@@ -133,7 +138,7 @@ struct cdc_ncm_ctx { + }; + + u8 cdc_ncm_select_altsetting(struct usb_interface *intf); +-int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_altsetting); ++int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_altsetting, int drvflags); + void cdc_ncm_unbind(struct usbnet *dev, struct usb_interface *intf); + struct sk_buff *cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign); + int cdc_ncm_rx_verify_nth16(struct cdc_ncm_ctx *ctx, struct sk_buff *skb_in); diff --git a/target/linux/generic/patches-3.18/191-usb-ehci-orion-fix-probe-for-GENERIC_PHY.patch b/target/linux/generic/patches-3.18/191-usb-ehci-orion-fix-probe-for-GENERIC_PHY.patch new file mode 100644 index 0000000..5a3dc06 --- /dev/null +++ b/target/linux/generic/patches-3.18/191-usb-ehci-orion-fix-probe-for-GENERIC_PHY.patch @@ -0,0 +1,35 @@ +From a95f03e51471dbdbafd3391991d867ac2358ed02 Mon Sep 17 00:00:00 2001 +From: Jonas Gorski +Date: Sun, 23 Aug 2015 14:23:29 +0200 +Subject: [PATCH] usb: ehci-orion: fix probe for !GENERIC_PHY + +Commit d445913ce0ab7f ("usb: ehci-orion: add optional PHY support") +added support for optional phys, but devm_phy_optional_get returns +-ENOSYS if GENERIC_PHY is not enabled. + +This causes probe failures, even when there are no phys specified: + +[ 1.443365] orion-ehci f1058000.usb: init f1058000.usb fail, -38 +[ 1.449403] orion-ehci: probe of f1058000.usb failed with error -38 + +Similar to dwc3, treat -ENOSYS as no phy. + +Fixes: d445913ce0ab7f ("usb: ehci-orion: add optional PHY support") + +Signed-off-by: Jonas Gorski +--- + drivers/usb/host/ehci-orion.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/usb/host/ehci-orion.c ++++ b/drivers/usb/host/ehci-orion.c +@@ -226,7 +226,8 @@ static int ehci_orion_drv_probe(struct p + priv->phy = devm_phy_optional_get(&pdev->dev, "usb"); + if (IS_ERR(priv->phy)) { + err = PTR_ERR(priv->phy); +- goto err_phy_get; ++ if (err != -ENOSYS) ++ goto err_phy_get; + } else { + err = phy_init(priv->phy); + if (err) diff --git a/target/linux/generic/patches-3.18/200-fix_localversion.patch b/target/linux/generic/patches-3.18/200-fix_localversion.patch new file mode 100644 index 0000000..70228bb --- /dev/null +++ b/target/linux/generic/patches-3.18/200-fix_localversion.patch @@ -0,0 +1,11 @@ +--- a/scripts/setlocalversion ++++ b/scripts/setlocalversion +@@ -165,7 +165,7 @@ else + # annotated or signed tagged state (as git describe only + # looks at signed or annotated tags - git tag -a/-s) and + # LOCALVERSION= is not specified +- if test "${LOCALVERSION+set}" != "set"; then ++ if test "${CONFIG_LOCALVERSION+set}" != "set"; then + scm=$(scm_version --short) + res="$res${scm:++}" + fi diff --git a/target/linux/generic/patches-3.18/201-extra_optimization.patch b/target/linux/generic/patches-3.18/201-extra_optimization.patch new file mode 100644 index 0000000..7ec93a4 --- /dev/null +++ b/target/linux/generic/patches-3.18/201-extra_optimization.patch @@ -0,0 +1,14 @@ +--- a/Makefile ++++ b/Makefile +@@ -612,9 +612,9 @@ include $(srctree)/arch/$(SRCARCH)/Makef + KBUILD_CFLAGS += $(call cc-option,-fno-delete-null-pointer-checks,) + + ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE +-KBUILD_CFLAGS += -Os $(call cc-disable-warning,maybe-uninitialized,) ++KBUILD_CFLAGS += -Os $(EXTRA_OPTIMIZATION) $(call cc-disable-warning,maybe-uninitialized,) + else +-KBUILD_CFLAGS += -O2 ++KBUILD_CFLAGS += -O2 -fno-reorder-blocks -fno-tree-ch $(EXTRA_OPTIMIZATION) + endif + + # Tell gcc to never replace conditional load with a non-conditional one diff --git a/target/linux/generic/patches-3.18/202-reduce_module_size.patch b/target/linux/generic/patches-3.18/202-reduce_module_size.patch new file mode 100644 index 0000000..b98ea4e --- /dev/null +++ b/target/linux/generic/patches-3.18/202-reduce_module_size.patch @@ -0,0 +1,11 @@ +--- a/Makefile ++++ b/Makefile +@@ -409,7 +409,7 @@ KBUILD_CFLAGS_KERNEL := + KBUILD_AFLAGS := -D__ASSEMBLY__ + KBUILD_AFLAGS_MODULE := -DMODULE + KBUILD_CFLAGS_MODULE := -DMODULE +-KBUILD_LDFLAGS_MODULE := -T $(srctree)/scripts/module-common.lds ++KBUILD_LDFLAGS_MODULE = -T $(srctree)/scripts/module-common.lds $(if $(CONFIG_PROFILING),,-s) + + # Read KERNELRELEASE from include/config/kernel.release (if it exists) + KERNELRELEASE = $(shell cat include/config/kernel.release 2> /dev/null) diff --git a/target/linux/generic/patches-3.18/203-kallsyms_uncompressed.patch b/target/linux/generic/patches-3.18/203-kallsyms_uncompressed.patch new file mode 100644 index 0000000..b9d8220 --- /dev/null +++ b/target/linux/generic/patches-3.18/203-kallsyms_uncompressed.patch @@ -0,0 +1,108 @@ +--- a/scripts/kallsyms.c ++++ b/scripts/kallsyms.c +@@ -58,6 +58,7 @@ static struct addr_range percpu_range = + static struct sym_entry *table; + static unsigned int table_size, table_cnt; + static int all_symbols = 0; ++static int uncompressed = 0; + static int absolute_percpu = 0; + static char symbol_prefix_char = '\0'; + static unsigned long long kernel_start_addr = 0; +@@ -392,6 +393,9 @@ static void write_src(void) + + free(markers); + ++ if (uncompressed) ++ return; ++ + output_label("kallsyms_token_table"); + off = 0; + for (i = 0; i < 256; i++) { +@@ -450,6 +454,9 @@ static void *find_token(unsigned char *s + { + int i; + ++ if (uncompressed) ++ return NULL; ++ + for (i = 0; i < len - 1; i++) { + if (str[i] == token[0] && str[i+1] == token[1]) + return &str[i]; +@@ -522,6 +529,9 @@ static void optimize_result(void) + { + int i, best; + ++ if (uncompressed) ++ return; ++ + /* using the '\0' symbol last allows compress_symbols to use standard + * fast string functions */ + for (i = 255; i >= 0; i--) { +@@ -692,7 +702,9 @@ int main(int argc, char **argv) + } else if (strncmp(argv[i], "--page-offset=", 14) == 0) { + const char *p = &argv[i][14]; + kernel_start_addr = strtoull(p, NULL, 16); +- } else ++ } else if (strcmp(argv[i], "--uncompressed") == 0) ++ uncompressed = 1; ++ else + usage(); + } + } else if (argc != 1) +--- a/init/Kconfig ++++ b/init/Kconfig +@@ -1338,6 +1338,17 @@ config SYSCTL_ARCH_UNALIGN_ALLOW + the unaligned access emulation. + see arch/parisc/kernel/unaligned.c for reference + ++config KALLSYMS_UNCOMPRESSED ++ bool "Keep kallsyms uncompressed" ++ depends on KALLSYMS ++ help ++ Normally kallsyms contains compressed symbols (using a token table), ++ reducing the uncompressed kernel image size. Keeping the symbol table ++ uncompressed significantly improves the size of this part in compressed ++ kernel images. ++ ++ Say N unless you need compressed kernel images to be small. ++ + config HAVE_PCSPKR_PLATFORM + bool + +--- a/scripts/link-vmlinux.sh ++++ b/scripts/link-vmlinux.sh +@@ -90,6 +90,10 @@ kallsyms() + kallsymopt="${kallsymopt} --absolute-percpu" + fi + ++ if [ -n "${CONFIG_KALLSYMS_UNCOMPRESSED}" ]; then ++ kallsymopt="${kallsymopt} --uncompressed" ++ fi ++ + local aflags="${KBUILD_AFLAGS} ${KBUILD_AFLAGS_KERNEL} \ + ${NOSTDINC_FLAGS} ${LINUXINCLUDE} ${KBUILD_CPPFLAGS}" + +--- a/kernel/kallsyms.c ++++ b/kernel/kallsyms.c +@@ -109,6 +109,11 @@ static unsigned int kallsyms_expand_symb + * For every byte on the compressed symbol data, copy the table + * entry for that byte. + */ ++#ifdef CONFIG_KALLSYMS_UNCOMPRESSED ++ memcpy(result, data + 1, len - 1); ++ result += len - 1; ++ len = 0; ++#endif + while (len) { + tptr = &kallsyms_token_table[kallsyms_token_index[*data]]; + data++; +@@ -141,6 +146,9 @@ tail: + */ + static char kallsyms_get_symbol_type(unsigned int off) + { ++#ifdef CONFIG_KALLSYMS_UNCOMPRESSED ++ return kallsyms_names[off + 1]; ++#endif + /* + * Get just the first code, look it up in the token table, + * and return the first char from this token. diff --git a/target/linux/generic/patches-3.18/204-module_strip.patch b/target/linux/generic/patches-3.18/204-module_strip.patch new file mode 100644 index 0000000..09bffe0 --- /dev/null +++ b/target/linux/generic/patches-3.18/204-module_strip.patch @@ -0,0 +1,194 @@ +From: Felix Fietkau +Subject: [PATCH] build: add a hack for removing non-essential module info + +Signed-off-by: Felix Fietkau +--- +--- a/include/linux/module.h ++++ b/include/linux/module.h +@@ -84,9 +84,10 @@ void trim_init_extable(struct module *m) + + /* Generic info of form tag = "info" */ + #define MODULE_INFO(tag, info) __MODULE_INFO(tag, tag, info) ++#define MODULE_INFO_STRIP(tag, info) __MODULE_INFO_STRIP(tag, tag, info) + + /* For userspace: you can also call me... */ +-#define MODULE_ALIAS(_alias) MODULE_INFO(alias, _alias) ++#define MODULE_ALIAS(_alias) MODULE_INFO_STRIP(alias, _alias) + + /* Soft module dependencies. See man modprobe.d for details. + * Example: MODULE_SOFTDEP("pre: module-foo module-bar post: module-baz") +@@ -127,12 +128,12 @@ void trim_init_extable(struct module *m) + * Author(s), use "Name " or just "Name", for multiple + * authors use multiple MODULE_AUTHOR() statements/lines. + */ +-#define MODULE_AUTHOR(_author) MODULE_INFO(author, _author) ++#define MODULE_AUTHOR(_author) MODULE_INFO_STRIP(author, _author) + + /* What your module does. */ +-#define MODULE_DESCRIPTION(_description) MODULE_INFO(description, _description) ++#define MODULE_DESCRIPTION(_description) MODULE_INFO_STRIP(description, _description) + +-#ifdef MODULE ++#if defined(MODULE) && !defined(CONFIG_MODULE_STRIPPED) + /* Creates an alias so file2alias.c can find device table. */ + #define MODULE_DEVICE_TABLE(type, name) \ + extern const struct type##_device_id __mod_##type##__##name##_device_table \ +@@ -159,7 +160,9 @@ void trim_init_extable(struct module *m) + */ + + #if defined(MODULE) || !defined(CONFIG_SYSFS) +-#define MODULE_VERSION(_version) MODULE_INFO(version, _version) ++#define MODULE_VERSION(_version) MODULE_INFO_STRIP(version, _version) ++#elif defined(CONFIG_MODULE_STRIPPED) ++#define MODULE_VERSION(_version) __MODULE_INFO_DISABLED(version) + #else + #define MODULE_VERSION(_version) \ + static struct module_version_attribute ___modver_attr = { \ +@@ -181,7 +184,7 @@ void trim_init_extable(struct module *m) + /* Optional firmware file (or files) needed by the module + * format is simply firmware file name. Multiple firmware + * files require multiple MODULE_FIRMWARE() specifiers */ +-#define MODULE_FIRMWARE(_firmware) MODULE_INFO(firmware, _firmware) ++#define MODULE_FIRMWARE(_firmware) MODULE_INFO_STRIP(firmware, _firmware) + + /* Given an address, look for it in the exception tables */ + const struct exception_table_entry *search_exception_tables(unsigned long add); +--- a/include/linux/moduleparam.h ++++ b/include/linux/moduleparam.h +@@ -16,6 +16,16 @@ + /* Chosen so that structs with an unsigned long line up. */ + #define MAX_PARAM_PREFIX_LEN (64 - sizeof(unsigned long)) + ++/* This struct is here for syntactic coherency, it is not used */ ++#define __MODULE_INFO_DISABLED(name) \ ++ struct __UNIQUE_ID(name) {} ++ ++#ifdef CONFIG_MODULE_STRIPPED ++#define __MODULE_INFO_STRIP(tag, name, info) __MODULE_INFO_DISABLED(name) ++#else ++#define __MODULE_INFO_STRIP(tag, name, info) __MODULE_INFO(tag, name, info) ++#endif ++ + #ifdef MODULE + #define __MODULE_INFO(tag, name, info) \ + static const char __UNIQUE_ID(name)[] \ +@@ -23,8 +33,7 @@ static const char __UNIQUE_ID(name)[] + = __stringify(tag) "=" info + #else /* !MODULE */ + /* This struct is here for syntactic coherency, it is not used */ +-#define __MODULE_INFO(tag, name, info) \ +- struct __UNIQUE_ID(name) {} ++#define __MODULE_INFO(tag, name, info) __MODULE_INFO_DISABLED(name) + #endif + #define __MODULE_PARM_TYPE(name, _type) \ + __MODULE_INFO(parmtype, name##type, #name ":" _type) +@@ -32,7 +41,7 @@ static const char __UNIQUE_ID(name)[] + /* One for each parameter, describing how to use it. Some files do + multiple of these per line, so can't just use MODULE_INFO. */ + #define MODULE_PARM_DESC(_parm, desc) \ +- __MODULE_INFO(parm, _parm, #_parm ":" desc) ++ __MODULE_INFO_STRIP(parm, _parm, #_parm ":" desc) + + struct kernel_param; + +--- a/init/Kconfig ++++ b/init/Kconfig +@@ -1987,6 +1987,13 @@ config MODULE_COMPRESS_XZ + + endchoice + ++config MODULE_STRIPPED ++ bool "Reduce module size" ++ depends on MODULES ++ help ++ Remove module parameter descriptions, author info, version, aliases, ++ device tables, etc. ++ + endif # MODULES + + config INIT_ALL_POSSIBLE +--- a/kernel/module.c ++++ b/kernel/module.c +@@ -2670,6 +2670,7 @@ static struct module *setup_load_info(st + + static int check_modinfo(struct module *mod, struct load_info *info, int flags) + { ++#ifndef CONFIG_MODULE_STRIPPED + const char *modmagic = get_modinfo(info, "vermagic"); + int err; + +@@ -2695,6 +2696,7 @@ static int check_modinfo(struct module * + pr_warn("%s: module is from the staging directory, the quality " + "is unknown, you have been warned.\n", mod->name); + } ++#endif + + /* Set up license info based on the info section */ + set_license(mod, get_modinfo(info, "license")); +--- a/scripts/mod/modpost.c ++++ b/scripts/mod/modpost.c +@@ -1726,7 +1726,9 @@ static void read_symbols(char *modname) + symname = remove_dot(info.strtab + sym->st_name); + + handle_modversions(mod, &info, sym, symname); ++#ifndef CONFIG_MODULE_STRIPPED + handle_moddevtable(mod, &info, sym, symname); ++#endif + } + if (!is_vmlinux(modname) || + (is_vmlinux(modname) && vmlinux_section_warnings)) +@@ -1870,7 +1872,9 @@ static void add_header(struct buffer *b, + buf_printf(b, "#include \n"); + buf_printf(b, "#include \n"); + buf_printf(b, "\n"); ++#ifndef CONFIG_MODULE_STRIPPED + buf_printf(b, "MODULE_INFO(vermagic, VERMAGIC_STRING);\n"); ++#endif + buf_printf(b, "\n"); + buf_printf(b, "__visible struct module __this_module\n"); + buf_printf(b, "__attribute__((section(\".gnu.linkonce.this_module\"))) = {\n"); +@@ -1887,16 +1891,20 @@ static void add_header(struct buffer *b, + + static void add_intree_flag(struct buffer *b, int is_intree) + { ++#ifndef CONFIG_MODULE_STRIPPED + if (is_intree) + buf_printf(b, "\nMODULE_INFO(intree, \"Y\");\n"); ++#endif + } + + static void add_staging_flag(struct buffer *b, const char *name) + { ++#ifndef CONFIG_MODULE_STRIPPED + static const char *staging_dir = "drivers/staging"; + + if (strncmp(staging_dir, name, strlen(staging_dir)) == 0) + buf_printf(b, "\nMODULE_INFO(staging, \"Y\");\n"); ++#endif + } + + /** +@@ -1989,11 +1997,13 @@ static void add_depends(struct buffer *b + + static void add_srcversion(struct buffer *b, struct module *mod) + { ++#ifndef CONFIG_MODULE_STRIPPED + if (mod->srcversion[0]) { + buf_printf(b, "\n"); + buf_printf(b, "MODULE_INFO(srcversion, \"%s\");\n", + mod->srcversion); + } ++#endif + } + + static void write_if_changed(struct buffer *b, const char *fname) +@@ -2224,7 +2234,9 @@ int main(int argc, char **argv) + add_staging_flag(&buf, mod->name); + err |= add_versions(&buf, mod); + add_depends(&buf, mod, modules); ++#ifndef CONFIG_MODULE_STRIPPED + add_moddevtable(&buf, mod); ++#endif + add_srcversion(&buf, mod); + + sprintf(fname, "%s.mod.c", mod->name); diff --git a/target/linux/generic/patches-3.18/205-backtrace_module_info.patch b/target/linux/generic/patches-3.18/205-backtrace_module_info.patch new file mode 100644 index 0000000..f83b21e --- /dev/null +++ b/target/linux/generic/patches-3.18/205-backtrace_module_info.patch @@ -0,0 +1,36 @@ +--- a/lib/vsprintf.c ++++ b/lib/vsprintf.c +@@ -614,8 +614,10 @@ char *symbol_string(char *buf, char *end + struct printf_spec spec, const char *fmt) + { + unsigned long value; +-#ifdef CONFIG_KALLSYMS + char sym[KSYM_SYMBOL_LEN]; ++#ifndef CONFIG_KALLSYMS ++ struct module *mod; ++ int len; + #endif + + if (fmt[1] == 'R') +@@ -629,15 +631,15 @@ char *symbol_string(char *buf, char *end + sprint_symbol(sym, value); + else + sprint_symbol_no_offset(sym, value); +- +- return string(buf, end, sym, spec); + #else +- spec.field_width = 2 * sizeof(void *); +- spec.flags |= SPECIAL | SMALL | ZEROPAD; +- spec.base = 16; ++ len = snprintf(sym, sizeof(sym), "0x%lx", value); + +- return number(buf, end, value, spec); ++ mod = __module_address(value); ++ if (mod) ++ snprintf(sym + len, sizeof(sym) - len, " [%s@%p+0x%x]", ++ mod->name, mod->module_core, mod->core_size); + #endif ++ return string(buf, end, sym, spec); + } + + static noinline_for_stack diff --git a/target/linux/generic/patches-3.18/210-darwin_scripts_include.patch b/target/linux/generic/patches-3.18/210-darwin_scripts_include.patch new file mode 100644 index 0000000..dc554de --- /dev/null +++ b/target/linux/generic/patches-3.18/210-darwin_scripts_include.patch @@ -0,0 +1,3088 @@ +--- a/scripts/kallsyms.c ++++ b/scripts/kallsyms.c +@@ -22,6 +22,35 @@ + #include + #include + #include ++#ifdef __APPLE__ ++/* Darwin has no memmem implementation, this one is ripped of the uClibc-0.9.28 source */ ++void *memmem (const void *haystack, size_t haystack_len, ++ const void *needle, size_t needle_len) ++{ ++ const char *begin; ++ const char *const last_possible ++ = (const char *) haystack + haystack_len - needle_len; ++ ++ if (needle_len == 0) ++ /* The first occurrence of the empty string is deemed to occur at ++ the beginning of the string. */ ++ return (void *) haystack; ++ ++ /* Sanity check, otherwise the loop might search through the whole ++ memory. */ ++ if (__builtin_expect (haystack_len < needle_len, 0)) ++ return NULL; ++ ++ for (begin = (const char *) haystack; begin <= last_possible; ++begin) ++ if (begin[0] == ((const char *) needle)[0] && ++ !memcmp ((const void *) &begin[1], ++ (const void *) ((const char *) needle + 1), ++ needle_len - 1)) ++ return (void *) begin; ++ ++ return NULL; ++} ++#endif + + #ifndef ARRAY_SIZE + #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) +--- a/scripts/kconfig/Makefile ++++ b/scripts/kconfig/Makefile +@@ -151,6 +151,9 @@ check-lxdialog := $(srctree)/$(src)/lxd + # we really need to do so. (Do not call gcc as part of make mrproper) + HOST_EXTRACFLAGS += $(shell $(CONFIG_SHELL) $(check-lxdialog) -ccflags) \ + -DLOCALE ++ifeq ($(shell uname -s),Darwin) ++HOST_LOADLIBES += -lncurses ++endif + + # =========================================================================== + # Shared Makefile for the various kconfig executables: +--- a/scripts/mod/mk_elfconfig.c ++++ b/scripts/mod/mk_elfconfig.c +@@ -1,7 +1,11 @@ + #include + #include + #include ++#ifndef __APPLE__ + #include ++#else ++#include "elf.h" ++#endif + + int + main(int argc, char **argv) +--- a/scripts/mod/modpost.h ++++ b/scripts/mod/modpost.h +@@ -7,7 +7,11 @@ + #include + #include + #include ++#if !(defined(__APPLE__) || defined(__CYGWIN__)) + #include ++#else ++#include "elf.h" ++#endif + + #include "elfconfig.h" + +--- /dev/null ++++ b/scripts/mod/elf.h +@@ -0,0 +1,3007 @@ ++/* This file defines standard ELF types, structures, and macros. ++ Copyright (C) 1995-2012 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#ifndef _ELF_H ++#define _ELF_H 1 ++ ++/* Standard ELF types. */ ++ ++#include ++ ++/* Type for a 16-bit quantity. */ ++typedef uint16_t Elf32_Half; ++typedef uint16_t Elf64_Half; ++ ++/* Types for signed and unsigned 32-bit quantities. */ ++typedef uint32_t Elf32_Word; ++typedef int32_t Elf32_Sword; ++typedef uint32_t Elf64_Word; ++typedef int32_t Elf64_Sword; ++ ++/* Types for signed and unsigned 64-bit quantities. */ ++typedef uint64_t Elf32_Xword; ++typedef int64_t Elf32_Sxword; ++typedef uint64_t Elf64_Xword; ++typedef int64_t Elf64_Sxword; ++ ++/* Type of addresses. */ ++typedef uint32_t Elf32_Addr; ++typedef uint64_t Elf64_Addr; ++ ++/* Type of file offsets. */ ++typedef uint32_t Elf32_Off; ++typedef uint64_t Elf64_Off; ++ ++/* Type for section indices, which are 16-bit quantities. */ ++typedef uint16_t Elf32_Section; ++typedef uint16_t Elf64_Section; ++ ++/* Type for version symbol information. */ ++typedef Elf32_Half Elf32_Versym; ++typedef Elf64_Half Elf64_Versym; ++ ++ ++/* The ELF file header. This appears at the start of every ELF file. */ ++ ++#define EI_NIDENT (16) ++ ++typedef struct ++{ ++ unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ ++ Elf32_Half e_type; /* Object file type */ ++ Elf32_Half e_machine; /* Architecture */ ++ Elf32_Word e_version; /* Object file version */ ++ Elf32_Addr e_entry; /* Entry point virtual address */ ++ Elf32_Off e_phoff; /* Program header table file offset */ ++ Elf32_Off e_shoff; /* Section header table file offset */ ++ Elf32_Word e_flags; /* Processor-specific flags */ ++ Elf32_Half e_ehsize; /* ELF header size in bytes */ ++ Elf32_Half e_phentsize; /* Program header table entry size */ ++ Elf32_Half e_phnum; /* Program header table entry count */ ++ Elf32_Half e_shentsize; /* Section header table entry size */ ++ Elf32_Half e_shnum; /* Section header table entry count */ ++ Elf32_Half e_shstrndx; /* Section header string table index */ ++} Elf32_Ehdr; ++ ++typedef struct ++{ ++ unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ ++ Elf64_Half e_type; /* Object file type */ ++ Elf64_Half e_machine; /* Architecture */ ++ Elf64_Word e_version; /* Object file version */ ++ Elf64_Addr e_entry; /* Entry point virtual address */ ++ Elf64_Off e_phoff; /* Program header table file offset */ ++ Elf64_Off e_shoff; /* Section header table file offset */ ++ Elf64_Word e_flags; /* Processor-specific flags */ ++ Elf64_Half e_ehsize; /* ELF header size in bytes */ ++ Elf64_Half e_phentsize; /* Program header table entry size */ ++ Elf64_Half e_phnum; /* Program header table entry count */ ++ Elf64_Half e_shentsize; /* Section header table entry size */ ++ Elf64_Half e_shnum; /* Section header table entry count */ ++ Elf64_Half e_shstrndx; /* Section header string table index */ ++} Elf64_Ehdr; ++ ++/* Fields in the e_ident array. The EI_* macros are indices into the ++ array. The macros under each EI_* macro are the values the byte ++ may have. */ ++ ++#define EI_MAG0 0 /* File identification byte 0 index */ ++#define ELFMAG0 0x7f /* Magic number byte 0 */ ++ ++#define EI_MAG1 1 /* File identification byte 1 index */ ++#define ELFMAG1 'E' /* Magic number byte 1 */ ++ ++#define EI_MAG2 2 /* File identification byte 2 index */ ++#define ELFMAG2 'L' /* Magic number byte 2 */ ++ ++#define EI_MAG3 3 /* File identification byte 3 index */ ++#define ELFMAG3 'F' /* Magic number byte 3 */ ++ ++/* Conglomeration of the identification bytes, for easy testing as a word. */ ++#define ELFMAG "\177ELF" ++#define SELFMAG 4 ++ ++#define EI_CLASS 4 /* File class byte index */ ++#define ELFCLASSNONE 0 /* Invalid class */ ++#define ELFCLASS32 1 /* 32-bit objects */ ++#define ELFCLASS64 2 /* 64-bit objects */ ++#define ELFCLASSNUM 3 ++ ++#define EI_DATA 5 /* Data encoding byte index */ ++#define ELFDATANONE 0 /* Invalid data encoding */ ++#define ELFDATA2LSB 1 /* 2's complement, little endian */ ++#define ELFDATA2MSB 2 /* 2's complement, big endian */ ++#define ELFDATANUM 3 ++ ++#define EI_VERSION 6 /* File version byte index */ ++ /* Value must be EV_CURRENT */ ++ ++#define EI_OSABI 7 /* OS ABI identification */ ++#define ELFOSABI_NONE 0 /* UNIX System V ABI */ ++#define ELFOSABI_SYSV 0 /* Alias. */ ++#define ELFOSABI_HPUX 1 /* HP-UX */ ++#define ELFOSABI_NETBSD 2 /* NetBSD. */ ++#define ELFOSABI_GNU 3 /* Object uses GNU ELF extensions. */ ++#define ELFOSABI_LINUX ELFOSABI_GNU /* Compatibility alias. */ ++#define ELFOSABI_SOLARIS 6 /* Sun Solaris. */ ++#define ELFOSABI_AIX 7 /* IBM AIX. */ ++#define ELFOSABI_IRIX 8 /* SGI Irix. */ ++#define ELFOSABI_FREEBSD 9 /* FreeBSD. */ ++#define ELFOSABI_TRU64 10 /* Compaq TRU64 UNIX. */ ++#define ELFOSABI_MODESTO 11 /* Novell Modesto. */ ++#define ELFOSABI_OPENBSD 12 /* OpenBSD. */ ++#define ELFOSABI_ARM_AEABI 64 /* ARM EABI */ ++#define ELFOSABI_ARM 97 /* ARM */ ++#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ ++ ++#define EI_ABIVERSION 8 /* ABI version */ ++ ++#define EI_PAD 9 /* Byte index of padding bytes */ ++ ++/* Legal values for e_type (object file type). */ ++ ++#define ET_NONE 0 /* No file type */ ++#define ET_REL 1 /* Relocatable file */ ++#define ET_EXEC 2 /* Executable file */ ++#define ET_DYN 3 /* Shared object file */ ++#define ET_CORE 4 /* Core file */ ++#define ET_NUM 5 /* Number of defined types */ ++#define ET_LOOS 0xfe00 /* OS-specific range start */ ++#define ET_HIOS 0xfeff /* OS-specific range end */ ++#define ET_LOPROC 0xff00 /* Processor-specific range start */ ++#define ET_HIPROC 0xffff /* Processor-specific range end */ ++ ++/* Legal values for e_machine (architecture). */ ++ ++#define EM_NONE 0 /* No machine */ ++#define EM_M32 1 /* AT&T WE 32100 */ ++#define EM_SPARC 2 /* SUN SPARC */ ++#define EM_386 3 /* Intel 80386 */ ++#define EM_68K 4 /* Motorola m68k family */ ++#define EM_88K 5 /* Motorola m88k family */ ++#define EM_860 7 /* Intel 80860 */ ++#define EM_MIPS 8 /* MIPS R3000 big-endian */ ++#define EM_S370 9 /* IBM System/370 */ ++#define EM_MIPS_RS3_LE 10 /* MIPS R3000 little-endian */ ++ ++#define EM_PARISC 15 /* HPPA */ ++#define EM_VPP500 17 /* Fujitsu VPP500 */ ++#define EM_SPARC32PLUS 18 /* Sun's "v8plus" */ ++#define EM_960 19 /* Intel 80960 */ ++#define EM_PPC 20 /* PowerPC */ ++#define EM_PPC64 21 /* PowerPC 64-bit */ ++#define EM_S390 22 /* IBM S390 */ ++ ++#define EM_V800 36 /* NEC V800 series */ ++#define EM_FR20 37 /* Fujitsu FR20 */ ++#define EM_RH32 38 /* TRW RH-32 */ ++#define EM_RCE 39 /* Motorola RCE */ ++#define EM_ARM 40 /* ARM */ ++#define EM_FAKE_ALPHA 41 /* Digital Alpha */ ++#define EM_SH 42 /* Hitachi SH */ ++#define EM_SPARCV9 43 /* SPARC v9 64-bit */ ++#define EM_TRICORE 44 /* Siemens Tricore */ ++#define EM_ARC 45 /* Argonaut RISC Core */ ++#define EM_H8_300 46 /* Hitachi H8/300 */ ++#define EM_H8_300H 47 /* Hitachi H8/300H */ ++#define EM_H8S 48 /* Hitachi H8S */ ++#define EM_H8_500 49 /* Hitachi H8/500 */ ++#define EM_IA_64 50 /* Intel Merced */ ++#define EM_MIPS_X 51 /* Stanford MIPS-X */ ++#define EM_COLDFIRE 52 /* Motorola Coldfire */ ++#define EM_68HC12 53 /* Motorola M68HC12 */ ++#define EM_MMA 54 /* Fujitsu MMA Multimedia Accelerator*/ ++#define EM_PCP 55 /* Siemens PCP */ ++#define EM_NCPU 56 /* Sony nCPU embeeded RISC */ ++#define EM_NDR1 57 /* Denso NDR1 microprocessor */ ++#define EM_STARCORE 58 /* Motorola Start*Core processor */ ++#define EM_ME16 59 /* Toyota ME16 processor */ ++#define EM_ST100 60 /* STMicroelectronic ST100 processor */ ++#define EM_TINYJ 61 /* Advanced Logic Corp. Tinyj emb.fam*/ ++#define EM_X86_64 62 /* AMD x86-64 architecture */ ++#define EM_PDSP 63 /* Sony DSP Processor */ ++ ++#define EM_FX66 66 /* Siemens FX66 microcontroller */ ++#define EM_ST9PLUS 67 /* STMicroelectronics ST9+ 8/16 mc */ ++#define EM_ST7 68 /* STmicroelectronics ST7 8 bit mc */ ++#define EM_68HC16 69 /* Motorola MC68HC16 microcontroller */ ++#define EM_68HC11 70 /* Motorola MC68HC11 microcontroller */ ++#define EM_68HC08 71 /* Motorola MC68HC08 microcontroller */ ++#define EM_68HC05 72 /* Motorola MC68HC05 microcontroller */ ++#define EM_SVX 73 /* Silicon Graphics SVx */ ++#define EM_ST19 74 /* STMicroelectronics ST19 8 bit mc */ ++#define EM_VAX 75 /* Digital VAX */ ++#define EM_CRIS 76 /* Axis Communications 32-bit embedded processor */ ++#define EM_JAVELIN 77 /* Infineon Technologies 32-bit embedded processor */ ++#define EM_FIREPATH 78 /* Element 14 64-bit DSP Processor */ ++#define EM_ZSP 79 /* LSI Logic 16-bit DSP Processor */ ++#define EM_MMIX 80 /* Donald Knuth's educational 64-bit processor */ ++#define EM_HUANY 81 /* Harvard University machine-independent object files */ ++#define EM_PRISM 82 /* SiTera Prism */ ++#define EM_AVR 83 /* Atmel AVR 8-bit microcontroller */ ++#define EM_FR30 84 /* Fujitsu FR30 */ ++#define EM_D10V 85 /* Mitsubishi D10V */ ++#define EM_D30V 86 /* Mitsubishi D30V */ ++#define EM_V850 87 /* NEC v850 */ ++#define EM_M32R 88 /* Mitsubishi M32R */ ++#define EM_MN10300 89 /* Matsushita MN10300 */ ++#define EM_MN10200 90 /* Matsushita MN10200 */ ++#define EM_PJ 91 /* picoJava */ ++#define EM_OPENRISC 92 /* OpenRISC 32-bit embedded processor */ ++#define EM_ARC_A5 93 /* ARC Cores Tangent-A5 */ ++#define EM_XTENSA 94 /* Tensilica Xtensa Architecture */ ++#define EM_TILEPRO 188 /* Tilera TILEPro */ ++#define EM_TILEGX 191 /* Tilera TILE-Gx */ ++#define EM_NUM 192 ++ ++/* If it is necessary to assign new unofficial EM_* values, please ++ pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the ++ chances of collision with official or non-GNU unofficial values. */ ++ ++#define EM_ALPHA 0x9026 ++ ++/* Legal values for e_version (version). */ ++ ++#define EV_NONE 0 /* Invalid ELF version */ ++#define EV_CURRENT 1 /* Current version */ ++#define EV_NUM 2 ++ ++/* Section header. */ ++ ++typedef struct ++{ ++ Elf32_Word sh_name; /* Section name (string tbl index) */ ++ Elf32_Word sh_type; /* Section type */ ++ Elf32_Word sh_flags; /* Section flags */ ++ Elf32_Addr sh_addr; /* Section virtual addr at execution */ ++ Elf32_Off sh_offset; /* Section file offset */ ++ Elf32_Word sh_size; /* Section size in bytes */ ++ Elf32_Word sh_link; /* Link to another section */ ++ Elf32_Word sh_info; /* Additional section information */ ++ Elf32_Word sh_addralign; /* Section alignment */ ++ Elf32_Word sh_entsize; /* Entry size if section holds table */ ++} Elf32_Shdr; ++ ++typedef struct ++{ ++ Elf64_Word sh_name; /* Section name (string tbl index) */ ++ Elf64_Word sh_type; /* Section type */ ++ Elf64_Xword sh_flags; /* Section flags */ ++ Elf64_Addr sh_addr; /* Section virtual addr at execution */ ++ Elf64_Off sh_offset; /* Section file offset */ ++ Elf64_Xword sh_size; /* Section size in bytes */ ++ Elf64_Word sh_link; /* Link to another section */ ++ Elf64_Word sh_info; /* Additional section information */ ++ Elf64_Xword sh_addralign; /* Section alignment */ ++ Elf64_Xword sh_entsize; /* Entry size if section holds table */ ++} Elf64_Shdr; ++ ++/* Special section indices. */ ++ ++#define SHN_UNDEF 0 /* Undefined section */ ++#define SHN_LORESERVE 0xff00 /* Start of reserved indices */ ++#define SHN_LOPROC 0xff00 /* Start of processor-specific */ ++#define SHN_BEFORE 0xff00 /* Order section before all others ++ (Solaris). */ ++#define SHN_AFTER 0xff01 /* Order section after all others ++ (Solaris). */ ++#define SHN_HIPROC 0xff1f /* End of processor-specific */ ++#define SHN_LOOS 0xff20 /* Start of OS-specific */ ++#define SHN_HIOS 0xff3f /* End of OS-specific */ ++#define SHN_ABS 0xfff1 /* Associated symbol is absolute */ ++#define SHN_COMMON 0xfff2 /* Associated symbol is common */ ++#define SHN_XINDEX 0xffff /* Index is in extra table. */ ++#define SHN_HIRESERVE 0xffff /* End of reserved indices */ ++ ++/* Legal values for sh_type (section type). */ ++ ++#define SHT_NULL 0 /* Section header table entry unused */ ++#define SHT_PROGBITS 1 /* Program data */ ++#define SHT_SYMTAB 2 /* Symbol table */ ++#define SHT_STRTAB 3 /* String table */ ++#define SHT_RELA 4 /* Relocation entries with addends */ ++#define SHT_HASH 5 /* Symbol hash table */ ++#define SHT_DYNAMIC 6 /* Dynamic linking information */ ++#define SHT_NOTE 7 /* Notes */ ++#define SHT_NOBITS 8 /* Program space with no data (bss) */ ++#define SHT_REL 9 /* Relocation entries, no addends */ ++#define SHT_SHLIB 10 /* Reserved */ ++#define SHT_DYNSYM 11 /* Dynamic linker symbol table */ ++#define SHT_INIT_ARRAY 14 /* Array of constructors */ ++#define SHT_FINI_ARRAY 15 /* Array of destructors */ ++#define SHT_PREINIT_ARRAY 16 /* Array of pre-constructors */ ++#define SHT_GROUP 17 /* Section group */ ++#define SHT_SYMTAB_SHNDX 18 /* Extended section indeces */ ++#define SHT_NUM 19 /* Number of defined types. */ ++#define SHT_LOOS 0x60000000 /* Start OS-specific. */ ++#define SHT_GNU_ATTRIBUTES 0x6ffffff5 /* Object attributes. */ ++#define SHT_GNU_HASH 0x6ffffff6 /* GNU-style hash table. */ ++#define SHT_GNU_LIBLIST 0x6ffffff7 /* Prelink library list */ ++#define SHT_CHECKSUM 0x6ffffff8 /* Checksum for DSO content. */ ++#define SHT_LOSUNW 0x6ffffffa /* Sun-specific low bound. */ ++#define SHT_SUNW_move 0x6ffffffa ++#define SHT_SUNW_COMDAT 0x6ffffffb ++#define SHT_SUNW_syminfo 0x6ffffffc ++#define SHT_GNU_verdef 0x6ffffffd /* Version definition section. */ ++#define SHT_GNU_verneed 0x6ffffffe /* Version needs section. */ ++#define SHT_GNU_versym 0x6fffffff /* Version symbol table. */ ++#define SHT_HISUNW 0x6fffffff /* Sun-specific high bound. */ ++#define SHT_HIOS 0x6fffffff /* End OS-specific type */ ++#define SHT_LOPROC 0x70000000 /* Start of processor-specific */ ++#define SHT_HIPROC 0x7fffffff /* End of processor-specific */ ++#define SHT_LOUSER 0x80000000 /* Start of application-specific */ ++#define SHT_HIUSER 0x8fffffff /* End of application-specific */ ++ ++/* Legal values for sh_flags (section flags). */ ++ ++#define SHF_WRITE (1 << 0) /* Writable */ ++#define SHF_ALLOC (1 << 1) /* Occupies memory during execution */ ++#define SHF_EXECINSTR (1 << 2) /* Executable */ ++#define SHF_MERGE (1 << 4) /* Might be merged */ ++#define SHF_STRINGS (1 << 5) /* Contains nul-terminated strings */ ++#define SHF_INFO_LINK (1 << 6) /* `sh_info' contains SHT index */ ++#define SHF_LINK_ORDER (1 << 7) /* Preserve order after combining */ ++#define SHF_OS_NONCONFORMING (1 << 8) /* Non-standard OS specific handling ++ required */ ++#define SHF_GROUP (1 << 9) /* Section is member of a group. */ ++#define SHF_TLS (1 << 10) /* Section hold thread-local data. */ ++#define SHF_MASKOS 0x0ff00000 /* OS-specific. */ ++#define SHF_MASKPROC 0xf0000000 /* Processor-specific */ ++#define SHF_ORDERED (1 << 30) /* Special ordering requirement ++ (Solaris). */ ++#define SHF_EXCLUDE (1 << 31) /* Section is excluded unless ++ referenced or allocated (Solaris).*/ ++ ++/* Section group handling. */ ++#define GRP_COMDAT 0x1 /* Mark group as COMDAT. */ ++ ++/* Symbol table entry. */ ++ ++typedef struct ++{ ++ Elf32_Word st_name; /* Symbol name (string tbl index) */ ++ Elf32_Addr st_value; /* Symbol value */ ++ Elf32_Word st_size; /* Symbol size */ ++ unsigned char st_info; /* Symbol type and binding */ ++ unsigned char st_other; /* Symbol visibility */ ++ Elf32_Section st_shndx; /* Section index */ ++} Elf32_Sym; ++ ++typedef struct ++{ ++ Elf64_Word st_name; /* Symbol name (string tbl index) */ ++ unsigned char st_info; /* Symbol type and binding */ ++ unsigned char st_other; /* Symbol visibility */ ++ Elf64_Section st_shndx; /* Section index */ ++ Elf64_Addr st_value; /* Symbol value */ ++ Elf64_Xword st_size; /* Symbol size */ ++} Elf64_Sym; ++ ++/* The syminfo section if available contains additional information about ++ every dynamic symbol. */ ++ ++typedef struct ++{ ++ Elf32_Half si_boundto; /* Direct bindings, symbol bound to */ ++ Elf32_Half si_flags; /* Per symbol flags */ ++} Elf32_Syminfo; ++ ++typedef struct ++{ ++ Elf64_Half si_boundto; /* Direct bindings, symbol bound to */ ++ Elf64_Half si_flags; /* Per symbol flags */ ++} Elf64_Syminfo; ++ ++/* Possible values for si_boundto. */ ++#define SYMINFO_BT_SELF 0xffff /* Symbol bound to self */ ++#define SYMINFO_BT_PARENT 0xfffe /* Symbol bound to parent */ ++#define SYMINFO_BT_LOWRESERVE 0xff00 /* Beginning of reserved entries */ ++ ++/* Possible bitmasks for si_flags. */ ++#define SYMINFO_FLG_DIRECT 0x0001 /* Direct bound symbol */ ++#define SYMINFO_FLG_PASSTHRU 0x0002 /* Pass-thru symbol for translator */ ++#define SYMINFO_FLG_COPY 0x0004 /* Symbol is a copy-reloc */ ++#define SYMINFO_FLG_LAZYLOAD 0x0008 /* Symbol bound to object to be lazy ++ loaded */ ++/* Syminfo version values. */ ++#define SYMINFO_NONE 0 ++#define SYMINFO_CURRENT 1 ++#define SYMINFO_NUM 2 ++ ++ ++/* How to extract and insert information held in the st_info field. */ ++ ++#define ELF32_ST_BIND(val) (((unsigned char) (val)) >> 4) ++#define ELF32_ST_TYPE(val) ((val) & 0xf) ++#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) ++ ++/* Both Elf32_Sym and Elf64_Sym use the same one-byte st_info field. */ ++#define ELF64_ST_BIND(val) ELF32_ST_BIND (val) ++#define ELF64_ST_TYPE(val) ELF32_ST_TYPE (val) ++#define ELF64_ST_INFO(bind, type) ELF32_ST_INFO ((bind), (type)) ++ ++/* Legal values for ST_BIND subfield of st_info (symbol binding). */ ++ ++#define STB_LOCAL 0 /* Local symbol */ ++#define STB_GLOBAL 1 /* Global symbol */ ++#define STB_WEAK 2 /* Weak symbol */ ++#define STB_NUM 3 /* Number of defined types. */ ++#define STB_LOOS 10 /* Start of OS-specific */ ++#define STB_GNU_UNIQUE 10 /* Unique symbol. */ ++#define STB_HIOS 12 /* End of OS-specific */ ++#define STB_LOPROC 13 /* Start of processor-specific */ ++#define STB_HIPROC 15 /* End of processor-specific */ ++ ++/* Legal values for ST_TYPE subfield of st_info (symbol type). */ ++ ++#define STT_NOTYPE 0 /* Symbol type is unspecified */ ++#define STT_OBJECT 1 /* Symbol is a data object */ ++#define STT_FUNC 2 /* Symbol is a code object */ ++#define STT_SECTION 3 /* Symbol associated with a section */ ++#define STT_FILE 4 /* Symbol's name is file name */ ++#define STT_COMMON 5 /* Symbol is a common data object */ ++#define STT_TLS 6 /* Symbol is thread-local data object*/ ++#define STT_NUM 7 /* Number of defined types. */ ++#define STT_LOOS 10 /* Start of OS-specific */ ++#define STT_GNU_IFUNC 10 /* Symbol is indirect code object */ ++#define STT_HIOS 12 /* End of OS-specific */ ++#define STT_LOPROC 13 /* Start of processor-specific */ ++#define STT_HIPROC 15 /* End of processor-specific */ ++ ++ ++/* Symbol table indices are found in the hash buckets and chain table ++ of a symbol hash table section. This special index value indicates ++ the end of a chain, meaning no further symbols are found in that bucket. */ ++ ++#define STN_UNDEF 0 /* End of a chain. */ ++ ++ ++/* How to extract and insert information held in the st_other field. */ ++ ++#define ELF32_ST_VISIBILITY(o) ((o) & 0x03) ++ ++/* For ELF64 the definitions are the same. */ ++#define ELF64_ST_VISIBILITY(o) ELF32_ST_VISIBILITY (o) ++ ++/* Symbol visibility specification encoded in the st_other field. */ ++#define STV_DEFAULT 0 /* Default symbol visibility rules */ ++#define STV_INTERNAL 1 /* Processor specific hidden class */ ++#define STV_HIDDEN 2 /* Sym unavailable in other modules */ ++#define STV_PROTECTED 3 /* Not preemptible, not exported */ ++ ++ ++/* Relocation table entry without addend (in section of type SHT_REL). */ ++ ++typedef struct ++{ ++ Elf32_Addr r_offset; /* Address */ ++ Elf32_Word r_info; /* Relocation type and symbol index */ ++} Elf32_Rel; ++ ++/* I have seen two different definitions of the Elf64_Rel and ++ Elf64_Rela structures, so we'll leave them out until Novell (or ++ whoever) gets their act together. */ ++/* The following, at least, is used on Sparc v9, MIPS, and Alpha. */ ++ ++typedef struct ++{ ++ Elf64_Addr r_offset; /* Address */ ++ Elf64_Xword r_info; /* Relocation type and symbol index */ ++} Elf64_Rel; ++ ++/* Relocation table entry with addend (in section of type SHT_RELA). */ ++ ++typedef struct ++{ ++ Elf32_Addr r_offset; /* Address */ ++ Elf32_Word r_info; /* Relocation type and symbol index */ ++ Elf32_Sword r_addend; /* Addend */ ++} Elf32_Rela; ++ ++typedef struct ++{ ++ Elf64_Addr r_offset; /* Address */ ++ Elf64_Xword r_info; /* Relocation type and symbol index */ ++ Elf64_Sxword r_addend; /* Addend */ ++} Elf64_Rela; ++ ++/* How to extract and insert information held in the r_info field. */ ++ ++#define ELF32_R_SYM(val) ((val) >> 8) ++#define ELF32_R_TYPE(val) ((val) & 0xff) ++#define ELF32_R_INFO(sym, type) (((sym) << 8) + ((type) & 0xff)) ++ ++#define ELF64_R_SYM(i) ((i) >> 32) ++#define ELF64_R_TYPE(i) ((i) & 0xffffffff) ++#define ELF64_R_INFO(sym,type) ((((Elf64_Xword) (sym)) << 32) + (type)) ++ ++/* Program segment header. */ ++ ++typedef struct ++{ ++ Elf32_Word p_type; /* Segment type */ ++ Elf32_Off p_offset; /* Segment file offset */ ++ Elf32_Addr p_vaddr; /* Segment virtual address */ ++ Elf32_Addr p_paddr; /* Segment physical address */ ++ Elf32_Word p_filesz; /* Segment size in file */ ++ Elf32_Word p_memsz; /* Segment size in memory */ ++ Elf32_Word p_flags; /* Segment flags */ ++ Elf32_Word p_align; /* Segment alignment */ ++} Elf32_Phdr; ++ ++typedef struct ++{ ++ Elf64_Word p_type; /* Segment type */ ++ Elf64_Word p_flags; /* Segment flags */ ++ Elf64_Off p_offset; /* Segment file offset */ ++ Elf64_Addr p_vaddr; /* Segment virtual address */ ++ Elf64_Addr p_paddr; /* Segment physical address */ ++ Elf64_Xword p_filesz; /* Segment size in file */ ++ Elf64_Xword p_memsz; /* Segment size in memory */ ++ Elf64_Xword p_align; /* Segment alignment */ ++} Elf64_Phdr; ++ ++/* Special value for e_phnum. This indicates that the real number of ++ program headers is too large to fit into e_phnum. Instead the real ++ value is in the field sh_info of section 0. */ ++ ++#define PN_XNUM 0xffff ++ ++/* Legal values for p_type (segment type). */ ++ ++#define PT_NULL 0 /* Program header table entry unused */ ++#define PT_LOAD 1 /* Loadable program segment */ ++#define PT_DYNAMIC 2 /* Dynamic linking information */ ++#define PT_INTERP 3 /* Program interpreter */ ++#define PT_NOTE 4 /* Auxiliary information */ ++#define PT_SHLIB 5 /* Reserved */ ++#define PT_PHDR 6 /* Entry for header table itself */ ++#define PT_TLS 7 /* Thread-local storage segment */ ++#define PT_NUM 8 /* Number of defined types */ ++#define PT_LOOS 0x60000000 /* Start of OS-specific */ ++#define PT_GNU_EH_FRAME 0x6474e550 /* GCC .eh_frame_hdr segment */ ++#define PT_GNU_STACK 0x6474e551 /* Indicates stack executability */ ++#define PT_GNU_RELRO 0x6474e552 /* Read-only after relocation */ ++#define PT_LOSUNW 0x6ffffffa ++#define PT_SUNWBSS 0x6ffffffa /* Sun Specific segment */ ++#define PT_SUNWSTACK 0x6ffffffb /* Stack segment */ ++#define PT_HISUNW 0x6fffffff ++#define PT_HIOS 0x6fffffff /* End of OS-specific */ ++#define PT_LOPROC 0x70000000 /* Start of processor-specific */ ++#define PT_HIPROC 0x7fffffff /* End of processor-specific */ ++ ++/* Legal values for p_flags (segment flags). */ ++ ++#define PF_X (1 << 0) /* Segment is executable */ ++#define PF_W (1 << 1) /* Segment is writable */ ++#define PF_R (1 << 2) /* Segment is readable */ ++#define PF_MASKOS 0x0ff00000 /* OS-specific */ ++#define PF_MASKPROC 0xf0000000 /* Processor-specific */ ++ ++/* Legal values for note segment descriptor types for core files. */ ++ ++#define NT_PRSTATUS 1 /* Contains copy of prstatus struct */ ++#define NT_FPREGSET 2 /* Contains copy of fpregset struct */ ++#define NT_PRPSINFO 3 /* Contains copy of prpsinfo struct */ ++#define NT_PRXREG 4 /* Contains copy of prxregset struct */ ++#define NT_TASKSTRUCT 4 /* Contains copy of task structure */ ++#define NT_PLATFORM 5 /* String from sysinfo(SI_PLATFORM) */ ++#define NT_AUXV 6 /* Contains copy of auxv array */ ++#define NT_GWINDOWS 7 /* Contains copy of gwindows struct */ ++#define NT_ASRS 8 /* Contains copy of asrset struct */ ++#define NT_PSTATUS 10 /* Contains copy of pstatus struct */ ++#define NT_PSINFO 13 /* Contains copy of psinfo struct */ ++#define NT_PRCRED 14 /* Contains copy of prcred struct */ ++#define NT_UTSNAME 15 /* Contains copy of utsname struct */ ++#define NT_LWPSTATUS 16 /* Contains copy of lwpstatus struct */ ++#define NT_LWPSINFO 17 /* Contains copy of lwpinfo struct */ ++#define NT_PRFPXREG 20 /* Contains copy of fprxregset struct */ ++#define NT_PRXFPREG 0x46e62b7f /* Contains copy of user_fxsr_struct */ ++#define NT_PPC_VMX 0x100 /* PowerPC Altivec/VMX registers */ ++#define NT_PPC_SPE 0x101 /* PowerPC SPE/EVR registers */ ++#define NT_PPC_VSX 0x102 /* PowerPC VSX registers */ ++#define NT_386_TLS 0x200 /* i386 TLS slots (struct user_desc) */ ++#define NT_386_IOPERM 0x201 /* x86 io permission bitmap (1=deny) */ ++#define NT_X86_XSTATE 0x202 /* x86 extended state using xsave */ ++ ++/* Legal values for the note segment descriptor types for object files. */ ++ ++#define NT_VERSION 1 /* Contains a version string. */ ++ ++ ++/* Dynamic section entry. */ ++ ++typedef struct ++{ ++ Elf32_Sword d_tag; /* Dynamic entry type */ ++ union ++ { ++ Elf32_Word d_val; /* Integer value */ ++ Elf32_Addr d_ptr; /* Address value */ ++ } d_un; ++} Elf32_Dyn; ++ ++typedef struct ++{ ++ Elf64_Sxword d_tag; /* Dynamic entry type */ ++ union ++ { ++ Elf64_Xword d_val; /* Integer value */ ++ Elf64_Addr d_ptr; /* Address value */ ++ } d_un; ++} Elf64_Dyn; ++ ++/* Legal values for d_tag (dynamic entry type). */ ++ ++#define DT_NULL 0 /* Marks end of dynamic section */ ++#define DT_NEEDED 1 /* Name of needed library */ ++#define DT_PLTRELSZ 2 /* Size in bytes of PLT relocs */ ++#define DT_PLTGOT 3 /* Processor defined value */ ++#define DT_HASH 4 /* Address of symbol hash table */ ++#define DT_STRTAB 5 /* Address of string table */ ++#define DT_SYMTAB 6 /* Address of symbol table */ ++#define DT_RELA 7 /* Address of Rela relocs */ ++#define DT_RELASZ 8 /* Total size of Rela relocs */ ++#define DT_RELAENT 9 /* Size of one Rela reloc */ ++#define DT_STRSZ 10 /* Size of string table */ ++#define DT_SYMENT 11 /* Size of one symbol table entry */ ++#define DT_INIT 12 /* Address of init function */ ++#define DT_FINI 13 /* Address of termination function */ ++#define DT_SONAME 14 /* Name of shared object */ ++#define DT_RPATH 15 /* Library search path (deprecated) */ ++#define DT_SYMBOLIC 16 /* Start symbol search here */ ++#define DT_REL 17 /* Address of Rel relocs */ ++#define DT_RELSZ 18 /* Total size of Rel relocs */ ++#define DT_RELENT 19 /* Size of one Rel reloc */ ++#define DT_PLTREL 20 /* Type of reloc in PLT */ ++#define DT_DEBUG 21 /* For debugging; unspecified */ ++#define DT_TEXTREL 22 /* Reloc might modify .text */ ++#define DT_JMPREL 23 /* Address of PLT relocs */ ++#define DT_BIND_NOW 24 /* Process relocations of object */ ++#define DT_INIT_ARRAY 25 /* Array with addresses of init fct */ ++#define DT_FINI_ARRAY 26 /* Array with addresses of fini fct */ ++#define DT_INIT_ARRAYSZ 27 /* Size in bytes of DT_INIT_ARRAY */ ++#define DT_FINI_ARRAYSZ 28 /* Size in bytes of DT_FINI_ARRAY */ ++#define DT_RUNPATH 29 /* Library search path */ ++#define DT_FLAGS 30 /* Flags for the object being loaded */ ++#define DT_ENCODING 32 /* Start of encoded range */ ++#define DT_PREINIT_ARRAY 32 /* Array with addresses of preinit fct*/ ++#define DT_PREINIT_ARRAYSZ 33 /* size in bytes of DT_PREINIT_ARRAY */ ++#define DT_NUM 34 /* Number used */ ++#define DT_LOOS 0x6000000d /* Start of OS-specific */ ++#define DT_HIOS 0x6ffff000 /* End of OS-specific */ ++#define DT_LOPROC 0x70000000 /* Start of processor-specific */ ++#define DT_HIPROC 0x7fffffff /* End of processor-specific */ ++#define DT_PROCNUM DT_MIPS_NUM /* Most used by any processor */ ++ ++/* DT_* entries which fall between DT_VALRNGHI & DT_VALRNGLO use the ++ Dyn.d_un.d_val field of the Elf*_Dyn structure. This follows Sun's ++ approach. */ ++#define DT_VALRNGLO 0x6ffffd00 ++#define DT_GNU_PRELINKED 0x6ffffdf5 /* Prelinking timestamp */ ++#define DT_GNU_CONFLICTSZ 0x6ffffdf6 /* Size of conflict section */ ++#define DT_GNU_LIBLISTSZ 0x6ffffdf7 /* Size of library list */ ++#define DT_CHECKSUM 0x6ffffdf8 ++#define DT_PLTPADSZ 0x6ffffdf9 ++#define DT_MOVEENT 0x6ffffdfa ++#define DT_MOVESZ 0x6ffffdfb ++#define DT_FEATURE_1 0x6ffffdfc /* Feature selection (DTF_*). */ ++#define DT_POSFLAG_1 0x6ffffdfd /* Flags for DT_* entries, effecting ++ the following DT_* entry. */ ++#define DT_SYMINSZ 0x6ffffdfe /* Size of syminfo table (in bytes) */ ++#define DT_SYMINENT 0x6ffffdff /* Entry size of syminfo */ ++#define DT_VALRNGHI 0x6ffffdff ++#define DT_VALTAGIDX(tag) (DT_VALRNGHI - (tag)) /* Reverse order! */ ++#define DT_VALNUM 12 ++ ++/* DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the ++ Dyn.d_un.d_ptr field of the Elf*_Dyn structure. ++ ++ If any adjustment is made to the ELF object after it has been ++ built these entries will need to be adjusted. */ ++#define DT_ADDRRNGLO 0x6ffffe00 ++#define DT_GNU_HASH 0x6ffffef5 /* GNU-style hash table. */ ++#define DT_TLSDESC_PLT 0x6ffffef6 ++#define DT_TLSDESC_GOT 0x6ffffef7 ++#define DT_GNU_CONFLICT 0x6ffffef8 /* Start of conflict section */ ++#define DT_GNU_LIBLIST 0x6ffffef9 /* Library list */ ++#define DT_CONFIG 0x6ffffefa /* Configuration information. */ ++#define DT_DEPAUDIT 0x6ffffefb /* Dependency auditing. */ ++#define DT_AUDIT 0x6ffffefc /* Object auditing. */ ++#define DT_PLTPAD 0x6ffffefd /* PLT padding. */ ++#define DT_MOVETAB 0x6ffffefe /* Move table. */ ++#define DT_SYMINFO 0x6ffffeff /* Syminfo table. */ ++#define DT_ADDRRNGHI 0x6ffffeff ++#define DT_ADDRTAGIDX(tag) (DT_ADDRRNGHI - (tag)) /* Reverse order! */ ++#define DT_ADDRNUM 11 ++ ++/* The versioning entry types. The next are defined as part of the ++ GNU extension. */ ++#define DT_VERSYM 0x6ffffff0 ++ ++#define DT_RELACOUNT 0x6ffffff9 ++#define DT_RELCOUNT 0x6ffffffa ++ ++/* These were chosen by Sun. */ ++#define DT_FLAGS_1 0x6ffffffb /* State flags, see DF_1_* below. */ ++#define DT_VERDEF 0x6ffffffc /* Address of version definition ++ table */ ++#define DT_VERDEFNUM 0x6ffffffd /* Number of version definitions */ ++#define DT_VERNEED 0x6ffffffe /* Address of table with needed ++ versions */ ++#define DT_VERNEEDNUM 0x6fffffff /* Number of needed versions */ ++#define DT_VERSIONTAGIDX(tag) (DT_VERNEEDNUM - (tag)) /* Reverse order! */ ++#define DT_VERSIONTAGNUM 16 ++ ++/* Sun added these machine-independent extensions in the "processor-specific" ++ range. Be compatible. */ ++#define DT_AUXILIARY 0x7ffffffd /* Shared object to load before self */ ++#define DT_FILTER 0x7fffffff /* Shared object to get values from */ ++#define DT_EXTRATAGIDX(tag) ((Elf32_Word)-((Elf32_Sword) (tag) <<1>>1)-1) ++#define DT_EXTRANUM 3 ++ ++/* Values of `d_un.d_val' in the DT_FLAGS entry. */ ++#define DF_ORIGIN 0x00000001 /* Object may use DF_ORIGIN */ ++#define DF_SYMBOLIC 0x00000002 /* Symbol resolutions starts here */ ++#define DF_TEXTREL 0x00000004 /* Object contains text relocations */ ++#define DF_BIND_NOW 0x00000008 /* No lazy binding for this object */ ++#define DF_STATIC_TLS 0x00000010 /* Module uses the static TLS model */ ++ ++/* State flags selectable in the `d_un.d_val' element of the DT_FLAGS_1 ++ entry in the dynamic section. */ ++#define DF_1_NOW 0x00000001 /* Set RTLD_NOW for this object. */ ++#define DF_1_GLOBAL 0x00000002 /* Set RTLD_GLOBAL for this object. */ ++#define DF_1_GROUP 0x00000004 /* Set RTLD_GROUP for this object. */ ++#define DF_1_NODELETE 0x00000008 /* Set RTLD_NODELETE for this object.*/ ++#define DF_1_LOADFLTR 0x00000010 /* Trigger filtee loading at runtime.*/ ++#define DF_1_INITFIRST 0x00000020 /* Set RTLD_INITFIRST for this object*/ ++#define DF_1_NOOPEN 0x00000040 /* Set RTLD_NOOPEN for this object. */ ++#define DF_1_ORIGIN 0x00000080 /* $ORIGIN must be handled. */ ++#define DF_1_DIRECT 0x00000100 /* Direct binding enabled. */ ++#define DF_1_TRANS 0x00000200 ++#define DF_1_INTERPOSE 0x00000400 /* Object is used to interpose. */ ++#define DF_1_NODEFLIB 0x00000800 /* Ignore default lib search path. */ ++#define DF_1_NODUMP 0x00001000 /* Object can't be dldump'ed. */ ++#define DF_1_CONFALT 0x00002000 /* Configuration alternative created.*/ ++#define DF_1_ENDFILTEE 0x00004000 /* Filtee terminates filters search. */ ++#define DF_1_DISPRELDNE 0x00008000 /* Disp reloc applied at build time. */ ++#define DF_1_DISPRELPND 0x00010000 /* Disp reloc applied at run-time. */ ++ ++/* Flags for the feature selection in DT_FEATURE_1. */ ++#define DTF_1_PARINIT 0x00000001 ++#define DTF_1_CONFEXP 0x00000002 ++ ++/* Flags in the DT_POSFLAG_1 entry effecting only the next DT_* entry. */ ++#define DF_P1_LAZYLOAD 0x00000001 /* Lazyload following object. */ ++#define DF_P1_GROUPPERM 0x00000002 /* Symbols from next object are not ++ generally available. */ ++ ++/* Version definition sections. */ ++ ++typedef struct ++{ ++ Elf32_Half vd_version; /* Version revision */ ++ Elf32_Half vd_flags; /* Version information */ ++ Elf32_Half vd_ndx; /* Version Index */ ++ Elf32_Half vd_cnt; /* Number of associated aux entries */ ++ Elf32_Word vd_hash; /* Version name hash value */ ++ Elf32_Word vd_aux; /* Offset in bytes to verdaux array */ ++ Elf32_Word vd_next; /* Offset in bytes to next verdef ++ entry */ ++} Elf32_Verdef; ++ ++typedef struct ++{ ++ Elf64_Half vd_version; /* Version revision */ ++ Elf64_Half vd_flags; /* Version information */ ++ Elf64_Half vd_ndx; /* Version Index */ ++ Elf64_Half vd_cnt; /* Number of associated aux entries */ ++ Elf64_Word vd_hash; /* Version name hash value */ ++ Elf64_Word vd_aux; /* Offset in bytes to verdaux array */ ++ Elf64_Word vd_next; /* Offset in bytes to next verdef ++ entry */ ++} Elf64_Verdef; ++ ++ ++/* Legal values for vd_version (version revision). */ ++#define VER_DEF_NONE 0 /* No version */ ++#define VER_DEF_CURRENT 1 /* Current version */ ++#define VER_DEF_NUM 2 /* Given version number */ ++ ++/* Legal values for vd_flags (version information flags). */ ++#define VER_FLG_BASE 0x1 /* Version definition of file itself */ ++#define VER_FLG_WEAK 0x2 /* Weak version identifier */ ++ ++/* Versym symbol index values. */ ++#define VER_NDX_LOCAL 0 /* Symbol is local. */ ++#define VER_NDX_GLOBAL 1 /* Symbol is global. */ ++#define VER_NDX_LORESERVE 0xff00 /* Beginning of reserved entries. */ ++#define VER_NDX_ELIMINATE 0xff01 /* Symbol is to be eliminated. */ ++ ++/* Auxialiary version information. */ ++ ++typedef struct ++{ ++ Elf32_Word vda_name; /* Version or dependency names */ ++ Elf32_Word vda_next; /* Offset in bytes to next verdaux ++ entry */ ++} Elf32_Verdaux; ++ ++typedef struct ++{ ++ Elf64_Word vda_name; /* Version or dependency names */ ++ Elf64_Word vda_next; /* Offset in bytes to next verdaux ++ entry */ ++} Elf64_Verdaux; ++ ++ ++/* Version dependency section. */ ++ ++typedef struct ++{ ++ Elf32_Half vn_version; /* Version of structure */ ++ Elf32_Half vn_cnt; /* Number of associated aux entries */ ++ Elf32_Word vn_file; /* Offset of filename for this ++ dependency */ ++ Elf32_Word vn_aux; /* Offset in bytes to vernaux array */ ++ Elf32_Word vn_next; /* Offset in bytes to next verneed ++ entry */ ++} Elf32_Verneed; ++ ++typedef struct ++{ ++ Elf64_Half vn_version; /* Version of structure */ ++ Elf64_Half vn_cnt; /* Number of associated aux entries */ ++ Elf64_Word vn_file; /* Offset of filename for this ++ dependency */ ++ Elf64_Word vn_aux; /* Offset in bytes to vernaux array */ ++ Elf64_Word vn_next; /* Offset in bytes to next verneed ++ entry */ ++} Elf64_Verneed; ++ ++ ++/* Legal values for vn_version (version revision). */ ++#define VER_NEED_NONE 0 /* No version */ ++#define VER_NEED_CURRENT 1 /* Current version */ ++#define VER_NEED_NUM 2 /* Given version number */ ++ ++/* Auxiliary needed version information. */ ++ ++typedef struct ++{ ++ Elf32_Word vna_hash; /* Hash value of dependency name */ ++ Elf32_Half vna_flags; /* Dependency specific information */ ++ Elf32_Half vna_other; /* Unused */ ++ Elf32_Word vna_name; /* Dependency name string offset */ ++ Elf32_Word vna_next; /* Offset in bytes to next vernaux ++ entry */ ++} Elf32_Vernaux; ++ ++typedef struct ++{ ++ Elf64_Word vna_hash; /* Hash value of dependency name */ ++ Elf64_Half vna_flags; /* Dependency specific information */ ++ Elf64_Half vna_other; /* Unused */ ++ Elf64_Word vna_name; /* Dependency name string offset */ ++ Elf64_Word vna_next; /* Offset in bytes to next vernaux ++ entry */ ++} Elf64_Vernaux; ++ ++ ++/* Legal values for vna_flags. */ ++#define VER_FLG_WEAK 0x2 /* Weak version identifier */ ++ ++ ++/* Auxiliary vector. */ ++ ++/* This vector is normally only used by the program interpreter. The ++ usual definition in an ABI supplement uses the name auxv_t. The ++ vector is not usually defined in a standard file, but it ++ can't hurt. We rename it to avoid conflicts. The sizes of these ++ types are an arrangement between the exec server and the program ++ interpreter, so we don't fully specify them here. */ ++ ++typedef struct ++{ ++ uint32_t a_type; /* Entry type */ ++ union ++ { ++ uint32_t a_val; /* Integer value */ ++ /* We use to have pointer elements added here. We cannot do that, ++ though, since it does not work when using 32-bit definitions ++ on 64-bit platforms and vice versa. */ ++ } a_un; ++} Elf32_auxv_t; ++ ++typedef struct ++{ ++ uint64_t a_type; /* Entry type */ ++ union ++ { ++ uint64_t a_val; /* Integer value */ ++ /* We use to have pointer elements added here. We cannot do that, ++ though, since it does not work when using 32-bit definitions ++ on 64-bit platforms and vice versa. */ ++ } a_un; ++} Elf64_auxv_t; ++ ++/* Legal values for a_type (entry type). */ ++ ++#define AT_NULL 0 /* End of vector */ ++#define AT_IGNORE 1 /* Entry should be ignored */ ++#define AT_EXECFD 2 /* File descriptor of program */ ++#define AT_PHDR 3 /* Program headers for program */ ++#define AT_PHENT 4 /* Size of program header entry */ ++#define AT_PHNUM 5 /* Number of program headers */ ++#define AT_PAGESZ 6 /* System page size */ ++#define AT_BASE 7 /* Base address of interpreter */ ++#define AT_FLAGS 8 /* Flags */ ++#define AT_ENTRY 9 /* Entry point of program */ ++#define AT_NOTELF 10 /* Program is not ELF */ ++#define AT_UID 11 /* Real uid */ ++#define AT_EUID 12 /* Effective uid */ ++#define AT_GID 13 /* Real gid */ ++#define AT_EGID 14 /* Effective gid */ ++#define AT_CLKTCK 17 /* Frequency of times() */ ++ ++/* Some more special a_type values describing the hardware. */ ++#define AT_PLATFORM 15 /* String identifying platform. */ ++#define AT_HWCAP 16 /* Machine dependent hints about ++ processor capabilities. */ ++ ++/* This entry gives some information about the FPU initialization ++ performed by the kernel. */ ++#define AT_FPUCW 18 /* Used FPU control word. */ ++ ++/* Cache block sizes. */ ++#define AT_DCACHEBSIZE 19 /* Data cache block size. */ ++#define AT_ICACHEBSIZE 20 /* Instruction cache block size. */ ++#define AT_UCACHEBSIZE 21 /* Unified cache block size. */ ++ ++/* A special ignored value for PPC, used by the kernel to control the ++ interpretation of the AUXV. Must be > 16. */ ++#define AT_IGNOREPPC 22 /* Entry should be ignored. */ ++ ++#define AT_SECURE 23 /* Boolean, was exec setuid-like? */ ++ ++#define AT_BASE_PLATFORM 24 /* String identifying real platforms.*/ ++ ++#define AT_RANDOM 25 /* Address of 16 random bytes. */ ++ ++#define AT_EXECFN 31 /* Filename of executable. */ ++ ++/* Pointer to the global system page used for system calls and other ++ nice things. */ ++#define AT_SYSINFO 32 ++#define AT_SYSINFO_EHDR 33 ++ ++/* Shapes of the caches. Bits 0-3 contains associativity; bits 4-7 contains ++ log2 of line size; mask those to get cache size. */ ++#define AT_L1I_CACHESHAPE 34 ++#define AT_L1D_CACHESHAPE 35 ++#define AT_L2_CACHESHAPE 36 ++#define AT_L3_CACHESHAPE 37 ++ ++/* Note section contents. Each entry in the note section begins with ++ a header of a fixed form. */ ++ ++typedef struct ++{ ++ Elf32_Word n_namesz; /* Length of the note's name. */ ++ Elf32_Word n_descsz; /* Length of the note's descriptor. */ ++ Elf32_Word n_type; /* Type of the note. */ ++} Elf32_Nhdr; ++ ++typedef struct ++{ ++ Elf64_Word n_namesz; /* Length of the note's name. */ ++ Elf64_Word n_descsz; /* Length of the note's descriptor. */ ++ Elf64_Word n_type; /* Type of the note. */ ++} Elf64_Nhdr; ++ ++/* Known names of notes. */ ++ ++/* Solaris entries in the note section have this name. */ ++#define ELF_NOTE_SOLARIS "SUNW Solaris" ++ ++/* Note entries for GNU systems have this name. */ ++#define ELF_NOTE_GNU "GNU" ++ ++ ++/* Defined types of notes for Solaris. */ ++ ++/* Value of descriptor (one word) is desired pagesize for the binary. */ ++#define ELF_NOTE_PAGESIZE_HINT 1 ++ ++ ++/* Defined note types for GNU systems. */ ++ ++/* ABI information. The descriptor consists of words: ++ word 0: OS descriptor ++ word 1: major version of the ABI ++ word 2: minor version of the ABI ++ word 3: subminor version of the ABI ++*/ ++#define NT_GNU_ABI_TAG 1 ++#define ELF_NOTE_ABI NT_GNU_ABI_TAG /* Old name. */ ++ ++/* Known OSes. These values can appear in word 0 of an ++ NT_GNU_ABI_TAG note section entry. */ ++#define ELF_NOTE_OS_LINUX 0 ++#define ELF_NOTE_OS_GNU 1 ++#define ELF_NOTE_OS_SOLARIS2 2 ++#define ELF_NOTE_OS_FREEBSD 3 ++ ++/* Synthetic hwcap information. The descriptor begins with two words: ++ word 0: number of entries ++ word 1: bitmask of enabled entries ++ Then follow variable-length entries, one byte followed by a ++ '\0'-terminated hwcap name string. The byte gives the bit ++ number to test if enabled, (1U << bit) & bitmask. */ ++#define NT_GNU_HWCAP 2 ++ ++/* Build ID bits as generated by ld --build-id. ++ The descriptor consists of any nonzero number of bytes. */ ++#define NT_GNU_BUILD_ID 3 ++ ++/* Version note generated by GNU gold containing a version string. */ ++#define NT_GNU_GOLD_VERSION 4 ++ ++ ++/* Move records. */ ++typedef struct ++{ ++ Elf32_Xword m_value; /* Symbol value. */ ++ Elf32_Word m_info; /* Size and index. */ ++ Elf32_Word m_poffset; /* Symbol offset. */ ++ Elf32_Half m_repeat; /* Repeat count. */ ++ Elf32_Half m_stride; /* Stride info. */ ++} Elf32_Move; ++ ++typedef struct ++{ ++ Elf64_Xword m_value; /* Symbol value. */ ++ Elf64_Xword m_info; /* Size and index. */ ++ Elf64_Xword m_poffset; /* Symbol offset. */ ++ Elf64_Half m_repeat; /* Repeat count. */ ++ Elf64_Half m_stride; /* Stride info. */ ++} Elf64_Move; ++ ++/* Macro to construct move records. */ ++#define ELF32_M_SYM(info) ((info) >> 8) ++#define ELF32_M_SIZE(info) ((unsigned char) (info)) ++#define ELF32_M_INFO(sym, size) (((sym) << 8) + (unsigned char) (size)) ++ ++#define ELF64_M_SYM(info) ELF32_M_SYM (info) ++#define ELF64_M_SIZE(info) ELF32_M_SIZE (info) ++#define ELF64_M_INFO(sym, size) ELF32_M_INFO (sym, size) ++ ++ ++/* Motorola 68k specific definitions. */ ++ ++/* Values for Elf32_Ehdr.e_flags. */ ++#define EF_CPU32 0x00810000 ++ ++/* m68k relocs. */ ++ ++#define R_68K_NONE 0 /* No reloc */ ++#define R_68K_32 1 /* Direct 32 bit */ ++#define R_68K_16 2 /* Direct 16 bit */ ++#define R_68K_8 3 /* Direct 8 bit */ ++#define R_68K_PC32 4 /* PC relative 32 bit */ ++#define R_68K_PC16 5 /* PC relative 16 bit */ ++#define R_68K_PC8 6 /* PC relative 8 bit */ ++#define R_68K_GOT32 7 /* 32 bit PC relative GOT entry */ ++#define R_68K_GOT16 8 /* 16 bit PC relative GOT entry */ ++#define R_68K_GOT8 9 /* 8 bit PC relative GOT entry */ ++#define R_68K_GOT32O 10 /* 32 bit GOT offset */ ++#define R_68K_GOT16O 11 /* 16 bit GOT offset */ ++#define R_68K_GOT8O 12 /* 8 bit GOT offset */ ++#define R_68K_PLT32 13 /* 32 bit PC relative PLT address */ ++#define R_68K_PLT16 14 /* 16 bit PC relative PLT address */ ++#define R_68K_PLT8 15 /* 8 bit PC relative PLT address */ ++#define R_68K_PLT32O 16 /* 32 bit PLT offset */ ++#define R_68K_PLT16O 17 /* 16 bit PLT offset */ ++#define R_68K_PLT8O 18 /* 8 bit PLT offset */ ++#define R_68K_COPY 19 /* Copy symbol at runtime */ ++#define R_68K_GLOB_DAT 20 /* Create GOT entry */ ++#define R_68K_JMP_SLOT 21 /* Create PLT entry */ ++#define R_68K_RELATIVE 22 /* Adjust by program base */ ++#define R_68K_TLS_GD32 25 /* 32 bit GOT offset for GD */ ++#define R_68K_TLS_GD16 26 /* 16 bit GOT offset for GD */ ++#define R_68K_TLS_GD8 27 /* 8 bit GOT offset for GD */ ++#define R_68K_TLS_LDM32 28 /* 32 bit GOT offset for LDM */ ++#define R_68K_TLS_LDM16 29 /* 16 bit GOT offset for LDM */ ++#define R_68K_TLS_LDM8 30 /* 8 bit GOT offset for LDM */ ++#define R_68K_TLS_LDO32 31 /* 32 bit module-relative offset */ ++#define R_68K_TLS_LDO16 32 /* 16 bit module-relative offset */ ++#define R_68K_TLS_LDO8 33 /* 8 bit module-relative offset */ ++#define R_68K_TLS_IE32 34 /* 32 bit GOT offset for IE */ ++#define R_68K_TLS_IE16 35 /* 16 bit GOT offset for IE */ ++#define R_68K_TLS_IE8 36 /* 8 bit GOT offset for IE */ ++#define R_68K_TLS_LE32 37 /* 32 bit offset relative to ++ static TLS block */ ++#define R_68K_TLS_LE16 38 /* 16 bit offset relative to ++ static TLS block */ ++#define R_68K_TLS_LE8 39 /* 8 bit offset relative to ++ static TLS block */ ++#define R_68K_TLS_DTPMOD32 40 /* 32 bit module number */ ++#define R_68K_TLS_DTPREL32 41 /* 32 bit module-relative offset */ ++#define R_68K_TLS_TPREL32 42 /* 32 bit TP-relative offset */ ++/* Keep this the last entry. */ ++#define R_68K_NUM 43 ++ ++/* Intel 80386 specific definitions. */ ++ ++/* i386 relocs. */ ++ ++#define R_386_NONE 0 /* No reloc */ ++#define R_386_32 1 /* Direct 32 bit */ ++#define R_386_PC32 2 /* PC relative 32 bit */ ++#define R_386_GOT32 3 /* 32 bit GOT entry */ ++#define R_386_PLT32 4 /* 32 bit PLT address */ ++#define R_386_COPY 5 /* Copy symbol at runtime */ ++#define R_386_GLOB_DAT 6 /* Create GOT entry */ ++#define R_386_JMP_SLOT 7 /* Create PLT entry */ ++#define R_386_RELATIVE 8 /* Adjust by program base */ ++#define R_386_GOTOFF 9 /* 32 bit offset to GOT */ ++#define R_386_GOTPC 10 /* 32 bit PC relative offset to GOT */ ++#define R_386_32PLT 11 ++#define R_386_TLS_TPOFF 14 /* Offset in static TLS block */ ++#define R_386_TLS_IE 15 /* Address of GOT entry for static TLS ++ block offset */ ++#define R_386_TLS_GOTIE 16 /* GOT entry for static TLS block ++ offset */ ++#define R_386_TLS_LE 17 /* Offset relative to static TLS ++ block */ ++#define R_386_TLS_GD 18 /* Direct 32 bit for GNU version of ++ general dynamic thread local data */ ++#define R_386_TLS_LDM 19 /* Direct 32 bit for GNU version of ++ local dynamic thread local data ++ in LE code */ ++#define R_386_16 20 ++#define R_386_PC16 21 ++#define R_386_8 22 ++#define R_386_PC8 23 ++#define R_386_TLS_GD_32 24 /* Direct 32 bit for general dynamic ++ thread local data */ ++#define R_386_TLS_GD_PUSH 25 /* Tag for pushl in GD TLS code */ ++#define R_386_TLS_GD_CALL 26 /* Relocation for call to ++ __tls_get_addr() */ ++#define R_386_TLS_GD_POP 27 /* Tag for popl in GD TLS code */ ++#define R_386_TLS_LDM_32 28 /* Direct 32 bit for local dynamic ++ thread local data in LE code */ ++#define R_386_TLS_LDM_PUSH 29 /* Tag for pushl in LDM TLS code */ ++#define R_386_TLS_LDM_CALL 30 /* Relocation for call to ++ __tls_get_addr() in LDM code */ ++#define R_386_TLS_LDM_POP 31 /* Tag for popl in LDM TLS code */ ++#define R_386_TLS_LDO_32 32 /* Offset relative to TLS block */ ++#define R_386_TLS_IE_32 33 /* GOT entry for negated static TLS ++ block offset */ ++#define R_386_TLS_LE_32 34 /* Negated offset relative to static ++ TLS block */ ++#define R_386_TLS_DTPMOD32 35 /* ID of module containing symbol */ ++#define R_386_TLS_DTPOFF32 36 /* Offset in TLS block */ ++#define R_386_TLS_TPOFF32 37 /* Negated offset in static TLS block */ ++/* 38? */ ++#define R_386_TLS_GOTDESC 39 /* GOT offset for TLS descriptor. */ ++#define R_386_TLS_DESC_CALL 40 /* Marker of call through TLS ++ descriptor for ++ relaxation. */ ++#define R_386_TLS_DESC 41 /* TLS descriptor containing ++ pointer to code and to ++ argument, returning the TLS ++ offset for the symbol. */ ++#define R_386_IRELATIVE 42 /* Adjust indirectly by program base */ ++/* Keep this the last entry. */ ++#define R_386_NUM 43 ++ ++/* SUN SPARC specific definitions. */ ++ ++/* Legal values for ST_TYPE subfield of st_info (symbol type). */ ++ ++#define STT_SPARC_REGISTER 13 /* Global register reserved to app. */ ++ ++/* Values for Elf64_Ehdr.e_flags. */ ++ ++#define EF_SPARCV9_MM 3 ++#define EF_SPARCV9_TSO 0 ++#define EF_SPARCV9_PSO 1 ++#define EF_SPARCV9_RMO 2 ++#define EF_SPARC_LEDATA 0x800000 /* little endian data */ ++#define EF_SPARC_EXT_MASK 0xFFFF00 ++#define EF_SPARC_32PLUS 0x000100 /* generic V8+ features */ ++#define EF_SPARC_SUN_US1 0x000200 /* Sun UltraSPARC1 extensions */ ++#define EF_SPARC_HAL_R1 0x000400 /* HAL R1 extensions */ ++#define EF_SPARC_SUN_US3 0x000800 /* Sun UltraSPARCIII extensions */ ++ ++/* SPARC relocs. */ ++ ++#define R_SPARC_NONE 0 /* No reloc */ ++#define R_SPARC_8 1 /* Direct 8 bit */ ++#define R_SPARC_16 2 /* Direct 16 bit */ ++#define R_SPARC_32 3 /* Direct 32 bit */ ++#define R_SPARC_DISP8 4 /* PC relative 8 bit */ ++#define R_SPARC_DISP16 5 /* PC relative 16 bit */ ++#define R_SPARC_DISP32 6 /* PC relative 32 bit */ ++#define R_SPARC_WDISP30 7 /* PC relative 30 bit shifted */ ++#define R_SPARC_WDISP22 8 /* PC relative 22 bit shifted */ ++#define R_SPARC_HI22 9 /* High 22 bit */ ++#define R_SPARC_22 10 /* Direct 22 bit */ ++#define R_SPARC_13 11 /* Direct 13 bit */ ++#define R_SPARC_LO10 12 /* Truncated 10 bit */ ++#define R_SPARC_GOT10 13 /* Truncated 10 bit GOT entry */ ++#define R_SPARC_GOT13 14 /* 13 bit GOT entry */ ++#define R_SPARC_GOT22 15 /* 22 bit GOT entry shifted */ ++#define R_SPARC_PC10 16 /* PC relative 10 bit truncated */ ++#define R_SPARC_PC22 17 /* PC relative 22 bit shifted */ ++#define R_SPARC_WPLT30 18 /* 30 bit PC relative PLT address */ ++#define R_SPARC_COPY 19 /* Copy symbol at runtime */ ++#define R_SPARC_GLOB_DAT 20 /* Create GOT entry */ ++#define R_SPARC_JMP_SLOT 21 /* Create PLT entry */ ++#define R_SPARC_RELATIVE 22 /* Adjust by program base */ ++#define R_SPARC_UA32 23 /* Direct 32 bit unaligned */ ++ ++/* Additional Sparc64 relocs. */ ++ ++#define R_SPARC_PLT32 24 /* Direct 32 bit ref to PLT entry */ ++#define R_SPARC_HIPLT22 25 /* High 22 bit PLT entry */ ++#define R_SPARC_LOPLT10 26 /* Truncated 10 bit PLT entry */ ++#define R_SPARC_PCPLT32 27 /* PC rel 32 bit ref to PLT entry */ ++#define R_SPARC_PCPLT22 28 /* PC rel high 22 bit PLT entry */ ++#define R_SPARC_PCPLT10 29 /* PC rel trunc 10 bit PLT entry */ ++#define R_SPARC_10 30 /* Direct 10 bit */ ++#define R_SPARC_11 31 /* Direct 11 bit */ ++#define R_SPARC_64 32 /* Direct 64 bit */ ++#define R_SPARC_OLO10 33 /* 10bit with secondary 13bit addend */ ++#define R_SPARC_HH22 34 /* Top 22 bits of direct 64 bit */ ++#define R_SPARC_HM10 35 /* High middle 10 bits of ... */ ++#define R_SPARC_LM22 36 /* Low middle 22 bits of ... */ ++#define R_SPARC_PC_HH22 37 /* Top 22 bits of pc rel 64 bit */ ++#define R_SPARC_PC_HM10 38 /* High middle 10 bit of ... */ ++#define R_SPARC_PC_LM22 39 /* Low miggle 22 bits of ... */ ++#define R_SPARC_WDISP16 40 /* PC relative 16 bit shifted */ ++#define R_SPARC_WDISP19 41 /* PC relative 19 bit shifted */ ++#define R_SPARC_GLOB_JMP 42 /* was part of v9 ABI but was removed */ ++#define R_SPARC_7 43 /* Direct 7 bit */ ++#define R_SPARC_5 44 /* Direct 5 bit */ ++#define R_SPARC_6 45 /* Direct 6 bit */ ++#define R_SPARC_DISP64 46 /* PC relative 64 bit */ ++#define R_SPARC_PLT64 47 /* Direct 64 bit ref to PLT entry */ ++#define R_SPARC_HIX22 48 /* High 22 bit complemented */ ++#define R_SPARC_LOX10 49 /* Truncated 11 bit complemented */ ++#define R_SPARC_H44 50 /* Direct high 12 of 44 bit */ ++#define R_SPARC_M44 51 /* Direct mid 22 of 44 bit */ ++#define R_SPARC_L44 52 /* Direct low 10 of 44 bit */ ++#define R_SPARC_REGISTER 53 /* Global register usage */ ++#define R_SPARC_UA64 54 /* Direct 64 bit unaligned */ ++#define R_SPARC_UA16 55 /* Direct 16 bit unaligned */ ++#define R_SPARC_TLS_GD_HI22 56 ++#define R_SPARC_TLS_GD_LO10 57 ++#define R_SPARC_TLS_GD_ADD 58 ++#define R_SPARC_TLS_GD_CALL 59 ++#define R_SPARC_TLS_LDM_HI22 60 ++#define R_SPARC_TLS_LDM_LO10 61 ++#define R_SPARC_TLS_LDM_ADD 62 ++#define R_SPARC_TLS_LDM_CALL 63 ++#define R_SPARC_TLS_LDO_HIX22 64 ++#define R_SPARC_TLS_LDO_LOX10 65 ++#define R_SPARC_TLS_LDO_ADD 66 ++#define R_SPARC_TLS_IE_HI22 67 ++#define R_SPARC_TLS_IE_LO10 68 ++#define R_SPARC_TLS_IE_LD 69 ++#define R_SPARC_TLS_IE_LDX 70 ++#define R_SPARC_TLS_IE_ADD 71 ++#define R_SPARC_TLS_LE_HIX22 72 ++#define R_SPARC_TLS_LE_LOX10 73 ++#define R_SPARC_TLS_DTPMOD32 74 ++#define R_SPARC_TLS_DTPMOD64 75 ++#define R_SPARC_TLS_DTPOFF32 76 ++#define R_SPARC_TLS_DTPOFF64 77 ++#define R_SPARC_TLS_TPOFF32 78 ++#define R_SPARC_TLS_TPOFF64 79 ++#define R_SPARC_GOTDATA_HIX22 80 ++#define R_SPARC_GOTDATA_LOX10 81 ++#define R_SPARC_GOTDATA_OP_HIX22 82 ++#define R_SPARC_GOTDATA_OP_LOX10 83 ++#define R_SPARC_GOTDATA_OP 84 ++#define R_SPARC_H34 85 ++#define R_SPARC_SIZE32 86 ++#define R_SPARC_SIZE64 87 ++#define R_SPARC_WDISP10 88 ++#define R_SPARC_JMP_IREL 248 ++#define R_SPARC_IRELATIVE 249 ++#define R_SPARC_GNU_VTINHERIT 250 ++#define R_SPARC_GNU_VTENTRY 251 ++#define R_SPARC_REV32 252 ++/* Keep this the last entry. */ ++#define R_SPARC_NUM 253 ++ ++/* For Sparc64, legal values for d_tag of Elf64_Dyn. */ ++ ++#define DT_SPARC_REGISTER 0x70000001 ++#define DT_SPARC_NUM 2 ++ ++/* MIPS R3000 specific definitions. */ ++ ++/* Legal values for e_flags field of Elf32_Ehdr. */ ++ ++#define EF_MIPS_NOREORDER 1 /* A .noreorder directive was used */ ++#define EF_MIPS_PIC 2 /* Contains PIC code */ ++#define EF_MIPS_CPIC 4 /* Uses PIC calling sequence */ ++#define EF_MIPS_XGOT 8 ++#define EF_MIPS_64BIT_WHIRL 16 ++#define EF_MIPS_ABI2 32 ++#define EF_MIPS_ABI_ON32 64 ++#define EF_MIPS_ARCH 0xf0000000 /* MIPS architecture level */ ++ ++/* Legal values for MIPS architecture level. */ ++ ++#define EF_MIPS_ARCH_1 0x00000000 /* -mips1 code. */ ++#define EF_MIPS_ARCH_2 0x10000000 /* -mips2 code. */ ++#define EF_MIPS_ARCH_3 0x20000000 /* -mips3 code. */ ++#define EF_MIPS_ARCH_4 0x30000000 /* -mips4 code. */ ++#define EF_MIPS_ARCH_5 0x40000000 /* -mips5 code. */ ++#define EF_MIPS_ARCH_32 0x60000000 /* MIPS32 code. */ ++#define EF_MIPS_ARCH_64 0x70000000 /* MIPS64 code. */ ++ ++/* The following are non-official names and should not be used. */ ++ ++#define E_MIPS_ARCH_1 0x00000000 /* -mips1 code. */ ++#define E_MIPS_ARCH_2 0x10000000 /* -mips2 code. */ ++#define E_MIPS_ARCH_3 0x20000000 /* -mips3 code. */ ++#define E_MIPS_ARCH_4 0x30000000 /* -mips4 code. */ ++#define E_MIPS_ARCH_5 0x40000000 /* -mips5 code. */ ++#define E_MIPS_ARCH_32 0x60000000 /* MIPS32 code. */ ++#define E_MIPS_ARCH_64 0x70000000 /* MIPS64 code. */ ++ ++/* Special section indices. */ ++ ++#define SHN_MIPS_ACOMMON 0xff00 /* Allocated common symbols */ ++#define SHN_MIPS_TEXT 0xff01 /* Allocated test symbols. */ ++#define SHN_MIPS_DATA 0xff02 /* Allocated data symbols. */ ++#define SHN_MIPS_SCOMMON 0xff03 /* Small common symbols */ ++#define SHN_MIPS_SUNDEFINED 0xff04 /* Small undefined symbols */ ++ ++/* Legal values for sh_type field of Elf32_Shdr. */ ++ ++#define SHT_MIPS_LIBLIST 0x70000000 /* Shared objects used in link */ ++#define SHT_MIPS_MSYM 0x70000001 ++#define SHT_MIPS_CONFLICT 0x70000002 /* Conflicting symbols */ ++#define SHT_MIPS_GPTAB 0x70000003 /* Global data area sizes */ ++#define SHT_MIPS_UCODE 0x70000004 /* Reserved for SGI/MIPS compilers */ ++#define SHT_MIPS_DEBUG 0x70000005 /* MIPS ECOFF debugging information*/ ++#define SHT_MIPS_REGINFO 0x70000006 /* Register usage information */ ++#define SHT_MIPS_PACKAGE 0x70000007 ++#define SHT_MIPS_PACKSYM 0x70000008 ++#define SHT_MIPS_RELD 0x70000009 ++#define SHT_MIPS_IFACE 0x7000000b ++#define SHT_MIPS_CONTENT 0x7000000c ++#define SHT_MIPS_OPTIONS 0x7000000d /* Miscellaneous options. */ ++#define SHT_MIPS_SHDR 0x70000010 ++#define SHT_MIPS_FDESC 0x70000011 ++#define SHT_MIPS_EXTSYM 0x70000012 ++#define SHT_MIPS_DENSE 0x70000013 ++#define SHT_MIPS_PDESC 0x70000014 ++#define SHT_MIPS_LOCSYM 0x70000015 ++#define SHT_MIPS_AUXSYM 0x70000016 ++#define SHT_MIPS_OPTSYM 0x70000017 ++#define SHT_MIPS_LOCSTR 0x70000018 ++#define SHT_MIPS_LINE 0x70000019 ++#define SHT_MIPS_RFDESC 0x7000001a ++#define SHT_MIPS_DELTASYM 0x7000001b ++#define SHT_MIPS_DELTAINST 0x7000001c ++#define SHT_MIPS_DELTACLASS 0x7000001d ++#define SHT_MIPS_DWARF 0x7000001e /* DWARF debugging information. */ ++#define SHT_MIPS_DELTADECL 0x7000001f ++#define SHT_MIPS_SYMBOL_LIB 0x70000020 ++#define SHT_MIPS_EVENTS 0x70000021 /* Event section. */ ++#define SHT_MIPS_TRANSLATE 0x70000022 ++#define SHT_MIPS_PIXIE 0x70000023 ++#define SHT_MIPS_XLATE 0x70000024 ++#define SHT_MIPS_XLATE_DEBUG 0x70000025 ++#define SHT_MIPS_WHIRL 0x70000026 ++#define SHT_MIPS_EH_REGION 0x70000027 ++#define SHT_MIPS_XLATE_OLD 0x70000028 ++#define SHT_MIPS_PDR_EXCEPTION 0x70000029 ++ ++/* Legal values for sh_flags field of Elf32_Shdr. */ ++ ++#define SHF_MIPS_GPREL 0x10000000 /* Must be part of global data area */ ++#define SHF_MIPS_MERGE 0x20000000 ++#define SHF_MIPS_ADDR 0x40000000 ++#define SHF_MIPS_STRINGS 0x80000000 ++#define SHF_MIPS_NOSTRIP 0x08000000 ++#define SHF_MIPS_LOCAL 0x04000000 ++#define SHF_MIPS_NAMES 0x02000000 ++#define SHF_MIPS_NODUPE 0x01000000 ++ ++ ++/* Symbol tables. */ ++ ++/* MIPS specific values for `st_other'. */ ++#define STO_MIPS_DEFAULT 0x0 ++#define STO_MIPS_INTERNAL 0x1 ++#define STO_MIPS_HIDDEN 0x2 ++#define STO_MIPS_PROTECTED 0x3 ++#define STO_MIPS_PLT 0x8 ++#define STO_MIPS_SC_ALIGN_UNUSED 0xff ++ ++/* MIPS specific values for `st_info'. */ ++#define STB_MIPS_SPLIT_COMMON 13 ++ ++/* Entries found in sections of type SHT_MIPS_GPTAB. */ ++ ++typedef union ++{ ++ struct ++ { ++ Elf32_Word gt_current_g_value; /* -G value used for compilation */ ++ Elf32_Word gt_unused; /* Not used */ ++ } gt_header; /* First entry in section */ ++ struct ++ { ++ Elf32_Word gt_g_value; /* If this value were used for -G */ ++ Elf32_Word gt_bytes; /* This many bytes would be used */ ++ } gt_entry; /* Subsequent entries in section */ ++} Elf32_gptab; ++ ++/* Entry found in sections of type SHT_MIPS_REGINFO. */ ++ ++typedef struct ++{ ++ Elf32_Word ri_gprmask; /* General registers used */ ++ Elf32_Word ri_cprmask[4]; /* Coprocessor registers used */ ++ Elf32_Sword ri_gp_value; /* $gp register value */ ++} Elf32_RegInfo; ++ ++/* Entries found in sections of type SHT_MIPS_OPTIONS. */ ++ ++typedef struct ++{ ++ unsigned char kind; /* Determines interpretation of the ++ variable part of descriptor. */ ++ unsigned char size; /* Size of descriptor, including header. */ ++ Elf32_Section section; /* Section header index of section affected, ++ 0 for global options. */ ++ Elf32_Word info; /* Kind-specific information. */ ++} Elf_Options; ++ ++/* Values for `kind' field in Elf_Options. */ ++ ++#define ODK_NULL 0 /* Undefined. */ ++#define ODK_REGINFO 1 /* Register usage information. */ ++#define ODK_EXCEPTIONS 2 /* Exception processing options. */ ++#define ODK_PAD 3 /* Section padding options. */ ++#define ODK_HWPATCH 4 /* Hardware workarounds performed */ ++#define ODK_FILL 5 /* record the fill value used by the linker. */ ++#define ODK_TAGS 6 /* reserve space for desktop tools to write. */ ++#define ODK_HWAND 7 /* HW workarounds. 'AND' bits when merging. */ ++#define ODK_HWOR 8 /* HW workarounds. 'OR' bits when merging. */ ++ ++/* Values for `info' in Elf_Options for ODK_EXCEPTIONS entries. */ ++ ++#define OEX_FPU_MIN 0x1f /* FPE's which MUST be enabled. */ ++#define OEX_FPU_MAX 0x1f00 /* FPE's which MAY be enabled. */ ++#define OEX_PAGE0 0x10000 /* page zero must be mapped. */ ++#define OEX_SMM 0x20000 /* Force sequential memory mode? */ ++#define OEX_FPDBUG 0x40000 /* Force floating point debug mode? */ ++#define OEX_PRECISEFP OEX_FPDBUG ++#define OEX_DISMISS 0x80000 /* Dismiss invalid address faults? */ ++ ++#define OEX_FPU_INVAL 0x10 ++#define OEX_FPU_DIV0 0x08 ++#define OEX_FPU_OFLO 0x04 ++#define OEX_FPU_UFLO 0x02 ++#define OEX_FPU_INEX 0x01 ++ ++/* Masks for `info' in Elf_Options for an ODK_HWPATCH entry. */ ++ ++#define OHW_R4KEOP 0x1 /* R4000 end-of-page patch. */ ++#define OHW_R8KPFETCH 0x2 /* may need R8000 prefetch patch. */ ++#define OHW_R5KEOP 0x4 /* R5000 end-of-page patch. */ ++#define OHW_R5KCVTL 0x8 /* R5000 cvt.[ds].l bug. clean=1. */ ++ ++#define OPAD_PREFIX 0x1 ++#define OPAD_POSTFIX 0x2 ++#define OPAD_SYMBOL 0x4 ++ ++/* Entry found in `.options' section. */ ++ ++typedef struct ++{ ++ Elf32_Word hwp_flags1; /* Extra flags. */ ++ Elf32_Word hwp_flags2; /* Extra flags. */ ++} Elf_Options_Hw; ++ ++/* Masks for `info' in ElfOptions for ODK_HWAND and ODK_HWOR entries. */ ++ ++#define OHWA0_R4KEOP_CHECKED 0x00000001 ++#define OHWA1_R4KEOP_CLEAN 0x00000002 ++ ++/* MIPS relocs. */ ++ ++#define R_MIPS_NONE 0 /* No reloc */ ++#define R_MIPS_16 1 /* Direct 16 bit */ ++#define R_MIPS_32 2 /* Direct 32 bit */ ++#define R_MIPS_REL32 3 /* PC relative 32 bit */ ++#define R_MIPS_26 4 /* Direct 26 bit shifted */ ++#define R_MIPS_HI16 5 /* High 16 bit */ ++#define R_MIPS_LO16 6 /* Low 16 bit */ ++#define R_MIPS_GPREL16 7 /* GP relative 16 bit */ ++#define R_MIPS_LITERAL 8 /* 16 bit literal entry */ ++#define R_MIPS_GOT16 9 /* 16 bit GOT entry */ ++#define R_MIPS_PC16 10 /* PC relative 16 bit */ ++#define R_MIPS_CALL16 11 /* 16 bit GOT entry for function */ ++#define R_MIPS_GPREL32 12 /* GP relative 32 bit */ ++ ++#define R_MIPS_SHIFT5 16 ++#define R_MIPS_SHIFT6 17 ++#define R_MIPS_64 18 ++#define R_MIPS_GOT_DISP 19 ++#define R_MIPS_GOT_PAGE 20 ++#define R_MIPS_GOT_OFST 21 ++#define R_MIPS_GOT_HI16 22 ++#define R_MIPS_GOT_LO16 23 ++#define R_MIPS_SUB 24 ++#define R_MIPS_INSERT_A 25 ++#define R_MIPS_INSERT_B 26 ++#define R_MIPS_DELETE 27 ++#define R_MIPS_HIGHER 28 ++#define R_MIPS_HIGHEST 29 ++#define R_MIPS_CALL_HI16 30 ++#define R_MIPS_CALL_LO16 31 ++#define R_MIPS_SCN_DISP 32 ++#define R_MIPS_REL16 33 ++#define R_MIPS_ADD_IMMEDIATE 34 ++#define R_MIPS_PJUMP 35 ++#define R_MIPS_RELGOT 36 ++#define R_MIPS_JALR 37 ++#define R_MIPS_TLS_DTPMOD32 38 /* Module number 32 bit */ ++#define R_MIPS_TLS_DTPREL32 39 /* Module-relative offset 32 bit */ ++#define R_MIPS_TLS_DTPMOD64 40 /* Module number 64 bit */ ++#define R_MIPS_TLS_DTPREL64 41 /* Module-relative offset 64 bit */ ++#define R_MIPS_TLS_GD 42 /* 16 bit GOT offset for GD */ ++#define R_MIPS_TLS_LDM 43 /* 16 bit GOT offset for LDM */ ++#define R_MIPS_TLS_DTPREL_HI16 44 /* Module-relative offset, high 16 bits */ ++#define R_MIPS_TLS_DTPREL_LO16 45 /* Module-relative offset, low 16 bits */ ++#define R_MIPS_TLS_GOTTPREL 46 /* 16 bit GOT offset for IE */ ++#define R_MIPS_TLS_TPREL32 47 /* TP-relative offset, 32 bit */ ++#define R_MIPS_TLS_TPREL64 48 /* TP-relative offset, 64 bit */ ++#define R_MIPS_TLS_TPREL_HI16 49 /* TP-relative offset, high 16 bits */ ++#define R_MIPS_TLS_TPREL_LO16 50 /* TP-relative offset, low 16 bits */ ++#define R_MIPS_GLOB_DAT 51 ++#define R_MIPS_COPY 126 ++#define R_MIPS_JUMP_SLOT 127 ++/* Keep this the last entry. */ ++#define R_MIPS_NUM 128 ++ ++/* Legal values for p_type field of Elf32_Phdr. */ ++ ++#define PT_MIPS_REGINFO 0x70000000 /* Register usage information */ ++#define PT_MIPS_RTPROC 0x70000001 /* Runtime procedure table. */ ++#define PT_MIPS_OPTIONS 0x70000002 ++ ++/* Special program header types. */ ++ ++#define PF_MIPS_LOCAL 0x10000000 ++ ++/* Legal values for d_tag field of Elf32_Dyn. */ ++ ++#define DT_MIPS_RLD_VERSION 0x70000001 /* Runtime linker interface version */ ++#define DT_MIPS_TIME_STAMP 0x70000002 /* Timestamp */ ++#define DT_MIPS_ICHECKSUM 0x70000003 /* Checksum */ ++#define DT_MIPS_IVERSION 0x70000004 /* Version string (string tbl index) */ ++#define DT_MIPS_FLAGS 0x70000005 /* Flags */ ++#define DT_MIPS_BASE_ADDRESS 0x70000006 /* Base address */ ++#define DT_MIPS_MSYM 0x70000007 ++#define DT_MIPS_CONFLICT 0x70000008 /* Address of CONFLICT section */ ++#define DT_MIPS_LIBLIST 0x70000009 /* Address of LIBLIST section */ ++#define DT_MIPS_LOCAL_GOTNO 0x7000000a /* Number of local GOT entries */ ++#define DT_MIPS_CONFLICTNO 0x7000000b /* Number of CONFLICT entries */ ++#define DT_MIPS_LIBLISTNO 0x70000010 /* Number of LIBLIST entries */ ++#define DT_MIPS_SYMTABNO 0x70000011 /* Number of DYNSYM entries */ ++#define DT_MIPS_UNREFEXTNO 0x70000012 /* First external DYNSYM */ ++#define DT_MIPS_GOTSYM 0x70000013 /* First GOT entry in DYNSYM */ ++#define DT_MIPS_HIPAGENO 0x70000014 /* Number of GOT page table entries */ ++#define DT_MIPS_RLD_MAP 0x70000016 /* Address of run time loader map. */ ++#define DT_MIPS_DELTA_CLASS 0x70000017 /* Delta C++ class definition. */ ++#define DT_MIPS_DELTA_CLASS_NO 0x70000018 /* Number of entries in ++ DT_MIPS_DELTA_CLASS. */ ++#define DT_MIPS_DELTA_INSTANCE 0x70000019 /* Delta C++ class instances. */ ++#define DT_MIPS_DELTA_INSTANCE_NO 0x7000001a /* Number of entries in ++ DT_MIPS_DELTA_INSTANCE. */ ++#define DT_MIPS_DELTA_RELOC 0x7000001b /* Delta relocations. */ ++#define DT_MIPS_DELTA_RELOC_NO 0x7000001c /* Number of entries in ++ DT_MIPS_DELTA_RELOC. */ ++#define DT_MIPS_DELTA_SYM 0x7000001d /* Delta symbols that Delta ++ relocations refer to. */ ++#define DT_MIPS_DELTA_SYM_NO 0x7000001e /* Number of entries in ++ DT_MIPS_DELTA_SYM. */ ++#define DT_MIPS_DELTA_CLASSSYM 0x70000020 /* Delta symbols that hold the ++ class declaration. */ ++#define DT_MIPS_DELTA_CLASSSYM_NO 0x70000021 /* Number of entries in ++ DT_MIPS_DELTA_CLASSSYM. */ ++#define DT_MIPS_CXX_FLAGS 0x70000022 /* Flags indicating for C++ flavor. */ ++#define DT_MIPS_PIXIE_INIT 0x70000023 ++#define DT_MIPS_SYMBOL_LIB 0x70000024 ++#define DT_MIPS_LOCALPAGE_GOTIDX 0x70000025 ++#define DT_MIPS_LOCAL_GOTIDX 0x70000026 ++#define DT_MIPS_HIDDEN_GOTIDX 0x70000027 ++#define DT_MIPS_PROTECTED_GOTIDX 0x70000028 ++#define DT_MIPS_OPTIONS 0x70000029 /* Address of .options. */ ++#define DT_MIPS_INTERFACE 0x7000002a /* Address of .interface. */ ++#define DT_MIPS_DYNSTR_ALIGN 0x7000002b ++#define DT_MIPS_INTERFACE_SIZE 0x7000002c /* Size of the .interface section. */ ++#define DT_MIPS_RLD_TEXT_RESOLVE_ADDR 0x7000002d /* Address of rld_text_rsolve ++ function stored in GOT. */ ++#define DT_MIPS_PERF_SUFFIX 0x7000002e /* Default suffix of dso to be added ++ by rld on dlopen() calls. */ ++#define DT_MIPS_COMPACT_SIZE 0x7000002f /* (O32)Size of compact rel section. */ ++#define DT_MIPS_GP_VALUE 0x70000030 /* GP value for aux GOTs. */ ++#define DT_MIPS_AUX_DYNAMIC 0x70000031 /* Address of aux .dynamic. */ ++/* The address of .got.plt in an executable using the new non-PIC ABI. */ ++#define DT_MIPS_PLTGOT 0x70000032 ++/* The base of the PLT in an executable using the new non-PIC ABI if that ++ PLT is writable. For a non-writable PLT, this is omitted or has a zero ++ value. */ ++#define DT_MIPS_RWPLT 0x70000034 ++#define DT_MIPS_NUM 0x35 ++ ++/* Legal values for DT_MIPS_FLAGS Elf32_Dyn entry. */ ++ ++#define RHF_NONE 0 /* No flags */ ++#define RHF_QUICKSTART (1 << 0) /* Use quickstart */ ++#define RHF_NOTPOT (1 << 1) /* Hash size not power of 2 */ ++#define RHF_NO_LIBRARY_REPLACEMENT (1 << 2) /* Ignore LD_LIBRARY_PATH */ ++#define RHF_NO_MOVE (1 << 3) ++#define RHF_SGI_ONLY (1 << 4) ++#define RHF_GUARANTEE_INIT (1 << 5) ++#define RHF_DELTA_C_PLUS_PLUS (1 << 6) ++#define RHF_GUARANTEE_START_INIT (1 << 7) ++#define RHF_PIXIE (1 << 8) ++#define RHF_DEFAULT_DELAY_LOAD (1 << 9) ++#define RHF_REQUICKSTART (1 << 10) ++#define RHF_REQUICKSTARTED (1 << 11) ++#define RHF_CORD (1 << 12) ++#define RHF_NO_UNRES_UNDEF (1 << 13) ++#define RHF_RLD_ORDER_SAFE (1 << 14) ++ ++/* Entries found in sections of type SHT_MIPS_LIBLIST. */ ++ ++typedef struct ++{ ++ Elf32_Word l_name; /* Name (string table index) */ ++ Elf32_Word l_time_stamp; /* Timestamp */ ++ Elf32_Word l_checksum; /* Checksum */ ++ Elf32_Word l_version; /* Interface version */ ++ Elf32_Word l_flags; /* Flags */ ++} Elf32_Lib; ++ ++typedef struct ++{ ++ Elf64_Word l_name; /* Name (string table index) */ ++ Elf64_Word l_time_stamp; /* Timestamp */ ++ Elf64_Word l_checksum; /* Checksum */ ++ Elf64_Word l_version; /* Interface version */ ++ Elf64_Word l_flags; /* Flags */ ++} Elf64_Lib; ++ ++ ++/* Legal values for l_flags. */ ++ ++#define LL_NONE 0 ++#define LL_EXACT_MATCH (1 << 0) /* Require exact match */ ++#define LL_IGNORE_INT_VER (1 << 1) /* Ignore interface version */ ++#define LL_REQUIRE_MINOR (1 << 2) ++#define LL_EXPORTS (1 << 3) ++#define LL_DELAY_LOAD (1 << 4) ++#define LL_DELTA (1 << 5) ++ ++/* Entries found in sections of type SHT_MIPS_CONFLICT. */ ++ ++typedef Elf32_Addr Elf32_Conflict; ++ ++ ++/* HPPA specific definitions. */ ++ ++/* Legal values for e_flags field of Elf32_Ehdr. */ ++ ++#define EF_PARISC_TRAPNIL 0x00010000 /* Trap nil pointer dereference. */ ++#define EF_PARISC_EXT 0x00020000 /* Program uses arch. extensions. */ ++#define EF_PARISC_LSB 0x00040000 /* Program expects little endian. */ ++#define EF_PARISC_WIDE 0x00080000 /* Program expects wide mode. */ ++#define EF_PARISC_NO_KABP 0x00100000 /* No kernel assisted branch ++ prediction. */ ++#define EF_PARISC_LAZYSWAP 0x00400000 /* Allow lazy swapping. */ ++#define EF_PARISC_ARCH 0x0000ffff /* Architecture version. */ ++ ++/* Defined values for `e_flags & EF_PARISC_ARCH' are: */ ++ ++#define EFA_PARISC_1_0 0x020b /* PA-RISC 1.0 big-endian. */ ++#define EFA_PARISC_1_1 0x0210 /* PA-RISC 1.1 big-endian. */ ++#define EFA_PARISC_2_0 0x0214 /* PA-RISC 2.0 big-endian. */ ++ ++/* Additional section indeces. */ ++ ++#define SHN_PARISC_ANSI_COMMON 0xff00 /* Section for tenatively declared ++ symbols in ANSI C. */ ++#define SHN_PARISC_HUGE_COMMON 0xff01 /* Common blocks in huge model. */ ++ ++/* Legal values for sh_type field of Elf32_Shdr. */ ++ ++#define SHT_PARISC_EXT 0x70000000 /* Contains product specific ext. */ ++#define SHT_PARISC_UNWIND 0x70000001 /* Unwind information. */ ++#define SHT_PARISC_DOC 0x70000002 /* Debug info for optimized code. */ ++ ++/* Legal values for sh_flags field of Elf32_Shdr. */ ++ ++#define SHF_PARISC_SHORT 0x20000000 /* Section with short addressing. */ ++#define SHF_PARISC_HUGE 0x40000000 /* Section far from gp. */ ++#define SHF_PARISC_SBP 0x80000000 /* Static branch prediction code. */ ++ ++/* Legal values for ST_TYPE subfield of st_info (symbol type). */ ++ ++#define STT_PARISC_MILLICODE 13 /* Millicode function entry point. */ ++ ++#define STT_HP_OPAQUE (STT_LOOS + 0x1) ++#define STT_HP_STUB (STT_LOOS + 0x2) ++ ++/* HPPA relocs. */ ++ ++#define R_PARISC_NONE 0 /* No reloc. */ ++#define R_PARISC_DIR32 1 /* Direct 32-bit reference. */ ++#define R_PARISC_DIR21L 2 /* Left 21 bits of eff. address. */ ++#define R_PARISC_DIR17R 3 /* Right 17 bits of eff. address. */ ++#define R_PARISC_DIR17F 4 /* 17 bits of eff. address. */ ++#define R_PARISC_DIR14R 6 /* Right 14 bits of eff. address. */ ++#define R_PARISC_PCREL32 9 /* 32-bit rel. address. */ ++#define R_PARISC_PCREL21L 10 /* Left 21 bits of rel. address. */ ++#define R_PARISC_PCREL17R 11 /* Right 17 bits of rel. address. */ ++#define R_PARISC_PCREL17F 12 /* 17 bits of rel. address. */ ++#define R_PARISC_PCREL14R 14 /* Right 14 bits of rel. address. */ ++#define R_PARISC_DPREL21L 18 /* Left 21 bits of rel. address. */ ++#define R_PARISC_DPREL14R 22 /* Right 14 bits of rel. address. */ ++#define R_PARISC_GPREL21L 26 /* GP-relative, left 21 bits. */ ++#define R_PARISC_GPREL14R 30 /* GP-relative, right 14 bits. */ ++#define R_PARISC_LTOFF21L 34 /* LT-relative, left 21 bits. */ ++#define R_PARISC_LTOFF14R 38 /* LT-relative, right 14 bits. */ ++#define R_PARISC_SECREL32 41 /* 32 bits section rel. address. */ ++#define R_PARISC_SEGBASE 48 /* No relocation, set segment base. */ ++#define R_PARISC_SEGREL32 49 /* 32 bits segment rel. address. */ ++#define R_PARISC_PLTOFF21L 50 /* PLT rel. address, left 21 bits. */ ++#define R_PARISC_PLTOFF14R 54 /* PLT rel. address, right 14 bits. */ ++#define R_PARISC_LTOFF_FPTR32 57 /* 32 bits LT-rel. function pointer. */ ++#define R_PARISC_LTOFF_FPTR21L 58 /* LT-rel. fct ptr, left 21 bits. */ ++#define R_PARISC_LTOFF_FPTR14R 62 /* LT-rel. fct ptr, right 14 bits. */ ++#define R_PARISC_FPTR64 64 /* 64 bits function address. */ ++#define R_PARISC_PLABEL32 65 /* 32 bits function address. */ ++#define R_PARISC_PLABEL21L 66 /* Left 21 bits of fdesc address. */ ++#define R_PARISC_PLABEL14R 70 /* Right 14 bits of fdesc address. */ ++#define R_PARISC_PCREL64 72 /* 64 bits PC-rel. address. */ ++#define R_PARISC_PCREL22F 74 /* 22 bits PC-rel. address. */ ++#define R_PARISC_PCREL14WR 75 /* PC-rel. address, right 14 bits. */ ++#define R_PARISC_PCREL14DR 76 /* PC rel. address, right 14 bits. */ ++#define R_PARISC_PCREL16F 77 /* 16 bits PC-rel. address. */ ++#define R_PARISC_PCREL16WF 78 /* 16 bits PC-rel. address. */ ++#define R_PARISC_PCREL16DF 79 /* 16 bits PC-rel. address. */ ++#define R_PARISC_DIR64 80 /* 64 bits of eff. address. */ ++#define R_PARISC_DIR14WR 83 /* 14 bits of eff. address. */ ++#define R_PARISC_DIR14DR 84 /* 14 bits of eff. address. */ ++#define R_PARISC_DIR16F 85 /* 16 bits of eff. address. */ ++#define R_PARISC_DIR16WF 86 /* 16 bits of eff. address. */ ++#define R_PARISC_DIR16DF 87 /* 16 bits of eff. address. */ ++#define R_PARISC_GPREL64 88 /* 64 bits of GP-rel. address. */ ++#define R_PARISC_GPREL14WR 91 /* GP-rel. address, right 14 bits. */ ++#define R_PARISC_GPREL14DR 92 /* GP-rel. address, right 14 bits. */ ++#define R_PARISC_GPREL16F 93 /* 16 bits GP-rel. address. */ ++#define R_PARISC_GPREL16WF 94 /* 16 bits GP-rel. address. */ ++#define R_PARISC_GPREL16DF 95 /* 16 bits GP-rel. address. */ ++#define R_PARISC_LTOFF64 96 /* 64 bits LT-rel. address. */ ++#define R_PARISC_LTOFF14WR 99 /* LT-rel. address, right 14 bits. */ ++#define R_PARISC_LTOFF14DR 100 /* LT-rel. address, right 14 bits. */ ++#define R_PARISC_LTOFF16F 101 /* 16 bits LT-rel. address. */ ++#define R_PARISC_LTOFF16WF 102 /* 16 bits LT-rel. address. */ ++#define R_PARISC_LTOFF16DF 103 /* 16 bits LT-rel. address. */ ++#define R_PARISC_SECREL64 104 /* 64 bits section rel. address. */ ++#define R_PARISC_SEGREL64 112 /* 64 bits segment rel. address. */ ++#define R_PARISC_PLTOFF14WR 115 /* PLT-rel. address, right 14 bits. */ ++#define R_PARISC_PLTOFF14DR 116 /* PLT-rel. address, right 14 bits. */ ++#define R_PARISC_PLTOFF16F 117 /* 16 bits LT-rel. address. */ ++#define R_PARISC_PLTOFF16WF 118 /* 16 bits PLT-rel. address. */ ++#define R_PARISC_PLTOFF16DF 119 /* 16 bits PLT-rel. address. */ ++#define R_PARISC_LTOFF_FPTR64 120 /* 64 bits LT-rel. function ptr. */ ++#define R_PARISC_LTOFF_FPTR14WR 123 /* LT-rel. fct. ptr., right 14 bits. */ ++#define R_PARISC_LTOFF_FPTR14DR 124 /* LT-rel. fct. ptr., right 14 bits. */ ++#define R_PARISC_LTOFF_FPTR16F 125 /* 16 bits LT-rel. function ptr. */ ++#define R_PARISC_LTOFF_FPTR16WF 126 /* 16 bits LT-rel. function ptr. */ ++#define R_PARISC_LTOFF_FPTR16DF 127 /* 16 bits LT-rel. function ptr. */ ++#define R_PARISC_LORESERVE 128 ++#define R_PARISC_COPY 128 /* Copy relocation. */ ++#define R_PARISC_IPLT 129 /* Dynamic reloc, imported PLT */ ++#define R_PARISC_EPLT 130 /* Dynamic reloc, exported PLT */ ++#define R_PARISC_TPREL32 153 /* 32 bits TP-rel. address. */ ++#define R_PARISC_TPREL21L 154 /* TP-rel. address, left 21 bits. */ ++#define R_PARISC_TPREL14R 158 /* TP-rel. address, right 14 bits. */ ++#define R_PARISC_LTOFF_TP21L 162 /* LT-TP-rel. address, left 21 bits. */ ++#define R_PARISC_LTOFF_TP14R 166 /* LT-TP-rel. address, right 14 bits.*/ ++#define R_PARISC_LTOFF_TP14F 167 /* 14 bits LT-TP-rel. address. */ ++#define R_PARISC_TPREL64 216 /* 64 bits TP-rel. address. */ ++#define R_PARISC_TPREL14WR 219 /* TP-rel. address, right 14 bits. */ ++#define R_PARISC_TPREL14DR 220 /* TP-rel. address, right 14 bits. */ ++#define R_PARISC_TPREL16F 221 /* 16 bits TP-rel. address. */ ++#define R_PARISC_TPREL16WF 222 /* 16 bits TP-rel. address. */ ++#define R_PARISC_TPREL16DF 223 /* 16 bits TP-rel. address. */ ++#define R_PARISC_LTOFF_TP64 224 /* 64 bits LT-TP-rel. address. */ ++#define R_PARISC_LTOFF_TP14WR 227 /* LT-TP-rel. address, right 14 bits.*/ ++#define R_PARISC_LTOFF_TP14DR 228 /* LT-TP-rel. address, right 14 bits.*/ ++#define R_PARISC_LTOFF_TP16F 229 /* 16 bits LT-TP-rel. address. */ ++#define R_PARISC_LTOFF_TP16WF 230 /* 16 bits LT-TP-rel. address. */ ++#define R_PARISC_LTOFF_TP16DF 231 /* 16 bits LT-TP-rel. address. */ ++#define R_PARISC_GNU_VTENTRY 232 ++#define R_PARISC_GNU_VTINHERIT 233 ++#define R_PARISC_TLS_GD21L 234 /* GD 21-bit left. */ ++#define R_PARISC_TLS_GD14R 235 /* GD 14-bit right. */ ++#define R_PARISC_TLS_GDCALL 236 /* GD call to __t_g_a. */ ++#define R_PARISC_TLS_LDM21L 237 /* LD module 21-bit left. */ ++#define R_PARISC_TLS_LDM14R 238 /* LD module 14-bit right. */ ++#define R_PARISC_TLS_LDMCALL 239 /* LD module call to __t_g_a. */ ++#define R_PARISC_TLS_LDO21L 240 /* LD offset 21-bit left. */ ++#define R_PARISC_TLS_LDO14R 241 /* LD offset 14-bit right. */ ++#define R_PARISC_TLS_DTPMOD32 242 /* DTP module 32-bit. */ ++#define R_PARISC_TLS_DTPMOD64 243 /* DTP module 64-bit. */ ++#define R_PARISC_TLS_DTPOFF32 244 /* DTP offset 32-bit. */ ++#define R_PARISC_TLS_DTPOFF64 245 /* DTP offset 32-bit. */ ++#define R_PARISC_TLS_LE21L R_PARISC_TPREL21L ++#define R_PARISC_TLS_LE14R R_PARISC_TPREL14R ++#define R_PARISC_TLS_IE21L R_PARISC_LTOFF_TP21L ++#define R_PARISC_TLS_IE14R R_PARISC_LTOFF_TP14R ++#define R_PARISC_TLS_TPREL32 R_PARISC_TPREL32 ++#define R_PARISC_TLS_TPREL64 R_PARISC_TPREL64 ++#define R_PARISC_HIRESERVE 255 ++ ++/* Legal values for p_type field of Elf32_Phdr/Elf64_Phdr. */ ++ ++#define PT_HP_TLS (PT_LOOS + 0x0) ++#define PT_HP_CORE_NONE (PT_LOOS + 0x1) ++#define PT_HP_CORE_VERSION (PT_LOOS + 0x2) ++#define PT_HP_CORE_KERNEL (PT_LOOS + 0x3) ++#define PT_HP_CORE_COMM (PT_LOOS + 0x4) ++#define PT_HP_CORE_PROC (PT_LOOS + 0x5) ++#define PT_HP_CORE_LOADABLE (PT_LOOS + 0x6) ++#define PT_HP_CORE_STACK (PT_LOOS + 0x7) ++#define PT_HP_CORE_SHM (PT_LOOS + 0x8) ++#define PT_HP_CORE_MMF (PT_LOOS + 0x9) ++#define PT_HP_PARALLEL (PT_LOOS + 0x10) ++#define PT_HP_FASTBIND (PT_LOOS + 0x11) ++#define PT_HP_OPT_ANNOT (PT_LOOS + 0x12) ++#define PT_HP_HSL_ANNOT (PT_LOOS + 0x13) ++#define PT_HP_STACK (PT_LOOS + 0x14) ++ ++#define PT_PARISC_ARCHEXT 0x70000000 ++#define PT_PARISC_UNWIND 0x70000001 ++ ++/* Legal values for p_flags field of Elf32_Phdr/Elf64_Phdr. */ ++ ++#define PF_PARISC_SBP 0x08000000 ++ ++#define PF_HP_PAGE_SIZE 0x00100000 ++#define PF_HP_FAR_SHARED 0x00200000 ++#define PF_HP_NEAR_SHARED 0x00400000 ++#define PF_HP_CODE 0x01000000 ++#define PF_HP_MODIFY 0x02000000 ++#define PF_HP_LAZYSWAP 0x04000000 ++#define PF_HP_SBP 0x08000000 ++ ++ ++/* Alpha specific definitions. */ ++ ++/* Legal values for e_flags field of Elf64_Ehdr. */ ++ ++#define EF_ALPHA_32BIT 1 /* All addresses must be < 2GB. */ ++#define EF_ALPHA_CANRELAX 2 /* Relocations for relaxing exist. */ ++ ++/* Legal values for sh_type field of Elf64_Shdr. */ ++ ++/* These two are primerily concerned with ECOFF debugging info. */ ++#define SHT_ALPHA_DEBUG 0x70000001 ++#define SHT_ALPHA_REGINFO 0x70000002 ++ ++/* Legal values for sh_flags field of Elf64_Shdr. */ ++ ++#define SHF_ALPHA_GPREL 0x10000000 ++ ++/* Legal values for st_other field of Elf64_Sym. */ ++#define STO_ALPHA_NOPV 0x80 /* No PV required. */ ++#define STO_ALPHA_STD_GPLOAD 0x88 /* PV only used for initial ldgp. */ ++ ++/* Alpha relocs. */ ++ ++#define R_ALPHA_NONE 0 /* No reloc */ ++#define R_ALPHA_REFLONG 1 /* Direct 32 bit */ ++#define R_ALPHA_REFQUAD 2 /* Direct 64 bit */ ++#define R_ALPHA_GPREL32 3 /* GP relative 32 bit */ ++#define R_ALPHA_LITERAL 4 /* GP relative 16 bit w/optimization */ ++#define R_ALPHA_LITUSE 5 /* Optimization hint for LITERAL */ ++#define R_ALPHA_GPDISP 6 /* Add displacement to GP */ ++#define R_ALPHA_BRADDR 7 /* PC+4 relative 23 bit shifted */ ++#define R_ALPHA_HINT 8 /* PC+4 relative 16 bit shifted */ ++#define R_ALPHA_SREL16 9 /* PC relative 16 bit */ ++#define R_ALPHA_SREL32 10 /* PC relative 32 bit */ ++#define R_ALPHA_SREL64 11 /* PC relative 64 bit */ ++#define R_ALPHA_GPRELHIGH 17 /* GP relative 32 bit, high 16 bits */ ++#define R_ALPHA_GPRELLOW 18 /* GP relative 32 bit, low 16 bits */ ++#define R_ALPHA_GPREL16 19 /* GP relative 16 bit */ ++#define R_ALPHA_COPY 24 /* Copy symbol at runtime */ ++#define R_ALPHA_GLOB_DAT 25 /* Create GOT entry */ ++#define R_ALPHA_JMP_SLOT 26 /* Create PLT entry */ ++#define R_ALPHA_RELATIVE 27 /* Adjust by program base */ ++#define R_ALPHA_TLS_GD_HI 28 ++#define R_ALPHA_TLSGD 29 ++#define R_ALPHA_TLS_LDM 30 ++#define R_ALPHA_DTPMOD64 31 ++#define R_ALPHA_GOTDTPREL 32 ++#define R_ALPHA_DTPREL64 33 ++#define R_ALPHA_DTPRELHI 34 ++#define R_ALPHA_DTPRELLO 35 ++#define R_ALPHA_DTPREL16 36 ++#define R_ALPHA_GOTTPREL 37 ++#define R_ALPHA_TPREL64 38 ++#define R_ALPHA_TPRELHI 39 ++#define R_ALPHA_TPRELLO 40 ++#define R_ALPHA_TPREL16 41 ++/* Keep this the last entry. */ ++#define R_ALPHA_NUM 46 ++ ++/* Magic values of the LITUSE relocation addend. */ ++#define LITUSE_ALPHA_ADDR 0 ++#define LITUSE_ALPHA_BASE 1 ++#define LITUSE_ALPHA_BYTOFF 2 ++#define LITUSE_ALPHA_JSR 3 ++#define LITUSE_ALPHA_TLS_GD 4 ++#define LITUSE_ALPHA_TLS_LDM 5 ++ ++/* Legal values for d_tag of Elf64_Dyn. */ ++#define DT_ALPHA_PLTRO (DT_LOPROC + 0) ++#define DT_ALPHA_NUM 1 ++ ++/* PowerPC specific declarations */ ++ ++/* Values for Elf32/64_Ehdr.e_flags. */ ++#define EF_PPC_EMB 0x80000000 /* PowerPC embedded flag */ ++ ++/* Cygnus local bits below */ ++#define EF_PPC_RELOCATABLE 0x00010000 /* PowerPC -mrelocatable flag*/ ++#define EF_PPC_RELOCATABLE_LIB 0x00008000 /* PowerPC -mrelocatable-lib ++ flag */ ++ ++/* PowerPC relocations defined by the ABIs */ ++#define R_PPC_NONE 0 ++#define R_PPC_ADDR32 1 /* 32bit absolute address */ ++#define R_PPC_ADDR24 2 /* 26bit address, 2 bits ignored. */ ++#define R_PPC_ADDR16 3 /* 16bit absolute address */ ++#define R_PPC_ADDR16_LO 4 /* lower 16bit of absolute address */ ++#define R_PPC_ADDR16_HI 5 /* high 16bit of absolute address */ ++#define R_PPC_ADDR16_HA 6 /* adjusted high 16bit */ ++#define R_PPC_ADDR14 7 /* 16bit address, 2 bits ignored */ ++#define R_PPC_ADDR14_BRTAKEN 8 ++#define R_PPC_ADDR14_BRNTAKEN 9 ++#define R_PPC_REL24 10 /* PC relative 26 bit */ ++#define R_PPC_REL14 11 /* PC relative 16 bit */ ++#define R_PPC_REL14_BRTAKEN 12 ++#define R_PPC_REL14_BRNTAKEN 13 ++#define R_PPC_GOT16 14 ++#define R_PPC_GOT16_LO 15 ++#define R_PPC_GOT16_HI 16 ++#define R_PPC_GOT16_HA 17 ++#define R_PPC_PLTREL24 18 ++#define R_PPC_COPY 19 ++#define R_PPC_GLOB_DAT 20 ++#define R_PPC_JMP_SLOT 21 ++#define R_PPC_RELATIVE 22 ++#define R_PPC_LOCAL24PC 23 ++#define R_PPC_UADDR32 24 ++#define R_PPC_UADDR16 25 ++#define R_PPC_REL32 26 ++#define R_PPC_PLT32 27 ++#define R_PPC_PLTREL32 28 ++#define R_PPC_PLT16_LO 29 ++#define R_PPC_PLT16_HI 30 ++#define R_PPC_PLT16_HA 31 ++#define R_PPC_SDAREL16 32 ++#define R_PPC_SECTOFF 33 ++#define R_PPC_SECTOFF_LO 34 ++#define R_PPC_SECTOFF_HI 35 ++#define R_PPC_SECTOFF_HA 36 ++ ++/* PowerPC relocations defined for the TLS access ABI. */ ++#define R_PPC_TLS 67 /* none (sym+add)@tls */ ++#define R_PPC_DTPMOD32 68 /* word32 (sym+add)@dtpmod */ ++#define R_PPC_TPREL16 69 /* half16* (sym+add)@tprel */ ++#define R_PPC_TPREL16_LO 70 /* half16 (sym+add)@tprel@l */ ++#define R_PPC_TPREL16_HI 71 /* half16 (sym+add)@tprel@h */ ++#define R_PPC_TPREL16_HA 72 /* half16 (sym+add)@tprel@ha */ ++#define R_PPC_TPREL32 73 /* word32 (sym+add)@tprel */ ++#define R_PPC_DTPREL16 74 /* half16* (sym+add)@dtprel */ ++#define R_PPC_DTPREL16_LO 75 /* half16 (sym+add)@dtprel@l */ ++#define R_PPC_DTPREL16_HI 76 /* half16 (sym+add)@dtprel@h */ ++#define R_PPC_DTPREL16_HA 77 /* half16 (sym+add)@dtprel@ha */ ++#define R_PPC_DTPREL32 78 /* word32 (sym+add)@dtprel */ ++#define R_PPC_GOT_TLSGD16 79 /* half16* (sym+add)@got@tlsgd */ ++#define R_PPC_GOT_TLSGD16_LO 80 /* half16 (sym+add)@got@tlsgd@l */ ++#define R_PPC_GOT_TLSGD16_HI 81 /* half16 (sym+add)@got@tlsgd@h */ ++#define R_PPC_GOT_TLSGD16_HA 82 /* half16 (sym+add)@got@tlsgd@ha */ ++#define R_PPC_GOT_TLSLD16 83 /* half16* (sym+add)@got@tlsld */ ++#define R_PPC_GOT_TLSLD16_LO 84 /* half16 (sym+add)@got@tlsld@l */ ++#define R_PPC_GOT_TLSLD16_HI 85 /* half16 (sym+add)@got@tlsld@h */ ++#define R_PPC_GOT_TLSLD16_HA 86 /* half16 (sym+add)@got@tlsld@ha */ ++#define R_PPC_GOT_TPREL16 87 /* half16* (sym+add)@got@tprel */ ++#define R_PPC_GOT_TPREL16_LO 88 /* half16 (sym+add)@got@tprel@l */ ++#define R_PPC_GOT_TPREL16_HI 89 /* half16 (sym+add)@got@tprel@h */ ++#define R_PPC_GOT_TPREL16_HA 90 /* half16 (sym+add)@got@tprel@ha */ ++#define R_PPC_GOT_DTPREL16 91 /* half16* (sym+add)@got@dtprel */ ++#define R_PPC_GOT_DTPREL16_LO 92 /* half16* (sym+add)@got@dtprel@l */ ++#define R_PPC_GOT_DTPREL16_HI 93 /* half16* (sym+add)@got@dtprel@h */ ++#define R_PPC_GOT_DTPREL16_HA 94 /* half16* (sym+add)@got@dtprel@ha */ ++ ++/* The remaining relocs are from the Embedded ELF ABI, and are not ++ in the SVR4 ELF ABI. */ ++#define R_PPC_EMB_NADDR32 101 ++#define R_PPC_EMB_NADDR16 102 ++#define R_PPC_EMB_NADDR16_LO 103 ++#define R_PPC_EMB_NADDR16_HI 104 ++#define R_PPC_EMB_NADDR16_HA 105 ++#define R_PPC_EMB_SDAI16 106 ++#define R_PPC_EMB_SDA2I16 107 ++#define R_PPC_EMB_SDA2REL 108 ++#define R_PPC_EMB_SDA21 109 /* 16 bit offset in SDA */ ++#define R_PPC_EMB_MRKREF 110 ++#define R_PPC_EMB_RELSEC16 111 ++#define R_PPC_EMB_RELST_LO 112 ++#define R_PPC_EMB_RELST_HI 113 ++#define R_PPC_EMB_RELST_HA 114 ++#define R_PPC_EMB_BIT_FLD 115 ++#define R_PPC_EMB_RELSDA 116 /* 16 bit relative offset in SDA */ ++ ++/* Diab tool relocations. */ ++#define R_PPC_DIAB_SDA21_LO 180 /* like EMB_SDA21, but lower 16 bit */ ++#define R_PPC_DIAB_SDA21_HI 181 /* like EMB_SDA21, but high 16 bit */ ++#define R_PPC_DIAB_SDA21_HA 182 /* like EMB_SDA21, adjusted high 16 */ ++#define R_PPC_DIAB_RELSDA_LO 183 /* like EMB_RELSDA, but lower 16 bit */ ++#define R_PPC_DIAB_RELSDA_HI 184 /* like EMB_RELSDA, but high 16 bit */ ++#define R_PPC_DIAB_RELSDA_HA 185 /* like EMB_RELSDA, adjusted high 16 */ ++ ++/* GNU extension to support local ifunc. */ ++#define R_PPC_IRELATIVE 248 ++ ++/* GNU relocs used in PIC code sequences. */ ++#define R_PPC_REL16 249 /* half16 (sym+add-.) */ ++#define R_PPC_REL16_LO 250 /* half16 (sym+add-.)@l */ ++#define R_PPC_REL16_HI 251 /* half16 (sym+add-.)@h */ ++#define R_PPC_REL16_HA 252 /* half16 (sym+add-.)@ha */ ++ ++/* This is a phony reloc to handle any old fashioned TOC16 references ++ that may still be in object files. */ ++#define R_PPC_TOC16 255 ++ ++/* PowerPC specific values for the Dyn d_tag field. */ ++#define DT_PPC_GOT (DT_LOPROC + 0) ++#define DT_PPC_NUM 1 ++ ++/* PowerPC64 relocations defined by the ABIs */ ++#define R_PPC64_NONE R_PPC_NONE ++#define R_PPC64_ADDR32 R_PPC_ADDR32 /* 32bit absolute address */ ++#define R_PPC64_ADDR24 R_PPC_ADDR24 /* 26bit address, word aligned */ ++#define R_PPC64_ADDR16 R_PPC_ADDR16 /* 16bit absolute address */ ++#define R_PPC64_ADDR16_LO R_PPC_ADDR16_LO /* lower 16bits of address */ ++#define R_PPC64_ADDR16_HI R_PPC_ADDR16_HI /* high 16bits of address. */ ++#define R_PPC64_ADDR16_HA R_PPC_ADDR16_HA /* adjusted high 16bits. */ ++#define R_PPC64_ADDR14 R_PPC_ADDR14 /* 16bit address, word aligned */ ++#define R_PPC64_ADDR14_BRTAKEN R_PPC_ADDR14_BRTAKEN ++#define R_PPC64_ADDR14_BRNTAKEN R_PPC_ADDR14_BRNTAKEN ++#define R_PPC64_REL24 R_PPC_REL24 /* PC-rel. 26 bit, word aligned */ ++#define R_PPC64_REL14 R_PPC_REL14 /* PC relative 16 bit */ ++#define R_PPC64_REL14_BRTAKEN R_PPC_REL14_BRTAKEN ++#define R_PPC64_REL14_BRNTAKEN R_PPC_REL14_BRNTAKEN ++#define R_PPC64_GOT16 R_PPC_GOT16 ++#define R_PPC64_GOT16_LO R_PPC_GOT16_LO ++#define R_PPC64_GOT16_HI R_PPC_GOT16_HI ++#define R_PPC64_GOT16_HA R_PPC_GOT16_HA ++ ++#define R_PPC64_COPY R_PPC_COPY ++#define R_PPC64_GLOB_DAT R_PPC_GLOB_DAT ++#define R_PPC64_JMP_SLOT R_PPC_JMP_SLOT ++#define R_PPC64_RELATIVE R_PPC_RELATIVE ++ ++#define R_PPC64_UADDR32 R_PPC_UADDR32 ++#define R_PPC64_UADDR16 R_PPC_UADDR16 ++#define R_PPC64_REL32 R_PPC_REL32 ++#define R_PPC64_PLT32 R_PPC_PLT32 ++#define R_PPC64_PLTREL32 R_PPC_PLTREL32 ++#define R_PPC64_PLT16_LO R_PPC_PLT16_LO ++#define R_PPC64_PLT16_HI R_PPC_PLT16_HI ++#define R_PPC64_PLT16_HA R_PPC_PLT16_HA ++ ++#define R_PPC64_SECTOFF R_PPC_SECTOFF ++#define R_PPC64_SECTOFF_LO R_PPC_SECTOFF_LO ++#define R_PPC64_SECTOFF_HI R_PPC_SECTOFF_HI ++#define R_PPC64_SECTOFF_HA R_PPC_SECTOFF_HA ++#define R_PPC64_ADDR30 37 /* word30 (S + A - P) >> 2 */ ++#define R_PPC64_ADDR64 38 /* doubleword64 S + A */ ++#define R_PPC64_ADDR16_HIGHER 39 /* half16 #higher(S + A) */ ++#define R_PPC64_ADDR16_HIGHERA 40 /* half16 #highera(S + A) */ ++#define R_PPC64_ADDR16_HIGHEST 41 /* half16 #highest(S + A) */ ++#define R_PPC64_ADDR16_HIGHESTA 42 /* half16 #highesta(S + A) */ ++#define R_PPC64_UADDR64 43 /* doubleword64 S + A */ ++#define R_PPC64_REL64 44 /* doubleword64 S + A - P */ ++#define R_PPC64_PLT64 45 /* doubleword64 L + A */ ++#define R_PPC64_PLTREL64 46 /* doubleword64 L + A - P */ ++#define R_PPC64_TOC16 47 /* half16* S + A - .TOC */ ++#define R_PPC64_TOC16_LO 48 /* half16 #lo(S + A - .TOC.) */ ++#define R_PPC64_TOC16_HI 49 /* half16 #hi(S + A - .TOC.) */ ++#define R_PPC64_TOC16_HA 50 /* half16 #ha(S + A - .TOC.) */ ++#define R_PPC64_TOC 51 /* doubleword64 .TOC */ ++#define R_PPC64_PLTGOT16 52 /* half16* M + A */ ++#define R_PPC64_PLTGOT16_LO 53 /* half16 #lo(M + A) */ ++#define R_PPC64_PLTGOT16_HI 54 /* half16 #hi(M + A) */ ++#define R_PPC64_PLTGOT16_HA 55 /* half16 #ha(M + A) */ ++ ++#define R_PPC64_ADDR16_DS 56 /* half16ds* (S + A) >> 2 */ ++#define R_PPC64_ADDR16_LO_DS 57 /* half16ds #lo(S + A) >> 2 */ ++#define R_PPC64_GOT16_DS 58 /* half16ds* (G + A) >> 2 */ ++#define R_PPC64_GOT16_LO_DS 59 /* half16ds #lo(G + A) >> 2 */ ++#define R_PPC64_PLT16_LO_DS 60 /* half16ds #lo(L + A) >> 2 */ ++#define R_PPC64_SECTOFF_DS 61 /* half16ds* (R + A) >> 2 */ ++#define R_PPC64_SECTOFF_LO_DS 62 /* half16ds #lo(R + A) >> 2 */ ++#define R_PPC64_TOC16_DS 63 /* half16ds* (S + A - .TOC.) >> 2 */ ++#define R_PPC64_TOC16_LO_DS 64 /* half16ds #lo(S + A - .TOC.) >> 2 */ ++#define R_PPC64_PLTGOT16_DS 65 /* half16ds* (M + A) >> 2 */ ++#define R_PPC64_PLTGOT16_LO_DS 66 /* half16ds #lo(M + A) >> 2 */ ++ ++/* PowerPC64 relocations defined for the TLS access ABI. */ ++#define R_PPC64_TLS 67 /* none (sym+add)@tls */ ++#define R_PPC64_DTPMOD64 68 /* doubleword64 (sym+add)@dtpmod */ ++#define R_PPC64_TPREL16 69 /* half16* (sym+add)@tprel */ ++#define R_PPC64_TPREL16_LO 70 /* half16 (sym+add)@tprel@l */ ++#define R_PPC64_TPREL16_HI 71 /* half16 (sym+add)@tprel@h */ ++#define R_PPC64_TPREL16_HA 72 /* half16 (sym+add)@tprel@ha */ ++#define R_PPC64_TPREL64 73 /* doubleword64 (sym+add)@tprel */ ++#define R_PPC64_DTPREL16 74 /* half16* (sym+add)@dtprel */ ++#define R_PPC64_DTPREL16_LO 75 /* half16 (sym+add)@dtprel@l */ ++#define R_PPC64_DTPREL16_HI 76 /* half16 (sym+add)@dtprel@h */ ++#define R_PPC64_DTPREL16_HA 77 /* half16 (sym+add)@dtprel@ha */ ++#define R_PPC64_DTPREL64 78 /* doubleword64 (sym+add)@dtprel */ ++#define R_PPC64_GOT_TLSGD16 79 /* half16* (sym+add)@got@tlsgd */ ++#define R_PPC64_GOT_TLSGD16_LO 80 /* half16 (sym+add)@got@tlsgd@l */ ++#define R_PPC64_GOT_TLSGD16_HI 81 /* half16 (sym+add)@got@tlsgd@h */ ++#define R_PPC64_GOT_TLSGD16_HA 82 /* half16 (sym+add)@got@tlsgd@ha */ ++#define R_PPC64_GOT_TLSLD16 83 /* half16* (sym+add)@got@tlsld */ ++#define R_PPC64_GOT_TLSLD16_LO 84 /* half16 (sym+add)@got@tlsld@l */ ++#define R_PPC64_GOT_TLSLD16_HI 85 /* half16 (sym+add)@got@tlsld@h */ ++#define R_PPC64_GOT_TLSLD16_HA 86 /* half16 (sym+add)@got@tlsld@ha */ ++#define R_PPC64_GOT_TPREL16_DS 87 /* half16ds* (sym+add)@got@tprel */ ++#define R_PPC64_GOT_TPREL16_LO_DS 88 /* half16ds (sym+add)@got@tprel@l */ ++#define R_PPC64_GOT_TPREL16_HI 89 /* half16 (sym+add)@got@tprel@h */ ++#define R_PPC64_GOT_TPREL16_HA 90 /* half16 (sym+add)@got@tprel@ha */ ++#define R_PPC64_GOT_DTPREL16_DS 91 /* half16ds* (sym+add)@got@dtprel */ ++#define R_PPC64_GOT_DTPREL16_LO_DS 92 /* half16ds (sym+add)@got@dtprel@l */ ++#define R_PPC64_GOT_DTPREL16_HI 93 /* half16 (sym+add)@got@dtprel@h */ ++#define R_PPC64_GOT_DTPREL16_HA 94 /* half16 (sym+add)@got@dtprel@ha */ ++#define R_PPC64_TPREL16_DS 95 /* half16ds* (sym+add)@tprel */ ++#define R_PPC64_TPREL16_LO_DS 96 /* half16ds (sym+add)@tprel@l */ ++#define R_PPC64_TPREL16_HIGHER 97 /* half16 (sym+add)@tprel@higher */ ++#define R_PPC64_TPREL16_HIGHERA 98 /* half16 (sym+add)@tprel@highera */ ++#define R_PPC64_TPREL16_HIGHEST 99 /* half16 (sym+add)@tprel@highest */ ++#define R_PPC64_TPREL16_HIGHESTA 100 /* half16 (sym+add)@tprel@highesta */ ++#define R_PPC64_DTPREL16_DS 101 /* half16ds* (sym+add)@dtprel */ ++#define R_PPC64_DTPREL16_LO_DS 102 /* half16ds (sym+add)@dtprel@l */ ++#define R_PPC64_DTPREL16_HIGHER 103 /* half16 (sym+add)@dtprel@higher */ ++#define R_PPC64_DTPREL16_HIGHERA 104 /* half16 (sym+add)@dtprel@highera */ ++#define R_PPC64_DTPREL16_HIGHEST 105 /* half16 (sym+add)@dtprel@highest */ ++#define R_PPC64_DTPREL16_HIGHESTA 106 /* half16 (sym+add)@dtprel@highesta */ ++ ++/* GNU extension to support local ifunc. */ ++#define R_PPC64_JMP_IREL 247 ++#define R_PPC64_IRELATIVE 248 ++#define R_PPC64_REL16 249 /* half16 (sym+add-.) */ ++#define R_PPC64_REL16_LO 250 /* half16 (sym+add-.)@l */ ++#define R_PPC64_REL16_HI 251 /* half16 (sym+add-.)@h */ ++#define R_PPC64_REL16_HA 252 /* half16 (sym+add-.)@ha */ ++ ++/* PowerPC64 specific values for the Dyn d_tag field. */ ++#define DT_PPC64_GLINK (DT_LOPROC + 0) ++#define DT_PPC64_OPD (DT_LOPROC + 1) ++#define DT_PPC64_OPDSZ (DT_LOPROC + 2) ++#define DT_PPC64_NUM 3 ++ ++ ++/* ARM specific declarations */ ++ ++/* Processor specific flags for the ELF header e_flags field. */ ++#define EF_ARM_RELEXEC 0x01 ++#define EF_ARM_HASENTRY 0x02 ++#define EF_ARM_INTERWORK 0x04 ++#define EF_ARM_APCS_26 0x08 ++#define EF_ARM_APCS_FLOAT 0x10 ++#define EF_ARM_PIC 0x20 ++#define EF_ARM_ALIGN8 0x40 /* 8-bit structure alignment is in use */ ++#define EF_ARM_NEW_ABI 0x80 ++#define EF_ARM_OLD_ABI 0x100 ++#define EF_ARM_SOFT_FLOAT 0x200 ++#define EF_ARM_VFP_FLOAT 0x400 ++#define EF_ARM_MAVERICK_FLOAT 0x800 ++ ++ ++/* Other constants defined in the ARM ELF spec. version B-01. */ ++/* NB. These conflict with values defined above. */ ++#define EF_ARM_SYMSARESORTED 0x04 ++#define EF_ARM_DYNSYMSUSESEGIDX 0x08 ++#define EF_ARM_MAPSYMSFIRST 0x10 ++#define EF_ARM_EABIMASK 0XFF000000 ++ ++/* Constants defined in AAELF. */ ++#define EF_ARM_BE8 0x00800000 ++#define EF_ARM_LE8 0x00400000 ++ ++#define EF_ARM_EABI_VERSION(flags) ((flags) & EF_ARM_EABIMASK) ++#define EF_ARM_EABI_UNKNOWN 0x00000000 ++#define EF_ARM_EABI_VER1 0x01000000 ++#define EF_ARM_EABI_VER2 0x02000000 ++#define EF_ARM_EABI_VER3 0x03000000 ++#define EF_ARM_EABI_VER4 0x04000000 ++#define EF_ARM_EABI_VER5 0x05000000 ++ ++/* Additional symbol types for Thumb. */ ++#define STT_ARM_TFUNC STT_LOPROC /* A Thumb function. */ ++#define STT_ARM_16BIT STT_HIPROC /* A Thumb label. */ ++ ++/* ARM-specific values for sh_flags */ ++#define SHF_ARM_ENTRYSECT 0x10000000 /* Section contains an entry point */ ++#define SHF_ARM_COMDEF 0x80000000 /* Section may be multiply defined ++ in the input to a link step. */ ++ ++/* ARM-specific program header flags */ ++#define PF_ARM_SB 0x10000000 /* Segment contains the location ++ addressed by the static base. */ ++#define PF_ARM_PI 0x20000000 /* Position-independent segment. */ ++#define PF_ARM_ABS 0x40000000 /* Absolute segment. */ ++ ++/* Processor specific values for the Phdr p_type field. */ ++#define PT_ARM_EXIDX (PT_LOPROC + 1) /* ARM unwind segment. */ ++ ++/* Processor specific values for the Shdr sh_type field. */ ++#define SHT_ARM_EXIDX (SHT_LOPROC + 1) /* ARM unwind section. */ ++#define SHT_ARM_PREEMPTMAP (SHT_LOPROC + 2) /* Preemption details. */ ++#define SHT_ARM_ATTRIBUTES (SHT_LOPROC + 3) /* ARM attributes section. */ ++ ++ ++/* ARM relocs. */ ++ ++#define R_ARM_NONE 0 /* No reloc */ ++#define R_ARM_PC24 1 /* PC relative 26 bit branch */ ++#define R_ARM_ABS32 2 /* Direct 32 bit */ ++#define R_ARM_REL32 3 /* PC relative 32 bit */ ++#define R_ARM_PC13 4 ++#define R_ARM_ABS16 5 /* Direct 16 bit */ ++#define R_ARM_ABS12 6 /* Direct 12 bit */ ++#define R_ARM_THM_ABS5 7 ++#define R_ARM_ABS8 8 /* Direct 8 bit */ ++#define R_ARM_SBREL32 9 ++#define R_ARM_THM_PC22 10 ++#define R_ARM_THM_PC8 11 ++#define R_ARM_AMP_VCALL9 12 ++#define R_ARM_SWI24 13 /* Obsolete static relocation. */ ++#define R_ARM_TLS_DESC 13 /* Dynamic relocation. */ ++#define R_ARM_THM_SWI8 14 ++#define R_ARM_XPC25 15 ++#define R_ARM_THM_XPC22 16 ++#define R_ARM_TLS_DTPMOD32 17 /* ID of module containing symbol */ ++#define R_ARM_TLS_DTPOFF32 18 /* Offset in TLS block */ ++#define R_ARM_TLS_TPOFF32 19 /* Offset in static TLS block */ ++#define R_ARM_COPY 20 /* Copy symbol at runtime */ ++#define R_ARM_GLOB_DAT 21 /* Create GOT entry */ ++#define R_ARM_JUMP_SLOT 22 /* Create PLT entry */ ++#define R_ARM_RELATIVE 23 /* Adjust by program base */ ++#define R_ARM_GOTOFF 24 /* 32 bit offset to GOT */ ++#define R_ARM_GOTPC 25 /* 32 bit PC relative offset to GOT */ ++#define R_ARM_GOT32 26 /* 32 bit GOT entry */ ++#define R_ARM_PLT32 27 /* 32 bit PLT address */ ++#define R_ARM_ALU_PCREL_7_0 32 ++#define R_ARM_ALU_PCREL_15_8 33 ++#define R_ARM_ALU_PCREL_23_15 34 ++#define R_ARM_LDR_SBREL_11_0 35 ++#define R_ARM_ALU_SBREL_19_12 36 ++#define R_ARM_ALU_SBREL_27_20 37 ++#define R_ARM_TLS_GOTDESC 90 ++#define R_ARM_TLS_CALL 91 ++#define R_ARM_TLS_DESCSEQ 92 ++#define R_ARM_THM_TLS_CALL 93 ++#define R_ARM_GNU_VTENTRY 100 ++#define R_ARM_GNU_VTINHERIT 101 ++#define R_ARM_THM_PC11 102 /* thumb unconditional branch */ ++#define R_ARM_THM_PC9 103 /* thumb conditional branch */ ++#define R_ARM_TLS_GD32 104 /* PC-rel 32 bit for global dynamic ++ thread local data */ ++#define R_ARM_TLS_LDM32 105 /* PC-rel 32 bit for local dynamic ++ thread local data */ ++#define R_ARM_TLS_LDO32 106 /* 32 bit offset relative to TLS ++ block */ ++#define R_ARM_TLS_IE32 107 /* PC-rel 32 bit for GOT entry of ++ static TLS block offset */ ++#define R_ARM_TLS_LE32 108 /* 32 bit offset relative to static ++ TLS block */ ++#define R_ARM_THM_TLS_DESCSEQ 129 ++#define R_ARM_IRELATIVE 160 ++#define R_ARM_RXPC25 249 ++#define R_ARM_RSBREL32 250 ++#define R_ARM_THM_RPC22 251 ++#define R_ARM_RREL32 252 ++#define R_ARM_RABS22 253 ++#define R_ARM_RPC24 254 ++#define R_ARM_RBASE 255 ++/* Keep this the last entry. */ ++#define R_ARM_NUM 256 ++ ++/* IA-64 specific declarations. */ ++ ++/* Processor specific flags for the Ehdr e_flags field. */ ++#define EF_IA_64_MASKOS 0x0000000f /* os-specific flags */ ++#define EF_IA_64_ABI64 0x00000010 /* 64-bit ABI */ ++#define EF_IA_64_ARCH 0xff000000 /* arch. version mask */ ++ ++/* Processor specific values for the Phdr p_type field. */ ++#define PT_IA_64_ARCHEXT (PT_LOPROC + 0) /* arch extension bits */ ++#define PT_IA_64_UNWIND (PT_LOPROC + 1) /* ia64 unwind bits */ ++#define PT_IA_64_HP_OPT_ANOT (PT_LOOS + 0x12) ++#define PT_IA_64_HP_HSL_ANOT (PT_LOOS + 0x13) ++#define PT_IA_64_HP_STACK (PT_LOOS + 0x14) ++ ++/* Processor specific flags for the Phdr p_flags field. */ ++#define PF_IA_64_NORECOV 0x80000000 /* spec insns w/o recovery */ ++ ++/* Processor specific values for the Shdr sh_type field. */ ++#define SHT_IA_64_EXT (SHT_LOPROC + 0) /* extension bits */ ++#define SHT_IA_64_UNWIND (SHT_LOPROC + 1) /* unwind bits */ ++ ++/* Processor specific flags for the Shdr sh_flags field. */ ++#define SHF_IA_64_SHORT 0x10000000 /* section near gp */ ++#define SHF_IA_64_NORECOV 0x20000000 /* spec insns w/o recovery */ ++ ++/* Processor specific values for the Dyn d_tag field. */ ++#define DT_IA_64_PLT_RESERVE (DT_LOPROC + 0) ++#define DT_IA_64_NUM 1 ++ ++/* IA-64 relocations. */ ++#define R_IA64_NONE 0x00 /* none */ ++#define R_IA64_IMM14 0x21 /* symbol + addend, add imm14 */ ++#define R_IA64_IMM22 0x22 /* symbol + addend, add imm22 */ ++#define R_IA64_IMM64 0x23 /* symbol + addend, mov imm64 */ ++#define R_IA64_DIR32MSB 0x24 /* symbol + addend, data4 MSB */ ++#define R_IA64_DIR32LSB 0x25 /* symbol + addend, data4 LSB */ ++#define R_IA64_DIR64MSB 0x26 /* symbol + addend, data8 MSB */ ++#define R_IA64_DIR64LSB 0x27 /* symbol + addend, data8 LSB */ ++#define R_IA64_GPREL22 0x2a /* @gprel(sym + add), add imm22 */ ++#define R_IA64_GPREL64I 0x2b /* @gprel(sym + add), mov imm64 */ ++#define R_IA64_GPREL32MSB 0x2c /* @gprel(sym + add), data4 MSB */ ++#define R_IA64_GPREL32LSB 0x2d /* @gprel(sym + add), data4 LSB */ ++#define R_IA64_GPREL64MSB 0x2e /* @gprel(sym + add), data8 MSB */ ++#define R_IA64_GPREL64LSB 0x2f /* @gprel(sym + add), data8 LSB */ ++#define R_IA64_LTOFF22 0x32 /* @ltoff(sym + add), add imm22 */ ++#define R_IA64_LTOFF64I 0x33 /* @ltoff(sym + add), mov imm64 */ ++#define R_IA64_PLTOFF22 0x3a /* @pltoff(sym + add), add imm22 */ ++#define R_IA64_PLTOFF64I 0x3b /* @pltoff(sym + add), mov imm64 */ ++#define R_IA64_PLTOFF64MSB 0x3e /* @pltoff(sym + add), data8 MSB */ ++#define R_IA64_PLTOFF64LSB 0x3f /* @pltoff(sym + add), data8 LSB */ ++#define R_IA64_FPTR64I 0x43 /* @fptr(sym + add), mov imm64 */ ++#define R_IA64_FPTR32MSB 0x44 /* @fptr(sym + add), data4 MSB */ ++#define R_IA64_FPTR32LSB 0x45 /* @fptr(sym + add), data4 LSB */ ++#define R_IA64_FPTR64MSB 0x46 /* @fptr(sym + add), data8 MSB */ ++#define R_IA64_FPTR64LSB 0x47 /* @fptr(sym + add), data8 LSB */ ++#define R_IA64_PCREL60B 0x48 /* @pcrel(sym + add), brl */ ++#define R_IA64_PCREL21B 0x49 /* @pcrel(sym + add), ptb, call */ ++#define R_IA64_PCREL21M 0x4a /* @pcrel(sym + add), chk.s */ ++#define R_IA64_PCREL21F 0x4b /* @pcrel(sym + add), fchkf */ ++#define R_IA64_PCREL32MSB 0x4c /* @pcrel(sym + add), data4 MSB */ ++#define R_IA64_PCREL32LSB 0x4d /* @pcrel(sym + add), data4 LSB */ ++#define R_IA64_PCREL64MSB 0x4e /* @pcrel(sym + add), data8 MSB */ ++#define R_IA64_PCREL64LSB 0x4f /* @pcrel(sym + add), data8 LSB */ ++#define R_IA64_LTOFF_FPTR22 0x52 /* @ltoff(@fptr(s+a)), imm22 */ ++#define R_IA64_LTOFF_FPTR64I 0x53 /* @ltoff(@fptr(s+a)), imm64 */ ++#define R_IA64_LTOFF_FPTR32MSB 0x54 /* @ltoff(@fptr(s+a)), data4 MSB */ ++#define R_IA64_LTOFF_FPTR32LSB 0x55 /* @ltoff(@fptr(s+a)), data4 LSB */ ++#define R_IA64_LTOFF_FPTR64MSB 0x56 /* @ltoff(@fptr(s+a)), data8 MSB */ ++#define R_IA64_LTOFF_FPTR64LSB 0x57 /* @ltoff(@fptr(s+a)), data8 LSB */ ++#define R_IA64_SEGREL32MSB 0x5c /* @segrel(sym + add), data4 MSB */ ++#define R_IA64_SEGREL32LSB 0x5d /* @segrel(sym + add), data4 LSB */ ++#define R_IA64_SEGREL64MSB 0x5e /* @segrel(sym + add), data8 MSB */ ++#define R_IA64_SEGREL64LSB 0x5f /* @segrel(sym + add), data8 LSB */ ++#define R_IA64_SECREL32MSB 0x64 /* @secrel(sym + add), data4 MSB */ ++#define R_IA64_SECREL32LSB 0x65 /* @secrel(sym + add), data4 LSB */ ++#define R_IA64_SECREL64MSB 0x66 /* @secrel(sym + add), data8 MSB */ ++#define R_IA64_SECREL64LSB 0x67 /* @secrel(sym + add), data8 LSB */ ++#define R_IA64_REL32MSB 0x6c /* data 4 + REL */ ++#define R_IA64_REL32LSB 0x6d /* data 4 + REL */ ++#define R_IA64_REL64MSB 0x6e /* data 8 + REL */ ++#define R_IA64_REL64LSB 0x6f /* data 8 + REL */ ++#define R_IA64_LTV32MSB 0x74 /* symbol + addend, data4 MSB */ ++#define R_IA64_LTV32LSB 0x75 /* symbol + addend, data4 LSB */ ++#define R_IA64_LTV64MSB 0x76 /* symbol + addend, data8 MSB */ ++#define R_IA64_LTV64LSB 0x77 /* symbol + addend, data8 LSB */ ++#define R_IA64_PCREL21BI 0x79 /* @pcrel(sym + add), 21bit inst */ ++#define R_IA64_PCREL22 0x7a /* @pcrel(sym + add), 22bit inst */ ++#define R_IA64_PCREL64I 0x7b /* @pcrel(sym + add), 64bit inst */ ++#define R_IA64_IPLTMSB 0x80 /* dynamic reloc, imported PLT, MSB */ ++#define R_IA64_IPLTLSB 0x81 /* dynamic reloc, imported PLT, LSB */ ++#define R_IA64_COPY 0x84 /* copy relocation */ ++#define R_IA64_SUB 0x85 /* Addend and symbol difference */ ++#define R_IA64_LTOFF22X 0x86 /* LTOFF22, relaxable. */ ++#define R_IA64_LDXMOV 0x87 /* Use of LTOFF22X. */ ++#define R_IA64_TPREL14 0x91 /* @tprel(sym + add), imm14 */ ++#define R_IA64_TPREL22 0x92 /* @tprel(sym + add), imm22 */ ++#define R_IA64_TPREL64I 0x93 /* @tprel(sym + add), imm64 */ ++#define R_IA64_TPREL64MSB 0x96 /* @tprel(sym + add), data8 MSB */ ++#define R_IA64_TPREL64LSB 0x97 /* @tprel(sym + add), data8 LSB */ ++#define R_IA64_LTOFF_TPREL22 0x9a /* @ltoff(@tprel(s+a)), imm2 */ ++#define R_IA64_DTPMOD64MSB 0xa6 /* @dtpmod(sym + add), data8 MSB */ ++#define R_IA64_DTPMOD64LSB 0xa7 /* @dtpmod(sym + add), data8 LSB */ ++#define R_IA64_LTOFF_DTPMOD22 0xaa /* @ltoff(@dtpmod(sym + add)), imm22 */ ++#define R_IA64_DTPREL14 0xb1 /* @dtprel(sym + add), imm14 */ ++#define R_IA64_DTPREL22 0xb2 /* @dtprel(sym + add), imm22 */ ++#define R_IA64_DTPREL64I 0xb3 /* @dtprel(sym + add), imm64 */ ++#define R_IA64_DTPREL32MSB 0xb4 /* @dtprel(sym + add), data4 MSB */ ++#define R_IA64_DTPREL32LSB 0xb5 /* @dtprel(sym + add), data4 LSB */ ++#define R_IA64_DTPREL64MSB 0xb6 /* @dtprel(sym + add), data8 MSB */ ++#define R_IA64_DTPREL64LSB 0xb7 /* @dtprel(sym + add), data8 LSB */ ++#define R_IA64_LTOFF_DTPREL22 0xba /* @ltoff(@dtprel(s+a)), imm22 */ ++ ++/* SH specific declarations */ ++ ++/* Processor specific flags for the ELF header e_flags field. */ ++#define EF_SH_MACH_MASK 0x1f ++#define EF_SH_UNKNOWN 0x0 ++#define EF_SH1 0x1 ++#define EF_SH2 0x2 ++#define EF_SH3 0x3 ++#define EF_SH_DSP 0x4 ++#define EF_SH3_DSP 0x5 ++#define EF_SH4AL_DSP 0x6 ++#define EF_SH3E 0x8 ++#define EF_SH4 0x9 ++#define EF_SH2E 0xb ++#define EF_SH4A 0xc ++#define EF_SH2A 0xd ++#define EF_SH4_NOFPU 0x10 ++#define EF_SH4A_NOFPU 0x11 ++#define EF_SH4_NOMMU_NOFPU 0x12 ++#define EF_SH2A_NOFPU 0x13 ++#define EF_SH3_NOMMU 0x14 ++#define EF_SH2A_SH4_NOFPU 0x15 ++#define EF_SH2A_SH3_NOFPU 0x16 ++#define EF_SH2A_SH4 0x17 ++#define EF_SH2A_SH3E 0x18 ++ ++/* SH relocs. */ ++#define R_SH_NONE 0 ++#define R_SH_DIR32 1 ++#define R_SH_REL32 2 ++#define R_SH_DIR8WPN 3 ++#define R_SH_IND12W 4 ++#define R_SH_DIR8WPL 5 ++#define R_SH_DIR8WPZ 6 ++#define R_SH_DIR8BP 7 ++#define R_SH_DIR8W 8 ++#define R_SH_DIR8L 9 ++#define R_SH_SWITCH16 25 ++#define R_SH_SWITCH32 26 ++#define R_SH_USES 27 ++#define R_SH_COUNT 28 ++#define R_SH_ALIGN 29 ++#define R_SH_CODE 30 ++#define R_SH_DATA 31 ++#define R_SH_LABEL 32 ++#define R_SH_SWITCH8 33 ++#define R_SH_GNU_VTINHERIT 34 ++#define R_SH_GNU_VTENTRY 35 ++#define R_SH_TLS_GD_32 144 ++#define R_SH_TLS_LD_32 145 ++#define R_SH_TLS_LDO_32 146 ++#define R_SH_TLS_IE_32 147 ++#define R_SH_TLS_LE_32 148 ++#define R_SH_TLS_DTPMOD32 149 ++#define R_SH_TLS_DTPOFF32 150 ++#define R_SH_TLS_TPOFF32 151 ++#define R_SH_GOT32 160 ++#define R_SH_PLT32 161 ++#define R_SH_COPY 162 ++#define R_SH_GLOB_DAT 163 ++#define R_SH_JMP_SLOT 164 ++#define R_SH_RELATIVE 165 ++#define R_SH_GOTOFF 166 ++#define R_SH_GOTPC 167 ++/* Keep this the last entry. */ ++#define R_SH_NUM 256 ++ ++/* S/390 specific definitions. */ ++ ++/* Valid values for the e_flags field. */ ++ ++#define EF_S390_HIGH_GPRS 0x00000001 /* High GPRs kernel facility needed. */ ++ ++/* Additional s390 relocs */ ++ ++#define R_390_NONE 0 /* No reloc. */ ++#define R_390_8 1 /* Direct 8 bit. */ ++#define R_390_12 2 /* Direct 12 bit. */ ++#define R_390_16 3 /* Direct 16 bit. */ ++#define R_390_32 4 /* Direct 32 bit. */ ++#define R_390_PC32 5 /* PC relative 32 bit. */ ++#define R_390_GOT12 6 /* 12 bit GOT offset. */ ++#define R_390_GOT32 7 /* 32 bit GOT offset. */ ++#define R_390_PLT32 8 /* 32 bit PC relative PLT address. */ ++#define R_390_COPY 9 /* Copy symbol at runtime. */ ++#define R_390_GLOB_DAT 10 /* Create GOT entry. */ ++#define R_390_JMP_SLOT 11 /* Create PLT entry. */ ++#define R_390_RELATIVE 12 /* Adjust by program base. */ ++#define R_390_GOTOFF32 13 /* 32 bit offset to GOT. */ ++#define R_390_GOTPC 14 /* 32 bit PC relative offset to GOT. */ ++#define R_390_GOT16 15 /* 16 bit GOT offset. */ ++#define R_390_PC16 16 /* PC relative 16 bit. */ ++#define R_390_PC16DBL 17 /* PC relative 16 bit shifted by 1. */ ++#define R_390_PLT16DBL 18 /* 16 bit PC rel. PLT shifted by 1. */ ++#define R_390_PC32DBL 19 /* PC relative 32 bit shifted by 1. */ ++#define R_390_PLT32DBL 20 /* 32 bit PC rel. PLT shifted by 1. */ ++#define R_390_GOTPCDBL 21 /* 32 bit PC rel. GOT shifted by 1. */ ++#define R_390_64 22 /* Direct 64 bit. */ ++#define R_390_PC64 23 /* PC relative 64 bit. */ ++#define R_390_GOT64 24 /* 64 bit GOT offset. */ ++#define R_390_PLT64 25 /* 64 bit PC relative PLT address. */ ++#define R_390_GOTENT 26 /* 32 bit PC rel. to GOT entry >> 1. */ ++#define R_390_GOTOFF16 27 /* 16 bit offset to GOT. */ ++#define R_390_GOTOFF64 28 /* 64 bit offset to GOT. */ ++#define R_390_GOTPLT12 29 /* 12 bit offset to jump slot. */ ++#define R_390_GOTPLT16 30 /* 16 bit offset to jump slot. */ ++#define R_390_GOTPLT32 31 /* 32 bit offset to jump slot. */ ++#define R_390_GOTPLT64 32 /* 64 bit offset to jump slot. */ ++#define R_390_GOTPLTENT 33 /* 32 bit rel. offset to jump slot. */ ++#define R_390_PLTOFF16 34 /* 16 bit offset from GOT to PLT. */ ++#define R_390_PLTOFF32 35 /* 32 bit offset from GOT to PLT. */ ++#define R_390_PLTOFF64 36 /* 16 bit offset from GOT to PLT. */ ++#define R_390_TLS_LOAD 37 /* Tag for load insn in TLS code. */ ++#define R_390_TLS_GDCALL 38 /* Tag for function call in general ++ dynamic TLS code. */ ++#define R_390_TLS_LDCALL 39 /* Tag for function call in local ++ dynamic TLS code. */ ++#define R_390_TLS_GD32 40 /* Direct 32 bit for general dynamic ++ thread local data. */ ++#define R_390_TLS_GD64 41 /* Direct 64 bit for general dynamic ++ thread local data. */ ++#define R_390_TLS_GOTIE12 42 /* 12 bit GOT offset for static TLS ++ block offset. */ ++#define R_390_TLS_GOTIE32 43 /* 32 bit GOT offset for static TLS ++ block offset. */ ++#define R_390_TLS_GOTIE64 44 /* 64 bit GOT offset for static TLS ++ block offset. */ ++#define R_390_TLS_LDM32 45 /* Direct 32 bit for local dynamic ++ thread local data in LE code. */ ++#define R_390_TLS_LDM64 46 /* Direct 64 bit for local dynamic ++ thread local data in LE code. */ ++#define R_390_TLS_IE32 47 /* 32 bit address of GOT entry for ++ negated static TLS block offset. */ ++#define R_390_TLS_IE64 48 /* 64 bit address of GOT entry for ++ negated static TLS block offset. */ ++#define R_390_TLS_IEENT 49 /* 32 bit rel. offset to GOT entry for ++ negated static TLS block offset. */ ++#define R_390_TLS_LE32 50 /* 32 bit negated offset relative to ++ static TLS block. */ ++#define R_390_TLS_LE64 51 /* 64 bit negated offset relative to ++ static TLS block. */ ++#define R_390_TLS_LDO32 52 /* 32 bit offset relative to TLS ++ block. */ ++#define R_390_TLS_LDO64 53 /* 64 bit offset relative to TLS ++ block. */ ++#define R_390_TLS_DTPMOD 54 /* ID of module containing symbol. */ ++#define R_390_TLS_DTPOFF 55 /* Offset in TLS block. */ ++#define R_390_TLS_TPOFF 56 /* Negated offset in static TLS ++ block. */ ++#define R_390_20 57 /* Direct 20 bit. */ ++#define R_390_GOT20 58 /* 20 bit GOT offset. */ ++#define R_390_GOTPLT20 59 /* 20 bit offset to jump slot. */ ++#define R_390_TLS_GOTIE20 60 /* 20 bit GOT offset for static TLS ++ block offset. */ ++#define R_390_IRELATIVE 61 /* STT_GNU_IFUNC relocation. */ ++/* Keep this the last entry. */ ++#define R_390_NUM 62 ++ ++ ++/* CRIS relocations. */ ++#define R_CRIS_NONE 0 ++#define R_CRIS_8 1 ++#define R_CRIS_16 2 ++#define R_CRIS_32 3 ++#define R_CRIS_8_PCREL 4 ++#define R_CRIS_16_PCREL 5 ++#define R_CRIS_32_PCREL 6 ++#define R_CRIS_GNU_VTINHERIT 7 ++#define R_CRIS_GNU_VTENTRY 8 ++#define R_CRIS_COPY 9 ++#define R_CRIS_GLOB_DAT 10 ++#define R_CRIS_JUMP_SLOT 11 ++#define R_CRIS_RELATIVE 12 ++#define R_CRIS_16_GOT 13 ++#define R_CRIS_32_GOT 14 ++#define R_CRIS_16_GOTPLT 15 ++#define R_CRIS_32_GOTPLT 16 ++#define R_CRIS_32_GOTREL 17 ++#define R_CRIS_32_PLT_GOTREL 18 ++#define R_CRIS_32_PLT_PCREL 19 ++ ++#define R_CRIS_NUM 20 ++ ++ ++/* AMD x86-64 relocations. */ ++#define R_X86_64_NONE 0 /* No reloc */ ++#define R_X86_64_64 1 /* Direct 64 bit */ ++#define R_X86_64_PC32 2 /* PC relative 32 bit signed */ ++#define R_X86_64_GOT32 3 /* 32 bit GOT entry */ ++#define R_X86_64_PLT32 4 /* 32 bit PLT address */ ++#define R_X86_64_COPY 5 /* Copy symbol at runtime */ ++#define R_X86_64_GLOB_DAT 6 /* Create GOT entry */ ++#define R_X86_64_JUMP_SLOT 7 /* Create PLT entry */ ++#define R_X86_64_RELATIVE 8 /* Adjust by program base */ ++#define R_X86_64_GOTPCREL 9 /* 32 bit signed PC relative ++ offset to GOT */ ++#define R_X86_64_32 10 /* Direct 32 bit zero extended */ ++#define R_X86_64_32S 11 /* Direct 32 bit sign extended */ ++#define R_X86_64_16 12 /* Direct 16 bit zero extended */ ++#define R_X86_64_PC16 13 /* 16 bit sign extended pc relative */ ++#define R_X86_64_8 14 /* Direct 8 bit sign extended */ ++#define R_X86_64_PC8 15 /* 8 bit sign extended pc relative */ ++#define R_X86_64_DTPMOD64 16 /* ID of module containing symbol */ ++#define R_X86_64_DTPOFF64 17 /* Offset in module's TLS block */ ++#define R_X86_64_TPOFF64 18 /* Offset in initial TLS block */ ++#define R_X86_64_TLSGD 19 /* 32 bit signed PC relative offset ++ to two GOT entries for GD symbol */ ++#define R_X86_64_TLSLD 20 /* 32 bit signed PC relative offset ++ to two GOT entries for LD symbol */ ++#define R_X86_64_DTPOFF32 21 /* Offset in TLS block */ ++#define R_X86_64_GOTTPOFF 22 /* 32 bit signed PC relative offset ++ to GOT entry for IE symbol */ ++#define R_X86_64_TPOFF32 23 /* Offset in initial TLS block */ ++#define R_X86_64_PC64 24 /* PC relative 64 bit */ ++#define R_X86_64_GOTOFF64 25 /* 64 bit offset to GOT */ ++#define R_X86_64_GOTPC32 26 /* 32 bit signed pc relative ++ offset to GOT */ ++#define R_X86_64_GOT64 27 /* 64-bit GOT entry offset */ ++#define R_X86_64_GOTPCREL64 28 /* 64-bit PC relative offset ++ to GOT entry */ ++#define R_X86_64_GOTPC64 29 /* 64-bit PC relative offset to GOT */ ++#define R_X86_64_GOTPLT64 30 /* like GOT64, says PLT entry needed */ ++#define R_X86_64_PLTOFF64 31 /* 64-bit GOT relative offset ++ to PLT entry */ ++#define R_X86_64_SIZE32 32 /* Size of symbol plus 32-bit addend */ ++#define R_X86_64_SIZE64 33 /* Size of symbol plus 64-bit addend */ ++#define R_X86_64_GOTPC32_TLSDESC 34 /* GOT offset for TLS descriptor. */ ++#define R_X86_64_TLSDESC_CALL 35 /* Marker for call through TLS ++ descriptor. */ ++#define R_X86_64_TLSDESC 36 /* TLS descriptor. */ ++#define R_X86_64_IRELATIVE 37 /* Adjust indirectly by program base */ ++#define R_X86_64_RELATIVE64 38 /* 64-bit adjust by program base */ ++ ++#define R_X86_64_NUM 39 ++ ++ ++/* AM33 relocations. */ ++#define R_MN10300_NONE 0 /* No reloc. */ ++#define R_MN10300_32 1 /* Direct 32 bit. */ ++#define R_MN10300_16 2 /* Direct 16 bit. */ ++#define R_MN10300_8 3 /* Direct 8 bit. */ ++#define R_MN10300_PCREL32 4 /* PC-relative 32-bit. */ ++#define R_MN10300_PCREL16 5 /* PC-relative 16-bit signed. */ ++#define R_MN10300_PCREL8 6 /* PC-relative 8-bit signed. */ ++#define R_MN10300_GNU_VTINHERIT 7 /* Ancient C++ vtable garbage... */ ++#define R_MN10300_GNU_VTENTRY 8 /* ... collection annotation. */ ++#define R_MN10300_24 9 /* Direct 24 bit. */ ++#define R_MN10300_GOTPC32 10 /* 32-bit PCrel offset to GOT. */ ++#define R_MN10300_GOTPC16 11 /* 16-bit PCrel offset to GOT. */ ++#define R_MN10300_GOTOFF32 12 /* 32-bit offset from GOT. */ ++#define R_MN10300_GOTOFF24 13 /* 24-bit offset from GOT. */ ++#define R_MN10300_GOTOFF16 14 /* 16-bit offset from GOT. */ ++#define R_MN10300_PLT32 15 /* 32-bit PCrel to PLT entry. */ ++#define R_MN10300_PLT16 16 /* 16-bit PCrel to PLT entry. */ ++#define R_MN10300_GOT32 17 /* 32-bit offset to GOT entry. */ ++#define R_MN10300_GOT24 18 /* 24-bit offset to GOT entry. */ ++#define R_MN10300_GOT16 19 /* 16-bit offset to GOT entry. */ ++#define R_MN10300_COPY 20 /* Copy symbol at runtime. */ ++#define R_MN10300_GLOB_DAT 21 /* Create GOT entry. */ ++#define R_MN10300_JMP_SLOT 22 /* Create PLT entry. */ ++#define R_MN10300_RELATIVE 23 /* Adjust by program base. */ ++ ++#define R_MN10300_NUM 24 ++ ++ ++/* M32R relocs. */ ++#define R_M32R_NONE 0 /* No reloc. */ ++#define R_M32R_16 1 /* Direct 16 bit. */ ++#define R_M32R_32 2 /* Direct 32 bit. */ ++#define R_M32R_24 3 /* Direct 24 bit. */ ++#define R_M32R_10_PCREL 4 /* PC relative 10 bit shifted. */ ++#define R_M32R_18_PCREL 5 /* PC relative 18 bit shifted. */ ++#define R_M32R_26_PCREL 6 /* PC relative 26 bit shifted. */ ++#define R_M32R_HI16_ULO 7 /* High 16 bit with unsigned low. */ ++#define R_M32R_HI16_SLO 8 /* High 16 bit with signed low. */ ++#define R_M32R_LO16 9 /* Low 16 bit. */ ++#define R_M32R_SDA16 10 /* 16 bit offset in SDA. */ ++#define R_M32R_GNU_VTINHERIT 11 ++#define R_M32R_GNU_VTENTRY 12 ++/* M32R relocs use SHT_RELA. */ ++#define R_M32R_16_RELA 33 /* Direct 16 bit. */ ++#define R_M32R_32_RELA 34 /* Direct 32 bit. */ ++#define R_M32R_24_RELA 35 /* Direct 24 bit. */ ++#define R_M32R_10_PCREL_RELA 36 /* PC relative 10 bit shifted. */ ++#define R_M32R_18_PCREL_RELA 37 /* PC relative 18 bit shifted. */ ++#define R_M32R_26_PCREL_RELA 38 /* PC relative 26 bit shifted. */ ++#define R_M32R_HI16_ULO_RELA 39 /* High 16 bit with unsigned low */ ++#define R_M32R_HI16_SLO_RELA 40 /* High 16 bit with signed low */ ++#define R_M32R_LO16_RELA 41 /* Low 16 bit */ ++#define R_M32R_SDA16_RELA 42 /* 16 bit offset in SDA */ ++#define R_M32R_RELA_GNU_VTINHERIT 43 ++#define R_M32R_RELA_GNU_VTENTRY 44 ++#define R_M32R_REL32 45 /* PC relative 32 bit. */ ++ ++#define R_M32R_GOT24 48 /* 24 bit GOT entry */ ++#define R_M32R_26_PLTREL 49 /* 26 bit PC relative to PLT shifted */ ++#define R_M32R_COPY 50 /* Copy symbol at runtime */ ++#define R_M32R_GLOB_DAT 51 /* Create GOT entry */ ++#define R_M32R_JMP_SLOT 52 /* Create PLT entry */ ++#define R_M32R_RELATIVE 53 /* Adjust by program base */ ++#define R_M32R_GOTOFF 54 /* 24 bit offset to GOT */ ++#define R_M32R_GOTPC24 55 /* 24 bit PC relative offset to GOT */ ++#define R_M32R_GOT16_HI_ULO 56 /* High 16 bit GOT entry with unsigned ++ low */ ++#define R_M32R_GOT16_HI_SLO 57 /* High 16 bit GOT entry with signed ++ low */ ++#define R_M32R_GOT16_LO 58 /* Low 16 bit GOT entry */ ++#define R_M32R_GOTPC_HI_ULO 59 /* High 16 bit PC relative offset to ++ GOT with unsigned low */ ++#define R_M32R_GOTPC_HI_SLO 60 /* High 16 bit PC relative offset to ++ GOT with signed low */ ++#define R_M32R_GOTPC_LO 61 /* Low 16 bit PC relative offset to ++ GOT */ ++#define R_M32R_GOTOFF_HI_ULO 62 /* High 16 bit offset to GOT ++ with unsigned low */ ++#define R_M32R_GOTOFF_HI_SLO 63 /* High 16 bit offset to GOT ++ with signed low */ ++#define R_M32R_GOTOFF_LO 64 /* Low 16 bit offset to GOT */ ++#define R_M32R_NUM 256 /* Keep this the last entry. */ ++ ++ ++/* TILEPro relocations. */ ++#define R_TILEPRO_NONE 0 /* No reloc */ ++#define R_TILEPRO_32 1 /* Direct 32 bit */ ++#define R_TILEPRO_16 2 /* Direct 16 bit */ ++#define R_TILEPRO_8 3 /* Direct 8 bit */ ++#define R_TILEPRO_32_PCREL 4 /* PC relative 32 bit */ ++#define R_TILEPRO_16_PCREL 5 /* PC relative 16 bit */ ++#define R_TILEPRO_8_PCREL 6 /* PC relative 8 bit */ ++#define R_TILEPRO_LO16 7 /* Low 16 bit */ ++#define R_TILEPRO_HI16 8 /* High 16 bit */ ++#define R_TILEPRO_HA16 9 /* High 16 bit, adjusted */ ++#define R_TILEPRO_COPY 10 /* Copy relocation */ ++#define R_TILEPRO_GLOB_DAT 11 /* Create GOT entry */ ++#define R_TILEPRO_JMP_SLOT 12 /* Create PLT entry */ ++#define R_TILEPRO_RELATIVE 13 /* Adjust by program base */ ++#define R_TILEPRO_BROFF_X1 14 /* X1 pipe branch offset */ ++#define R_TILEPRO_JOFFLONG_X1 15 /* X1 pipe jump offset */ ++#define R_TILEPRO_JOFFLONG_X1_PLT 16 /* X1 pipe jump offset to PLT */ ++#define R_TILEPRO_IMM8_X0 17 /* X0 pipe 8-bit */ ++#define R_TILEPRO_IMM8_Y0 18 /* Y0 pipe 8-bit */ ++#define R_TILEPRO_IMM8_X1 19 /* X1 pipe 8-bit */ ++#define R_TILEPRO_IMM8_Y1 20 /* Y1 pipe 8-bit */ ++#define R_TILEPRO_MT_IMM15_X1 21 /* X1 pipe mtspr */ ++#define R_TILEPRO_MF_IMM15_X1 22 /* X1 pipe mfspr */ ++#define R_TILEPRO_IMM16_X0 23 /* X0 pipe 16-bit */ ++#define R_TILEPRO_IMM16_X1 24 /* X1 pipe 16-bit */ ++#define R_TILEPRO_IMM16_X0_LO 25 /* X0 pipe low 16-bit */ ++#define R_TILEPRO_IMM16_X1_LO 26 /* X1 pipe low 16-bit */ ++#define R_TILEPRO_IMM16_X0_HI 27 /* X0 pipe high 16-bit */ ++#define R_TILEPRO_IMM16_X1_HI 28 /* X1 pipe high 16-bit */ ++#define R_TILEPRO_IMM16_X0_HA 29 /* X0 pipe high 16-bit, adjusted */ ++#define R_TILEPRO_IMM16_X1_HA 30 /* X1 pipe high 16-bit, adjusted */ ++#define R_TILEPRO_IMM16_X0_PCREL 31 /* X0 pipe PC relative 16 bit */ ++#define R_TILEPRO_IMM16_X1_PCREL 32 /* X1 pipe PC relative 16 bit */ ++#define R_TILEPRO_IMM16_X0_LO_PCREL 33 /* X0 pipe PC relative low 16 bit */ ++#define R_TILEPRO_IMM16_X1_LO_PCREL 34 /* X1 pipe PC relative low 16 bit */ ++#define R_TILEPRO_IMM16_X0_HI_PCREL 35 /* X0 pipe PC relative high 16 bit */ ++#define R_TILEPRO_IMM16_X1_HI_PCREL 36 /* X1 pipe PC relative high 16 bit */ ++#define R_TILEPRO_IMM16_X0_HA_PCREL 37 /* X0 pipe PC relative ha() 16 bit */ ++#define R_TILEPRO_IMM16_X1_HA_PCREL 38 /* X1 pipe PC relative ha() 16 bit */ ++#define R_TILEPRO_IMM16_X0_GOT 39 /* X0 pipe 16-bit GOT offset */ ++#define R_TILEPRO_IMM16_X1_GOT 40 /* X1 pipe 16-bit GOT offset */ ++#define R_TILEPRO_IMM16_X0_GOT_LO 41 /* X0 pipe low 16-bit GOT offset */ ++#define R_TILEPRO_IMM16_X1_GOT_LO 42 /* X1 pipe low 16-bit GOT offset */ ++#define R_TILEPRO_IMM16_X0_GOT_HI 43 /* X0 pipe high 16-bit GOT offset */ ++#define R_TILEPRO_IMM16_X1_GOT_HI 44 /* X1 pipe high 16-bit GOT offset */ ++#define R_TILEPRO_IMM16_X0_GOT_HA 45 /* X0 pipe ha() 16-bit GOT offset */ ++#define R_TILEPRO_IMM16_X1_GOT_HA 46 /* X1 pipe ha() 16-bit GOT offset */ ++#define R_TILEPRO_MMSTART_X0 47 /* X0 pipe mm "start" */ ++#define R_TILEPRO_MMEND_X0 48 /* X0 pipe mm "end" */ ++#define R_TILEPRO_MMSTART_X1 49 /* X1 pipe mm "start" */ ++#define R_TILEPRO_MMEND_X1 50 /* X1 pipe mm "end" */ ++#define R_TILEPRO_SHAMT_X0 51 /* X0 pipe shift amount */ ++#define R_TILEPRO_SHAMT_X1 52 /* X1 pipe shift amount */ ++#define R_TILEPRO_SHAMT_Y0 53 /* Y0 pipe shift amount */ ++#define R_TILEPRO_SHAMT_Y1 54 /* Y1 pipe shift amount */ ++#define R_TILEPRO_DEST_IMM8_X1 55 /* X1 pipe destination 8-bit */ ++/* Relocs 56-59 are currently not defined. */ ++#define R_TILEPRO_TLS_GD_CALL 60 /* "jal" for TLS GD */ ++#define R_TILEPRO_IMM8_X0_TLS_GD_ADD 61 /* X0 pipe "addi" for TLS GD */ ++#define R_TILEPRO_IMM8_X1_TLS_GD_ADD 62 /* X1 pipe "addi" for TLS GD */ ++#define R_TILEPRO_IMM8_Y0_TLS_GD_ADD 63 /* Y0 pipe "addi" for TLS GD */ ++#define R_TILEPRO_IMM8_Y1_TLS_GD_ADD 64 /* Y1 pipe "addi" for TLS GD */ ++#define R_TILEPRO_TLS_IE_LOAD 65 /* "lw_tls" for TLS IE */ ++#define R_TILEPRO_IMM16_X0_TLS_GD 66 /* X0 pipe 16-bit TLS GD offset */ ++#define R_TILEPRO_IMM16_X1_TLS_GD 67 /* X1 pipe 16-bit TLS GD offset */ ++#define R_TILEPRO_IMM16_X0_TLS_GD_LO 68 /* X0 pipe low 16-bit TLS GD offset */ ++#define R_TILEPRO_IMM16_X1_TLS_GD_LO 69 /* X1 pipe low 16-bit TLS GD offset */ ++#define R_TILEPRO_IMM16_X0_TLS_GD_HI 70 /* X0 pipe high 16-bit TLS GD offset */ ++#define R_TILEPRO_IMM16_X1_TLS_GD_HI 71 /* X1 pipe high 16-bit TLS GD offset */ ++#define R_TILEPRO_IMM16_X0_TLS_GD_HA 72 /* X0 pipe ha() 16-bit TLS GD offset */ ++#define R_TILEPRO_IMM16_X1_TLS_GD_HA 73 /* X1 pipe ha() 16-bit TLS GD offset */ ++#define R_TILEPRO_IMM16_X0_TLS_IE 74 /* X0 pipe 16-bit TLS IE offset */ ++#define R_TILEPRO_IMM16_X1_TLS_IE 75 /* X1 pipe 16-bit TLS IE offset */ ++#define R_TILEPRO_IMM16_X0_TLS_IE_LO 76 /* X0 pipe low 16-bit TLS IE offset */ ++#define R_TILEPRO_IMM16_X1_TLS_IE_LO 77 /* X1 pipe low 16-bit TLS IE offset */ ++#define R_TILEPRO_IMM16_X0_TLS_IE_HI 78 /* X0 pipe high 16-bit TLS IE offset */ ++#define R_TILEPRO_IMM16_X1_TLS_IE_HI 79 /* X1 pipe high 16-bit TLS IE offset */ ++#define R_TILEPRO_IMM16_X0_TLS_IE_HA 80 /* X0 pipe ha() 16-bit TLS IE offset */ ++#define R_TILEPRO_IMM16_X1_TLS_IE_HA 81 /* X1 pipe ha() 16-bit TLS IE offset */ ++#define R_TILEPRO_TLS_DTPMOD32 82 /* ID of module containing symbol */ ++#define R_TILEPRO_TLS_DTPOFF32 83 /* Offset in TLS block */ ++#define R_TILEPRO_TLS_TPOFF32 84 /* Offset in static TLS block */ ++#define R_TILEPRO_IMM16_X0_TLS_LE 85 /* X0 pipe 16-bit TLS LE offset */ ++#define R_TILEPRO_IMM16_X1_TLS_LE 86 /* X1 pipe 16-bit TLS LE offset */ ++#define R_TILEPRO_IMM16_X0_TLS_LE_LO 87 /* X0 pipe low 16-bit TLS LE offset */ ++#define R_TILEPRO_IMM16_X1_TLS_LE_LO 88 /* X1 pipe low 16-bit TLS LE offset */ ++#define R_TILEPRO_IMM16_X0_TLS_LE_HI 89 /* X0 pipe high 16-bit TLS LE offset */ ++#define R_TILEPRO_IMM16_X1_TLS_LE_HI 90 /* X1 pipe high 16-bit TLS LE offset */ ++#define R_TILEPRO_IMM16_X0_TLS_LE_HA 91 /* X0 pipe ha() 16-bit TLS LE offset */ ++#define R_TILEPRO_IMM16_X1_TLS_LE_HA 92 /* X1 pipe ha() 16-bit TLS LE offset */ ++ ++#define R_TILEPRO_GNU_VTINHERIT 128 /* GNU C++ vtable hierarchy */ ++#define R_TILEPRO_GNU_VTENTRY 129 /* GNU C++ vtable member usage */ ++ ++#define R_TILEPRO_NUM 130 ++ ++ ++/* TILE-Gx relocations. */ ++#define R_TILEGX_NONE 0 /* No reloc */ ++#define R_TILEGX_64 1 /* Direct 64 bit */ ++#define R_TILEGX_32 2 /* Direct 32 bit */ ++#define R_TILEGX_16 3 /* Direct 16 bit */ ++#define R_TILEGX_8 4 /* Direct 8 bit */ ++#define R_TILEGX_64_PCREL 5 /* PC relative 64 bit */ ++#define R_TILEGX_32_PCREL 6 /* PC relative 32 bit */ ++#define R_TILEGX_16_PCREL 7 /* PC relative 16 bit */ ++#define R_TILEGX_8_PCREL 8 /* PC relative 8 bit */ ++#define R_TILEGX_HW0 9 /* hword 0 16-bit */ ++#define R_TILEGX_HW1 10 /* hword 1 16-bit */ ++#define R_TILEGX_HW2 11 /* hword 2 16-bit */ ++#define R_TILEGX_HW3 12 /* hword 3 16-bit */ ++#define R_TILEGX_HW0_LAST 13 /* last hword 0 16-bit */ ++#define R_TILEGX_HW1_LAST 14 /* last hword 1 16-bit */ ++#define R_TILEGX_HW2_LAST 15 /* last hword 2 16-bit */ ++#define R_TILEGX_COPY 16 /* Copy relocation */ ++#define R_TILEGX_GLOB_DAT 17 /* Create GOT entry */ ++#define R_TILEGX_JMP_SLOT 18 /* Create PLT entry */ ++#define R_TILEGX_RELATIVE 19 /* Adjust by program base */ ++#define R_TILEGX_BROFF_X1 20 /* X1 pipe branch offset */ ++#define R_TILEGX_JUMPOFF_X1 21 /* X1 pipe jump offset */ ++#define R_TILEGX_JUMPOFF_X1_PLT 22 /* X1 pipe jump offset to PLT */ ++#define R_TILEGX_IMM8_X0 23 /* X0 pipe 8-bit */ ++#define R_TILEGX_IMM8_Y0 24 /* Y0 pipe 8-bit */ ++#define R_TILEGX_IMM8_X1 25 /* X1 pipe 8-bit */ ++#define R_TILEGX_IMM8_Y1 26 /* Y1 pipe 8-bit */ ++#define R_TILEGX_DEST_IMM8_X1 27 /* X1 pipe destination 8-bit */ ++#define R_TILEGX_MT_IMM14_X1 28 /* X1 pipe mtspr */ ++#define R_TILEGX_MF_IMM14_X1 29 /* X1 pipe mfspr */ ++#define R_TILEGX_MMSTART_X0 30 /* X0 pipe mm "start" */ ++#define R_TILEGX_MMEND_X0 31 /* X0 pipe mm "end" */ ++#define R_TILEGX_SHAMT_X0 32 /* X0 pipe shift amount */ ++#define R_TILEGX_SHAMT_X1 33 /* X1 pipe shift amount */ ++#define R_TILEGX_SHAMT_Y0 34 /* Y0 pipe shift amount */ ++#define R_TILEGX_SHAMT_Y1 35 /* Y1 pipe shift amount */ ++#define R_TILEGX_IMM16_X0_HW0 36 /* X0 pipe hword 0 */ ++#define R_TILEGX_IMM16_X1_HW0 37 /* X1 pipe hword 0 */ ++#define R_TILEGX_IMM16_X0_HW1 38 /* X0 pipe hword 1 */ ++#define R_TILEGX_IMM16_X1_HW1 39 /* X1 pipe hword 1 */ ++#define R_TILEGX_IMM16_X0_HW2 40 /* X0 pipe hword 2 */ ++#define R_TILEGX_IMM16_X1_HW2 41 /* X1 pipe hword 2 */ ++#define R_TILEGX_IMM16_X0_HW3 42 /* X0 pipe hword 3 */ ++#define R_TILEGX_IMM16_X1_HW3 43 /* X1 pipe hword 3 */ ++#define R_TILEGX_IMM16_X0_HW0_LAST 44 /* X0 pipe last hword 0 */ ++#define R_TILEGX_IMM16_X1_HW0_LAST 45 /* X1 pipe last hword 0 */ ++#define R_TILEGX_IMM16_X0_HW1_LAST 46 /* X0 pipe last hword 1 */ ++#define R_TILEGX_IMM16_X1_HW1_LAST 47 /* X1 pipe last hword 1 */ ++#define R_TILEGX_IMM16_X0_HW2_LAST 48 /* X0 pipe last hword 2 */ ++#define R_TILEGX_IMM16_X1_HW2_LAST 49 /* X1 pipe last hword 2 */ ++#define R_TILEGX_IMM16_X0_HW0_PCREL 50 /* X0 pipe PC relative hword 0 */ ++#define R_TILEGX_IMM16_X1_HW0_PCREL 51 /* X1 pipe PC relative hword 0 */ ++#define R_TILEGX_IMM16_X0_HW1_PCREL 52 /* X0 pipe PC relative hword 1 */ ++#define R_TILEGX_IMM16_X1_HW1_PCREL 53 /* X1 pipe PC relative hword 1 */ ++#define R_TILEGX_IMM16_X0_HW2_PCREL 54 /* X0 pipe PC relative hword 2 */ ++#define R_TILEGX_IMM16_X1_HW2_PCREL 55 /* X1 pipe PC relative hword 2 */ ++#define R_TILEGX_IMM16_X0_HW3_PCREL 56 /* X0 pipe PC relative hword 3 */ ++#define R_TILEGX_IMM16_X1_HW3_PCREL 57 /* X1 pipe PC relative hword 3 */ ++#define R_TILEGX_IMM16_X0_HW0_LAST_PCREL 58 /* X0 pipe PC-rel last hword 0 */ ++#define R_TILEGX_IMM16_X1_HW0_LAST_PCREL 59 /* X1 pipe PC-rel last hword 0 */ ++#define R_TILEGX_IMM16_X0_HW1_LAST_PCREL 60 /* X0 pipe PC-rel last hword 1 */ ++#define R_TILEGX_IMM16_X1_HW1_LAST_PCREL 61 /* X1 pipe PC-rel last hword 1 */ ++#define R_TILEGX_IMM16_X0_HW2_LAST_PCREL 62 /* X0 pipe PC-rel last hword 2 */ ++#define R_TILEGX_IMM16_X1_HW2_LAST_PCREL 63 /* X1 pipe PC-rel last hword 2 */ ++#define R_TILEGX_IMM16_X0_HW0_GOT 64 /* X0 pipe hword 0 GOT offset */ ++#define R_TILEGX_IMM16_X1_HW0_GOT 65 /* X1 pipe hword 0 GOT offset */ ++/* Relocs 66-71 are currently not defined. */ ++#define R_TILEGX_IMM16_X0_HW0_LAST_GOT 72 /* X0 pipe last hword 0 GOT offset */ ++#define R_TILEGX_IMM16_X1_HW0_LAST_GOT 73 /* X1 pipe last hword 0 GOT offset */ ++#define R_TILEGX_IMM16_X0_HW1_LAST_GOT 74 /* X0 pipe last hword 1 GOT offset */ ++#define R_TILEGX_IMM16_X1_HW1_LAST_GOT 75 /* X1 pipe last hword 1 GOT offset */ ++/* Relocs 76-77 are currently not defined. */ ++#define R_TILEGX_IMM16_X0_HW0_TLS_GD 78 /* X0 pipe hword 0 TLS GD offset */ ++#define R_TILEGX_IMM16_X1_HW0_TLS_GD 79 /* X1 pipe hword 0 TLS GD offset */ ++#define R_TILEGX_IMM16_X0_HW0_TLS_LE 80 /* X0 pipe hword 0 TLS LE offset */ ++#define R_TILEGX_IMM16_X1_HW0_TLS_LE 81 /* X1 pipe hword 0 TLS LE offset */ ++#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_LE 82 /* X0 pipe last hword 0 LE off */ ++#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_LE 83 /* X1 pipe last hword 0 LE off */ ++#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_LE 84 /* X0 pipe last hword 1 LE off */ ++#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_LE 85 /* X1 pipe last hword 1 LE off */ ++#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD 86 /* X0 pipe last hword 0 GD off */ ++#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD 87 /* X1 pipe last hword 0 GD off */ ++#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD 88 /* X0 pipe last hword 1 GD off */ ++#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD 89 /* X1 pipe last hword 1 GD off */ ++/* Relocs 90-91 are currently not defined. */ ++#define R_TILEGX_IMM16_X0_HW0_TLS_IE 92 /* X0 pipe hword 0 TLS IE offset */ ++#define R_TILEGX_IMM16_X1_HW0_TLS_IE 93 /* X1 pipe hword 0 TLS IE offset */ ++/* Relocs 94-99 are currently not defined. */ ++#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE 100 /* X0 pipe last hword 0 IE off */ ++#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE 101 /* X1 pipe last hword 0 IE off */ ++#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE 102 /* X0 pipe last hword 1 IE off */ ++#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE 103 /* X1 pipe last hword 1 IE off */ ++/* Relocs 104-105 are currently not defined. */ ++#define R_TILEGX_TLS_DTPMOD64 106 /* 64-bit ID of symbol's module */ ++#define R_TILEGX_TLS_DTPOFF64 107 /* 64-bit offset in TLS block */ ++#define R_TILEGX_TLS_TPOFF64 108 /* 64-bit offset in static TLS block */ ++#define R_TILEGX_TLS_DTPMOD32 109 /* 32-bit ID of symbol's module */ ++#define R_TILEGX_TLS_DTPOFF32 110 /* 32-bit offset in TLS block */ ++#define R_TILEGX_TLS_TPOFF32 111 /* 32-bit offset in static TLS block */ ++#define R_TILEGX_TLS_GD_CALL 112 /* "jal" for TLS GD */ ++#define R_TILEGX_IMM8_X0_TLS_GD_ADD 113 /* X0 pipe "addi" for TLS GD */ ++#define R_TILEGX_IMM8_X1_TLS_GD_ADD 114 /* X1 pipe "addi" for TLS GD */ ++#define R_TILEGX_IMM8_Y0_TLS_GD_ADD 115 /* Y0 pipe "addi" for TLS GD */ ++#define R_TILEGX_IMM8_Y1_TLS_GD_ADD 116 /* Y1 pipe "addi" for TLS GD */ ++#define R_TILEGX_TLS_IE_LOAD 117 /* "ld_tls" for TLS IE */ ++#define R_TILEGX_IMM8_X0_TLS_ADD 118 /* X0 pipe "addi" for TLS GD/IE */ ++#define R_TILEGX_IMM8_X1_TLS_ADD 119 /* X1 pipe "addi" for TLS GD/IE */ ++#define R_TILEGX_IMM8_Y0_TLS_ADD 120 /* Y0 pipe "addi" for TLS GD/IE */ ++#define R_TILEGX_IMM8_Y1_TLS_ADD 121 /* Y1 pipe "addi" for TLS GD/IE */ ++ ++#define R_TILEGX_GNU_VTINHERIT 128 /* GNU C++ vtable hierarchy */ ++#define R_TILEGX_GNU_VTENTRY 129 /* GNU C++ vtable member usage */ ++ ++#define R_TILEGX_NUM 130 ++ ++#endif /* elf.h */ diff --git a/target/linux/generic/patches-3.18/212-byteshift_portability.patch b/target/linux/generic/patches-3.18/212-byteshift_portability.patch new file mode 100644 index 0000000..0f23ba9 --- /dev/null +++ b/target/linux/generic/patches-3.18/212-byteshift_portability.patch @@ -0,0 +1,51 @@ +--- a/tools/include/tools/be_byteshift.h ++++ b/tools/include/tools/be_byteshift.h +@@ -1,6 +1,10 @@ + #ifndef _TOOLS_BE_BYTESHIFT_H + #define _TOOLS_BE_BYTESHIFT_H + ++#ifndef __linux__ ++#include "linux_types.h" ++#endif ++ + #include + + static inline uint16_t __get_unaligned_be16(const uint8_t *p) +--- a/tools/include/tools/le_byteshift.h ++++ b/tools/include/tools/le_byteshift.h +@@ -1,6 +1,10 @@ + #ifndef _TOOLS_LE_BYTESHIFT_H + #define _TOOLS_LE_BYTESHIFT_H + ++#ifndef __linux__ ++#include "linux_types.h" ++#endif ++ + #include + + static inline uint16_t __get_unaligned_le16(const uint8_t *p) +--- /dev/null ++++ b/tools/include/tools/linux_types.h +@@ -0,0 +1,22 @@ ++#ifndef __LINUX_TYPES_H ++#define __LINUX_TYPES_H ++ ++#include ++ ++typedef uint8_t __u8; ++typedef uint8_t __be8; ++typedef uint8_t __le8; ++ ++typedef uint16_t __u16; ++typedef uint16_t __be16; ++typedef uint16_t __le16; ++ ++typedef uint32_t __u32; ++typedef uint32_t __be32; ++typedef uint32_t __le32; ++ ++typedef uint64_t __u64; ++typedef uint64_t __be64; ++typedef uint64_t __le64; ++ ++#endif diff --git a/target/linux/generic/patches-3.18/213-x86_vdso_portability.patch b/target/linux/generic/patches-3.18/213-x86_vdso_portability.patch new file mode 100644 index 0000000..937ab90 --- /dev/null +++ b/target/linux/generic/patches-3.18/213-x86_vdso_portability.patch @@ -0,0 +1,13 @@ +--- a/arch/x86/vdso/vdso2c.c ++++ b/arch/x86/vdso/vdso2c.c +@@ -63,8 +63,8 @@ + + #include + +-#include +-#include ++#include ++#include + + const char *outfilename; + diff --git a/target/linux/generic/patches-3.18/214-spidev_h_portability.patch b/target/linux/generic/patches-3.18/214-spidev_h_portability.patch new file mode 100644 index 0000000..dbee090 --- /dev/null +++ b/target/linux/generic/patches-3.18/214-spidev_h_portability.patch @@ -0,0 +1,11 @@ +--- a/include/uapi/linux/spi/spidev.h ++++ b/include/uapi/linux/spi/spidev.h +@@ -111,7 +111,7 @@ struct spi_ioc_transfer { + + /* not all platforms use or _IOC_TYPECHECK() ... */ + #define SPI_MSGSIZE(N) \ +- ((((N)*(sizeof (struct spi_ioc_transfer))) < (1 << _IOC_SIZEBITS)) \ ++ ((((N)*(sizeof (struct spi_ioc_transfer))) < (1 << 13)) \ + ? ((N)*(sizeof (struct spi_ioc_transfer))) : 0) + #define SPI_IOC_MESSAGE(N) _IOW(SPI_IOC_MAGIC, 0, char[SPI_MSGSIZE(N)]) + diff --git a/target/linux/generic/patches-3.18/220-gc_sections.patch b/target/linux/generic/patches-3.18/220-gc_sections.patch new file mode 100644 index 0000000..775e11c --- /dev/null +++ b/target/linux/generic/patches-3.18/220-gc_sections.patch @@ -0,0 +1,531 @@ +From: Felix Fietkau + +use -ffunction-sections, -fdata-sections and --gc-sections + +In combination with kernel symbol export stripping this significantly reduces +the kernel image size. Used on both ARM and MIPS architectures. + +Signed-off-by: Felix Fietkau +Signed-off-by: Jonas Gorski +Signed-off-by: Gabor Juhos +--- + +--- a/arch/mips/Makefile ++++ b/arch/mips/Makefile +@@ -89,10 +89,14 @@ all-$(CONFIG_SYS_SUPPORTS_ZBOOT)+= vmlin + # + cflags-y += -G 0 -mno-abicalls -fno-pic -pipe + cflags-y += -msoft-float +-LDFLAGS_vmlinux += -G 0 -static -n -nostdlib ++LDFLAGS_vmlinux += -G 0 -static -n -nostdlib --gc-sections + KBUILD_AFLAGS_MODULE += -mlong-calls + KBUILD_CFLAGS_MODULE += -mlong-calls + ++ifndef CONFIG_FUNCTION_TRACER ++KBUILD_CFLAGS_KERNEL += -ffunction-sections -fdata-sections ++endif ++ + # + # pass -msoft-float to GAS if it supports it. However on newer binutils + # (specifically newer than 2.24.51.20140728) we then also need to explicitly +--- a/arch/mips/kernel/vmlinux.lds.S ++++ b/arch/mips/kernel/vmlinux.lds.S +@@ -67,7 +67,7 @@ SECTIONS + /* Exception table for data bus errors */ + __dbe_table : { + __start___dbe_table = .; +- *(__dbe_table) ++ KEEP(*(__dbe_table)) + __stop___dbe_table = .; + } + +@@ -112,7 +112,7 @@ SECTIONS + . = ALIGN(4); + .mips.machines.init : AT(ADDR(.mips.machines.init) - LOAD_OFFSET) { + __mips_machines_start = .; +- *(.mips.machines.init) ++ KEEP(*(.mips.machines.init)) + __mips_machines_end = .; + } + +--- a/include/asm-generic/vmlinux.lds.h ++++ b/include/asm-generic/vmlinux.lds.h +@@ -89,7 +89,7 @@ + #ifdef CONFIG_FTRACE_MCOUNT_RECORD + #define MCOUNT_REC() . = ALIGN(8); \ + VMLINUX_SYMBOL(__start_mcount_loc) = .; \ +- *(__mcount_loc) \ ++ KEEP(*(__mcount_loc)) \ + VMLINUX_SYMBOL(__stop_mcount_loc) = .; + #else + #define MCOUNT_REC() +@@ -97,7 +97,7 @@ + + #ifdef CONFIG_TRACE_BRANCH_PROFILING + #define LIKELY_PROFILE() VMLINUX_SYMBOL(__start_annotated_branch_profile) = .; \ +- *(_ftrace_annotated_branch) \ ++ KEEP(*(_ftrace_annotated_branch)) \ + VMLINUX_SYMBOL(__stop_annotated_branch_profile) = .; + #else + #define LIKELY_PROFILE() +@@ -105,7 +105,7 @@ + + #ifdef CONFIG_PROFILE_ALL_BRANCHES + #define BRANCH_PROFILE() VMLINUX_SYMBOL(__start_branch_profile) = .; \ +- *(_ftrace_branch) \ ++ KEEP(*(_ftrace_branch)) \ + VMLINUX_SYMBOL(__stop_branch_profile) = .; + #else + #define BRANCH_PROFILE() +@@ -114,7 +114,7 @@ + #ifdef CONFIG_KPROBES + #define KPROBE_BLACKLIST() . = ALIGN(8); \ + VMLINUX_SYMBOL(__start_kprobe_blacklist) = .; \ +- *(_kprobe_blacklist) \ ++ KEEP(*(_kprobe_blacklist)) \ + VMLINUX_SYMBOL(__stop_kprobe_blacklist) = .; + #else + #define KPROBE_BLACKLIST() +@@ -123,7 +123,7 @@ + #ifdef CONFIG_EVENT_TRACING + #define FTRACE_EVENTS() . = ALIGN(8); \ + VMLINUX_SYMBOL(__start_ftrace_events) = .; \ +- *(_ftrace_events) \ ++ KEEP(*(_ftrace_events)) \ + VMLINUX_SYMBOL(__stop_ftrace_events) = .; + #else + #define FTRACE_EVENTS() +@@ -131,7 +131,7 @@ + + #ifdef CONFIG_TRACING + #define TRACE_PRINTKS() VMLINUX_SYMBOL(__start___trace_bprintk_fmt) = .; \ +- *(__trace_printk_fmt) /* Trace_printk fmt' pointer */ \ ++ KEEP(*(__trace_printk_fmt)) /* Trace_printk fmt' pointer */ \ + VMLINUX_SYMBOL(__stop___trace_bprintk_fmt) = .; + #define TRACEPOINT_STR() VMLINUX_SYMBOL(__start___tracepoint_str) = .; \ + *(__tracepoint_str) /* Trace_printk fmt' pointer */ \ +@@ -144,7 +144,7 @@ + #ifdef CONFIG_FTRACE_SYSCALLS + #define TRACE_SYSCALLS() . = ALIGN(8); \ + VMLINUX_SYMBOL(__start_syscalls_metadata) = .; \ +- *(__syscalls_metadata) \ ++ KEEP(*(__syscalls_metadata)) \ + VMLINUX_SYMBOL(__stop_syscalls_metadata) = .; + #else + #define TRACE_SYSCALLS() +@@ -158,8 +158,8 @@ + #define _OF_TABLE_1(name) \ + . = ALIGN(8); \ + VMLINUX_SYMBOL(__##name##_of_table) = .; \ +- *(__##name##_of_table) \ +- *(__##name##_of_table_end) ++ KEEP(*(__##name##_of_table)) \ ++ KEEP(*(__##name##_of_table_end)) + + #define CLKSRC_OF_TABLES() OF_TABLE(CONFIG_CLKSRC_OF, clksrc) + #define IRQCHIP_OF_MATCH_TABLE() OF_TABLE(CONFIG_IRQCHIP, irqchip) +@@ -171,7 +171,7 @@ + #define KERNEL_DTB() \ + STRUCT_ALIGN(); \ + VMLINUX_SYMBOL(__dtb_start) = .; \ +- *(.dtb.init.rodata) \ ++ KEEP(*(.dtb.init.rodata)) \ + VMLINUX_SYMBOL(__dtb_end) = .; + + /* .data section */ +@@ -187,16 +187,17 @@ + /* implement dynamic printk debug */ \ + . = ALIGN(8); \ + VMLINUX_SYMBOL(__start___jump_table) = .; \ +- *(__jump_table) \ ++ KEEP(*(__jump_table)) \ + VMLINUX_SYMBOL(__stop___jump_table) = .; \ + . = ALIGN(8); \ + VMLINUX_SYMBOL(__start___verbose) = .; \ +- *(__verbose) \ ++ KEEP(*(__verbose)) \ + VMLINUX_SYMBOL(__stop___verbose) = .; \ + LIKELY_PROFILE() \ + BRANCH_PROFILE() \ + TRACE_PRINTKS() \ +- TRACEPOINT_STR() ++ TRACEPOINT_STR() \ ++ *(.data.[a-zA-Z_]*) + + /* + * Data section helpers +@@ -250,35 +251,35 @@ + /* PCI quirks */ \ + .pci_fixup : AT(ADDR(.pci_fixup) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start_pci_fixups_early) = .; \ +- *(.pci_fixup_early) \ ++ KEEP(*(.pci_fixup_early)) \ + VMLINUX_SYMBOL(__end_pci_fixups_early) = .; \ + VMLINUX_SYMBOL(__start_pci_fixups_header) = .; \ +- *(.pci_fixup_header) \ ++ KEEP(*(.pci_fixup_header)) \ + VMLINUX_SYMBOL(__end_pci_fixups_header) = .; \ + VMLINUX_SYMBOL(__start_pci_fixups_final) = .; \ +- *(.pci_fixup_final) \ ++ KEEP(*(.pci_fixup_final)) \ + VMLINUX_SYMBOL(__end_pci_fixups_final) = .; \ + VMLINUX_SYMBOL(__start_pci_fixups_enable) = .; \ +- *(.pci_fixup_enable) \ ++ KEEP(*(.pci_fixup_enable)) \ + VMLINUX_SYMBOL(__end_pci_fixups_enable) = .; \ + VMLINUX_SYMBOL(__start_pci_fixups_resume) = .; \ +- *(.pci_fixup_resume) \ ++ KEEP(*(.pci_fixup_resume)) \ + VMLINUX_SYMBOL(__end_pci_fixups_resume) = .; \ + VMLINUX_SYMBOL(__start_pci_fixups_resume_early) = .; \ +- *(.pci_fixup_resume_early) \ ++ KEEP(*(.pci_fixup_resume_early)) \ + VMLINUX_SYMBOL(__end_pci_fixups_resume_early) = .; \ + VMLINUX_SYMBOL(__start_pci_fixups_suspend) = .; \ +- *(.pci_fixup_suspend) \ ++ KEEP(*(.pci_fixup_suspend)) \ + VMLINUX_SYMBOL(__end_pci_fixups_suspend) = .; \ + VMLINUX_SYMBOL(__start_pci_fixups_suspend_late) = .; \ +- *(.pci_fixup_suspend_late) \ ++ KEEP(*(.pci_fixup_suspend_late)) \ + VMLINUX_SYMBOL(__end_pci_fixups_suspend_late) = .; \ + } \ + \ + /* Built-in firmware blobs */ \ + .builtin_fw : AT(ADDR(.builtin_fw) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start_builtin_fw) = .; \ +- *(.builtin_fw) \ ++ KEEP(*(.builtin_fw)) \ + VMLINUX_SYMBOL(__end_builtin_fw) = .; \ + } \ + \ +@@ -287,49 +288,49 @@ + /* Kernel symbol table: Normal symbols */ \ + __ksymtab : AT(ADDR(__ksymtab) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___ksymtab) = .; \ +- *(SORT(___ksymtab+*)) \ ++ KEEP(*(SORT(___ksymtab+*))) \ + VMLINUX_SYMBOL(__stop___ksymtab) = .; \ + } \ + \ + /* Kernel symbol table: GPL-only symbols */ \ + __ksymtab_gpl : AT(ADDR(__ksymtab_gpl) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___ksymtab_gpl) = .; \ +- *(SORT(___ksymtab_gpl+*)) \ ++ KEEP(*(SORT(___ksymtab_gpl+*))) \ + VMLINUX_SYMBOL(__stop___ksymtab_gpl) = .; \ + } \ + \ + /* Kernel symbol table: Normal unused symbols */ \ + __ksymtab_unused : AT(ADDR(__ksymtab_unused) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___ksymtab_unused) = .; \ +- *(SORT(___ksymtab_unused+*)) \ ++ KEEP(*(SORT(___ksymtab_unused+*))) \ + VMLINUX_SYMBOL(__stop___ksymtab_unused) = .; \ + } \ + \ + /* Kernel symbol table: GPL-only unused symbols */ \ + __ksymtab_unused_gpl : AT(ADDR(__ksymtab_unused_gpl) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___ksymtab_unused_gpl) = .; \ +- *(SORT(___ksymtab_unused_gpl+*)) \ ++ KEEP(*(SORT(___ksymtab_unused_gpl+*))) \ + VMLINUX_SYMBOL(__stop___ksymtab_unused_gpl) = .; \ + } \ + \ + /* Kernel symbol table: GPL-future-only symbols */ \ + __ksymtab_gpl_future : AT(ADDR(__ksymtab_gpl_future) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___ksymtab_gpl_future) = .; \ +- *(SORT(___ksymtab_gpl_future+*)) \ ++ KEEP(*(SORT(___ksymtab_gpl_future+*))) \ + VMLINUX_SYMBOL(__stop___ksymtab_gpl_future) = .; \ + } \ + \ + /* Kernel symbol table: Normal symbols */ \ + __kcrctab : AT(ADDR(__kcrctab) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___kcrctab) = .; \ +- *(SORT(___kcrctab+*)) \ ++ KEEP(*(SORT(___kcrctab+*))) \ + VMLINUX_SYMBOL(__stop___kcrctab) = .; \ + } \ + \ + /* Kernel symbol table: GPL-only symbols */ \ + __kcrctab_gpl : AT(ADDR(__kcrctab_gpl) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___kcrctab_gpl) = .; \ +- *(SORT(___kcrctab_gpl+*)) \ ++ KEEP(*(SORT(___kcrctab_gpl+*))) \ + VMLINUX_SYMBOL(__stop___kcrctab_gpl) = .; \ + } \ + \ +@@ -343,14 +344,14 @@ + /* Kernel symbol table: GPL-only unused symbols */ \ + __kcrctab_unused_gpl : AT(ADDR(__kcrctab_unused_gpl) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___kcrctab_unused_gpl) = .; \ +- *(SORT(___kcrctab_unused_gpl+*)) \ ++ KEEP(*(SORT(___kcrctab_unused_gpl+*))) \ + VMLINUX_SYMBOL(__stop___kcrctab_unused_gpl) = .; \ + } \ + \ + /* Kernel symbol table: GPL-future-only symbols */ \ + __kcrctab_gpl_future : AT(ADDR(__kcrctab_gpl_future) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___kcrctab_gpl_future) = .; \ +- *(SORT(___kcrctab_gpl_future+*)) \ ++ KEEP(*(SORT(___kcrctab_gpl_future+*))) \ + VMLINUX_SYMBOL(__stop___kcrctab_gpl_future) = .; \ + } \ + \ +@@ -369,14 +370,14 @@ + /* Built-in module parameters. */ \ + __param : AT(ADDR(__param) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___param) = .; \ +- *(__param) \ ++ KEEP(*(__param)) \ + VMLINUX_SYMBOL(__stop___param) = .; \ + } \ + \ + /* Built-in module versions. */ \ + __modver : AT(ADDR(__modver) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___modver) = .; \ +- *(__modver) \ ++ KEEP(*(__modver)) \ + VMLINUX_SYMBOL(__stop___modver) = .; \ + . = ALIGN((align)); \ + VMLINUX_SYMBOL(__end_rodata) = .; \ +@@ -432,7 +433,7 @@ + #define ENTRY_TEXT \ + ALIGN_FUNCTION(); \ + VMLINUX_SYMBOL(__entry_text_start) = .; \ +- *(.entry.text) \ ++ KEEP(*(.entry.text)) \ + VMLINUX_SYMBOL(__entry_text_end) = .; + + #ifdef CONFIG_FUNCTION_GRAPH_TRACER +@@ -460,7 +461,7 @@ + . = ALIGN(align); \ + __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___ex_table) = .; \ +- *(__ex_table) \ ++ KEEP(*(__ex_table)) \ + VMLINUX_SYMBOL(__stop___ex_table) = .; \ + } + +@@ -476,8 +477,8 @@ + #ifdef CONFIG_CONSTRUCTORS + #define KERNEL_CTORS() . = ALIGN(8); \ + VMLINUX_SYMBOL(__ctors_start) = .; \ +- *(.ctors) \ +- *(.init_array) \ ++ KEEP(*(.ctors)) \ ++ KEEP(*(.init_array)) \ + VMLINUX_SYMBOL(__ctors_end) = .; + #else + #define KERNEL_CTORS() +@@ -525,7 +526,7 @@ + #define SBSS(sbss_align) \ + . = ALIGN(sbss_align); \ + .sbss : AT(ADDR(.sbss) - LOAD_OFFSET) { \ +- *(.sbss) \ ++ *(.sbss .sbss.*) \ + *(.scommon) \ + } + +@@ -543,7 +544,7 @@ + BSS_FIRST_SECTIONS \ + *(.bss..page_aligned) \ + *(.dynbss) \ +- *(.bss) \ ++ *(.bss .bss.*) \ + *(COMMON) \ + } + +@@ -592,7 +593,7 @@ + . = ALIGN(8); \ + __bug_table : AT(ADDR(__bug_table) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___bug_table) = .; \ +- *(__bug_table) \ ++ KEEP(*(__bug_table)) \ + VMLINUX_SYMBOL(__stop___bug_table) = .; \ + } + #else +@@ -604,7 +605,7 @@ + . = ALIGN(4); \ + .tracedata : AT(ADDR(.tracedata) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__tracedata_start) = .; \ +- *(.tracedata) \ ++ KEEP(*(.tracedata)) \ + VMLINUX_SYMBOL(__tracedata_end) = .; \ + } + #else +@@ -621,17 +622,17 @@ + #define INIT_SETUP(initsetup_align) \ + . = ALIGN(initsetup_align); \ + VMLINUX_SYMBOL(__setup_start) = .; \ +- *(.init.setup) \ ++ KEEP(*(.init.setup)) \ + VMLINUX_SYMBOL(__setup_end) = .; + + #define INIT_CALLS_LEVEL(level) \ + VMLINUX_SYMBOL(__initcall##level##_start) = .; \ +- *(.initcall##level##.init) \ +- *(.initcall##level##s.init) \ ++ KEEP(*(.initcall##level##.init)) \ ++ KEEP(*(.initcall##level##s.init)) \ + + #define INIT_CALLS \ + VMLINUX_SYMBOL(__initcall_start) = .; \ +- *(.initcallearly.init) \ ++ KEEP(*(.initcallearly.init)) \ + INIT_CALLS_LEVEL(0) \ + INIT_CALLS_LEVEL(1) \ + INIT_CALLS_LEVEL(2) \ +@@ -645,21 +646,21 @@ + + #define CON_INITCALL \ + VMLINUX_SYMBOL(__con_initcall_start) = .; \ +- *(.con_initcall.init) \ ++ KEEP(*(.con_initcall.init)) \ + VMLINUX_SYMBOL(__con_initcall_end) = .; + + #define SECURITY_INITCALL \ + VMLINUX_SYMBOL(__security_initcall_start) = .; \ +- *(.security_initcall.init) \ ++ KEEP(*(.security_initcall.init)) \ + VMLINUX_SYMBOL(__security_initcall_end) = .; + + #ifdef CONFIG_BLK_DEV_INITRD + #define INIT_RAM_FS \ + . = ALIGN(4); \ + VMLINUX_SYMBOL(__initramfs_start) = .; \ +- *(.init.ramfs) \ ++ KEEP(*(.init.ramfs)) \ + . = ALIGN(8); \ +- *(.init.ramfs.info) ++ KEEP(*(.init.ramfs.info)) + #else + #define INIT_RAM_FS + #endif +--- a/arch/arm/Makefile ++++ b/arch/arm/Makefile +@@ -18,11 +18,16 @@ ifeq ($(CONFIG_CPU_ENDIAN_BE8),y) + LDFLAGS_vmlinux += --be8 + LDFLAGS_MODULE += --be8 + endif ++LDFLAGS_vmlinux += --gc-sections + + OBJCOPYFLAGS :=-O binary -R .comment -S + GZFLAGS :=-9 + #KBUILD_CFLAGS +=-pipe + ++ifndef CONFIG_FUNCTION_TRACER ++KBUILD_CFLAGS_KERNEL += -ffunction-sections -fdata-sections ++endif ++ + # Never generate .eh_frame + KBUILD_CFLAGS += $(call cc-option,-fno-dwarf2-cfi-asm) + +--- a/arch/arm/kernel/vmlinux.lds.S ++++ b/arch/arm/kernel/vmlinux.lds.S +@@ -12,13 +12,13 @@ + #define PROC_INFO \ + . = ALIGN(4); \ + VMLINUX_SYMBOL(__proc_info_begin) = .; \ +- *(.proc.info.init) \ ++ KEEP(*(.proc.info.init)) \ + VMLINUX_SYMBOL(__proc_info_end) = .; + + #define IDMAP_TEXT \ + ALIGN_FUNCTION(); \ + VMLINUX_SYMBOL(__idmap_text_start) = .; \ +- *(.idmap.text) \ ++ KEEP(*(.idmap.text)) \ + VMLINUX_SYMBOL(__idmap_text_end) = .; \ + . = ALIGN(32); \ + VMLINUX_SYMBOL(__hyp_idmap_text_start) = .; \ +@@ -93,7 +93,7 @@ SECTIONS + .text : { /* Real text segment */ + _stext = .; /* Text and read-only data */ + __exception_text_start = .; +- *(.exception.text) ++ KEEP(*(.exception.text)) + __exception_text_end = .; + IRQENTRY_TEXT + TEXT_TEXT +@@ -118,7 +118,7 @@ SECTIONS + __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) { + __start___ex_table = .; + #ifdef CONFIG_MMU +- *(__ex_table) ++ KEEP(*(__ex_table)) + #endif + __stop___ex_table = .; + } +@@ -130,12 +130,12 @@ SECTIONS + . = ALIGN(8); + .ARM.unwind_idx : { + __start_unwind_idx = .; +- *(.ARM.exidx*) ++ KEEP(*(.ARM.exidx*)) + __stop_unwind_idx = .; + } + .ARM.unwind_tab : { + __start_unwind_tab = .; +- *(.ARM.extab*) ++ KEEP(*(.ARM.extab*)) + __stop_unwind_tab = .; + } + #endif +@@ -154,14 +154,14 @@ SECTIONS + */ + __vectors_start = .; + .vectors 0 : AT(__vectors_start) { +- *(.vectors) ++ KEEP(*(.vectors)) + } + . = __vectors_start + SIZEOF(.vectors); + __vectors_end = .; + + __stubs_start = .; + .stubs 0x1000 : AT(__stubs_start) { +- *(.stubs) ++ KEEP(*(.stubs)) + } + . = __stubs_start + SIZEOF(.stubs); + __stubs_end = .; +@@ -175,24 +175,24 @@ SECTIONS + } + .init.arch.info : { + __arch_info_begin = .; +- *(.arch.info.init) ++ KEEP(*(.arch.info.init)) + __arch_info_end = .; + } + .init.tagtable : { + __tagtable_begin = .; +- *(.taglist.init) ++ KEEP(*(.taglist.init)) + __tagtable_end = .; + } + #ifdef CONFIG_SMP_ON_UP + .init.smpalt : { + __smpalt_begin = .; +- *(.alt.smp.init) ++ KEEP(*(.alt.smp.init)) + __smpalt_end = .; + } + #endif + .init.pv_table : { + __pv_table_begin = .; +- *(.pv_table) ++ KEEP(*(.pv_table)) + __pv_table_end = .; + } + .init.data : { +--- a/arch/arm/boot/compressed/Makefile ++++ b/arch/arm/boot/compressed/Makefile +@@ -122,6 +122,7 @@ ifeq ($(CONFIG_FUNCTION_TRACER),y) + ORIG_CFLAGS := $(KBUILD_CFLAGS) + KBUILD_CFLAGS = $(subst -pg, , $(ORIG_CFLAGS)) + endif ++KBUILD_CFLAGS_KERNEL := $(patsubst -f%-sections,,$(KBUILD_CFLAGS_KERNEL)) + + ccflags-y := -fpic -mno-single-pic-base -fno-builtin -I$(obj) + asflags-y := -DZIMAGE diff --git a/target/linux/generic/patches-3.18/221-module_exports.patch b/target/linux/generic/patches-3.18/221-module_exports.patch new file mode 100644 index 0000000..f2cad7a --- /dev/null +++ b/target/linux/generic/patches-3.18/221-module_exports.patch @@ -0,0 +1,88 @@ +--- a/include/asm-generic/vmlinux.lds.h ++++ b/include/asm-generic/vmlinux.lds.h +@@ -54,6 +54,16 @@ + #define LOAD_OFFSET 0 + #endif + ++#ifndef SYMTAB_KEEP ++#define SYMTAB_KEEP KEEP(*(SORT(___ksymtab+*))) ++#define SYMTAB_KEEP_GPL KEEP(*(SORT(___ksymtab_gpl+*))) ++#endif ++ ++#ifndef SYMTAB_DISCARD ++#define SYMTAB_DISCARD ++#define SYMTAB_DISCARD_GPL ++#endif ++ + #include + + /* Align . to a 8 byte boundary equals to maximum function alignment. */ +@@ -288,14 +298,14 @@ + /* Kernel symbol table: Normal symbols */ \ + __ksymtab : AT(ADDR(__ksymtab) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___ksymtab) = .; \ +- KEEP(*(SORT(___ksymtab+*))) \ ++ SYMTAB_KEEP \ + VMLINUX_SYMBOL(__stop___ksymtab) = .; \ + } \ + \ + /* Kernel symbol table: GPL-only symbols */ \ + __ksymtab_gpl : AT(ADDR(__ksymtab_gpl) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___ksymtab_gpl) = .; \ +- KEEP(*(SORT(___ksymtab_gpl+*))) \ ++ SYMTAB_KEEP_GPL \ + VMLINUX_SYMBOL(__stop___ksymtab_gpl) = .; \ + } \ + \ +@@ -357,7 +367,7 @@ + \ + /* Kernel symbol table: strings */ \ + __ksymtab_strings : AT(ADDR(__ksymtab_strings) - LOAD_OFFSET) { \ +- *(__ksymtab_strings) \ ++ *(__ksymtab_strings+*) \ + } \ + \ + /* __*init sections */ \ +@@ -679,6 +689,8 @@ + EXIT_TEXT \ + EXIT_DATA \ + EXIT_CALL \ ++ SYMTAB_DISCARD \ ++ SYMTAB_DISCARD_GPL \ + *(.discard) \ + *(.discard.*) \ + } +--- a/scripts/Makefile.build ++++ b/scripts/Makefile.build +@@ -298,7 +298,7 @@ targets += $(extra-y) $(MAKECMDGOALS) $( + # Linker scripts preprocessor (.lds.S -> .lds) + # --------------------------------------------------------------------------- + quiet_cmd_cpp_lds_S = LDS $@ +- cmd_cpp_lds_S = $(CPP) $(cpp_flags) -P -C -U$(ARCH) \ ++ cmd_cpp_lds_S = $(CPP) $(EXTRA_LDSFLAGS) $(cpp_flags) -P -C -U$(ARCH) \ + -D__ASSEMBLY__ -DLINKER_SCRIPT -o $@ $< + + $(obj)/%.lds: $(src)/%.lds.S FORCE +--- a/include/linux/export.h ++++ b/include/linux/export.h +@@ -52,12 +52,19 @@ extern struct module __this_module; + #define __CRC_SYMBOL(sym, sec) + #endif + ++#ifdef MODULE ++#define __EXPORT_SUFFIX(sym) ++#else ++#define __EXPORT_SUFFIX(sym) "+" #sym ++#endif ++ + /* For every exported symbol, place a struct in the __ksymtab section */ + #define __EXPORT_SYMBOL(sym, sec) \ + extern typeof(sym) sym; \ + __CRC_SYMBOL(sym, sec) \ + static const char __kstrtab_##sym[] \ +- __attribute__((section("__ksymtab_strings"), aligned(1))) \ ++ __attribute__((section("__ksymtab_strings" \ ++ __EXPORT_SUFFIX(sym)), aligned(1))) \ + = VMLINUX_SYMBOL_STR(sym); \ + extern const struct kernel_symbol __ksymtab_##sym; \ + __visible const struct kernel_symbol __ksymtab_##sym \ diff --git a/target/linux/generic/patches-3.18/230-openwrt_lzma_options.patch b/target/linux/generic/patches-3.18/230-openwrt_lzma_options.patch new file mode 100644 index 0000000..e59fdcd --- /dev/null +++ b/target/linux/generic/patches-3.18/230-openwrt_lzma_options.patch @@ -0,0 +1,58 @@ +--- a/scripts/Makefile.lib ++++ b/scripts/Makefile.lib +@@ -325,7 +325,7 @@ cmd_bzip2 = (cat $(filter-out FORCE,$^) + + quiet_cmd_lzma = LZMA $@ + cmd_lzma = (cat $(filter-out FORCE,$^) | \ +- lzma -9 && $(call size_append, $(filter-out FORCE,$^))) > $@ || \ ++ lzma e -d20 -lc1 -lp2 -pb2 -eos -si -so && $(call size_append, $(filter-out FORCE,$^))) > $@ || \ + (rm -f $@ ; false) + + quiet_cmd_lzo = LZO $@ +--- a/scripts/gen_initramfs_list.sh ++++ b/scripts/gen_initramfs_list.sh +@@ -226,7 +226,7 @@ cpio_list= + output="/dev/stdout" + output_file="" + is_cpio_compressed= +-compr="gzip -n -9 -f" ++compr="gzip -n -9 -f -" + + arg="$1" + case "$arg" in +@@ -242,13 +242,13 @@ case "$arg" in + output=${cpio_list} + echo "$output_file" | grep -q "\.gz$" \ + && [ -x "`which gzip 2> /dev/null`" ] \ +- && compr="gzip -n -9 -f" ++ && compr="gzip -n -9 -f -" + echo "$output_file" | grep -q "\.bz2$" \ + && [ -x "`which bzip2 2> /dev/null`" ] \ +- && compr="bzip2 -9 -f" ++ && compr="bzip2 -9 -f -" + echo "$output_file" | grep -q "\.lzma$" \ + && [ -x "`which lzma 2> /dev/null`" ] \ +- && compr="lzma -9 -f" ++ && compr="lzma e -d20 -lc1 -lp2 -pb2 -eos -si -so" + echo "$output_file" | grep -q "\.xz$" \ + && [ -x "`which xz 2> /dev/null`" ] \ + && compr="xz --check=crc32 --lzma2=dict=1MiB" +@@ -315,7 +315,7 @@ if [ ! -z ${output_file} ]; then + if [ "${is_cpio_compressed}" = "compressed" ]; then + cat ${cpio_tfile} > ${output_file} + else +- (cat ${cpio_tfile} | ${compr} - > ${output_file}) \ ++ (cat ${cpio_tfile} | ${compr} > ${output_file}) \ + || (rm -f ${output_file} ; false) + fi + [ -z ${cpio_file} ] && rm ${cpio_tfile} +--- a/lib/decompress.c ++++ b/lib/decompress.c +@@ -48,6 +48,7 @@ static const struct compress_format comp + { {037, 0236}, "gzip", gunzip }, + { {0x42, 0x5a}, "bzip2", bunzip2 }, + { {0x5d, 0x00}, "lzma", unlzma }, ++ { {0x6d, 0x00}, "lzma-openwrt", unlzma }, + { {0xfd, 0x37}, "xz", unxz }, + { {0x89, 0x4c}, "lzo", unlzo }, + { {0x02, 0x21}, "lz4", unlz4 }, diff --git a/target/linux/generic/patches-3.18/250-netfilter_depends.patch b/target/linux/generic/patches-3.18/250-netfilter_depends.patch new file mode 100644 index 0000000..47be4a0 --- /dev/null +++ b/target/linux/generic/patches-3.18/250-netfilter_depends.patch @@ -0,0 +1,18 @@ +--- a/net/netfilter/Kconfig ++++ b/net/netfilter/Kconfig +@@ -210,7 +210,6 @@ config NF_CONNTRACK_FTP + + config NF_CONNTRACK_H323 + tristate "H.323 protocol support" +- depends on (IPV6 || IPV6=n) + depends on NETFILTER_ADVANCED + help + H.323 is a VoIP signalling protocol from ITU-T. As one of the most +@@ -907,7 +906,6 @@ config NETFILTER_XT_TARGET_SECMARK + + config NETFILTER_XT_TARGET_TCPMSS + tristate '"TCPMSS" target support' +- depends on (IPV6 || IPV6=n) + default m if NETFILTER_ADVANCED=n + ---help--- + This option adds a `TCPMSS' target, which allows you to alter the diff --git a/target/linux/generic/patches-3.18/251-sound_kconfig.patch b/target/linux/generic/patches-3.18/251-sound_kconfig.patch new file mode 100644 index 0000000..c2ebace --- /dev/null +++ b/target/linux/generic/patches-3.18/251-sound_kconfig.patch @@ -0,0 +1,18 @@ +--- a/sound/core/Kconfig ++++ b/sound/core/Kconfig +@@ -10,13 +10,13 @@ config SND_DMAENGINE_PCM + tristate + + config SND_HWDEP +- tristate ++ tristate "Sound hardware support" + + config SND_RAWMIDI + tristate + + config SND_COMPRESS_OFFLOAD +- tristate ++ tristate "Compression offloading support" + + # To be effective this also requires INPUT - users should say: + # select SND_JACK if INPUT=y || INPUT=SND diff --git a/target/linux/generic/patches-3.18/252-mv_cesa_depends.patch b/target/linux/generic/patches-3.18/252-mv_cesa_depends.patch new file mode 100644 index 0000000..fee28db --- /dev/null +++ b/target/linux/generic/patches-3.18/252-mv_cesa_depends.patch @@ -0,0 +1,10 @@ +--- a/drivers/crypto/Kconfig ++++ b/drivers/crypto/Kconfig +@@ -164,6 +164,7 @@ config CRYPTO_DEV_MV_CESA + depends on PLAT_ORION + select CRYPTO_ALGAPI + select CRYPTO_AES ++ select CRYPTO_HASH2 + select CRYPTO_BLKCIPHER2 + select CRYPTO_HASH + help diff --git a/target/linux/generic/patches-3.18/253-ssb_b43_default_on.patch b/target/linux/generic/patches-3.18/253-ssb_b43_default_on.patch new file mode 100644 index 0000000..29d2a41 --- /dev/null +++ b/target/linux/generic/patches-3.18/253-ssb_b43_default_on.patch @@ -0,0 +1,29 @@ +--- a/drivers/ssb/Kconfig ++++ b/drivers/ssb/Kconfig +@@ -29,6 +29,7 @@ config SSB_SPROM + config SSB_BLOCKIO + bool + depends on SSB ++ default y + + config SSB_PCIHOST_POSSIBLE + bool +@@ -49,7 +50,7 @@ config SSB_PCIHOST + config SSB_B43_PCI_BRIDGE + bool + depends on SSB_PCIHOST +- default n ++ default y + + config SSB_PCMCIAHOST_POSSIBLE + bool +--- a/drivers/bcma/Kconfig ++++ b/drivers/bcma/Kconfig +@@ -17,6 +17,7 @@ config BCMA + config BCMA_BLOCKIO + bool + depends on BCMA ++ default y + + config BCMA_HOST_PCI_POSSIBLE + bool diff --git a/target/linux/generic/patches-3.18/254-textsearch_kconfig_hacks.patch b/target/linux/generic/patches-3.18/254-textsearch_kconfig_hacks.patch new file mode 100644 index 0000000..3c3b1e1 --- /dev/null +++ b/target/linux/generic/patches-3.18/254-textsearch_kconfig_hacks.patch @@ -0,0 +1,23 @@ +--- a/lib/Kconfig ++++ b/lib/Kconfig +@@ -320,16 +320,16 @@ config BCH_CONST_T + # Textsearch support is select'ed if needed + # + config TEXTSEARCH +- boolean ++ boolean "Textsearch support" + + config TEXTSEARCH_KMP +- tristate ++ tristate "Textsearch KMP" + + config TEXTSEARCH_BM +- tristate ++ tristate "Textsearch BM" + + config TEXTSEARCH_FSM +- tristate ++ tristate "Textsearch FSM" + + config BTREE + boolean diff --git a/target/linux/generic/patches-3.18/255-lib80211_kconfig_hacks.patch b/target/linux/generic/patches-3.18/255-lib80211_kconfig_hacks.patch new file mode 100644 index 0000000..d875235 --- /dev/null +++ b/target/linux/generic/patches-3.18/255-lib80211_kconfig_hacks.patch @@ -0,0 +1,31 @@ +--- a/net/wireless/Kconfig ++++ b/net/wireless/Kconfig +@@ -183,7 +183,7 @@ config CFG80211_WEXT + extensions with cfg80211-based drivers. + + config LIB80211 +- tristate ++ tristate "LIB80211" + default n + help + This options enables a library of common routines used +@@ -192,13 +192,16 @@ config LIB80211 + Drivers should select this themselves if needed. + + config LIB80211_CRYPT_WEP +- tristate ++ tristate "LIB80211_CRYPT_WEP" ++ select LIB80211 + + config LIB80211_CRYPT_CCMP +- tristate ++ tristate "LIB80211_CRYPT_CCMP" ++ select LIB80211 + + config LIB80211_CRYPT_TKIP +- tristate ++ tristate "LIB80211_CRYPT_TKIP" ++ select LIB80211 + + config LIB80211_DEBUG + bool "lib80211 debugging messages" diff --git a/target/linux/generic/patches-3.18/256-crypto_add_kconfig_prompts.patch b/target/linux/generic/patches-3.18/256-crypto_add_kconfig_prompts.patch new file mode 100644 index 0000000..f9f6c0e --- /dev/null +++ b/target/linux/generic/patches-3.18/256-crypto_add_kconfig_prompts.patch @@ -0,0 +1,47 @@ +--- a/crypto/Kconfig ++++ b/crypto/Kconfig +@@ -32,7 +32,7 @@ config CRYPTO_FIPS + this is. + + config CRYPTO_ALGAPI +- tristate ++ tristate "ALGAPI" + select CRYPTO_ALGAPI2 + help + This option provides the API for cryptographic algorithms. +@@ -41,7 +41,7 @@ config CRYPTO_ALGAPI2 + tristate + + config CRYPTO_AEAD +- tristate ++ tristate "AEAD" + select CRYPTO_AEAD2 + select CRYPTO_ALGAPI + +@@ -50,7 +50,7 @@ config CRYPTO_AEAD2 + select CRYPTO_ALGAPI2 + + config CRYPTO_BLKCIPHER +- tristate ++ tristate "BLKCIPHER" + select CRYPTO_BLKCIPHER2 + select CRYPTO_ALGAPI + +@@ -61,7 +61,7 @@ config CRYPTO_BLKCIPHER2 + select CRYPTO_WORKQUEUE + + config CRYPTO_HASH +- tristate ++ tristate "HASH" + select CRYPTO_HASH2 + select CRYPTO_ALGAPI + +@@ -70,7 +70,7 @@ config CRYPTO_HASH2 + select CRYPTO_ALGAPI2 + + config CRYPTO_RNG +- tristate ++ tristate "RNG" + select CRYPTO_RNG2 + select CRYPTO_ALGAPI + diff --git a/target/linux/generic/patches-3.18/257-wireless_ext_kconfig_hack.patch b/target/linux/generic/patches-3.18/257-wireless_ext_kconfig_hack.patch new file mode 100644 index 0000000..daac589 --- /dev/null +++ b/target/linux/generic/patches-3.18/257-wireless_ext_kconfig_hack.patch @@ -0,0 +1,22 @@ +--- a/net/wireless/Kconfig ++++ b/net/wireless/Kconfig +@@ -1,5 +1,5 @@ + config WIRELESS_EXT +- bool ++ bool "Wireless extensions" + + config WEXT_CORE + def_bool y +@@ -11,10 +11,10 @@ config WEXT_PROC + depends on WEXT_CORE + + config WEXT_SPY +- bool ++ bool "WEXT_SPY" + + config WEXT_PRIV +- bool ++ bool "WEXT_PRIV" + + config CFG80211 + tristate "cfg80211 - wireless configuration API" diff --git a/target/linux/generic/patches-3.18/258-netfilter_netlink_kconfig_hack.patch b/target/linux/generic/patches-3.18/258-netfilter_netlink_kconfig_hack.patch new file mode 100644 index 0000000..9d827c2 --- /dev/null +++ b/target/linux/generic/patches-3.18/258-netfilter_netlink_kconfig_hack.patch @@ -0,0 +1,11 @@ +--- a/net/netfilter/Kconfig ++++ b/net/netfilter/Kconfig +@@ -2,7 +2,7 @@ menu "Core Netfilter Configuration" + depends on NET && INET && NETFILTER + + config NETFILTER_NETLINK +- tristate ++ tristate "Netfilter NFNETLINK interface" + + config NETFILTER_NETLINK_ACCT + tristate "Netfilter NFACCT over NFNETLINK interface" diff --git a/target/linux/generic/patches-3.18/259-regmap_dynamic.patch b/target/linux/generic/patches-3.18/259-regmap_dynamic.patch new file mode 100644 index 0000000..b1d4ad2 --- /dev/null +++ b/target/linux/generic/patches-3.18/259-regmap_dynamic.patch @@ -0,0 +1,80 @@ +--- a/drivers/base/regmap/Kconfig ++++ b/drivers/base/regmap/Kconfig +@@ -3,26 +3,31 @@ + # subsystems should select the appropriate symbols. + + config REGMAP +- default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_MMIO || REGMAP_IRQ) + select LZO_COMPRESS + select LZO_DECOMPRESS + select IRQ_DOMAIN if REGMAP_IRQ +- bool ++ tristate "Regmap" + + config REGMAP_I2C +- tristate ++ tristate "Regmap I2C" ++ select REGMAP + depends on I2C + + config REGMAP_SPI +- tristate ++ tristate "Regmap SPI" ++ select REGMAP ++ depends on SPI_MASTER + depends on SPI + + config REGMAP_SPMI ++ select REGMAP + tristate + depends on SPMI + + config REGMAP_MMIO +- tristate ++ tristate "Regmap MMIO" ++ select REGMAP + + config REGMAP_IRQ ++ select REGMAP + bool +--- a/include/linux/regmap.h ++++ b/include/linux/regmap.h +@@ -49,7 +49,7 @@ struct reg_default { + unsigned int def; + }; + +-#ifdef CONFIG_REGMAP ++#if IS_ENABLED(CONFIG_REGMAP) + + enum regmap_endian { + /* Unspecified -> 0 -> Backwards compatible default */ +--- a/drivers/base/regmap/Makefile ++++ b/drivers/base/regmap/Makefile +@@ -1,6 +1,8 @@ +-obj-$(CONFIG_REGMAP) += regmap.o regcache.o +-obj-$(CONFIG_REGMAP) += regcache-rbtree.o regcache-lzo.o regcache-flat.o +-obj-$(CONFIG_DEBUG_FS) += regmap-debugfs.o ++regmap-core-objs = regmap.o regcache.o regcache-rbtree.o regcache-lzo.o regcache-flat.o ++ifdef CONFIG_DEBUG_FS ++regmap-core-objs += regmap-debugfs.o ++endif ++obj-$(CONFIG_REGMAP) += regmap-core.o + obj-$(CONFIG_REGMAP_I2C) += regmap-i2c.o + obj-$(CONFIG_REGMAP_SPI) += regmap-spi.o + obj-$(CONFIG_REGMAP_SPMI) += regmap-spmi.o +--- a/drivers/base/regmap/regmap.c ++++ b/drivers/base/regmap/regmap.c +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -2630,3 +2631,5 @@ static int __init regmap_initcall(void) + return 0; + } + postcore_initcall(regmap_initcall); ++ ++MODULE_LICENSE("GPL"); diff --git a/target/linux/generic/patches-3.18/260-crypto_test_dependencies.patch b/target/linux/generic/patches-3.18/260-crypto_test_dependencies.patch new file mode 100644 index 0000000..8a96fd9 --- /dev/null +++ b/target/linux/generic/patches-3.18/260-crypto_test_dependencies.patch @@ -0,0 +1,37 @@ +--- a/crypto/Kconfig ++++ b/crypto/Kconfig +@@ -96,10 +96,10 @@ config CRYPTO_MANAGER + + config CRYPTO_MANAGER2 + def_tristate CRYPTO_MANAGER || (CRYPTO_MANAGER!=n && CRYPTO_ALGAPI=y) +- select CRYPTO_AEAD2 +- select CRYPTO_HASH2 +- select CRYPTO_BLKCIPHER2 +- select CRYPTO_PCOMP2 ++ select CRYPTO_AEAD2 if !CRYPTO_MANAGER_DISABLE_TESTS ++ select CRYPTO_HASH2 if !CRYPTO_MANAGER_DISABLE_TESTS ++ select CRYPTO_BLKCIPHER2 if !CRYPTO_MANAGER_DISABLE_TESTS ++ select CRYPTO_PCOMP2 if !CRYPTO_MANAGER_DISABLE_TESTS + + config CRYPTO_USER + tristate "Userspace cryptographic algorithm configuration" +--- a/crypto/algboss.c ++++ b/crypto/algboss.c +@@ -248,6 +248,9 @@ static int cryptomgr_schedule_test(struc + type = alg->cra_flags; + + /* This piece of crap needs to disappear into per-type test hooks. */ ++#ifdef CONFIG_CRYPTO_MANAGER_DISABLE_TESTS ++ type |= CRYPTO_ALG_TESTED; ++#else + if ((!((type ^ CRYPTO_ALG_TYPE_BLKCIPHER) & + CRYPTO_ALG_TYPE_BLKCIPHER_MASK) && !(type & CRYPTO_ALG_GENIV) && + ((alg->cra_flags & CRYPTO_ALG_TYPE_MASK) == +@@ -256,6 +259,7 @@ static int cryptomgr_schedule_test(struc + (!((type ^ CRYPTO_ALG_TYPE_AEAD) & CRYPTO_ALG_TYPE_MASK) && + alg->cra_type == &crypto_nivaead_type && alg->cra_aead.ivsize)) + type |= CRYPTO_ALG_TESTED; ++#endif + + param->type = type; + diff --git a/target/linux/generic/patches-3.18/262-compressor_kconfig_hack.patch b/target/linux/generic/patches-3.18/262-compressor_kconfig_hack.patch new file mode 100644 index 0000000..51b4fc8 --- /dev/null +++ b/target/linux/generic/patches-3.18/262-compressor_kconfig_hack.patch @@ -0,0 +1,35 @@ +--- a/lib/Kconfig ++++ b/lib/Kconfig +@@ -205,25 +205,25 @@ config RANDOM32_SELFTEST + # compression support is select'ed if needed + # + config ZLIB_INFLATE +- tristate ++ tristate "ZLIB inflate support" + + config ZLIB_DEFLATE +- tristate ++ tristate "ZLIB deflate support" + + config LZO_COMPRESS +- tristate ++ tristate "LZO compress support" + + config LZO_DECOMPRESS +- tristate ++ tristate "LZO decompress support" + + config LZ4_COMPRESS +- tristate ++ tristate "LZ4 compress support" + + config LZ4HC_COMPRESS +- tristate ++ tristate "LZ4HC compress support" + + config LZ4_DECOMPRESS +- tristate ++ tristate "LZ4 decompress support" + + source "lib/xz/Kconfig" + diff --git a/target/linux/generic/patches-3.18/270-uapi-kernel.h-glibc-specific-inclusion-of-sysinfo.h.patch b/target/linux/generic/patches-3.18/270-uapi-kernel.h-glibc-specific-inclusion-of-sysinfo.h.patch new file mode 100644 index 0000000..762f498 --- /dev/null +++ b/target/linux/generic/patches-3.18/270-uapi-kernel.h-glibc-specific-inclusion-of-sysinfo.h.patch @@ -0,0 +1,34 @@ +From 8b05e325824d3b38e52a7748b3b5dc34dc1c0f6d Mon Sep 17 00:00:00 2001 +From: David Heidelberger +Date: Mon, 29 Jun 2015 14:37:54 +0200 +Subject: [PATCH 1/3] uapi/kernel.h: glibc specific inclusion of sysinfo.h + +including sysinfo.h from kernel.h makes no sense whatsoever, +but removing it breaks glibc's userspace header, +which includes kernel.h instead of sysinfo.h from their sys/sysinfo.h. +this seems to be a historical mistake. +on musl, including any header that uses kernel.h directly or indirectly +plus sys/sysinfo.h will produce a compile error due to redefinition of +struct sysinfo from sys/sysinfo.h. +so for now, only include it on glibc or when including from kernel +in order not to break their headers. + +Signed-off-by: John Spencer +Signed-off-by: David Heidelberger +Signed-off-by: Jonas Gorski +--- + include/uapi/linux/kernel.h | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/include/uapi/linux/kernel.h ++++ b/include/uapi/linux/kernel.h +@@ -1,7 +1,9 @@ + #ifndef _UAPI_LINUX_KERNEL_H + #define _UAPI_LINUX_KERNEL_H + ++#if defined(__KERNEL__) || defined( __GLIBC__) + #include ++#endif + + /* + * 'kernel.h' contains some often-used function prototypes etc diff --git a/target/linux/generic/patches-3.18/271-uapi-libc-compat.h-do-not-rely-on-__GLIBC__.patch b/target/linux/generic/patches-3.18/271-uapi-libc-compat.h-do-not-rely-on-__GLIBC__.patch new file mode 100644 index 0000000..891299e --- /dev/null +++ b/target/linux/generic/patches-3.18/271-uapi-libc-compat.h-do-not-rely-on-__GLIBC__.patch @@ -0,0 +1,81 @@ +From f972afc2509eebcb00d370256c55b112a3b5ffca Mon Sep 17 00:00:00 2001 +From: David Heidelberger +Date: Mon, 29 Jun 2015 16:50:40 +0200 +Subject: [PATCH 2/3] uapi/libc-compat.h: do not rely on __GLIBC__ + +Musl provides the same structs as glibc, but does not provide a define to +allow its detection. Since the absence of __GLIBC__ also can mean that it +is included from the kernel, change the __GLIBC__ detection to +!__KERNEL__, which should always be true when included from userspace. + +Signed-off-by: John Spencer +Tested-by: David Heidelberger +Signed-off-by: Jonas Gorski +--- + include/uapi/linux/libc-compat.h | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +--- a/include/uapi/linux/libc-compat.h ++++ b/include/uapi/linux/libc-compat.h +@@ -48,13 +48,13 @@ + #ifndef _UAPI_LIBC_COMPAT_H + #define _UAPI_LIBC_COMPAT_H + +-/* We have included glibc headers... */ +-#if defined(__GLIBC__) ++/* We have included libc headers... */ ++#if !defined(__KERNEL__) + +-/* Coordinate with glibc netinet/in.h header. */ ++/* Coordinate with libc netinet/in.h header. */ + #if defined(_NETINET_IN_H) + +-/* GLIBC headers included first so don't define anything ++/* LIBC headers included first so don't define anything + * that would already be defined. */ + #define __UAPI_DEF_IN_ADDR 0 + #define __UAPI_DEF_IN_IPPROTO 0 +@@ -68,7 +68,7 @@ + * if the glibc code didn't define them. This guard matches + * the guard in glibc/inet/netinet/in.h which defines the + * additional in6_addr macros e.g. s6_addr16, and s6_addr32. */ +-#if defined(__USE_MISC) || defined (__USE_GNU) ++#if !defined(__GLIBC__) || defined(__USE_MISC) || defined (__USE_GNU) + #define __UAPI_DEF_IN6_ADDR_ALT 0 + #else + #define __UAPI_DEF_IN6_ADDR_ALT 1 +@@ -81,7 +81,7 @@ + #else + + /* Linux headers included first, and we must define everything +- * we need. The expectation is that glibc will check the ++ * we need. The expectation is that the libc will check the + * __UAPI_DEF_* defines and adjust appropriately. */ + #define __UAPI_DEF_IN_ADDR 1 + #define __UAPI_DEF_IN_IPPROTO 1 +@@ -91,7 +91,7 @@ + #define __UAPI_DEF_IN_CLASS 1 + + #define __UAPI_DEF_IN6_ADDR 1 +-/* We unconditionally define the in6_addr macros and glibc must ++/* We unconditionally define the in6_addr macros and the libc must + * coordinate. */ + #define __UAPI_DEF_IN6_ADDR_ALT 1 + #define __UAPI_DEF_SOCKADDR_IN6 1 +@@ -111,7 +111,7 @@ + /* If we did not see any headers from any supported C libraries, + * or we are being included in the kernel, then define everything + * that we need. */ +-#else /* !defined(__GLIBC__) */ ++#else /* defined(__KERNEL__) */ + + /* Definitions for in.h */ + #define __UAPI_DEF_IN_ADDR 1 +@@ -132,6 +132,6 @@ + /* Definitions for xattr.h */ + #define __UAPI_DEF_XATTR 1 + +-#endif /* __GLIBC__ */ ++#endif /* __KERNEL__ */ + + #endif /* _UAPI_LIBC_COMPAT_H */ diff --git a/target/linux/generic/patches-3.18/272-uapi-if_ether.h-prevent-redefinition-of-struct-ethhd.patch b/target/linux/generic/patches-3.18/272-uapi-if_ether.h-prevent-redefinition-of-struct-ethhd.patch new file mode 100644 index 0000000..feea4c3 --- /dev/null +++ b/target/linux/generic/patches-3.18/272-uapi-if_ether.h-prevent-redefinition-of-struct-ethhd.patch @@ -0,0 +1,67 @@ +From fcbb6fed85ea9ff4feb4f1ebd4f0f235fdaf06b6 Mon Sep 17 00:00:00 2001 +From: David Heidelberger +Date: Mon, 29 Jun 2015 16:53:03 +0200 +Subject: [PATCH 3/3] uapi/if_ether.h: prevent redefinition of struct ethhdr + +Musl provides its own ethhdr struct definition. Add a guard to prevent +its definition of the appropriate musl header has already been included. + +Signed-off-by: John Spencer +Tested-by: David Heidelberger +Signed-off-by: Jonas Gorski +--- + include/uapi/linux/if_ether.h | 3 +++ + include/uapi/linux/libc-compat.h | 11 +++++++++++ + 2 files changed, 14 insertions(+) + +--- a/include/uapi/linux/if_ether.h ++++ b/include/uapi/linux/if_ether.h +@@ -22,6 +22,7 @@ + #define _UAPI_LINUX_IF_ETHER_H + + #include ++#include + + /* + * IEEE 802.3 Ethernet magic constants. The frame sizes omit the preamble +@@ -134,11 +135,13 @@ + * This is an Ethernet frame header. + */ + ++#if __UAPI_DEF_ETHHDR + struct ethhdr { + unsigned char h_dest[ETH_ALEN]; /* destination eth addr */ + unsigned char h_source[ETH_ALEN]; /* source ether addr */ + __be16 h_proto; /* packet type ID field */ + } __attribute__((packed)); ++#endif + + + #endif /* _UAPI_LINUX_IF_ETHER_H */ +--- a/include/uapi/linux/libc-compat.h ++++ b/include/uapi/linux/libc-compat.h +@@ -51,6 +51,14 @@ + /* We have included libc headers... */ + #if !defined(__KERNEL__) + ++/* musl defines the ethhdr struct itself in its netinet/if_ether.h. ++ * Glibc just includes the kernel header and uses a different guard. */ ++#if defined(_NETINET_IF_ETHER_H) ++#define __UAPI_DEF_ETHHDR 0 ++#else ++#define __UAPI_DEF_ETHHDR 1 ++#endif ++ + /* Coordinate with libc netinet/in.h header. */ + #if defined(_NETINET_IN_H) + +@@ -113,6 +121,9 @@ + * that we need. */ + #else /* defined(__KERNEL__) */ + ++/* Definitions for if_ether.h */ ++#define __UAPI_DEF_ETHHDR 1 ++ + /* Definitions for in.h */ + #define __UAPI_DEF_IN_ADDR 1 + #define __UAPI_DEF_IN_IPPROTO 1 diff --git a/target/linux/generic/patches-3.18/300-mips_expose_boot_raw.patch b/target/linux/generic/patches-3.18/300-mips_expose_boot_raw.patch new file mode 100644 index 0000000..69d61f2 --- /dev/null +++ b/target/linux/generic/patches-3.18/300-mips_expose_boot_raw.patch @@ -0,0 +1,39 @@ +From: Mark Miller + +This exposes the CONFIG_BOOT_RAW symbol in Kconfig. This is needed on +certain Broadcom chipsets running CFE in order to load the kernel. + +Signed-off-by: Mark Miller +Acked-by: Rob Landley +--- +--- a/arch/mips/Kconfig ++++ b/arch/mips/Kconfig +@@ -892,9 +892,6 @@ config FW_ARC + config ARCH_MAY_HAVE_PC_FDC + bool + +-config BOOT_RAW +- bool +- + config CEVT_BCM1480 + bool + +@@ -2503,6 +2500,18 @@ config USE_OF + config BUILTIN_DTB + bool + ++config BOOT_RAW ++ bool "Enable the kernel to be executed from the load address" ++ default n ++ help ++ Allow the kernel to be executed from the load address for ++ bootloaders which cannot read the ELF format. This places ++ a jump to start_kernel at the load address. ++ ++ If unsure, say N. ++ ++ ++ + endmenu + + config LOCKDEP_SUPPORT diff --git a/target/linux/generic/patches-3.18/301-mips_image_cmdline_hack.patch b/target/linux/generic/patches-3.18/301-mips_image_cmdline_hack.patch new file mode 100644 index 0000000..c87d448 --- /dev/null +++ b/target/linux/generic/patches-3.18/301-mips_image_cmdline_hack.patch @@ -0,0 +1,28 @@ +--- a/arch/mips/Kconfig ++++ b/arch/mips/Kconfig +@@ -988,6 +988,10 @@ config SYNC_R4K + config MIPS_MACHINE + def_bool n + ++config IMAGE_CMDLINE_HACK ++ bool "OpenWrt specific image command line hack" ++ default n ++ + config NO_IOPORT_MAP + def_bool n + +--- a/arch/mips/kernel/head.S ++++ b/arch/mips/kernel/head.S +@@ -80,6 +80,12 @@ FEXPORT(__kernel_entry) + j kernel_entry + #endif + ++#ifdef CONFIG_IMAGE_CMDLINE_HACK ++ .ascii "CMDLINE:" ++EXPORT(__image_cmdline) ++ .fill 0x400 ++#endif /* CONFIG_IMAGE_CMDLINE_HACK */ ++ + __REF + + NESTED(kernel_entry, 16, sp) # kernel entry point diff --git a/target/linux/generic/patches-3.18/302-mips_no_branch_likely.patch b/target/linux/generic/patches-3.18/302-mips_no_branch_likely.patch new file mode 100644 index 0000000..44c6b04 --- /dev/null +++ b/target/linux/generic/patches-3.18/302-mips_no_branch_likely.patch @@ -0,0 +1,11 @@ +--- a/arch/mips/Makefile ++++ b/arch/mips/Makefile +@@ -87,7 +87,7 @@ all-$(CONFIG_SYS_SUPPORTS_ZBOOT)+= vmlin + # machines may also. Since BFD is incredibly buggy with respect to + # crossformat linking we rely on the elf2ecoff tool for format conversion. + # +-cflags-y += -G 0 -mno-abicalls -fno-pic -pipe ++cflags-y += -G 0 -mno-abicalls -fno-pic -pipe -mno-branch-likely + cflags-y += -msoft-float + LDFLAGS_vmlinux += -G 0 -static -n -nostdlib --gc-sections + KBUILD_AFLAGS_MODULE += -mlong-calls diff --git a/target/linux/generic/patches-3.18/304-mips_disable_fpu.patch b/target/linux/generic/patches-3.18/304-mips_disable_fpu.patch new file mode 100644 index 0000000..779e20a --- /dev/null +++ b/target/linux/generic/patches-3.18/304-mips_disable_fpu.patch @@ -0,0 +1,105 @@ +From: Manuel Lauss +Subject: [RFC PATCH v4 2/2] MIPS: make FPU emulator optional +Date: Mon, 7 Apr 2014 12:57:04 +0200 +Message-Id: <1396868224-252888-2-git-send-email-manuel.lauss@gmail.com> + +This small patch makes the MIPS FPU emulator optional. The kernel +kills float-users on systems without a hardware FPU by sending a SIGILL. + +Disabling the emulator shrinks vmlinux by about 54kBytes (32bit, +optimizing for size). + +Signed-off-by: Manuel Lauss +--- +v4: rediffed because of patch 1/2, should now work with micromips as well +v3: updated patch description with size savings. +v2: incorporated changes suggested by Jonas Gorski + force the fpu emulator on for micromips: relocating the parts + of the mmips code in the emulator to other areas would be a + much larger change; I went the cheap route instead with this. + + arch/mips/Kbuild | 2 +- + arch/mips/Kconfig | 14 ++++++++++++++ + arch/mips/include/asm/fpu.h | 5 +++-- + arch/mips/include/asm/fpu_emulator.h | 15 +++++++++++++++ + 4 files changed, 33 insertions(+), 3 deletions(-) + +--- a/arch/mips/Kconfig ++++ b/arch/mips/Kconfig +@@ -2495,6 +2495,20 @@ config MIPS_O32_FP64_SUPPORT + + If unsure, say N. + ++config MIPS_FPU_EMULATOR ++ bool "MIPS FPU Emulator" ++ default y ++ help ++ This option lets you disable the built-in MIPS FPU (Coprocessor 1) ++ emulator, which handles floating-point instructions on processors ++ without a hardware FPU. It is generally a good idea to keep the ++ emulator built-in, unless you are perfectly sure you have a ++ complete soft-float environment. With the emulator disabled, all ++ users of float operations will be killed with an illegal instr- ++ uction exception. ++ ++ Say Y, please. ++ + config USE_OF + bool + select OF +--- a/arch/mips/Makefile ++++ b/arch/mips/Makefile +@@ -275,7 +275,7 @@ OBJCOPYFLAGS += --remove-section=.regin + head-y := arch/mips/kernel/head.o + + libs-y += arch/mips/lib/ +-libs-y += arch/mips/math-emu/ ++libs-$(CONFIG_MIPS_FPU_EMULATOR) += arch/mips/math-emu/ + + # See arch/mips/Kbuild for content of core part of the kernel + core-y += arch/mips/ +--- a/arch/mips/include/asm/fpu.h ++++ b/arch/mips/include/asm/fpu.h +@@ -169,8 +169,10 @@ static inline int init_fpu(void) + ret = __own_fpu(); + if (!ret) + _init_fpu(); +- } else ++ } else if (IS_ENABLED(CONFIG_MIPS_FPU_EMULATOR)) + fpu_emulator_init_fpu(); ++ else ++ ret = SIGILL; + + return ret; + } +--- a/arch/mips/include/asm/fpu_emulator.h ++++ b/arch/mips/include/asm/fpu_emulator.h +@@ -30,6 +30,7 @@ + #include + #include + ++#ifdef CONFIG_MIPS_FPU_EMULATOR + #ifdef CONFIG_DEBUG_FS + + struct mips_fpu_emulator_stats { +@@ -65,6 +66,20 @@ extern int do_dsemulret(struct pt_regs * + extern int fpu_emulator_cop1Handler(struct pt_regs *xcp, + struct mips_fpu_struct *ctx, int has_fpu, + void *__user *fault_addr); ++#else /* no CONFIG_MIPS_FPU_EMULATOR */ ++static inline int do_dsemulret(struct pt_regs *xcp) ++{ ++ return 0; /* 0 means error, should never get here anyway */ ++} ++ ++static inline int fpu_emulator_cop1Handler(struct pt_regs *xcp, ++ struct mips_fpu_struct *ctx, int has_fpu, ++ void *__user *fault_addr) ++{ ++ return SIGILL; /* we don't speak MIPS FPU */ ++} ++#endif /* CONFIG_MIPS_FPU_EMULATOR */ ++ + int process_fpemu_return(int sig, void __user *fault_addr); + int mm_isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, + unsigned long *contpc); diff --git a/target/linux/generic/patches-3.18/305-mips_module_reloc.patch b/target/linux/generic/patches-3.18/305-mips_module_reloc.patch new file mode 100644 index 0000000..f8ca914 --- /dev/null +++ b/target/linux/generic/patches-3.18/305-mips_module_reloc.patch @@ -0,0 +1,353 @@ +--- a/arch/mips/Makefile ++++ b/arch/mips/Makefile +@@ -90,8 +90,13 @@ all-$(CONFIG_SYS_SUPPORTS_ZBOOT)+= vmlin + cflags-y += -G 0 -mno-abicalls -fno-pic -pipe -mno-branch-likely + cflags-y += -msoft-float + LDFLAGS_vmlinux += -G 0 -static -n -nostdlib --gc-sections ++ifdef CONFIG_64BIT + KBUILD_AFLAGS_MODULE += -mlong-calls + KBUILD_CFLAGS_MODULE += -mlong-calls ++else ++KBUILD_AFLAGS_MODULE += -mno-long-calls ++KBUILD_CFLAGS_MODULE += -mno-long-calls ++endif + + ifndef CONFIG_FUNCTION_TRACER + KBUILD_CFLAGS_KERNEL += -ffunction-sections -fdata-sections +--- a/arch/mips/include/asm/module.h ++++ b/arch/mips/include/asm/module.h +@@ -11,6 +11,11 @@ struct mod_arch_specific { + const struct exception_table_entry *dbe_start; + const struct exception_table_entry *dbe_end; + struct mips_hi16 *r_mips_hi16_list; ++ ++ void *phys_plt_tbl; ++ void *virt_plt_tbl; ++ unsigned int phys_plt_offset; ++ unsigned int virt_plt_offset; + }; + + typedef uint8_t Elf64_Byte; /* Type for a 8-bit quantity. */ +--- a/arch/mips/kernel/module.c ++++ b/arch/mips/kernel/module.c +@@ -43,14 +43,222 @@ struct mips_hi16 { + static LIST_HEAD(dbe_list); + static DEFINE_SPINLOCK(dbe_lock); + +-#ifdef MODULE_START ++/* ++ * Get the potential max trampolines size required of the init and ++ * non-init sections. Only used if we cannot find enough contiguous ++ * physically mapped memory to put the module into. ++ */ ++static unsigned int ++get_plt_size(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, ++ const char *secstrings, unsigned int symindex, bool is_init) ++{ ++ unsigned long ret = 0; ++ unsigned int i, j; ++ Elf_Sym *syms; ++ ++ /* Everything marked ALLOC (this includes the exported symbols) */ ++ for (i = 1; i < hdr->e_shnum; ++i) { ++ unsigned int info = sechdrs[i].sh_info; ++ ++ if (sechdrs[i].sh_type != SHT_REL ++ && sechdrs[i].sh_type != SHT_RELA) ++ continue; ++ ++ /* Not a valid relocation section? */ ++ if (info >= hdr->e_shnum) ++ continue; ++ ++ /* Don't bother with non-allocated sections */ ++ if (!(sechdrs[info].sh_flags & SHF_ALLOC)) ++ continue; ++ ++ /* If it's called *.init*, and we're not init, we're ++ not interested */ ++ if ((strstr(secstrings + sechdrs[i].sh_name, ".init") != 0) ++ != is_init) ++ continue; ++ ++ syms = (Elf_Sym *) sechdrs[symindex].sh_addr; ++ if (sechdrs[i].sh_type == SHT_REL) { ++ Elf_Mips_Rel *rel = (void *) sechdrs[i].sh_addr; ++ unsigned int size = sechdrs[i].sh_size / sizeof(*rel); ++ ++ for (j = 0; j < size; ++j) { ++ Elf_Sym *sym; ++ ++ if (ELF_MIPS_R_TYPE(rel[j]) != R_MIPS_26) ++ continue; ++ ++ sym = syms + ELF_MIPS_R_SYM(rel[j]); ++ if (!is_init && sym->st_shndx != SHN_UNDEF) ++ continue; ++ ++ ret += 4 * sizeof(int); ++ } ++ } else { ++ Elf_Mips_Rela *rela = (void *) sechdrs[i].sh_addr; ++ unsigned int size = sechdrs[i].sh_size / sizeof(*rela); ++ ++ for (j = 0; j < size; ++j) { ++ Elf_Sym *sym; ++ ++ if (ELF_MIPS_R_TYPE(rela[j]) != R_MIPS_26) ++ continue; ++ ++ sym = syms + ELF_MIPS_R_SYM(rela[j]); ++ if (!is_init && sym->st_shndx != SHN_UNDEF) ++ continue; ++ ++ ret += 4 * sizeof(int); ++ } ++ } ++ } ++ ++ return ret; ++} ++ ++#ifndef MODULE_START ++static void *alloc_phys(unsigned long size) ++{ ++ unsigned order; ++ struct page *page; ++ struct page *p; ++ ++ size = PAGE_ALIGN(size); ++ order = get_order(size); ++ ++ page = alloc_pages(GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN | ++ __GFP_THISNODE, order); ++ if (!page) ++ return NULL; ++ ++ split_page(page, order); ++ ++ for (p = page + (size >> PAGE_SHIFT); p < page + (1 << order); ++p) ++ __free_page(p); ++ ++ return page_address(page); ++} ++#endif ++ ++static void free_phys(void *ptr, unsigned long size) ++{ ++ struct page *page; ++ struct page *end; ++ ++ page = virt_to_page(ptr); ++ end = page + (PAGE_ALIGN(size) >> PAGE_SHIFT); ++ ++ for (; page < end; ++page) ++ __free_page(page); ++} ++ ++ + void *module_alloc(unsigned long size) + { ++#ifdef MODULE_START + return __vmalloc_node_range(size, 1, MODULE_START, MODULE_END, + GFP_KERNEL, PAGE_KERNEL, NUMA_NO_NODE, + __builtin_return_address(0)); ++#else ++ void *ptr; ++ ++ if (size == 0) ++ return NULL; ++ ++ ptr = alloc_phys(size); ++ ++ /* If we failed to allocate physically contiguous memory, ++ * fall back to regular vmalloc. The module loader code will ++ * create jump tables to handle long jumps */ ++ if (!ptr) ++ return vmalloc(size); ++ ++ return ptr; ++#endif + } ++ ++static inline bool is_phys_addr(void *ptr) ++{ ++#ifdef CONFIG_64BIT ++ return (KSEGX((unsigned long)ptr) == CKSEG0); ++#else ++ return (KSEGX(ptr) == KSEG0); + #endif ++} ++ ++/* Free memory returned from module_alloc */ ++void module_free(struct module *mod, void *module_region) ++{ ++ if (is_phys_addr(module_region)) { ++ if (mod->module_init == module_region) ++ free_phys(module_region, mod->init_size); ++ else if (mod->module_core == module_region) ++ free_phys(module_region, mod->core_size); ++ else ++ BUG(); ++ } else { ++ vfree(module_region); ++ } ++} ++ ++static void *__module_alloc(int size, bool phys) ++{ ++ void *ptr; ++ ++ if (phys) ++ ptr = kmalloc(size, GFP_KERNEL); ++ else ++ ptr = vmalloc(size); ++ return ptr; ++} ++ ++static void __module_free(void *ptr) ++{ ++ if (is_phys_addr(ptr)) ++ kfree(ptr); ++ else ++ vfree(ptr); ++} ++ ++int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs, ++ char *secstrings, struct module *mod) ++{ ++ unsigned int symindex = 0; ++ unsigned int core_size, init_size; ++ int i; ++ ++ mod->arch.phys_plt_offset = 0; ++ mod->arch.virt_plt_offset = 0; ++ mod->arch.phys_plt_tbl = NULL; ++ mod->arch.virt_plt_tbl = NULL; ++ ++ if (IS_ENABLED(CONFIG_64BIT)) ++ return 0; ++ ++ for (i = 1; i < hdr->e_shnum; i++) ++ if (sechdrs[i].sh_type == SHT_SYMTAB) ++ symindex = i; ++ ++ core_size = get_plt_size(hdr, sechdrs, secstrings, symindex, false); ++ init_size = get_plt_size(hdr, sechdrs, secstrings, symindex, true); ++ ++ if ((core_size + init_size) == 0) ++ return 0; ++ ++ mod->arch.phys_plt_tbl = __module_alloc(core_size + init_size, 1); ++ if (!mod->arch.phys_plt_tbl) ++ return -ENOMEM; ++ ++ mod->arch.virt_plt_tbl = __module_alloc(core_size + init_size, 0); ++ if (!mod->arch.virt_plt_tbl) { ++ __module_free(mod->arch.phys_plt_tbl); ++ mod->arch.phys_plt_tbl = NULL; ++ return -ENOMEM; ++ } ++ ++ return 0; ++} + + int apply_r_mips_none(struct module *me, u32 *location, Elf_Addr v) + { +@@ -64,8 +272,39 @@ static int apply_r_mips_32_rel(struct mo + return 0; + } + ++static Elf_Addr add_plt_entry_to(unsigned *plt_offset, ++ void *start, Elf_Addr v) ++{ ++ unsigned *tramp = start + *plt_offset; ++ *plt_offset += 4 * sizeof(int); ++ ++ /* adjust carry for addiu */ ++ if (v & 0x00008000) ++ v += 0x10000; ++ ++ tramp[0] = 0x3c190000 | (v >> 16); /* lui t9, hi16 */ ++ tramp[1] = 0x27390000 | (v & 0xffff); /* addiu t9, t9, lo16 */ ++ tramp[2] = 0x03200008; /* jr t9 */ ++ tramp[3] = 0x00000000; /* nop */ ++ ++ return (Elf_Addr) tramp; ++} ++ ++static Elf_Addr add_plt_entry(struct module *me, void *location, Elf_Addr v) ++{ ++ if (is_phys_addr(location)) ++ return add_plt_entry_to(&me->arch.phys_plt_offset, ++ me->arch.phys_plt_tbl, v); ++ else ++ return add_plt_entry_to(&me->arch.virt_plt_offset, ++ me->arch.virt_plt_tbl, v); ++ ++} ++ + static int apply_r_mips_26_rel(struct module *me, u32 *location, Elf_Addr v) + { ++ u32 ofs = *location & 0x03ffffff; ++ + if (v % 4) { + pr_err("module %s: dangerous R_MIPS_26 REL relocation\n", + me->name); +@@ -73,14 +312,17 @@ static int apply_r_mips_26_rel(struct mo + } + + if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) { +- printk(KERN_ERR +- "module %s: relocation overflow\n", +- me->name); +- return -ENOEXEC; ++ v = add_plt_entry(me, location, v + (ofs << 2)); ++ if (!v) { ++ printk(KERN_ERR ++ "module %s: relocation overflow\n", me->name); ++ return -ENOEXEC; ++ } ++ ofs = 0; + } + + *location = (*location & ~0x03ffffff) | +- ((*location + (v >> 2)) & 0x03ffffff); ++ ((ofs + (v >> 2)) & 0x03ffffff); + + return 0; + } +@@ -287,9 +529,33 @@ int module_finalize(const Elf_Ehdr *hdr, + list_add(&me->arch.dbe_list, &dbe_list); + spin_unlock_irq(&dbe_lock); + } ++ ++ /* Get rid of the fixup trampoline if we're running the module ++ * from physically mapped address space */ ++ if (me->arch.phys_plt_offset == 0) { ++ __module_free(me->arch.phys_plt_tbl); ++ me->arch.phys_plt_tbl = NULL; ++ } ++ if (me->arch.virt_plt_offset == 0) { ++ __module_free(me->arch.virt_plt_tbl); ++ me->arch.virt_plt_tbl = NULL; ++ } ++ + return 0; + } + ++void module_arch_freeing_init(struct module *mod) ++{ ++ if (mod->arch.phys_plt_tbl) { ++ __module_free(mod->arch.phys_plt_tbl); ++ mod->arch.phys_plt_tbl = NULL; ++ } ++ if (mod->arch.virt_plt_tbl) { ++ __module_free(mod->arch.virt_plt_tbl); ++ mod->arch.virt_plt_tbl = NULL; ++ } ++} ++ + void module_arch_cleanup(struct module *mod) + { + spin_lock_irq(&dbe_lock); diff --git a/target/linux/generic/patches-3.18/306-mips_mem_functions_performance.patch b/target/linux/generic/patches-3.18/306-mips_mem_functions_performance.patch new file mode 100644 index 0000000..9818677 --- /dev/null +++ b/target/linux/generic/patches-3.18/306-mips_mem_functions_performance.patch @@ -0,0 +1,83 @@ +--- a/arch/mips/include/asm/string.h ++++ b/arch/mips/include/asm/string.h +@@ -133,11 +133,44 @@ strncmp(__const__ char *__cs, __const__ + + #define __HAVE_ARCH_MEMSET + extern void *memset(void *__s, int __c, size_t __count); ++#define memset(__s, __c, len) \ ++({ \ ++ size_t __len = (len); \ ++ void *__ret; \ ++ if (__builtin_constant_p(len) && __len >= 64) \ ++ __ret = memset((__s), (__c), __len); \ ++ else \ ++ __ret = __builtin_memset((__s), (__c), __len); \ ++ __ret; \ ++}) + + #define __HAVE_ARCH_MEMCPY + extern void *memcpy(void *__to, __const__ void *__from, size_t __n); ++#define memcpy(dst, src, len) \ ++({ \ ++ size_t __len = (len); \ ++ void *__ret; \ ++ if (__builtin_constant_p(len) && __len >= 64) \ ++ __ret = memcpy((dst), (src), __len); \ ++ else \ ++ __ret = __builtin_memcpy((dst), (src), __len); \ ++ __ret; \ ++}) + + #define __HAVE_ARCH_MEMMOVE + extern void *memmove(void *__dest, __const__ void *__src, size_t __n); ++#define memmove(dst, src, len) \ ++({ \ ++ size_t __len = (len); \ ++ void *__ret; \ ++ if (__builtin_constant_p(len) && __len >= 64) \ ++ __ret = memmove((dst), (src), __len); \ ++ else \ ++ __ret = __builtin_memmove((dst), (src), __len); \ ++ __ret; \ ++}) ++ ++#define __HAVE_ARCH_MEMCMP ++#define memcmp(src1, src2, len) __builtin_memcmp((src1), (src2), (len)) + + #endif /* _ASM_STRING_H */ +--- a/arch/mips/lib/Makefile ++++ b/arch/mips/lib/Makefile +@@ -4,7 +4,7 @@ + + lib-y += bitops.o csum_partial.o delay.o memcpy.o memset.o \ + mips-atomic.o strlen_user.o strncpy_user.o \ +- strnlen_user.o uncached.o ++ strnlen_user.o uncached.o memcmp.o + + obj-y += iomap.o + obj-$(CONFIG_PCI) += iomap-pci.o +--- /dev/null ++++ b/arch/mips/lib/memcmp.c +@@ -0,0 +1,22 @@ ++/* ++ * copied from linux/lib/string.c ++ * ++ * Copyright (C) 1991, 1992 Linus Torvalds ++ */ ++ ++#include ++#include ++ ++#undef memcmp ++int memcmp(const void *cs, const void *ct, size_t count) ++{ ++ const unsigned char *su1, *su2; ++ int res = 0; ++ ++ for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--) ++ if ((res = *su1 - *su2) != 0) ++ break; ++ return res; ++} ++EXPORT_SYMBOL(memcmp); ++ diff --git a/target/linux/generic/patches-3.18/307-mips_highmem_offset.patch b/target/linux/generic/patches-3.18/307-mips_highmem_offset.patch new file mode 100644 index 0000000..c9f0c84 --- /dev/null +++ b/target/linux/generic/patches-3.18/307-mips_highmem_offset.patch @@ -0,0 +1,17 @@ +Adjust highmem offset to 0x10000000 to ensure that all kmalloc allocations +stay within the same 256M boundary. This ensures that -mlong-calls is not +needed on systems with more than 256M RAM. + +Signed-off-by: Felix Fietkau +--- +--- a/arch/mips/include/asm/mach-generic/spaces.h ++++ b/arch/mips/include/asm/mach-generic/spaces.h +@@ -44,7 +44,7 @@ + * Memory above this physical address will be considered highmem. + */ + #ifndef HIGHMEM_START +-#define HIGHMEM_START _AC(0x20000000, UL) ++#define HIGHMEM_START _AC(0x10000000, UL) + #endif + + #endif /* CONFIG_32BIT */ diff --git a/target/linux/generic/patches-3.18/309-mips_fuse_workaround.patch b/target/linux/generic/patches-3.18/309-mips_fuse_workaround.patch new file mode 100644 index 0000000..934b119 --- /dev/null +++ b/target/linux/generic/patches-3.18/309-mips_fuse_workaround.patch @@ -0,0 +1,32 @@ +--- a/arch/mips/mm/cache.c ++++ b/arch/mips/mm/cache.c +@@ -38,6 +38,7 @@ void (*__flush_cache_vunmap)(void); + + void (*__flush_kernel_vmap_range)(unsigned long vaddr, int size); + EXPORT_SYMBOL_GPL(__flush_kernel_vmap_range); ++EXPORT_SYMBOL(__flush_cache_all); + void (*__invalidate_kernel_vmap_range)(unsigned long vaddr, int size); + + /* MIPS specific cache operations */ +--- a/fs/fuse/dev.c ++++ b/fs/fuse/dev.c +@@ -20,6 +20,9 @@ + #include + #include + #include ++#ifdef CONFIG_MIPS ++#include ++#endif + + MODULE_ALIAS_MISCDEV(FUSE_MINOR); + MODULE_ALIAS("devname:fuse"); +@@ -749,6 +752,9 @@ static int fuse_copy_fill(struct fuse_co + static int fuse_copy_do(struct fuse_copy_state *cs, void **val, unsigned *size) + { + unsigned ncpy = min(*size, cs->len); ++#ifdef CONFIG_MIPS ++ __flush_cache_all(); ++#endif + if (val) { + void *pgaddr = kmap_atomic(cs->pg); + void *buf = pgaddr + cs->offset; diff --git a/target/linux/generic/patches-3.18/310-arm_module_unresolved_weak_sym.patch b/target/linux/generic/patches-3.18/310-arm_module_unresolved_weak_sym.patch new file mode 100644 index 0000000..9210c1d --- /dev/null +++ b/target/linux/generic/patches-3.18/310-arm_module_unresolved_weak_sym.patch @@ -0,0 +1,13 @@ +--- a/arch/arm/kernel/module.c ++++ b/arch/arm/kernel/module.c +@@ -83,6 +83,10 @@ apply_relocate(Elf32_Shdr *sechdrs, cons + return -ENOEXEC; + } + ++ if ((IS_ERR_VALUE(sym->st_value) || !sym->st_value) && ++ ELF_ST_BIND(sym->st_info) == STB_WEAK) ++ continue; ++ + loc = dstsec->sh_addr + rel->r_offset; + + switch (ELF32_R_TYPE(rel->r_info)) { diff --git a/target/linux/generic/patches-3.18/320-ppc4xx_optimization.patch b/target/linux/generic/patches-3.18/320-ppc4xx_optimization.patch new file mode 100644 index 0000000..8673de4 --- /dev/null +++ b/target/linux/generic/patches-3.18/320-ppc4xx_optimization.patch @@ -0,0 +1,31 @@ +Upstream doesn't optimize the kernel and bootwrappers for ppc44x because +they still want to support gcc 3.3 -- well, we don't. + +--- a/arch/powerpc/Makefile ++++ b/arch/powerpc/Makefile +@@ -203,7 +203,8 @@ ifeq ($(CONFIG_FUNCTION_TRACER),y) + KBUILD_CFLAGS += -mno-sched-epilog + endif + +-cpu-as-$(CONFIG_4xx) += -Wa,-m405 ++cpu-as-$(CONFIG_40x) += -Wa,-m405 ++cpu-as-$(CONFIG_44x) += -Wa,-m440 + cpu-as-$(CONFIG_ALTIVEC) += -Wa,-maltivec + cpu-as-$(CONFIG_E200) += -Wa,-me200 + +--- a/arch/powerpc/boot/Makefile ++++ b/arch/powerpc/boot/Makefile +@@ -45,10 +45,10 @@ BOOTCFLAGS += -I$(obj) -I$(srctree)/$(ob + DTC_FLAGS ?= -p 1024 + + $(obj)/4xx.o: BOOTCFLAGS += -mcpu=405 +-$(obj)/ebony.o: BOOTCFLAGS += -mcpu=405 ++$(obj)/ebony.o: BOOTCFLAGS += -mcpu=440 + $(obj)/cuboot-hotfoot.o: BOOTCFLAGS += -mcpu=405 +-$(obj)/cuboot-taishan.o: BOOTCFLAGS += -mcpu=405 +-$(obj)/cuboot-katmai.o: BOOTCFLAGS += -mcpu=405 ++$(obj)/cuboot-taishan.o: BOOTCFLAGS += -mcpu=440 ++$(obj)/cuboot-katmai.o: BOOTCFLAGS += -mcpu=440 + $(obj)/cuboot-acadia.o: BOOTCFLAGS += -mcpu=405 + $(obj)/treeboot-walnut.o: BOOTCFLAGS += -mcpu=405 + $(obj)/treeboot-iss4xx.o: BOOTCFLAGS += -mcpu=405 diff --git a/target/linux/generic/patches-3.18/321-powerpc_crtsavres_prereq.patch b/target/linux/generic/patches-3.18/321-powerpc_crtsavres_prereq.patch new file mode 100644 index 0000000..ab6ea7b --- /dev/null +++ b/target/linux/generic/patches-3.18/321-powerpc_crtsavres_prereq.patch @@ -0,0 +1,10 @@ +--- a/arch/powerpc/Makefile ++++ b/arch/powerpc/Makefile +@@ -165,7 +165,6 @@ CPP = $(CC) -E $(KBUILD_CFLAGS) + + CHECKFLAGS += -m$(CONFIG_WORD_SIZE) -D__powerpc__ -D__powerpc$(CONFIG_WORD_SIZE)__ + +-KBUILD_LDFLAGS_MODULE += arch/powerpc/lib/crtsavres.o + + ifeq ($(CONFIG_476FPE_ERR46),y) + KBUILD_LDFLAGS_MODULE += --ppc476-workaround \ diff --git a/target/linux/generic/patches-3.18/330-MIPS-kexec-Accept-command-line-parameters-from-users.patch b/target/linux/generic/patches-3.18/330-MIPS-kexec-Accept-command-line-parameters-from-users.patch new file mode 100644 index 0000000..a69d197 --- /dev/null +++ b/target/linux/generic/patches-3.18/330-MIPS-kexec-Accept-command-line-parameters-from-users.patch @@ -0,0 +1,298 @@ +From d8582dcf1ed66eee88a11e4760f42c0d6c8822be Mon Sep 17 00:00:00 2001 +From: Yousong Zhou +Date: Sat, 31 Jan 2015 22:26:03 +0800 +Subject: [PATCH 331/331] MIPS: kexec: Accept command line parameters from + userspace. + +Signed-off-by: Yousong Zhou +--- + arch/mips/kernel/machine_kexec.c | 153 +++++++++++++++++++++++++++++++----- + arch/mips/kernel/machine_kexec.h | 20 +++++ + arch/mips/kernel/relocate_kernel.S | 21 +++-- + 3 files changed, 167 insertions(+), 27 deletions(-) + create mode 100644 arch/mips/kernel/machine_kexec.h + +--- a/arch/mips/kernel/machine_kexec.c ++++ b/arch/mips/kernel/machine_kexec.c +@@ -10,45 +10,145 @@ + #include + #include + ++#include + #include + #include +- +-extern const unsigned char relocate_new_kernel[]; +-extern const size_t relocate_new_kernel_size; +- +-extern unsigned long kexec_start_address; +-extern unsigned long kexec_indirection_page; ++#include ++#include "machine_kexec.h" + + int (*_machine_kexec_prepare)(struct kimage *) = NULL; + void (*_machine_kexec_shutdown)(void) = NULL; + void (*_machine_crash_shutdown)(struct pt_regs *regs) = NULL; ++ + #ifdef CONFIG_SMP + void (*relocated_kexec_smp_wait) (void *); + atomic_t kexec_ready_to_reboot = ATOMIC_INIT(0); + #endif + +-int +-machine_kexec_prepare(struct kimage *kimage) ++static void machine_kexec_print_args(void) + { ++ unsigned long argc = (int)kexec_args[0]; ++ int i; ++ ++ pr_info("kexec_args[0] (argc): %lu\n", argc); ++ pr_info("kexec_args[1] (argv): %p\n", (void *)kexec_args[1]); ++ pr_info("kexec_args[2] (env ): %p\n", (void *)kexec_args[2]); ++ pr_info("kexec_args[3] (desc): %p\n", (void *)kexec_args[3]); ++ ++ for (i = 0; i < argc; i++) { ++ pr_info("kexec_argv[%d] = %p, %s\n", ++ i, kexec_argv[i], kexec_argv[i]); ++ } ++} ++ ++static void machine_kexec_init_argv(struct kimage *image) ++{ ++ void __user *buf = NULL; ++ size_t bufsz; ++ size_t size; ++ int i; ++ ++ bufsz = 0; ++ for (i = 0; i < image->nr_segments; i++) { ++ struct kexec_segment *seg; ++ ++ seg = &image->segment[i]; ++ if (seg->bufsz < 6) ++ continue; ++ ++ if (strncmp((char *) seg->buf, "kexec ", 6)) ++ continue; ++ ++ buf = seg->buf; ++ bufsz = seg->bufsz; ++ break; ++ } ++ ++ if (!buf) ++ return; ++ ++ size = KEXEC_COMMAND_LINE_SIZE; ++ size = min(size, bufsz); ++ if (size < bufsz) ++ pr_warn("kexec command line truncated to %zd bytes\n", size); ++ ++ /* Copy to kernel space */ ++ copy_from_user(kexec_argv_buf, buf, size); ++ kexec_argv_buf[size - 1] = 0; ++} ++ ++static void machine_kexec_parse_argv(struct kimage *image) ++{ ++ char *reboot_code_buffer; ++ int reloc_delta; ++ char *ptr; ++ int argc; ++ int i; ++ ++ ptr = kexec_argv_buf; ++ argc = 0; ++ ++ /* ++ * convert command line string to array of parameters ++ * (as bootloader does). ++ */ ++ while (ptr && *ptr && (KEXEC_MAX_ARGC > argc)) { ++ if (*ptr == ' ') { ++ *ptr++ = '\0'; ++ continue; ++ } ++ ++ kexec_argv[argc++] = ptr; ++ ptr = strchr(ptr, ' '); ++ } ++ ++ if (!argc) ++ return; ++ ++ kexec_args[0] = argc; ++ kexec_args[1] = (unsigned long)kexec_argv; ++ kexec_args[2] = 0; ++ kexec_args[3] = 0; ++ ++ reboot_code_buffer = page_address(image->control_code_page); ++ reloc_delta = reboot_code_buffer - (char *)kexec_relocate_new_kernel; ++ ++ kexec_args[1] += reloc_delta; ++ for (i = 0; i < argc; i++) ++ kexec_argv[i] += reloc_delta; ++} ++ ++int machine_kexec_prepare(struct kimage *kimage) ++{ ++ /* ++ * Whenever arguments passed from kexec-tools, Init the arguments as ++ * the original ones to try avoiding booting failure. ++ */ ++ ++ kexec_args[0] = fw_arg0; ++ kexec_args[1] = fw_arg1; ++ kexec_args[2] = fw_arg2; ++ kexec_args[3] = fw_arg3; ++ ++ machine_kexec_init_argv(kimage); ++ machine_kexec_parse_argv(kimage); ++ + if (_machine_kexec_prepare) + return _machine_kexec_prepare(kimage); + return 0; + } + +-void +-machine_kexec_cleanup(struct kimage *kimage) ++void machine_kexec_cleanup(struct kimage *kimage) + { + } + +-void +-machine_shutdown(void) ++void machine_shutdown(void) + { + if (_machine_kexec_shutdown) + _machine_kexec_shutdown(); + } + +-void +-machine_crash_shutdown(struct pt_regs *regs) ++void machine_crash_shutdown(struct pt_regs *regs) + { + if (_machine_crash_shutdown) + _machine_crash_shutdown(regs); +@@ -66,10 +166,12 @@ machine_kexec(struct kimage *image) + unsigned long *ptr; + + reboot_code_buffer = +- (unsigned long)page_address(image->control_code_page); ++ (unsigned long)page_address(image->control_code_page); ++ pr_info("reboot_code_buffer = %p\n", (void *)reboot_code_buffer); + + kexec_start_address = + (unsigned long) phys_to_virt(image->start); ++ pr_info("kexec_start_address = %p\n", (void *)kexec_start_address); + + if (image->type == KEXEC_TYPE_DEFAULT) { + kexec_indirection_page = +@@ -77,9 +179,19 @@ machine_kexec(struct kimage *image) + } else { + kexec_indirection_page = (unsigned long)&image->head; + } ++ pr_info("kexec_indirection_page = %p\n", (void *)kexec_indirection_page); + +- memcpy((void*)reboot_code_buffer, relocate_new_kernel, +- relocate_new_kernel_size); ++ pr_info("Where is memcpy: %p\n", memcpy); ++ pr_info("kexec_relocate_new_kernel = %p, kexec_relocate_new_kernel_end = %p\n", ++ (void *)kexec_relocate_new_kernel, &kexec_relocate_new_kernel_end); ++ pr_info("Copy %lu bytes from %p to %p\n", KEXEC_RELOCATE_NEW_KERNEL_SIZE, ++ (void *)kexec_relocate_new_kernel, (void *)reboot_code_buffer); ++ memcpy((void*)reboot_code_buffer, kexec_relocate_new_kernel, ++ KEXEC_RELOCATE_NEW_KERNEL_SIZE); ++ ++ pr_info("Before _print_args().\n"); ++ machine_kexec_print_args(); ++ pr_info("Before eval loop.\n"); + + /* + * The generic kexec code builds a page list with physical +@@ -98,15 +210,16 @@ machine_kexec(struct kimage *image) + /* + * we do not want to be bothered. + */ ++ pr_info("Before irq_disable.\n"); + local_irq_disable(); + +- printk("Will call new kernel at %08lx\n", image->start); +- printk("Bye ...\n"); ++ pr_info("Will call new kernel at %08lx\n", image->start); ++ pr_info("Bye ...\n"); + __flush_cache_all(); + #ifdef CONFIG_SMP + /* All secondary cpus now may jump to kexec_wait cycle */ + relocated_kexec_smp_wait = reboot_code_buffer + +- (void *)(kexec_smp_wait - relocate_new_kernel); ++ (void *)(kexec_smp_wait - kexec_relocate_new_kernel); + smp_wmb(); + atomic_set(&kexec_ready_to_reboot, 1); + #endif +--- /dev/null ++++ b/arch/mips/kernel/machine_kexec.h +@@ -0,0 +1,20 @@ ++#ifndef _MACHINE_KEXEC_H ++#define _MACHINE_KEXEC_H ++ ++#ifndef __ASSEMBLY__ ++extern const unsigned char kexec_relocate_new_kernel[]; ++extern unsigned long kexec_relocate_new_kernel_end; ++extern unsigned long kexec_start_address; ++extern unsigned long kexec_indirection_page; ++ ++extern char kexec_argv_buf[]; ++extern char *kexec_argv[]; ++ ++#define KEXEC_RELOCATE_NEW_KERNEL_SIZE ((unsigned long)&kexec_relocate_new_kernel_end - (unsigned long)kexec_relocate_new_kernel) ++#endif /* !__ASSEMBLY__ */ ++ ++#define KEXEC_COMMAND_LINE_SIZE 256 ++#define KEXEC_ARGV_SIZE (KEXEC_COMMAND_LINE_SIZE / 16) ++#define KEXEC_MAX_ARGC (KEXEC_ARGV_SIZE / sizeof(long)) ++ ++#endif +--- a/arch/mips/kernel/relocate_kernel.S ++++ b/arch/mips/kernel/relocate_kernel.S +@@ -12,8 +12,9 @@ + #include + #include + #include ++#include "machine_kexec.h" + +-LEAF(relocate_new_kernel) ++LEAF(kexec_relocate_new_kernel) + PTR_L a0, arg0 + PTR_L a1, arg1 + PTR_L a2, arg2 +@@ -98,7 +99,7 @@ done: + #endif + /* jump to kexec_start_address */ + j s1 +- END(relocate_new_kernel) ++ END(kexec_relocate_new_kernel) + + #ifdef CONFIG_SMP + /* +@@ -184,9 +185,15 @@ kexec_indirection_page: + PTR 0 + .size kexec_indirection_page, PTRSIZE + +-relocate_new_kernel_end: ++kexec_argv_buf: ++ EXPORT(kexec_argv_buf) ++ .skip KEXEC_COMMAND_LINE_SIZE ++ .size kexec_argv_buf, KEXEC_COMMAND_LINE_SIZE ++ ++kexec_argv: ++ EXPORT(kexec_argv) ++ .skip KEXEC_ARGV_SIZE ++ .size kexec_argv, KEXEC_ARGV_SIZE + +-relocate_new_kernel_size: +- EXPORT(relocate_new_kernel_size) +- PTR relocate_new_kernel_end - relocate_new_kernel +- .size relocate_new_kernel_size, PTRSIZE ++kexec_relocate_new_kernel_end: ++ EXPORT(kexec_relocate_new_kernel_end) diff --git a/target/linux/generic/patches-3.18/400-mtd-add-rootfs-split-support.patch b/target/linux/generic/patches-3.18/400-mtd-add-rootfs-split-support.patch new file mode 100644 index 0000000..0a6e134 --- /dev/null +++ b/target/linux/generic/patches-3.18/400-mtd-add-rootfs-split-support.patch @@ -0,0 +1,171 @@ +--- a/drivers/mtd/Kconfig ++++ b/drivers/mtd/Kconfig +@@ -12,6 +12,23 @@ menuconfig MTD + + if MTD + ++menu "OpenWrt specific MTD options" ++ ++config MTD_ROOTFS_ROOT_DEV ++ bool "Automatically set 'rootfs' partition to be root filesystem" ++ default y ++ ++config MTD_SPLIT_FIRMWARE ++ bool "Automatically split firmware partition for kernel+rootfs" ++ default y ++ ++config MTD_SPLIT_FIRMWARE_NAME ++ string "Firmware partition name" ++ depends on MTD_SPLIT_FIRMWARE ++ default "firmware" ++ ++endmenu ++ + config MTD_TESTS + tristate "MTD tests support (DANGEROUS)" + depends on m +--- a/drivers/mtd/mtdpart.c ++++ b/drivers/mtd/mtdpart.c +@@ -30,9 +30,11 @@ + #include + #include + #include ++#include + #include + + #include "mtdcore.h" ++#include "mtdsplit/mtdsplit.h" + + /* Our partition linked list */ + static LIST_HEAD(mtd_partitions); +@@ -46,13 +48,14 @@ struct mtd_part { + struct list_head list; + }; + ++static void mtd_partition_split(struct mtd_info *master, struct mtd_part *part); ++ + /* + * Given a pointer to the MTD object in the mtd_part structure, we can retrieve + * the pointer to that structure with this macro. + */ + #define PART(x) ((struct mtd_part *)(x)) + +- + /* + * MTD methods which simply translate the effective address and pass through + * to the _real_ device. +@@ -548,8 +551,10 @@ out_register: + return slave; + } + +-int mtd_add_partition(struct mtd_info *master, const char *name, +- long long offset, long long length) ++ ++static int ++__mtd_add_partition(struct mtd_info *master, const char *name, ++ long long offset, long long length, bool dup_check) + { + struct mtd_partition part; + struct mtd_part *p, *new; +@@ -581,21 +586,24 @@ int mtd_add_partition(struct mtd_info *m + end = offset + length; + + mutex_lock(&mtd_partitions_mutex); +- list_for_each_entry(p, &mtd_partitions, list) +- if (p->master == master) { +- if ((start >= p->offset) && +- (start < (p->offset + p->mtd.size))) +- goto err_inv; +- +- if ((end >= p->offset) && +- (end < (p->offset + p->mtd.size))) +- goto err_inv; +- } ++ if (dup_check) { ++ list_for_each_entry(p, &mtd_partitions, list) ++ if (p->master == master) { ++ if ((start >= p->offset) && ++ (start < (p->offset + p->mtd.size))) ++ goto err_inv; ++ ++ if ((end >= p->offset) && ++ (end < (p->offset + p->mtd.size))) ++ goto err_inv; ++ } ++ } + + list_add(&new->list, &mtd_partitions); + mutex_unlock(&mtd_partitions_mutex); + + add_mtd_device(&new->mtd); ++ mtd_partition_split(master, new); + + return ret; + err_inv: +@@ -605,6 +613,12 @@ err_inv: + } + EXPORT_SYMBOL_GPL(mtd_add_partition); + ++int mtd_add_partition(struct mtd_info *master, const char *name, ++ long long offset, long long length) ++{ ++ return __mtd_add_partition(master, name, offset, length, true); ++} ++ + int mtd_del_partition(struct mtd_info *master, int partno) + { + struct mtd_part *slave, *next; +@@ -628,6 +642,35 @@ int mtd_del_partition(struct mtd_info *m + } + EXPORT_SYMBOL_GPL(mtd_del_partition); + ++#ifdef CONFIG_MTD_SPLIT_FIRMWARE_NAME ++#define SPLIT_FIRMWARE_NAME CONFIG_MTD_SPLIT_FIRMWARE_NAME ++#else ++#define SPLIT_FIRMWARE_NAME "unused" ++#endif ++ ++static void split_firmware(struct mtd_info *master, struct mtd_part *part) ++{ ++} ++ ++void __weak arch_split_mtd_part(struct mtd_info *master, const char *name, ++ int offset, int size) ++{ ++} ++ ++static void mtd_partition_split(struct mtd_info *master, struct mtd_part *part) ++{ ++ static int rootfs_found = 0; ++ ++ if (rootfs_found) ++ return; ++ ++ if (!strcmp(part->mtd.name, SPLIT_FIRMWARE_NAME) && ++ config_enabled(CONFIG_MTD_SPLIT_FIRMWARE)) ++ split_firmware(master, part); ++ ++ arch_split_mtd_part(master, part->mtd.name, part->offset, ++ part->mtd.size); ++} + /* + * This function, given a master MTD object and a partition table, creates + * and registers slave MTD objects which are bound to the master according to +@@ -657,6 +700,7 @@ int add_mtd_partitions(struct mtd_info * + mutex_unlock(&mtd_partitions_mutex); + + add_mtd_device(&slave->mtd); ++ mtd_partition_split(master, slave); + + cur_offset = slave->offset + slave->mtd.size; + } +--- a/include/linux/mtd/partitions.h ++++ b/include/linux/mtd/partitions.h +@@ -84,5 +84,7 @@ int mtd_add_partition(struct mtd_info *m + long long offset, long long length); + int mtd_del_partition(struct mtd_info *master, int partno); + uint64_t mtd_get_device_size(const struct mtd_info *mtd); ++extern void __weak arch_split_mtd_part(struct mtd_info *master, ++ const char *name, int offset, int size); + + #endif diff --git a/target/linux/generic/patches-3.18/401-mtd-add-support-for-different-partition-parser-types.patch b/target/linux/generic/patches-3.18/401-mtd-add-support-for-different-partition-parser-types.patch new file mode 100644 index 0000000..6842341 --- /dev/null +++ b/target/linux/generic/patches-3.18/401-mtd-add-support-for-different-partition-parser-types.patch @@ -0,0 +1,113 @@ +From 02cff0ccaa6d364f5c1eeea83f47ac80ccc967d4 Mon Sep 17 00:00:00 2001 +From: Gabor Juhos +Date: Tue, 3 Sep 2013 18:11:50 +0200 +Subject: [PATCH] mtd: add support for different partition parser types + +Signed-off-by: Gabor Juhos +--- + drivers/mtd/mtdpart.c | 56 ++++++++++++++++++++++++++++++++++++++++ + include/linux/mtd/partitions.h | 11 ++++++++ + 2 files changed, 67 insertions(+) + +--- a/drivers/mtd/mtdpart.c ++++ b/drivers/mtd/mtdpart.c +@@ -730,6 +730,30 @@ static struct mtd_part_parser *get_parti + + #define put_partition_parser(p) do { module_put((p)->owner); } while (0) + ++static struct mtd_part_parser * ++get_partition_parser_by_type(enum mtd_parser_type type, ++ struct mtd_part_parser *start) ++{ ++ struct mtd_part_parser *p, *ret = NULL; ++ ++ spin_lock(&part_parser_lock); ++ ++ p = list_prepare_entry(start, &part_parsers, list); ++ if (start) ++ put_partition_parser(start); ++ ++ list_for_each_entry_continue(p, &part_parsers, list) { ++ if (p->type == type && try_module_get(p->owner)) { ++ ret = p; ++ break; ++ } ++ } ++ ++ spin_unlock(&part_parser_lock); ++ ++ return ret; ++} ++ + void register_mtd_parser(struct mtd_part_parser *p) + { + spin_lock(&part_parser_lock); +@@ -845,6 +869,38 @@ int parse_mtd_partitions(struct mtd_info + return ret; + } + ++int parse_mtd_partitions_by_type(struct mtd_info *master, ++ enum mtd_parser_type type, ++ struct mtd_partition **pparts, ++ struct mtd_part_parser_data *data) ++{ ++ struct mtd_part_parser *prev = NULL; ++ int ret = 0; ++ ++ while (1) { ++ struct mtd_part_parser *parser; ++ ++ parser = get_partition_parser_by_type(type, prev); ++ if (!parser) ++ break; ++ ++ ret = (*parser->parse_fn)(master, pparts, data); ++ ++ if (ret > 0) { ++ put_partition_parser(parser); ++ printk(KERN_NOTICE ++ "%d %s partitions found on MTD device %s\n", ++ ret, parser->name, master->name); ++ break; ++ } ++ ++ prev = parser; ++ } ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(parse_mtd_partitions_by_type); ++ + int mtd_is_partition(const struct mtd_info *mtd) + { + struct mtd_part *part; +--- a/include/linux/mtd/partitions.h ++++ b/include/linux/mtd/partitions.h +@@ -68,12 +68,17 @@ struct mtd_part_parser_data { + * Functions dealing with the various ways of partitioning the space + */ + ++enum mtd_parser_type { ++ MTD_PARSER_TYPE_DEVICE = 0, ++}; ++ + struct mtd_part_parser { + struct list_head list; + struct module *owner; + const char *name; + int (*parse_fn)(struct mtd_info *, struct mtd_partition **, + struct mtd_part_parser_data *); ++ enum mtd_parser_type type; + }; + + extern void register_mtd_parser(struct mtd_part_parser *parser); +@@ -87,4 +92,9 @@ uint64_t mtd_get_device_size(const struc + extern void __weak arch_split_mtd_part(struct mtd_info *master, + const char *name, int offset, int size); + ++int parse_mtd_partitions_by_type(struct mtd_info *master, ++ enum mtd_parser_type type, ++ struct mtd_partition **pparts, ++ struct mtd_part_parser_data *data); ++ + #endif diff --git a/target/linux/generic/patches-3.18/402-mtd-use-typed-mtd-parsers-for-rootfs-and-firmware-split.patch b/target/linux/generic/patches-3.18/402-mtd-use-typed-mtd-parsers-for-rootfs-and-firmware-split.patch new file mode 100644 index 0000000..dead0fb --- /dev/null +++ b/target/linux/generic/patches-3.18/402-mtd-use-typed-mtd-parsers-for-rootfs-and-firmware-split.patch @@ -0,0 +1,72 @@ +--- a/drivers/mtd/mtdpart.c ++++ b/drivers/mtd/mtdpart.c +@@ -642,6 +642,37 @@ int mtd_del_partition(struct mtd_info *m + } + EXPORT_SYMBOL_GPL(mtd_del_partition); + ++static int ++run_parsers_by_type(struct mtd_part *slave, enum mtd_parser_type type) ++{ ++ struct mtd_partition *parts; ++ int nr_parts; ++ int i; ++ ++ nr_parts = parse_mtd_partitions_by_type(&slave->mtd, type, &parts, ++ NULL); ++ if (nr_parts <= 0) ++ return nr_parts; ++ ++ if (WARN_ON(!parts)) ++ return 0; ++ ++ for (i = 0; i < nr_parts; i++) { ++ /* adjust partition offsets */ ++ parts[i].offset += slave->offset; ++ ++ __mtd_add_partition(slave->master, ++ parts[i].name, ++ parts[i].offset, ++ parts[i].size, ++ false); ++ } ++ ++ kfree(parts); ++ ++ return nr_parts; ++} ++ + #ifdef CONFIG_MTD_SPLIT_FIRMWARE_NAME + #define SPLIT_FIRMWARE_NAME CONFIG_MTD_SPLIT_FIRMWARE_NAME + #else +@@ -650,6 +681,7 @@ EXPORT_SYMBOL_GPL(mtd_del_partition); + + static void split_firmware(struct mtd_info *master, struct mtd_part *part) + { ++ run_parsers_by_type(part, MTD_PARSER_TYPE_FIRMWARE); + } + + void __weak arch_split_mtd_part(struct mtd_info *master, const char *name, +@@ -664,6 +696,12 @@ static void mtd_partition_split(struct m + if (rootfs_found) + return; + ++ if (!strcmp(part->mtd.name, "rootfs")) { ++ run_parsers_by_type(part, MTD_PARSER_TYPE_ROOTFS); ++ ++ rootfs_found = 1; ++ } ++ + if (!strcmp(part->mtd.name, SPLIT_FIRMWARE_NAME) && + config_enabled(CONFIG_MTD_SPLIT_FIRMWARE)) + split_firmware(master, part); +--- a/include/linux/mtd/partitions.h ++++ b/include/linux/mtd/partitions.h +@@ -70,6 +70,8 @@ struct mtd_part_parser_data { + + enum mtd_parser_type { + MTD_PARSER_TYPE_DEVICE = 0, ++ MTD_PARSER_TYPE_ROOTFS, ++ MTD_PARSER_TYPE_FIRMWARE, + }; + + struct mtd_part_parser { diff --git a/target/linux/generic/patches-3.18/403-mtd-hook-mtdsplit-to-Kbuild.patch b/target/linux/generic/patches-3.18/403-mtd-hook-mtdsplit-to-Kbuild.patch new file mode 100644 index 0000000..0cf1c38 --- /dev/null +++ b/target/linux/generic/patches-3.18/403-mtd-hook-mtdsplit-to-Kbuild.patch @@ -0,0 +1,22 @@ +--- a/drivers/mtd/Kconfig ++++ b/drivers/mtd/Kconfig +@@ -27,6 +27,8 @@ config MTD_SPLIT_FIRMWARE_NAME + depends on MTD_SPLIT_FIRMWARE + default "firmware" + ++source "drivers/mtd/mtdsplit/Kconfig" ++ + endmenu + + config MTD_TESTS +--- a/drivers/mtd/Makefile ++++ b/drivers/mtd/Makefile +@@ -6,6 +6,8 @@ + obj-$(CONFIG_MTD) += mtd.o + mtd-y := mtdcore.o mtdsuper.o mtdconcat.o mtdpart.o mtdchar.o + ++obj-$(CONFIG_MTD_SPLIT) += mtdsplit/ ++ + obj-$(CONFIG_MTD_OF_PARTS) += ofpart.o + obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o + obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o diff --git a/target/linux/generic/patches-3.18/404-mtd-add-more-helper-functions.patch b/target/linux/generic/patches-3.18/404-mtd-add-more-helper-functions.patch new file mode 100644 index 0000000..b2f62c1 --- /dev/null +++ b/target/linux/generic/patches-3.18/404-mtd-add-more-helper-functions.patch @@ -0,0 +1,101 @@ +--- a/drivers/mtd/mtdpart.c ++++ b/drivers/mtd/mtdpart.c +@@ -446,14 +446,12 @@ static struct mtd_part *allocate_partiti + if (slave->offset == MTDPART_OFS_APPEND) + slave->offset = cur_offset; + if (slave->offset == MTDPART_OFS_NXTBLK) { +- slave->offset = cur_offset; +- if (mtd_mod_by_eb(cur_offset, master) != 0) { +- /* Round up to next erasesize */ +- slave->offset = (mtd_div_by_eb(cur_offset, master) + 1) * master->erasesize; ++ /* Round up to next erasesize */ ++ slave->offset = mtd_roundup_to_eb(cur_offset, master); ++ if (slave->offset != cur_offset) + printk(KERN_NOTICE "Moving partition %d: " + "0x%012llx -> 0x%012llx\n", partno, + (unsigned long long)cur_offset, (unsigned long long)slave->offset); +- } + } + if (slave->offset == MTDPART_OFS_RETAIN) { + slave->offset = cur_offset; +@@ -673,6 +671,17 @@ run_parsers_by_type(struct mtd_part *sla + return nr_parts; + } + ++static inline unsigned long ++mtd_pad_erasesize(struct mtd_info *mtd, int offset, int len) ++{ ++ unsigned long mask = mtd->erasesize - 1; ++ ++ len += offset & mask; ++ len = (len + mask) & ~mask; ++ len -= offset & mask; ++ return len; ++} ++ + #ifdef CONFIG_MTD_SPLIT_FIRMWARE_NAME + #define SPLIT_FIRMWARE_NAME CONFIG_MTD_SPLIT_FIRMWARE_NAME + #else +@@ -956,6 +965,24 @@ int mtd_is_partition(const struct mtd_in + } + EXPORT_SYMBOL_GPL(mtd_is_partition); + ++struct mtd_info *mtdpart_get_master(const struct mtd_info *mtd) ++{ ++ if (!mtd_is_partition(mtd)) ++ return (struct mtd_info *)mtd; ++ ++ return PART(mtd)->master; ++} ++EXPORT_SYMBOL_GPL(mtdpart_get_master); ++ ++uint64_t mtdpart_get_offset(const struct mtd_info *mtd) ++{ ++ if (!mtd_is_partition(mtd)) ++ return 0; ++ ++ return PART(mtd)->offset; ++} ++EXPORT_SYMBOL_GPL(mtdpart_get_offset); ++ + /* Returns the size of the entire flash chip */ + uint64_t mtd_get_device_size(const struct mtd_info *mtd) + { +--- a/include/linux/mtd/partitions.h ++++ b/include/linux/mtd/partitions.h +@@ -90,6 +90,8 @@ int mtd_is_partition(const struct mtd_in + int mtd_add_partition(struct mtd_info *master, const char *name, + long long offset, long long length); + int mtd_del_partition(struct mtd_info *master, int partno); ++struct mtd_info *mtdpart_get_master(const struct mtd_info *mtd); ++uint64_t mtdpart_get_offset(const struct mtd_info *mtd); + uint64_t mtd_get_device_size(const struct mtd_info *mtd); + extern void __weak arch_split_mtd_part(struct mtd_info *master, + const char *name, int offset, int size); +--- a/include/linux/mtd/mtd.h ++++ b/include/linux/mtd/mtd.h +@@ -333,6 +333,24 @@ static inline uint32_t mtd_mod_by_eb(uin + return do_div(sz, mtd->erasesize); + } + ++static inline uint64_t mtd_roundup_to_eb(uint64_t sz, struct mtd_info *mtd) ++{ ++ if (mtd_mod_by_eb(sz, mtd) == 0) ++ return sz; ++ ++ /* Round up to next erase block */ ++ return (mtd_div_by_eb(sz, mtd) + 1) * mtd->erasesize; ++} ++ ++static inline uint64_t mtd_rounddown_to_eb(uint64_t sz, struct mtd_info *mtd) ++{ ++ if (mtd_mod_by_eb(sz, mtd) == 0) ++ return sz; ++ ++ /* Round down to the start of the current erase block */ ++ return (mtd_div_by_eb(sz, mtd)) * mtd->erasesize; ++} ++ + static inline uint32_t mtd_div_by_ws(uint64_t sz, struct mtd_info *mtd) + { + if (mtd->writesize_shift) diff --git a/target/linux/generic/patches-3.18/405-mtd-old-firmware-uimage-splitter.patch b/target/linux/generic/patches-3.18/405-mtd-old-firmware-uimage-splitter.patch new file mode 100644 index 0000000..7e74c4e --- /dev/null +++ b/target/linux/generic/patches-3.18/405-mtd-old-firmware-uimage-splitter.patch @@ -0,0 +1,70 @@ +--- a/drivers/mtd/Kconfig ++++ b/drivers/mtd/Kconfig +@@ -27,6 +27,11 @@ config MTD_SPLIT_FIRMWARE_NAME + depends on MTD_SPLIT_FIRMWARE + default "firmware" + ++config MTD_UIMAGE_SPLIT ++ bool "Enable split support for firmware partitions containing a uImage" ++ depends on MTD_SPLIT_FIRMWARE ++ default y ++ + source "drivers/mtd/mtdsplit/Kconfig" + + endmenu +--- a/drivers/mtd/mtdpart.c ++++ b/drivers/mtd/mtdpart.c +@@ -682,6 +682,37 @@ mtd_pad_erasesize(struct mtd_info *mtd, + return len; + } + ++#define UBOOT_MAGIC 0x27051956 ++ ++static void split_uimage(struct mtd_info *master, struct mtd_part *part) ++{ ++ struct { ++ __be32 magic; ++ __be32 pad[2]; ++ __be32 size; ++ } hdr; ++ size_t len; ++ ++ if (mtd_read(master, part->offset, sizeof(hdr), &len, (void *) &hdr)) ++ return; ++ ++ if (len != sizeof(hdr) || hdr.magic != cpu_to_be32(UBOOT_MAGIC)) ++ return; ++ ++ len = be32_to_cpu(hdr.size) + 0x40; ++ len = mtd_pad_erasesize(master, part->offset, len); ++ if (len + master->erasesize > part->mtd.size) ++ return; ++ ++ if (config_enabled(CONFIG_MTD_SPLIT_UIMAGE_FW)) ++ pr_err("Dedicated partitioner didn't split firmware partition, please fill a bug report!\n"); ++ else ++ pr_warn("Support for built-in firmware splitter will be removed, please use CONFIG_MTD_SPLIT_UIMAGE_FW\n"); ++ ++ __mtd_add_partition(master, "rootfs", part->offset + len, ++ part->mtd.size - len, false); ++} ++ + #ifdef CONFIG_MTD_SPLIT_FIRMWARE_NAME + #define SPLIT_FIRMWARE_NAME CONFIG_MTD_SPLIT_FIRMWARE_NAME + #else +@@ -690,7 +721,14 @@ mtd_pad_erasesize(struct mtd_info *mtd, + + static void split_firmware(struct mtd_info *master, struct mtd_part *part) + { +- run_parsers_by_type(part, MTD_PARSER_TYPE_FIRMWARE); ++ int ret; ++ ++ ret = run_parsers_by_type(part, MTD_PARSER_TYPE_FIRMWARE); ++ if (ret > 0) ++ return; ++ ++ if (config_enabled(CONFIG_MTD_UIMAGE_SPLIT)) ++ split_uimage(master, part); + } + + void __weak arch_split_mtd_part(struct mtd_info *master, const char *name, diff --git a/target/linux/generic/patches-3.18/406-mtd-old-rootfs-squashfs-splitter.patch b/target/linux/generic/patches-3.18/406-mtd-old-rootfs-squashfs-splitter.patch new file mode 100644 index 0000000..cc548ef --- /dev/null +++ b/target/linux/generic/patches-3.18/406-mtd-old-rootfs-squashfs-splitter.patch @@ -0,0 +1,76 @@ +--- a/drivers/mtd/Kconfig ++++ b/drivers/mtd/Kconfig +@@ -18,6 +18,11 @@ config MTD_ROOTFS_ROOT_DEV + bool "Automatically set 'rootfs' partition to be root filesystem" + default y + ++config MTD_ROOTFS_SPLIT ++ bool "Automatically split 'rootfs' partition for squashfs" ++ select MTD_SPLIT ++ default y ++ + config MTD_SPLIT_FIRMWARE + bool "Automatically split firmware partition for kernel+rootfs" + default y +--- a/drivers/mtd/mtdpart.c ++++ b/drivers/mtd/mtdpart.c +@@ -682,6 +682,47 @@ mtd_pad_erasesize(struct mtd_info *mtd, + return len; + } + ++static int split_squashfs(struct mtd_info *master, int offset, int *split_offset) ++{ ++ size_t squashfs_len; ++ int len, ret; ++ ++ ret = mtd_get_squashfs_len(master, offset, &squashfs_len); ++ if (ret) ++ return ret; ++ ++ len = mtd_pad_erasesize(master, offset, squashfs_len); ++ *split_offset = offset + len; ++ ++ return 0; ++} ++ ++static void split_rootfs_data(struct mtd_info *master, struct mtd_part *part) ++{ ++ unsigned int split_offset = 0; ++ unsigned int split_size; ++ int ret; ++ ++ ret = split_squashfs(master, part->offset, &split_offset); ++ if (ret) ++ return; ++ ++ if (split_offset <= 0) ++ return; ++ ++ if (config_enabled(CONFIG_MTD_SPLIT_SQUASHFS_ROOT)) ++ pr_err("Dedicated partitioner didn't create \"rootfs_data\" partition, please fill a bug report!\n"); ++ else ++ pr_warn("Support for built-in \"rootfs_data\" splitter will be removed, please use CONFIG_MTD_SPLIT_SQUASHFS_ROOT\n"); ++ ++ split_size = part->mtd.size - (split_offset - part->offset); ++ printk(KERN_INFO "mtd: partition \"%s\" created automatically, ofs=0x%x, len=0x%x\n", ++ ROOTFS_SPLIT_NAME, split_offset, split_size); ++ ++ __mtd_add_partition(master, ROOTFS_SPLIT_NAME, split_offset, ++ split_size, false); ++} ++ + #define UBOOT_MAGIC 0x27051956 + + static void split_uimage(struct mtd_info *master, struct mtd_part *part) +@@ -744,7 +785,10 @@ static void mtd_partition_split(struct m + return; + + if (!strcmp(part->mtd.name, "rootfs")) { +- run_parsers_by_type(part, MTD_PARSER_TYPE_ROOTFS); ++ int num = run_parsers_by_type(part, MTD_PARSER_TYPE_ROOTFS); ++ ++ if (num <= 0 && config_enabled(CONFIG_MTD_ROOTFS_SPLIT)) ++ split_rootfs_data(master, part); + + rootfs_found = 1; + } diff --git a/target/linux/generic/patches-3.18/410-mtd-move-forward-declaration-of-struct-mtd_info.patch b/target/linux/generic/patches-3.18/410-mtd-move-forward-declaration-of-struct-mtd_info.patch new file mode 100644 index 0000000..78ebbf8 --- /dev/null +++ b/target/linux/generic/patches-3.18/410-mtd-move-forward-declaration-of-struct-mtd_info.patch @@ -0,0 +1,18 @@ +--- a/include/linux/mtd/partitions.h ++++ b/include/linux/mtd/partitions.h +@@ -35,6 +35,7 @@ + * Note: writeable partitions require their size and offset be + * erasesize aligned (e.g. use MTDPART_OFS_NEXTBLK). + */ ++struct mtd_info; + + struct mtd_partition { + const char *name; /* identifier string */ +@@ -50,7 +51,6 @@ struct mtd_partition { + #define MTDPART_SIZ_FULL (0) + + +-struct mtd_info; + struct device_node; + + /** diff --git a/target/linux/generic/patches-3.18/411-mtd-partial_eraseblock_write.patch b/target/linux/generic/patches-3.18/411-mtd-partial_eraseblock_write.patch new file mode 100644 index 0000000..5d5c6ed --- /dev/null +++ b/target/linux/generic/patches-3.18/411-mtd-partial_eraseblock_write.patch @@ -0,0 +1,142 @@ +--- a/drivers/mtd/mtdpart.c ++++ b/drivers/mtd/mtdpart.c +@@ -36,6 +36,8 @@ + #include "mtdcore.h" + #include "mtdsplit/mtdsplit.h" + ++#define MTD_ERASE_PARTIAL 0x8000 /* partition only covers parts of an erase block */ ++ + /* Our partition linked list */ + static LIST_HEAD(mtd_partitions); + static DEFINE_MUTEX(mtd_partitions_mutex); +@@ -234,13 +236,61 @@ static int part_erase(struct mtd_info *m + struct mtd_part *part = PART(mtd); + int ret; + ++ ++ instr->partial_start = false; ++ if (mtd->flags & MTD_ERASE_PARTIAL) { ++ size_t readlen = 0; ++ u64 mtd_ofs; ++ ++ instr->erase_buf = kmalloc(part->master->erasesize, GFP_ATOMIC); ++ if (!instr->erase_buf) ++ return -ENOMEM; ++ ++ mtd_ofs = part->offset + instr->addr; ++ instr->erase_buf_ofs = do_div(mtd_ofs, part->master->erasesize); ++ ++ if (instr->erase_buf_ofs > 0) { ++ instr->addr -= instr->erase_buf_ofs; ++ ret = mtd_read(part->master, ++ instr->addr + part->offset, ++ part->master->erasesize, ++ &readlen, instr->erase_buf); ++ ++ instr->len += instr->erase_buf_ofs; ++ instr->partial_start = true; ++ } else { ++ mtd_ofs = part->offset + part->mtd.size; ++ instr->erase_buf_ofs = part->master->erasesize - ++ do_div(mtd_ofs, part->master->erasesize); ++ ++ if (instr->erase_buf_ofs > 0) { ++ instr->len += instr->erase_buf_ofs; ++ ret = mtd_read(part->master, ++ part->offset + instr->addr + ++ instr->len - part->master->erasesize, ++ part->master->erasesize, &readlen, ++ instr->erase_buf); ++ } else { ++ ret = 0; ++ } ++ } ++ if (ret < 0) { ++ kfree(instr->erase_buf); ++ return ret; ++ } ++ ++ } ++ + instr->addr += part->offset; + ret = part->master->_erase(part->master, instr); + if (ret) { + if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN) + instr->fail_addr -= part->offset; + instr->addr -= part->offset; ++ if (mtd->flags & MTD_ERASE_PARTIAL) ++ kfree(instr->erase_buf); + } ++ + return ret; + } + +@@ -248,7 +298,25 @@ void mtd_erase_callback(struct erase_inf + { + if (instr->mtd->_erase == part_erase) { + struct mtd_part *part = PART(instr->mtd); ++ size_t wrlen = 0; + ++ if (instr->mtd->flags & MTD_ERASE_PARTIAL) { ++ if (instr->partial_start) { ++ part->master->_write(part->master, ++ instr->addr, instr->erase_buf_ofs, ++ &wrlen, instr->erase_buf); ++ instr->addr += instr->erase_buf_ofs; ++ } else { ++ instr->len -= instr->erase_buf_ofs; ++ part->master->_write(part->master, ++ instr->addr + instr->len, ++ instr->erase_buf_ofs, &wrlen, ++ instr->erase_buf + ++ part->master->erasesize - ++ instr->erase_buf_ofs); ++ } ++ kfree(instr->erase_buf); ++ } + if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN) + instr->fail_addr -= part->offset; + instr->addr -= part->offset; +@@ -515,17 +583,20 @@ static struct mtd_part *allocate_partiti + if ((slave->mtd.flags & MTD_WRITEABLE) && + mtd_mod_by_eb(slave->offset, &slave->mtd)) { + /* Doesn't start on a boundary of major erase size */ +- /* FIXME: Let it be writable if it is on a boundary of +- * _minor_ erase size though */ +- slave->mtd.flags &= ~MTD_WRITEABLE; +- printk(KERN_WARNING"mtd: partition \"%s\" doesn't start on an erase block boundary -- force read-only\n", +- part->name); ++ slave->mtd.flags |= MTD_ERASE_PARTIAL; ++ if (((u32) slave->mtd.size) > master->erasesize) ++ slave->mtd.flags &= ~MTD_WRITEABLE; ++ else ++ slave->mtd.erasesize = slave->mtd.size; + } + if ((slave->mtd.flags & MTD_WRITEABLE) && +- mtd_mod_by_eb(slave->mtd.size, &slave->mtd)) { +- slave->mtd.flags &= ~MTD_WRITEABLE; +- printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n", +- part->name); ++ mtd_mod_by_eb(slave->offset + slave->mtd.size, &slave->mtd)) { ++ slave->mtd.flags |= MTD_ERASE_PARTIAL; ++ ++ if ((u32) slave->mtd.size > master->erasesize) ++ slave->mtd.flags &= ~MTD_WRITEABLE; ++ else ++ slave->mtd.erasesize = slave->mtd.size; + } + + slave->mtd.ecclayout = master->ecclayout; +--- a/include/linux/mtd/mtd.h ++++ b/include/linux/mtd/mtd.h +@@ -55,6 +55,10 @@ struct erase_info { + u_long priv; + u_char state; + struct erase_info *next; ++ ++ u8 *erase_buf; ++ u32 erase_buf_ofs; ++ bool partial_start; + }; + + struct mtd_erase_region_info { diff --git a/target/linux/generic/patches-3.18/412-mtd-partial_eraseblock_unlock.patch b/target/linux/generic/patches-3.18/412-mtd-partial_eraseblock_unlock.patch new file mode 100644 index 0000000..62f9d5b --- /dev/null +++ b/target/linux/generic/patches-3.18/412-mtd-partial_eraseblock_unlock.patch @@ -0,0 +1,18 @@ +--- a/drivers/mtd/mtdpart.c ++++ b/drivers/mtd/mtdpart.c +@@ -335,7 +335,14 @@ static int part_lock(struct mtd_info *mt + static int part_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) + { + struct mtd_part *part = PART(mtd); +- return part->master->_unlock(part->master, ofs + part->offset, len); ++ ++ ofs += part->offset; ++ if (mtd->flags & MTD_ERASE_PARTIAL) { ++ /* round up len to next erasesize and round down offset to prev block */ ++ len = (mtd_div_by_eb(len, part->master) + 1) * part->master->erasesize; ++ ofs &= ~(part->master->erasesize - 1); ++ } ++ return part->master->_unlock(part->master, ofs, len); + } + + static int part_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len) diff --git a/target/linux/generic/patches-3.18/420-mtd-redboot_space.patch b/target/linux/generic/patches-3.18/420-mtd-redboot_space.patch new file mode 100644 index 0000000..f74affc --- /dev/null +++ b/target/linux/generic/patches-3.18/420-mtd-redboot_space.patch @@ -0,0 +1,30 @@ +--- a/drivers/mtd/redboot.c ++++ b/drivers/mtd/redboot.c +@@ -265,14 +265,21 @@ static int parse_redboot_partitions(stru + #endif + names += strlen(names)+1; + +-#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED + if(fl->next && fl->img->flash_base + fl->img->size + master->erasesize <= fl->next->img->flash_base) { +- i++; +- parts[i].offset = parts[i-1].size + parts[i-1].offset; +- parts[i].size = fl->next->img->flash_base - parts[i].offset; +- parts[i].name = nullname; +- } ++ if (!strcmp(parts[i].name, "rootfs")) { ++ parts[i].size = fl->next->img->flash_base; ++ parts[i].size &= ~(master->erasesize - 1); ++ parts[i].size -= parts[i].offset; ++#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED ++ nrparts--; ++ } else { ++ i++; ++ parts[i].offset = parts[i-1].size + parts[i-1].offset; ++ parts[i].size = fl->next->img->flash_base - parts[i].offset; ++ parts[i].name = nullname; + #endif ++ } ++ } + tmp_fl = fl; + fl = fl->next; + kfree(tmp_fl); diff --git a/target/linux/generic/patches-3.18/430-mtd-add-myloader-partition-parser.patch b/target/linux/generic/patches-3.18/430-mtd-add-myloader-partition-parser.patch new file mode 100644 index 0000000..25e0ecd --- /dev/null +++ b/target/linux/generic/patches-3.18/430-mtd-add-myloader-partition-parser.patch @@ -0,0 +1,35 @@ +--- a/drivers/mtd/Kconfig ++++ b/drivers/mtd/Kconfig +@@ -184,6 +184,22 @@ config MTD_BCM47XX_PARTS + This provides partitions parser for devices based on BCM47xx + boards. + ++config MTD_MYLOADER_PARTS ++ tristate "MyLoader partition parsing" ++ depends on ADM5120 || ATH25 || ATH79 ++ ---help--- ++ MyLoader is a bootloader which allows the user to define partitions ++ in flash devices, by putting a table in the second erase block ++ on the device, similar to a partition table. This table gives the ++ offsets and lengths of the user defined partitions. ++ ++ If you need code which can detect and parse these tables, and ++ register MTD 'partitions' corresponding to each image detected, ++ enable this option. ++ ++ You will still need the parsing functions to be called by the driver ++ for your particular device. It won't happen automatically. ++ + comment "User Modules And Translation Layers" + + # +--- a/drivers/mtd/Makefile ++++ b/drivers/mtd/Makefile +@@ -15,6 +15,7 @@ obj-$(CONFIG_MTD_AFS_PARTS) += afs.o + obj-$(CONFIG_MTD_AR7_PARTS) += ar7part.o + obj-$(CONFIG_MTD_BCM63XX_PARTS) += bcm63xxpart.o + obj-$(CONFIG_MTD_BCM47XX_PARTS) += bcm47xxpart.o ++obj-$(CONFIG_MTD_MYLOADER_PARTS) += myloader.o + + # 'Users' - code which presents functionality to userspace. + obj-$(CONFIG_MTD_BLKDEVS) += mtd_blkdevs.o diff --git a/target/linux/generic/patches-3.18/431-mtd-bcm47xxpart-support-for-Xiaomi-specific-board_da.patch b/target/linux/generic/patches-3.18/431-mtd-bcm47xxpart-support-for-Xiaomi-specific-board_da.patch new file mode 100644 index 0000000..a30e698 --- /dev/null +++ b/target/linux/generic/patches-3.18/431-mtd-bcm47xxpart-support-for-Xiaomi-specific-board_da.patch @@ -0,0 +1,34 @@ +From 841e59ba3e496d86ca5f069204d5e5c1ad43c01d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Tue, 27 Jan 2015 22:29:21 +0100 +Subject: [PATCH] mtd: bcm47xxpart: support for Xiaomi specific board_data + partition +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Rafał Miłecki +--- + drivers/mtd/bcm47xxpart.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/mtd/bcm47xxpart.c ++++ b/drivers/mtd/bcm47xxpart.c +@@ -33,6 +33,7 @@ + /* Magics */ + #define BOARD_DATA_MAGIC 0x5246504D /* MPFR */ + #define BOARD_DATA_MAGIC2 0xBD0D0BBD ++#define BOARD_DATA_XIAOMI_MAGIC 0x474D4442 /* GMDB */ + #define CFE_MAGIC 0x43464531 /* 1EFC */ + #define FACTORY_MAGIC 0x59544346 /* FCTY */ + #define NVRAM_HEADER 0x48534C46 /* FLSH */ +@@ -262,7 +263,8 @@ static int bcm47xxpart_parse(struct mtd_ + } + + /* Some devices (ex. WNDR3700v3) don't have a standard 'MPFR' */ +- if (buf[0x000 / 4] == BOARD_DATA_MAGIC2) { ++ if (buf[0x000 / 4] == BOARD_DATA_MAGIC2 || ++ le32_to_cpu(buf[0x000 / 4]) == BOARD_DATA_XIAOMI_MAGIC) { + bcm47xxpart_add_part(&parts[curr_part++], "board_data", + offset, MTD_WRITEABLE); + continue; diff --git a/target/linux/generic/patches-3.18/432-mtd-bcm47xxpart-detect-T_Meter-partition.patch b/target/linux/generic/patches-3.18/432-mtd-bcm47xxpart-detect-T_Meter-partition.patch new file mode 100644 index 0000000..1edc995 --- /dev/null +++ b/target/linux/generic/patches-3.18/432-mtd-bcm47xxpart-detect-T_Meter-partition.patch @@ -0,0 +1,42 @@ +From fd54aa583296f9adfb1f519affbc10ba521eb809 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Wed, 28 Jan 2015 22:14:41 +0100 +Subject: [PATCH] mtd: bcm47xxpart: detect T_Meter partition +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +It can be found on many Netgear devices. It consists of many 0x30 blocks +starting with 4D 54. + +Signed-off-by: Rafał Miłecki +--- + drivers/mtd/bcm47xxpart.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +--- a/drivers/mtd/bcm47xxpart.c ++++ b/drivers/mtd/bcm47xxpart.c +@@ -39,6 +39,7 @@ + #define NVRAM_HEADER 0x48534C46 /* FLSH */ + #define POT_MAGIC1 0x54544f50 /* POTT */ + #define POT_MAGIC2 0x504f /* OP */ ++#define T_METER_MAGIC 0x4D540000 /* MT */ + #define ML_MAGIC1 0x39685a42 + #define ML_MAGIC2 0x26594131 + #define TRX_MAGIC 0x30524448 +@@ -176,6 +177,15 @@ static int bcm47xxpart_parse(struct mtd_ + MTD_WRITEABLE); + continue; + } ++ ++ /* T_Meter */ ++ if ((le32_to_cpu(buf[0x000 / 4]) & 0xFFFF0000) == T_METER_MAGIC && ++ (le32_to_cpu(buf[0x030 / 4]) & 0xFFFF0000) == T_METER_MAGIC && ++ (le32_to_cpu(buf[0x060 / 4]) & 0xFFFF0000) == T_METER_MAGIC) { ++ bcm47xxpart_add_part(&parts[curr_part++], "T_Meter", offset, ++ MTD_WRITEABLE); ++ continue; ++ } + + /* TRX */ + if (buf[0x000 / 4] == TRX_MAGIC) { diff --git a/target/linux/generic/patches-3.18/440-block2mtd_init.patch b/target/linux/generic/patches-3.18/440-block2mtd_init.patch new file mode 100644 index 0000000..5ab6026 --- /dev/null +++ b/target/linux/generic/patches-3.18/440-block2mtd_init.patch @@ -0,0 +1,107 @@ +--- a/drivers/mtd/devices/block2mtd.c ++++ b/drivers/mtd/devices/block2mtd.c +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -209,11 +210,12 @@ static void block2mtd_free_device(struct + } + + +-static struct block2mtd_dev *add_device(char *devname, int erase_size) ++static struct block2mtd_dev *add_device(char *devname, int erase_size, const char *mtdname) + { + const fmode_t mode = FMODE_READ | FMODE_WRITE | FMODE_EXCL; + struct block_device *bdev; + struct block2mtd_dev *dev; ++ struct mtd_partition *part; + char *name; + + if (!devname) +@@ -257,13 +259,16 @@ static struct block2mtd_dev *add_device( + + /* Setup the MTD structure */ + /* make the name contain the block device in */ +- name = kasprintf(GFP_KERNEL, "block2mtd: %s", devname); ++ if (!mtdname) ++ mtdname = devname; ++ name = kmalloc(strlen(mtdname) + 1, GFP_KERNEL); + if (!name) + goto err_destroy_mutex; + ++ strcpy(name, mtdname); + dev->mtd.name = name; + +- dev->mtd.size = dev->blkdev->bd_inode->i_size & PAGE_MASK; ++ dev->mtd.size = dev->blkdev->bd_inode->i_size & PAGE_MASK & ~(erase_size - 1); + dev->mtd.erasesize = erase_size; + dev->mtd.writesize = 1; + dev->mtd.writebufsize = PAGE_SIZE; +@@ -276,15 +281,18 @@ static struct block2mtd_dev *add_device( + dev->mtd.priv = dev; + dev->mtd.owner = THIS_MODULE; + +- if (mtd_device_register(&dev->mtd, NULL, 0)) { ++ part = kzalloc(sizeof(struct mtd_partition), GFP_KERNEL); ++ part->name = name; ++ part->offset = 0; ++ part->size = dev->mtd.size; ++ if (mtd_device_register(&dev->mtd, part, 1)) { + /* Device didn't get added, so free the entry */ + goto err_destroy_mutex; + } + list_add(&dev->list, &blkmtd_device_list); + pr_info("mtd%d: [%s] erase_size = %dKiB [%d]\n", + dev->mtd.index, +- dev->mtd.name + strlen("block2mtd: "), +- dev->mtd.erasesize >> 10, dev->mtd.erasesize); ++ mtdname, dev->mtd.erasesize >> 10, dev->mtd.erasesize); + return dev; + + err_destroy_mutex: +@@ -353,9 +361,9 @@ static char block2mtd_paramline[80 + 12] + + static int block2mtd_setup2(const char *val) + { +- char buf[80 + 12]; /* 80 for device, 12 for erase size */ ++ char buf[80 + 12 + 80]; /* 80 for device, 12 for erase size, 80 for name */ + char *str = buf; +- char *token[2]; ++ char *token[3]; + char *name; + size_t erase_size = PAGE_SIZE; + int i, ret; +@@ -368,7 +376,7 @@ static int block2mtd_setup2(const char * + strcpy(str, val); + kill_final_newline(str); + +- for (i = 0; i < 2; i++) ++ for (i = 0; i < 3; i++) + token[i] = strsep(&str, ","); + + if (str) { +@@ -394,8 +402,10 @@ static int block2mtd_setup2(const char * + return 0; + } + } ++ if (token[2] && (strlen(token[2]) + 1 > 80)) ++ pr_err("mtd device name too long\n"); + +- add_device(name, erase_size); ++ add_device(name, erase_size, token[2]); + + return 0; + } +@@ -429,7 +439,7 @@ static int block2mtd_setup(const char *v + + + module_param_call(block2mtd, block2mtd_setup, NULL, NULL, 0200); +-MODULE_PARM_DESC(block2mtd, "Device to use. \"block2mtd=[,]\""); ++MODULE_PARM_DESC(block2mtd, "Device to use. \"block2mtd=[,[,]]\""); + + static int __init block2mtd_init(void) + { diff --git a/target/linux/generic/patches-3.18/441-block2mtd_probe.patch b/target/linux/generic/patches-3.18/441-block2mtd_probe.patch new file mode 100644 index 0000000..6836a48 --- /dev/null +++ b/target/linux/generic/patches-3.18/441-block2mtd_probe.patch @@ -0,0 +1,110 @@ +--- a/drivers/mtd/devices/block2mtd.c ++++ b/drivers/mtd/devices/block2mtd.c +@@ -10,6 +10,7 @@ + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + + #include ++#include + #include + #include + #include +@@ -210,13 +211,16 @@ static void block2mtd_free_device(struct + } + + +-static struct block2mtd_dev *add_device(char *devname, int erase_size, const char *mtdname) ++static struct block2mtd_dev *add_device(char *devname, int erase_size, const char *mtdname, int timeout) + { + const fmode_t mode = FMODE_READ | FMODE_WRITE | FMODE_EXCL; +- struct block_device *bdev; ++ struct block_device *bdev = ERR_PTR(-ENODEV); + struct block2mtd_dev *dev; + struct mtd_partition *part; + char *name; ++#ifndef MODULE ++ int i; ++#endif + + if (!devname) + return NULL; +@@ -227,15 +231,20 @@ static struct block2mtd_dev *add_device( + + /* Get a handle on the device */ + bdev = blkdev_get_by_path(devname, mode, dev); ++ + #ifndef MODULE +- if (IS_ERR(bdev)) { ++ for (i = 0; IS_ERR(bdev) && i <= timeout; i++) { ++ dev_t devt; + +- /* We might not have rootfs mounted at this point. Try +- to resolve the device name by other means. */ ++ if (i) ++ msleep(1000); ++ wait_for_device_probe(); ++ ++ devt = name_to_dev_t(devname); ++ if (!devt) ++ continue; + +- dev_t devt = name_to_dev_t(devname); +- if (devt) +- bdev = blkdev_get_by_dev(devt, mode, dev); ++ bdev = blkdev_get_by_dev(devt, mode, dev); + } + #endif + +@@ -361,11 +370,12 @@ static char block2mtd_paramline[80 + 12] + + static int block2mtd_setup2(const char *val) + { +- char buf[80 + 12 + 80]; /* 80 for device, 12 for erase size, 80 for name */ ++ char buf[80 + 12 + 80 + 8]; /* 80 for device, 12 for erase size, 80 for name, 8 for timeout */ + char *str = buf; +- char *token[3]; ++ char *token[4]; + char *name; + size_t erase_size = PAGE_SIZE; ++ unsigned long timeout = 0; + int i, ret; + + if (strnlen(val, sizeof(buf)) >= sizeof(buf)) { +@@ -376,7 +386,7 @@ static int block2mtd_setup2(const char * + strcpy(str, val); + kill_final_newline(str); + +- for (i = 0; i < 3; i++) ++ for (i = 0; i < 4; i++) + token[i] = strsep(&str, ","); + + if (str) { +@@ -405,7 +415,10 @@ static int block2mtd_setup2(const char * + if (token[2] && (strlen(token[2]) + 1 > 80)) + pr_err("mtd device name too long\n"); + +- add_device(name, erase_size, token[2]); ++ if (token[3] && kstrtoul(token[3], 0, &timeout)) ++ pr_err("invalid timeout\n"); ++ ++ add_device(name, erase_size, token[2], timeout); + + return 0; + } +@@ -439,7 +452,7 @@ static int block2mtd_setup(const char *v + + + module_param_call(block2mtd, block2mtd_setup, NULL, NULL, 0200); +-MODULE_PARM_DESC(block2mtd, "Device to use. \"block2mtd=[,[,]]\""); ++MODULE_PARM_DESC(block2mtd, "Device to use. \"block2mtd=[,[,[,]]]\""); + + static int __init block2mtd_init(void) + { +@@ -474,7 +487,7 @@ static void block2mtd_exit(void) + } + + +-module_init(block2mtd_init); ++late_initcall(block2mtd_init); + module_exit(block2mtd_exit); + + MODULE_LICENSE("GPL"); diff --git a/target/linux/generic/patches-3.18/450-mtd-nand-allow-to-use-platform-specific-chip-fixup.patch b/target/linux/generic/patches-3.18/450-mtd-nand-allow-to-use-platform-specific-chip-fixup.patch new file mode 100644 index 0000000..0f5abaa --- /dev/null +++ b/target/linux/generic/patches-3.18/450-mtd-nand-allow-to-use-platform-specific-chip-fixup.patch @@ -0,0 +1,37 @@ +--- + drivers/mtd/nand/plat_nand.c | 13 ++++++++++++- + include/linux/mtd/nand.h | 1 + + 2 files changed, 13 insertions(+), 1 deletion(-) + +--- a/include/linux/mtd/nand.h ++++ b/include/linux/mtd/nand.h +@@ -851,6 +851,7 @@ struct platform_nand_chip { + unsigned int options; + unsigned int bbt_options; + const char **part_probe_types; ++ int (*chip_fixup)(struct mtd_info *mtd); + }; + + /* Keep gcc happy */ +--- a/drivers/mtd/nand/plat_nand.c ++++ b/drivers/mtd/nand/plat_nand.c +@@ -90,7 +90,18 @@ static int plat_nand_probe(struct platfo + } + + /* Scan to find existence of the device */ +- if (nand_scan(&data->mtd, pdata->chip.nr_chips)) { ++ if (nand_scan_ident(&data->mtd, pdata->chip.nr_chips, NULL)) { ++ err = -ENXIO; ++ goto out; ++ } ++ ++ if (pdata->chip.chip_fixup) { ++ err = pdata->chip.chip_fixup(&data->mtd); ++ if (err) ++ goto out; ++ } ++ ++ if (nand_scan_tail(&data->mtd)) { + err = -ENXIO; + goto out; + } diff --git a/target/linux/generic/patches-3.18/451-mtd-nand-fix-return-code-of-nand_correct_data-function.patch b/target/linux/generic/patches-3.18/451-mtd-nand-fix-return-code-of-nand_correct_data-function.patch new file mode 100644 index 0000000..6a2092c --- /dev/null +++ b/target/linux/generic/patches-3.18/451-mtd-nand-fix-return-code-of-nand_correct_data-function.patch @@ -0,0 +1,11 @@ +--- a/drivers/mtd/nand/nand_ecc.c ++++ b/drivers/mtd/nand/nand_ecc.c +@@ -507,7 +507,7 @@ int __nand_correct_data(unsigned char *b + return 1; /* error in ECC data; no action needed */ + + pr_err("%s: uncorrectable ECC error\n", __func__); +- return -1; ++ return -EBADMSG; + } + EXPORT_SYMBOL(__nand_correct_data); + diff --git a/target/linux/generic/patches-3.18/460-mtd-cfi_cmdset_0002-no-erase_suspend.patch b/target/linux/generic/patches-3.18/460-mtd-cfi_cmdset_0002-no-erase_suspend.patch new file mode 100644 index 0000000..68fbd12 --- /dev/null +++ b/target/linux/generic/patches-3.18/460-mtd-cfi_cmdset_0002-no-erase_suspend.patch @@ -0,0 +1,11 @@ +--- a/drivers/mtd/chips/cfi_cmdset_0002.c ++++ b/drivers/mtd/chips/cfi_cmdset_0002.c +@@ -809,7 +809,7 @@ static int get_chip(struct map_info *map + return 0; + + case FL_ERASING: +- if (!cfip || !(cfip->EraseSuspend & (0x1|0x2)) || ++ if (1 /* no suspend */ || !cfip || !(cfip->EraseSuspend & (0x1|0x2)) || + !(mode == FL_READY || mode == FL_POINT || + (mode == FL_WRITING && (cfip->EraseSuspend & 0x2)))) + goto sleep; diff --git a/target/linux/generic/patches-3.18/461-mtd-cfi_cmdset_0002-add-buffer-write-cmd-timeout.patch b/target/linux/generic/patches-3.18/461-mtd-cfi_cmdset_0002-add-buffer-write-cmd-timeout.patch new file mode 100644 index 0000000..c437a14 --- /dev/null +++ b/target/linux/generic/patches-3.18/461-mtd-cfi_cmdset_0002-add-buffer-write-cmd-timeout.patch @@ -0,0 +1,18 @@ +From: George Kashperko + +Issue map read after Write Buffer Load command to ensure chip is ready +to receive data. +Signed-off-by: George Kashperko +--- + drivers/mtd/chips/cfi_cmdset_0002.c | 1 + + 1 file changed, 1 insertion(+) +--- a/drivers/mtd/chips/cfi_cmdset_0002.c ++++ b/drivers/mtd/chips/cfi_cmdset_0002.c +@@ -1830,6 +1830,7 @@ static int __xipram do_write_buffer(stru + + /* Write Buffer Load */ + map_write(map, CMD(0x25), cmd_adr); ++ (void) map_read(map, cmd_adr); + + chip->state = FL_WRITING_TO_BUFFER; + diff --git a/target/linux/generic/patches-3.18/472-mtd-m25p80-add-support-for-Winbond-W25X05-flash.patch b/target/linux/generic/patches-3.18/472-mtd-m25p80-add-support-for-Winbond-W25X05-flash.patch new file mode 100644 index 0000000..dca6895 --- /dev/null +++ b/target/linux/generic/patches-3.18/472-mtd-m25p80-add-support-for-Winbond-W25X05-flash.patch @@ -0,0 +1,20 @@ +From eef9dfc4e821408af1af13aa0cc707fc496fb7c6 Mon Sep 17 00:00:00 2001 +From: Gabor Juhos +Date: Wed, 11 Dec 2013 19:05:59 +0100 +Subject: [PATCH] m25p80: add support for the Winbond W25X05 flash + +Signed-off-by: Gabor Juhos +--- + drivers/mtd/devices/m25p80.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/mtd/spi-nor/spi-nor.c ++++ b/drivers/mtd/spi-nor/spi-nor.c +@@ -617,6 +617,7 @@ static const struct spi_device_id spi_no + { "m25px80", INFO(0x207114, 0, 64 * 1024, 16, 0) }, + + /* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */ ++ { "w25x05", INFO(0xef3010, 0, 64 * 1024, 1, SECT_4K) }, + { "w25x10", INFO(0xef3011, 0, 64 * 1024, 2, SECT_4K) }, + { "w25x20", INFO(0xef3012, 0, 64 * 1024, 4, SECT_4K) }, + { "w25x40", INFO(0xef3013, 0, 64 * 1024, 8, SECT_4K) }, diff --git a/target/linux/generic/patches-3.18/473-mtd-spi-nor-add-support-for-the-Macronix-MX25L512E-S.patch b/target/linux/generic/patches-3.18/473-mtd-spi-nor-add-support-for-the-Macronix-MX25L512E-S.patch new file mode 100644 index 0000000..8082fa6 --- /dev/null +++ b/target/linux/generic/patches-3.18/473-mtd-spi-nor-add-support-for-the-Macronix-MX25L512E-S.patch @@ -0,0 +1,21 @@ +From 0d7388de0911c1a4fc4a8a3898ef9d0ab818ca08 Mon Sep 17 00:00:00 2001 +From: Gabor Juhos +Date: Tue, 7 Apr 2015 18:35:15 +0200 +Subject: [PATCH] mtd: spi-nor: add support for the Macronix MX25L512E SPI + flash chip + +Signed-off-by: Gabor Juhos +--- + drivers/mtd/spi-nor/spi-nor.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/mtd/spi-nor/spi-nor.c ++++ b/drivers/mtd/spi-nor/spi-nor.c +@@ -517,6 +517,7 @@ static const struct spi_device_id spi_no + { "640s33b", INFO(0x898913, 0, 64 * 1024, 128, 0) }, + + /* Macronix */ ++ { "mx25l512e", INFO(0xc22010, 0, 64 * 1024, 1, SECT_4K) }, + { "mx25l2005a", INFO(0xc22012, 0, 64 * 1024, 4, SECT_4K) }, + { "mx25l4005a", INFO(0xc22013, 0, 64 * 1024, 8, SECT_4K) }, + { "mx25l8005", INFO(0xc22014, 0, 64 * 1024, 16, 0) }, diff --git a/target/linux/generic/patches-3.18/474-mtd-spi-nor-add-support-for-the-ISSI-SI25CD512-SPI-f.patch b/target/linux/generic/patches-3.18/474-mtd-spi-nor-add-support-for-the-ISSI-SI25CD512-SPI-f.patch new file mode 100644 index 0000000..f572237 --- /dev/null +++ b/target/linux/generic/patches-3.18/474-mtd-spi-nor-add-support-for-the-ISSI-SI25CD512-SPI-f.patch @@ -0,0 +1,22 @@ +From 34e2b403040a2f9d3ba071d95a7f42457e2950f9 Mon Sep 17 00:00:00 2001 +From: Gabor Juhos +Date: Tue, 7 Apr 2015 18:35:15 +0200 +Subject: [PATCH] mtd: spi-nor: add support for the ISSI SI25CD512 SPI flash + +Signed-off-by: Gabor Juhos +--- + drivers/mtd/spi-nor/spi-nor.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/mtd/spi-nor/spi-nor.c ++++ b/drivers/mtd/spi-nor/spi-nor.c +@@ -516,6 +516,9 @@ static const struct spi_device_id spi_no + { "320s33b", INFO(0x898912, 0, 64 * 1024, 64, 0) }, + { "640s33b", INFO(0x898913, 0, 64 * 1024, 128, 0) }, + ++ /* ISSI */ ++ { "is25cd512", INFO(0x7f9d20, 0, 32 * 1024, 2, SECT_4K) }, ++ + /* Macronix */ + { "mx25l512e", INFO(0xc22010, 0, 64 * 1024, 1, SECT_4K) }, + { "mx25l2005a", INFO(0xc22012, 0, 64 * 1024, 4, SECT_4K) }, diff --git a/target/linux/generic/patches-3.18/480-mtd-set-rootfs-to-be-root-dev.patch b/target/linux/generic/patches-3.18/480-mtd-set-rootfs-to-be-root-dev.patch new file mode 100644 index 0000000..8fc3578 --- /dev/null +++ b/target/linux/generic/patches-3.18/480-mtd-set-rootfs-to-be-root-dev.patch @@ -0,0 +1,26 @@ +--- a/drivers/mtd/mtdcore.c ++++ b/drivers/mtd/mtdcore.c +@@ -37,6 +37,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -456,6 +457,15 @@ int add_mtd_device(struct mtd_info *mtd) + of this try_ nonsense, and no bitching about it + either. :) */ + __module_get(THIS_MODULE); ++ ++ if (!strcmp(mtd->name, "rootfs") && ++ config_enabled(CONFIG_MTD_ROOTFS_ROOT_DEV) && ++ ROOT_DEV == 0) { ++ pr_notice("mtd: device %d (%s) set to be root filesystem\n", ++ mtd->index, mtd->name); ++ ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, mtd->index); ++ } ++ + return 0; + + fail_added: diff --git a/target/linux/generic/patches-3.18/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch b/target/linux/generic/patches-3.18/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch new file mode 100644 index 0000000..d7b20b8 --- /dev/null +++ b/target/linux/generic/patches-3.18/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch @@ -0,0 +1,76 @@ +From 8a52e4100d7c3a4a1dfddfa02b8864a9b0068c13 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Sat, 17 May 2014 03:36:18 +0200 +Subject: [PATCH 1/5] ubi: auto-attach mtd device named "ubi" or "data" on boot +To: openwrt-devel@lists.openwrt.org + +Signed-off-by: Daniel Golle +--- + drivers/mtd/ubi/build.c | 36 ++++++++++++++++++++++++++++++++++++ + 1 file changed, 36 insertions(+) + +--- a/drivers/mtd/ubi/build.c ++++ b/drivers/mtd/ubi/build.c +@@ -1209,6 +1209,49 @@ static struct mtd_info * __init open_mtd + return mtd; + } + ++/* ++ * This function tries attaching mtd partitions named either "ubi" or "data" ++ * during boot. ++ */ ++static void __init ubi_auto_attach(void) ++{ ++ int err; ++ struct mtd_info *mtd; ++ ++ /* try attaching mtd device named "ubi" or "data" */ ++ mtd = open_mtd_device("ubi"); ++ if (IS_ERR(mtd)) ++ mtd = open_mtd_device("data"); ++ ++ if (!IS_ERR(mtd)) { ++ size_t len; ++ char magic[4]; ++ ++ /* check for a valid ubi magic */ ++ err = mtd_read(mtd, 0, 4, &len, (void *) magic); ++ if (!err && len == 4 && strncmp(magic, "UBI#", 4)) { ++ ubi_err("no valid UBI magic found inside mtd%d", mtd->index); ++ put_mtd_device(mtd); ++ return; ++ } ++ ++ /* auto-add only media types where UBI makes sense */ ++ if (mtd->type == MTD_NANDFLASH || ++ mtd->type == MTD_NORFLASH || ++ mtd->type == MTD_DATAFLASH || ++ mtd->type == MTD_MLCNANDFLASH) { ++ mutex_lock(&ubi_devices_mutex); ++ ubi_msg("auto-attach mtd%d", mtd->index); ++ err = ubi_attach_mtd_dev(mtd, UBI_DEV_NUM_AUTO, 0, 0); ++ mutex_unlock(&ubi_devices_mutex); ++ if (err < 0) { ++ ubi_err("cannot attach mtd%d", mtd->index); ++ put_mtd_device(mtd); ++ } ++ } ++ } ++} ++ + static int __init ubi_init(void) + { + int err, i, k; +@@ -1298,6 +1341,12 @@ static int __init ubi_init(void) + } + } + ++ /* auto-attach mtd devices only if built-in to the kernel and no ubi.mtd ++ * parameter was given */ ++ if (config_enabled(CONFIG_MTD_ROOTFS_ROOT_DEV) && ++ !ubi_is_module() && !mtd_devs) ++ ubi_auto_attach(); ++ + err = ubiblock_init(); + if (err) { + ubi_err("block: cannot initialize, error %d", err); diff --git a/target/linux/generic/patches-3.18/491-ubi-auto-create-ubiblock-device-for-rootfs.patch b/target/linux/generic/patches-3.18/491-ubi-auto-create-ubiblock-device-for-rootfs.patch new file mode 100644 index 0000000..b152fba --- /dev/null +++ b/target/linux/generic/patches-3.18/491-ubi-auto-create-ubiblock-device-for-rootfs.patch @@ -0,0 +1,69 @@ +From 0f3966579815f889bb2fcb4846152c35f65e79c4 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Thu, 15 May 2014 21:06:33 +0200 +Subject: [PATCH 2/5] ubi: auto-create ubiblock device for rootfs +To: openwrt-devel@lists.openwrt.org + +Signed-off-by: Daniel Golle +--- + drivers/mtd/ubi/block.c | 42 ++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 42 insertions(+) + +--- a/drivers/mtd/ubi/block.c ++++ b/drivers/mtd/ubi/block.c +@@ -615,6 +615,44 @@ static int __init ubiblock_create_from_p + return ret; + } + ++#define UBIFS_NODE_MAGIC 0x06101831 ++static inline int ubi_vol_is_ubifs(struct ubi_volume_desc *desc) ++{ ++ int ret; ++ uint32_t magic_of, magic; ++ ret = ubi_read(desc, 0, (char *)&magic_of, 0, 4); ++ if (ret) ++ return 0; ++ magic = le32_to_cpu(magic_of); ++ return magic == UBIFS_NODE_MAGIC; ++} ++ ++static void __init ubiblock_create_auto_rootfs(void) ++{ ++ int ubi_num, ret, is_ubifs; ++ struct ubi_volume_desc *desc; ++ struct ubi_volume_info vi; ++ ++ for (ubi_num = 0; ubi_num < UBI_MAX_DEVICES; ubi_num++) { ++ desc = ubi_open_volume_nm(ubi_num, "rootfs", UBI_READONLY); ++ if (IS_ERR(desc)) ++ continue; ++ ++ ubi_get_volume_info(desc, &vi); ++ is_ubifs = ubi_vol_is_ubifs(desc); ++ ubi_close_volume(desc); ++ if (is_ubifs) ++ break; ++ ++ ret = ubiblock_create(&vi); ++ if (ret) ++ ubi_err("block: can't add '%s' volume, err=%d\n", ++ vi.name, ret); ++ /* always break if we get here */ ++ break; ++ } ++} ++ + static void ubiblock_remove_all(void) + { + struct ubiblock *next; +@@ -645,6 +683,10 @@ int __init ubiblock_init(void) + if (ret) + goto err_remove; + ++ /* auto-attach "rootfs" volume if existing and non-ubifs */ ++ if (config_enabled(CONFIG_MTD_ROOTFS_ROOT_DEV)) ++ ubiblock_create_auto_rootfs(); ++ + /* + * Block devices are only created upon user requests, so we ignore + * existing volumes. diff --git a/target/linux/generic/patches-3.18/492-try-auto-mounting-ubi0-rootfs-in-init-do_mounts.c.patch b/target/linux/generic/patches-3.18/492-try-auto-mounting-ubi0-rootfs-in-init-do_mounts.c.patch new file mode 100644 index 0000000..e4f31fd --- /dev/null +++ b/target/linux/generic/patches-3.18/492-try-auto-mounting-ubi0-rootfs-in-init-do_mounts.c.patch @@ -0,0 +1,53 @@ +From eea9e1785e4c05c2a3444506aabafa0ae958538f Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Sat, 17 May 2014 03:35:02 +0200 +Subject: [PATCH 4/5] try auto-mounting ubi0:rootfs in init/do_mounts.c +To: openwrt-devel@lists.openwrt.org + +Signed-off-by: Daniel Golle +--- + init/do_mounts.c | 26 +++++++++++++++++++++++++- + 1 file changed, 25 insertions(+), 1 deletion(-) + +--- a/init/do_mounts.c ++++ b/init/do_mounts.c +@@ -433,7 +433,27 @@ retry: + out: + put_page(page); + } +- ++ ++static int __init mount_ubi_rootfs(void) ++{ ++ int flags = MS_SILENT; ++ int err, tried = 0; ++ ++ while (tried < 2) { ++ err = do_mount_root("ubi0:rootfs", "ubifs", flags, \ ++ root_mount_data); ++ switch (err) { ++ case -EACCES: ++ flags |= MS_RDONLY; ++ tried++; ++ default: ++ return err; ++ } ++ } ++ ++ return -EINVAL; ++} ++ + #ifdef CONFIG_ROOT_NFS + + #define NFSROOT_TIMEOUT_MIN 5 +@@ -527,6 +547,10 @@ void __init mount_root(void) + change_floppy("root floppy"); + } + #endif ++#ifdef CONFIG_MTD_ROOTFS_ROOT_DEV ++ if (!mount_ubi_rootfs()) ++ return; ++#endif + #ifdef CONFIG_BLOCK + create_dev("/dev/root", ROOT_DEV); + mount_block_root("/dev/root", root_mountflags); diff --git a/target/linux/generic/patches-3.18/493-ubi-set-ROOT_DEV-to-ubiblock-rootfs-if-unset.patch b/target/linux/generic/patches-3.18/493-ubi-set-ROOT_DEV-to-ubiblock-rootfs-if-unset.patch new file mode 100644 index 0000000..46917d1 --- /dev/null +++ b/target/linux/generic/patches-3.18/493-ubi-set-ROOT_DEV-to-ubiblock-rootfs-if-unset.patch @@ -0,0 +1,37 @@ +From cd68d1b12b5ea4c01a664c064179ada42bf55d3d Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Thu, 15 May 2014 20:55:42 +0200 +Subject: [PATCH 5/5] ubi: set ROOT_DEV to ubiblock "rootfs" if unset +To: openwrt-devel@lists.openwrt.org + +Signed-off-by: Daniel Golle +--- + drivers/mtd/ubi/block.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +--- a/drivers/mtd/ubi/block.c ++++ b/drivers/mtd/ubi/block.c +@@ -48,6 +48,7 @@ + #include + #include + #include ++#include + + #include "ubi-media.h" + #include "ubi.h" +@@ -448,6 +449,15 @@ int ubiblock_create(struct ubi_volume_in + add_disk(dev->gd); + ubi_msg("%s created from ubi%d:%d(%s)", + dev->gd->disk_name, dev->ubi_num, dev->vol_id, vi->name); ++ ++ if (!strcmp(vi->name, "rootfs") && ++ config_enabled(CONFIG_MTD_ROOTFS_ROOT_DEV) && ++ ROOT_DEV == 0) { ++ pr_notice("ubiblock: device ubiblock%d_%d (%s) set to be root filesystem\n", ++ dev->ubi_num, dev->vol_id, vi->name); ++ ROOT_DEV = MKDEV(gd->major, gd->first_minor); ++ } ++ + return 0; + + out_free_queue: diff --git a/target/linux/generic/patches-3.18/494-mtd-ubi-add-EOF-marker-support.patch b/target/linux/generic/patches-3.18/494-mtd-ubi-add-EOF-marker-support.patch new file mode 100644 index 0000000..cd02c13 --- /dev/null +++ b/target/linux/generic/patches-3.18/494-mtd-ubi-add-EOF-marker-support.patch @@ -0,0 +1,51 @@ +--- a/drivers/mtd/ubi/attach.c ++++ b/drivers/mtd/ubi/attach.c +@@ -800,6 +800,13 @@ out_unlock: + return err; + } + ++static bool ec_hdr_has_eof(struct ubi_ec_hdr *ech) ++{ ++ return ech->padding1[0] == 'E' && ++ ech->padding1[1] == 'O' && ++ ech->padding1[2] == 'F'; ++} ++ + /** + * scan_peb - scan and process UBI headers of a PEB. + * @ubi: UBI device description object +@@ -830,9 +837,21 @@ static int scan_peb(struct ubi_device *u + return 0; + } + +- err = ubi_io_read_ec_hdr(ubi, pnum, ech, 0); +- if (err < 0) +- return err; ++ if (!ai->eof_found) { ++ err = ubi_io_read_ec_hdr(ubi, pnum, ech, 0); ++ if (err < 0) ++ return err; ++ ++ if (ec_hdr_has_eof(ech)) { ++ ubi_msg("EOF marker found, PEBs from %d will be erased", ++ pnum); ++ ai->eof_found = true; ++ } ++ } ++ ++ if (ai->eof_found) ++ err = UBI_IO_FF_BITFLIPS; ++ + switch (err) { + case 0: + break; +--- a/drivers/mtd/ubi/ubi.h ++++ b/drivers/mtd/ubi/ubi.h +@@ -701,6 +701,7 @@ struct ubi_attach_info { + int mean_ec; + uint64_t ec_sum; + int ec_count; ++ bool eof_found; + struct kmem_cache *aeb_slab_cache; + }; + diff --git a/target/linux/generic/patches-3.18/500-yaffs-Kbuild-integration.patch b/target/linux/generic/patches-3.18/500-yaffs-Kbuild-integration.patch new file mode 100644 index 0000000..de6643a --- /dev/null +++ b/target/linux/generic/patches-3.18/500-yaffs-Kbuild-integration.patch @@ -0,0 +1,18 @@ +--- a/fs/Kconfig ++++ b/fs/Kconfig +@@ -39,6 +39,7 @@ source "fs/gfs2/Kconfig" + source "fs/ocfs2/Kconfig" + source "fs/btrfs/Kconfig" + source "fs/nilfs2/Kconfig" ++source "fs/yaffs2/Kconfig" + + endif # BLOCK + +--- a/fs/Makefile ++++ b/fs/Makefile +@@ -126,3 +126,5 @@ obj-y += exofs/ # Multiple modules + obj-$(CONFIG_CEPH_FS) += ceph/ + obj-$(CONFIG_PSTORE) += pstore/ + obj-$(CONFIG_EFIVAR_FS) += efivarfs/ ++obj-$(CONFIG_YAFFS_FS) += yaffs2/ ++ diff --git a/target/linux/generic/patches-3.18/502-yaffs-fix-compat-tags-handling.patch b/target/linux/generic/patches-3.18/502-yaffs-fix-compat-tags-handling.patch new file mode 100644 index 0000000..a18cf6f --- /dev/null +++ b/target/linux/generic/patches-3.18/502-yaffs-fix-compat-tags-handling.patch @@ -0,0 +1,239 @@ +Subject: yaffs: fix compat tags handling + +Signed-off-by: Gabor Juhos +--- +--- a/fs/yaffs2/yaffs_tagscompat.c ++++ b/fs/yaffs2/yaffs_tagscompat.c +@@ -17,7 +17,9 @@ + #include "yaffs_getblockinfo.h" + #include "yaffs_trace.h" + ++#if 0 + static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk); ++#endif + + + /********** Tags ECC calculations *********/ +@@ -71,6 +73,7 @@ int yaffs_check_tags_ecc(struct yaffs_ta + return 0; + } + ++#if 0 + /********** Tags **********/ + + static void yaffs_load_tags_to_spare(struct yaffs_spare *spare_ptr, +@@ -379,3 +382,214 @@ void yaffs_tags_compat_install(struct ya + if(!dev->tagger.mark_bad_fn) + dev->tagger.mark_bad_fn = yaffs_tags_compat_mark_bad; + } ++#else ++ ++#include "yaffs_packedtags1.h" ++ ++static int yaffs_tags_compat_write(struct yaffs_dev *dev, ++ int nand_chunk, ++ const u8 *data, ++ const struct yaffs_ext_tags *tags) ++{ ++ struct yaffs_packed_tags1 pt1; ++ u8 tag_buf[9]; ++ int retval; ++ ++ /* we assume that yaffs_packed_tags1 and yaffs_tags are compatible */ ++ compile_time_assertion(sizeof(struct yaffs_packed_tags1) == 12); ++ compile_time_assertion(sizeof(struct yaffs_tags) == 8); ++ ++ yaffs_pack_tags1(&pt1, tags); ++ yaffs_calc_tags_ecc((struct yaffs_tags *)&pt1); ++ ++ /* When deleting a chunk, the upper layer provides only skeletal ++ * tags, one with is_deleted set. However, we need to update the ++ * tags, not erase them completely. So we use the NAND write property ++ * that only zeroed-bits stick and set tag bytes to all-ones and ++ * zero just the (not) deleted bit. ++ */ ++ if (!dev->param.tags_9bytes) { ++ if (tags->is_deleted) { ++ memset(&pt1, 0xff, 8); ++ /* clear delete status bit to indicate deleted */ ++ pt1.deleted = 0; ++ } ++ memcpy(tag_buf, &pt1, 8); ++ } else { ++ if (tags->is_deleted) { ++ memset(tag_buf, 0xff, 8); ++ tag_buf[8] = 0; ++ } else { ++ memcpy(tag_buf, &pt1, 8); ++ tag_buf[8] = 0xff; ++ } ++ } ++ ++ retval = dev->drv.drv_write_chunk_fn(dev, nand_chunk, ++ data, ++ (data) ? dev->data_bytes_per_chunk : 0, ++ tag_buf, ++ (dev->param.tags_9bytes) ? 9 : 8); ++ ++ return retval; ++} ++ ++/* Return with empty extended tags but add ecc_result. ++ */ ++static int return_empty_tags(struct yaffs_ext_tags *tags, ++ enum yaffs_ecc_result ecc_result, ++ int retval) ++{ ++ if (tags) { ++ memset(tags, 0, sizeof(*tags)); ++ tags->ecc_result = ecc_result; ++ } ++ ++ return retval; ++} ++ ++static int yaffs_tags_compat_read(struct yaffs_dev *dev, ++ int nand_chunk, ++ u8 *data, ++ struct yaffs_ext_tags *tags) ++{ ++ struct yaffs_packed_tags1 pt1; ++ enum yaffs_ecc_result ecc_result; ++ int retval; ++ int deleted; ++ u8 tag_buf[9]; ++ ++ retval = dev->drv.drv_read_chunk_fn(dev, nand_chunk, ++ data, dev->param.total_bytes_per_chunk, ++ tag_buf, ++ (dev->param.tags_9bytes) ? 9 : 8, ++ &ecc_result); ++ ++ switch (ecc_result) { ++ case YAFFS_ECC_RESULT_NO_ERROR: ++ case YAFFS_ECC_RESULT_FIXED: ++ break; ++ ++ case YAFFS_ECC_RESULT_UNFIXED: ++ default: ++ return_empty_tags(tags, YAFFS_ECC_RESULT_UNFIXED, 0); ++ tags->block_bad = dev->drv.drv_check_bad_fn(dev, nand_chunk); ++ return YAFFS_FAIL; ++ } ++ ++ /* Check for a blank/erased chunk. */ ++ if (yaffs_check_ff(tag_buf, 8)) { ++ /* when blank, upper layers want ecc_result to be <= NO_ERROR */ ++ return return_empty_tags(tags, YAFFS_ECC_RESULT_NO_ERROR, ++ YAFFS_OK); ++ } ++ ++ memcpy(&pt1, tag_buf, 8); ++ ++ if (!dev->param.tags_9bytes) { ++ /* Read deleted status (bit) then return it to it's non-deleted ++ * state before performing tags mini-ECC check. pt1.deleted is ++ * inverted. ++ */ ++ deleted = !pt1.deleted; ++ pt1.deleted = 1; ++ } else { ++ deleted = (hweight8(tag_buf[8]) < 7) ? 1 : 0; ++ } ++ ++ /* Check the packed tags mini-ECC and correct if necessary/possible. */ ++ retval = yaffs_check_tags_ecc((struct yaffs_tags *)&pt1); ++ switch (retval) { ++ case 0: ++ /* no tags error, use MTD result */ ++ break; ++ case 1: ++ /* recovered tags-ECC error */ ++ dev->n_tags_ecc_fixed++; ++ if (ecc_result == YAFFS_ECC_RESULT_NO_ERROR) ++ ecc_result = YAFFS_ECC_RESULT_FIXED; ++ break; ++ default: ++ /* unrecovered tags-ECC error */ ++ dev->n_tags_ecc_unfixed++; ++ return return_empty_tags(tags, YAFFS_ECC_RESULT_UNFIXED, ++ YAFFS_FAIL); ++ } ++ ++ /* Unpack the tags to extended form and set ECC result. ++ * [set should_be_ff just to keep yaffs_unpack_tags1 happy] ++ */ ++ pt1.should_be_ff = 0xffffffff; ++ yaffs_unpack_tags1(tags, &pt1); ++ tags->ecc_result = ecc_result; ++ ++ /* Set deleted state */ ++ tags->is_deleted = deleted; ++ return YAFFS_OK; ++} ++ ++static int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int block_no) ++{ ++ return dev->drv.drv_mark_bad_fn(dev, block_no); ++} ++ ++static int yaffs_tags_compat_query_block(struct yaffs_dev *dev, ++ int block_no, ++ enum yaffs_block_state *state, ++ u32 *seq_number) ++{ ++ struct yaffs_ext_tags tags; ++ int retval; ++ ++ yaffs_trace(YAFFS_TRACE_MTD, "%s %d", __func__, block_no); ++ ++ *seq_number = 0; ++ ++ retval = dev->drv.drv_check_bad_fn(dev, block_no); ++ if (retval == YAFFS_FAIL) { ++ *state = YAFFS_BLOCK_STATE_DEAD; ++ goto out; ++ } ++ ++ yaffs_tags_compat_read(dev, block_no * dev->param.chunks_per_block, ++ NULL, &tags); ++ ++ if (tags.ecc_result != YAFFS_ECC_RESULT_NO_ERROR) { ++ yaffs_trace(YAFFS_TRACE_MTD, "block %d is marked bad", ++ block_no); ++ *state = YAFFS_BLOCK_STATE_NEEDS_SCAN; ++ } else if (tags.chunk_used) { ++ *seq_number = tags.seq_number; ++ *state = YAFFS_BLOCK_STATE_NEEDS_SCAN; ++ } else { ++ *state = YAFFS_BLOCK_STATE_EMPTY; ++ } ++ ++ retval = YAFFS_OK; ++ ++out: ++ yaffs_trace(YAFFS_TRACE_MTD, ++ "block query returns seq %u state %d", ++ *seq_number, *state); ++ ++ return retval; ++} ++ ++void yaffs_tags_compat_install(struct yaffs_dev *dev) ++{ ++ if (dev->param.is_yaffs2) ++ return; ++ ++ if (!dev->tagger.write_chunk_tags_fn) ++ dev->tagger.write_chunk_tags_fn = yaffs_tags_compat_write; ++ ++ if (!dev->tagger.read_chunk_tags_fn) ++ dev->tagger.read_chunk_tags_fn = yaffs_tags_compat_read; ++ ++ if (!dev->tagger.query_block_fn) ++ dev->tagger.query_block_fn = yaffs_tags_compat_query_block; ++ ++ if (!dev->tagger.mark_bad_fn) ++ dev->tagger.mark_bad_fn = yaffs_tags_compat_mark_bad; ++} ++#endif diff --git a/target/linux/generic/patches-3.18/503-yaffs-add-tags-9bytes-mount-option.patch b/target/linux/generic/patches-3.18/503-yaffs-add-tags-9bytes-mount-option.patch new file mode 100644 index 0000000..3f51baf --- /dev/null +++ b/target/linux/generic/patches-3.18/503-yaffs-add-tags-9bytes-mount-option.patch @@ -0,0 +1,115 @@ +Subject: yaffs: add support for tags-9bytes mount option + +Signed-off-by: Gabor Juhos +--- +--- a/fs/yaffs2/yaffs_vfs.c ++++ b/fs/yaffs2/yaffs_vfs.c +@@ -2644,6 +2644,7 @@ static const struct super_operations yaf + + struct yaffs_options { + int inband_tags; ++ int tags_9bytes; + int skip_checkpoint_read; + int skip_checkpoint_write; + int no_cache; +@@ -2683,6 +2684,8 @@ static int yaffs_parse_options(struct ya + + if (!strcmp(cur_opt, "inband-tags")) { + options->inband_tags = 1; ++ } else if (!strcmp(cur_opt, "tags-9bytes")) { ++ options->tags_9bytes = 1; + } else if (!strcmp(cur_opt, "tags-ecc-off")) { + options->tags_ecc_on = 0; + options->tags_ecc_overridden = 1; +@@ -2756,7 +2759,6 @@ static struct super_block *yaffs_interna + struct yaffs_param *param; + + int read_only = 0; +- int inband_tags = 0; + + struct yaffs_options options; + +@@ -2796,6 +2798,9 @@ static struct super_block *yaffs_interna + + memset(&options, 0, sizeof(options)); + ++ if (IS_ENABLED(CONFIG_YAFFS_9BYTE_TAGS)) ++ options.tags_9bytes = 1; ++ + if (yaffs_parse_options(&options, data_str)) { + /* Option parsing failed */ + return NULL; +@@ -2829,17 +2834,22 @@ static struct super_block *yaffs_interna + } + + /* Added NCB 26/5/2006 for completeness */ +- if (yaffs_version == 2 && !options.inband_tags +- && WRITE_SIZE(mtd) == 512) { ++ if (yaffs_version == 2 && ++ (!options.inband_tags || options.tags_9bytes) && ++ WRITE_SIZE(mtd) == 512) { + yaffs_trace(YAFFS_TRACE_ALWAYS, "auto selecting yaffs1"); + yaffs_version = 1; + } + +- if (mtd->oobavail < sizeof(struct yaffs_packed_tags2) || +- options.inband_tags) +- inband_tags = 1; ++ if (yaffs_version == 2 && ++ mtd->oobavail < sizeof(struct yaffs_packed_tags2)) { ++ yaffs_trace(YAFFS_TRACE_ALWAYS, "auto selecting inband tags"); ++ options.inband_tags = 1; ++ } + +- if(yaffs_verify_mtd(mtd, yaffs_version, inband_tags) < 0) ++ err = yaffs_verify_mtd(mtd, yaffs_version, options.inband_tags, ++ options.tags_9bytes); ++ if (err < 0) + return NULL; + + /* OK, so if we got here, we have an MTD that's NAND and looks +@@ -2896,7 +2906,8 @@ static struct super_block *yaffs_interna + + param->n_reserved_blocks = 5; + param->n_caches = (options.no_cache) ? 0 : 10; +- param->inband_tags = inband_tags; ++ param->inband_tags = options.inband_tags; ++ param->tags_9bytes = options.tags_9bytes; + + param->enable_xattr = 1; + if (options.lazy_loading_overridden) +--- a/fs/yaffs2/yaffs_mtdif.c ++++ b/fs/yaffs2/yaffs_mtdif.c +@@ -278,7 +278,8 @@ struct mtd_info * yaffs_get_mtd_device(d + return mtd; + } + +-int yaffs_verify_mtd(struct mtd_info *mtd, int yaffs_version, int inband_tags) ++int yaffs_verify_mtd(struct mtd_info *mtd, int yaffs_version, int inband_tags, ++ int tags_9bytes) + { + if (yaffs_version == 2) { + if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE || +@@ -297,6 +298,12 @@ int yaffs_verify_mtd(struct mtd_info *mt + ); + return -1; + } ++ ++ if (tags_9bytes && mtd->oobavail < 9) { ++ yaffs_trace(YAFFS_TRACE_ALWAYS, ++ "MTD device does not support 9-byte tags"); ++ return -1; ++ } + } + + return 0; +--- a/fs/yaffs2/yaffs_mtdif.h ++++ b/fs/yaffs2/yaffs_mtdif.h +@@ -21,5 +21,6 @@ + void yaffs_mtd_drv_install(struct yaffs_dev *dev); + struct mtd_info * yaffs_get_mtd_device(dev_t sdev); + void yaffs_put_mtd_device(struct mtd_info *mtd); +-int yaffs_verify_mtd(struct mtd_info *mtd, int yaffs_version, int inband_tags); ++int yaffs_verify_mtd(struct mtd_info *mtd, int yaffs_version, int inband_tags, ++ int tags_9bytes); + #endif diff --git a/target/linux/generic/patches-3.18/504-yaffs-3.16-new-fops.patch b/target/linux/generic/patches-3.18/504-yaffs-3.16-new-fops.patch new file mode 100644 index 0000000..11c6da0 --- /dev/null +++ b/target/linux/generic/patches-3.18/504-yaffs-3.16-new-fops.patch @@ -0,0 +1,25 @@ +--- a/fs/yaffs2/yaffs_vfs.c ++++ b/fs/yaffs2/yaffs_vfs.c +@@ -774,7 +774,21 @@ static int yaffs_sync_object(struct file + } + + +-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22)) ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) ++static const struct file_operations yaffs_file_operations = { ++ .read = new_sync_read, ++ .read_iter = generic_file_read_iter, ++ .write = new_sync_write, ++ .write_iter = generic_file_write_iter, ++ .mmap = generic_file_mmap, ++ .flush = yaffs_file_flush, ++ .fsync = yaffs_sync_object, ++ .splice_read = generic_file_splice_read, ++ .splice_write = iter_file_splice_write, ++ .llseek = generic_file_llseek, ++}; ++ ++#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22)) + static const struct file_operations yaffs_file_operations = { + .read = do_sync_read, + .write = do_sync_write, diff --git a/target/linux/generic/patches-3.18/520-squashfs_update_xz_comp_opts.patch b/target/linux/generic/patches-3.18/520-squashfs_update_xz_comp_opts.patch new file mode 100644 index 0000000..ad11b30 --- /dev/null +++ b/target/linux/generic/patches-3.18/520-squashfs_update_xz_comp_opts.patch @@ -0,0 +1,25 @@ +From f31b7c0efa255dd17a5f584022a319387f09b0d8 Mon Sep 17 00:00:00 2001 +From: Jonas Gorski +Date: Tue, 12 Apr 2011 19:55:41 +0200 +Subject: [PATCH] squashfs: update xz compressor options struct. + +Update the xz compressor options struct to match the squashfs userspace +one. +--- + fs/squashfs/xz_wrapper.c | 4 +++- + 1 files changed, 3 insertions(+), 1 deletions(-) + +--- a/fs/squashfs/xz_wrapper.c ++++ b/fs/squashfs/xz_wrapper.c +@@ -40,8 +40,10 @@ struct squashfs_xz { + }; + + struct disk_comp_opts { +- __le32 dictionary_size; + __le32 flags; ++ __le16 bit_opts; ++ __le16 fb; ++ __le32 dictionary_size; + }; + + struct comp_opts { diff --git a/target/linux/generic/patches-3.18/530-jffs2_make_lzma_available.patch b/target/linux/generic/patches-3.18/530-jffs2_make_lzma_available.patch new file mode 100644 index 0000000..c92209a --- /dev/null +++ b/target/linux/generic/patches-3.18/530-jffs2_make_lzma_available.patch @@ -0,0 +1,5142 @@ +--- a/fs/jffs2/Kconfig ++++ b/fs/jffs2/Kconfig +@@ -139,6 +139,15 @@ config JFFS2_LZO + This feature was added in July, 2007. Say 'N' if you need + compatibility with older bootloaders or kernels. + ++config JFFS2_LZMA ++ bool "JFFS2 LZMA compression support" if JFFS2_COMPRESSION_OPTIONS ++ select LZMA_COMPRESS ++ select LZMA_DECOMPRESS ++ depends on JFFS2_FS ++ default n ++ help ++ JFFS2 wrapper to the LZMA C SDK ++ + config JFFS2_RTIME + bool "JFFS2 RTIME compression support" if JFFS2_COMPRESSION_OPTIONS + depends on JFFS2_FS +--- a/fs/jffs2/Makefile ++++ b/fs/jffs2/Makefile +@@ -18,4 +18,7 @@ jffs2-$(CONFIG_JFFS2_RUBIN) += compr_rub + jffs2-$(CONFIG_JFFS2_RTIME) += compr_rtime.o + jffs2-$(CONFIG_JFFS2_ZLIB) += compr_zlib.o + jffs2-$(CONFIG_JFFS2_LZO) += compr_lzo.o ++jffs2-$(CONFIG_JFFS2_LZMA) += compr_lzma.o + jffs2-$(CONFIG_JFFS2_SUMMARY) += summary.o ++ ++CFLAGS_compr_lzma.o += -Iinclude/linux -Ilib/lzma +--- a/fs/jffs2/compr.c ++++ b/fs/jffs2/compr.c +@@ -378,6 +378,9 @@ int __init jffs2_compressors_init(void) + #ifdef CONFIG_JFFS2_LZO + jffs2_lzo_init(); + #endif ++#ifdef CONFIG_JFFS2_LZMA ++ jffs2_lzma_init(); ++#endif + /* Setting default compression mode */ + #ifdef CONFIG_JFFS2_CMODE_NONE + jffs2_compression_mode = JFFS2_COMPR_MODE_NONE; +@@ -401,6 +404,9 @@ int __init jffs2_compressors_init(void) + int jffs2_compressors_exit(void) + { + /* Unregistering compressors */ ++#ifdef CONFIG_JFFS2_LZMA ++ jffs2_lzma_exit(); ++#endif + #ifdef CONFIG_JFFS2_LZO + jffs2_lzo_exit(); + #endif +--- a/fs/jffs2/compr.h ++++ b/fs/jffs2/compr.h +@@ -29,9 +29,9 @@ + #define JFFS2_DYNRUBIN_PRIORITY 20 + #define JFFS2_LZARI_PRIORITY 30 + #define JFFS2_RTIME_PRIORITY 50 +-#define JFFS2_ZLIB_PRIORITY 60 +-#define JFFS2_LZO_PRIORITY 80 +- ++#define JFFS2_LZMA_PRIORITY 70 ++#define JFFS2_ZLIB_PRIORITY 80 ++#define JFFS2_LZO_PRIORITY 90 + + #define JFFS2_RUBINMIPS_DISABLED /* RUBINs will be used only */ + #define JFFS2_DYNRUBIN_DISABLED /* for decompression */ +@@ -101,5 +101,9 @@ void jffs2_zlib_exit(void); + int jffs2_lzo_init(void); + void jffs2_lzo_exit(void); + #endif ++#ifdef CONFIG_JFFS2_LZMA ++int jffs2_lzma_init(void); ++void jffs2_lzma_exit(void); ++#endif + + #endif /* __JFFS2_COMPR_H__ */ +--- /dev/null ++++ b/fs/jffs2/compr_lzma.c +@@ -0,0 +1,128 @@ ++/* ++ * JFFS2 -- Journalling Flash File System, Version 2. ++ * ++ * For licensing information, see the file 'LICENCE' in this directory. ++ * ++ * JFFS2 wrapper to the LZMA C SDK ++ * ++ */ ++ ++#include ++#include "compr.h" ++ ++#ifdef __KERNEL__ ++ static DEFINE_MUTEX(deflate_mutex); ++#endif ++ ++CLzmaEncHandle *p; ++Byte propsEncoded[LZMA_PROPS_SIZE]; ++SizeT propsSize = sizeof(propsEncoded); ++ ++STATIC void lzma_free_workspace(void) ++{ ++ LzmaEnc_Destroy(p, &lzma_alloc, &lzma_alloc); ++} ++ ++STATIC int INIT lzma_alloc_workspace(CLzmaEncProps *props) ++{ ++ if ((p = (CLzmaEncHandle *)LzmaEnc_Create(&lzma_alloc)) == NULL) ++ { ++ PRINT_ERROR("Failed to allocate lzma deflate workspace\n"); ++ return -ENOMEM; ++ } ++ ++ if (LzmaEnc_SetProps(p, props) != SZ_OK) ++ { ++ lzma_free_workspace(); ++ return -1; ++ } ++ ++ if (LzmaEnc_WriteProperties(p, propsEncoded, &propsSize) != SZ_OK) ++ { ++ lzma_free_workspace(); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++STATIC int jffs2_lzma_compress(unsigned char *data_in, unsigned char *cpage_out, ++ uint32_t *sourcelen, uint32_t *dstlen) ++{ ++ SizeT compress_size = (SizeT)(*dstlen); ++ int ret; ++ ++ #ifdef __KERNEL__ ++ mutex_lock(&deflate_mutex); ++ #endif ++ ++ ret = LzmaEnc_MemEncode(p, cpage_out, &compress_size, data_in, *sourcelen, ++ 0, NULL, &lzma_alloc, &lzma_alloc); ++ ++ #ifdef __KERNEL__ ++ mutex_unlock(&deflate_mutex); ++ #endif ++ ++ if (ret != SZ_OK) ++ return -1; ++ ++ *dstlen = (uint32_t)compress_size; ++ ++ return 0; ++} ++ ++STATIC int jffs2_lzma_decompress(unsigned char *data_in, unsigned char *cpage_out, ++ uint32_t srclen, uint32_t destlen) ++{ ++ int ret; ++ SizeT dl = (SizeT)destlen; ++ SizeT sl = (SizeT)srclen; ++ ELzmaStatus status; ++ ++ ret = LzmaDecode(cpage_out, &dl, data_in, &sl, propsEncoded, ++ propsSize, LZMA_FINISH_ANY, &status, &lzma_alloc); ++ ++ if (ret != SZ_OK || status == LZMA_STATUS_NOT_FINISHED || dl != (SizeT)destlen) ++ return -1; ++ ++ return 0; ++} ++ ++static struct jffs2_compressor jffs2_lzma_comp = { ++ .priority = JFFS2_LZMA_PRIORITY, ++ .name = "lzma", ++ .compr = JFFS2_COMPR_LZMA, ++ .compress = &jffs2_lzma_compress, ++ .decompress = &jffs2_lzma_decompress, ++ .disabled = 0, ++}; ++ ++int INIT jffs2_lzma_init(void) ++{ ++ int ret; ++ CLzmaEncProps props; ++ LzmaEncProps_Init(&props); ++ ++ props.dictSize = LZMA_BEST_DICT(0x2000); ++ props.level = LZMA_BEST_LEVEL; ++ props.lc = LZMA_BEST_LC; ++ props.lp = LZMA_BEST_LP; ++ props.pb = LZMA_BEST_PB; ++ props.fb = LZMA_BEST_FB; ++ ++ ret = lzma_alloc_workspace(&props); ++ if (ret < 0) ++ return ret; ++ ++ ret = jffs2_register_compressor(&jffs2_lzma_comp); ++ if (ret) ++ lzma_free_workspace(); ++ ++ return ret; ++} ++ ++void jffs2_lzma_exit(void) ++{ ++ jffs2_unregister_compressor(&jffs2_lzma_comp); ++ lzma_free_workspace(); ++} +--- a/fs/jffs2/super.c ++++ b/fs/jffs2/super.c +@@ -375,14 +375,41 @@ static int __init init_jffs2_fs(void) + BUILD_BUG_ON(sizeof(struct jffs2_raw_inode) != 68); + BUILD_BUG_ON(sizeof(struct jffs2_raw_summary) != 32); + +- pr_info("version 2.2." ++ pr_info("version 2.2" + #ifdef CONFIG_JFFS2_FS_WRITEBUFFER + " (NAND)" + #endif + #ifdef CONFIG_JFFS2_SUMMARY +- " (SUMMARY) " ++ " (SUMMARY)" + #endif +- " © 2001-2006 Red Hat, Inc.\n"); ++#ifdef CONFIG_JFFS2_ZLIB ++ " (ZLIB)" ++#endif ++#ifdef CONFIG_JFFS2_LZO ++ " (LZO)" ++#endif ++#ifdef CONFIG_JFFS2_LZMA ++ " (LZMA)" ++#endif ++#ifdef CONFIG_JFFS2_RTIME ++ " (RTIME)" ++#endif ++#ifdef CONFIG_JFFS2_RUBIN ++ " (RUBIN)" ++#endif ++#ifdef CONFIG_JFFS2_CMODE_NONE ++ " (CMODE_NONE)" ++#endif ++#ifdef CONFIG_JFFS2_CMODE_PRIORITY ++ " (CMODE_PRIORITY)" ++#endif ++#ifdef CONFIG_JFFS2_CMODE_SIZE ++ " (CMODE_SIZE)" ++#endif ++#ifdef CONFIG_JFFS2_CMODE_FAVOURLZO ++ " (CMODE_FAVOURLZO)" ++#endif ++ " (c) 2001-2006 Red Hat, Inc.\n"); + + jffs2_inode_cachep = kmem_cache_create("jffs2_i", + sizeof(struct jffs2_inode_info), +--- a/include/uapi/linux/jffs2.h ++++ b/include/uapi/linux/jffs2.h +@@ -46,6 +46,7 @@ + #define JFFS2_COMPR_DYNRUBIN 0x05 + #define JFFS2_COMPR_ZLIB 0x06 + #define JFFS2_COMPR_LZO 0x07 ++#define JFFS2_COMPR_LZMA 0x08 + /* Compatibility flags. */ + #define JFFS2_COMPAT_MASK 0xc000 /* What do to if an unknown nodetype is found */ + #define JFFS2_NODE_ACCURATE 0x2000 +--- /dev/null ++++ b/include/linux/lzma.h +@@ -0,0 +1,62 @@ ++#ifndef __LZMA_H__ ++#define __LZMA_H__ ++ ++#ifdef __KERNEL__ ++ #include ++ #include ++ #include ++ #include ++ #include ++ #define LZMA_MALLOC vmalloc ++ #define LZMA_FREE vfree ++ #define PRINT_ERROR(msg) printk(KERN_WARNING #msg) ++ #define INIT __init ++ #define STATIC static ++#else ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ #ifndef PAGE_SIZE ++ extern int page_size; ++ #define PAGE_SIZE page_size ++ #endif ++ #define LZMA_MALLOC malloc ++ #define LZMA_FREE free ++ #define PRINT_ERROR(msg) fprintf(stderr, msg) ++ #define INIT ++ #define STATIC ++#endif ++ ++#include "lzma/LzmaDec.h" ++#include "lzma/LzmaEnc.h" ++ ++#define LZMA_BEST_LEVEL (9) ++#define LZMA_BEST_LC (0) ++#define LZMA_BEST_LP (0) ++#define LZMA_BEST_PB (0) ++#define LZMA_BEST_FB (273) ++ ++#define LZMA_BEST_DICT(n) (((int)((n) / 2)) * 2) ++ ++static void *p_lzma_malloc(void *p, size_t size) ++{ ++ if (size == 0) ++ return NULL; ++ ++ return LZMA_MALLOC(size); ++} ++ ++static void p_lzma_free(void *p, void *address) ++{ ++ if (address != NULL) ++ LZMA_FREE(address); ++} ++ ++static ISzAlloc lzma_alloc = {p_lzma_malloc, p_lzma_free}; ++ ++#endif +--- /dev/null ++++ b/include/linux/lzma/LzFind.h +@@ -0,0 +1,115 @@ ++/* LzFind.h -- Match finder for LZ algorithms ++2009-04-22 : Igor Pavlov : Public domain */ ++ ++#ifndef __LZ_FIND_H ++#define __LZ_FIND_H ++ ++#include "Types.h" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++typedef UInt32 CLzRef; ++ ++typedef struct _CMatchFinder ++{ ++ Byte *buffer; ++ UInt32 pos; ++ UInt32 posLimit; ++ UInt32 streamPos; ++ UInt32 lenLimit; ++ ++ UInt32 cyclicBufferPos; ++ UInt32 cyclicBufferSize; /* it must be = (historySize + 1) */ ++ ++ UInt32 matchMaxLen; ++ CLzRef *hash; ++ CLzRef *son; ++ UInt32 hashMask; ++ UInt32 cutValue; ++ ++ Byte *bufferBase; ++ ISeqInStream *stream; ++ int streamEndWasReached; ++ ++ UInt32 blockSize; ++ UInt32 keepSizeBefore; ++ UInt32 keepSizeAfter; ++ ++ UInt32 numHashBytes; ++ int directInput; ++ size_t directInputRem; ++ int btMode; ++ int bigHash; ++ UInt32 historySize; ++ UInt32 fixedHashSize; ++ UInt32 hashSizeSum; ++ UInt32 numSons; ++ SRes result; ++ UInt32 crc[256]; ++} CMatchFinder; ++ ++#define Inline_MatchFinder_GetPointerToCurrentPos(p) ((p)->buffer) ++#define Inline_MatchFinder_GetIndexByte(p, index) ((p)->buffer[(Int32)(index)]) ++ ++#define Inline_MatchFinder_GetNumAvailableBytes(p) ((p)->streamPos - (p)->pos) ++ ++int MatchFinder_NeedMove(CMatchFinder *p); ++Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p); ++void MatchFinder_MoveBlock(CMatchFinder *p); ++void MatchFinder_ReadIfRequired(CMatchFinder *p); ++ ++void MatchFinder_Construct(CMatchFinder *p); ++ ++/* Conditions: ++ historySize <= 3 GB ++ keepAddBufferBefore + matchMaxLen + keepAddBufferAfter < 511MB ++*/ ++int MatchFinder_Create(CMatchFinder *p, UInt32 historySize, ++ UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ++ ISzAlloc *alloc); ++void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc); ++void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems); ++void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue); ++ ++UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *buffer, CLzRef *son, ++ UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue, ++ UInt32 *distances, UInt32 maxLen); ++ ++/* ++Conditions: ++ Mf_GetNumAvailableBytes_Func must be called before each Mf_GetMatchLen_Func. ++ Mf_GetPointerToCurrentPos_Func's result must be used only before any other function ++*/ ++ ++typedef void (*Mf_Init_Func)(void *object); ++typedef Byte (*Mf_GetIndexByte_Func)(void *object, Int32 index); ++typedef UInt32 (*Mf_GetNumAvailableBytes_Func)(void *object); ++typedef const Byte * (*Mf_GetPointerToCurrentPos_Func)(void *object); ++typedef UInt32 (*Mf_GetMatches_Func)(void *object, UInt32 *distances); ++typedef void (*Mf_Skip_Func)(void *object, UInt32); ++ ++typedef struct _IMatchFinder ++{ ++ Mf_Init_Func Init; ++ Mf_GetIndexByte_Func GetIndexByte; ++ Mf_GetNumAvailableBytes_Func GetNumAvailableBytes; ++ Mf_GetPointerToCurrentPos_Func GetPointerToCurrentPos; ++ Mf_GetMatches_Func GetMatches; ++ Mf_Skip_Func Skip; ++} IMatchFinder; ++ ++void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable); ++ ++void MatchFinder_Init(CMatchFinder *p); ++UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances); ++UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances); ++void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num); ++void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif +--- /dev/null ++++ b/include/linux/lzma/LzHash.h +@@ -0,0 +1,54 @@ ++/* LzHash.h -- HASH functions for LZ algorithms ++2009-02-07 : Igor Pavlov : Public domain */ ++ ++#ifndef __LZ_HASH_H ++#define __LZ_HASH_H ++ ++#define kHash2Size (1 << 10) ++#define kHash3Size (1 << 16) ++#define kHash4Size (1 << 20) ++ ++#define kFix3HashSize (kHash2Size) ++#define kFix4HashSize (kHash2Size + kHash3Size) ++#define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size) ++ ++#define HASH2_CALC hashValue = cur[0] | ((UInt32)cur[1] << 8); ++ ++#define HASH3_CALC { \ ++ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ ++ hash2Value = temp & (kHash2Size - 1); \ ++ hashValue = (temp ^ ((UInt32)cur[2] << 8)) & p->hashMask; } ++ ++#define HASH4_CALC { \ ++ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ ++ hash2Value = temp & (kHash2Size - 1); \ ++ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \ ++ hashValue = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & p->hashMask; } ++ ++#define HASH5_CALC { \ ++ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ ++ hash2Value = temp & (kHash2Size - 1); \ ++ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \ ++ hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)); \ ++ hashValue = (hash4Value ^ (p->crc[cur[4]] << 3)) & p->hashMask; \ ++ hash4Value &= (kHash4Size - 1); } ++ ++/* #define HASH_ZIP_CALC hashValue = ((cur[0] | ((UInt32)cur[1] << 8)) ^ p->crc[cur[2]]) & 0xFFFF; */ ++#define HASH_ZIP_CALC hashValue = ((cur[2] | ((UInt32)cur[0] << 8)) ^ p->crc[cur[1]]) & 0xFFFF; ++ ++ ++#define MT_HASH2_CALC \ ++ hash2Value = (p->crc[cur[0]] ^ cur[1]) & (kHash2Size - 1); ++ ++#define MT_HASH3_CALC { \ ++ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ ++ hash2Value = temp & (kHash2Size - 1); \ ++ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); } ++ ++#define MT_HASH4_CALC { \ ++ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ ++ hash2Value = temp & (kHash2Size - 1); \ ++ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \ ++ hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & (kHash4Size - 1); } ++ ++#endif +--- /dev/null ++++ b/include/linux/lzma/LzmaDec.h +@@ -0,0 +1,231 @@ ++/* LzmaDec.h -- LZMA Decoder ++2009-02-07 : Igor Pavlov : Public domain */ ++ ++#ifndef __LZMA_DEC_H ++#define __LZMA_DEC_H ++ ++#include "Types.h" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/* #define _LZMA_PROB32 */ ++/* _LZMA_PROB32 can increase the speed on some CPUs, ++ but memory usage for CLzmaDec::probs will be doubled in that case */ ++ ++#ifdef _LZMA_PROB32 ++#define CLzmaProb UInt32 ++#else ++#define CLzmaProb UInt16 ++#endif ++ ++ ++/* ---------- LZMA Properties ---------- */ ++ ++#define LZMA_PROPS_SIZE 5 ++ ++typedef struct _CLzmaProps ++{ ++ unsigned lc, lp, pb; ++ UInt32 dicSize; ++} CLzmaProps; ++ ++/* LzmaProps_Decode - decodes properties ++Returns: ++ SZ_OK ++ SZ_ERROR_UNSUPPORTED - Unsupported properties ++*/ ++ ++SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size); ++ ++ ++/* ---------- LZMA Decoder state ---------- */ ++ ++/* LZMA_REQUIRED_INPUT_MAX = number of required input bytes for worst case. ++ Num bits = log2((2^11 / 31) ^ 22) + 26 < 134 + 26 = 160; */ ++ ++#define LZMA_REQUIRED_INPUT_MAX 20 ++ ++typedef struct ++{ ++ CLzmaProps prop; ++ CLzmaProb *probs; ++ Byte *dic; ++ const Byte *buf; ++ UInt32 range, code; ++ SizeT dicPos; ++ SizeT dicBufSize; ++ UInt32 processedPos; ++ UInt32 checkDicSize; ++ unsigned state; ++ UInt32 reps[4]; ++ unsigned remainLen; ++ int needFlush; ++ int needInitState; ++ UInt32 numProbs; ++ unsigned tempBufSize; ++ Byte tempBuf[LZMA_REQUIRED_INPUT_MAX]; ++} CLzmaDec; ++ ++#define LzmaDec_Construct(p) { (p)->dic = 0; (p)->probs = 0; } ++ ++void LzmaDec_Init(CLzmaDec *p); ++ ++/* There are two types of LZMA streams: ++ 0) Stream with end mark. That end mark adds about 6 bytes to compressed size. ++ 1) Stream without end mark. You must know exact uncompressed size to decompress such stream. */ ++ ++typedef enum ++{ ++ LZMA_FINISH_ANY, /* finish at any point */ ++ LZMA_FINISH_END /* block must be finished at the end */ ++} ELzmaFinishMode; ++ ++/* ELzmaFinishMode has meaning only if the decoding reaches output limit !!! ++ ++ You must use LZMA_FINISH_END, when you know that current output buffer ++ covers last bytes of block. In other cases you must use LZMA_FINISH_ANY. ++ ++ If LZMA decoder sees end marker before reaching output limit, it returns SZ_OK, ++ and output value of destLen will be less than output buffer size limit. ++ You can check status result also. ++ ++ You can use multiple checks to test data integrity after full decompression: ++ 1) Check Result and "status" variable. ++ 2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize. ++ 3) Check that output(srcLen) = compressedSize, if you know real compressedSize. ++ You must use correct finish mode in that case. */ ++ ++typedef enum ++{ ++ LZMA_STATUS_NOT_SPECIFIED, /* use main error code instead */ ++ LZMA_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */ ++ LZMA_STATUS_NOT_FINISHED, /* stream was not finished */ ++ LZMA_STATUS_NEEDS_MORE_INPUT, /* you must provide more input bytes */ ++ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK /* there is probability that stream was finished without end mark */ ++} ELzmaStatus; ++ ++/* ELzmaStatus is used only as output value for function call */ ++ ++ ++/* ---------- Interfaces ---------- */ ++ ++/* There are 3 levels of interfaces: ++ 1) Dictionary Interface ++ 2) Buffer Interface ++ 3) One Call Interface ++ You can select any of these interfaces, but don't mix functions from different ++ groups for same object. */ ++ ++ ++/* There are two variants to allocate state for Dictionary Interface: ++ 1) LzmaDec_Allocate / LzmaDec_Free ++ 2) LzmaDec_AllocateProbs / LzmaDec_FreeProbs ++ You can use variant 2, if you set dictionary buffer manually. ++ For Buffer Interface you must always use variant 1. ++ ++LzmaDec_Allocate* can return: ++ SZ_OK ++ SZ_ERROR_MEM - Memory allocation error ++ SZ_ERROR_UNSUPPORTED - Unsupported properties ++*/ ++ ++SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc); ++void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc); ++ ++SRes LzmaDec_Allocate(CLzmaDec *state, const Byte *prop, unsigned propsSize, ISzAlloc *alloc); ++void LzmaDec_Free(CLzmaDec *state, ISzAlloc *alloc); ++ ++/* ---------- Dictionary Interface ---------- */ ++ ++/* You can use it, if you want to eliminate the overhead for data copying from ++ dictionary to some other external buffer. ++ You must work with CLzmaDec variables directly in this interface. ++ ++ STEPS: ++ LzmaDec_Constr() ++ LzmaDec_Allocate() ++ for (each new stream) ++ { ++ LzmaDec_Init() ++ while (it needs more decompression) ++ { ++ LzmaDec_DecodeToDic() ++ use data from CLzmaDec::dic and update CLzmaDec::dicPos ++ } ++ } ++ LzmaDec_Free() ++*/ ++ ++/* LzmaDec_DecodeToDic ++ ++ The decoding to internal dictionary buffer (CLzmaDec::dic). ++ You must manually update CLzmaDec::dicPos, if it reaches CLzmaDec::dicBufSize !!! ++ ++finishMode: ++ It has meaning only if the decoding reaches output limit (dicLimit). ++ LZMA_FINISH_ANY - Decode just dicLimit bytes. ++ LZMA_FINISH_END - Stream must be finished after dicLimit. ++ ++Returns: ++ SZ_OK ++ status: ++ LZMA_STATUS_FINISHED_WITH_MARK ++ LZMA_STATUS_NOT_FINISHED ++ LZMA_STATUS_NEEDS_MORE_INPUT ++ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK ++ SZ_ERROR_DATA - Data error ++*/ ++ ++SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, ++ const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); ++ ++ ++/* ---------- Buffer Interface ---------- */ ++ ++/* It's zlib-like interface. ++ See LzmaDec_DecodeToDic description for information about STEPS and return results, ++ but you must use LzmaDec_DecodeToBuf instead of LzmaDec_DecodeToDic and you don't need ++ to work with CLzmaDec variables manually. ++ ++finishMode: ++ It has meaning only if the decoding reaches output limit (*destLen). ++ LZMA_FINISH_ANY - Decode just destLen bytes. ++ LZMA_FINISH_END - Stream must be finished after (*destLen). ++*/ ++ ++SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, ++ const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); ++ ++ ++/* ---------- One Call Interface ---------- */ ++ ++/* LzmaDecode ++ ++finishMode: ++ It has meaning only if the decoding reaches output limit (*destLen). ++ LZMA_FINISH_ANY - Decode just destLen bytes. ++ LZMA_FINISH_END - Stream must be finished after (*destLen). ++ ++Returns: ++ SZ_OK ++ status: ++ LZMA_STATUS_FINISHED_WITH_MARK ++ LZMA_STATUS_NOT_FINISHED ++ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK ++ SZ_ERROR_DATA - Data error ++ SZ_ERROR_MEM - Memory allocation error ++ SZ_ERROR_UNSUPPORTED - Unsupported properties ++ SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src). ++*/ ++ ++SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ++ const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, ++ ELzmaStatus *status, ISzAlloc *alloc); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif +--- /dev/null ++++ b/include/linux/lzma/LzmaEnc.h +@@ -0,0 +1,80 @@ ++/* LzmaEnc.h -- LZMA Encoder ++2009-02-07 : Igor Pavlov : Public domain */ ++ ++#ifndef __LZMA_ENC_H ++#define __LZMA_ENC_H ++ ++#include "Types.h" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++#define LZMA_PROPS_SIZE 5 ++ ++typedef struct _CLzmaEncProps ++{ ++ int level; /* 0 <= level <= 9 */ ++ UInt32 dictSize; /* (1 << 12) <= dictSize <= (1 << 27) for 32-bit version ++ (1 << 12) <= dictSize <= (1 << 30) for 64-bit version ++ default = (1 << 24) */ ++ int lc; /* 0 <= lc <= 8, default = 3 */ ++ int lp; /* 0 <= lp <= 4, default = 0 */ ++ int pb; /* 0 <= pb <= 4, default = 2 */ ++ int algo; /* 0 - fast, 1 - normal, default = 1 */ ++ int fb; /* 5 <= fb <= 273, default = 32 */ ++ int btMode; /* 0 - hashChain Mode, 1 - binTree mode - normal, default = 1 */ ++ int numHashBytes; /* 2, 3 or 4, default = 4 */ ++ UInt32 mc; /* 1 <= mc <= (1 << 30), default = 32 */ ++ unsigned writeEndMark; /* 0 - do not write EOPM, 1 - write EOPM, default = 0 */ ++ int numThreads; /* 1 or 2, default = 2 */ ++} CLzmaEncProps; ++ ++void LzmaEncProps_Init(CLzmaEncProps *p); ++void LzmaEncProps_Normalize(CLzmaEncProps *p); ++UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2); ++ ++ ++/* ---------- CLzmaEncHandle Interface ---------- */ ++ ++/* LzmaEnc_* functions can return the following exit codes: ++Returns: ++ SZ_OK - OK ++ SZ_ERROR_MEM - Memory allocation error ++ SZ_ERROR_PARAM - Incorrect paramater in props ++ SZ_ERROR_WRITE - Write callback error. ++ SZ_ERROR_PROGRESS - some break from progress callback ++ SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version) ++*/ ++ ++typedef void * CLzmaEncHandle; ++ ++CLzmaEncHandle LzmaEnc_Create(ISzAlloc *alloc); ++void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAlloc *alloc, ISzAlloc *allocBig); ++SRes LzmaEnc_SetProps(CLzmaEncHandle p, const CLzmaEncProps *props); ++SRes LzmaEnc_WriteProperties(CLzmaEncHandle p, Byte *properties, SizeT *size); ++SRes LzmaEnc_Encode(CLzmaEncHandle p, ISeqOutStream *outStream, ISeqInStream *inStream, ++ ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig); ++SRes LzmaEnc_MemEncode(CLzmaEncHandle p, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, ++ int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig); ++ ++/* ---------- One Call Interface ---------- */ ++ ++/* LzmaEncode ++Return code: ++ SZ_OK - OK ++ SZ_ERROR_MEM - Memory allocation error ++ SZ_ERROR_PARAM - Incorrect paramater ++ SZ_ERROR_OUTPUT_EOF - output buffer overflow ++ SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version) ++*/ ++ ++SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, ++ const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark, ++ ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif +--- /dev/null ++++ b/include/linux/lzma/Types.h +@@ -0,0 +1,226 @@ ++/* Types.h -- Basic types ++2009-11-23 : Igor Pavlov : Public domain */ ++ ++#ifndef __7Z_TYPES_H ++#define __7Z_TYPES_H ++ ++#include ++ ++#ifdef _WIN32 ++#include ++#endif ++ ++#ifndef EXTERN_C_BEGIN ++#ifdef __cplusplus ++#define EXTERN_C_BEGIN extern "C" { ++#define EXTERN_C_END } ++#else ++#define EXTERN_C_BEGIN ++#define EXTERN_C_END ++#endif ++#endif ++ ++EXTERN_C_BEGIN ++ ++#define SZ_OK 0 ++ ++#define SZ_ERROR_DATA 1 ++#define SZ_ERROR_MEM 2 ++#define SZ_ERROR_CRC 3 ++#define SZ_ERROR_UNSUPPORTED 4 ++#define SZ_ERROR_PARAM 5 ++#define SZ_ERROR_INPUT_EOF 6 ++#define SZ_ERROR_OUTPUT_EOF 7 ++#define SZ_ERROR_READ 8 ++#define SZ_ERROR_WRITE 9 ++#define SZ_ERROR_PROGRESS 10 ++#define SZ_ERROR_FAIL 11 ++#define SZ_ERROR_THREAD 12 ++ ++#define SZ_ERROR_ARCHIVE 16 ++#define SZ_ERROR_NO_ARCHIVE 17 ++ ++typedef int SRes; ++ ++#ifdef _WIN32 ++typedef DWORD WRes; ++#else ++typedef int WRes; ++#endif ++ ++#ifndef RINOK ++#define RINOK(x) { int __result__ = (x); if (__result__ != 0) return __result__; } ++#endif ++ ++typedef unsigned char Byte; ++typedef short Int16; ++typedef unsigned short UInt16; ++ ++#ifdef _LZMA_UINT32_IS_ULONG ++typedef long Int32; ++typedef unsigned long UInt32; ++#else ++typedef int Int32; ++typedef unsigned int UInt32; ++#endif ++ ++#ifdef _SZ_NO_INT_64 ++ ++/* define _SZ_NO_INT_64, if your compiler doesn't support 64-bit integers. ++ NOTES: Some code will work incorrectly in that case! */ ++ ++typedef long Int64; ++typedef unsigned long UInt64; ++ ++#else ++ ++#if defined(_MSC_VER) || defined(__BORLANDC__) ++typedef __int64 Int64; ++typedef unsigned __int64 UInt64; ++#else ++typedef long long int Int64; ++typedef unsigned long long int UInt64; ++#endif ++ ++#endif ++ ++#ifdef _LZMA_NO_SYSTEM_SIZE_T ++typedef UInt32 SizeT; ++#else ++typedef size_t SizeT; ++#endif ++ ++typedef int Bool; ++#define True 1 ++#define False 0 ++ ++ ++#ifdef _WIN32 ++#define MY_STD_CALL __stdcall ++#else ++#define MY_STD_CALL ++#endif ++ ++#ifdef _MSC_VER ++ ++#if _MSC_VER >= 1300 ++#define MY_NO_INLINE __declspec(noinline) ++#else ++#define MY_NO_INLINE ++#endif ++ ++#define MY_CDECL __cdecl ++#define MY_FAST_CALL __fastcall ++ ++#else ++ ++#define MY_CDECL ++#define MY_FAST_CALL ++ ++#endif ++ ++ ++/* The following interfaces use first parameter as pointer to structure */ ++ ++typedef struct ++{ ++ SRes (*Read)(void *p, void *buf, size_t *size); ++ /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. ++ (output(*size) < input(*size)) is allowed */ ++} ISeqInStream; ++ ++/* it can return SZ_ERROR_INPUT_EOF */ ++SRes SeqInStream_Read(ISeqInStream *stream, void *buf, size_t size); ++SRes SeqInStream_Read2(ISeqInStream *stream, void *buf, size_t size, SRes errorType); ++SRes SeqInStream_ReadByte(ISeqInStream *stream, Byte *buf); ++ ++typedef struct ++{ ++ size_t (*Write)(void *p, const void *buf, size_t size); ++ /* Returns: result - the number of actually written bytes. ++ (result < size) means error */ ++} ISeqOutStream; ++ ++typedef enum ++{ ++ SZ_SEEK_SET = 0, ++ SZ_SEEK_CUR = 1, ++ SZ_SEEK_END = 2 ++} ESzSeek; ++ ++typedef struct ++{ ++ SRes (*Read)(void *p, void *buf, size_t *size); /* same as ISeqInStream::Read */ ++ SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin); ++} ISeekInStream; ++ ++typedef struct ++{ ++ SRes (*Look)(void *p, void **buf, size_t *size); ++ /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. ++ (output(*size) > input(*size)) is not allowed ++ (output(*size) < input(*size)) is allowed */ ++ SRes (*Skip)(void *p, size_t offset); ++ /* offset must be <= output(*size) of Look */ ++ ++ SRes (*Read)(void *p, void *buf, size_t *size); ++ /* reads directly (without buffer). It's same as ISeqInStream::Read */ ++ SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin); ++} ILookInStream; ++ ++SRes LookInStream_LookRead(ILookInStream *stream, void *buf, size_t *size); ++SRes LookInStream_SeekTo(ILookInStream *stream, UInt64 offset); ++ ++/* reads via ILookInStream::Read */ ++SRes LookInStream_Read2(ILookInStream *stream, void *buf, size_t size, SRes errorType); ++SRes LookInStream_Read(ILookInStream *stream, void *buf, size_t size); ++ ++#define LookToRead_BUF_SIZE (1 << 14) ++ ++typedef struct ++{ ++ ILookInStream s; ++ ISeekInStream *realStream; ++ size_t pos; ++ size_t size; ++ Byte buf[LookToRead_BUF_SIZE]; ++} CLookToRead; ++ ++void LookToRead_CreateVTable(CLookToRead *p, int lookahead); ++void LookToRead_Init(CLookToRead *p); ++ ++typedef struct ++{ ++ ISeqInStream s; ++ ILookInStream *realStream; ++} CSecToLook; ++ ++void SecToLook_CreateVTable(CSecToLook *p); ++ ++typedef struct ++{ ++ ISeqInStream s; ++ ILookInStream *realStream; ++} CSecToRead; ++ ++void SecToRead_CreateVTable(CSecToRead *p); ++ ++typedef struct ++{ ++ SRes (*Progress)(void *p, UInt64 inSize, UInt64 outSize); ++ /* Returns: result. (result != SZ_OK) means break. ++ Value (UInt64)(Int64)-1 for size means unknown value. */ ++} ICompressProgress; ++ ++typedef struct ++{ ++ void *(*Alloc)(void *p, size_t size); ++ void (*Free)(void *p, void *address); /* address can be 0 */ ++} ISzAlloc; ++ ++#define IAlloc_Alloc(p, size) (p)->Alloc((p), size) ++#define IAlloc_Free(p, a) (p)->Free((p), a) ++ ++EXTERN_C_END ++ ++#endif +--- a/lib/Kconfig ++++ b/lib/Kconfig +@@ -227,6 +227,12 @@ config LZ4_DECOMPRESS + + source "lib/xz/Kconfig" + ++config LZMA_COMPRESS ++ tristate ++ ++config LZMA_DECOMPRESS ++ tristate ++ + # + # These all provide a common interface (hence the apparent duplication with + # ZLIB_INFLATE; DECOMPRESS_GZIP is just a wrapper.) +--- a/lib/Makefile ++++ b/lib/Makefile +@@ -2,6 +2,16 @@ + # Makefile for some libs needed in the kernel. + # + ++ifdef CONFIG_JFFS2_ZLIB ++ CONFIG_ZLIB_INFLATE:=y ++ CONFIG_ZLIB_DEFLATE:=y ++endif ++ ++ifdef CONFIG_JFFS2_LZMA ++ CONFIG_LZMA_DECOMPRESS:=y ++ CONFIG_LZMA_COMPRESS:=y ++endif ++ + ifdef CONFIG_FUNCTION_TRACER + ORIG_CFLAGS := $(KBUILD_CFLAGS) + KBUILD_CFLAGS = $(subst -pg,,$(ORIG_CFLAGS)) +@@ -85,6 +95,8 @@ obj-$(CONFIG_LZ4HC_COMPRESS) += lz4/ + obj-$(CONFIG_LZ4_DECOMPRESS) += lz4/ + obj-$(CONFIG_XZ_DEC) += xz/ + obj-$(CONFIG_RAID6_PQ) += raid6/ ++obj-$(CONFIG_LZMA_COMPRESS) += lzma/ ++obj-$(CONFIG_LZMA_DECOMPRESS) += lzma/ + + lib-$(CONFIG_DECOMPRESS_GZIP) += decompress_inflate.o + lib-$(CONFIG_DECOMPRESS_BZIP2) += decompress_bunzip2.o +--- /dev/null ++++ b/lib/lzma/LzFind.c +@@ -0,0 +1,761 @@ ++/* LzFind.c -- Match finder for LZ algorithms ++2009-04-22 : Igor Pavlov : Public domain */ ++ ++#include ++ ++#include "LzFind.h" ++#include "LzHash.h" ++ ++#define kEmptyHashValue 0 ++#define kMaxValForNormalize ((UInt32)0xFFFFFFFF) ++#define kNormalizeStepMin (1 << 10) /* it must be power of 2 */ ++#define kNormalizeMask (~(kNormalizeStepMin - 1)) ++#define kMaxHistorySize ((UInt32)3 << 30) ++ ++#define kStartMaxLen 3 ++ ++static void LzInWindow_Free(CMatchFinder *p, ISzAlloc *alloc) ++{ ++ if (!p->directInput) ++ { ++ alloc->Free(alloc, p->bufferBase); ++ p->bufferBase = 0; ++ } ++} ++ ++/* keepSizeBefore + keepSizeAfter + keepSizeReserv must be < 4G) */ ++ ++static int LzInWindow_Create(CMatchFinder *p, UInt32 keepSizeReserv, ISzAlloc *alloc) ++{ ++ UInt32 blockSize = p->keepSizeBefore + p->keepSizeAfter + keepSizeReserv; ++ if (p->directInput) ++ { ++ p->blockSize = blockSize; ++ return 1; ++ } ++ if (p->bufferBase == 0 || p->blockSize != blockSize) ++ { ++ LzInWindow_Free(p, alloc); ++ p->blockSize = blockSize; ++ p->bufferBase = (Byte *)alloc->Alloc(alloc, (size_t)blockSize); ++ } ++ return (p->bufferBase != 0); ++} ++ ++Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; } ++Byte MatchFinder_GetIndexByte(CMatchFinder *p, Int32 index) { return p->buffer[index]; } ++ ++UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return p->streamPos - p->pos; } ++ ++void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue) ++{ ++ p->posLimit -= subValue; ++ p->pos -= subValue; ++ p->streamPos -= subValue; ++} ++ ++static void MatchFinder_ReadBlock(CMatchFinder *p) ++{ ++ if (p->streamEndWasReached || p->result != SZ_OK) ++ return; ++ if (p->directInput) ++ { ++ UInt32 curSize = 0xFFFFFFFF - p->streamPos; ++ if (curSize > p->directInputRem) ++ curSize = (UInt32)p->directInputRem; ++ p->directInputRem -= curSize; ++ p->streamPos += curSize; ++ if (p->directInputRem == 0) ++ p->streamEndWasReached = 1; ++ return; ++ } ++ for (;;) ++ { ++ Byte *dest = p->buffer + (p->streamPos - p->pos); ++ size_t size = (p->bufferBase + p->blockSize - dest); ++ if (size == 0) ++ return; ++ p->result = p->stream->Read(p->stream, dest, &size); ++ if (p->result != SZ_OK) ++ return; ++ if (size == 0) ++ { ++ p->streamEndWasReached = 1; ++ return; ++ } ++ p->streamPos += (UInt32)size; ++ if (p->streamPos - p->pos > p->keepSizeAfter) ++ return; ++ } ++} ++ ++void MatchFinder_MoveBlock(CMatchFinder *p) ++{ ++ memmove(p->bufferBase, ++ p->buffer - p->keepSizeBefore, ++ (size_t)(p->streamPos - p->pos + p->keepSizeBefore)); ++ p->buffer = p->bufferBase + p->keepSizeBefore; ++} ++ ++int MatchFinder_NeedMove(CMatchFinder *p) ++{ ++ if (p->directInput) ++ return 0; ++ /* if (p->streamEndWasReached) return 0; */ ++ return ((size_t)(p->bufferBase + p->blockSize - p->buffer) <= p->keepSizeAfter); ++} ++ ++void MatchFinder_ReadIfRequired(CMatchFinder *p) ++{ ++ if (p->streamEndWasReached) ++ return; ++ if (p->keepSizeAfter >= p->streamPos - p->pos) ++ MatchFinder_ReadBlock(p); ++} ++ ++static void MatchFinder_CheckAndMoveAndRead(CMatchFinder *p) ++{ ++ if (MatchFinder_NeedMove(p)) ++ MatchFinder_MoveBlock(p); ++ MatchFinder_ReadBlock(p); ++} ++ ++static void MatchFinder_SetDefaultSettings(CMatchFinder *p) ++{ ++ p->cutValue = 32; ++ p->btMode = 1; ++ p->numHashBytes = 4; ++ p->bigHash = 0; ++} ++ ++#define kCrcPoly 0xEDB88320 ++ ++void MatchFinder_Construct(CMatchFinder *p) ++{ ++ UInt32 i; ++ p->bufferBase = 0; ++ p->directInput = 0; ++ p->hash = 0; ++ MatchFinder_SetDefaultSettings(p); ++ ++ for (i = 0; i < 256; i++) ++ { ++ UInt32 r = i; ++ int j; ++ for (j = 0; j < 8; j++) ++ r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1)); ++ p->crc[i] = r; ++ } ++} ++ ++static void MatchFinder_FreeThisClassMemory(CMatchFinder *p, ISzAlloc *alloc) ++{ ++ alloc->Free(alloc, p->hash); ++ p->hash = 0; ++} ++ ++void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc) ++{ ++ MatchFinder_FreeThisClassMemory(p, alloc); ++ LzInWindow_Free(p, alloc); ++} ++ ++static CLzRef* AllocRefs(UInt32 num, ISzAlloc *alloc) ++{ ++ size_t sizeInBytes = (size_t)num * sizeof(CLzRef); ++ if (sizeInBytes / sizeof(CLzRef) != num) ++ return 0; ++ return (CLzRef *)alloc->Alloc(alloc, sizeInBytes); ++} ++ ++int MatchFinder_Create(CMatchFinder *p, UInt32 historySize, ++ UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ++ ISzAlloc *alloc) ++{ ++ UInt32 sizeReserv; ++ if (historySize > kMaxHistorySize) ++ { ++ MatchFinder_Free(p, alloc); ++ return 0; ++ } ++ sizeReserv = historySize >> 1; ++ if (historySize > ((UInt32)2 << 30)) ++ sizeReserv = historySize >> 2; ++ sizeReserv += (keepAddBufferBefore + matchMaxLen + keepAddBufferAfter) / 2 + (1 << 19); ++ ++ p->keepSizeBefore = historySize + keepAddBufferBefore + 1; ++ p->keepSizeAfter = matchMaxLen + keepAddBufferAfter; ++ /* we need one additional byte, since we use MoveBlock after pos++ and before dictionary using */ ++ if (LzInWindow_Create(p, sizeReserv, alloc)) ++ { ++ UInt32 newCyclicBufferSize = historySize + 1; ++ UInt32 hs; ++ p->matchMaxLen = matchMaxLen; ++ { ++ p->fixedHashSize = 0; ++ if (p->numHashBytes == 2) ++ hs = (1 << 16) - 1; ++ else ++ { ++ hs = historySize - 1; ++ hs |= (hs >> 1); ++ hs |= (hs >> 2); ++ hs |= (hs >> 4); ++ hs |= (hs >> 8); ++ hs >>= 1; ++ hs |= 0xFFFF; /* don't change it! It's required for Deflate */ ++ if (hs > (1 << 24)) ++ { ++ if (p->numHashBytes == 3) ++ hs = (1 << 24) - 1; ++ else ++ hs >>= 1; ++ } ++ } ++ p->hashMask = hs; ++ hs++; ++ if (p->numHashBytes > 2) p->fixedHashSize += kHash2Size; ++ if (p->numHashBytes > 3) p->fixedHashSize += kHash3Size; ++ if (p->numHashBytes > 4) p->fixedHashSize += kHash4Size; ++ hs += p->fixedHashSize; ++ } ++ ++ { ++ UInt32 prevSize = p->hashSizeSum + p->numSons; ++ UInt32 newSize; ++ p->historySize = historySize; ++ p->hashSizeSum = hs; ++ p->cyclicBufferSize = newCyclicBufferSize; ++ p->numSons = (p->btMode ? newCyclicBufferSize * 2 : newCyclicBufferSize); ++ newSize = p->hashSizeSum + p->numSons; ++ if (p->hash != 0 && prevSize == newSize) ++ return 1; ++ MatchFinder_FreeThisClassMemory(p, alloc); ++ p->hash = AllocRefs(newSize, alloc); ++ if (p->hash != 0) ++ { ++ p->son = p->hash + p->hashSizeSum; ++ return 1; ++ } ++ } ++ } ++ MatchFinder_Free(p, alloc); ++ return 0; ++} ++ ++static void MatchFinder_SetLimits(CMatchFinder *p) ++{ ++ UInt32 limit = kMaxValForNormalize - p->pos; ++ UInt32 limit2 = p->cyclicBufferSize - p->cyclicBufferPos; ++ if (limit2 < limit) ++ limit = limit2; ++ limit2 = p->streamPos - p->pos; ++ if (limit2 <= p->keepSizeAfter) ++ { ++ if (limit2 > 0) ++ limit2 = 1; ++ } ++ else ++ limit2 -= p->keepSizeAfter; ++ if (limit2 < limit) ++ limit = limit2; ++ { ++ UInt32 lenLimit = p->streamPos - p->pos; ++ if (lenLimit > p->matchMaxLen) ++ lenLimit = p->matchMaxLen; ++ p->lenLimit = lenLimit; ++ } ++ p->posLimit = p->pos + limit; ++} ++ ++void MatchFinder_Init(CMatchFinder *p) ++{ ++ UInt32 i; ++ for (i = 0; i < p->hashSizeSum; i++) ++ p->hash[i] = kEmptyHashValue; ++ p->cyclicBufferPos = 0; ++ p->buffer = p->bufferBase; ++ p->pos = p->streamPos = p->cyclicBufferSize; ++ p->result = SZ_OK; ++ p->streamEndWasReached = 0; ++ MatchFinder_ReadBlock(p); ++ MatchFinder_SetLimits(p); ++} ++ ++static UInt32 MatchFinder_GetSubValue(CMatchFinder *p) ++{ ++ return (p->pos - p->historySize - 1) & kNormalizeMask; ++} ++ ++void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems) ++{ ++ UInt32 i; ++ for (i = 0; i < numItems; i++) ++ { ++ UInt32 value = items[i]; ++ if (value <= subValue) ++ value = kEmptyHashValue; ++ else ++ value -= subValue; ++ items[i] = value; ++ } ++} ++ ++static void MatchFinder_Normalize(CMatchFinder *p) ++{ ++ UInt32 subValue = MatchFinder_GetSubValue(p); ++ MatchFinder_Normalize3(subValue, p->hash, p->hashSizeSum + p->numSons); ++ MatchFinder_ReduceOffsets(p, subValue); ++} ++ ++static void MatchFinder_CheckLimits(CMatchFinder *p) ++{ ++ if (p->pos == kMaxValForNormalize) ++ MatchFinder_Normalize(p); ++ if (!p->streamEndWasReached && p->keepSizeAfter == p->streamPos - p->pos) ++ MatchFinder_CheckAndMoveAndRead(p); ++ if (p->cyclicBufferPos == p->cyclicBufferSize) ++ p->cyclicBufferPos = 0; ++ MatchFinder_SetLimits(p); ++} ++ ++static UInt32 * Hc_GetMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, ++ UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue, ++ UInt32 *distances, UInt32 maxLen) ++{ ++ son[_cyclicBufferPos] = curMatch; ++ for (;;) ++ { ++ UInt32 delta = pos - curMatch; ++ if (cutValue-- == 0 || delta >= _cyclicBufferSize) ++ return distances; ++ { ++ const Byte *pb = cur - delta; ++ curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)]; ++ if (pb[maxLen] == cur[maxLen] && *pb == *cur) ++ { ++ UInt32 len = 0; ++ while (++len != lenLimit) ++ if (pb[len] != cur[len]) ++ break; ++ if (maxLen < len) ++ { ++ *distances++ = maxLen = len; ++ *distances++ = delta - 1; ++ if (len == lenLimit) ++ return distances; ++ } ++ } ++ } ++ } ++} ++ ++UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, ++ UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue, ++ UInt32 *distances, UInt32 maxLen) ++{ ++ CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1; ++ CLzRef *ptr1 = son + (_cyclicBufferPos << 1); ++ UInt32 len0 = 0, len1 = 0; ++ for (;;) ++ { ++ UInt32 delta = pos - curMatch; ++ if (cutValue-- == 0 || delta >= _cyclicBufferSize) ++ { ++ *ptr0 = *ptr1 = kEmptyHashValue; ++ return distances; ++ } ++ { ++ CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1); ++ const Byte *pb = cur - delta; ++ UInt32 len = (len0 < len1 ? len0 : len1); ++ if (pb[len] == cur[len]) ++ { ++ if (++len != lenLimit && pb[len] == cur[len]) ++ while (++len != lenLimit) ++ if (pb[len] != cur[len]) ++ break; ++ if (maxLen < len) ++ { ++ *distances++ = maxLen = len; ++ *distances++ = delta - 1; ++ if (len == lenLimit) ++ { ++ *ptr1 = pair[0]; ++ *ptr0 = pair[1]; ++ return distances; ++ } ++ } ++ } ++ if (pb[len] < cur[len]) ++ { ++ *ptr1 = curMatch; ++ ptr1 = pair + 1; ++ curMatch = *ptr1; ++ len1 = len; ++ } ++ else ++ { ++ *ptr0 = curMatch; ++ ptr0 = pair; ++ curMatch = *ptr0; ++ len0 = len; ++ } ++ } ++ } ++} ++ ++static void SkipMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, ++ UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue) ++{ ++ CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1; ++ CLzRef *ptr1 = son + (_cyclicBufferPos << 1); ++ UInt32 len0 = 0, len1 = 0; ++ for (;;) ++ { ++ UInt32 delta = pos - curMatch; ++ if (cutValue-- == 0 || delta >= _cyclicBufferSize) ++ { ++ *ptr0 = *ptr1 = kEmptyHashValue; ++ return; ++ } ++ { ++ CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1); ++ const Byte *pb = cur - delta; ++ UInt32 len = (len0 < len1 ? len0 : len1); ++ if (pb[len] == cur[len]) ++ { ++ while (++len != lenLimit) ++ if (pb[len] != cur[len]) ++ break; ++ { ++ if (len == lenLimit) ++ { ++ *ptr1 = pair[0]; ++ *ptr0 = pair[1]; ++ return; ++ } ++ } ++ } ++ if (pb[len] < cur[len]) ++ { ++ *ptr1 = curMatch; ++ ptr1 = pair + 1; ++ curMatch = *ptr1; ++ len1 = len; ++ } ++ else ++ { ++ *ptr0 = curMatch; ++ ptr0 = pair; ++ curMatch = *ptr0; ++ len0 = len; ++ } ++ } ++ } ++} ++ ++#define MOVE_POS \ ++ ++p->cyclicBufferPos; \ ++ p->buffer++; \ ++ if (++p->pos == p->posLimit) MatchFinder_CheckLimits(p); ++ ++#define MOVE_POS_RET MOVE_POS return offset; ++ ++static void MatchFinder_MovePos(CMatchFinder *p) { MOVE_POS; } ++ ++#define GET_MATCHES_HEADER2(minLen, ret_op) \ ++ UInt32 lenLimit; UInt32 hashValue; const Byte *cur; UInt32 curMatch; \ ++ lenLimit = p->lenLimit; { if (lenLimit < minLen) { MatchFinder_MovePos(p); ret_op; }} \ ++ cur = p->buffer; ++ ++#define GET_MATCHES_HEADER(minLen) GET_MATCHES_HEADER2(minLen, return 0) ++#define SKIP_HEADER(minLen) GET_MATCHES_HEADER2(minLen, continue) ++ ++#define MF_PARAMS(p) p->pos, p->buffer, p->son, p->cyclicBufferPos, p->cyclicBufferSize, p->cutValue ++ ++#define GET_MATCHES_FOOTER(offset, maxLen) \ ++ offset = (UInt32)(GetMatchesSpec1(lenLimit, curMatch, MF_PARAMS(p), \ ++ distances + offset, maxLen) - distances); MOVE_POS_RET; ++ ++#define SKIP_FOOTER \ ++ SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); MOVE_POS; ++ ++static UInt32 Bt2_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) ++{ ++ UInt32 offset; ++ GET_MATCHES_HEADER(2) ++ HASH2_CALC; ++ curMatch = p->hash[hashValue]; ++ p->hash[hashValue] = p->pos; ++ offset = 0; ++ GET_MATCHES_FOOTER(offset, 1) ++} ++ ++UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) ++{ ++ UInt32 offset; ++ GET_MATCHES_HEADER(3) ++ HASH_ZIP_CALC; ++ curMatch = p->hash[hashValue]; ++ p->hash[hashValue] = p->pos; ++ offset = 0; ++ GET_MATCHES_FOOTER(offset, 2) ++} ++ ++static UInt32 Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) ++{ ++ UInt32 hash2Value, delta2, maxLen, offset; ++ GET_MATCHES_HEADER(3) ++ ++ HASH3_CALC; ++ ++ delta2 = p->pos - p->hash[hash2Value]; ++ curMatch = p->hash[kFix3HashSize + hashValue]; ++ ++ p->hash[hash2Value] = ++ p->hash[kFix3HashSize + hashValue] = p->pos; ++ ++ ++ maxLen = 2; ++ offset = 0; ++ if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur) ++ { ++ for (; maxLen != lenLimit; maxLen++) ++ if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen]) ++ break; ++ distances[0] = maxLen; ++ distances[1] = delta2 - 1; ++ offset = 2; ++ if (maxLen == lenLimit) ++ { ++ SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); ++ MOVE_POS_RET; ++ } ++ } ++ GET_MATCHES_FOOTER(offset, maxLen) ++} ++ ++static UInt32 Bt4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) ++{ ++ UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset; ++ GET_MATCHES_HEADER(4) ++ ++ HASH4_CALC; ++ ++ delta2 = p->pos - p->hash[ hash2Value]; ++ delta3 = p->pos - p->hash[kFix3HashSize + hash3Value]; ++ curMatch = p->hash[kFix4HashSize + hashValue]; ++ ++ p->hash[ hash2Value] = ++ p->hash[kFix3HashSize + hash3Value] = ++ p->hash[kFix4HashSize + hashValue] = p->pos; ++ ++ maxLen = 1; ++ offset = 0; ++ if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur) ++ { ++ distances[0] = maxLen = 2; ++ distances[1] = delta2 - 1; ++ offset = 2; ++ } ++ if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur) ++ { ++ maxLen = 3; ++ distances[offset + 1] = delta3 - 1; ++ offset += 2; ++ delta2 = delta3; ++ } ++ if (offset != 0) ++ { ++ for (; maxLen != lenLimit; maxLen++) ++ if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen]) ++ break; ++ distances[offset - 2] = maxLen; ++ if (maxLen == lenLimit) ++ { ++ SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); ++ MOVE_POS_RET; ++ } ++ } ++ if (maxLen < 3) ++ maxLen = 3; ++ GET_MATCHES_FOOTER(offset, maxLen) ++} ++ ++static UInt32 Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) ++{ ++ UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset; ++ GET_MATCHES_HEADER(4) ++ ++ HASH4_CALC; ++ ++ delta2 = p->pos - p->hash[ hash2Value]; ++ delta3 = p->pos - p->hash[kFix3HashSize + hash3Value]; ++ curMatch = p->hash[kFix4HashSize + hashValue]; ++ ++ p->hash[ hash2Value] = ++ p->hash[kFix3HashSize + hash3Value] = ++ p->hash[kFix4HashSize + hashValue] = p->pos; ++ ++ maxLen = 1; ++ offset = 0; ++ if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur) ++ { ++ distances[0] = maxLen = 2; ++ distances[1] = delta2 - 1; ++ offset = 2; ++ } ++ if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur) ++ { ++ maxLen = 3; ++ distances[offset + 1] = delta3 - 1; ++ offset += 2; ++ delta2 = delta3; ++ } ++ if (offset != 0) ++ { ++ for (; maxLen != lenLimit; maxLen++) ++ if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen]) ++ break; ++ distances[offset - 2] = maxLen; ++ if (maxLen == lenLimit) ++ { ++ p->son[p->cyclicBufferPos] = curMatch; ++ MOVE_POS_RET; ++ } ++ } ++ if (maxLen < 3) ++ maxLen = 3; ++ offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p), ++ distances + offset, maxLen) - (distances)); ++ MOVE_POS_RET ++} ++ ++UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) ++{ ++ UInt32 offset; ++ GET_MATCHES_HEADER(3) ++ HASH_ZIP_CALC; ++ curMatch = p->hash[hashValue]; ++ p->hash[hashValue] = p->pos; ++ offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p), ++ distances, 2) - (distances)); ++ MOVE_POS_RET ++} ++ ++static void Bt2_MatchFinder_Skip(CMatchFinder *p, UInt32 num) ++{ ++ do ++ { ++ SKIP_HEADER(2) ++ HASH2_CALC; ++ curMatch = p->hash[hashValue]; ++ p->hash[hashValue] = p->pos; ++ SKIP_FOOTER ++ } ++ while (--num != 0); ++} ++ ++void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num) ++{ ++ do ++ { ++ SKIP_HEADER(3) ++ HASH_ZIP_CALC; ++ curMatch = p->hash[hashValue]; ++ p->hash[hashValue] = p->pos; ++ SKIP_FOOTER ++ } ++ while (--num != 0); ++} ++ ++static void Bt3_MatchFinder_Skip(CMatchFinder *p, UInt32 num) ++{ ++ do ++ { ++ UInt32 hash2Value; ++ SKIP_HEADER(3) ++ HASH3_CALC; ++ curMatch = p->hash[kFix3HashSize + hashValue]; ++ p->hash[hash2Value] = ++ p->hash[kFix3HashSize + hashValue] = p->pos; ++ SKIP_FOOTER ++ } ++ while (--num != 0); ++} ++ ++static void Bt4_MatchFinder_Skip(CMatchFinder *p, UInt32 num) ++{ ++ do ++ { ++ UInt32 hash2Value, hash3Value; ++ SKIP_HEADER(4) ++ HASH4_CALC; ++ curMatch = p->hash[kFix4HashSize + hashValue]; ++ p->hash[ hash2Value] = ++ p->hash[kFix3HashSize + hash3Value] = p->pos; ++ p->hash[kFix4HashSize + hashValue] = p->pos; ++ SKIP_FOOTER ++ } ++ while (--num != 0); ++} ++ ++static void Hc4_MatchFinder_Skip(CMatchFinder *p, UInt32 num) ++{ ++ do ++ { ++ UInt32 hash2Value, hash3Value; ++ SKIP_HEADER(4) ++ HASH4_CALC; ++ curMatch = p->hash[kFix4HashSize + hashValue]; ++ p->hash[ hash2Value] = ++ p->hash[kFix3HashSize + hash3Value] = ++ p->hash[kFix4HashSize + hashValue] = p->pos; ++ p->son[p->cyclicBufferPos] = curMatch; ++ MOVE_POS ++ } ++ while (--num != 0); ++} ++ ++void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num) ++{ ++ do ++ { ++ SKIP_HEADER(3) ++ HASH_ZIP_CALC; ++ curMatch = p->hash[hashValue]; ++ p->hash[hashValue] = p->pos; ++ p->son[p->cyclicBufferPos] = curMatch; ++ MOVE_POS ++ } ++ while (--num != 0); ++} ++ ++void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable) ++{ ++ vTable->Init = (Mf_Init_Func)MatchFinder_Init; ++ vTable->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinder_GetIndexByte; ++ vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinder_GetNumAvailableBytes; ++ vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinder_GetPointerToCurrentPos; ++ if (!p->btMode) ++ { ++ vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches; ++ vTable->Skip = (Mf_Skip_Func)Hc4_MatchFinder_Skip; ++ } ++ else if (p->numHashBytes == 2) ++ { ++ vTable->GetMatches = (Mf_GetMatches_Func)Bt2_MatchFinder_GetMatches; ++ vTable->Skip = (Mf_Skip_Func)Bt2_MatchFinder_Skip; ++ } ++ else if (p->numHashBytes == 3) ++ { ++ vTable->GetMatches = (Mf_GetMatches_Func)Bt3_MatchFinder_GetMatches; ++ vTable->Skip = (Mf_Skip_Func)Bt3_MatchFinder_Skip; ++ } ++ else ++ { ++ vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches; ++ vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip; ++ } ++} +--- /dev/null ++++ b/lib/lzma/LzmaDec.c +@@ -0,0 +1,999 @@ ++/* LzmaDec.c -- LZMA Decoder ++2009-09-20 : Igor Pavlov : Public domain */ ++ ++#include "LzmaDec.h" ++ ++#include ++ ++#define kNumTopBits 24 ++#define kTopValue ((UInt32)1 << kNumTopBits) ++ ++#define kNumBitModelTotalBits 11 ++#define kBitModelTotal (1 << kNumBitModelTotalBits) ++#define kNumMoveBits 5 ++ ++#define RC_INIT_SIZE 5 ++ ++#define NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); } ++ ++#define IF_BIT_0(p) ttt = *(p); NORMALIZE; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) ++#define UPDATE_0(p) range = bound; *(p) = (CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); ++#define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CLzmaProb)(ttt - (ttt >> kNumMoveBits)); ++#define GET_BIT2(p, i, A0, A1) IF_BIT_0(p) \ ++ { UPDATE_0(p); i = (i + i); A0; } else \ ++ { UPDATE_1(p); i = (i + i) + 1; A1; } ++#define GET_BIT(p, i) GET_BIT2(p, i, ; , ;) ++ ++#define TREE_GET_BIT(probs, i) { GET_BIT((probs + i), i); } ++#define TREE_DECODE(probs, limit, i) \ ++ { i = 1; do { TREE_GET_BIT(probs, i); } while (i < limit); i -= limit; } ++ ++/* #define _LZMA_SIZE_OPT */ ++ ++#ifdef _LZMA_SIZE_OPT ++#define TREE_6_DECODE(probs, i) TREE_DECODE(probs, (1 << 6), i) ++#else ++#define TREE_6_DECODE(probs, i) \ ++ { i = 1; \ ++ TREE_GET_BIT(probs, i); \ ++ TREE_GET_BIT(probs, i); \ ++ TREE_GET_BIT(probs, i); \ ++ TREE_GET_BIT(probs, i); \ ++ TREE_GET_BIT(probs, i); \ ++ TREE_GET_BIT(probs, i); \ ++ i -= 0x40; } ++#endif ++ ++#define NORMALIZE_CHECK if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_ERROR; range <<= 8; code = (code << 8) | (*buf++); } ++ ++#define IF_BIT_0_CHECK(p) ttt = *(p); NORMALIZE_CHECK; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) ++#define UPDATE_0_CHECK range = bound; ++#define UPDATE_1_CHECK range -= bound; code -= bound; ++#define GET_BIT2_CHECK(p, i, A0, A1) IF_BIT_0_CHECK(p) \ ++ { UPDATE_0_CHECK; i = (i + i); A0; } else \ ++ { UPDATE_1_CHECK; i = (i + i) + 1; A1; } ++#define GET_BIT_CHECK(p, i) GET_BIT2_CHECK(p, i, ; , ;) ++#define TREE_DECODE_CHECK(probs, limit, i) \ ++ { i = 1; do { GET_BIT_CHECK(probs + i, i) } while (i < limit); i -= limit; } ++ ++ ++#define kNumPosBitsMax 4 ++#define kNumPosStatesMax (1 << kNumPosBitsMax) ++ ++#define kLenNumLowBits 3 ++#define kLenNumLowSymbols (1 << kLenNumLowBits) ++#define kLenNumMidBits 3 ++#define kLenNumMidSymbols (1 << kLenNumMidBits) ++#define kLenNumHighBits 8 ++#define kLenNumHighSymbols (1 << kLenNumHighBits) ++ ++#define LenChoice 0 ++#define LenChoice2 (LenChoice + 1) ++#define LenLow (LenChoice2 + 1) ++#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits)) ++#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits)) ++#define kNumLenProbs (LenHigh + kLenNumHighSymbols) ++ ++ ++#define kNumStates 12 ++#define kNumLitStates 7 ++ ++#define kStartPosModelIndex 4 ++#define kEndPosModelIndex 14 ++#define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) ++ ++#define kNumPosSlotBits 6 ++#define kNumLenToPosStates 4 ++ ++#define kNumAlignBits 4 ++#define kAlignTableSize (1 << kNumAlignBits) ++ ++#define kMatchMinLen 2 ++#define kMatchSpecLenStart (kMatchMinLen + kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols) ++ ++#define IsMatch 0 ++#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax)) ++#define IsRepG0 (IsRep + kNumStates) ++#define IsRepG1 (IsRepG0 + kNumStates) ++#define IsRepG2 (IsRepG1 + kNumStates) ++#define IsRep0Long (IsRepG2 + kNumStates) ++#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax)) ++#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits)) ++#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex) ++#define LenCoder (Align + kAlignTableSize) ++#define RepLenCoder (LenCoder + kNumLenProbs) ++#define Literal (RepLenCoder + kNumLenProbs) ++ ++#define LZMA_BASE_SIZE 1846 ++#define LZMA_LIT_SIZE 768 ++ ++#define LzmaProps_GetNumProbs(p) ((UInt32)LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((p)->lc + (p)->lp))) ++ ++#if Literal != LZMA_BASE_SIZE ++StopCompilingDueBUG ++#endif ++ ++#define LZMA_DIC_MIN (1 << 12) ++ ++/* First LZMA-symbol is always decoded. ++And it decodes new LZMA-symbols while (buf < bufLimit), but "buf" is without last normalization ++Out: ++ Result: ++ SZ_OK - OK ++ SZ_ERROR_DATA - Error ++ p->remainLen: ++ < kMatchSpecLenStart : normal remain ++ = kMatchSpecLenStart : finished ++ = kMatchSpecLenStart + 1 : Flush marker ++ = kMatchSpecLenStart + 2 : State Init Marker ++*/ ++ ++static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte *bufLimit) ++{ ++ CLzmaProb *probs = p->probs; ++ ++ unsigned state = p->state; ++ UInt32 rep0 = p->reps[0], rep1 = p->reps[1], rep2 = p->reps[2], rep3 = p->reps[3]; ++ unsigned pbMask = ((unsigned)1 << (p->prop.pb)) - 1; ++ unsigned lpMask = ((unsigned)1 << (p->prop.lp)) - 1; ++ unsigned lc = p->prop.lc; ++ ++ Byte *dic = p->dic; ++ SizeT dicBufSize = p->dicBufSize; ++ SizeT dicPos = p->dicPos; ++ ++ UInt32 processedPos = p->processedPos; ++ UInt32 checkDicSize = p->checkDicSize; ++ unsigned len = 0; ++ ++ const Byte *buf = p->buf; ++ UInt32 range = p->range; ++ UInt32 code = p->code; ++ ++ do ++ { ++ CLzmaProb *prob; ++ UInt32 bound; ++ unsigned ttt; ++ unsigned posState = processedPos & pbMask; ++ ++ prob = probs + IsMatch + (state << kNumPosBitsMax) + posState; ++ IF_BIT_0(prob) ++ { ++ unsigned symbol; ++ UPDATE_0(prob); ++ prob = probs + Literal; ++ if (checkDicSize != 0 || processedPos != 0) ++ prob += (LZMA_LIT_SIZE * (((processedPos & lpMask) << lc) + ++ (dic[(dicPos == 0 ? dicBufSize : dicPos) - 1] >> (8 - lc)))); ++ ++ if (state < kNumLitStates) ++ { ++ state -= (state < 4) ? state : 3; ++ symbol = 1; ++ do { GET_BIT(prob + symbol, symbol) } while (symbol < 0x100); ++ } ++ else ++ { ++ unsigned matchByte = p->dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; ++ unsigned offs = 0x100; ++ state -= (state < 10) ? 3 : 6; ++ symbol = 1; ++ do ++ { ++ unsigned bit; ++ CLzmaProb *probLit; ++ matchByte <<= 1; ++ bit = (matchByte & offs); ++ probLit = prob + offs + bit + symbol; ++ GET_BIT2(probLit, symbol, offs &= ~bit, offs &= bit) ++ } ++ while (symbol < 0x100); ++ } ++ dic[dicPos++] = (Byte)symbol; ++ processedPos++; ++ continue; ++ } ++ else ++ { ++ UPDATE_1(prob); ++ prob = probs + IsRep + state; ++ IF_BIT_0(prob) ++ { ++ UPDATE_0(prob); ++ state += kNumStates; ++ prob = probs + LenCoder; ++ } ++ else ++ { ++ UPDATE_1(prob); ++ if (checkDicSize == 0 && processedPos == 0) ++ return SZ_ERROR_DATA; ++ prob = probs + IsRepG0 + state; ++ IF_BIT_0(prob) ++ { ++ UPDATE_0(prob); ++ prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState; ++ IF_BIT_0(prob) ++ { ++ UPDATE_0(prob); ++ dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; ++ dicPos++; ++ processedPos++; ++ state = state < kNumLitStates ? 9 : 11; ++ continue; ++ } ++ UPDATE_1(prob); ++ } ++ else ++ { ++ UInt32 distance; ++ UPDATE_1(prob); ++ prob = probs + IsRepG1 + state; ++ IF_BIT_0(prob) ++ { ++ UPDATE_0(prob); ++ distance = rep1; ++ } ++ else ++ { ++ UPDATE_1(prob); ++ prob = probs + IsRepG2 + state; ++ IF_BIT_0(prob) ++ { ++ UPDATE_0(prob); ++ distance = rep2; ++ } ++ else ++ { ++ UPDATE_1(prob); ++ distance = rep3; ++ rep3 = rep2; ++ } ++ rep2 = rep1; ++ } ++ rep1 = rep0; ++ rep0 = distance; ++ } ++ state = state < kNumLitStates ? 8 : 11; ++ prob = probs + RepLenCoder; ++ } ++ { ++ unsigned limit, offset; ++ CLzmaProb *probLen = prob + LenChoice; ++ IF_BIT_0(probLen) ++ { ++ UPDATE_0(probLen); ++ probLen = prob + LenLow + (posState << kLenNumLowBits); ++ offset = 0; ++ limit = (1 << kLenNumLowBits); ++ } ++ else ++ { ++ UPDATE_1(probLen); ++ probLen = prob + LenChoice2; ++ IF_BIT_0(probLen) ++ { ++ UPDATE_0(probLen); ++ probLen = prob + LenMid + (posState << kLenNumMidBits); ++ offset = kLenNumLowSymbols; ++ limit = (1 << kLenNumMidBits); ++ } ++ else ++ { ++ UPDATE_1(probLen); ++ probLen = prob + LenHigh; ++ offset = kLenNumLowSymbols + kLenNumMidSymbols; ++ limit = (1 << kLenNumHighBits); ++ } ++ } ++ TREE_DECODE(probLen, limit, len); ++ len += offset; ++ } ++ ++ if (state >= kNumStates) ++ { ++ UInt32 distance; ++ prob = probs + PosSlot + ++ ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits); ++ TREE_6_DECODE(prob, distance); ++ if (distance >= kStartPosModelIndex) ++ { ++ unsigned posSlot = (unsigned)distance; ++ int numDirectBits = (int)(((distance >> 1) - 1)); ++ distance = (2 | (distance & 1)); ++ if (posSlot < kEndPosModelIndex) ++ { ++ distance <<= numDirectBits; ++ prob = probs + SpecPos + distance - posSlot - 1; ++ { ++ UInt32 mask = 1; ++ unsigned i = 1; ++ do ++ { ++ GET_BIT2(prob + i, i, ; , distance |= mask); ++ mask <<= 1; ++ } ++ while (--numDirectBits != 0); ++ } ++ } ++ else ++ { ++ numDirectBits -= kNumAlignBits; ++ do ++ { ++ NORMALIZE ++ range >>= 1; ++ ++ { ++ UInt32 t; ++ code -= range; ++ t = (0 - ((UInt32)code >> 31)); /* (UInt32)((Int32)code >> 31) */ ++ distance = (distance << 1) + (t + 1); ++ code += range & t; ++ } ++ /* ++ distance <<= 1; ++ if (code >= range) ++ { ++ code -= range; ++ distance |= 1; ++ } ++ */ ++ } ++ while (--numDirectBits != 0); ++ prob = probs + Align; ++ distance <<= kNumAlignBits; ++ { ++ unsigned i = 1; ++ GET_BIT2(prob + i, i, ; , distance |= 1); ++ GET_BIT2(prob + i, i, ; , distance |= 2); ++ GET_BIT2(prob + i, i, ; , distance |= 4); ++ GET_BIT2(prob + i, i, ; , distance |= 8); ++ } ++ if (distance == (UInt32)0xFFFFFFFF) ++ { ++ len += kMatchSpecLenStart; ++ state -= kNumStates; ++ break; ++ } ++ } ++ } ++ rep3 = rep2; ++ rep2 = rep1; ++ rep1 = rep0; ++ rep0 = distance + 1; ++ if (checkDicSize == 0) ++ { ++ if (distance >= processedPos) ++ return SZ_ERROR_DATA; ++ } ++ else if (distance >= checkDicSize) ++ return SZ_ERROR_DATA; ++ state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3; ++ } ++ ++ len += kMatchMinLen; ++ ++ if (limit == dicPos) ++ return SZ_ERROR_DATA; ++ { ++ SizeT rem = limit - dicPos; ++ unsigned curLen = ((rem < len) ? (unsigned)rem : len); ++ SizeT pos = (dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0); ++ ++ processedPos += curLen; ++ ++ len -= curLen; ++ if (pos + curLen <= dicBufSize) ++ { ++ Byte *dest = dic + dicPos; ++ ptrdiff_t src = (ptrdiff_t)pos - (ptrdiff_t)dicPos; ++ const Byte *lim = dest + curLen; ++ dicPos += curLen; ++ do ++ *(dest) = (Byte)*(dest + src); ++ while (++dest != lim); ++ } ++ else ++ { ++ do ++ { ++ dic[dicPos++] = dic[pos]; ++ if (++pos == dicBufSize) ++ pos = 0; ++ } ++ while (--curLen != 0); ++ } ++ } ++ } ++ } ++ while (dicPos < limit && buf < bufLimit); ++ NORMALIZE; ++ p->buf = buf; ++ p->range = range; ++ p->code = code; ++ p->remainLen = len; ++ p->dicPos = dicPos; ++ p->processedPos = processedPos; ++ p->reps[0] = rep0; ++ p->reps[1] = rep1; ++ p->reps[2] = rep2; ++ p->reps[3] = rep3; ++ p->state = state; ++ ++ return SZ_OK; ++} ++ ++static void MY_FAST_CALL LzmaDec_WriteRem(CLzmaDec *p, SizeT limit) ++{ ++ if (p->remainLen != 0 && p->remainLen < kMatchSpecLenStart) ++ { ++ Byte *dic = p->dic; ++ SizeT dicPos = p->dicPos; ++ SizeT dicBufSize = p->dicBufSize; ++ unsigned len = p->remainLen; ++ UInt32 rep0 = p->reps[0]; ++ if (limit - dicPos < len) ++ len = (unsigned)(limit - dicPos); ++ ++ if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= len) ++ p->checkDicSize = p->prop.dicSize; ++ ++ p->processedPos += len; ++ p->remainLen -= len; ++ while (len-- != 0) ++ { ++ dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; ++ dicPos++; ++ } ++ p->dicPos = dicPos; ++ } ++} ++ ++static int MY_FAST_CALL LzmaDec_DecodeReal2(CLzmaDec *p, SizeT limit, const Byte *bufLimit) ++{ ++ do ++ { ++ SizeT limit2 = limit; ++ if (p->checkDicSize == 0) ++ { ++ UInt32 rem = p->prop.dicSize - p->processedPos; ++ if (limit - p->dicPos > rem) ++ limit2 = p->dicPos + rem; ++ } ++ RINOK(LzmaDec_DecodeReal(p, limit2, bufLimit)); ++ if (p->processedPos >= p->prop.dicSize) ++ p->checkDicSize = p->prop.dicSize; ++ LzmaDec_WriteRem(p, limit); ++ } ++ while (p->dicPos < limit && p->buf < bufLimit && p->remainLen < kMatchSpecLenStart); ++ ++ if (p->remainLen > kMatchSpecLenStart) ++ { ++ p->remainLen = kMatchSpecLenStart; ++ } ++ return 0; ++} ++ ++typedef enum ++{ ++ DUMMY_ERROR, /* unexpected end of input stream */ ++ DUMMY_LIT, ++ DUMMY_MATCH, ++ DUMMY_REP ++} ELzmaDummy; ++ ++static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inSize) ++{ ++ UInt32 range = p->range; ++ UInt32 code = p->code; ++ const Byte *bufLimit = buf + inSize; ++ CLzmaProb *probs = p->probs; ++ unsigned state = p->state; ++ ELzmaDummy res; ++ ++ { ++ CLzmaProb *prob; ++ UInt32 bound; ++ unsigned ttt; ++ unsigned posState = (p->processedPos) & ((1 << p->prop.pb) - 1); ++ ++ prob = probs + IsMatch + (state << kNumPosBitsMax) + posState; ++ IF_BIT_0_CHECK(prob) ++ { ++ UPDATE_0_CHECK ++ ++ /* if (bufLimit - buf >= 7) return DUMMY_LIT; */ ++ ++ prob = probs + Literal; ++ if (p->checkDicSize != 0 || p->processedPos != 0) ++ prob += (LZMA_LIT_SIZE * ++ ((((p->processedPos) & ((1 << (p->prop.lp)) - 1)) << p->prop.lc) + ++ (p->dic[(p->dicPos == 0 ? p->dicBufSize : p->dicPos) - 1] >> (8 - p->prop.lc)))); ++ ++ if (state < kNumLitStates) ++ { ++ unsigned symbol = 1; ++ do { GET_BIT_CHECK(prob + symbol, symbol) } while (symbol < 0x100); ++ } ++ else ++ { ++ unsigned matchByte = p->dic[p->dicPos - p->reps[0] + ++ ((p->dicPos < p->reps[0]) ? p->dicBufSize : 0)]; ++ unsigned offs = 0x100; ++ unsigned symbol = 1; ++ do ++ { ++ unsigned bit; ++ CLzmaProb *probLit; ++ matchByte <<= 1; ++ bit = (matchByte & offs); ++ probLit = prob + offs + bit + symbol; ++ GET_BIT2_CHECK(probLit, symbol, offs &= ~bit, offs &= bit) ++ } ++ while (symbol < 0x100); ++ } ++ res = DUMMY_LIT; ++ } ++ else ++ { ++ unsigned len; ++ UPDATE_1_CHECK; ++ ++ prob = probs + IsRep + state; ++ IF_BIT_0_CHECK(prob) ++ { ++ UPDATE_0_CHECK; ++ state = 0; ++ prob = probs + LenCoder; ++ res = DUMMY_MATCH; ++ } ++ else ++ { ++ UPDATE_1_CHECK; ++ res = DUMMY_REP; ++ prob = probs + IsRepG0 + state; ++ IF_BIT_0_CHECK(prob) ++ { ++ UPDATE_0_CHECK; ++ prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState; ++ IF_BIT_0_CHECK(prob) ++ { ++ UPDATE_0_CHECK; ++ NORMALIZE_CHECK; ++ return DUMMY_REP; ++ } ++ else ++ { ++ UPDATE_1_CHECK; ++ } ++ } ++ else ++ { ++ UPDATE_1_CHECK; ++ prob = probs + IsRepG1 + state; ++ IF_BIT_0_CHECK(prob) ++ { ++ UPDATE_0_CHECK; ++ } ++ else ++ { ++ UPDATE_1_CHECK; ++ prob = probs + IsRepG2 + state; ++ IF_BIT_0_CHECK(prob) ++ { ++ UPDATE_0_CHECK; ++ } ++ else ++ { ++ UPDATE_1_CHECK; ++ } ++ } ++ } ++ state = kNumStates; ++ prob = probs + RepLenCoder; ++ } ++ { ++ unsigned limit, offset; ++ CLzmaProb *probLen = prob + LenChoice; ++ IF_BIT_0_CHECK(probLen) ++ { ++ UPDATE_0_CHECK; ++ probLen = prob + LenLow + (posState << kLenNumLowBits); ++ offset = 0; ++ limit = 1 << kLenNumLowBits; ++ } ++ else ++ { ++ UPDATE_1_CHECK; ++ probLen = prob + LenChoice2; ++ IF_BIT_0_CHECK(probLen) ++ { ++ UPDATE_0_CHECK; ++ probLen = prob + LenMid + (posState << kLenNumMidBits); ++ offset = kLenNumLowSymbols; ++ limit = 1 << kLenNumMidBits; ++ } ++ else ++ { ++ UPDATE_1_CHECK; ++ probLen = prob + LenHigh; ++ offset = kLenNumLowSymbols + kLenNumMidSymbols; ++ limit = 1 << kLenNumHighBits; ++ } ++ } ++ TREE_DECODE_CHECK(probLen, limit, len); ++ len += offset; ++ } ++ ++ if (state < 4) ++ { ++ unsigned posSlot; ++ prob = probs + PosSlot + ++ ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << ++ kNumPosSlotBits); ++ TREE_DECODE_CHECK(prob, 1 << kNumPosSlotBits, posSlot); ++ if (posSlot >= kStartPosModelIndex) ++ { ++ int numDirectBits = ((posSlot >> 1) - 1); ++ ++ /* if (bufLimit - buf >= 8) return DUMMY_MATCH; */ ++ ++ if (posSlot < kEndPosModelIndex) ++ { ++ prob = probs + SpecPos + ((2 | (posSlot & 1)) << numDirectBits) - posSlot - 1; ++ } ++ else ++ { ++ numDirectBits -= kNumAlignBits; ++ do ++ { ++ NORMALIZE_CHECK ++ range >>= 1; ++ code -= range & (((code - range) >> 31) - 1); ++ /* if (code >= range) code -= range; */ ++ } ++ while (--numDirectBits != 0); ++ prob = probs + Align; ++ numDirectBits = kNumAlignBits; ++ } ++ { ++ unsigned i = 1; ++ do ++ { ++ GET_BIT_CHECK(prob + i, i); ++ } ++ while (--numDirectBits != 0); ++ } ++ } ++ } ++ } ++ } ++ NORMALIZE_CHECK; ++ return res; ++} ++ ++ ++static void LzmaDec_InitRc(CLzmaDec *p, const Byte *data) ++{ ++ p->code = ((UInt32)data[1] << 24) | ((UInt32)data[2] << 16) | ((UInt32)data[3] << 8) | ((UInt32)data[4]); ++ p->range = 0xFFFFFFFF; ++ p->needFlush = 0; ++} ++ ++void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState) ++{ ++ p->needFlush = 1; ++ p->remainLen = 0; ++ p->tempBufSize = 0; ++ ++ if (initDic) ++ { ++ p->processedPos = 0; ++ p->checkDicSize = 0; ++ p->needInitState = 1; ++ } ++ if (initState) ++ p->needInitState = 1; ++} ++ ++void LzmaDec_Init(CLzmaDec *p) ++{ ++ p->dicPos = 0; ++ LzmaDec_InitDicAndState(p, True, True); ++} ++ ++static void LzmaDec_InitStateReal(CLzmaDec *p) ++{ ++ UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (p->prop.lc + p->prop.lp)); ++ UInt32 i; ++ CLzmaProb *probs = p->probs; ++ for (i = 0; i < numProbs; i++) ++ probs[i] = kBitModelTotal >> 1; ++ p->reps[0] = p->reps[1] = p->reps[2] = p->reps[3] = 1; ++ p->state = 0; ++ p->needInitState = 0; ++} ++ ++SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen, ++ ELzmaFinishMode finishMode, ELzmaStatus *status) ++{ ++ SizeT inSize = *srcLen; ++ (*srcLen) = 0; ++ LzmaDec_WriteRem(p, dicLimit); ++ ++ *status = LZMA_STATUS_NOT_SPECIFIED; ++ ++ while (p->remainLen != kMatchSpecLenStart) ++ { ++ int checkEndMarkNow; ++ ++ if (p->needFlush != 0) ++ { ++ for (; inSize > 0 && p->tempBufSize < RC_INIT_SIZE; (*srcLen)++, inSize--) ++ p->tempBuf[p->tempBufSize++] = *src++; ++ if (p->tempBufSize < RC_INIT_SIZE) ++ { ++ *status = LZMA_STATUS_NEEDS_MORE_INPUT; ++ return SZ_OK; ++ } ++ if (p->tempBuf[0] != 0) ++ return SZ_ERROR_DATA; ++ ++ LzmaDec_InitRc(p, p->tempBuf); ++ p->tempBufSize = 0; ++ } ++ ++ checkEndMarkNow = 0; ++ if (p->dicPos >= dicLimit) ++ { ++ if (p->remainLen == 0 && p->code == 0) ++ { ++ *status = LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK; ++ return SZ_OK; ++ } ++ if (finishMode == LZMA_FINISH_ANY) ++ { ++ *status = LZMA_STATUS_NOT_FINISHED; ++ return SZ_OK; ++ } ++ if (p->remainLen != 0) ++ { ++ *status = LZMA_STATUS_NOT_FINISHED; ++ return SZ_ERROR_DATA; ++ } ++ checkEndMarkNow = 1; ++ } ++ ++ if (p->needInitState) ++ LzmaDec_InitStateReal(p); ++ ++ if (p->tempBufSize == 0) ++ { ++ SizeT processed; ++ const Byte *bufLimit; ++ if (inSize < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) ++ { ++ int dummyRes = LzmaDec_TryDummy(p, src, inSize); ++ if (dummyRes == DUMMY_ERROR) ++ { ++ memcpy(p->tempBuf, src, inSize); ++ p->tempBufSize = (unsigned)inSize; ++ (*srcLen) += inSize; ++ *status = LZMA_STATUS_NEEDS_MORE_INPUT; ++ return SZ_OK; ++ } ++ if (checkEndMarkNow && dummyRes != DUMMY_MATCH) ++ { ++ *status = LZMA_STATUS_NOT_FINISHED; ++ return SZ_ERROR_DATA; ++ } ++ bufLimit = src; ++ } ++ else ++ bufLimit = src + inSize - LZMA_REQUIRED_INPUT_MAX; ++ p->buf = src; ++ if (LzmaDec_DecodeReal2(p, dicLimit, bufLimit) != 0) ++ return SZ_ERROR_DATA; ++ processed = (SizeT)(p->buf - src); ++ (*srcLen) += processed; ++ src += processed; ++ inSize -= processed; ++ } ++ else ++ { ++ unsigned rem = p->tempBufSize, lookAhead = 0; ++ while (rem < LZMA_REQUIRED_INPUT_MAX && lookAhead < inSize) ++ p->tempBuf[rem++] = src[lookAhead++]; ++ p->tempBufSize = rem; ++ if (rem < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) ++ { ++ int dummyRes = LzmaDec_TryDummy(p, p->tempBuf, rem); ++ if (dummyRes == DUMMY_ERROR) ++ { ++ (*srcLen) += lookAhead; ++ *status = LZMA_STATUS_NEEDS_MORE_INPUT; ++ return SZ_OK; ++ } ++ if (checkEndMarkNow && dummyRes != DUMMY_MATCH) ++ { ++ *status = LZMA_STATUS_NOT_FINISHED; ++ return SZ_ERROR_DATA; ++ } ++ } ++ p->buf = p->tempBuf; ++ if (LzmaDec_DecodeReal2(p, dicLimit, p->buf) != 0) ++ return SZ_ERROR_DATA; ++ lookAhead -= (rem - (unsigned)(p->buf - p->tempBuf)); ++ (*srcLen) += lookAhead; ++ src += lookAhead; ++ inSize -= lookAhead; ++ p->tempBufSize = 0; ++ } ++ } ++ if (p->code == 0) ++ *status = LZMA_STATUS_FINISHED_WITH_MARK; ++ return (p->code == 0) ? SZ_OK : SZ_ERROR_DATA; ++} ++ ++SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) ++{ ++ SizeT outSize = *destLen; ++ SizeT inSize = *srcLen; ++ *srcLen = *destLen = 0; ++ for (;;) ++ { ++ SizeT inSizeCur = inSize, outSizeCur, dicPos; ++ ELzmaFinishMode curFinishMode; ++ SRes res; ++ if (p->dicPos == p->dicBufSize) ++ p->dicPos = 0; ++ dicPos = p->dicPos; ++ if (outSize > p->dicBufSize - dicPos) ++ { ++ outSizeCur = p->dicBufSize; ++ curFinishMode = LZMA_FINISH_ANY; ++ } ++ else ++ { ++ outSizeCur = dicPos + outSize; ++ curFinishMode = finishMode; ++ } ++ ++ res = LzmaDec_DecodeToDic(p, outSizeCur, src, &inSizeCur, curFinishMode, status); ++ src += inSizeCur; ++ inSize -= inSizeCur; ++ *srcLen += inSizeCur; ++ outSizeCur = p->dicPos - dicPos; ++ memcpy(dest, p->dic + dicPos, outSizeCur); ++ dest += outSizeCur; ++ outSize -= outSizeCur; ++ *destLen += outSizeCur; ++ if (res != 0) ++ return res; ++ if (outSizeCur == 0 || outSize == 0) ++ return SZ_OK; ++ } ++} ++ ++void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc) ++{ ++ alloc->Free(alloc, p->probs); ++ p->probs = 0; ++} ++ ++static void LzmaDec_FreeDict(CLzmaDec *p, ISzAlloc *alloc) ++{ ++ alloc->Free(alloc, p->dic); ++ p->dic = 0; ++} ++ ++void LzmaDec_Free(CLzmaDec *p, ISzAlloc *alloc) ++{ ++ LzmaDec_FreeProbs(p, alloc); ++ LzmaDec_FreeDict(p, alloc); ++} ++ ++SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size) ++{ ++ UInt32 dicSize; ++ Byte d; ++ ++ if (size < LZMA_PROPS_SIZE) ++ return SZ_ERROR_UNSUPPORTED; ++ else ++ dicSize = data[1] | ((UInt32)data[2] << 8) | ((UInt32)data[3] << 16) | ((UInt32)data[4] << 24); ++ ++ if (dicSize < LZMA_DIC_MIN) ++ dicSize = LZMA_DIC_MIN; ++ p->dicSize = dicSize; ++ ++ d = data[0]; ++ if (d >= (9 * 5 * 5)) ++ return SZ_ERROR_UNSUPPORTED; ++ ++ p->lc = d % 9; ++ d /= 9; ++ p->pb = d / 5; ++ p->lp = d % 5; ++ ++ return SZ_OK; ++} ++ ++static SRes LzmaDec_AllocateProbs2(CLzmaDec *p, const CLzmaProps *propNew, ISzAlloc *alloc) ++{ ++ UInt32 numProbs = LzmaProps_GetNumProbs(propNew); ++ if (p->probs == 0 || numProbs != p->numProbs) ++ { ++ LzmaDec_FreeProbs(p, alloc); ++ p->probs = (CLzmaProb *)alloc->Alloc(alloc, numProbs * sizeof(CLzmaProb)); ++ p->numProbs = numProbs; ++ if (p->probs == 0) ++ return SZ_ERROR_MEM; ++ } ++ return SZ_OK; ++} ++ ++SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) ++{ ++ CLzmaProps propNew; ++ RINOK(LzmaProps_Decode(&propNew, props, propsSize)); ++ RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); ++ p->prop = propNew; ++ return SZ_OK; ++} ++ ++SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) ++{ ++ CLzmaProps propNew; ++ SizeT dicBufSize; ++ RINOK(LzmaProps_Decode(&propNew, props, propsSize)); ++ RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); ++ dicBufSize = propNew.dicSize; ++ if (p->dic == 0 || dicBufSize != p->dicBufSize) ++ { ++ LzmaDec_FreeDict(p, alloc); ++ p->dic = (Byte *)alloc->Alloc(alloc, dicBufSize); ++ if (p->dic == 0) ++ { ++ LzmaDec_FreeProbs(p, alloc); ++ return SZ_ERROR_MEM; ++ } ++ } ++ p->dicBufSize = dicBufSize; ++ p->prop = propNew; ++ return SZ_OK; ++} ++ ++SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ++ const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, ++ ELzmaStatus *status, ISzAlloc *alloc) ++{ ++ CLzmaDec p; ++ SRes res; ++ SizeT inSize = *srcLen; ++ SizeT outSize = *destLen; ++ *srcLen = *destLen = 0; ++ if (inSize < RC_INIT_SIZE) ++ return SZ_ERROR_INPUT_EOF; ++ ++ LzmaDec_Construct(&p); ++ res = LzmaDec_AllocateProbs(&p, propData, propSize, alloc); ++ if (res != 0) ++ return res; ++ p.dic = dest; ++ p.dicBufSize = outSize; ++ ++ LzmaDec_Init(&p); ++ ++ *srcLen = inSize; ++ res = LzmaDec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status); ++ ++ if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT) ++ res = SZ_ERROR_INPUT_EOF; ++ ++ (*destLen) = p.dicPos; ++ LzmaDec_FreeProbs(&p, alloc); ++ return res; ++} +--- /dev/null ++++ b/lib/lzma/LzmaEnc.c +@@ -0,0 +1,2271 @@ ++/* LzmaEnc.c -- LZMA Encoder ++2009-11-24 : Igor Pavlov : Public domain */ ++ ++#include ++ ++/* #define SHOW_STAT */ ++/* #define SHOW_STAT2 */ ++ ++#if defined(SHOW_STAT) || defined(SHOW_STAT2) ++#include ++#endif ++ ++#include "LzmaEnc.h" ++ ++/* disable MT */ ++#define _7ZIP_ST ++ ++#include "LzFind.h" ++#ifndef _7ZIP_ST ++#include "LzFindMt.h" ++#endif ++ ++#ifdef SHOW_STAT ++static int ttt = 0; ++#endif ++ ++#define kBlockSizeMax ((1 << LZMA_NUM_BLOCK_SIZE_BITS) - 1) ++ ++#define kBlockSize (9 << 10) ++#define kUnpackBlockSize (1 << 18) ++#define kMatchArraySize (1 << 21) ++#define kMatchRecordMaxSize ((LZMA_MATCH_LEN_MAX * 2 + 3) * LZMA_MATCH_LEN_MAX) ++ ++#define kNumMaxDirectBits (31) ++ ++#define kNumTopBits 24 ++#define kTopValue ((UInt32)1 << kNumTopBits) ++ ++#define kNumBitModelTotalBits 11 ++#define kBitModelTotal (1 << kNumBitModelTotalBits) ++#define kNumMoveBits 5 ++#define kProbInitValue (kBitModelTotal >> 1) ++ ++#define kNumMoveReducingBits 4 ++#define kNumBitPriceShiftBits 4 ++#define kBitPrice (1 << kNumBitPriceShiftBits) ++ ++void LzmaEncProps_Init(CLzmaEncProps *p) ++{ ++ p->level = 5; ++ p->dictSize = p->mc = 0; ++ p->lc = p->lp = p->pb = p->algo = p->fb = p->btMode = p->numHashBytes = p->numThreads = -1; ++ p->writeEndMark = 0; ++} ++ ++void LzmaEncProps_Normalize(CLzmaEncProps *p) ++{ ++ int level = p->level; ++ if (level < 0) level = 5; ++ p->level = level; ++ if (p->dictSize == 0) p->dictSize = (level <= 5 ? (1 << (level * 2 + 14)) : (level == 6 ? (1 << 25) : (1 << 26))); ++ if (p->lc < 0) p->lc = 3; ++ if (p->lp < 0) p->lp = 0; ++ if (p->pb < 0) p->pb = 2; ++ if (p->algo < 0) p->algo = (level < 5 ? 0 : 1); ++ if (p->fb < 0) p->fb = (level < 7 ? 32 : 64); ++ if (p->btMode < 0) p->btMode = (p->algo == 0 ? 0 : 1); ++ if (p->numHashBytes < 0) p->numHashBytes = 4; ++ if (p->mc == 0) p->mc = (16 + (p->fb >> 1)) >> (p->btMode ? 0 : 1); ++ if (p->numThreads < 0) ++ p->numThreads = ++ #ifndef _7ZIP_ST ++ ((p->btMode && p->algo) ? 2 : 1); ++ #else ++ 1; ++ #endif ++} ++ ++UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2) ++{ ++ CLzmaEncProps props = *props2; ++ LzmaEncProps_Normalize(&props); ++ return props.dictSize; ++} ++ ++/* #define LZMA_LOG_BSR */ ++/* Define it for Intel's CPU */ ++ ++ ++#ifdef LZMA_LOG_BSR ++ ++#define kDicLogSizeMaxCompress 30 ++ ++#define BSR2_RET(pos, res) { unsigned long i; _BitScanReverse(&i, (pos)); res = (i + i) + ((pos >> (i - 1)) & 1); } ++ ++UInt32 GetPosSlot1(UInt32 pos) ++{ ++ UInt32 res; ++ BSR2_RET(pos, res); ++ return res; ++} ++#define GetPosSlot2(pos, res) { BSR2_RET(pos, res); } ++#define GetPosSlot(pos, res) { if (pos < 2) res = pos; else BSR2_RET(pos, res); } ++ ++#else ++ ++#define kNumLogBits (9 + (int)sizeof(size_t) / 2) ++#define kDicLogSizeMaxCompress ((kNumLogBits - 1) * 2 + 7) ++ ++void LzmaEnc_FastPosInit(Byte *g_FastPos) ++{ ++ int c = 2, slotFast; ++ g_FastPos[0] = 0; ++ g_FastPos[1] = 1; ++ ++ for (slotFast = 2; slotFast < kNumLogBits * 2; slotFast++) ++ { ++ UInt32 k = (1 << ((slotFast >> 1) - 1)); ++ UInt32 j; ++ for (j = 0; j < k; j++, c++) ++ g_FastPos[c] = (Byte)slotFast; ++ } ++} ++ ++#define BSR2_RET(pos, res) { UInt32 i = 6 + ((kNumLogBits - 1) & \ ++ (0 - (((((UInt32)1 << (kNumLogBits + 6)) - 1) - pos) >> 31))); \ ++ res = p->g_FastPos[pos >> i] + (i * 2); } ++/* ++#define BSR2_RET(pos, res) { res = (pos < (1 << (kNumLogBits + 6))) ? \ ++ p->g_FastPos[pos >> 6] + 12 : \ ++ p->g_FastPos[pos >> (6 + kNumLogBits - 1)] + (6 + (kNumLogBits - 1)) * 2; } ++*/ ++ ++#define GetPosSlot1(pos) p->g_FastPos[pos] ++#define GetPosSlot2(pos, res) { BSR2_RET(pos, res); } ++#define GetPosSlot(pos, res) { if (pos < kNumFullDistances) res = p->g_FastPos[pos]; else BSR2_RET(pos, res); } ++ ++#endif ++ ++ ++#define LZMA_NUM_REPS 4 ++ ++typedef unsigned CState; ++ ++typedef struct ++{ ++ UInt32 price; ++ ++ CState state; ++ int prev1IsChar; ++ int prev2; ++ ++ UInt32 posPrev2; ++ UInt32 backPrev2; ++ ++ UInt32 posPrev; ++ UInt32 backPrev; ++ UInt32 backs[LZMA_NUM_REPS]; ++} COptimal; ++ ++#define kNumOpts (1 << 12) ++ ++#define kNumLenToPosStates 4 ++#define kNumPosSlotBits 6 ++#define kDicLogSizeMin 0 ++#define kDicLogSizeMax 32 ++#define kDistTableSizeMax (kDicLogSizeMax * 2) ++ ++ ++#define kNumAlignBits 4 ++#define kAlignTableSize (1 << kNumAlignBits) ++#define kAlignMask (kAlignTableSize - 1) ++ ++#define kStartPosModelIndex 4 ++#define kEndPosModelIndex 14 ++#define kNumPosModels (kEndPosModelIndex - kStartPosModelIndex) ++ ++#define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) ++ ++#ifdef _LZMA_PROB32 ++#define CLzmaProb UInt32 ++#else ++#define CLzmaProb UInt16 ++#endif ++ ++#define LZMA_PB_MAX 4 ++#define LZMA_LC_MAX 8 ++#define LZMA_LP_MAX 4 ++ ++#define LZMA_NUM_PB_STATES_MAX (1 << LZMA_PB_MAX) ++ ++ ++#define kLenNumLowBits 3 ++#define kLenNumLowSymbols (1 << kLenNumLowBits) ++#define kLenNumMidBits 3 ++#define kLenNumMidSymbols (1 << kLenNumMidBits) ++#define kLenNumHighBits 8 ++#define kLenNumHighSymbols (1 << kLenNumHighBits) ++ ++#define kLenNumSymbolsTotal (kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols) ++ ++#define LZMA_MATCH_LEN_MIN 2 ++#define LZMA_MATCH_LEN_MAX (LZMA_MATCH_LEN_MIN + kLenNumSymbolsTotal - 1) ++ ++#define kNumStates 12 ++ ++typedef struct ++{ ++ CLzmaProb choice; ++ CLzmaProb choice2; ++ CLzmaProb low[LZMA_NUM_PB_STATES_MAX << kLenNumLowBits]; ++ CLzmaProb mid[LZMA_NUM_PB_STATES_MAX << kLenNumMidBits]; ++ CLzmaProb high[kLenNumHighSymbols]; ++} CLenEnc; ++ ++typedef struct ++{ ++ CLenEnc p; ++ UInt32 prices[LZMA_NUM_PB_STATES_MAX][kLenNumSymbolsTotal]; ++ UInt32 tableSize; ++ UInt32 counters[LZMA_NUM_PB_STATES_MAX]; ++} CLenPriceEnc; ++ ++typedef struct ++{ ++ UInt32 range; ++ Byte cache; ++ UInt64 low; ++ UInt64 cacheSize; ++ Byte *buf; ++ Byte *bufLim; ++ Byte *bufBase; ++ ISeqOutStream *outStream; ++ UInt64 processed; ++ SRes res; ++} CRangeEnc; ++ ++typedef struct ++{ ++ CLzmaProb *litProbs; ++ ++ CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX]; ++ CLzmaProb isRep[kNumStates]; ++ CLzmaProb isRepG0[kNumStates]; ++ CLzmaProb isRepG1[kNumStates]; ++ CLzmaProb isRepG2[kNumStates]; ++ CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX]; ++ ++ CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits]; ++ CLzmaProb posEncoders[kNumFullDistances - kEndPosModelIndex]; ++ CLzmaProb posAlignEncoder[1 << kNumAlignBits]; ++ ++ CLenPriceEnc lenEnc; ++ CLenPriceEnc repLenEnc; ++ ++ UInt32 reps[LZMA_NUM_REPS]; ++ UInt32 state; ++} CSaveState; ++ ++typedef struct ++{ ++ IMatchFinder matchFinder; ++ void *matchFinderObj; ++ ++ #ifndef _7ZIP_ST ++ Bool mtMode; ++ CMatchFinderMt matchFinderMt; ++ #endif ++ ++ CMatchFinder matchFinderBase; ++ ++ #ifndef _7ZIP_ST ++ Byte pad[128]; ++ #endif ++ ++ UInt32 optimumEndIndex; ++ UInt32 optimumCurrentIndex; ++ ++ UInt32 longestMatchLength; ++ UInt32 numPairs; ++ UInt32 numAvail; ++ COptimal opt[kNumOpts]; ++ ++ #ifndef LZMA_LOG_BSR ++ Byte g_FastPos[1 << kNumLogBits]; ++ #endif ++ ++ UInt32 ProbPrices[kBitModelTotal >> kNumMoveReducingBits]; ++ UInt32 matches[LZMA_MATCH_LEN_MAX * 2 + 2 + 1]; ++ UInt32 numFastBytes; ++ UInt32 additionalOffset; ++ UInt32 reps[LZMA_NUM_REPS]; ++ UInt32 state; ++ ++ UInt32 posSlotPrices[kNumLenToPosStates][kDistTableSizeMax]; ++ UInt32 distancesPrices[kNumLenToPosStates][kNumFullDistances]; ++ UInt32 alignPrices[kAlignTableSize]; ++ UInt32 alignPriceCount; ++ ++ UInt32 distTableSize; ++ ++ unsigned lc, lp, pb; ++ unsigned lpMask, pbMask; ++ ++ CLzmaProb *litProbs; ++ ++ CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX]; ++ CLzmaProb isRep[kNumStates]; ++ CLzmaProb isRepG0[kNumStates]; ++ CLzmaProb isRepG1[kNumStates]; ++ CLzmaProb isRepG2[kNumStates]; ++ CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX]; ++ ++ CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits]; ++ CLzmaProb posEncoders[kNumFullDistances - kEndPosModelIndex]; ++ CLzmaProb posAlignEncoder[1 << kNumAlignBits]; ++ ++ CLenPriceEnc lenEnc; ++ CLenPriceEnc repLenEnc; ++ ++ unsigned lclp; ++ ++ Bool fastMode; ++ ++ CRangeEnc rc; ++ ++ Bool writeEndMark; ++ UInt64 nowPos64; ++ UInt32 matchPriceCount; ++ Bool finished; ++ Bool multiThread; ++ ++ SRes result; ++ UInt32 dictSize; ++ UInt32 matchFinderCycles; ++ ++ int needInit; ++ ++ CSaveState saveState; ++} CLzmaEnc; ++ ++void LzmaEnc_SaveState(CLzmaEncHandle pp) ++{ ++ CLzmaEnc *p = (CLzmaEnc *)pp; ++ CSaveState *dest = &p->saveState; ++ int i; ++ dest->lenEnc = p->lenEnc; ++ dest->repLenEnc = p->repLenEnc; ++ dest->state = p->state; ++ ++ for (i = 0; i < kNumStates; i++) ++ { ++ memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i])); ++ memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i])); ++ } ++ for (i = 0; i < kNumLenToPosStates; i++) ++ memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i])); ++ memcpy(dest->isRep, p->isRep, sizeof(p->isRep)); ++ memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0)); ++ memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1)); ++ memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2)); ++ memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders)); ++ memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder)); ++ memcpy(dest->reps, p->reps, sizeof(p->reps)); ++ memcpy(dest->litProbs, p->litProbs, (0x300 << p->lclp) * sizeof(CLzmaProb)); ++} ++ ++void LzmaEnc_RestoreState(CLzmaEncHandle pp) ++{ ++ CLzmaEnc *dest = (CLzmaEnc *)pp; ++ const CSaveState *p = &dest->saveState; ++ int i; ++ dest->lenEnc = p->lenEnc; ++ dest->repLenEnc = p->repLenEnc; ++ dest->state = p->state; ++ ++ for (i = 0; i < kNumStates; i++) ++ { ++ memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i])); ++ memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i])); ++ } ++ for (i = 0; i < kNumLenToPosStates; i++) ++ memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i])); ++ memcpy(dest->isRep, p->isRep, sizeof(p->isRep)); ++ memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0)); ++ memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1)); ++ memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2)); ++ memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders)); ++ memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder)); ++ memcpy(dest->reps, p->reps, sizeof(p->reps)); ++ memcpy(dest->litProbs, p->litProbs, (0x300 << dest->lclp) * sizeof(CLzmaProb)); ++} ++ ++SRes LzmaEnc_SetProps(CLzmaEncHandle pp, const CLzmaEncProps *props2) ++{ ++ CLzmaEnc *p = (CLzmaEnc *)pp; ++ CLzmaEncProps props = *props2; ++ LzmaEncProps_Normalize(&props); ++ ++ if (props.lc > LZMA_LC_MAX || props.lp > LZMA_LP_MAX || props.pb > LZMA_PB_MAX || ++ props.dictSize > (1 << kDicLogSizeMaxCompress) || props.dictSize > (1 << 30)) ++ return SZ_ERROR_PARAM; ++ p->dictSize = props.dictSize; ++ p->matchFinderCycles = props.mc; ++ { ++ unsigned fb = props.fb; ++ if (fb < 5) ++ fb = 5; ++ if (fb > LZMA_MATCH_LEN_MAX) ++ fb = LZMA_MATCH_LEN_MAX; ++ p->numFastBytes = fb; ++ } ++ p->lc = props.lc; ++ p->lp = props.lp; ++ p->pb = props.pb; ++ p->fastMode = (props.algo == 0); ++ p->matchFinderBase.btMode = props.btMode; ++ { ++ UInt32 numHashBytes = 4; ++ if (props.btMode) ++ { ++ if (props.numHashBytes < 2) ++ numHashBytes = 2; ++ else if (props.numHashBytes < 4) ++ numHashBytes = props.numHashBytes; ++ } ++ p->matchFinderBase.numHashBytes = numHashBytes; ++ } ++ ++ p->matchFinderBase.cutValue = props.mc; ++ ++ p->writeEndMark = props.writeEndMark; ++ ++ #ifndef _7ZIP_ST ++ /* ++ if (newMultiThread != _multiThread) ++ { ++ ReleaseMatchFinder(); ++ _multiThread = newMultiThread; ++ } ++ */ ++ p->multiThread = (props.numThreads > 1); ++ #endif ++ ++ return SZ_OK; ++} ++ ++static const int kLiteralNextStates[kNumStates] = {0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5}; ++static const int kMatchNextStates[kNumStates] = {7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10}; ++static const int kRepNextStates[kNumStates] = {8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11}; ++static const int kShortRepNextStates[kNumStates]= {9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11}; ++ ++#define IsCharState(s) ((s) < 7) ++ ++#define GetLenToPosState(len) (((len) < kNumLenToPosStates + 1) ? (len) - 2 : kNumLenToPosStates - 1) ++ ++#define kInfinityPrice (1 << 30) ++ ++static void RangeEnc_Construct(CRangeEnc *p) ++{ ++ p->outStream = 0; ++ p->bufBase = 0; ++} ++ ++#define RangeEnc_GetProcessed(p) ((p)->processed + ((p)->buf - (p)->bufBase) + (p)->cacheSize) ++ ++#define RC_BUF_SIZE (1 << 16) ++static int RangeEnc_Alloc(CRangeEnc *p, ISzAlloc *alloc) ++{ ++ if (p->bufBase == 0) ++ { ++ p->bufBase = (Byte *)alloc->Alloc(alloc, RC_BUF_SIZE); ++ if (p->bufBase == 0) ++ return 0; ++ p->bufLim = p->bufBase + RC_BUF_SIZE; ++ } ++ return 1; ++} ++ ++static void RangeEnc_Free(CRangeEnc *p, ISzAlloc *alloc) ++{ ++ alloc->Free(alloc, p->bufBase); ++ p->bufBase = 0; ++} ++ ++static void RangeEnc_Init(CRangeEnc *p) ++{ ++ /* Stream.Init(); */ ++ p->low = 0; ++ p->range = 0xFFFFFFFF; ++ p->cacheSize = 1; ++ p->cache = 0; ++ ++ p->buf = p->bufBase; ++ ++ p->processed = 0; ++ p->res = SZ_OK; ++} ++ ++static void RangeEnc_FlushStream(CRangeEnc *p) ++{ ++ size_t num; ++ if (p->res != SZ_OK) ++ return; ++ num = p->buf - p->bufBase; ++ if (num != p->outStream->Write(p->outStream, p->bufBase, num)) ++ p->res = SZ_ERROR_WRITE; ++ p->processed += num; ++ p->buf = p->bufBase; ++} ++ ++static void MY_FAST_CALL RangeEnc_ShiftLow(CRangeEnc *p) ++{ ++ if ((UInt32)p->low < (UInt32)0xFF000000 || (int)(p->low >> 32) != 0) ++ { ++ Byte temp = p->cache; ++ do ++ { ++ Byte *buf = p->buf; ++ *buf++ = (Byte)(temp + (Byte)(p->low >> 32)); ++ p->buf = buf; ++ if (buf == p->bufLim) ++ RangeEnc_FlushStream(p); ++ temp = 0xFF; ++ } ++ while (--p->cacheSize != 0); ++ p->cache = (Byte)((UInt32)p->low >> 24); ++ } ++ p->cacheSize++; ++ p->low = (UInt32)p->low << 8; ++} ++ ++static void RangeEnc_FlushData(CRangeEnc *p) ++{ ++ int i; ++ for (i = 0; i < 5; i++) ++ RangeEnc_ShiftLow(p); ++} ++ ++static void RangeEnc_EncodeDirectBits(CRangeEnc *p, UInt32 value, int numBits) ++{ ++ do ++ { ++ p->range >>= 1; ++ p->low += p->range & (0 - ((value >> --numBits) & 1)); ++ if (p->range < kTopValue) ++ { ++ p->range <<= 8; ++ RangeEnc_ShiftLow(p); ++ } ++ } ++ while (numBits != 0); ++} ++ ++static void RangeEnc_EncodeBit(CRangeEnc *p, CLzmaProb *prob, UInt32 symbol) ++{ ++ UInt32 ttt = *prob; ++ UInt32 newBound = (p->range >> kNumBitModelTotalBits) * ttt; ++ if (symbol == 0) ++ { ++ p->range = newBound; ++ ttt += (kBitModelTotal - ttt) >> kNumMoveBits; ++ } ++ else ++ { ++ p->low += newBound; ++ p->range -= newBound; ++ ttt -= ttt >> kNumMoveBits; ++ } ++ *prob = (CLzmaProb)ttt; ++ if (p->range < kTopValue) ++ { ++ p->range <<= 8; ++ RangeEnc_ShiftLow(p); ++ } ++} ++ ++static void LitEnc_Encode(CRangeEnc *p, CLzmaProb *probs, UInt32 symbol) ++{ ++ symbol |= 0x100; ++ do ++ { ++ RangeEnc_EncodeBit(p, probs + (symbol >> 8), (symbol >> 7) & 1); ++ symbol <<= 1; ++ } ++ while (symbol < 0x10000); ++} ++ ++static void LitEnc_EncodeMatched(CRangeEnc *p, CLzmaProb *probs, UInt32 symbol, UInt32 matchByte) ++{ ++ UInt32 offs = 0x100; ++ symbol |= 0x100; ++ do ++ { ++ matchByte <<= 1; ++ RangeEnc_EncodeBit(p, probs + (offs + (matchByte & offs) + (symbol >> 8)), (symbol >> 7) & 1); ++ symbol <<= 1; ++ offs &= ~(matchByte ^ symbol); ++ } ++ while (symbol < 0x10000); ++} ++ ++void LzmaEnc_InitPriceTables(UInt32 *ProbPrices) ++{ ++ UInt32 i; ++ for (i = (1 << kNumMoveReducingBits) / 2; i < kBitModelTotal; i += (1 << kNumMoveReducingBits)) ++ { ++ const int kCyclesBits = kNumBitPriceShiftBits; ++ UInt32 w = i; ++ UInt32 bitCount = 0; ++ int j; ++ for (j = 0; j < kCyclesBits; j++) ++ { ++ w = w * w; ++ bitCount <<= 1; ++ while (w >= ((UInt32)1 << 16)) ++ { ++ w >>= 1; ++ bitCount++; ++ } ++ } ++ ProbPrices[i >> kNumMoveReducingBits] = ((kNumBitModelTotalBits << kCyclesBits) - 15 - bitCount); ++ } ++} ++ ++ ++#define GET_PRICE(prob, symbol) \ ++ p->ProbPrices[((prob) ^ (((-(int)(symbol))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits]; ++ ++#define GET_PRICEa(prob, symbol) \ ++ ProbPrices[((prob) ^ ((-((int)(symbol))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits]; ++ ++#define GET_PRICE_0(prob) p->ProbPrices[(prob) >> kNumMoveReducingBits] ++#define GET_PRICE_1(prob) p->ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits] ++ ++#define GET_PRICE_0a(prob) ProbPrices[(prob) >> kNumMoveReducingBits] ++#define GET_PRICE_1a(prob) ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits] ++ ++static UInt32 LitEnc_GetPrice(const CLzmaProb *probs, UInt32 symbol, UInt32 *ProbPrices) ++{ ++ UInt32 price = 0; ++ symbol |= 0x100; ++ do ++ { ++ price += GET_PRICEa(probs[symbol >> 8], (symbol >> 7) & 1); ++ symbol <<= 1; ++ } ++ while (symbol < 0x10000); ++ return price; ++} ++ ++static UInt32 LitEnc_GetPriceMatched(const CLzmaProb *probs, UInt32 symbol, UInt32 matchByte, UInt32 *ProbPrices) ++{ ++ UInt32 price = 0; ++ UInt32 offs = 0x100; ++ symbol |= 0x100; ++ do ++ { ++ matchByte <<= 1; ++ price += GET_PRICEa(probs[offs + (matchByte & offs) + (symbol >> 8)], (symbol >> 7) & 1); ++ symbol <<= 1; ++ offs &= ~(matchByte ^ symbol); ++ } ++ while (symbol < 0x10000); ++ return price; ++} ++ ++ ++static void RcTree_Encode(CRangeEnc *rc, CLzmaProb *probs, int numBitLevels, UInt32 symbol) ++{ ++ UInt32 m = 1; ++ int i; ++ for (i = numBitLevels; i != 0;) ++ { ++ UInt32 bit; ++ i--; ++ bit = (symbol >> i) & 1; ++ RangeEnc_EncodeBit(rc, probs + m, bit); ++ m = (m << 1) | bit; ++ } ++} ++ ++static void RcTree_ReverseEncode(CRangeEnc *rc, CLzmaProb *probs, int numBitLevels, UInt32 symbol) ++{ ++ UInt32 m = 1; ++ int i; ++ for (i = 0; i < numBitLevels; i++) ++ { ++ UInt32 bit = symbol & 1; ++ RangeEnc_EncodeBit(rc, probs + m, bit); ++ m = (m << 1) | bit; ++ symbol >>= 1; ++ } ++} ++ ++static UInt32 RcTree_GetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, UInt32 *ProbPrices) ++{ ++ UInt32 price = 0; ++ symbol |= (1 << numBitLevels); ++ while (symbol != 1) ++ { ++ price += GET_PRICEa(probs[symbol >> 1], symbol & 1); ++ symbol >>= 1; ++ } ++ return price; ++} ++ ++static UInt32 RcTree_ReverseGetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, UInt32 *ProbPrices) ++{ ++ UInt32 price = 0; ++ UInt32 m = 1; ++ int i; ++ for (i = numBitLevels; i != 0; i--) ++ { ++ UInt32 bit = symbol & 1; ++ symbol >>= 1; ++ price += GET_PRICEa(probs[m], bit); ++ m = (m << 1) | bit; ++ } ++ return price; ++} ++ ++ ++static void LenEnc_Init(CLenEnc *p) ++{ ++ unsigned i; ++ p->choice = p->choice2 = kProbInitValue; ++ for (i = 0; i < (LZMA_NUM_PB_STATES_MAX << kLenNumLowBits); i++) ++ p->low[i] = kProbInitValue; ++ for (i = 0; i < (LZMA_NUM_PB_STATES_MAX << kLenNumMidBits); i++) ++ p->mid[i] = kProbInitValue; ++ for (i = 0; i < kLenNumHighSymbols; i++) ++ p->high[i] = kProbInitValue; ++} ++ ++static void LenEnc_Encode(CLenEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 posState) ++{ ++ if (symbol < kLenNumLowSymbols) ++ { ++ RangeEnc_EncodeBit(rc, &p->choice, 0); ++ RcTree_Encode(rc, p->low + (posState << kLenNumLowBits), kLenNumLowBits, symbol); ++ } ++ else ++ { ++ RangeEnc_EncodeBit(rc, &p->choice, 1); ++ if (symbol < kLenNumLowSymbols + kLenNumMidSymbols) ++ { ++ RangeEnc_EncodeBit(rc, &p->choice2, 0); ++ RcTree_Encode(rc, p->mid + (posState << kLenNumMidBits), kLenNumMidBits, symbol - kLenNumLowSymbols); ++ } ++ else ++ { ++ RangeEnc_EncodeBit(rc, &p->choice2, 1); ++ RcTree_Encode(rc, p->high, kLenNumHighBits, symbol - kLenNumLowSymbols - kLenNumMidSymbols); ++ } ++ } ++} ++ ++static void LenEnc_SetPrices(CLenEnc *p, UInt32 posState, UInt32 numSymbols, UInt32 *prices, UInt32 *ProbPrices) ++{ ++ UInt32 a0 = GET_PRICE_0a(p->choice); ++ UInt32 a1 = GET_PRICE_1a(p->choice); ++ UInt32 b0 = a1 + GET_PRICE_0a(p->choice2); ++ UInt32 b1 = a1 + GET_PRICE_1a(p->choice2); ++ UInt32 i = 0; ++ for (i = 0; i < kLenNumLowSymbols; i++) ++ { ++ if (i >= numSymbols) ++ return; ++ prices[i] = a0 + RcTree_GetPrice(p->low + (posState << kLenNumLowBits), kLenNumLowBits, i, ProbPrices); ++ } ++ for (; i < kLenNumLowSymbols + kLenNumMidSymbols; i++) ++ { ++ if (i >= numSymbols) ++ return; ++ prices[i] = b0 + RcTree_GetPrice(p->mid + (posState << kLenNumMidBits), kLenNumMidBits, i - kLenNumLowSymbols, ProbPrices); ++ } ++ for (; i < numSymbols; i++) ++ prices[i] = b1 + RcTree_GetPrice(p->high, kLenNumHighBits, i - kLenNumLowSymbols - kLenNumMidSymbols, ProbPrices); ++} ++ ++static void MY_FAST_CALL LenPriceEnc_UpdateTable(CLenPriceEnc *p, UInt32 posState, UInt32 *ProbPrices) ++{ ++ LenEnc_SetPrices(&p->p, posState, p->tableSize, p->prices[posState], ProbPrices); ++ p->counters[posState] = p->tableSize; ++} ++ ++static void LenPriceEnc_UpdateTables(CLenPriceEnc *p, UInt32 numPosStates, UInt32 *ProbPrices) ++{ ++ UInt32 posState; ++ for (posState = 0; posState < numPosStates; posState++) ++ LenPriceEnc_UpdateTable(p, posState, ProbPrices); ++} ++ ++static void LenEnc_Encode2(CLenPriceEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 posState, Bool updatePrice, UInt32 *ProbPrices) ++{ ++ LenEnc_Encode(&p->p, rc, symbol, posState); ++ if (updatePrice) ++ if (--p->counters[posState] == 0) ++ LenPriceEnc_UpdateTable(p, posState, ProbPrices); ++} ++ ++ ++ ++ ++static void MovePos(CLzmaEnc *p, UInt32 num) ++{ ++ #ifdef SHOW_STAT ++ ttt += num; ++ printf("\n MovePos %d", num); ++ #endif ++ if (num != 0) ++ { ++ p->additionalOffset += num; ++ p->matchFinder.Skip(p->matchFinderObj, num); ++ } ++} ++ ++static UInt32 ReadMatchDistances(CLzmaEnc *p, UInt32 *numDistancePairsRes) ++{ ++ UInt32 lenRes = 0, numPairs; ++ p->numAvail = p->matchFinder.GetNumAvailableBytes(p->matchFinderObj); ++ numPairs = p->matchFinder.GetMatches(p->matchFinderObj, p->matches); ++ #ifdef SHOW_STAT ++ printf("\n i = %d numPairs = %d ", ttt, numPairs / 2); ++ ttt++; ++ { ++ UInt32 i; ++ for (i = 0; i < numPairs; i += 2) ++ printf("%2d %6d | ", p->matches[i], p->matches[i + 1]); ++ } ++ #endif ++ if (numPairs > 0) ++ { ++ lenRes = p->matches[numPairs - 2]; ++ if (lenRes == p->numFastBytes) ++ { ++ const Byte *pby = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; ++ UInt32 distance = p->matches[numPairs - 1] + 1; ++ UInt32 numAvail = p->numAvail; ++ if (numAvail > LZMA_MATCH_LEN_MAX) ++ numAvail = LZMA_MATCH_LEN_MAX; ++ { ++ const Byte *pby2 = pby - distance; ++ for (; lenRes < numAvail && pby[lenRes] == pby2[lenRes]; lenRes++); ++ } ++ } ++ } ++ p->additionalOffset++; ++ *numDistancePairsRes = numPairs; ++ return lenRes; ++} ++ ++ ++#define MakeAsChar(p) (p)->backPrev = (UInt32)(-1); (p)->prev1IsChar = False; ++#define MakeAsShortRep(p) (p)->backPrev = 0; (p)->prev1IsChar = False; ++#define IsShortRep(p) ((p)->backPrev == 0) ++ ++static UInt32 GetRepLen1Price(CLzmaEnc *p, UInt32 state, UInt32 posState) ++{ ++ return ++ GET_PRICE_0(p->isRepG0[state]) + ++ GET_PRICE_0(p->isRep0Long[state][posState]); ++} ++ ++static UInt32 GetPureRepPrice(CLzmaEnc *p, UInt32 repIndex, UInt32 state, UInt32 posState) ++{ ++ UInt32 price; ++ if (repIndex == 0) ++ { ++ price = GET_PRICE_0(p->isRepG0[state]); ++ price += GET_PRICE_1(p->isRep0Long[state][posState]); ++ } ++ else ++ { ++ price = GET_PRICE_1(p->isRepG0[state]); ++ if (repIndex == 1) ++ price += GET_PRICE_0(p->isRepG1[state]); ++ else ++ { ++ price += GET_PRICE_1(p->isRepG1[state]); ++ price += GET_PRICE(p->isRepG2[state], repIndex - 2); ++ } ++ } ++ return price; ++} ++ ++static UInt32 GetRepPrice(CLzmaEnc *p, UInt32 repIndex, UInt32 len, UInt32 state, UInt32 posState) ++{ ++ return p->repLenEnc.prices[posState][len - LZMA_MATCH_LEN_MIN] + ++ GetPureRepPrice(p, repIndex, state, posState); ++} ++ ++static UInt32 Backward(CLzmaEnc *p, UInt32 *backRes, UInt32 cur) ++{ ++ UInt32 posMem = p->opt[cur].posPrev; ++ UInt32 backMem = p->opt[cur].backPrev; ++ p->optimumEndIndex = cur; ++ do ++ { ++ if (p->opt[cur].prev1IsChar) ++ { ++ MakeAsChar(&p->opt[posMem]) ++ p->opt[posMem].posPrev = posMem - 1; ++ if (p->opt[cur].prev2) ++ { ++ p->opt[posMem - 1].prev1IsChar = False; ++ p->opt[posMem - 1].posPrev = p->opt[cur].posPrev2; ++ p->opt[posMem - 1].backPrev = p->opt[cur].backPrev2; ++ } ++ } ++ { ++ UInt32 posPrev = posMem; ++ UInt32 backCur = backMem; ++ ++ backMem = p->opt[posPrev].backPrev; ++ posMem = p->opt[posPrev].posPrev; ++ ++ p->opt[posPrev].backPrev = backCur; ++ p->opt[posPrev].posPrev = cur; ++ cur = posPrev; ++ } ++ } ++ while (cur != 0); ++ *backRes = p->opt[0].backPrev; ++ p->optimumCurrentIndex = p->opt[0].posPrev; ++ return p->optimumCurrentIndex; ++} ++ ++#define LIT_PROBS(pos, prevByte) (p->litProbs + ((((pos) & p->lpMask) << p->lc) + ((prevByte) >> (8 - p->lc))) * 0x300) ++ ++static UInt32 GetOptimum(CLzmaEnc *p, UInt32 position, UInt32 *backRes) ++{ ++ UInt32 numAvail, mainLen, numPairs, repMaxIndex, i, posState, lenEnd, len, cur; ++ UInt32 matchPrice, repMatchPrice, normalMatchPrice; ++ UInt32 reps[LZMA_NUM_REPS], repLens[LZMA_NUM_REPS]; ++ UInt32 *matches; ++ const Byte *data; ++ Byte curByte, matchByte; ++ if (p->optimumEndIndex != p->optimumCurrentIndex) ++ { ++ const COptimal *opt = &p->opt[p->optimumCurrentIndex]; ++ UInt32 lenRes = opt->posPrev - p->optimumCurrentIndex; ++ *backRes = opt->backPrev; ++ p->optimumCurrentIndex = opt->posPrev; ++ return lenRes; ++ } ++ p->optimumCurrentIndex = p->optimumEndIndex = 0; ++ ++ if (p->additionalOffset == 0) ++ mainLen = ReadMatchDistances(p, &numPairs); ++ else ++ { ++ mainLen = p->longestMatchLength; ++ numPairs = p->numPairs; ++ } ++ ++ numAvail = p->numAvail; ++ if (numAvail < 2) ++ { ++ *backRes = (UInt32)(-1); ++ return 1; ++ } ++ if (numAvail > LZMA_MATCH_LEN_MAX) ++ numAvail = LZMA_MATCH_LEN_MAX; ++ ++ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; ++ repMaxIndex = 0; ++ for (i = 0; i < LZMA_NUM_REPS; i++) ++ { ++ UInt32 lenTest; ++ const Byte *data2; ++ reps[i] = p->reps[i]; ++ data2 = data - (reps[i] + 1); ++ if (data[0] != data2[0] || data[1] != data2[1]) ++ { ++ repLens[i] = 0; ++ continue; ++ } ++ for (lenTest = 2; lenTest < numAvail && data[lenTest] == data2[lenTest]; lenTest++); ++ repLens[i] = lenTest; ++ if (lenTest > repLens[repMaxIndex]) ++ repMaxIndex = i; ++ } ++ if (repLens[repMaxIndex] >= p->numFastBytes) ++ { ++ UInt32 lenRes; ++ *backRes = repMaxIndex; ++ lenRes = repLens[repMaxIndex]; ++ MovePos(p, lenRes - 1); ++ return lenRes; ++ } ++ ++ matches = p->matches; ++ if (mainLen >= p->numFastBytes) ++ { ++ *backRes = matches[numPairs - 1] + LZMA_NUM_REPS; ++ MovePos(p, mainLen - 1); ++ return mainLen; ++ } ++ curByte = *data; ++ matchByte = *(data - (reps[0] + 1)); ++ ++ if (mainLen < 2 && curByte != matchByte && repLens[repMaxIndex] < 2) ++ { ++ *backRes = (UInt32)-1; ++ return 1; ++ } ++ ++ p->opt[0].state = (CState)p->state; ++ ++ posState = (position & p->pbMask); ++ ++ { ++ const CLzmaProb *probs = LIT_PROBS(position, *(data - 1)); ++ p->opt[1].price = GET_PRICE_0(p->isMatch[p->state][posState]) + ++ (!IsCharState(p->state) ? ++ LitEnc_GetPriceMatched(probs, curByte, matchByte, p->ProbPrices) : ++ LitEnc_GetPrice(probs, curByte, p->ProbPrices)); ++ } ++ ++ MakeAsChar(&p->opt[1]); ++ ++ matchPrice = GET_PRICE_1(p->isMatch[p->state][posState]); ++ repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[p->state]); ++ ++ if (matchByte == curByte) ++ { ++ UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(p, p->state, posState); ++ if (shortRepPrice < p->opt[1].price) ++ { ++ p->opt[1].price = shortRepPrice; ++ MakeAsShortRep(&p->opt[1]); ++ } ++ } ++ lenEnd = ((mainLen >= repLens[repMaxIndex]) ? mainLen : repLens[repMaxIndex]); ++ ++ if (lenEnd < 2) ++ { ++ *backRes = p->opt[1].backPrev; ++ return 1; ++ } ++ ++ p->opt[1].posPrev = 0; ++ for (i = 0; i < LZMA_NUM_REPS; i++) ++ p->opt[0].backs[i] = reps[i]; ++ ++ len = lenEnd; ++ do ++ p->opt[len--].price = kInfinityPrice; ++ while (len >= 2); ++ ++ for (i = 0; i < LZMA_NUM_REPS; i++) ++ { ++ UInt32 repLen = repLens[i]; ++ UInt32 price; ++ if (repLen < 2) ++ continue; ++ price = repMatchPrice + GetPureRepPrice(p, i, p->state, posState); ++ do ++ { ++ UInt32 curAndLenPrice = price + p->repLenEnc.prices[posState][repLen - 2]; ++ COptimal *opt = &p->opt[repLen]; ++ if (curAndLenPrice < opt->price) ++ { ++ opt->price = curAndLenPrice; ++ opt->posPrev = 0; ++ opt->backPrev = i; ++ opt->prev1IsChar = False; ++ } ++ } ++ while (--repLen >= 2); ++ } ++ ++ normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[p->state]); ++ ++ len = ((repLens[0] >= 2) ? repLens[0] + 1 : 2); ++ if (len <= mainLen) ++ { ++ UInt32 offs = 0; ++ while (len > matches[offs]) ++ offs += 2; ++ for (; ; len++) ++ { ++ COptimal *opt; ++ UInt32 distance = matches[offs + 1]; ++ ++ UInt32 curAndLenPrice = normalMatchPrice + p->lenEnc.prices[posState][len - LZMA_MATCH_LEN_MIN]; ++ UInt32 lenToPosState = GetLenToPosState(len); ++ if (distance < kNumFullDistances) ++ curAndLenPrice += p->distancesPrices[lenToPosState][distance]; ++ else ++ { ++ UInt32 slot; ++ GetPosSlot2(distance, slot); ++ curAndLenPrice += p->alignPrices[distance & kAlignMask] + p->posSlotPrices[lenToPosState][slot]; ++ } ++ opt = &p->opt[len]; ++ if (curAndLenPrice < opt->price) ++ { ++ opt->price = curAndLenPrice; ++ opt->posPrev = 0; ++ opt->backPrev = distance + LZMA_NUM_REPS; ++ opt->prev1IsChar = False; ++ } ++ if (len == matches[offs]) ++ { ++ offs += 2; ++ if (offs == numPairs) ++ break; ++ } ++ } ++ } ++ ++ cur = 0; ++ ++ #ifdef SHOW_STAT2 ++ if (position >= 0) ++ { ++ unsigned i; ++ printf("\n pos = %4X", position); ++ for (i = cur; i <= lenEnd; i++) ++ printf("\nprice[%4X] = %d", position - cur + i, p->opt[i].price); ++ } ++ #endif ++ ++ for (;;) ++ { ++ UInt32 numAvailFull, newLen, numPairs, posPrev, state, posState, startLen; ++ UInt32 curPrice, curAnd1Price, matchPrice, repMatchPrice; ++ Bool nextIsChar; ++ Byte curByte, matchByte; ++ const Byte *data; ++ COptimal *curOpt; ++ COptimal *nextOpt; ++ ++ cur++; ++ if (cur == lenEnd) ++ return Backward(p, backRes, cur); ++ ++ newLen = ReadMatchDistances(p, &numPairs); ++ if (newLen >= p->numFastBytes) ++ { ++ p->numPairs = numPairs; ++ p->longestMatchLength = newLen; ++ return Backward(p, backRes, cur); ++ } ++ position++; ++ curOpt = &p->opt[cur]; ++ posPrev = curOpt->posPrev; ++ if (curOpt->prev1IsChar) ++ { ++ posPrev--; ++ if (curOpt->prev2) ++ { ++ state = p->opt[curOpt->posPrev2].state; ++ if (curOpt->backPrev2 < LZMA_NUM_REPS) ++ state = kRepNextStates[state]; ++ else ++ state = kMatchNextStates[state]; ++ } ++ else ++ state = p->opt[posPrev].state; ++ state = kLiteralNextStates[state]; ++ } ++ else ++ state = p->opt[posPrev].state; ++ if (posPrev == cur - 1) ++ { ++ if (IsShortRep(curOpt)) ++ state = kShortRepNextStates[state]; ++ else ++ state = kLiteralNextStates[state]; ++ } ++ else ++ { ++ UInt32 pos; ++ const COptimal *prevOpt; ++ if (curOpt->prev1IsChar && curOpt->prev2) ++ { ++ posPrev = curOpt->posPrev2; ++ pos = curOpt->backPrev2; ++ state = kRepNextStates[state]; ++ } ++ else ++ { ++ pos = curOpt->backPrev; ++ if (pos < LZMA_NUM_REPS) ++ state = kRepNextStates[state]; ++ else ++ state = kMatchNextStates[state]; ++ } ++ prevOpt = &p->opt[posPrev]; ++ if (pos < LZMA_NUM_REPS) ++ { ++ UInt32 i; ++ reps[0] = prevOpt->backs[pos]; ++ for (i = 1; i <= pos; i++) ++ reps[i] = prevOpt->backs[i - 1]; ++ for (; i < LZMA_NUM_REPS; i++) ++ reps[i] = prevOpt->backs[i]; ++ } ++ else ++ { ++ UInt32 i; ++ reps[0] = (pos - LZMA_NUM_REPS); ++ for (i = 1; i < LZMA_NUM_REPS; i++) ++ reps[i] = prevOpt->backs[i - 1]; ++ } ++ } ++ curOpt->state = (CState)state; ++ ++ curOpt->backs[0] = reps[0]; ++ curOpt->backs[1] = reps[1]; ++ curOpt->backs[2] = reps[2]; ++ curOpt->backs[3] = reps[3]; ++ ++ curPrice = curOpt->price; ++ nextIsChar = False; ++ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; ++ curByte = *data; ++ matchByte = *(data - (reps[0] + 1)); ++ ++ posState = (position & p->pbMask); ++ ++ curAnd1Price = curPrice + GET_PRICE_0(p->isMatch[state][posState]); ++ { ++ const CLzmaProb *probs = LIT_PROBS(position, *(data - 1)); ++ curAnd1Price += ++ (!IsCharState(state) ? ++ LitEnc_GetPriceMatched(probs, curByte, matchByte, p->ProbPrices) : ++ LitEnc_GetPrice(probs, curByte, p->ProbPrices)); ++ } ++ ++ nextOpt = &p->opt[cur + 1]; ++ ++ if (curAnd1Price < nextOpt->price) ++ { ++ nextOpt->price = curAnd1Price; ++ nextOpt->posPrev = cur; ++ MakeAsChar(nextOpt); ++ nextIsChar = True; ++ } ++ ++ matchPrice = curPrice + GET_PRICE_1(p->isMatch[state][posState]); ++ repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[state]); ++ ++ if (matchByte == curByte && !(nextOpt->posPrev < cur && nextOpt->backPrev == 0)) ++ { ++ UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(p, state, posState); ++ if (shortRepPrice <= nextOpt->price) ++ { ++ nextOpt->price = shortRepPrice; ++ nextOpt->posPrev = cur; ++ MakeAsShortRep(nextOpt); ++ nextIsChar = True; ++ } ++ } ++ numAvailFull = p->numAvail; ++ { ++ UInt32 temp = kNumOpts - 1 - cur; ++ if (temp < numAvailFull) ++ numAvailFull = temp; ++ } ++ ++ if (numAvailFull < 2) ++ continue; ++ numAvail = (numAvailFull <= p->numFastBytes ? numAvailFull : p->numFastBytes); ++ ++ if (!nextIsChar && matchByte != curByte) /* speed optimization */ ++ { ++ /* try Literal + rep0 */ ++ UInt32 temp; ++ UInt32 lenTest2; ++ const Byte *data2 = data - (reps[0] + 1); ++ UInt32 limit = p->numFastBytes + 1; ++ if (limit > numAvailFull) ++ limit = numAvailFull; ++ ++ for (temp = 1; temp < limit && data[temp] == data2[temp]; temp++); ++ lenTest2 = temp - 1; ++ if (lenTest2 >= 2) ++ { ++ UInt32 state2 = kLiteralNextStates[state]; ++ UInt32 posStateNext = (position + 1) & p->pbMask; ++ UInt32 nextRepMatchPrice = curAnd1Price + ++ GET_PRICE_1(p->isMatch[state2][posStateNext]) + ++ GET_PRICE_1(p->isRep[state2]); ++ /* for (; lenTest2 >= 2; lenTest2--) */ ++ { ++ UInt32 curAndLenPrice; ++ COptimal *opt; ++ UInt32 offset = cur + 1 + lenTest2; ++ while (lenEnd < offset) ++ p->opt[++lenEnd].price = kInfinityPrice; ++ curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext); ++ opt = &p->opt[offset]; ++ if (curAndLenPrice < opt->price) ++ { ++ opt->price = curAndLenPrice; ++ opt->posPrev = cur + 1; ++ opt->backPrev = 0; ++ opt->prev1IsChar = True; ++ opt->prev2 = False; ++ } ++ } ++ } ++ } ++ ++ startLen = 2; /* speed optimization */ ++ { ++ UInt32 repIndex; ++ for (repIndex = 0; repIndex < LZMA_NUM_REPS; repIndex++) ++ { ++ UInt32 lenTest; ++ UInt32 lenTestTemp; ++ UInt32 price; ++ const Byte *data2 = data - (reps[repIndex] + 1); ++ if (data[0] != data2[0] || data[1] != data2[1]) ++ continue; ++ for (lenTest = 2; lenTest < numAvail && data[lenTest] == data2[lenTest]; lenTest++); ++ while (lenEnd < cur + lenTest) ++ p->opt[++lenEnd].price = kInfinityPrice; ++ lenTestTemp = lenTest; ++ price = repMatchPrice + GetPureRepPrice(p, repIndex, state, posState); ++ do ++ { ++ UInt32 curAndLenPrice = price + p->repLenEnc.prices[posState][lenTest - 2]; ++ COptimal *opt = &p->opt[cur + lenTest]; ++ if (curAndLenPrice < opt->price) ++ { ++ opt->price = curAndLenPrice; ++ opt->posPrev = cur; ++ opt->backPrev = repIndex; ++ opt->prev1IsChar = False; ++ } ++ } ++ while (--lenTest >= 2); ++ lenTest = lenTestTemp; ++ ++ if (repIndex == 0) ++ startLen = lenTest + 1; ++ ++ /* if (_maxMode) */ ++ { ++ UInt32 lenTest2 = lenTest + 1; ++ UInt32 limit = lenTest2 + p->numFastBytes; ++ UInt32 nextRepMatchPrice; ++ if (limit > numAvailFull) ++ limit = numAvailFull; ++ for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++); ++ lenTest2 -= lenTest + 1; ++ if (lenTest2 >= 2) ++ { ++ UInt32 state2 = kRepNextStates[state]; ++ UInt32 posStateNext = (position + lenTest) & p->pbMask; ++ UInt32 curAndLenCharPrice = ++ price + p->repLenEnc.prices[posState][lenTest - 2] + ++ GET_PRICE_0(p->isMatch[state2][posStateNext]) + ++ LitEnc_GetPriceMatched(LIT_PROBS(position + lenTest, data[lenTest - 1]), ++ data[lenTest], data2[lenTest], p->ProbPrices); ++ state2 = kLiteralNextStates[state2]; ++ posStateNext = (position + lenTest + 1) & p->pbMask; ++ nextRepMatchPrice = curAndLenCharPrice + ++ GET_PRICE_1(p->isMatch[state2][posStateNext]) + ++ GET_PRICE_1(p->isRep[state2]); ++ ++ /* for (; lenTest2 >= 2; lenTest2--) */ ++ { ++ UInt32 curAndLenPrice; ++ COptimal *opt; ++ UInt32 offset = cur + lenTest + 1 + lenTest2; ++ while (lenEnd < offset) ++ p->opt[++lenEnd].price = kInfinityPrice; ++ curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext); ++ opt = &p->opt[offset]; ++ if (curAndLenPrice < opt->price) ++ { ++ opt->price = curAndLenPrice; ++ opt->posPrev = cur + lenTest + 1; ++ opt->backPrev = 0; ++ opt->prev1IsChar = True; ++ opt->prev2 = True; ++ opt->posPrev2 = cur; ++ opt->backPrev2 = repIndex; ++ } ++ } ++ } ++ } ++ } ++ } ++ /* for (UInt32 lenTest = 2; lenTest <= newLen; lenTest++) */ ++ if (newLen > numAvail) ++ { ++ newLen = numAvail; ++ for (numPairs = 0; newLen > matches[numPairs]; numPairs += 2); ++ matches[numPairs] = newLen; ++ numPairs += 2; ++ } ++ if (newLen >= startLen) ++ { ++ UInt32 normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[state]); ++ UInt32 offs, curBack, posSlot; ++ UInt32 lenTest; ++ while (lenEnd < cur + newLen) ++ p->opt[++lenEnd].price = kInfinityPrice; ++ ++ offs = 0; ++ while (startLen > matches[offs]) ++ offs += 2; ++ curBack = matches[offs + 1]; ++ GetPosSlot2(curBack, posSlot); ++ for (lenTest = /*2*/ startLen; ; lenTest++) ++ { ++ UInt32 curAndLenPrice = normalMatchPrice + p->lenEnc.prices[posState][lenTest - LZMA_MATCH_LEN_MIN]; ++ UInt32 lenToPosState = GetLenToPosState(lenTest); ++ COptimal *opt; ++ if (curBack < kNumFullDistances) ++ curAndLenPrice += p->distancesPrices[lenToPosState][curBack]; ++ else ++ curAndLenPrice += p->posSlotPrices[lenToPosState][posSlot] + p->alignPrices[curBack & kAlignMask]; ++ ++ opt = &p->opt[cur + lenTest]; ++ if (curAndLenPrice < opt->price) ++ { ++ opt->price = curAndLenPrice; ++ opt->posPrev = cur; ++ opt->backPrev = curBack + LZMA_NUM_REPS; ++ opt->prev1IsChar = False; ++ } ++ ++ if (/*_maxMode && */lenTest == matches[offs]) ++ { ++ /* Try Match + Literal + Rep0 */ ++ const Byte *data2 = data - (curBack + 1); ++ UInt32 lenTest2 = lenTest + 1; ++ UInt32 limit = lenTest2 + p->numFastBytes; ++ UInt32 nextRepMatchPrice; ++ if (limit > numAvailFull) ++ limit = numAvailFull; ++ for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++); ++ lenTest2 -= lenTest + 1; ++ if (lenTest2 >= 2) ++ { ++ UInt32 state2 = kMatchNextStates[state]; ++ UInt32 posStateNext = (position + lenTest) & p->pbMask; ++ UInt32 curAndLenCharPrice = curAndLenPrice + ++ GET_PRICE_0(p->isMatch[state2][posStateNext]) + ++ LitEnc_GetPriceMatched(LIT_PROBS(position + lenTest, data[lenTest - 1]), ++ data[lenTest], data2[lenTest], p->ProbPrices); ++ state2 = kLiteralNextStates[state2]; ++ posStateNext = (posStateNext + 1) & p->pbMask; ++ nextRepMatchPrice = curAndLenCharPrice + ++ GET_PRICE_1(p->isMatch[state2][posStateNext]) + ++ GET_PRICE_1(p->isRep[state2]); ++ ++ /* for (; lenTest2 >= 2; lenTest2--) */ ++ { ++ UInt32 offset = cur + lenTest + 1 + lenTest2; ++ UInt32 curAndLenPrice; ++ COptimal *opt; ++ while (lenEnd < offset) ++ p->opt[++lenEnd].price = kInfinityPrice; ++ curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext); ++ opt = &p->opt[offset]; ++ if (curAndLenPrice < opt->price) ++ { ++ opt->price = curAndLenPrice; ++ opt->posPrev = cur + lenTest + 1; ++ opt->backPrev = 0; ++ opt->prev1IsChar = True; ++ opt->prev2 = True; ++ opt->posPrev2 = cur; ++ opt->backPrev2 = curBack + LZMA_NUM_REPS; ++ } ++ } ++ } ++ offs += 2; ++ if (offs == numPairs) ++ break; ++ curBack = matches[offs + 1]; ++ if (curBack >= kNumFullDistances) ++ GetPosSlot2(curBack, posSlot); ++ } ++ } ++ } ++ } ++} ++ ++#define ChangePair(smallDist, bigDist) (((bigDist) >> 7) > (smallDist)) ++ ++static UInt32 GetOptimumFast(CLzmaEnc *p, UInt32 *backRes) ++{ ++ UInt32 numAvail, mainLen, mainDist, numPairs, repIndex, repLen, i; ++ const Byte *data; ++ const UInt32 *matches; ++ ++ if (p->additionalOffset == 0) ++ mainLen = ReadMatchDistances(p, &numPairs); ++ else ++ { ++ mainLen = p->longestMatchLength; ++ numPairs = p->numPairs; ++ } ++ ++ numAvail = p->numAvail; ++ *backRes = (UInt32)-1; ++ if (numAvail < 2) ++ return 1; ++ if (numAvail > LZMA_MATCH_LEN_MAX) ++ numAvail = LZMA_MATCH_LEN_MAX; ++ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; ++ ++ repLen = repIndex = 0; ++ for (i = 0; i < LZMA_NUM_REPS; i++) ++ { ++ UInt32 len; ++ const Byte *data2 = data - (p->reps[i] + 1); ++ if (data[0] != data2[0] || data[1] != data2[1]) ++ continue; ++ for (len = 2; len < numAvail && data[len] == data2[len]; len++); ++ if (len >= p->numFastBytes) ++ { ++ *backRes = i; ++ MovePos(p, len - 1); ++ return len; ++ } ++ if (len > repLen) ++ { ++ repIndex = i; ++ repLen = len; ++ } ++ } ++ ++ matches = p->matches; ++ if (mainLen >= p->numFastBytes) ++ { ++ *backRes = matches[numPairs - 1] + LZMA_NUM_REPS; ++ MovePos(p, mainLen - 1); ++ return mainLen; ++ } ++ ++ mainDist = 0; /* for GCC */ ++ if (mainLen >= 2) ++ { ++ mainDist = matches[numPairs - 1]; ++ while (numPairs > 2 && mainLen == matches[numPairs - 4] + 1) ++ { ++ if (!ChangePair(matches[numPairs - 3], mainDist)) ++ break; ++ numPairs -= 2; ++ mainLen = matches[numPairs - 2]; ++ mainDist = matches[numPairs - 1]; ++ } ++ if (mainLen == 2 && mainDist >= 0x80) ++ mainLen = 1; ++ } ++ ++ if (repLen >= 2 && ( ++ (repLen + 1 >= mainLen) || ++ (repLen + 2 >= mainLen && mainDist >= (1 << 9)) || ++ (repLen + 3 >= mainLen && mainDist >= (1 << 15)))) ++ { ++ *backRes = repIndex; ++ MovePos(p, repLen - 1); ++ return repLen; ++ } ++ ++ if (mainLen < 2 || numAvail <= 2) ++ return 1; ++ ++ p->longestMatchLength = ReadMatchDistances(p, &p->numPairs); ++ if (p->longestMatchLength >= 2) ++ { ++ UInt32 newDistance = matches[p->numPairs - 1]; ++ if ((p->longestMatchLength >= mainLen && newDistance < mainDist) || ++ (p->longestMatchLength == mainLen + 1 && !ChangePair(mainDist, newDistance)) || ++ (p->longestMatchLength > mainLen + 1) || ++ (p->longestMatchLength + 1 >= mainLen && mainLen >= 3 && ChangePair(newDistance, mainDist))) ++ return 1; ++ } ++ ++ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; ++ for (i = 0; i < LZMA_NUM_REPS; i++) ++ { ++ UInt32 len, limit; ++ const Byte *data2 = data - (p->reps[i] + 1); ++ if (data[0] != data2[0] || data[1] != data2[1]) ++ continue; ++ limit = mainLen - 1; ++ for (len = 2; len < limit && data[len] == data2[len]; len++); ++ if (len >= limit) ++ return 1; ++ } ++ *backRes = mainDist + LZMA_NUM_REPS; ++ MovePos(p, mainLen - 2); ++ return mainLen; ++} ++ ++static void WriteEndMarker(CLzmaEnc *p, UInt32 posState) ++{ ++ UInt32 len; ++ RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 1); ++ RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 0); ++ p->state = kMatchNextStates[p->state]; ++ len = LZMA_MATCH_LEN_MIN; ++ LenEnc_Encode2(&p->lenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices); ++ RcTree_Encode(&p->rc, p->posSlotEncoder[GetLenToPosState(len)], kNumPosSlotBits, (1 << kNumPosSlotBits) - 1); ++ RangeEnc_EncodeDirectBits(&p->rc, (((UInt32)1 << 30) - 1) >> kNumAlignBits, 30 - kNumAlignBits); ++ RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, kAlignMask); ++} ++ ++static SRes CheckErrors(CLzmaEnc *p) ++{ ++ if (p->result != SZ_OK) ++ return p->result; ++ if (p->rc.res != SZ_OK) ++ p->result = SZ_ERROR_WRITE; ++ if (p->matchFinderBase.result != SZ_OK) ++ p->result = SZ_ERROR_READ; ++ if (p->result != SZ_OK) ++ p->finished = True; ++ return p->result; ++} ++ ++static SRes Flush(CLzmaEnc *p, UInt32 nowPos) ++{ ++ /* ReleaseMFStream(); */ ++ p->finished = True; ++ if (p->writeEndMark) ++ WriteEndMarker(p, nowPos & p->pbMask); ++ RangeEnc_FlushData(&p->rc); ++ RangeEnc_FlushStream(&p->rc); ++ return CheckErrors(p); ++} ++ ++static void FillAlignPrices(CLzmaEnc *p) ++{ ++ UInt32 i; ++ for (i = 0; i < kAlignTableSize; i++) ++ p->alignPrices[i] = RcTree_ReverseGetPrice(p->posAlignEncoder, kNumAlignBits, i, p->ProbPrices); ++ p->alignPriceCount = 0; ++} ++ ++static void FillDistancesPrices(CLzmaEnc *p) ++{ ++ UInt32 tempPrices[kNumFullDistances]; ++ UInt32 i, lenToPosState; ++ for (i = kStartPosModelIndex; i < kNumFullDistances; i++) ++ { ++ UInt32 posSlot = GetPosSlot1(i); ++ UInt32 footerBits = ((posSlot >> 1) - 1); ++ UInt32 base = ((2 | (posSlot & 1)) << footerBits); ++ tempPrices[i] = RcTree_ReverseGetPrice(p->posEncoders + base - posSlot - 1, footerBits, i - base, p->ProbPrices); ++ } ++ ++ for (lenToPosState = 0; lenToPosState < kNumLenToPosStates; lenToPosState++) ++ { ++ UInt32 posSlot; ++ const CLzmaProb *encoder = p->posSlotEncoder[lenToPosState]; ++ UInt32 *posSlotPrices = p->posSlotPrices[lenToPosState]; ++ for (posSlot = 0; posSlot < p->distTableSize; posSlot++) ++ posSlotPrices[posSlot] = RcTree_GetPrice(encoder, kNumPosSlotBits, posSlot, p->ProbPrices); ++ for (posSlot = kEndPosModelIndex; posSlot < p->distTableSize; posSlot++) ++ posSlotPrices[posSlot] += ((((posSlot >> 1) - 1) - kNumAlignBits) << kNumBitPriceShiftBits); ++ ++ { ++ UInt32 *distancesPrices = p->distancesPrices[lenToPosState]; ++ UInt32 i; ++ for (i = 0; i < kStartPosModelIndex; i++) ++ distancesPrices[i] = posSlotPrices[i]; ++ for (; i < kNumFullDistances; i++) ++ distancesPrices[i] = posSlotPrices[GetPosSlot1(i)] + tempPrices[i]; ++ } ++ } ++ p->matchPriceCount = 0; ++} ++ ++void LzmaEnc_Construct(CLzmaEnc *p) ++{ ++ RangeEnc_Construct(&p->rc); ++ MatchFinder_Construct(&p->matchFinderBase); ++ #ifndef _7ZIP_ST ++ MatchFinderMt_Construct(&p->matchFinderMt); ++ p->matchFinderMt.MatchFinder = &p->matchFinderBase; ++ #endif ++ ++ { ++ CLzmaEncProps props; ++ LzmaEncProps_Init(&props); ++ LzmaEnc_SetProps(p, &props); ++ } ++ ++ #ifndef LZMA_LOG_BSR ++ LzmaEnc_FastPosInit(p->g_FastPos); ++ #endif ++ ++ LzmaEnc_InitPriceTables(p->ProbPrices); ++ p->litProbs = 0; ++ p->saveState.litProbs = 0; ++} ++ ++CLzmaEncHandle LzmaEnc_Create(ISzAlloc *alloc) ++{ ++ void *p; ++ p = alloc->Alloc(alloc, sizeof(CLzmaEnc)); ++ if (p != 0) ++ LzmaEnc_Construct((CLzmaEnc *)p); ++ return p; ++} ++ ++void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAlloc *alloc) ++{ ++ alloc->Free(alloc, p->litProbs); ++ alloc->Free(alloc, p->saveState.litProbs); ++ p->litProbs = 0; ++ p->saveState.litProbs = 0; ++} ++ ++void LzmaEnc_Destruct(CLzmaEnc *p, ISzAlloc *alloc, ISzAlloc *allocBig) ++{ ++ #ifndef _7ZIP_ST ++ MatchFinderMt_Destruct(&p->matchFinderMt, allocBig); ++ #endif ++ MatchFinder_Free(&p->matchFinderBase, allocBig); ++ LzmaEnc_FreeLits(p, alloc); ++ RangeEnc_Free(&p->rc, alloc); ++} ++ ++void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAlloc *alloc, ISzAlloc *allocBig) ++{ ++ LzmaEnc_Destruct((CLzmaEnc *)p, alloc, allocBig); ++ alloc->Free(alloc, p); ++} ++ ++static SRes LzmaEnc_CodeOneBlock(CLzmaEnc *p, Bool useLimits, UInt32 maxPackSize, UInt32 maxUnpackSize) ++{ ++ UInt32 nowPos32, startPos32; ++ if (p->needInit) ++ { ++ p->matchFinder.Init(p->matchFinderObj); ++ p->needInit = 0; ++ } ++ ++ if (p->finished) ++ return p->result; ++ RINOK(CheckErrors(p)); ++ ++ nowPos32 = (UInt32)p->nowPos64; ++ startPos32 = nowPos32; ++ ++ if (p->nowPos64 == 0) ++ { ++ UInt32 numPairs; ++ Byte curByte; ++ if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0) ++ return Flush(p, nowPos32); ++ ReadMatchDistances(p, &numPairs); ++ RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][0], 0); ++ p->state = kLiteralNextStates[p->state]; ++ curByte = p->matchFinder.GetIndexByte(p->matchFinderObj, 0 - p->additionalOffset); ++ LitEnc_Encode(&p->rc, p->litProbs, curByte); ++ p->additionalOffset--; ++ nowPos32++; ++ } ++ ++ if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) != 0) ++ for (;;) ++ { ++ UInt32 pos, len, posState; ++ ++ if (p->fastMode) ++ len = GetOptimumFast(p, &pos); ++ else ++ len = GetOptimum(p, nowPos32, &pos); ++ ++ #ifdef SHOW_STAT2 ++ printf("\n pos = %4X, len = %d pos = %d", nowPos32, len, pos); ++ #endif ++ ++ posState = nowPos32 & p->pbMask; ++ if (len == 1 && pos == (UInt32)-1) ++ { ++ Byte curByte; ++ CLzmaProb *probs; ++ const Byte *data; ++ ++ RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 0); ++ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset; ++ curByte = *data; ++ probs = LIT_PROBS(nowPos32, *(data - 1)); ++ if (IsCharState(p->state)) ++ LitEnc_Encode(&p->rc, probs, curByte); ++ else ++ LitEnc_EncodeMatched(&p->rc, probs, curByte, *(data - p->reps[0] - 1)); ++ p->state = kLiteralNextStates[p->state]; ++ } ++ else ++ { ++ RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 1); ++ if (pos < LZMA_NUM_REPS) ++ { ++ RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 1); ++ if (pos == 0) ++ { ++ RangeEnc_EncodeBit(&p->rc, &p->isRepG0[p->state], 0); ++ RangeEnc_EncodeBit(&p->rc, &p->isRep0Long[p->state][posState], ((len == 1) ? 0 : 1)); ++ } ++ else ++ { ++ UInt32 distance = p->reps[pos]; ++ RangeEnc_EncodeBit(&p->rc, &p->isRepG0[p->state], 1); ++ if (pos == 1) ++ RangeEnc_EncodeBit(&p->rc, &p->isRepG1[p->state], 0); ++ else ++ { ++ RangeEnc_EncodeBit(&p->rc, &p->isRepG1[p->state], 1); ++ RangeEnc_EncodeBit(&p->rc, &p->isRepG2[p->state], pos - 2); ++ if (pos == 3) ++ p->reps[3] = p->reps[2]; ++ p->reps[2] = p->reps[1]; ++ } ++ p->reps[1] = p->reps[0]; ++ p->reps[0] = distance; ++ } ++ if (len == 1) ++ p->state = kShortRepNextStates[p->state]; ++ else ++ { ++ LenEnc_Encode2(&p->repLenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices); ++ p->state = kRepNextStates[p->state]; ++ } ++ } ++ else ++ { ++ UInt32 posSlot; ++ RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 0); ++ p->state = kMatchNextStates[p->state]; ++ LenEnc_Encode2(&p->lenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices); ++ pos -= LZMA_NUM_REPS; ++ GetPosSlot(pos, posSlot); ++ RcTree_Encode(&p->rc, p->posSlotEncoder[GetLenToPosState(len)], kNumPosSlotBits, posSlot); ++ ++ if (posSlot >= kStartPosModelIndex) ++ { ++ UInt32 footerBits = ((posSlot >> 1) - 1); ++ UInt32 base = ((2 | (posSlot & 1)) << footerBits); ++ UInt32 posReduced = pos - base; ++ ++ if (posSlot < kEndPosModelIndex) ++ RcTree_ReverseEncode(&p->rc, p->posEncoders + base - posSlot - 1, footerBits, posReduced); ++ else ++ { ++ RangeEnc_EncodeDirectBits(&p->rc, posReduced >> kNumAlignBits, footerBits - kNumAlignBits); ++ RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, posReduced & kAlignMask); ++ p->alignPriceCount++; ++ } ++ } ++ p->reps[3] = p->reps[2]; ++ p->reps[2] = p->reps[1]; ++ p->reps[1] = p->reps[0]; ++ p->reps[0] = pos; ++ p->matchPriceCount++; ++ } ++ } ++ p->additionalOffset -= len; ++ nowPos32 += len; ++ if (p->additionalOffset == 0) ++ { ++ UInt32 processed; ++ if (!p->fastMode) ++ { ++ if (p->matchPriceCount >= (1 << 7)) ++ FillDistancesPrices(p); ++ if (p->alignPriceCount >= kAlignTableSize) ++ FillAlignPrices(p); ++ } ++ if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0) ++ break; ++ processed = nowPos32 - startPos32; ++ if (useLimits) ++ { ++ if (processed + kNumOpts + 300 >= maxUnpackSize || ++ RangeEnc_GetProcessed(&p->rc) + kNumOpts * 2 >= maxPackSize) ++ break; ++ } ++ else if (processed >= (1 << 15)) ++ { ++ p->nowPos64 += nowPos32 - startPos32; ++ return CheckErrors(p); ++ } ++ } ++ } ++ p->nowPos64 += nowPos32 - startPos32; ++ return Flush(p, nowPos32); ++} ++ ++#define kBigHashDicLimit ((UInt32)1 << 24) ++ ++static SRes LzmaEnc_Alloc(CLzmaEnc *p, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig) ++{ ++ UInt32 beforeSize = kNumOpts; ++ Bool btMode; ++ if (!RangeEnc_Alloc(&p->rc, alloc)) ++ return SZ_ERROR_MEM; ++ btMode = (p->matchFinderBase.btMode != 0); ++ #ifndef _7ZIP_ST ++ p->mtMode = (p->multiThread && !p->fastMode && btMode); ++ #endif ++ ++ { ++ unsigned lclp = p->lc + p->lp; ++ if (p->litProbs == 0 || p->saveState.litProbs == 0 || p->lclp != lclp) ++ { ++ LzmaEnc_FreeLits(p, alloc); ++ p->litProbs = (CLzmaProb *)alloc->Alloc(alloc, (0x300 << lclp) * sizeof(CLzmaProb)); ++ p->saveState.litProbs = (CLzmaProb *)alloc->Alloc(alloc, (0x300 << lclp) * sizeof(CLzmaProb)); ++ if (p->litProbs == 0 || p->saveState.litProbs == 0) ++ { ++ LzmaEnc_FreeLits(p, alloc); ++ return SZ_ERROR_MEM; ++ } ++ p->lclp = lclp; ++ } ++ } ++ ++ p->matchFinderBase.bigHash = (p->dictSize > kBigHashDicLimit); ++ ++ if (beforeSize + p->dictSize < keepWindowSize) ++ beforeSize = keepWindowSize - p->dictSize; ++ ++ #ifndef _7ZIP_ST ++ if (p->mtMode) ++ { ++ RINOK(MatchFinderMt_Create(&p->matchFinderMt, p->dictSize, beforeSize, p->numFastBytes, LZMA_MATCH_LEN_MAX, allocBig)); ++ p->matchFinderObj = &p->matchFinderMt; ++ MatchFinderMt_CreateVTable(&p->matchFinderMt, &p->matchFinder); ++ } ++ else ++ #endif ++ { ++ if (!MatchFinder_Create(&p->matchFinderBase, p->dictSize, beforeSize, p->numFastBytes, LZMA_MATCH_LEN_MAX, allocBig)) ++ return SZ_ERROR_MEM; ++ p->matchFinderObj = &p->matchFinderBase; ++ MatchFinder_CreateVTable(&p->matchFinderBase, &p->matchFinder); ++ } ++ return SZ_OK; ++} ++ ++void LzmaEnc_Init(CLzmaEnc *p) ++{ ++ UInt32 i; ++ p->state = 0; ++ for (i = 0 ; i < LZMA_NUM_REPS; i++) ++ p->reps[i] = 0; ++ ++ RangeEnc_Init(&p->rc); ++ ++ ++ for (i = 0; i < kNumStates; i++) ++ { ++ UInt32 j; ++ for (j = 0; j < LZMA_NUM_PB_STATES_MAX; j++) ++ { ++ p->isMatch[i][j] = kProbInitValue; ++ p->isRep0Long[i][j] = kProbInitValue; ++ } ++ p->isRep[i] = kProbInitValue; ++ p->isRepG0[i] = kProbInitValue; ++ p->isRepG1[i] = kProbInitValue; ++ p->isRepG2[i] = kProbInitValue; ++ } ++ ++ { ++ UInt32 num = 0x300 << (p->lp + p->lc); ++ for (i = 0; i < num; i++) ++ p->litProbs[i] = kProbInitValue; ++ } ++ ++ { ++ for (i = 0; i < kNumLenToPosStates; i++) ++ { ++ CLzmaProb *probs = p->posSlotEncoder[i]; ++ UInt32 j; ++ for (j = 0; j < (1 << kNumPosSlotBits); j++) ++ probs[j] = kProbInitValue; ++ } ++ } ++ { ++ for (i = 0; i < kNumFullDistances - kEndPosModelIndex; i++) ++ p->posEncoders[i] = kProbInitValue; ++ } ++ ++ LenEnc_Init(&p->lenEnc.p); ++ LenEnc_Init(&p->repLenEnc.p); ++ ++ for (i = 0; i < (1 << kNumAlignBits); i++) ++ p->posAlignEncoder[i] = kProbInitValue; ++ ++ p->optimumEndIndex = 0; ++ p->optimumCurrentIndex = 0; ++ p->additionalOffset = 0; ++ ++ p->pbMask = (1 << p->pb) - 1; ++ p->lpMask = (1 << p->lp) - 1; ++} ++ ++void LzmaEnc_InitPrices(CLzmaEnc *p) ++{ ++ if (!p->fastMode) ++ { ++ FillDistancesPrices(p); ++ FillAlignPrices(p); ++ } ++ ++ p->lenEnc.tableSize = ++ p->repLenEnc.tableSize = ++ p->numFastBytes + 1 - LZMA_MATCH_LEN_MIN; ++ LenPriceEnc_UpdateTables(&p->lenEnc, 1 << p->pb, p->ProbPrices); ++ LenPriceEnc_UpdateTables(&p->repLenEnc, 1 << p->pb, p->ProbPrices); ++} ++ ++static SRes LzmaEnc_AllocAndInit(CLzmaEnc *p, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig) ++{ ++ UInt32 i; ++ for (i = 0; i < (UInt32)kDicLogSizeMaxCompress; i++) ++ if (p->dictSize <= ((UInt32)1 << i)) ++ break; ++ p->distTableSize = i * 2; ++ ++ p->finished = False; ++ p->result = SZ_OK; ++ RINOK(LzmaEnc_Alloc(p, keepWindowSize, alloc, allocBig)); ++ LzmaEnc_Init(p); ++ LzmaEnc_InitPrices(p); ++ p->nowPos64 = 0; ++ return SZ_OK; ++} ++ ++static SRes LzmaEnc_Prepare(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ++ ISzAlloc *alloc, ISzAlloc *allocBig) ++{ ++ CLzmaEnc *p = (CLzmaEnc *)pp; ++ p->matchFinderBase.stream = inStream; ++ p->needInit = 1; ++ p->rc.outStream = outStream; ++ return LzmaEnc_AllocAndInit(p, 0, alloc, allocBig); ++} ++ ++SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle pp, ++ ISeqInStream *inStream, UInt32 keepWindowSize, ++ ISzAlloc *alloc, ISzAlloc *allocBig) ++{ ++ CLzmaEnc *p = (CLzmaEnc *)pp; ++ p->matchFinderBase.stream = inStream; ++ p->needInit = 1; ++ return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig); ++} ++ ++static void LzmaEnc_SetInputBuf(CLzmaEnc *p, const Byte *src, SizeT srcLen) ++{ ++ p->matchFinderBase.directInput = 1; ++ p->matchFinderBase.bufferBase = (Byte *)src; ++ p->matchFinderBase.directInputRem = srcLen; ++} ++ ++SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen, ++ UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig) ++{ ++ CLzmaEnc *p = (CLzmaEnc *)pp; ++ LzmaEnc_SetInputBuf(p, src, srcLen); ++ p->needInit = 1; ++ ++ return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig); ++} ++ ++void LzmaEnc_Finish(CLzmaEncHandle pp) ++{ ++ #ifndef _7ZIP_ST ++ CLzmaEnc *p = (CLzmaEnc *)pp; ++ if (p->mtMode) ++ MatchFinderMt_ReleaseStream(&p->matchFinderMt); ++ #else ++ pp = pp; ++ #endif ++} ++ ++typedef struct ++{ ++ ISeqOutStream funcTable; ++ Byte *data; ++ SizeT rem; ++ Bool overflow; ++} CSeqOutStreamBuf; ++ ++static size_t MyWrite(void *pp, const void *data, size_t size) ++{ ++ CSeqOutStreamBuf *p = (CSeqOutStreamBuf *)pp; ++ if (p->rem < size) ++ { ++ size = p->rem; ++ p->overflow = True; ++ } ++ memcpy(p->data, data, size); ++ p->rem -= size; ++ p->data += size; ++ return size; ++} ++ ++ ++UInt32 LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle pp) ++{ ++ const CLzmaEnc *p = (CLzmaEnc *)pp; ++ return p->matchFinder.GetNumAvailableBytes(p->matchFinderObj); ++} ++ ++const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp) ++{ ++ const CLzmaEnc *p = (CLzmaEnc *)pp; ++ return p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset; ++} ++ ++SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, Bool reInit, ++ Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize) ++{ ++ CLzmaEnc *p = (CLzmaEnc *)pp; ++ UInt64 nowPos64; ++ SRes res; ++ CSeqOutStreamBuf outStream; ++ ++ outStream.funcTable.Write = MyWrite; ++ outStream.data = dest; ++ outStream.rem = *destLen; ++ outStream.overflow = False; ++ ++ p->writeEndMark = False; ++ p->finished = False; ++ p->result = SZ_OK; ++ ++ if (reInit) ++ LzmaEnc_Init(p); ++ LzmaEnc_InitPrices(p); ++ nowPos64 = p->nowPos64; ++ RangeEnc_Init(&p->rc); ++ p->rc.outStream = &outStream.funcTable; ++ ++ res = LzmaEnc_CodeOneBlock(p, True, desiredPackSize, *unpackSize); ++ ++ *unpackSize = (UInt32)(p->nowPos64 - nowPos64); ++ *destLen -= outStream.rem; ++ if (outStream.overflow) ++ return SZ_ERROR_OUTPUT_EOF; ++ ++ return res; ++} ++ ++static SRes LzmaEnc_Encode2(CLzmaEnc *p, ICompressProgress *progress) ++{ ++ SRes res = SZ_OK; ++ ++ #ifndef _7ZIP_ST ++ Byte allocaDummy[0x300]; ++ int i = 0; ++ for (i = 0; i < 16; i++) ++ allocaDummy[i] = (Byte)i; ++ #endif ++ ++ for (;;) ++ { ++ res = LzmaEnc_CodeOneBlock(p, False, 0, 0); ++ if (res != SZ_OK || p->finished != 0) ++ break; ++ if (progress != 0) ++ { ++ res = progress->Progress(progress, p->nowPos64, RangeEnc_GetProcessed(&p->rc)); ++ if (res != SZ_OK) ++ { ++ res = SZ_ERROR_PROGRESS; ++ break; ++ } ++ } ++ } ++ LzmaEnc_Finish(p); ++ return res; ++} ++ ++SRes LzmaEnc_Encode(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress, ++ ISzAlloc *alloc, ISzAlloc *allocBig) ++{ ++ RINOK(LzmaEnc_Prepare(pp, outStream, inStream, alloc, allocBig)); ++ return LzmaEnc_Encode2((CLzmaEnc *)pp, progress); ++} ++ ++SRes LzmaEnc_WriteProperties(CLzmaEncHandle pp, Byte *props, SizeT *size) ++{ ++ CLzmaEnc *p = (CLzmaEnc *)pp; ++ int i; ++ UInt32 dictSize = p->dictSize; ++ if (*size < LZMA_PROPS_SIZE) ++ return SZ_ERROR_PARAM; ++ *size = LZMA_PROPS_SIZE; ++ props[0] = (Byte)((p->pb * 5 + p->lp) * 9 + p->lc); ++ ++ for (i = 11; i <= 30; i++) ++ { ++ if (dictSize <= ((UInt32)2 << i)) ++ { ++ dictSize = (2 << i); ++ break; ++ } ++ if (dictSize <= ((UInt32)3 << i)) ++ { ++ dictSize = (3 << i); ++ break; ++ } ++ } ++ ++ for (i = 0; i < 4; i++) ++ props[1 + i] = (Byte)(dictSize >> (8 * i)); ++ return SZ_OK; ++} ++ ++SRes LzmaEnc_MemEncode(CLzmaEncHandle pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, ++ int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig) ++{ ++ SRes res; ++ CLzmaEnc *p = (CLzmaEnc *)pp; ++ ++ CSeqOutStreamBuf outStream; ++ ++ LzmaEnc_SetInputBuf(p, src, srcLen); ++ ++ outStream.funcTable.Write = MyWrite; ++ outStream.data = dest; ++ outStream.rem = *destLen; ++ outStream.overflow = False; ++ ++ p->writeEndMark = writeEndMark; ++ ++ p->rc.outStream = &outStream.funcTable; ++ res = LzmaEnc_MemPrepare(pp, src, srcLen, 0, alloc, allocBig); ++ if (res == SZ_OK) ++ res = LzmaEnc_Encode2(p, progress); ++ ++ *destLen -= outStream.rem; ++ if (outStream.overflow) ++ return SZ_ERROR_OUTPUT_EOF; ++ return res; ++} ++ ++SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, ++ const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark, ++ ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig) ++{ ++ CLzmaEnc *p = (CLzmaEnc *)LzmaEnc_Create(alloc); ++ SRes res; ++ if (p == 0) ++ return SZ_ERROR_MEM; ++ ++ res = LzmaEnc_SetProps(p, props); ++ if (res == SZ_OK) ++ { ++ res = LzmaEnc_WriteProperties(p, propsEncoded, propsSize); ++ if (res == SZ_OK) ++ res = LzmaEnc_MemEncode(p, dest, destLen, src, srcLen, ++ writeEndMark, progress, alloc, allocBig); ++ } ++ ++ LzmaEnc_Destroy(p, alloc, allocBig); ++ return res; ++} +--- /dev/null ++++ b/lib/lzma/Makefile +@@ -0,0 +1,7 @@ ++lzma_compress-objs := LzFind.o LzmaEnc.o ++lzma_decompress-objs := LzmaDec.o ++ ++obj-$(CONFIG_LZMA_COMPRESS) += lzma_compress.o ++obj-$(CONFIG_LZMA_DECOMPRESS) += lzma_decompress.o ++ ++EXTRA_CFLAGS += -Iinclude/linux -Iinclude/linux/lzma -include types.h diff --git a/target/linux/generic/patches-3.18/531-debloat_lzma.patch b/target/linux/generic/patches-3.18/531-debloat_lzma.patch new file mode 100644 index 0000000..aa3c498 --- /dev/null +++ b/target/linux/generic/patches-3.18/531-debloat_lzma.patch @@ -0,0 +1,1024 @@ +--- a/include/linux/lzma/LzmaDec.h ++++ b/include/linux/lzma/LzmaDec.h +@@ -31,14 +31,6 @@ typedef struct _CLzmaProps + UInt32 dicSize; + } CLzmaProps; + +-/* LzmaProps_Decode - decodes properties +-Returns: +- SZ_OK +- SZ_ERROR_UNSUPPORTED - Unsupported properties +-*/ +- +-SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size); +- + + /* ---------- LZMA Decoder state ---------- */ + +@@ -70,8 +62,6 @@ typedef struct + + #define LzmaDec_Construct(p) { (p)->dic = 0; (p)->probs = 0; } + +-void LzmaDec_Init(CLzmaDec *p); +- + /* There are two types of LZMA streams: + 0) Stream with end mark. That end mark adds about 6 bytes to compressed size. + 1) Stream without end mark. You must know exact uncompressed size to decompress such stream. */ +@@ -108,97 +98,6 @@ typedef enum + + /* ELzmaStatus is used only as output value for function call */ + +- +-/* ---------- Interfaces ---------- */ +- +-/* There are 3 levels of interfaces: +- 1) Dictionary Interface +- 2) Buffer Interface +- 3) One Call Interface +- You can select any of these interfaces, but don't mix functions from different +- groups for same object. */ +- +- +-/* There are two variants to allocate state for Dictionary Interface: +- 1) LzmaDec_Allocate / LzmaDec_Free +- 2) LzmaDec_AllocateProbs / LzmaDec_FreeProbs +- You can use variant 2, if you set dictionary buffer manually. +- For Buffer Interface you must always use variant 1. +- +-LzmaDec_Allocate* can return: +- SZ_OK +- SZ_ERROR_MEM - Memory allocation error +- SZ_ERROR_UNSUPPORTED - Unsupported properties +-*/ +- +-SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc); +-void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc); +- +-SRes LzmaDec_Allocate(CLzmaDec *state, const Byte *prop, unsigned propsSize, ISzAlloc *alloc); +-void LzmaDec_Free(CLzmaDec *state, ISzAlloc *alloc); +- +-/* ---------- Dictionary Interface ---------- */ +- +-/* You can use it, if you want to eliminate the overhead for data copying from +- dictionary to some other external buffer. +- You must work with CLzmaDec variables directly in this interface. +- +- STEPS: +- LzmaDec_Constr() +- LzmaDec_Allocate() +- for (each new stream) +- { +- LzmaDec_Init() +- while (it needs more decompression) +- { +- LzmaDec_DecodeToDic() +- use data from CLzmaDec::dic and update CLzmaDec::dicPos +- } +- } +- LzmaDec_Free() +-*/ +- +-/* LzmaDec_DecodeToDic +- +- The decoding to internal dictionary buffer (CLzmaDec::dic). +- You must manually update CLzmaDec::dicPos, if it reaches CLzmaDec::dicBufSize !!! +- +-finishMode: +- It has meaning only if the decoding reaches output limit (dicLimit). +- LZMA_FINISH_ANY - Decode just dicLimit bytes. +- LZMA_FINISH_END - Stream must be finished after dicLimit. +- +-Returns: +- SZ_OK +- status: +- LZMA_STATUS_FINISHED_WITH_MARK +- LZMA_STATUS_NOT_FINISHED +- LZMA_STATUS_NEEDS_MORE_INPUT +- LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK +- SZ_ERROR_DATA - Data error +-*/ +- +-SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, +- const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); +- +- +-/* ---------- Buffer Interface ---------- */ +- +-/* It's zlib-like interface. +- See LzmaDec_DecodeToDic description for information about STEPS and return results, +- but you must use LzmaDec_DecodeToBuf instead of LzmaDec_DecodeToDic and you don't need +- to work with CLzmaDec variables manually. +- +-finishMode: +- It has meaning only if the decoding reaches output limit (*destLen). +- LZMA_FINISH_ANY - Decode just destLen bytes. +- LZMA_FINISH_END - Stream must be finished after (*destLen). +-*/ +- +-SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, +- const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); +- +- + /* ---------- One Call Interface ---------- */ + + /* LzmaDecode +--- a/lib/lzma/LzmaDec.c ++++ b/lib/lzma/LzmaDec.c +@@ -682,7 +682,7 @@ static void LzmaDec_InitRc(CLzmaDec *p, + p->needFlush = 0; + } + +-void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState) ++static void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState) + { + p->needFlush = 1; + p->remainLen = 0; +@@ -698,7 +698,7 @@ void LzmaDec_InitDicAndState(CLzmaDec *p + p->needInitState = 1; + } + +-void LzmaDec_Init(CLzmaDec *p) ++static void LzmaDec_Init(CLzmaDec *p) + { + p->dicPos = 0; + LzmaDec_InitDicAndState(p, True, True); +@@ -716,7 +716,7 @@ static void LzmaDec_InitStateReal(CLzmaD + p->needInitState = 0; + } + +-SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen, ++static SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen, + ELzmaFinishMode finishMode, ELzmaStatus *status) + { + SizeT inSize = *srcLen; +@@ -837,65 +837,13 @@ SRes LzmaDec_DecodeToDic(CLzmaDec *p, Si + return (p->code == 0) ? SZ_OK : SZ_ERROR_DATA; + } + +-SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) +-{ +- SizeT outSize = *destLen; +- SizeT inSize = *srcLen; +- *srcLen = *destLen = 0; +- for (;;) +- { +- SizeT inSizeCur = inSize, outSizeCur, dicPos; +- ELzmaFinishMode curFinishMode; +- SRes res; +- if (p->dicPos == p->dicBufSize) +- p->dicPos = 0; +- dicPos = p->dicPos; +- if (outSize > p->dicBufSize - dicPos) +- { +- outSizeCur = p->dicBufSize; +- curFinishMode = LZMA_FINISH_ANY; +- } +- else +- { +- outSizeCur = dicPos + outSize; +- curFinishMode = finishMode; +- } +- +- res = LzmaDec_DecodeToDic(p, outSizeCur, src, &inSizeCur, curFinishMode, status); +- src += inSizeCur; +- inSize -= inSizeCur; +- *srcLen += inSizeCur; +- outSizeCur = p->dicPos - dicPos; +- memcpy(dest, p->dic + dicPos, outSizeCur); +- dest += outSizeCur; +- outSize -= outSizeCur; +- *destLen += outSizeCur; +- if (res != 0) +- return res; +- if (outSizeCur == 0 || outSize == 0) +- return SZ_OK; +- } +-} +- +-void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc) ++static void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc) + { + alloc->Free(alloc, p->probs); + p->probs = 0; + } + +-static void LzmaDec_FreeDict(CLzmaDec *p, ISzAlloc *alloc) +-{ +- alloc->Free(alloc, p->dic); +- p->dic = 0; +-} +- +-void LzmaDec_Free(CLzmaDec *p, ISzAlloc *alloc) +-{ +- LzmaDec_FreeProbs(p, alloc); +- LzmaDec_FreeDict(p, alloc); +-} +- +-SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size) ++static SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size) + { + UInt32 dicSize; + Byte d; +@@ -935,7 +883,7 @@ static SRes LzmaDec_AllocateProbs2(CLzma + return SZ_OK; + } + +-SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) ++static SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) + { + CLzmaProps propNew; + RINOK(LzmaProps_Decode(&propNew, props, propsSize)); +@@ -943,28 +891,6 @@ SRes LzmaDec_AllocateProbs(CLzmaDec *p, + p->prop = propNew; + return SZ_OK; + } +- +-SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) +-{ +- CLzmaProps propNew; +- SizeT dicBufSize; +- RINOK(LzmaProps_Decode(&propNew, props, propsSize)); +- RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); +- dicBufSize = propNew.dicSize; +- if (p->dic == 0 || dicBufSize != p->dicBufSize) +- { +- LzmaDec_FreeDict(p, alloc); +- p->dic = (Byte *)alloc->Alloc(alloc, dicBufSize); +- if (p->dic == 0) +- { +- LzmaDec_FreeProbs(p, alloc); +- return SZ_ERROR_MEM; +- } +- } +- p->dicBufSize = dicBufSize; +- p->prop = propNew; +- return SZ_OK; +-} + + SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, + const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, +--- a/include/linux/lzma/LzmaEnc.h ++++ b/include/linux/lzma/LzmaEnc.h +@@ -31,9 +31,6 @@ typedef struct _CLzmaEncProps + } CLzmaEncProps; + + void LzmaEncProps_Init(CLzmaEncProps *p); +-void LzmaEncProps_Normalize(CLzmaEncProps *p); +-UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2); +- + + /* ---------- CLzmaEncHandle Interface ---------- */ + +@@ -53,26 +50,9 @@ CLzmaEncHandle LzmaEnc_Create(ISzAlloc * + void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAlloc *alloc, ISzAlloc *allocBig); + SRes LzmaEnc_SetProps(CLzmaEncHandle p, const CLzmaEncProps *props); + SRes LzmaEnc_WriteProperties(CLzmaEncHandle p, Byte *properties, SizeT *size); +-SRes LzmaEnc_Encode(CLzmaEncHandle p, ISeqOutStream *outStream, ISeqInStream *inStream, +- ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig); + SRes LzmaEnc_MemEncode(CLzmaEncHandle p, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, + int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig); + +-/* ---------- One Call Interface ---------- */ +- +-/* LzmaEncode +-Return code: +- SZ_OK - OK +- SZ_ERROR_MEM - Memory allocation error +- SZ_ERROR_PARAM - Incorrect paramater +- SZ_ERROR_OUTPUT_EOF - output buffer overflow +- SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version) +-*/ +- +-SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, +- const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark, +- ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig); +- + #ifdef __cplusplus + } + #endif +--- a/lib/lzma/LzmaEnc.c ++++ b/lib/lzma/LzmaEnc.c +@@ -53,7 +53,7 @@ void LzmaEncProps_Init(CLzmaEncProps *p) + p->writeEndMark = 0; + } + +-void LzmaEncProps_Normalize(CLzmaEncProps *p) ++static void LzmaEncProps_Normalize(CLzmaEncProps *p) + { + int level = p->level; + if (level < 0) level = 5; +@@ -76,7 +76,7 @@ void LzmaEncProps_Normalize(CLzmaEncProp + #endif + } + +-UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2) ++static UInt32 __maybe_unused LzmaEncProps_GetDictSize(const CLzmaEncProps *props2) + { + CLzmaEncProps props = *props2; + LzmaEncProps_Normalize(&props); +@@ -93,7 +93,7 @@ UInt32 LzmaEncProps_GetDictSize(const CL + + #define BSR2_RET(pos, res) { unsigned long i; _BitScanReverse(&i, (pos)); res = (i + i) + ((pos >> (i - 1)) & 1); } + +-UInt32 GetPosSlot1(UInt32 pos) ++static UInt32 GetPosSlot1(UInt32 pos) + { + UInt32 res; + BSR2_RET(pos, res); +@@ -107,7 +107,7 @@ UInt32 GetPosSlot1(UInt32 pos) + #define kNumLogBits (9 + (int)sizeof(size_t) / 2) + #define kDicLogSizeMaxCompress ((kNumLogBits - 1) * 2 + 7) + +-void LzmaEnc_FastPosInit(Byte *g_FastPos) ++static void LzmaEnc_FastPosInit(Byte *g_FastPos) + { + int c = 2, slotFast; + g_FastPos[0] = 0; +@@ -339,58 +339,6 @@ typedef struct + CSaveState saveState; + } CLzmaEnc; + +-void LzmaEnc_SaveState(CLzmaEncHandle pp) +-{ +- CLzmaEnc *p = (CLzmaEnc *)pp; +- CSaveState *dest = &p->saveState; +- int i; +- dest->lenEnc = p->lenEnc; +- dest->repLenEnc = p->repLenEnc; +- dest->state = p->state; +- +- for (i = 0; i < kNumStates; i++) +- { +- memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i])); +- memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i])); +- } +- for (i = 0; i < kNumLenToPosStates; i++) +- memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i])); +- memcpy(dest->isRep, p->isRep, sizeof(p->isRep)); +- memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0)); +- memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1)); +- memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2)); +- memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders)); +- memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder)); +- memcpy(dest->reps, p->reps, sizeof(p->reps)); +- memcpy(dest->litProbs, p->litProbs, (0x300 << p->lclp) * sizeof(CLzmaProb)); +-} +- +-void LzmaEnc_RestoreState(CLzmaEncHandle pp) +-{ +- CLzmaEnc *dest = (CLzmaEnc *)pp; +- const CSaveState *p = &dest->saveState; +- int i; +- dest->lenEnc = p->lenEnc; +- dest->repLenEnc = p->repLenEnc; +- dest->state = p->state; +- +- for (i = 0; i < kNumStates; i++) +- { +- memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i])); +- memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i])); +- } +- for (i = 0; i < kNumLenToPosStates; i++) +- memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i])); +- memcpy(dest->isRep, p->isRep, sizeof(p->isRep)); +- memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0)); +- memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1)); +- memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2)); +- memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders)); +- memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder)); +- memcpy(dest->reps, p->reps, sizeof(p->reps)); +- memcpy(dest->litProbs, p->litProbs, (0x300 << dest->lclp) * sizeof(CLzmaProb)); +-} +- + SRes LzmaEnc_SetProps(CLzmaEncHandle pp, const CLzmaEncProps *props2) + { + CLzmaEnc *p = (CLzmaEnc *)pp; +@@ -600,7 +548,7 @@ static void LitEnc_EncodeMatched(CRangeE + while (symbol < 0x10000); + } + +-void LzmaEnc_InitPriceTables(UInt32 *ProbPrices) ++static void LzmaEnc_InitPriceTables(UInt32 *ProbPrices) + { + UInt32 i; + for (i = (1 << kNumMoveReducingBits) / 2; i < kBitModelTotal; i += (1 << kNumMoveReducingBits)) +@@ -1676,7 +1624,7 @@ static void FillDistancesPrices(CLzmaEnc + p->matchPriceCount = 0; + } + +-void LzmaEnc_Construct(CLzmaEnc *p) ++static void LzmaEnc_Construct(CLzmaEnc *p) + { + RangeEnc_Construct(&p->rc); + MatchFinder_Construct(&p->matchFinderBase); +@@ -1709,7 +1657,7 @@ CLzmaEncHandle LzmaEnc_Create(ISzAlloc * + return p; + } + +-void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAlloc *alloc) ++static void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAlloc *alloc) + { + alloc->Free(alloc, p->litProbs); + alloc->Free(alloc, p->saveState.litProbs); +@@ -1717,7 +1665,7 @@ void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAl + p->saveState.litProbs = 0; + } + +-void LzmaEnc_Destruct(CLzmaEnc *p, ISzAlloc *alloc, ISzAlloc *allocBig) ++static void LzmaEnc_Destruct(CLzmaEnc *p, ISzAlloc *alloc, ISzAlloc *allocBig) + { + #ifndef _7ZIP_ST + MatchFinderMt_Destruct(&p->matchFinderMt, allocBig); +@@ -1947,7 +1895,7 @@ static SRes LzmaEnc_Alloc(CLzmaEnc *p, U + return SZ_OK; + } + +-void LzmaEnc_Init(CLzmaEnc *p) ++static void LzmaEnc_Init(CLzmaEnc *p) + { + UInt32 i; + p->state = 0; +@@ -2005,7 +1953,7 @@ void LzmaEnc_Init(CLzmaEnc *p) + p->lpMask = (1 << p->lp) - 1; + } + +-void LzmaEnc_InitPrices(CLzmaEnc *p) ++static void LzmaEnc_InitPrices(CLzmaEnc *p) + { + if (!p->fastMode) + { +@@ -2037,26 +1985,6 @@ static SRes LzmaEnc_AllocAndInit(CLzmaEn + return SZ_OK; + } + +-static SRes LzmaEnc_Prepare(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, +- ISzAlloc *alloc, ISzAlloc *allocBig) +-{ +- CLzmaEnc *p = (CLzmaEnc *)pp; +- p->matchFinderBase.stream = inStream; +- p->needInit = 1; +- p->rc.outStream = outStream; +- return LzmaEnc_AllocAndInit(p, 0, alloc, allocBig); +-} +- +-SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle pp, +- ISeqInStream *inStream, UInt32 keepWindowSize, +- ISzAlloc *alloc, ISzAlloc *allocBig) +-{ +- CLzmaEnc *p = (CLzmaEnc *)pp; +- p->matchFinderBase.stream = inStream; +- p->needInit = 1; +- return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig); +-} +- + static void LzmaEnc_SetInputBuf(CLzmaEnc *p, const Byte *src, SizeT srcLen) + { + p->matchFinderBase.directInput = 1; +@@ -2064,7 +1992,7 @@ static void LzmaEnc_SetInputBuf(CLzmaEnc + p->matchFinderBase.directInputRem = srcLen; + } + +-SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen, ++static SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen, + UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig) + { + CLzmaEnc *p = (CLzmaEnc *)pp; +@@ -2074,7 +2002,7 @@ SRes LzmaEnc_MemPrepare(CLzmaEncHandle p + return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig); + } + +-void LzmaEnc_Finish(CLzmaEncHandle pp) ++static void LzmaEnc_Finish(CLzmaEncHandle pp) + { + #ifndef _7ZIP_ST + CLzmaEnc *p = (CLzmaEnc *)pp; +@@ -2107,53 +2035,6 @@ static size_t MyWrite(void *pp, const vo + return size; + } + +- +-UInt32 LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle pp) +-{ +- const CLzmaEnc *p = (CLzmaEnc *)pp; +- return p->matchFinder.GetNumAvailableBytes(p->matchFinderObj); +-} +- +-const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp) +-{ +- const CLzmaEnc *p = (CLzmaEnc *)pp; +- return p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset; +-} +- +-SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, Bool reInit, +- Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize) +-{ +- CLzmaEnc *p = (CLzmaEnc *)pp; +- UInt64 nowPos64; +- SRes res; +- CSeqOutStreamBuf outStream; +- +- outStream.funcTable.Write = MyWrite; +- outStream.data = dest; +- outStream.rem = *destLen; +- outStream.overflow = False; +- +- p->writeEndMark = False; +- p->finished = False; +- p->result = SZ_OK; +- +- if (reInit) +- LzmaEnc_Init(p); +- LzmaEnc_InitPrices(p); +- nowPos64 = p->nowPos64; +- RangeEnc_Init(&p->rc); +- p->rc.outStream = &outStream.funcTable; +- +- res = LzmaEnc_CodeOneBlock(p, True, desiredPackSize, *unpackSize); +- +- *unpackSize = (UInt32)(p->nowPos64 - nowPos64); +- *destLen -= outStream.rem; +- if (outStream.overflow) +- return SZ_ERROR_OUTPUT_EOF; +- +- return res; +-} +- + static SRes LzmaEnc_Encode2(CLzmaEnc *p, ICompressProgress *progress) + { + SRes res = SZ_OK; +@@ -2184,13 +2065,6 @@ static SRes LzmaEnc_Encode2(CLzmaEnc *p, + return res; + } + +-SRes LzmaEnc_Encode(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress, +- ISzAlloc *alloc, ISzAlloc *allocBig) +-{ +- RINOK(LzmaEnc_Prepare(pp, outStream, inStream, alloc, allocBig)); +- return LzmaEnc_Encode2((CLzmaEnc *)pp, progress); +-} +- + SRes LzmaEnc_WriteProperties(CLzmaEncHandle pp, Byte *props, SizeT *size) + { + CLzmaEnc *p = (CLzmaEnc *)pp; +@@ -2247,25 +2121,3 @@ SRes LzmaEnc_MemEncode(CLzmaEncHandle pp + return SZ_ERROR_OUTPUT_EOF; + return res; + } +- +-SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, +- const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark, +- ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig) +-{ +- CLzmaEnc *p = (CLzmaEnc *)LzmaEnc_Create(alloc); +- SRes res; +- if (p == 0) +- return SZ_ERROR_MEM; +- +- res = LzmaEnc_SetProps(p, props); +- if (res == SZ_OK) +- { +- res = LzmaEnc_WriteProperties(p, propsEncoded, propsSize); +- if (res == SZ_OK) +- res = LzmaEnc_MemEncode(p, dest, destLen, src, srcLen, +- writeEndMark, progress, alloc, allocBig); +- } +- +- LzmaEnc_Destroy(p, alloc, allocBig); +- return res; +-} +--- a/include/linux/lzma/LzFind.h ++++ b/include/linux/lzma/LzFind.h +@@ -55,11 +55,6 @@ typedef struct _CMatchFinder + + #define Inline_MatchFinder_GetNumAvailableBytes(p) ((p)->streamPos - (p)->pos) + +-int MatchFinder_NeedMove(CMatchFinder *p); +-Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p); +-void MatchFinder_MoveBlock(CMatchFinder *p); +-void MatchFinder_ReadIfRequired(CMatchFinder *p); +- + void MatchFinder_Construct(CMatchFinder *p); + + /* Conditions: +@@ -70,12 +65,6 @@ int MatchFinder_Create(CMatchFinder *p, + UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter, + ISzAlloc *alloc); + void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc); +-void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems); +-void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue); +- +-UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *buffer, CLzRef *son, +- UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue, +- UInt32 *distances, UInt32 maxLen); + + /* + Conditions: +@@ -102,12 +91,6 @@ typedef struct _IMatchFinder + + void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable); + +-void MatchFinder_Init(CMatchFinder *p); +-UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances); +-UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances); +-void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num); +-void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num); +- + #ifdef __cplusplus + } + #endif +--- a/lib/lzma/LzFind.c ++++ b/lib/lzma/LzFind.c +@@ -14,9 +14,15 @@ + + #define kStartMaxLen 3 + ++#if 0 ++#define DIRECT_INPUT p->directInput ++#else ++#define DIRECT_INPUT 1 ++#endif ++ + static void LzInWindow_Free(CMatchFinder *p, ISzAlloc *alloc) + { +- if (!p->directInput) ++ if (!DIRECT_INPUT) + { + alloc->Free(alloc, p->bufferBase); + p->bufferBase = 0; +@@ -28,7 +34,7 @@ static void LzInWindow_Free(CMatchFinder + static int LzInWindow_Create(CMatchFinder *p, UInt32 keepSizeReserv, ISzAlloc *alloc) + { + UInt32 blockSize = p->keepSizeBefore + p->keepSizeAfter + keepSizeReserv; +- if (p->directInput) ++ if (DIRECT_INPUT) + { + p->blockSize = blockSize; + return 1; +@@ -42,12 +48,12 @@ static int LzInWindow_Create(CMatchFinde + return (p->bufferBase != 0); + } + +-Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; } +-Byte MatchFinder_GetIndexByte(CMatchFinder *p, Int32 index) { return p->buffer[index]; } ++static Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; } ++static Byte MatchFinder_GetIndexByte(CMatchFinder *p, Int32 index) { return p->buffer[index]; } + +-UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return p->streamPos - p->pos; } ++static UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return p->streamPos - p->pos; } + +-void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue) ++static void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue) + { + p->posLimit -= subValue; + p->pos -= subValue; +@@ -58,7 +64,7 @@ static void MatchFinder_ReadBlock(CMatch + { + if (p->streamEndWasReached || p->result != SZ_OK) + return; +- if (p->directInput) ++ if (DIRECT_INPUT) + { + UInt32 curSize = 0xFFFFFFFF - p->streamPos; + if (curSize > p->directInputRem) +@@ -89,7 +95,7 @@ static void MatchFinder_ReadBlock(CMatch + } + } + +-void MatchFinder_MoveBlock(CMatchFinder *p) ++static void MatchFinder_MoveBlock(CMatchFinder *p) + { + memmove(p->bufferBase, + p->buffer - p->keepSizeBefore, +@@ -97,22 +103,14 @@ void MatchFinder_MoveBlock(CMatchFinder + p->buffer = p->bufferBase + p->keepSizeBefore; + } + +-int MatchFinder_NeedMove(CMatchFinder *p) ++static int MatchFinder_NeedMove(CMatchFinder *p) + { +- if (p->directInput) ++ if (DIRECT_INPUT) + return 0; + /* if (p->streamEndWasReached) return 0; */ + return ((size_t)(p->bufferBase + p->blockSize - p->buffer) <= p->keepSizeAfter); + } + +-void MatchFinder_ReadIfRequired(CMatchFinder *p) +-{ +- if (p->streamEndWasReached) +- return; +- if (p->keepSizeAfter >= p->streamPos - p->pos) +- MatchFinder_ReadBlock(p); +-} +- + static void MatchFinder_CheckAndMoveAndRead(CMatchFinder *p) + { + if (MatchFinder_NeedMove(p)) +@@ -268,7 +266,7 @@ static void MatchFinder_SetLimits(CMatch + p->posLimit = p->pos + limit; + } + +-void MatchFinder_Init(CMatchFinder *p) ++static void MatchFinder_Init(CMatchFinder *p) + { + UInt32 i; + for (i = 0; i < p->hashSizeSum; i++) +@@ -287,7 +285,7 @@ static UInt32 MatchFinder_GetSubValue(CM + return (p->pos - p->historySize - 1) & kNormalizeMask; + } + +-void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems) ++static void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems) + { + UInt32 i; + for (i = 0; i < numItems; i++) +@@ -319,38 +317,7 @@ static void MatchFinder_CheckLimits(CMat + MatchFinder_SetLimits(p); + } + +-static UInt32 * Hc_GetMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, +- UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue, +- UInt32 *distances, UInt32 maxLen) +-{ +- son[_cyclicBufferPos] = curMatch; +- for (;;) +- { +- UInt32 delta = pos - curMatch; +- if (cutValue-- == 0 || delta >= _cyclicBufferSize) +- return distances; +- { +- const Byte *pb = cur - delta; +- curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)]; +- if (pb[maxLen] == cur[maxLen] && *pb == *cur) +- { +- UInt32 len = 0; +- while (++len != lenLimit) +- if (pb[len] != cur[len]) +- break; +- if (maxLen < len) +- { +- *distances++ = maxLen = len; +- *distances++ = delta - 1; +- if (len == lenLimit) +- return distances; +- } +- } +- } +- } +-} +- +-UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, ++static UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, + UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue, + UInt32 *distances, UInt32 maxLen) + { +@@ -460,10 +427,10 @@ static void SkipMatchesSpec(UInt32 lenLi + p->buffer++; \ + if (++p->pos == p->posLimit) MatchFinder_CheckLimits(p); + +-#define MOVE_POS_RET MOVE_POS return offset; +- + static void MatchFinder_MovePos(CMatchFinder *p) { MOVE_POS; } + ++#define MOVE_POS_RET MatchFinder_MovePos(p); return offset; ++ + #define GET_MATCHES_HEADER2(minLen, ret_op) \ + UInt32 lenLimit; UInt32 hashValue; const Byte *cur; UInt32 curMatch; \ + lenLimit = p->lenLimit; { if (lenLimit < minLen) { MatchFinder_MovePos(p); ret_op; }} \ +@@ -479,62 +446,7 @@ static void MatchFinder_MovePos(CMatchFi + distances + offset, maxLen) - distances); MOVE_POS_RET; + + #define SKIP_FOOTER \ +- SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); MOVE_POS; +- +-static UInt32 Bt2_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +-{ +- UInt32 offset; +- GET_MATCHES_HEADER(2) +- HASH2_CALC; +- curMatch = p->hash[hashValue]; +- p->hash[hashValue] = p->pos; +- offset = 0; +- GET_MATCHES_FOOTER(offset, 1) +-} +- +-UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +-{ +- UInt32 offset; +- GET_MATCHES_HEADER(3) +- HASH_ZIP_CALC; +- curMatch = p->hash[hashValue]; +- p->hash[hashValue] = p->pos; +- offset = 0; +- GET_MATCHES_FOOTER(offset, 2) +-} +- +-static UInt32 Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +-{ +- UInt32 hash2Value, delta2, maxLen, offset; +- GET_MATCHES_HEADER(3) +- +- HASH3_CALC; +- +- delta2 = p->pos - p->hash[hash2Value]; +- curMatch = p->hash[kFix3HashSize + hashValue]; +- +- p->hash[hash2Value] = +- p->hash[kFix3HashSize + hashValue] = p->pos; +- +- +- maxLen = 2; +- offset = 0; +- if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur) +- { +- for (; maxLen != lenLimit; maxLen++) +- if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen]) +- break; +- distances[0] = maxLen; +- distances[1] = delta2 - 1; +- offset = 2; +- if (maxLen == lenLimit) +- { +- SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); +- MOVE_POS_RET; +- } +- } +- GET_MATCHES_FOOTER(offset, maxLen) +-} ++ SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); MatchFinder_MovePos(p); + + static UInt32 Bt4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) + { +@@ -583,108 +495,6 @@ static UInt32 Bt4_MatchFinder_GetMatches + GET_MATCHES_FOOTER(offset, maxLen) + } + +-static UInt32 Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +-{ +- UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset; +- GET_MATCHES_HEADER(4) +- +- HASH4_CALC; +- +- delta2 = p->pos - p->hash[ hash2Value]; +- delta3 = p->pos - p->hash[kFix3HashSize + hash3Value]; +- curMatch = p->hash[kFix4HashSize + hashValue]; +- +- p->hash[ hash2Value] = +- p->hash[kFix3HashSize + hash3Value] = +- p->hash[kFix4HashSize + hashValue] = p->pos; +- +- maxLen = 1; +- offset = 0; +- if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur) +- { +- distances[0] = maxLen = 2; +- distances[1] = delta2 - 1; +- offset = 2; +- } +- if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur) +- { +- maxLen = 3; +- distances[offset + 1] = delta3 - 1; +- offset += 2; +- delta2 = delta3; +- } +- if (offset != 0) +- { +- for (; maxLen != lenLimit; maxLen++) +- if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen]) +- break; +- distances[offset - 2] = maxLen; +- if (maxLen == lenLimit) +- { +- p->son[p->cyclicBufferPos] = curMatch; +- MOVE_POS_RET; +- } +- } +- if (maxLen < 3) +- maxLen = 3; +- offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p), +- distances + offset, maxLen) - (distances)); +- MOVE_POS_RET +-} +- +-UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +-{ +- UInt32 offset; +- GET_MATCHES_HEADER(3) +- HASH_ZIP_CALC; +- curMatch = p->hash[hashValue]; +- p->hash[hashValue] = p->pos; +- offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p), +- distances, 2) - (distances)); +- MOVE_POS_RET +-} +- +-static void Bt2_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +-{ +- do +- { +- SKIP_HEADER(2) +- HASH2_CALC; +- curMatch = p->hash[hashValue]; +- p->hash[hashValue] = p->pos; +- SKIP_FOOTER +- } +- while (--num != 0); +-} +- +-void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +-{ +- do +- { +- SKIP_HEADER(3) +- HASH_ZIP_CALC; +- curMatch = p->hash[hashValue]; +- p->hash[hashValue] = p->pos; +- SKIP_FOOTER +- } +- while (--num != 0); +-} +- +-static void Bt3_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +-{ +- do +- { +- UInt32 hash2Value; +- SKIP_HEADER(3) +- HASH3_CALC; +- curMatch = p->hash[kFix3HashSize + hashValue]; +- p->hash[hash2Value] = +- p->hash[kFix3HashSize + hashValue] = p->pos; +- SKIP_FOOTER +- } +- while (--num != 0); +-} +- + static void Bt4_MatchFinder_Skip(CMatchFinder *p, UInt32 num) + { + do +@@ -701,61 +511,12 @@ static void Bt4_MatchFinder_Skip(CMatchF + while (--num != 0); + } + +-static void Hc4_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +-{ +- do +- { +- UInt32 hash2Value, hash3Value; +- SKIP_HEADER(4) +- HASH4_CALC; +- curMatch = p->hash[kFix4HashSize + hashValue]; +- p->hash[ hash2Value] = +- p->hash[kFix3HashSize + hash3Value] = +- p->hash[kFix4HashSize + hashValue] = p->pos; +- p->son[p->cyclicBufferPos] = curMatch; +- MOVE_POS +- } +- while (--num != 0); +-} +- +-void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +-{ +- do +- { +- SKIP_HEADER(3) +- HASH_ZIP_CALC; +- curMatch = p->hash[hashValue]; +- p->hash[hashValue] = p->pos; +- p->son[p->cyclicBufferPos] = curMatch; +- MOVE_POS +- } +- while (--num != 0); +-} +- + void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable) + { + vTable->Init = (Mf_Init_Func)MatchFinder_Init; + vTable->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinder_GetIndexByte; + vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinder_GetNumAvailableBytes; + vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinder_GetPointerToCurrentPos; +- if (!p->btMode) +- { +- vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches; +- vTable->Skip = (Mf_Skip_Func)Hc4_MatchFinder_Skip; +- } +- else if (p->numHashBytes == 2) +- { +- vTable->GetMatches = (Mf_GetMatches_Func)Bt2_MatchFinder_GetMatches; +- vTable->Skip = (Mf_Skip_Func)Bt2_MatchFinder_Skip; +- } +- else if (p->numHashBytes == 3) +- { +- vTable->GetMatches = (Mf_GetMatches_Func)Bt3_MatchFinder_GetMatches; +- vTable->Skip = (Mf_Skip_Func)Bt3_MatchFinder_Skip; +- } +- else +- { +- vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches; +- vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip; +- } ++ vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches; ++ vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip; + } diff --git a/target/linux/generic/patches-3.18/532-jffs2_eofdetect.patch b/target/linux/generic/patches-3.18/532-jffs2_eofdetect.patch new file mode 100644 index 0000000..9cbe183 --- /dev/null +++ b/target/linux/generic/patches-3.18/532-jffs2_eofdetect.patch @@ -0,0 +1,56 @@ +--- a/fs/jffs2/build.c ++++ b/fs/jffs2/build.c +@@ -114,6 +114,16 @@ static int jffs2_build_filesystem(struct + dbg_fsbuild("scanned flash completely\n"); + jffs2_dbg_dump_block_lists_nolock(c); + ++ if (c->flags & (1 << 7)) { ++ printk("%s(): unlocking the mtd device... ", __func__); ++ mtd_unlock(c->mtd, 0, c->mtd->size); ++ printk("done.\n"); ++ ++ printk("%s(): erasing all blocks after the end marker... ", __func__); ++ jffs2_erase_pending_blocks(c, -1); ++ printk("done.\n"); ++ } ++ + dbg_fsbuild("pass 1 starting\n"); + c->flags |= JFFS2_SB_FLAG_BUILDING; + /* Now scan the directory tree, increasing nlink according to every dirent found. */ +--- a/fs/jffs2/scan.c ++++ b/fs/jffs2/scan.c +@@ -148,8 +148,14 @@ int jffs2_scan_medium(struct jffs2_sb_in + /* reset summary info for next eraseblock scan */ + jffs2_sum_reset_collected(s); + +- ret = jffs2_scan_eraseblock(c, jeb, buf_size?flashbuf:(flashbuf+jeb->offset), +- buf_size, s); ++ if (c->flags & (1 << 7)) { ++ if (mtd_block_isbad(c->mtd, jeb->offset)) ++ ret = BLK_STATE_BADBLOCK; ++ else ++ ret = BLK_STATE_ALLFF; ++ } else ++ ret = jffs2_scan_eraseblock(c, jeb, buf_size?flashbuf:(flashbuf+jeb->offset), ++ buf_size, s); + + if (ret < 0) + goto out; +@@ -561,6 +567,17 @@ full_scan: + return err; + } + ++ if ((buf[0] == 0xde) && ++ (buf[1] == 0xad) && ++ (buf[2] == 0xc0) && ++ (buf[3] == 0xde)) { ++ /* end of filesystem. erase everything after this point */ ++ printk("%s(): End of filesystem marker found at 0x%x\n", __func__, jeb->offset); ++ c->flags |= (1 << 7); ++ ++ return BLK_STATE_ALLFF; ++ } ++ + /* We temporarily use 'ofs' as a pointer into the buffer/jeb */ + ofs = 0; + max_ofs = EMPTY_SCAN_SIZE(c->sector_size); diff --git a/target/linux/generic/patches-3.18/540-crypto-xz-decompression-support.patch b/target/linux/generic/patches-3.18/540-crypto-xz-decompression-support.patch new file mode 100644 index 0000000..00b0b7c --- /dev/null +++ b/target/linux/generic/patches-3.18/540-crypto-xz-decompression-support.patch @@ -0,0 +1,146 @@ +--- a/crypto/Kconfig ++++ b/crypto/Kconfig +@@ -1437,6 +1437,13 @@ config CRYPTO_LZ4HC + help + This is the LZ4 high compression mode algorithm. + ++config CRYPTO_XZ ++ tristate "XZ compression algorithm" ++ select CRYPTO_ALGAPI ++ select XZ_DEC ++ help ++ This is the XZ algorithm. Only decompression is supported for now. ++ + comment "Random Number Generation" + + config CRYPTO_ANSI_CPRNG +--- a/crypto/Makefile ++++ b/crypto/Makefile +@@ -89,6 +89,7 @@ obj-$(CONFIG_CRYPTO_AUTHENC) += authenc. + obj-$(CONFIG_CRYPTO_LZO) += lzo.o + obj-$(CONFIG_CRYPTO_LZ4) += lz4.o + obj-$(CONFIG_CRYPTO_LZ4HC) += lz4hc.o ++obj-$(CONFIG_CRYPTO_XZ) += xz.o + obj-$(CONFIG_CRYPTO_842) += 842.o + obj-$(CONFIG_CRYPTO_RNG2) += rng.o + obj-$(CONFIG_CRYPTO_RNG2) += krng.o +--- /dev/null ++++ b/crypto/xz.c +@@ -0,0 +1,117 @@ ++/* ++ * Cryptographic API. ++ * ++ * XZ decompression support. ++ * ++ * Copyright (c) 2012 Gabor Juhos ++ * ++ * 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. ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++struct xz_comp_ctx { ++ struct xz_dec *decomp_state; ++ struct xz_buf decomp_buf; ++}; ++ ++static int crypto_xz_decomp_init(struct xz_comp_ctx *ctx) ++{ ++ ctx->decomp_state = xz_dec_init(XZ_SINGLE, 0); ++ if (!ctx->decomp_state) ++ return -ENOMEM; ++ ++ return 0; ++} ++ ++static void crypto_xz_decomp_exit(struct xz_comp_ctx *ctx) ++{ ++ xz_dec_end(ctx->decomp_state); ++} ++ ++static int crypto_xz_init(struct crypto_tfm *tfm) ++{ ++ struct xz_comp_ctx *ctx = crypto_tfm_ctx(tfm); ++ ++ return crypto_xz_decomp_init(ctx); ++} ++ ++static void crypto_xz_exit(struct crypto_tfm *tfm) ++{ ++ struct xz_comp_ctx *ctx = crypto_tfm_ctx(tfm); ++ ++ crypto_xz_decomp_exit(ctx); ++} ++ ++static int crypto_xz_compress(struct crypto_tfm *tfm, const u8 *src, ++ unsigned int slen, u8 *dst, unsigned int *dlen) ++{ ++ return -EOPNOTSUPP; ++} ++ ++static int crypto_xz_decompress(struct crypto_tfm *tfm, const u8 *src, ++ unsigned int slen, u8 *dst, unsigned int *dlen) ++{ ++ struct xz_comp_ctx *dctx = crypto_tfm_ctx(tfm); ++ struct xz_buf *xz_buf = &dctx->decomp_buf; ++ int ret; ++ ++ memset(xz_buf, '\0', sizeof(struct xz_buf)); ++ ++ xz_buf->in = (u8 *) src; ++ xz_buf->in_pos = 0; ++ xz_buf->in_size = slen; ++ xz_buf->out = (u8 *) dst; ++ xz_buf->out_pos = 0; ++ xz_buf->out_size = *dlen; ++ ++ ret = xz_dec_run(dctx->decomp_state, xz_buf); ++ if (ret != XZ_STREAM_END) { ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ *dlen = xz_buf->out_pos; ++ ret = 0; ++ ++out: ++ return ret; ++} ++ ++static struct crypto_alg crypto_xz_alg = { ++ .cra_name = "xz", ++ .cra_flags = CRYPTO_ALG_TYPE_COMPRESS, ++ .cra_ctxsize = sizeof(struct xz_comp_ctx), ++ .cra_module = THIS_MODULE, ++ .cra_list = LIST_HEAD_INIT(crypto_xz_alg.cra_list), ++ .cra_init = crypto_xz_init, ++ .cra_exit = crypto_xz_exit, ++ .cra_u = { .compress = { ++ .coa_compress = crypto_xz_compress, ++ .coa_decompress = crypto_xz_decompress } } ++}; ++ ++static int __init crypto_xz_mod_init(void) ++{ ++ return crypto_register_alg(&crypto_xz_alg); ++} ++ ++static void __exit crypto_xz_mod_exit(void) ++{ ++ crypto_unregister_alg(&crypto_xz_alg); ++} ++ ++module_init(crypto_xz_mod_init); ++module_exit(crypto_xz_mod_exit); ++ ++MODULE_LICENSE("GPL v2"); ++MODULE_DESCRIPTION("Crypto XZ decompression support"); ++MODULE_AUTHOR("Gabor Juhos "); diff --git a/target/linux/generic/patches-3.18/541-ubifs-xz-decompression-support.patch b/target/linux/generic/patches-3.18/541-ubifs-xz-decompression-support.patch new file mode 100644 index 0000000..f85689c --- /dev/null +++ b/target/linux/generic/patches-3.18/541-ubifs-xz-decompression-support.patch @@ -0,0 +1,92 @@ +--- a/fs/ubifs/Kconfig ++++ b/fs/ubifs/Kconfig +@@ -5,8 +5,10 @@ config UBIFS_FS + select CRYPTO if UBIFS_FS_ADVANCED_COMPR + select CRYPTO if UBIFS_FS_LZO + select CRYPTO if UBIFS_FS_ZLIB ++ select CRYPTO if UBIFS_FS_XZ + select CRYPTO_LZO if UBIFS_FS_LZO + select CRYPTO_DEFLATE if UBIFS_FS_ZLIB ++ select CRYPTO_XZ if UBIFS_FS_XZ + depends on MTD_UBI + help + UBIFS is a file system for flash devices which works on top of UBI. +@@ -35,3 +37,12 @@ config UBIFS_FS_ZLIB + default y + help + Zlib compresses better than LZO but it is slower. Say 'Y' if unsure. ++ ++config UBIFS_FS_XZ ++ bool "XZ decompression support" if UBIFS_FS_ADVANCED_COMPR ++ depends on UBIFS_FS ++ default y ++ help ++ XZ compresses better the ZLIB but it is slower.. ++ Say 'Y' if unsure. ++ +--- a/fs/ubifs/compress.c ++++ b/fs/ubifs/compress.c +@@ -71,6 +71,24 @@ static struct ubifs_compressor zlib_comp + }; + #endif + ++#ifdef CONFIG_UBIFS_FS_XZ ++static DEFINE_MUTEX(xz_enc_mutex); ++static DEFINE_MUTEX(xz_dec_mutex); ++ ++static struct ubifs_compressor xz_compr = { ++ .compr_type = UBIFS_COMPR_XZ, ++ .comp_mutex = &xz_enc_mutex, ++ .decomp_mutex = &xz_dec_mutex, ++ .name = "xz", ++ .capi_name = "xz", ++}; ++#else ++static struct ubifs_compressor xz_compr = { ++ .compr_type = UBIFS_COMPR_XZ, ++ .name = "xz", ++}; ++#endif ++ + /* All UBIFS compressors */ + struct ubifs_compressor *ubifs_compressors[UBIFS_COMPR_TYPES_CNT]; + +@@ -232,9 +250,15 @@ int __init ubifs_compressors_init(void) + if (err) + goto out_lzo; + ++ err = compr_init(&xz_compr); ++ if (err) ++ goto out_zlib; ++ + ubifs_compressors[UBIFS_COMPR_NONE] = &none_compr; + return 0; + ++out_zlib: ++ compr_exit(&zlib_compr); + out_lzo: + compr_exit(&lzo_compr); + return err; +@@ -247,4 +271,5 @@ void ubifs_compressors_exit(void) + { + compr_exit(&lzo_compr); + compr_exit(&zlib_compr); ++ compr_exit(&xz_compr); + } +--- a/fs/ubifs/ubifs-media.h ++++ b/fs/ubifs/ubifs-media.h +@@ -332,12 +332,14 @@ enum { + * UBIFS_COMPR_NONE: no compression + * UBIFS_COMPR_LZO: LZO compression + * UBIFS_COMPR_ZLIB: ZLIB compression ++ * UBIFS_COMPR_XZ: XZ compression + * UBIFS_COMPR_TYPES_CNT: count of supported compression types + */ + enum { + UBIFS_COMPR_NONE, + UBIFS_COMPR_LZO, + UBIFS_COMPR_ZLIB, ++ UBIFS_COMPR_XZ, + UBIFS_COMPR_TYPES_CNT, + }; + diff --git a/target/linux/generic/patches-3.18/550-ubifs-symlink-xattr-support.patch b/target/linux/generic/patches-3.18/550-ubifs-symlink-xattr-support.patch new file mode 100644 index 0000000..d3f2ccc --- /dev/null +++ b/target/linux/generic/patches-3.18/550-ubifs-symlink-xattr-support.patch @@ -0,0 +1,55 @@ +--- a/fs/ubifs/file.c ++++ b/fs/ubifs/file.c +@@ -1573,6 +1573,10 @@ const struct inode_operations ubifs_syml + .follow_link = ubifs_follow_link, + .setattr = ubifs_setattr, + .getattr = ubifs_getattr, ++ .setxattr = ubifs_setxattr, ++ .getxattr = ubifs_getxattr, ++ .listxattr = ubifs_listxattr, ++ .removexattr = ubifs_removexattr, + }; + + const struct file_operations ubifs_file_operations = { +--- a/fs/ubifs/journal.c ++++ b/fs/ubifs/journal.c +@@ -572,6 +572,13 @@ int ubifs_jnl_update(struct ubifs_info * + aligned_dlen = ALIGN(dlen, 8); + aligned_ilen = ALIGN(ilen, 8); + len = aligned_dlen + aligned_ilen + UBIFS_INO_NODE_SZ; ++ if (xent) { ++ /* ++ * Make sure to account for host_ui->data_len in ++ * length calculation in case there is extended attribute. ++ */ ++ len += host_ui->data_len; ++ } + dent = kmalloc(len, GFP_NOFS); + if (!dent) + return -ENOMEM; +@@ -648,7 +655,8 @@ int ubifs_jnl_update(struct ubifs_info * + + ino_key_init(c, &ino_key, dir->i_ino); + ino_offs += aligned_ilen; +- err = ubifs_tnc_add(c, &ino_key, lnum, ino_offs, UBIFS_INO_NODE_SZ); ++ err = ubifs_tnc_add(c, &ino_key, lnum, ino_offs, ++ UBIFS_INO_NODE_SZ + host_ui->data_len); + if (err) + goto out_ro; + +--- a/fs/ubifs/xattr.c ++++ b/fs/ubifs/xattr.c +@@ -209,12 +209,12 @@ static int change_xattr(struct ubifs_inf + goto out_free; + } + inode->i_size = ui->ui_size = size; +- ui->data_len = size; + + mutex_lock(&host_ui->ui_mutex); + host->i_ctime = ubifs_current_time(host); + host_ui->xattr_size -= CALC_XATTR_BYTES(ui->data_len); + host_ui->xattr_size += CALC_XATTR_BYTES(size); ++ ui->data_len = size; + + /* + * It is important to write the host inode after the xattr inode diff --git a/target/linux/generic/patches-3.18/551-ubifs-fix-default-compression-selection.patch b/target/linux/generic/patches-3.18/551-ubifs-fix-default-compression-selection.patch new file mode 100644 index 0000000..1b0f307 --- /dev/null +++ b/target/linux/generic/patches-3.18/551-ubifs-fix-default-compression-selection.patch @@ -0,0 +1,29 @@ +--- a/fs/ubifs/sb.c ++++ b/fs/ubifs/sb.c +@@ -63,6 +63,17 @@ + /* Default time granularity in nanoseconds */ + #define DEFAULT_TIME_GRAN 1000000000 + ++static int get_default_compressor(void) ++{ ++ if (ubifs_compr_present(UBIFS_COMPR_LZO)) ++ return UBIFS_COMPR_LZO; ++ ++ if (ubifs_compr_present(UBIFS_COMPR_ZLIB)) ++ return UBIFS_COMPR_ZLIB; ++ ++ return UBIFS_COMPR_NONE; ++} ++ + /** + * create_default_filesystem - format empty UBI volume. + * @c: UBIFS file-system description object +@@ -183,7 +194,7 @@ static int create_default_filesystem(str + if (c->mount_opts.override_compr) + sup->default_compr = cpu_to_le16(c->mount_opts.compr_type); + else +- sup->default_compr = cpu_to_le16(UBIFS_COMPR_LZO); ++ sup->default_compr = cpu_to_le16(get_default_compressor()); + + generate_random_uuid(sup->uuid); + diff --git a/target/linux/generic/patches-3.18/600-netfilter_conntrack_flush.patch b/target/linux/generic/patches-3.18/600-netfilter_conntrack_flush.patch new file mode 100644 index 0000000..bc6ed3e --- /dev/null +++ b/target/linux/generic/patches-3.18/600-netfilter_conntrack_flush.patch @@ -0,0 +1,86 @@ +--- a/net/netfilter/nf_conntrack_standalone.c ++++ b/net/netfilter/nf_conntrack_standalone.c +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + #include + #ifdef CONFIG_SYSCTL + #include +@@ -262,10 +263,66 @@ static int ct_open(struct inode *inode, + sizeof(struct ct_iter_state)); + } + ++struct kill_request { ++ u16 family; ++ union nf_inet_addr addr; ++}; ++ ++static int kill_matching(struct nf_conn *i, void *data) ++{ ++ struct kill_request *kr = data; ++ struct nf_conntrack_tuple *t1 = &i->tuplehash[IP_CT_DIR_ORIGINAL].tuple; ++ struct nf_conntrack_tuple *t2 = &i->tuplehash[IP_CT_DIR_REPLY].tuple; ++ ++ if (!kr->family) ++ return 1; ++ ++ if (t1->src.l3num != kr->family) ++ return 0; ++ ++ return (nf_inet_addr_cmp(&kr->addr, &t1->src.u3) || ++ nf_inet_addr_cmp(&kr->addr, &t1->dst.u3) || ++ nf_inet_addr_cmp(&kr->addr, &t2->src.u3) || ++ nf_inet_addr_cmp(&kr->addr, &t2->dst.u3)); ++} ++ ++static ssize_t ct_file_write(struct file *file, const char __user *buf, ++ size_t count, loff_t *ppos) ++{ ++ struct seq_file *seq = file->private_data; ++ struct net *net = seq_file_net(seq); ++ struct kill_request kr = { }; ++ char req[INET6_ADDRSTRLEN] = { }; ++ ++ if (count == 0) ++ return 0; ++ ++ if (count >= INET6_ADDRSTRLEN) ++ count = INET6_ADDRSTRLEN - 1; ++ ++ if (copy_from_user(req, buf, count)) ++ return -EFAULT; ++ ++ if (strnchr(req, count, ':')) { ++ kr.family = AF_INET6; ++ if (!in6_pton(req, count, (void *)&kr.addr, '\n', NULL)) ++ return -EINVAL; ++ } else if (strnchr(req, count, '.')) { ++ kr.family = AF_INET; ++ if (!in4_pton(req, count, (void *)&kr.addr, '\n', NULL)) ++ return -EINVAL; ++ } ++ ++ nf_ct_iterate_cleanup(net, kill_matching, &kr, 0, 0); ++ ++ return count; ++} ++ + static const struct file_operations ct_file_ops = { + .owner = THIS_MODULE, + .open = ct_open, + .read = seq_read, ++ .write = ct_file_write, + .llseek = seq_lseek, + .release = seq_release_net, + }; +@@ -367,7 +424,7 @@ static int nf_conntrack_standalone_init_ + { + struct proc_dir_entry *pde; + +- pde = proc_create("nf_conntrack", 0440, net->proc_net, &ct_file_ops); ++ pde = proc_create("nf_conntrack", 0660, net->proc_net, &ct_file_ops); + if (!pde) + goto out_nf_conntrack; + diff --git a/target/linux/generic/patches-3.18/610-netfilter_match_bypass_default_checks.patch b/target/linux/generic/patches-3.18/610-netfilter_match_bypass_default_checks.patch new file mode 100644 index 0000000..358d64b --- /dev/null +++ b/target/linux/generic/patches-3.18/610-netfilter_match_bypass_default_checks.patch @@ -0,0 +1,93 @@ +--- a/include/uapi/linux/netfilter_ipv4/ip_tables.h ++++ b/include/uapi/linux/netfilter_ipv4/ip_tables.h +@@ -87,6 +87,7 @@ struct ipt_ip { + #define IPT_F_FRAG 0x01 /* Set if rule is a fragment rule */ + #define IPT_F_GOTO 0x02 /* Set if jump is a goto */ + #define IPT_F_MASK 0x03 /* All possible flag bits mask. */ ++#define IPT_F_NO_DEF_MATCH 0x80 /* Internal: no default match rules present */ + + /* Values for "inv" field in struct ipt_ip. */ + #define IPT_INV_VIA_IN 0x01 /* Invert the sense of IN IFACE. */ +--- a/net/ipv4/netfilter/ip_tables.c ++++ b/net/ipv4/netfilter/ip_tables.c +@@ -82,6 +82,9 @@ ip_packet_match(const struct iphdr *ip, + + #define FWINV(bool, invflg) ((bool) ^ !!(ipinfo->invflags & (invflg))) + ++ if (ipinfo->flags & IPT_F_NO_DEF_MATCH) ++ return true; ++ + if (FWINV((ip->saddr&ipinfo->smsk.s_addr) != ipinfo->src.s_addr, + IPT_INV_SRCIP) || + FWINV((ip->daddr&ipinfo->dmsk.s_addr) != ipinfo->dst.s_addr, +@@ -135,6 +138,29 @@ ip_packet_match(const struct iphdr *ip, + return true; + } + ++static void ++ip_checkdefault(struct ipt_ip *ip) ++{ ++ static const char iface_mask[IFNAMSIZ] = {}; ++ ++ if (ip->invflags || ip->flags & IPT_F_FRAG) ++ return; ++ ++ if (memcmp(ip->iniface_mask, iface_mask, IFNAMSIZ) != 0) ++ return; ++ ++ if (memcmp(ip->outiface_mask, iface_mask, IFNAMSIZ) != 0) ++ return; ++ ++ if (ip->smsk.s_addr || ip->dmsk.s_addr) ++ return; ++ ++ if (ip->proto) ++ return; ++ ++ ip->flags |= IPT_F_NO_DEF_MATCH; ++} ++ + static bool + ip_checkentry(const struct ipt_ip *ip) + { +@@ -565,7 +591,7 @@ static void cleanup_match(struct xt_entr + } + + static int +-check_entry(const struct ipt_entry *e, const char *name) ++check_entry(struct ipt_entry *e, const char *name) + { + const struct xt_entry_target *t; + +@@ -574,6 +600,8 @@ check_entry(const struct ipt_entry *e, c + return -EINVAL; + } + ++ ip_checkdefault(&e->ip); ++ + if (e->target_offset + sizeof(struct xt_entry_target) > + e->next_offset) + return -EINVAL; +@@ -935,6 +963,7 @@ copy_entries_to_user(unsigned int total_ + const struct xt_table_info *private = table->private; + int ret = 0; + const void *loc_cpu_entry; ++ u8 flags; + + counters = alloc_counters(table); + if (IS_ERR(counters)) +@@ -965,6 +994,14 @@ copy_entries_to_user(unsigned int total_ + ret = -EFAULT; + goto free_counters; + } ++ ++ flags = e->ip.flags & IPT_F_MASK; ++ if (copy_to_user(userptr + off ++ + offsetof(struct ipt_entry, ip.flags), ++ &flags, sizeof(flags)) != 0) { ++ ret = -EFAULT; ++ goto free_counters; ++ } + + for (i = sizeof(struct ipt_entry); + i < e->target_offset; diff --git a/target/linux/generic/patches-3.18/611-netfilter_match_bypass_default_table.patch b/target/linux/generic/patches-3.18/611-netfilter_match_bypass_default_table.patch new file mode 100644 index 0000000..ef993c8 --- /dev/null +++ b/target/linux/generic/patches-3.18/611-netfilter_match_bypass_default_table.patch @@ -0,0 +1,94 @@ +--- a/net/ipv4/netfilter/ip_tables.c ++++ b/net/ipv4/netfilter/ip_tables.c +@@ -310,6 +310,33 @@ struct ipt_entry *ipt_next_entry(const s + return (void *)entry + entry->next_offset; + } + ++static bool ++ipt_handle_default_rule(struct ipt_entry *e, unsigned int *verdict) ++{ ++ struct xt_entry_target *t; ++ struct xt_standard_target *st; ++ ++ if (e->target_offset != sizeof(struct ipt_entry)) ++ return false; ++ ++ if (!(e->ip.flags & IPT_F_NO_DEF_MATCH)) ++ return false; ++ ++ t = ipt_get_target(e); ++ if (t->u.kernel.target->target) ++ return false; ++ ++ st = (struct xt_standard_target *) t; ++ if (st->verdict == XT_RETURN) ++ return false; ++ ++ if (st->verdict >= 0) ++ return false; ++ ++ *verdict = (unsigned)(-st->verdict) - 1; ++ return true; ++} ++ + /* Returns one of the generic firewall policies, like NF_ACCEPT. */ + unsigned int + ipt_do_table(struct sk_buff *skb, +@@ -331,9 +358,33 @@ ipt_do_table(struct sk_buff *skb, + unsigned int addend; + + /* Initialization */ ++ IP_NF_ASSERT(table->valid_hooks & (1 << hook)); ++ local_bh_disable(); ++ private = table->private; ++ cpu = smp_processor_id(); ++ /* ++ * Ensure we load private-> members after we've fetched the base ++ * pointer. ++ */ ++ smp_read_barrier_depends(); ++ table_base = private->entries[cpu]; ++ ++ e = get_entry(table_base, private->hook_entry[hook]); ++ if (ipt_handle_default_rule(e, &verdict)) { ++ ADD_COUNTER(e->counters, skb->len, 1); ++ local_bh_enable(); ++ return verdict; ++ } ++ + ip = ip_hdr(skb); + indev = in ? in->name : nulldevname; + outdev = out ? out->name : nulldevname; ++ ++ addend = xt_write_recseq_begin(); ++ jumpstack = (struct ipt_entry **)private->jumpstack[cpu]; ++ stackptr = per_cpu_ptr(private->stackptr, cpu); ++ origptr = *stackptr; ++ + /* We handle fragments by dealing with the first fragment as + * if it was a normal packet. All other fragments are treated + * normally, except that they will NEVER match rules that ask +@@ -348,23 +399,6 @@ ipt_do_table(struct sk_buff *skb, + acpar.family = NFPROTO_IPV4; + acpar.hooknum = hook; + +- IP_NF_ASSERT(table->valid_hooks & (1 << hook)); +- local_bh_disable(); +- addend = xt_write_recseq_begin(); +- private = table->private; +- cpu = smp_processor_id(); +- /* +- * Ensure we load private-> members after we've fetched the base +- * pointer. +- */ +- smp_read_barrier_depends(); +- table_base = private->entries[cpu]; +- jumpstack = (struct ipt_entry **)private->jumpstack[cpu]; +- stackptr = per_cpu_ptr(private->stackptr, cpu); +- origptr = *stackptr; +- +- e = get_entry(table_base, private->hook_entry[hook]); +- + pr_debug("Entering %s(hook %u); sp at %u (UF %p)\n", + table->name, hook, origptr, + get_entry(table_base, private->underflow[hook])); diff --git a/target/linux/generic/patches-3.18/612-netfilter_match_reduce_memory_access.patch b/target/linux/generic/patches-3.18/612-netfilter_match_reduce_memory_access.patch new file mode 100644 index 0000000..72172d8 --- /dev/null +++ b/target/linux/generic/patches-3.18/612-netfilter_match_reduce_memory_access.patch @@ -0,0 +1,16 @@ +--- a/net/ipv4/netfilter/ip_tables.c ++++ b/net/ipv4/netfilter/ip_tables.c +@@ -85,9 +85,11 @@ ip_packet_match(const struct iphdr *ip, + if (ipinfo->flags & IPT_F_NO_DEF_MATCH) + return true; + +- if (FWINV((ip->saddr&ipinfo->smsk.s_addr) != ipinfo->src.s_addr, ++ if (FWINV(ipinfo->smsk.s_addr && ++ (ip->saddr&ipinfo->smsk.s_addr) != ipinfo->src.s_addr, + IPT_INV_SRCIP) || +- FWINV((ip->daddr&ipinfo->dmsk.s_addr) != ipinfo->dst.s_addr, ++ FWINV(ipinfo->dmsk.s_addr && ++ (ip->daddr&ipinfo->dmsk.s_addr) != ipinfo->dst.s_addr, + IPT_INV_DSTIP)) { + dprintf("Source or dest mismatch.\n"); + diff --git a/target/linux/generic/patches-3.18/613-netfilter_optional_tcp_window_check.patch b/target/linux/generic/patches-3.18/613-netfilter_optional_tcp_window_check.patch new file mode 100644 index 0000000..1d3b37c --- /dev/null +++ b/target/linux/generic/patches-3.18/613-netfilter_optional_tcp_window_check.patch @@ -0,0 +1,36 @@ +--- a/net/netfilter/nf_conntrack_proto_tcp.c ++++ b/net/netfilter/nf_conntrack_proto_tcp.c +@@ -33,6 +33,9 @@ + #include + #include + ++/* Do not check the TCP window for incoming packets */ ++static int nf_ct_tcp_no_window_check __read_mostly = 1; ++ + /* "Be conservative in what you do, + be liberal in what you accept from others." + If it's non-zero, we mark only out of window RST segments as INVALID. */ +@@ -515,6 +518,9 @@ static bool tcp_in_window(const struct n + s32 receiver_offset; + bool res, in_recv_win; + ++ if (nf_ct_tcp_no_window_check) ++ return true; ++ + /* + * Get the required data from the packet. + */ +@@ -1452,6 +1458,13 @@ static struct ctl_table tcp_sysctl_table + .mode = 0644, + .proc_handler = proc_dointvec, + }, ++ { ++ .procname = "nf_conntrack_tcp_no_window_check", ++ .data = &nf_ct_tcp_no_window_check, ++ .maxlen = sizeof(unsigned int), ++ .mode = 0644, ++ .proc_handler = proc_dointvec, ++ }, + { } + }; + diff --git a/target/linux/generic/patches-3.18/615-netfilter_add_xt_id_match.patch b/target/linux/generic/patches-3.18/615-netfilter_add_xt_id_match.patch new file mode 100644 index 0000000..45f59a2 --- /dev/null +++ b/target/linux/generic/patches-3.18/615-netfilter_add_xt_id_match.patch @@ -0,0 +1,95 @@ +--- a/include/uapi/linux/netfilter/Kbuild ++++ b/include/uapi/linux/netfilter/Kbuild +@@ -55,6 +55,7 @@ header-y += xt_ecn.h + header-y += xt_esp.h + header-y += xt_hashlimit.h + header-y += xt_helper.h ++header-y += xt_id.h + header-y += xt_ipcomp.h + header-y += xt_iprange.h + header-y += xt_ipvs.h +--- /dev/null ++++ b/include/uapi/linux/netfilter/xt_id.h +@@ -0,0 +1,8 @@ ++#ifndef _XT_ID_H ++#define _XT_ID_H ++ ++struct xt_id_info { ++ u32 id; ++}; ++ ++#endif /* XT_ID_H */ +--- a/net/netfilter/Kconfig ++++ b/net/netfilter/Kconfig +@@ -1157,6 +1157,13 @@ config NETFILTER_XT_MATCH_IPCOMP + + To compile it as a module, choose M here. If unsure, say N. + ++config NETFILTER_XT_MATCH_ID ++ tristate '"id" match support' ++ depends on NETFILTER_ADVANCED ++ ---help--- ++ This option adds a `id' dummy-match, which allows you to put ++ numeric IDs into your iptables ruleset. ++ + config NETFILTER_XT_MATCH_IPRANGE + tristate '"iprange" address range match support' + depends on NETFILTER_ADVANCED +--- a/net/netfilter/Makefile ++++ b/net/netfilter/Makefile +@@ -143,6 +143,7 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_ESP) += + obj-$(CONFIG_NETFILTER_XT_MATCH_HASHLIMIT) += xt_hashlimit.o + obj-$(CONFIG_NETFILTER_XT_MATCH_HELPER) += xt_helper.o + obj-$(CONFIG_NETFILTER_XT_MATCH_HL) += xt_hl.o ++obj-$(CONFIG_NETFILTER_XT_MATCH_ID) += xt_id.o + obj-$(CONFIG_NETFILTER_XT_MATCH_IPCOMP) += xt_ipcomp.o + obj-$(CONFIG_NETFILTER_XT_MATCH_IPRANGE) += xt_iprange.o + obj-$(CONFIG_NETFILTER_XT_MATCH_IPVS) += xt_ipvs.o +--- /dev/null ++++ b/net/netfilter/xt_id.c +@@ -0,0 +1,45 @@ ++/* ++ * Implements a dummy match to allow attaching IDs to rules ++ * ++ * 2014-08-01 Jo-Philipp Wich ++ */ ++ ++#include ++#include ++#include ++#include ++ ++MODULE_AUTHOR("Jo-Philipp Wich "); ++MODULE_DESCRIPTION("Xtables: No-op match which can be tagged with a 32bit ID"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("ipt_id"); ++MODULE_ALIAS("ip6t_id"); ++ ++static bool ++id_mt(const struct sk_buff *skb, struct xt_action_param *par) ++{ ++ /* We always match */ ++ return true; ++} ++ ++static struct xt_match id_mt_reg __read_mostly = { ++ .name = "id", ++ .revision = 0, ++ .family = NFPROTO_UNSPEC, ++ .match = id_mt, ++ .matchsize = sizeof(struct xt_id_info), ++ .me = THIS_MODULE, ++}; ++ ++static int __init id_mt_init(void) ++{ ++ return xt_register_match(&id_mt_reg); ++} ++ ++static void __exit id_mt_exit(void) ++{ ++ xt_unregister_match(&id_mt_reg); ++} ++ ++module_init(id_mt_init); ++module_exit(id_mt_exit); diff --git a/target/linux/generic/patches-3.18/616-net_optimize_xfrm_calls.patch b/target/linux/generic/patches-3.18/616-net_optimize_xfrm_calls.patch new file mode 100644 index 0000000..2a64d54 --- /dev/null +++ b/target/linux/generic/patches-3.18/616-net_optimize_xfrm_calls.patch @@ -0,0 +1,12 @@ +--- a/net/netfilter/nf_nat_core.c ++++ b/net/netfilter/nf_nat_core.c +@@ -90,6 +90,9 @@ int nf_xfrm_me_harder(struct sk_buff *sk + struct dst_entry *dst; + int err; + ++ if (skb->dev && !dev_net(skb->dev)->xfrm.policy_count[XFRM_POLICY_OUT]) ++ return 0; ++ + err = xfrm_decode_session(skb, &fl, family); + if (err < 0) + return err; diff --git a/target/linux/generic/patches-3.18/620-sched_esfq.patch b/target/linux/generic/patches-3.18/620-sched_esfq.patch new file mode 100644 index 0000000..9726e4a --- /dev/null +++ b/target/linux/generic/patches-3.18/620-sched_esfq.patch @@ -0,0 +1,791 @@ +--- a/include/uapi/linux/pkt_sched.h ++++ b/include/uapi/linux/pkt_sched.h +@@ -226,6 +226,33 @@ struct tc_sfq_xstats { + __s32 allot; + }; + ++/* ESFQ section */ ++ ++enum ++{ ++ /* traditional */ ++ TCA_SFQ_HASH_CLASSIC, ++ TCA_SFQ_HASH_DST, ++ TCA_SFQ_HASH_SRC, ++ TCA_SFQ_HASH_FWMARK, ++ /* conntrack */ ++ TCA_SFQ_HASH_CTORIGDST, ++ TCA_SFQ_HASH_CTORIGSRC, ++ TCA_SFQ_HASH_CTREPLDST, ++ TCA_SFQ_HASH_CTREPLSRC, ++ TCA_SFQ_HASH_CTNATCHG, ++}; ++ ++struct tc_esfq_qopt ++{ ++ unsigned quantum; /* Bytes per round allocated to flow */ ++ int perturb_period; /* Period of hash perturbation */ ++ __u32 limit; /* Maximal packets in queue */ ++ unsigned divisor; /* Hash divisor */ ++ unsigned flows; /* Maximal number of flows */ ++ unsigned hash_kind; /* Hash function to use for flow identification */ ++}; ++ + /* RED section */ + + enum { +--- a/net/sched/Kconfig ++++ b/net/sched/Kconfig +@@ -148,6 +148,37 @@ config NET_SCH_SFQ + To compile this code as a module, choose M here: the + module will be called sch_sfq. + ++config NET_SCH_ESFQ ++ tristate "Enhanced Stochastic Fairness Queueing (ESFQ)" ++ ---help--- ++ Say Y here if you want to use the Enhanced Stochastic Fairness ++ Queueing (ESFQ) packet scheduling algorithm for some of your network ++ devices or as a leaf discipline for a classful qdisc such as HTB or ++ CBQ (see the top of for details and ++ references to the SFQ algorithm). ++ ++ This is an enchanced SFQ version which allows you to control some ++ hardcoded values in the SFQ scheduler. ++ ++ ESFQ also adds control of the hash function used to identify packet ++ flows. The original SFQ discipline hashes by connection; ESFQ add ++ several other hashing methods, such as by src IP or by dst IP, which ++ can be more fair to users in some networking situations. ++ ++ To compile this code as a module, choose M here: the ++ module will be called sch_esfq. ++ ++config NET_SCH_ESFQ_NFCT ++ bool "Connection Tracking Hash Types" ++ depends on NET_SCH_ESFQ && NF_CONNTRACK ++ ---help--- ++ Say Y here to enable support for hashing based on netfilter connection ++ tracking information. This is useful for a router that is also using ++ NAT to connect privately-addressed hosts to the Internet. If you want ++ to provide fair distribution of upstream bandwidth, ESFQ must use ++ connection tracking information, since all outgoing packets will share ++ the same source address. ++ + config NET_SCH_TEQL + tristate "True Link Equalizer (TEQL)" + ---help--- +--- a/net/sched/Makefile ++++ b/net/sched/Makefile +@@ -26,6 +26,7 @@ obj-$(CONFIG_NET_SCH_INGRESS) += sch_ing + obj-$(CONFIG_NET_SCH_DSMARK) += sch_dsmark.o + obj-$(CONFIG_NET_SCH_SFB) += sch_sfb.o + obj-$(CONFIG_NET_SCH_SFQ) += sch_sfq.o ++obj-$(CONFIG_NET_SCH_ESFQ) += sch_esfq.o + obj-$(CONFIG_NET_SCH_TBF) += sch_tbf.o + obj-$(CONFIG_NET_SCH_TEQL) += sch_teql.o + obj-$(CONFIG_NET_SCH_PRIO) += sch_prio.o +--- /dev/null ++++ b/net/sched/sch_esfq.c +@@ -0,0 +1,702 @@ ++/* ++ * net/sched/sch_esfq.c Extended Stochastic Fairness Queueing discipline. ++ * ++ * 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. ++ * ++ * Authors: Alexey Kuznetsov, ++ * ++ * Changes: Alexander Atanasov, ++ * Added dynamic depth,limit,divisor,hash_kind options. ++ * Added dst and src hashes. ++ * ++ * Alexander Clouter, ++ * Ported ESFQ to Linux 2.6. ++ * ++ * Corey Hickey, ++ * Maintenance of the Linux 2.6 port. ++ * Added fwmark hash (thanks to Robert Kurjata). ++ * Added usage of jhash. ++ * Added conntrack support. ++ * Added ctnatchg hash (thanks to Ben Pfountz). ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#ifdef CONFIG_NET_SCH_ESFQ_NFCT ++#include ++#endif ++ ++/* Stochastic Fairness Queuing algorithm. ++ For more comments look at sch_sfq.c. ++ The difference is that you can change limit, depth, ++ hash table size and choose alternate hash types. ++ ++ classic: same as in sch_sfq.c ++ dst: destination IP address ++ src: source IP address ++ fwmark: netfilter mark value ++ ctorigdst: original destination IP address ++ ctorigsrc: original source IP address ++ ctrepldst: reply destination IP address ++ ctreplsrc: reply source IP ++ ++*/ ++ ++#define ESFQ_HEAD 0 ++#define ESFQ_TAIL 1 ++ ++/* This type should contain at least SFQ_DEPTH*2 values */ ++typedef unsigned int esfq_index; ++ ++struct esfq_head ++{ ++ esfq_index next; ++ esfq_index prev; ++}; ++ ++struct esfq_sched_data ++{ ++/* Parameters */ ++ int perturb_period; ++ unsigned quantum; /* Allotment per round: MUST BE >= MTU */ ++ int limit; ++ unsigned depth; ++ unsigned hash_divisor; ++ unsigned hash_kind; ++/* Variables */ ++ struct timer_list perturb_timer; ++ int perturbation; ++ esfq_index tail; /* Index of current slot in round */ ++ esfq_index max_depth; /* Maximal depth */ ++ ++ esfq_index *ht; /* Hash table */ ++ esfq_index *next; /* Active slots link */ ++ short *allot; /* Current allotment per slot */ ++ unsigned short *hash; /* Hash value indexed by slots */ ++ struct sk_buff_head *qs; /* Slot queue */ ++ struct esfq_head *dep; /* Linked list of slots, indexed by depth */ ++}; ++ ++/* This contains the info we will hash. */ ++struct esfq_packet_info ++{ ++ u32 proto; /* protocol or port */ ++ u32 src; /* source from packet header */ ++ u32 dst; /* destination from packet header */ ++ u32 ctorigsrc; /* original source from conntrack */ ++ u32 ctorigdst; /* original destination from conntrack */ ++ u32 ctreplsrc; /* reply source from conntrack */ ++ u32 ctrepldst; /* reply destination from conntrack */ ++ u32 mark; /* netfilter mark (fwmark) */ ++}; ++ ++static __inline__ unsigned esfq_jhash_1word(struct esfq_sched_data *q,u32 a) ++{ ++ return jhash_1word(a, q->perturbation) & (q->hash_divisor-1); ++} ++ ++static __inline__ unsigned esfq_jhash_2words(struct esfq_sched_data *q, u32 a, u32 b) ++{ ++ return jhash_2words(a, b, q->perturbation) & (q->hash_divisor-1); ++} ++ ++static __inline__ unsigned esfq_jhash_3words(struct esfq_sched_data *q, u32 a, u32 b, u32 c) ++{ ++ return jhash_3words(a, b, c, q->perturbation) & (q->hash_divisor-1); ++} ++ ++static unsigned esfq_hash(struct esfq_sched_data *q, struct sk_buff *skb) ++{ ++ struct esfq_packet_info info; ++#ifdef CONFIG_NET_SCH_ESFQ_NFCT ++ enum ip_conntrack_info ctinfo; ++ struct nf_conn *ct = nf_ct_get(skb, &ctinfo); ++#endif ++ ++ switch (skb->protocol) { ++ case __constant_htons(ETH_P_IP): ++ { ++ struct iphdr *iph = ip_hdr(skb); ++ info.dst = iph->daddr; ++ info.src = iph->saddr; ++ if (!(iph->frag_off&htons(IP_MF|IP_OFFSET)) && ++ (iph->protocol == IPPROTO_TCP || ++ iph->protocol == IPPROTO_UDP || ++ iph->protocol == IPPROTO_SCTP || ++ iph->protocol == IPPROTO_DCCP || ++ iph->protocol == IPPROTO_ESP)) ++ info.proto = *(((u32*)iph) + iph->ihl); ++ else ++ info.proto = iph->protocol; ++ break; ++ } ++ case __constant_htons(ETH_P_IPV6): ++ { ++ struct ipv6hdr *iph = ipv6_hdr(skb); ++ /* Hash ipv6 addresses into a u32. This isn't ideal, ++ * but the code is simple. */ ++ info.dst = jhash2(iph->daddr.s6_addr32, 4, q->perturbation); ++ info.src = jhash2(iph->saddr.s6_addr32, 4, q->perturbation); ++ if (iph->nexthdr == IPPROTO_TCP || ++ iph->nexthdr == IPPROTO_UDP || ++ iph->nexthdr == IPPROTO_SCTP || ++ iph->nexthdr == IPPROTO_DCCP || ++ iph->nexthdr == IPPROTO_ESP) ++ info.proto = *(u32*)&iph[1]; ++ else ++ info.proto = iph->nexthdr; ++ break; ++ } ++ default: ++ info.dst = (u32)(unsigned long)skb_dst(skb); ++ info.src = (u32)(unsigned long)skb->sk; ++ info.proto = skb->protocol; ++ } ++ ++ info.mark = skb->mark; ++ ++#ifdef CONFIG_NET_SCH_ESFQ_NFCT ++ /* defaults if there is no conntrack info */ ++ info.ctorigsrc = info.src; ++ info.ctorigdst = info.dst; ++ info.ctreplsrc = info.dst; ++ info.ctrepldst = info.src; ++ /* collect conntrack info */ ++ if (ct && ct != &nf_conntrack_untracked) { ++ if (skb->protocol == __constant_htons(ETH_P_IP)) { ++ info.ctorigsrc = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip; ++ info.ctorigdst = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.ip; ++ info.ctreplsrc = ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip; ++ info.ctrepldst = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip; ++ } ++ else if (skb->protocol == __constant_htons(ETH_P_IPV6)) { ++ /* Again, hash ipv6 addresses into a single u32. */ ++ info.ctorigsrc = jhash2(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip6, 4, q->perturbation); ++ info.ctorigdst = jhash2(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.ip6, 4, q->perturbation); ++ info.ctreplsrc = jhash2(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip6, 4, q->perturbation); ++ info.ctrepldst = jhash2(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip6, 4, q->perturbation); ++ } ++ ++ } ++#endif ++ ++ switch(q->hash_kind) { ++ case TCA_SFQ_HASH_CLASSIC: ++ return esfq_jhash_3words(q, info.dst, info.src, info.proto); ++ case TCA_SFQ_HASH_DST: ++ return esfq_jhash_1word(q, info.dst); ++ case TCA_SFQ_HASH_SRC: ++ return esfq_jhash_1word(q, info.src); ++ case TCA_SFQ_HASH_FWMARK: ++ return esfq_jhash_1word(q, info.mark); ++#ifdef CONFIG_NET_SCH_ESFQ_NFCT ++ case TCA_SFQ_HASH_CTORIGDST: ++ return esfq_jhash_1word(q, info.ctorigdst); ++ case TCA_SFQ_HASH_CTORIGSRC: ++ return esfq_jhash_1word(q, info.ctorigsrc); ++ case TCA_SFQ_HASH_CTREPLDST: ++ return esfq_jhash_1word(q, info.ctrepldst); ++ case TCA_SFQ_HASH_CTREPLSRC: ++ return esfq_jhash_1word(q, info.ctreplsrc); ++ case TCA_SFQ_HASH_CTNATCHG: ++ { ++ if (info.ctorigdst == info.ctreplsrc) ++ return esfq_jhash_1word(q, info.ctorigsrc); ++ return esfq_jhash_1word(q, info.ctreplsrc); ++ } ++#endif ++ default: ++ if (net_ratelimit()) ++ printk(KERN_WARNING "ESFQ: Unknown hash method. Falling back to classic.\n"); ++ } ++ return esfq_jhash_3words(q, info.dst, info.src, info.proto); ++} ++ ++static inline void esfq_link(struct esfq_sched_data *q, esfq_index x) ++{ ++ esfq_index p, n; ++ int d = q->qs[x].qlen + q->depth; ++ ++ p = d; ++ n = q->dep[d].next; ++ q->dep[x].next = n; ++ q->dep[x].prev = p; ++ q->dep[p].next = q->dep[n].prev = x; ++} ++ ++static inline void esfq_dec(struct esfq_sched_data *q, esfq_index x) ++{ ++ esfq_index p, n; ++ ++ n = q->dep[x].next; ++ p = q->dep[x].prev; ++ q->dep[p].next = n; ++ q->dep[n].prev = p; ++ ++ if (n == p && q->max_depth == q->qs[x].qlen + 1) ++ q->max_depth--; ++ ++ esfq_link(q, x); ++} ++ ++static inline void esfq_inc(struct esfq_sched_data *q, esfq_index x) ++{ ++ esfq_index p, n; ++ int d; ++ ++ n = q->dep[x].next; ++ p = q->dep[x].prev; ++ q->dep[p].next = n; ++ q->dep[n].prev = p; ++ d = q->qs[x].qlen; ++ if (q->max_depth < d) ++ q->max_depth = d; ++ ++ esfq_link(q, x); ++} ++ ++static unsigned int esfq_drop(struct Qdisc *sch) ++{ ++ struct esfq_sched_data *q = qdisc_priv(sch); ++ esfq_index d = q->max_depth; ++ struct sk_buff *skb; ++ unsigned int len; ++ ++ /* Queue is full! Find the longest slot and ++ drop a packet from it */ ++ ++ if (d > 1) { ++ esfq_index x = q->dep[d+q->depth].next; ++ skb = q->qs[x].prev; ++ len = skb->len; ++ __skb_unlink(skb, &q->qs[x]); ++ kfree_skb(skb); ++ esfq_dec(q, x); ++ sch->q.qlen--; ++ sch->qstats.drops++; ++ sch->qstats.backlog -= len; ++ return len; ++ } ++ ++ if (d == 1) { ++ /* It is difficult to believe, but ALL THE SLOTS HAVE LENGTH 1. */ ++ d = q->next[q->tail]; ++ q->next[q->tail] = q->next[d]; ++ q->allot[q->next[d]] += q->quantum; ++ skb = q->qs[d].prev; ++ len = skb->len; ++ __skb_unlink(skb, &q->qs[d]); ++ kfree_skb(skb); ++ esfq_dec(q, d); ++ sch->q.qlen--; ++ q->ht[q->hash[d]] = q->depth; ++ sch->qstats.drops++; ++ sch->qstats.backlog -= len; ++ return len; ++ } ++ ++ return 0; ++} ++ ++static void esfq_q_enqueue(struct sk_buff *skb, struct esfq_sched_data *q, unsigned int end) ++{ ++ unsigned hash = esfq_hash(q, skb); ++ unsigned depth = q->depth; ++ esfq_index x; ++ ++ x = q->ht[hash]; ++ if (x == depth) { ++ q->ht[hash] = x = q->dep[depth].next; ++ q->hash[x] = hash; ++ } ++ ++ if (end == ESFQ_TAIL) ++ __skb_queue_tail(&q->qs[x], skb); ++ else ++ __skb_queue_head(&q->qs[x], skb); ++ ++ esfq_inc(q, x); ++ if (q->qs[x].qlen == 1) { /* The flow is new */ ++ if (q->tail == depth) { /* It is the first flow */ ++ q->tail = x; ++ q->next[x] = x; ++ q->allot[x] = q->quantum; ++ } else { ++ q->next[x] = q->next[q->tail]; ++ q->next[q->tail] = x; ++ q->tail = x; ++ } ++ } ++} ++ ++static int esfq_enqueue(struct sk_buff *skb, struct Qdisc* sch) ++{ ++ struct esfq_sched_data *q = qdisc_priv(sch); ++ esfq_q_enqueue(skb, q, ESFQ_TAIL); ++ sch->qstats.backlog += skb->len; ++ if (++sch->q.qlen < q->limit-1) { ++ sch->bstats.bytes += skb->len; ++ sch->bstats.packets++; ++ return 0; ++ } ++ ++ sch->qstats.drops++; ++ esfq_drop(sch); ++ return NET_XMIT_CN; ++} ++ ++static struct sk_buff *esfq_peek(struct Qdisc* sch) ++{ ++ struct esfq_sched_data *q = qdisc_priv(sch); ++ esfq_index a; ++ ++ /* No active slots */ ++ if (q->tail == q->depth) ++ return NULL; ++ ++ a = q->next[q->tail]; ++ return skb_peek(&q->qs[a]); ++} ++ ++static struct sk_buff *esfq_q_dequeue(struct esfq_sched_data *q) ++{ ++ struct sk_buff *skb; ++ unsigned depth = q->depth; ++ esfq_index a, old_a; ++ ++ /* No active slots */ ++ if (q->tail == depth) ++ return NULL; ++ ++ a = old_a = q->next[q->tail]; ++ ++ /* Grab packet */ ++ skb = __skb_dequeue(&q->qs[a]); ++ esfq_dec(q, a); ++ ++ /* Is the slot empty? */ ++ if (q->qs[a].qlen == 0) { ++ q->ht[q->hash[a]] = depth; ++ a = q->next[a]; ++ if (a == old_a) { ++ q->tail = depth; ++ return skb; ++ } ++ q->next[q->tail] = a; ++ q->allot[a] += q->quantum; ++ } else if ((q->allot[a] -= skb->len) <= 0) { ++ q->tail = a; ++ a = q->next[a]; ++ q->allot[a] += q->quantum; ++ } ++ ++ return skb; ++} ++ ++static struct sk_buff *esfq_dequeue(struct Qdisc* sch) ++{ ++ struct esfq_sched_data *q = qdisc_priv(sch); ++ struct sk_buff *skb; ++ ++ skb = esfq_q_dequeue(q); ++ if (skb == NULL) ++ return NULL; ++ sch->q.qlen--; ++ sch->qstats.backlog -= skb->len; ++ return skb; ++} ++ ++static void esfq_q_destroy(struct esfq_sched_data *q) ++{ ++ del_timer(&q->perturb_timer); ++ if(q->ht) ++ kfree(q->ht); ++ if(q->dep) ++ kfree(q->dep); ++ if(q->next) ++ kfree(q->next); ++ if(q->allot) ++ kfree(q->allot); ++ if(q->hash) ++ kfree(q->hash); ++ if(q->qs) ++ kfree(q->qs); ++} ++ ++static void esfq_destroy(struct Qdisc *sch) ++{ ++ struct esfq_sched_data *q = qdisc_priv(sch); ++ esfq_q_destroy(q); ++} ++ ++ ++static void esfq_reset(struct Qdisc* sch) ++{ ++ struct sk_buff *skb; ++ ++ while ((skb = esfq_dequeue(sch)) != NULL) ++ kfree_skb(skb); ++} ++ ++static void esfq_perturbation(unsigned long arg) ++{ ++ struct Qdisc *sch = (struct Qdisc*)arg; ++ struct esfq_sched_data *q = qdisc_priv(sch); ++ ++ q->perturbation = prandom_u32()&0x1F; ++ ++ if (q->perturb_period) { ++ q->perturb_timer.expires = jiffies + q->perturb_period; ++ add_timer(&q->perturb_timer); ++ } ++} ++ ++static unsigned int esfq_check_hash(unsigned int kind) ++{ ++ switch (kind) { ++ case TCA_SFQ_HASH_CTORIGDST: ++ case TCA_SFQ_HASH_CTORIGSRC: ++ case TCA_SFQ_HASH_CTREPLDST: ++ case TCA_SFQ_HASH_CTREPLSRC: ++ case TCA_SFQ_HASH_CTNATCHG: ++#ifndef CONFIG_NET_SCH_ESFQ_NFCT ++ { ++ if (net_ratelimit()) ++ printk(KERN_WARNING "ESFQ: Conntrack hash types disabled in kernel config. Falling back to classic.\n"); ++ return TCA_SFQ_HASH_CLASSIC; ++ } ++#endif ++ case TCA_SFQ_HASH_CLASSIC: ++ case TCA_SFQ_HASH_DST: ++ case TCA_SFQ_HASH_SRC: ++ case TCA_SFQ_HASH_FWMARK: ++ return kind; ++ default: ++ { ++ if (net_ratelimit()) ++ printk(KERN_WARNING "ESFQ: Unknown hash type. Falling back to classic.\n"); ++ return TCA_SFQ_HASH_CLASSIC; ++ } ++ } ++} ++ ++static int esfq_q_init(struct esfq_sched_data *q, struct nlattr *opt) ++{ ++ struct tc_esfq_qopt *ctl = nla_data(opt); ++ esfq_index p = ~0U/2; ++ int i; ++ ++ if (opt && opt->nla_len < nla_attr_size(sizeof(*ctl))) ++ return -EINVAL; ++ ++ q->perturbation = 0; ++ q->hash_kind = TCA_SFQ_HASH_CLASSIC; ++ q->max_depth = 0; ++ if (opt == NULL) { ++ q->perturb_period = 0; ++ q->hash_divisor = 1024; ++ q->tail = q->limit = q->depth = 128; ++ ++ } else { ++ struct tc_esfq_qopt *ctl = nla_data(opt); ++ if (ctl->quantum) ++ q->quantum = ctl->quantum; ++ q->perturb_period = ctl->perturb_period*HZ; ++ q->hash_divisor = ctl->divisor ? : 1024; ++ q->tail = q->limit = q->depth = ctl->flows ? : 128; ++ ++ if ( q->depth > p - 1 ) ++ return -EINVAL; ++ ++ if (ctl->limit) ++ q->limit = min_t(u32, ctl->limit, q->depth); ++ ++ if (ctl->hash_kind) { ++ q->hash_kind = esfq_check_hash(ctl->hash_kind); ++ } ++ } ++ ++ q->ht = kmalloc(q->hash_divisor*sizeof(esfq_index), GFP_KERNEL); ++ if (!q->ht) ++ goto err_case; ++ q->dep = kmalloc((1+q->depth*2)*sizeof(struct esfq_head), GFP_KERNEL); ++ if (!q->dep) ++ goto err_case; ++ q->next = kmalloc(q->depth*sizeof(esfq_index), GFP_KERNEL); ++ if (!q->next) ++ goto err_case; ++ q->allot = kmalloc(q->depth*sizeof(short), GFP_KERNEL); ++ if (!q->allot) ++ goto err_case; ++ q->hash = kmalloc(q->depth*sizeof(unsigned short), GFP_KERNEL); ++ if (!q->hash) ++ goto err_case; ++ q->qs = kmalloc(q->depth*sizeof(struct sk_buff_head), GFP_KERNEL); ++ if (!q->qs) ++ goto err_case; ++ ++ for (i=0; i< q->hash_divisor; i++) ++ q->ht[i] = q->depth; ++ for (i=0; idepth; i++) { ++ skb_queue_head_init(&q->qs[i]); ++ q->dep[i+q->depth].next = i+q->depth; ++ q->dep[i+q->depth].prev = i+q->depth; ++ } ++ ++ for (i=0; idepth; i++) ++ esfq_link(q, i); ++ return 0; ++err_case: ++ esfq_q_destroy(q); ++ return -ENOBUFS; ++} ++ ++static int esfq_init(struct Qdisc *sch, struct nlattr *opt) ++{ ++ struct esfq_sched_data *q = qdisc_priv(sch); ++ int err; ++ ++ q->quantum = psched_mtu(qdisc_dev(sch)); /* default */ ++ if ((err = esfq_q_init(q, opt))) ++ return err; ++ ++ init_timer(&q->perturb_timer); ++ q->perturb_timer.data = (unsigned long)sch; ++ q->perturb_timer.function = esfq_perturbation; ++ if (q->perturb_period) { ++ q->perturb_timer.expires = jiffies + q->perturb_period; ++ add_timer(&q->perturb_timer); ++ } ++ ++ return 0; ++} ++ ++static int esfq_change(struct Qdisc *sch, struct nlattr *opt) ++{ ++ struct esfq_sched_data *q = qdisc_priv(sch); ++ struct esfq_sched_data new; ++ struct sk_buff *skb; ++ int err; ++ ++ /* set up new queue */ ++ memset(&new, 0, sizeof(struct esfq_sched_data)); ++ new.quantum = psched_mtu(qdisc_dev(sch)); /* default */ ++ if ((err = esfq_q_init(&new, opt))) ++ return err; ++ ++ /* copy all packets from the old queue to the new queue */ ++ sch_tree_lock(sch); ++ while ((skb = esfq_q_dequeue(q)) != NULL) ++ esfq_q_enqueue(skb, &new, ESFQ_TAIL); ++ ++ /* clean up the old queue */ ++ esfq_q_destroy(q); ++ ++ /* copy elements of the new queue into the old queue */ ++ q->perturb_period = new.perturb_period; ++ q->quantum = new.quantum; ++ q->limit = new.limit; ++ q->depth = new.depth; ++ q->hash_divisor = new.hash_divisor; ++ q->hash_kind = new.hash_kind; ++ q->tail = new.tail; ++ q->max_depth = new.max_depth; ++ q->ht = new.ht; ++ q->dep = new.dep; ++ q->next = new.next; ++ q->allot = new.allot; ++ q->hash = new.hash; ++ q->qs = new.qs; ++ ++ /* finish up */ ++ if (q->perturb_period) { ++ q->perturb_timer.expires = jiffies + q->perturb_period; ++ add_timer(&q->perturb_timer); ++ } else { ++ q->perturbation = 0; ++ } ++ sch_tree_unlock(sch); ++ return 0; ++} ++ ++static int esfq_dump(struct Qdisc *sch, struct sk_buff *skb) ++{ ++ struct esfq_sched_data *q = qdisc_priv(sch); ++ unsigned char *b = skb_tail_pointer(skb); ++ struct tc_esfq_qopt opt; ++ ++ opt.quantum = q->quantum; ++ opt.perturb_period = q->perturb_period/HZ; ++ ++ opt.limit = q->limit; ++ opt.divisor = q->hash_divisor; ++ opt.flows = q->depth; ++ opt.hash_kind = q->hash_kind; ++ ++ if (nla_put(skb, TCA_OPTIONS, sizeof(opt), &opt)) ++ goto nla_put_failure; ++ ++ return skb->len; ++ ++nla_put_failure: ++ nlmsg_trim(skb, b); ++ return -1; ++} ++ ++static struct Qdisc_ops esfq_qdisc_ops = ++{ ++ .next = NULL, ++ .cl_ops = NULL, ++ .id = "esfq", ++ .priv_size = sizeof(struct esfq_sched_data), ++ .enqueue = esfq_enqueue, ++ .dequeue = esfq_dequeue, ++ .peek = esfq_peek, ++ .drop = esfq_drop, ++ .init = esfq_init, ++ .reset = esfq_reset, ++ .destroy = esfq_destroy, ++ .change = esfq_change, ++ .dump = esfq_dump, ++ .owner = THIS_MODULE, ++}; ++ ++static int __init esfq_module_init(void) ++{ ++ return register_qdisc(&esfq_qdisc_ops); ++} ++static void __exit esfq_module_exit(void) ++{ ++ unregister_qdisc(&esfq_qdisc_ops); ++} ++module_init(esfq_module_init) ++module_exit(esfq_module_exit) ++MODULE_LICENSE("GPL"); diff --git a/target/linux/generic/patches-3.18/621-sched_act_connmark.patch b/target/linux/generic/patches-3.18/621-sched_act_connmark.patch new file mode 100644 index 0000000..9459749 --- /dev/null +++ b/target/linux/generic/patches-3.18/621-sched_act_connmark.patch @@ -0,0 +1,161 @@ +--- /dev/null ++++ b/net/sched/act_connmark.c +@@ -0,0 +1,126 @@ ++/* ++ * Copyright (c) 2011 Felix Fietkau ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#define TCA_ACT_CONNMARK 20 ++ ++#define CONNMARK_TAB_MASK 3 ++ ++static int tcf_connmark(struct sk_buff *skb, const struct tc_action *a, ++ struct tcf_result *res) ++{ ++ struct nf_conn *c; ++ enum ip_conntrack_info ctinfo; ++ int proto; ++ int r; ++ ++ if (skb->protocol == htons(ETH_P_IP)) { ++ if (skb->len < sizeof(struct iphdr)) ++ goto out; ++ proto = PF_INET; ++ } else if (skb->protocol == htons(ETH_P_IPV6)) { ++ if (skb->len < sizeof(struct ipv6hdr)) ++ goto out; ++ proto = PF_INET6; ++ } else ++ goto out; ++ ++ r = nf_conntrack_in(dev_net(skb->dev), proto, NF_INET_PRE_ROUTING, skb); ++ if (r != NF_ACCEPT) ++ goto out; ++ ++ c = nf_ct_get(skb, &ctinfo); ++ if (!c) ++ goto out; ++ ++ skb->mark = c->mark; ++ nf_conntrack_put(skb->nfct); ++ skb->nfct = NULL; ++ ++out: ++ return TC_ACT_PIPE; ++} ++ ++static int tcf_connmark_init(struct net *net, struct nlattr *nla, ++ struct nlattr *est, struct tc_action *a, ++ int ovr, int bind) ++{ ++ int ret = 0; ++ ++ if (!tcf_hash_check(0, a, bind)) { ++ ret = tcf_hash_create(0, est, a, sizeof(struct tcf_common), bind); ++ if (ret) ++ return ret; ++ ++ tcf_hash_insert(a); ++ ret = ACT_P_CREATED; ++ } else { ++ if (!ovr) { ++ tcf_hash_release(a, bind); ++ return -EEXIST; ++ } ++ } ++ ++ return ret; ++} ++ ++static inline int tcf_connmark_dump(struct sk_buff *skb, struct tc_action *a, ++ int bind, int ref) ++{ ++ return skb->len; ++} ++ ++static struct tc_action_ops act_connmark_ops = { ++ .kind = "connmark", ++ .type = TCA_ACT_CONNMARK, ++ .owner = THIS_MODULE, ++ .act = tcf_connmark, ++ .dump = tcf_connmark_dump, ++ .init = tcf_connmark_init, ++}; ++ ++MODULE_AUTHOR("Felix Fietkau "); ++MODULE_DESCRIPTION("Connection tracking mark restoring"); ++MODULE_LICENSE("GPL"); ++ ++static int __init connmark_init_module(void) ++{ ++ ++ return tcf_register_action(&act_connmark_ops, CONNMARK_TAB_MASK); ++} ++ ++static void __exit connmark_cleanup_module(void) ++{ ++ tcf_unregister_action(&act_connmark_ops); ++} ++ ++module_init(connmark_init_module); ++module_exit(connmark_cleanup_module); +--- a/net/sched/Kconfig ++++ b/net/sched/Kconfig +@@ -717,6 +717,19 @@ config NET_ACT_CSUM + To compile this code as a module, choose M here: the + module will be called act_csum. + ++config NET_ACT_CONNMARK ++ tristate "Connection Tracking Marking" ++ depends on NET_CLS_ACT ++ depends on NF_CONNTRACK ++ depends on NF_CONNTRACK_MARK ++ ---help--- ++ Say Y here to restore the connmark from a scheduler action ++ ++ If unsure, say N. ++ ++ To compile this code as a module, choose M here: the ++ module will be called act_connmark. ++ + config NET_CLS_IND + bool "Incoming device classification" + depends on NET_CLS_U32 || NET_CLS_FW +--- a/net/sched/Makefile ++++ b/net/sched/Makefile +@@ -16,6 +16,7 @@ obj-$(CONFIG_NET_ACT_PEDIT) += act_pedit + obj-$(CONFIG_NET_ACT_SIMP) += act_simple.o + obj-$(CONFIG_NET_ACT_SKBEDIT) += act_skbedit.o + obj-$(CONFIG_NET_ACT_CSUM) += act_csum.o ++obj-$(CONFIG_NET_ACT_CONNMARK) += act_connmark.o + obj-$(CONFIG_NET_SCH_FIFO) += sch_fifo.o + obj-$(CONFIG_NET_SCH_CBQ) += sch_cbq.o + obj-$(CONFIG_NET_SCH_HTB) += sch_htb.o diff --git a/target/linux/generic/patches-3.18/630-packet_socket_type.patch b/target/linux/generic/patches-3.18/630-packet_socket_type.patch new file mode 100644 index 0000000..fa057b2 --- /dev/null +++ b/target/linux/generic/patches-3.18/630-packet_socket_type.patch @@ -0,0 +1,134 @@ +This patch allows the user to specify desired packet types (outgoing, +broadcast, unicast, etc.) on packet sockets via setsockopt. +This can reduce the load in situations where only a limited number +of packet types are necessary + +Signed-off-by: Felix Fietkau + +--- a/include/uapi/linux/if_packet.h ++++ b/include/uapi/linux/if_packet.h +@@ -31,6 +31,8 @@ struct sockaddr_ll { + #define PACKET_KERNEL 7 /* To kernel space */ + /* Unused, PACKET_FASTROUTE and PACKET_LOOPBACK are invisible to user space */ + #define PACKET_FASTROUTE 6 /* Fastrouted frame */ ++#define PACKET_MASK_ANY 0xffffffff /* mask for packet type bits */ ++ + + /* Packet socket options */ + +@@ -54,6 +56,7 @@ struct sockaddr_ll { + #define PACKET_FANOUT 18 + #define PACKET_TX_HAS_OFF 19 + #define PACKET_QDISC_BYPASS 20 ++#define PACKET_RECV_TYPE 21 + + #define PACKET_FANOUT_HASH 0 + #define PACKET_FANOUT_LB 1 +--- a/net/packet/af_packet.c ++++ b/net/packet/af_packet.c +@@ -1516,6 +1516,7 @@ static int packet_rcv_spkt(struct sk_buf + { + struct sock *sk; + struct sockaddr_pkt *spkt; ++ struct packet_sock *po; + + /* + * When we registered the protocol we saved the socket in the data +@@ -1523,6 +1524,7 @@ static int packet_rcv_spkt(struct sk_buf + */ + + sk = pt->af_packet_priv; ++ po = pkt_sk(sk); + + /* + * Yank back the headers [hope the device set this +@@ -1535,7 +1537,7 @@ static int packet_rcv_spkt(struct sk_buf + * so that this procedure is noop. + */ + +- if (skb->pkt_type == PACKET_LOOPBACK) ++ if (!(po->pkt_type & (1 << skb->pkt_type))) + goto out; + + if (!net_eq(dev_net(dev), sock_net(sk))) +@@ -1742,12 +1744,12 @@ static int packet_rcv(struct sk_buff *sk + int skb_len = skb->len; + unsigned int snaplen, res; + +- if (skb->pkt_type == PACKET_LOOPBACK) +- goto drop; +- + sk = pt->af_packet_priv; + po = pkt_sk(sk); + ++ if (!(po->pkt_type & (1 << skb->pkt_type))) ++ goto drop; ++ + if (!net_eq(dev_net(dev), sock_net(sk))) + goto drop; + +@@ -1867,12 +1869,12 @@ static int tpacket_rcv(struct sk_buff *s + BUILD_BUG_ON(TPACKET_ALIGN(sizeof(*h.h2)) != 32); + BUILD_BUG_ON(TPACKET_ALIGN(sizeof(*h.h3)) != 48); + +- if (skb->pkt_type == PACKET_LOOPBACK) +- goto drop; +- + sk = pt->af_packet_priv; + po = pkt_sk(sk); + ++ if (!(po->pkt_type & (1 << skb->pkt_type))) ++ goto drop; ++ + if (!net_eq(dev_net(dev), sock_net(sk))) + goto drop; + +@@ -2809,6 +2811,7 @@ static int packet_create(struct net *net + spin_lock_init(&po->bind_lock); + mutex_init(&po->pg_vec_lock); + po->prot_hook.func = packet_rcv; ++ po->pkt_type = PACKET_MASK_ANY & ~(1 << PACKET_LOOPBACK); + + if (sock->type == SOCK_PACKET) + po->prot_hook.func = packet_rcv_spkt; +@@ -3389,6 +3392,16 @@ packet_setsockopt(struct socket *sock, i + po->xmit = val ? packet_direct_xmit : dev_queue_xmit; + return 0; + } ++ case PACKET_RECV_TYPE: ++ { ++ unsigned int val; ++ if (optlen != sizeof(val)) ++ return -EINVAL; ++ if (copy_from_user(&val, optval, sizeof(val))) ++ return -EFAULT; ++ po->pkt_type = val & ~BIT(PACKET_LOOPBACK); ++ return 0; ++ } + default: + return -ENOPROTOOPT; + } +@@ -3440,6 +3453,13 @@ static int packet_getsockopt(struct sock + case PACKET_VNET_HDR: + val = po->has_vnet_hdr; + break; ++ case PACKET_RECV_TYPE: ++ if (len > sizeof(unsigned int)) ++ len = sizeof(unsigned int); ++ val = po->pkt_type; ++ ++ data = &val; ++ break; + case PACKET_VERSION: + val = po->tp_version; + break; +--- a/net/packet/internal.h ++++ b/net/packet/internal.h +@@ -117,6 +117,7 @@ struct packet_sock { + struct net_device __rcu *cached_dev; + int (*xmit)(struct sk_buff *skb); + struct packet_type prot_hook ____cacheline_aligned_in_smp; ++ unsigned int pkt_type; + }; + + static struct packet_sock *pkt_sk(struct sock *sk) diff --git a/target/linux/generic/patches-3.18/640-bridge_no_eap_forward.patch b/target/linux/generic/patches-3.18/640-bridge_no_eap_forward.patch new file mode 100644 index 0000000..7f38c4a --- /dev/null +++ b/target/linux/generic/patches-3.18/640-bridge_no_eap_forward.patch @@ -0,0 +1,23 @@ +From: Felix Fietkau +Subject: [PATCH] bridge: no EAP forward + +When bridging, do not forward EAP frames to other ports, only deliver +them locally. +Fixes WPA authentication issues with multiples APs that are connected to +each other via bridges. +--- +--- a/net/bridge/br_input.c ++++ b/net/bridge/br_input.c +@@ -97,7 +97,11 @@ int br_handle_frame_finish(struct sk_buf + + dst = NULL; + +- if (is_broadcast_ether_addr(dest)) { ++ if (skb->protocol == htons(ETH_P_PAE)) { ++ skb2 = skb; ++ /* Do not forward 802.1x/EAP frames */ ++ skb = NULL; ++ } else if (is_broadcast_ether_addr(dest)) { + skb2 = skb; + unicast = false; + } else if (is_multicast_ether_addr(dest)) { diff --git a/target/linux/generic/patches-3.18/641-bridge_always_accept_eap.patch b/target/linux/generic/patches-3.18/641-bridge_always_accept_eap.patch new file mode 100644 index 0000000..7d314ad --- /dev/null +++ b/target/linux/generic/patches-3.18/641-bridge_always_accept_eap.patch @@ -0,0 +1,17 @@ +From: Felix Fietkau +Subject: [PATCH] bridge: always accept EAP + +Allow EAP frames to pass through bridges even in learning state. Fixes +issues with WDS. +--- +--- a/net/bridge/br_input.c ++++ b/net/bridge/br_input.c +@@ -84,7 +84,7 @@ int br_handle_frame_finish(struct sk_buf + br_multicast_rcv(br, p, skb, vid)) + goto drop; + +- if (p->state == BR_STATE_LEARNING) ++ if ((p->state == BR_STATE_LEARNING) && skb->protocol != htons(ETH_P_PAE)) + goto drop; + + BR_INPUT_SKB_CB(skb)->brdev = br->dev; diff --git a/target/linux/generic/patches-3.18/642-bridge_port_isolate.patch b/target/linux/generic/patches-3.18/642-bridge_port_isolate.patch new file mode 100644 index 0000000..df3a657 --- /dev/null +++ b/target/linux/generic/patches-3.18/642-bridge_port_isolate.patch @@ -0,0 +1,107 @@ +From: Felix Fietkau +Subject: [PATCH] bridge: port isolate + +Isolating individual bridge ports +--- +--- a/net/bridge/br_private.h ++++ b/net/bridge/br_private.h +@@ -172,6 +172,7 @@ struct net_bridge_port + #define BR_FLOOD 0x00000040 + #define BR_AUTO_MASK (BR_FLOOD | BR_LEARNING) + #define BR_PROMISC 0x00000080 ++#define BR_ISOLATE_MODE 0x00000100 + + #ifdef CONFIG_BRIDGE_IGMP_SNOOPING + struct bridge_mcast_own_query ip4_own_query; +--- a/net/bridge/br_sysfs_if.c ++++ b/net/bridge/br_sysfs_if.c +@@ -171,6 +171,22 @@ BRPORT_ATTR_FLAG(root_block, BR_ROOT_BLO + BRPORT_ATTR_FLAG(learning, BR_LEARNING); + BRPORT_ATTR_FLAG(unicast_flood, BR_FLOOD); + ++static ssize_t show_isolate_mode(struct net_bridge_port *p, char *buf) ++{ ++ int isolate_mode = (p->flags & BR_ISOLATE_MODE) ? 1 : 0; ++ return sprintf(buf, "%d\n", isolate_mode); ++} ++static ssize_t store_isolate_mode(struct net_bridge_port *p, unsigned long v) ++{ ++ if (v) ++ p->flags |= BR_ISOLATE_MODE; ++ else ++ p->flags &= ~BR_ISOLATE_MODE; ++ return 0; ++} ++static BRPORT_ATTR(isolate_mode, S_IRUGO | S_IWUSR, ++ show_isolate_mode, store_isolate_mode); ++ + #ifdef CONFIG_BRIDGE_IGMP_SNOOPING + static ssize_t show_multicast_router(struct net_bridge_port *p, char *buf) + { +@@ -213,6 +229,7 @@ static const struct brport_attribute *br + &brport_attr_multicast_router, + &brport_attr_multicast_fast_leave, + #endif ++ &brport_attr_isolate_mode, + NULL + }; + +--- a/net/bridge/br_input.c ++++ b/net/bridge/br_input.c +@@ -120,8 +120,8 @@ int br_handle_frame_finish(struct sk_buf + + unicast = false; + br->dev->stats.multicast++; +- } else if ((dst = __br_fdb_get(br, dest, vid)) && +- dst->is_local) { ++ } else if ((p->flags & BR_ISOLATE_MODE) || ++ ((dst = __br_fdb_get(br, dest, vid)) && dst->is_local)) { + skb2 = skb; + /* Do not forward the packet since it's local. */ + skb = NULL; +--- a/net/bridge/br_forward.c ++++ b/net/bridge/br_forward.c +@@ -117,7 +117,7 @@ EXPORT_SYMBOL_GPL(br_deliver); + /* called with rcu_read_lock */ + void br_forward(const struct net_bridge_port *to, struct sk_buff *skb, struct sk_buff *skb0) + { +- if (should_deliver(to, skb)) { ++ if (should_deliver(to, skb) && !(to->flags & BR_ISOLATE_MODE)) { + if (skb0) + deliver_clone(to, skb, __br_forward); + else +@@ -173,7 +173,7 @@ static void br_flood(struct net_bridge * + struct sk_buff *skb0, + void (*__packet_hook)(const struct net_bridge_port *p, + struct sk_buff *skb), +- bool unicast) ++ bool unicast, bool forward) + { + struct net_bridge_port *p; + struct net_bridge_port *prev; +@@ -181,6 +181,8 @@ static void br_flood(struct net_bridge * + prev = NULL; + + list_for_each_entry_rcu(p, &br->port_list, list) { ++ if (forward && (p->flags & BR_ISOLATE_MODE)) ++ continue; + /* Do not flood unicast traffic to ports that turn it off */ + if (unicast && !(p->flags & BR_FLOOD)) + continue; +@@ -207,14 +209,14 @@ out: + /* called with rcu_read_lock */ + void br_flood_deliver(struct net_bridge *br, struct sk_buff *skb, bool unicast) + { +- br_flood(br, skb, NULL, __br_deliver, unicast); ++ br_flood(br, skb, NULL, __br_deliver, unicast, false); + } + + /* called under bridge lock */ + void br_flood_forward(struct net_bridge *br, struct sk_buff *skb, + struct sk_buff *skb2, bool unicast) + { +- br_flood(br, skb, skb2, __br_forward, unicast); ++ br_flood(br, skb, skb2, __br_forward, unicast, true); + } + + #ifdef CONFIG_BRIDGE_IGMP_SNOOPING diff --git a/target/linux/generic/patches-3.18/643-bridge_remove_ipv6_dependency.patch b/target/linux/generic/patches-3.18/643-bridge_remove_ipv6_dependency.patch new file mode 100644 index 0000000..25f49c0 --- /dev/null +++ b/target/linux/generic/patches-3.18/643-bridge_remove_ipv6_dependency.patch @@ -0,0 +1,123 @@ +From: Jonas Gorski +Subject: [PATCH] bridge: remove IPv6 depependency of bridge in 2.6.38+ + +Since 2.6.38 the bridge module has a dependency to IPv6 if IPv6 is +enabled. Since the IPv6 module isn't exactly lightweight and bridge also +only needs a single function from IPv6, it's rather easy to create a +common "lib" module with a RCU pointer to the actual implementation, if +the IPv6 module is loaded (although slightly hackish). + +The codepath seems to be only taken when using IPv6, so there should be +no negative side effects when IPv6 isn't loaded. I did not measure how +big the performance impact is. +--- +--- a/include/net/addrconf.h ++++ b/include/net/addrconf.h +@@ -88,6 +88,12 @@ int ipv6_rcv_saddr_equal(const struct so + void addrconf_join_solict(struct net_device *dev, const struct in6_addr *addr); + void addrconf_leave_solict(struct inet6_dev *idev, const struct in6_addr *addr); + ++extern int (*ipv6_dev_get_saddr_hook)(struct net *net, ++ const struct net_device *dev, ++ const struct in6_addr *daddr, ++ unsigned int prefs, ++ struct in6_addr *saddr); ++ + static inline unsigned long addrconf_timeout_fixup(u32 timeout, + unsigned int unit) + { +--- a/net/bridge/Kconfig ++++ b/net/bridge/Kconfig +@@ -6,7 +6,6 @@ config BRIDGE + tristate "802.1d Ethernet Bridging" + select LLC + select STP +- depends on IPV6 || IPV6=n + ---help--- + If you say Y here, then your Linux box will be able to act as an + Ethernet bridge, which means that the different Ethernet segments it +--- a/net/ipv6/Makefile ++++ b/net/ipv6/Makefile +@@ -45,6 +45,7 @@ obj-y += addrconf_core.o exthdrs_core.o + obj-$(CONFIG_INET) += output_core.o protocol.o $(ipv6-offload) + + obj-$(subst m,y,$(CONFIG_IPV6)) += inet6_hashtables.o ++obj-$(subst m,y,$(CONFIG_IPV6)) += inet6_stubs.o + + ifneq ($(CONFIG_IPV6),) + obj-$(CONFIG_NET_UDP_TUNNEL) += ip6_udp_tunnel.o +--- a/net/ipv6/addrconf.c ++++ b/net/ipv6/addrconf.c +@@ -1317,7 +1317,7 @@ out: + return ret; + } + +-int ipv6_dev_get_saddr(struct net *net, const struct net_device *dst_dev, ++static int __ipv6_dev_get_saddr(struct net *net, const struct net_device *dst_dev, + const struct in6_addr *daddr, unsigned int prefs, + struct in6_addr *saddr) + { +@@ -1442,7 +1442,6 @@ try_nextdev: + in6_ifa_put(hiscore->ifa); + return 0; + } +-EXPORT_SYMBOL(ipv6_dev_get_saddr); + + int __ipv6_get_lladdr(struct inet6_dev *idev, struct in6_addr *addr, + u32 banned_flags) +@@ -5451,6 +5450,9 @@ int __init addrconf_init(void) + + ipv6_addr_label_rtnl_register(); + ++ BUG_ON(ipv6_dev_get_saddr_hook != NULL); ++ rcu_assign_pointer(ipv6_dev_get_saddr_hook, __ipv6_dev_get_saddr); ++ + return 0; + errout: + rtnl_af_unregister(&inet6_ops); +@@ -5470,6 +5472,9 @@ void addrconf_cleanup(void) + struct net_device *dev; + int i; + ++ rcu_assign_pointer(ipv6_dev_get_saddr_hook, NULL); ++ synchronize_rcu(); ++ + unregister_netdevice_notifier(&ipv6_dev_notf); + unregister_pernet_subsys(&addrconf_ops); + ipv6_addr_label_cleanup(); +--- /dev/null ++++ b/net/ipv6/inet6_stubs.c +@@ -0,0 +1,33 @@ ++/* ++ * 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. ++ */ ++#include ++#include ++ ++int (*ipv6_dev_get_saddr_hook)(struct net *net, const struct net_device *dev, ++ const struct in6_addr *daddr, unsigned int prefs, ++ struct in6_addr *saddr); ++ ++EXPORT_SYMBOL(ipv6_dev_get_saddr_hook); ++ ++int ipv6_dev_get_saddr(struct net *net, const struct net_device *dst_dev, ++ const struct in6_addr *daddr, unsigned int prefs, ++ struct in6_addr *saddr) ++{ ++ int ret = -EADDRNOTAVAIL; ++ typeof(ipv6_dev_get_saddr_hook) dev_get_saddr; ++ ++ rcu_read_lock(); ++ dev_get_saddr = rcu_dereference(ipv6_dev_get_saddr_hook); ++ ++ if (dev_get_saddr) ++ ret = dev_get_saddr(net, dst_dev, daddr, prefs, saddr); ++ ++ rcu_read_unlock(); ++ return ret; ++} ++EXPORT_SYMBOL(ipv6_dev_get_saddr); ++ diff --git a/target/linux/generic/patches-3.18/645-bridge_multicast_to_unicast.patch b/target/linux/generic/patches-3.18/645-bridge_multicast_to_unicast.patch new file mode 100644 index 0000000..e23a6c4 --- /dev/null +++ b/target/linux/generic/patches-3.18/645-bridge_multicast_to_unicast.patch @@ -0,0 +1,390 @@ +From: Felix Fietkau +Subject: [PATCH] bridge: multicast to unicast + +Implement optinal multicast->unicast conversion for igmp snooping +--- +--- a/net/bridge/br_multicast.c ++++ b/net/bridge/br_multicast.c +@@ -635,7 +635,8 @@ struct net_bridge_port_group *br_multica + struct net_bridge_port *port, + struct br_ip *group, + struct net_bridge_port_group __rcu *next, +- unsigned char state) ++ unsigned char state, ++ const unsigned char *src) + { + struct net_bridge_port_group *p; + +@@ -650,12 +651,33 @@ struct net_bridge_port_group *br_multica + hlist_add_head(&p->mglist, &port->mglist); + setup_timer(&p->timer, br_multicast_port_group_expired, + (unsigned long)p); ++ if ((port->flags & BR_MULTICAST_TO_UCAST) && src) { ++ memcpy(p->eth_addr, src, ETH_ALEN); ++ p->unicast = true; ++ } + return p; + } + ++static bool br_port_group_equal(struct net_bridge_port_group *p, ++ struct net_bridge_port *port, ++ const unsigned char *src) ++{ ++ if (p->port != port) ++ return false; ++ ++ if (!p->unicast) ++ return true; ++ ++ if (!src) ++ return false; ++ ++ return ether_addr_equal(src, p->eth_addr); ++} ++ + static int br_multicast_add_group(struct net_bridge *br, + struct net_bridge_port *port, +- struct br_ip *group) ++ struct br_ip *group, ++ const unsigned char *src) + { + struct net_bridge_mdb_entry *mp; + struct net_bridge_port_group *p; +@@ -682,13 +704,13 @@ static int br_multicast_add_group(struct + for (pp = &mp->ports; + (p = mlock_dereference(*pp, br)) != NULL; + pp = &p->next) { +- if (p->port == port) ++ if (br_port_group_equal(p, port, src)) + goto found; + if ((unsigned long)p->port < (unsigned long)port) + break; + } + +- p = br_multicast_new_port_group(port, group, *pp, MDB_TEMPORARY); ++ p = br_multicast_new_port_group(port, group, *pp, MDB_TEMPORARY, src); + if (unlikely(!p)) + goto err; + rcu_assign_pointer(*pp, p); +@@ -707,7 +729,7 @@ err: + static int br_ip4_multicast_add_group(struct net_bridge *br, + struct net_bridge_port *port, + __be32 group, +- __u16 vid) ++ __u16 vid, const unsigned char *src) + { + struct br_ip br_group; + +@@ -718,14 +740,14 @@ static int br_ip4_multicast_add_group(st + br_group.proto = htons(ETH_P_IP); + br_group.vid = vid; + +- return br_multicast_add_group(br, port, &br_group); ++ return br_multicast_add_group(br, port, &br_group, src); + } + + #if IS_ENABLED(CONFIG_IPV6) + static int br_ip6_multicast_add_group(struct net_bridge *br, + struct net_bridge_port *port, + const struct in6_addr *group, +- __u16 vid) ++ __u16 vid, const unsigned char *src) + { + struct br_ip br_group; + +@@ -736,7 +758,7 @@ static int br_ip6_multicast_add_group(st + br_group.proto = htons(ETH_P_IPV6); + br_group.vid = vid; + +- return br_multicast_add_group(br, port, &br_group); ++ return br_multicast_add_group(br, port, &br_group, src); + } + #endif + +@@ -965,6 +987,7 @@ static int br_ip4_multicast_igmp3_report + struct sk_buff *skb, + u16 vid) + { ++ const unsigned char *src; + struct igmpv3_report *ih; + struct igmpv3_grec *grec; + int i; +@@ -1008,7 +1031,8 @@ static int br_ip4_multicast_igmp3_report + continue; + } + +- err = br_ip4_multicast_add_group(br, port, group, vid); ++ src = eth_hdr(skb)->h_source; ++ err = br_ip4_multicast_add_group(br, port, group, vid, src); + if (err) + break; + } +@@ -1022,6 +1046,7 @@ static int br_ip6_multicast_mld2_report( + struct sk_buff *skb, + u16 vid) + { ++ const unsigned char *src; + struct icmp6hdr *icmp6h; + struct mld2_grec *grec; + int i; +@@ -1069,8 +1094,9 @@ static int br_ip6_multicast_mld2_report( + continue; + } + ++ src = eth_hdr(skb)->h_source; + err = br_ip6_multicast_add_group(br, port, &grec->grec_mca, +- vid); ++ vid, src); + if (err) + break; + } +@@ -1406,7 +1432,8 @@ br_multicast_leave_group(struct net_brid + struct net_bridge_port *port, + struct br_ip *group, + struct bridge_mcast_other_query *other_query, +- struct bridge_mcast_own_query *own_query) ++ struct bridge_mcast_own_query *own_query, ++ const unsigned char *src) + { + struct net_bridge_mdb_htable *mdb; + struct net_bridge_mdb_entry *mp; +@@ -1456,7 +1483,7 @@ br_multicast_leave_group(struct net_brid + for (pp = &mp->ports; + (p = mlock_dereference(*pp, br)) != NULL; + pp = &p->next) { +- if (p->port != port) ++ if (!br_port_group_equal(p, port, src)) + continue; + + rcu_assign_pointer(*pp, p->next); +@@ -1490,7 +1517,7 @@ br_multicast_leave_group(struct net_brid + for (p = mlock_dereference(mp->ports, br); + p != NULL; + p = mlock_dereference(p->next, br)) { +- if (p->port != port) ++ if (!br_port_group_equal(p, port, src)) + continue; + + if (!hlist_unhashed(&p->mglist) && +@@ -1508,8 +1535,8 @@ out: + + static void br_ip4_multicast_leave_group(struct net_bridge *br, + struct net_bridge_port *port, +- __be32 group, +- __u16 vid) ++ __be32 group, __u16 vid, ++ const unsigned char *src) + { + struct br_ip br_group; + struct bridge_mcast_own_query *own_query; +@@ -1524,14 +1551,14 @@ static void br_ip4_multicast_leave_group + br_group.vid = vid; + + br_multicast_leave_group(br, port, &br_group, &br->ip4_other_query, +- own_query); ++ own_query, src); + } + + #if IS_ENABLED(CONFIG_IPV6) + static void br_ip6_multicast_leave_group(struct net_bridge *br, + struct net_bridge_port *port, + const struct in6_addr *group, +- __u16 vid) ++ __u16 vid, const unsigned char *src) + { + struct br_ip br_group; + struct bridge_mcast_own_query *own_query; +@@ -1546,7 +1573,7 @@ static void br_ip6_multicast_leave_group + br_group.vid = vid; + + br_multicast_leave_group(br, port, &br_group, &br->ip6_other_query, +- own_query); ++ own_query, src); + } + #endif + +@@ -1555,6 +1582,7 @@ static int br_multicast_ipv4_rcv(struct + struct sk_buff *skb, + u16 vid) + { ++ const unsigned char *src; + struct sk_buff *skb2 = skb; + const struct iphdr *iph; + struct igmphdr *ih; +@@ -1628,7 +1656,8 @@ static int br_multicast_ipv4_rcv(struct + case IGMP_HOST_MEMBERSHIP_REPORT: + case IGMPV2_HOST_MEMBERSHIP_REPORT: + BR_INPUT_SKB_CB(skb)->mrouters_only = 1; +- err = br_ip4_multicast_add_group(br, port, ih->group, vid); ++ src = eth_hdr(skb)->h_source; ++ err = br_ip4_multicast_add_group(br, port, ih->group, vid, src); + break; + case IGMPV3_HOST_MEMBERSHIP_REPORT: + err = br_ip4_multicast_igmp3_report(br, port, skb2, vid); +@@ -1637,7 +1666,8 @@ static int br_multicast_ipv4_rcv(struct + err = br_ip4_multicast_query(br, port, skb2, vid); + break; + case IGMP_HOST_LEAVE_MESSAGE: +- br_ip4_multicast_leave_group(br, port, ih->group, vid); ++ src = eth_hdr(skb)->h_source; ++ br_ip4_multicast_leave_group(br, port, ih->group, vid, src); + break; + } + +@@ -1655,6 +1685,7 @@ static int br_multicast_ipv6_rcv(struct + struct sk_buff *skb, + u16 vid) + { ++ const unsigned char *src; + struct sk_buff *skb2; + const struct ipv6hdr *ip6h; + u8 icmp6_type; +@@ -1764,7 +1795,9 @@ static int br_multicast_ipv6_rcv(struct + } + mld = (struct mld_msg *)skb_transport_header(skb2); + BR_INPUT_SKB_CB(skb)->mrouters_only = 1; +- err = br_ip6_multicast_add_group(br, port, &mld->mld_mca, vid); ++ src = eth_hdr(skb)->h_source; ++ err = br_ip6_multicast_add_group(br, port, &mld->mld_mca, vid, ++ src); + break; + } + case ICMPV6_MLD2_REPORT: +@@ -1781,7 +1814,8 @@ static int br_multicast_ipv6_rcv(struct + goto out; + } + mld = (struct mld_msg *)skb_transport_header(skb2); +- br_ip6_multicast_leave_group(br, port, &mld->mld_mca, vid); ++ src = eth_hdr(skb)->h_source; ++ br_ip6_multicast_leave_group(br, port, &mld->mld_mca, vid, src); + } + } + +--- a/net/bridge/br_private.h ++++ b/net/bridge/br_private.h +@@ -112,6 +112,9 @@ struct net_bridge_port_group { + struct timer_list timer; + struct br_ip addr; + unsigned char state; ++ ++ unsigned char eth_addr[ETH_ALEN]; ++ bool unicast; + }; + + struct net_bridge_mdb_entry +@@ -173,6 +176,7 @@ struct net_bridge_port + #define BR_AUTO_MASK (BR_FLOOD | BR_LEARNING) + #define BR_PROMISC 0x00000080 + #define BR_ISOLATE_MODE 0x00000100 ++#define BR_MULTICAST_TO_UCAST 0x00000200 + + #ifdef CONFIG_BRIDGE_IGMP_SNOOPING + struct bridge_mcast_own_query ip4_own_query; +@@ -485,7 +489,8 @@ void br_multicast_free_pg(struct rcu_hea + struct net_bridge_port_group * + br_multicast_new_port_group(struct net_bridge_port *port, struct br_ip *group, + struct net_bridge_port_group __rcu *next, +- unsigned char state); ++ unsigned char state, ++ const unsigned char *src); + void br_mdb_init(void); + void br_mdb_uninit(void); + void br_mdb_notify(struct net_device *dev, struct net_bridge_port *port, +--- a/net/bridge/br_mdb.c ++++ b/net/bridge/br_mdb.c +@@ -342,7 +342,7 @@ static int br_mdb_add_group(struct net_b + break; + } + +- p = br_multicast_new_port_group(port, group, *pp, state); ++ p = br_multicast_new_port_group(port, group, *pp, state, NULL); + if (unlikely(!p)) + return -ENOMEM; + rcu_assign_pointer(*pp, p); +--- a/net/bridge/br_forward.c ++++ b/net/bridge/br_forward.c +@@ -168,6 +168,34 @@ out: + return p; + } + ++static struct net_bridge_port *maybe_deliver_addr( ++ struct net_bridge_port *prev, struct net_bridge_port *p, ++ struct sk_buff *skb, const unsigned char *addr, ++ void (*__packet_hook)(const struct net_bridge_port *p, ++ struct sk_buff *skb)) ++{ ++ struct net_device *dev = BR_INPUT_SKB_CB(skb)->brdev; ++ const unsigned char *src = eth_hdr(skb)->h_source; ++ ++ if (!should_deliver(p, skb)) ++ return prev; ++ ++ /* Even with hairpin, no soliloquies - prevent breaking IPv6 DAD */ ++ if (skb->dev == p->dev && ether_addr_equal(src, addr)) ++ return prev; ++ ++ skb = skb_copy(skb, GFP_ATOMIC); ++ if (!skb) { ++ dev->stats.tx_dropped++; ++ return prev; ++ } ++ ++ memcpy(eth_hdr(skb)->h_dest, addr, ETH_ALEN); ++ __packet_hook(p, skb); ++ ++ return prev; ++} ++ + /* called under bridge lock */ + static void br_flood(struct net_bridge *br, struct sk_buff *skb, + struct sk_buff *skb0, +@@ -232,6 +260,7 @@ static void br_multicast_flood(struct ne + struct net_bridge_port *prev = NULL; + struct net_bridge_port_group *p; + struct hlist_node *rp; ++ const unsigned char *addr; + + rp = rcu_dereference(hlist_first_rcu(&br->router_list)); + p = mdst ? rcu_dereference(mdst->ports) : NULL; +@@ -242,10 +271,19 @@ static void br_multicast_flood(struct ne + rport = rp ? hlist_entry(rp, struct net_bridge_port, rlist) : + NULL; + +- port = (unsigned long)lport > (unsigned long)rport ? +- lport : rport; +- +- prev = maybe_deliver(prev, port, skb, __packet_hook); ++ if ((unsigned long)lport > (unsigned long)rport) { ++ port = lport; ++ addr = p->unicast ? p->eth_addr : NULL; ++ } else { ++ port = rport; ++ addr = NULL; ++ } ++ ++ if (addr) ++ prev = maybe_deliver_addr(prev, port, skb, addr, ++ __packet_hook); ++ else ++ prev = maybe_deliver(prev, port, skb, __packet_hook); + if (IS_ERR(prev)) + goto out; + +--- a/net/bridge/br_sysfs_if.c ++++ b/net/bridge/br_sysfs_if.c +@@ -202,6 +202,7 @@ static BRPORT_ATTR(multicast_router, S_I + store_multicast_router); + + BRPORT_ATTR_FLAG(multicast_fast_leave, BR_MULTICAST_FAST_LEAVE); ++BRPORT_ATTR_FLAG(multicast_to_unicast, BR_MULTICAST_TO_UCAST); + #endif + + static const struct brport_attribute *brport_attrs[] = { +@@ -228,6 +229,7 @@ static const struct brport_attribute *br + #ifdef CONFIG_BRIDGE_IGMP_SNOOPING + &brport_attr_multicast_router, + &brport_attr_multicast_fast_leave, ++ &brport_attr_multicast_to_unicast, + #endif + &brport_attr_isolate_mode, + NULL diff --git a/target/linux/generic/patches-3.18/650-pppoe_header_pad.patch b/target/linux/generic/patches-3.18/650-pppoe_header_pad.patch new file mode 100644 index 0000000..4b623fa --- /dev/null +++ b/target/linux/generic/patches-3.18/650-pppoe_header_pad.patch @@ -0,0 +1,20 @@ +--- a/drivers/net/ppp/pppoe.c ++++ b/drivers/net/ppp/pppoe.c +@@ -868,7 +868,7 @@ static int pppoe_sendmsg(struct kiocb *i + goto end; + + +- skb = sock_wmalloc(sk, total_len + dev->hard_header_len + 32, ++ skb = sock_wmalloc(sk, total_len + dev->hard_header_len + 32 + NET_SKB_PAD, + 0, GFP_KERNEL); + if (!skb) { + error = -ENOMEM; +@@ -876,7 +876,7 @@ static int pppoe_sendmsg(struct kiocb *i + } + + /* Reserve space for headers. */ +- skb_reserve(skb, dev->hard_header_len); ++ skb_reserve(skb, dev->hard_header_len + NET_SKB_PAD); + skb_reset_network_header(skb); + + skb->dev = dev; diff --git a/target/linux/generic/patches-3.18/651-wireless_mesh_header.patch b/target/linux/generic/patches-3.18/651-wireless_mesh_header.patch new file mode 100644 index 0000000..16da5cd --- /dev/null +++ b/target/linux/generic/patches-3.18/651-wireless_mesh_header.patch @@ -0,0 +1,11 @@ +--- a/include/linux/netdevice.h ++++ b/include/linux/netdevice.h +@@ -130,7 +130,7 @@ static inline bool dev_xmit_complete(int + */ + + #if defined(CONFIG_WLAN) || IS_ENABLED(CONFIG_AX25) +-# if defined(CONFIG_MAC80211_MESH) ++# if 1 || defined(CONFIG_MAC80211_MESH) + # define LL_MAX_HEADER 128 + # else + # define LL_MAX_HEADER 96 diff --git a/target/linux/generic/patches-3.18/653-disable_netlink_trim.patch b/target/linux/generic/patches-3.18/653-disable_netlink_trim.patch new file mode 100644 index 0000000..b8fbe92 --- /dev/null +++ b/target/linux/generic/patches-3.18/653-disable_netlink_trim.patch @@ -0,0 +1,30 @@ +--- a/net/netlink/af_netlink.c ++++ b/net/netlink/af_netlink.c +@@ -1690,27 +1690,7 @@ void netlink_detachskb(struct sock *sk, + + static struct sk_buff *netlink_trim(struct sk_buff *skb, gfp_t allocation) + { +- int delta; +- + WARN_ON(skb->sk != NULL); +- if (netlink_skb_is_mmaped(skb)) +- return skb; +- +- delta = skb->end - skb->tail; +- if (is_vmalloc_addr(skb->head) || delta * 2 < skb->truesize) +- return skb; +- +- if (skb_shared(skb)) { +- struct sk_buff *nskb = skb_clone(skb, allocation); +- if (!nskb) +- return skb; +- consume_skb(skb); +- skb = nskb; +- } +- +- if (!pskb_expand_head(skb, 0, -delta, allocation)) +- skb->truesize -= delta; +- + return skb; + } + diff --git a/target/linux/generic/patches-3.18/655-increase_skb_pad.patch b/target/linux/generic/patches-3.18/655-increase_skb_pad.patch new file mode 100644 index 0000000..19344cc --- /dev/null +++ b/target/linux/generic/patches-3.18/655-increase_skb_pad.patch @@ -0,0 +1,11 @@ +--- a/include/linux/skbuff.h ++++ b/include/linux/skbuff.h +@@ -2023,7 +2023,7 @@ static inline int pskb_network_may_pull( + * NET_IP_ALIGN(2) + ethernet_header(14) + IP_header(20/40) + ports(8) + */ + #ifndef NET_SKB_PAD +-#define NET_SKB_PAD max(32, L1_CACHE_BYTES) ++#define NET_SKB_PAD max(64, L1_CACHE_BYTES) + #endif + + int ___pskb_trim(struct sk_buff *skb, unsigned int len); diff --git a/target/linux/generic/patches-3.18/656-skb_reduce_truesize-helper.patch b/target/linux/generic/patches-3.18/656-skb_reduce_truesize-helper.patch new file mode 100644 index 0000000..b326a8b --- /dev/null +++ b/target/linux/generic/patches-3.18/656-skb_reduce_truesize-helper.patch @@ -0,0 +1,41 @@ +From 4593a806e31119c5bd3faa00c7210ad862d515af Mon Sep 17 00:00:00 2001 +From: Dave Taht +Date: Mon, 31 Dec 2012 10:02:21 -0800 +Subject: [PATCH 3/7] skb_reduce_truesize: helper function for shrinking skbs + whenever needed + +On embedded devices in particular, large queues of small packets from the rx +path with a large truesize can exist. Reducing their size can reduce +memory pressure. skb_reduce_truesize is a helper function for doing this, +when needed. +--- + include/linux/skbuff.h | 18 ++++++++++++++++++ + 1 file changed, 18 insertions(+) + +--- a/include/linux/skbuff.h ++++ b/include/linux/skbuff.h +@@ -2068,6 +2068,24 @@ static inline void pskb_trim_unique(stru + BUG_ON(err); + } + ++/* ++ * Caller wants to reduce memory needs before queueing skb ++ * The (expensive) copy should not be be done in fast path. ++ */ ++static inline struct sk_buff *skb_reduce_truesize(struct sk_buff *skb) ++{ ++ if (skb->truesize > 2 * SKB_TRUESIZE(skb->len)) { ++ struct sk_buff *nskb; ++ nskb = skb_copy_expand(skb, skb_headroom(skb), 0, ++ GFP_ATOMIC | __GFP_NOWARN); ++ if (nskb) { ++ __kfree_skb(skb); ++ skb = nskb; ++ } ++ } ++ return skb; ++} ++ + /** + * skb_orphan - orphan a buffer + * @skb: buffer to orphan diff --git a/target/linux/generic/patches-3.18/657-qdisc_reduce_truesize.patch b/target/linux/generic/patches-3.18/657-qdisc_reduce_truesize.patch new file mode 100644 index 0000000..6777eec --- /dev/null +++ b/target/linux/generic/patches-3.18/657-qdisc_reduce_truesize.patch @@ -0,0 +1,63 @@ +From bc9fec2f87d57bdbff30d296605e24504513f65c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Dave=20T=C3=A4ht?= +Date: Mon, 17 Sep 2012 19:20:22 -0700 +Subject: [PATCH 4/7] net: add skb_reduce_truesize support to common qdiscs + +Reduce skb size under load when queues begin to fill on the +commont qdiscs. +--- + net/sched/sch_codel.c | 2 ++ + net/sched/sch_fifo.c | 12 ++++++++---- + net/sched/sch_fq_codel.c | 2 ++ + 3 files changed, 12 insertions(+), 4 deletions(-) + +--- a/net/sched/sch_codel.c ++++ b/net/sched/sch_codel.c +@@ -96,6 +96,8 @@ static int codel_qdisc_enqueue(struct sk + struct codel_sched_data *q; + + if (likely(qdisc_qlen(sch) < sch->limit)) { ++ if(qdisc_qlen(sch) > 128) ++ skb = skb_reduce_truesize(skb); + codel_set_enqueue_time(skb); + return qdisc_enqueue_tail(skb, sch); + } +--- a/net/sched/sch_fifo.c ++++ b/net/sched/sch_fifo.c +@@ -29,17 +29,21 @@ static int bfifo_enqueue(struct sk_buff + + static int pfifo_enqueue(struct sk_buff *skb, struct Qdisc *sch) + { +- if (likely(skb_queue_len(&sch->q) < sch->limit)) ++ if (likely(skb_queue_len(&sch->q) < sch->limit)) { ++ if (skb_queue_len(&sch->q) > 128) ++ skb = skb_reduce_truesize(skb); + return qdisc_enqueue_tail(skb, sch); +- ++ } + return qdisc_reshape_fail(skb, sch); + } + + static int pfifo_tail_enqueue(struct sk_buff *skb, struct Qdisc *sch) + { +- if (likely(skb_queue_len(&sch->q) < sch->limit)) ++ if (likely(skb_queue_len(&sch->q) < sch->limit)) { ++ if (skb_queue_len(&sch->q) > 128) ++ skb = skb_reduce_truesize(skb); + return qdisc_enqueue_tail(skb, sch); +- ++ } + /* queue full, remove one skb to fulfill the limit */ + __qdisc_queue_drop_head(sch, &sch->q); + qdisc_qstats_drop(sch); +--- a/net/sched/sch_fq_codel.c ++++ b/net/sched/sch_fq_codel.c +@@ -185,6 +185,8 @@ static int fq_codel_enqueue(struct sk_bu + return ret; + } + idx--; ++ if (sch->q.qlen > 128) ++ skb = skb_reduce_truesize(skb); + + codel_set_enqueue_time(skb); + flow = &q->flows[idx]; diff --git a/target/linux/generic/patches-3.18/660-fq_codel_defaults.patch b/target/linux/generic/patches-3.18/660-fq_codel_defaults.patch new file mode 100644 index 0000000..f7f4659 --- /dev/null +++ b/target/linux/generic/patches-3.18/660-fq_codel_defaults.patch @@ -0,0 +1,14 @@ +--- a/net/sched/sch_fq_codel.c ++++ b/net/sched/sch_fq_codel.c +@@ -387,9 +387,9 @@ static int fq_codel_init(struct Qdisc *s + struct fq_codel_sched_data *q = qdisc_priv(sch); + int i; + +- sch->limit = 10*1024; ++ sch->limit = 1024; + q->flows_cnt = 1024; +- q->quantum = psched_mtu(qdisc_dev(sch)); ++ q->quantum = 300; + q->perturbation = prandom_u32(); + INIT_LIST_HEAD(&q->new_flows); + INIT_LIST_HEAD(&q->old_flows); diff --git a/target/linux/generic/patches-3.18/661-fq_codel_keep_dropped_stats.patch b/target/linux/generic/patches-3.18/661-fq_codel_keep_dropped_stats.patch new file mode 100644 index 0000000..45a8d68 --- /dev/null +++ b/target/linux/generic/patches-3.18/661-fq_codel_keep_dropped_stats.patch @@ -0,0 +1,10 @@ +--- a/net/sched/sch_fq_codel.c ++++ b/net/sched/sch_fq_codel.c +@@ -198,7 +198,6 @@ static int fq_codel_enqueue(struct sk_bu + list_add_tail(&flow->flowchain, &q->new_flows); + q->new_flow_count++; + flow->deficit = q->quantum; +- flow->dropped = 0; + } + if (++sch->q.qlen <= sch->limit) + return NET_XMIT_SUCCESS; diff --git a/target/linux/generic/patches-3.18/662-use_fq_codel_by_default.patch b/target/linux/generic/patches-3.18/662-use_fq_codel_by_default.patch new file mode 100644 index 0000000..ba7c384 --- /dev/null +++ b/target/linux/generic/patches-3.18/662-use_fq_codel_by_default.patch @@ -0,0 +1,95 @@ +--- a/net/sched/Kconfig ++++ b/net/sched/Kconfig +@@ -3,8 +3,9 @@ + # + + menuconfig NET_SCHED +- bool "QoS and/or fair queueing" ++ def_bool y + select NET_SCH_FIFO ++ select NET_SCH_FQ_CODEL + ---help--- + When the kernel has several packets to send out over a network + device, it has to decide which ones to send first, which ones to +--- a/net/sched/sch_fq_codel.c ++++ b/net/sched/sch_fq_codel.c +@@ -592,7 +592,7 @@ static const struct Qdisc_class_ops fq_c + .walk = fq_codel_walk, + }; + +-static struct Qdisc_ops fq_codel_qdisc_ops __read_mostly = { ++struct Qdisc_ops fq_codel_qdisc_ops __read_mostly = { + .cl_ops = &fq_codel_class_ops, + .id = "fq_codel", + .priv_size = sizeof(struct fq_codel_sched_data), +@@ -608,6 +608,7 @@ static struct Qdisc_ops fq_codel_qdisc_o + .dump_stats = fq_codel_dump_stats, + .owner = THIS_MODULE, + }; ++EXPORT_SYMBOL(fq_codel_qdisc_ops); + + static int __init fq_codel_module_init(void) + { +--- a/include/net/sch_generic.h ++++ b/include/net/sch_generic.h +@@ -341,6 +341,7 @@ extern struct Qdisc noop_qdisc; + extern struct Qdisc_ops noop_qdisc_ops; + extern struct Qdisc_ops pfifo_fast_ops; + extern struct Qdisc_ops mq_qdisc_ops; ++extern struct Qdisc_ops fq_codel_qdisc_ops; + extern const struct Qdisc_ops *default_qdisc_ops; + + struct Qdisc_class_common { +--- a/net/sched/sch_generic.c ++++ b/net/sched/sch_generic.c +@@ -31,7 +31,7 @@ + #include + + /* Qdisc to use by default */ +-const struct Qdisc_ops *default_qdisc_ops = &pfifo_fast_ops; ++const struct Qdisc_ops *default_qdisc_ops = &fq_codel_qdisc_ops; + EXPORT_SYMBOL(default_qdisc_ops); + + /* Main transmission queue. */ +@@ -737,7 +737,7 @@ static void attach_one_default_qdisc(str + + if (dev->tx_queue_len) { + qdisc = qdisc_create_dflt(dev_queue, +- default_qdisc_ops, TC_H_ROOT); ++ &fq_codel_qdisc_ops, TC_H_ROOT); + if (!qdisc) { + netdev_info(dev, "activation failed\n"); + return; +--- a/net/sched/sch_mq.c ++++ b/net/sched/sch_mq.c +@@ -57,7 +57,7 @@ static int mq_init(struct Qdisc *sch, st + + for (ntx = 0; ntx < dev->num_tx_queues; ntx++) { + dev_queue = netdev_get_tx_queue(dev, ntx); +- qdisc = qdisc_create_dflt(dev_queue, default_qdisc_ops, ++ qdisc = qdisc_create_dflt(dev_queue, &fq_codel_qdisc_ops, + TC_H_MAKE(TC_H_MAJ(sch->handle), + TC_H_MIN(ntx + 1))); + if (qdisc == NULL) +--- a/net/sched/sch_mqprio.c ++++ b/net/sched/sch_mqprio.c +@@ -124,7 +124,7 @@ static int mqprio_init(struct Qdisc *sch + + for (i = 0; i < dev->num_tx_queues; i++) { + dev_queue = netdev_get_tx_queue(dev, i); +- qdisc = qdisc_create_dflt(dev_queue, default_qdisc_ops, ++ qdisc = qdisc_create_dflt(dev_queue, &fq_codel_qdisc_ops, + TC_H_MAKE(TC_H_MAJ(sch->handle), + TC_H_MIN(i + 1))); + if (qdisc == NULL) { +--- a/net/sched/sch_api.c ++++ b/net/sched/sch_api.c +@@ -1947,7 +1947,7 @@ static int __init pktsched_init(void) + return err; + } + +- register_qdisc(&pfifo_fast_ops); ++ register_qdisc(&fq_codel_qdisc_ops); + register_qdisc(&pfifo_qdisc_ops); + register_qdisc(&bfifo_qdisc_ops); + register_qdisc(&pfifo_head_drop_qdisc_ops); diff --git a/target/linux/generic/patches-3.18/663-remove_pfifo_fast.patch b/target/linux/generic/patches-3.18/663-remove_pfifo_fast.patch new file mode 100644 index 0000000..5b26ca3 --- /dev/null +++ b/target/linux/generic/patches-3.18/663-remove_pfifo_fast.patch @@ -0,0 +1,143 @@ +--- a/net/sched/sch_generic.c ++++ b/net/sched/sch_generic.c +@@ -442,140 +442,6 @@ static struct Qdisc noqueue_qdisc = { + .busylock = __SPIN_LOCK_UNLOCKED(noqueue_qdisc.busylock), + }; + +- +-static const u8 prio2band[TC_PRIO_MAX + 1] = { +- 1, 2, 2, 2, 1, 2, 0, 0 , 1, 1, 1, 1, 1, 1, 1, 1 +-}; +- +-/* 3-band FIFO queue: old style, but should be a bit faster than +- generic prio+fifo combination. +- */ +- +-#define PFIFO_FAST_BANDS 3 +- +-/* +- * Private data for a pfifo_fast scheduler containing: +- * - queues for the three band +- * - bitmap indicating which of the bands contain skbs +- */ +-struct pfifo_fast_priv { +- u32 bitmap; +- struct sk_buff_head q[PFIFO_FAST_BANDS]; +-}; +- +-/* +- * Convert a bitmap to the first band number where an skb is queued, where: +- * bitmap=0 means there are no skbs on any band. +- * bitmap=1 means there is an skb on band 0. +- * bitmap=7 means there are skbs on all 3 bands, etc. +- */ +-static const int bitmap2band[] = {-1, 0, 1, 0, 2, 0, 1, 0}; +- +-static inline struct sk_buff_head *band2list(struct pfifo_fast_priv *priv, +- int band) +-{ +- return priv->q + band; +-} +- +-static int pfifo_fast_enqueue(struct sk_buff *skb, struct Qdisc *qdisc) +-{ +- if (skb_queue_len(&qdisc->q) < qdisc_dev(qdisc)->tx_queue_len) { +- int band = prio2band[skb->priority & TC_PRIO_MAX]; +- struct pfifo_fast_priv *priv = qdisc_priv(qdisc); +- struct sk_buff_head *list = band2list(priv, band); +- +- priv->bitmap |= (1 << band); +- qdisc->q.qlen++; +- return __qdisc_enqueue_tail(skb, qdisc, list); +- } +- +- return qdisc_drop(skb, qdisc); +-} +- +-static struct sk_buff *pfifo_fast_dequeue(struct Qdisc *qdisc) +-{ +- struct pfifo_fast_priv *priv = qdisc_priv(qdisc); +- int band = bitmap2band[priv->bitmap]; +- +- if (likely(band >= 0)) { +- struct sk_buff_head *list = band2list(priv, band); +- struct sk_buff *skb = __qdisc_dequeue_head(qdisc, list); +- +- qdisc->q.qlen--; +- if (skb_queue_empty(list)) +- priv->bitmap &= ~(1 << band); +- +- return skb; +- } +- +- return NULL; +-} +- +-static struct sk_buff *pfifo_fast_peek(struct Qdisc *qdisc) +-{ +- struct pfifo_fast_priv *priv = qdisc_priv(qdisc); +- int band = bitmap2band[priv->bitmap]; +- +- if (band >= 0) { +- struct sk_buff_head *list = band2list(priv, band); +- +- return skb_peek(list); +- } +- +- return NULL; +-} +- +-static void pfifo_fast_reset(struct Qdisc *qdisc) +-{ +- int prio; +- struct pfifo_fast_priv *priv = qdisc_priv(qdisc); +- +- for (prio = 0; prio < PFIFO_FAST_BANDS; prio++) +- __qdisc_reset_queue(qdisc, band2list(priv, prio)); +- +- priv->bitmap = 0; +- qdisc->qstats.backlog = 0; +- qdisc->q.qlen = 0; +-} +- +-static int pfifo_fast_dump(struct Qdisc *qdisc, struct sk_buff *skb) +-{ +- struct tc_prio_qopt opt = { .bands = PFIFO_FAST_BANDS }; +- +- memcpy(&opt.priomap, prio2band, TC_PRIO_MAX + 1); +- if (nla_put(skb, TCA_OPTIONS, sizeof(opt), &opt)) +- goto nla_put_failure; +- return skb->len; +- +-nla_put_failure: +- return -1; +-} +- +-static int pfifo_fast_init(struct Qdisc *qdisc, struct nlattr *opt) +-{ +- int prio; +- struct pfifo_fast_priv *priv = qdisc_priv(qdisc); +- +- for (prio = 0; prio < PFIFO_FAST_BANDS; prio++) +- __skb_queue_head_init(band2list(priv, prio)); +- +- /* Can by-pass the queue discipline */ +- qdisc->flags |= TCQ_F_CAN_BYPASS; +- return 0; +-} +- +-struct Qdisc_ops pfifo_fast_ops __read_mostly = { +- .id = "pfifo_fast", +- .priv_size = sizeof(struct pfifo_fast_priv), +- .enqueue = pfifo_fast_enqueue, +- .dequeue = pfifo_fast_dequeue, +- .peek = pfifo_fast_peek, +- .init = pfifo_fast_init, +- .reset = pfifo_fast_reset, +- .dump = pfifo_fast_dump, +- .owner = THIS_MODULE, +-}; +- + static struct lock_class_key qdisc_tx_busylock; + + struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue, diff --git a/target/linux/generic/patches-3.18/666-Add-support-for-MAP-E-FMRs-mesh-mode.patch b/target/linux/generic/patches-3.18/666-Add-support-for-MAP-E-FMRs-mesh-mode.patch new file mode 100644 index 0000000..000665f --- /dev/null +++ b/target/linux/generic/patches-3.18/666-Add-support-for-MAP-E-FMRs-mesh-mode.patch @@ -0,0 +1,481 @@ +From 775d6fe74d1eaec2ba387535b068dde2dc89de9e Mon Sep 17 00:00:00 2001 +From: Steven Barth +Date: Thu, 22 May 2014 09:49:05 +0200 +Subject: [PATCH] Add support for MAP-E FMRs (mesh mode) + +MAP-E FMRs (draft-ietf-softwire-map-10) are rules for IPv4-communication +between MAP CEs (mesh mode) without the need to forward such data to a +border relay. This is similar to how 6rd works but for IPv4 over IPv6. + +Signed-off-by: Steven Barth +--- + include/net/ip6_tunnel.h | 13 ++ + include/uapi/linux/if_tunnel.h | 13 ++ + net/ipv6/ip6_tunnel.c | 276 +++++++++++++++++++++++++++++++++++++++-- + 3 files changed, 291 insertions(+), 11 deletions(-) + +--- a/include/net/ip6_tunnel.h ++++ b/include/net/ip6_tunnel.h +@@ -15,6 +15,18 @@ + /* determine capability on a per-packet basis */ + #define IP6_TNL_F_CAP_PER_PACKET 0x40000 + ++/* IPv6 tunnel FMR */ ++struct __ip6_tnl_fmr { ++ struct __ip6_tnl_fmr *next; /* next fmr in list */ ++ struct in6_addr ip6_prefix; ++ struct in_addr ip4_prefix; ++ ++ __u8 ip6_prefix_len; ++ __u8 ip4_prefix_len; ++ __u8 ea_len; ++ __u8 offset; ++}; ++ + struct __ip6_tnl_parm { + char name[IFNAMSIZ]; /* name of tunnel device */ + int link; /* ifindex of underlying L2 interface */ +@@ -25,6 +37,7 @@ struct __ip6_tnl_parm { + __u32 flags; /* tunnel flags */ + struct in6_addr laddr; /* local tunnel end-point address */ + struct in6_addr raddr; /* remote tunnel end-point address */ ++ struct __ip6_tnl_fmr *fmrs; /* FMRs */ + + __be16 i_flags; + __be16 o_flags; +--- a/include/uapi/linux/if_tunnel.h ++++ b/include/uapi/linux/if_tunnel.h +@@ -57,10 +57,23 @@ enum { + IFLA_IPTUN_ENCAP_FLAGS, + IFLA_IPTUN_ENCAP_SPORT, + IFLA_IPTUN_ENCAP_DPORT, ++ IFLA_IPTUN_FMRS, + __IFLA_IPTUN_MAX, + }; + #define IFLA_IPTUN_MAX (__IFLA_IPTUN_MAX - 1) + ++enum { ++ IFLA_IPTUN_FMR_UNSPEC, ++ IFLA_IPTUN_FMR_IP6_PREFIX, ++ IFLA_IPTUN_FMR_IP4_PREFIX, ++ IFLA_IPTUN_FMR_IP6_PREFIX_LEN, ++ IFLA_IPTUN_FMR_IP4_PREFIX_LEN, ++ IFLA_IPTUN_FMR_EA_LEN, ++ IFLA_IPTUN_FMR_OFFSET, ++ __IFLA_IPTUN_FMR_MAX, ++}; ++#define IFLA_IPTUN_FMR_MAX (__IFLA_IPTUN_FMR_MAX - 1) ++ + enum tunnel_encap_types { + TUNNEL_ENCAP_NONE, + TUNNEL_ENCAP_FOU, +--- a/net/ipv6/ip6_tunnel.c ++++ b/net/ipv6/ip6_tunnel.c +@@ -16,6 +16,8 @@ + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * ++ * Changes: ++ * Steven Barth : MAP-E FMR support + */ + + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +@@ -77,11 +79,9 @@ static bool log_ecn_error = true; + module_param(log_ecn_error, bool, 0644); + MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN"); + +-static u32 HASH(const struct in6_addr *addr1, const struct in6_addr *addr2) ++static u32 HASH(const struct in6_addr *addr) + { +- u32 hash = ipv6_addr_hash(addr1) ^ ipv6_addr_hash(addr2); +- +- return hash_32(hash, HASH_SIZE_SHIFT); ++ return hash_32(ipv6_addr_hash(addr), HASH_SIZE_SHIFT); + } + + static int ip6_tnl_dev_init(struct net_device *dev); +@@ -180,15 +180,24 @@ EXPORT_SYMBOL_GPL(ip6_tnl_dst_store); + static struct ip6_tnl * + ip6_tnl_lookup(struct net *net, const struct in6_addr *remote, const struct in6_addr *local) + { +- unsigned int hash = HASH(remote, local); ++ unsigned int hash = HASH(local); + struct ip6_tnl *t; + struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); ++ struct __ip6_tnl_fmr *fmr; + + for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) { +- if (ipv6_addr_equal(local, &t->parms.laddr) && +- ipv6_addr_equal(remote, &t->parms.raddr) && +- (t->dev->flags & IFF_UP)) ++ if (!ipv6_addr_equal(local, &t->parms.laddr) || ++ !(t->dev->flags & IFF_UP)) ++ continue; ++ ++ if (ipv6_addr_equal(remote, &t->parms.raddr)) + return t; ++ ++ for (fmr = t->parms.fmrs; fmr; fmr = fmr->next) { ++ if (ipv6_prefix_equal(remote, &fmr->ip6_prefix, ++ fmr->ip6_prefix_len)) ++ return t; ++ } + } + t = rcu_dereference(ip6n->tnls_wc[0]); + if (t && (t->dev->flags & IFF_UP)) +@@ -218,7 +227,7 @@ ip6_tnl_bucket(struct ip6_tnl_net *ip6n, + + if (!ipv6_addr_any(remote) || !ipv6_addr_any(local)) { + prio = 1; +- h = HASH(remote, local); ++ h = HASH(local); + } + return &ip6n->tnls[prio][h]; + } +@@ -388,6 +397,12 @@ ip6_tnl_dev_uninit(struct net_device *de + struct net *net = t->net; + struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); + ++ while (t->parms.fmrs) { ++ struct __ip6_tnl_fmr *next = t->parms.fmrs->next; ++ kfree(t->parms.fmrs); ++ t->parms.fmrs = next; ++ } ++ + if (dev == ip6n->fb_tnl_dev) + RCU_INIT_POINTER(ip6n->tnls_wc[0], NULL); + else +@@ -771,6 +786,108 @@ int ip6_tnl_rcv_ctl(struct ip6_tnl *t, + } + EXPORT_SYMBOL_GPL(ip6_tnl_rcv_ctl); + ++ ++/** ++ * ip4ip6_fmr_calc - calculate target / source IPv6-address based on FMR ++ * @dest: destination IPv6 address buffer ++ * @skb: received socket buffer ++ * @fmr: MAP FMR ++ * @xmit: Calculate for xmit or rcv ++ **/ ++static void ip4ip6_fmr_calc(struct in6_addr *dest, ++ const struct iphdr *iph, const uint8_t *end, ++ const struct __ip6_tnl_fmr *fmr, bool xmit) ++{ ++ int psidlen = fmr->ea_len - (32 - fmr->ip4_prefix_len); ++ u8 *portp = NULL; ++ bool use_dest_addr; ++ const struct iphdr *dsth = iph; ++ ++ if ((u8*)dsth >= end) ++ return; ++ ++ /* find significant IP header */ ++ if (iph->protocol == IPPROTO_ICMP) { ++ struct icmphdr *ih = (struct icmphdr*)(((u8*)dsth) + dsth->ihl * 4); ++ if (ih && ((u8*)&ih[1]) <= end && ( ++ ih->type == ICMP_DEST_UNREACH || ++ ih->type == ICMP_SOURCE_QUENCH || ++ ih->type == ICMP_TIME_EXCEEDED || ++ ih->type == ICMP_PARAMETERPROB || ++ ih->type == ICMP_REDIRECT)) ++ dsth = (const struct iphdr*)&ih[1]; ++ } ++ ++ /* in xmit-path use dest port by default and source port only if ++ this is an ICMP reply to something else; vice versa in rcv-path */ ++ use_dest_addr = (xmit && dsth == iph) || (!xmit && dsth != iph); ++ ++ /* get dst port */ ++ if (((u8*)&dsth[1]) <= end && ( ++ dsth->protocol == IPPROTO_UDP || ++ dsth->protocol == IPPROTO_TCP || ++ dsth->protocol == IPPROTO_SCTP || ++ dsth->protocol == IPPROTO_DCCP)) { ++ /* for UDP, TCP, SCTP and DCCP source and dest port ++ follow IPv4 header directly */ ++ portp = ((u8*)dsth) + dsth->ihl * 4; ++ ++ if (use_dest_addr) ++ portp += sizeof(u16); ++ } else if (iph->protocol == IPPROTO_ICMP) { ++ struct icmphdr *ih = (struct icmphdr*)(((u8*)dsth) + dsth->ihl * 4); ++ ++ /* use icmp identifier as port */ ++ if (((u8*)&ih) <= end && ( ++ (use_dest_addr && ( ++ ih->type == ICMP_ECHOREPLY || ++ ih->type == ICMP_TIMESTAMPREPLY || ++ ih->type == ICMP_INFO_REPLY || ++ ih->type == ICMP_ADDRESSREPLY)) || ++ (!use_dest_addr && ( ++ ih->type == ICMP_ECHO || ++ ih->type == ICMP_TIMESTAMP || ++ ih->type == ICMP_INFO_REQUEST || ++ ih->type == ICMP_ADDRESS) ++ ))) ++ portp = (u8*)&ih->un.echo.id; ++ } ++ ++ if ((portp && &portp[2] <= end) || psidlen == 0) { ++ int frombyte = fmr->ip6_prefix_len / 8; ++ int fromrem = fmr->ip6_prefix_len % 8; ++ int bytes = sizeof(struct in6_addr) - frombyte; ++ const u32 *addr = (use_dest_addr) ? &iph->daddr : &iph->saddr; ++ u64 eabits = ((u64)ntohl(*addr)) << (32 + fmr->ip4_prefix_len); ++ u64 t = 0; ++ ++ /* extract PSID from port and add it to eabits */ ++ u16 psidbits = 0; ++ if (psidlen > 0) { ++ psidbits = ((u16)portp[0]) << 8 | ((u16)portp[1]); ++ psidbits >>= 16 - psidlen - fmr->offset; ++ psidbits = (u16)(psidbits << (16 - psidlen)); ++ eabits |= ((u64)psidbits) << (48 - (fmr->ea_len - psidlen)); ++ } ++ ++ /* rewrite destination address */ ++ *dest = fmr->ip6_prefix; ++ memcpy(&dest->s6_addr[10], addr, sizeof(*addr)); ++ dest->s6_addr16[7] = htons(psidbits >> (16 - psidlen)); ++ ++ if (bytes > sizeof(u64)) ++ bytes = sizeof(u64); ++ ++ /* insert eabits */ ++ memcpy(&t, &dest->s6_addr[frombyte], bytes); ++ t = be64_to_cpu(t) & ~(((((u64)1) << fmr->ea_len) - 1) ++ << (64 - fmr->ea_len - fromrem)); ++ t = cpu_to_be64(t | (eabits >> fromrem)); ++ memcpy(&dest->s6_addr[frombyte], &t, bytes); ++ } ++} ++ ++ + /** + * ip6_tnl_rcv - decapsulate IPv6 packet and retransmit it locally + * @skb: received socket buffer +@@ -815,6 +932,26 @@ static int ip6_tnl_rcv(struct sk_buff *s + skb_reset_network_header(skb); + skb->protocol = htons(protocol); + memset(skb->cb, 0, sizeof(struct inet6_skb_parm)); ++ if (protocol == ETH_P_IP && ++ !ipv6_addr_equal(&ipv6h->saddr, &t->parms.raddr)) { ++ /* Packet didn't come from BR, so lookup FMR */ ++ struct __ip6_tnl_fmr *fmr; ++ struct in6_addr expected = t->parms.raddr; ++ for (fmr = t->parms.fmrs; fmr; fmr = fmr->next) ++ if (ipv6_prefix_equal(&ipv6h->saddr, ++ &fmr->ip6_prefix, fmr->ip6_prefix_len)) ++ break; ++ ++ /* Check that IPv6 matches IPv4 source to prevent spoofing */ ++ if (fmr) ++ ip4ip6_fmr_calc(&expected, ip_hdr(skb), ++ skb_tail_pointer(skb), fmr, false); ++ ++ if (!ipv6_addr_equal(&ipv6h->saddr, &expected)) { ++ rcu_read_unlock(); ++ goto discard; ++ } ++ } + + __skb_tunnel_rx(skb, t->dev, t->net); + +@@ -1076,6 +1213,7 @@ ip4ip6_tnl_xmit(struct sk_buff *skb, str + __u8 dsfield; + __u32 mtu; + int err; ++ struct __ip6_tnl_fmr *fmr; + + if ((t->parms.proto != IPPROTO_IPIP && t->parms.proto != 0) || + !ip6_tnl_xmit_ctl(t)) +@@ -1095,6 +1233,18 @@ ip4ip6_tnl_xmit(struct sk_buff *skb, str + if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK) + fl6.flowi6_mark = skb->mark; + ++ /* try to find matching FMR */ ++ for (fmr = t->parms.fmrs; fmr; fmr = fmr->next) { ++ unsigned mshift = 32 - fmr->ip4_prefix_len; ++ if (ntohl(fmr->ip4_prefix.s_addr) >> mshift == ++ ntohl(iph->daddr) >> mshift) ++ break; ++ } ++ ++ /* change dstaddr according to FMR */ ++ if (fmr) ++ ip4ip6_fmr_calc(&fl6.daddr, iph, skb_tail_pointer(skb), fmr, true); ++ + err = ip6_tnl_xmit2(skb, dev, dsfield, &fl6, encap_limit, &mtu); + if (err != 0) { + /* XXX: send ICMP error even if DF is not set. */ +@@ -1263,6 +1413,14 @@ ip6_tnl_change(struct ip6_tnl *t, const + t->parms.flowinfo = p->flowinfo; + t->parms.link = p->link; + t->parms.proto = p->proto; ++ ++ while (t->parms.fmrs) { ++ struct __ip6_tnl_fmr *next = t->parms.fmrs->next; ++ kfree(t->parms.fmrs); ++ t->parms.fmrs = next; ++ } ++ t->parms.fmrs = p->fmrs; ++ + ip6_tnl_dst_reset(t); + ip6_tnl_link_config(t); + return 0; +@@ -1293,6 +1451,7 @@ ip6_tnl_parm_from_user(struct __ip6_tnl_ + p->flowinfo = u->flowinfo; + p->link = u->link; + p->proto = u->proto; ++ p->fmrs = NULL; + memcpy(p->name, u->name, sizeof(u->name)); + } + +@@ -1568,6 +1727,15 @@ static int ip6_tnl_validate(struct nlatt + return 0; + } + ++static const struct nla_policy ip6_tnl_fmr_policy[IFLA_IPTUN_FMR_MAX + 1] = { ++ [IFLA_IPTUN_FMR_IP6_PREFIX] = { .len = sizeof(struct in6_addr) }, ++ [IFLA_IPTUN_FMR_IP4_PREFIX] = { .len = sizeof(struct in_addr) }, ++ [IFLA_IPTUN_FMR_IP6_PREFIX_LEN] = { .type = NLA_U8 }, ++ [IFLA_IPTUN_FMR_IP4_PREFIX_LEN] = { .type = NLA_U8 }, ++ [IFLA_IPTUN_FMR_EA_LEN] = { .type = NLA_U8 }, ++ [IFLA_IPTUN_FMR_OFFSET] = { .type = NLA_U8 } ++}; ++ + static void ip6_tnl_netlink_parms(struct nlattr *data[], + struct __ip6_tnl_parm *parms) + { +@@ -1601,6 +1769,46 @@ static void ip6_tnl_netlink_parms(struct + + if (data[IFLA_IPTUN_PROTO]) + parms->proto = nla_get_u8(data[IFLA_IPTUN_PROTO]); ++ ++ if (data[IFLA_IPTUN_FMRS]) { ++ unsigned rem; ++ struct nlattr *fmr; ++ nla_for_each_nested(fmr, data[IFLA_IPTUN_FMRS], rem) { ++ struct nlattr *fmrd[IFLA_IPTUN_FMR_MAX + 1], *c; ++ struct __ip6_tnl_fmr *nfmr; ++ ++ nla_parse_nested(fmrd, IFLA_IPTUN_FMR_MAX, ++ fmr, ip6_tnl_fmr_policy); ++ ++ if (!(nfmr = kzalloc(sizeof(*nfmr), GFP_KERNEL))) ++ continue; ++ ++ nfmr->offset = 6; ++ ++ if ((c = fmrd[IFLA_IPTUN_FMR_IP6_PREFIX])) ++ nla_memcpy(&nfmr->ip6_prefix, fmrd[IFLA_IPTUN_FMR_IP6_PREFIX], ++ sizeof(nfmr->ip6_prefix)); ++ ++ if ((c = fmrd[IFLA_IPTUN_FMR_IP4_PREFIX])) ++ nla_memcpy(&nfmr->ip4_prefix, fmrd[IFLA_IPTUN_FMR_IP4_PREFIX], ++ sizeof(nfmr->ip4_prefix)); ++ ++ if ((c = fmrd[IFLA_IPTUN_FMR_IP6_PREFIX_LEN])) ++ nfmr->ip6_prefix_len = nla_get_u8(c); ++ ++ if ((c = fmrd[IFLA_IPTUN_FMR_IP4_PREFIX_LEN])) ++ nfmr->ip4_prefix_len = nla_get_u8(c); ++ ++ if ((c = fmrd[IFLA_IPTUN_FMR_EA_LEN])) ++ nfmr->ea_len = nla_get_u8(c); ++ ++ if ((c = fmrd[IFLA_IPTUN_FMR_OFFSET])) ++ nfmr->offset = nla_get_u8(c); ++ ++ nfmr->next = parms->fmrs; ++ parms->fmrs = nfmr; ++ } ++ } + } + + static int ip6_tnl_newlink(struct net *src_net, struct net_device *dev, +@@ -1653,6 +1861,12 @@ static void ip6_tnl_dellink(struct net_d + + static size_t ip6_tnl_get_size(const struct net_device *dev) + { ++ const struct ip6_tnl *t = netdev_priv(dev); ++ struct __ip6_tnl_fmr *c; ++ int fmrs = 0; ++ for (c = t->parms.fmrs; c; c = c->next) ++ ++fmrs; ++ + return + /* IFLA_IPTUN_LINK */ + nla_total_size(4) + +@@ -1670,6 +1884,24 @@ static size_t ip6_tnl_get_size(const str + nla_total_size(4) + + /* IFLA_IPTUN_PROTO */ + nla_total_size(1) + ++ /* IFLA_IPTUN_FMRS */ ++ nla_total_size(0) + ++ ( ++ /* nest */ ++ nla_total_size(0) + ++ /* IFLA_IPTUN_FMR_IP6_PREFIX */ ++ nla_total_size(sizeof(struct in6_addr)) + ++ /* IFLA_IPTUN_FMR_IP4_PREFIX */ ++ nla_total_size(sizeof(struct in_addr)) + ++ /* IFLA_IPTUN_FMR_EA_LEN */ ++ nla_total_size(1) + ++ /* IFLA_IPTUN_FMR_IP6_PREFIX_LEN */ ++ nla_total_size(1) + ++ /* IFLA_IPTUN_FMR_IP4_PREFIX_LEN */ ++ nla_total_size(1) + ++ /* IFLA_IPTUN_FMR_OFFSET */ ++ nla_total_size(1) ++ ) * fmrs + + 0; + } + +@@ -1677,6 +1909,9 @@ static int ip6_tnl_fill_info(struct sk_b + { + struct ip6_tnl *tunnel = netdev_priv(dev); + struct __ip6_tnl_parm *parm = &tunnel->parms; ++ struct __ip6_tnl_fmr *c; ++ int fmrcnt = 0; ++ struct nlattr *fmrs; + + if (nla_put_u32(skb, IFLA_IPTUN_LINK, parm->link) || + nla_put(skb, IFLA_IPTUN_LOCAL, sizeof(struct in6_addr), +@@ -1687,8 +1922,27 @@ static int ip6_tnl_fill_info(struct sk_b + nla_put_u8(skb, IFLA_IPTUN_ENCAP_LIMIT, parm->encap_limit) || + nla_put_be32(skb, IFLA_IPTUN_FLOWINFO, parm->flowinfo) || + nla_put_u32(skb, IFLA_IPTUN_FLAGS, parm->flags) || +- nla_put_u8(skb, IFLA_IPTUN_PROTO, parm->proto)) ++ nla_put_u8(skb, IFLA_IPTUN_PROTO, parm->proto) || ++ !(fmrs = nla_nest_start(skb, IFLA_IPTUN_FMRS))) + goto nla_put_failure; ++ ++ for (c = parm->fmrs; c; c = c->next) { ++ struct nlattr *fmr = nla_nest_start(skb, ++fmrcnt); ++ if (!fmr || ++ nla_put(skb, IFLA_IPTUN_FMR_IP6_PREFIX, ++ sizeof(c->ip6_prefix), &c->ip6_prefix) || ++ nla_put(skb, IFLA_IPTUN_FMR_IP4_PREFIX, ++ sizeof(c->ip4_prefix), &c->ip4_prefix) || ++ nla_put_u8(skb, IFLA_IPTUN_FMR_IP6_PREFIX_LEN, c->ip6_prefix_len) || ++ nla_put_u8(skb, IFLA_IPTUN_FMR_IP4_PREFIX_LEN, c->ip4_prefix_len) || ++ nla_put_u8(skb, IFLA_IPTUN_FMR_EA_LEN, c->ea_len) || ++ nla_put_u8(skb, IFLA_IPTUN_FMR_OFFSET, c->offset)) ++ goto nla_put_failure; ++ ++ nla_nest_end(skb, fmr); ++ } ++ nla_nest_end(skb, fmrs); ++ + return 0; + + nla_put_failure: +@@ -1704,6 +1958,7 @@ static const struct nla_policy ip6_tnl_p + [IFLA_IPTUN_FLOWINFO] = { .type = NLA_U32 }, + [IFLA_IPTUN_FLAGS] = { .type = NLA_U32 }, + [IFLA_IPTUN_PROTO] = { .type = NLA_U8 }, ++ [IFLA_IPTUN_FMRS] = { .type = NLA_NESTED }, + }; + + static struct rtnl_link_ops ip6_link_ops __read_mostly = { diff --git a/target/linux/generic/patches-3.18/667-ipv6-Fixed-source-specific-default-route-handling.patch b/target/linux/generic/patches-3.18/667-ipv6-Fixed-source-specific-default-route-handling.patch new file mode 100644 index 0000000..d02e085 --- /dev/null +++ b/target/linux/generic/patches-3.18/667-ipv6-Fixed-source-specific-default-route-handling.patch @@ -0,0 +1,96 @@ +From e16e888b525503be05b3aea64190e8b3bdef44d0 Mon Sep 17 00:00:00 2001 +From: Markus Stenberg +Date: Tue, 5 May 2015 13:36:59 +0300 +Subject: [PATCH] ipv6: Fixed source specific default route handling. + +If there are only IPv6 source specific default routes present, the +host gets -ENETUNREACH on e.g. connect() because ip6_dst_lookup_tail +calls ip6_route_output first, and given source address any, it fails, +and ip6_route_get_saddr is never called. + +The change is to use the ip6_route_get_saddr, even if the initial +ip6_route_output fails, and then doing ip6_route_output _again_ after +we have appropriate source address available. + +Note that this is '99% fix' to the problem; a correct fix would be to +do route lookups only within addrconf.c when picking a source address, +and never call ip6_route_output before source address has been +populated. + +Signed-off-by: Markus Stenberg +Signed-off-by: David S. Miller +--- + net/ipv6/ip6_output.c | 39 +++++++++++++++++++++++++++++++-------- + net/ipv6/route.c | 5 +++-- + 2 files changed, 34 insertions(+), 10 deletions(-) + +--- a/net/ipv6/ip6_output.c ++++ b/net/ipv6/ip6_output.c +@@ -900,21 +900,45 @@ static int ip6_dst_lookup_tail(struct so + #endif + int err; + +- if (*dst == NULL) +- *dst = ip6_route_output(net, sk, fl6); +- +- if ((err = (*dst)->error)) +- goto out_err_release; ++ /* The correct way to handle this would be to do ++ * ip6_route_get_saddr, and then ip6_route_output; however, ++ * the route-specific preferred source forces the ++ * ip6_route_output call _before_ ip6_route_get_saddr. ++ * ++ * In source specific routing (no src=any default route), ++ * ip6_route_output will fail given src=any saddr, though, so ++ * that's why we try it again later. ++ */ ++ if (ipv6_addr_any(&fl6->saddr) && (!*dst || !(*dst)->error)) { ++ struct rt6_info *rt; ++ bool had_dst = *dst != NULL; + +- if (ipv6_addr_any(&fl6->saddr)) { +- struct rt6_info *rt = (struct rt6_info *) *dst; ++ if (!had_dst) ++ *dst = ip6_route_output(net, sk, fl6); ++ rt = (*dst)->error ? NULL : (struct rt6_info *)*dst; + err = ip6_route_get_saddr(net, rt, &fl6->daddr, + sk ? inet6_sk(sk)->srcprefs : 0, + &fl6->saddr); + if (err) + goto out_err_release; ++ ++ /* If we had an erroneous initial result, pretend it ++ * never existed and let the SA-enabled version take ++ * over. ++ */ ++ if (!had_dst && (*dst)->error) { ++ dst_release(*dst); ++ *dst = NULL; ++ } + } + ++ if (!*dst) ++ *dst = ip6_route_output(net, sk, fl6); ++ ++ err = (*dst)->error; ++ if (err) ++ goto out_err_release; ++ + #ifdef CONFIG_IPV6_OPTIMISTIC_DAD + /* + * Here if the dst entry we've looked up +--- a/net/ipv6/route.c ++++ b/net/ipv6/route.c +@@ -2182,9 +2182,10 @@ int ip6_route_get_saddr(struct net *net, + unsigned int prefs, + struct in6_addr *saddr) + { +- struct inet6_dev *idev = ip6_dst_idev((struct dst_entry *)rt); ++ struct inet6_dev *idev = ++ rt ? ip6_dst_idev((struct dst_entry *)rt) : NULL; + int err = 0; +- if (rt->rt6i_prefsrc.plen) ++ if (rt && rt->rt6i_prefsrc.plen) + *saddr = rt->rt6i_prefsrc.addr; + else + err = ipv6_dev_get_saddr(net, idev ? idev->dev : NULL, diff --git a/target/linux/generic/patches-3.18/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch b/target/linux/generic/patches-3.18/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch new file mode 100644 index 0000000..1bf9dc9 --- /dev/null +++ b/target/linux/generic/patches-3.18/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch @@ -0,0 +1,249 @@ +From 1b5aaa4b16f6e6471ab1c07b38068197a1b4c395 Mon Sep 17 00:00:00 2001 +From: Jonas Gorski +Date: Fri, 24 May 2013 14:40:54 +0200 +Subject: [PATCH 1/2] ipv6: allow rejecting with "source address failed policy" + +RFC6204 L-14 requires rejecting traffic from invalid addresses with +ICMPv6 Destination Unreachable, Code 5 (Source address failed ingress/ +egress policy) on the LAN side, so add an appropriate rule for that. + +Signed-off-by: Jonas Gorski +--- + include/net/netns/ipv6.h | 1 + + include/uapi/linux/fib_rules.h | 4 +++ + include/uapi/linux/rtnetlink.h | 1 + + net/ipv4/fib_semantics.c | 4 +++ + net/ipv4/fib_trie.c | 1 + + net/ipv4/ipmr.c | 1 + + net/ipv6/fib6_rules.c | 4 +++ + net/ipv6/ip6mr.c | 2 ++ + net/ipv6/route.c | 58 +++++++++++++++++++++++++++++++++++++++++- + 9 files changed, 75 insertions(+), 1 deletion(-) + +--- a/include/net/netns/ipv6.h ++++ b/include/net/netns/ipv6.h +@@ -59,6 +59,7 @@ struct netns_ipv6 { + unsigned long ip6_rt_last_gc; + #ifdef CONFIG_IPV6_MULTIPLE_TABLES + struct rt6_info *ip6_prohibit_entry; ++ struct rt6_info *ip6_policy_failed_entry; + struct rt6_info *ip6_blk_hole_entry; + struct fib6_table *fib6_local_tbl; + struct fib_rules_ops *fib6_rules_ops; +--- a/include/uapi/linux/fib_rules.h ++++ b/include/uapi/linux/fib_rules.h +@@ -64,6 +64,10 @@ enum { + FR_ACT_BLACKHOLE, /* Drop without notification */ + FR_ACT_UNREACHABLE, /* Drop with ENETUNREACH */ + FR_ACT_PROHIBIT, /* Drop with EACCES */ ++ FR_ACT_RES9, ++ FR_ACT_RES10, ++ FR_ACT_RES11, ++ FR_ACT_POLICY_FAILED, /* Drop with EACCES */ + __FR_ACT_MAX, + }; + +--- a/include/uapi/linux/rtnetlink.h ++++ b/include/uapi/linux/rtnetlink.h +@@ -203,6 +203,7 @@ enum { + RTN_THROW, /* Not in this table */ + RTN_NAT, /* Translate this address */ + RTN_XRESOLVE, /* Use external resolver */ ++ RTN_POLICY_FAILED, /* Failed ingress/egress policy */ + __RTN_MAX + }; + +--- a/net/ipv4/fib_semantics.c ++++ b/net/ipv4/fib_semantics.c +@@ -138,6 +138,10 @@ const struct fib_prop fib_props[RTN_MAX + .error = -EINVAL, + .scope = RT_SCOPE_NOWHERE, + }, ++ [RTN_POLICY_FAILED] = { ++ .error = -EACCES, ++ .scope = RT_SCOPE_UNIVERSE, ++ }, + }; + + static void rt_fibinfo_free(struct rtable __rcu **rtp) +--- a/net/ipv4/fib_trie.c ++++ b/net/ipv4/fib_trie.c +@@ -2236,6 +2236,7 @@ static const char *const rtn_type_names[ + [RTN_THROW] = "THROW", + [RTN_NAT] = "NAT", + [RTN_XRESOLVE] = "XRESOLVE", ++ [RTN_POLICY_FAILED] = "POLICY_FAILED", + }; + + static inline const char *rtn_type(char *buf, size_t len, unsigned int t) +--- a/net/ipv4/ipmr.c ++++ b/net/ipv4/ipmr.c +@@ -184,6 +184,7 @@ static int ipmr_rule_action(struct fib_r + case FR_ACT_UNREACHABLE: + return -ENETUNREACH; + case FR_ACT_PROHIBIT: ++ case FR_ACT_POLICY_FAILED: + return -EACCES; + case FR_ACT_BLACKHOLE: + default: +--- a/net/ipv6/fib6_rules.c ++++ b/net/ipv6/fib6_rules.c +@@ -73,6 +73,10 @@ static int fib6_rule_action(struct fib_r + err = -EACCES; + rt = net->ipv6.ip6_prohibit_entry; + goto discard_pkt; ++ case FR_ACT_POLICY_FAILED: ++ err = -EACCES; ++ rt = net->ipv6.ip6_policy_failed_entry; ++ goto discard_pkt; + } + + table = fib6_get_table(net, rule->table); +--- a/net/ipv6/ip6mr.c ++++ b/net/ipv6/ip6mr.c +@@ -169,6 +169,8 @@ static int ip6mr_rule_action(struct fib_ + return -ENETUNREACH; + case FR_ACT_PROHIBIT: + return -EACCES; ++ case FR_ACT_POLICY_FAILED: ++ return -EACCES; + case FR_ACT_BLACKHOLE: + default: + return -EINVAL; +--- a/net/ipv6/route.c ++++ b/net/ipv6/route.c +@@ -87,6 +87,8 @@ static int ip6_pkt_discard(struct sk_bu + static int ip6_pkt_discard_out(struct sock *sk, struct sk_buff *skb); + static int ip6_pkt_prohibit(struct sk_buff *skb); + static int ip6_pkt_prohibit_out(struct sock *sk, struct sk_buff *skb); ++static int ip6_pkt_policy_failed(struct sk_buff *skb); ++static int ip6_pkt_policy_failed_out(struct sock *sk, struct sk_buff *skb); + static void ip6_link_failure(struct sk_buff *skb); + static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk, + struct sk_buff *skb, u32 mtu); +@@ -283,6 +285,21 @@ static const struct rt6_info ip6_prohibi + .rt6i_ref = ATOMIC_INIT(1), + }; + ++static const struct rt6_info ip6_policy_failed_entry_template = { ++ .dst = { ++ .__refcnt = ATOMIC_INIT(1), ++ .__use = 1, ++ .obsolete = DST_OBSOLETE_FORCE_CHK, ++ .error = -EACCES, ++ .input = ip6_pkt_policy_failed, ++ .output = ip6_pkt_policy_failed_out, ++ }, ++ .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP), ++ .rt6i_protocol = RTPROT_KERNEL, ++ .rt6i_metric = ~(u32) 0, ++ .rt6i_ref = ATOMIC_INIT(1), ++}; ++ + static const struct rt6_info ip6_blk_hole_entry_template = { + .dst = { + .__refcnt = ATOMIC_INIT(1), +@@ -1578,6 +1595,11 @@ int ip6_route_add(struct fib6_config *cf + rt->dst.output = ip6_pkt_prohibit_out; + rt->dst.input = ip6_pkt_prohibit; + break; ++ case RTN_POLICY_FAILED: ++ rt->dst.error = -EACCES; ++ rt->dst.output = ip6_pkt_policy_failed_out; ++ rt->dst.input = ip6_pkt_policy_failed; ++ break; + case RTN_THROW: + default: + rt->dst.error = (cfg->fc_type == RTN_THROW) ? -EAGAIN +@@ -2139,6 +2161,17 @@ static int ip6_pkt_prohibit_out(struct s + return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES); + } + ++static int ip6_pkt_policy_failed(struct sk_buff *skb) ++{ ++ return ip6_pkt_drop(skb, ICMPV6_POLICY_FAIL, IPSTATS_MIB_INNOROUTES); ++} ++ ++static int ip6_pkt_policy_failed_out(struct sock *sk, struct sk_buff *skb) ++{ ++ skb->dev = skb_dst(skb)->dev; ++ return ip6_pkt_drop(skb, ICMPV6_POLICY_FAIL, IPSTATS_MIB_OUTNOROUTES); ++} ++ + /* + * Allocate a dst for local (unicast / anycast) address. + */ +@@ -2363,7 +2396,8 @@ static int rtm_to_fib6_config(struct sk_ + if (rtm->rtm_type == RTN_UNREACHABLE || + rtm->rtm_type == RTN_BLACKHOLE || + rtm->rtm_type == RTN_PROHIBIT || +- rtm->rtm_type == RTN_THROW) ++ rtm->rtm_type == RTN_THROW || ++ rtm->rtm_type == RTN_POLICY_FAILED) + cfg->fc_flags |= RTF_REJECT; + + if (rtm->rtm_type == RTN_LOCAL) +@@ -2565,6 +2599,9 @@ static int rt6_fill_node(struct net *net + case -EACCES: + rtm->rtm_type = RTN_PROHIBIT; + break; ++ case -EPERM: ++ rtm->rtm_type = RTN_POLICY_FAILED; ++ break; + case -EAGAIN: + rtm->rtm_type = RTN_THROW; + break; +@@ -2818,6 +2855,8 @@ static int ip6_route_dev_notify(struct n + #ifdef CONFIG_IPV6_MULTIPLE_TABLES + net->ipv6.ip6_prohibit_entry->dst.dev = dev; + net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev); ++ net->ipv6.ip6_policy_failed_entry->dst.dev = dev; ++ net->ipv6.ip6_policy_failed_entry->rt6i_idev = in6_dev_get(dev); + net->ipv6.ip6_blk_hole_entry->dst.dev = dev; + net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev); + #endif +@@ -3034,6 +3073,17 @@ static int __net_init ip6_route_net_init + net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops; + dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst, + ip6_template_metrics, true); ++ ++ net->ipv6.ip6_policy_failed_entry = ++ kmemdup(&ip6_policy_failed_entry_template, ++ sizeof(*net->ipv6.ip6_policy_failed_entry), GFP_KERNEL); ++ if (!net->ipv6.ip6_policy_failed_entry) ++ goto out_ip6_blk_hole_entry; ++ net->ipv6.ip6_policy_failed_entry->dst.path = ++ (struct dst_entry *)net->ipv6.ip6_policy_failed_entry; ++ net->ipv6.ip6_policy_failed_entry->dst.ops = &net->ipv6.ip6_dst_ops; ++ dst_init_metrics(&net->ipv6.ip6_policy_failed_entry->dst, ++ ip6_template_metrics, true); + #endif + + net->ipv6.sysctl.flush_delay = 0; +@@ -3052,6 +3102,8 @@ out: + return ret; + + #ifdef CONFIG_IPV6_MULTIPLE_TABLES ++out_ip6_blk_hole_entry: ++ kfree(net->ipv6.ip6_blk_hole_entry); + out_ip6_prohibit_entry: + kfree(net->ipv6.ip6_prohibit_entry); + out_ip6_null_entry: +@@ -3069,6 +3121,7 @@ static void __net_exit ip6_route_net_exi + #ifdef CONFIG_IPV6_MULTIPLE_TABLES + kfree(net->ipv6.ip6_prohibit_entry); + kfree(net->ipv6.ip6_blk_hole_entry); ++ kfree(net->ipv6.ip6_policy_failed_entry); + #endif + dst_entries_destroy(&net->ipv6.ip6_dst_ops); + } +@@ -3165,6 +3218,9 @@ int __init ip6_route_init(void) + init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); + init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev; + init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); ++ init_net.ipv6.ip6_policy_failed_entry->dst.dev = init_net.loopback_dev; ++ init_net.ipv6.ip6_policy_failed_entry->rt6i_idev = ++ in6_dev_get(init_net.loopback_dev); + #endif + ret = fib6_init(); + if (ret) diff --git a/target/linux/generic/patches-3.18/671-net-provide-defines-for-_POLICY_FAILED-until-all-cod.patch b/target/linux/generic/patches-3.18/671-net-provide-defines-for-_POLICY_FAILED-until-all-cod.patch new file mode 100644 index 0000000..25a8639 --- /dev/null +++ b/target/linux/generic/patches-3.18/671-net-provide-defines-for-_POLICY_FAILED-until-all-cod.patch @@ -0,0 +1,53 @@ +From 7749b481ce5d7e232b1f7da5e6b2c44816f51681 Mon Sep 17 00:00:00 2001 +From: Jonas Gorski +Date: Sun, 19 Jan 2014 20:45:51 +0100 +Subject: [PATCH 2/2] net: provide defines for _POLICY_FAILED until all code is + updated + +Upstream introduced ICMPV6_POLICY_FAIL for code 5 of destination +unreachable, conflicting with our name. + +Add appropriate defines to allow our code to build with the new +name until we have updated our local patches for older kernels +and userspace packages. + +Signed-off-by: Jonas Gorski +--- + include/uapi/linux/fib_rules.h | 2 ++ + include/uapi/linux/icmpv6.h | 2 ++ + include/uapi/linux/rtnetlink.h | 2 ++ + 3 files changed, 6 insertions(+) + +--- a/include/uapi/linux/fib_rules.h ++++ b/include/uapi/linux/fib_rules.h +@@ -71,6 +71,8 @@ enum { + __FR_ACT_MAX, + }; + ++#define FR_ACT_FAILED_POLICY FR_ACT_POLICY_FAILED ++ + #define FR_ACT_MAX (__FR_ACT_MAX - 1) + + #endif +--- a/include/uapi/linux/icmpv6.h ++++ b/include/uapi/linux/icmpv6.h +@@ -118,6 +118,8 @@ struct icmp6hdr { + #define ICMPV6_POLICY_FAIL 5 + #define ICMPV6_REJECT_ROUTE 6 + ++#define ICMPV6_FAILED_POLICY ICMPV6_POLICY_FAIL ++ + /* + * Codes for Time Exceeded + */ +--- a/include/uapi/linux/rtnetlink.h ++++ b/include/uapi/linux/rtnetlink.h +@@ -207,6 +207,8 @@ enum { + __RTN_MAX + }; + ++#define RTN_FAILED_POLICY RTN_POLICY_FAILED ++ + #define RTN_MAX (__RTN_MAX - 1) + + diff --git a/target/linux/generic/patches-3.18/680-NET-skip-GRO-for-foreign-MAC-addresses.patch b/target/linux/generic/patches-3.18/680-NET-skip-GRO-for-foreign-MAC-addresses.patch new file mode 100644 index 0000000..4a2f36b --- /dev/null +++ b/target/linux/generic/patches-3.18/680-NET-skip-GRO-for-foreign-MAC-addresses.patch @@ -0,0 +1,160 @@ +Subject: NET: skip GRO for foreign MAC addresses + +For network drivers using napi_gro_receive, packets are run through GRO, +even when the destination MAC address does not match, and they're supposed +to be delivered to another host behind a different bridge port. + +This can be very expensive, because for drivers without TSO or scatter- +gather, this can only be undone by copying the skb and checksumming it +again. + +To be able to track foreign MAC addresses in an inexpensive way, create +a mask of changed bits in MAC addresses of upper devices. This allows +handling VLANs and bridge devices with different addresses (as long as +they are not too different). + +Signed-off-by: Felix Fietkau + +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -4001,6 +4001,9 @@ static enum gro_result dev_gro_receive(s + enum gro_result ret; + int grow; + ++ if (skb->gro_skip) ++ goto normal; ++ + if (!(skb->dev->features & NETIF_F_GRO)) + goto normal; + +@@ -5064,6 +5067,48 @@ static void __netdev_adjacent_dev_unlink + &upper_dev->adj_list.lower); + } + ++static void __netdev_addr_mask(unsigned char *mask, const unsigned char *addr, ++ struct net_device *dev) ++{ ++ int i; ++ ++ for (i = 0; i < dev->addr_len; i++) ++ mask[i] |= addr[i] ^ dev->dev_addr[i]; ++} ++ ++static void __netdev_upper_mask(unsigned char *mask, struct net_device *dev, ++ struct net_device *lower) ++{ ++ struct net_device *cur; ++ struct list_head *iter; ++ ++ netdev_for_each_upper_dev_rcu(dev, cur, iter) { ++ __netdev_addr_mask(mask, cur->dev_addr, lower); ++ __netdev_upper_mask(mask, cur, lower); ++ } ++} ++ ++static void __netdev_update_addr_mask(struct net_device *dev) ++{ ++ unsigned char mask[MAX_ADDR_LEN]; ++ struct net_device *cur; ++ struct list_head *iter; ++ ++ memset(mask, 0, sizeof(mask)); ++ __netdev_upper_mask(mask, dev, dev); ++ memcpy(dev->local_addr_mask, mask, dev->addr_len); ++ ++ netdev_for_each_lower_dev(dev, cur, iter) ++ __netdev_update_addr_mask(cur); ++} ++ ++static void netdev_update_addr_mask(struct net_device *dev) ++{ ++ rcu_read_lock(); ++ __netdev_update_addr_mask(dev); ++ rcu_read_unlock(); ++} ++ + static int __netdev_upper_dev_link(struct net_device *dev, + struct net_device *upper_dev, bool master, + void *private) +@@ -5124,6 +5169,7 @@ static int __netdev_upper_dev_link(struc + goto rollback_lower_mesh; + } + ++ netdev_update_addr_mask(dev); + call_netdevice_notifiers(NETDEV_CHANGEUPPER, dev); + return 0; + +@@ -5241,6 +5287,7 @@ void netdev_upper_dev_unlink(struct net_ + list_for_each_entry(i, &upper_dev->all_adj_list.upper, list) + __netdev_adjacent_dev_unlink(dev, i->dev); + ++ netdev_update_addr_mask(dev); + call_netdevice_notifiers(NETDEV_CHANGEUPPER, dev); + } + EXPORT_SYMBOL(netdev_upper_dev_unlink); +@@ -5760,6 +5807,7 @@ int dev_set_mac_address(struct net_devic + if (err) + return err; + dev->addr_assign_type = NET_ADDR_SET; ++ netdev_update_addr_mask(dev); + call_netdevice_notifiers(NETDEV_CHANGEADDR, dev); + add_device_randomness(dev->dev_addr, dev->addr_len); + return 0; +--- a/include/linux/netdevice.h ++++ b/include/linux/netdevice.h +@@ -1548,6 +1548,8 @@ struct net_device { + struct netdev_hw_addr_list mc; + struct netdev_hw_addr_list dev_addrs; + ++ unsigned char local_addr_mask[MAX_ADDR_LEN]; ++ + #ifdef CONFIG_SYSFS + struct kset *queues_kset; + #endif +--- a/include/linux/skbuff.h ++++ b/include/linux/skbuff.h +@@ -597,7 +597,8 @@ struct sk_buff { + #endif + __u8 ipvs_property:1; + __u8 inner_protocol_type:1; +- /* 4 or 6 bit hole */ ++ __u8 gro_skip:1; ++ /* 3 or 5 bit hole */ + + #ifdef CONFIG_NET_SCHED + __u16 tc_index; /* traffic control index */ +--- a/net/ethernet/eth.c ++++ b/net/ethernet/eth.c +@@ -172,6 +172,18 @@ u32 eth_get_headlen(void *data, unsigned + } + EXPORT_SYMBOL(eth_get_headlen); + ++static inline bool ++eth_check_local_mask(const void *addr1, const void *addr2, const void *mask) ++{ ++ const u16 *a1 = addr1; ++ const u16 *a2 = addr2; ++ const u16 *m = mask; ++ ++ return (((a1[0] ^ a2[0]) & ~m[0]) | ++ ((a1[1] ^ a2[1]) & ~m[1]) | ++ ((a1[2] ^ a2[2]) & ~m[2])); ++} ++ + /** + * eth_type_trans - determine the packet's protocol ID. + * @skb: received socket data +@@ -199,8 +211,12 @@ __be16 eth_type_trans(struct sk_buff *sk + skb->pkt_type = PACKET_MULTICAST; + } + else if (unlikely(!ether_addr_equal_64bits(eth->h_dest, +- dev->dev_addr))) ++ dev->dev_addr))) { + skb->pkt_type = PACKET_OTHERHOST; ++ if (eth_check_local_mask(eth->h_dest, dev->dev_addr, ++ dev->local_addr_mask)) ++ skb->gro_skip = 1; ++ } + + /* + * Some variants of DSA tagging don't have an ethertype field diff --git a/target/linux/generic/patches-3.18/681-NET-add-of_get_mac_address_mtd.patch b/target/linux/generic/patches-3.18/681-NET-add-of_get_mac_address_mtd.patch new file mode 100644 index 0000000..a836eed --- /dev/null +++ b/target/linux/generic/patches-3.18/681-NET-add-of_get_mac_address_mtd.patch @@ -0,0 +1,88 @@ +From: John Crispin +Date: Sun, 27 Jul 2014 09:40:01 +0100 +Subject: NET: add of_get_mac_address_mtd() + +Many embedded devices have information such as mac addresses stored inside mtd +devices. This patch allows us to add a property inside a node describing a +network interface. The new property points at a mtd partition with an offset +where the mac address can be found. + +Signed-off-by: John Crispin +--- + drivers/of/of_net.c | 37 +++++++++++++++++++++++++++++++++++++ + include/linux/of_net.h | 1 + + 2 files changed, 38 insertions(+) + +--- a/drivers/of/of_net.c ++++ b/drivers/of/of_net.c +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + + /** + * of_get_phy_mode - Get phy mode for given device_node +@@ -75,3 +76,45 @@ const void *of_get_mac_address(struct de + return NULL; + } + EXPORT_SYMBOL(of_get_mac_address); ++ ++#ifdef CONFIG_MTD ++int of_get_mac_address_mtd(struct device_node *np, unsigned char *mac) ++{ ++ struct device_node *mtd_np = NULL; ++ size_t retlen; ++ int size, ret; ++ struct mtd_info *mtd; ++ const char *part; ++ const __be32 *list; ++ phandle phandle; ++ u32 mac_inc = 0; ++ ++ list = of_get_property(np, "mtd-mac-address", &size); ++ if (!list || (size != (2 * sizeof(*list)))) ++ return -ENOENT; ++ ++ phandle = be32_to_cpup(list++); ++ if (phandle) ++ mtd_np = of_find_node_by_phandle(phandle); ++ ++ if (!mtd_np) ++ return -ENOENT; ++ ++ part = of_get_property(mtd_np, "label", NULL); ++ if (!part) ++ part = mtd_np->name; ++ ++ mtd = get_mtd_device_nm(part); ++ if (IS_ERR(mtd)) ++ return PTR_ERR(mtd); ++ ++ ret = mtd_read(mtd, be32_to_cpup(list), 6, &retlen, mac); ++ put_mtd_device(mtd); ++ ++ if (!of_property_read_u32(np, "mtd-mac-address-increment", &mac_inc)) ++ mac[5] += mac_inc; ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(of_get_mac_address_mtd); ++#endif +--- a/include/linux/of_net.h ++++ b/include/linux/of_net.h +@@ -11,6 +11,14 @@ + #include + extern int of_get_phy_mode(struct device_node *np); + extern const void *of_get_mac_address(struct device_node *np); ++#ifdef CONFIG_MTD ++extern int of_get_mac_address_mtd(struct device_node *np, unsigned char *mac); ++#else ++static inline int of_get_mac_address_mtd(struct device_node *np, unsigned char *mac) ++{ ++ return -ENOENT; ++} ++#endif + #else + static inline int of_get_phy_mode(struct device_node *np) + { diff --git a/target/linux/generic/patches-3.18/700-swconfig.patch b/target/linux/generic/patches-3.18/700-swconfig.patch new file mode 100644 index 0000000..7cf525a --- /dev/null +++ b/target/linux/generic/patches-3.18/700-swconfig.patch @@ -0,0 +1,39 @@ +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -12,6 +12,16 @@ menuconfig PHYLIB + + if PHYLIB + ++config SWCONFIG ++ tristate "Switch configuration API" ++ ---help--- ++ Switch configuration API using netlink. This allows ++ you to configure the VLAN features of certain switches. ++ ++config SWCONFIG_LEDS ++ bool "Switch LED trigger support" ++ depends on (SWCONFIG && LEDS_TRIGGERS) ++ + comment "MII PHY device drivers" + + config AT803X_PHY +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -3,6 +3,7 @@ + libphy-objs := phy.o phy_device.o mdio_bus.o + + obj-$(CONFIG_PHYLIB) += libphy.o ++obj-$(CONFIG_SWCONFIG) += swconfig.o + obj-$(CONFIG_MARVELL_PHY) += marvell.o + obj-$(CONFIG_DAVICOM_PHY) += davicom.o + obj-$(CONFIG_CICADA_PHY) += cicada.o +--- a/include/uapi/linux/Kbuild ++++ b/include/uapi/linux/Kbuild +@@ -374,6 +374,7 @@ header-y += stddef.h + header-y += string.h + header-y += suspend_ioctls.h + header-y += swab.h ++header-y += switch.h + header-y += synclink.h + header-y += sysctl.h + header-y += sysinfo.h diff --git a/target/linux/generic/patches-3.18/701-phy_extension.patch b/target/linux/generic/patches-3.18/701-phy_extension.patch new file mode 100644 index 0000000..5c63dbe --- /dev/null +++ b/target/linux/generic/patches-3.18/701-phy_extension.patch @@ -0,0 +1,63 @@ +--- a/drivers/net/phy/phy.c ++++ b/drivers/net/phy/phy.c +@@ -357,6 +357,50 @@ int phy_ethtool_gset(struct phy_device * + } + EXPORT_SYMBOL(phy_ethtool_gset); + ++int phy_ethtool_ioctl(struct phy_device *phydev, void *useraddr) ++{ ++ u32 cmd; ++ int tmp; ++ struct ethtool_cmd ecmd = { ETHTOOL_GSET }; ++ struct ethtool_value edata = { ETHTOOL_GLINK }; ++ ++ if (get_user(cmd, (u32 *) useraddr)) ++ return -EFAULT; ++ ++ switch (cmd) { ++ case ETHTOOL_GSET: ++ phy_ethtool_gset(phydev, &ecmd); ++ if (copy_to_user(useraddr, &ecmd, sizeof(ecmd))) ++ return -EFAULT; ++ return 0; ++ ++ case ETHTOOL_SSET: ++ if (copy_from_user(&ecmd, useraddr, sizeof(ecmd))) ++ return -EFAULT; ++ return phy_ethtool_sset(phydev, &ecmd); ++ ++ case ETHTOOL_NWAY_RST: ++ /* if autoneg is off, it's an error */ ++ tmp = phy_read(phydev, MII_BMCR); ++ if (tmp & BMCR_ANENABLE) { ++ tmp |= (BMCR_ANRESTART); ++ phy_write(phydev, MII_BMCR, tmp); ++ return 0; ++ } ++ return -EINVAL; ++ ++ case ETHTOOL_GLINK: ++ edata.data = (phy_read(phydev, ++ MII_BMSR) & BMSR_LSTATUS) ? 1 : 0; ++ if (copy_to_user(useraddr, &edata, sizeof(edata))) ++ return -EFAULT; ++ return 0; ++ } ++ ++ return -EOPNOTSUPP; ++} ++EXPORT_SYMBOL(phy_ethtool_ioctl); ++ + /** + * phy_mii_ioctl - generic PHY MII ioctl interface + * @phydev: the phy_device struct +--- a/include/linux/phy.h ++++ b/include/linux/phy.h +@@ -748,6 +748,7 @@ void phy_start_machine(struct phy_device + void phy_stop_machine(struct phy_device *phydev); + int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd); + int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd); ++int phy_ethtool_ioctl(struct phy_device *phydev, void *useraddr); + int phy_mii_ioctl(struct phy_device *phydev, struct ifreq *ifr, int cmd); + int phy_start_interrupts(struct phy_device *phydev); + void phy_print_status(struct phy_device *phydev); diff --git a/target/linux/generic/patches-3.18/702-phy_add_aneg_done_function.patch b/target/linux/generic/patches-3.18/702-phy_add_aneg_done_function.patch new file mode 100644 index 0000000..d20fc04 --- /dev/null +++ b/target/linux/generic/patches-3.18/702-phy_add_aneg_done_function.patch @@ -0,0 +1,27 @@ +--- a/include/linux/phy.h ++++ b/include/linux/phy.h +@@ -484,6 +484,12 @@ struct phy_driver { + /* Determines the negotiated speed and duplex */ + int (*read_status)(struct phy_device *phydev); + ++ /* ++ * Update the value in phydev->link to reflect the ++ * current link value ++ */ ++ int (*update_link)(struct phy_device *phydev); ++ + /* Clears any pending interrupts */ + int (*ack_interrupt)(struct phy_device *phydev); + +--- a/drivers/net/phy/phy_device.c ++++ b/drivers/net/phy/phy_device.c +@@ -915,6 +915,9 @@ int genphy_update_link(struct phy_device + { + int status; + ++ if (phydev->drv->update_link) ++ return phydev->drv->update_link(phydev); ++ + /* Do a fake read */ + status = phy_read(phydev, MII_BMSR); + if (status < 0) diff --git a/target/linux/generic/patches-3.18/703-phy-add-detach-callback-to-struct-phy_driver.patch b/target/linux/generic/patches-3.18/703-phy-add-detach-callback-to-struct-phy_driver.patch new file mode 100644 index 0000000..061e40f --- /dev/null +++ b/target/linux/generic/patches-3.18/703-phy-add-detach-callback-to-struct-phy_driver.patch @@ -0,0 +1,27 @@ +--- a/drivers/net/phy/phy_device.c ++++ b/drivers/net/phy/phy_device.c +@@ -674,6 +674,9 @@ void phy_detach(struct phy_device *phyde + { + int i; + ++ if (phydev->drv && phydev->drv->detach) ++ phydev->drv->detach(phydev); ++ + if (phydev->bus->dev.driver) + module_put(phydev->bus->dev.driver->owner); + +--- a/include/linux/phy.h ++++ b/include/linux/phy.h +@@ -502,6 +502,12 @@ struct phy_driver { + */ + int (*did_interrupt)(struct phy_device *phydev); + ++ /* ++ * Called before an ethernet device is detached ++ * from the PHY. ++ */ ++ void (*detach)(struct phy_device *phydev); ++ + /* Clears up any memory if needed */ + void (*remove)(struct phy_device *phydev); + diff --git a/target/linux/generic/patches-3.18/704-phy-no-genphy-soft-reset.patch b/target/linux/generic/patches-3.18/704-phy-no-genphy-soft-reset.patch new file mode 100644 index 0000000..0350f9e --- /dev/null +++ b/target/linux/generic/patches-3.18/704-phy-no-genphy-soft-reset.patch @@ -0,0 +1,29 @@ +--- a/drivers/net/phy/phy_device.c ++++ b/drivers/net/phy/phy_device.c +@@ -1133,7 +1133,7 @@ int genphy_config_init(struct phy_device + return 0; + } + +-static int gen10g_soft_reset(struct phy_device *phydev) ++static int no_soft_reset(struct phy_device *phydev) + { + /* Do nothing for now */ + return 0; +@@ -1347,7 +1347,7 @@ static struct phy_driver genphy_driver[] + .phy_id = 0xffffffff, + .phy_id_mask = 0xffffffff, + .name = "Generic PHY", +- .soft_reset = genphy_soft_reset, ++ .soft_reset = no_soft_reset, + .config_init = genphy_config_init, + .features = PHY_GBIT_FEATURES | SUPPORTED_MII | + SUPPORTED_AUI | SUPPORTED_FIBRE | +@@ -1362,7 +1362,7 @@ static struct phy_driver genphy_driver[] + .phy_id = 0xffffffff, + .phy_id_mask = 0xffffffff, + .name = "Generic 10G PHY", +- .soft_reset = gen10g_soft_reset, ++ .soft_reset = no_soft_reset, + .config_init = gen10g_config_init, + .features = 0, + .config_aneg = gen10g_config_aneg, diff --git a/target/linux/generic/patches-3.18/710-phy-add-mdio_register_board_info.patch b/target/linux/generic/patches-3.18/710-phy-add-mdio_register_board_info.patch new file mode 100644 index 0000000..cc3cb24 --- /dev/null +++ b/target/linux/generic/patches-3.18/710-phy-add-mdio_register_board_info.patch @@ -0,0 +1,192 @@ +--- a/drivers/net/phy/mdio_bus.c ++++ b/drivers/net/phy/mdio_bus.c +@@ -38,6 +38,8 @@ + + #include + ++#include "mdio-boardinfo.h" ++ + /** + * mdiobus_alloc_size - allocate a mii_bus structure + * @size: extra amount of memory to allocate for private storage. +@@ -335,9 +337,21 @@ void mdiobus_free(struct mii_bus *bus) + } + EXPORT_SYMBOL(mdiobus_free); + ++static void mdiobus_setup_phydev_from_boardinfo(struct mii_bus *bus, ++ struct phy_device *phydev, ++ struct mdio_board_info *bi) ++{ ++ if (strcmp(bus->id, bi->bus_id) || ++ bi->phy_addr != phydev->addr) ++ return; ++ ++ phydev->dev.platform_data = (void *) bi->platform_data; ++} ++ + struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr) + { + struct phy_device *phydev; ++ struct mdio_board_entry *be; + int err; + + phydev = get_phy_device(bus, addr, false); +@@ -350,6 +364,12 @@ struct phy_device *mdiobus_scan(struct m + */ + of_mdiobus_link_phydev(bus, phydev); + ++ mutex_lock(&__mdio_board_lock); ++ list_for_each_entry(be, &__mdio_board_list, list) ++ mdiobus_setup_phydev_from_boardinfo(bus, phydev, ++ &be->board_info); ++ mutex_unlock(&__mdio_board_lock); ++ + err = phy_device_register(phydev); + if (err) { + phy_device_free(phydev); +--- a/include/linux/phy.h ++++ b/include/linux/phy.h +@@ -785,4 +785,22 @@ int __init mdio_bus_init(void); + void mdio_bus_exit(void); + + extern struct bus_type mdio_bus_type; ++ ++struct mdio_board_info { ++ const char *bus_id; ++ int phy_addr; ++ ++ const void *platform_data; ++}; ++ ++#ifdef CONFIG_MDIO_BOARDINFO ++int mdiobus_register_board_info(const struct mdio_board_info *info, unsigned n); ++#else ++static inline int ++mdiobus_register_board_info(const struct mdio_board_info *info, unsigned n) ++{ ++ return 0; ++} ++#endif ++ + #endif /* __PHY_H */ +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -12,6 +12,10 @@ menuconfig PHYLIB + + if PHYLIB + ++config MDIO_BOARDINFO ++ bool ++ default y ++ + config SWCONFIG + tristate "Switch configuration API" + ---help--- +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -2,6 +2,8 @@ + + libphy-objs := phy.o phy_device.o mdio_bus.o + ++obj-$(CONFIG_MDIO_BOARDINFO) += mdio-boardinfo.o ++ + obj-$(CONFIG_PHYLIB) += libphy.o + obj-$(CONFIG_SWCONFIG) += swconfig.o + obj-$(CONFIG_MARVELL_PHY) += marvell.o +--- /dev/null ++++ b/drivers/net/phy/mdio-boardinfo.c +@@ -0,0 +1,58 @@ ++/* ++ * mdio-boardinfo.c - collect pre-declarations of PHY devices ++ * ++ * 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. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "mdio-boardinfo.h" ++ ++/* ++ * These symbols are exported ONLY FOR the mdio_bus component. ++ * No other users will be supported. ++ */ ++ ++LIST_HEAD(__mdio_board_list); ++EXPORT_SYMBOL_GPL(__mdio_board_list); ++ ++DEFINE_MUTEX(__mdio_board_lock); ++EXPORT_SYMBOL_GPL(__mdio_board_lock); ++ ++/** ++ * mdio_register_board_info - register PHY devices for a given board ++ * @info: array of chip descriptors ++ * @n: how many descriptors are provided ++ * Context: can sleep ++ * ++ * The board info passed can safely be __initdata ... but be careful of ++ * any embedded pointers (platform_data, etc), they're copied as-is. ++ */ ++int __init ++mdiobus_register_board_info(struct mdio_board_info const *info, unsigned n) ++{ ++ struct mdio_board_entry *be; ++ int i; ++ ++ be = kzalloc(n * sizeof(*be), GFP_KERNEL); ++ if (!be) ++ return -ENOMEM; ++ ++ for (i = 0; i < n; i++, be++, info++) { ++ memcpy(&be->board_info, info, sizeof(*info)); ++ mutex_lock(&__mdio_board_lock); ++ list_add_tail(&be->list, &__mdio_board_list); ++ mutex_unlock(&__mdio_board_lock); ++ } ++ ++ return 0; ++} +--- /dev/null ++++ b/drivers/net/phy/mdio-boardinfo.h +@@ -0,0 +1,22 @@ ++/* ++ * mdio-boardinfo.h - boardinfo interface internal to the mdio_bus component ++ * ++ * 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. ++ * ++ */ ++ ++#include ++ ++struct mdio_board_entry { ++ struct list_head list; ++ struct mdio_board_info board_info; ++}; ++ ++/* __mdio_board_lock protects __mdio_board_list ++ * only mdio_bus components are allowed to use these symbols. ++ */ ++extern struct mutex __mdio_board_lock; ++extern struct list_head __mdio_board_list; +--- a/drivers/net/Makefile ++++ b/drivers/net/Makefile +@@ -15,7 +15,7 @@ obj-$(CONFIG_MII) += mii.o + obj-$(CONFIG_MDIO) += mdio.o + obj-$(CONFIG_NET) += Space.o loopback.o + obj-$(CONFIG_NETCONSOLE) += netconsole.o +-obj-$(CONFIG_PHYLIB) += phy/ ++obj-y += phy/ + obj-$(CONFIG_RIONET) += rionet.o + obj-$(CONFIG_NET_TEAM) += team/ + obj-$(CONFIG_TUN) += tun.o diff --git a/target/linux/generic/patches-3.18/720-phy_adm6996.patch b/target/linux/generic/patches-3.18/720-phy_adm6996.patch new file mode 100644 index 0000000..b0b8db4 --- /dev/null +++ b/target/linux/generic/patches-3.18/720-phy_adm6996.patch @@ -0,0 +1,26 @@ +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -132,6 +132,13 @@ config MICREL_PHY + ---help--- + Supports the KSZ9021, VSC8201, KS8001 PHYs. + ++config ADM6996_PHY ++ tristate "Driver for ADM6996 switches" ++ select SWCONFIG ++ ---help--- ++ Currently supports the ADM6996FC and ADM6996M switches. ++ Support for FC is very limited. ++ + config FIXED_PHY + bool "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs" + depends on PHYLIB=y +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -18,6 +18,7 @@ obj-$(CONFIG_BCM63XX_PHY) += bcm63xx.o + obj-$(CONFIG_BCM7XXX_PHY) += bcm7xxx.o + obj-$(CONFIG_BCM87XX_PHY) += bcm87xx.o + obj-$(CONFIG_ICPLUS_PHY) += icplus.o ++obj-$(CONFIG_ADM6996_PHY) += adm6996.o + obj-$(CONFIG_REALTEK_PHY) += realtek.o + obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o + obj-$(CONFIG_FIXED_PHY) += fixed.o diff --git a/target/linux/generic/patches-3.18/721-phy_packets.patch b/target/linux/generic/patches-3.18/721-phy_packets.patch new file mode 100644 index 0000000..7616817 --- /dev/null +++ b/target/linux/generic/patches-3.18/721-phy_packets.patch @@ -0,0 +1,161 @@ +--- a/include/linux/netdevice.h ++++ b/include/linux/netdevice.h +@@ -1220,6 +1220,7 @@ enum netdev_priv_flags { + IFF_LIVE_ADDR_CHANGE = 1<<20, + IFF_MACVLAN = 1<<21, + IFF_XMIT_DST_RELEASE_PERM = 1<<22, ++ IFF_NO_IP_ALIGN = 1<<23, + }; + + #define IFF_802_1Q_VLAN IFF_802_1Q_VLAN +@@ -1245,6 +1246,7 @@ enum netdev_priv_flags { + #define IFF_LIVE_ADDR_CHANGE IFF_LIVE_ADDR_CHANGE + #define IFF_MACVLAN IFF_MACVLAN + #define IFF_XMIT_DST_RELEASE_PERM IFF_XMIT_DST_RELEASE_PERM ++#define IFF_NO_IP_ALIGN IFF_NO_IP_ALIGN + + /** + * struct net_device - The DEVICE structure. +@@ -1515,6 +1517,11 @@ struct net_device { + const struct ethtool_ops *ethtool_ops; + const struct forwarding_accel_ops *fwd_ops; + ++#ifdef CONFIG_ETHERNET_PACKET_MANGLE ++ void (*eth_mangle_rx)(struct net_device *dev, struct sk_buff *skb); ++ struct sk_buff *(*eth_mangle_tx)(struct net_device *dev, struct sk_buff *skb); ++#endif ++ + const struct header_ops *header_ops; + + unsigned int flags; +@@ -1579,6 +1586,10 @@ struct net_device { + void *ax25_ptr; + struct wireless_dev *ieee80211_ptr; + ++#ifdef CONFIG_ETHERNET_PACKET_MANGLE ++ void *phy_ptr; /* PHY device specific data */ ++#endif ++ + /* + * Cache lines mostly used on receive path (including eth_type_trans()) + */ +--- a/include/linux/skbuff.h ++++ b/include/linux/skbuff.h +@@ -2054,6 +2054,10 @@ static inline int pskb_trim(struct sk_bu + return (len < skb->len) ? __pskb_trim(skb, len) : 0; + } + ++extern struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev, ++ unsigned int length, gfp_t gfp); ++ ++ + /** + * pskb_trim_unique - remove end from a paged unique (not cloned) buffer + * @skb: buffer to alter +@@ -2180,16 +2184,6 @@ static inline struct sk_buff *dev_alloc_ + } + + +-static inline struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev, +- unsigned int length, gfp_t gfp) +-{ +- struct sk_buff *skb = __netdev_alloc_skb(dev, length + NET_IP_ALIGN, gfp); +- +- if (NET_IP_ALIGN && skb) +- skb_reserve(skb, NET_IP_ALIGN); +- return skb; +-} +- + static inline struct sk_buff *netdev_alloc_skb_ip_align(struct net_device *dev, + unsigned int length) + { +--- a/net/Kconfig ++++ b/net/Kconfig +@@ -25,6 +25,12 @@ menuconfig NET + + if NET + ++config ETHERNET_PACKET_MANGLE ++ bool ++ help ++ This option can be selected by phy drivers that need to mangle ++ packets going in or out of an ethernet device. ++ + config WANT_COMPAT_NETLINK_MESSAGES + bool + help +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -2623,10 +2623,20 @@ static int xmit_one(struct sk_buff *skb, + if (!list_empty(&ptype_all)) + dev_queue_xmit_nit(skb, dev); + +- len = skb->len; +- trace_net_dev_start_xmit(skb, dev); +- rc = netdev_start_xmit(skb, dev, txq, more); +- trace_net_dev_xmit(skb, rc, dev, len); ++#ifdef CONFIG_ETHERNET_PACKET_MANGLE ++ if (!dev->eth_mangle_tx || ++ (skb = dev->eth_mangle_tx(dev, skb)) != NULL) ++#else ++ if (1) ++#endif ++ { ++ len = skb->len; ++ trace_net_dev_start_xmit(skb, dev); ++ rc = netdev_start_xmit(skb, dev, txq, more); ++ trace_net_dev_xmit(skb, rc, dev, len); ++ } else { ++ rc = NETDEV_TX_OK; ++ } + + return rc; + } +--- a/net/core/skbuff.c ++++ b/net/core/skbuff.c +@@ -63,6 +63,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -469,6 +470,22 @@ struct sk_buff *__netdev_alloc_skb(struc + } + EXPORT_SYMBOL(__netdev_alloc_skb); + ++struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev, ++ unsigned int length, gfp_t gfp) ++{ ++ struct sk_buff *skb = __netdev_alloc_skb(dev, length + NET_IP_ALIGN, gfp); ++ ++#ifdef CONFIG_ETHERNET_PACKET_MANGLE ++ if (dev && (dev->priv_flags & IFF_NO_IP_ALIGN)) ++ return skb; ++#endif ++ ++ if (NET_IP_ALIGN && skb) ++ skb_reserve(skb, NET_IP_ALIGN); ++ return skb; ++} ++EXPORT_SYMBOL(__netdev_alloc_skb_ip_align); ++ + void skb_add_rx_frag(struct sk_buff *skb, int i, struct page *page, int off, + int size, unsigned int truesize) + { +--- a/net/ethernet/eth.c ++++ b/net/ethernet/eth.c +@@ -200,6 +200,12 @@ __be16 eth_type_trans(struct sk_buff *sk + const struct ethhdr *eth; + + skb->dev = dev; ++ ++#ifdef CONFIG_ETHERNET_PACKET_MANGLE ++ if (dev->eth_mangle_rx) ++ dev->eth_mangle_rx(dev, skb); ++#endif ++ + skb_reset_mac_header(skb); + skb_pull_inline(skb, ETH_HLEN); + eth = eth_hdr(skb); diff --git a/target/linux/generic/patches-3.18/722-phy_mvswitch.patch b/target/linux/generic/patches-3.18/722-phy_mvswitch.patch new file mode 100644 index 0000000..f577a9f --- /dev/null +++ b/target/linux/generic/patches-3.18/722-phy_mvswitch.patch @@ -0,0 +1,23 @@ +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -139,6 +139,10 @@ config ADM6996_PHY + Currently supports the ADM6996FC and ADM6996M switches. + Support for FC is very limited. + ++config MVSWITCH_PHY ++ tristate "Driver for Marvell 88E6060 switches" ++ select ETHERNET_PACKET_MANGLE ++ + config FIXED_PHY + bool "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs" + depends on PHYLIB=y +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -19,6 +19,7 @@ obj-$(CONFIG_BCM7XXX_PHY) += bcm7xxx.o + obj-$(CONFIG_BCM87XX_PHY) += bcm87xx.o + obj-$(CONFIG_ICPLUS_PHY) += icplus.o + obj-$(CONFIG_ADM6996_PHY) += adm6996.o ++obj-$(CONFIG_MVSWITCH_PHY) += mvswitch.o + obj-$(CONFIG_REALTEK_PHY) += realtek.o + obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o + obj-$(CONFIG_FIXED_PHY) += fixed.o diff --git a/target/linux/generic/patches-3.18/723-phy_ip175c.patch b/target/linux/generic/patches-3.18/723-phy_ip175c.patch new file mode 100644 index 0000000..c7c4f99 --- /dev/null +++ b/target/linux/generic/patches-3.18/723-phy_ip175c.patch @@ -0,0 +1,23 @@ +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -143,6 +143,10 @@ config MVSWITCH_PHY + tristate "Driver for Marvell 88E6060 switches" + select ETHERNET_PACKET_MANGLE + ++config IP17XX_PHY ++ tristate "Driver for IC+ IP17xx switches" ++ select SWCONFIG ++ + config FIXED_PHY + bool "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs" + depends on PHYLIB=y +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -20,6 +20,7 @@ obj-$(CONFIG_BCM87XX_PHY) += bcm87xx.o + obj-$(CONFIG_ICPLUS_PHY) += icplus.o + obj-$(CONFIG_ADM6996_PHY) += adm6996.o + obj-$(CONFIG_MVSWITCH_PHY) += mvswitch.o ++obj-$(CONFIG_IP17XX_PHY) += ip17xx.o + obj-$(CONFIG_REALTEK_PHY) += realtek.o + obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o + obj-$(CONFIG_FIXED_PHY) += fixed.o diff --git a/target/linux/generic/patches-3.18/724-phy_ar8216.patch b/target/linux/generic/patches-3.18/724-phy_ar8216.patch new file mode 100644 index 0000000..acb2df8 --- /dev/null +++ b/target/linux/generic/patches-3.18/724-phy_ar8216.patch @@ -0,0 +1,24 @@ +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -147,6 +147,11 @@ config IP17XX_PHY + tristate "Driver for IC+ IP17xx switches" + select SWCONFIG + ++config AR8216_PHY ++ tristate "Driver for Atheros AR8216 switches" ++ select ETHERNET_PACKET_MANGLE ++ select SWCONFIG ++ + config FIXED_PHY + bool "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs" + depends on PHYLIB=y +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -22,6 +22,7 @@ obj-$(CONFIG_ADM6996_PHY) += adm6996.o + obj-$(CONFIG_MVSWITCH_PHY) += mvswitch.o + obj-$(CONFIG_IP17XX_PHY) += ip17xx.o + obj-$(CONFIG_REALTEK_PHY) += realtek.o ++obj-$(CONFIG_AR8216_PHY) += ar8216.o ar8327.o + obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o + obj-$(CONFIG_FIXED_PHY) += fixed.o + obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o diff --git a/target/linux/generic/patches-3.18/725-phy_rtl8306.patch b/target/linux/generic/patches-3.18/725-phy_rtl8306.patch new file mode 100644 index 0000000..78ac6ce --- /dev/null +++ b/target/linux/generic/patches-3.18/725-phy_rtl8306.patch @@ -0,0 +1,23 @@ +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -152,6 +152,10 @@ config AR8216_PHY + select ETHERNET_PACKET_MANGLE + select SWCONFIG + ++config RTL8306_PHY ++ tristate "Driver for Realtek RTL8306S switches" ++ select SWCONFIG ++ + config FIXED_PHY + bool "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs" + depends on PHYLIB=y +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -23,6 +23,7 @@ obj-$(CONFIG_MVSWITCH_PHY) += mvswitch.o + obj-$(CONFIG_IP17XX_PHY) += ip17xx.o + obj-$(CONFIG_REALTEK_PHY) += realtek.o + obj-$(CONFIG_AR8216_PHY) += ar8216.o ar8327.o ++obj-$(CONFIG_RTL8306_PHY) += rtl8306.o + obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o + obj-$(CONFIG_FIXED_PHY) += fixed.o + obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o diff --git a/target/linux/generic/patches-3.18/726-phy_rtl8366.patch b/target/linux/generic/patches-3.18/726-phy_rtl8366.patch new file mode 100644 index 0000000..4a4a4ac --- /dev/null +++ b/target/linux/generic/patches-3.18/726-phy_rtl8366.patch @@ -0,0 +1,45 @@ +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -250,6 +250,30 @@ config MDIO_BCM_UNIMAC + controllers as well as some Broadcom Ethernet switches such as the + Starfighter 2 switches. + ++config RTL8366_SMI ++ tristate "Driver for the RTL8366 SMI interface" ++ depends on GPIOLIB ++ ---help--- ++ This module implements the SMI interface protocol which is used ++ by some RTL8366 ethernet switch devices via the generic GPIO API. ++ ++if RTL8366_SMI ++ ++config RTL8366_SMI_DEBUG_FS ++ bool "RTL8366 SMI interface debugfs support" ++ depends on DEBUG_FS ++ default n ++ ++config RTL8366S_PHY ++ tristate "Driver for the Realtek RTL8366S switch" ++ select SWCONFIG ++ ++config RTL8366RB_PHY ++ tristate "Driver for the Realtek RTL8366RB switch" ++ select SWCONFIG ++ ++endif # RTL8366_SMI ++ + endif # PHYLIB + + config MICREL_KS8995MA +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -24,6 +24,9 @@ obj-$(CONFIG_IP17XX_PHY) += ip17xx.o + obj-$(CONFIG_REALTEK_PHY) += realtek.o + obj-$(CONFIG_AR8216_PHY) += ar8216.o ar8327.o + obj-$(CONFIG_RTL8306_PHY) += rtl8306.o ++obj-$(CONFIG_RTL8366_SMI) += rtl8366_smi.o ++obj-$(CONFIG_RTL8366S_PHY) += rtl8366s.o ++obj-$(CONFIG_RTL8366RB_PHY) += rtl8366rb.o + obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o + obj-$(CONFIG_FIXED_PHY) += fixed.o + obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o diff --git a/target/linux/generic/patches-3.18/727-phy-rtl8367.patch b/target/linux/generic/patches-3.18/727-phy-rtl8367.patch new file mode 100644 index 0000000..8481b58 --- /dev/null +++ b/target/linux/generic/patches-3.18/727-phy-rtl8367.patch @@ -0,0 +1,23 @@ +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -272,6 +272,10 @@ config RTL8366RB_PHY + tristate "Driver for the Realtek RTL8366RB switch" + select SWCONFIG + ++config RTL8367_PHY ++ tristate "Driver for the Realtek RTL8367R/M switches" ++ select SWCONFIG ++ + endif # RTL8366_SMI + + endif # PHYLIB +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -27,6 +27,7 @@ obj-$(CONFIG_RTL8306_PHY) += rtl8306.o + obj-$(CONFIG_RTL8366_SMI) += rtl8366_smi.o + obj-$(CONFIG_RTL8366S_PHY) += rtl8366s.o + obj-$(CONFIG_RTL8366RB_PHY) += rtl8366rb.o ++obj-$(CONFIG_RTL8367_PHY) += rtl8367.o + obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o + obj-$(CONFIG_FIXED_PHY) += fixed.o + obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o diff --git a/target/linux/generic/patches-3.18/728-phy-rtl8367b.patch b/target/linux/generic/patches-3.18/728-phy-rtl8367b.patch new file mode 100644 index 0000000..958ff58 --- /dev/null +++ b/target/linux/generic/patches-3.18/728-phy-rtl8367b.patch @@ -0,0 +1,23 @@ +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -276,6 +276,10 @@ config RTL8367_PHY + tristate "Driver for the Realtek RTL8367R/M switches" + select SWCONFIG + ++config RTL8367B_PHY ++ tristate "Driver fot the Realtek RTL8367R-VB switch" ++ select SWCONFIG ++ + endif # RTL8366_SMI + + endif # PHYLIB +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -28,6 +28,7 @@ obj-$(CONFIG_RTL8366_SMI) += rtl8366_smi + obj-$(CONFIG_RTL8366S_PHY) += rtl8366s.o + obj-$(CONFIG_RTL8366RB_PHY) += rtl8366rb.o + obj-$(CONFIG_RTL8367_PHY) += rtl8367.o ++obj-$(CONFIG_RTL8367B_PHY) += rtl8367b.o + obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o + obj-$(CONFIG_FIXED_PHY) += fixed.o + obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o diff --git a/target/linux/generic/patches-3.18/729-phy-tantos.patch b/target/linux/generic/patches-3.18/729-phy-tantos.patch new file mode 100644 index 0000000..019f919 --- /dev/null +++ b/target/linux/generic/patches-3.18/729-phy-tantos.patch @@ -0,0 +1,21 @@ +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -287,3 +287,8 @@ endif # PHYLIB + config MICREL_KS8995MA + tristate "Micrel KS8995MA 5-ports 10/100 managed Ethernet switch" + depends on SPI ++ ++config PSB6970_PHY ++ tristate "Lantiq XWAY Tantos (PSB6970) Ethernet switch" ++ select SWCONFIG ++ select ETHERNET_PACKET_MANGLE +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -30,6 +30,7 @@ obj-$(CONFIG_RTL8366RB_PHY) += rtl8366rb + obj-$(CONFIG_RTL8367_PHY) += rtl8367.o + obj-$(CONFIG_RTL8367B_PHY) += rtl8367b.o + obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o ++obj-$(CONFIG_PSB6970_PHY) += psb6970.o + obj-$(CONFIG_FIXED_PHY) += fixed.o + obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o + obj-$(CONFIG_MDIO_GPIO) += mdio-gpio.o diff --git a/target/linux/generic/patches-3.18/730-phy_b53.patch b/target/linux/generic/patches-3.18/730-phy_b53.patch new file mode 100644 index 0000000..c2dfcfa --- /dev/null +++ b/target/linux/generic/patches-3.18/730-phy_b53.patch @@ -0,0 +1,21 @@ +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -282,6 +282,8 @@ config RTL8367B_PHY + + endif # RTL8366_SMI + ++source "drivers/net/phy/b53/Kconfig" ++ + endif # PHYLIB + + config MICREL_KS8995MA +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -31,6 +31,7 @@ obj-$(CONFIG_RTL8367_PHY) += rtl8367.o + obj-$(CONFIG_RTL8367B_PHY) += rtl8367b.o + obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o + obj-$(CONFIG_PSB6970_PHY) += psb6970.o ++obj-$(CONFIG_B53) += b53/ + obj-$(CONFIG_FIXED_PHY) += fixed.o + obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o + obj-$(CONFIG_MDIO_GPIO) += mdio-gpio.o diff --git a/target/linux/generic/patches-3.18/731-phy_mvswitch_3.10_compilation.patch b/target/linux/generic/patches-3.18/731-phy_mvswitch_3.10_compilation.patch new file mode 100644 index 0000000..2053bd2 --- /dev/null +++ b/target/linux/generic/patches-3.18/731-phy_mvswitch_3.10_compilation.patch @@ -0,0 +1,35 @@ +From e6a5abb9a02be0bceb4782d9f736bfb4ae217505 Mon Sep 17 00:00:00 2001 +From: Jonas Gorski +Date: Sat, 21 Sep 2013 13:56:51 +0200 +Subject: [PATCH] phy: mvswitch: fix 3.10 compilation + +Update to API changes in 3.10. + +Signed-off-by: Jonas Gorsi +--- + target/linux/generic/files/drivers/net/phy/mvswitch.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/drivers/net/phy/mvswitch.c ++++ b/drivers/net/phy/mvswitch.c +@@ -173,7 +173,7 @@ mvswitch_mangle_rx(struct net_device *de + if (vlan == -1) + return; + +- __vlan_hwaccel_put_tag(skb, vlan); ++ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan); + } + + +@@ -307,9 +307,9 @@ mvswitch_config_init(struct phy_device * + + #ifdef HEADER_MODE + dev->priv_flags |= IFF_NO_IP_ALIGN; +- dev->features |= NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_TX; ++ dev->features |= NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_TX; + #else +- dev->features |= NETIF_F_HW_VLAN_RX; ++ dev->features |= NETIF_F_HW_VLAN_CTAG_RX; + #endif + + return 0; diff --git a/target/linux/generic/patches-3.18/732-phy-ar8216-led-support.patch b/target/linux/generic/patches-3.18/732-phy-ar8216-led-support.patch new file mode 100644 index 0000000..c753967 --- /dev/null +++ b/target/linux/generic/patches-3.18/732-phy-ar8216-led-support.patch @@ -0,0 +1,13 @@ +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -152,6 +152,10 @@ config AR8216_PHY + select ETHERNET_PACKET_MANGLE + select SWCONFIG + ++config AR8216_PHY_LEDS ++ bool "Atheros AR8216 switch LED support" ++ depends on (AR8216_PHY && LEDS_CLASS) ++ + config RTL8306_PHY + tristate "Driver for Realtek RTL8306S switches" + select SWCONFIG diff --git a/target/linux/generic/patches-3.18/733-phy_mvsw61xx.patch b/target/linux/generic/patches-3.18/733-phy_mvsw61xx.patch new file mode 100644 index 0000000..041d168 --- /dev/null +++ b/target/linux/generic/patches-3.18/733-phy_mvsw61xx.patch @@ -0,0 +1,23 @@ +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -143,6 +143,10 @@ config MVSWITCH_PHY + tristate "Driver for Marvell 88E6060 switches" + select ETHERNET_PACKET_MANGLE + ++config MVSW61XX_PHY ++ tristate "Driver for Marvell 88E6171/6172 switches" ++ select SWCONFIG ++ + config IP17XX_PHY + tristate "Driver for IC+ IP17xx switches" + select SWCONFIG +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -20,6 +20,7 @@ obj-$(CONFIG_BCM87XX_PHY) += bcm87xx.o + obj-$(CONFIG_ICPLUS_PHY) += icplus.o + obj-$(CONFIG_ADM6996_PHY) += adm6996.o + obj-$(CONFIG_MVSWITCH_PHY) += mvswitch.o ++obj-$(CONFIG_MVSW61XX_PHY) += mvsw61xx.o + obj-$(CONFIG_IP17XX_PHY) += ip17xx.o + obj-$(CONFIG_REALTEK_PHY) += realtek.o + obj-$(CONFIG_AR8216_PHY) += ar8216.o ar8327.o diff --git a/target/linux/generic/patches-3.18/750-hostap_txpower.patch b/target/linux/generic/patches-3.18/750-hostap_txpower.patch new file mode 100644 index 0000000..768c80f --- /dev/null +++ b/target/linux/generic/patches-3.18/750-hostap_txpower.patch @@ -0,0 +1,154 @@ +--- a/drivers/net/wireless/hostap/hostap_ap.c ++++ b/drivers/net/wireless/hostap/hostap_ap.c +@@ -2403,13 +2403,13 @@ int prism2_ap_get_sta_qual(local_info_t + addr[count].sa_family = ARPHRD_ETHER; + memcpy(addr[count].sa_data, sta->addr, ETH_ALEN); + if (sta->last_rx_silence == 0) +- qual[count].qual = sta->last_rx_signal < 27 ? +- 0 : (sta->last_rx_signal - 27) * 92 / 127; ++ qual[count].qual = (sta->last_rx_signal - 156) == 0 ? ++ 0 : (sta->last_rx_signal - 156) * 92 / 64; + else +- qual[count].qual = sta->last_rx_signal - +- sta->last_rx_silence - 35; +- qual[count].level = HFA384X_LEVEL_TO_dBm(sta->last_rx_signal); +- qual[count].noise = HFA384X_LEVEL_TO_dBm(sta->last_rx_silence); ++ qual[count].qual = (sta->last_rx_signal - ++ sta->last_rx_silence) * 92 / 64; ++ qual[count].level = sta->last_rx_signal; ++ qual[count].noise = sta->last_rx_silence; + qual[count].updated = sta->last_rx_updated; + + sta->last_rx_updated = IW_QUAL_DBM; +@@ -2475,13 +2475,13 @@ int prism2_ap_translate_scan(struct net_ + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = IWEVQUAL; + if (sta->last_rx_silence == 0) +- iwe.u.qual.qual = sta->last_rx_signal < 27 ? +- 0 : (sta->last_rx_signal - 27) * 92 / 127; ++ iwe.u.qual.qual = (sta->last_rx_signal -156) == 0 ? ++ 0 : (sta->last_rx_signal - 156) * 92 / 64; + else +- iwe.u.qual.qual = sta->last_rx_signal - +- sta->last_rx_silence - 35; +- iwe.u.qual.level = HFA384X_LEVEL_TO_dBm(sta->last_rx_signal); +- iwe.u.qual.noise = HFA384X_LEVEL_TO_dBm(sta->last_rx_silence); ++ iwe.u.qual.qual = (sta->last_rx_signal - ++ sta->last_rx_silence) * 92 / 64; ++ iwe.u.qual.level = sta->last_rx_signal; ++ iwe.u.qual.noise = sta->last_rx_silence; + iwe.u.qual.updated = sta->last_rx_updated; + iwe.len = IW_EV_QUAL_LEN; + current_ev = iwe_stream_add_event(info, current_ev, end_buf, +--- a/drivers/net/wireless/hostap/hostap_config.h ++++ b/drivers/net/wireless/hostap/hostap_config.h +@@ -45,4 +45,9 @@ + */ + /* #define PRISM2_NO_STATION_MODES */ + ++/* Enable TX power Setting functions ++ * (min att = -128 , max att = 127) ++ */ ++#define RAW_TXPOWER_SETTING ++ + #endif /* HOSTAP_CONFIG_H */ +--- a/drivers/net/wireless/hostap/hostap.h ++++ b/drivers/net/wireless/hostap/hostap.h +@@ -90,6 +90,7 @@ extern const struct iw_handler_def hosta + extern const struct ethtool_ops prism2_ethtool_ops; + + int hostap_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); ++int hostap_restore_power(struct net_device *dev); + + + #endif /* HOSTAP_H */ +--- a/drivers/net/wireless/hostap/hostap_hw.c ++++ b/drivers/net/wireless/hostap/hostap_hw.c +@@ -928,6 +928,7 @@ static int hfa384x_set_rid(struct net_de + prism2_hw_reset(dev); + } + ++ hostap_restore_power(dev); + return res; + } + +--- a/drivers/net/wireless/hostap/hostap_info.c ++++ b/drivers/net/wireless/hostap/hostap_info.c +@@ -435,6 +435,11 @@ static void handle_info_queue_linkstatus + } + + /* Get BSSID if we have a valid AP address */ ++ ++ if ( val == HFA384X_LINKSTATUS_CONNECTED || ++ val == HFA384X_LINKSTATUS_DISCONNECTED ) ++ hostap_restore_power(local->dev); ++ + if (connected) { + netif_carrier_on(local->dev); + netif_carrier_on(local->ddev); +--- a/drivers/net/wireless/hostap/hostap_ioctl.c ++++ b/drivers/net/wireless/hostap/hostap_ioctl.c +@@ -1479,23 +1479,20 @@ static int prism2_txpower_hfa386x_to_dBm + val = 255; + + tmp = val; +- tmp >>= 2; + +- return -12 - tmp; ++ return tmp; + } + + static u16 prism2_txpower_dBm_to_hfa386x(int val) + { + signed char tmp; + +- if (val > 20) +- return 128; +- else if (val < -43) ++ if (val > 127) + return 127; ++ else if (val < -128) ++ return 128; + + tmp = val; +- tmp = -12 - tmp; +- tmp <<= 2; + + return (unsigned char) tmp; + } +@@ -4052,3 +4049,35 @@ int hostap_ioctl(struct net_device *dev, + + return ret; + } ++ ++/* BUG FIX: Restore power setting value when lost due to F/W bug */ ++ ++int hostap_restore_power(struct net_device *dev) ++{ ++ struct hostap_interface *iface = netdev_priv(dev); ++ local_info_t *local = iface->local; ++ ++ u16 val; ++ int ret = 0; ++ ++ if (local->txpower_type == PRISM2_TXPOWER_OFF) { ++ val = 0xff; /* use all standby and sleep modes */ ++ ret = local->func->cmd(dev, HFA384X_CMDCODE_WRITEMIF, ++ HFA386X_CR_A_D_TEST_MODES2, ++ &val, NULL); ++ } ++ ++#ifdef RAW_TXPOWER_SETTING ++ if (local->txpower_type == PRISM2_TXPOWER_FIXED) { ++ val = HFA384X_TEST_CFG_BIT_ALC; ++ local->func->cmd(dev, HFA384X_CMDCODE_TEST | ++ (HFA384X_TEST_CFG_BITS << 8), 0, &val, NULL); ++ val = prism2_txpower_dBm_to_hfa386x(local->txpower); ++ ret = (local->func->cmd(dev, HFA384X_CMDCODE_WRITEMIF, ++ HFA386X_CR_MANUAL_TX_POWER, &val, NULL)); ++ } ++#endif /* RAW_TXPOWER_SETTING */ ++ return (ret ? -EOPNOTSUPP : 0); ++} ++ ++EXPORT_SYMBOL(hostap_restore_power); diff --git a/target/linux/generic/patches-3.18/773-bgmac-add-srab-switch.patch b/target/linux/generic/patches-3.18/773-bgmac-add-srab-switch.patch new file mode 100644 index 0000000..b883d73 --- /dev/null +++ b/target/linux/generic/patches-3.18/773-bgmac-add-srab-switch.patch @@ -0,0 +1,72 @@ +Register switch connected to srab + +Signed-off-by: Hauke Mehrtens + +--- a/drivers/net/ethernet/broadcom/bgmac.c ++++ b/drivers/net/ethernet/broadcom/bgmac.c +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + #include + + static const struct bcma_device_id bgmac_bcma_tbl[] = { +@@ -1538,6 +1539,17 @@ static void bgmac_mii_unregister(struct + mdiobus_free(mii_bus); + } + ++static struct b53_platform_data bgmac_b53_pdata = { ++}; ++ ++static struct platform_device bgmac_b53_dev = { ++ .name = "b53-srab-switch", ++ .id = -1, ++ .dev = { ++ .platform_data = &bgmac_b53_pdata, ++ }, ++}; ++ + /************************************************** + * BCMA bus ops + **************************************************/ +@@ -1664,6 +1676,16 @@ static int bgmac_probe(struct bcma_devic + net_dev->hw_features = net_dev->features; + net_dev->vlan_features = net_dev->features; + ++ if ((ci->id == BCMA_CHIP_ID_BCM4707 || ++ ci->id == BCMA_CHIP_ID_BCM53018) && ++ !bgmac_b53_pdata.regs) { ++ bgmac_b53_pdata.regs = ioremap_nocache(0x18007000, 0x1000); ++ ++ err = platform_device_register(&bgmac_b53_dev); ++ if (!err) ++ bgmac->b53_device = &bgmac_b53_dev; ++ } ++ + err = register_netdev(bgmac->net_dev); + if (err) { + bgmac_err(bgmac, "Cannot register net device\n"); +@@ -1690,6 +1712,10 @@ static void bgmac_remove(struct bcma_dev + { + struct bgmac *bgmac = bcma_get_drvdata(core); + ++ if (bgmac->b53_device) ++ platform_device_unregister(&bgmac_b53_dev); ++ bgmac->b53_device = NULL; ++ + unregister_netdev(bgmac->net_dev); + bgmac_mii_unregister(bgmac); + netif_napi_del(&bgmac->napi); +--- a/drivers/net/ethernet/broadcom/bgmac.h ++++ b/drivers/net/ethernet/broadcom/bgmac.h +@@ -462,6 +462,9 @@ struct bgmac { + bool has_robosw; + + bool loopback; ++ ++ /* platform device for associated switch */ ++ struct platform_device *b53_device; + }; + + static inline u32 bgmac_read(struct bgmac *bgmac, u16 offset) diff --git a/target/linux/generic/patches-3.18/780-igb-Fix-Null-pointer-dereference-in-igb_reset_q_vect.patch b/target/linux/generic/patches-3.18/780-igb-Fix-Null-pointer-dereference-in-igb_reset_q_vect.patch new file mode 100644 index 0000000..e541b2c --- /dev/null +++ b/target/linux/generic/patches-3.18/780-igb-Fix-Null-pointer-dereference-in-igb_reset_q_vect.patch @@ -0,0 +1,40 @@ +From cb06d102327eadcd1bdc480bfd9f8876251d1007 Mon Sep 17 00:00:00 2001 +From: Christoph Paasch +Date: Fri, 21 Mar 2014 03:48:19 -0700 +Subject: [PATCH] igb: Fix Null-pointer dereference in igb_reset_q_vector + +When igb_set_interrupt_capability() calls +igb_reset_interrupt_capability() (e.g., because CONFIG_PCI_MSI is unset), +num_q_vectors has been set but no vector has yet been allocated. + +igb_reset_interrupt_capability() will then call igb_reset_q_vector, +which assumes that the vector is allocated. As this is not the case, we +are accessing a NULL-pointer. + +This patch fixes it by checking that q_vector is indeed different from +NULL. + +Fixes: 02ef6e1d0b0023 (igb: Fix queue allocation method to accommodate changing during runtime) +Cc: Carolyn Wyborny +Signed-off-by: Christoph Paasch +Tested-by: Jeff Pieper +Signed-off-by: Jeff Kirsher +--- + drivers/net/ethernet/intel/igb/igb_main.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/drivers/net/ethernet/intel/igb/igb_main.c ++++ b/drivers/net/ethernet/intel/igb/igb_main.c +@@ -1034,6 +1034,12 @@ static void igb_reset_q_vector(struct ig + if (!q_vector) + return; + ++ /* Coming from igb_set_interrupt_capability, the vectors are not yet ++ * allocated. So, q_vector is NULL so we should stop here. ++ */ ++ if (!q_vector) ++ return; ++ + if (q_vector->tx.ring) + adapter->tx_ring[q_vector->tx.ring->queue_index] = NULL; + diff --git a/target/linux/generic/patches-3.18/785-hso-support-0af0-9300.patch b/target/linux/generic/patches-3.18/785-hso-support-0af0-9300.patch new file mode 100644 index 0000000..50bccc4 --- /dev/null +++ b/target/linux/generic/patches-3.18/785-hso-support-0af0-9300.patch @@ -0,0 +1,25 @@ +--- a/drivers/net/usb/hso.c ++++ b/drivers/net/usb/hso.c +@@ -468,6 +468,7 @@ static const struct usb_device_id hso_id + {USB_DEVICE(0x0af0, 0x8900)}, + {USB_DEVICE(0x0af0, 0x9000)}, + {USB_DEVICE(0x0af0, 0x9200)}, /* Option GTM671WFS */ ++ {USB_DEVICE(0x0af0, 0x9300)}, /* GTM 66xxWFS */ + {USB_DEVICE(0x0af0, 0xd035)}, + {USB_DEVICE(0x0af0, 0xd055)}, + {USB_DEVICE(0x0af0, 0xd155)}, +--- a/drivers/usb/storage/unusual_devs.h ++++ b/drivers/usb/storage/unusual_devs.h +@@ -1330,6 +1330,12 @@ UNUSUAL_DEV( 0x0af0, 0x8304, 0x0000, 0x0 + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + 0 ), + ++UNUSUAL_DEV( 0x0af0, 0x9300, 0x0000, 0x0000, ++ "Option", ++ "Globetrotter 66xxWFS SD-Card", ++ USB_SC_DEVICE, USB_PR_DEVICE, NULL, ++ 0 ), ++ + UNUSUAL_DEV( 0x0af0, 0xc100, 0x0000, 0x0000, + "Option", + "GI 070x SD-Card", diff --git a/target/linux/generic/patches-3.18/810-pci_disable_common_quirks.patch b/target/linux/generic/patches-3.18/810-pci_disable_common_quirks.patch new file mode 100644 index 0000000..b6c0b38 --- /dev/null +++ b/target/linux/generic/patches-3.18/810-pci_disable_common_quirks.patch @@ -0,0 +1,51 @@ +--- a/drivers/pci/Kconfig ++++ b/drivers/pci/Kconfig +@@ -58,6 +58,12 @@ config XEN_PCIDEV_FRONTEND + The PCI device frontend driver allows the kernel to import arbitrary + PCI devices from a PCI backend to support PCI driver domains. + ++config PCI_DISABLE_COMMON_QUIRKS ++ bool "PCI disable common quirks" ++ depends on PCI ++ help ++ If you don't know what to do here, say N. ++ + config HT_IRQ + bool "Interrupts on hypertransport devices" + default y +--- a/drivers/pci/quirks.c ++++ b/drivers/pci/quirks.c +@@ -41,6 +41,7 @@ static void quirk_mmio_always_on(struct + DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_BRIDGE_HOST, 8, quirk_mmio_always_on); + ++#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS + /* The Mellanox Tavor device gives false positive parity errors + * Mark this device with a broken_parity_status, to allow + * PCI scanning code to "skip" this now blacklisted device. +@@ -2905,6 +2906,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_I + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x65f9, quirk_intel_mc_errata); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x65fa, quirk_intel_mc_errata); + ++#endif /* !CONFIG_PCI_DISABLE_COMMON_QUIRKS */ + + /* + * Ivytown NTB BAR sizes are misreported by the hardware due to an erratum. To +@@ -2961,6 +2963,8 @@ static void fixup_debug_report(struct pc + } + } + ++#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS ++ + /* + * Some BIOS implementations leave the Intel GPU interrupts enabled, + * even though no one is handling them (f.e. i915 driver is never loaded). +@@ -2995,6 +2999,8 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_IN + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x010a, disable_igfx_irq); + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0152, disable_igfx_irq); + ++#endif /* !CONFIG_PCI_DISABLE_COMMON_QUIRKS */ ++ + /* + * PCI devices which are on Intel chips can skip the 10ms delay + * before entering D3 mode. diff --git a/target/linux/generic/patches-3.18/811-pci_disable_usb_common_quirks.patch b/target/linux/generic/patches-3.18/811-pci_disable_usb_common_quirks.patch new file mode 100644 index 0000000..b54d150 --- /dev/null +++ b/target/linux/generic/patches-3.18/811-pci_disable_usb_common_quirks.patch @@ -0,0 +1,101 @@ + +--- a/drivers/usb/host/pci-quirks.c ++++ b/drivers/usb/host/pci-quirks.c +@@ -97,6 +97,8 @@ struct amd_chipset_type { + u8 rev; + }; + ++#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS ++ + static struct amd_chipset_info { + struct pci_dev *nb_dev; + struct pci_dev *smbus_dev; +@@ -454,6 +456,10 @@ void usb_amd_dev_put(void) + } + EXPORT_SYMBOL_GPL(usb_amd_dev_put); + ++#endif /* CONFIG_PCI_DISABLE_COMMON_QUIRKS */ ++ ++#if IS_ENABLED(CONFIG_USB_UHCI_HCD) ++ + /* + * Make sure the controller is completely inactive, unable to + * generate interrupts or do DMA. +@@ -533,8 +539,17 @@ reset_needed: + uhci_reset_hc(pdev, base); + return 1; + } ++#else ++int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base) ++{ ++ return 0; ++} ++ ++#endif + EXPORT_SYMBOL_GPL(uhci_check_and_reset_hc); + ++#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS ++ + static inline int io_type_enabled(struct pci_dev *pdev, unsigned int mask) + { + u16 cmd; +@@ -1095,3 +1110,4 @@ static void quirk_usb_early_handoff(stru + } + DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_SERIAL_USB, 8, quirk_usb_early_handoff); ++#endif +--- a/drivers/usb/host/pci-quirks.h ++++ b/drivers/usb/host/pci-quirks.h +@@ -4,6 +4,9 @@ + #ifdef CONFIG_PCI + void uhci_reset_hc(struct pci_dev *pdev, unsigned long base); + int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base); ++#endif /* CONFIG_PCI */ ++ ++#if defined(CONFIG_PCI) && !defined(CONFIG_PCI_DISABLE_COMMON_QUIRKS) + int usb_amd_find_chipset_info(void); + int usb_hcd_amd_remote_wakeup_quirk(struct pci_dev *pdev); + bool usb_amd_hang_symptom_quirk(void); +@@ -16,11 +19,24 @@ void usb_disable_xhci_ports(struct pci_d + void sb800_prefetch(struct device *dev, int on); + #else + struct pci_dev; ++static inline int usb_amd_find_chipset_info(void) ++{ ++ return 0; ++} ++static inline bool usb_amd_hang_symptom_quirk(void) ++{ ++ return false; ++} ++static inline bool usb_amd_prefetch_quirk(void) ++{ ++ return false; ++} + static inline void usb_amd_quirk_pll_disable(void) {} + static inline void usb_amd_quirk_pll_enable(void) {} + static inline void usb_amd_dev_put(void) {} + static inline void usb_disable_xhci_ports(struct pci_dev *xhci_pdev) {} + static inline void sb800_prefetch(struct device *dev, int on) {} +-#endif /* CONFIG_PCI */ ++static inline void usb_enable_intel_xhci_ports(struct pci_dev *xhci_pdev) {} ++#endif + + #endif /* __LINUX_USB_PCI_QUIRKS_H */ +--- a/include/linux/usb/hcd.h ++++ b/include/linux/usb/hcd.h +@@ -444,7 +444,14 @@ extern int usb_hcd_pci_probe(struct pci_ + extern void usb_hcd_pci_remove(struct pci_dev *dev); + extern void usb_hcd_pci_shutdown(struct pci_dev *dev); + ++#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS + extern int usb_hcd_amd_remote_wakeup_quirk(struct pci_dev *dev); ++#else ++static inline int usb_hcd_amd_remote_wakeup_quirk(struct pci_dev *dev) ++{ ++ return 0; ++} ++#endif + + #ifdef CONFIG_PM + extern const struct dev_pm_ops usb_hcd_pci_pm_ops; diff --git a/target/linux/generic/patches-3.18/820-usb_add_usb_find_device_by_name.patch b/target/linux/generic/patches-3.18/820-usb_add_usb_find_device_by_name.patch new file mode 100644 index 0000000..e381cc9 --- /dev/null +++ b/target/linux/generic/patches-3.18/820-usb_add_usb_find_device_by_name.patch @@ -0,0 +1,84 @@ +--- a/drivers/usb/core/usb.c ++++ b/drivers/usb/core/usb.c +@@ -690,6 +690,71 @@ int __usb_get_extra_descriptor(char *buf + } + EXPORT_SYMBOL_GPL(__usb_get_extra_descriptor); + ++static struct usb_device *match_device_name(struct usb_device *dev, ++ const char *name) ++{ ++ struct usb_device *ret_dev = NULL; ++ struct usb_device *childdev = NULL; ++ int child; ++ ++ dev_dbg(&dev->dev, "check for name %s ...\n", name); ++ ++ /* see if this device matches */ ++ if (strcmp(dev_name(&dev->dev), name) == 0 ) { ++ dev_dbg(&dev->dev, "matched this device!\n"); ++ ret_dev = usb_get_dev(dev); ++ goto exit; ++ } ++ /* look through all of the children of this device */ ++ usb_hub_for_each_child(dev, child, childdev) { ++ if (childdev) { ++ usb_lock_device(childdev); ++ ret_dev = match_device_name(childdev, name); ++ usb_unlock_device(childdev); ++ if (ret_dev) ++ goto exit; ++ } ++ } ++exit: ++ return ret_dev; ++} ++ ++/** ++ * usb_find_device_by_name - find a specific usb device in the system ++ * @name: the name of the device to find ++ * ++ * Returns a pointer to a struct usb_device if such a specified usb ++ * device is present in the system currently. The usage count of the ++ * device will be incremented if a device is found. Make sure to call ++ * usb_put_dev() when the caller is finished with the device. ++ * ++ * If a device with the specified bus id is not found, NULL is returned. ++ */ ++struct usb_device *usb_find_device_by_name(const char *name) ++{ ++ struct list_head *buslist; ++ struct usb_bus *bus; ++ struct usb_device *dev = NULL; ++ ++ mutex_lock(&usb_bus_list_lock); ++ for (buslist = usb_bus_list.next; ++ buslist != &usb_bus_list; ++ buslist = buslist->next) { ++ bus = container_of(buslist, struct usb_bus, bus_list); ++ if (!bus->root_hub) ++ continue; ++ usb_lock_device(bus->root_hub); ++ dev = match_device_name(bus->root_hub, name); ++ usb_unlock_device(bus->root_hub); ++ if (dev) ++ goto exit; ++ } ++exit: ++ mutex_unlock(&usb_bus_list_lock); ++ return dev; ++} ++EXPORT_SYMBOL_GPL(usb_find_device_by_name); ++ + /** + * usb_alloc_coherent - allocate dma-consistent buffer for URB_NO_xxx_DMA_MAP + * @dev: device the buffer will be used with +--- a/include/linux/usb.h ++++ b/include/linux/usb.h +@@ -721,6 +721,7 @@ static inline bool usb_device_no_sg_cons + return udev && udev->bus && udev->bus->no_sg_constraint; + } + ++extern struct usb_device *usb_find_device_by_name(const char *name); + + /*-------------------------------------------------------------------------*/ + diff --git a/target/linux/generic/patches-3.18/821-usb-dwc2-dualrole.patch b/target/linux/generic/patches-3.18/821-usb-dwc2-dualrole.patch new file mode 100644 index 0000000..9e841cb --- /dev/null +++ b/target/linux/generic/patches-3.18/821-usb-dwc2-dualrole.patch @@ -0,0 +1,146 @@ +--- a/drivers/usb/dwc2/Kconfig ++++ b/drivers/usb/dwc2/Kconfig +@@ -1,6 +1,6 @@ + config USB_DWC2 +- bool "DesignWare USB2 DRD Core Support" +- depends on USB ++ tristate "DesignWare USB2 DRD Core Support" ++ depends on USB || USB_GADGET + help + Say Y here if your system has a Dual Role Hi-Speed USB + controller based on the DesignWare HSOTG IP Core. +@@ -10,49 +10,61 @@ config USB_DWC2 + bus interface module (if you have a PCI bus system) will be + called dwc2_pci.ko, and the platform interface module (for + controllers directly connected to the CPU) will be called +- dwc2_platform.ko. For gadget mode, there will be a single +- module called dwc2_gadget.ko. +- +- NOTE: The s3c-hsotg driver is now renamed to dwc2_gadget. The +- host and gadget drivers are still currently separate drivers. +- There are plans to merge the dwc2_gadget driver with the dwc2 +- host driver in the near future to create a dual-role driver. ++ dwc2_platform.ko. For all modes(host, gadget and dual-role), there ++ will be an additional module named dwc2.ko. + + if USB_DWC2 + ++choice ++ bool "DWC2 Mode Selection" ++ default USB_DWC2_DUAL_ROLE if (USB && USB_GADGET) ++ default USB_DWC2_HOST if (USB && !USB_GADGET) ++ default USB_DWC2_PERIPHERAL if (!USB && USB_GADGET) ++ + config USB_DWC2_HOST +- tristate "Host only mode" ++ bool "Host only mode" + depends on USB + help + The Designware USB2.0 high-speed host controller +- integrated into many SoCs. ++ integrated into many SoCs. Select this option if you want the ++ driver to operate in Host-only mode. + +-config USB_DWC2_PLATFORM +- bool "DWC2 Platform" +- depends on USB_DWC2_HOST +- default USB_DWC2_HOST ++comment "Gadget/Dual-role mode requires USB Gadget support to be enabled" ++ ++config USB_DWC2_PERIPHERAL ++ bool "Gadget only mode" ++ depends on USB_GADGET=y || USB_GADGET=USB_DWC2 ++ help ++ The Designware USB2.0 high-speed gadget controller ++ integrated into many SoCs. Select this option if you want the ++ driver to operate in Peripheral-only mode. This option requires ++ USB_GADGET to be enabled. ++ ++config USB_DWC2_DUAL_ROLE ++ bool "Dual Role mode" ++ depends on (USB=y || USB=USB_DWC2) && (USB_GADGET=y || USB_GADGET=USB_DWC2) + help +- The Designware USB2.0 platform interface module for +- controllers directly connected to the CPU. This is only +- used for host mode. ++ Select this option if you want the driver to work in a dual-role ++ mode. In this mode both host and gadget features are enabled, and ++ the role will be determined by the cable that gets plugged-in. This ++ option requires USB_GADGET to be enabled. ++endchoice ++ ++config USB_DWC2_PLATFORM ++ tristate "DWC2 Platform" ++ default USB_DWC2_HOST || USB_DWC2_PERIPHERAL ++ help ++ The Designware USB2.0 platform interface module for ++ controllers directly connected to the CPU. + + config USB_DWC2_PCI +- bool "DWC2 PCI" ++ tristate "DWC2 PCI" + depends on USB_DWC2_HOST && PCI + default USB_DWC2_HOST + help + The Designware USB2.0 PCI interface module for controllers + connected to a PCI bus. This is only used for host mode. + +-comment "Gadget mode requires USB Gadget support to be enabled" +- +-config USB_DWC2_PERIPHERAL +- tristate "Gadget only mode" +- depends on USB_GADGET +- help +- The Designware USB2.0 high-speed gadget controller +- integrated into many SoCs. +- + config USB_DWC2_DEBUG + bool "Enable Debugging Messages" + help +--- a/drivers/usb/dwc2/Makefile ++++ b/drivers/usb/dwc2/Makefile +@@ -1,28 +1,28 @@ + ccflags-$(CONFIG_USB_DWC2_DEBUG) += -DDEBUG + ccflags-$(CONFIG_USB_DWC2_VERBOSE) += -DVERBOSE_DEBUG + +-obj-$(CONFIG_USB_DWC2_HOST) += dwc2.o ++obj-$(CONFIG_USB_DWC2) += dwc2.o + dwc2-y := core.o core_intr.o +-dwc2-y += hcd.o hcd_intr.o +-dwc2-y += hcd_queue.o hcd_ddma.o ++ ++ifneq ($(filter y,$(CONFIG_USB_DWC2_HOST) $(CONFIG_USB_DWC2_DUAL_ROLE)),) ++ dwc2-y += hcd.o hcd_intr.o ++ dwc2-y += hcd_queue.o hcd_ddma.o ++endif ++ ++ifneq ($(filter y,$(CONFIG_USB_DWC2_PERIPHERAL) $(CONFIG_USB_DWC2_DUAL_ROLE)),) ++ dwc2-y += gadget.o ++endif + + # NOTE: The previous s3c-hsotg peripheral mode only driver has been moved to + # this location and renamed gadget.c. When building for dynamically linked +-# modules, dwc2_gadget.ko will get built for peripheral mode. For host mode, +-# the core module will be dwc2.ko, the PCI bus interface module will called +-# dwc2_pci.ko and the platform interface module will be called dwc2_platform.ko. +-# At present the host and gadget driver will be separate drivers, but there +-# are plans in the near future to create a dual-role driver. ++# modules, dwc2.ko will get built for host mode, peripheral mode, and dual-role ++# mode. The PCI bus interface module will called dwc2_pci.ko and the platform ++# interface module will be called dwc2_platform.ko. + + ifneq ($(CONFIG_USB_DWC2_PCI),) +- obj-$(CONFIG_USB_DWC2_HOST) += dwc2_pci.o ++ obj-$(CONFIG_USB_DWC2) += dwc2_pci.o + dwc2_pci-y := pci.o + endif + +-ifneq ($(CONFIG_USB_DWC2_PLATFORM),) +- obj-$(CONFIG_USB_DWC2_HOST) += dwc2_platform.o +- dwc2_platform-y := platform.o +-endif +- +-obj-$(CONFIG_USB_DWC2_PERIPHERAL) += dwc2_gadget.o +-dwc2_gadget-y := gadget.o ++obj-$(CONFIG_USB_DWC2_PLATFORM) += dwc2_platform.o ++dwc2_platform-y := platform.o diff --git a/target/linux/generic/patches-3.18/830-ledtrig_morse.patch b/target/linux/generic/patches-3.18/830-ledtrig_morse.patch new file mode 100644 index 0000000..a41facc --- /dev/null +++ b/target/linux/generic/patches-3.18/830-ledtrig_morse.patch @@ -0,0 +1,28 @@ +--- a/drivers/leds/trigger/Kconfig ++++ b/drivers/leds/trigger/Kconfig +@@ -108,4 +108,8 @@ config LEDS_TRIGGER_CAMERA + This enables direct flash/torch on/off by the driver, kernel space. + If unsure, say Y. + ++config LEDS_TRIGGER_MORSE ++ tristate "LED Morse Trigger" ++ depends on LEDS_TRIGGERS ++ + endif # LEDS_TRIGGERS +--- a/drivers/leds/Makefile ++++ b/drivers/leds/Makefile +@@ -62,3 +62,4 @@ obj-$(CONFIG_LEDS_DAC124S085) += leds-d + + # LED Triggers + obj-$(CONFIG_LEDS_TRIGGERS) += trigger/ ++obj-$(CONFIG_LEDS_TRIGGER_MORSE) += ledtrig-morse.o +--- a/drivers/leds/ledtrig-morse.c ++++ b/drivers/leds/ledtrig-morse.c +@@ -26,7 +26,6 @@ + #include + #include + #include +-#include + #include + #include + #include diff --git a/target/linux/generic/patches-3.18/831-ledtrig_netdev.patch b/target/linux/generic/patches-3.18/831-ledtrig_netdev.patch new file mode 100644 index 0000000..3f39fb6 --- /dev/null +++ b/target/linux/generic/patches-3.18/831-ledtrig_netdev.patch @@ -0,0 +1,60 @@ +--- a/drivers/leds/trigger/Kconfig ++++ b/drivers/leds/trigger/Kconfig +@@ -112,4 +112,11 @@ config LEDS_TRIGGER_MORSE + tristate "LED Morse Trigger" + depends on LEDS_TRIGGERS + ++config LEDS_TRIGGER_NETDEV ++ tristate "LED Netdev Trigger" ++ depends on NET && LEDS_TRIGGERS ++ help ++ This allows LEDs to be controlled by network device activity. ++ If unsure, say Y. ++ + endif # LEDS_TRIGGERS +--- a/drivers/leds/Makefile ++++ b/drivers/leds/Makefile +@@ -63,3 +63,4 @@ obj-$(CONFIG_LEDS_DAC124S085) += leds-d + # LED Triggers + obj-$(CONFIG_LEDS_TRIGGERS) += trigger/ + obj-$(CONFIG_LEDS_TRIGGER_MORSE) += ledtrig-morse.o ++obj-$(CONFIG_LEDS_TRIGGER_NETDEV) += ledtrig-netdev.o +--- a/drivers/leds/ledtrig-netdev.c ++++ b/drivers/leds/ledtrig-netdev.c +@@ -22,7 +22,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -254,7 +253,7 @@ static int netdev_trig_notify(struct not + unsigned long evt, + void *dv) + { +- struct net_device *dev = dv; ++ struct net_device *dev = netdev_notifier_info_to_dev((struct netdev_notifier_info *) dv); + struct led_netdev_data *trigger_data = container_of(nb, struct led_netdev_data, notifier); + + if (evt != NETDEV_UP && evt != NETDEV_DOWN && evt != NETDEV_CHANGE && evt != NETDEV_REGISTER && evt != NETDEV_UNREGISTER) +@@ -294,8 +293,9 @@ done: + static void netdev_trig_timer(unsigned long arg) + { + struct led_netdev_data *trigger_data = (struct led_netdev_data *)arg; +- const struct net_device_stats *dev_stats; ++ struct rtnl_link_stats64 *dev_stats; + unsigned new_activity; ++ struct rtnl_link_stats64 temp; + + write_lock(&trigger_data->lock); + +@@ -305,7 +305,7 @@ static void netdev_trig_timer(unsigned l + goto no_restart; + } + +- dev_stats = dev_get_stats(trigger_data->net_dev); ++ dev_stats = dev_get_stats(trigger_data->net_dev, &temp); + new_activity = + ((trigger_data->mode & MODE_TX) ? dev_stats->tx_packets : 0) + + ((trigger_data->mode & MODE_RX) ? dev_stats->rx_packets : 0); diff --git a/target/linux/generic/patches-3.18/832-ledtrig_usbdev.patch b/target/linux/generic/patches-3.18/832-ledtrig_usbdev.patch new file mode 100644 index 0000000..d8c9492 --- /dev/null +++ b/target/linux/generic/patches-3.18/832-ledtrig_usbdev.patch @@ -0,0 +1,31 @@ +--- a/drivers/leds/trigger/Kconfig ++++ b/drivers/leds/trigger/Kconfig +@@ -119,4 +119,11 @@ config LEDS_TRIGGER_NETDEV + This allows LEDs to be controlled by network device activity. + If unsure, say Y. + ++config LEDS_TRIGGER_USBDEV ++ tristate "LED USB device Trigger" ++ depends on USB && LEDS_TRIGGERS ++ help ++ This allows LEDs to be controlled by the presence/activity of ++ an USB device. If unsure, say N. ++ + endif # LEDS_TRIGGERS +--- a/drivers/leds/Makefile ++++ b/drivers/leds/Makefile +@@ -64,3 +64,4 @@ obj-$(CONFIG_LEDS_DAC124S085) += leds-d + obj-$(CONFIG_LEDS_TRIGGERS) += trigger/ + obj-$(CONFIG_LEDS_TRIGGER_MORSE) += ledtrig-morse.o + obj-$(CONFIG_LEDS_TRIGGER_NETDEV) += ledtrig-netdev.o ++obj-$(CONFIG_LEDS_TRIGGER_USBDEV) += ledtrig-usbdev.o +--- a/drivers/leds/ledtrig-usbdev.c ++++ b/drivers/leds/ledtrig-usbdev.c +@@ -24,7 +24,6 @@ + #include + #include + #include +-#include + #include + #include + #include diff --git a/target/linux/generic/patches-3.18/834-ledtrig-libata.patch b/target/linux/generic/patches-3.18/834-ledtrig-libata.patch new file mode 100644 index 0000000..4c0ffca --- /dev/null +++ b/target/linux/generic/patches-3.18/834-ledtrig-libata.patch @@ -0,0 +1,153 @@ +From 52cfd51cdf6a6e14d4fb270c6343abac3bac00f4 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Fri, 12 Dec 2014 13:38:33 +0100 +Subject: [PATCH] libata: add ledtrig support +To: linux-ide@vger.kernel.org, + Tejun Heo + +This adds a LED trigger for each ATA port indicating disk activity. + +As this is needed only on specific platforms (NAS SoCs and such), +these platforms should define ARCH_WANTS_LIBATA_LEDS if there +are boards with LED(s) intended to indicate ATA disk activity and +need the OS to take care of that. +In that way, if not selected, LED trigger support not will be +included in libata-core and both, codepaths and structures remain +untouched. + +Signed-off-by: Daniel Golle +--- + drivers/ata/Kconfig | 16 ++++++++++++++++ + drivers/ata/libata-core.c | 41 +++++++++++++++++++++++++++++++++++++++++ + include/linux/libata.h | 9 +++++++++ + 3 files changed, 66 insertions(+) + +--- a/drivers/ata/Kconfig ++++ b/drivers/ata/Kconfig +@@ -46,6 +46,22 @@ config ATA_VERBOSE_ERROR + + If unsure, say Y. + ++config ARCH_WANT_LIBATA_LEDS ++ bool ++ ++config ATA_LEDS ++ bool "support ATA port LED triggers" ++ depends on ARCH_WANT_LIBATA_LEDS ++ select NEW_LEDS ++ select LEDS_CLASS ++ select LEDS_TRIGGERS ++ default y ++ help ++ This option adds a LED trigger for each registered ATA port. ++ It is used to drive disk activity leds connected via GPIO. ++ ++ If unsure, say N. ++ + config ATA_ACPI + bool "ATA ACPI Support" + depends on ACPI && PCI +--- a/drivers/ata/libata-core.c ++++ b/drivers/ata/libata-core.c +@@ -725,6 +725,19 @@ u64 ata_tf_read_block(struct ata_taskfil + return block; + } + ++#ifdef CONFIG_ATA_LEDS ++#define LIBATA_BLINK_DELAY 20 /* ms */ ++static inline void ata_led_act(struct ata_port *ap) ++{ ++ unsigned long led_delay = LIBATA_BLINK_DELAY; ++ ++ if (unlikely(!ap->ledtrig)) ++ return; ++ ++ led_trigger_blink_oneshot(ap->ledtrig, &led_delay, &led_delay, 0); ++} ++#endif ++ + /** + * ata_build_rw_tf - Build ATA taskfile for given read/write request + * @tf: Target ATA taskfile +@@ -4798,6 +4811,9 @@ static struct ata_queued_cmd *ata_qc_new + break; + } + } ++#ifdef CONFIG_ATA_LEDS ++ ata_led_act(ap); ++#endif + + return qc; + } +@@ -5708,6 +5724,9 @@ struct ata_port *ata_port_alloc(struct a + ap->stats.unhandled_irq = 1; + ap->stats.idle_irq = 1; + #endif ++#ifdef CONFIG_ATA_LEDS ++ ap->ledtrig = kzalloc(sizeof(struct led_trigger), GFP_KERNEL); ++#endif + ata_sff_port_init(ap); + + return ap; +@@ -5729,6 +5748,12 @@ static void ata_host_release(struct devi + + kfree(ap->pmp_link); + kfree(ap->slave_link); ++#ifdef CONFIG_ATA_LEDS ++ if (ap->ledtrig) { ++ led_trigger_unregister(ap->ledtrig); ++ kfree(ap->ledtrig); ++ }; ++#endif + kfree(ap); + host->ports[i] = NULL; + } +@@ -6175,7 +6200,23 @@ int ata_host_register(struct ata_host *h + host->ports[i]->print_id = atomic_inc_return(&ata_print_id); + host->ports[i]->local_port_no = i + 1; + } ++#ifdef CONFIG_ATA_LEDS ++ for (i = 0; i < host->n_ports; i++) { ++ if (unlikely(!host->ports[i]->ledtrig)) ++ continue; + ++ snprintf(host->ports[i]->ledtrig_name, ++ sizeof(host->ports[i]->ledtrig_name), "ata%u", ++ host->ports[i]->print_id); ++ ++ host->ports[i]->ledtrig->name = host->ports[i]->ledtrig_name; ++ ++ if (led_trigger_register(host->ports[i]->ledtrig)) { ++ kfree(host->ports[i]->ledtrig); ++ host->ports[i]->ledtrig = NULL; ++ } ++ } ++#endif + /* Create associated sysfs transport objects */ + for (i = 0; i < host->n_ports; i++) { + rc = ata_tport_add(host->dev,host->ports[i]); +--- a/include/linux/libata.h ++++ b/include/linux/libata.h +@@ -38,6 +38,9 @@ + #include + #include + #include ++#ifdef CONFIG_ATA_LEDS ++#include ++#endif + + /* + * Define if arch has non-standard setup. This is a _PCI_ standard +@@ -874,6 +877,12 @@ struct ata_port { + #ifdef CONFIG_ATA_ACPI + struct ata_acpi_gtm __acpi_init_gtm; /* use ata_acpi_init_gtm() */ + #endif ++ ++#ifdef CONFIG_ATA_LEDS ++ struct led_trigger *ledtrig; ++ char ledtrig_name[8]; ++#endif ++ + /* owned by EH */ + u8 sector_buf[ATA_SECT_SIZE] ____cacheline_aligned; + }; diff --git a/target/linux/generic/patches-3.18/840-rtc7301.patch b/target/linux/generic/patches-3.18/840-rtc7301.patch new file mode 100644 index 0000000..2134d87 --- /dev/null +++ b/target/linux/generic/patches-3.18/840-rtc7301.patch @@ -0,0 +1,250 @@ +--- a/drivers/rtc/Kconfig ++++ b/drivers/rtc/Kconfig +@@ -979,6 +979,15 @@ config RTC_DRV_NUC900 + If you say yes here you get support for the RTC subsystem of the + NUC910/NUC920 used in embedded systems. + ++config RTC_DRV_RTC7301 ++ tristate "Epson RTC-7301 SF/DG" ++ help ++ If you say Y here you will get support for the ++ Epson RTC-7301 SF/DG RTC chips. ++ ++ This driver can also be built as a module. If so, the module ++ will be called rtc-7301. ++ + comment "on-CPU RTC drivers" + + config RTC_DRV_DAVINCI +--- a/drivers/rtc/Makefile ++++ b/drivers/rtc/Makefile +@@ -115,6 +115,7 @@ obj-$(CONFIG_RTC_DRV_RP5C01) += rtc-rp5c + obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o + obj-$(CONFIG_RTC_DRV_RS5C348) += rtc-rs5c348.o + obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o ++obj-$(CONFIG_RTC_DRV_RTC7301) += rtc-rtc7301.o + obj-$(CONFIG_RTC_DRV_RV3029C2) += rtc-rv3029c2.o + obj-$(CONFIG_RTC_DRV_RX4581) += rtc-rx4581.o + obj-$(CONFIG_RTC_DRV_RX8025) += rtc-rx8025.o +--- /dev/null ++++ b/drivers/rtc/rtc-rtc7301.c +@@ -0,0 +1,219 @@ ++/* ++ * Driver for Epson RTC-7301SF/DG ++ * ++ * Copyright (C) 2009 Jose Vasconcellos ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define RTC_NAME "rtc7301" ++#define RTC_VERSION "0.1" ++ ++/* Epson RTC-7301 register addresses */ ++#define RTC7301_SEC 0x00 ++#define RTC7301_SEC10 0x01 ++#define RTC7301_MIN 0x02 ++#define RTC7301_MIN10 0x03 ++#define RTC7301_HOUR 0x04 ++#define RTC7301_HOUR10 0x05 ++#define RTC7301_WEEKDAY 0x06 ++#define RTC7301_DAY 0x07 ++#define RTC7301_DAY10 0x08 ++#define RTC7301_MON 0x09 ++#define RTC7301_MON10 0x0A ++#define RTC7301_YEAR 0x0B ++#define RTC7301_YEAR10 0x0C ++#define RTC7301_YEAR100 0x0D ++#define RTC7301_YEAR1000 0x0E ++#define RTC7301_CTRLREG 0x0F ++ ++static uint8_t __iomem *rtc7301_base; ++ ++#define read_reg(offset) (readb(rtc7301_base + offset) & 0xf) ++#define write_reg(offset, data) writeb(data, rtc7301_base + (offset)) ++ ++#define rtc7301_isbusy() (read_reg(RTC7301_CTRLREG) & 1) ++ ++static void rtc7301_init_settings(void) ++{ ++ int i; ++ ++ write_reg(RTC7301_CTRLREG, 2); ++ write_reg(RTC7301_YEAR1000, 2); ++ udelay(122); ++ ++ /* bank 1 */ ++ write_reg(RTC7301_CTRLREG, 6); ++ for (i=0; i<15; i++) ++ write_reg(i, 0); ++ ++ /* bank 2 */ ++ write_reg(RTC7301_CTRLREG, 14); ++ for (i=0; i<15; i++) ++ write_reg(i, 0); ++ write_reg(RTC7301_CTRLREG, 0); ++} ++ ++static int rtc7301_get_datetime(struct device *dev, struct rtc_time *dt) ++{ ++ int cnt; ++ uint8_t buf[16]; ++ ++ cnt = 0; ++ while (rtc7301_isbusy()) { ++ udelay(244); ++ if (cnt++ > 100) { ++ dev_err(dev, "%s: timeout error %x\n", __func__, rtc7301_base[RTC7301_CTRLREG]); ++ return -EIO; ++ } ++ } ++ ++ for (cnt=0; cnt<16; cnt++) ++ buf[cnt] = read_reg(cnt); ++ ++ if (buf[RTC7301_SEC10] & 8) { ++ dev_err(dev, "%s: RTC not set\n", __func__); ++ return -EINVAL; ++ } ++ ++ memset(dt, 0, sizeof(*dt)); ++ ++ dt->tm_sec = buf[RTC7301_SEC] + buf[RTC7301_SEC10]*10; ++ dt->tm_min = buf[RTC7301_MIN] + buf[RTC7301_MIN10]*10; ++ dt->tm_hour = buf[RTC7301_HOUR] + buf[RTC7301_HOUR10]*10; ++ ++ dt->tm_mday = buf[RTC7301_DAY] + buf[RTC7301_DAY10]*10; ++ dt->tm_mon = buf[RTC7301_MON] + buf[RTC7301_MON10]*10 - 1; ++ dt->tm_year = buf[RTC7301_YEAR] + buf[RTC7301_YEAR10]*10 + ++ buf[RTC7301_YEAR100]*100 + ++ ((buf[RTC7301_YEAR1000] & 3)*1000) - 1900; ++ ++ /* the rtc device may contain illegal values on power up ++ * according to the data sheet. make sure they are valid. ++ */ ++ ++ return rtc_valid_tm(dt); ++} ++ ++static int rtc7301_set_datetime(struct device *dev, struct rtc_time *dt) ++{ ++ int data; ++ ++ data = dt->tm_year + 1900; ++ if (data >= 2100 || data < 1900) ++ return -EINVAL; ++ ++ write_reg(RTC7301_CTRLREG, 2); ++ udelay(122); ++ ++ data = bin2bcd(dt->tm_sec); ++ write_reg(RTC7301_SEC, data); ++ write_reg(RTC7301_SEC10, (data >> 4)); ++ ++ data = bin2bcd(dt->tm_min); ++ write_reg(RTC7301_MIN, data ); ++ write_reg(RTC7301_MIN10, (data >> 4)); ++ ++ data = bin2bcd(dt->tm_hour); ++ write_reg(RTC7301_HOUR, data); ++ write_reg(RTC7301_HOUR10, (data >> 4)); ++ ++ data = bin2bcd(dt->tm_mday); ++ write_reg(RTC7301_DAY, data); ++ write_reg(RTC7301_DAY10, (data>> 4)); ++ ++ data = bin2bcd(dt->tm_mon + 1); ++ write_reg(RTC7301_MON, data); ++ write_reg(RTC7301_MON10, (data >> 4)); ++ ++ data = bin2bcd(dt->tm_year % 100); ++ write_reg(RTC7301_YEAR, data); ++ write_reg(RTC7301_YEAR10, (data >> 4)); ++ data = bin2bcd((1900 + dt->tm_year) / 100); ++ write_reg(RTC7301_YEAR100, data); ++ ++ data = bin2bcd(dt->tm_wday); ++ write_reg(RTC7301_WEEKDAY, data); ++ ++ write_reg(RTC7301_CTRLREG, 0); ++ ++ return 0; ++} ++ ++static const struct rtc_class_ops rtc7301_rtc_ops = { ++ .read_time = rtc7301_get_datetime, ++ .set_time = rtc7301_set_datetime, ++}; ++ ++static int rtc7301_probe(struct platform_device *pdev) ++{ ++ struct rtc_device *rtc; ++ struct resource *res; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) ++ return -ENOENT; ++ ++ rtc7301_base = ioremap_nocache(res->start, 0x1000 /*res->end - res->start + 1*/); ++ if (!rtc7301_base) ++ return -EINVAL; ++ ++ rtc = rtc_device_register(RTC_NAME, &pdev->dev, ++ &rtc7301_rtc_ops, THIS_MODULE); ++ if (IS_ERR(rtc)) { ++ iounmap(rtc7301_base); ++ return PTR_ERR(rtc); ++ } ++ ++ platform_set_drvdata(pdev, rtc); ++ ++ rtc7301_init_settings(); ++ return 0; ++} ++ ++static int rtc7301_remove(struct platform_device *pdev) ++{ ++ struct rtc_device *rtc = platform_get_drvdata(pdev); ++ ++ if (rtc) ++ rtc_device_unregister(rtc); ++ if (rtc7301_base) ++ iounmap(rtc7301_base); ++ return 0; ++} ++ ++static struct platform_driver rtc7301_driver = { ++ .driver = { ++ .name = RTC_NAME, ++ .owner = THIS_MODULE, ++ }, ++ .probe = rtc7301_probe, ++ .remove = rtc7301_remove, ++}; ++ ++static __init int rtc7301_init(void) ++{ ++ return platform_driver_register(&rtc7301_driver); ++} ++module_init(rtc7301_init); ++ ++static __exit void rtc7301_exit(void) ++{ ++ platform_driver_unregister(&rtc7301_driver); ++} ++module_exit(rtc7301_exit); ++ ++MODULE_DESCRIPTION("Epson 7301 RTC driver"); ++MODULE_AUTHOR("Jose Vasconcellos "); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:" RTC_NAME); ++MODULE_VERSION(RTC_VERSION); diff --git a/target/linux/generic/patches-3.18/841-rtc_pt7c4338.patch b/target/linux/generic/patches-3.18/841-rtc_pt7c4338.patch new file mode 100644 index 0000000..83b0232 --- /dev/null +++ b/target/linux/generic/patches-3.18/841-rtc_pt7c4338.patch @@ -0,0 +1,247 @@ +--- a/drivers/rtc/Kconfig ++++ b/drivers/rtc/Kconfig +@@ -567,6 +567,15 @@ config RTC_DRV_S5M + This driver can also be built as a module. If so, the module + will be called rtc-s5m. + ++config RTC_DRV_PT7C4338 ++ tristate "Pericom Technology Inc. PT7C4338 RTC" ++ help ++ If you say yes here you get support for the Pericom Technology ++ Inc. PT7C4338 RTC chip. ++ ++ This driver can also be built as a module. If so, the module ++ will be called rtc-pt7c4338. ++ + endif # I2C + + comment "SPI RTC drivers" +--- a/drivers/rtc/Makefile ++++ b/drivers/rtc/Makefile +@@ -106,6 +106,7 @@ obj-$(CONFIG_RTC_DRV_PL030) += rtc-pl030 + obj-$(CONFIG_RTC_DRV_PL031) += rtc-pl031.o + obj-$(CONFIG_RTC_DRV_PM8XXX) += rtc-pm8xxx.o + obj-$(CONFIG_RTC_DRV_PS3) += rtc-ps3.o ++obj-$(CONFIG_RTC_DRV_PT7C4338) += rtc-pt7c4338.o + obj-$(CONFIG_RTC_DRV_PUV3) += rtc-puv3.o + obj-$(CONFIG_RTC_DRV_PXA) += rtc-pxa.o + obj-$(CONFIG_RTC_DRV_R9701) += rtc-r9701.o +--- /dev/null ++++ b/drivers/rtc/rtc-pt7c4338.c +@@ -0,0 +1,216 @@ ++/* ++ * Copyright 2010 Freescale Semiconductor, Inc. ++ * ++ * Author: Priyanka Jain ++ * ++ * 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 Date & Time support (no alarms) for PT7C4338 chip. ++ * ++ * This file is based on drivers/rtc/rtc-ds1307.c ++ * ++ * PT7C4338 chip is manufactured by Pericom Technology Inc. ++ * It is a serial real-time clock which provides ++ * 1)Low-power clock/calendar. ++ * 2)Programmable square-wave output. ++ * It has 56 bytes of nonvolatile RAM. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* RTC register addresses */ ++#define PT7C4338_REG_SECONDS 0x00 ++#define PT7C4338_REG_MINUTES 0x01 ++#define PT7C4338_REG_HOURS 0x02 ++#define PT7C4338_REG_AMPM 0x02 ++#define PT7C4338_REG_DAY 0x03 ++#define PT7C4338_REG_DATE 0x04 ++#define PT7C4338_REG_MONTH 0x05 ++#define PT7C4338_REG_YEAR 0x06 ++#define PT7C4338_REG_CTRL_STAT 0x07 ++ ++/* RTC second register address bit */ ++#define PT7C4338_SEC_BIT_CH 0x80 /*Clock Halt (in Register 0)*/ ++ ++/* RTC control and status register bits */ ++#define PT7C4338_CTRL_STAT_BIT_RS0 0x1 /*Rate select 0*/ ++#define PT7C4338_CTRL_STAT_BIT_RS1 0x2 /*Rate select 1*/ ++#define PT7C4338_CTRL_STAT_BIT_SQWE 0x10 /*Square Wave Enable*/ ++#define PT7C4338_CTRL_STAT_BIT_OSF 0x20 /*Oscillator Stop Flag*/ ++#define PT7C4338_CTRL_STAT_BIT_OUT 0x80 /*Output Level Control*/ ++ ++static const struct i2c_device_id pt7c4338_id[] = { ++ { "pt7c4338", 0 }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, pt7c4338_id); ++ ++struct pt7c4338{ ++ struct i2c_client *client; ++ struct rtc_device *rtc; ++}; ++ ++static int pt7c4338_read_time(struct device *dev, struct rtc_time *time) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ int ret; ++ u8 buf[7]; ++ u8 year, month, day, hour, minute, second; ++ u8 week, twelve_hr, am_pm; ++ ++ ret = i2c_smbus_read_i2c_block_data(client, ++ PT7C4338_REG_SECONDS, 7, buf); ++ if (ret < 0) ++ return ret; ++ if (ret < 7) ++ return -EIO; ++ ++ second = buf[0]; ++ minute = buf[1]; ++ hour = buf[2]; ++ week = buf[3]; ++ day = buf[4]; ++ month = buf[5]; ++ year = buf[6]; ++ ++ /* Extract additional information for AM/PM */ ++ twelve_hr = hour & 0x40; ++ am_pm = hour & 0x20; ++ ++ /* Write to rtc_time structure */ ++ time->tm_sec = bcd2bin(second & 0x7f); ++ time->tm_min = bcd2bin(minute & 0x7f); ++ if (twelve_hr) { ++ /* Convert to 24 hr */ ++ if (am_pm) ++ time->tm_hour = bcd2bin(hour & 0x10) + 12; ++ else ++ time->tm_hour = bcd2bin(hour & 0xBF); ++ } else { ++ time->tm_hour = bcd2bin(hour); ++ } ++ ++ time->tm_wday = bcd2bin(week & 0x07) - 1; ++ time->tm_mday = bcd2bin(day & 0x3f); ++ time->tm_mon = bcd2bin(month & 0x1F) - 1; ++ /* assume 20YY not 19YY */ ++ time->tm_year = bcd2bin(year) + 100; ++ ++ return 0; ++} ++ ++static int pt7c4338_set_time(struct device *dev, struct rtc_time *time) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ u8 buf[7]; ++ ++ /* Extract time from rtc_time and load into pt7c4338*/ ++ buf[0] = bin2bcd(time->tm_sec); ++ buf[1] = bin2bcd(time->tm_min); ++ buf[2] = bin2bcd(time->tm_hour); ++ buf[3] = bin2bcd(time->tm_wday + 1); /* Day of the week */ ++ buf[4] = bin2bcd(time->tm_mday); /* Date */ ++ buf[5] = bin2bcd(time->tm_mon + 1); ++ ++ /* assume 20YY not 19YY */ ++ if (time->tm_year >= 100) ++ buf[6] = bin2bcd(time->tm_year - 100); ++ else ++ buf[6] = bin2bcd(time->tm_year); ++ ++ return i2c_smbus_write_i2c_block_data(client, ++ PT7C4338_REG_SECONDS, 7, buf); ++} ++ ++static const struct rtc_class_ops pt7c4338_rtc_ops = { ++ .read_time = pt7c4338_read_time, ++ .set_time = pt7c4338_set_time, ++}; ++ ++static int pt7c4338_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct pt7c4338 *pt7c4338; ++ struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); ++ int ret; ++ ++ pt7c4338 = kzalloc(sizeof(struct pt7c4338), GFP_KERNEL); ++ if (!pt7c4338) ++ return -ENOMEM; ++ ++ pt7c4338->client = client; ++ i2c_set_clientdata(client, pt7c4338); ++ pt7c4338->rtc = rtc_device_register(client->name, &client->dev, ++ &pt7c4338_rtc_ops, THIS_MODULE); ++ if (IS_ERR(pt7c4338->rtc)) { ++ ret = PTR_ERR(pt7c4338->rtc); ++ dev_err(&client->dev, "unable to register the class device\n"); ++ goto out_free; ++ } ++ ++ return 0; ++out_free: ++ i2c_set_clientdata(client, NULL); ++ kfree(pt7c4338); ++ return ret; ++} ++ ++static int pt7c4338_remove(struct i2c_client *client) ++{ ++ struct pt7c4338 *pt7c4338 = i2c_get_clientdata(client); ++ ++ rtc_device_unregister(pt7c4338->rtc); ++ i2c_set_clientdata(client, NULL); ++ kfree(pt7c4338); ++ return 0; ++} ++ ++static struct i2c_driver pt7c4338_driver = { ++ .driver = { ++ .name = "rtc-pt7c4338", ++ .owner = THIS_MODULE, ++ }, ++ .probe = pt7c4338_probe, ++ .remove = pt7c4338_remove, ++ .id_table = pt7c4338_id, ++}; ++ ++static int __init pt7c4338_init(void) ++{ ++ return i2c_add_driver(&pt7c4338_driver); ++} ++ ++static void __exit pt7c4338_exit(void) ++{ ++ i2c_del_driver(&pt7c4338_driver); ++} ++ ++module_init(pt7c4338_init); ++module_exit(pt7c4338_exit); ++ ++MODULE_AUTHOR("Priyanka Jain "); ++MODULE_DESCRIPTION("pericom Technology Inc. PT7C4338 RTC Driver"); ++MODULE_LICENSE("GPL"); diff --git a/target/linux/generic/patches-3.18/861-04_spi_gpio_implement_spi_delay.patch b/target/linux/generic/patches-3.18/861-04_spi_gpio_implement_spi_delay.patch new file mode 100644 index 0000000..e7b32a5 --- /dev/null +++ b/target/linux/generic/patches-3.18/861-04_spi_gpio_implement_spi_delay.patch @@ -0,0 +1,58 @@ +Implement the SPI-GPIO delay function for busses that need speed limitation. + +--mb + + + +--- a/drivers/spi/spi-gpio.c ++++ b/drivers/spi/spi-gpio.c +@@ -21,6 +21,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -73,6 +74,7 @@ struct spi_gpio { + * #define SPI_MOSI_GPIO 120 + * #define SPI_SCK_GPIO 121 + * #define SPI_N_CHIPSEL 4 ++ * #undef NEED_SPIDELAY + * #include "spi-gpio.c" + */ + +@@ -80,6 +82,7 @@ struct spi_gpio { + #define DRIVER_NAME "spi_gpio" + + #define GENERIC_BITBANG /* vs tight inlines */ ++#define NEED_SPIDELAY 1 + + /* all functions referencing these symbols must define pdata */ + #define SPI_MISO_GPIO ((pdata)->miso) +@@ -130,12 +133,20 @@ static inline int getmiso(const struct s + #undef pdata + + /* +- * NOTE: this clocks "as fast as we can". It "should" be a function of the +- * requested device clock. Software overhead means we usually have trouble +- * reaching even one Mbit/sec (except when we can inline bitops), so for now +- * we'll just assume we never need additional per-bit slowdowns. ++ * NOTE: to clock "as fast as we can", set spi_device.max_speed_hz ++ * and spi_transfer.speed_hz to 0. ++ * Otherwise this is a function of the requested device clock. ++ * Software overhead means we usually have trouble ++ * reaching even one Mbit/sec (except when we can inline bitops). So on small ++ * embedded devices with fast SPI slaves you usually don't need a delay. + */ +-#define spidelay(nsecs) do {} while (0) ++static inline void spidelay(unsigned nsecs) ++{ ++#ifdef NEED_SPIDELAY ++ if (unlikely(nsecs)) ++ ndelay(nsecs); ++#endif /* NEED_SPIDELAY */ ++} + + #include "spi-bitbang-txrx.h" + diff --git a/target/linux/generic/patches-3.18/862-gpio_spi_driver.patch b/target/linux/generic/patches-3.18/862-gpio_spi_driver.patch new file mode 100644 index 0000000..70bf11f --- /dev/null +++ b/target/linux/generic/patches-3.18/862-gpio_spi_driver.patch @@ -0,0 +1,373 @@ +THIS CODE IS DEPRECATED. + +Please use the new mainline SPI-GPIO driver, as of 2.6.29. + +--mb + + + +--- + drivers/spi/Kconfig | 9 + + drivers/spi/Makefile | 1 + drivers/spi/spi_gpio_old.c | 251 +++++++++++++++++++++++++++++++++++++++ + include/linux/spi/spi_gpio_old.h | 73 +++++++++++ + 4 files changed, 334 insertions(+) + +--- /dev/null ++++ b/include/linux/spi/spi_gpio_old.h +@@ -0,0 +1,73 @@ ++/* ++ * spi_gpio interface to platform code ++ * ++ * Copyright (c) 2008 Piotr Skamruk ++ * Copyright (c) 2008 Michael Buesch ++ * ++ * 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. ++ */ ++#ifndef _LINUX_SPI_SPI_GPIO ++#define _LINUX_SPI_SPI_GPIO ++ ++#include ++#include ++ ++ ++/** ++ * struct spi_gpio_platform_data - Data definitions for a SPI-GPIO device. ++ * ++ * This structure holds information about a GPIO-based SPI device. ++ * ++ * @pin_clk: The GPIO pin number of the CLOCK pin. ++ * ++ * @pin_miso: The GPIO pin number of the MISO pin. ++ * ++ * @pin_mosi: The GPIO pin number of the MOSI pin. ++ * ++ * @pin_cs: The GPIO pin number of the CHIPSELECT pin. ++ * ++ * @cs_activelow: If true, the chip is selected when the CS line is low. ++ * ++ * @no_spi_delay: If true, no delay is done in the lowlevel bitbanging. ++ * Note that doing no delay is not standards compliant, ++ * but it might be needed to speed up transfers on some ++ * slow embedded machines. ++ * ++ * @boardinfo_setup: This callback is called after the ++ * SPI master device was registered, but before the ++ * device is registered. ++ * @boardinfo_setup_data: Data argument passed to boardinfo_setup(). ++ */ ++struct spi_gpio_platform_data { ++ unsigned int pin_clk; ++ unsigned int pin_miso; ++ unsigned int pin_mosi; ++ unsigned int pin_cs; ++ bool cs_activelow; ++ bool no_spi_delay; ++ int (*boardinfo_setup)(struct spi_board_info *bi, ++ struct spi_master *master, ++ void *data); ++ void *boardinfo_setup_data; ++}; ++ ++/** ++ * SPI_GPIO_PLATDEV_NAME - The platform device name string. ++ * ++ * The name string that has to be used for platform_device_alloc ++ * when allocating a spi-gpio device. ++ */ ++#define SPI_GPIO_PLATDEV_NAME "spi-gpio" ++ ++/** ++ * spi_gpio_next_id - Get another platform device ID number. ++ * ++ * This returns the next platform device ID number that has to be used ++ * for platform_device_alloc. The ID is opaque and should not be used for ++ * anything else. ++ */ ++int spi_gpio_next_id(void); ++ ++#endif /* _LINUX_SPI_SPI_GPIO */ +--- /dev/null ++++ b/drivers/spi/spi_gpio_old.c +@@ -0,0 +1,251 @@ ++/* ++ * Bitbanging SPI bus driver using GPIO API ++ * ++ * Copyright (c) 2008 Piotr Skamruk ++ * Copyright (c) 2008 Michael Buesch ++ * ++ * based on spi_s3c2410_gpio.c ++ * Copyright (c) 2006 Ben Dooks ++ * Copyright (c) 2006 Simtec Electronics ++ * and on i2c-gpio.c ++ * Copyright (C) 2007 Atmel 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++struct spi_gpio { ++ struct spi_bitbang bitbang; ++ struct spi_gpio_platform_data *info; ++ struct platform_device *pdev; ++ struct spi_board_info bi; ++}; ++ ++ ++static inline struct spi_gpio *spidev_to_sg(struct spi_device *dev) ++{ ++ return dev->controller_data; ++} ++ ++static inline void setsck(struct spi_device *dev, int val) ++{ ++ struct spi_gpio *sp = spidev_to_sg(dev); ++ gpio_set_value(sp->info->pin_clk, val ? 1 : 0); ++} ++ ++static inline void setmosi(struct spi_device *dev, int val) ++{ ++ struct spi_gpio *sp = spidev_to_sg(dev); ++ gpio_set_value(sp->info->pin_mosi, val ? 1 : 0); ++} ++ ++static inline u32 getmiso(struct spi_device *dev) ++{ ++ struct spi_gpio *sp = spidev_to_sg(dev); ++ return gpio_get_value(sp->info->pin_miso) ? 1 : 0; ++} ++ ++static inline void do_spidelay(struct spi_device *dev, unsigned nsecs) ++{ ++ struct spi_gpio *sp = spidev_to_sg(dev); ++ ++ if (!sp->info->no_spi_delay) ++ ndelay(nsecs); ++} ++ ++#define spidelay(nsecs) do { \ ++ /* Steal the spi_device pointer from our caller. \ ++ * The bitbang-API should probably get fixed here... */ \ ++ do_spidelay(spi, nsecs); \ ++ } while (0) ++ ++#define EXPAND_BITBANG_TXRX ++#include "spi-bitbang-txrx.h" ++ ++static u32 spi_gpio_txrx_mode0(struct spi_device *spi, ++ unsigned nsecs, u32 word, u8 bits) ++{ ++ return bitbang_txrx_be_cpha0(spi, nsecs, 0, 0, word, bits); ++} ++ ++static u32 spi_gpio_txrx_mode1(struct spi_device *spi, ++ unsigned nsecs, u32 word, u8 bits) ++{ ++ return bitbang_txrx_be_cpha1(spi, nsecs, 0, 0, word, bits); ++} ++ ++static u32 spi_gpio_txrx_mode2(struct spi_device *spi, ++ unsigned nsecs, u32 word, u8 bits) ++{ ++ return bitbang_txrx_be_cpha0(spi, nsecs, 1, 0, word, bits); ++} ++ ++static u32 spi_gpio_txrx_mode3(struct spi_device *spi, ++ unsigned nsecs, u32 word, u8 bits) ++{ ++ return bitbang_txrx_be_cpha1(spi, nsecs, 1, 0, word, bits); ++} ++ ++static void spi_gpio_chipselect(struct spi_device *dev, int on) ++{ ++ struct spi_gpio *sp = spidev_to_sg(dev); ++ ++ if (sp->info->cs_activelow) ++ on = !on; ++ gpio_set_value(sp->info->pin_cs, on ? 1 : 0); ++} ++ ++static int spi_gpio_probe(struct platform_device *pdev) ++{ ++ struct spi_master *master; ++ struct spi_gpio_platform_data *pdata; ++ struct spi_gpio *sp; ++ struct spi_device *spidev; ++ int err; ++ ++ pdata = pdev->dev.platform_data; ++ if (!pdata) ++ return -ENXIO; ++ ++ err = -ENOMEM; ++ master = spi_alloc_master(&pdev->dev, sizeof(struct spi_gpio)); ++ if (!master) ++ goto err_alloc_master; ++ ++ sp = spi_master_get_devdata(master); ++ platform_set_drvdata(pdev, sp); ++ sp->info = pdata; ++ ++ err = gpio_request(pdata->pin_clk, "spi_clock"); ++ if (err) ++ goto err_request_clk; ++ err = gpio_request(pdata->pin_mosi, "spi_mosi"); ++ if (err) ++ goto err_request_mosi; ++ err = gpio_request(pdata->pin_miso, "spi_miso"); ++ if (err) ++ goto err_request_miso; ++ err = gpio_request(pdata->pin_cs, "spi_cs"); ++ if (err) ++ goto err_request_cs; ++ ++ sp->bitbang.master = spi_master_get(master); ++ sp->bitbang.master->bus_num = -1; ++ sp->bitbang.master->num_chipselect = 1; ++ sp->bitbang.chipselect = spi_gpio_chipselect; ++ sp->bitbang.txrx_word[SPI_MODE_0] = spi_gpio_txrx_mode0; ++ sp->bitbang.txrx_word[SPI_MODE_1] = spi_gpio_txrx_mode1; ++ sp->bitbang.txrx_word[SPI_MODE_2] = spi_gpio_txrx_mode2; ++ sp->bitbang.txrx_word[SPI_MODE_3] = spi_gpio_txrx_mode3; ++ ++ gpio_direction_output(pdata->pin_clk, 0); ++ gpio_direction_output(pdata->pin_mosi, 0); ++ gpio_direction_output(pdata->pin_cs, ++ pdata->cs_activelow ? 1 : 0); ++ gpio_direction_input(pdata->pin_miso); ++ ++ err = spi_bitbang_start(&sp->bitbang); ++ if (err) ++ goto err_no_bitbang; ++ err = pdata->boardinfo_setup(&sp->bi, master, ++ pdata->boardinfo_setup_data); ++ if (err) ++ goto err_bi_setup; ++ sp->bi.controller_data = sp; ++ spidev = spi_new_device(master, &sp->bi); ++ if (!spidev) ++ goto err_new_dev; ++ ++ return 0; ++ ++err_new_dev: ++err_bi_setup: ++ spi_bitbang_stop(&sp->bitbang); ++err_no_bitbang: ++ spi_master_put(sp->bitbang.master); ++ gpio_free(pdata->pin_cs); ++err_request_cs: ++ gpio_free(pdata->pin_miso); ++err_request_miso: ++ gpio_free(pdata->pin_mosi); ++err_request_mosi: ++ gpio_free(pdata->pin_clk); ++err_request_clk: ++ kfree(master); ++ ++err_alloc_master: ++ return err; ++} ++ ++static int spi_gpio_remove(struct platform_device *pdev) ++{ ++ struct spi_gpio *sp; ++ struct spi_gpio_platform_data *pdata; ++ ++ pdata = pdev->dev.platform_data; ++ sp = platform_get_drvdata(pdev); ++ ++ gpio_free(pdata->pin_clk); ++ gpio_free(pdata->pin_mosi); ++ gpio_free(pdata->pin_miso); ++ gpio_free(pdata->pin_cs); ++ spi_bitbang_stop(&sp->bitbang); ++ spi_master_put(sp->bitbang.master); ++ ++ return 0; ++} ++ ++static struct platform_driver spi_gpio_driver = { ++ .driver = { ++ .name = SPI_GPIO_PLATDEV_NAME, ++ .owner = THIS_MODULE, ++ }, ++ .probe = spi_gpio_probe, ++ .remove = spi_gpio_remove, ++}; ++ ++int spi_gpio_next_id(void) ++{ ++ static atomic_t counter = ATOMIC_INIT(-1); ++ ++ return atomic_inc_return(&counter); ++} ++EXPORT_SYMBOL(spi_gpio_next_id); ++ ++static int __init spi_gpio_init(void) ++{ ++ int err; ++ ++ err = platform_driver_register(&spi_gpio_driver); ++ if (err) ++ printk(KERN_ERR "spi-gpio: register failed: %d\n", err); ++ ++ return err; ++} ++module_init(spi_gpio_init); ++ ++static void __exit spi_gpio_exit(void) ++{ ++ platform_driver_unregister(&spi_gpio_driver); ++} ++module_exit(spi_gpio_exit); ++ ++MODULE_AUTHOR("Piot Skamruk "); ++MODULE_AUTHOR("Michael Buesch"); ++MODULE_DESCRIPTION("Platform independent GPIO bitbanging SPI driver"); ++MODULE_LICENSE("GPL v2"); +--- a/drivers/spi/Kconfig ++++ b/drivers/spi/Kconfig +@@ -225,6 +225,15 @@ config SPI_GPIO + GPIO operations, you should be able to leverage that for better + speed with a custom version of this driver; see the source code. + ++config SPI_GPIO_OLD ++ tristate "Old GPIO API based bitbanging SPI controller (DEPRECATED)" ++ depends on SPI_MASTER && GPIOLIB ++ select SPI_BITBANG ++ help ++ This code is deprecated. Please use the new mainline SPI-GPIO driver. ++ ++ If unsure, say N. ++ + config SPI_IMX + tristate "Freescale i.MX SPI controllers" + depends on ARCH_MXC || COMPILE_TEST +--- a/drivers/spi/Makefile ++++ b/drivers/spi/Makefile +@@ -40,6 +40,7 @@ obj-$(CONFIG_SPI_FSL_LIB) += spi-fsl-li + obj-$(CONFIG_SPI_FSL_ESPI) += spi-fsl-espi.o + obj-$(CONFIG_SPI_FSL_SPI) += spi-fsl-spi.o + obj-$(CONFIG_SPI_GPIO) += spi-gpio.o ++obj-$(CONFIG_SPI_GPIO_OLD) += spi_gpio_old.o + obj-$(CONFIG_SPI_IMX) += spi-imx.o + obj-$(CONFIG_SPI_LM70_LLP) += spi-lm70llp.o + obj-$(CONFIG_SPI_MPC512x_PSC) += spi-mpc512x-psc.o diff --git a/target/linux/generic/patches-3.18/863-gpiommc.patch b/target/linux/generic/patches-3.18/863-gpiommc.patch new file mode 100644 index 0000000..2929333 --- /dev/null +++ b/target/linux/generic/patches-3.18/863-gpiommc.patch @@ -0,0 +1,844 @@ +--- /dev/null ++++ b/drivers/mmc/host/gpiommc.c +@@ -0,0 +1,609 @@ ++/* ++ * Driver an MMC/SD card on a bitbanging GPIO SPI bus. ++ * This module hooks up the mmc_spi and spi_gpio modules and also ++ * provides a configfs interface. ++ * ++ * Copyright 2008 Michael Buesch ++ * ++ * Licensed under the GNU/GPL. See COPYING for details. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#define PFX "gpio-mmc: " ++ ++ ++struct gpiommc_device { ++ struct platform_device *pdev; ++ struct platform_device *spi_pdev; ++ struct spi_board_info boardinfo; ++}; ++ ++ ++MODULE_DESCRIPTION("GPIO based MMC driver"); ++MODULE_AUTHOR("Michael Buesch"); ++MODULE_LICENSE("GPL"); ++ ++ ++static int gpiommc_boardinfo_setup(struct spi_board_info *bi, ++ struct spi_master *master, ++ void *data) ++{ ++ struct gpiommc_device *d = data; ++ struct gpiommc_platform_data *pdata = d->pdev->dev.platform_data; ++ ++ /* Bind the SPI master to the MMC-SPI host driver. */ ++ strlcpy(bi->modalias, "mmc_spi", sizeof(bi->modalias)); ++ ++ bi->max_speed_hz = pdata->max_bus_speed; ++ bi->bus_num = master->bus_num; ++ bi->mode = pdata->mode; ++ ++ return 0; ++} ++ ++static int gpiommc_probe(struct platform_device *pdev) ++{ ++ struct gpiommc_platform_data *mmc_pdata = pdev->dev.platform_data; ++ struct spi_gpio_platform_data spi_pdata; ++ struct gpiommc_device *d; ++ int err; ++ ++ err = -ENXIO; ++ if (!mmc_pdata) ++ goto error; ++ ++#ifdef CONFIG_MMC_SPI_MODULE ++ err = request_module("mmc_spi"); ++ if (err) { ++ printk(KERN_WARNING PFX ++ "Failed to request mmc_spi module.\n"); ++ } ++#endif /* CONFIG_MMC_SPI_MODULE */ ++ ++ /* Allocate the GPIO-MMC device */ ++ err = -ENOMEM; ++ d = kzalloc(sizeof(*d), GFP_KERNEL); ++ if (!d) ++ goto error; ++ d->pdev = pdev; ++ ++ /* Create the SPI-GPIO device */ ++ d->spi_pdev = platform_device_alloc(SPI_GPIO_PLATDEV_NAME, ++ spi_gpio_next_id()); ++ if (!d->spi_pdev) ++ goto err_free_d; ++ ++ memset(&spi_pdata, 0, sizeof(spi_pdata)); ++ spi_pdata.pin_clk = mmc_pdata->pins.gpio_clk; ++ spi_pdata.pin_miso = mmc_pdata->pins.gpio_do; ++ spi_pdata.pin_mosi = mmc_pdata->pins.gpio_di; ++ spi_pdata.pin_cs = mmc_pdata->pins.gpio_cs; ++ spi_pdata.cs_activelow = mmc_pdata->pins.cs_activelow; ++ spi_pdata.no_spi_delay = mmc_pdata->no_spi_delay; ++ spi_pdata.boardinfo_setup = gpiommc_boardinfo_setup; ++ spi_pdata.boardinfo_setup_data = d; ++ ++ err = platform_device_add_data(d->spi_pdev, &spi_pdata, ++ sizeof(spi_pdata)); ++ if (err) ++ goto err_free_pdev; ++ err = platform_device_add(d->spi_pdev); ++ if (err) ++ goto err_free_pdata; ++ platform_set_drvdata(pdev, d); ++ ++ printk(KERN_INFO PFX "MMC-Card \"%s\" " ++ "attached to GPIO pins di=%u, do=%u, clk=%u, cs=%u\n", ++ mmc_pdata->name, mmc_pdata->pins.gpio_di, ++ mmc_pdata->pins.gpio_do, ++ mmc_pdata->pins.gpio_clk, ++ mmc_pdata->pins.gpio_cs); ++ ++ return 0; ++ ++err_free_pdata: ++ kfree(d->spi_pdev->dev.platform_data); ++ d->spi_pdev->dev.platform_data = NULL; ++err_free_pdev: ++ platform_device_put(d->spi_pdev); ++err_free_d: ++ kfree(d); ++error: ++ return err; ++} ++ ++static int gpiommc_remove(struct platform_device *pdev) ++{ ++ struct gpiommc_device *d = platform_get_drvdata(pdev); ++ struct gpiommc_platform_data *pdata = d->pdev->dev.platform_data; ++ ++ platform_device_unregister(d->spi_pdev); ++ printk(KERN_INFO PFX "GPIO based MMC-Card \"%s\" removed\n", ++ pdata->name); ++ platform_device_put(d->spi_pdev); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_GPIOMMC_CONFIGFS ++ ++/* A device that was created through configfs */ ++struct gpiommc_configfs_device { ++ struct config_item item; ++ /* The platform device, after registration. */ ++ struct platform_device *pdev; ++ /* The configuration */ ++ struct gpiommc_platform_data pdata; ++}; ++ ++#define GPIO_INVALID -1 ++ ++static inline bool gpiommc_is_registered(struct gpiommc_configfs_device *dev) ++{ ++ return (dev->pdev != NULL); ++} ++ ++static inline struct gpiommc_configfs_device *ci_to_gpiommc(struct config_item *item) ++{ ++ return item ? container_of(item, struct gpiommc_configfs_device, item) : NULL; ++} ++ ++static struct configfs_attribute gpiommc_attr_DI = { ++ .ca_owner = THIS_MODULE, ++ .ca_name = "gpio_data_in", ++ .ca_mode = S_IRUGO | S_IWUSR, ++}; ++ ++static struct configfs_attribute gpiommc_attr_DO = { ++ .ca_owner = THIS_MODULE, ++ .ca_name = "gpio_data_out", ++ .ca_mode = S_IRUGO | S_IWUSR, ++}; ++ ++static struct configfs_attribute gpiommc_attr_CLK = { ++ .ca_owner = THIS_MODULE, ++ .ca_name = "gpio_clock", ++ .ca_mode = S_IRUGO | S_IWUSR, ++}; ++ ++static struct configfs_attribute gpiommc_attr_CS = { ++ .ca_owner = THIS_MODULE, ++ .ca_name = "gpio_chipselect", ++ .ca_mode = S_IRUGO | S_IWUSR, ++}; ++ ++static struct configfs_attribute gpiommc_attr_CS_activelow = { ++ .ca_owner = THIS_MODULE, ++ .ca_name = "gpio_chipselect_activelow", ++ .ca_mode = S_IRUGO | S_IWUSR, ++}; ++ ++static struct configfs_attribute gpiommc_attr_spimode = { ++ .ca_owner = THIS_MODULE, ++ .ca_name = "spi_mode", ++ .ca_mode = S_IRUGO | S_IWUSR, ++}; ++ ++static struct configfs_attribute gpiommc_attr_spidelay = { ++ .ca_owner = THIS_MODULE, ++ .ca_name = "spi_delay", ++ .ca_mode = S_IRUGO | S_IWUSR, ++}; ++ ++static struct configfs_attribute gpiommc_attr_max_bus_speed = { ++ .ca_owner = THIS_MODULE, ++ .ca_name = "max_bus_speed", ++ .ca_mode = S_IRUGO | S_IWUSR, ++}; ++ ++static struct configfs_attribute gpiommc_attr_register = { ++ .ca_owner = THIS_MODULE, ++ .ca_name = "register", ++ .ca_mode = S_IRUGO | S_IWUSR, ++}; ++ ++static struct configfs_attribute *gpiommc_config_attrs[] = { ++ &gpiommc_attr_DI, ++ &gpiommc_attr_DO, ++ &gpiommc_attr_CLK, ++ &gpiommc_attr_CS, ++ &gpiommc_attr_CS_activelow, ++ &gpiommc_attr_spimode, ++ &gpiommc_attr_spidelay, ++ &gpiommc_attr_max_bus_speed, ++ &gpiommc_attr_register, ++ NULL, ++}; ++ ++static ssize_t gpiommc_config_attr_show(struct config_item *item, ++ struct configfs_attribute *attr, ++ char *page) ++{ ++ struct gpiommc_configfs_device *dev = ci_to_gpiommc(item); ++ ssize_t count = 0; ++ unsigned int gpio; ++ int err = 0; ++ ++ if (attr == &gpiommc_attr_DI) { ++ gpio = dev->pdata.pins.gpio_di; ++ if (gpio == GPIO_INVALID) ++ count = snprintf(page, PAGE_SIZE, "not configured\n"); ++ else ++ count = snprintf(page, PAGE_SIZE, "%u\n", gpio); ++ goto out; ++ } ++ if (attr == &gpiommc_attr_DO) { ++ gpio = dev->pdata.pins.gpio_do; ++ if (gpio == GPIO_INVALID) ++ count = snprintf(page, PAGE_SIZE, "not configured\n"); ++ else ++ count = snprintf(page, PAGE_SIZE, "%u\n", gpio); ++ goto out; ++ } ++ if (attr == &gpiommc_attr_CLK) { ++ gpio = dev->pdata.pins.gpio_clk; ++ if (gpio == GPIO_INVALID) ++ count = snprintf(page, PAGE_SIZE, "not configured\n"); ++ else ++ count = snprintf(page, PAGE_SIZE, "%u\n", gpio); ++ goto out; ++ } ++ if (attr == &gpiommc_attr_CS) { ++ gpio = dev->pdata.pins.gpio_cs; ++ if (gpio == GPIO_INVALID) ++ count = snprintf(page, PAGE_SIZE, "not configured\n"); ++ else ++ count = snprintf(page, PAGE_SIZE, "%u\n", gpio); ++ goto out; ++ } ++ if (attr == &gpiommc_attr_CS_activelow) { ++ count = snprintf(page, PAGE_SIZE, "%u\n", ++ dev->pdata.pins.cs_activelow); ++ goto out; ++ } ++ if (attr == &gpiommc_attr_spimode) { ++ count = snprintf(page, PAGE_SIZE, "%u\n", ++ dev->pdata.mode); ++ goto out; ++ } ++ if (attr == &gpiommc_attr_spidelay) { ++ count = snprintf(page, PAGE_SIZE, "%u\n", ++ !dev->pdata.no_spi_delay); ++ goto out; ++ } ++ if (attr == &gpiommc_attr_max_bus_speed) { ++ count = snprintf(page, PAGE_SIZE, "%u\n", ++ dev->pdata.max_bus_speed); ++ goto out; ++ } ++ if (attr == &gpiommc_attr_register) { ++ count = snprintf(page, PAGE_SIZE, "%u\n", ++ gpiommc_is_registered(dev)); ++ goto out; ++ } ++ WARN_ON(1); ++ err = -ENOSYS; ++out: ++ return err ? err : count; ++} ++ ++static int gpiommc_do_register(struct gpiommc_configfs_device *dev, ++ const char *name) ++{ ++ int err; ++ ++ if (gpiommc_is_registered(dev)) ++ return 0; ++ ++ if (!gpio_is_valid(dev->pdata.pins.gpio_di) || ++ !gpio_is_valid(dev->pdata.pins.gpio_do) || ++ !gpio_is_valid(dev->pdata.pins.gpio_clk) || ++ !gpio_is_valid(dev->pdata.pins.gpio_cs)) { ++ printk(KERN_ERR PFX ++ "configfs: Invalid GPIO pin number(s)\n"); ++ return -EINVAL; ++ } ++ ++ strlcpy(dev->pdata.name, name, ++ sizeof(dev->pdata.name)); ++ ++ dev->pdev = platform_device_alloc(GPIOMMC_PLATDEV_NAME, ++ gpiommc_next_id()); ++ if (!dev->pdev) ++ return -ENOMEM; ++ err = platform_device_add_data(dev->pdev, &dev->pdata, ++ sizeof(dev->pdata)); ++ if (err) { ++ platform_device_put(dev->pdev); ++ return err; ++ } ++ err = platform_device_add(dev->pdev); ++ if (err) { ++ platform_device_put(dev->pdev); ++ return err; ++ } ++ ++ return 0; ++} ++ ++static void gpiommc_do_unregister(struct gpiommc_configfs_device *dev) ++{ ++ if (!gpiommc_is_registered(dev)) ++ return; ++ ++ platform_device_unregister(dev->pdev); ++ dev->pdev = NULL; ++} ++ ++static ssize_t gpiommc_config_attr_store(struct config_item *item, ++ struct configfs_attribute *attr, ++ const char *page, size_t count) ++{ ++ struct gpiommc_configfs_device *dev = ci_to_gpiommc(item); ++ int err = -EINVAL; ++ unsigned long data; ++ ++ if (attr == &gpiommc_attr_register) { ++ err = kstrtoul(page, 10, &data); ++ if (err) ++ goto out; ++ err = -EINVAL; ++ if (data == 1) ++ err = gpiommc_do_register(dev, item->ci_name); ++ if (data == 0) { ++ gpiommc_do_unregister(dev); ++ err = 0; ++ } ++ goto out; ++ } ++ ++ if (gpiommc_is_registered(dev)) { ++ /* The rest of the config parameters can only be set ++ * as long as the device is not registered, yet. */ ++ err = -EBUSY; ++ goto out; ++ } ++ ++ if (attr == &gpiommc_attr_DI) { ++ err = kstrtoul(page, 10, &data); ++ if (err) ++ goto out; ++ err = -EINVAL; ++ if (!gpio_is_valid(data)) ++ goto out; ++ dev->pdata.pins.gpio_di = data; ++ err = 0; ++ goto out; ++ } ++ if (attr == &gpiommc_attr_DO) { ++ err = kstrtoul(page, 10, &data); ++ if (err) ++ goto out; ++ err = -EINVAL; ++ if (!gpio_is_valid(data)) ++ goto out; ++ dev->pdata.pins.gpio_do = data; ++ err = 0; ++ goto out; ++ } ++ if (attr == &gpiommc_attr_CLK) { ++ err = kstrtoul(page, 10, &data); ++ if (err) ++ goto out; ++ err = -EINVAL; ++ if (!gpio_is_valid(data)) ++ goto out; ++ dev->pdata.pins.gpio_clk = data; ++ err = 0; ++ goto out; ++ } ++ if (attr == &gpiommc_attr_CS) { ++ err = kstrtoul(page, 10, &data); ++ if (err) ++ goto out; ++ err = -EINVAL; ++ if (!gpio_is_valid(data)) ++ goto out; ++ dev->pdata.pins.gpio_cs = data; ++ err = 0; ++ goto out; ++ } ++ if (attr == &gpiommc_attr_CS_activelow) { ++ err = kstrtoul(page, 10, &data); ++ if (err) ++ goto out; ++ err = -EINVAL; ++ if (data != 0 && data != 1) ++ goto out; ++ dev->pdata.pins.cs_activelow = data; ++ err = 0; ++ goto out; ++ } ++ if (attr == &gpiommc_attr_spimode) { ++ err = kstrtoul(page, 10, &data); ++ if (err) ++ goto out; ++ err = -EINVAL; ++ switch (data) { ++ case 0: ++ dev->pdata.mode = SPI_MODE_0; ++ break; ++ case 1: ++ dev->pdata.mode = SPI_MODE_1; ++ break; ++ case 2: ++ dev->pdata.mode = SPI_MODE_2; ++ break; ++ case 3: ++ dev->pdata.mode = SPI_MODE_3; ++ break; ++ default: ++ goto out; ++ } ++ err = 0; ++ goto out; ++ } ++ if (attr == &gpiommc_attr_spidelay) { ++ err = kstrtoul(page, 10, &data); ++ if (err) ++ goto out; ++ err = -EINVAL; ++ if (data != 0 && data != 1) ++ goto out; ++ dev->pdata.no_spi_delay = !data; ++ err = 0; ++ goto out; ++ } ++ if (attr == &gpiommc_attr_max_bus_speed) { ++ err = kstrtoul(page, 10, &data); ++ if (err) ++ goto out; ++ err = -EINVAL; ++ if (data > UINT_MAX) ++ goto out; ++ dev->pdata.max_bus_speed = data; ++ err = 0; ++ goto out; ++ } ++ WARN_ON(1); ++ err = -ENOSYS; ++out: ++ return err ? err : count; ++} ++ ++static void gpiommc_config_item_release(struct config_item *item) ++{ ++ struct gpiommc_configfs_device *dev = ci_to_gpiommc(item); ++ ++ kfree(dev); ++} ++ ++static struct configfs_item_operations gpiommc_config_item_ops = { ++ .release = gpiommc_config_item_release, ++ .show_attribute = gpiommc_config_attr_show, ++ .store_attribute = gpiommc_config_attr_store, ++}; ++ ++static struct config_item_type gpiommc_dev_ci_type = { ++ .ct_item_ops = &gpiommc_config_item_ops, ++ .ct_attrs = gpiommc_config_attrs, ++ .ct_owner = THIS_MODULE, ++}; ++ ++static struct config_item *gpiommc_make_item(struct config_group *group, ++ const char *name) ++{ ++ struct gpiommc_configfs_device *dev; ++ ++ if (strlen(name) > GPIOMMC_MAX_NAMELEN) { ++ printk(KERN_ERR PFX "configfs: device name too long\n"); ++ return NULL; ++ } ++ ++ dev = kzalloc(sizeof(*dev), GFP_KERNEL); ++ if (!dev) ++ return NULL; ++ ++ config_item_init_type_name(&dev->item, name, ++ &gpiommc_dev_ci_type); ++ ++ /* Assign default configuration */ ++ dev->pdata.pins.gpio_di = GPIO_INVALID; ++ dev->pdata.pins.gpio_do = GPIO_INVALID; ++ dev->pdata.pins.gpio_clk = GPIO_INVALID; ++ dev->pdata.pins.gpio_cs = GPIO_INVALID; ++ dev->pdata.pins.cs_activelow = 1; ++ dev->pdata.mode = SPI_MODE_0; ++ dev->pdata.no_spi_delay = 0; ++ dev->pdata.max_bus_speed = 5000000; /* 5 MHz */ ++ ++ return &(dev->item); ++} ++ ++static void gpiommc_drop_item(struct config_group *group, ++ struct config_item *item) ++{ ++ struct gpiommc_configfs_device *dev = ci_to_gpiommc(item); ++ ++ gpiommc_do_unregister(dev); ++ kfree(dev); ++} ++ ++static struct configfs_group_operations gpiommc_ct_group_ops = { ++ .make_item = gpiommc_make_item, ++ .drop_item = gpiommc_drop_item, ++}; ++ ++static struct config_item_type gpiommc_ci_type = { ++ .ct_group_ops = &gpiommc_ct_group_ops, ++ .ct_owner = THIS_MODULE, ++}; ++ ++static struct configfs_subsystem gpiommc_subsys = { ++ .su_group = { ++ .cg_item = { ++ .ci_namebuf = GPIOMMC_PLATDEV_NAME, ++ .ci_type = &gpiommc_ci_type, ++ }, ++ }, ++ .su_mutex = __MUTEX_INITIALIZER(gpiommc_subsys.su_mutex), ++}; ++ ++#endif /* CONFIG_GPIOMMC_CONFIGFS */ ++ ++static struct platform_driver gpiommc_plat_driver = { ++ .probe = gpiommc_probe, ++ .remove = gpiommc_remove, ++ .driver = { ++ .name = GPIOMMC_PLATDEV_NAME, ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++int gpiommc_next_id(void) ++{ ++ static atomic_t counter = ATOMIC_INIT(-1); ++ ++ return atomic_inc_return(&counter); ++} ++EXPORT_SYMBOL(gpiommc_next_id); ++ ++static int __init gpiommc_modinit(void) ++{ ++ int err; ++ ++ err = platform_driver_register(&gpiommc_plat_driver); ++ if (err) ++ return err; ++ ++#ifdef CONFIG_GPIOMMC_CONFIGFS ++ config_group_init(&gpiommc_subsys.su_group); ++ err = configfs_register_subsystem(&gpiommc_subsys); ++ if (err) { ++ platform_driver_unregister(&gpiommc_plat_driver); ++ return err; ++ } ++#endif /* CONFIG_GPIOMMC_CONFIGFS */ ++ ++ return 0; ++} ++module_init(gpiommc_modinit); ++ ++static void __exit gpiommc_modexit(void) ++{ ++#ifdef CONFIG_GPIOMMC_CONFIGFS ++ configfs_unregister_subsystem(&gpiommc_subsys); ++#endif ++ platform_driver_unregister(&gpiommc_plat_driver); ++} ++module_exit(gpiommc_modexit); +--- a/drivers/mmc/host/Kconfig ++++ b/drivers/mmc/host/Kconfig +@@ -534,6 +534,31 @@ config MMC_SDHI + This provides support for the SDHI SD/SDIO controller found in + SuperH and ARM SH-Mobile SoCs + ++config GPIOMMC ++ tristate "MMC/SD over GPIO-based SPI" ++ depends on MMC && MMC_SPI && SPI_GPIO_OLD ++ help ++ This driver hooks up the mmc_spi and spi_gpio modules so that ++ MMC/SD cards can be used on a GPIO based bus by bitbanging ++ the SPI protocol in software. ++ ++ This driver provides a configfs interface to dynamically create ++ and destroy GPIO-based MMC/SD card devices. It also provides ++ a platform device interface API. ++ See Documentation/gpiommc.txt for details. ++ ++ The module will be called gpiommc. ++ ++ If unsure, say N. ++ ++config GPIOMMC_CONFIGFS ++ bool ++ depends on GPIOMMC && CONFIGFS_FS ++ default y ++ help ++ This option automatically enables configfs support for gpiommc ++ if configfs is available. ++ + config MMC_CB710 + tristate "ENE CB710 MMC/SD Interface support" + depends on PCI +--- a/drivers/mmc/host/Makefile ++++ b/drivers/mmc/host/Makefile +@@ -40,6 +40,7 @@ tmio_mmc_core-$(subst m,y,$(CONFIG_MMC_S + obj-$(CONFIG_MMC_SDHI) += sh_mobile_sdhi.o + obj-$(CONFIG_MMC_CB710) += cb710-mmc.o + obj-$(CONFIG_MMC_VIA_SDMMC) += via-sdmmc.o ++obj-$(CONFIG_GPIOMMC) += gpiommc.o + obj-$(CONFIG_SDH_BFIN) += bfin_sdh.o + obj-$(CONFIG_MMC_DW) += dw_mmc.o + obj-$(CONFIG_MMC_DW_PLTFM) += dw_mmc-pltfm.o +--- /dev/null ++++ b/include/linux/mmc/gpiommc.h +@@ -0,0 +1,71 @@ ++/* ++ * Device driver for MMC/SD cards driven over a GPIO bus. ++ * ++ * Copyright (c) 2008 Michael Buesch ++ * ++ * Licensed under the GNU/GPL version 2. ++ */ ++#ifndef LINUX_GPIOMMC_H_ ++#define LINUX_GPIOMMC_H_ ++ ++#include ++ ++ ++#define GPIOMMC_MAX_NAMELEN 15 ++#define GPIOMMC_MAX_NAMELEN_STR __stringify(GPIOMMC_MAX_NAMELEN) ++ ++/** ++ * struct gpiommc_pins - Hardware pin assignments ++ * ++ * @gpio_di: The GPIO number of the DATA IN pin ++ * @gpio_do: The GPIO number of the DATA OUT pin ++ * @gpio_clk: The GPIO number of the CLOCK pin ++ * @gpio_cs: The GPIO number of the CHIPSELECT pin ++ * @cs_activelow: If true, the chip is considered selected if @gpio_cs is low. ++ */ ++struct gpiommc_pins { ++ unsigned int gpio_di; ++ unsigned int gpio_do; ++ unsigned int gpio_clk; ++ unsigned int gpio_cs; ++ bool cs_activelow; ++}; ++ ++/** ++ * struct gpiommc_platform_data - Platform data for a MMC-over-SPI-GPIO device. ++ * ++ * @name: The unique name string of the device. ++ * @pins: The hardware pin assignments. ++ * @mode: The hardware mode. This is either SPI_MODE_0, ++ * SPI_MODE_1, SPI_MODE_2 or SPI_MODE_3. See the SPI documentation. ++ * @no_spi_delay: Do not use delays in the lowlevel SPI bitbanging code. ++ * This is not standards compliant, but may be required for some ++ * embedded machines to gain reasonable speed. ++ * @max_bus_speed: The maximum speed of the SPI bus, in Hertz. ++ */ ++struct gpiommc_platform_data { ++ char name[GPIOMMC_MAX_NAMELEN + 1]; ++ struct gpiommc_pins pins; ++ u8 mode; ++ bool no_spi_delay; ++ unsigned int max_bus_speed; ++}; ++ ++/** ++ * GPIOMMC_PLATDEV_NAME - The platform device name string. ++ * ++ * The name string that has to be used for platform_device_alloc ++ * when allocating a gpiommc device. ++ */ ++#define GPIOMMC_PLATDEV_NAME "gpiommc" ++ ++/** ++ * gpiommc_next_id - Get another platform device ID number. ++ * ++ * This returns the next platform device ID number that has to be used ++ * for platform_device_alloc. The ID is opaque and should not be used for ++ * anything else. ++ */ ++int gpiommc_next_id(void); ++ ++#endif /* LINUX_GPIOMMC_H_ */ +--- /dev/null ++++ b/Documentation/gpiommc.txt +@@ -0,0 +1,97 @@ ++GPIOMMC - Driver for an MMC/SD card on a bitbanging GPIO SPI bus ++================================================================ ++ ++The gpiommc module hooks up the mmc_spi and spi_gpio modules for running an ++MMC or SD card on GPIO pins. ++ ++Two interfaces for registering a new MMC/SD card device are provided: ++A static platform-device based mechanism and a dynamic configfs based interface. ++ ++ ++Registering devices via platform-device ++======================================= ++ ++The platform-device interface is used for registering MMC/SD devices that are ++part of the hardware platform. This is most useful only for embedded machines ++with MMC/SD devices statically connected to the platform GPIO bus. ++ ++The data structures are declared in . ++ ++To register a new device, define an instance of struct gpiommc_platform_data. ++This structure holds any information about how the device is hooked up to the ++GPIO pins and what hardware modes the device supports. See the docbook-style ++documentation in the header file for more information on the struct fields. ++ ++Then allocate a new instance of a platform device by doing: ++ ++ pdev = platform_device_alloc(GPIOMMC_PLATDEV_NAME, gpiommc_next_id()); ++ ++This will allocate the platform device data structures and hook it up to the ++gpiommc driver. ++Then add the gpiommc_platform_data to the platform device. ++ ++ err = platform_device_add_data(pdev, pdata, sizeof(struct gpiommc_platform_data)); ++ ++You may free the local instance of struct gpiommc_platform_data now. (So the ++struct may be allocated on the stack, too). ++Now simply register the platform device. ++ ++ err = platform_device_add(pdev); ++ ++Done. The gpiommc probe routine will be invoked now and you should see a kernel ++log message for the added device. ++ ++ ++Registering devices via configfs ++================================ ++ ++MMC/SD cards connected via GPIO often are a pretty dynamic thing, as for example ++selfmade hacks for soldering an MMC/SD card to standard GPIO pins on embedded ++hardware are a common situation. ++So we provide a dynamic interface to conveniently handle adding and removing ++devices from userspace, without the need to recompile the kernel. ++ ++The "gpiommc" subdirectory at the configfs mountpoint is used for handling ++the dynamic configuration. ++ ++To create a new device, it must first be allocated with mkdir. ++The following command will allocate a device named "my_mmc": ++ mkdir /config/gpiommc/my_mmc ++ ++There are several configuration files available in the new ++/config/gpiommc/my_mmc/ directory: ++ ++gpio_data_in = The SPI data-IN GPIO pin number. ++gpio_data_out = The SPI data-OUT GPIO pin number. ++gpio_clock = The SPI Clock GPIO pin number. ++gpio_chipselect = The SPI Chipselect GPIO pin number. ++gpio_chipselect_activelow = Boolean. If 0, Chipselect is active-HIGH. ++ If 1, Chipselect is active-LOW. ++spi_mode = The SPI data mode. Can be 0-3. ++spi_delay = Enable all delays in the lowlevel bitbanging. ++max_bus_speed = The maximum SPI bus speed. In Hertz. ++ ++register = Not a configuration parameter. ++ Used to register the configured card ++ with the kernel. ++ ++The device must first get configured and then registered by writing "1" to ++the "register" file. ++The configuration parameters "gpio_data_in", "gpio_data_out", "gpio_clock" ++and "gpio_chipselect" are essential and _must_ be configured before writing ++"1" to the "register" file. The registration will fail, otherwise. ++ ++The default values for the other parameters are: ++gpio_chipselect_activelow = 1 (CS active-LOW) ++spi_mode = 0 (SPI_MODE_0) ++spi_delay = 1 (enabled) ++max_bus_speed = 5000000 (5 Mhz) ++ ++Configuration values can not be changed after registration. To unregister ++the device, write a "0" to the "register" file. The configuration can be ++changed again after unregistering. ++ ++To completely remove the device, simply rmdir the directory ++(/config/gpiommc/my_mmc in this example). ++There's no need to first unregister the device before removing it. That will ++be done automatically. +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -4279,6 +4279,11 @@ T: git git://linuxtv.org/anttip/media_tr + S: Maintained + F: drivers/media/usb/hackrf/ + ++GPIOMMC DRIVER ++P: Michael Buesch ++M: mb@bu3sch.de ++S: Maintained ++ + HARDWARE MONITORING + M: Jean Delvare + M: Guenter Roeck diff --git a/target/linux/generic/patches-3.18/864-gpiommc_configfs_locking.patch b/target/linux/generic/patches-3.18/864-gpiommc_configfs_locking.patch new file mode 100644 index 0000000..92815d9 --- /dev/null +++ b/target/linux/generic/patches-3.18/864-gpiommc_configfs_locking.patch @@ -0,0 +1,58 @@ +The gpiommc configfs context structure needs locking, as configfs +does not lock access between files. + +--- a/drivers/mmc/host/gpiommc.c ++++ b/drivers/mmc/host/gpiommc.c +@@ -144,6 +144,8 @@ struct gpiommc_configfs_device { + struct platform_device *pdev; + /* The configuration */ + struct gpiommc_platform_data pdata; ++ /* Mutex to protect this structure */ ++ struct mutex mutex; + }; + + #define GPIO_INVALID -1 +@@ -234,6 +236,8 @@ static ssize_t gpiommc_config_attr_show( + unsigned int gpio; + int err = 0; + ++ mutex_lock(&dev->mutex); ++ + if (attr == &gpiommc_attr_DI) { + gpio = dev->pdata.pins.gpio_di; + if (gpio == GPIO_INVALID) +@@ -294,6 +298,8 @@ static ssize_t gpiommc_config_attr_show( + WARN_ON(1); + err = -ENOSYS; + out: ++ mutex_unlock(&dev->mutex); ++ + return err ? err : count; + } + +@@ -353,6 +359,8 @@ static ssize_t gpiommc_config_attr_store + int err = -EINVAL; + unsigned long data; + ++ mutex_lock(&dev->mutex); ++ + if (attr == &gpiommc_attr_register) { + err = kstrtoul(page, 10, &data); + if (err) +@@ -478,6 +486,8 @@ static ssize_t gpiommc_config_attr_store + WARN_ON(1); + err = -ENOSYS; + out: ++ mutex_unlock(&dev->mutex); ++ + return err ? err : count; + } + +@@ -514,6 +524,7 @@ static struct config_item *gpiommc_make_ + if (!dev) + return NULL; + ++ mutex_init(&dev->mutex); + config_item_init_type_name(&dev->item, name, + &gpiommc_dev_ci_type); + diff --git a/target/linux/generic/patches-3.18/870-hifn795x_byteswap.patch b/target/linux/generic/patches-3.18/870-hifn795x_byteswap.patch new file mode 100644 index 0000000..3a37c95 --- /dev/null +++ b/target/linux/generic/patches-3.18/870-hifn795x_byteswap.patch @@ -0,0 +1,17 @@ +--- a/drivers/crypto/hifn_795x.c ++++ b/drivers/crypto/hifn_795x.c +@@ -682,12 +682,12 @@ static inline u32 hifn_read_1(struct hif + + static inline void hifn_write_0(struct hifn_device *dev, u32 reg, u32 val) + { +- writel((__force u32)cpu_to_le32(val), dev->bar[0] + reg); ++ writel(val, dev->bar[0] + reg); + } + + static inline void hifn_write_1(struct hifn_device *dev, u32 reg, u32 val) + { +- writel((__force u32)cpu_to_le32(val), dev->bar[1] + reg); ++ writel(val, dev->bar[1] + reg); + } + + static void hifn_wait_puc(struct hifn_device *dev) diff --git a/target/linux/generic/patches-3.18/880-gateworks_system_controller.patch b/target/linux/generic/patches-3.18/880-gateworks_system_controller.patch new file mode 100644 index 0000000..55e95be --- /dev/null +++ b/target/linux/generic/patches-3.18/880-gateworks_system_controller.patch @@ -0,0 +1,339 @@ +--- a/drivers/hwmon/Kconfig ++++ b/drivers/hwmon/Kconfig +@@ -507,6 +507,15 @@ config SENSORS_G762 + This driver can also be built as a module. If so, the module + will be called g762. + ++config SENSORS_GSC ++ tristate "Gateworks System Controller" ++ depends on I2C ++ help ++ If you say yes here you get support for the Gateworks System Controller. ++ ++ This driver can also be built as a module. If so, the module ++ will be called gsc. ++ + config SENSORS_GPIO_FAN + tristate "GPIO fan" + depends on GPIOLIB +--- a/drivers/hwmon/Makefile ++++ b/drivers/hwmon/Makefile +@@ -153,6 +153,7 @@ obj-$(CONFIG_SENSORS_W83L785TS) += w83l7 + obj-$(CONFIG_SENSORS_W83L786NG) += w83l786ng.o + obj-$(CONFIG_SENSORS_WM831X) += wm831x-hwmon.o + obj-$(CONFIG_SENSORS_WM8350) += wm8350-hwmon.o ++obj-$(CONFIG_SENSORS_GSC) += gsc.o + + obj-$(CONFIG_PMBUS) += pmbus/ + +--- /dev/null ++++ b/drivers/hwmon/gsc.c +@@ -0,0 +1,308 @@ ++/* ++ * A hwmon driver for the Gateworks System Controller ++ * Copyright (C) 2009 Gateworks Corporation ++ * ++ * Author: Chris Lang ++ * ++ * 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 - version 2. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define DRV_VERSION "0.2" ++ ++enum chips { gsp }; ++ ++/* AD7418 registers */ ++#define GSP_REG_TEMP_IN 0x00 ++#define GSP_REG_VIN 0x02 ++#define GSP_REG_3P3 0x05 ++#define GSP_REG_BAT 0x08 ++#define GSP_REG_5P0 0x0b ++#define GSP_REG_CORE 0x0e ++#define GSP_REG_CPU1 0x11 ++#define GSP_REG_CPU2 0x14 ++#define GSP_REG_DRAM 0x17 ++#define GSP_REG_EXT_BAT 0x1a ++#define GSP_REG_IO1 0x1d ++#define GSP_REG_IO2 0x20 ++#define GSP_REG_PCIE 0x23 ++#define GSP_REG_CURRENT 0x26 ++#define GSP_FAN_0 0x2C ++#define GSP_FAN_1 0x2E ++#define GSP_FAN_2 0x30 ++#define GSP_FAN_3 0x32 ++#define GSP_FAN_4 0x34 ++#define GSP_FAN_5 0x36 ++ ++struct gsp_sensor_info { ++ const char* name; ++ int reg; ++}; ++ ++static const struct gsp_sensor_info gsp_sensors[] = { ++ {"temp", GSP_REG_TEMP_IN}, ++ {"vin", GSP_REG_VIN}, ++ {"3p3", GSP_REG_3P3}, ++ {"bat", GSP_REG_BAT}, ++ {"5p0", GSP_REG_5P0}, ++ {"core", GSP_REG_CORE}, ++ {"cpu1", GSP_REG_CPU1}, ++ {"cpu2", GSP_REG_CPU2}, ++ {"dram", GSP_REG_DRAM}, ++ {"ext_bat", GSP_REG_EXT_BAT}, ++ {"io1", GSP_REG_IO1}, ++ {"io2", GSP_REG_IO2}, ++ {"pci2", GSP_REG_PCIE}, ++ {"current", GSP_REG_CURRENT}, ++ {"fan_point0", GSP_FAN_0}, ++ {"fan_point1", GSP_FAN_1}, ++ {"fan_point2", GSP_FAN_2}, ++ {"fan_point3", GSP_FAN_3}, ++ {"fan_point4", GSP_FAN_4}, ++ {"fan_point5", GSP_FAN_5}, ++}; ++ ++struct gsp_data { ++ struct device *hwmon_dev; ++ struct attribute_group attrs; ++ enum chips type; ++}; ++ ++static int gsp_probe(struct i2c_client *client, ++ const struct i2c_device_id *id); ++static int gsp_remove(struct i2c_client *client); ++ ++static const struct i2c_device_id gsp_id[] = { ++ { "gsp", 0 }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, gsp_id); ++ ++static struct i2c_driver gsp_driver = { ++ .driver = { ++ .name = "gsp", ++ }, ++ .probe = gsp_probe, ++ .remove = gsp_remove, ++ .id_table = gsp_id, ++}; ++ ++/* All registers are word-sized, except for the configuration registers. ++ * AD7418 uses a high-byte first convention. Do NOT use those functions to ++ * access the configuration registers CONF and CONF2, as they are byte-sized. ++ */ ++static inline int gsp_read(struct i2c_client *client, u8 reg) ++{ ++ unsigned int adc = 0; ++ if (reg == GSP_REG_TEMP_IN || reg > GSP_REG_CURRENT) ++ { ++ adc |= i2c_smbus_read_byte_data(client, reg); ++ adc |= i2c_smbus_read_byte_data(client, reg + 1) << 8; ++ return adc; ++ } ++ else ++ { ++ adc |= i2c_smbus_read_byte_data(client, reg); ++ adc |= i2c_smbus_read_byte_data(client, reg + 1) << 8; ++ adc |= i2c_smbus_read_byte_data(client, reg + 2) << 16; ++ return adc; ++ } ++} ++ ++static inline int gsp_write(struct i2c_client *client, u8 reg, u16 value) ++{ ++ i2c_smbus_write_byte_data(client, reg, value & 0xff); ++ i2c_smbus_write_byte_data(client, reg + 1, ((value >> 8) & 0xff)); ++ return 1; ++} ++ ++static ssize_t show_adc(struct device *dev, struct device_attribute *devattr, ++ char *buf) ++{ ++ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); ++ struct i2c_client *client = to_i2c_client(dev); ++ return sprintf(buf, "%d\n", gsp_read(client, gsp_sensors[attr->index].reg)); ++} ++ ++static ssize_t show_label(struct device *dev, ++ struct device_attribute *devattr, char *buf) ++{ ++ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); ++ ++ return sprintf(buf, "%s\n", gsp_sensors[attr->index].name); ++} ++ ++static ssize_t store_fan(struct device *dev, ++ struct device_attribute *devattr, const char *buf, size_t count) ++{ ++ u16 val; ++ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); ++ struct i2c_client *client = to_i2c_client(dev); ++ val = simple_strtoul(buf, NULL, 10); ++ gsp_write(client, gsp_sensors[attr->index].reg, val); ++ return count; ++} ++ ++static SENSOR_DEVICE_ATTR(temp0_input, S_IRUGO, show_adc, NULL, 0); ++static SENSOR_DEVICE_ATTR(temp0_label, S_IRUGO, show_label, NULL, 0); ++ ++static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, show_adc, NULL, 1); ++static SENSOR_DEVICE_ATTR(in0_label, S_IRUGO, show_label, NULL, 1); ++static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_adc, NULL, 2); ++static SENSOR_DEVICE_ATTR(in1_label, S_IRUGO, show_label, NULL, 2); ++static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_adc, NULL, 3); ++static SENSOR_DEVICE_ATTR(in2_label, S_IRUGO, show_label, NULL, 3); ++static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_adc, NULL, 4); ++static SENSOR_DEVICE_ATTR(in3_label, S_IRUGO, show_label, NULL, 4); ++static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, show_adc, NULL, 5); ++static SENSOR_DEVICE_ATTR(in4_label, S_IRUGO, show_label, NULL, 5); ++static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, show_adc, NULL, 6); ++static SENSOR_DEVICE_ATTR(in5_label, S_IRUGO, show_label, NULL, 6); ++static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, show_adc, NULL, 7); ++static SENSOR_DEVICE_ATTR(in6_label, S_IRUGO, show_label, NULL, 7); ++static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, show_adc, NULL, 8); ++static SENSOR_DEVICE_ATTR(in7_label, S_IRUGO, show_label, NULL, 8); ++static SENSOR_DEVICE_ATTR(in8_input, S_IRUGO, show_adc, NULL, 9); ++static SENSOR_DEVICE_ATTR(in8_label, S_IRUGO, show_label, NULL, 9); ++static SENSOR_DEVICE_ATTR(in9_input, S_IRUGO, show_adc, NULL, 10); ++static SENSOR_DEVICE_ATTR(in9_label, S_IRUGO, show_label, NULL, 10); ++static SENSOR_DEVICE_ATTR(in10_input, S_IRUGO, show_adc, NULL, 11); ++static SENSOR_DEVICE_ATTR(in10_label, S_IRUGO, show_label, NULL, 11); ++static SENSOR_DEVICE_ATTR(in11_input, S_IRUGO, show_adc, NULL, 12); ++static SENSOR_DEVICE_ATTR(in11_label, S_IRUGO, show_label, NULL, 12); ++static SENSOR_DEVICE_ATTR(in12_input, S_IRUGO, show_adc, NULL, 13); ++static SENSOR_DEVICE_ATTR(in12_label, S_IRUGO, show_label, NULL, 13); ++ ++static SENSOR_DEVICE_ATTR(fan0_point0, S_IRUGO | S_IWUSR, show_adc, store_fan, 14); ++static SENSOR_DEVICE_ATTR(fan0_point1, S_IRUGO | S_IWUSR, show_adc, store_fan, 15); ++static SENSOR_DEVICE_ATTR(fan0_point2, S_IRUGO | S_IWUSR, show_adc, store_fan, 16); ++static SENSOR_DEVICE_ATTR(fan0_point3, S_IRUGO | S_IWUSR, show_adc, store_fan, 17); ++static SENSOR_DEVICE_ATTR(fan0_point4, S_IRUGO | S_IWUSR, show_adc, store_fan, 18); ++static SENSOR_DEVICE_ATTR(fan0_point5, S_IRUGO | S_IWUSR, show_adc, store_fan, 19); ++ ++static struct attribute *gsp_attributes[] = { ++ &sensor_dev_attr_temp0_input.dev_attr.attr, ++ &sensor_dev_attr_in0_input.dev_attr.attr, ++ &sensor_dev_attr_in1_input.dev_attr.attr, ++ &sensor_dev_attr_in2_input.dev_attr.attr, ++ &sensor_dev_attr_in3_input.dev_attr.attr, ++ &sensor_dev_attr_in4_input.dev_attr.attr, ++ &sensor_dev_attr_in5_input.dev_attr.attr, ++ &sensor_dev_attr_in6_input.dev_attr.attr, ++ &sensor_dev_attr_in7_input.dev_attr.attr, ++ &sensor_dev_attr_in8_input.dev_attr.attr, ++ &sensor_dev_attr_in9_input.dev_attr.attr, ++ &sensor_dev_attr_in10_input.dev_attr.attr, ++ &sensor_dev_attr_in11_input.dev_attr.attr, ++ &sensor_dev_attr_in12_input.dev_attr.attr, ++ ++ &sensor_dev_attr_temp0_label.dev_attr.attr, ++ &sensor_dev_attr_in0_label.dev_attr.attr, ++ &sensor_dev_attr_in1_label.dev_attr.attr, ++ &sensor_dev_attr_in2_label.dev_attr.attr, ++ &sensor_dev_attr_in3_label.dev_attr.attr, ++ &sensor_dev_attr_in4_label.dev_attr.attr, ++ &sensor_dev_attr_in5_label.dev_attr.attr, ++ &sensor_dev_attr_in6_label.dev_attr.attr, ++ &sensor_dev_attr_in7_label.dev_attr.attr, ++ &sensor_dev_attr_in8_label.dev_attr.attr, ++ &sensor_dev_attr_in9_label.dev_attr.attr, ++ &sensor_dev_attr_in10_label.dev_attr.attr, ++ &sensor_dev_attr_in11_label.dev_attr.attr, ++ &sensor_dev_attr_in12_label.dev_attr.attr, ++ ++ &sensor_dev_attr_fan0_point0.dev_attr.attr, ++ &sensor_dev_attr_fan0_point1.dev_attr.attr, ++ &sensor_dev_attr_fan0_point2.dev_attr.attr, ++ &sensor_dev_attr_fan0_point3.dev_attr.attr, ++ &sensor_dev_attr_fan0_point4.dev_attr.attr, ++ &sensor_dev_attr_fan0_point5.dev_attr.attr, ++ NULL ++}; ++ ++ ++static int gsp_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct i2c_adapter *adapter = client->adapter; ++ struct gsp_data *data; ++ int err; ++ ++ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | ++ I2C_FUNC_SMBUS_WORD_DATA)) { ++ err = -EOPNOTSUPP; ++ goto exit; ++ } ++ ++ if (!(data = kzalloc(sizeof(struct gsp_data), GFP_KERNEL))) { ++ err = -ENOMEM; ++ goto exit; ++ } ++ ++ i2c_set_clientdata(client, data); ++ ++ data->type = id->driver_data; ++ ++ switch (data->type) { ++ case 0: ++ data->attrs.attrs = gsp_attributes; ++ break; ++ } ++ ++ dev_info(&client->dev, "%s chip found\n", client->name); ++ ++ /* Register sysfs hooks */ ++ if ((err = sysfs_create_group(&client->dev.kobj, &data->attrs))) ++ goto exit_free; ++ ++ data->hwmon_dev = hwmon_device_register(&client->dev); ++ if (IS_ERR(data->hwmon_dev)) { ++ err = PTR_ERR(data->hwmon_dev); ++ goto exit_remove; ++ } ++ ++ return 0; ++ ++exit_remove: ++ sysfs_remove_group(&client->dev.kobj, &data->attrs); ++exit_free: ++ kfree(data); ++exit: ++ return err; ++} ++ ++static int gsp_remove(struct i2c_client *client) ++{ ++ struct gsp_data *data = i2c_get_clientdata(client); ++ hwmon_device_unregister(data->hwmon_dev); ++ sysfs_remove_group(&client->dev.kobj, &data->attrs); ++ kfree(data); ++ return 0; ++} ++ ++static int __init gsp_init(void) ++{ ++ return i2c_add_driver(&gsp_driver); ++} ++ ++static void __exit gsp_exit(void) ++{ ++ i2c_del_driver(&gsp_driver); ++} ++ ++module_init(gsp_init); ++module_exit(gsp_exit); ++ ++MODULE_AUTHOR("Chris Lang "); ++MODULE_DESCRIPTION("GSC HWMON driver"); ++MODULE_LICENSE("GPL"); ++MODULE_VERSION(DRV_VERSION); ++ diff --git a/target/linux/generic/patches-3.18/890-8250_optional_sysrq.patch b/target/linux/generic/patches-3.18/890-8250_optional_sysrq.patch new file mode 100644 index 0000000..8815e4c --- /dev/null +++ b/target/linux/generic/patches-3.18/890-8250_optional_sysrq.patch @@ -0,0 +1,24 @@ +--- a/drivers/tty/serial/8250/8250_core.c ++++ b/drivers/tty/serial/8250/8250_core.c +@@ -16,7 +16,7 @@ + * membase is an 'ioremapped' cookie. + */ + +-#if defined(CONFIG_SERIAL_8250_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) ++#if defined(CONFIG_SERIAL_8250_SYSRQ) && defined(CONFIG_MAGIC_SYSRQ) + #define SUPPORT_SYSRQ + #endif + +--- a/drivers/tty/serial/8250/Kconfig ++++ b/drivers/tty/serial/8250/Kconfig +@@ -91,6 +91,10 @@ config SERIAL_8250_CONSOLE + + If unsure, say N. + ++config SERIAL_8250_SYSRQ ++ bool "Magic sysrq support on 8250/16550 devices" ++ depends on SERIAL_8250_CONSOLE ++ + config SERIAL_8250_GSC + tristate + depends on SERIAL_8250 && GSC diff --git a/target/linux/generic/patches-3.18/900-slab_maxsize.patch b/target/linux/generic/patches-3.18/900-slab_maxsize.patch new file mode 100644 index 0000000..9375305 --- /dev/null +++ b/target/linux/generic/patches-3.18/900-slab_maxsize.patch @@ -0,0 +1,13 @@ +--- a/include/linux/slab.h ++++ b/include/linux/slab.h +@@ -172,8 +172,8 @@ size_t ksize(const void *); + * to do various tricks to work around compiler limitations in order to + * ensure proper constant folding. + */ +-#define KMALLOC_SHIFT_HIGH ((MAX_ORDER + PAGE_SHIFT - 1) <= 25 ? \ +- (MAX_ORDER + PAGE_SHIFT - 1) : 25) ++#define KMALLOC_SHIFT_HIGH ((MAX_ORDER + PAGE_SHIFT - 1) <= 17 ? \ ++ (MAX_ORDER + PAGE_SHIFT - 1) : 17) + #define KMALLOC_SHIFT_MAX KMALLOC_SHIFT_HIGH + #ifndef KMALLOC_SHIFT_LOW + #define KMALLOC_SHIFT_LOW 5 diff --git a/target/linux/generic/patches-3.18/901-debloat_sock_diag.patch b/target/linux/generic/patches-3.18/901-debloat_sock_diag.patch new file mode 100644 index 0000000..99f23a0 --- /dev/null +++ b/target/linux/generic/patches-3.18/901-debloat_sock_diag.patch @@ -0,0 +1,65 @@ +--- a/net/Kconfig ++++ b/net/Kconfig +@@ -89,6 +89,9 @@ source "net/netlabel/Kconfig" + + endif # if INET + ++config SOCK_DIAG ++ bool ++ + config NETWORK_SECMARK + bool "Security Marking" + help +--- a/net/core/Makefile ++++ b/net/core/Makefile +@@ -9,8 +9,9 @@ obj-$(CONFIG_SYSCTL) += sysctl_net_core. + + obj-y += dev.o ethtool.o dev_addr_lists.o dst.o netevent.o \ + neighbour.o rtnetlink.o utils.o link_watch.o filter.o \ +- sock_diag.o dev_ioctl.o tso.o ++ dev_ioctl.o tso.o + ++obj-$(CONFIG_SOCK_DIAG) += sock_diag.o + obj-$(CONFIG_XFRM) += flow.o + obj-y += net-sysfs.o + obj-$(CONFIG_PROC_FS) += net-procfs.o +--- a/net/ipv4/Kconfig ++++ b/net/ipv4/Kconfig +@@ -419,6 +419,7 @@ config INET_LRO + + config INET_DIAG + tristate "INET: socket monitoring interface" ++ select SOCK_DIAG + default y + ---help--- + Support for INET (TCP, DCCP, etc) socket monitoring interface used by +--- a/net/unix/Kconfig ++++ b/net/unix/Kconfig +@@ -22,6 +22,7 @@ config UNIX + config UNIX_DIAG + tristate "UNIX: socket monitoring interface" + depends on UNIX ++ select SOCK_DIAG + default n + ---help--- + Support for UNIX socket monitoring interface used by the ss tool. +--- a/net/netlink/Kconfig ++++ b/net/netlink/Kconfig +@@ -13,6 +13,7 @@ config NETLINK_MMAP + + config NETLINK_DIAG + tristate "NETLINK: socket monitoring interface" ++ select SOCK_DIAG + default n + ---help--- + Support for NETLINK socket monitoring interface used by the ss tool. +--- a/net/packet/Kconfig ++++ b/net/packet/Kconfig +@@ -18,6 +18,7 @@ config PACKET + config PACKET_DIAG + tristate "Packet: sockets monitoring interface" + depends on PACKET ++ select SOCK_DIAG + default n + ---help--- + Support for PF_PACKET sockets monitoring interface used by the ss tool. diff --git a/target/linux/generic/patches-3.18/902-debloat_proc.patch b/target/linux/generic/patches-3.18/902-debloat_proc.patch new file mode 100644 index 0000000..52beed2 --- /dev/null +++ b/target/linux/generic/patches-3.18/902-debloat_proc.patch @@ -0,0 +1,341 @@ +--- a/fs/locks.c ++++ b/fs/locks.c +@@ -2611,6 +2611,8 @@ static const struct file_operations proc + + static int __init proc_locks_init(void) + { ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return 0; + proc_create("locks", 0, NULL, &proc_locks_operations); + return 0; + } +--- a/fs/proc/Kconfig ++++ b/fs/proc/Kconfig +@@ -71,3 +71,8 @@ config PROC_PAGE_MONITOR + /proc/pid/smaps, /proc/pid/clear_refs, /proc/pid/pagemap, + /proc/kpagecount, and /proc/kpageflags. Disabling these + interfaces will reduce the size of the kernel by approximately 4kb. ++ ++config PROC_STRIPPED ++ default n ++ depends on EXPERT ++ bool "Strip non-essential /proc functionality to reduce code size" +--- a/fs/proc/consoles.c ++++ b/fs/proc/consoles.c +@@ -106,6 +106,9 @@ static const struct file_operations proc + + static int __init proc_consoles_init(void) + { ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return 0; ++ + proc_create("consoles", 0, NULL, &proc_consoles_operations); + return 0; + } +--- a/fs/proc/proc_tty.c ++++ b/fs/proc/proc_tty.c +@@ -143,7 +143,10 @@ static const struct file_operations proc + void proc_tty_register_driver(struct tty_driver *driver) + { + struct proc_dir_entry *ent; +- ++ ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return; ++ + if (!driver->driver_name || driver->proc_entry || + !driver->ops->proc_fops) + return; +@@ -160,6 +163,9 @@ void proc_tty_unregister_driver(struct t + { + struct proc_dir_entry *ent; + ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return; ++ + ent = driver->proc_entry; + if (!ent) + return; +@@ -174,6 +180,9 @@ void proc_tty_unregister_driver(struct t + */ + void __init proc_tty_init(void) + { ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return; ++ + if (!proc_mkdir("tty", NULL)) + return; + proc_mkdir("tty/ldisc", NULL); /* Preserved: it's userspace visible */ +--- a/kernel/exec_domain.c ++++ b/kernel/exec_domain.c +@@ -176,6 +176,8 @@ static const struct file_operations exec + + static int __init proc_execdomains_init(void) + { ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return 0; + proc_create("execdomains", 0, NULL, &execdomains_proc_fops); + return 0; + } +--- a/kernel/irq/proc.c ++++ b/kernel/irq/proc.c +@@ -328,6 +328,9 @@ void register_irq_proc(unsigned int irq, + { + char name [MAX_NAMELEN]; + ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED) && !IS_ENABLED(CONFIG_SMP)) ++ return; ++ + if (!root_irq_dir || (desc->irq_data.chip == &no_irq_chip) || desc->dir) + return; + +@@ -364,6 +367,9 @@ void unregister_irq_proc(unsigned int ir + { + char name [MAX_NAMELEN]; + ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED) && !IS_ENABLED(CONFIG_SMP)) ++ return; ++ + if (!root_irq_dir || !desc->dir) + return; + #ifdef CONFIG_SMP +@@ -399,6 +405,9 @@ void init_irq_proc(void) + unsigned int irq; + struct irq_desc *desc; + ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED) && !IS_ENABLED(CONFIG_SMP)) ++ return; ++ + /* create /proc/irq */ + root_irq_dir = proc_mkdir("irq", NULL); + if (!root_irq_dir) +--- a/kernel/time/timer_list.c ++++ b/kernel/time/timer_list.c +@@ -362,6 +362,8 @@ static int __init init_timer_list_procfs + { + struct proc_dir_entry *pe; + ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return 0; + pe = proc_create("timer_list", 0444, NULL, &timer_list_fops); + if (!pe) + return -ENOMEM; +--- a/mm/vmalloc.c ++++ b/mm/vmalloc.c +@@ -2662,6 +2662,8 @@ static const struct file_operations proc + + static int __init proc_vmalloc_init(void) + { ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return 0; + proc_create("vmallocinfo", S_IRUSR, NULL, &proc_vmalloc_operations); + return 0; + } +--- a/mm/vmstat.c ++++ b/mm/vmstat.c +@@ -1424,10 +1424,12 @@ static int __init setup_vmstat(void) + cpu_notifier_register_done(); + #endif + #ifdef CONFIG_PROC_FS +- proc_create("buddyinfo", S_IRUGO, NULL, &fragmentation_file_operations); +- proc_create("pagetypeinfo", S_IRUGO, NULL, &pagetypeinfo_file_ops); ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) { ++ proc_create("buddyinfo", S_IRUGO, NULL, &fragmentation_file_operations); ++ proc_create("pagetypeinfo", S_IRUGO, NULL, &pagetypeinfo_file_ops); ++ proc_create("zoneinfo", S_IRUGO, NULL, &proc_zoneinfo_file_operations); ++ } + proc_create("vmstat", S_IRUGO, NULL, &proc_vmstat_file_operations); +- proc_create("zoneinfo", S_IRUGO, NULL, &proc_zoneinfo_file_operations); + #endif + return 0; + } +--- a/net/8021q/vlanproc.c ++++ b/net/8021q/vlanproc.c +@@ -127,6 +127,9 @@ void vlan_proc_cleanup(struct net *net) + { + struct vlan_net *vn = net_generic(net, vlan_net_id); + ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return; ++ + if (vn->proc_vlan_conf) + remove_proc_entry(name_conf, vn->proc_vlan_dir); + +@@ -146,6 +149,9 @@ int __net_init vlan_proc_init(struct net + { + struct vlan_net *vn = net_generic(net, vlan_net_id); + ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return 0; ++ + vn->proc_vlan_dir = proc_net_mkdir(net, name_root, net->proc_net); + if (!vn->proc_vlan_dir) + goto err; +--- a/net/core/sock.c ++++ b/net/core/sock.c +@@ -2934,6 +2934,8 @@ static __net_initdata struct pernet_oper + + static int __init proto_init(void) + { ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return 0; + return register_pernet_subsys(&proto_net_ops); + } + +--- a/net/ipv4/fib_trie.c ++++ b/net/ipv4/fib_trie.c +@@ -2490,10 +2490,12 @@ static const struct file_operations fib_ + + int __net_init fib_proc_init(struct net *net) + { +- if (!proc_create("fib_trie", S_IRUGO, net->proc_net, &fib_trie_fops)) ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED) && ++ !proc_create("fib_trie", S_IRUGO, net->proc_net, &fib_trie_fops)) + goto out1; + +- if (!proc_create("fib_triestat", S_IRUGO, net->proc_net, ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED) && ++ !proc_create("fib_triestat", S_IRUGO, net->proc_net, + &fib_triestat_fops)) + goto out2; + +@@ -2503,17 +2505,21 @@ int __net_init fib_proc_init(struct net + return 0; + + out3: +- remove_proc_entry("fib_triestat", net->proc_net); ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ remove_proc_entry("fib_triestat", net->proc_net); + out2: +- remove_proc_entry("fib_trie", net->proc_net); ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ remove_proc_entry("fib_trie", net->proc_net); + out1: + return -ENOMEM; + } + + void __net_exit fib_proc_exit(struct net *net) + { +- remove_proc_entry("fib_trie", net->proc_net); +- remove_proc_entry("fib_triestat", net->proc_net); ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) { ++ remove_proc_entry("fib_trie", net->proc_net); ++ remove_proc_entry("fib_triestat", net->proc_net); ++ } + remove_proc_entry("route", net->proc_net); + } + +--- a/net/ipv4/proc.c ++++ b/net/ipv4/proc.c +@@ -524,6 +524,9 @@ static __net_initdata struct pernet_oper + + int __init ip_misc_proc_init(void) + { ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return 0; ++ + return register_pernet_subsys(&ip_proc_ops); + } + +--- a/net/ipv4/route.c ++++ b/net/ipv4/route.c +@@ -416,6 +416,9 @@ static struct pernet_operations ip_rt_pr + + static int __init ip_rt_proc_init(void) + { ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return 0; ++ + return register_pernet_subsys(&ip_rt_proc_ops); + } + +--- a/ipc/msg.c ++++ b/ipc/msg.c +@@ -1072,6 +1072,9 @@ void __init msg_init(void) + printk(KERN_INFO "msgmni has been set to %d\n", + init_ipc_ns.msg_ctlmni); + ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return; ++ + ipc_init_proc_interface("sysvipc/msg", + " key msqid perms cbytes qnum lspid lrpid uid gid cuid cgid stime rtime ctime\n", + IPC_MSG_IDS, sysvipc_msg_proc_show); +--- a/ipc/sem.c ++++ b/ipc/sem.c +@@ -191,6 +191,8 @@ void sem_exit_ns(struct ipc_namespace *n + void __init sem_init(void) + { + sem_init_ns(&init_ipc_ns); ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return; + ipc_init_proc_interface("sysvipc/sem", + " key semid perms nsems uid gid cuid cgid otime ctime\n", + IPC_SEM_IDS, sysvipc_sem_proc_show); +--- a/ipc/shm.c ++++ b/ipc/shm.c +@@ -118,6 +118,8 @@ pure_initcall(ipc_ns_init); + + void __init shm_init(void) + { ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return; + ipc_init_proc_interface("sysvipc/shm", + #if BITS_PER_LONG <= 32 + " key shmid perms size cpid lpid nattch uid gid cuid cgid atime dtime ctime rss swap\n", +--- a/ipc/util.c ++++ b/ipc/util.c +@@ -161,6 +161,9 @@ void __init ipc_init_proc_interface(cons + struct proc_dir_entry *pde; + struct ipc_proc_iface *iface; + ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return; ++ + iface = kmalloc(sizeof(*iface), GFP_KERNEL); + if (!iface) + return; +--- a/net/core/net-procfs.c ++++ b/net/core/net-procfs.c +@@ -318,10 +318,12 @@ static int __net_init dev_proc_net_init( + + if (!proc_create("dev", S_IRUGO, net->proc_net, &dev_seq_fops)) + goto out; +- if (!proc_create("softnet_stat", S_IRUGO, net->proc_net, ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED) && ++ !proc_create("softnet_stat", S_IRUGO, net->proc_net, + &softnet_seq_fops)) + goto out_dev; +- if (!proc_create("ptype", S_IRUGO, net->proc_net, &ptype_seq_fops)) ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED) && ++ !proc_create("ptype", S_IRUGO, net->proc_net, &ptype_seq_fops)) + goto out_softnet; + + if (wext_proc_init(net)) +@@ -330,9 +332,11 @@ static int __net_init dev_proc_net_init( + out: + return rc; + out_ptype: +- remove_proc_entry("ptype", net->proc_net); ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ remove_proc_entry("ptype", net->proc_net); + out_softnet: +- remove_proc_entry("softnet_stat", net->proc_net); ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ remove_proc_entry("softnet_stat", net->proc_net); + out_dev: + remove_proc_entry("dev", net->proc_net); + goto out; +@@ -342,8 +346,10 @@ static void __net_exit dev_proc_net_exit + { + wext_proc_exit(net); + +- remove_proc_entry("ptype", net->proc_net); +- remove_proc_entry("softnet_stat", net->proc_net); ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) { ++ remove_proc_entry("ptype", net->proc_net); ++ remove_proc_entry("softnet_stat", net->proc_net); ++ } + remove_proc_entry("dev", net->proc_net); + } + diff --git a/target/linux/generic/patches-3.18/903-debloat_direct_io.patch b/target/linux/generic/patches-3.18/903-debloat_direct_io.patch new file mode 100644 index 0000000..c633ed1 --- /dev/null +++ b/target/linux/generic/patches-3.18/903-debloat_direct_io.patch @@ -0,0 +1,83 @@ +--- a/fs/Kconfig ++++ b/fs/Kconfig +@@ -62,6 +62,11 @@ config FILE_LOCKING + for filesystems like NFS and for the flock() system + call. Disabling this option saves about 11k. + ++config DIRECT_IO ++ bool "Enable O_DIRECT support" if EXPERT ++ depends on BLOCK ++ default y ++ + source "fs/notify/Kconfig" + + source "fs/quota/Kconfig" +--- a/fs/Makefile ++++ b/fs/Makefile +@@ -14,7 +14,8 @@ obj-y := open.o read_write.o file_table. + stack.o fs_struct.o statfs.o fs_pin.o + + ifeq ($(CONFIG_BLOCK),y) +-obj-y += buffer.o block_dev.o direct-io.o mpage.o ++obj-y += buffer.o block_dev.o mpage.o ++obj-$(CONFIG_DIRECT_IO) += direct-io.o + else + obj-y += no-block.o + endif +--- a/include/linux/fs.h ++++ b/include/linux/fs.h +@@ -2530,12 +2530,25 @@ enum { + DIO_ASYNC_EXTEND = 0x04, + }; + ++#ifdef CONFIG_DIRECT_IO + void dio_end_io(struct bio *bio, int error); + + ssize_t __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, + struct block_device *bdev, struct iov_iter *iter, loff_t offset, + get_block_t get_block, dio_iodone_t end_io, + dio_submit_t submit_io, int flags); ++#else ++static inline void dio_end_io(struct bio *bio, int error) ++{ ++} ++static inline ssize_t __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, ++ struct block_device *bdev, struct iov_iter *iter, loff_t offset, ++ get_block_t get_block, dio_iodone_t end_io, ++ dio_submit_t submit_io, int flags) ++{ ++ return -EOPNOTSUPP; ++} ++#endif + + static inline ssize_t blockdev_direct_IO(int rw, struct kiocb *iocb, + struct inode *inode, struct iov_iter *iter, loff_t offset, +--- a/fs/fcntl.c ++++ b/fs/fcntl.c +@@ -52,8 +52,10 @@ static int setfl(int fd, struct file * f + arg |= O_NONBLOCK; + + if (arg & O_DIRECT) { ++#ifdef CONFIG_DIRECT_IO + if (!filp->f_mapping || !filp->f_mapping->a_ops || + !filp->f_mapping->a_ops->direct_IO) ++#endif + return -EINVAL; + } + +--- a/fs/open.c ++++ b/fs/open.c +@@ -655,9 +655,12 @@ int open_check_o_direct(struct file *f) + { + /* NB: we're sure to have correct a_ops only after f_op->open */ + if (f->f_flags & O_DIRECT) { ++#ifdef CONFIG_DIRECT_IO + if (!f->f_mapping->a_ops || + ((!f->f_mapping->a_ops->direct_IO) && +- (!f->f_mapping->a_ops->get_xip_mem))) { ++ (!f->f_mapping->a_ops->get_xip_mem))) ++#endif ++ { + return -EINVAL; + } + } diff --git a/target/linux/generic/patches-3.18/910-kobject_uevent.patch b/target/linux/generic/patches-3.18/910-kobject_uevent.patch new file mode 100644 index 0000000..f69294b --- /dev/null +++ b/target/linux/generic/patches-3.18/910-kobject_uevent.patch @@ -0,0 +1,21 @@ +--- a/lib/kobject_uevent.c ++++ b/lib/kobject_uevent.c +@@ -53,6 +53,18 @@ static const char *kobject_actions[] = { + [KOBJ_OFFLINE] = "offline", + }; + ++u64 uevent_next_seqnum(void) ++{ ++ u64 seq; ++ ++ mutex_lock(&uevent_sock_mutex); ++ seq = ++uevent_seqnum; ++ mutex_unlock(&uevent_sock_mutex); ++ ++ return seq; ++} ++EXPORT_SYMBOL_GPL(uevent_next_seqnum); ++ + /** + * kobject_action_type - translate action string to numeric type + * diff --git a/target/linux/generic/patches-3.18/911-kobject_add_broadcast_uevent.patch b/target/linux/generic/patches-3.18/911-kobject_add_broadcast_uevent.patch new file mode 100644 index 0000000..6e4c140 --- /dev/null +++ b/target/linux/generic/patches-3.18/911-kobject_add_broadcast_uevent.patch @@ -0,0 +1,65 @@ +--- a/include/linux/kobject.h ++++ b/include/linux/kobject.h +@@ -32,6 +32,8 @@ + #define UEVENT_NUM_ENVP 32 /* number of env pointers */ + #define UEVENT_BUFFER_SIZE 2048 /* buffer for the variables */ + ++struct sk_buff; ++ + #ifdef CONFIG_UEVENT_HELPER + /* path to the userspace helper executed on an event */ + extern char uevent_helper[]; +@@ -221,4 +223,7 @@ int add_uevent_var(struct kobj_uevent_en + int kobject_action_type(const char *buf, size_t count, + enum kobject_action *type); + ++int broadcast_uevent(struct sk_buff *skb, __u32 pid, __u32 group, ++ gfp_t allocation); ++ + #endif /* _KOBJECT_H_ */ +--- a/lib/kobject_uevent.c ++++ b/lib/kobject_uevent.c +@@ -424,6 +424,43 @@ int add_uevent_var(struct kobj_uevent_en + EXPORT_SYMBOL_GPL(add_uevent_var); + + #if defined(CONFIG_NET) ++int broadcast_uevent(struct sk_buff *skb, __u32 pid, __u32 group, ++ gfp_t allocation) ++{ ++ struct uevent_sock *ue_sk; ++ int err = 0; ++ ++ /* send netlink message */ ++ mutex_lock(&uevent_sock_mutex); ++ list_for_each_entry(ue_sk, &uevent_sock_list, list) { ++ struct sock *uevent_sock = ue_sk->sk; ++ struct sk_buff *skb2; ++ ++ skb2 = skb_clone(skb, allocation); ++ if (!skb2) ++ break; ++ ++ err = netlink_broadcast(uevent_sock, skb2, pid, group, ++ allocation); ++ if (err) ++ break; ++ } ++ mutex_unlock(&uevent_sock_mutex); ++ ++ kfree_skb(skb); ++ return err; ++} ++#else ++int broadcast_uevent(struct sk_buff *skb, __u32 pid, __u32 group, ++ gfp_t allocation) ++{ ++ kfree_skb(skb); ++ return 0; ++} ++#endif ++EXPORT_SYMBOL_GPL(broadcast_uevent); ++ ++#if defined(CONFIG_NET) + static int uevent_net_init(struct net *net) + { + struct uevent_sock *ue_sk; diff --git a/target/linux/generic/patches-3.18/921-use_preinit_as_init.patch b/target/linux/generic/patches-3.18/921-use_preinit_as_init.patch new file mode 100644 index 0000000..57c2fe2 --- /dev/null +++ b/target/linux/generic/patches-3.18/921-use_preinit_as_init.patch @@ -0,0 +1,12 @@ +--- a/init/main.c ++++ b/init/main.c +@@ -963,7 +963,8 @@ static int __ref kernel_init(void *unuse + pr_err("Failed to execute %s (error %d). Attempting defaults...\n", + execute_command, ret); + } +- if (!try_to_run_init_process("/sbin/init") || ++ if (!try_to_run_init_process("/etc/preinit") || ++ !try_to_run_init_process("/sbin/init") || + !try_to_run_init_process("/etc/init") || + !try_to_run_init_process("/bin/init") || + !try_to_run_init_process("/bin/sh")) diff --git a/target/linux/generic/patches-3.18/922-always-create-console-node-in-initramfs.patch b/target/linux/generic/patches-3.18/922-always-create-console-node-in-initramfs.patch new file mode 100644 index 0000000..988de35 --- /dev/null +++ b/target/linux/generic/patches-3.18/922-always-create-console-node-in-initramfs.patch @@ -0,0 +1,30 @@ +--- a/scripts/gen_initramfs_list.sh ++++ b/scripts/gen_initramfs_list.sh +@@ -59,6 +59,18 @@ default_initramfs() { + EOF + } + ++list_openwrt_initramfs() { ++ : ++} ++ ++openwrt_initramfs() { ++ # make sure that /dev/console exists ++ cat <<-EOF >> ${output} ++ dir /dev 0755 0 0 ++ nod /dev/console 0600 0 0 c 5 1 ++ EOF ++} ++ + filetype() { + local argv1="$1" + +@@ -177,6 +189,8 @@ dir_filelist() { + if [ "$(echo "${dirlist}" | wc -l)" -gt 1 ]; then + ${dep_list}print_mtime "$1" + ++ ${dep_list}openwrt_initramfs ++ + echo "${dirlist}" | \ + while read x; do + ${dep_list}parse ${x} diff --git a/target/linux/generic/patches-3.18/930-crashlog.patch b/target/linux/generic/patches-3.18/930-crashlog.patch new file mode 100644 index 0000000..b1c38a7 --- /dev/null +++ b/target/linux/generic/patches-3.18/930-crashlog.patch @@ -0,0 +1,276 @@ +--- /dev/null ++++ b/include/linux/crashlog.h +@@ -0,0 +1,17 @@ ++#ifndef __CRASHLOG_H ++#define __CRASHLOG_H ++ ++#ifdef CONFIG_CRASHLOG ++void crashlog_init_bootmem(struct bootmem_data *bdata); ++void crashlog_init_memblock(phys_addr_t addr, phys_addr_t size); ++#else ++static inline void crashlog_init_bootmem(struct bootmem_data *bdata) ++{ ++} ++ ++static inline void crashlog_init_memblock(phys_addr_t addr, phys_addr_t size) ++{ ++} ++#endif ++ ++#endif +--- a/init/Kconfig ++++ b/init/Kconfig +@@ -1279,6 +1279,10 @@ config RELAY + + If unsure, say N. + ++config CRASHLOG ++ bool "Crash logging" ++ depends on (!NO_BOOTMEM || HAVE_MEMBLOCK) && !(ARM || SPARC || PPC) ++ + config BLK_DEV_INITRD + bool "Initial RAM filesystem and RAM disk (initramfs/initrd) support" + depends on BROKEN || !FRV +--- a/kernel/Makefile ++++ b/kernel/Makefile +@@ -96,6 +96,7 @@ obj-$(CONFIG_CRASH_DUMP) += crash_dump.o + obj-$(CONFIG_JUMP_LABEL) += jump_label.o + obj-$(CONFIG_CONTEXT_TRACKING) += context_tracking.o + obj-$(CONFIG_TORTURE_TEST) += torture.o ++obj-$(CONFIG_CRASHLOG) += crashlog.o + + $(obj)/configs.o: $(obj)/config_data.h + +--- /dev/null ++++ b/kernel/crashlog.c +@@ -0,0 +1,181 @@ ++/* ++ * Crash information logger ++ * Copyright (C) 2010 Felix Fietkau ++ * ++ * Based on ramoops.c ++ * Copyright (C) 2010 Marco Stornelli ++ * ++ * 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 ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define CRASHLOG_PAGES 4 ++#define CRASHLOG_SIZE (CRASHLOG_PAGES * PAGE_SIZE) ++#define CRASHLOG_MAGIC 0xa1eedead ++ ++/* ++ * Start the log at 1M before the end of RAM, as some boot loaders like ++ * to use the end of the RAM for stack usage and other things ++ * If this fails, fall back to using the last part. ++ */ ++#define CRASHLOG_OFFSET (1024 * 1024) ++ ++struct crashlog_data { ++ u32 magic; ++ u32 len; ++ u8 data[]; ++}; ++ ++static struct debugfs_blob_wrapper crashlog_blob; ++static unsigned long crashlog_addr = 0; ++static struct crashlog_data *crashlog_buf; ++static struct kmsg_dumper dump; ++static bool first = true; ++ ++extern struct list_head *crashlog_modules; ++ ++#ifndef CONFIG_NO_BOOTMEM ++void __init crashlog_init_bootmem(bootmem_data_t *bdata) ++{ ++ unsigned long addr; ++ ++ if (crashlog_addr) ++ return; ++ ++ addr = PFN_PHYS(bdata->node_low_pfn) - CRASHLOG_OFFSET; ++ if (reserve_bootmem(addr, CRASHLOG_SIZE, BOOTMEM_EXCLUSIVE) < 0) { ++ printk("Crashlog failed to allocate RAM at address 0x%lx\n", addr); ++ bdata->node_low_pfn -= CRASHLOG_PAGES; ++ addr = PFN_PHYS(bdata->node_low_pfn); ++ } ++ crashlog_addr = addr; ++} ++#endif ++ ++#ifdef CONFIG_HAVE_MEMBLOCK ++void __meminit crashlog_init_memblock(phys_addr_t addr, phys_addr_t size) ++{ ++ if (crashlog_addr) ++ return; ++ ++ addr += size - CRASHLOG_OFFSET; ++ if (memblock_reserve(addr, CRASHLOG_SIZE)) { ++ printk("Crashlog failed to allocate RAM at address 0x%lx\n", (unsigned long) addr); ++ return; ++ } ++ ++ crashlog_addr = addr; ++} ++#endif ++ ++static void __init crashlog_copy(void) ++{ ++ if (crashlog_buf->magic != CRASHLOG_MAGIC) ++ return; ++ ++ if (!crashlog_buf->len || crashlog_buf->len > ++ CRASHLOG_SIZE - sizeof(*crashlog_buf)) ++ return; ++ ++ crashlog_blob.size = crashlog_buf->len; ++ crashlog_blob.data = kmemdup(crashlog_buf->data, ++ crashlog_buf->len, GFP_KERNEL); ++ ++ debugfs_create_blob("crashlog", 0700, NULL, &crashlog_blob); ++} ++ ++static int get_maxlen(void) ++{ ++ return CRASHLOG_SIZE - sizeof(*crashlog_buf) - crashlog_buf->len; ++} ++ ++static void crashlog_printf(const char *fmt, ...) ++{ ++ va_list args; ++ int len = get_maxlen(); ++ ++ if (!len) ++ return; ++ ++ va_start(args, fmt); ++ crashlog_buf->len += vscnprintf( ++ &crashlog_buf->data[crashlog_buf->len], ++ len, fmt, args); ++ va_end(args); ++} ++ ++static void crashlog_do_dump(struct kmsg_dumper *dumper, ++ enum kmsg_dump_reason reason) ++{ ++ struct timeval tv; ++ struct module *m; ++ char *buf; ++ size_t len; ++ ++ if (!first) ++ crashlog_printf("\n===================================\n"); ++ ++ do_gettimeofday(&tv); ++ crashlog_printf("Time: %lu.%lu\n", ++ (long)tv.tv_sec, (long)tv.tv_usec); ++ ++ if (first) { ++ crashlog_printf("Modules:"); ++ list_for_each_entry(m, crashlog_modules, list) { ++ crashlog_printf("\t%s@%p+%x", m->name, ++ m->module_core, m->core_size, ++ m->module_init, m->init_size); ++ } ++ crashlog_printf("\n"); ++ first = false; ++ } ++ ++ buf = (char *)&crashlog_buf->data[crashlog_buf->len]; ++ ++ kmsg_dump_get_buffer(dumper, true, buf, get_maxlen(), &len); ++ ++ crashlog_buf->len += len; ++} ++ ++ ++int __init crashlog_init_fs(void) ++{ ++ if (!crashlog_addr) ++ return -ENOMEM; ++ ++ crashlog_buf = ioremap(crashlog_addr, CRASHLOG_SIZE); ++ ++ crashlog_copy(); ++ ++ crashlog_buf->magic = CRASHLOG_MAGIC; ++ crashlog_buf->len = 0; ++ ++ dump.max_reason = KMSG_DUMP_OOPS; ++ dump.dump = crashlog_do_dump; ++ kmsg_dump_register(&dump); ++ ++ return 0; ++} ++module_init(crashlog_init_fs); +--- a/mm/bootmem.c ++++ b/mm/bootmem.c +@@ -15,6 +15,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -177,6 +178,7 @@ static unsigned long __init free_all_boo + if (!bdata->node_bootmem_map) + return 0; + ++ crashlog_init_bootmem(bdata); + map = bdata->node_bootmem_map; + start = bdata->node_min_pfn; + end = bdata->node_low_pfn; +--- a/kernel/module.c ++++ b/kernel/module.c +@@ -105,6 +105,9 @@ static LIST_HEAD(modules); + #ifdef CONFIG_KGDB_KDB + struct list_head *kdb_modules = &modules; /* kdb needs the list of modules */ + #endif /* CONFIG_KGDB_KDB */ ++#ifdef CONFIG_CRASHLOG ++struct list_head *crashlog_modules = &modules; ++#endif + + #ifdef CONFIG_MODULE_SIG + #ifdef CONFIG_MODULE_SIG_FORCE +--- a/mm/memblock.c ++++ b/mm/memblock.c +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -477,6 +478,8 @@ static void __init_memblock memblock_ins + memblock_set_region_node(rgn, nid); + type->cnt++; + type->total_size += size; ++ if (type == &memblock.memory && idx == 0) ++ crashlog_init_memblock(base, size); + } + + /** diff --git a/target/linux/generic/patches-3.18/940-ocf_kbuild_integration.patch b/target/linux/generic/patches-3.18/940-ocf_kbuild_integration.patch new file mode 100644 index 0000000..240f15e --- /dev/null +++ b/target/linux/generic/patches-3.18/940-ocf_kbuild_integration.patch @@ -0,0 +1,20 @@ +--- a/crypto/Kconfig ++++ b/crypto/Kconfig +@@ -1519,3 +1519,6 @@ source "drivers/crypto/Kconfig" + source crypto/asymmetric_keys/Kconfig + + endif # if CRYPTO ++ ++source "crypto/ocf/Kconfig" ++ +--- a/crypto/Makefile ++++ b/crypto/Makefile +@@ -101,6 +101,8 @@ obj-$(CONFIG_CRYPTO_USER_API) += af_alg. + obj-$(CONFIG_CRYPTO_USER_API_HASH) += algif_hash.o + obj-$(CONFIG_CRYPTO_USER_API_SKCIPHER) += algif_skcipher.o + ++obj-$(CONFIG_OCF_OCF) += ocf/ ++ + # + # generic algorithms and the async_tx api + # diff --git a/target/linux/generic/patches-3.18/941-ocf_20120127.patch b/target/linux/generic/patches-3.18/941-ocf_20120127.patch new file mode 100644 index 0000000..ee36f1e --- /dev/null +++ b/target/linux/generic/patches-3.18/941-ocf_20120127.patch @@ -0,0 +1,166 @@ +--- a/drivers/char/random.c ++++ b/drivers/char/random.c +@@ -139,6 +139,9 @@ + * that might otherwise be identical and have very little entropy + * available to them (particularly common in the embedded world). + * ++ * void random_input_words(__u32 *buf, size_t wordcount, int ent_count) ++ * int random_input_wait(void); ++ * + * add_input_randomness() uses the input layer interrupt timing, as well as + * the event type information from the hardware. + * +@@ -152,6 +155,13 @@ + * seek times do not make for good sources of entropy, as their seek + * times are usually fairly consistent. + * ++ * random_input_words() just provides a raw block of entropy to the input ++ * pool, such as from a hardware entropy generator. ++ * ++ * random_input_wait() suspends the caller until such time as the ++ * entropy pool falls below the write threshold, and returns a count of how ++ * much entropy (in bits) is needed to sustain the pool. ++ * + * All of these routines try to estimate how many bits of randomness a + * particular randomness source. They do this by keeping track of the + * first and second order deltas of the event timings. +@@ -938,6 +948,63 @@ void add_disk_randomness(struct gendisk + EXPORT_SYMBOL_GPL(add_disk_randomness); + #endif + ++/* ++ * random_input_words - add bulk entropy to pool ++ * ++ * @buf: buffer to add ++ * @wordcount: number of __u32 words to add ++ * @ent_count: total amount of entropy (in bits) to credit ++ * ++ * this provides bulk input of entropy to the input pool ++ * ++ */ ++void random_input_words(__u32 *buf, size_t wordcount, int ent_count) ++{ ++ mix_pool_bytes(&input_pool, buf, wordcount*4); ++ ++ credit_entropy_bits(&input_pool, ent_count); ++ ++ pr_notice("crediting %d bits => %d\n", ++ ent_count, input_pool.entropy_count); ++ /* ++ * Wake up waiting processes if we have enough ++ * entropy. ++ */ ++ if (input_pool.entropy_count >= random_read_wakeup_bits) ++ wake_up_interruptible(&random_read_wait); ++} ++EXPORT_SYMBOL(random_input_words); ++ ++/* ++ * random_input_wait - wait until random needs entropy ++ * ++ * this function sleeps until the /dev/random subsystem actually ++ * needs more entropy, and then return the amount of entropy ++ * that it would be nice to have added to the system. ++ */ ++int random_input_wait(void) ++{ ++ int count; ++ ++ wait_event_interruptible(random_write_wait, ++ input_pool.entropy_count < random_write_wakeup_bits); ++ ++ count = random_write_wakeup_bits - input_pool.entropy_count; ++ ++ /* likely we got woken up due to a signal */ ++ if (count <= 0) count = random_read_wakeup_bits; ++ ++ pr_notice("requesting %d bits from input_wait()er %d<%d\n", ++ count, ++ input_pool.entropy_count, random_write_wakeup_bits); ++ ++ return count; ++} ++EXPORT_SYMBOL(random_input_wait); ++ ++ ++#define EXTRACT_SIZE 10 ++ + /********************************************************************* + * + * Entropy extraction routines +--- a/fs/fcntl.c ++++ b/fs/fcntl.c +@@ -140,6 +140,7 @@ pid_t f_getown(struct file *filp) + read_unlock(&filp->f_owner.lock); + return pid; + } ++EXPORT_SYMBOL(sys_dup); + + static int f_setown_ex(struct file *filp, unsigned long arg) + { +--- a/include/linux/miscdevice.h ++++ b/include/linux/miscdevice.h +@@ -19,6 +19,7 @@ + #define APOLLO_MOUSE_MINOR 7 /* unused */ + #define PC110PAD_MINOR 9 /* unused */ + /*#define ADB_MOUSE_MINOR 10 FIXME OBSOLETE */ ++#define CRYPTODEV_MINOR 70 /* /dev/crypto */ + #define WATCHDOG_MINOR 130 /* Watchdog timer */ + #define TEMP_MINOR 131 /* Temperature Sensor */ + #define RTC_MINOR 135 +--- a/include/uapi/linux/random.h ++++ b/include/uapi/linux/random.h +@@ -34,6 +34,30 @@ + /* Clear the entropy pool and associated counters. (Superuser only.) */ + #define RNDCLEARPOOL _IO( 'R', 0x06 ) + ++#ifdef CONFIG_FIPS_RNG ++ ++/* Size of seed value - equal to AES blocksize */ ++#define AES_BLOCK_SIZE_BYTES 16 ++#define SEED_SIZE_BYTES AES_BLOCK_SIZE_BYTES ++/* Size of AES key */ ++#define KEY_SIZE_BYTES 16 ++ ++/* ioctl() structure used by FIPS 140-2 Tests */ ++struct rand_fips_test { ++ unsigned char key[KEY_SIZE_BYTES]; /* Input */ ++ unsigned char datetime[SEED_SIZE_BYTES]; /* Input */ ++ unsigned char seed[SEED_SIZE_BYTES]; /* Input */ ++ unsigned char result[SEED_SIZE_BYTES]; /* Output */ ++}; ++ ++/* FIPS 140-2 RNG Variable Seed Test. (Superuser only.) */ ++#define RNDFIPSVST _IOWR('R', 0x10, struct rand_fips_test) ++ ++/* FIPS 140-2 RNG Monte Carlo Test. (Superuser only.) */ ++#define RNDFIPSMCT _IOWR('R', 0x11, struct rand_fips_test) ++ ++#endif /* #ifdef CONFIG_FIPS_RNG */ ++ + struct rand_pool_info { + int entropy_count; + int buf_size; +--- a/include/linux/random.h ++++ b/include/linux/random.h +@@ -13,6 +13,10 @@ extern void add_input_randomness(unsigne + unsigned int value); + extern void add_interrupt_randomness(int irq, int irq_flags); + ++extern void random_input_words(__u32 *buf, size_t wordcount, int ent_count); ++extern int random_input_wait(void); ++#define HAS_RANDOM_INPUT_WAIT 1 ++ + extern void get_random_bytes(void *buf, int nbytes); + extern void get_random_bytes_arch(void *buf, int nbytes); + void generate_random_uuid(unsigned char uuid_out[16]); +--- a/kernel/pid.c ++++ b/kernel/pid.c +@@ -427,6 +427,7 @@ void transfer_pid(struct task_struct *ol + new->pids[type].pid = old->pids[type].pid; + hlist_replace_rcu(&old->pids[type].node, &new->pids[type].node); + } ++EXPORT_SYMBOL(find_task_by_vpid); + + struct task_struct *pid_task(struct pid *pid, enum pid_type type) + { diff --git a/target/linux/generic/patches-3.18/960-decompress_unlzo_fix.patch b/target/linux/generic/patches-3.18/960-decompress_unlzo_fix.patch new file mode 100644 index 0000000..ee7c118 --- /dev/null +++ b/target/linux/generic/patches-3.18/960-decompress_unlzo_fix.patch @@ -0,0 +1,23 @@ +--- /dev/null ++++ b/include/linux/decompress/unlzo_mm.h +@@ -0,0 +1,10 @@ ++#ifndef UNLZO_MM_H ++#define UNLZO_MM_H ++ ++#ifdef STATIC ++#define INIT ++#else ++#define INIT __init ++#endif ++ ++#endif +--- a/lib/decompress_unlzo.c ++++ b/lib/decompress_unlzo.c +@@ -38,6 +38,7 @@ + + #include + #include ++#include + #include + + #include diff --git a/target/linux/generic/patches-3.18/970-remove-unsane-filenames-from-deps_initramfs-list.patch b/target/linux/generic/patches-3.18/970-remove-unsane-filenames-from-deps_initramfs-list.patch new file mode 100644 index 0000000..ac13c9e --- /dev/null +++ b/target/linux/generic/patches-3.18/970-remove-unsane-filenames-from-deps_initramfs-list.patch @@ -0,0 +1,29 @@ +--- a/usr/Makefile ++++ b/usr/Makefile +@@ -53,6 +53,8 @@ ifneq ($(wildcard $(obj)/.initramfs_data + include $(obj)/.initramfs_data.cpio.d + endif + ++deps_initramfs_sane := $(foreach v,$(deps_initramfs),$(if $(findstring :,$(v)),,$(v))) ++ + quiet_cmd_initfs = GEN $@ + cmd_initfs = $(initramfs) -o $@ $(ramfs-args) $(ramfs-input) + +@@ -61,14 +63,14 @@ targets := initramfs_data.cpio.gz initra + initramfs_data.cpio.lzo initramfs_data.cpio.lz4 \ + initramfs_data.cpio + # do not try to update files included in initramfs +-$(deps_initramfs): ; ++$(deps_initramfs_sane): ; + +-$(deps_initramfs): klibcdirs ++$(deps_initramfs_sane): klibcdirs + # We rebuild initramfs_data.cpio if: + # 1) Any included file is newer then initramfs_data.cpio + # 2) There are changes in which files are included (added or deleted) + # 3) If gen_init_cpio are newer than initramfs_data.cpio + # 4) arguments to gen_initramfs.sh changes +-$(obj)/initramfs_data.cpio$(suffix_y): $(obj)/gen_init_cpio $(deps_initramfs) klibcdirs ++$(obj)/initramfs_data.cpio$(suffix_y): $(obj)/gen_init_cpio $(deps_initramfs_sane) klibcdirs + $(Q)$(initramfs) -l $(ramfs-input) > $(obj)/.initramfs_data.cpio.d + $(call if_changed,initfs) diff --git a/target/linux/generic/patches-3.18/980-arm_openwrt_machtypes.patch b/target/linux/generic/patches-3.18/980-arm_openwrt_machtypes.patch new file mode 100644 index 0000000..5e9718b --- /dev/null +++ b/target/linux/generic/patches-3.18/980-arm_openwrt_machtypes.patch @@ -0,0 +1,32 @@ +--- a/arch/arm/tools/mach-types ++++ b/arch/arm/tools/mach-types +@@ -1007,3 +1007,29 @@ eco5_bx2 MACH_ECO5_BX2 ECO5_BX2 4572 + eukrea_cpuimx28sd MACH_EUKREA_CPUIMX28SD EUKREA_CPUIMX28SD 4573 + domotab MACH_DOMOTAB DOMOTAB 4574 + pfla03 MACH_PFLA03 PFLA03 4575 ++# ++# Additional mach-types supported by OpenWrt ++# ++wg302v1 MACH_WG302V1 WG302V1 889 ++pronghorn MACH_PRONGHORN PRONGHORN 928 ++pronghorn_metro MACH_PRONGHORNMETRO PRONGHORNMETRO 1040 ++sidewinder MACH_SIDEWINDER SIDEWINDER 1041 ++wrt300nv2 MACH_WRT300NV2 WRT300NV2 1077 ++compex42x MACH_COMPEXWP18 COMPEXWP18 1273 ++goldfish MACH_GOLDFISH GOLDFISH 1441 ++cambria MACH_CAMBRIA CAMBRIA 1468 ++dt2 MACH_DT2 DT2 1514 ++ap1000 MACH_AP1000 AP1000 1543 ++tw2662 MACH_TW2662 TW2662 1658 ++tw5334 MACH_TW5334 TW5334 1664 ++usr8200 MACH_USR8200 USR8200 1762 ++mi424wr MACH_MI424WR MI424WR 1778 ++gw2388 MACH_GW2388 GW2388 2635 ++iconnect MACH_ICONNECT ICONNECT 2870 ++nsb3ast MACH_NSB3AST NSB3AST 2917 ++goflexnet MACH_GOFLEXNET GOFLEXNET 3089 ++nas6210 MACH_NAS6210 NAS6210 3104 ++ns_k330 MACH_NS_K330 NS_K330 3108 ++bcm2708 MACH_BCM2708 BCM2708 3138 ++wn802t MACH_WN802T WN802T 3306 ++nsa310 MACH_NSA310 NSA310 4022 diff --git a/target/linux/generic/patches-3.18/990-gpio_wdt.patch b/target/linux/generic/patches-3.18/990-gpio_wdt.patch new file mode 100644 index 0000000..4742273 --- /dev/null +++ b/target/linux/generic/patches-3.18/990-gpio_wdt.patch @@ -0,0 +1,360 @@ +This generic GPIO watchdog is used on Huawei E970 (brcm47xx) + +Signed-off-by: Mathias Adam + +--- a/drivers/watchdog/Kconfig ++++ b/drivers/watchdog/Kconfig +@@ -1139,6 +1139,15 @@ config WDT_MTX1 + Hardware driver for the MTX-1 boards. This is a watchdog timer that + will reboot the machine after a 100 seconds timer expired. + ++config GPIO_WDT ++ tristate "GPIO Hardware Watchdog" ++ help ++ Hardware driver for GPIO-controlled watchdogs. GPIO pin and ++ toggle interval settings are platform-specific. The driver ++ will stop toggling the GPIO (i.e. machine reboots) after a ++ 100 second timer expired and no process has written to ++ /dev/watchdog during that time. ++ + config PNX833X_WDT + tristate "PNX833x Hardware Watchdog" + depends on SOC_PNX8335 +--- a/drivers/watchdog/Makefile ++++ b/drivers/watchdog/Makefile +@@ -134,6 +134,7 @@ obj-$(CONFIG_RC32434_WDT) += rc32434_wdt + obj-$(CONFIG_INDYDOG) += indydog.o + obj-$(CONFIG_JZ4740_WDT) += jz4740_wdt.o + obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o ++obj-$(CONFIG_GPIO_WDT) += old_gpio_wdt.o + obj-$(CONFIG_PNX833X_WDT) += pnx833x_wdt.o + obj-$(CONFIG_SIBYTE_WDOG) += sb_wdog.o + obj-$(CONFIG_AR7_WDT) += ar7_wdt.o +--- /dev/null ++++ b/drivers/watchdog/old_gpio_wdt.c +@@ -0,0 +1,301 @@ ++/* ++ * Driver for GPIO-controlled Hardware Watchdogs. ++ * ++ * Copyright (C) 2013 Mathias Adam ++ * ++ * Replaces mtx1_wdt (driver for the MTX-1 Watchdog): ++ * ++ * (C) Copyright 2005 4G Systems , ++ * All Rights Reserved. ++ * http://www.4g-systems.biz ++ * ++ * (C) Copyright 2007 OpenWrt.org, Florian Fainelli ++ * ++ * 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. ++ * ++ * Neither Michael Stickel nor 4G Systems admit liability nor provide ++ * warranty for any of this software. This material is provided ++ * "AS-IS" and at no charge. ++ * ++ * (c) Copyright 2005 4G Systems ++ * ++ * Release 0.01. ++ * Author: Michael Stickel michael.stickel@4g-systems.biz ++ * ++ * Release 0.02. ++ * Author: Florian Fainelli florian@openwrt.org ++ * use the Linux watchdog/timer APIs ++ * ++ * Release 0.03. ++ * Author: Mathias Adam ++ * make it a generic gpio watchdog driver ++ * ++ * The Watchdog is configured to reset the MTX-1 ++ * if it is not triggered for 100 seconds. ++ * It should not be triggered more often than 1.6 seconds. ++ * ++ * A timer triggers the watchdog every 5 seconds, until ++ * it is opened for the first time. After the first open ++ * it MUST be triggered every 2..95 seconds. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static int ticks = 100 * HZ; ++ ++static struct { ++ struct completion stop; ++ spinlock_t lock; ++ int running; ++ struct timer_list timer; ++ int queue; ++ int default_ticks; ++ unsigned long inuse; ++ unsigned gpio; ++ unsigned int gstate; ++ int interval; ++ int first_interval; ++} gpio_wdt_device; ++ ++static void gpio_wdt_trigger(unsigned long unused) ++{ ++ spin_lock(&gpio_wdt_device.lock); ++ if (gpio_wdt_device.running && ticks > 0) ++ ticks -= gpio_wdt_device.interval; ++ ++ /* toggle wdt gpio */ ++ gpio_wdt_device.gstate = !gpio_wdt_device.gstate; ++ gpio_set_value(gpio_wdt_device.gpio, gpio_wdt_device.gstate); ++ ++ if (gpio_wdt_device.queue && ticks > 0) ++ mod_timer(&gpio_wdt_device.timer, jiffies + gpio_wdt_device.interval); ++ else ++ complete(&gpio_wdt_device.stop); ++ spin_unlock(&gpio_wdt_device.lock); ++} ++ ++static void gpio_wdt_reset(void) ++{ ++ ticks = gpio_wdt_device.default_ticks; ++} ++ ++ ++static void gpio_wdt_start(void) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&gpio_wdt_device.lock, flags); ++ if (!gpio_wdt_device.queue) { ++ gpio_wdt_device.queue = 1; ++ gpio_wdt_device.gstate = 1; ++ gpio_set_value(gpio_wdt_device.gpio, 1); ++ mod_timer(&gpio_wdt_device.timer, jiffies + gpio_wdt_device.first_interval); ++ } ++ gpio_wdt_device.running++; ++ spin_unlock_irqrestore(&gpio_wdt_device.lock, flags); ++} ++ ++static int gpio_wdt_stop(void) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&gpio_wdt_device.lock, flags); ++ if (gpio_wdt_device.queue) { ++ gpio_wdt_device.queue = 0; ++ gpio_wdt_device.gstate = 0; ++ gpio_set_value(gpio_wdt_device.gpio, 0); ++ } ++ ticks = gpio_wdt_device.default_ticks; ++ spin_unlock_irqrestore(&gpio_wdt_device.lock, flags); ++ return 0; ++} ++ ++/* Filesystem functions */ ++ ++static int gpio_wdt_open(struct inode *inode, struct file *file) ++{ ++ if (test_and_set_bit(0, &gpio_wdt_device.inuse)) ++ return -EBUSY; ++ return nonseekable_open(inode, file); ++} ++ ++ ++static int gpio_wdt_release(struct inode *inode, struct file *file) ++{ ++ clear_bit(0, &gpio_wdt_device.inuse); ++ return 0; ++} ++ ++static long gpio_wdt_ioctl(struct file *file, unsigned int cmd, ++ unsigned long arg) ++{ ++ void __user *argp = (void __user *)arg; ++ int __user *p = (int __user *)argp; ++ unsigned int value; ++ static const struct watchdog_info ident = { ++ .options = WDIOF_CARDRESET, ++ .identity = "GPIO WDT", ++ }; ++ ++ switch (cmd) { ++ case WDIOC_GETSUPPORT: ++ if (copy_to_user(argp, &ident, sizeof(ident))) ++ return -EFAULT; ++ break; ++ case WDIOC_GETSTATUS: ++ case WDIOC_GETBOOTSTATUS: ++ put_user(0, p); ++ break; ++ case WDIOC_SETOPTIONS: ++ if (get_user(value, p)) ++ return -EFAULT; ++ if (value & WDIOS_ENABLECARD) ++ gpio_wdt_start(); ++ else if (value & WDIOS_DISABLECARD) ++ gpio_wdt_stop(); ++ else ++ return -EINVAL; ++ return 0; ++ case WDIOC_KEEPALIVE: ++ gpio_wdt_reset(); ++ break; ++ default: ++ return -ENOTTY; ++ } ++ return 0; ++} ++ ++ ++static ssize_t gpio_wdt_write(struct file *file, const char *buf, ++ size_t count, loff_t *ppos) ++{ ++ if (!count) ++ return -EIO; ++ gpio_wdt_reset(); ++ return count; ++} ++ ++static const struct file_operations gpio_wdt_fops = { ++ .owner = THIS_MODULE, ++ .llseek = no_llseek, ++ .unlocked_ioctl = gpio_wdt_ioctl, ++ .open = gpio_wdt_open, ++ .write = gpio_wdt_write, ++ .release = gpio_wdt_release, ++}; ++ ++ ++static struct miscdevice gpio_wdt_misc = { ++ .minor = WATCHDOG_MINOR, ++ .name = "watchdog", ++ .fops = &gpio_wdt_fops, ++}; ++ ++ ++static int gpio_wdt_probe(struct platform_device *pdev) ++{ ++ int ret; ++ struct gpio_wdt_platform_data *gpio_wdt_data = pdev->dev.platform_data; ++ ++ gpio_wdt_device.gpio = gpio_wdt_data->gpio; ++ gpio_wdt_device.interval = gpio_wdt_data->interval; ++ gpio_wdt_device.first_interval = gpio_wdt_data->first_interval; ++ if (gpio_wdt_device.first_interval <= 0) { ++ gpio_wdt_device.first_interval = gpio_wdt_device.interval; ++ } ++ ++ ret = gpio_request(gpio_wdt_device.gpio, "gpio-wdt"); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "failed to request gpio"); ++ return ret; ++ } ++ ++ spin_lock_init(&gpio_wdt_device.lock); ++ init_completion(&gpio_wdt_device.stop); ++ gpio_wdt_device.queue = 0; ++ clear_bit(0, &gpio_wdt_device.inuse); ++ setup_timer(&gpio_wdt_device.timer, gpio_wdt_trigger, 0L); ++ gpio_wdt_device.default_ticks = ticks; ++ ++ gpio_wdt_start(); ++ dev_info(&pdev->dev, "GPIO Hardware Watchdog driver (gpio=%i interval=%i/%i)\n", ++ gpio_wdt_data->gpio, gpio_wdt_data->first_interval, gpio_wdt_data->interval); ++ return 0; ++} ++ ++static int gpio_wdt_remove(struct platform_device *pdev) ++{ ++ /* FIXME: do we need to lock this test ? */ ++ if (gpio_wdt_device.queue) { ++ gpio_wdt_device.queue = 0; ++ wait_for_completion(&gpio_wdt_device.stop); ++ } ++ ++ gpio_free(gpio_wdt_device.gpio); ++ misc_deregister(&gpio_wdt_misc); ++ return 0; ++} ++ ++static struct platform_driver gpio_wdt_driver = { ++ .probe = gpio_wdt_probe, ++ .remove = gpio_wdt_remove, ++ .driver.name = "gpio-wdt", ++ .driver.owner = THIS_MODULE, ++}; ++ ++static int __init gpio_wdt_init(void) ++{ ++ return platform_driver_register(&gpio_wdt_driver); ++} ++arch_initcall(gpio_wdt_init); ++ ++/* ++ * We do wdt initialization in two steps: arch_initcall probes the wdt ++ * very early to start pinging the watchdog (misc devices are not yet ++ * available), and later module_init() just registers the misc device. ++ */ ++static int gpio_wdt_init_late(void) ++{ ++ int ret; ++ ++ ret = misc_register(&gpio_wdt_misc); ++ if (ret < 0) { ++ pr_err("GPIO_WDT: failed to register misc device\n"); ++ return ret; ++ } ++ return 0; ++} ++#ifndef MODULE ++module_init(gpio_wdt_init_late); ++#endif ++ ++static void __exit gpio_wdt_exit(void) ++{ ++ platform_driver_unregister(&gpio_wdt_driver); ++} ++module_exit(gpio_wdt_exit); ++ ++MODULE_AUTHOR("Michael Stickel, Florian Fainelli, Mathias Adam"); ++MODULE_DESCRIPTION("Driver for GPIO hardware watchdogs"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); ++MODULE_ALIAS("platform:gpio-wdt"); +--- /dev/null ++++ b/include/linux/old_gpio_wdt.h +@@ -0,0 +1,21 @@ ++/* ++ * Definitions for the GPIO watchdog driver ++ * ++ * Copyright (C) 2013 Mathias Adam ++ * ++ * 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. ++ * ++ */ ++ ++#ifndef _GPIO_WDT_H_ ++#define _GPIO_WDT_H_ ++ ++struct gpio_wdt_platform_data { ++ int gpio; /* GPIO line number */ ++ int interval; /* watchdog reset interval in system ticks */ ++ int first_interval; /* first wd reset interval in system ticks */ ++}; ++ ++#endif /* _GPIO_WDT_H_ */ diff --git a/target/linux/generic/patches-3.18/995-mangle_bootargs.patch b/target/linux/generic/patches-3.18/995-mangle_bootargs.patch new file mode 100644 index 0000000..0029e90 --- /dev/null +++ b/target/linux/generic/patches-3.18/995-mangle_bootargs.patch @@ -0,0 +1,58 @@ +--- a/init/main.c ++++ b/init/main.c +@@ -362,6 +362,29 @@ static inline void setup_nr_cpu_ids(void + static inline void smp_prepare_cpus(unsigned int maxcpus) { } + #endif + ++#ifdef CONFIG_MANGLE_BOOTARGS ++static void __init mangle_bootargs(char *command_line) ++{ ++ char *rootdev; ++ char *rootfs; ++ ++ rootdev = strstr(command_line, "root=/dev/mtdblock"); ++ ++ if (rootdev) ++ strncpy(rootdev, "mangled_rootblock=", 18); ++ ++ rootfs = strstr(command_line, "rootfstype"); ++ ++ if (rootfs) ++ strncpy(rootfs, "mangled_fs", 10); ++ ++} ++#else ++static void __init mangle_bootargs(char *command_line) ++{ ++} ++#endif ++ + /* + * We need to store the untouched command line for future reference. + * We also need to store the touched command line since the parameter +@@ -530,6 +553,7 @@ asmlinkage __visible void __init start_k + pr_notice("%s", linux_banner); + setup_arch(&command_line); + mm_init_cpumask(&init_mm); ++ mangle_bootargs(command_line); + setup_command_line(command_line); + setup_nr_cpu_ids(); + setup_per_cpu_areas(); +--- a/init/Kconfig ++++ b/init/Kconfig +@@ -1597,6 +1597,15 @@ config EMBEDDED + an embedded system so certain expert options are available + for configuration. + ++config MANGLE_BOOTARGS ++ bool "Rename offending bootargs" ++ depends on EXPERT ++ help ++ Sometimes the bootloader passed bogus root= and rootfstype= ++ parameters to the kernel, and while you want to ignore them, ++ you need to know the values f.e. to support dual firmware ++ layouts on the flash. ++ + config HAVE_PERF_EVENTS + bool + help diff --git a/target/linux/generic/patches-3.18/997-device_tree_cmdline.patch b/target/linux/generic/patches-3.18/997-device_tree_cmdline.patch new file mode 100644 index 0000000..dd725b0 --- /dev/null +++ b/target/linux/generic/patches-3.18/997-device_tree_cmdline.patch @@ -0,0 +1,24 @@ +--- a/drivers/of/fdt.c ++++ b/drivers/of/fdt.c +@@ -903,6 +903,9 @@ int __init early_init_dt_scan_chosen(uns + p = of_get_flat_dt_prop(node, "bootargs", &l); + if (p != NULL && l > 0) + strlcpy(data, p, min((int)l, COMMAND_LINE_SIZE)); ++ p = of_get_flat_dt_prop(node, "bootargs-append", &l); ++ if (p != NULL && l > 0) ++ strlcat(data, p, min_t(int, strlen(data) + (int)l, COMMAND_LINE_SIZE)); + + /* + * CONFIG_CMDLINE is meant to be a default in case nothing else +--- a/arch/mips/kernel/prom.c ++++ b/arch/mips/kernel/prom.c +@@ -49,6 +49,9 @@ void * __init early_init_dt_alloc_memory + + void __init __dt_setup_arch(void *bph) + { ++ if (boot_command_line[0] == '\0') ++ strcpy(boot_command_line, arcs_cmdline); ++ + if (!early_init_dt_scan(bph)) + return; + diff --git a/target/linux/generic/patches-3.18/998-enable_wilink_platform_without_drivers.patch b/target/linux/generic/patches-3.18/998-enable_wilink_platform_without_drivers.patch new file mode 100644 index 0000000..d317de1 --- /dev/null +++ b/target/linux/generic/patches-3.18/998-enable_wilink_platform_without_drivers.patch @@ -0,0 +1,15 @@ +We use backports for driver updates - make sure we can compile in the glue code regardless + +Signed-off-by: Imre Kaloz + +--- a/drivers/net/wireless/ti/Kconfig ++++ b/drivers/net/wireless/ti/Kconfig +@@ -15,7 +15,7 @@ source "drivers/net/wireless/ti/wlcore/K + + config WILINK_PLATFORM_DATA + bool "TI WiLink platform data" +- depends on WLCORE_SDIO || WL1251_SDIO ++ depends on WLCORE_SDIO || WL1251_SDIO || ARCH_OMAP2PLUS + default y + ---help--- + Small platform data bit needed to pass data to the sdio modules. diff --git a/target/linux/generic/patches-3.18/999-seccomp_log.patch b/target/linux/generic/patches-3.18/999-seccomp_log.patch new file mode 100644 index 0000000..1db6b18 --- /dev/null +++ b/target/linux/generic/patches-3.18/999-seccomp_log.patch @@ -0,0 +1,34 @@ +--- a/kernel/seccomp.c ++++ b/kernel/seccomp.c +@@ -614,6 +614,7 @@ int __secure_computing(void) + #ifdef CONFIG_SECCOMP_FILTER + static u32 __seccomp_phase1_filter(int this_syscall, struct seccomp_data *sd) + { ++ char name[sizeof(current->comm)]; + u32 filter_ret, action; + int data; + +@@ -644,6 +645,13 @@ static u32 __seccomp_phase1_filter(int t + case SECCOMP_RET_TRACE: + return filter_ret; /* Save the rest for phase 2. */ + ++ case SECCOMP_RET_LOG: ++ get_task_comm(name, current); ++ pr_err_ratelimited("seccomp: %s [%u] tried to call non-whitelisted syscall: %d\n", name, current->pid, this_syscall); ++ syscall_set_return_value(current, task_pt_regs(current), ++ -data, 0); ++ goto skip; ++ + case SECCOMP_RET_ALLOW: + return SECCOMP_PHASE1_OK; + +--- a/include/uapi/linux/seccomp.h ++++ b/include/uapi/linux/seccomp.h +@@ -28,6 +28,7 @@ + #define SECCOMP_RET_KILL 0x00000000U /* kill the task immediately */ + #define SECCOMP_RET_TRAP 0x00030000U /* disallow and force a SIGSYS */ + #define SECCOMP_RET_ERRNO 0x00050000U /* returns an errno */ ++#define SECCOMP_RET_LOG 0x00070000U /* allow + logline */ + #define SECCOMP_RET_TRACE 0x7ff00000U /* pass to a tracer or disallow */ + #define SECCOMP_RET_ALLOW 0x7fff0000U /* allow */ + diff --git a/target/linux/generic/patches-4.0/000-keep_initrafs_the_default.patch b/target/linux/generic/patches-4.0/000-keep_initrafs_the_default.patch new file mode 100644 index 0000000..7d28e02 --- /dev/null +++ b/target/linux/generic/patches-4.0/000-keep_initrafs_the_default.patch @@ -0,0 +1,25 @@ +Upstream changed the default rootfs to tmpfs when none has been passed +to the kernel - this doesn't fit our purposes, so change it back. + +Signed-off-by: Imre Kaloz + +--- a/init/do_mounts.c ++++ b/init/do_mounts.c +@@ -625,6 +625,7 @@ int __init init_rootfs(void) + if (err) + return err; + ++#if 0 + if (IS_ENABLED(CONFIG_TMPFS) && !saved_root_name[0] && + (!root_fs_names || strstr(root_fs_names, "tmpfs"))) { + err = shmem_init(); +@@ -632,6 +633,9 @@ int __init init_rootfs(void) + } else { + err = init_ramfs_fs(); + } ++#else ++ err = init_ramfs_fs(); ++#endif + + if (err) + unregister_filesystem(&rootfs_fs_type); diff --git a/target/linux/generic/patches-4.0/020-ssb_update.patch b/target/linux/generic/patches-4.0/020-ssb_update.patch new file mode 100644 index 0000000..d7e15ae --- /dev/null +++ b/target/linux/generic/patches-4.0/020-ssb_update.patch @@ -0,0 +1,30 @@ +--- a/drivers/ssb/driver_pcicore.c ++++ b/drivers/ssb/driver_pcicore.c +@@ -357,6 +357,16 @@ static void ssb_pcicore_init_hostmode(st + pcicore_write32(pc, SSB_PCICORE_SBTOPCI2, + SSB_PCICORE_SBTOPCI_MEM | SSB_PCI_DMA); + ++ /* ++ * Accessing PCI config without a proper delay after devices reset (not ++ * GPIO reset) was causing reboots on WRT300N v1.0 (BCM4704). ++ * Tested delay 850 us lowered reboot chance to 50-80%, 1000 us fixed it ++ * completely. Flushing all writes was also tested but with no luck. ++ * The same problem was reported for WRT350N v1 (BCM4705), so we just ++ * sleep here unconditionally. ++ */ ++ usleep_range(1000, 2000); ++ + /* Enable PCI bridge BAR0 prefetch and burst */ + val = PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY; + ssb_extpci_write_config(pc, 0, 0, 0, PCI_COMMAND, &val, 2); +--- a/drivers/ssb/main.c ++++ b/drivers/ssb/main.c +@@ -1135,6 +1135,8 @@ static u32 ssb_tmslow_reject_bitmask(str + case SSB_IDLOW_SSBREV_25: /* TODO - find the proper REJECT bit */ + case SSB_IDLOW_SSBREV_27: /* same here */ + return SSB_TMSLOW_REJECT; /* this is a guess */ ++ case SSB_IDLOW_SSBREV: ++ break; + default: + WARN(1, KERN_INFO "ssb: Backplane Revision 0x%.8X\n", rev); + } diff --git a/target/linux/generic/patches-4.0/021-bcma-from-4.1.patch b/target/linux/generic/patches-4.0/021-bcma-from-4.1.patch new file mode 100644 index 0000000..8f3e167 --- /dev/null +++ b/target/linux/generic/patches-4.0/021-bcma-from-4.1.patch @@ -0,0 +1,680 @@ +--- a/drivers/bcma/bcma_private.h ++++ b/drivers/bcma/bcma_private.h +@@ -26,6 +26,7 @@ bool bcma_wait_value(struct bcma_device + int timeout); + void bcma_prepare_core(struct bcma_bus *bus, struct bcma_device *core); + void bcma_init_bus(struct bcma_bus *bus); ++void bcma_unregister_cores(struct bcma_bus *bus); + int bcma_bus_register(struct bcma_bus *bus); + void bcma_bus_unregister(struct bcma_bus *bus); + int __init bcma_bus_early_register(struct bcma_bus *bus); +@@ -42,6 +43,9 @@ int bcma_bus_scan(struct bcma_bus *bus); + int bcma_sprom_get(struct bcma_bus *bus); + + /* driver_chipcommon.c */ ++void bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc); ++void bcma_core_chipcommon_init(struct bcma_drv_cc *cc); ++void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable); + #ifdef CONFIG_BCMA_DRIVER_MIPS + void bcma_chipco_serial_init(struct bcma_drv_cc *cc); + extern struct platform_device bcma_pflash_dev; +@@ -52,6 +56,8 @@ int bcma_core_chipcommon_b_init(struct b + void bcma_core_chipcommon_b_free(struct bcma_drv_cc_b *ccb); + + /* driver_chipcommon_pmu.c */ ++void bcma_pmu_early_init(struct bcma_drv_cc *cc); ++void bcma_pmu_init(struct bcma_drv_cc *cc); + u32 bcma_pmu_get_alp_clock(struct bcma_drv_cc *cc); + u32 bcma_pmu_get_cpu_clock(struct bcma_drv_cc *cc); + +@@ -100,7 +106,35 @@ static inline void __exit bcma_host_soc_ + #endif /* CONFIG_BCMA_HOST_SOC && CONFIG_OF */ + + /* driver_pci.c */ ++#ifdef CONFIG_BCMA_DRIVER_PCI + u32 bcma_pcie_read(struct bcma_drv_pci *pc, u32 address); ++void bcma_core_pci_early_init(struct bcma_drv_pci *pc); ++void bcma_core_pci_init(struct bcma_drv_pci *pc); ++void bcma_core_pci_up(struct bcma_drv_pci *pc); ++void bcma_core_pci_down(struct bcma_drv_pci *pc); ++#else ++static inline void bcma_core_pci_early_init(struct bcma_drv_pci *pc) ++{ ++ WARN_ON(pc->core->bus->hosttype == BCMA_HOSTTYPE_PCI); ++} ++static inline void bcma_core_pci_init(struct bcma_drv_pci *pc) ++{ ++ /* Initialization is required for PCI hosted bus */ ++ WARN_ON(pc->core->bus->hosttype == BCMA_HOSTTYPE_PCI); ++} ++#endif ++ ++/* driver_pcie2.c */ ++#ifdef CONFIG_BCMA_DRIVER_PCI ++void bcma_core_pcie2_init(struct bcma_drv_pcie2 *pcie2); ++void bcma_core_pcie2_up(struct bcma_drv_pcie2 *pcie2); ++#else ++static inline void bcma_core_pcie2_init(struct bcma_drv_pcie2 *pcie2) ++{ ++ /* Initialization is required for PCI hosted bus */ ++ WARN_ON(pcie2->core->bus->hosttype == BCMA_HOSTTYPE_PCI); ++} ++#endif + + extern int bcma_chipco_watchdog_register(struct bcma_drv_cc *cc); + +@@ -117,6 +151,39 @@ static inline void bcma_core_pci_hostmod + } + #endif /* CONFIG_BCMA_DRIVER_PCI_HOSTMODE */ + ++/************************************************** ++ * driver_mips.c ++ **************************************************/ ++ ++#ifdef CONFIG_BCMA_DRIVER_MIPS ++unsigned int bcma_core_mips_irq(struct bcma_device *dev); ++void bcma_core_mips_early_init(struct bcma_drv_mips *mcore); ++void bcma_core_mips_init(struct bcma_drv_mips *mcore); ++#else ++static inline unsigned int bcma_core_mips_irq(struct bcma_device *dev) ++{ ++ return 0; ++} ++static inline void bcma_core_mips_early_init(struct bcma_drv_mips *mcore) ++{ ++} ++static inline void bcma_core_mips_init(struct bcma_drv_mips *mcore) ++{ ++} ++#endif ++ ++/************************************************** ++ * driver_gmac_cmn.c ++ **************************************************/ ++ ++#ifdef CONFIG_BCMA_DRIVER_GMAC_CMN ++void bcma_core_gmac_cmn_init(struct bcma_drv_gmac_cmn *gc); ++#else ++static inline void bcma_core_gmac_cmn_init(struct bcma_drv_gmac_cmn *gc) ++{ ++} ++#endif ++ + #ifdef CONFIG_BCMA_DRIVER_GPIO + /* driver_gpio.c */ + int bcma_gpio_init(struct bcma_drv_cc *cc); +--- a/drivers/bcma/driver_gpio.c ++++ b/drivers/bcma/driver_gpio.c +@@ -17,6 +17,8 @@ + + #include "bcma_private.h" + ++#define BCMA_GPIO_MAX_PINS 32 ++ + static inline struct bcma_drv_cc *bcma_gpio_get_cc(struct gpio_chip *chip) + { + return container_of(chip, struct bcma_drv_cc, gpio); +@@ -76,7 +78,7 @@ static void bcma_gpio_free(struct gpio_c + bcma_chipco_gpio_pullup(cc, 1 << gpio, 0); + } + +-#if IS_BUILTIN(CONFIG_BCM47XX) ++#if IS_BUILTIN(CONFIG_BCM47XX) || IS_BUILTIN(CONFIG_ARCH_BCM_5301X) + static int bcma_gpio_to_irq(struct gpio_chip *chip, unsigned gpio) + { + struct bcma_drv_cc *cc = bcma_gpio_get_cc(chip); +@@ -204,6 +206,7 @@ static void bcma_gpio_irq_domain_exit(st + + int bcma_gpio_init(struct bcma_drv_cc *cc) + { ++ struct bcma_bus *bus = cc->core->bus; + struct gpio_chip *chip = &cc->gpio; + int err; + +@@ -215,14 +218,14 @@ int bcma_gpio_init(struct bcma_drv_cc *c + chip->set = bcma_gpio_set_value; + chip->direction_input = bcma_gpio_direction_input; + chip->direction_output = bcma_gpio_direction_output; +-#if IS_BUILTIN(CONFIG_BCM47XX) ++#if IS_BUILTIN(CONFIG_BCM47XX) || IS_BUILTIN(CONFIG_ARCH_BCM_5301X) + chip->to_irq = bcma_gpio_to_irq; + #endif + #if IS_BUILTIN(CONFIG_OF) + if (cc->core->bus->hosttype == BCMA_HOSTTYPE_SOC) + chip->of_node = cc->core->dev.of_node; + #endif +- switch (cc->core->bus->chipinfo.id) { ++ switch (bus->chipinfo.id) { + case BCMA_CHIP_ID_BCM5357: + case BCMA_CHIP_ID_BCM53572: + chip->ngpio = 32; +@@ -231,13 +234,17 @@ int bcma_gpio_init(struct bcma_drv_cc *c + chip->ngpio = 16; + } + +- /* There is just one SoC in one device and its GPIO addresses should be +- * deterministic to address them more easily. The other buses could get +- * a random base number. */ +- if (cc->core->bus->hosttype == BCMA_HOSTTYPE_SOC) +- chip->base = 0; +- else +- chip->base = -1; ++ /* ++ * On MIPS we register GPIO devices (LEDs, buttons) using absolute GPIO ++ * pin numbers. We don't have Device Tree there and we can't really use ++ * relative (per chip) numbers. ++ * So let's use predictable base for BCM47XX and "random" for all other. ++ */ ++#if IS_BUILTIN(CONFIG_BCM47XX) ++ chip->base = bus->num * BCMA_GPIO_MAX_PINS; ++#else ++ chip->base = -1; ++#endif + + err = bcma_gpio_irq_domain_init(cc); + if (err) +--- a/drivers/bcma/driver_pci.c ++++ b/drivers/bcma/driver_pci.c +@@ -282,39 +282,6 @@ void bcma_core_pci_power_save(struct bcm + } + EXPORT_SYMBOL_GPL(bcma_core_pci_power_save); + +-int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core, +- bool enable) +-{ +- struct pci_dev *pdev; +- u32 coremask, tmp; +- int err = 0; +- +- if (!pc || core->bus->hosttype != BCMA_HOSTTYPE_PCI) { +- /* This bcma device is not on a PCI host-bus. So the IRQs are +- * not routed through the PCI core. +- * So we must not enable routing through the PCI core. */ +- goto out; +- } +- +- pdev = pc->core->bus->host_pci; +- +- err = pci_read_config_dword(pdev, BCMA_PCI_IRQMASK, &tmp); +- if (err) +- goto out; +- +- coremask = BIT(core->core_index) << 8; +- if (enable) +- tmp |= coremask; +- else +- tmp &= ~coremask; +- +- err = pci_write_config_dword(pdev, BCMA_PCI_IRQMASK, tmp); +- +-out: +- return err; +-} +-EXPORT_SYMBOL_GPL(bcma_core_pci_irq_ctl); +- + static void bcma_core_pci_extend_L1timer(struct bcma_drv_pci *pc, bool extend) + { + u32 w; +@@ -328,28 +295,12 @@ static void bcma_core_pci_extend_L1timer + bcma_pcie_read(pc, BCMA_CORE_PCI_DLLP_PMTHRESHREG); + } + +-void bcma_core_pci_up(struct bcma_bus *bus) ++void bcma_core_pci_up(struct bcma_drv_pci *pc) + { +- struct bcma_drv_pci *pc; +- +- if (bus->hosttype != BCMA_HOSTTYPE_PCI) +- return; +- +- pc = &bus->drv_pci[0]; +- + bcma_core_pci_extend_L1timer(pc, true); + } +-EXPORT_SYMBOL_GPL(bcma_core_pci_up); + +-void bcma_core_pci_down(struct bcma_bus *bus) ++void bcma_core_pci_down(struct bcma_drv_pci *pc) + { +- struct bcma_drv_pci *pc; +- +- if (bus->hosttype != BCMA_HOSTTYPE_PCI) +- return; +- +- pc = &bus->drv_pci[0]; +- + bcma_core_pci_extend_L1timer(pc, false); + } +-EXPORT_SYMBOL_GPL(bcma_core_pci_down); +--- a/drivers/bcma/driver_pci_host.c ++++ b/drivers/bcma/driver_pci_host.c +@@ -11,6 +11,7 @@ + + #include "bcma_private.h" + #include ++#include + #include + #include + #include +--- a/drivers/bcma/driver_pcie2.c ++++ b/drivers/bcma/driver_pcie2.c +@@ -10,6 +10,7 @@ + + #include "bcma_private.h" + #include ++#include + + /************************************************** + * R/W ops. +@@ -156,14 +157,23 @@ static void pciedev_reg_pm_clk_period(st + + void bcma_core_pcie2_init(struct bcma_drv_pcie2 *pcie2) + { +- struct bcma_chipinfo *ci = &pcie2->core->bus->chipinfo; ++ struct bcma_bus *bus = pcie2->core->bus; ++ struct bcma_chipinfo *ci = &bus->chipinfo; + u32 tmp; + + tmp = pcie2_read32(pcie2, BCMA_CORE_PCIE2_SPROM(54)); + if ((tmp & 0xe) >> 1 == 2) + bcma_core_pcie2_cfg_write(pcie2, 0x4e0, 0x17); + +- /* TODO: Do we need pcie_reqsize? */ ++ switch (bus->chipinfo.id) { ++ case BCMA_CHIP_ID_BCM4360: ++ case BCMA_CHIP_ID_BCM4352: ++ pcie2->reqsize = 1024; ++ break; ++ default: ++ pcie2->reqsize = 128; ++ break; ++ } + + if (ci->id == BCMA_CHIP_ID_BCM4360 && ci->rev > 3) + bcma_core_pcie2_war_delay_perst_enab(pcie2, true); +@@ -173,3 +183,18 @@ void bcma_core_pcie2_init(struct bcma_dr + pciedev_crwlpciegen2_180(pcie2); + pciedev_crwlpciegen2_182(pcie2); + } ++ ++/************************************************** ++ * Runtime ops. ++ **************************************************/ ++ ++void bcma_core_pcie2_up(struct bcma_drv_pcie2 *pcie2) ++{ ++ struct bcma_bus *bus = pcie2->core->bus; ++ struct pci_dev *dev = bus->host_pci; ++ int err; ++ ++ err = pcie_set_readrq(dev, pcie2->reqsize); ++ if (err) ++ bcma_err(bus, "Error setting PCI_EXP_DEVCTL_READRQ: %d\n", err); ++} +--- a/drivers/bcma/host_pci.c ++++ b/drivers/bcma/host_pci.c +@@ -213,16 +213,26 @@ static int bcma_host_pci_probe(struct pc + /* Initialize struct, detect chip */ + bcma_init_bus(bus); + ++ /* Scan bus to find out generation of PCIe core */ ++ err = bcma_bus_scan(bus); ++ if (err) ++ goto err_pci_unmap_mmio; ++ ++ if (bcma_find_core(bus, BCMA_CORE_PCIE2)) ++ bus->host_is_pcie2 = true; ++ + /* Register */ + err = bcma_bus_register(bus); + if (err) +- goto err_pci_unmap_mmio; ++ goto err_unregister_cores; + + pci_set_drvdata(dev, bus); + + out: + return err; + ++err_unregister_cores: ++ bcma_unregister_cores(bus); + err_pci_unmap_mmio: + pci_iounmap(dev, bus->mmio); + err_pci_release_regions: +@@ -283,9 +293,12 @@ static const struct pci_device_id bcma_p + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4357) }, + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4358) }, + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4359) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4360) }, + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4365) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43a0) }, + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43a9) }, + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43aa) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43b1) }, + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4727) }, + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 43227) }, /* 0xa8db, BCM43217 (sic!) */ + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 43228) }, /* 0xa8dc */ +@@ -310,3 +323,65 @@ void __exit bcma_host_pci_exit(void) + { + pci_unregister_driver(&bcma_pci_bridge_driver); + } ++ ++/************************************************** ++ * Runtime ops for drivers. ++ **************************************************/ ++ ++/* See also pcicore_up */ ++void bcma_host_pci_up(struct bcma_bus *bus) ++{ ++ if (bus->hosttype != BCMA_HOSTTYPE_PCI) ++ return; ++ ++ if (bus->host_is_pcie2) ++ bcma_core_pcie2_up(&bus->drv_pcie2); ++ else ++ bcma_core_pci_up(&bus->drv_pci[0]); ++} ++EXPORT_SYMBOL_GPL(bcma_host_pci_up); ++ ++/* See also pcicore_down */ ++void bcma_host_pci_down(struct bcma_bus *bus) ++{ ++ if (bus->hosttype != BCMA_HOSTTYPE_PCI) ++ return; ++ ++ if (!bus->host_is_pcie2) ++ bcma_core_pci_down(&bus->drv_pci[0]); ++} ++EXPORT_SYMBOL_GPL(bcma_host_pci_down); ++ ++/* See also si_pci_setup */ ++int bcma_host_pci_irq_ctl(struct bcma_bus *bus, struct bcma_device *core, ++ bool enable) ++{ ++ struct pci_dev *pdev; ++ u32 coremask, tmp; ++ int err = 0; ++ ++ if (bus->hosttype != BCMA_HOSTTYPE_PCI) { ++ /* This bcma device is not on a PCI host-bus. So the IRQs are ++ * not routed through the PCI core. ++ * So we must not enable routing through the PCI core. */ ++ goto out; ++ } ++ ++ pdev = bus->host_pci; ++ ++ err = pci_read_config_dword(pdev, BCMA_PCI_IRQMASK, &tmp); ++ if (err) ++ goto out; ++ ++ coremask = BIT(core->core_index) << 8; ++ if (enable) ++ tmp |= coremask; ++ else ++ tmp &= ~coremask; ++ ++ err = pci_write_config_dword(pdev, BCMA_PCI_IRQMASK, tmp); ++ ++out: ++ return err; ++} ++EXPORT_SYMBOL_GPL(bcma_host_pci_irq_ctl); +--- a/drivers/bcma/main.c ++++ b/drivers/bcma/main.c +@@ -363,7 +363,7 @@ static int bcma_register_devices(struct + return 0; + } + +-static void bcma_unregister_cores(struct bcma_bus *bus) ++void bcma_unregister_cores(struct bcma_bus *bus) + { + struct bcma_device *core, *tmp; + +--- a/drivers/net/wireless/b43/main.c ++++ b/drivers/net/wireless/b43/main.c +@@ -4819,7 +4819,7 @@ static void b43_wireless_core_exit(struc + switch (dev->dev->bus_type) { + #ifdef CONFIG_B43_BCMA + case B43_BUS_BCMA: +- bcma_core_pci_down(dev->dev->bdev->bus); ++ bcma_host_pci_down(dev->dev->bdev->bus); + break; + #endif + #ifdef CONFIG_B43_SSB +@@ -4866,9 +4866,9 @@ static int b43_wireless_core_init(struct + switch (dev->dev->bus_type) { + #ifdef CONFIG_B43_BCMA + case B43_BUS_BCMA: +- bcma_core_pci_irq_ctl(&dev->dev->bdev->bus->drv_pci[0], ++ bcma_host_pci_irq_ctl(dev->dev->bdev->bus, + dev->dev->bdev, true); +- bcma_core_pci_up(dev->dev->bdev->bus); ++ bcma_host_pci_up(dev->dev->bdev->bus); + break; + #endif + #ifdef CONFIG_B43_SSB +--- a/drivers/net/wireless/brcm80211/brcmsmac/main.c ++++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c +@@ -4668,7 +4668,7 @@ static int brcms_b_attach(struct brcms_c + brcms_c_coredisable(wlc_hw); + + /* Match driver "down" state */ +- bcma_core_pci_down(wlc_hw->d11core->bus); ++ bcma_host_pci_down(wlc_hw->d11core->bus); + + /* turn off pll and xtal to match driver "down" state */ + brcms_b_xtal(wlc_hw, OFF); +@@ -4959,7 +4959,7 @@ static int brcms_b_up_prep(struct brcms_ + * Configure pci/pcmcia here instead of in brcms_c_attach() + * to allow mfg hotswap: down, hotswap (chip power cycle), up. + */ +- bcma_core_pci_irq_ctl(&wlc_hw->d11core->bus->drv_pci[0], wlc_hw->d11core, ++ bcma_host_pci_irq_ctl(wlc_hw->d11core->bus, wlc_hw->d11core, + true); + + /* +@@ -4969,12 +4969,12 @@ static int brcms_b_up_prep(struct brcms_ + */ + if (brcms_b_radio_read_hwdisabled(wlc_hw)) { + /* put SB PCI in down state again */ +- bcma_core_pci_down(wlc_hw->d11core->bus); ++ bcma_host_pci_down(wlc_hw->d11core->bus); + brcms_b_xtal(wlc_hw, OFF); + return -ENOMEDIUM; + } + +- bcma_core_pci_up(wlc_hw->d11core->bus); ++ bcma_host_pci_up(wlc_hw->d11core->bus); + + /* reset the d11 core */ + brcms_b_corereset(wlc_hw, BRCMS_USE_COREFLAGS); +@@ -5171,7 +5171,7 @@ static int brcms_b_down_finish(struct br + + /* turn off primary xtal and pll */ + if (!wlc_hw->noreset) { +- bcma_core_pci_down(wlc_hw->d11core->bus); ++ bcma_host_pci_down(wlc_hw->d11core->bus); + brcms_b_xtal(wlc_hw, OFF); + } + } +--- a/include/linux/bcma/bcma.h ++++ b/include/linux/bcma/bcma.h +@@ -434,6 +434,27 @@ static inline struct bcma_device *bcma_f + return bcma_find_core_unit(bus, coreid, 0); + } + ++#ifdef CONFIG_BCMA_HOST_PCI ++extern void bcma_host_pci_up(struct bcma_bus *bus); ++extern void bcma_host_pci_down(struct bcma_bus *bus); ++extern int bcma_host_pci_irq_ctl(struct bcma_bus *bus, ++ struct bcma_device *core, bool enable); ++#else ++static inline void bcma_host_pci_up(struct bcma_bus *bus) ++{ ++} ++static inline void bcma_host_pci_down(struct bcma_bus *bus) ++{ ++} ++static inline int bcma_host_pci_irq_ctl(struct bcma_bus *bus, ++ struct bcma_device *core, bool enable) ++{ ++ if (bus->hosttype == BCMA_HOSTTYPE_PCI) ++ return -ENOTSUPP; ++ return 0; ++} ++#endif ++ + extern bool bcma_core_is_enabled(struct bcma_device *core); + extern void bcma_core_disable(struct bcma_device *core, u32 flags); + extern int bcma_core_enable(struct bcma_device *core, u32 flags); +--- a/include/linux/bcma/bcma_driver_pci.h ++++ b/include/linux/bcma/bcma_driver_pci.h +@@ -238,13 +238,13 @@ struct bcma_drv_pci { + #define pcicore_write16(pc, offset, val) bcma_write16((pc)->core, offset, val) + #define pcicore_write32(pc, offset, val) bcma_write32((pc)->core, offset, val) + +-extern void bcma_core_pci_early_init(struct bcma_drv_pci *pc); +-extern void bcma_core_pci_init(struct bcma_drv_pci *pc); +-extern int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, +- struct bcma_device *core, bool enable); +-extern void bcma_core_pci_up(struct bcma_bus *bus); +-extern void bcma_core_pci_down(struct bcma_bus *bus); ++#ifdef CONFIG_BCMA_DRIVER_PCI + extern void bcma_core_pci_power_save(struct bcma_bus *bus, bool up); ++#else ++static inline void bcma_core_pci_power_save(struct bcma_bus *bus, bool up) ++{ ++} ++#endif + + extern int bcma_core_pci_pcibios_map_irq(const struct pci_dev *dev); + extern int bcma_core_pci_plat_dev_init(struct pci_dev *dev); +--- a/include/linux/bcma/bcma_driver_pcie2.h ++++ b/include/linux/bcma/bcma_driver_pcie2.h +@@ -143,6 +143,8 @@ + + struct bcma_drv_pcie2 { + struct bcma_device *core; ++ ++ u16 reqsize; + }; + + #define pcie2_read16(pcie2, offset) bcma_read16((pcie2)->core, offset) +@@ -153,6 +155,4 @@ struct bcma_drv_pcie2 { + #define pcie2_set32(pcie2, offset, set) bcma_set32((pcie2)->core, offset, set) + #define pcie2_mask32(pcie2, offset, mask) bcma_mask32((pcie2)->core, offset, mask) + +-void bcma_core_pcie2_init(struct bcma_drv_pcie2 *pcie2); +- + #endif /* LINUX_BCMA_DRIVER_PCIE2_H_ */ +--- a/drivers/bcma/Kconfig ++++ b/drivers/bcma/Kconfig +@@ -26,6 +26,7 @@ config BCMA_HOST_PCI_POSSIBLE + config BCMA_HOST_PCI + bool "Support for BCMA on PCI-host bus" + depends on BCMA_HOST_PCI_POSSIBLE ++ select BCMA_DRIVER_PCI + default y + + config BCMA_DRIVER_PCI_HOSTMODE +@@ -44,6 +45,22 @@ config BCMA_HOST_SOC + + If unsure, say N + ++config BCMA_DRIVER_PCI ++ bool "BCMA Broadcom PCI core driver" ++ depends on BCMA && PCI ++ default y ++ help ++ BCMA bus may have many versions of PCIe core. This driver ++ supports: ++ 1) PCIe core working in clientmode ++ 2) PCIe Gen 2 clientmode core ++ ++ In general PCIe (Gen 2) clientmode core is required on PCIe ++ hosted buses. It's responsible for initialization and basic ++ hardware management. ++ This driver is also prerequisite for a hostmode PCIe core ++ support. ++ + config BCMA_DRIVER_MIPS + bool "BCMA Broadcom MIPS core driver" + depends on BCMA && MIPS +--- a/drivers/bcma/Makefile ++++ b/drivers/bcma/Makefile +@@ -3,8 +3,8 @@ bcma-y += driver_chipcommon.o driver + bcma-y += driver_chipcommon_b.o + bcma-$(CONFIG_BCMA_SFLASH) += driver_chipcommon_sflash.o + bcma-$(CONFIG_BCMA_NFLASH) += driver_chipcommon_nflash.o +-bcma-y += driver_pci.o +-bcma-y += driver_pcie2.o ++bcma-$(CONFIG_BCMA_DRIVER_PCI) += driver_pci.o ++bcma-$(CONFIG_BCMA_DRIVER_PCI) += driver_pcie2.o + bcma-$(CONFIG_BCMA_DRIVER_PCI_HOSTMODE) += driver_pci_host.o + bcma-$(CONFIG_BCMA_DRIVER_MIPS) += driver_mips.o + bcma-$(CONFIG_BCMA_DRIVER_GMAC_CMN) += driver_gmac_cmn.o +--- a/include/linux/bcma/bcma_driver_chipcommon.h ++++ b/include/linux/bcma/bcma_driver_chipcommon.h +@@ -663,14 +663,6 @@ struct bcma_drv_cc_b { + #define bcma_cc_maskset32(cc, offset, mask, set) \ + bcma_cc_write32(cc, offset, (bcma_cc_read32(cc, offset) & (mask)) | (set)) + +-extern void bcma_core_chipcommon_init(struct bcma_drv_cc *cc); +-extern void bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc); +- +-extern void bcma_chipco_suspend(struct bcma_drv_cc *cc); +-extern void bcma_chipco_resume(struct bcma_drv_cc *cc); +- +-void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable); +- + extern u32 bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc, u32 ticks); + + extern u32 bcma_chipco_get_alp_clock(struct bcma_drv_cc *cc); +@@ -690,9 +682,6 @@ u32 bcma_chipco_gpio_pullup(struct bcma_ + u32 bcma_chipco_gpio_pulldown(struct bcma_drv_cc *cc, u32 mask, u32 value); + + /* PMU support */ +-extern void bcma_pmu_init(struct bcma_drv_cc *cc); +-extern void bcma_pmu_early_init(struct bcma_drv_cc *cc); +- + extern void bcma_chipco_pll_write(struct bcma_drv_cc *cc, u32 offset, + u32 value); + extern void bcma_chipco_pll_maskset(struct bcma_drv_cc *cc, u32 offset, +--- a/include/linux/bcma/bcma_driver_gmac_cmn.h ++++ b/include/linux/bcma/bcma_driver_gmac_cmn.h +@@ -91,10 +91,4 @@ struct bcma_drv_gmac_cmn { + #define gmac_cmn_write16(gc, offset, val) bcma_write16((gc)->core, offset, val) + #define gmac_cmn_write32(gc, offset, val) bcma_write32((gc)->core, offset, val) + +-#ifdef CONFIG_BCMA_DRIVER_GMAC_CMN +-extern void bcma_core_gmac_cmn_init(struct bcma_drv_gmac_cmn *gc); +-#else +-static inline void bcma_core_gmac_cmn_init(struct bcma_drv_gmac_cmn *gc) { } +-#endif +- + #endif /* LINUX_BCMA_DRIVER_GMAC_CMN_H_ */ +--- a/include/linux/bcma/bcma_driver_mips.h ++++ b/include/linux/bcma/bcma_driver_mips.h +@@ -39,21 +39,6 @@ struct bcma_drv_mips { + u8 early_setup_done:1; + }; + +-#ifdef CONFIG_BCMA_DRIVER_MIPS +-extern void bcma_core_mips_init(struct bcma_drv_mips *mcore); +-extern void bcma_core_mips_early_init(struct bcma_drv_mips *mcore); +- +-extern unsigned int bcma_core_mips_irq(struct bcma_device *dev); +-#else +-static inline void bcma_core_mips_init(struct bcma_drv_mips *mcore) { } +-static inline void bcma_core_mips_early_init(struct bcma_drv_mips *mcore) { } +- +-static inline unsigned int bcma_core_mips_irq(struct bcma_device *dev) +-{ +- return 0; +-} +-#endif +- + extern u32 bcma_cpu_clock(struct bcma_drv_mips *mcore); + + #endif /* LINUX_BCMA_DRIVER_MIPS_H_ */ diff --git a/target/linux/generic/patches-4.0/021-ssb_sprom.patch b/target/linux/generic/patches-4.0/021-ssb_sprom.patch new file mode 100644 index 0000000..52d8080 --- /dev/null +++ b/target/linux/generic/patches-4.0/021-ssb_sprom.patch @@ -0,0 +1,32 @@ +--- a/include/linux/ssb/ssb.h ++++ b/include/linux/ssb/ssb.h +@@ -29,10 +29,13 @@ struct ssb_sprom { + u8 il0mac[6] __aligned(sizeof(u16)); /* MAC address for 802.11b/g */ + u8 et0mac[6] __aligned(sizeof(u16)); /* MAC address for Ethernet */ + u8 et1mac[6] __aligned(sizeof(u16)); /* MAC address for 802.11a */ ++ u8 et2mac[6] __aligned(sizeof(u16)); /* MAC address for extra Ethernet */ + u8 et0phyaddr; /* MII address for enet0 */ + u8 et1phyaddr; /* MII address for enet1 */ ++ u8 et2phyaddr; /* MII address for enet2 */ + u8 et0mdcport; /* MDIO for enet0 */ + u8 et1mdcport; /* MDIO for enet1 */ ++ u8 et2mdcport; /* MDIO for enet2 */ + u16 dev_id; /* Device ID overriding e.g. PCI ID */ + u16 board_rev; /* Board revision number from SPROM. */ + u16 board_num; /* Board number from SPROM. */ +@@ -88,11 +91,14 @@ struct ssb_sprom { + u32 ofdm5glpo; /* 5.2GHz OFDM power offset */ + u32 ofdm5gpo; /* 5.3GHz OFDM power offset */ + u32 ofdm5ghpo; /* 5.8GHz OFDM power offset */ ++ u32 boardflags; ++ u32 boardflags2; ++ u32 boardflags3; ++ /* TODO: Switch all drivers to new u32 fields and drop below ones */ + u16 boardflags_lo; /* Board flags (bits 0-15) */ + u16 boardflags_hi; /* Board flags (bits 16-31) */ + u16 boardflags2_lo; /* Board flags (bits 32-47) */ + u16 boardflags2_hi; /* Board flags (bits 48-63) */ +- /* TODO store board flags in a single u64 */ + + struct ssb_sprom_core_pwr_info core_pwr_info[4]; + diff --git a/target/linux/generic/patches-4.0/022-bcma-from-4.2.patch b/target/linux/generic/patches-4.0/022-bcma-from-4.2.patch new file mode 100644 index 0000000..ba3df18 --- /dev/null +++ b/target/linux/generic/patches-4.0/022-bcma-from-4.2.patch @@ -0,0 +1,86 @@ +--- a/drivers/bcma/driver_gpio.c ++++ b/drivers/bcma/driver_gpio.c +@@ -226,6 +226,7 @@ int bcma_gpio_init(struct bcma_drv_cc *c + chip->of_node = cc->core->dev.of_node; + #endif + switch (bus->chipinfo.id) { ++ case BCMA_CHIP_ID_BCM4707: + case BCMA_CHIP_ID_BCM5357: + case BCMA_CHIP_ID_BCM53572: + chip->ngpio = 32; +@@ -235,16 +236,17 @@ int bcma_gpio_init(struct bcma_drv_cc *c + } + + /* +- * On MIPS we register GPIO devices (LEDs, buttons) using absolute GPIO +- * pin numbers. We don't have Device Tree there and we can't really use +- * relative (per chip) numbers. +- * So let's use predictable base for BCM47XX and "random" for all other. ++ * Register SoC GPIO devices with absolute GPIO pin base. ++ * On MIPS, we don't have Device Tree and we can't use relative (per chip) ++ * GPIO numbers. ++ * On some ARM devices, user space may want to access some system GPIO ++ * pins directly, which is easier to do with a predictable GPIO base. + */ +-#if IS_BUILTIN(CONFIG_BCM47XX) +- chip->base = bus->num * BCMA_GPIO_MAX_PINS; +-#else +- chip->base = -1; +-#endif ++ if (IS_BUILTIN(CONFIG_BCM47XX) || ++ cc->core->bus->hosttype == BCMA_HOSTTYPE_SOC) ++ chip->base = bus->num * BCMA_GPIO_MAX_PINS; ++ else ++ chip->base = -1; + + err = bcma_gpio_irq_domain_init(cc); + if (err) +--- a/drivers/bcma/Kconfig ++++ b/drivers/bcma/Kconfig +@@ -29,12 +29,6 @@ config BCMA_HOST_PCI + select BCMA_DRIVER_PCI + default y + +-config BCMA_DRIVER_PCI_HOSTMODE +- bool "Driver for PCI core working in hostmode" +- depends on BCMA && MIPS && BCMA_HOST_PCI +- help +- PCI core hostmode operation (external PCI bus). +- + config BCMA_HOST_SOC + bool "Support for BCMA in a SoC" + depends on BCMA +@@ -61,6 +55,12 @@ config BCMA_DRIVER_PCI + This driver is also prerequisite for a hostmode PCIe core + support. + ++config BCMA_DRIVER_PCI_HOSTMODE ++ bool "Driver for PCI core working in hostmode" ++ depends on BCMA && MIPS && BCMA_DRIVER_PCI ++ help ++ PCI core hostmode operation (external PCI bus). ++ + config BCMA_DRIVER_MIPS + bool "BCMA Broadcom MIPS core driver" + depends on BCMA && MIPS +--- a/include/linux/bcma/bcma_driver_pci.h ++++ b/include/linux/bcma/bcma_driver_pci.h +@@ -246,7 +246,18 @@ static inline void bcma_core_pci_power_s + } + #endif + ++#ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE + extern int bcma_core_pci_pcibios_map_irq(const struct pci_dev *dev); + extern int bcma_core_pci_plat_dev_init(struct pci_dev *dev); ++#else ++static inline int bcma_core_pci_pcibios_map_irq(const struct pci_dev *dev) ++{ ++ return -ENOTSUPP; ++} ++static inline int bcma_core_pci_plat_dev_init(struct pci_dev *dev) ++{ ++ return -ENOTSUPP; ++} ++#endif + + #endif /* LINUX_BCMA_DRIVER_PCI_H_ */ diff --git a/target/linux/generic/patches-4.0/050-backport_netfilter_rtcache.patch b/target/linux/generic/patches-4.0/050-backport_netfilter_rtcache.patch new file mode 100644 index 0000000..f4783fd --- /dev/null +++ b/target/linux/generic/patches-4.0/050-backport_netfilter_rtcache.patch @@ -0,0 +1,509 @@ +Subject: netfilter: conntrack: cache route for forwarded connections + +... to avoid per-packet FIB lookup if possible. + +The cached dst is re-used provided the input interface +is the same as that of the previous packet in the same direction. + +If not, the cached dst is invalidated. + +For ipv6 we also need to store sernum, else dst_check doesn't work, +pointed out by Eric Dumazet. + +This should speed up forwarding when conntrack is already in use +anyway, especially when using reverse path filtering -- active RPF +enforces two FIB lookups for each packet. + +Before the routing cache removal this didn't matter since RPF was performed +only when route cache didn't yield a result; but without route cache it +comes at higher price. + +Julian Anastasov suggested to add NETDEV_UNREGISTER handler to +avoid holding on to dsts of 'frozen' conntracks. + +Signed-off-by: Florian Westphal + +--- a/include/net/netfilter/nf_conntrack_extend.h ++++ b/include/net/netfilter/nf_conntrack_extend.h +@@ -30,6 +30,9 @@ enum nf_ct_ext_id { + #if IS_ENABLED(CONFIG_NETFILTER_SYNPROXY) + NF_CT_EXT_SYNPROXY, + #endif ++#if IS_ENABLED(CONFIG_NF_CONNTRACK_RTCACHE) ++ NF_CT_EXT_RTCACHE, ++#endif + NF_CT_EXT_NUM, + }; + +@@ -43,6 +46,7 @@ enum nf_ct_ext_id { + #define NF_CT_EXT_TIMEOUT_TYPE struct nf_conn_timeout + #define NF_CT_EXT_LABELS_TYPE struct nf_conn_labels + #define NF_CT_EXT_SYNPROXY_TYPE struct nf_conn_synproxy ++#define NF_CT_EXT_RTCACHE_TYPE struct nf_conn_rtcache + + /* Extensions: optional stuff which isn't permanently in struct. */ + struct nf_ct_ext { +--- /dev/null ++++ b/include/net/netfilter/nf_conntrack_rtcache.h +@@ -0,0 +1,34 @@ ++#include ++#include ++#include ++ ++struct dst_entry; ++ ++struct nf_conn_dst_cache { ++ struct dst_entry *dst; ++ int iif; ++#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6) ++ u32 cookie; ++#endif ++ ++}; ++ ++struct nf_conn_rtcache { ++ struct nf_conn_dst_cache cached_dst[IP_CT_DIR_MAX]; ++}; ++ ++static inline ++struct nf_conn_rtcache *nf_ct_rtcache_find(const struct nf_conn *ct) ++{ ++#if IS_ENABLED(CONFIG_NF_CONNTRACK_RTCACHE) ++ return nf_ct_ext_find(ct, NF_CT_EXT_RTCACHE); ++#else ++ return NULL; ++#endif ++} ++ ++static inline int nf_conn_rtcache_iif_get(const struct nf_conn_rtcache *rtc, ++ enum ip_conntrack_dir dir) ++{ ++ return rtc->cached_dst[dir].iif; ++} +--- a/net/netfilter/Kconfig ++++ b/net/netfilter/Kconfig +@@ -106,6 +106,18 @@ config NF_CONNTRACK_EVENTS + + If unsure, say `N'. + ++config NF_CONNTRACK_RTCACHE ++ tristate "Cache route entries in conntrack objects" ++ depends on NETFILTER_ADVANCED ++ depends on NF_CONNTRACK ++ help ++ If this option is enabled, the connection tracking code will ++ cache routing information for each connection that is being ++ forwarded, at a cost of 32 bytes per conntrack object. ++ ++ To compile it as a module, choose M here. If unsure, say N. ++ The module will be called nf_conntrack_rtcache. ++ + config NF_CONNTRACK_TIMEOUT + bool 'Connection tracking timeout' + depends on NETFILTER_ADVANCED +--- a/net/netfilter/Makefile ++++ b/net/netfilter/Makefile +@@ -18,6 +18,9 @@ obj-$(CONFIG_NETFILTER_NETLINK_LOG) += n + # connection tracking + obj-$(CONFIG_NF_CONNTRACK) += nf_conntrack.o + ++# optional conntrack route cache extension ++obj-$(CONFIG_NF_CONNTRACK_RTCACHE) += nf_conntrack_rtcache.o ++ + # SCTP protocol connection tracking + obj-$(CONFIG_NF_CT_PROTO_DCCP) += nf_conntrack_proto_dccp.o + obj-$(CONFIG_NF_CT_PROTO_GRE) += nf_conntrack_proto_gre.o +--- /dev/null ++++ b/net/netfilter/nf_conntrack_rtcache.c +@@ -0,0 +1,391 @@ ++/* route cache for netfilter. ++ * ++ * (C) 2014 Red Hat GmbH ++ * ++ * 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. ++ */ ++ ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++#include ++#include ++#include ++ ++#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6) ++#include ++#endif ++ ++static void __nf_conn_rtcache_destroy(struct nf_conn_rtcache *rtc, ++ enum ip_conntrack_dir dir) ++{ ++ struct dst_entry *dst = rtc->cached_dst[dir].dst; ++ ++ dst_release(dst); ++} ++ ++static void nf_conn_rtcache_destroy(struct nf_conn *ct) ++{ ++ struct nf_conn_rtcache *rtc = nf_ct_rtcache_find(ct); ++ ++ if (!rtc) ++ return; ++ ++ __nf_conn_rtcache_destroy(rtc, IP_CT_DIR_ORIGINAL); ++ __nf_conn_rtcache_destroy(rtc, IP_CT_DIR_REPLY); ++} ++ ++static void nf_ct_rtcache_ext_add(struct nf_conn *ct) ++{ ++ struct nf_conn_rtcache *rtc; ++ ++ rtc = nf_ct_ext_add(ct, NF_CT_EXT_RTCACHE, GFP_ATOMIC); ++ if (rtc) { ++ rtc->cached_dst[IP_CT_DIR_ORIGINAL].iif = -1; ++ rtc->cached_dst[IP_CT_DIR_ORIGINAL].dst = NULL; ++ rtc->cached_dst[IP_CT_DIR_REPLY].iif = -1; ++ rtc->cached_dst[IP_CT_DIR_REPLY].dst = NULL; ++ } ++} ++ ++static struct nf_conn_rtcache *nf_ct_rtcache_find_usable(struct nf_conn *ct) ++{ ++ if (nf_ct_is_untracked(ct)) ++ return NULL; ++ return nf_ct_rtcache_find(ct); ++} ++ ++static struct dst_entry * ++nf_conn_rtcache_dst_get(const struct nf_conn_rtcache *rtc, ++ enum ip_conntrack_dir dir) ++{ ++ return rtc->cached_dst[dir].dst; ++} ++ ++static u32 nf_rtcache_get_cookie(int pf, const struct dst_entry *dst) ++{ ++#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6) ++ if (pf == NFPROTO_IPV6) { ++ const struct rt6_info *rt = (const struct rt6_info *)dst; ++ ++ if (rt->rt6i_node) ++ return (u32)rt->rt6i_node->fn_sernum; ++ } ++#endif ++ return 0; ++} ++ ++static void nf_conn_rtcache_dst_set(int pf, ++ struct nf_conn_rtcache *rtc, ++ struct dst_entry *dst, ++ enum ip_conntrack_dir dir, int iif) ++{ ++ if (rtc->cached_dst[dir].iif != iif) ++ rtc->cached_dst[dir].iif = iif; ++ ++ if (rtc->cached_dst[dir].dst != dst) { ++ struct dst_entry *old; ++ ++ dst_hold(dst); ++ ++ old = xchg(&rtc->cached_dst[dir].dst, dst); ++ dst_release(old); ++ ++#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6) ++ if (pf == NFPROTO_IPV6) ++ rtc->cached_dst[dir].cookie = ++ nf_rtcache_get_cookie(pf, dst); ++#endif ++ } ++} ++ ++static void nf_conn_rtcache_dst_obsolete(struct nf_conn_rtcache *rtc, ++ enum ip_conntrack_dir dir) ++{ ++ struct dst_entry *old; ++ ++ pr_debug("Invalidate iif %d for dir %d on cache %p\n", ++ rtc->cached_dst[dir].iif, dir, rtc); ++ ++ old = xchg(&rtc->cached_dst[dir].dst, NULL); ++ dst_release(old); ++ rtc->cached_dst[dir].iif = -1; ++} ++ ++static unsigned int nf_rtcache_in(const struct nf_hook_ops *ops, ++ struct sk_buff *skb, ++ const struct net_device *in, ++ const struct net_device *out, ++ int (*okfn)(struct sk_buff *)) ++{ ++ struct nf_conn_rtcache *rtc; ++ enum ip_conntrack_info ctinfo; ++ enum ip_conntrack_dir dir; ++ struct dst_entry *dst; ++ struct nf_conn *ct; ++ int iif; ++ u32 cookie; ++ ++ if (skb_dst(skb) || skb->sk) ++ return NF_ACCEPT; ++ ++ ct = nf_ct_get(skb, &ctinfo); ++ if (!ct) ++ return NF_ACCEPT; ++ ++ rtc = nf_ct_rtcache_find_usable(ct); ++ if (!rtc) ++ return NF_ACCEPT; ++ ++ /* if iif changes, don't use cache and let ip stack ++ * do route lookup. ++ * ++ * If rp_filter is enabled it might toss skb, so ++ * we don't want to avoid these checks. ++ */ ++ dir = CTINFO2DIR(ctinfo); ++ iif = nf_conn_rtcache_iif_get(rtc, dir); ++ if (in->ifindex != iif) { ++ pr_debug("ct %p, iif %d, cached iif %d, skip cached entry\n", ++ ct, iif, in->ifindex); ++ return NF_ACCEPT; ++ } ++ dst = nf_conn_rtcache_dst_get(rtc, dir); ++ if (dst == NULL) ++ return NF_ACCEPT; ++ ++ cookie = nf_rtcache_get_cookie(ops->pf, dst); ++ ++ dst = dst_check(dst, cookie); ++ pr_debug("obtained dst %p for skb %p, cookie %d\n", dst, skb, cookie); ++ if (likely(dst)) ++ skb_dst_set_noref(skb, dst); ++ else ++ nf_conn_rtcache_dst_obsolete(rtc, dir); ++ ++ return NF_ACCEPT; ++} ++ ++static unsigned int nf_rtcache_forward(const struct nf_hook_ops *ops, ++ struct sk_buff *skb, ++ const struct net_device *in, ++ const struct net_device *out, ++ int (*okfn)(struct sk_buff *)) ++{ ++ struct nf_conn_rtcache *rtc; ++ enum ip_conntrack_info ctinfo; ++ enum ip_conntrack_dir dir; ++ struct nf_conn *ct; ++ struct dst_entry *dst = skb_dst(skb); ++ int iif; ++ ++ ct = nf_ct_get(skb, &ctinfo); ++ if (!ct) ++ return NF_ACCEPT; ++ ++ if (dst && dst_xfrm(dst)) ++ return NF_ACCEPT; ++ ++ if (!nf_ct_is_confirmed(ct)) { ++ if (WARN_ON(nf_ct_rtcache_find(ct))) ++ return NF_ACCEPT; ++ nf_ct_rtcache_ext_add(ct); ++ return NF_ACCEPT; ++ } ++ ++ rtc = nf_ct_rtcache_find_usable(ct); ++ if (!rtc) ++ return NF_ACCEPT; ++ ++ dir = CTINFO2DIR(ctinfo); ++ iif = nf_conn_rtcache_iif_get(rtc, dir); ++ pr_debug("ct %p, skb %p, dir %d, iif %d, cached iif %d\n", ++ ct, skb, dir, iif, in->ifindex); ++ if (likely(in->ifindex == iif)) ++ return NF_ACCEPT; ++ ++ nf_conn_rtcache_dst_set(ops->pf, rtc, skb_dst(skb), dir, in->ifindex); ++ return NF_ACCEPT; ++} ++ ++static int nf_rtcache_dst_remove(struct nf_conn *ct, void *data) ++{ ++ struct nf_conn_rtcache *rtc = nf_ct_rtcache_find(ct); ++ struct net_device *dev = data; ++ ++ if (!rtc) ++ return 0; ++ ++ if (dev->ifindex == rtc->cached_dst[IP_CT_DIR_ORIGINAL].iif || ++ dev->ifindex == rtc->cached_dst[IP_CT_DIR_REPLY].iif) { ++ nf_conn_rtcache_dst_obsolete(rtc, IP_CT_DIR_ORIGINAL); ++ nf_conn_rtcache_dst_obsolete(rtc, IP_CT_DIR_REPLY); ++ } ++ ++ return 0; ++} ++ ++static int nf_rtcache_netdev_event(struct notifier_block *this, ++ unsigned long event, void *ptr) ++{ ++ struct net_device *dev = netdev_notifier_info_to_dev(ptr); ++ struct net *net = dev_net(dev); ++ ++ if (event == NETDEV_DOWN) ++ nf_ct_iterate_cleanup(net, nf_rtcache_dst_remove, dev, 0, 0); ++ ++ return NOTIFY_DONE; ++} ++ ++static struct notifier_block nf_rtcache_notifier = { ++ .notifier_call = nf_rtcache_netdev_event, ++}; ++ ++static struct nf_hook_ops rtcache_ops[] = { ++ { ++ .hook = nf_rtcache_in, ++ .owner = THIS_MODULE, ++ .pf = NFPROTO_IPV4, ++ .hooknum = NF_INET_PRE_ROUTING, ++ .priority = NF_IP_PRI_LAST, ++ }, ++ { ++ .hook = nf_rtcache_forward, ++ .owner = THIS_MODULE, ++ .pf = NFPROTO_IPV4, ++ .hooknum = NF_INET_FORWARD, ++ .priority = NF_IP_PRI_LAST, ++ }, ++#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6) ++ { ++ .hook = nf_rtcache_in, ++ .owner = THIS_MODULE, ++ .pf = NFPROTO_IPV6, ++ .hooknum = NF_INET_PRE_ROUTING, ++ .priority = NF_IP_PRI_LAST, ++ }, ++ { ++ .hook = nf_rtcache_forward, ++ .owner = THIS_MODULE, ++ .pf = NFPROTO_IPV6, ++ .hooknum = NF_INET_FORWARD, ++ .priority = NF_IP_PRI_LAST, ++ }, ++#endif ++}; ++ ++static struct nf_ct_ext_type rtcache_extend __read_mostly = { ++ .len = sizeof(struct nf_conn_rtcache), ++ .align = __alignof__(struct nf_conn_rtcache), ++ .id = NF_CT_EXT_RTCACHE, ++ .destroy = nf_conn_rtcache_destroy, ++}; ++ ++static int __init nf_conntrack_rtcache_init(void) ++{ ++ int ret = nf_ct_extend_register(&rtcache_extend); ++ ++ if (ret < 0) { ++ pr_err("nf_conntrack_rtcache: Unable to register extension\n"); ++ return ret; ++ } ++ ++ ret = nf_register_hooks(rtcache_ops, ARRAY_SIZE(rtcache_ops)); ++ if (ret < 0) { ++ nf_ct_extend_unregister(&rtcache_extend); ++ return ret; ++ } ++ ++ ret = register_netdevice_notifier(&nf_rtcache_notifier); ++ if (ret) { ++ nf_unregister_hooks(rtcache_ops, ARRAY_SIZE(rtcache_ops)); ++ nf_ct_extend_unregister(&rtcache_extend); ++ } ++ ++ return ret; ++} ++ ++static int nf_rtcache_ext_remove(struct nf_conn *ct, void *data) ++{ ++ struct nf_conn_rtcache *rtc = nf_ct_rtcache_find(ct); ++ ++ return rtc != NULL; ++} ++ ++static bool __exit nf_conntrack_rtcache_wait_for_dying(struct net *net) ++{ ++ bool wait = false; ++ int cpu; ++ ++ for_each_possible_cpu(cpu) { ++ struct nf_conntrack_tuple_hash *h; ++ struct hlist_nulls_node *n; ++ struct nf_conn *ct; ++ struct ct_pcpu *pcpu = per_cpu_ptr(net->ct.pcpu_lists, cpu); ++ ++ rcu_read_lock(); ++ spin_lock_bh(&pcpu->lock); ++ ++ hlist_nulls_for_each_entry(h, n, &pcpu->dying, hnnode) { ++ ct = nf_ct_tuplehash_to_ctrack(h); ++ if (nf_ct_rtcache_find(ct) != NULL) { ++ wait = true; ++ break; ++ } ++ } ++ spin_unlock_bh(&pcpu->lock); ++ rcu_read_unlock(); ++ } ++ ++ return wait; ++} ++ ++static void __exit nf_conntrack_rtcache_fini(void) ++{ ++ struct net *net; ++ int count = 0; ++ ++ /* remove hooks so no new connections get rtcache extension */ ++ nf_unregister_hooks(rtcache_ops, ARRAY_SIZE(rtcache_ops)); ++ ++ synchronize_net(); ++ ++ unregister_netdevice_notifier(&nf_rtcache_notifier); ++ ++ rtnl_lock(); ++ ++ /* zap all conntracks with rtcache extension */ ++ for_each_net(net) ++ nf_ct_iterate_cleanup(net, nf_rtcache_ext_remove, NULL, 0, 0); ++ ++ for_each_net(net) { ++ /* .. and make sure they're gone from dying list, too */ ++ while (nf_conntrack_rtcache_wait_for_dying(net)) { ++ msleep(200); ++ WARN_ONCE(++count > 25, "Waiting for all rtcache conntracks to go away\n"); ++ } ++ } ++ ++ rtnl_unlock(); ++ synchronize_net(); ++ nf_ct_extend_unregister(&rtcache_extend); ++} ++module_init(nf_conntrack_rtcache_init); ++module_exit(nf_conntrack_rtcache_fini); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Florian Westphal "); ++MODULE_DESCRIPTION("Conntrack route cache extension"); diff --git a/target/linux/generic/patches-4.0/060-mips_decompressor_memmove.patch b/target/linux/generic/patches-4.0/060-mips_decompressor_memmove.patch new file mode 100644 index 0000000..d215b80 --- /dev/null +++ b/target/linux/generic/patches-4.0/060-mips_decompressor_memmove.patch @@ -0,0 +1,22 @@ +--- a/arch/mips/boot/compressed/string.c ++++ b/arch/mips/boot/compressed/string.c +@@ -26,3 +26,19 @@ void *memset(void *s, int c, size_t n) + ss[i] = c; + return s; + } ++ ++void *memmove(void *__dest, __const void *__src, size_t count) ++{ ++ unsigned char *d = __dest; ++ const unsigned char *s = __src; ++ ++ if (__dest == __src) ++ return __dest; ++ ++ if (__dest < __src) ++ return memcpy(__dest, __src, count); ++ ++ while (count--) ++ d[count] = s[count]; ++ return __dest; ++} diff --git a/target/linux/generic/patches-4.0/070-bgmac-register-fixed-PHY-for-ARM-BCM470X-BCM5301X-ch.patch b/target/linux/generic/patches-4.0/070-bgmac-register-fixed-PHY-for-ARM-BCM470X-BCM5301X-ch.patch new file mode 100644 index 0000000..9f0baff --- /dev/null +++ b/target/linux/generic/patches-4.0/070-bgmac-register-fixed-PHY-for-ARM-BCM470X-BCM5301X-ch.patch @@ -0,0 +1,76 @@ +From c25b23b8a387e7d31f7a74af8e37b61e9e6ebb21 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Fri, 20 Mar 2015 23:14:31 +0100 +Subject: [PATCH] bgmac: register fixed PHY for ARM BCM470X / BCM5301X chipsets +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +On ARM SoCs with bgmac Ethernet hardware we don't have any normal PHY. +There is always a switch attached but it's not even controlled over MDIO +like in case of MIPS devices. +We need a fixed PHY to be able to send/receive packets from the switch. + +Signed-off-by: Rafał Miłecki +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/broadcom/bgmac.c | 34 ++++++++++++++++++++++++++++++++++ + 1 file changed, 34 insertions(+) + +--- a/drivers/net/ethernet/broadcom/bgmac.c ++++ b/drivers/net/ethernet/broadcom/bgmac.c +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -1330,13 +1331,46 @@ static void bgmac_adjust_link(struct net + } + } + ++static int bgmac_fixed_phy_register(struct bgmac *bgmac) ++{ ++ struct fixed_phy_status fphy_status = { ++ .link = 1, ++ .speed = SPEED_1000, ++ .duplex = DUPLEX_FULL, ++ }; ++ struct phy_device *phy_dev; ++ int err; ++ ++ phy_dev = fixed_phy_register(PHY_POLL, &fphy_status, NULL); ++ if (!phy_dev || IS_ERR(phy_dev)) { ++ bgmac_err(bgmac, "Failed to register fixed PHY device\n"); ++ return -ENODEV; ++ } ++ ++ err = phy_connect_direct(bgmac->net_dev, phy_dev, bgmac_adjust_link, ++ PHY_INTERFACE_MODE_MII); ++ if (err) { ++ bgmac_err(bgmac, "Connecting PHY failed\n"); ++ return err; ++ } ++ ++ bgmac->phy_dev = phy_dev; ++ ++ return err; ++} ++ + static int bgmac_mii_register(struct bgmac *bgmac) + { ++ struct bcma_chipinfo *ci = &bgmac->core->bus->chipinfo; + struct mii_bus *mii_bus; + struct phy_device *phy_dev; + char bus_id[MII_BUS_ID_SIZE + 3]; + int i, err = 0; + ++ if (ci->id == BCMA_CHIP_ID_BCM4707 || ++ ci->id == BCMA_CHIP_ID_BCM53018) ++ return bgmac_fixed_phy_register(bgmac); ++ + mii_bus = mdiobus_alloc(); + if (!mii_bus) + return -ENOMEM; diff --git a/target/linux/generic/patches-4.0/071-bgmac-allow-enabling-on-ARCH_BCM_5301X.patch b/target/linux/generic/patches-4.0/071-bgmac-allow-enabling-on-ARCH_BCM_5301X.patch new file mode 100644 index 0000000..3c5b79d --- /dev/null +++ b/target/linux/generic/patches-4.0/071-bgmac-allow-enabling-on-ARCH_BCM_5301X.patch @@ -0,0 +1,28 @@ +From fc300dc3733fdc328e6e10c7b8379b60c26cd648 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Fri, 20 Mar 2015 23:14:32 +0100 +Subject: [PATCH] bgmac: allow enabling on ARCH_BCM_5301X +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Home routers based on ARM SoCs like BCM4708 also have bcma bus with core +supported by bgmac. + +Signed-off-by: Rafał Miłecki +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/broadcom/Kconfig | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/ethernet/broadcom/Kconfig ++++ b/drivers/net/ethernet/broadcom/Kconfig +@@ -142,7 +142,7 @@ config BNX2X_SRIOV + + config BGMAC + tristate "BCMA bus GBit core support" +- depends on BCMA_HOST_SOC && HAS_DMA && BCM47XX ++ depends on BCMA_HOST_SOC && HAS_DMA && (BCM47XX || ARCH_BCM_5301X) + select PHYLIB + ---help--- + This driver supports GBit MAC and BCM4706 GBit MAC cores on BCMA bus. diff --git a/target/linux/generic/patches-4.0/072-01-bgmac-fix-descriptor-frame-start-end-definitions.patch b/target/linux/generic/patches-4.0/072-01-bgmac-fix-descriptor-frame-start-end-definitions.patch new file mode 100644 index 0000000..fdfae3a --- /dev/null +++ b/target/linux/generic/patches-4.0/072-01-bgmac-fix-descriptor-frame-start-end-definitions.patch @@ -0,0 +1,24 @@ +From: Felix Fietkau +Date: Mon, 23 Mar 2015 02:40:06 +0100 +Subject: [PATCH] bgmac: fix descriptor frame start/end definitions + +The start-of-frame and end-of-frame bits were accidentally swapped. +In the current code it does not make any difference, since they are +always used together. + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/broadcom/bgmac.h ++++ b/drivers/net/ethernet/broadcom/bgmac.h +@@ -345,8 +345,8 @@ + + #define BGMAC_DESC_CTL0_EOT 0x10000000 /* End of ring */ + #define BGMAC_DESC_CTL0_IOC 0x20000000 /* IRQ on complete */ +-#define BGMAC_DESC_CTL0_SOF 0x40000000 /* Start of frame */ +-#define BGMAC_DESC_CTL0_EOF 0x80000000 /* End of frame */ ++#define BGMAC_DESC_CTL0_EOF 0x40000000 /* End of frame */ ++#define BGMAC_DESC_CTL0_SOF 0x80000000 /* Start of frame */ + #define BGMAC_DESC_CTL1_LEN 0x00001FFF + + #define BGMAC_PHY_NOREGS 0x1E diff --git a/target/linux/generic/patches-4.0/072-02-bgmac-implement-GRO-and-use-build_skb.patch b/target/linux/generic/patches-4.0/072-02-bgmac-implement-GRO-and-use-build_skb.patch new file mode 100644 index 0000000..2a2df60 --- /dev/null +++ b/target/linux/generic/patches-4.0/072-02-bgmac-implement-GRO-and-use-build_skb.patch @@ -0,0 +1,189 @@ +From: Felix Fietkau +Date: Mon, 23 Mar 2015 02:41:25 +0100 +Subject: [PATCH] bgmac: implement GRO and use build_skb + +This improves performance for routing and local rx + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/broadcom/bgmac.c ++++ b/drivers/net/ethernet/broadcom/bgmac.c +@@ -276,31 +276,31 @@ static int bgmac_dma_rx_skb_for_slot(str + struct bgmac_slot_info *slot) + { + struct device *dma_dev = bgmac->core->dma_dev; +- struct sk_buff *skb; + dma_addr_t dma_addr; + struct bgmac_rx_header *rx; ++ void *buf; + + /* Alloc skb */ +- skb = netdev_alloc_skb(bgmac->net_dev, BGMAC_RX_BUF_SIZE); +- if (!skb) ++ buf = netdev_alloc_frag(BGMAC_RX_ALLOC_SIZE); ++ if (!buf) + return -ENOMEM; + + /* Poison - if everything goes fine, hardware will overwrite it */ +- rx = (struct bgmac_rx_header *)skb->data; ++ rx = buf; + rx->len = cpu_to_le16(0xdead); + rx->flags = cpu_to_le16(0xbeef); + + /* Map skb for the DMA */ +- dma_addr = dma_map_single(dma_dev, skb->data, +- BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE); ++ dma_addr = dma_map_single(dma_dev, buf, BGMAC_RX_BUF_SIZE, ++ DMA_FROM_DEVICE); + if (dma_mapping_error(dma_dev, dma_addr)) { + bgmac_err(bgmac, "DMA mapping error\n"); +- dev_kfree_skb(skb); ++ put_page(virt_to_head_page(buf)); + return -ENOMEM; + } + + /* Update the slot */ +- slot->skb = skb; ++ slot->buf = buf; + slot->dma_addr = dma_addr; + + return 0; +@@ -343,8 +343,9 @@ static int bgmac_dma_rx_read(struct bgma + while (ring->start != ring->end) { + struct device *dma_dev = bgmac->core->dma_dev; + struct bgmac_slot_info *slot = &ring->slots[ring->start]; +- struct sk_buff *skb = slot->skb; +- struct bgmac_rx_header *rx; ++ struct bgmac_rx_header *rx = slot->buf; ++ struct sk_buff *skb; ++ void *buf = slot->buf; + u16 len, flags; + + /* Unmap buffer to make it accessible to the CPU */ +@@ -352,7 +353,6 @@ static int bgmac_dma_rx_read(struct bgma + BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE); + + /* Get info from the header */ +- rx = (struct bgmac_rx_header *)skb->data; + len = le16_to_cpu(rx->len); + flags = le16_to_cpu(rx->flags); + +@@ -393,12 +393,13 @@ static int bgmac_dma_rx_read(struct bgma + dma_unmap_single(dma_dev, old_dma_addr, + BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE); + ++ skb = build_skb(buf, BGMAC_RX_ALLOC_SIZE); + skb_put(skb, BGMAC_RX_FRAME_OFFSET + len); + skb_pull(skb, BGMAC_RX_FRAME_OFFSET); + + skb_checksum_none_assert(skb); + skb->protocol = eth_type_trans(skb, bgmac->net_dev); +- netif_receive_skb(skb); ++ napi_gro_receive(&bgmac->napi, skb); + handled++; + } while (0); + +@@ -434,12 +435,11 @@ static bool bgmac_dma_unaligned(struct b + return false; + } + +-static void bgmac_dma_ring_free(struct bgmac *bgmac, +- struct bgmac_dma_ring *ring) ++static void bgmac_dma_tx_ring_free(struct bgmac *bgmac, ++ struct bgmac_dma_ring *ring) + { + struct device *dma_dev = bgmac->core->dma_dev; + struct bgmac_slot_info *slot; +- int size; + int i; + + for (i = 0; i < ring->num_slots; i++) { +@@ -451,23 +451,55 @@ static void bgmac_dma_ring_free(struct b + dev_kfree_skb(slot->skb); + } + } ++} ++ ++static void bgmac_dma_rx_ring_free(struct bgmac *bgmac, ++ struct bgmac_dma_ring *ring) ++{ ++ struct device *dma_dev = bgmac->core->dma_dev; ++ struct bgmac_slot_info *slot; ++ int i; ++ ++ for (i = 0; i < ring->num_slots; i++) { ++ slot = &ring->slots[i]; ++ if (!slot->buf) ++ continue; + +- if (ring->cpu_base) { +- /* Free ring of descriptors */ +- size = ring->num_slots * sizeof(struct bgmac_dma_desc); +- dma_free_coherent(dma_dev, size, ring->cpu_base, +- ring->dma_base); ++ if (slot->dma_addr) ++ dma_unmap_single(dma_dev, slot->dma_addr, ++ BGMAC_RX_BUF_SIZE, ++ DMA_FROM_DEVICE); ++ put_page(virt_to_head_page(slot->buf)); + } + } + ++static void bgmac_dma_ring_desc_free(struct bgmac *bgmac, ++ struct bgmac_dma_ring *ring) ++{ ++ struct device *dma_dev = bgmac->core->dma_dev; ++ int size; ++ ++ if (!ring->cpu_base) ++ return; ++ ++ /* Free ring of descriptors */ ++ size = ring->num_slots * sizeof(struct bgmac_dma_desc); ++ dma_free_coherent(dma_dev, size, ring->cpu_base, ++ ring->dma_base); ++} ++ + static void bgmac_dma_free(struct bgmac *bgmac) + { + int i; + +- for (i = 0; i < BGMAC_MAX_TX_RINGS; i++) +- bgmac_dma_ring_free(bgmac, &bgmac->tx_ring[i]); +- for (i = 0; i < BGMAC_MAX_RX_RINGS; i++) +- bgmac_dma_ring_free(bgmac, &bgmac->rx_ring[i]); ++ for (i = 0; i < BGMAC_MAX_TX_RINGS; i++) { ++ bgmac_dma_tx_ring_free(bgmac, &bgmac->tx_ring[i]); ++ bgmac_dma_ring_desc_free(bgmac, &bgmac->tx_ring[i]); ++ } ++ for (i = 0; i < BGMAC_MAX_RX_RINGS; i++) { ++ bgmac_dma_rx_ring_free(bgmac, &bgmac->rx_ring[i]); ++ bgmac_dma_ring_desc_free(bgmac, &bgmac->rx_ring[i]); ++ } + } + + static int bgmac_dma_alloc(struct bgmac *bgmac) +--- a/drivers/net/ethernet/broadcom/bgmac.h ++++ b/drivers/net/ethernet/broadcom/bgmac.h +@@ -362,6 +362,8 @@ + #define BGMAC_RX_FRAME_OFFSET 30 /* There are 2 unused bytes between header and real data */ + #define BGMAC_RX_MAX_FRAME_SIZE 1536 /* Copied from b44/tg3 */ + #define BGMAC_RX_BUF_SIZE (BGMAC_RX_FRAME_OFFSET + BGMAC_RX_MAX_FRAME_SIZE) ++#define BGMAC_RX_ALLOC_SIZE (SKB_DATA_ALIGN(BGMAC_RX_BUF_SIZE) + \ ++ SKB_DATA_ALIGN(sizeof(struct skb_shared_info))) + + #define BGMAC_BFL_ENETROBO 0x0010 /* has ephy roboswitch spi */ + #define BGMAC_BFL_ENETADM 0x0080 /* has ADMtek switch */ +@@ -383,7 +385,10 @@ + #define ETHER_MAX_LEN 1518 + + struct bgmac_slot_info { +- struct sk_buff *skb; ++ union { ++ struct sk_buff *skb; ++ void *buf; ++ }; + dma_addr_t dma_addr; + }; + diff --git a/target/linux/generic/patches-4.0/072-03-bgmac-implement-scatter-gather-support.patch b/target/linux/generic/patches-4.0/072-03-bgmac-implement-scatter-gather-support.patch new file mode 100644 index 0000000..5cb21a5 --- /dev/null +++ b/target/linux/generic/patches-4.0/072-03-bgmac-implement-scatter-gather-support.patch @@ -0,0 +1,267 @@ +From: Felix Fietkau +Date: Mon, 23 Mar 2015 02:42:26 +0100 +Subject: [PATCH] bgmac: implement scatter/gather support + +Always use software checksumming, since the hardware does not have any +checksum offload support. +This significantly improves local TCP tx performance. + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/broadcom/bgmac.c ++++ b/drivers/net/ethernet/broadcom/bgmac.c +@@ -115,53 +115,91 @@ static void bgmac_dma_tx_enable(struct b + bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_TX_CTL, ctl); + } + ++static void ++bgmac_dma_tx_add_buf(struct bgmac *bgmac, struct bgmac_dma_ring *ring, ++ int i, int len, u32 ctl0) ++{ ++ struct bgmac_slot_info *slot; ++ struct bgmac_dma_desc *dma_desc; ++ u32 ctl1; ++ ++ if (i == ring->num_slots - 1) ++ ctl0 |= BGMAC_DESC_CTL0_EOT; ++ ++ ctl1 = len & BGMAC_DESC_CTL1_LEN; ++ ++ slot = &ring->slots[i]; ++ dma_desc = &ring->cpu_base[i]; ++ dma_desc->addr_low = cpu_to_le32(lower_32_bits(slot->dma_addr)); ++ dma_desc->addr_high = cpu_to_le32(upper_32_bits(slot->dma_addr)); ++ dma_desc->ctl0 = cpu_to_le32(ctl0); ++ dma_desc->ctl1 = cpu_to_le32(ctl1); ++} ++ + static netdev_tx_t bgmac_dma_tx_add(struct bgmac *bgmac, + struct bgmac_dma_ring *ring, + struct sk_buff *skb) + { + struct device *dma_dev = bgmac->core->dma_dev; + struct net_device *net_dev = bgmac->net_dev; +- struct bgmac_dma_desc *dma_desc; +- struct bgmac_slot_info *slot; +- u32 ctl0, ctl1; ++ struct bgmac_slot_info *slot = &ring->slots[ring->end]; + int free_slots; ++ int nr_frags; ++ u32 flags; ++ int index = ring->end; ++ int i; + + if (skb->len > BGMAC_DESC_CTL1_LEN) { + bgmac_err(bgmac, "Too long skb (%d)\n", skb->len); +- goto err_stop_drop; ++ goto err_drop; + } + ++ if (skb->ip_summed == CHECKSUM_PARTIAL) ++ skb_checksum_help(skb); ++ ++ nr_frags = skb_shinfo(skb)->nr_frags; ++ + if (ring->start <= ring->end) + free_slots = ring->start - ring->end + BGMAC_TX_RING_SLOTS; + else + free_slots = ring->start - ring->end; +- if (free_slots == 1) { ++ ++ if (free_slots <= nr_frags + 1) { + bgmac_err(bgmac, "TX ring is full, queue should be stopped!\n"); + netif_stop_queue(net_dev); + return NETDEV_TX_BUSY; + } + +- slot = &ring->slots[ring->end]; +- slot->skb = skb; +- slot->dma_addr = dma_map_single(dma_dev, skb->data, skb->len, ++ slot->dma_addr = dma_map_single(dma_dev, skb->data, skb_headlen(skb), + DMA_TO_DEVICE); +- if (dma_mapping_error(dma_dev, slot->dma_addr)) { +- bgmac_err(bgmac, "Mapping error of skb on ring 0x%X\n", +- ring->mmio_base); +- goto err_stop_drop; +- } ++ if (unlikely(dma_mapping_error(dma_dev, slot->dma_addr))) ++ goto err_dma_head; + +- ctl0 = BGMAC_DESC_CTL0_IOC | BGMAC_DESC_CTL0_SOF | BGMAC_DESC_CTL0_EOF; +- if (ring->end == ring->num_slots - 1) +- ctl0 |= BGMAC_DESC_CTL0_EOT; +- ctl1 = skb->len & BGMAC_DESC_CTL1_LEN; ++ flags = BGMAC_DESC_CTL0_SOF; ++ if (!nr_frags) ++ flags |= BGMAC_DESC_CTL0_EOF | BGMAC_DESC_CTL0_IOC; ++ ++ bgmac_dma_tx_add_buf(bgmac, ring, index, skb_headlen(skb), flags); ++ flags = 0; ++ ++ for (i = 0; i < nr_frags; i++) { ++ struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i]; ++ int len = skb_frag_size(frag); ++ ++ index = (index + 1) % BGMAC_TX_RING_SLOTS; ++ slot = &ring->slots[index]; ++ slot->dma_addr = skb_frag_dma_map(dma_dev, frag, 0, ++ len, DMA_TO_DEVICE); ++ if (unlikely(dma_mapping_error(dma_dev, slot->dma_addr))) ++ goto err_dma; + +- dma_desc = ring->cpu_base; +- dma_desc += ring->end; +- dma_desc->addr_low = cpu_to_le32(lower_32_bits(slot->dma_addr)); +- dma_desc->addr_high = cpu_to_le32(upper_32_bits(slot->dma_addr)); +- dma_desc->ctl0 = cpu_to_le32(ctl0); +- dma_desc->ctl1 = cpu_to_le32(ctl1); ++ if (i == nr_frags - 1) ++ flags |= BGMAC_DESC_CTL0_EOF | BGMAC_DESC_CTL0_IOC; ++ ++ bgmac_dma_tx_add_buf(bgmac, ring, index, len, flags); ++ } ++ ++ slot->skb = skb; + + netdev_sent_queue(net_dev, skb->len); + +@@ -170,20 +208,35 @@ static netdev_tx_t bgmac_dma_tx_add(stru + /* Increase ring->end to point empty slot. We tell hardware the first + * slot it should *not* read. + */ +- if (++ring->end >= BGMAC_TX_RING_SLOTS) +- ring->end = 0; ++ ring->end = (index + 1) % BGMAC_TX_RING_SLOTS; + bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_TX_INDEX, + ring->index_base + + ring->end * sizeof(struct bgmac_dma_desc)); + +- /* Always keep one slot free to allow detecting bugged calls. */ +- if (--free_slots == 1) ++ free_slots -= nr_frags + 1; ++ if (free_slots < 8) + netif_stop_queue(net_dev); + + return NETDEV_TX_OK; + +-err_stop_drop: +- netif_stop_queue(net_dev); ++err_dma: ++ dma_unmap_single(dma_dev, slot->dma_addr, skb_headlen(skb), ++ DMA_TO_DEVICE); ++ ++ while (i > 0) { ++ int index = (ring->end + i) % BGMAC_TX_RING_SLOTS; ++ struct bgmac_slot_info *slot = &ring->slots[index]; ++ u32 ctl1 = le32_to_cpu(ring->cpu_base[index].ctl1); ++ int len = ctl1 & BGMAC_DESC_CTL1_LEN; ++ ++ dma_unmap_page(dma_dev, slot->dma_addr, len, DMA_TO_DEVICE); ++ } ++ ++err_dma_head: ++ bgmac_err(bgmac, "Mapping error of skb on ring 0x%X\n", ++ ring->mmio_base); ++ ++err_drop: + dev_kfree_skb(skb); + return NETDEV_TX_OK; + } +@@ -205,32 +258,45 @@ static void bgmac_dma_tx_free(struct bgm + + while (ring->start != empty_slot) { + struct bgmac_slot_info *slot = &ring->slots[ring->start]; ++ u32 ctl1 = le32_to_cpu(ring->cpu_base[ring->start].ctl1); ++ int len = ctl1 & BGMAC_DESC_CTL1_LEN; + +- if (slot->skb) { ++ if (!slot->dma_addr) { ++ bgmac_err(bgmac, "Hardware reported transmission for empty TX ring slot %d! End of ring: %d\n", ++ ring->start, ring->end); ++ goto next; ++ } ++ ++ if (ctl1 & BGMAC_DESC_CTL0_SOF) + /* Unmap no longer used buffer */ +- dma_unmap_single(dma_dev, slot->dma_addr, +- slot->skb->len, DMA_TO_DEVICE); +- slot->dma_addr = 0; ++ dma_unmap_single(dma_dev, slot->dma_addr, len, ++ DMA_TO_DEVICE); ++ else ++ dma_unmap_page(dma_dev, slot->dma_addr, len, ++ DMA_TO_DEVICE); + ++ if (slot->skb) { + bytes_compl += slot->skb->len; + pkts_compl++; + + /* Free memory! :) */ + dev_kfree_skb(slot->skb); + slot->skb = NULL; +- } else { +- bgmac_err(bgmac, "Hardware reported transmission for empty TX ring slot %d! End of ring: %d\n", +- ring->start, ring->end); + } + ++next: ++ slot->dma_addr = 0; + if (++ring->start >= BGMAC_TX_RING_SLOTS) + ring->start = 0; + freed = true; + } + ++ if (!pkts_compl) ++ return; ++ + netdev_completed_queue(bgmac->net_dev, pkts_compl, bytes_compl); + +- if (freed && netif_queue_stopped(bgmac->net_dev)) ++ if (netif_queue_stopped(bgmac->net_dev)) + netif_wake_queue(bgmac->net_dev); + } + +@@ -439,17 +505,25 @@ static void bgmac_dma_tx_ring_free(struc + struct bgmac_dma_ring *ring) + { + struct device *dma_dev = bgmac->core->dma_dev; ++ struct bgmac_dma_desc *dma_desc = ring->cpu_base; + struct bgmac_slot_info *slot; + int i; + + for (i = 0; i < ring->num_slots; i++) { ++ int len = dma_desc[i].ctl1 & BGMAC_DESC_CTL1_LEN; ++ + slot = &ring->slots[i]; +- if (slot->skb) { +- if (slot->dma_addr) +- dma_unmap_single(dma_dev, slot->dma_addr, +- slot->skb->len, DMA_TO_DEVICE); +- dev_kfree_skb(slot->skb); +- } ++ dev_kfree_skb(slot->skb); ++ ++ if (!slot->dma_addr) ++ continue; ++ ++ if (slot->skb) ++ dma_unmap_single(dma_dev, slot->dma_addr, ++ len, DMA_TO_DEVICE); ++ else ++ dma_unmap_page(dma_dev, slot->dma_addr, ++ len, DMA_TO_DEVICE); + } + } + +@@ -1583,6 +1657,10 @@ static int bgmac_probe(struct bcma_devic + goto err_dma_free; + } + ++ net_dev->features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; ++ net_dev->hw_features = net_dev->features; ++ net_dev->vlan_features = net_dev->features; ++ + err = register_netdev(bgmac->net_dev); + if (err) { + bgmac_err(bgmac, "Cannot register net device\n"); diff --git a/target/linux/generic/patches-4.0/072-04-bgmac-simplify-tx-ring-index-handling.patch b/target/linux/generic/patches-4.0/072-04-bgmac-simplify-tx-ring-index-handling.patch new file mode 100644 index 0000000..241a308 --- /dev/null +++ b/target/linux/generic/patches-4.0/072-04-bgmac-simplify-tx-ring-index-handling.patch @@ -0,0 +1,125 @@ +From: Felix Fietkau +Date: Sun, 12 Apr 2015 09:58:56 +0200 +Subject: [PATCH] bgmac: simplify tx ring index handling + +Keep incrementing ring->start and ring->end instead of pointing it to +the actual ring slot entry. This simplifies the calculation of the +number of free slots. + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/broadcom/bgmac.c ++++ b/drivers/net/ethernet/broadcom/bgmac.c +@@ -142,11 +142,10 @@ static netdev_tx_t bgmac_dma_tx_add(stru + { + struct device *dma_dev = bgmac->core->dma_dev; + struct net_device *net_dev = bgmac->net_dev; +- struct bgmac_slot_info *slot = &ring->slots[ring->end]; +- int free_slots; ++ int index = ring->end % BGMAC_TX_RING_SLOTS; ++ struct bgmac_slot_info *slot = &ring->slots[index]; + int nr_frags; + u32 flags; +- int index = ring->end; + int i; + + if (skb->len > BGMAC_DESC_CTL1_LEN) { +@@ -159,12 +158,10 @@ static netdev_tx_t bgmac_dma_tx_add(stru + + nr_frags = skb_shinfo(skb)->nr_frags; + +- if (ring->start <= ring->end) +- free_slots = ring->start - ring->end + BGMAC_TX_RING_SLOTS; +- else +- free_slots = ring->start - ring->end; +- +- if (free_slots <= nr_frags + 1) { ++ /* ring->end - ring->start will return the number of valid slots, ++ * even when ring->end overflows ++ */ ++ if (ring->end - ring->start + nr_frags + 1 >= BGMAC_TX_RING_SLOTS) { + bgmac_err(bgmac, "TX ring is full, queue should be stopped!\n"); + netif_stop_queue(net_dev); + return NETDEV_TX_BUSY; +@@ -200,7 +197,7 @@ static netdev_tx_t bgmac_dma_tx_add(stru + } + + slot->skb = skb; +- ++ ring->end += nr_frags + 1; + netdev_sent_queue(net_dev, skb->len); + + wmb(); +@@ -208,13 +205,12 @@ static netdev_tx_t bgmac_dma_tx_add(stru + /* Increase ring->end to point empty slot. We tell hardware the first + * slot it should *not* read. + */ +- ring->end = (index + 1) % BGMAC_TX_RING_SLOTS; + bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_TX_INDEX, + ring->index_base + +- ring->end * sizeof(struct bgmac_dma_desc)); ++ (ring->end % BGMAC_TX_RING_SLOTS) * ++ sizeof(struct bgmac_dma_desc)); + +- free_slots -= nr_frags + 1; +- if (free_slots < 8) ++ if (ring->end - ring->start >= BGMAC_TX_RING_SLOTS - 8) + netif_stop_queue(net_dev); + + return NETDEV_TX_OK; +@@ -256,17 +252,17 @@ static void bgmac_dma_tx_free(struct bgm + empty_slot &= BGMAC_DMA_TX_STATDPTR; + empty_slot /= sizeof(struct bgmac_dma_desc); + +- while (ring->start != empty_slot) { +- struct bgmac_slot_info *slot = &ring->slots[ring->start]; +- u32 ctl1 = le32_to_cpu(ring->cpu_base[ring->start].ctl1); +- int len = ctl1 & BGMAC_DESC_CTL1_LEN; ++ while (ring->start != ring->end) { ++ int slot_idx = ring->start % BGMAC_TX_RING_SLOTS; ++ struct bgmac_slot_info *slot = &ring->slots[slot_idx]; ++ u32 ctl1; ++ int len; + +- if (!slot->dma_addr) { +- bgmac_err(bgmac, "Hardware reported transmission for empty TX ring slot %d! End of ring: %d\n", +- ring->start, ring->end); +- goto next; +- } ++ if (slot_idx == empty_slot) ++ break; + ++ ctl1 = le32_to_cpu(ring->cpu_base[slot_idx].ctl1); ++ len = ctl1 & BGMAC_DESC_CTL1_LEN; + if (ctl1 & BGMAC_DESC_CTL0_SOF) + /* Unmap no longer used buffer */ + dma_unmap_single(dma_dev, slot->dma_addr, len, +@@ -284,10 +280,8 @@ static void bgmac_dma_tx_free(struct bgm + slot->skb = NULL; + } + +-next: + slot->dma_addr = 0; +- if (++ring->start >= BGMAC_TX_RING_SLOTS) +- ring->start = 0; ++ ring->start++; + freed = true; + } + +--- a/drivers/net/ethernet/broadcom/bgmac.h ++++ b/drivers/net/ethernet/broadcom/bgmac.h +@@ -414,10 +414,10 @@ enum bgmac_dma_ring_type { + * empty. + */ + struct bgmac_dma_ring { +- u16 num_slots; +- u16 start; +- u16 end; ++ u32 start; ++ u32 end; + ++ u16 num_slots; + u16 mmio_base; + struct bgmac_dma_desc *cpu_base; + dma_addr_t dma_base; diff --git a/target/linux/generic/patches-4.0/072-05-bgmac-leave-interrupts-disabled-as-long-as-there-is-.patch b/target/linux/generic/patches-4.0/072-05-bgmac-leave-interrupts-disabled-as-long-as-there-is-.patch new file mode 100644 index 0000000..3bbe9ea --- /dev/null +++ b/target/linux/generic/patches-4.0/072-05-bgmac-leave-interrupts-disabled-as-long-as-there-is-.patch @@ -0,0 +1,87 @@ +From: Felix Fietkau +Date: Sun, 12 Apr 2015 10:08:04 +0200 +Subject: [PATCH] bgmac: leave interrupts disabled as long as there is work + to do + +Always poll rx and tx during NAPI poll instead of relying on the status +of the first interrupt. This prevents bgmac_poll from leaving unfinished +work around until the next IRQ. +In my tests this makes bridging/routing throughput under heavy load more +stable and ensures that no new IRQs arrive as long as bgmac_poll uses up +the entire budget. + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/broadcom/bgmac.c ++++ b/drivers/net/ethernet/broadcom/bgmac.c +@@ -1109,8 +1109,6 @@ static void bgmac_chip_reset(struct bgma + bgmac_phy_init(bgmac); + + netdev_reset_queue(bgmac->net_dev); +- +- bgmac->int_status = 0; + } + + static void bgmac_chip_intrs_on(struct bgmac *bgmac) +@@ -1225,14 +1223,13 @@ static irqreturn_t bgmac_interrupt(int i + if (!int_status) + return IRQ_NONE; + +- /* Ack */ +- bgmac_write(bgmac, BGMAC_INT_STATUS, int_status); ++ int_status &= ~(BGMAC_IS_TX0 | BGMAC_IS_RX); ++ if (int_status) ++ bgmac_err(bgmac, "Unknown IRQs: 0x%08X\n", int_status); + + /* Disable new interrupts until handling existing ones */ + bgmac_chip_intrs_off(bgmac); + +- bgmac->int_status = int_status; +- + napi_schedule(&bgmac->napi); + + return IRQ_HANDLED; +@@ -1241,25 +1238,17 @@ static irqreturn_t bgmac_interrupt(int i + static int bgmac_poll(struct napi_struct *napi, int weight) + { + struct bgmac *bgmac = container_of(napi, struct bgmac, napi); +- struct bgmac_dma_ring *ring; + int handled = 0; + +- if (bgmac->int_status & BGMAC_IS_TX0) { +- ring = &bgmac->tx_ring[0]; +- bgmac_dma_tx_free(bgmac, ring); +- bgmac->int_status &= ~BGMAC_IS_TX0; +- } ++ /* Ack */ ++ bgmac_write(bgmac, BGMAC_INT_STATUS, ~0); + +- if (bgmac->int_status & BGMAC_IS_RX) { +- ring = &bgmac->rx_ring[0]; +- handled += bgmac_dma_rx_read(bgmac, ring, weight); +- bgmac->int_status &= ~BGMAC_IS_RX; +- } ++ bgmac_dma_tx_free(bgmac, &bgmac->tx_ring[0]); ++ handled += bgmac_dma_rx_read(bgmac, &bgmac->rx_ring[0], weight); + +- if (bgmac->int_status) { +- bgmac_err(bgmac, "Unknown IRQs: 0x%08X\n", bgmac->int_status); +- bgmac->int_status = 0; +- } ++ /* Poll again if more events arrived in the meantime */ ++ if (bgmac_read(bgmac, BGMAC_INT_STATUS) & (BGMAC_IS_TX0 | BGMAC_IS_RX)) ++ return handled; + + if (handled < weight) { + napi_complete(napi); +--- a/drivers/net/ethernet/broadcom/bgmac.h ++++ b/drivers/net/ethernet/broadcom/bgmac.h +@@ -452,7 +452,6 @@ struct bgmac { + + /* Int */ + u32 int_mask; +- u32 int_status; + + /* Current MAC state */ + int mac_speed; diff --git a/target/linux/generic/patches-4.0/072-06-bgmac-set-received-skb-headroom-to-NET_SKB_PAD.patch b/target/linux/generic/patches-4.0/072-06-bgmac-set-received-skb-headroom-to-NET_SKB_PAD.patch new file mode 100644 index 0000000..2c490ef --- /dev/null +++ b/target/linux/generic/patches-4.0/072-06-bgmac-set-received-skb-headroom-to-NET_SKB_PAD.patch @@ -0,0 +1,66 @@ +From: Felix Fietkau +Date: Sun, 12 Apr 2015 10:13:28 +0200 +Subject: [PATCH] bgmac: set received skb headroom to NET_SKB_PAD + +A packet buffer offset of 30 bytes is inefficient, because the first 2 +bytes end up in a different cacheline. + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/broadcom/bgmac.c ++++ b/drivers/net/ethernet/broadcom/bgmac.c +@@ -346,13 +346,13 @@ static int bgmac_dma_rx_skb_for_slot(str + return -ENOMEM; + + /* Poison - if everything goes fine, hardware will overwrite it */ +- rx = buf; ++ rx = buf + BGMAC_RX_BUF_OFFSET; + rx->len = cpu_to_le16(0xdead); + rx->flags = cpu_to_le16(0xbeef); + + /* Map skb for the DMA */ +- dma_addr = dma_map_single(dma_dev, buf, BGMAC_RX_BUF_SIZE, +- DMA_FROM_DEVICE); ++ dma_addr = dma_map_single(dma_dev, buf + BGMAC_RX_BUF_OFFSET, ++ BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE); + if (dma_mapping_error(dma_dev, dma_addr)) { + bgmac_err(bgmac, "DMA mapping error\n"); + put_page(virt_to_head_page(buf)); +@@ -403,7 +403,7 @@ static int bgmac_dma_rx_read(struct bgma + while (ring->start != ring->end) { + struct device *dma_dev = bgmac->core->dma_dev; + struct bgmac_slot_info *slot = &ring->slots[ring->start]; +- struct bgmac_rx_header *rx = slot->buf; ++ struct bgmac_rx_header *rx = slot->buf + BGMAC_RX_BUF_OFFSET; + struct sk_buff *skb; + void *buf = slot->buf; + u16 len, flags; +@@ -454,8 +454,10 @@ static int bgmac_dma_rx_read(struct bgma + BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE); + + skb = build_skb(buf, BGMAC_RX_ALLOC_SIZE); +- skb_put(skb, BGMAC_RX_FRAME_OFFSET + len); +- skb_pull(skb, BGMAC_RX_FRAME_OFFSET); ++ skb_put(skb, BGMAC_RX_FRAME_OFFSET + ++ BGMAC_RX_BUF_OFFSET + len); ++ skb_pull(skb, BGMAC_RX_FRAME_OFFSET + ++ BGMAC_RX_BUF_OFFSET); + + skb_checksum_none_assert(skb); + skb->protocol = eth_type_trans(skb, bgmac->net_dev); +--- a/drivers/net/ethernet/broadcom/bgmac.h ++++ b/drivers/net/ethernet/broadcom/bgmac.h +@@ -360,9 +360,11 @@ + + #define BGMAC_RX_HEADER_LEN 28 /* Last 24 bytes are unused. Well... */ + #define BGMAC_RX_FRAME_OFFSET 30 /* There are 2 unused bytes between header and real data */ ++#define BGMAC_RX_BUF_OFFSET (NET_SKB_PAD + NET_IP_ALIGN - \ ++ BGMAC_RX_FRAME_OFFSET) + #define BGMAC_RX_MAX_FRAME_SIZE 1536 /* Copied from b44/tg3 */ + #define BGMAC_RX_BUF_SIZE (BGMAC_RX_FRAME_OFFSET + BGMAC_RX_MAX_FRAME_SIZE) +-#define BGMAC_RX_ALLOC_SIZE (SKB_DATA_ALIGN(BGMAC_RX_BUF_SIZE) + \ ++#define BGMAC_RX_ALLOC_SIZE (SKB_DATA_ALIGN(BGMAC_RX_BUF_SIZE + BGMAC_RX_BUF_OFFSET) + \ + SKB_DATA_ALIGN(sizeof(struct skb_shared_info))) + + #define BGMAC_BFL_ENETROBO 0x0010 /* has ephy roboswitch spi */ diff --git a/target/linux/generic/patches-4.0/072-07-bgmac-simplify-rx-DMA-error-handling.patch b/target/linux/generic/patches-4.0/072-07-bgmac-simplify-rx-DMA-error-handling.patch new file mode 100644 index 0000000..2ca9d10 --- /dev/null +++ b/target/linux/generic/patches-4.0/072-07-bgmac-simplify-rx-DMA-error-handling.patch @@ -0,0 +1,130 @@ +From: Felix Fietkau +Date: Sun, 12 Apr 2015 22:23:07 +0200 +Subject: [PATCH] bgmac: simplify/optimize rx DMA error handling + +Allocate a new buffer before processing the completed one. If allocation +fails, reuse the old buffer. + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/broadcom/bgmac.c ++++ b/drivers/net/ethernet/broadcom/bgmac.c +@@ -386,6 +386,19 @@ static void bgmac_dma_rx_setup_desc(stru + dma_desc->ctl1 = cpu_to_le32(ctl1); + } + ++static void bgmac_dma_rx_poison_buf(struct device *dma_dev, ++ struct bgmac_slot_info *slot) ++{ ++ struct bgmac_rx_header *rx = slot->buf + BGMAC_RX_BUF_OFFSET; ++ ++ dma_sync_single_for_cpu(dma_dev, slot->dma_addr, BGMAC_RX_BUF_SIZE, ++ DMA_FROM_DEVICE); ++ rx->len = cpu_to_le16(0xdead); ++ rx->flags = cpu_to_le16(0xbeef); ++ dma_sync_single_for_device(dma_dev, slot->dma_addr, BGMAC_RX_BUF_SIZE, ++ DMA_FROM_DEVICE); ++} ++ + static int bgmac_dma_rx_read(struct bgmac *bgmac, struct bgmac_dma_ring *ring, + int weight) + { +@@ -406,53 +419,35 @@ static int bgmac_dma_rx_read(struct bgma + struct bgmac_rx_header *rx = slot->buf + BGMAC_RX_BUF_OFFSET; + struct sk_buff *skb; + void *buf = slot->buf; ++ dma_addr_t dma_addr = slot->dma_addr; + u16 len, flags; + +- /* Unmap buffer to make it accessible to the CPU */ +- dma_sync_single_for_cpu(dma_dev, slot->dma_addr, +- BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE); +- +- /* Get info from the header */ +- len = le16_to_cpu(rx->len); +- flags = le16_to_cpu(rx->flags); +- + do { +- dma_addr_t old_dma_addr = slot->dma_addr; +- int err; ++ /* Prepare new skb as replacement */ ++ if (bgmac_dma_rx_skb_for_slot(bgmac, slot)) { ++ bgmac_dma_rx_poison_buf(dma_dev, slot); ++ break; ++ } ++ ++ /* Unmap buffer to make it accessible to the CPU */ ++ dma_unmap_single(dma_dev, dma_addr, ++ BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE); ++ ++ /* Get info from the header */ ++ len = le16_to_cpu(rx->len); ++ flags = le16_to_cpu(rx->flags); + + /* Check for poison and drop or pass the packet */ + if (len == 0xdead && flags == 0xbeef) { + bgmac_err(bgmac, "Found poisoned packet at slot %d, DMA issue!\n", + ring->start); +- dma_sync_single_for_device(dma_dev, +- slot->dma_addr, +- BGMAC_RX_BUF_SIZE, +- DMA_FROM_DEVICE); ++ put_page(virt_to_head_page(buf)); + break; + } + + /* Omit CRC. */ + len -= ETH_FCS_LEN; + +- /* Prepare new skb as replacement */ +- err = bgmac_dma_rx_skb_for_slot(bgmac, slot); +- if (err) { +- /* Poison the old skb */ +- rx->len = cpu_to_le16(0xdead); +- rx->flags = cpu_to_le16(0xbeef); +- +- dma_sync_single_for_device(dma_dev, +- slot->dma_addr, +- BGMAC_RX_BUF_SIZE, +- DMA_FROM_DEVICE); +- break; +- } +- bgmac_dma_rx_setup_desc(bgmac, ring, ring->start); +- +- /* Unmap old skb, we'll pass it to the netfif */ +- dma_unmap_single(dma_dev, old_dma_addr, +- BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE); +- + skb = build_skb(buf, BGMAC_RX_ALLOC_SIZE); + skb_put(skb, BGMAC_RX_FRAME_OFFSET + + BGMAC_RX_BUF_OFFSET + len); +@@ -465,6 +460,8 @@ static int bgmac_dma_rx_read(struct bgma + handled++; + } while (0); + ++ bgmac_dma_rx_setup_desc(bgmac, ring, ring->start); ++ + if (++ring->start >= BGMAC_RX_RING_SLOTS) + ring->start = 0; + +@@ -532,14 +529,14 @@ static void bgmac_dma_rx_ring_free(struc + + for (i = 0; i < ring->num_slots; i++) { + slot = &ring->slots[i]; +- if (!slot->buf) ++ if (!slot->dma_addr) + continue; + +- if (slot->dma_addr) +- dma_unmap_single(dma_dev, slot->dma_addr, +- BGMAC_RX_BUF_SIZE, +- DMA_FROM_DEVICE); ++ dma_unmap_single(dma_dev, slot->dma_addr, ++ BGMAC_RX_BUF_SIZE, ++ DMA_FROM_DEVICE); + put_page(virt_to_head_page(slot->buf)); ++ slot->dma_addr = 0; + } + } + diff --git a/target/linux/generic/patches-4.0/072-08-bgmac-add-check-for-oversized-packets.patch b/target/linux/generic/patches-4.0/072-08-bgmac-add-check-for-oversized-packets.patch new file mode 100644 index 0000000..705aa2d --- /dev/null +++ b/target/linux/generic/patches-4.0/072-08-bgmac-add-check-for-oversized-packets.patch @@ -0,0 +1,27 @@ +From: Felix Fietkau +Date: Sun, 12 Apr 2015 22:28:20 +0200 +Subject: [PATCH] bgmac: add check for oversized packets + +In very rare cases, the MAC can catch an internal buffer that is bigger +than it's supposed to be. Instead of crashing the kernel, simply pass +the buffer back to the hardware + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/broadcom/bgmac.c ++++ b/drivers/net/ethernet/broadcom/bgmac.c +@@ -445,6 +445,13 @@ static int bgmac_dma_rx_read(struct bgma + break; + } + ++ if (len > BGMAC_RX_ALLOC_SIZE) { ++ bgmac_err(bgmac, "Found oversized packet at slot %d, DMA issue!\n", ++ ring->start); ++ put_page(virt_to_head_page(buf)); ++ break; ++ } ++ + /* Omit CRC. */ + len -= ETH_FCS_LEN; + diff --git a/target/linux/generic/patches-4.0/072-09-bgmac-increase-rx-ring-size-from-511-to-512.patch b/target/linux/generic/patches-4.0/072-09-bgmac-increase-rx-ring-size-from-511-to-512.patch new file mode 100644 index 0000000..4888cc3 --- /dev/null +++ b/target/linux/generic/patches-4.0/072-09-bgmac-increase-rx-ring-size-from-511-to-512.patch @@ -0,0 +1,23 @@ +From: Felix Fietkau +Date: Sun, 12 Apr 2015 22:36:16 +0200 +Subject: [PATCH] bgmac: increase rx ring size from 511 to 512 + +Limiting it to 511 looks like a failed attempt at leaving one descriptor +empty to allow the hardware to stop processing a buffer that has not +been prepared yet. However, this doesn't work because this affects the +total ring size as well + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/broadcom/bgmac.h ++++ b/drivers/net/ethernet/broadcom/bgmac.h +@@ -356,7 +356,7 @@ + #define BGMAC_MAX_RX_RINGS 1 + + #define BGMAC_TX_RING_SLOTS 128 +-#define BGMAC_RX_RING_SLOTS 512 - 1 /* Why -1? Well, Broadcom does that... */ ++#define BGMAC_RX_RING_SLOTS 512 + + #define BGMAC_RX_HEADER_LEN 28 /* Last 24 bytes are unused. Well... */ + #define BGMAC_RX_FRAME_OFFSET 30 /* There are 2 unused bytes between header and real data */ diff --git a/target/linux/generic/patches-4.0/072-10-bgmac-simplify-dma-init-cleanup.patch b/target/linux/generic/patches-4.0/072-10-bgmac-simplify-dma-init-cleanup.patch new file mode 100644 index 0000000..f8d7921 --- /dev/null +++ b/target/linux/generic/patches-4.0/072-10-bgmac-simplify-dma-init-cleanup.patch @@ -0,0 +1,184 @@ +From: Felix Fietkau +Date: Sun, 12 Apr 2015 23:19:32 +0200 +Subject: [PATCH] bgmac: simplify dma init/cleanup + +Instead of allocating buffers at device init time and initializing +descriptors at device open, do both at the same time (during open). +Free all buffers when closing the device. + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/broadcom/bgmac.c ++++ b/drivers/net/ethernet/broadcom/bgmac.c +@@ -562,18 +562,26 @@ static void bgmac_dma_ring_desc_free(str + ring->dma_base); + } + +-static void bgmac_dma_free(struct bgmac *bgmac) ++static void bgmac_dma_cleanup(struct bgmac *bgmac) + { + int i; + +- for (i = 0; i < BGMAC_MAX_TX_RINGS; i++) { ++ for (i = 0; i < BGMAC_MAX_TX_RINGS; i++) + bgmac_dma_tx_ring_free(bgmac, &bgmac->tx_ring[i]); +- bgmac_dma_ring_desc_free(bgmac, &bgmac->tx_ring[i]); +- } +- for (i = 0; i < BGMAC_MAX_RX_RINGS; i++) { ++ ++ for (i = 0; i < BGMAC_MAX_RX_RINGS; i++) + bgmac_dma_rx_ring_free(bgmac, &bgmac->rx_ring[i]); ++} ++ ++static void bgmac_dma_free(struct bgmac *bgmac) ++{ ++ int i; ++ ++ for (i = 0; i < BGMAC_MAX_TX_RINGS; i++) ++ bgmac_dma_ring_desc_free(bgmac, &bgmac->tx_ring[i]); ++ ++ for (i = 0; i < BGMAC_MAX_RX_RINGS; i++) + bgmac_dma_ring_desc_free(bgmac, &bgmac->rx_ring[i]); +- } + } + + static int bgmac_dma_alloc(struct bgmac *bgmac) +@@ -621,8 +629,6 @@ static int bgmac_dma_alloc(struct bgmac + } + + for (i = 0; i < BGMAC_MAX_RX_RINGS; i++) { +- int j; +- + ring = &bgmac->rx_ring[i]; + ring->num_slots = BGMAC_RX_RING_SLOTS; + ring->mmio_base = ring_base[i]; +@@ -645,15 +651,6 @@ static int bgmac_dma_alloc(struct bgmac + ring->index_base = lower_32_bits(ring->dma_base); + else + ring->index_base = 0; +- +- /* Alloc RX slots */ +- for (j = 0; j < ring->num_slots; j++) { +- err = bgmac_dma_rx_skb_for_slot(bgmac, &ring->slots[j]); +- if (err) { +- bgmac_err(bgmac, "Can't allocate skb for slot in RX ring\n"); +- goto err_dma_free; +- } +- } + } + + return 0; +@@ -663,10 +660,10 @@ err_dma_free: + return -ENOMEM; + } + +-static void bgmac_dma_init(struct bgmac *bgmac) ++static int bgmac_dma_init(struct bgmac *bgmac) + { + struct bgmac_dma_ring *ring; +- int i; ++ int i, err; + + for (i = 0; i < BGMAC_MAX_TX_RINGS; i++) { + ring = &bgmac->tx_ring[i]; +@@ -698,8 +695,13 @@ static void bgmac_dma_init(struct bgmac + if (ring->unaligned) + bgmac_dma_rx_enable(bgmac, ring); + +- for (j = 0; j < ring->num_slots; j++) ++ for (j = 0; j < ring->num_slots; j++) { ++ err = bgmac_dma_rx_skb_for_slot(bgmac, &ring->slots[j]); ++ if (err) ++ goto error; ++ + bgmac_dma_rx_setup_desc(bgmac, ring, j); ++ } + + bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_RX_INDEX, + ring->index_base + +@@ -708,6 +710,12 @@ static void bgmac_dma_init(struct bgmac + ring->start = 0; + ring->end = 0; + } ++ ++ return 0; ++ ++error: ++ bgmac_dma_cleanup(bgmac); ++ return err; + } + + /************************************************** +@@ -1183,11 +1191,8 @@ static void bgmac_enable(struct bgmac *b + } + + /* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipinit */ +-static void bgmac_chip_init(struct bgmac *bgmac, bool full_init) ++static void bgmac_chip_init(struct bgmac *bgmac) + { +- struct bgmac_dma_ring *ring; +- int i; +- + /* 1 interrupt per received frame */ + bgmac_write(bgmac, BGMAC_INT_RECV_LAZY, 1 << BGMAC_IRL_FC_SHIFT); + +@@ -1205,16 +1210,7 @@ static void bgmac_chip_init(struct bgmac + + bgmac_write(bgmac, BGMAC_RXMAX_LENGTH, 32 + ETHER_MAX_LEN); + +- if (full_init) { +- bgmac_dma_init(bgmac); +- if (1) /* FIXME: is there any case we don't want IRQs? */ +- bgmac_chip_intrs_on(bgmac); +- } else { +- for (i = 0; i < BGMAC_MAX_RX_RINGS; i++) { +- ring = &bgmac->rx_ring[i]; +- bgmac_dma_rx_enable(bgmac, ring); +- } +- } ++ bgmac_chip_intrs_on(bgmac); + + bgmac_enable(bgmac); + } +@@ -1274,23 +1270,27 @@ static int bgmac_open(struct net_device + int err = 0; + + bgmac_chip_reset(bgmac); ++ ++ err = bgmac_dma_init(bgmac); ++ if (err) ++ return err; ++ + /* Specs say about reclaiming rings here, but we do that in DMA init */ +- bgmac_chip_init(bgmac, true); ++ bgmac_chip_init(bgmac); + + err = request_irq(bgmac->core->irq, bgmac_interrupt, IRQF_SHARED, + KBUILD_MODNAME, net_dev); + if (err < 0) { + bgmac_err(bgmac, "IRQ request error: %d!\n", err); +- goto err_out; ++ bgmac_dma_cleanup(bgmac); ++ return err; + } + napi_enable(&bgmac->napi); + + phy_start(bgmac->phy_dev); + + netif_carrier_on(net_dev); +- +-err_out: +- return err; ++ return 0; + } + + static int bgmac_stop(struct net_device *net_dev) +@@ -1306,6 +1306,7 @@ static int bgmac_stop(struct net_device + free_irq(bgmac->core->irq, net_dev); + + bgmac_chip_reset(bgmac); ++ bgmac_dma_cleanup(bgmac); + + return 0; + } diff --git a/target/linux/generic/patches-4.0/072-11-bgmac-fix-DMA-rx-corruption.patch b/target/linux/generic/patches-4.0/072-11-bgmac-fix-DMA-rx-corruption.patch new file mode 100644 index 0000000..2e670d8 --- /dev/null +++ b/target/linux/generic/patches-4.0/072-11-bgmac-fix-DMA-rx-corruption.patch @@ -0,0 +1,88 @@ +From: Felix Fietkau +Date: Sun, 12 Apr 2015 11:59:47 +0200 +Subject: [PATCH] bgmac: fix DMA rx corruption + +The driver needs to inform the hardware about the first invalid (not yet +filled) rx slot, by writing its DMA descriptor pointer offset to the +BGMAC_DMA_RX_INDEX register. + +This register was set to a value exceeding the rx ring size, effectively +allowing the hardware constant access to the full ring, regardless of +which slots are initialized. + +To fix this issue, always mark the last filled rx slot as invalid. + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/broadcom/bgmac.c ++++ b/drivers/net/ethernet/broadcom/bgmac.c +@@ -366,6 +366,16 @@ static int bgmac_dma_rx_skb_for_slot(str + return 0; + } + ++static void bgmac_dma_rx_update_index(struct bgmac *bgmac, ++ struct bgmac_dma_ring *ring) ++{ ++ wmb(); ++ ++ bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_RX_INDEX, ++ ring->index_base + ++ ring->end * sizeof(struct bgmac_dma_desc)); ++} ++ + static void bgmac_dma_rx_setup_desc(struct bgmac *bgmac, + struct bgmac_dma_ring *ring, int desc_idx) + { +@@ -384,6 +394,8 @@ static void bgmac_dma_rx_setup_desc(stru + dma_desc->addr_high = cpu_to_le32(upper_32_bits(ring->slots[desc_idx].dma_addr)); + dma_desc->ctl0 = cpu_to_le32(ctl0); + dma_desc->ctl1 = cpu_to_le32(ctl1); ++ ++ ring->end = desc_idx; + } + + static void bgmac_dma_rx_poison_buf(struct device *dma_dev, +@@ -411,9 +423,7 @@ static int bgmac_dma_rx_read(struct bgma + end_slot &= BGMAC_DMA_RX_STATDPTR; + end_slot /= sizeof(struct bgmac_dma_desc); + +- ring->end = end_slot; +- +- while (ring->start != ring->end) { ++ while (ring->start != end_slot) { + struct device *dma_dev = bgmac->core->dma_dev; + struct bgmac_slot_info *slot = &ring->slots[ring->start]; + struct bgmac_rx_header *rx = slot->buf + BGMAC_RX_BUF_OFFSET; +@@ -476,6 +486,8 @@ static int bgmac_dma_rx_read(struct bgma + break; + } + ++ bgmac_dma_rx_update_index(bgmac, ring); ++ + return handled; + } + +@@ -695,6 +707,8 @@ static int bgmac_dma_init(struct bgmac * + if (ring->unaligned) + bgmac_dma_rx_enable(bgmac, ring); + ++ ring->start = 0; ++ ring->end = 0; + for (j = 0; j < ring->num_slots; j++) { + err = bgmac_dma_rx_skb_for_slot(bgmac, &ring->slots[j]); + if (err) +@@ -703,12 +717,7 @@ static int bgmac_dma_init(struct bgmac * + bgmac_dma_rx_setup_desc(bgmac, ring, j); + } + +- bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_RX_INDEX, +- ring->index_base + +- ring->num_slots * sizeof(struct bgmac_dma_desc)); +- +- ring->start = 0; +- ring->end = 0; ++ bgmac_dma_rx_update_index(bgmac, ring); + } + + return 0; diff --git a/target/linux/generic/patches-4.0/072-12-bgmac-drop-ring-num_slots.patch b/target/linux/generic/patches-4.0/072-12-bgmac-drop-ring-num_slots.patch new file mode 100644 index 0000000..4cd2e3f --- /dev/null +++ b/target/linux/generic/patches-4.0/072-12-bgmac-drop-ring-num_slots.patch @@ -0,0 +1,132 @@ +From: Felix Fietkau +Date: Sun, 12 Apr 2015 23:28:38 +0200 +Subject: [PATCH] bgmac: drop ring->num_slots + +The ring size is always known at compile time, so make the code a bit +more efficient + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/broadcom/bgmac.c ++++ b/drivers/net/ethernet/broadcom/bgmac.c +@@ -123,7 +123,7 @@ bgmac_dma_tx_add_buf(struct bgmac *bgmac + struct bgmac_dma_desc *dma_desc; + u32 ctl1; + +- if (i == ring->num_slots - 1) ++ if (i == BGMAC_TX_RING_SLOTS - 1) + ctl0 |= BGMAC_DESC_CTL0_EOT; + + ctl1 = len & BGMAC_DESC_CTL1_LEN; +@@ -382,7 +382,7 @@ static void bgmac_dma_rx_setup_desc(stru + struct bgmac_dma_desc *dma_desc = ring->cpu_base + desc_idx; + u32 ctl0 = 0, ctl1 = 0; + +- if (desc_idx == ring->num_slots - 1) ++ if (desc_idx == BGMAC_RX_RING_SLOTS - 1) + ctl0 |= BGMAC_DESC_CTL0_EOT; + ctl1 |= BGMAC_RX_BUF_SIZE & BGMAC_DESC_CTL1_LEN; + /* Is there any BGMAC device that requires extension? */ +@@ -521,7 +521,7 @@ static void bgmac_dma_tx_ring_free(struc + struct bgmac_slot_info *slot; + int i; + +- for (i = 0; i < ring->num_slots; i++) { ++ for (i = 0; i < BGMAC_TX_RING_SLOTS; i++) { + int len = dma_desc[i].ctl1 & BGMAC_DESC_CTL1_LEN; + + slot = &ring->slots[i]; +@@ -546,7 +546,7 @@ static void bgmac_dma_rx_ring_free(struc + struct bgmac_slot_info *slot; + int i; + +- for (i = 0; i < ring->num_slots; i++) { ++ for (i = 0; i < BGMAC_RX_RING_SLOTS; i++) { + slot = &ring->slots[i]; + if (!slot->dma_addr) + continue; +@@ -560,7 +560,8 @@ static void bgmac_dma_rx_ring_free(struc + } + + static void bgmac_dma_ring_desc_free(struct bgmac *bgmac, +- struct bgmac_dma_ring *ring) ++ struct bgmac_dma_ring *ring, ++ int num_slots) + { + struct device *dma_dev = bgmac->core->dma_dev; + int size; +@@ -569,7 +570,7 @@ static void bgmac_dma_ring_desc_free(str + return; + + /* Free ring of descriptors */ +- size = ring->num_slots * sizeof(struct bgmac_dma_desc); ++ size = num_slots * sizeof(struct bgmac_dma_desc); + dma_free_coherent(dma_dev, size, ring->cpu_base, + ring->dma_base); + } +@@ -590,10 +591,12 @@ static void bgmac_dma_free(struct bgmac + int i; + + for (i = 0; i < BGMAC_MAX_TX_RINGS; i++) +- bgmac_dma_ring_desc_free(bgmac, &bgmac->tx_ring[i]); ++ bgmac_dma_ring_desc_free(bgmac, &bgmac->tx_ring[i], ++ BGMAC_TX_RING_SLOTS); + + for (i = 0; i < BGMAC_MAX_RX_RINGS; i++) +- bgmac_dma_ring_desc_free(bgmac, &bgmac->rx_ring[i]); ++ bgmac_dma_ring_desc_free(bgmac, &bgmac->rx_ring[i], ++ BGMAC_RX_RING_SLOTS); + } + + static int bgmac_dma_alloc(struct bgmac *bgmac) +@@ -616,11 +619,10 @@ static int bgmac_dma_alloc(struct bgmac + + for (i = 0; i < BGMAC_MAX_TX_RINGS; i++) { + ring = &bgmac->tx_ring[i]; +- ring->num_slots = BGMAC_TX_RING_SLOTS; + ring->mmio_base = ring_base[i]; + + /* Alloc ring of descriptors */ +- size = ring->num_slots * sizeof(struct bgmac_dma_desc); ++ size = BGMAC_TX_RING_SLOTS * sizeof(struct bgmac_dma_desc); + ring->cpu_base = dma_zalloc_coherent(dma_dev, size, + &ring->dma_base, + GFP_KERNEL); +@@ -642,11 +644,10 @@ static int bgmac_dma_alloc(struct bgmac + + for (i = 0; i < BGMAC_MAX_RX_RINGS; i++) { + ring = &bgmac->rx_ring[i]; +- ring->num_slots = BGMAC_RX_RING_SLOTS; + ring->mmio_base = ring_base[i]; + + /* Alloc ring of descriptors */ +- size = ring->num_slots * sizeof(struct bgmac_dma_desc); ++ size = BGMAC_RX_RING_SLOTS * sizeof(struct bgmac_dma_desc); + ring->cpu_base = dma_zalloc_coherent(dma_dev, size, + &ring->dma_base, + GFP_KERNEL); +@@ -709,7 +710,7 @@ static int bgmac_dma_init(struct bgmac * + + ring->start = 0; + ring->end = 0; +- for (j = 0; j < ring->num_slots; j++) { ++ for (j = 0; j < BGMAC_RX_RING_SLOTS; j++) { + err = bgmac_dma_rx_skb_for_slot(bgmac, &ring->slots[j]); + if (err) + goto error; +--- a/drivers/net/ethernet/broadcom/bgmac.h ++++ b/drivers/net/ethernet/broadcom/bgmac.h +@@ -419,11 +419,10 @@ struct bgmac_dma_ring { + u32 start; + u32 end; + +- u16 num_slots; +- u16 mmio_base; + struct bgmac_dma_desc *cpu_base; + dma_addr_t dma_base; + u32 index_base; /* Used for unaligned rings only, otherwise 0 */ ++ u16 mmio_base; + bool unaligned; + + struct bgmac_slot_info slots[BGMAC_RX_RING_SLOTS]; diff --git a/target/linux/generic/patches-4.0/072-13-bgmac-fix-MAC-soft-reset-bit-for-corerev-4.patch b/target/linux/generic/patches-4.0/072-13-bgmac-fix-MAC-soft-reset-bit-for-corerev-4.patch new file mode 100644 index 0000000..a3d9fd6 --- /dev/null +++ b/target/linux/generic/patches-4.0/072-13-bgmac-fix-MAC-soft-reset-bit-for-corerev-4.patch @@ -0,0 +1,24 @@ +From: Felix Fietkau +Date: Mon, 13 Apr 2015 15:54:04 +0200 +Subject: [PATCH] bgmac: fix MAC soft-reset bit for corerev > 4 + +Only core revisions older than 4 use BGMAC_CMDCFG_SR_REV0 + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/broadcom/bgmac.h ++++ b/drivers/net/ethernet/broadcom/bgmac.h +@@ -198,9 +198,9 @@ + #define BGMAC_CMDCFG_TAI 0x00000200 + #define BGMAC_CMDCFG_HD 0x00000400 /* Set if in half duplex mode */ + #define BGMAC_CMDCFG_HD_SHIFT 10 +-#define BGMAC_CMDCFG_SR_REV0 0x00000800 /* Set to reset mode, for other revs */ +-#define BGMAC_CMDCFG_SR_REV4 0x00002000 /* Set to reset mode, only for core rev 4 */ +-#define BGMAC_CMDCFG_SR(rev) ((rev == 4) ? BGMAC_CMDCFG_SR_REV4 : BGMAC_CMDCFG_SR_REV0) ++#define BGMAC_CMDCFG_SR_REV0 0x00000800 /* Set to reset mode, for core rev 0-3 */ ++#define BGMAC_CMDCFG_SR_REV4 0x00002000 /* Set to reset mode, for core rev >= 4 */ ++#define BGMAC_CMDCFG_SR(rev) ((rev >= 4) ? BGMAC_CMDCFG_SR_REV4 : BGMAC_CMDCFG_SR_REV0) + #define BGMAC_CMDCFG_ML 0x00008000 /* Set to activate mac loopback mode */ + #define BGMAC_CMDCFG_AE 0x00400000 + #define BGMAC_CMDCFG_CFE 0x00800000 diff --git a/target/linux/generic/patches-4.0/072-14-bgmac-reset-all-4-GMAC-cores-on-init.patch b/target/linux/generic/patches-4.0/072-14-bgmac-reset-all-4-GMAC-cores-on-init.patch new file mode 100644 index 0000000..2a913a6 --- /dev/null +++ b/target/linux/generic/patches-4.0/072-14-bgmac-reset-all-4-GMAC-cores-on-init.patch @@ -0,0 +1,28 @@ +From: Felix Fietkau +Date: Mon, 13 Apr 2015 15:56:26 +0200 +Subject: [PATCH] bgmac: reset all 4 GMAC cores on init + +On a BCM4709 based device, I found that GMAC cores may be enabled at +probe time, but only become usable after a full reset. +Disable cores before re-enabling them to ensure that they are properly +reset. + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/broadcom/bgmac.c ++++ b/drivers/net/ethernet/broadcom/bgmac.c +@@ -1623,8 +1623,11 @@ static int bgmac_probe(struct bcma_devic + ns_core = bcma_find_core_unit(core->bus, + BCMA_CORE_MAC_GBIT, + ns_gmac); +- if (ns_core && !bcma_core_is_enabled(ns_core)) +- bcma_core_enable(ns_core, 0); ++ if (!ns_core) ++ continue; ++ ++ bcma_core_disable(ns_core, 0); ++ bcma_core_enable(ns_core, 0); + } + } + diff --git a/target/linux/generic/patches-4.0/072-15-bgmac-fix-requests-for-extra-polling-calls-from-NAPI.patch b/target/linux/generic/patches-4.0/072-15-bgmac-fix-requests-for-extra-polling-calls-from-NAPI.patch new file mode 100644 index 0000000..62e9379 --- /dev/null +++ b/target/linux/generic/patches-4.0/072-15-bgmac-fix-requests-for-extra-polling-calls-from-NAPI.patch @@ -0,0 +1,30 @@ +From 047f89922c6381432501f248d08226ff9adc4ee3 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Thu, 23 Apr 2015 20:45:25 +0200 +Subject: [PATCH][FIX 4.1] bgmac: fix requests for extra polling calls from + NAPI +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +After d75b1ade567f ("net: less interrupt masking in NAPI") polling +function has to return whole budget when it wants NAPI to call it again. + +Signed-off-by: Rafał Miłecki +Cc: Felix Fietkau +Fixes: eb64e2923a886 ("bgmac: leave interrupts disabled as long as there is work to do") +--- + drivers/net/ethernet/broadcom/bgmac.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/ethernet/broadcom/bgmac.c ++++ b/drivers/net/ethernet/broadcom/bgmac.c +@@ -1260,7 +1260,7 @@ static int bgmac_poll(struct napi_struct + + /* Poll again if more events arrived in the meantime */ + if (bgmac_read(bgmac, BGMAC_INT_STATUS) & (BGMAC_IS_TX0 | BGMAC_IS_RX)) +- return handled; ++ return weight; + + if (handled < weight) { + napi_complete(napi); diff --git a/target/linux/generic/patches-4.0/073-pppoe-Use-workqueue-to-die-properly-when-a-PADT-is-r.patch b/target/linux/generic/patches-4.0/073-pppoe-Use-workqueue-to-die-properly-when-a-PADT-is-r.patch new file mode 100644 index 0000000..de85830 --- /dev/null +++ b/target/linux/generic/patches-4.0/073-pppoe-Use-workqueue-to-die-properly-when-a-PADT-is-r.patch @@ -0,0 +1,89 @@ +From: Simon Farnsworth +Date: Sun, 1 Mar 2015 10:54:39 +0000 +Subject: [PATCH] pppoe: Use workqueue to die properly when a PADT is received + +When a PADT frame is received, the socket may not be in a good state to +close down the PPP interface. The current implementation handles this by +simply blocking all further PPP traffic, and hoping that the lack of traffic +will trigger the user to investigate. + +Use schedule_work to get to a process context from which we clear down the +PPP interface, in a fashion analogous to hangup on a TTY-based PPP +interface. This causes pppd to disconnect immediately, and allows tools to +take immediate corrective action. + +Note that pppd's rp_pppoe.so plugin has code in it to disable the session +when it disconnects; however, as a consequence of this patch, the session is +already disabled before rp_pppoe.so is asked to disable the session. The +result is a harmless error message: + +Failed to disconnect PPPoE socket: 114 Operation already in progress + +This message is safe to ignore, as long as the error is 114 Operation +already in progress; in that specific case, it means that the PPPoE session +has already been disabled before pppd tried to disable it. + +Signed-off-by: Simon Farnsworth +Tested-by: Dan Williams +Tested-by: Christoph Schulz +Signed-off-by: David S. Miller +--- + +--- a/drivers/net/ppp/pppoe.c ++++ b/drivers/net/ppp/pppoe.c +@@ -455,6 +455,18 @@ out: + return NET_RX_DROP; + } + ++static void pppoe_unbind_sock_work(struct work_struct *work) ++{ ++ struct pppox_sock *po = container_of(work, struct pppox_sock, ++ proto.pppoe.padt_work); ++ struct sock *sk = sk_pppox(po); ++ ++ lock_sock(sk); ++ pppox_unbind_sock(sk); ++ release_sock(sk); ++ sock_put(sk); ++} ++ + /************************************************************************ + * + * Receive a PPPoE Discovery frame. +@@ -500,7 +512,8 @@ static int pppoe_disc_rcv(struct sk_buff + } + + bh_unlock_sock(sk); +- sock_put(sk); ++ if (!schedule_work(&po->proto.pppoe.padt_work)) ++ sock_put(sk); + } + + abort: +@@ -613,6 +626,8 @@ static int pppoe_connect(struct socket * + + lock_sock(sk); + ++ INIT_WORK(&po->proto.pppoe.padt_work, pppoe_unbind_sock_work); ++ + error = -EINVAL; + if (sp->sa_protocol != PX_PROTO_OE) + goto end; +--- a/include/linux/if_pppox.h ++++ b/include/linux/if_pppox.h +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + #include + + static inline struct pppoe_hdr *pppoe_hdr(const struct sk_buff *skb) +@@ -32,6 +33,7 @@ struct pppoe_opt { + struct pppoe_addr pa; /* what this socket is bound to*/ + struct sockaddr_pppox relay; /* what socket data will be + relayed to (PPPoE relaying) */ ++ struct work_struct padt_work;/* Work item for handling PADT */ + }; + + struct pptp_opt { diff --git a/target/linux/generic/patches-4.0/091-mtd-spi-nor-add-support-Spansion_S25FL164K b/target/linux/generic/patches-4.0/091-mtd-spi-nor-add-support-Spansion_S25FL164K new file mode 100644 index 0000000..51d93de --- /dev/null +++ b/target/linux/generic/patches-4.0/091-mtd-spi-nor-add-support-Spansion_S25FL164K @@ -0,0 +1,10 @@ +--- a/drivers/mtd/spi-nor/spi-nor.c ++++ b/drivers/mtd/spi-nor/spi-nor.c +@@ -598,6 +598,7 @@ static const struct spi_device_id spi_no + { "s25fl016k", INFO(0xef4015, 0, 64 * 1024, 32, SECT_4K) }, + { "s25fl064k", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) }, + { "s25fl132k", INFO(0x014016, 0, 64 * 1024, 64, 0) }, ++ { "s25fl164k", INFO(0x014017, 0, 64 * 1024, 128, SECT_4K) }, + + /* SST -- large erase sizes are "overlays", "sectors" are 4K */ + { "sst25vf040b", INFO(0xbf258d, 0, 64 * 1024, 8, SECT_4K | SST_WRITE) }, diff --git a/target/linux/generic/patches-4.0/095-api-fix-compatibility-of-linux-in.h-with-netinet-in..patch b/target/linux/generic/patches-4.0/095-api-fix-compatibility-of-linux-in.h-with-netinet-in..patch new file mode 100644 index 0000000..d0bea94 --- /dev/null +++ b/target/linux/generic/patches-4.0/095-api-fix-compatibility-of-linux-in.h-with-netinet-in..patch @@ -0,0 +1,146 @@ +From 279c6c7fa64f5763e6b9f05e7ab3840092e702e7 Mon Sep 17 00:00:00 2001 +From: Stephen Hemminger +Date: Mon, 29 Jun 2015 14:57:48 -1000 +Subject: [PATCH] api: fix compatibility of linux/in.h with netinet/in.h + +u +This fixes breakage to iproute2 build with recent kernel headers +caused by: + commit a263653ed798216c0069922d7b5237ca49436007 + Author: Pablo Neira Ayuso + Date: Wed Jun 17 10:28:27 2015 -0500 + + netfilter: don't pull include/linux/netfilter.h from netns headers + +The issue is that definitions in linux/in.h overlap with those +in netinet/in.h. This patch solves this by introducing the same +mechanism as was used to solve the same problem with linux/in6.h + +Signed-off-by: Stephen Hemminger +Signed-off-by: David S. Miller +--- + include/uapi/linux/in.h | 16 +++++++++++++--- + include/uapi/linux/libc-compat.h | 22 ++++++++++++++++++++++ + 2 files changed, 35 insertions(+), 3 deletions(-) + +--- a/include/uapi/linux/in.h ++++ b/include/uapi/linux/in.h +@@ -19,8 +19,10 @@ + #define _UAPI_LINUX_IN_H + + #include ++#include + #include + ++#if __UAPI_DEF_IN_IPPROTO + /* Standard well-defined IP protocols. */ + enum { + IPPROTO_IP = 0, /* Dummy protocol for TCP */ +@@ -73,12 +75,14 @@ enum { + #define IPPROTO_RAW IPPROTO_RAW + IPPROTO_MAX + }; ++#endif + +- ++#if __UAPI_DEF_IN_ADDR + /* Internet address. */ + struct in_addr { + __be32 s_addr; + }; ++#endif + + #define IP_TOS 1 + #define IP_TTL 2 +@@ -155,6 +159,7 @@ struct in_addr { + + /* Request struct for multicast socket ops */ + ++#if __UAPI_DEF_IP_MREQ + struct ip_mreq { + struct in_addr imr_multiaddr; /* IP multicast address of group */ + struct in_addr imr_interface; /* local IP address of interface */ +@@ -206,14 +211,18 @@ struct group_filter { + #define GROUP_FILTER_SIZE(numsrc) \ + (sizeof(struct group_filter) - sizeof(struct __kernel_sockaddr_storage) \ + + (numsrc) * sizeof(struct __kernel_sockaddr_storage)) ++#endif + ++#if __UAPI_DEF_IN_PKTINFO + struct in_pktinfo { + int ipi_ifindex; + struct in_addr ipi_spec_dst; + struct in_addr ipi_addr; + }; ++#endif + + /* Structure describing an Internet (IP) socket address. */ ++#if __UAPI_DEF_SOCKADDR_IN + #define __SOCK_SIZE__ 16 /* sizeof(struct sockaddr) */ + struct sockaddr_in { + __kernel_sa_family_t sin_family; /* Address family */ +@@ -225,8 +234,9 @@ struct sockaddr_in { + sizeof(unsigned short int) - sizeof(struct in_addr)]; + }; + #define sin_zero __pad /* for BSD UNIX comp. -FvK */ ++#endif + +- ++#if __UAPI_DEF_IN_CLASS + /* + * Definitions of the bits in an Internet address integer. + * On subnets, host and network parts are found according +@@ -277,7 +287,7 @@ struct sockaddr_in { + #define INADDR_ALLHOSTS_GROUP 0xe0000001U /* 224.0.0.1 */ + #define INADDR_ALLRTRS_GROUP 0xe0000002U /* 224.0.0.2 */ + #define INADDR_MAX_LOCAL_GROUP 0xe00000ffU /* 224.0.0.255 */ +- ++#endif + + /* contains the htonl type stuff.. */ + #include +--- a/include/uapi/linux/libc-compat.h ++++ b/include/uapi/linux/libc-compat.h +@@ -56,6 +56,13 @@ + + /* GLIBC headers included first so don't define anything + * that would already be defined. */ ++#define __UAPI_DEF_IN_ADDR 0 ++#define __UAPI_DEF_IN_IPPROTO 0 ++#define __UAPI_DEF_IN_PKTINFO 0 ++#define __UAPI_DEF_IP_MREQ 0 ++#define __UAPI_DEF_SOCKADDR_IN 0 ++#define __UAPI_DEF_IN_CLASS 0 ++ + #define __UAPI_DEF_IN6_ADDR 0 + /* The exception is the in6_addr macros which must be defined + * if the glibc code didn't define them. This guard matches +@@ -78,6 +85,13 @@ + /* Linux headers included first, and we must define everything + * we need. The expectation is that glibc will check the + * __UAPI_DEF_* defines and adjust appropriately. */ ++#define __UAPI_DEF_IN_ADDR 1 ++#define __UAPI_DEF_IN_IPPROTO 1 ++#define __UAPI_DEF_IN_PKTINFO 1 ++#define __UAPI_DEF_IP_MREQ 1 ++#define __UAPI_DEF_SOCKADDR_IN 1 ++#define __UAPI_DEF_IN_CLASS 1 ++ + #define __UAPI_DEF_IN6_ADDR 1 + /* We unconditionally define the in6_addr macros and glibc must + * coordinate. */ +@@ -103,6 +117,14 @@ + * that we need. */ + #else /* !defined(__GLIBC__) */ + ++/* Definitions for in.h */ ++#define __UAPI_DEF_IN_ADDR 1 ++#define __UAPI_DEF_IN_IPPROTO 1 ++#define __UAPI_DEF_IN_PKTINFO 1 ++#define __UAPI_DEF_IP_MREQ 1 ++#define __UAPI_DEF_SOCKADDR_IN 1 ++#define __UAPI_DEF_IN_CLASS 1 ++ + /* Definitions for in6.h */ + #define __UAPI_DEF_IN6_ADDR 1 + #define __UAPI_DEF_IN6_ADDR_ALT 1 diff --git a/target/linux/generic/patches-4.0/100-pppoe-drop-pppoe-device-in-pppoe_unbind_sock_work.patch b/target/linux/generic/patches-4.0/100-pppoe-drop-pppoe-device-in-pppoe_unbind_sock_work.patch new file mode 100644 index 0000000..c461b3e --- /dev/null +++ b/target/linux/generic/patches-4.0/100-pppoe-drop-pppoe-device-in-pppoe_unbind_sock_work.patch @@ -0,0 +1,27 @@ +From: Felix Fietkau +Date: Sat, 9 May 2015 23:03:47 +0200 +Subject: [PATCH] pppoe: drop pppoe device in pppoe_unbind_sock_work + +After receiving a PADT and the socket is closed, user space will no +longer drop the reference to the pppoe device. +This leads to errors like this: + +[ 488.570000] unregister_netdevice: waiting for eth0.2 to become free. Usage count = 2 + +Fixes: 287f3a943fe ("pppoe: Use workqueue to die properly when a PADT is received") +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ppp/pppoe.c ++++ b/drivers/net/ppp/pppoe.c +@@ -462,6 +462,10 @@ static void pppoe_unbind_sock_work(struc + struct sock *sk = sk_pppox(po); + + lock_sock(sk); ++ if (po->pppoe_dev) { ++ dev_put(po->pppoe_dev); ++ po->pppoe_dev = NULL; ++ } + pppox_unbind_sock(sk); + release_sock(sk); + sock_put(sk); diff --git a/target/linux/generic/patches-4.0/102-ehci_hcd_ignore_oc.patch b/target/linux/generic/patches-4.0/102-ehci_hcd_ignore_oc.patch new file mode 100644 index 0000000..4da579c --- /dev/null +++ b/target/linux/generic/patches-4.0/102-ehci_hcd_ignore_oc.patch @@ -0,0 +1,82 @@ +From 1e311820ec3055e3f08e687de6564692a7cec675 Mon Sep 17 00:00:00 2001 +From: Florian Fainelli +Date: Mon, 28 Jan 2013 20:06:29 +0100 +Subject: [PATCH 11/12] USB: EHCI: add ignore_oc flag to disable overcurrent + checking + +This patch adds an ignore_oc flag which can be set by EHCI controller +not supporting or wanting to disable overcurrent checking. The EHCI +platform data in include/linux/usb/ehci_pdriver.h is also augmented to +take advantage of this new flag. + +Signed-off-by: Florian Fainelli +--- + drivers/usb/host/ehci-hcd.c | 2 +- + drivers/usb/host/ehci-hub.c | 4 ++-- + drivers/usb/host/ehci-platform.c | 1 + + drivers/usb/host/ehci.h | 1 + + include/linux/usb/ehci_pdriver.h | 1 + + 5 files changed, 6 insertions(+), 3 deletions(-) + +--- a/drivers/usb/host/ehci-hcd.c ++++ b/drivers/usb/host/ehci-hcd.c +@@ -638,7 +638,7 @@ static int ehci_run (struct usb_hcd *hcd + "USB %x.%x started, EHCI %x.%02x%s\n", + ((ehci->sbrn & 0xf0)>>4), (ehci->sbrn & 0x0f), + temp >> 8, temp & 0xff, +- ignore_oc ? ", overcurrent ignored" : ""); ++ (ignore_oc || ehci->ignore_oc) ? ", overcurrent ignored" : ""); + + ehci_writel(ehci, INTR_MASK, + &ehci->regs->intr_enable); /* Turn On Interrupts */ +--- a/drivers/usb/host/ehci-hub.c ++++ b/drivers/usb/host/ehci-hub.c +@@ -633,7 +633,7 @@ ehci_hub_status_data (struct usb_hcd *hc + * always set, seem to clear PORT_OCC and PORT_CSC when writing to + * PORT_POWER; that's surprising, but maybe within-spec. + */ +- if (!ignore_oc) ++ if (!ignore_oc && !ehci->ignore_oc) + mask = PORT_CSC | PORT_PEC | PORT_OCC; + else + mask = PORT_CSC | PORT_PEC; +@@ -995,7 +995,7 @@ int ehci_hub_control( + if (temp & PORT_PEC) + status |= USB_PORT_STAT_C_ENABLE << 16; + +- if ((temp & PORT_OCC) && !ignore_oc){ ++ if ((temp & PORT_OCC) && (!ignore_oc && !ehci->ignore_oc)){ + status |= USB_PORT_STAT_C_OVERCURRENT << 16; + + /* +--- a/drivers/usb/host/ehci-platform.c ++++ b/drivers/usb/host/ehci-platform.c +@@ -264,6 +264,8 @@ static int ehci_platform_probe(struct pl + ehci->big_endian_desc = 1; + if (pdata->big_endian_mmio) + ehci->big_endian_mmio = 1; ++ if (pdata->ignore_oc) ++ ehci->ignore_oc = 1; + + #ifndef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO + if (ehci->big_endian_mmio) { +--- a/drivers/usb/host/ehci.h ++++ b/drivers/usb/host/ehci.h +@@ -226,6 +226,7 @@ struct ehci_hcd { /* one per controlle + unsigned frame_index_bug:1; /* MosChip (AKA NetMos) */ + unsigned need_oc_pp_cycle:1; /* MPC834X port power */ + unsigned imx28_write_fix:1; /* For Freescale i.MX28 */ ++ unsigned ignore_oc:1; + + /* required for usb32 quirk */ + #define OHCI_CTRL_HCFS (3 << 6) +--- a/include/linux/usb/ehci_pdriver.h ++++ b/include/linux/usb/ehci_pdriver.h +@@ -49,6 +49,7 @@ struct usb_ehci_pdata { + unsigned no_io_watchdog:1; + unsigned reset_on_resume:1; + unsigned dma_mask_64:1; ++ unsigned ignore_oc:1; + + /* Turn on all power and clocks */ + int (*power_on)(struct platform_device *pdev); diff --git a/target/linux/generic/patches-4.0/110-jffs2-use-.rename2-and-add-RENAME_WHITEOUT-support.patch b/target/linux/generic/patches-4.0/110-jffs2-use-.rename2-and-add-RENAME_WHITEOUT-support.patch new file mode 100644 index 0000000..9d32777 --- /dev/null +++ b/target/linux/generic/patches-4.0/110-jffs2-use-.rename2-and-add-RENAME_WHITEOUT-support.patch @@ -0,0 +1,86 @@ +From: Felix Fietkau +Date: Fri, 10 Apr 2015 13:35:29 +0200 +Subject: [PATCH] jffs2: use .rename2 and add RENAME_WHITEOUT support + +It is required for renames on overlayfs + +Signed-off-by: Felix Fietkau +--- + +--- a/fs/jffs2/dir.c ++++ b/fs/jffs2/dir.c +@@ -35,7 +35,7 @@ static int jffs2_mkdir (struct inode *,s + static int jffs2_rmdir (struct inode *,struct dentry *); + static int jffs2_mknod (struct inode *,struct dentry *,umode_t,dev_t); + static int jffs2_rename (struct inode *, struct dentry *, +- struct inode *, struct dentry *); ++ struct inode *, struct dentry *, unsigned int); + + const struct file_operations jffs2_dir_operations = + { +@@ -57,7 +57,7 @@ const struct inode_operations jffs2_dir_ + .mkdir = jffs2_mkdir, + .rmdir = jffs2_rmdir, + .mknod = jffs2_mknod, +- .rename = jffs2_rename, ++ .rename2 = jffs2_rename, + .get_acl = jffs2_get_acl, + .set_acl = jffs2_set_acl, + .setattr = jffs2_setattr, +@@ -756,8 +756,27 @@ static int jffs2_mknod (struct inode *di + return ret; + } + ++static int jffs2_whiteout(struct inode *old_dir, struct dentry *old_dentry) ++{ ++ struct dentry *wh; ++ int err; ++ ++ wh = d_alloc(old_dentry->d_parent, &old_dentry->d_name); ++ if (!wh) ++ return -ENOMEM; ++ ++ err = jffs2_mknod(old_dir, wh, S_IFCHR | WHITEOUT_MODE, ++ WHITEOUT_DEV); ++ if (err) ++ return err; ++ ++ d_rehash(wh); ++ return 0; ++} ++ + static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry, +- struct inode *new_dir_i, struct dentry *new_dentry) ++ struct inode *new_dir_i, struct dentry *new_dentry, ++ unsigned int flags) + { + int ret; + struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dir_i->i_sb); +@@ -765,6 +784,9 @@ static int jffs2_rename (struct inode *o + uint8_t type; + uint32_t now; + ++ if (flags & ~RENAME_WHITEOUT) ++ return -EINVAL; ++ + /* The VFS will check for us and prevent trying to rename a + * file over a directory and vice versa, but if it's a directory, + * the VFS can't check whether the victim is empty. The filesystem +@@ -828,9 +850,14 @@ static int jffs2_rename (struct inode *o + if (d_is_dir(old_dentry) && !victim_f) + inc_nlink(new_dir_i); + +- /* Unlink the original */ +- ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i), +- old_dentry->d_name.name, old_dentry->d_name.len, NULL, now); ++ if (flags & RENAME_WHITEOUT) ++ /* Replace with whiteout */ ++ ret = jffs2_whiteout(old_dir_i, old_dentry); ++ else ++ /* Unlink the original */ ++ ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i), ++ old_dentry->d_name.name, ++ old_dentry->d_name.len, NULL, now); + + /* We don't touch inode->i_nlink */ + diff --git a/target/linux/generic/patches-4.0/111-jffs2-add-RENAME_EXCHANGE-support.patch b/target/linux/generic/patches-4.0/111-jffs2-add-RENAME_EXCHANGE-support.patch new file mode 100644 index 0000000..5e4722d --- /dev/null +++ b/target/linux/generic/patches-4.0/111-jffs2-add-RENAME_EXCHANGE-support.patch @@ -0,0 +1,58 @@ +From: Felix Fietkau +Date: Sat, 25 Apr 2015 12:41:32 +0200 +Subject: [PATCH] jffs2: add RENAME_EXCHANGE support + +Signed-off-by: Felix Fietkau +--- + +--- a/fs/jffs2/dir.c ++++ b/fs/jffs2/dir.c +@@ -784,7 +784,7 @@ static int jffs2_rename (struct inode *o + uint8_t type; + uint32_t now; + +- if (flags & ~RENAME_WHITEOUT) ++ if (flags & ~(RENAME_WHITEOUT | RENAME_EXCHANGE)) + return -EINVAL; + + /* The VFS will check for us and prevent trying to rename a +@@ -792,7 +792,7 @@ static int jffs2_rename (struct inode *o + * the VFS can't check whether the victim is empty. The filesystem + * needs to do that for itself. + */ +- if (new_dentry->d_inode) { ++ if (new_dentry->d_inode && !(flags & RENAME_EXCHANGE)) { + victim_f = JFFS2_INODE_INFO(new_dentry->d_inode); + if (d_is_dir(new_dentry)) { + struct jffs2_full_dirent *fd; +@@ -827,7 +827,7 @@ static int jffs2_rename (struct inode *o + if (ret) + return ret; + +- if (victim_f) { ++ if (victim_f && !(flags & RENAME_EXCHANGE)) { + /* There was a victim. Kill it off nicely */ + if (d_is_dir(new_dentry)) + clear_nlink(new_dentry->d_inode); +@@ -853,6 +853,12 @@ static int jffs2_rename (struct inode *o + if (flags & RENAME_WHITEOUT) + /* Replace with whiteout */ + ret = jffs2_whiteout(old_dir_i, old_dentry); ++ else if (flags & RENAME_EXCHANGE) ++ /* Replace the original */ ++ ret = jffs2_do_link(c, JFFS2_INODE_INFO(old_dir_i), ++ new_dentry->d_inode->i_ino, type, ++ old_dentry->d_name.name, old_dentry->d_name.len, ++ now); + else + /* Unlink the original */ + ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i), +@@ -879,7 +885,7 @@ static int jffs2_rename (struct inode *o + return ret; + } + +- if (d_is_dir(old_dentry)) ++ if (d_is_dir(old_dentry) && !(flags & RENAME_EXCHANGE)) + drop_nlink(old_dir_i); + + new_dir_i->i_mtime = new_dir_i->i_ctime = old_dir_i->i_mtime = old_dir_i->i_ctime = ITIME(now); diff --git a/target/linux/generic/patches-4.0/120-bridge_allow_receiption_on_disabled_port.patch b/target/linux/generic/patches-4.0/120-bridge_allow_receiption_on_disabled_port.patch new file mode 100644 index 0000000..bd24fdb --- /dev/null +++ b/target/linux/generic/patches-4.0/120-bridge_allow_receiption_on_disabled_port.patch @@ -0,0 +1,54 @@ +From: Stephen Hemminger +Subject: bridge: allow receiption on disabled port + +When an ethernet device is enslaved to a bridge, and the bridge STP +detects loss of carrier (or operational state down), then normally +packet receiption is blocked. + +This breaks control applications like WPA which maybe expecting to +receive packets to negotiate to bring link up. The bridge needs to +block forwarding packets from these disabled ports, but there is no +hard requirement to not allow local packet delivery. + +Signed-off-by: Stephen Hemminger +Signed-off-by: Felix Fietkau + +--- a/net/bridge/br_input.c ++++ b/net/bridge/br_input.c +@@ -207,11 +207,13 @@ EXPORT_SYMBOL_GPL(br_handle_frame_finish + static int br_handle_local_finish(struct sk_buff *skb) + { + struct net_bridge_port *p = br_port_get_rcu(skb->dev); +- u16 vid = 0; ++ if (p->state != BR_STATE_DISABLED) { ++ u16 vid = 0; + +- /* check if vlan is allowed, to avoid spoofing */ +- if (p->flags & BR_LEARNING && br_should_learn(p, skb, &vid)) +- br_fdb_update(p->br, p, eth_hdr(skb)->h_source, vid, false); ++ /* check if vlan is allowed, to avoid spoofing */ ++ if (p->flags & BR_LEARNING && br_should_learn(p, skb, &vid)) ++ br_fdb_update(p->br, p, eth_hdr(skb)->h_source, vid, false); ++ } + return 0; /* process further */ + } + +@@ -285,6 +287,18 @@ rx_handler_result_t br_handle_frame(stru + + forward: + switch (p->state) { ++ case BR_STATE_DISABLED: ++ if (ether_addr_equal(p->br->dev->dev_addr, dest)) ++ skb->pkt_type = PACKET_HOST; ++ ++ if (NF_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL, ++ br_handle_local_finish)) ++ break; ++ ++ BR_INPUT_SKB_CB(skb)->brdev = p->br->dev; ++ br_pass_frame_up(skb); ++ break; ++ + case BR_STATE_FORWARDING: + rhook = rcu_dereference(br_should_route_hook); + if (rhook) { diff --git a/target/linux/generic/patches-4.0/130-MIPS-kernel-fix-sched_getaffinity-with-MT-FPAFF-enab.patch b/target/linux/generic/patches-4.0/130-MIPS-kernel-fix-sched_getaffinity-with-MT-FPAFF-enab.patch new file mode 100644 index 0000000..a7bfef3 --- /dev/null +++ b/target/linux/generic/patches-4.0/130-MIPS-kernel-fix-sched_getaffinity-with-MT-FPAFF-enab.patch @@ -0,0 +1,35 @@ +From: Felix Fietkau +Date: Sun, 19 Jul 2015 00:21:57 +0200 +Subject: [PATCH] MIPS: kernel: fix sched_getaffinity with MT FPAFF enabled + +p->thread.user_cpus_allowed is zero-initialized and is only filled on +the first sched_setaffinity call. + +To avoid adding overhead in the task initialization codepath, simply OR +the returned mask in sched_getaffinity with p->cpus_allowed. + +Cc: stable@vger.kernel.org +Signed-off-by: Felix Fietkau +--- + +--- a/arch/mips/kernel/mips-mt-fpaff.c ++++ b/arch/mips/kernel/mips-mt-fpaff.c +@@ -154,7 +154,7 @@ asmlinkage long mipsmt_sys_sched_getaffi + unsigned long __user *user_mask_ptr) + { + unsigned int real_len; +- cpumask_t mask; ++ cpumask_t allowed, mask; + int retval; + struct task_struct *p; + +@@ -173,7 +173,8 @@ asmlinkage long mipsmt_sys_sched_getaffi + if (retval) + goto out_unlock; + +- cpumask_and(&mask, &p->thread.user_cpus_allowed, cpu_possible_mask); ++ cpumask_or(&allowed, &p->thread.user_cpus_allowed, &p->cpus_allowed); ++ cpumask_and(&mask, &allowed, cpu_active_mask); + + out_unlock: + read_unlock(&tasklist_lock); diff --git a/target/linux/generic/patches-4.0/132-mips_inline_dma_ops.patch b/target/linux/generic/patches-4.0/132-mips_inline_dma_ops.patch new file mode 100644 index 0000000..eb12a28 --- /dev/null +++ b/target/linux/generic/patches-4.0/132-mips_inline_dma_ops.patch @@ -0,0 +1,693 @@ +From 2c58080407554e1bac8fd50d23cb02420524caed Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Mon, 12 Aug 2013 12:50:22 +0200 +Subject: [PATCH] MIPS: partially inline dma ops + +Several DMA ops are no-op on many platforms, and the indirection through +the mips_dma_map_ops function table is causing the compiler to emit +unnecessary code. + +Inlining visibly improves network performance in my tests (on a 24Kc +based system), and also slightly reduces code size of a few drivers. + +Signed-off-by: Felix Fietkau +--- + arch/mips/Kconfig | 4 + + arch/mips/include/asm/dma-mapping.h | 360 +++++++++++++++++++++++++++++++++++- + arch/mips/mm/dma-default.c | 163 ++-------------- + 3 files changed, 373 insertions(+), 154 deletions(-) + +--- a/arch/mips/Kconfig ++++ b/arch/mips/Kconfig +@@ -1526,6 +1526,7 @@ config CPU_CAVIUM_OCTEON + select CPU_SUPPORTS_HUGEPAGES + select USB_EHCI_BIG_ENDIAN_MMIO + select MIPS_L1_CACHE_SHIFT_7 ++ select SYS_HAS_DMA_OPS + help + The Cavium Octeon processor is a highly integrated chip containing + many ethernet hardware widgets for networking tasks. The processor +@@ -1790,6 +1791,9 @@ config MIPS_MALTA_PM + bool + default y + ++config SYS_HAS_DMA_OPS ++ bool ++ + # + # CPU may reorder R->R, R->W, W->R, W->W + # Reordering beyond LL and SC is handled in WEAK_REORDERING_BEYOND_LLSC +--- a/arch/mips/include/asm/dma-mapping.h ++++ b/arch/mips/include/asm/dma-mapping.h +@@ -1,9 +1,16 @@ + #ifndef _ASM_DMA_MAPPING_H + #define _ASM_DMA_MAPPING_H + ++#include ++#include ++#include ++#include ++#include ++ + #include + #include + #include ++#include + #include + + #ifndef CONFIG_SGI_IP27 /* Kludge to fix 2.6.39 build for IP27 */ +@@ -12,12 +19,48 @@ + + extern struct dma_map_ops *mips_dma_map_ops; + ++void __dma_sync(struct page *page, unsigned long offset, size_t size, ++ enum dma_data_direction direction); ++void *mips_dma_alloc_coherent(struct device *dev, size_t size, ++ dma_addr_t *dma_handle, gfp_t gfp, ++ struct dma_attrs *attrs); ++void mips_dma_free_coherent(struct device *dev, size_t size, void *vaddr, ++ dma_addr_t dma_handle, struct dma_attrs *attrs); ++ + static inline struct dma_map_ops *get_dma_ops(struct device *dev) + { ++#ifdef CONFIG_SYS_HAS_DMA_OPS + if (dev && dev->archdata.dma_ops) + return dev->archdata.dma_ops; + else + return mips_dma_map_ops; ++#else ++ return NULL; ++#endif ++} ++ ++/* ++ * Warning on the terminology - Linux calls an uncached area coherent; ++ * MIPS terminology calls memory areas with hardware maintained coherency ++ * coherent. ++ */ ++ ++static inline int cpu_needs_post_dma_flush(struct device *dev) ++{ ++#ifndef CONFIG_SYS_HAS_CPU_R10000 ++ return 0; ++#endif ++ return !plat_device_is_coherent(dev) && ++ (boot_cpu_type() == CPU_R10000 || ++ boot_cpu_type() == CPU_R12000 || ++ boot_cpu_type() == CPU_BMIPS5000); ++} ++ ++static inline struct page *dma_addr_to_page(struct device *dev, ++ dma_addr_t dma_addr) ++{ ++ return pfn_to_page( ++ plat_dma_addr_to_phys(dev, dma_addr) >> PAGE_SHIFT); + } + + static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) +@@ -30,12 +73,304 @@ static inline bool dma_capable(struct de + + static inline void dma_mark_clean(void *addr, size_t size) {} + +-#include ++static inline dma_addr_t dma_map_single_attrs(struct device *dev, void *ptr, ++ size_t size, ++ enum dma_data_direction dir, ++ struct dma_attrs *attrs) ++{ ++ struct dma_map_ops *ops = get_dma_ops(dev); ++ unsigned long offset = (unsigned long)ptr & ~PAGE_MASK; ++ struct page *page = virt_to_page(ptr); ++ dma_addr_t addr; ++ ++ kmemcheck_mark_initialized(ptr, size); ++ BUG_ON(!valid_dma_direction(dir)); ++ if (ops) { ++ addr = ops->map_page(dev, page, offset, size, dir, attrs); ++ } else { ++ if (!plat_device_is_coherent(dev)) ++ __dma_sync(page, offset, size, dir); ++ ++ addr = plat_map_dma_mem_page(dev, page) + offset; ++ } ++ debug_dma_map_page(dev, page, offset, size, dir, addr, true); ++ return addr; ++} ++ ++static inline void dma_unmap_single_attrs(struct device *dev, dma_addr_t addr, ++ size_t size, ++ enum dma_data_direction dir, ++ struct dma_attrs *attrs) ++{ ++ struct dma_map_ops *ops = get_dma_ops(dev); ++ ++ BUG_ON(!valid_dma_direction(dir)); ++ if (ops) { ++ ops->unmap_page(dev, addr, size, dir, attrs); ++ } else { ++ if (cpu_needs_post_dma_flush(dev)) ++ __dma_sync(dma_addr_to_page(dev, addr), ++ addr & ~PAGE_MASK, size, dir); ++ ++ plat_unmap_dma_mem(dev, addr, size, dir); ++ } ++ debug_dma_unmap_page(dev, addr, size, dir, true); ++} ++ ++static inline int dma_map_sg_attrs(struct device *dev, struct scatterlist *sg, ++ int nents, enum dma_data_direction dir, ++ struct dma_attrs *attrs) ++{ ++ struct dma_map_ops *ops = get_dma_ops(dev); ++ int i, ents; ++ struct scatterlist *s; ++ ++ for_each_sg(sg, s, nents, i) ++ kmemcheck_mark_initialized(sg_virt(s), s->length); ++ BUG_ON(!valid_dma_direction(dir)); ++ if (ops) { ++ ents = ops->map_sg(dev, sg, nents, dir, attrs); ++ } else { ++ for_each_sg(sg, s, nents, i) { ++ struct page *page = sg_page(s); ++ ++ if (!plat_device_is_coherent(dev)) ++ __dma_sync(page, s->offset, s->length, dir); ++#ifdef CONFIG_NEED_SG_DMA_LENGTH ++ s->dma_length = s->length; ++#endif ++ s->dma_address = ++ plat_map_dma_mem_page(dev, page) + s->offset; ++ } ++ ents = nents; ++ } ++ debug_dma_map_sg(dev, sg, nents, ents, dir); ++ ++ return ents; ++} ++ ++static inline void dma_unmap_sg_attrs(struct device *dev, struct scatterlist *sg, ++ int nents, enum dma_data_direction dir, ++ struct dma_attrs *attrs) ++{ ++ struct dma_map_ops *ops = get_dma_ops(dev); ++ struct scatterlist *s; ++ int i; ++ ++ BUG_ON(!valid_dma_direction(dir)); ++ debug_dma_unmap_sg(dev, sg, nents, dir); ++ if (ops) { ++ ops->unmap_sg(dev, sg, nents, dir, attrs); ++ return; ++ } ++ ++ for_each_sg(sg, s, nents, i) { ++ if (!plat_device_is_coherent(dev) && dir != DMA_TO_DEVICE) ++ __dma_sync(sg_page(s), s->offset, s->length, dir); ++ plat_unmap_dma_mem(dev, s->dma_address, s->length, dir); ++ } ++} ++ ++static inline dma_addr_t dma_map_page(struct device *dev, struct page *page, ++ size_t offset, size_t size, ++ enum dma_data_direction dir) ++{ ++ struct dma_map_ops *ops = get_dma_ops(dev); ++ dma_addr_t addr; ++ ++ kmemcheck_mark_initialized(page_address(page) + offset, size); ++ BUG_ON(!valid_dma_direction(dir)); ++ if (ops) { ++ addr = ops->map_page(dev, page, offset, size, dir, NULL); ++ } else { ++ if (!plat_device_is_coherent(dev)) ++ __dma_sync(page, offset, size, dir); ++ ++ addr = plat_map_dma_mem_page(dev, page) + offset; ++ } ++ debug_dma_map_page(dev, page, offset, size, dir, addr, false); ++ ++ return addr; ++} ++ ++static inline void dma_unmap_page(struct device *dev, dma_addr_t addr, ++ size_t size, enum dma_data_direction dir) ++{ ++ struct dma_map_ops *ops = get_dma_ops(dev); ++ ++ BUG_ON(!valid_dma_direction(dir)); ++ if (ops) { ++ ops->unmap_page(dev, addr, size, dir, NULL); ++ } else { ++ if (cpu_needs_post_dma_flush(dev)) ++ __dma_sync(dma_addr_to_page(dev, addr), ++ addr & ~PAGE_MASK, size, dir); ++ ++ plat_unmap_dma_mem(dev, addr, size, dir); ++ } ++ debug_dma_unmap_page(dev, addr, size, dir, false); ++} ++ ++static inline void dma_sync_single_for_cpu(struct device *dev, dma_addr_t addr, ++ size_t size, ++ enum dma_data_direction dir) ++{ ++ struct dma_map_ops *ops = get_dma_ops(dev); ++ ++ BUG_ON(!valid_dma_direction(dir)); ++ if (ops) ++ ops->sync_single_for_cpu(dev, addr, size, dir); ++ else if (cpu_needs_post_dma_flush(dev)) ++ __dma_sync(dma_addr_to_page(dev, addr), ++ addr & ~PAGE_MASK, size, dir); ++ debug_dma_sync_single_for_cpu(dev, addr, size, dir); ++} ++ ++static inline void dma_sync_single_for_device(struct device *dev, ++ dma_addr_t addr, size_t size, ++ enum dma_data_direction dir) ++{ ++ struct dma_map_ops *ops = get_dma_ops(dev); ++ ++ BUG_ON(!valid_dma_direction(dir)); ++ if (ops) ++ ops->sync_single_for_device(dev, addr, size, dir); ++ else if (!plat_device_is_coherent(dev)) ++ __dma_sync(dma_addr_to_page(dev, addr), ++ addr & ~PAGE_MASK, size, dir); ++ debug_dma_sync_single_for_device(dev, addr, size, dir); ++} ++ ++static inline void dma_sync_single_range_for_cpu(struct device *dev, ++ dma_addr_t addr, ++ unsigned long offset, ++ size_t size, ++ enum dma_data_direction dir) ++{ ++ const struct dma_map_ops *ops = get_dma_ops(dev); ++ ++ BUG_ON(!valid_dma_direction(dir)); ++ if (ops) ++ ops->sync_single_for_cpu(dev, addr + offset, size, dir); ++ else if (cpu_needs_post_dma_flush(dev)) ++ __dma_sync(dma_addr_to_page(dev, addr + offset), ++ (addr + offset) & ~PAGE_MASK, size, dir); ++ debug_dma_sync_single_range_for_cpu(dev, addr, offset, size, dir); ++} ++ ++static inline void dma_sync_single_range_for_device(struct device *dev, ++ dma_addr_t addr, ++ unsigned long offset, ++ size_t size, ++ enum dma_data_direction dir) ++{ ++ const struct dma_map_ops *ops = get_dma_ops(dev); ++ ++ BUG_ON(!valid_dma_direction(dir)); ++ if (ops) ++ ops->sync_single_for_device(dev, addr + offset, size, dir); ++ else if (!plat_device_is_coherent(dev)) ++ __dma_sync(dma_addr_to_page(dev, addr + offset), ++ (addr + offset) & ~PAGE_MASK, size, dir); ++ debug_dma_sync_single_range_for_device(dev, addr, offset, size, dir); ++} ++ ++static inline void ++dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, ++ int nelems, enum dma_data_direction dir) ++{ ++ struct dma_map_ops *ops = get_dma_ops(dev); ++ struct scatterlist *s; ++ int i; ++ ++ BUG_ON(!valid_dma_direction(dir)); ++ if (ops) ++ ops->sync_sg_for_cpu(dev, sg, nelems, dir); ++ else if (cpu_needs_post_dma_flush(dev)) { ++ for_each_sg(sg, s, nelems, i) ++ __dma_sync(sg_page(s), s->offset, s->length, dir); ++ } ++ debug_dma_sync_sg_for_cpu(dev, sg, nelems, dir); ++} ++ ++static inline void ++dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, ++ int nelems, enum dma_data_direction dir) ++{ ++ struct dma_map_ops *ops = get_dma_ops(dev); ++ struct scatterlist *s; ++ int i; ++ ++ BUG_ON(!valid_dma_direction(dir)); ++ if (ops) ++ ops->sync_sg_for_device(dev, sg, nelems, dir); ++ else if (!plat_device_is_coherent(dev)) { ++ for_each_sg(sg, s, nelems, i) ++ __dma_sync(sg_page(s), s->offset, s->length, dir); ++ } ++ debug_dma_sync_sg_for_device(dev, sg, nelems, dir); ++ ++} ++ ++#define dma_map_single(d, a, s, r) dma_map_single_attrs(d, a, s, r, NULL) ++#define dma_unmap_single(d, a, s, r) dma_unmap_single_attrs(d, a, s, r, NULL) ++#define dma_map_sg(d, s, n, r) dma_map_sg_attrs(d, s, n, r, NULL) ++#define dma_unmap_sg(d, s, n, r) dma_unmap_sg_attrs(d, s, n, r, NULL) ++ ++extern int dma_common_mmap(struct device *dev, struct vm_area_struct *vma, ++ void *cpu_addr, dma_addr_t dma_addr, size_t size); ++ ++/** ++ * dma_mmap_attrs - map a coherent DMA allocation into user space ++ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices ++ * @vma: vm_area_struct describing requested user mapping ++ * @cpu_addr: kernel CPU-view address returned from dma_alloc_attrs ++ * @handle: device-view address returned from dma_alloc_attrs ++ * @size: size of memory originally requested in dma_alloc_attrs ++ * @attrs: attributes of mapping properties requested in dma_alloc_attrs ++ * ++ * Map a coherent DMA buffer previously allocated by dma_alloc_attrs ++ * into user space. The coherent DMA buffer must not be freed by the ++ * driver until the user space mapping has been released. ++ */ ++static inline int ++dma_mmap_attrs(struct device *dev, struct vm_area_struct *vma, void *cpu_addr, ++ dma_addr_t dma_addr, size_t size, struct dma_attrs *attrs) ++{ ++ struct dma_map_ops *ops = get_dma_ops(dev); ++ BUG_ON(!ops); ++ if (ops && ops->mmap) ++ return ops->mmap(dev, vma, cpu_addr, dma_addr, size, attrs); ++ return dma_common_mmap(dev, vma, cpu_addr, dma_addr, size); ++} ++ ++#define dma_mmap_coherent(d, v, c, h, s) dma_mmap_attrs(d, v, c, h, s, NULL) ++ ++int ++dma_common_get_sgtable(struct device *dev, struct sg_table *sgt, ++ void *cpu_addr, dma_addr_t dma_addr, size_t size); ++ ++static inline int ++dma_get_sgtable_attrs(struct device *dev, struct sg_table *sgt, void *cpu_addr, ++ dma_addr_t dma_addr, size_t size, struct dma_attrs *attrs) ++{ ++ struct dma_map_ops *ops = get_dma_ops(dev); ++ BUG_ON(!ops); ++ if (ops && ops->get_sgtable) ++ return ops->get_sgtable(dev, sgt, cpu_addr, dma_addr, size, ++ attrs); ++ return dma_common_get_sgtable(dev, sgt, cpu_addr, dma_addr, size); ++} ++ ++#define dma_get_sgtable(d, t, v, h, s) dma_get_sgtable_attrs(d, t, v, h, s, NULL) ++ + + static inline int dma_supported(struct device *dev, u64 mask) + { + struct dma_map_ops *ops = get_dma_ops(dev); +- return ops->dma_supported(dev, mask); ++ if (ops) ++ return ops->dma_supported(dev, mask); ++ return plat_dma_supported(dev, mask); + } + + static inline int dma_mapping_error(struct device *dev, u64 mask) +@@ -43,7 +378,9 @@ static inline int dma_mapping_error(stru + struct dma_map_ops *ops = get_dma_ops(dev); + + debug_dma_mapping_error(dev, mask); +- return ops->mapping_error(dev, mask); ++ if (ops) ++ return ops->mapping_error(dev, mask); ++ return 0; + } + + static inline int +@@ -54,7 +391,7 @@ dma_set_mask(struct device *dev, u64 mas + if(!dev->dma_mask || !dma_supported(dev, mask)) + return -EIO; + +- if (ops->set_dma_mask) ++ if (ops && ops->set_dma_mask) + return ops->set_dma_mask(dev, mask); + + *dev->dma_mask = mask; +@@ -74,7 +411,11 @@ static inline void *dma_alloc_attrs(stru + void *ret; + struct dma_map_ops *ops = get_dma_ops(dev); + +- ret = ops->alloc(dev, size, dma_handle, gfp, attrs); ++ if (ops) ++ ret = ops->alloc(dev, size, dma_handle, gfp, attrs); ++ else ++ ret = mips_dma_alloc_coherent(dev, size, dma_handle, gfp, ++ attrs); + + debug_dma_alloc_coherent(dev, size, *dma_handle, ret); + +@@ -89,7 +430,10 @@ static inline void dma_free_attrs(struct + { + struct dma_map_ops *ops = get_dma_ops(dev); + +- ops->free(dev, size, vaddr, dma_handle, attrs); ++ if (ops) ++ ops->free(dev, size, vaddr, dma_handle, attrs); ++ else ++ mips_dma_free_coherent(dev, size, vaddr, dma_handle, attrs); + + debug_dma_free_coherent(dev, size, vaddr, dma_handle); + } +--- a/arch/mips/mm/dma-default.c ++++ b/arch/mips/mm/dma-default.c +@@ -26,7 +26,7 @@ + + #ifdef CONFIG_DMA_MAYBE_COHERENT + int coherentio = 0; /* User defined DMA coherency from command line. */ +-EXPORT_SYMBOL_GPL(coherentio); ++EXPORT_SYMBOL(coherentio); + int hw_coherentio = 0; /* Actual hardware supported DMA coherency setting. */ + + static int __init setcoherentio(char *str) +@@ -46,35 +46,6 @@ static int __init setnocoherentio(char * + early_param("nocoherentio", setnocoherentio); + #endif + +-static inline struct page *dma_addr_to_page(struct device *dev, +- dma_addr_t dma_addr) +-{ +- return pfn_to_page( +- plat_dma_addr_to_phys(dev, dma_addr) >> PAGE_SHIFT); +-} +- +-/* +- * The affected CPUs below in 'cpu_needs_post_dma_flush()' can +- * speculatively fill random cachelines with stale data at any time, +- * requiring an extra flush post-DMA. +- * +- * Warning on the terminology - Linux calls an uncached area coherent; +- * MIPS terminology calls memory areas with hardware maintained coherency +- * coherent. +- * +- * Note that the R14000 and R16000 should also be checked for in this +- * condition. However this function is only called on non-I/O-coherent +- * systems and only the R10000 and R12000 are used in such systems, the +- * SGI IP28 Indigo² rsp. SGI IP32 aka O2. +- */ +-static inline int cpu_needs_post_dma_flush(struct device *dev) +-{ +- return !plat_device_is_coherent(dev) && +- (boot_cpu_type() == CPU_R10000 || +- boot_cpu_type() == CPU_R12000 || +- boot_cpu_type() == CPU_BMIPS5000); +-} +- + static gfp_t massage_gfp_flags(const struct device *dev, gfp_t gfp) + { + gfp_t dma_flag; +@@ -130,8 +101,9 @@ void *dma_alloc_noncoherent(struct devic + } + EXPORT_SYMBOL(dma_alloc_noncoherent); + +-static void *mips_dma_alloc_coherent(struct device *dev, size_t size, +- dma_addr_t * dma_handle, gfp_t gfp, struct dma_attrs *attrs) ++void *mips_dma_alloc_coherent(struct device *dev, size_t size, ++ dma_addr_t *dma_handle, gfp_t gfp, ++ struct dma_attrs *attrs) + { + void *ret; + struct page *page = NULL; +@@ -162,6 +134,7 @@ static void *mips_dma_alloc_coherent(str + + return ret; + } ++EXPORT_SYMBOL(mips_dma_alloc_coherent); + + + void dma_free_noncoherent(struct device *dev, size_t size, void *vaddr, +@@ -172,8 +145,8 @@ void dma_free_noncoherent(struct device + } + EXPORT_SYMBOL(dma_free_noncoherent); + +-static void mips_dma_free_coherent(struct device *dev, size_t size, void *vaddr, +- dma_addr_t dma_handle, struct dma_attrs *attrs) ++void mips_dma_free_coherent(struct device *dev, size_t size, void *vaddr, ++ dma_addr_t dma_handle, struct dma_attrs *attrs) + { + unsigned long addr = (unsigned long) vaddr; + int order = get_order(size); +@@ -193,6 +166,7 @@ static void mips_dma_free_coherent(struc + if (!dma_release_from_contiguous(dev, page, count)) + __free_pages(page, get_order(size)); + } ++EXPORT_SYMBOL(mips_dma_free_coherent); + + static inline void __dma_sync_virtual(void *addr, size_t size, + enum dma_data_direction direction) +@@ -221,8 +195,8 @@ static inline void __dma_sync_virtual(vo + * If highmem is not configured then the bulk of this loop gets + * optimized out. + */ +-static inline void __dma_sync(struct page *page, +- unsigned long offset, size_t size, enum dma_data_direction direction) ++void __dma_sync(struct page *page, unsigned long offset, size_t size, ++ enum dma_data_direction direction) + { + size_t left = size; + +@@ -251,108 +225,7 @@ static inline void __dma_sync(struct pag + left -= len; + } while (left); + } +- +-static void mips_dma_unmap_page(struct device *dev, dma_addr_t dma_addr, +- size_t size, enum dma_data_direction direction, struct dma_attrs *attrs) +-{ +- if (cpu_needs_post_dma_flush(dev)) +- __dma_sync(dma_addr_to_page(dev, dma_addr), +- dma_addr & ~PAGE_MASK, size, direction); +- +- plat_unmap_dma_mem(dev, dma_addr, size, direction); +-} +- +-static int mips_dma_map_sg(struct device *dev, struct scatterlist *sg, +- int nents, enum dma_data_direction direction, struct dma_attrs *attrs) +-{ +- int i; +- +- for (i = 0; i < nents; i++, sg++) { +- if (!plat_device_is_coherent(dev)) +- __dma_sync(sg_page(sg), sg->offset, sg->length, +- direction); +-#ifdef CONFIG_NEED_SG_DMA_LENGTH +- sg->dma_length = sg->length; +-#endif +- sg->dma_address = plat_map_dma_mem_page(dev, sg_page(sg)) + +- sg->offset; +- } +- +- return nents; +-} +- +-static dma_addr_t mips_dma_map_page(struct device *dev, struct page *page, +- unsigned long offset, size_t size, enum dma_data_direction direction, +- struct dma_attrs *attrs) +-{ +- if (!plat_device_is_coherent(dev)) +- __dma_sync(page, offset, size, direction); +- +- return plat_map_dma_mem_page(dev, page) + offset; +-} +- +-static void mips_dma_unmap_sg(struct device *dev, struct scatterlist *sg, +- int nhwentries, enum dma_data_direction direction, +- struct dma_attrs *attrs) +-{ +- int i; +- +- for (i = 0; i < nhwentries; i++, sg++) { +- if (!plat_device_is_coherent(dev) && +- direction != DMA_TO_DEVICE) +- __dma_sync(sg_page(sg), sg->offset, sg->length, +- direction); +- plat_unmap_dma_mem(dev, sg->dma_address, sg->length, direction); +- } +-} +- +-static void mips_dma_sync_single_for_cpu(struct device *dev, +- dma_addr_t dma_handle, size_t size, enum dma_data_direction direction) +-{ +- if (cpu_needs_post_dma_flush(dev)) +- __dma_sync(dma_addr_to_page(dev, dma_handle), +- dma_handle & ~PAGE_MASK, size, direction); +-} +- +-static void mips_dma_sync_single_for_device(struct device *dev, +- dma_addr_t dma_handle, size_t size, enum dma_data_direction direction) +-{ +- if (!plat_device_is_coherent(dev)) +- __dma_sync(dma_addr_to_page(dev, dma_handle), +- dma_handle & ~PAGE_MASK, size, direction); +-} +- +-static void mips_dma_sync_sg_for_cpu(struct device *dev, +- struct scatterlist *sg, int nelems, enum dma_data_direction direction) +-{ +- int i; +- +- if (cpu_needs_post_dma_flush(dev)) +- for (i = 0; i < nelems; i++, sg++) +- __dma_sync(sg_page(sg), sg->offset, sg->length, +- direction); +-} +- +-static void mips_dma_sync_sg_for_device(struct device *dev, +- struct scatterlist *sg, int nelems, enum dma_data_direction direction) +-{ +- int i; +- +- if (!plat_device_is_coherent(dev)) +- for (i = 0; i < nelems; i++, sg++) +- __dma_sync(sg_page(sg), sg->offset, sg->length, +- direction); +-} +- +-int mips_dma_mapping_error(struct device *dev, dma_addr_t dma_addr) +-{ +- return 0; +-} +- +-int mips_dma_supported(struct device *dev, u64 mask) +-{ +- return plat_dma_supported(dev, mask); +-} ++EXPORT_SYMBOL(__dma_sync); + + void dma_cache_sync(struct device *dev, void *vaddr, size_t size, + enum dma_data_direction direction) +@@ -365,23 +238,10 @@ void dma_cache_sync(struct device *dev, + + EXPORT_SYMBOL(dma_cache_sync); + +-static struct dma_map_ops mips_default_dma_map_ops = { +- .alloc = mips_dma_alloc_coherent, +- .free = mips_dma_free_coherent, +- .map_page = mips_dma_map_page, +- .unmap_page = mips_dma_unmap_page, +- .map_sg = mips_dma_map_sg, +- .unmap_sg = mips_dma_unmap_sg, +- .sync_single_for_cpu = mips_dma_sync_single_for_cpu, +- .sync_single_for_device = mips_dma_sync_single_for_device, +- .sync_sg_for_cpu = mips_dma_sync_sg_for_cpu, +- .sync_sg_for_device = mips_dma_sync_sg_for_device, +- .mapping_error = mips_dma_mapping_error, +- .dma_supported = mips_dma_supported +-}; +- +-struct dma_map_ops *mips_dma_map_ops = &mips_default_dma_map_ops; ++#ifdef CONFIG_SYS_HAS_DMA_OPS ++struct dma_map_ops *mips_dma_map_ops = NULL; + EXPORT_SYMBOL(mips_dma_map_ops); ++#endif + + #define PREALLOC_DMA_DEBUG_ENTRIES (1 << 16) + diff --git a/target/linux/generic/patches-4.0/140-overlayfs_readdir_locking_fix.patch b/target/linux/generic/patches-4.0/140-overlayfs_readdir_locking_fix.patch new file mode 100644 index 0000000..67dff98 --- /dev/null +++ b/target/linux/generic/patches-4.0/140-overlayfs_readdir_locking_fix.patch @@ -0,0 +1,148 @@ +Patch by: Miklos Szeredi + +Some filesystems (e.g. jffs2) lock the same resources for both readdir +and lookup, leading to a deadlock in ovl_cache_entry_new, which is called +from the filldir, and calls lookup itself. + +--- a/fs/overlayfs/readdir.c ++++ b/fs/overlayfs/readdir.c +@@ -23,6 +23,7 @@ struct ovl_cache_entry { + u64 ino; + struct list_head l_node; + struct rb_node node; ++ struct ovl_cache_entry *next_maybe_whiteout; + bool is_whiteout; + char name[]; + }; +@@ -39,7 +40,7 @@ struct ovl_readdir_data { + struct rb_root root; + struct list_head *list; + struct list_head middle; +- struct dentry *dir; ++ struct ovl_cache_entry *first_maybe_whiteout; + int count; + int err; + }; +@@ -79,7 +80,7 @@ static struct ovl_cache_entry *ovl_cache + return NULL; + } + +-static struct ovl_cache_entry *ovl_cache_entry_new(struct dentry *dir, ++static struct ovl_cache_entry *ovl_cache_entry_new(struct ovl_readdir_data *rdd, + const char *name, int len, + u64 ino, unsigned int d_type) + { +@@ -98,29 +99,8 @@ static struct ovl_cache_entry *ovl_cache + p->is_whiteout = false; + + if (d_type == DT_CHR) { +- struct dentry *dentry; +- const struct cred *old_cred; +- struct cred *override_cred; +- +- override_cred = prepare_creds(); +- if (!override_cred) { +- kfree(p); +- return NULL; +- } +- +- /* +- * CAP_DAC_OVERRIDE for lookup +- */ +- cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE); +- old_cred = override_creds(override_cred); +- +- dentry = lookup_one_len(name, dir, len); +- if (!IS_ERR(dentry)) { +- p->is_whiteout = ovl_is_whiteout(dentry); +- dput(dentry); +- } +- revert_creds(old_cred); +- put_cred(override_cred); ++ p->next_maybe_whiteout = rdd->first_maybe_whiteout; ++ rdd->first_maybe_whiteout = p; + } + return p; + } +@@ -148,7 +128,7 @@ static int ovl_cache_entry_add_rb(struct + return 0; + } + +- p = ovl_cache_entry_new(rdd->dir, name, len, ino, d_type); ++ p = ovl_cache_entry_new(rdd, name, len, ino, d_type); + if (p == NULL) + return -ENOMEM; + +@@ -169,7 +149,7 @@ static int ovl_fill_lower(struct ovl_rea + if (p) { + list_move_tail(&p->l_node, &rdd->middle); + } else { +- p = ovl_cache_entry_new(rdd->dir, name, namelen, ino, d_type); ++ p = ovl_cache_entry_new(rdd, name, namelen, ino, d_type); + if (p == NULL) + rdd->err = -ENOMEM; + else +@@ -219,6 +199,43 @@ static int ovl_fill_merge(struct dir_con + return ovl_fill_lower(rdd, name, namelen, offset, ino, d_type); + } + ++static int ovl_check_whiteouts(struct dentry *dir, struct ovl_readdir_data *rdd) ++{ ++ int err = 0; ++ ++ mutex_lock(&dir->d_inode->i_mutex); ++ while (rdd->first_maybe_whiteout) { ++ struct dentry *dentry; ++ const struct cred *old_cred; ++ struct cred *override_cred; ++ struct ovl_cache_entry *p = rdd->first_maybe_whiteout; ++ ++ rdd->first_maybe_whiteout = p->next_maybe_whiteout; ++ ++ override_cred = prepare_creds(); ++ if (!override_cred) { ++ err = -ENOMEM; ++ break; ++ } ++ /* ++ * CAP_DAC_OVERRIDE for lookup ++ */ ++ cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE); ++ old_cred = override_creds(override_cred); ++ ++ dentry = lookup_one_len(p->name, dir, p->len); ++ if (!IS_ERR(dentry)) { ++ p->is_whiteout = ovl_is_whiteout(dentry); ++ dput(dentry); ++ } ++ revert_creds(old_cred); ++ put_cred(override_cred); ++ } ++ mutex_unlock(&dir->d_inode->i_mutex); ++ ++ return err; ++} ++ + static inline int ovl_dir_read(struct path *realpath, + struct ovl_readdir_data *rdd) + { +@@ -229,7 +246,7 @@ static inline int ovl_dir_read(struct pa + if (IS_ERR(realfile)) + return PTR_ERR(realfile); + +- rdd->dir = realpath->dentry; ++ rdd->first_maybe_whiteout = NULL; + rdd->ctx.pos = 0; + do { + rdd->count = 0; +@@ -238,6 +255,10 @@ static inline int ovl_dir_read(struct pa + if (err >= 0) + err = rdd->err; + } while (!err && rdd->count); ++ ++ if (!err && rdd->first_maybe_whiteout) ++ err = ovl_check_whiteouts(realpath->dentry, rdd); ++ + fput(realfile); + + return err; diff --git a/target/linux/generic/patches-4.0/180-usb-xhci-make-USB_XHCI_PLATFORM-selectable.patch b/target/linux/generic/patches-4.0/180-usb-xhci-make-USB_XHCI_PLATFORM-selectable.patch new file mode 100644 index 0000000..a17e398 --- /dev/null +++ b/target/linux/generic/patches-4.0/180-usb-xhci-make-USB_XHCI_PLATFORM-selectable.patch @@ -0,0 +1,41 @@ +From 9612e686b235dc9e33c8dfb5e6d2ff2b2140fb9d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Tue, 16 Jun 2015 21:01:30 +0200 +Subject: [PATCH V2] usb: xhci: make USB_XHCI_PLATFORM selectable +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Right now xhci-plat-hcd can be built when using one of platform specific +drivers only (mvebu/rcar). There shouldn't be such limitation as some +platforms may not require any quirks and may want to just use a generic +driver ("generic-xhci" / "xhci-hcd"). + +Signed-off-by: Rafał Miłecki +--- +Greg/Mathias: I'm not sure if it's more like USB subsystem stuff or xHCI +Could you decide which one of you could pick that, please? + +V2: Drop useless "default n", thanks Sergei :) +--- + drivers/usb/host/Kconfig | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +--- a/drivers/usb/host/Kconfig ++++ b/drivers/usb/host/Kconfig +@@ -32,7 +32,14 @@ config USB_XHCI_PCI + default y + + config USB_XHCI_PLATFORM +- tristate ++ tristate "Generic xHCI driver for a platform device" ++ ---help--- ++ Adds an xHCI host driver for a generic platform device, which ++ provides a memory space and an irq. ++ It is also a prerequisite for platform specific drivers that ++ implement some extra quirks. ++ ++ If unsure, say N. + + config USB_XHCI_MVEBU + tristate "xHCI support for Marvell Armada 375/38x" diff --git a/target/linux/generic/patches-4.0/190-cdc_ncm_add_support_for_moving_ndp_to_end_of_ncm_frame.patch b/target/linux/generic/patches-4.0/190-cdc_ncm_add_support_for_moving_ndp_to_end_of_ncm_frame.patch new file mode 100644 index 0000000..09cbe0c --- /dev/null +++ b/target/linux/generic/patches-4.0/190-cdc_ncm_add_support_for_moving_ndp_to_end_of_ncm_frame.patch @@ -0,0 +1,228 @@ +From 4a0e3e989d66bb7204b163d9cfaa7fa96d0f2023 Mon Sep 17 00:00:00 2001 +From: Enrico Mioso +Date: Wed, 8 Jul 2015 13:05:57 +0200 +Subject: [PATCH] cdc_ncm: Add support for moving NDP to end of NCM frame + +NCM specs are not actually mandating a specific position in the frame for +the NDP (Network Datagram Pointer). However, some Huawei devices will +ignore our aggregates if it is not placed after the datagrams it points +to. Add support for doing just this, in a per-device configurable way. +While at it, update NCM subdrivers, disabling this functionality in all of +them, except in huawei_cdc_ncm where it is enabled instead. +We aren't making any distinction between different Huawei NCM devices, +based on what the vendor driver does. Standard NCM devices are left +unaffected: if they are compliant, they should be always usable, still +stay on the safe side. + +This change has been tested and working with a Huawei E3131 device (which +works regardless of NDP position), a Huawei E3531 (also working both +ways) and an E3372 (which mandates NDP to be after indexed datagrams). + +V1->V2: +- corrected wrong NDP acronym definition +- fixed possible NULL pointer dereference +- patch cleanup +V2->V3: +- Properly account for the NDP size when writing new packets to SKB + +Signed-off-by: Enrico Mioso +Signed-off-by: David S. Miller +--- + drivers/net/usb/cdc_mbim.c | 2 +- + drivers/net/usb/cdc_ncm.c | 61 ++++++++++++++++++++++++++++++++++++---- + drivers/net/usb/huawei_cdc_ncm.c | 7 +++-- + include/linux/usb/cdc_ncm.h | 7 ++++- + 4 files changed, 67 insertions(+), 10 deletions(-) + +--- a/drivers/net/usb/cdc_mbim.c ++++ b/drivers/net/usb/cdc_mbim.c +@@ -158,7 +158,7 @@ static int cdc_mbim_bind(struct usbnet * + if (!cdc_ncm_comm_intf_is_mbim(intf->cur_altsetting)) + goto err; + +- ret = cdc_ncm_bind_common(dev, intf, data_altsetting); ++ ret = cdc_ncm_bind_common(dev, intf, data_altsetting, 0); + if (ret) + goto err; + +--- a/drivers/net/usb/cdc_ncm.c ++++ b/drivers/net/usb/cdc_ncm.c +@@ -684,10 +684,12 @@ static void cdc_ncm_free(struct cdc_ncm_ + ctx->tx_curr_skb = NULL; + } + ++ kfree(ctx->delayed_ndp16); ++ + kfree(ctx); + } + +-int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_altsetting) ++int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_altsetting, int drvflags) + { + const struct usb_cdc_union_desc *union_desc = NULL; + struct cdc_ncm_ctx *ctx; +@@ -855,6 +857,17 @@ advance: + /* finish setting up the device specific data */ + cdc_ncm_setup(dev); + ++ /* Device-specific flags */ ++ ctx->drvflags = drvflags; ++ ++ /* Allocate the delayed NDP if needed. */ ++ if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END) { ++ ctx->delayed_ndp16 = kzalloc(ctx->max_ndp_size, GFP_KERNEL); ++ if (!ctx->delayed_ndp16) ++ goto error2; ++ dev_info(&intf->dev, "NDP will be placed at end of frame for this device."); ++ } ++ + /* override ethtool_ops */ + dev->net->ethtool_ops = &cdc_ncm_ethtool_ops; + +@@ -954,8 +967,11 @@ static int cdc_ncm_bind(struct usbnet *d + if (cdc_ncm_select_altsetting(intf) != CDC_NCM_COMM_ALTSETTING_NCM) + return -ENODEV; + +- /* The NCM data altsetting is fixed */ +- ret = cdc_ncm_bind_common(dev, intf, CDC_NCM_DATA_ALTSETTING_NCM); ++ /* The NCM data altsetting is fixed, so we hard-coded it. ++ * Additionally, generic NCM devices are assumed to accept arbitrarily ++ * placed NDP. ++ */ ++ ret = cdc_ncm_bind_common(dev, intf, CDC_NCM_DATA_ALTSETTING_NCM, 0); + + /* + * We should get an event when network connection is "connected" or +@@ -986,6 +1002,14 @@ static struct usb_cdc_ncm_ndp16 *cdc_ncm + struct usb_cdc_ncm_nth16 *nth16 = (void *)skb->data; + size_t ndpoffset = le16_to_cpu(nth16->wNdpIndex); + ++ /* If NDP should be moved to the end of the NCM package, we can't follow the ++ * NTH16 header as we would normally do. NDP isn't written to the SKB yet, and ++ * the wNdpIndex field in the header is actually not consistent with reality. It will be later. ++ */ ++ if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END) ++ if (ctx->delayed_ndp16->dwSignature == sign) ++ return ctx->delayed_ndp16; ++ + /* follow the chain of NDPs, looking for a match */ + while (ndpoffset) { + ndp16 = (struct usb_cdc_ncm_ndp16 *)(skb->data + ndpoffset); +@@ -995,7 +1019,8 @@ static struct usb_cdc_ncm_ndp16 *cdc_ncm + } + + /* align new NDP */ +- cdc_ncm_align_tail(skb, ctx->tx_ndp_modulus, 0, ctx->tx_max); ++ if (!(ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END)) ++ cdc_ncm_align_tail(skb, ctx->tx_ndp_modulus, 0, ctx->tx_max); + + /* verify that there is room for the NDP and the datagram (reserve) */ + if ((ctx->tx_max - skb->len - reserve) < ctx->max_ndp_size) +@@ -1008,7 +1033,11 @@ static struct usb_cdc_ncm_ndp16 *cdc_ncm + nth16->wNdpIndex = cpu_to_le16(skb->len); + + /* push a new empty NDP */ +- ndp16 = (struct usb_cdc_ncm_ndp16 *)memset(skb_put(skb, ctx->max_ndp_size), 0, ctx->max_ndp_size); ++ if (!(ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END)) ++ ndp16 = (struct usb_cdc_ncm_ndp16 *)memset(skb_put(skb, ctx->max_ndp_size), 0, ctx->max_ndp_size); ++ else ++ ndp16 = ctx->delayed_ndp16; ++ + ndp16->dwSignature = sign; + ndp16->wLength = cpu_to_le16(sizeof(struct usb_cdc_ncm_ndp16) + sizeof(struct usb_cdc_ncm_dpe16)); + return ndp16; +@@ -1023,6 +1052,15 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev + struct sk_buff *skb_out; + u16 n = 0, index, ndplen; + u8 ready2send = 0; ++ u32 delayed_ndp_size; ++ ++ /* When our NDP gets written in cdc_ncm_ndp(), then skb_out->len gets updated ++ * accordingly. Otherwise, we should check here. ++ */ ++ if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END) ++ delayed_ndp_size = ctx->max_ndp_size; ++ else ++ delayed_ndp_size = 0; + + /* if there is a remaining skb, it gets priority */ + if (skb != NULL) { +@@ -1077,7 +1115,7 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev + cdc_ncm_align_tail(skb_out, ctx->tx_modulus, ctx->tx_remainder, ctx->tx_max); + + /* check if we had enough room left for both NDP and frame */ +- if (!ndp16 || skb_out->len + skb->len > ctx->tx_max) { ++ if (!ndp16 || skb_out->len + skb->len + delayed_ndp_size > ctx->tx_max) { + if (n == 0) { + /* won't fit, MTU problem? */ + dev_kfree_skb_any(skb); +@@ -1150,6 +1188,17 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev + /* variables will be reset at next call */ + } + ++ /* If requested, put NDP at end of frame. */ ++ if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END) { ++ nth16 = (struct usb_cdc_ncm_nth16 *)skb_out->data; ++ cdc_ncm_align_tail(skb_out, ctx->tx_ndp_modulus, 0, ctx->tx_max); ++ nth16->wNdpIndex = cpu_to_le16(skb_out->len); ++ memcpy(skb_put(skb_out, ctx->max_ndp_size), ctx->delayed_ndp16, ctx->max_ndp_size); ++ ++ /* Zero out delayed NDP - signature checking will naturally fail. */ ++ ndp16 = memset(ctx->delayed_ndp16, 0, ctx->max_ndp_size); ++ } ++ + /* If collected data size is less or equal ctx->min_tx_pkt + * bytes, we send buffers as it is. If we get more data, it + * would be more efficient for USB HS mobile device with DMA +--- a/drivers/net/usb/huawei_cdc_ncm.c ++++ b/drivers/net/usb/huawei_cdc_ncm.c +@@ -73,11 +73,14 @@ static int huawei_cdc_ncm_bind(struct us + struct usb_driver *subdriver = ERR_PTR(-ENODEV); + int ret = -ENODEV; + struct huawei_cdc_ncm_state *drvstate = (void *)&usbnet_dev->data; ++ int drvflags = 0; + + /* altsetting should always be 1 for NCM devices - so we hard-coded +- * it here ++ * it here. Some huawei devices will need the NDP part of the NCM package to ++ * be at the end of the frame. + */ +- ret = cdc_ncm_bind_common(usbnet_dev, intf, 1); ++ drvflags |= CDC_NCM_FLAG_NDP_TO_END; ++ ret = cdc_ncm_bind_common(usbnet_dev, intf, 1, drvflags); + if (ret) + goto err; + +--- a/include/linux/usb/cdc_ncm.h ++++ b/include/linux/usb/cdc_ncm.h +@@ -80,6 +80,9 @@ + #define CDC_NCM_TIMER_INTERVAL_MIN 5UL + #define CDC_NCM_TIMER_INTERVAL_MAX (U32_MAX / NSEC_PER_USEC) + ++/* Driver flags */ ++#define CDC_NCM_FLAG_NDP_TO_END 0x02 /* NDP is placed at end of frame */ ++ + #define cdc_ncm_comm_intf_is_mbim(x) ((x)->desc.bInterfaceSubClass == USB_CDC_SUBCLASS_MBIM && \ + (x)->desc.bInterfaceProtocol == USB_CDC_PROTO_NONE) + #define cdc_ncm_data_intf_is_mbim(x) ((x)->desc.bInterfaceProtocol == USB_CDC_MBIM_PROTO_NTB) +@@ -103,9 +106,11 @@ struct cdc_ncm_ctx { + + spinlock_t mtx; + atomic_t stop; ++ int drvflags; + + u32 timer_interval; + u32 max_ndp_size; ++ struct usb_cdc_ncm_ndp16 *delayed_ndp16; + + u32 tx_timer_pending; + u32 tx_curr_frame_num; +@@ -133,7 +138,7 @@ struct cdc_ncm_ctx { + }; + + u8 cdc_ncm_select_altsetting(struct usb_interface *intf); +-int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_altsetting); ++int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_altsetting, int drvflags); + void cdc_ncm_unbind(struct usbnet *dev, struct usb_interface *intf); + struct sk_buff *cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign); + int cdc_ncm_rx_verify_nth16(struct cdc_ncm_ctx *ctx, struct sk_buff *skb_in); diff --git a/target/linux/generic/patches-4.0/191-usb-ehci-orion-fix-probe-for-GENERIC_PHY.patch b/target/linux/generic/patches-4.0/191-usb-ehci-orion-fix-probe-for-GENERIC_PHY.patch new file mode 100644 index 0000000..cda4ca0 --- /dev/null +++ b/target/linux/generic/patches-4.0/191-usb-ehci-orion-fix-probe-for-GENERIC_PHY.patch @@ -0,0 +1,35 @@ +From a95f03e51471dbdbafd3391991d867ac2358ed02 Mon Sep 17 00:00:00 2001 +From: Jonas Gorski +Date: Sun, 23 Aug 2015 14:23:29 +0200 +Subject: [PATCH] usb: ehci-orion: fix probe for !GENERIC_PHY + +Commit d445913ce0ab7f ("usb: ehci-orion: add optional PHY support") +added support for optional phys, but devm_phy_optional_get returns +-ENOSYS if GENERIC_PHY is not enabled. + +This causes probe failures, even when there are no phys specified: + +[ 1.443365] orion-ehci f1058000.usb: init f1058000.usb fail, -38 +[ 1.449403] orion-ehci: probe of f1058000.usb failed with error -38 + +Similar to dwc3, treat -ENOSYS as no phy. + +Fixes: d445913ce0ab7f ("usb: ehci-orion: add optional PHY support") + +Signed-off-by: Jonas Gorski +--- + drivers/usb/host/ehci-orion.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/usb/host/ehci-orion.c ++++ b/drivers/usb/host/ehci-orion.c +@@ -218,7 +218,8 @@ static int ehci_orion_drv_probe(struct p + priv->phy = devm_phy_optional_get(&pdev->dev, "usb"); + if (IS_ERR(priv->phy)) { + err = PTR_ERR(priv->phy); +- goto err_phy_get; ++ if (err != -ENOSYS) ++ goto err_phy_get; + } else { + err = phy_init(priv->phy); + if (err) diff --git a/target/linux/generic/patches-4.0/200-fix_localversion.patch b/target/linux/generic/patches-4.0/200-fix_localversion.patch new file mode 100644 index 0000000..70228bb --- /dev/null +++ b/target/linux/generic/patches-4.0/200-fix_localversion.patch @@ -0,0 +1,11 @@ +--- a/scripts/setlocalversion ++++ b/scripts/setlocalversion +@@ -165,7 +165,7 @@ else + # annotated or signed tagged state (as git describe only + # looks at signed or annotated tags - git tag -a/-s) and + # LOCALVERSION= is not specified +- if test "${LOCALVERSION+set}" != "set"; then ++ if test "${CONFIG_LOCALVERSION+set}" != "set"; then + scm=$(scm_version --short) + res="$res${scm:++}" + fi diff --git a/target/linux/generic/patches-4.0/201-extra_optimization.patch b/target/linux/generic/patches-4.0/201-extra_optimization.patch new file mode 100644 index 0000000..a339826 --- /dev/null +++ b/target/linux/generic/patches-4.0/201-extra_optimization.patch @@ -0,0 +1,14 @@ +--- a/Makefile ++++ b/Makefile +@@ -614,9 +614,9 @@ include $(srctree)/arch/$(SRCARCH)/Makef + KBUILD_CFLAGS += $(call cc-option,-fno-delete-null-pointer-checks,) + + ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE +-KBUILD_CFLAGS += -Os $(call cc-disable-warning,maybe-uninitialized,) ++KBUILD_CFLAGS += -Os $(EXTRA_OPTIMIZATION) $(call cc-disable-warning,maybe-uninitialized,) + else +-KBUILD_CFLAGS += -O2 ++KBUILD_CFLAGS += -O2 -fno-reorder-blocks -fno-tree-ch $(EXTRA_OPTIMIZATION) + endif + + # Tell gcc to never replace conditional load with a non-conditional one diff --git a/target/linux/generic/patches-4.0/202-reduce_module_size.patch b/target/linux/generic/patches-4.0/202-reduce_module_size.patch new file mode 100644 index 0000000..3f36af8 --- /dev/null +++ b/target/linux/generic/patches-4.0/202-reduce_module_size.patch @@ -0,0 +1,11 @@ +--- a/Makefile ++++ b/Makefile +@@ -410,7 +410,7 @@ KBUILD_CFLAGS_KERNEL := + KBUILD_AFLAGS := -D__ASSEMBLY__ + KBUILD_AFLAGS_MODULE := -DMODULE + KBUILD_CFLAGS_MODULE := -DMODULE +-KBUILD_LDFLAGS_MODULE := -T $(srctree)/scripts/module-common.lds ++KBUILD_LDFLAGS_MODULE = -T $(srctree)/scripts/module-common.lds $(if $(CONFIG_PROFILING),,-s) + + # Read KERNELRELEASE from include/config/kernel.release (if it exists) + KERNELRELEASE = $(shell cat include/config/kernel.release 2> /dev/null) diff --git a/target/linux/generic/patches-4.0/203-kallsyms_uncompressed.patch b/target/linux/generic/patches-4.0/203-kallsyms_uncompressed.patch new file mode 100644 index 0000000..99f0ad2 --- /dev/null +++ b/target/linux/generic/patches-4.0/203-kallsyms_uncompressed.patch @@ -0,0 +1,108 @@ +--- a/scripts/kallsyms.c ++++ b/scripts/kallsyms.c +@@ -58,6 +58,7 @@ static struct addr_range percpu_range = + static struct sym_entry *table; + static unsigned int table_size, table_cnt; + static int all_symbols = 0; ++static int uncompressed = 0; + static int absolute_percpu = 0; + static char symbol_prefix_char = '\0'; + static unsigned long long kernel_start_addr = 0; +@@ -392,6 +393,9 @@ static void write_src(void) + + free(markers); + ++ if (uncompressed) ++ return; ++ + output_label("kallsyms_token_table"); + off = 0; + for (i = 0; i < 256; i++) { +@@ -450,6 +454,9 @@ static void *find_token(unsigned char *s + { + int i; + ++ if (uncompressed) ++ return NULL; ++ + for (i = 0; i < len - 1; i++) { + if (str[i] == token[0] && str[i+1] == token[1]) + return &str[i]; +@@ -522,6 +529,9 @@ static void optimize_result(void) + { + int i, best; + ++ if (uncompressed) ++ return; ++ + /* using the '\0' symbol last allows compress_symbols to use standard + * fast string functions */ + for (i = 255; i >= 0; i--) { +@@ -692,7 +702,9 @@ int main(int argc, char **argv) + } else if (strncmp(argv[i], "--page-offset=", 14) == 0) { + const char *p = &argv[i][14]; + kernel_start_addr = strtoull(p, NULL, 16); +- } else ++ } else if (strcmp(argv[i], "--uncompressed") == 0) ++ uncompressed = 1; ++ else + usage(); + } + } else if (argc != 1) +--- a/init/Kconfig ++++ b/init/Kconfig +@@ -1324,6 +1324,17 @@ config SYSCTL_ARCH_UNALIGN_ALLOW + the unaligned access emulation. + see arch/parisc/kernel/unaligned.c for reference + ++config KALLSYMS_UNCOMPRESSED ++ bool "Keep kallsyms uncompressed" ++ depends on KALLSYMS ++ help ++ Normally kallsyms contains compressed symbols (using a token table), ++ reducing the uncompressed kernel image size. Keeping the symbol table ++ uncompressed significantly improves the size of this part in compressed ++ kernel images. ++ ++ Say N unless you need compressed kernel images to be small. ++ + config HAVE_PCSPKR_PLATFORM + bool + +--- a/scripts/link-vmlinux.sh ++++ b/scripts/link-vmlinux.sh +@@ -90,6 +90,10 @@ kallsyms() + kallsymopt="${kallsymopt} --absolute-percpu" + fi + ++ if [ -n "${CONFIG_KALLSYMS_UNCOMPRESSED}" ]; then ++ kallsymopt="${kallsymopt} --uncompressed" ++ fi ++ + local aflags="${KBUILD_AFLAGS} ${KBUILD_AFLAGS_KERNEL} \ + ${NOSTDINC_FLAGS} ${LINUXINCLUDE} ${KBUILD_CPPFLAGS}" + +--- a/kernel/kallsyms.c ++++ b/kernel/kallsyms.c +@@ -109,6 +109,11 @@ static unsigned int kallsyms_expand_symb + * For every byte on the compressed symbol data, copy the table + * entry for that byte. + */ ++#ifdef CONFIG_KALLSYMS_UNCOMPRESSED ++ memcpy(result, data + 1, len - 1); ++ result += len - 1; ++ len = 0; ++#endif + while (len) { + tptr = &kallsyms_token_table[kallsyms_token_index[*data]]; + data++; +@@ -141,6 +146,9 @@ tail: + */ + static char kallsyms_get_symbol_type(unsigned int off) + { ++#ifdef CONFIG_KALLSYMS_UNCOMPRESSED ++ return kallsyms_names[off + 1]; ++#endif + /* + * Get just the first code, look it up in the token table, + * and return the first char from this token. diff --git a/target/linux/generic/patches-4.0/204-module_strip.patch b/target/linux/generic/patches-4.0/204-module_strip.patch new file mode 100644 index 0000000..584839a --- /dev/null +++ b/target/linux/generic/patches-4.0/204-module_strip.patch @@ -0,0 +1,194 @@ +From: Felix Fietkau +Subject: [PATCH] build: add a hack for removing non-essential module info + +Signed-off-by: Felix Fietkau +--- +--- a/include/linux/module.h ++++ b/include/linux/module.h +@@ -84,9 +84,10 @@ void trim_init_extable(struct module *m) + + /* Generic info of form tag = "info" */ + #define MODULE_INFO(tag, info) __MODULE_INFO(tag, tag, info) ++#define MODULE_INFO_STRIP(tag, info) __MODULE_INFO_STRIP(tag, tag, info) + + /* For userspace: you can also call me... */ +-#define MODULE_ALIAS(_alias) MODULE_INFO(alias, _alias) ++#define MODULE_ALIAS(_alias) MODULE_INFO_STRIP(alias, _alias) + + /* Soft module dependencies. See man modprobe.d for details. + * Example: MODULE_SOFTDEP("pre: module-foo module-bar post: module-baz") +@@ -127,12 +128,12 @@ void trim_init_extable(struct module *m) + * Author(s), use "Name " or just "Name", for multiple + * authors use multiple MODULE_AUTHOR() statements/lines. + */ +-#define MODULE_AUTHOR(_author) MODULE_INFO(author, _author) ++#define MODULE_AUTHOR(_author) MODULE_INFO_STRIP(author, _author) + + /* What your module does. */ +-#define MODULE_DESCRIPTION(_description) MODULE_INFO(description, _description) ++#define MODULE_DESCRIPTION(_description) MODULE_INFO_STRIP(description, _description) + +-#ifdef MODULE ++#if defined(MODULE) && !defined(CONFIG_MODULE_STRIPPED) + /* Creates an alias so file2alias.c can find device table. */ + #define MODULE_DEVICE_TABLE(type, name) \ + extern const typeof(name) __mod_##type##__##name##_device_table \ +@@ -159,7 +160,9 @@ extern const typeof(name) __mod_##type## + */ + + #if defined(MODULE) || !defined(CONFIG_SYSFS) +-#define MODULE_VERSION(_version) MODULE_INFO(version, _version) ++#define MODULE_VERSION(_version) MODULE_INFO_STRIP(version, _version) ++#elif defined(CONFIG_MODULE_STRIPPED) ++#define MODULE_VERSION(_version) __MODULE_INFO_DISABLED(version) + #else + #define MODULE_VERSION(_version) \ + static struct module_version_attribute ___modver_attr = { \ +@@ -181,7 +184,7 @@ extern const typeof(name) __mod_##type## + /* Optional firmware file (or files) needed by the module + * format is simply firmware file name. Multiple firmware + * files require multiple MODULE_FIRMWARE() specifiers */ +-#define MODULE_FIRMWARE(_firmware) MODULE_INFO(firmware, _firmware) ++#define MODULE_FIRMWARE(_firmware) MODULE_INFO_STRIP(firmware, _firmware) + + /* Given an address, look for it in the exception tables */ + const struct exception_table_entry *search_exception_tables(unsigned long add); +--- a/include/linux/moduleparam.h ++++ b/include/linux/moduleparam.h +@@ -16,6 +16,16 @@ + /* Chosen so that structs with an unsigned long line up. */ + #define MAX_PARAM_PREFIX_LEN (64 - sizeof(unsigned long)) + ++/* This struct is here for syntactic coherency, it is not used */ ++#define __MODULE_INFO_DISABLED(name) \ ++ struct __UNIQUE_ID(name) {} ++ ++#ifdef CONFIG_MODULE_STRIPPED ++#define __MODULE_INFO_STRIP(tag, name, info) __MODULE_INFO_DISABLED(name) ++#else ++#define __MODULE_INFO_STRIP(tag, name, info) __MODULE_INFO(tag, name, info) ++#endif ++ + #ifdef MODULE + #define __MODULE_INFO(tag, name, info) \ + static const char __UNIQUE_ID(name)[] \ +@@ -23,8 +33,7 @@ static const char __UNIQUE_ID(name)[] + = __stringify(tag) "=" info + #else /* !MODULE */ + /* This struct is here for syntactic coherency, it is not used */ +-#define __MODULE_INFO(tag, name, info) \ +- struct __UNIQUE_ID(name) {} ++#define __MODULE_INFO(tag, name, info) __MODULE_INFO_DISABLED(name) + #endif + #define __MODULE_PARM_TYPE(name, _type) \ + __MODULE_INFO(parmtype, name##type, #name ":" _type) +@@ -32,7 +41,7 @@ static const char __UNIQUE_ID(name)[] + /* One for each parameter, describing how to use it. Some files do + multiple of these per line, so can't just use MODULE_INFO. */ + #define MODULE_PARM_DESC(_parm, desc) \ +- __MODULE_INFO(parm, _parm, #_parm ":" desc) ++ __MODULE_INFO_STRIP(parm, _parm, #_parm ":" desc) + + struct kernel_param; + +--- a/init/Kconfig ++++ b/init/Kconfig +@@ -1974,6 +1974,13 @@ config MODULE_COMPRESS_XZ + + endchoice + ++config MODULE_STRIPPED ++ bool "Reduce module size" ++ depends on MODULES ++ help ++ Remove module parameter descriptions, author info, version, aliases, ++ device tables, etc. ++ + endif # MODULES + + config INIT_ALL_POSSIBLE +--- a/kernel/module.c ++++ b/kernel/module.c +@@ -2680,6 +2680,7 @@ static struct module *setup_load_info(st + + static int check_modinfo(struct module *mod, struct load_info *info, int flags) + { ++#ifndef CONFIG_MODULE_STRIPPED + const char *modmagic = get_modinfo(info, "vermagic"); + int err; + +@@ -2705,6 +2706,7 @@ static int check_modinfo(struct module * + pr_warn("%s: module is from the staging directory, the quality " + "is unknown, you have been warned.\n", mod->name); + } ++#endif + + /* Set up license info based on the info section */ + set_license(mod, get_modinfo(info, "license")); +--- a/scripts/mod/modpost.c ++++ b/scripts/mod/modpost.c +@@ -1726,7 +1726,9 @@ static void read_symbols(char *modname) + symname = remove_dot(info.strtab + sym->st_name); + + handle_modversions(mod, &info, sym, symname); ++#ifndef CONFIG_MODULE_STRIPPED + handle_moddevtable(mod, &info, sym, symname); ++#endif + } + if (!is_vmlinux(modname) || + (is_vmlinux(modname) && vmlinux_section_warnings)) +@@ -1870,7 +1872,9 @@ static void add_header(struct buffer *b, + buf_printf(b, "#include \n"); + buf_printf(b, "#include \n"); + buf_printf(b, "\n"); ++#ifndef CONFIG_MODULE_STRIPPED + buf_printf(b, "MODULE_INFO(vermagic, VERMAGIC_STRING);\n"); ++#endif + buf_printf(b, "\n"); + buf_printf(b, "__visible struct module __this_module\n"); + buf_printf(b, "__attribute__((section(\".gnu.linkonce.this_module\"))) = {\n"); +@@ -1887,16 +1891,20 @@ static void add_header(struct buffer *b, + + static void add_intree_flag(struct buffer *b, int is_intree) + { ++#ifndef CONFIG_MODULE_STRIPPED + if (is_intree) + buf_printf(b, "\nMODULE_INFO(intree, \"Y\");\n"); ++#endif + } + + static void add_staging_flag(struct buffer *b, const char *name) + { ++#ifndef CONFIG_MODULE_STRIPPED + static const char *staging_dir = "drivers/staging"; + + if (strncmp(staging_dir, name, strlen(staging_dir)) == 0) + buf_printf(b, "\nMODULE_INFO(staging, \"Y\");\n"); ++#endif + } + + /** +@@ -1989,11 +1997,13 @@ static void add_depends(struct buffer *b + + static void add_srcversion(struct buffer *b, struct module *mod) + { ++#ifndef CONFIG_MODULE_STRIPPED + if (mod->srcversion[0]) { + buf_printf(b, "\n"); + buf_printf(b, "MODULE_INFO(srcversion, \"%s\");\n", + mod->srcversion); + } ++#endif + } + + static void write_if_changed(struct buffer *b, const char *fname) +@@ -2224,7 +2234,9 @@ int main(int argc, char **argv) + add_staging_flag(&buf, mod->name); + err |= add_versions(&buf, mod); + add_depends(&buf, mod, modules); ++#ifndef CONFIG_MODULE_STRIPPED + add_moddevtable(&buf, mod); ++#endif + add_srcversion(&buf, mod); + + sprintf(fname, "%s.mod.c", mod->name); diff --git a/target/linux/generic/patches-4.0/205-backtrace_module_info.patch b/target/linux/generic/patches-4.0/205-backtrace_module_info.patch new file mode 100644 index 0000000..2d0cc5a --- /dev/null +++ b/target/linux/generic/patches-4.0/205-backtrace_module_info.patch @@ -0,0 +1,36 @@ +--- a/lib/vsprintf.c ++++ b/lib/vsprintf.c +@@ -615,8 +615,10 @@ char *symbol_string(char *buf, char *end + struct printf_spec spec, const char *fmt) + { + unsigned long value; +-#ifdef CONFIG_KALLSYMS + char sym[KSYM_SYMBOL_LEN]; ++#ifndef CONFIG_KALLSYMS ++ struct module *mod; ++ int len; + #endif + + if (fmt[1] == 'R') +@@ -630,15 +632,15 @@ char *symbol_string(char *buf, char *end + sprint_symbol(sym, value); + else + sprint_symbol_no_offset(sym, value); +- +- return string(buf, end, sym, spec); + #else +- spec.field_width = 2 * sizeof(void *); +- spec.flags |= SPECIAL | SMALL | ZEROPAD; +- spec.base = 16; ++ len = snprintf(sym, sizeof(sym), "0x%lx", value); + +- return number(buf, end, value, spec); ++ mod = __module_address(value); ++ if (mod) ++ snprintf(sym + len, sizeof(sym) - len, " [%s@%p+0x%x]", ++ mod->name, mod->module_core, mod->core_size); + #endif ++ return string(buf, end, sym, spec); + } + + static noinline_for_stack diff --git a/target/linux/generic/patches-4.0/210-darwin_scripts_include.patch b/target/linux/generic/patches-4.0/210-darwin_scripts_include.patch new file mode 100644 index 0000000..dc554de --- /dev/null +++ b/target/linux/generic/patches-4.0/210-darwin_scripts_include.patch @@ -0,0 +1,3088 @@ +--- a/scripts/kallsyms.c ++++ b/scripts/kallsyms.c +@@ -22,6 +22,35 @@ + #include + #include + #include ++#ifdef __APPLE__ ++/* Darwin has no memmem implementation, this one is ripped of the uClibc-0.9.28 source */ ++void *memmem (const void *haystack, size_t haystack_len, ++ const void *needle, size_t needle_len) ++{ ++ const char *begin; ++ const char *const last_possible ++ = (const char *) haystack + haystack_len - needle_len; ++ ++ if (needle_len == 0) ++ /* The first occurrence of the empty string is deemed to occur at ++ the beginning of the string. */ ++ return (void *) haystack; ++ ++ /* Sanity check, otherwise the loop might search through the whole ++ memory. */ ++ if (__builtin_expect (haystack_len < needle_len, 0)) ++ return NULL; ++ ++ for (begin = (const char *) haystack; begin <= last_possible; ++begin) ++ if (begin[0] == ((const char *) needle)[0] && ++ !memcmp ((const void *) &begin[1], ++ (const void *) ((const char *) needle + 1), ++ needle_len - 1)) ++ return (void *) begin; ++ ++ return NULL; ++} ++#endif + + #ifndef ARRAY_SIZE + #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) +--- a/scripts/kconfig/Makefile ++++ b/scripts/kconfig/Makefile +@@ -151,6 +151,9 @@ check-lxdialog := $(srctree)/$(src)/lxd + # we really need to do so. (Do not call gcc as part of make mrproper) + HOST_EXTRACFLAGS += $(shell $(CONFIG_SHELL) $(check-lxdialog) -ccflags) \ + -DLOCALE ++ifeq ($(shell uname -s),Darwin) ++HOST_LOADLIBES += -lncurses ++endif + + # =========================================================================== + # Shared Makefile for the various kconfig executables: +--- a/scripts/mod/mk_elfconfig.c ++++ b/scripts/mod/mk_elfconfig.c +@@ -1,7 +1,11 @@ + #include + #include + #include ++#ifndef __APPLE__ + #include ++#else ++#include "elf.h" ++#endif + + int + main(int argc, char **argv) +--- a/scripts/mod/modpost.h ++++ b/scripts/mod/modpost.h +@@ -7,7 +7,11 @@ + #include + #include + #include ++#if !(defined(__APPLE__) || defined(__CYGWIN__)) + #include ++#else ++#include "elf.h" ++#endif + + #include "elfconfig.h" + +--- /dev/null ++++ b/scripts/mod/elf.h +@@ -0,0 +1,3007 @@ ++/* This file defines standard ELF types, structures, and macros. ++ Copyright (C) 1995-2012 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#ifndef _ELF_H ++#define _ELF_H 1 ++ ++/* Standard ELF types. */ ++ ++#include ++ ++/* Type for a 16-bit quantity. */ ++typedef uint16_t Elf32_Half; ++typedef uint16_t Elf64_Half; ++ ++/* Types for signed and unsigned 32-bit quantities. */ ++typedef uint32_t Elf32_Word; ++typedef int32_t Elf32_Sword; ++typedef uint32_t Elf64_Word; ++typedef int32_t Elf64_Sword; ++ ++/* Types for signed and unsigned 64-bit quantities. */ ++typedef uint64_t Elf32_Xword; ++typedef int64_t Elf32_Sxword; ++typedef uint64_t Elf64_Xword; ++typedef int64_t Elf64_Sxword; ++ ++/* Type of addresses. */ ++typedef uint32_t Elf32_Addr; ++typedef uint64_t Elf64_Addr; ++ ++/* Type of file offsets. */ ++typedef uint32_t Elf32_Off; ++typedef uint64_t Elf64_Off; ++ ++/* Type for section indices, which are 16-bit quantities. */ ++typedef uint16_t Elf32_Section; ++typedef uint16_t Elf64_Section; ++ ++/* Type for version symbol information. */ ++typedef Elf32_Half Elf32_Versym; ++typedef Elf64_Half Elf64_Versym; ++ ++ ++/* The ELF file header. This appears at the start of every ELF file. */ ++ ++#define EI_NIDENT (16) ++ ++typedef struct ++{ ++ unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ ++ Elf32_Half e_type; /* Object file type */ ++ Elf32_Half e_machine; /* Architecture */ ++ Elf32_Word e_version; /* Object file version */ ++ Elf32_Addr e_entry; /* Entry point virtual address */ ++ Elf32_Off e_phoff; /* Program header table file offset */ ++ Elf32_Off e_shoff; /* Section header table file offset */ ++ Elf32_Word e_flags; /* Processor-specific flags */ ++ Elf32_Half e_ehsize; /* ELF header size in bytes */ ++ Elf32_Half e_phentsize; /* Program header table entry size */ ++ Elf32_Half e_phnum; /* Program header table entry count */ ++ Elf32_Half e_shentsize; /* Section header table entry size */ ++ Elf32_Half e_shnum; /* Section header table entry count */ ++ Elf32_Half e_shstrndx; /* Section header string table index */ ++} Elf32_Ehdr; ++ ++typedef struct ++{ ++ unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ ++ Elf64_Half e_type; /* Object file type */ ++ Elf64_Half e_machine; /* Architecture */ ++ Elf64_Word e_version; /* Object file version */ ++ Elf64_Addr e_entry; /* Entry point virtual address */ ++ Elf64_Off e_phoff; /* Program header table file offset */ ++ Elf64_Off e_shoff; /* Section header table file offset */ ++ Elf64_Word e_flags; /* Processor-specific flags */ ++ Elf64_Half e_ehsize; /* ELF header size in bytes */ ++ Elf64_Half e_phentsize; /* Program header table entry size */ ++ Elf64_Half e_phnum; /* Program header table entry count */ ++ Elf64_Half e_shentsize; /* Section header table entry size */ ++ Elf64_Half e_shnum; /* Section header table entry count */ ++ Elf64_Half e_shstrndx; /* Section header string table index */ ++} Elf64_Ehdr; ++ ++/* Fields in the e_ident array. The EI_* macros are indices into the ++ array. The macros under each EI_* macro are the values the byte ++ may have. */ ++ ++#define EI_MAG0 0 /* File identification byte 0 index */ ++#define ELFMAG0 0x7f /* Magic number byte 0 */ ++ ++#define EI_MAG1 1 /* File identification byte 1 index */ ++#define ELFMAG1 'E' /* Magic number byte 1 */ ++ ++#define EI_MAG2 2 /* File identification byte 2 index */ ++#define ELFMAG2 'L' /* Magic number byte 2 */ ++ ++#define EI_MAG3 3 /* File identification byte 3 index */ ++#define ELFMAG3 'F' /* Magic number byte 3 */ ++ ++/* Conglomeration of the identification bytes, for easy testing as a word. */ ++#define ELFMAG "\177ELF" ++#define SELFMAG 4 ++ ++#define EI_CLASS 4 /* File class byte index */ ++#define ELFCLASSNONE 0 /* Invalid class */ ++#define ELFCLASS32 1 /* 32-bit objects */ ++#define ELFCLASS64 2 /* 64-bit objects */ ++#define ELFCLASSNUM 3 ++ ++#define EI_DATA 5 /* Data encoding byte index */ ++#define ELFDATANONE 0 /* Invalid data encoding */ ++#define ELFDATA2LSB 1 /* 2's complement, little endian */ ++#define ELFDATA2MSB 2 /* 2's complement, big endian */ ++#define ELFDATANUM 3 ++ ++#define EI_VERSION 6 /* File version byte index */ ++ /* Value must be EV_CURRENT */ ++ ++#define EI_OSABI 7 /* OS ABI identification */ ++#define ELFOSABI_NONE 0 /* UNIX System V ABI */ ++#define ELFOSABI_SYSV 0 /* Alias. */ ++#define ELFOSABI_HPUX 1 /* HP-UX */ ++#define ELFOSABI_NETBSD 2 /* NetBSD. */ ++#define ELFOSABI_GNU 3 /* Object uses GNU ELF extensions. */ ++#define ELFOSABI_LINUX ELFOSABI_GNU /* Compatibility alias. */ ++#define ELFOSABI_SOLARIS 6 /* Sun Solaris. */ ++#define ELFOSABI_AIX 7 /* IBM AIX. */ ++#define ELFOSABI_IRIX 8 /* SGI Irix. */ ++#define ELFOSABI_FREEBSD 9 /* FreeBSD. */ ++#define ELFOSABI_TRU64 10 /* Compaq TRU64 UNIX. */ ++#define ELFOSABI_MODESTO 11 /* Novell Modesto. */ ++#define ELFOSABI_OPENBSD 12 /* OpenBSD. */ ++#define ELFOSABI_ARM_AEABI 64 /* ARM EABI */ ++#define ELFOSABI_ARM 97 /* ARM */ ++#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ ++ ++#define EI_ABIVERSION 8 /* ABI version */ ++ ++#define EI_PAD 9 /* Byte index of padding bytes */ ++ ++/* Legal values for e_type (object file type). */ ++ ++#define ET_NONE 0 /* No file type */ ++#define ET_REL 1 /* Relocatable file */ ++#define ET_EXEC 2 /* Executable file */ ++#define ET_DYN 3 /* Shared object file */ ++#define ET_CORE 4 /* Core file */ ++#define ET_NUM 5 /* Number of defined types */ ++#define ET_LOOS 0xfe00 /* OS-specific range start */ ++#define ET_HIOS 0xfeff /* OS-specific range end */ ++#define ET_LOPROC 0xff00 /* Processor-specific range start */ ++#define ET_HIPROC 0xffff /* Processor-specific range end */ ++ ++/* Legal values for e_machine (architecture). */ ++ ++#define EM_NONE 0 /* No machine */ ++#define EM_M32 1 /* AT&T WE 32100 */ ++#define EM_SPARC 2 /* SUN SPARC */ ++#define EM_386 3 /* Intel 80386 */ ++#define EM_68K 4 /* Motorola m68k family */ ++#define EM_88K 5 /* Motorola m88k family */ ++#define EM_860 7 /* Intel 80860 */ ++#define EM_MIPS 8 /* MIPS R3000 big-endian */ ++#define EM_S370 9 /* IBM System/370 */ ++#define EM_MIPS_RS3_LE 10 /* MIPS R3000 little-endian */ ++ ++#define EM_PARISC 15 /* HPPA */ ++#define EM_VPP500 17 /* Fujitsu VPP500 */ ++#define EM_SPARC32PLUS 18 /* Sun's "v8plus" */ ++#define EM_960 19 /* Intel 80960 */ ++#define EM_PPC 20 /* PowerPC */ ++#define EM_PPC64 21 /* PowerPC 64-bit */ ++#define EM_S390 22 /* IBM S390 */ ++ ++#define EM_V800 36 /* NEC V800 series */ ++#define EM_FR20 37 /* Fujitsu FR20 */ ++#define EM_RH32 38 /* TRW RH-32 */ ++#define EM_RCE 39 /* Motorola RCE */ ++#define EM_ARM 40 /* ARM */ ++#define EM_FAKE_ALPHA 41 /* Digital Alpha */ ++#define EM_SH 42 /* Hitachi SH */ ++#define EM_SPARCV9 43 /* SPARC v9 64-bit */ ++#define EM_TRICORE 44 /* Siemens Tricore */ ++#define EM_ARC 45 /* Argonaut RISC Core */ ++#define EM_H8_300 46 /* Hitachi H8/300 */ ++#define EM_H8_300H 47 /* Hitachi H8/300H */ ++#define EM_H8S 48 /* Hitachi H8S */ ++#define EM_H8_500 49 /* Hitachi H8/500 */ ++#define EM_IA_64 50 /* Intel Merced */ ++#define EM_MIPS_X 51 /* Stanford MIPS-X */ ++#define EM_COLDFIRE 52 /* Motorola Coldfire */ ++#define EM_68HC12 53 /* Motorola M68HC12 */ ++#define EM_MMA 54 /* Fujitsu MMA Multimedia Accelerator*/ ++#define EM_PCP 55 /* Siemens PCP */ ++#define EM_NCPU 56 /* Sony nCPU embeeded RISC */ ++#define EM_NDR1 57 /* Denso NDR1 microprocessor */ ++#define EM_STARCORE 58 /* Motorola Start*Core processor */ ++#define EM_ME16 59 /* Toyota ME16 processor */ ++#define EM_ST100 60 /* STMicroelectronic ST100 processor */ ++#define EM_TINYJ 61 /* Advanced Logic Corp. Tinyj emb.fam*/ ++#define EM_X86_64 62 /* AMD x86-64 architecture */ ++#define EM_PDSP 63 /* Sony DSP Processor */ ++ ++#define EM_FX66 66 /* Siemens FX66 microcontroller */ ++#define EM_ST9PLUS 67 /* STMicroelectronics ST9+ 8/16 mc */ ++#define EM_ST7 68 /* STmicroelectronics ST7 8 bit mc */ ++#define EM_68HC16 69 /* Motorola MC68HC16 microcontroller */ ++#define EM_68HC11 70 /* Motorola MC68HC11 microcontroller */ ++#define EM_68HC08 71 /* Motorola MC68HC08 microcontroller */ ++#define EM_68HC05 72 /* Motorola MC68HC05 microcontroller */ ++#define EM_SVX 73 /* Silicon Graphics SVx */ ++#define EM_ST19 74 /* STMicroelectronics ST19 8 bit mc */ ++#define EM_VAX 75 /* Digital VAX */ ++#define EM_CRIS 76 /* Axis Communications 32-bit embedded processor */ ++#define EM_JAVELIN 77 /* Infineon Technologies 32-bit embedded processor */ ++#define EM_FIREPATH 78 /* Element 14 64-bit DSP Processor */ ++#define EM_ZSP 79 /* LSI Logic 16-bit DSP Processor */ ++#define EM_MMIX 80 /* Donald Knuth's educational 64-bit processor */ ++#define EM_HUANY 81 /* Harvard University machine-independent object files */ ++#define EM_PRISM 82 /* SiTera Prism */ ++#define EM_AVR 83 /* Atmel AVR 8-bit microcontroller */ ++#define EM_FR30 84 /* Fujitsu FR30 */ ++#define EM_D10V 85 /* Mitsubishi D10V */ ++#define EM_D30V 86 /* Mitsubishi D30V */ ++#define EM_V850 87 /* NEC v850 */ ++#define EM_M32R 88 /* Mitsubishi M32R */ ++#define EM_MN10300 89 /* Matsushita MN10300 */ ++#define EM_MN10200 90 /* Matsushita MN10200 */ ++#define EM_PJ 91 /* picoJava */ ++#define EM_OPENRISC 92 /* OpenRISC 32-bit embedded processor */ ++#define EM_ARC_A5 93 /* ARC Cores Tangent-A5 */ ++#define EM_XTENSA 94 /* Tensilica Xtensa Architecture */ ++#define EM_TILEPRO 188 /* Tilera TILEPro */ ++#define EM_TILEGX 191 /* Tilera TILE-Gx */ ++#define EM_NUM 192 ++ ++/* If it is necessary to assign new unofficial EM_* values, please ++ pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the ++ chances of collision with official or non-GNU unofficial values. */ ++ ++#define EM_ALPHA 0x9026 ++ ++/* Legal values for e_version (version). */ ++ ++#define EV_NONE 0 /* Invalid ELF version */ ++#define EV_CURRENT 1 /* Current version */ ++#define EV_NUM 2 ++ ++/* Section header. */ ++ ++typedef struct ++{ ++ Elf32_Word sh_name; /* Section name (string tbl index) */ ++ Elf32_Word sh_type; /* Section type */ ++ Elf32_Word sh_flags; /* Section flags */ ++ Elf32_Addr sh_addr; /* Section virtual addr at execution */ ++ Elf32_Off sh_offset; /* Section file offset */ ++ Elf32_Word sh_size; /* Section size in bytes */ ++ Elf32_Word sh_link; /* Link to another section */ ++ Elf32_Word sh_info; /* Additional section information */ ++ Elf32_Word sh_addralign; /* Section alignment */ ++ Elf32_Word sh_entsize; /* Entry size if section holds table */ ++} Elf32_Shdr; ++ ++typedef struct ++{ ++ Elf64_Word sh_name; /* Section name (string tbl index) */ ++ Elf64_Word sh_type; /* Section type */ ++ Elf64_Xword sh_flags; /* Section flags */ ++ Elf64_Addr sh_addr; /* Section virtual addr at execution */ ++ Elf64_Off sh_offset; /* Section file offset */ ++ Elf64_Xword sh_size; /* Section size in bytes */ ++ Elf64_Word sh_link; /* Link to another section */ ++ Elf64_Word sh_info; /* Additional section information */ ++ Elf64_Xword sh_addralign; /* Section alignment */ ++ Elf64_Xword sh_entsize; /* Entry size if section holds table */ ++} Elf64_Shdr; ++ ++/* Special section indices. */ ++ ++#define SHN_UNDEF 0 /* Undefined section */ ++#define SHN_LORESERVE 0xff00 /* Start of reserved indices */ ++#define SHN_LOPROC 0xff00 /* Start of processor-specific */ ++#define SHN_BEFORE 0xff00 /* Order section before all others ++ (Solaris). */ ++#define SHN_AFTER 0xff01 /* Order section after all others ++ (Solaris). */ ++#define SHN_HIPROC 0xff1f /* End of processor-specific */ ++#define SHN_LOOS 0xff20 /* Start of OS-specific */ ++#define SHN_HIOS 0xff3f /* End of OS-specific */ ++#define SHN_ABS 0xfff1 /* Associated symbol is absolute */ ++#define SHN_COMMON 0xfff2 /* Associated symbol is common */ ++#define SHN_XINDEX 0xffff /* Index is in extra table. */ ++#define SHN_HIRESERVE 0xffff /* End of reserved indices */ ++ ++/* Legal values for sh_type (section type). */ ++ ++#define SHT_NULL 0 /* Section header table entry unused */ ++#define SHT_PROGBITS 1 /* Program data */ ++#define SHT_SYMTAB 2 /* Symbol table */ ++#define SHT_STRTAB 3 /* String table */ ++#define SHT_RELA 4 /* Relocation entries with addends */ ++#define SHT_HASH 5 /* Symbol hash table */ ++#define SHT_DYNAMIC 6 /* Dynamic linking information */ ++#define SHT_NOTE 7 /* Notes */ ++#define SHT_NOBITS 8 /* Program space with no data (bss) */ ++#define SHT_REL 9 /* Relocation entries, no addends */ ++#define SHT_SHLIB 10 /* Reserved */ ++#define SHT_DYNSYM 11 /* Dynamic linker symbol table */ ++#define SHT_INIT_ARRAY 14 /* Array of constructors */ ++#define SHT_FINI_ARRAY 15 /* Array of destructors */ ++#define SHT_PREINIT_ARRAY 16 /* Array of pre-constructors */ ++#define SHT_GROUP 17 /* Section group */ ++#define SHT_SYMTAB_SHNDX 18 /* Extended section indeces */ ++#define SHT_NUM 19 /* Number of defined types. */ ++#define SHT_LOOS 0x60000000 /* Start OS-specific. */ ++#define SHT_GNU_ATTRIBUTES 0x6ffffff5 /* Object attributes. */ ++#define SHT_GNU_HASH 0x6ffffff6 /* GNU-style hash table. */ ++#define SHT_GNU_LIBLIST 0x6ffffff7 /* Prelink library list */ ++#define SHT_CHECKSUM 0x6ffffff8 /* Checksum for DSO content. */ ++#define SHT_LOSUNW 0x6ffffffa /* Sun-specific low bound. */ ++#define SHT_SUNW_move 0x6ffffffa ++#define SHT_SUNW_COMDAT 0x6ffffffb ++#define SHT_SUNW_syminfo 0x6ffffffc ++#define SHT_GNU_verdef 0x6ffffffd /* Version definition section. */ ++#define SHT_GNU_verneed 0x6ffffffe /* Version needs section. */ ++#define SHT_GNU_versym 0x6fffffff /* Version symbol table. */ ++#define SHT_HISUNW 0x6fffffff /* Sun-specific high bound. */ ++#define SHT_HIOS 0x6fffffff /* End OS-specific type */ ++#define SHT_LOPROC 0x70000000 /* Start of processor-specific */ ++#define SHT_HIPROC 0x7fffffff /* End of processor-specific */ ++#define SHT_LOUSER 0x80000000 /* Start of application-specific */ ++#define SHT_HIUSER 0x8fffffff /* End of application-specific */ ++ ++/* Legal values for sh_flags (section flags). */ ++ ++#define SHF_WRITE (1 << 0) /* Writable */ ++#define SHF_ALLOC (1 << 1) /* Occupies memory during execution */ ++#define SHF_EXECINSTR (1 << 2) /* Executable */ ++#define SHF_MERGE (1 << 4) /* Might be merged */ ++#define SHF_STRINGS (1 << 5) /* Contains nul-terminated strings */ ++#define SHF_INFO_LINK (1 << 6) /* `sh_info' contains SHT index */ ++#define SHF_LINK_ORDER (1 << 7) /* Preserve order after combining */ ++#define SHF_OS_NONCONFORMING (1 << 8) /* Non-standard OS specific handling ++ required */ ++#define SHF_GROUP (1 << 9) /* Section is member of a group. */ ++#define SHF_TLS (1 << 10) /* Section hold thread-local data. */ ++#define SHF_MASKOS 0x0ff00000 /* OS-specific. */ ++#define SHF_MASKPROC 0xf0000000 /* Processor-specific */ ++#define SHF_ORDERED (1 << 30) /* Special ordering requirement ++ (Solaris). */ ++#define SHF_EXCLUDE (1 << 31) /* Section is excluded unless ++ referenced or allocated (Solaris).*/ ++ ++/* Section group handling. */ ++#define GRP_COMDAT 0x1 /* Mark group as COMDAT. */ ++ ++/* Symbol table entry. */ ++ ++typedef struct ++{ ++ Elf32_Word st_name; /* Symbol name (string tbl index) */ ++ Elf32_Addr st_value; /* Symbol value */ ++ Elf32_Word st_size; /* Symbol size */ ++ unsigned char st_info; /* Symbol type and binding */ ++ unsigned char st_other; /* Symbol visibility */ ++ Elf32_Section st_shndx; /* Section index */ ++} Elf32_Sym; ++ ++typedef struct ++{ ++ Elf64_Word st_name; /* Symbol name (string tbl index) */ ++ unsigned char st_info; /* Symbol type and binding */ ++ unsigned char st_other; /* Symbol visibility */ ++ Elf64_Section st_shndx; /* Section index */ ++ Elf64_Addr st_value; /* Symbol value */ ++ Elf64_Xword st_size; /* Symbol size */ ++} Elf64_Sym; ++ ++/* The syminfo section if available contains additional information about ++ every dynamic symbol. */ ++ ++typedef struct ++{ ++ Elf32_Half si_boundto; /* Direct bindings, symbol bound to */ ++ Elf32_Half si_flags; /* Per symbol flags */ ++} Elf32_Syminfo; ++ ++typedef struct ++{ ++ Elf64_Half si_boundto; /* Direct bindings, symbol bound to */ ++ Elf64_Half si_flags; /* Per symbol flags */ ++} Elf64_Syminfo; ++ ++/* Possible values for si_boundto. */ ++#define SYMINFO_BT_SELF 0xffff /* Symbol bound to self */ ++#define SYMINFO_BT_PARENT 0xfffe /* Symbol bound to parent */ ++#define SYMINFO_BT_LOWRESERVE 0xff00 /* Beginning of reserved entries */ ++ ++/* Possible bitmasks for si_flags. */ ++#define SYMINFO_FLG_DIRECT 0x0001 /* Direct bound symbol */ ++#define SYMINFO_FLG_PASSTHRU 0x0002 /* Pass-thru symbol for translator */ ++#define SYMINFO_FLG_COPY 0x0004 /* Symbol is a copy-reloc */ ++#define SYMINFO_FLG_LAZYLOAD 0x0008 /* Symbol bound to object to be lazy ++ loaded */ ++/* Syminfo version values. */ ++#define SYMINFO_NONE 0 ++#define SYMINFO_CURRENT 1 ++#define SYMINFO_NUM 2 ++ ++ ++/* How to extract and insert information held in the st_info field. */ ++ ++#define ELF32_ST_BIND(val) (((unsigned char) (val)) >> 4) ++#define ELF32_ST_TYPE(val) ((val) & 0xf) ++#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) ++ ++/* Both Elf32_Sym and Elf64_Sym use the same one-byte st_info field. */ ++#define ELF64_ST_BIND(val) ELF32_ST_BIND (val) ++#define ELF64_ST_TYPE(val) ELF32_ST_TYPE (val) ++#define ELF64_ST_INFO(bind, type) ELF32_ST_INFO ((bind), (type)) ++ ++/* Legal values for ST_BIND subfield of st_info (symbol binding). */ ++ ++#define STB_LOCAL 0 /* Local symbol */ ++#define STB_GLOBAL 1 /* Global symbol */ ++#define STB_WEAK 2 /* Weak symbol */ ++#define STB_NUM 3 /* Number of defined types. */ ++#define STB_LOOS 10 /* Start of OS-specific */ ++#define STB_GNU_UNIQUE 10 /* Unique symbol. */ ++#define STB_HIOS 12 /* End of OS-specific */ ++#define STB_LOPROC 13 /* Start of processor-specific */ ++#define STB_HIPROC 15 /* End of processor-specific */ ++ ++/* Legal values for ST_TYPE subfield of st_info (symbol type). */ ++ ++#define STT_NOTYPE 0 /* Symbol type is unspecified */ ++#define STT_OBJECT 1 /* Symbol is a data object */ ++#define STT_FUNC 2 /* Symbol is a code object */ ++#define STT_SECTION 3 /* Symbol associated with a section */ ++#define STT_FILE 4 /* Symbol's name is file name */ ++#define STT_COMMON 5 /* Symbol is a common data object */ ++#define STT_TLS 6 /* Symbol is thread-local data object*/ ++#define STT_NUM 7 /* Number of defined types. */ ++#define STT_LOOS 10 /* Start of OS-specific */ ++#define STT_GNU_IFUNC 10 /* Symbol is indirect code object */ ++#define STT_HIOS 12 /* End of OS-specific */ ++#define STT_LOPROC 13 /* Start of processor-specific */ ++#define STT_HIPROC 15 /* End of processor-specific */ ++ ++ ++/* Symbol table indices are found in the hash buckets and chain table ++ of a symbol hash table section. This special index value indicates ++ the end of a chain, meaning no further symbols are found in that bucket. */ ++ ++#define STN_UNDEF 0 /* End of a chain. */ ++ ++ ++/* How to extract and insert information held in the st_other field. */ ++ ++#define ELF32_ST_VISIBILITY(o) ((o) & 0x03) ++ ++/* For ELF64 the definitions are the same. */ ++#define ELF64_ST_VISIBILITY(o) ELF32_ST_VISIBILITY (o) ++ ++/* Symbol visibility specification encoded in the st_other field. */ ++#define STV_DEFAULT 0 /* Default symbol visibility rules */ ++#define STV_INTERNAL 1 /* Processor specific hidden class */ ++#define STV_HIDDEN 2 /* Sym unavailable in other modules */ ++#define STV_PROTECTED 3 /* Not preemptible, not exported */ ++ ++ ++/* Relocation table entry without addend (in section of type SHT_REL). */ ++ ++typedef struct ++{ ++ Elf32_Addr r_offset; /* Address */ ++ Elf32_Word r_info; /* Relocation type and symbol index */ ++} Elf32_Rel; ++ ++/* I have seen two different definitions of the Elf64_Rel and ++ Elf64_Rela structures, so we'll leave them out until Novell (or ++ whoever) gets their act together. */ ++/* The following, at least, is used on Sparc v9, MIPS, and Alpha. */ ++ ++typedef struct ++{ ++ Elf64_Addr r_offset; /* Address */ ++ Elf64_Xword r_info; /* Relocation type and symbol index */ ++} Elf64_Rel; ++ ++/* Relocation table entry with addend (in section of type SHT_RELA). */ ++ ++typedef struct ++{ ++ Elf32_Addr r_offset; /* Address */ ++ Elf32_Word r_info; /* Relocation type and symbol index */ ++ Elf32_Sword r_addend; /* Addend */ ++} Elf32_Rela; ++ ++typedef struct ++{ ++ Elf64_Addr r_offset; /* Address */ ++ Elf64_Xword r_info; /* Relocation type and symbol index */ ++ Elf64_Sxword r_addend; /* Addend */ ++} Elf64_Rela; ++ ++/* How to extract and insert information held in the r_info field. */ ++ ++#define ELF32_R_SYM(val) ((val) >> 8) ++#define ELF32_R_TYPE(val) ((val) & 0xff) ++#define ELF32_R_INFO(sym, type) (((sym) << 8) + ((type) & 0xff)) ++ ++#define ELF64_R_SYM(i) ((i) >> 32) ++#define ELF64_R_TYPE(i) ((i) & 0xffffffff) ++#define ELF64_R_INFO(sym,type) ((((Elf64_Xword) (sym)) << 32) + (type)) ++ ++/* Program segment header. */ ++ ++typedef struct ++{ ++ Elf32_Word p_type; /* Segment type */ ++ Elf32_Off p_offset; /* Segment file offset */ ++ Elf32_Addr p_vaddr; /* Segment virtual address */ ++ Elf32_Addr p_paddr; /* Segment physical address */ ++ Elf32_Word p_filesz; /* Segment size in file */ ++ Elf32_Word p_memsz; /* Segment size in memory */ ++ Elf32_Word p_flags; /* Segment flags */ ++ Elf32_Word p_align; /* Segment alignment */ ++} Elf32_Phdr; ++ ++typedef struct ++{ ++ Elf64_Word p_type; /* Segment type */ ++ Elf64_Word p_flags; /* Segment flags */ ++ Elf64_Off p_offset; /* Segment file offset */ ++ Elf64_Addr p_vaddr; /* Segment virtual address */ ++ Elf64_Addr p_paddr; /* Segment physical address */ ++ Elf64_Xword p_filesz; /* Segment size in file */ ++ Elf64_Xword p_memsz; /* Segment size in memory */ ++ Elf64_Xword p_align; /* Segment alignment */ ++} Elf64_Phdr; ++ ++/* Special value for e_phnum. This indicates that the real number of ++ program headers is too large to fit into e_phnum. Instead the real ++ value is in the field sh_info of section 0. */ ++ ++#define PN_XNUM 0xffff ++ ++/* Legal values for p_type (segment type). */ ++ ++#define PT_NULL 0 /* Program header table entry unused */ ++#define PT_LOAD 1 /* Loadable program segment */ ++#define PT_DYNAMIC 2 /* Dynamic linking information */ ++#define PT_INTERP 3 /* Program interpreter */ ++#define PT_NOTE 4 /* Auxiliary information */ ++#define PT_SHLIB 5 /* Reserved */ ++#define PT_PHDR 6 /* Entry for header table itself */ ++#define PT_TLS 7 /* Thread-local storage segment */ ++#define PT_NUM 8 /* Number of defined types */ ++#define PT_LOOS 0x60000000 /* Start of OS-specific */ ++#define PT_GNU_EH_FRAME 0x6474e550 /* GCC .eh_frame_hdr segment */ ++#define PT_GNU_STACK 0x6474e551 /* Indicates stack executability */ ++#define PT_GNU_RELRO 0x6474e552 /* Read-only after relocation */ ++#define PT_LOSUNW 0x6ffffffa ++#define PT_SUNWBSS 0x6ffffffa /* Sun Specific segment */ ++#define PT_SUNWSTACK 0x6ffffffb /* Stack segment */ ++#define PT_HISUNW 0x6fffffff ++#define PT_HIOS 0x6fffffff /* End of OS-specific */ ++#define PT_LOPROC 0x70000000 /* Start of processor-specific */ ++#define PT_HIPROC 0x7fffffff /* End of processor-specific */ ++ ++/* Legal values for p_flags (segment flags). */ ++ ++#define PF_X (1 << 0) /* Segment is executable */ ++#define PF_W (1 << 1) /* Segment is writable */ ++#define PF_R (1 << 2) /* Segment is readable */ ++#define PF_MASKOS 0x0ff00000 /* OS-specific */ ++#define PF_MASKPROC 0xf0000000 /* Processor-specific */ ++ ++/* Legal values for note segment descriptor types for core files. */ ++ ++#define NT_PRSTATUS 1 /* Contains copy of prstatus struct */ ++#define NT_FPREGSET 2 /* Contains copy of fpregset struct */ ++#define NT_PRPSINFO 3 /* Contains copy of prpsinfo struct */ ++#define NT_PRXREG 4 /* Contains copy of prxregset struct */ ++#define NT_TASKSTRUCT 4 /* Contains copy of task structure */ ++#define NT_PLATFORM 5 /* String from sysinfo(SI_PLATFORM) */ ++#define NT_AUXV 6 /* Contains copy of auxv array */ ++#define NT_GWINDOWS 7 /* Contains copy of gwindows struct */ ++#define NT_ASRS 8 /* Contains copy of asrset struct */ ++#define NT_PSTATUS 10 /* Contains copy of pstatus struct */ ++#define NT_PSINFO 13 /* Contains copy of psinfo struct */ ++#define NT_PRCRED 14 /* Contains copy of prcred struct */ ++#define NT_UTSNAME 15 /* Contains copy of utsname struct */ ++#define NT_LWPSTATUS 16 /* Contains copy of lwpstatus struct */ ++#define NT_LWPSINFO 17 /* Contains copy of lwpinfo struct */ ++#define NT_PRFPXREG 20 /* Contains copy of fprxregset struct */ ++#define NT_PRXFPREG 0x46e62b7f /* Contains copy of user_fxsr_struct */ ++#define NT_PPC_VMX 0x100 /* PowerPC Altivec/VMX registers */ ++#define NT_PPC_SPE 0x101 /* PowerPC SPE/EVR registers */ ++#define NT_PPC_VSX 0x102 /* PowerPC VSX registers */ ++#define NT_386_TLS 0x200 /* i386 TLS slots (struct user_desc) */ ++#define NT_386_IOPERM 0x201 /* x86 io permission bitmap (1=deny) */ ++#define NT_X86_XSTATE 0x202 /* x86 extended state using xsave */ ++ ++/* Legal values for the note segment descriptor types for object files. */ ++ ++#define NT_VERSION 1 /* Contains a version string. */ ++ ++ ++/* Dynamic section entry. */ ++ ++typedef struct ++{ ++ Elf32_Sword d_tag; /* Dynamic entry type */ ++ union ++ { ++ Elf32_Word d_val; /* Integer value */ ++ Elf32_Addr d_ptr; /* Address value */ ++ } d_un; ++} Elf32_Dyn; ++ ++typedef struct ++{ ++ Elf64_Sxword d_tag; /* Dynamic entry type */ ++ union ++ { ++ Elf64_Xword d_val; /* Integer value */ ++ Elf64_Addr d_ptr; /* Address value */ ++ } d_un; ++} Elf64_Dyn; ++ ++/* Legal values for d_tag (dynamic entry type). */ ++ ++#define DT_NULL 0 /* Marks end of dynamic section */ ++#define DT_NEEDED 1 /* Name of needed library */ ++#define DT_PLTRELSZ 2 /* Size in bytes of PLT relocs */ ++#define DT_PLTGOT 3 /* Processor defined value */ ++#define DT_HASH 4 /* Address of symbol hash table */ ++#define DT_STRTAB 5 /* Address of string table */ ++#define DT_SYMTAB 6 /* Address of symbol table */ ++#define DT_RELA 7 /* Address of Rela relocs */ ++#define DT_RELASZ 8 /* Total size of Rela relocs */ ++#define DT_RELAENT 9 /* Size of one Rela reloc */ ++#define DT_STRSZ 10 /* Size of string table */ ++#define DT_SYMENT 11 /* Size of one symbol table entry */ ++#define DT_INIT 12 /* Address of init function */ ++#define DT_FINI 13 /* Address of termination function */ ++#define DT_SONAME 14 /* Name of shared object */ ++#define DT_RPATH 15 /* Library search path (deprecated) */ ++#define DT_SYMBOLIC 16 /* Start symbol search here */ ++#define DT_REL 17 /* Address of Rel relocs */ ++#define DT_RELSZ 18 /* Total size of Rel relocs */ ++#define DT_RELENT 19 /* Size of one Rel reloc */ ++#define DT_PLTREL 20 /* Type of reloc in PLT */ ++#define DT_DEBUG 21 /* For debugging; unspecified */ ++#define DT_TEXTREL 22 /* Reloc might modify .text */ ++#define DT_JMPREL 23 /* Address of PLT relocs */ ++#define DT_BIND_NOW 24 /* Process relocations of object */ ++#define DT_INIT_ARRAY 25 /* Array with addresses of init fct */ ++#define DT_FINI_ARRAY 26 /* Array with addresses of fini fct */ ++#define DT_INIT_ARRAYSZ 27 /* Size in bytes of DT_INIT_ARRAY */ ++#define DT_FINI_ARRAYSZ 28 /* Size in bytes of DT_FINI_ARRAY */ ++#define DT_RUNPATH 29 /* Library search path */ ++#define DT_FLAGS 30 /* Flags for the object being loaded */ ++#define DT_ENCODING 32 /* Start of encoded range */ ++#define DT_PREINIT_ARRAY 32 /* Array with addresses of preinit fct*/ ++#define DT_PREINIT_ARRAYSZ 33 /* size in bytes of DT_PREINIT_ARRAY */ ++#define DT_NUM 34 /* Number used */ ++#define DT_LOOS 0x6000000d /* Start of OS-specific */ ++#define DT_HIOS 0x6ffff000 /* End of OS-specific */ ++#define DT_LOPROC 0x70000000 /* Start of processor-specific */ ++#define DT_HIPROC 0x7fffffff /* End of processor-specific */ ++#define DT_PROCNUM DT_MIPS_NUM /* Most used by any processor */ ++ ++/* DT_* entries which fall between DT_VALRNGHI & DT_VALRNGLO use the ++ Dyn.d_un.d_val field of the Elf*_Dyn structure. This follows Sun's ++ approach. */ ++#define DT_VALRNGLO 0x6ffffd00 ++#define DT_GNU_PRELINKED 0x6ffffdf5 /* Prelinking timestamp */ ++#define DT_GNU_CONFLICTSZ 0x6ffffdf6 /* Size of conflict section */ ++#define DT_GNU_LIBLISTSZ 0x6ffffdf7 /* Size of library list */ ++#define DT_CHECKSUM 0x6ffffdf8 ++#define DT_PLTPADSZ 0x6ffffdf9 ++#define DT_MOVEENT 0x6ffffdfa ++#define DT_MOVESZ 0x6ffffdfb ++#define DT_FEATURE_1 0x6ffffdfc /* Feature selection (DTF_*). */ ++#define DT_POSFLAG_1 0x6ffffdfd /* Flags for DT_* entries, effecting ++ the following DT_* entry. */ ++#define DT_SYMINSZ 0x6ffffdfe /* Size of syminfo table (in bytes) */ ++#define DT_SYMINENT 0x6ffffdff /* Entry size of syminfo */ ++#define DT_VALRNGHI 0x6ffffdff ++#define DT_VALTAGIDX(tag) (DT_VALRNGHI - (tag)) /* Reverse order! */ ++#define DT_VALNUM 12 ++ ++/* DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the ++ Dyn.d_un.d_ptr field of the Elf*_Dyn structure. ++ ++ If any adjustment is made to the ELF object after it has been ++ built these entries will need to be adjusted. */ ++#define DT_ADDRRNGLO 0x6ffffe00 ++#define DT_GNU_HASH 0x6ffffef5 /* GNU-style hash table. */ ++#define DT_TLSDESC_PLT 0x6ffffef6 ++#define DT_TLSDESC_GOT 0x6ffffef7 ++#define DT_GNU_CONFLICT 0x6ffffef8 /* Start of conflict section */ ++#define DT_GNU_LIBLIST 0x6ffffef9 /* Library list */ ++#define DT_CONFIG 0x6ffffefa /* Configuration information. */ ++#define DT_DEPAUDIT 0x6ffffefb /* Dependency auditing. */ ++#define DT_AUDIT 0x6ffffefc /* Object auditing. */ ++#define DT_PLTPAD 0x6ffffefd /* PLT padding. */ ++#define DT_MOVETAB 0x6ffffefe /* Move table. */ ++#define DT_SYMINFO 0x6ffffeff /* Syminfo table. */ ++#define DT_ADDRRNGHI 0x6ffffeff ++#define DT_ADDRTAGIDX(tag) (DT_ADDRRNGHI - (tag)) /* Reverse order! */ ++#define DT_ADDRNUM 11 ++ ++/* The versioning entry types. The next are defined as part of the ++ GNU extension. */ ++#define DT_VERSYM 0x6ffffff0 ++ ++#define DT_RELACOUNT 0x6ffffff9 ++#define DT_RELCOUNT 0x6ffffffa ++ ++/* These were chosen by Sun. */ ++#define DT_FLAGS_1 0x6ffffffb /* State flags, see DF_1_* below. */ ++#define DT_VERDEF 0x6ffffffc /* Address of version definition ++ table */ ++#define DT_VERDEFNUM 0x6ffffffd /* Number of version definitions */ ++#define DT_VERNEED 0x6ffffffe /* Address of table with needed ++ versions */ ++#define DT_VERNEEDNUM 0x6fffffff /* Number of needed versions */ ++#define DT_VERSIONTAGIDX(tag) (DT_VERNEEDNUM - (tag)) /* Reverse order! */ ++#define DT_VERSIONTAGNUM 16 ++ ++/* Sun added these machine-independent extensions in the "processor-specific" ++ range. Be compatible. */ ++#define DT_AUXILIARY 0x7ffffffd /* Shared object to load before self */ ++#define DT_FILTER 0x7fffffff /* Shared object to get values from */ ++#define DT_EXTRATAGIDX(tag) ((Elf32_Word)-((Elf32_Sword) (tag) <<1>>1)-1) ++#define DT_EXTRANUM 3 ++ ++/* Values of `d_un.d_val' in the DT_FLAGS entry. */ ++#define DF_ORIGIN 0x00000001 /* Object may use DF_ORIGIN */ ++#define DF_SYMBOLIC 0x00000002 /* Symbol resolutions starts here */ ++#define DF_TEXTREL 0x00000004 /* Object contains text relocations */ ++#define DF_BIND_NOW 0x00000008 /* No lazy binding for this object */ ++#define DF_STATIC_TLS 0x00000010 /* Module uses the static TLS model */ ++ ++/* State flags selectable in the `d_un.d_val' element of the DT_FLAGS_1 ++ entry in the dynamic section. */ ++#define DF_1_NOW 0x00000001 /* Set RTLD_NOW for this object. */ ++#define DF_1_GLOBAL 0x00000002 /* Set RTLD_GLOBAL for this object. */ ++#define DF_1_GROUP 0x00000004 /* Set RTLD_GROUP for this object. */ ++#define DF_1_NODELETE 0x00000008 /* Set RTLD_NODELETE for this object.*/ ++#define DF_1_LOADFLTR 0x00000010 /* Trigger filtee loading at runtime.*/ ++#define DF_1_INITFIRST 0x00000020 /* Set RTLD_INITFIRST for this object*/ ++#define DF_1_NOOPEN 0x00000040 /* Set RTLD_NOOPEN for this object. */ ++#define DF_1_ORIGIN 0x00000080 /* $ORIGIN must be handled. */ ++#define DF_1_DIRECT 0x00000100 /* Direct binding enabled. */ ++#define DF_1_TRANS 0x00000200 ++#define DF_1_INTERPOSE 0x00000400 /* Object is used to interpose. */ ++#define DF_1_NODEFLIB 0x00000800 /* Ignore default lib search path. */ ++#define DF_1_NODUMP 0x00001000 /* Object can't be dldump'ed. */ ++#define DF_1_CONFALT 0x00002000 /* Configuration alternative created.*/ ++#define DF_1_ENDFILTEE 0x00004000 /* Filtee terminates filters search. */ ++#define DF_1_DISPRELDNE 0x00008000 /* Disp reloc applied at build time. */ ++#define DF_1_DISPRELPND 0x00010000 /* Disp reloc applied at run-time. */ ++ ++/* Flags for the feature selection in DT_FEATURE_1. */ ++#define DTF_1_PARINIT 0x00000001 ++#define DTF_1_CONFEXP 0x00000002 ++ ++/* Flags in the DT_POSFLAG_1 entry effecting only the next DT_* entry. */ ++#define DF_P1_LAZYLOAD 0x00000001 /* Lazyload following object. */ ++#define DF_P1_GROUPPERM 0x00000002 /* Symbols from next object are not ++ generally available. */ ++ ++/* Version definition sections. */ ++ ++typedef struct ++{ ++ Elf32_Half vd_version; /* Version revision */ ++ Elf32_Half vd_flags; /* Version information */ ++ Elf32_Half vd_ndx; /* Version Index */ ++ Elf32_Half vd_cnt; /* Number of associated aux entries */ ++ Elf32_Word vd_hash; /* Version name hash value */ ++ Elf32_Word vd_aux; /* Offset in bytes to verdaux array */ ++ Elf32_Word vd_next; /* Offset in bytes to next verdef ++ entry */ ++} Elf32_Verdef; ++ ++typedef struct ++{ ++ Elf64_Half vd_version; /* Version revision */ ++ Elf64_Half vd_flags; /* Version information */ ++ Elf64_Half vd_ndx; /* Version Index */ ++ Elf64_Half vd_cnt; /* Number of associated aux entries */ ++ Elf64_Word vd_hash; /* Version name hash value */ ++ Elf64_Word vd_aux; /* Offset in bytes to verdaux array */ ++ Elf64_Word vd_next; /* Offset in bytes to next verdef ++ entry */ ++} Elf64_Verdef; ++ ++ ++/* Legal values for vd_version (version revision). */ ++#define VER_DEF_NONE 0 /* No version */ ++#define VER_DEF_CURRENT 1 /* Current version */ ++#define VER_DEF_NUM 2 /* Given version number */ ++ ++/* Legal values for vd_flags (version information flags). */ ++#define VER_FLG_BASE 0x1 /* Version definition of file itself */ ++#define VER_FLG_WEAK 0x2 /* Weak version identifier */ ++ ++/* Versym symbol index values. */ ++#define VER_NDX_LOCAL 0 /* Symbol is local. */ ++#define VER_NDX_GLOBAL 1 /* Symbol is global. */ ++#define VER_NDX_LORESERVE 0xff00 /* Beginning of reserved entries. */ ++#define VER_NDX_ELIMINATE 0xff01 /* Symbol is to be eliminated. */ ++ ++/* Auxialiary version information. */ ++ ++typedef struct ++{ ++ Elf32_Word vda_name; /* Version or dependency names */ ++ Elf32_Word vda_next; /* Offset in bytes to next verdaux ++ entry */ ++} Elf32_Verdaux; ++ ++typedef struct ++{ ++ Elf64_Word vda_name; /* Version or dependency names */ ++ Elf64_Word vda_next; /* Offset in bytes to next verdaux ++ entry */ ++} Elf64_Verdaux; ++ ++ ++/* Version dependency section. */ ++ ++typedef struct ++{ ++ Elf32_Half vn_version; /* Version of structure */ ++ Elf32_Half vn_cnt; /* Number of associated aux entries */ ++ Elf32_Word vn_file; /* Offset of filename for this ++ dependency */ ++ Elf32_Word vn_aux; /* Offset in bytes to vernaux array */ ++ Elf32_Word vn_next; /* Offset in bytes to next verneed ++ entry */ ++} Elf32_Verneed; ++ ++typedef struct ++{ ++ Elf64_Half vn_version; /* Version of structure */ ++ Elf64_Half vn_cnt; /* Number of associated aux entries */ ++ Elf64_Word vn_file; /* Offset of filename for this ++ dependency */ ++ Elf64_Word vn_aux; /* Offset in bytes to vernaux array */ ++ Elf64_Word vn_next; /* Offset in bytes to next verneed ++ entry */ ++} Elf64_Verneed; ++ ++ ++/* Legal values for vn_version (version revision). */ ++#define VER_NEED_NONE 0 /* No version */ ++#define VER_NEED_CURRENT 1 /* Current version */ ++#define VER_NEED_NUM 2 /* Given version number */ ++ ++/* Auxiliary needed version information. */ ++ ++typedef struct ++{ ++ Elf32_Word vna_hash; /* Hash value of dependency name */ ++ Elf32_Half vna_flags; /* Dependency specific information */ ++ Elf32_Half vna_other; /* Unused */ ++ Elf32_Word vna_name; /* Dependency name string offset */ ++ Elf32_Word vna_next; /* Offset in bytes to next vernaux ++ entry */ ++} Elf32_Vernaux; ++ ++typedef struct ++{ ++ Elf64_Word vna_hash; /* Hash value of dependency name */ ++ Elf64_Half vna_flags; /* Dependency specific information */ ++ Elf64_Half vna_other; /* Unused */ ++ Elf64_Word vna_name; /* Dependency name string offset */ ++ Elf64_Word vna_next; /* Offset in bytes to next vernaux ++ entry */ ++} Elf64_Vernaux; ++ ++ ++/* Legal values for vna_flags. */ ++#define VER_FLG_WEAK 0x2 /* Weak version identifier */ ++ ++ ++/* Auxiliary vector. */ ++ ++/* This vector is normally only used by the program interpreter. The ++ usual definition in an ABI supplement uses the name auxv_t. The ++ vector is not usually defined in a standard file, but it ++ can't hurt. We rename it to avoid conflicts. The sizes of these ++ types are an arrangement between the exec server and the program ++ interpreter, so we don't fully specify them here. */ ++ ++typedef struct ++{ ++ uint32_t a_type; /* Entry type */ ++ union ++ { ++ uint32_t a_val; /* Integer value */ ++ /* We use to have pointer elements added here. We cannot do that, ++ though, since it does not work when using 32-bit definitions ++ on 64-bit platforms and vice versa. */ ++ } a_un; ++} Elf32_auxv_t; ++ ++typedef struct ++{ ++ uint64_t a_type; /* Entry type */ ++ union ++ { ++ uint64_t a_val; /* Integer value */ ++ /* We use to have pointer elements added here. We cannot do that, ++ though, since it does not work when using 32-bit definitions ++ on 64-bit platforms and vice versa. */ ++ } a_un; ++} Elf64_auxv_t; ++ ++/* Legal values for a_type (entry type). */ ++ ++#define AT_NULL 0 /* End of vector */ ++#define AT_IGNORE 1 /* Entry should be ignored */ ++#define AT_EXECFD 2 /* File descriptor of program */ ++#define AT_PHDR 3 /* Program headers for program */ ++#define AT_PHENT 4 /* Size of program header entry */ ++#define AT_PHNUM 5 /* Number of program headers */ ++#define AT_PAGESZ 6 /* System page size */ ++#define AT_BASE 7 /* Base address of interpreter */ ++#define AT_FLAGS 8 /* Flags */ ++#define AT_ENTRY 9 /* Entry point of program */ ++#define AT_NOTELF 10 /* Program is not ELF */ ++#define AT_UID 11 /* Real uid */ ++#define AT_EUID 12 /* Effective uid */ ++#define AT_GID 13 /* Real gid */ ++#define AT_EGID 14 /* Effective gid */ ++#define AT_CLKTCK 17 /* Frequency of times() */ ++ ++/* Some more special a_type values describing the hardware. */ ++#define AT_PLATFORM 15 /* String identifying platform. */ ++#define AT_HWCAP 16 /* Machine dependent hints about ++ processor capabilities. */ ++ ++/* This entry gives some information about the FPU initialization ++ performed by the kernel. */ ++#define AT_FPUCW 18 /* Used FPU control word. */ ++ ++/* Cache block sizes. */ ++#define AT_DCACHEBSIZE 19 /* Data cache block size. */ ++#define AT_ICACHEBSIZE 20 /* Instruction cache block size. */ ++#define AT_UCACHEBSIZE 21 /* Unified cache block size. */ ++ ++/* A special ignored value for PPC, used by the kernel to control the ++ interpretation of the AUXV. Must be > 16. */ ++#define AT_IGNOREPPC 22 /* Entry should be ignored. */ ++ ++#define AT_SECURE 23 /* Boolean, was exec setuid-like? */ ++ ++#define AT_BASE_PLATFORM 24 /* String identifying real platforms.*/ ++ ++#define AT_RANDOM 25 /* Address of 16 random bytes. */ ++ ++#define AT_EXECFN 31 /* Filename of executable. */ ++ ++/* Pointer to the global system page used for system calls and other ++ nice things. */ ++#define AT_SYSINFO 32 ++#define AT_SYSINFO_EHDR 33 ++ ++/* Shapes of the caches. Bits 0-3 contains associativity; bits 4-7 contains ++ log2 of line size; mask those to get cache size. */ ++#define AT_L1I_CACHESHAPE 34 ++#define AT_L1D_CACHESHAPE 35 ++#define AT_L2_CACHESHAPE 36 ++#define AT_L3_CACHESHAPE 37 ++ ++/* Note section contents. Each entry in the note section begins with ++ a header of a fixed form. */ ++ ++typedef struct ++{ ++ Elf32_Word n_namesz; /* Length of the note's name. */ ++ Elf32_Word n_descsz; /* Length of the note's descriptor. */ ++ Elf32_Word n_type; /* Type of the note. */ ++} Elf32_Nhdr; ++ ++typedef struct ++{ ++ Elf64_Word n_namesz; /* Length of the note's name. */ ++ Elf64_Word n_descsz; /* Length of the note's descriptor. */ ++ Elf64_Word n_type; /* Type of the note. */ ++} Elf64_Nhdr; ++ ++/* Known names of notes. */ ++ ++/* Solaris entries in the note section have this name. */ ++#define ELF_NOTE_SOLARIS "SUNW Solaris" ++ ++/* Note entries for GNU systems have this name. */ ++#define ELF_NOTE_GNU "GNU" ++ ++ ++/* Defined types of notes for Solaris. */ ++ ++/* Value of descriptor (one word) is desired pagesize for the binary. */ ++#define ELF_NOTE_PAGESIZE_HINT 1 ++ ++ ++/* Defined note types for GNU systems. */ ++ ++/* ABI information. The descriptor consists of words: ++ word 0: OS descriptor ++ word 1: major version of the ABI ++ word 2: minor version of the ABI ++ word 3: subminor version of the ABI ++*/ ++#define NT_GNU_ABI_TAG 1 ++#define ELF_NOTE_ABI NT_GNU_ABI_TAG /* Old name. */ ++ ++/* Known OSes. These values can appear in word 0 of an ++ NT_GNU_ABI_TAG note section entry. */ ++#define ELF_NOTE_OS_LINUX 0 ++#define ELF_NOTE_OS_GNU 1 ++#define ELF_NOTE_OS_SOLARIS2 2 ++#define ELF_NOTE_OS_FREEBSD 3 ++ ++/* Synthetic hwcap information. The descriptor begins with two words: ++ word 0: number of entries ++ word 1: bitmask of enabled entries ++ Then follow variable-length entries, one byte followed by a ++ '\0'-terminated hwcap name string. The byte gives the bit ++ number to test if enabled, (1U << bit) & bitmask. */ ++#define NT_GNU_HWCAP 2 ++ ++/* Build ID bits as generated by ld --build-id. ++ The descriptor consists of any nonzero number of bytes. */ ++#define NT_GNU_BUILD_ID 3 ++ ++/* Version note generated by GNU gold containing a version string. */ ++#define NT_GNU_GOLD_VERSION 4 ++ ++ ++/* Move records. */ ++typedef struct ++{ ++ Elf32_Xword m_value; /* Symbol value. */ ++ Elf32_Word m_info; /* Size and index. */ ++ Elf32_Word m_poffset; /* Symbol offset. */ ++ Elf32_Half m_repeat; /* Repeat count. */ ++ Elf32_Half m_stride; /* Stride info. */ ++} Elf32_Move; ++ ++typedef struct ++{ ++ Elf64_Xword m_value; /* Symbol value. */ ++ Elf64_Xword m_info; /* Size and index. */ ++ Elf64_Xword m_poffset; /* Symbol offset. */ ++ Elf64_Half m_repeat; /* Repeat count. */ ++ Elf64_Half m_stride; /* Stride info. */ ++} Elf64_Move; ++ ++/* Macro to construct move records. */ ++#define ELF32_M_SYM(info) ((info) >> 8) ++#define ELF32_M_SIZE(info) ((unsigned char) (info)) ++#define ELF32_M_INFO(sym, size) (((sym) << 8) + (unsigned char) (size)) ++ ++#define ELF64_M_SYM(info) ELF32_M_SYM (info) ++#define ELF64_M_SIZE(info) ELF32_M_SIZE (info) ++#define ELF64_M_INFO(sym, size) ELF32_M_INFO (sym, size) ++ ++ ++/* Motorola 68k specific definitions. */ ++ ++/* Values for Elf32_Ehdr.e_flags. */ ++#define EF_CPU32 0x00810000 ++ ++/* m68k relocs. */ ++ ++#define R_68K_NONE 0 /* No reloc */ ++#define R_68K_32 1 /* Direct 32 bit */ ++#define R_68K_16 2 /* Direct 16 bit */ ++#define R_68K_8 3 /* Direct 8 bit */ ++#define R_68K_PC32 4 /* PC relative 32 bit */ ++#define R_68K_PC16 5 /* PC relative 16 bit */ ++#define R_68K_PC8 6 /* PC relative 8 bit */ ++#define R_68K_GOT32 7 /* 32 bit PC relative GOT entry */ ++#define R_68K_GOT16 8 /* 16 bit PC relative GOT entry */ ++#define R_68K_GOT8 9 /* 8 bit PC relative GOT entry */ ++#define R_68K_GOT32O 10 /* 32 bit GOT offset */ ++#define R_68K_GOT16O 11 /* 16 bit GOT offset */ ++#define R_68K_GOT8O 12 /* 8 bit GOT offset */ ++#define R_68K_PLT32 13 /* 32 bit PC relative PLT address */ ++#define R_68K_PLT16 14 /* 16 bit PC relative PLT address */ ++#define R_68K_PLT8 15 /* 8 bit PC relative PLT address */ ++#define R_68K_PLT32O 16 /* 32 bit PLT offset */ ++#define R_68K_PLT16O 17 /* 16 bit PLT offset */ ++#define R_68K_PLT8O 18 /* 8 bit PLT offset */ ++#define R_68K_COPY 19 /* Copy symbol at runtime */ ++#define R_68K_GLOB_DAT 20 /* Create GOT entry */ ++#define R_68K_JMP_SLOT 21 /* Create PLT entry */ ++#define R_68K_RELATIVE 22 /* Adjust by program base */ ++#define R_68K_TLS_GD32 25 /* 32 bit GOT offset for GD */ ++#define R_68K_TLS_GD16 26 /* 16 bit GOT offset for GD */ ++#define R_68K_TLS_GD8 27 /* 8 bit GOT offset for GD */ ++#define R_68K_TLS_LDM32 28 /* 32 bit GOT offset for LDM */ ++#define R_68K_TLS_LDM16 29 /* 16 bit GOT offset for LDM */ ++#define R_68K_TLS_LDM8 30 /* 8 bit GOT offset for LDM */ ++#define R_68K_TLS_LDO32 31 /* 32 bit module-relative offset */ ++#define R_68K_TLS_LDO16 32 /* 16 bit module-relative offset */ ++#define R_68K_TLS_LDO8 33 /* 8 bit module-relative offset */ ++#define R_68K_TLS_IE32 34 /* 32 bit GOT offset for IE */ ++#define R_68K_TLS_IE16 35 /* 16 bit GOT offset for IE */ ++#define R_68K_TLS_IE8 36 /* 8 bit GOT offset for IE */ ++#define R_68K_TLS_LE32 37 /* 32 bit offset relative to ++ static TLS block */ ++#define R_68K_TLS_LE16 38 /* 16 bit offset relative to ++ static TLS block */ ++#define R_68K_TLS_LE8 39 /* 8 bit offset relative to ++ static TLS block */ ++#define R_68K_TLS_DTPMOD32 40 /* 32 bit module number */ ++#define R_68K_TLS_DTPREL32 41 /* 32 bit module-relative offset */ ++#define R_68K_TLS_TPREL32 42 /* 32 bit TP-relative offset */ ++/* Keep this the last entry. */ ++#define R_68K_NUM 43 ++ ++/* Intel 80386 specific definitions. */ ++ ++/* i386 relocs. */ ++ ++#define R_386_NONE 0 /* No reloc */ ++#define R_386_32 1 /* Direct 32 bit */ ++#define R_386_PC32 2 /* PC relative 32 bit */ ++#define R_386_GOT32 3 /* 32 bit GOT entry */ ++#define R_386_PLT32 4 /* 32 bit PLT address */ ++#define R_386_COPY 5 /* Copy symbol at runtime */ ++#define R_386_GLOB_DAT 6 /* Create GOT entry */ ++#define R_386_JMP_SLOT 7 /* Create PLT entry */ ++#define R_386_RELATIVE 8 /* Adjust by program base */ ++#define R_386_GOTOFF 9 /* 32 bit offset to GOT */ ++#define R_386_GOTPC 10 /* 32 bit PC relative offset to GOT */ ++#define R_386_32PLT 11 ++#define R_386_TLS_TPOFF 14 /* Offset in static TLS block */ ++#define R_386_TLS_IE 15 /* Address of GOT entry for static TLS ++ block offset */ ++#define R_386_TLS_GOTIE 16 /* GOT entry for static TLS block ++ offset */ ++#define R_386_TLS_LE 17 /* Offset relative to static TLS ++ block */ ++#define R_386_TLS_GD 18 /* Direct 32 bit for GNU version of ++ general dynamic thread local data */ ++#define R_386_TLS_LDM 19 /* Direct 32 bit for GNU version of ++ local dynamic thread local data ++ in LE code */ ++#define R_386_16 20 ++#define R_386_PC16 21 ++#define R_386_8 22 ++#define R_386_PC8 23 ++#define R_386_TLS_GD_32 24 /* Direct 32 bit for general dynamic ++ thread local data */ ++#define R_386_TLS_GD_PUSH 25 /* Tag for pushl in GD TLS code */ ++#define R_386_TLS_GD_CALL 26 /* Relocation for call to ++ __tls_get_addr() */ ++#define R_386_TLS_GD_POP 27 /* Tag for popl in GD TLS code */ ++#define R_386_TLS_LDM_32 28 /* Direct 32 bit for local dynamic ++ thread local data in LE code */ ++#define R_386_TLS_LDM_PUSH 29 /* Tag for pushl in LDM TLS code */ ++#define R_386_TLS_LDM_CALL 30 /* Relocation for call to ++ __tls_get_addr() in LDM code */ ++#define R_386_TLS_LDM_POP 31 /* Tag for popl in LDM TLS code */ ++#define R_386_TLS_LDO_32 32 /* Offset relative to TLS block */ ++#define R_386_TLS_IE_32 33 /* GOT entry for negated static TLS ++ block offset */ ++#define R_386_TLS_LE_32 34 /* Negated offset relative to static ++ TLS block */ ++#define R_386_TLS_DTPMOD32 35 /* ID of module containing symbol */ ++#define R_386_TLS_DTPOFF32 36 /* Offset in TLS block */ ++#define R_386_TLS_TPOFF32 37 /* Negated offset in static TLS block */ ++/* 38? */ ++#define R_386_TLS_GOTDESC 39 /* GOT offset for TLS descriptor. */ ++#define R_386_TLS_DESC_CALL 40 /* Marker of call through TLS ++ descriptor for ++ relaxation. */ ++#define R_386_TLS_DESC 41 /* TLS descriptor containing ++ pointer to code and to ++ argument, returning the TLS ++ offset for the symbol. */ ++#define R_386_IRELATIVE 42 /* Adjust indirectly by program base */ ++/* Keep this the last entry. */ ++#define R_386_NUM 43 ++ ++/* SUN SPARC specific definitions. */ ++ ++/* Legal values for ST_TYPE subfield of st_info (symbol type). */ ++ ++#define STT_SPARC_REGISTER 13 /* Global register reserved to app. */ ++ ++/* Values for Elf64_Ehdr.e_flags. */ ++ ++#define EF_SPARCV9_MM 3 ++#define EF_SPARCV9_TSO 0 ++#define EF_SPARCV9_PSO 1 ++#define EF_SPARCV9_RMO 2 ++#define EF_SPARC_LEDATA 0x800000 /* little endian data */ ++#define EF_SPARC_EXT_MASK 0xFFFF00 ++#define EF_SPARC_32PLUS 0x000100 /* generic V8+ features */ ++#define EF_SPARC_SUN_US1 0x000200 /* Sun UltraSPARC1 extensions */ ++#define EF_SPARC_HAL_R1 0x000400 /* HAL R1 extensions */ ++#define EF_SPARC_SUN_US3 0x000800 /* Sun UltraSPARCIII extensions */ ++ ++/* SPARC relocs. */ ++ ++#define R_SPARC_NONE 0 /* No reloc */ ++#define R_SPARC_8 1 /* Direct 8 bit */ ++#define R_SPARC_16 2 /* Direct 16 bit */ ++#define R_SPARC_32 3 /* Direct 32 bit */ ++#define R_SPARC_DISP8 4 /* PC relative 8 bit */ ++#define R_SPARC_DISP16 5 /* PC relative 16 bit */ ++#define R_SPARC_DISP32 6 /* PC relative 32 bit */ ++#define R_SPARC_WDISP30 7 /* PC relative 30 bit shifted */ ++#define R_SPARC_WDISP22 8 /* PC relative 22 bit shifted */ ++#define R_SPARC_HI22 9 /* High 22 bit */ ++#define R_SPARC_22 10 /* Direct 22 bit */ ++#define R_SPARC_13 11 /* Direct 13 bit */ ++#define R_SPARC_LO10 12 /* Truncated 10 bit */ ++#define R_SPARC_GOT10 13 /* Truncated 10 bit GOT entry */ ++#define R_SPARC_GOT13 14 /* 13 bit GOT entry */ ++#define R_SPARC_GOT22 15 /* 22 bit GOT entry shifted */ ++#define R_SPARC_PC10 16 /* PC relative 10 bit truncated */ ++#define R_SPARC_PC22 17 /* PC relative 22 bit shifted */ ++#define R_SPARC_WPLT30 18 /* 30 bit PC relative PLT address */ ++#define R_SPARC_COPY 19 /* Copy symbol at runtime */ ++#define R_SPARC_GLOB_DAT 20 /* Create GOT entry */ ++#define R_SPARC_JMP_SLOT 21 /* Create PLT entry */ ++#define R_SPARC_RELATIVE 22 /* Adjust by program base */ ++#define R_SPARC_UA32 23 /* Direct 32 bit unaligned */ ++ ++/* Additional Sparc64 relocs. */ ++ ++#define R_SPARC_PLT32 24 /* Direct 32 bit ref to PLT entry */ ++#define R_SPARC_HIPLT22 25 /* High 22 bit PLT entry */ ++#define R_SPARC_LOPLT10 26 /* Truncated 10 bit PLT entry */ ++#define R_SPARC_PCPLT32 27 /* PC rel 32 bit ref to PLT entry */ ++#define R_SPARC_PCPLT22 28 /* PC rel high 22 bit PLT entry */ ++#define R_SPARC_PCPLT10 29 /* PC rel trunc 10 bit PLT entry */ ++#define R_SPARC_10 30 /* Direct 10 bit */ ++#define R_SPARC_11 31 /* Direct 11 bit */ ++#define R_SPARC_64 32 /* Direct 64 bit */ ++#define R_SPARC_OLO10 33 /* 10bit with secondary 13bit addend */ ++#define R_SPARC_HH22 34 /* Top 22 bits of direct 64 bit */ ++#define R_SPARC_HM10 35 /* High middle 10 bits of ... */ ++#define R_SPARC_LM22 36 /* Low middle 22 bits of ... */ ++#define R_SPARC_PC_HH22 37 /* Top 22 bits of pc rel 64 bit */ ++#define R_SPARC_PC_HM10 38 /* High middle 10 bit of ... */ ++#define R_SPARC_PC_LM22 39 /* Low miggle 22 bits of ... */ ++#define R_SPARC_WDISP16 40 /* PC relative 16 bit shifted */ ++#define R_SPARC_WDISP19 41 /* PC relative 19 bit shifted */ ++#define R_SPARC_GLOB_JMP 42 /* was part of v9 ABI but was removed */ ++#define R_SPARC_7 43 /* Direct 7 bit */ ++#define R_SPARC_5 44 /* Direct 5 bit */ ++#define R_SPARC_6 45 /* Direct 6 bit */ ++#define R_SPARC_DISP64 46 /* PC relative 64 bit */ ++#define R_SPARC_PLT64 47 /* Direct 64 bit ref to PLT entry */ ++#define R_SPARC_HIX22 48 /* High 22 bit complemented */ ++#define R_SPARC_LOX10 49 /* Truncated 11 bit complemented */ ++#define R_SPARC_H44 50 /* Direct high 12 of 44 bit */ ++#define R_SPARC_M44 51 /* Direct mid 22 of 44 bit */ ++#define R_SPARC_L44 52 /* Direct low 10 of 44 bit */ ++#define R_SPARC_REGISTER 53 /* Global register usage */ ++#define R_SPARC_UA64 54 /* Direct 64 bit unaligned */ ++#define R_SPARC_UA16 55 /* Direct 16 bit unaligned */ ++#define R_SPARC_TLS_GD_HI22 56 ++#define R_SPARC_TLS_GD_LO10 57 ++#define R_SPARC_TLS_GD_ADD 58 ++#define R_SPARC_TLS_GD_CALL 59 ++#define R_SPARC_TLS_LDM_HI22 60 ++#define R_SPARC_TLS_LDM_LO10 61 ++#define R_SPARC_TLS_LDM_ADD 62 ++#define R_SPARC_TLS_LDM_CALL 63 ++#define R_SPARC_TLS_LDO_HIX22 64 ++#define R_SPARC_TLS_LDO_LOX10 65 ++#define R_SPARC_TLS_LDO_ADD 66 ++#define R_SPARC_TLS_IE_HI22 67 ++#define R_SPARC_TLS_IE_LO10 68 ++#define R_SPARC_TLS_IE_LD 69 ++#define R_SPARC_TLS_IE_LDX 70 ++#define R_SPARC_TLS_IE_ADD 71 ++#define R_SPARC_TLS_LE_HIX22 72 ++#define R_SPARC_TLS_LE_LOX10 73 ++#define R_SPARC_TLS_DTPMOD32 74 ++#define R_SPARC_TLS_DTPMOD64 75 ++#define R_SPARC_TLS_DTPOFF32 76 ++#define R_SPARC_TLS_DTPOFF64 77 ++#define R_SPARC_TLS_TPOFF32 78 ++#define R_SPARC_TLS_TPOFF64 79 ++#define R_SPARC_GOTDATA_HIX22 80 ++#define R_SPARC_GOTDATA_LOX10 81 ++#define R_SPARC_GOTDATA_OP_HIX22 82 ++#define R_SPARC_GOTDATA_OP_LOX10 83 ++#define R_SPARC_GOTDATA_OP 84 ++#define R_SPARC_H34 85 ++#define R_SPARC_SIZE32 86 ++#define R_SPARC_SIZE64 87 ++#define R_SPARC_WDISP10 88 ++#define R_SPARC_JMP_IREL 248 ++#define R_SPARC_IRELATIVE 249 ++#define R_SPARC_GNU_VTINHERIT 250 ++#define R_SPARC_GNU_VTENTRY 251 ++#define R_SPARC_REV32 252 ++/* Keep this the last entry. */ ++#define R_SPARC_NUM 253 ++ ++/* For Sparc64, legal values for d_tag of Elf64_Dyn. */ ++ ++#define DT_SPARC_REGISTER 0x70000001 ++#define DT_SPARC_NUM 2 ++ ++/* MIPS R3000 specific definitions. */ ++ ++/* Legal values for e_flags field of Elf32_Ehdr. */ ++ ++#define EF_MIPS_NOREORDER 1 /* A .noreorder directive was used */ ++#define EF_MIPS_PIC 2 /* Contains PIC code */ ++#define EF_MIPS_CPIC 4 /* Uses PIC calling sequence */ ++#define EF_MIPS_XGOT 8 ++#define EF_MIPS_64BIT_WHIRL 16 ++#define EF_MIPS_ABI2 32 ++#define EF_MIPS_ABI_ON32 64 ++#define EF_MIPS_ARCH 0xf0000000 /* MIPS architecture level */ ++ ++/* Legal values for MIPS architecture level. */ ++ ++#define EF_MIPS_ARCH_1 0x00000000 /* -mips1 code. */ ++#define EF_MIPS_ARCH_2 0x10000000 /* -mips2 code. */ ++#define EF_MIPS_ARCH_3 0x20000000 /* -mips3 code. */ ++#define EF_MIPS_ARCH_4 0x30000000 /* -mips4 code. */ ++#define EF_MIPS_ARCH_5 0x40000000 /* -mips5 code. */ ++#define EF_MIPS_ARCH_32 0x60000000 /* MIPS32 code. */ ++#define EF_MIPS_ARCH_64 0x70000000 /* MIPS64 code. */ ++ ++/* The following are non-official names and should not be used. */ ++ ++#define E_MIPS_ARCH_1 0x00000000 /* -mips1 code. */ ++#define E_MIPS_ARCH_2 0x10000000 /* -mips2 code. */ ++#define E_MIPS_ARCH_3 0x20000000 /* -mips3 code. */ ++#define E_MIPS_ARCH_4 0x30000000 /* -mips4 code. */ ++#define E_MIPS_ARCH_5 0x40000000 /* -mips5 code. */ ++#define E_MIPS_ARCH_32 0x60000000 /* MIPS32 code. */ ++#define E_MIPS_ARCH_64 0x70000000 /* MIPS64 code. */ ++ ++/* Special section indices. */ ++ ++#define SHN_MIPS_ACOMMON 0xff00 /* Allocated common symbols */ ++#define SHN_MIPS_TEXT 0xff01 /* Allocated test symbols. */ ++#define SHN_MIPS_DATA 0xff02 /* Allocated data symbols. */ ++#define SHN_MIPS_SCOMMON 0xff03 /* Small common symbols */ ++#define SHN_MIPS_SUNDEFINED 0xff04 /* Small undefined symbols */ ++ ++/* Legal values for sh_type field of Elf32_Shdr. */ ++ ++#define SHT_MIPS_LIBLIST 0x70000000 /* Shared objects used in link */ ++#define SHT_MIPS_MSYM 0x70000001 ++#define SHT_MIPS_CONFLICT 0x70000002 /* Conflicting symbols */ ++#define SHT_MIPS_GPTAB 0x70000003 /* Global data area sizes */ ++#define SHT_MIPS_UCODE 0x70000004 /* Reserved for SGI/MIPS compilers */ ++#define SHT_MIPS_DEBUG 0x70000005 /* MIPS ECOFF debugging information*/ ++#define SHT_MIPS_REGINFO 0x70000006 /* Register usage information */ ++#define SHT_MIPS_PACKAGE 0x70000007 ++#define SHT_MIPS_PACKSYM 0x70000008 ++#define SHT_MIPS_RELD 0x70000009 ++#define SHT_MIPS_IFACE 0x7000000b ++#define SHT_MIPS_CONTENT 0x7000000c ++#define SHT_MIPS_OPTIONS 0x7000000d /* Miscellaneous options. */ ++#define SHT_MIPS_SHDR 0x70000010 ++#define SHT_MIPS_FDESC 0x70000011 ++#define SHT_MIPS_EXTSYM 0x70000012 ++#define SHT_MIPS_DENSE 0x70000013 ++#define SHT_MIPS_PDESC 0x70000014 ++#define SHT_MIPS_LOCSYM 0x70000015 ++#define SHT_MIPS_AUXSYM 0x70000016 ++#define SHT_MIPS_OPTSYM 0x70000017 ++#define SHT_MIPS_LOCSTR 0x70000018 ++#define SHT_MIPS_LINE 0x70000019 ++#define SHT_MIPS_RFDESC 0x7000001a ++#define SHT_MIPS_DELTASYM 0x7000001b ++#define SHT_MIPS_DELTAINST 0x7000001c ++#define SHT_MIPS_DELTACLASS 0x7000001d ++#define SHT_MIPS_DWARF 0x7000001e /* DWARF debugging information. */ ++#define SHT_MIPS_DELTADECL 0x7000001f ++#define SHT_MIPS_SYMBOL_LIB 0x70000020 ++#define SHT_MIPS_EVENTS 0x70000021 /* Event section. */ ++#define SHT_MIPS_TRANSLATE 0x70000022 ++#define SHT_MIPS_PIXIE 0x70000023 ++#define SHT_MIPS_XLATE 0x70000024 ++#define SHT_MIPS_XLATE_DEBUG 0x70000025 ++#define SHT_MIPS_WHIRL 0x70000026 ++#define SHT_MIPS_EH_REGION 0x70000027 ++#define SHT_MIPS_XLATE_OLD 0x70000028 ++#define SHT_MIPS_PDR_EXCEPTION 0x70000029 ++ ++/* Legal values for sh_flags field of Elf32_Shdr. */ ++ ++#define SHF_MIPS_GPREL 0x10000000 /* Must be part of global data area */ ++#define SHF_MIPS_MERGE 0x20000000 ++#define SHF_MIPS_ADDR 0x40000000 ++#define SHF_MIPS_STRINGS 0x80000000 ++#define SHF_MIPS_NOSTRIP 0x08000000 ++#define SHF_MIPS_LOCAL 0x04000000 ++#define SHF_MIPS_NAMES 0x02000000 ++#define SHF_MIPS_NODUPE 0x01000000 ++ ++ ++/* Symbol tables. */ ++ ++/* MIPS specific values for `st_other'. */ ++#define STO_MIPS_DEFAULT 0x0 ++#define STO_MIPS_INTERNAL 0x1 ++#define STO_MIPS_HIDDEN 0x2 ++#define STO_MIPS_PROTECTED 0x3 ++#define STO_MIPS_PLT 0x8 ++#define STO_MIPS_SC_ALIGN_UNUSED 0xff ++ ++/* MIPS specific values for `st_info'. */ ++#define STB_MIPS_SPLIT_COMMON 13 ++ ++/* Entries found in sections of type SHT_MIPS_GPTAB. */ ++ ++typedef union ++{ ++ struct ++ { ++ Elf32_Word gt_current_g_value; /* -G value used for compilation */ ++ Elf32_Word gt_unused; /* Not used */ ++ } gt_header; /* First entry in section */ ++ struct ++ { ++ Elf32_Word gt_g_value; /* If this value were used for -G */ ++ Elf32_Word gt_bytes; /* This many bytes would be used */ ++ } gt_entry; /* Subsequent entries in section */ ++} Elf32_gptab; ++ ++/* Entry found in sections of type SHT_MIPS_REGINFO. */ ++ ++typedef struct ++{ ++ Elf32_Word ri_gprmask; /* General registers used */ ++ Elf32_Word ri_cprmask[4]; /* Coprocessor registers used */ ++ Elf32_Sword ri_gp_value; /* $gp register value */ ++} Elf32_RegInfo; ++ ++/* Entries found in sections of type SHT_MIPS_OPTIONS. */ ++ ++typedef struct ++{ ++ unsigned char kind; /* Determines interpretation of the ++ variable part of descriptor. */ ++ unsigned char size; /* Size of descriptor, including header. */ ++ Elf32_Section section; /* Section header index of section affected, ++ 0 for global options. */ ++ Elf32_Word info; /* Kind-specific information. */ ++} Elf_Options; ++ ++/* Values for `kind' field in Elf_Options. */ ++ ++#define ODK_NULL 0 /* Undefined. */ ++#define ODK_REGINFO 1 /* Register usage information. */ ++#define ODK_EXCEPTIONS 2 /* Exception processing options. */ ++#define ODK_PAD 3 /* Section padding options. */ ++#define ODK_HWPATCH 4 /* Hardware workarounds performed */ ++#define ODK_FILL 5 /* record the fill value used by the linker. */ ++#define ODK_TAGS 6 /* reserve space for desktop tools to write. */ ++#define ODK_HWAND 7 /* HW workarounds. 'AND' bits when merging. */ ++#define ODK_HWOR 8 /* HW workarounds. 'OR' bits when merging. */ ++ ++/* Values for `info' in Elf_Options for ODK_EXCEPTIONS entries. */ ++ ++#define OEX_FPU_MIN 0x1f /* FPE's which MUST be enabled. */ ++#define OEX_FPU_MAX 0x1f00 /* FPE's which MAY be enabled. */ ++#define OEX_PAGE0 0x10000 /* page zero must be mapped. */ ++#define OEX_SMM 0x20000 /* Force sequential memory mode? */ ++#define OEX_FPDBUG 0x40000 /* Force floating point debug mode? */ ++#define OEX_PRECISEFP OEX_FPDBUG ++#define OEX_DISMISS 0x80000 /* Dismiss invalid address faults? */ ++ ++#define OEX_FPU_INVAL 0x10 ++#define OEX_FPU_DIV0 0x08 ++#define OEX_FPU_OFLO 0x04 ++#define OEX_FPU_UFLO 0x02 ++#define OEX_FPU_INEX 0x01 ++ ++/* Masks for `info' in Elf_Options for an ODK_HWPATCH entry. */ ++ ++#define OHW_R4KEOP 0x1 /* R4000 end-of-page patch. */ ++#define OHW_R8KPFETCH 0x2 /* may need R8000 prefetch patch. */ ++#define OHW_R5KEOP 0x4 /* R5000 end-of-page patch. */ ++#define OHW_R5KCVTL 0x8 /* R5000 cvt.[ds].l bug. clean=1. */ ++ ++#define OPAD_PREFIX 0x1 ++#define OPAD_POSTFIX 0x2 ++#define OPAD_SYMBOL 0x4 ++ ++/* Entry found in `.options' section. */ ++ ++typedef struct ++{ ++ Elf32_Word hwp_flags1; /* Extra flags. */ ++ Elf32_Word hwp_flags2; /* Extra flags. */ ++} Elf_Options_Hw; ++ ++/* Masks for `info' in ElfOptions for ODK_HWAND and ODK_HWOR entries. */ ++ ++#define OHWA0_R4KEOP_CHECKED 0x00000001 ++#define OHWA1_R4KEOP_CLEAN 0x00000002 ++ ++/* MIPS relocs. */ ++ ++#define R_MIPS_NONE 0 /* No reloc */ ++#define R_MIPS_16 1 /* Direct 16 bit */ ++#define R_MIPS_32 2 /* Direct 32 bit */ ++#define R_MIPS_REL32 3 /* PC relative 32 bit */ ++#define R_MIPS_26 4 /* Direct 26 bit shifted */ ++#define R_MIPS_HI16 5 /* High 16 bit */ ++#define R_MIPS_LO16 6 /* Low 16 bit */ ++#define R_MIPS_GPREL16 7 /* GP relative 16 bit */ ++#define R_MIPS_LITERAL 8 /* 16 bit literal entry */ ++#define R_MIPS_GOT16 9 /* 16 bit GOT entry */ ++#define R_MIPS_PC16 10 /* PC relative 16 bit */ ++#define R_MIPS_CALL16 11 /* 16 bit GOT entry for function */ ++#define R_MIPS_GPREL32 12 /* GP relative 32 bit */ ++ ++#define R_MIPS_SHIFT5 16 ++#define R_MIPS_SHIFT6 17 ++#define R_MIPS_64 18 ++#define R_MIPS_GOT_DISP 19 ++#define R_MIPS_GOT_PAGE 20 ++#define R_MIPS_GOT_OFST 21 ++#define R_MIPS_GOT_HI16 22 ++#define R_MIPS_GOT_LO16 23 ++#define R_MIPS_SUB 24 ++#define R_MIPS_INSERT_A 25 ++#define R_MIPS_INSERT_B 26 ++#define R_MIPS_DELETE 27 ++#define R_MIPS_HIGHER 28 ++#define R_MIPS_HIGHEST 29 ++#define R_MIPS_CALL_HI16 30 ++#define R_MIPS_CALL_LO16 31 ++#define R_MIPS_SCN_DISP 32 ++#define R_MIPS_REL16 33 ++#define R_MIPS_ADD_IMMEDIATE 34 ++#define R_MIPS_PJUMP 35 ++#define R_MIPS_RELGOT 36 ++#define R_MIPS_JALR 37 ++#define R_MIPS_TLS_DTPMOD32 38 /* Module number 32 bit */ ++#define R_MIPS_TLS_DTPREL32 39 /* Module-relative offset 32 bit */ ++#define R_MIPS_TLS_DTPMOD64 40 /* Module number 64 bit */ ++#define R_MIPS_TLS_DTPREL64 41 /* Module-relative offset 64 bit */ ++#define R_MIPS_TLS_GD 42 /* 16 bit GOT offset for GD */ ++#define R_MIPS_TLS_LDM 43 /* 16 bit GOT offset for LDM */ ++#define R_MIPS_TLS_DTPREL_HI16 44 /* Module-relative offset, high 16 bits */ ++#define R_MIPS_TLS_DTPREL_LO16 45 /* Module-relative offset, low 16 bits */ ++#define R_MIPS_TLS_GOTTPREL 46 /* 16 bit GOT offset for IE */ ++#define R_MIPS_TLS_TPREL32 47 /* TP-relative offset, 32 bit */ ++#define R_MIPS_TLS_TPREL64 48 /* TP-relative offset, 64 bit */ ++#define R_MIPS_TLS_TPREL_HI16 49 /* TP-relative offset, high 16 bits */ ++#define R_MIPS_TLS_TPREL_LO16 50 /* TP-relative offset, low 16 bits */ ++#define R_MIPS_GLOB_DAT 51 ++#define R_MIPS_COPY 126 ++#define R_MIPS_JUMP_SLOT 127 ++/* Keep this the last entry. */ ++#define R_MIPS_NUM 128 ++ ++/* Legal values for p_type field of Elf32_Phdr. */ ++ ++#define PT_MIPS_REGINFO 0x70000000 /* Register usage information */ ++#define PT_MIPS_RTPROC 0x70000001 /* Runtime procedure table. */ ++#define PT_MIPS_OPTIONS 0x70000002 ++ ++/* Special program header types. */ ++ ++#define PF_MIPS_LOCAL 0x10000000 ++ ++/* Legal values for d_tag field of Elf32_Dyn. */ ++ ++#define DT_MIPS_RLD_VERSION 0x70000001 /* Runtime linker interface version */ ++#define DT_MIPS_TIME_STAMP 0x70000002 /* Timestamp */ ++#define DT_MIPS_ICHECKSUM 0x70000003 /* Checksum */ ++#define DT_MIPS_IVERSION 0x70000004 /* Version string (string tbl index) */ ++#define DT_MIPS_FLAGS 0x70000005 /* Flags */ ++#define DT_MIPS_BASE_ADDRESS 0x70000006 /* Base address */ ++#define DT_MIPS_MSYM 0x70000007 ++#define DT_MIPS_CONFLICT 0x70000008 /* Address of CONFLICT section */ ++#define DT_MIPS_LIBLIST 0x70000009 /* Address of LIBLIST section */ ++#define DT_MIPS_LOCAL_GOTNO 0x7000000a /* Number of local GOT entries */ ++#define DT_MIPS_CONFLICTNO 0x7000000b /* Number of CONFLICT entries */ ++#define DT_MIPS_LIBLISTNO 0x70000010 /* Number of LIBLIST entries */ ++#define DT_MIPS_SYMTABNO 0x70000011 /* Number of DYNSYM entries */ ++#define DT_MIPS_UNREFEXTNO 0x70000012 /* First external DYNSYM */ ++#define DT_MIPS_GOTSYM 0x70000013 /* First GOT entry in DYNSYM */ ++#define DT_MIPS_HIPAGENO 0x70000014 /* Number of GOT page table entries */ ++#define DT_MIPS_RLD_MAP 0x70000016 /* Address of run time loader map. */ ++#define DT_MIPS_DELTA_CLASS 0x70000017 /* Delta C++ class definition. */ ++#define DT_MIPS_DELTA_CLASS_NO 0x70000018 /* Number of entries in ++ DT_MIPS_DELTA_CLASS. */ ++#define DT_MIPS_DELTA_INSTANCE 0x70000019 /* Delta C++ class instances. */ ++#define DT_MIPS_DELTA_INSTANCE_NO 0x7000001a /* Number of entries in ++ DT_MIPS_DELTA_INSTANCE. */ ++#define DT_MIPS_DELTA_RELOC 0x7000001b /* Delta relocations. */ ++#define DT_MIPS_DELTA_RELOC_NO 0x7000001c /* Number of entries in ++ DT_MIPS_DELTA_RELOC. */ ++#define DT_MIPS_DELTA_SYM 0x7000001d /* Delta symbols that Delta ++ relocations refer to. */ ++#define DT_MIPS_DELTA_SYM_NO 0x7000001e /* Number of entries in ++ DT_MIPS_DELTA_SYM. */ ++#define DT_MIPS_DELTA_CLASSSYM 0x70000020 /* Delta symbols that hold the ++ class declaration. */ ++#define DT_MIPS_DELTA_CLASSSYM_NO 0x70000021 /* Number of entries in ++ DT_MIPS_DELTA_CLASSSYM. */ ++#define DT_MIPS_CXX_FLAGS 0x70000022 /* Flags indicating for C++ flavor. */ ++#define DT_MIPS_PIXIE_INIT 0x70000023 ++#define DT_MIPS_SYMBOL_LIB 0x70000024 ++#define DT_MIPS_LOCALPAGE_GOTIDX 0x70000025 ++#define DT_MIPS_LOCAL_GOTIDX 0x70000026 ++#define DT_MIPS_HIDDEN_GOTIDX 0x70000027 ++#define DT_MIPS_PROTECTED_GOTIDX 0x70000028 ++#define DT_MIPS_OPTIONS 0x70000029 /* Address of .options. */ ++#define DT_MIPS_INTERFACE 0x7000002a /* Address of .interface. */ ++#define DT_MIPS_DYNSTR_ALIGN 0x7000002b ++#define DT_MIPS_INTERFACE_SIZE 0x7000002c /* Size of the .interface section. */ ++#define DT_MIPS_RLD_TEXT_RESOLVE_ADDR 0x7000002d /* Address of rld_text_rsolve ++ function stored in GOT. */ ++#define DT_MIPS_PERF_SUFFIX 0x7000002e /* Default suffix of dso to be added ++ by rld on dlopen() calls. */ ++#define DT_MIPS_COMPACT_SIZE 0x7000002f /* (O32)Size of compact rel section. */ ++#define DT_MIPS_GP_VALUE 0x70000030 /* GP value for aux GOTs. */ ++#define DT_MIPS_AUX_DYNAMIC 0x70000031 /* Address of aux .dynamic. */ ++/* The address of .got.plt in an executable using the new non-PIC ABI. */ ++#define DT_MIPS_PLTGOT 0x70000032 ++/* The base of the PLT in an executable using the new non-PIC ABI if that ++ PLT is writable. For a non-writable PLT, this is omitted or has a zero ++ value. */ ++#define DT_MIPS_RWPLT 0x70000034 ++#define DT_MIPS_NUM 0x35 ++ ++/* Legal values for DT_MIPS_FLAGS Elf32_Dyn entry. */ ++ ++#define RHF_NONE 0 /* No flags */ ++#define RHF_QUICKSTART (1 << 0) /* Use quickstart */ ++#define RHF_NOTPOT (1 << 1) /* Hash size not power of 2 */ ++#define RHF_NO_LIBRARY_REPLACEMENT (1 << 2) /* Ignore LD_LIBRARY_PATH */ ++#define RHF_NO_MOVE (1 << 3) ++#define RHF_SGI_ONLY (1 << 4) ++#define RHF_GUARANTEE_INIT (1 << 5) ++#define RHF_DELTA_C_PLUS_PLUS (1 << 6) ++#define RHF_GUARANTEE_START_INIT (1 << 7) ++#define RHF_PIXIE (1 << 8) ++#define RHF_DEFAULT_DELAY_LOAD (1 << 9) ++#define RHF_REQUICKSTART (1 << 10) ++#define RHF_REQUICKSTARTED (1 << 11) ++#define RHF_CORD (1 << 12) ++#define RHF_NO_UNRES_UNDEF (1 << 13) ++#define RHF_RLD_ORDER_SAFE (1 << 14) ++ ++/* Entries found in sections of type SHT_MIPS_LIBLIST. */ ++ ++typedef struct ++{ ++ Elf32_Word l_name; /* Name (string table index) */ ++ Elf32_Word l_time_stamp; /* Timestamp */ ++ Elf32_Word l_checksum; /* Checksum */ ++ Elf32_Word l_version; /* Interface version */ ++ Elf32_Word l_flags; /* Flags */ ++} Elf32_Lib; ++ ++typedef struct ++{ ++ Elf64_Word l_name; /* Name (string table index) */ ++ Elf64_Word l_time_stamp; /* Timestamp */ ++ Elf64_Word l_checksum; /* Checksum */ ++ Elf64_Word l_version; /* Interface version */ ++ Elf64_Word l_flags; /* Flags */ ++} Elf64_Lib; ++ ++ ++/* Legal values for l_flags. */ ++ ++#define LL_NONE 0 ++#define LL_EXACT_MATCH (1 << 0) /* Require exact match */ ++#define LL_IGNORE_INT_VER (1 << 1) /* Ignore interface version */ ++#define LL_REQUIRE_MINOR (1 << 2) ++#define LL_EXPORTS (1 << 3) ++#define LL_DELAY_LOAD (1 << 4) ++#define LL_DELTA (1 << 5) ++ ++/* Entries found in sections of type SHT_MIPS_CONFLICT. */ ++ ++typedef Elf32_Addr Elf32_Conflict; ++ ++ ++/* HPPA specific definitions. */ ++ ++/* Legal values for e_flags field of Elf32_Ehdr. */ ++ ++#define EF_PARISC_TRAPNIL 0x00010000 /* Trap nil pointer dereference. */ ++#define EF_PARISC_EXT 0x00020000 /* Program uses arch. extensions. */ ++#define EF_PARISC_LSB 0x00040000 /* Program expects little endian. */ ++#define EF_PARISC_WIDE 0x00080000 /* Program expects wide mode. */ ++#define EF_PARISC_NO_KABP 0x00100000 /* No kernel assisted branch ++ prediction. */ ++#define EF_PARISC_LAZYSWAP 0x00400000 /* Allow lazy swapping. */ ++#define EF_PARISC_ARCH 0x0000ffff /* Architecture version. */ ++ ++/* Defined values for `e_flags & EF_PARISC_ARCH' are: */ ++ ++#define EFA_PARISC_1_0 0x020b /* PA-RISC 1.0 big-endian. */ ++#define EFA_PARISC_1_1 0x0210 /* PA-RISC 1.1 big-endian. */ ++#define EFA_PARISC_2_0 0x0214 /* PA-RISC 2.0 big-endian. */ ++ ++/* Additional section indeces. */ ++ ++#define SHN_PARISC_ANSI_COMMON 0xff00 /* Section for tenatively declared ++ symbols in ANSI C. */ ++#define SHN_PARISC_HUGE_COMMON 0xff01 /* Common blocks in huge model. */ ++ ++/* Legal values for sh_type field of Elf32_Shdr. */ ++ ++#define SHT_PARISC_EXT 0x70000000 /* Contains product specific ext. */ ++#define SHT_PARISC_UNWIND 0x70000001 /* Unwind information. */ ++#define SHT_PARISC_DOC 0x70000002 /* Debug info for optimized code. */ ++ ++/* Legal values for sh_flags field of Elf32_Shdr. */ ++ ++#define SHF_PARISC_SHORT 0x20000000 /* Section with short addressing. */ ++#define SHF_PARISC_HUGE 0x40000000 /* Section far from gp. */ ++#define SHF_PARISC_SBP 0x80000000 /* Static branch prediction code. */ ++ ++/* Legal values for ST_TYPE subfield of st_info (symbol type). */ ++ ++#define STT_PARISC_MILLICODE 13 /* Millicode function entry point. */ ++ ++#define STT_HP_OPAQUE (STT_LOOS + 0x1) ++#define STT_HP_STUB (STT_LOOS + 0x2) ++ ++/* HPPA relocs. */ ++ ++#define R_PARISC_NONE 0 /* No reloc. */ ++#define R_PARISC_DIR32 1 /* Direct 32-bit reference. */ ++#define R_PARISC_DIR21L 2 /* Left 21 bits of eff. address. */ ++#define R_PARISC_DIR17R 3 /* Right 17 bits of eff. address. */ ++#define R_PARISC_DIR17F 4 /* 17 bits of eff. address. */ ++#define R_PARISC_DIR14R 6 /* Right 14 bits of eff. address. */ ++#define R_PARISC_PCREL32 9 /* 32-bit rel. address. */ ++#define R_PARISC_PCREL21L 10 /* Left 21 bits of rel. address. */ ++#define R_PARISC_PCREL17R 11 /* Right 17 bits of rel. address. */ ++#define R_PARISC_PCREL17F 12 /* 17 bits of rel. address. */ ++#define R_PARISC_PCREL14R 14 /* Right 14 bits of rel. address. */ ++#define R_PARISC_DPREL21L 18 /* Left 21 bits of rel. address. */ ++#define R_PARISC_DPREL14R 22 /* Right 14 bits of rel. address. */ ++#define R_PARISC_GPREL21L 26 /* GP-relative, left 21 bits. */ ++#define R_PARISC_GPREL14R 30 /* GP-relative, right 14 bits. */ ++#define R_PARISC_LTOFF21L 34 /* LT-relative, left 21 bits. */ ++#define R_PARISC_LTOFF14R 38 /* LT-relative, right 14 bits. */ ++#define R_PARISC_SECREL32 41 /* 32 bits section rel. address. */ ++#define R_PARISC_SEGBASE 48 /* No relocation, set segment base. */ ++#define R_PARISC_SEGREL32 49 /* 32 bits segment rel. address. */ ++#define R_PARISC_PLTOFF21L 50 /* PLT rel. address, left 21 bits. */ ++#define R_PARISC_PLTOFF14R 54 /* PLT rel. address, right 14 bits. */ ++#define R_PARISC_LTOFF_FPTR32 57 /* 32 bits LT-rel. function pointer. */ ++#define R_PARISC_LTOFF_FPTR21L 58 /* LT-rel. fct ptr, left 21 bits. */ ++#define R_PARISC_LTOFF_FPTR14R 62 /* LT-rel. fct ptr, right 14 bits. */ ++#define R_PARISC_FPTR64 64 /* 64 bits function address. */ ++#define R_PARISC_PLABEL32 65 /* 32 bits function address. */ ++#define R_PARISC_PLABEL21L 66 /* Left 21 bits of fdesc address. */ ++#define R_PARISC_PLABEL14R 70 /* Right 14 bits of fdesc address. */ ++#define R_PARISC_PCREL64 72 /* 64 bits PC-rel. address. */ ++#define R_PARISC_PCREL22F 74 /* 22 bits PC-rel. address. */ ++#define R_PARISC_PCREL14WR 75 /* PC-rel. address, right 14 bits. */ ++#define R_PARISC_PCREL14DR 76 /* PC rel. address, right 14 bits. */ ++#define R_PARISC_PCREL16F 77 /* 16 bits PC-rel. address. */ ++#define R_PARISC_PCREL16WF 78 /* 16 bits PC-rel. address. */ ++#define R_PARISC_PCREL16DF 79 /* 16 bits PC-rel. address. */ ++#define R_PARISC_DIR64 80 /* 64 bits of eff. address. */ ++#define R_PARISC_DIR14WR 83 /* 14 bits of eff. address. */ ++#define R_PARISC_DIR14DR 84 /* 14 bits of eff. address. */ ++#define R_PARISC_DIR16F 85 /* 16 bits of eff. address. */ ++#define R_PARISC_DIR16WF 86 /* 16 bits of eff. address. */ ++#define R_PARISC_DIR16DF 87 /* 16 bits of eff. address. */ ++#define R_PARISC_GPREL64 88 /* 64 bits of GP-rel. address. */ ++#define R_PARISC_GPREL14WR 91 /* GP-rel. address, right 14 bits. */ ++#define R_PARISC_GPREL14DR 92 /* GP-rel. address, right 14 bits. */ ++#define R_PARISC_GPREL16F 93 /* 16 bits GP-rel. address. */ ++#define R_PARISC_GPREL16WF 94 /* 16 bits GP-rel. address. */ ++#define R_PARISC_GPREL16DF 95 /* 16 bits GP-rel. address. */ ++#define R_PARISC_LTOFF64 96 /* 64 bits LT-rel. address. */ ++#define R_PARISC_LTOFF14WR 99 /* LT-rel. address, right 14 bits. */ ++#define R_PARISC_LTOFF14DR 100 /* LT-rel. address, right 14 bits. */ ++#define R_PARISC_LTOFF16F 101 /* 16 bits LT-rel. address. */ ++#define R_PARISC_LTOFF16WF 102 /* 16 bits LT-rel. address. */ ++#define R_PARISC_LTOFF16DF 103 /* 16 bits LT-rel. address. */ ++#define R_PARISC_SECREL64 104 /* 64 bits section rel. address. */ ++#define R_PARISC_SEGREL64 112 /* 64 bits segment rel. address. */ ++#define R_PARISC_PLTOFF14WR 115 /* PLT-rel. address, right 14 bits. */ ++#define R_PARISC_PLTOFF14DR 116 /* PLT-rel. address, right 14 bits. */ ++#define R_PARISC_PLTOFF16F 117 /* 16 bits LT-rel. address. */ ++#define R_PARISC_PLTOFF16WF 118 /* 16 bits PLT-rel. address. */ ++#define R_PARISC_PLTOFF16DF 119 /* 16 bits PLT-rel. address. */ ++#define R_PARISC_LTOFF_FPTR64 120 /* 64 bits LT-rel. function ptr. */ ++#define R_PARISC_LTOFF_FPTR14WR 123 /* LT-rel. fct. ptr., right 14 bits. */ ++#define R_PARISC_LTOFF_FPTR14DR 124 /* LT-rel. fct. ptr., right 14 bits. */ ++#define R_PARISC_LTOFF_FPTR16F 125 /* 16 bits LT-rel. function ptr. */ ++#define R_PARISC_LTOFF_FPTR16WF 126 /* 16 bits LT-rel. function ptr. */ ++#define R_PARISC_LTOFF_FPTR16DF 127 /* 16 bits LT-rel. function ptr. */ ++#define R_PARISC_LORESERVE 128 ++#define R_PARISC_COPY 128 /* Copy relocation. */ ++#define R_PARISC_IPLT 129 /* Dynamic reloc, imported PLT */ ++#define R_PARISC_EPLT 130 /* Dynamic reloc, exported PLT */ ++#define R_PARISC_TPREL32 153 /* 32 bits TP-rel. address. */ ++#define R_PARISC_TPREL21L 154 /* TP-rel. address, left 21 bits. */ ++#define R_PARISC_TPREL14R 158 /* TP-rel. address, right 14 bits. */ ++#define R_PARISC_LTOFF_TP21L 162 /* LT-TP-rel. address, left 21 bits. */ ++#define R_PARISC_LTOFF_TP14R 166 /* LT-TP-rel. address, right 14 bits.*/ ++#define R_PARISC_LTOFF_TP14F 167 /* 14 bits LT-TP-rel. address. */ ++#define R_PARISC_TPREL64 216 /* 64 bits TP-rel. address. */ ++#define R_PARISC_TPREL14WR 219 /* TP-rel. address, right 14 bits. */ ++#define R_PARISC_TPREL14DR 220 /* TP-rel. address, right 14 bits. */ ++#define R_PARISC_TPREL16F 221 /* 16 bits TP-rel. address. */ ++#define R_PARISC_TPREL16WF 222 /* 16 bits TP-rel. address. */ ++#define R_PARISC_TPREL16DF 223 /* 16 bits TP-rel. address. */ ++#define R_PARISC_LTOFF_TP64 224 /* 64 bits LT-TP-rel. address. */ ++#define R_PARISC_LTOFF_TP14WR 227 /* LT-TP-rel. address, right 14 bits.*/ ++#define R_PARISC_LTOFF_TP14DR 228 /* LT-TP-rel. address, right 14 bits.*/ ++#define R_PARISC_LTOFF_TP16F 229 /* 16 bits LT-TP-rel. address. */ ++#define R_PARISC_LTOFF_TP16WF 230 /* 16 bits LT-TP-rel. address. */ ++#define R_PARISC_LTOFF_TP16DF 231 /* 16 bits LT-TP-rel. address. */ ++#define R_PARISC_GNU_VTENTRY 232 ++#define R_PARISC_GNU_VTINHERIT 233 ++#define R_PARISC_TLS_GD21L 234 /* GD 21-bit left. */ ++#define R_PARISC_TLS_GD14R 235 /* GD 14-bit right. */ ++#define R_PARISC_TLS_GDCALL 236 /* GD call to __t_g_a. */ ++#define R_PARISC_TLS_LDM21L 237 /* LD module 21-bit left. */ ++#define R_PARISC_TLS_LDM14R 238 /* LD module 14-bit right. */ ++#define R_PARISC_TLS_LDMCALL 239 /* LD module call to __t_g_a. */ ++#define R_PARISC_TLS_LDO21L 240 /* LD offset 21-bit left. */ ++#define R_PARISC_TLS_LDO14R 241 /* LD offset 14-bit right. */ ++#define R_PARISC_TLS_DTPMOD32 242 /* DTP module 32-bit. */ ++#define R_PARISC_TLS_DTPMOD64 243 /* DTP module 64-bit. */ ++#define R_PARISC_TLS_DTPOFF32 244 /* DTP offset 32-bit. */ ++#define R_PARISC_TLS_DTPOFF64 245 /* DTP offset 32-bit. */ ++#define R_PARISC_TLS_LE21L R_PARISC_TPREL21L ++#define R_PARISC_TLS_LE14R R_PARISC_TPREL14R ++#define R_PARISC_TLS_IE21L R_PARISC_LTOFF_TP21L ++#define R_PARISC_TLS_IE14R R_PARISC_LTOFF_TP14R ++#define R_PARISC_TLS_TPREL32 R_PARISC_TPREL32 ++#define R_PARISC_TLS_TPREL64 R_PARISC_TPREL64 ++#define R_PARISC_HIRESERVE 255 ++ ++/* Legal values for p_type field of Elf32_Phdr/Elf64_Phdr. */ ++ ++#define PT_HP_TLS (PT_LOOS + 0x0) ++#define PT_HP_CORE_NONE (PT_LOOS + 0x1) ++#define PT_HP_CORE_VERSION (PT_LOOS + 0x2) ++#define PT_HP_CORE_KERNEL (PT_LOOS + 0x3) ++#define PT_HP_CORE_COMM (PT_LOOS + 0x4) ++#define PT_HP_CORE_PROC (PT_LOOS + 0x5) ++#define PT_HP_CORE_LOADABLE (PT_LOOS + 0x6) ++#define PT_HP_CORE_STACK (PT_LOOS + 0x7) ++#define PT_HP_CORE_SHM (PT_LOOS + 0x8) ++#define PT_HP_CORE_MMF (PT_LOOS + 0x9) ++#define PT_HP_PARALLEL (PT_LOOS + 0x10) ++#define PT_HP_FASTBIND (PT_LOOS + 0x11) ++#define PT_HP_OPT_ANNOT (PT_LOOS + 0x12) ++#define PT_HP_HSL_ANNOT (PT_LOOS + 0x13) ++#define PT_HP_STACK (PT_LOOS + 0x14) ++ ++#define PT_PARISC_ARCHEXT 0x70000000 ++#define PT_PARISC_UNWIND 0x70000001 ++ ++/* Legal values for p_flags field of Elf32_Phdr/Elf64_Phdr. */ ++ ++#define PF_PARISC_SBP 0x08000000 ++ ++#define PF_HP_PAGE_SIZE 0x00100000 ++#define PF_HP_FAR_SHARED 0x00200000 ++#define PF_HP_NEAR_SHARED 0x00400000 ++#define PF_HP_CODE 0x01000000 ++#define PF_HP_MODIFY 0x02000000 ++#define PF_HP_LAZYSWAP 0x04000000 ++#define PF_HP_SBP 0x08000000 ++ ++ ++/* Alpha specific definitions. */ ++ ++/* Legal values for e_flags field of Elf64_Ehdr. */ ++ ++#define EF_ALPHA_32BIT 1 /* All addresses must be < 2GB. */ ++#define EF_ALPHA_CANRELAX 2 /* Relocations for relaxing exist. */ ++ ++/* Legal values for sh_type field of Elf64_Shdr. */ ++ ++/* These two are primerily concerned with ECOFF debugging info. */ ++#define SHT_ALPHA_DEBUG 0x70000001 ++#define SHT_ALPHA_REGINFO 0x70000002 ++ ++/* Legal values for sh_flags field of Elf64_Shdr. */ ++ ++#define SHF_ALPHA_GPREL 0x10000000 ++ ++/* Legal values for st_other field of Elf64_Sym. */ ++#define STO_ALPHA_NOPV 0x80 /* No PV required. */ ++#define STO_ALPHA_STD_GPLOAD 0x88 /* PV only used for initial ldgp. */ ++ ++/* Alpha relocs. */ ++ ++#define R_ALPHA_NONE 0 /* No reloc */ ++#define R_ALPHA_REFLONG 1 /* Direct 32 bit */ ++#define R_ALPHA_REFQUAD 2 /* Direct 64 bit */ ++#define R_ALPHA_GPREL32 3 /* GP relative 32 bit */ ++#define R_ALPHA_LITERAL 4 /* GP relative 16 bit w/optimization */ ++#define R_ALPHA_LITUSE 5 /* Optimization hint for LITERAL */ ++#define R_ALPHA_GPDISP 6 /* Add displacement to GP */ ++#define R_ALPHA_BRADDR 7 /* PC+4 relative 23 bit shifted */ ++#define R_ALPHA_HINT 8 /* PC+4 relative 16 bit shifted */ ++#define R_ALPHA_SREL16 9 /* PC relative 16 bit */ ++#define R_ALPHA_SREL32 10 /* PC relative 32 bit */ ++#define R_ALPHA_SREL64 11 /* PC relative 64 bit */ ++#define R_ALPHA_GPRELHIGH 17 /* GP relative 32 bit, high 16 bits */ ++#define R_ALPHA_GPRELLOW 18 /* GP relative 32 bit, low 16 bits */ ++#define R_ALPHA_GPREL16 19 /* GP relative 16 bit */ ++#define R_ALPHA_COPY 24 /* Copy symbol at runtime */ ++#define R_ALPHA_GLOB_DAT 25 /* Create GOT entry */ ++#define R_ALPHA_JMP_SLOT 26 /* Create PLT entry */ ++#define R_ALPHA_RELATIVE 27 /* Adjust by program base */ ++#define R_ALPHA_TLS_GD_HI 28 ++#define R_ALPHA_TLSGD 29 ++#define R_ALPHA_TLS_LDM 30 ++#define R_ALPHA_DTPMOD64 31 ++#define R_ALPHA_GOTDTPREL 32 ++#define R_ALPHA_DTPREL64 33 ++#define R_ALPHA_DTPRELHI 34 ++#define R_ALPHA_DTPRELLO 35 ++#define R_ALPHA_DTPREL16 36 ++#define R_ALPHA_GOTTPREL 37 ++#define R_ALPHA_TPREL64 38 ++#define R_ALPHA_TPRELHI 39 ++#define R_ALPHA_TPRELLO 40 ++#define R_ALPHA_TPREL16 41 ++/* Keep this the last entry. */ ++#define R_ALPHA_NUM 46 ++ ++/* Magic values of the LITUSE relocation addend. */ ++#define LITUSE_ALPHA_ADDR 0 ++#define LITUSE_ALPHA_BASE 1 ++#define LITUSE_ALPHA_BYTOFF 2 ++#define LITUSE_ALPHA_JSR 3 ++#define LITUSE_ALPHA_TLS_GD 4 ++#define LITUSE_ALPHA_TLS_LDM 5 ++ ++/* Legal values for d_tag of Elf64_Dyn. */ ++#define DT_ALPHA_PLTRO (DT_LOPROC + 0) ++#define DT_ALPHA_NUM 1 ++ ++/* PowerPC specific declarations */ ++ ++/* Values for Elf32/64_Ehdr.e_flags. */ ++#define EF_PPC_EMB 0x80000000 /* PowerPC embedded flag */ ++ ++/* Cygnus local bits below */ ++#define EF_PPC_RELOCATABLE 0x00010000 /* PowerPC -mrelocatable flag*/ ++#define EF_PPC_RELOCATABLE_LIB 0x00008000 /* PowerPC -mrelocatable-lib ++ flag */ ++ ++/* PowerPC relocations defined by the ABIs */ ++#define R_PPC_NONE 0 ++#define R_PPC_ADDR32 1 /* 32bit absolute address */ ++#define R_PPC_ADDR24 2 /* 26bit address, 2 bits ignored. */ ++#define R_PPC_ADDR16 3 /* 16bit absolute address */ ++#define R_PPC_ADDR16_LO 4 /* lower 16bit of absolute address */ ++#define R_PPC_ADDR16_HI 5 /* high 16bit of absolute address */ ++#define R_PPC_ADDR16_HA 6 /* adjusted high 16bit */ ++#define R_PPC_ADDR14 7 /* 16bit address, 2 bits ignored */ ++#define R_PPC_ADDR14_BRTAKEN 8 ++#define R_PPC_ADDR14_BRNTAKEN 9 ++#define R_PPC_REL24 10 /* PC relative 26 bit */ ++#define R_PPC_REL14 11 /* PC relative 16 bit */ ++#define R_PPC_REL14_BRTAKEN 12 ++#define R_PPC_REL14_BRNTAKEN 13 ++#define R_PPC_GOT16 14 ++#define R_PPC_GOT16_LO 15 ++#define R_PPC_GOT16_HI 16 ++#define R_PPC_GOT16_HA 17 ++#define R_PPC_PLTREL24 18 ++#define R_PPC_COPY 19 ++#define R_PPC_GLOB_DAT 20 ++#define R_PPC_JMP_SLOT 21 ++#define R_PPC_RELATIVE 22 ++#define R_PPC_LOCAL24PC 23 ++#define R_PPC_UADDR32 24 ++#define R_PPC_UADDR16 25 ++#define R_PPC_REL32 26 ++#define R_PPC_PLT32 27 ++#define R_PPC_PLTREL32 28 ++#define R_PPC_PLT16_LO 29 ++#define R_PPC_PLT16_HI 30 ++#define R_PPC_PLT16_HA 31 ++#define R_PPC_SDAREL16 32 ++#define R_PPC_SECTOFF 33 ++#define R_PPC_SECTOFF_LO 34 ++#define R_PPC_SECTOFF_HI 35 ++#define R_PPC_SECTOFF_HA 36 ++ ++/* PowerPC relocations defined for the TLS access ABI. */ ++#define R_PPC_TLS 67 /* none (sym+add)@tls */ ++#define R_PPC_DTPMOD32 68 /* word32 (sym+add)@dtpmod */ ++#define R_PPC_TPREL16 69 /* half16* (sym+add)@tprel */ ++#define R_PPC_TPREL16_LO 70 /* half16 (sym+add)@tprel@l */ ++#define R_PPC_TPREL16_HI 71 /* half16 (sym+add)@tprel@h */ ++#define R_PPC_TPREL16_HA 72 /* half16 (sym+add)@tprel@ha */ ++#define R_PPC_TPREL32 73 /* word32 (sym+add)@tprel */ ++#define R_PPC_DTPREL16 74 /* half16* (sym+add)@dtprel */ ++#define R_PPC_DTPREL16_LO 75 /* half16 (sym+add)@dtprel@l */ ++#define R_PPC_DTPREL16_HI 76 /* half16 (sym+add)@dtprel@h */ ++#define R_PPC_DTPREL16_HA 77 /* half16 (sym+add)@dtprel@ha */ ++#define R_PPC_DTPREL32 78 /* word32 (sym+add)@dtprel */ ++#define R_PPC_GOT_TLSGD16 79 /* half16* (sym+add)@got@tlsgd */ ++#define R_PPC_GOT_TLSGD16_LO 80 /* half16 (sym+add)@got@tlsgd@l */ ++#define R_PPC_GOT_TLSGD16_HI 81 /* half16 (sym+add)@got@tlsgd@h */ ++#define R_PPC_GOT_TLSGD16_HA 82 /* half16 (sym+add)@got@tlsgd@ha */ ++#define R_PPC_GOT_TLSLD16 83 /* half16* (sym+add)@got@tlsld */ ++#define R_PPC_GOT_TLSLD16_LO 84 /* half16 (sym+add)@got@tlsld@l */ ++#define R_PPC_GOT_TLSLD16_HI 85 /* half16 (sym+add)@got@tlsld@h */ ++#define R_PPC_GOT_TLSLD16_HA 86 /* half16 (sym+add)@got@tlsld@ha */ ++#define R_PPC_GOT_TPREL16 87 /* half16* (sym+add)@got@tprel */ ++#define R_PPC_GOT_TPREL16_LO 88 /* half16 (sym+add)@got@tprel@l */ ++#define R_PPC_GOT_TPREL16_HI 89 /* half16 (sym+add)@got@tprel@h */ ++#define R_PPC_GOT_TPREL16_HA 90 /* half16 (sym+add)@got@tprel@ha */ ++#define R_PPC_GOT_DTPREL16 91 /* half16* (sym+add)@got@dtprel */ ++#define R_PPC_GOT_DTPREL16_LO 92 /* half16* (sym+add)@got@dtprel@l */ ++#define R_PPC_GOT_DTPREL16_HI 93 /* half16* (sym+add)@got@dtprel@h */ ++#define R_PPC_GOT_DTPREL16_HA 94 /* half16* (sym+add)@got@dtprel@ha */ ++ ++/* The remaining relocs are from the Embedded ELF ABI, and are not ++ in the SVR4 ELF ABI. */ ++#define R_PPC_EMB_NADDR32 101 ++#define R_PPC_EMB_NADDR16 102 ++#define R_PPC_EMB_NADDR16_LO 103 ++#define R_PPC_EMB_NADDR16_HI 104 ++#define R_PPC_EMB_NADDR16_HA 105 ++#define R_PPC_EMB_SDAI16 106 ++#define R_PPC_EMB_SDA2I16 107 ++#define R_PPC_EMB_SDA2REL 108 ++#define R_PPC_EMB_SDA21 109 /* 16 bit offset in SDA */ ++#define R_PPC_EMB_MRKREF 110 ++#define R_PPC_EMB_RELSEC16 111 ++#define R_PPC_EMB_RELST_LO 112 ++#define R_PPC_EMB_RELST_HI 113 ++#define R_PPC_EMB_RELST_HA 114 ++#define R_PPC_EMB_BIT_FLD 115 ++#define R_PPC_EMB_RELSDA 116 /* 16 bit relative offset in SDA */ ++ ++/* Diab tool relocations. */ ++#define R_PPC_DIAB_SDA21_LO 180 /* like EMB_SDA21, but lower 16 bit */ ++#define R_PPC_DIAB_SDA21_HI 181 /* like EMB_SDA21, but high 16 bit */ ++#define R_PPC_DIAB_SDA21_HA 182 /* like EMB_SDA21, adjusted high 16 */ ++#define R_PPC_DIAB_RELSDA_LO 183 /* like EMB_RELSDA, but lower 16 bit */ ++#define R_PPC_DIAB_RELSDA_HI 184 /* like EMB_RELSDA, but high 16 bit */ ++#define R_PPC_DIAB_RELSDA_HA 185 /* like EMB_RELSDA, adjusted high 16 */ ++ ++/* GNU extension to support local ifunc. */ ++#define R_PPC_IRELATIVE 248 ++ ++/* GNU relocs used in PIC code sequences. */ ++#define R_PPC_REL16 249 /* half16 (sym+add-.) */ ++#define R_PPC_REL16_LO 250 /* half16 (sym+add-.)@l */ ++#define R_PPC_REL16_HI 251 /* half16 (sym+add-.)@h */ ++#define R_PPC_REL16_HA 252 /* half16 (sym+add-.)@ha */ ++ ++/* This is a phony reloc to handle any old fashioned TOC16 references ++ that may still be in object files. */ ++#define R_PPC_TOC16 255 ++ ++/* PowerPC specific values for the Dyn d_tag field. */ ++#define DT_PPC_GOT (DT_LOPROC + 0) ++#define DT_PPC_NUM 1 ++ ++/* PowerPC64 relocations defined by the ABIs */ ++#define R_PPC64_NONE R_PPC_NONE ++#define R_PPC64_ADDR32 R_PPC_ADDR32 /* 32bit absolute address */ ++#define R_PPC64_ADDR24 R_PPC_ADDR24 /* 26bit address, word aligned */ ++#define R_PPC64_ADDR16 R_PPC_ADDR16 /* 16bit absolute address */ ++#define R_PPC64_ADDR16_LO R_PPC_ADDR16_LO /* lower 16bits of address */ ++#define R_PPC64_ADDR16_HI R_PPC_ADDR16_HI /* high 16bits of address. */ ++#define R_PPC64_ADDR16_HA R_PPC_ADDR16_HA /* adjusted high 16bits. */ ++#define R_PPC64_ADDR14 R_PPC_ADDR14 /* 16bit address, word aligned */ ++#define R_PPC64_ADDR14_BRTAKEN R_PPC_ADDR14_BRTAKEN ++#define R_PPC64_ADDR14_BRNTAKEN R_PPC_ADDR14_BRNTAKEN ++#define R_PPC64_REL24 R_PPC_REL24 /* PC-rel. 26 bit, word aligned */ ++#define R_PPC64_REL14 R_PPC_REL14 /* PC relative 16 bit */ ++#define R_PPC64_REL14_BRTAKEN R_PPC_REL14_BRTAKEN ++#define R_PPC64_REL14_BRNTAKEN R_PPC_REL14_BRNTAKEN ++#define R_PPC64_GOT16 R_PPC_GOT16 ++#define R_PPC64_GOT16_LO R_PPC_GOT16_LO ++#define R_PPC64_GOT16_HI R_PPC_GOT16_HI ++#define R_PPC64_GOT16_HA R_PPC_GOT16_HA ++ ++#define R_PPC64_COPY R_PPC_COPY ++#define R_PPC64_GLOB_DAT R_PPC_GLOB_DAT ++#define R_PPC64_JMP_SLOT R_PPC_JMP_SLOT ++#define R_PPC64_RELATIVE R_PPC_RELATIVE ++ ++#define R_PPC64_UADDR32 R_PPC_UADDR32 ++#define R_PPC64_UADDR16 R_PPC_UADDR16 ++#define R_PPC64_REL32 R_PPC_REL32 ++#define R_PPC64_PLT32 R_PPC_PLT32 ++#define R_PPC64_PLTREL32 R_PPC_PLTREL32 ++#define R_PPC64_PLT16_LO R_PPC_PLT16_LO ++#define R_PPC64_PLT16_HI R_PPC_PLT16_HI ++#define R_PPC64_PLT16_HA R_PPC_PLT16_HA ++ ++#define R_PPC64_SECTOFF R_PPC_SECTOFF ++#define R_PPC64_SECTOFF_LO R_PPC_SECTOFF_LO ++#define R_PPC64_SECTOFF_HI R_PPC_SECTOFF_HI ++#define R_PPC64_SECTOFF_HA R_PPC_SECTOFF_HA ++#define R_PPC64_ADDR30 37 /* word30 (S + A - P) >> 2 */ ++#define R_PPC64_ADDR64 38 /* doubleword64 S + A */ ++#define R_PPC64_ADDR16_HIGHER 39 /* half16 #higher(S + A) */ ++#define R_PPC64_ADDR16_HIGHERA 40 /* half16 #highera(S + A) */ ++#define R_PPC64_ADDR16_HIGHEST 41 /* half16 #highest(S + A) */ ++#define R_PPC64_ADDR16_HIGHESTA 42 /* half16 #highesta(S + A) */ ++#define R_PPC64_UADDR64 43 /* doubleword64 S + A */ ++#define R_PPC64_REL64 44 /* doubleword64 S + A - P */ ++#define R_PPC64_PLT64 45 /* doubleword64 L + A */ ++#define R_PPC64_PLTREL64 46 /* doubleword64 L + A - P */ ++#define R_PPC64_TOC16 47 /* half16* S + A - .TOC */ ++#define R_PPC64_TOC16_LO 48 /* half16 #lo(S + A - .TOC.) */ ++#define R_PPC64_TOC16_HI 49 /* half16 #hi(S + A - .TOC.) */ ++#define R_PPC64_TOC16_HA 50 /* half16 #ha(S + A - .TOC.) */ ++#define R_PPC64_TOC 51 /* doubleword64 .TOC */ ++#define R_PPC64_PLTGOT16 52 /* half16* M + A */ ++#define R_PPC64_PLTGOT16_LO 53 /* half16 #lo(M + A) */ ++#define R_PPC64_PLTGOT16_HI 54 /* half16 #hi(M + A) */ ++#define R_PPC64_PLTGOT16_HA 55 /* half16 #ha(M + A) */ ++ ++#define R_PPC64_ADDR16_DS 56 /* half16ds* (S + A) >> 2 */ ++#define R_PPC64_ADDR16_LO_DS 57 /* half16ds #lo(S + A) >> 2 */ ++#define R_PPC64_GOT16_DS 58 /* half16ds* (G + A) >> 2 */ ++#define R_PPC64_GOT16_LO_DS 59 /* half16ds #lo(G + A) >> 2 */ ++#define R_PPC64_PLT16_LO_DS 60 /* half16ds #lo(L + A) >> 2 */ ++#define R_PPC64_SECTOFF_DS 61 /* half16ds* (R + A) >> 2 */ ++#define R_PPC64_SECTOFF_LO_DS 62 /* half16ds #lo(R + A) >> 2 */ ++#define R_PPC64_TOC16_DS 63 /* half16ds* (S + A - .TOC.) >> 2 */ ++#define R_PPC64_TOC16_LO_DS 64 /* half16ds #lo(S + A - .TOC.) >> 2 */ ++#define R_PPC64_PLTGOT16_DS 65 /* half16ds* (M + A) >> 2 */ ++#define R_PPC64_PLTGOT16_LO_DS 66 /* half16ds #lo(M + A) >> 2 */ ++ ++/* PowerPC64 relocations defined for the TLS access ABI. */ ++#define R_PPC64_TLS 67 /* none (sym+add)@tls */ ++#define R_PPC64_DTPMOD64 68 /* doubleword64 (sym+add)@dtpmod */ ++#define R_PPC64_TPREL16 69 /* half16* (sym+add)@tprel */ ++#define R_PPC64_TPREL16_LO 70 /* half16 (sym+add)@tprel@l */ ++#define R_PPC64_TPREL16_HI 71 /* half16 (sym+add)@tprel@h */ ++#define R_PPC64_TPREL16_HA 72 /* half16 (sym+add)@tprel@ha */ ++#define R_PPC64_TPREL64 73 /* doubleword64 (sym+add)@tprel */ ++#define R_PPC64_DTPREL16 74 /* half16* (sym+add)@dtprel */ ++#define R_PPC64_DTPREL16_LO 75 /* half16 (sym+add)@dtprel@l */ ++#define R_PPC64_DTPREL16_HI 76 /* half16 (sym+add)@dtprel@h */ ++#define R_PPC64_DTPREL16_HA 77 /* half16 (sym+add)@dtprel@ha */ ++#define R_PPC64_DTPREL64 78 /* doubleword64 (sym+add)@dtprel */ ++#define R_PPC64_GOT_TLSGD16 79 /* half16* (sym+add)@got@tlsgd */ ++#define R_PPC64_GOT_TLSGD16_LO 80 /* half16 (sym+add)@got@tlsgd@l */ ++#define R_PPC64_GOT_TLSGD16_HI 81 /* half16 (sym+add)@got@tlsgd@h */ ++#define R_PPC64_GOT_TLSGD16_HA 82 /* half16 (sym+add)@got@tlsgd@ha */ ++#define R_PPC64_GOT_TLSLD16 83 /* half16* (sym+add)@got@tlsld */ ++#define R_PPC64_GOT_TLSLD16_LO 84 /* half16 (sym+add)@got@tlsld@l */ ++#define R_PPC64_GOT_TLSLD16_HI 85 /* half16 (sym+add)@got@tlsld@h */ ++#define R_PPC64_GOT_TLSLD16_HA 86 /* half16 (sym+add)@got@tlsld@ha */ ++#define R_PPC64_GOT_TPREL16_DS 87 /* half16ds* (sym+add)@got@tprel */ ++#define R_PPC64_GOT_TPREL16_LO_DS 88 /* half16ds (sym+add)@got@tprel@l */ ++#define R_PPC64_GOT_TPREL16_HI 89 /* half16 (sym+add)@got@tprel@h */ ++#define R_PPC64_GOT_TPREL16_HA 90 /* half16 (sym+add)@got@tprel@ha */ ++#define R_PPC64_GOT_DTPREL16_DS 91 /* half16ds* (sym+add)@got@dtprel */ ++#define R_PPC64_GOT_DTPREL16_LO_DS 92 /* half16ds (sym+add)@got@dtprel@l */ ++#define R_PPC64_GOT_DTPREL16_HI 93 /* half16 (sym+add)@got@dtprel@h */ ++#define R_PPC64_GOT_DTPREL16_HA 94 /* half16 (sym+add)@got@dtprel@ha */ ++#define R_PPC64_TPREL16_DS 95 /* half16ds* (sym+add)@tprel */ ++#define R_PPC64_TPREL16_LO_DS 96 /* half16ds (sym+add)@tprel@l */ ++#define R_PPC64_TPREL16_HIGHER 97 /* half16 (sym+add)@tprel@higher */ ++#define R_PPC64_TPREL16_HIGHERA 98 /* half16 (sym+add)@tprel@highera */ ++#define R_PPC64_TPREL16_HIGHEST 99 /* half16 (sym+add)@tprel@highest */ ++#define R_PPC64_TPREL16_HIGHESTA 100 /* half16 (sym+add)@tprel@highesta */ ++#define R_PPC64_DTPREL16_DS 101 /* half16ds* (sym+add)@dtprel */ ++#define R_PPC64_DTPREL16_LO_DS 102 /* half16ds (sym+add)@dtprel@l */ ++#define R_PPC64_DTPREL16_HIGHER 103 /* half16 (sym+add)@dtprel@higher */ ++#define R_PPC64_DTPREL16_HIGHERA 104 /* half16 (sym+add)@dtprel@highera */ ++#define R_PPC64_DTPREL16_HIGHEST 105 /* half16 (sym+add)@dtprel@highest */ ++#define R_PPC64_DTPREL16_HIGHESTA 106 /* half16 (sym+add)@dtprel@highesta */ ++ ++/* GNU extension to support local ifunc. */ ++#define R_PPC64_JMP_IREL 247 ++#define R_PPC64_IRELATIVE 248 ++#define R_PPC64_REL16 249 /* half16 (sym+add-.) */ ++#define R_PPC64_REL16_LO 250 /* half16 (sym+add-.)@l */ ++#define R_PPC64_REL16_HI 251 /* half16 (sym+add-.)@h */ ++#define R_PPC64_REL16_HA 252 /* half16 (sym+add-.)@ha */ ++ ++/* PowerPC64 specific values for the Dyn d_tag field. */ ++#define DT_PPC64_GLINK (DT_LOPROC + 0) ++#define DT_PPC64_OPD (DT_LOPROC + 1) ++#define DT_PPC64_OPDSZ (DT_LOPROC + 2) ++#define DT_PPC64_NUM 3 ++ ++ ++/* ARM specific declarations */ ++ ++/* Processor specific flags for the ELF header e_flags field. */ ++#define EF_ARM_RELEXEC 0x01 ++#define EF_ARM_HASENTRY 0x02 ++#define EF_ARM_INTERWORK 0x04 ++#define EF_ARM_APCS_26 0x08 ++#define EF_ARM_APCS_FLOAT 0x10 ++#define EF_ARM_PIC 0x20 ++#define EF_ARM_ALIGN8 0x40 /* 8-bit structure alignment is in use */ ++#define EF_ARM_NEW_ABI 0x80 ++#define EF_ARM_OLD_ABI 0x100 ++#define EF_ARM_SOFT_FLOAT 0x200 ++#define EF_ARM_VFP_FLOAT 0x400 ++#define EF_ARM_MAVERICK_FLOAT 0x800 ++ ++ ++/* Other constants defined in the ARM ELF spec. version B-01. */ ++/* NB. These conflict with values defined above. */ ++#define EF_ARM_SYMSARESORTED 0x04 ++#define EF_ARM_DYNSYMSUSESEGIDX 0x08 ++#define EF_ARM_MAPSYMSFIRST 0x10 ++#define EF_ARM_EABIMASK 0XFF000000 ++ ++/* Constants defined in AAELF. */ ++#define EF_ARM_BE8 0x00800000 ++#define EF_ARM_LE8 0x00400000 ++ ++#define EF_ARM_EABI_VERSION(flags) ((flags) & EF_ARM_EABIMASK) ++#define EF_ARM_EABI_UNKNOWN 0x00000000 ++#define EF_ARM_EABI_VER1 0x01000000 ++#define EF_ARM_EABI_VER2 0x02000000 ++#define EF_ARM_EABI_VER3 0x03000000 ++#define EF_ARM_EABI_VER4 0x04000000 ++#define EF_ARM_EABI_VER5 0x05000000 ++ ++/* Additional symbol types for Thumb. */ ++#define STT_ARM_TFUNC STT_LOPROC /* A Thumb function. */ ++#define STT_ARM_16BIT STT_HIPROC /* A Thumb label. */ ++ ++/* ARM-specific values for sh_flags */ ++#define SHF_ARM_ENTRYSECT 0x10000000 /* Section contains an entry point */ ++#define SHF_ARM_COMDEF 0x80000000 /* Section may be multiply defined ++ in the input to a link step. */ ++ ++/* ARM-specific program header flags */ ++#define PF_ARM_SB 0x10000000 /* Segment contains the location ++ addressed by the static base. */ ++#define PF_ARM_PI 0x20000000 /* Position-independent segment. */ ++#define PF_ARM_ABS 0x40000000 /* Absolute segment. */ ++ ++/* Processor specific values for the Phdr p_type field. */ ++#define PT_ARM_EXIDX (PT_LOPROC + 1) /* ARM unwind segment. */ ++ ++/* Processor specific values for the Shdr sh_type field. */ ++#define SHT_ARM_EXIDX (SHT_LOPROC + 1) /* ARM unwind section. */ ++#define SHT_ARM_PREEMPTMAP (SHT_LOPROC + 2) /* Preemption details. */ ++#define SHT_ARM_ATTRIBUTES (SHT_LOPROC + 3) /* ARM attributes section. */ ++ ++ ++/* ARM relocs. */ ++ ++#define R_ARM_NONE 0 /* No reloc */ ++#define R_ARM_PC24 1 /* PC relative 26 bit branch */ ++#define R_ARM_ABS32 2 /* Direct 32 bit */ ++#define R_ARM_REL32 3 /* PC relative 32 bit */ ++#define R_ARM_PC13 4 ++#define R_ARM_ABS16 5 /* Direct 16 bit */ ++#define R_ARM_ABS12 6 /* Direct 12 bit */ ++#define R_ARM_THM_ABS5 7 ++#define R_ARM_ABS8 8 /* Direct 8 bit */ ++#define R_ARM_SBREL32 9 ++#define R_ARM_THM_PC22 10 ++#define R_ARM_THM_PC8 11 ++#define R_ARM_AMP_VCALL9 12 ++#define R_ARM_SWI24 13 /* Obsolete static relocation. */ ++#define R_ARM_TLS_DESC 13 /* Dynamic relocation. */ ++#define R_ARM_THM_SWI8 14 ++#define R_ARM_XPC25 15 ++#define R_ARM_THM_XPC22 16 ++#define R_ARM_TLS_DTPMOD32 17 /* ID of module containing symbol */ ++#define R_ARM_TLS_DTPOFF32 18 /* Offset in TLS block */ ++#define R_ARM_TLS_TPOFF32 19 /* Offset in static TLS block */ ++#define R_ARM_COPY 20 /* Copy symbol at runtime */ ++#define R_ARM_GLOB_DAT 21 /* Create GOT entry */ ++#define R_ARM_JUMP_SLOT 22 /* Create PLT entry */ ++#define R_ARM_RELATIVE 23 /* Adjust by program base */ ++#define R_ARM_GOTOFF 24 /* 32 bit offset to GOT */ ++#define R_ARM_GOTPC 25 /* 32 bit PC relative offset to GOT */ ++#define R_ARM_GOT32 26 /* 32 bit GOT entry */ ++#define R_ARM_PLT32 27 /* 32 bit PLT address */ ++#define R_ARM_ALU_PCREL_7_0 32 ++#define R_ARM_ALU_PCREL_15_8 33 ++#define R_ARM_ALU_PCREL_23_15 34 ++#define R_ARM_LDR_SBREL_11_0 35 ++#define R_ARM_ALU_SBREL_19_12 36 ++#define R_ARM_ALU_SBREL_27_20 37 ++#define R_ARM_TLS_GOTDESC 90 ++#define R_ARM_TLS_CALL 91 ++#define R_ARM_TLS_DESCSEQ 92 ++#define R_ARM_THM_TLS_CALL 93 ++#define R_ARM_GNU_VTENTRY 100 ++#define R_ARM_GNU_VTINHERIT 101 ++#define R_ARM_THM_PC11 102 /* thumb unconditional branch */ ++#define R_ARM_THM_PC9 103 /* thumb conditional branch */ ++#define R_ARM_TLS_GD32 104 /* PC-rel 32 bit for global dynamic ++ thread local data */ ++#define R_ARM_TLS_LDM32 105 /* PC-rel 32 bit for local dynamic ++ thread local data */ ++#define R_ARM_TLS_LDO32 106 /* 32 bit offset relative to TLS ++ block */ ++#define R_ARM_TLS_IE32 107 /* PC-rel 32 bit for GOT entry of ++ static TLS block offset */ ++#define R_ARM_TLS_LE32 108 /* 32 bit offset relative to static ++ TLS block */ ++#define R_ARM_THM_TLS_DESCSEQ 129 ++#define R_ARM_IRELATIVE 160 ++#define R_ARM_RXPC25 249 ++#define R_ARM_RSBREL32 250 ++#define R_ARM_THM_RPC22 251 ++#define R_ARM_RREL32 252 ++#define R_ARM_RABS22 253 ++#define R_ARM_RPC24 254 ++#define R_ARM_RBASE 255 ++/* Keep this the last entry. */ ++#define R_ARM_NUM 256 ++ ++/* IA-64 specific declarations. */ ++ ++/* Processor specific flags for the Ehdr e_flags field. */ ++#define EF_IA_64_MASKOS 0x0000000f /* os-specific flags */ ++#define EF_IA_64_ABI64 0x00000010 /* 64-bit ABI */ ++#define EF_IA_64_ARCH 0xff000000 /* arch. version mask */ ++ ++/* Processor specific values for the Phdr p_type field. */ ++#define PT_IA_64_ARCHEXT (PT_LOPROC + 0) /* arch extension bits */ ++#define PT_IA_64_UNWIND (PT_LOPROC + 1) /* ia64 unwind bits */ ++#define PT_IA_64_HP_OPT_ANOT (PT_LOOS + 0x12) ++#define PT_IA_64_HP_HSL_ANOT (PT_LOOS + 0x13) ++#define PT_IA_64_HP_STACK (PT_LOOS + 0x14) ++ ++/* Processor specific flags for the Phdr p_flags field. */ ++#define PF_IA_64_NORECOV 0x80000000 /* spec insns w/o recovery */ ++ ++/* Processor specific values for the Shdr sh_type field. */ ++#define SHT_IA_64_EXT (SHT_LOPROC + 0) /* extension bits */ ++#define SHT_IA_64_UNWIND (SHT_LOPROC + 1) /* unwind bits */ ++ ++/* Processor specific flags for the Shdr sh_flags field. */ ++#define SHF_IA_64_SHORT 0x10000000 /* section near gp */ ++#define SHF_IA_64_NORECOV 0x20000000 /* spec insns w/o recovery */ ++ ++/* Processor specific values for the Dyn d_tag field. */ ++#define DT_IA_64_PLT_RESERVE (DT_LOPROC + 0) ++#define DT_IA_64_NUM 1 ++ ++/* IA-64 relocations. */ ++#define R_IA64_NONE 0x00 /* none */ ++#define R_IA64_IMM14 0x21 /* symbol + addend, add imm14 */ ++#define R_IA64_IMM22 0x22 /* symbol + addend, add imm22 */ ++#define R_IA64_IMM64 0x23 /* symbol + addend, mov imm64 */ ++#define R_IA64_DIR32MSB 0x24 /* symbol + addend, data4 MSB */ ++#define R_IA64_DIR32LSB 0x25 /* symbol + addend, data4 LSB */ ++#define R_IA64_DIR64MSB 0x26 /* symbol + addend, data8 MSB */ ++#define R_IA64_DIR64LSB 0x27 /* symbol + addend, data8 LSB */ ++#define R_IA64_GPREL22 0x2a /* @gprel(sym + add), add imm22 */ ++#define R_IA64_GPREL64I 0x2b /* @gprel(sym + add), mov imm64 */ ++#define R_IA64_GPREL32MSB 0x2c /* @gprel(sym + add), data4 MSB */ ++#define R_IA64_GPREL32LSB 0x2d /* @gprel(sym + add), data4 LSB */ ++#define R_IA64_GPREL64MSB 0x2e /* @gprel(sym + add), data8 MSB */ ++#define R_IA64_GPREL64LSB 0x2f /* @gprel(sym + add), data8 LSB */ ++#define R_IA64_LTOFF22 0x32 /* @ltoff(sym + add), add imm22 */ ++#define R_IA64_LTOFF64I 0x33 /* @ltoff(sym + add), mov imm64 */ ++#define R_IA64_PLTOFF22 0x3a /* @pltoff(sym + add), add imm22 */ ++#define R_IA64_PLTOFF64I 0x3b /* @pltoff(sym + add), mov imm64 */ ++#define R_IA64_PLTOFF64MSB 0x3e /* @pltoff(sym + add), data8 MSB */ ++#define R_IA64_PLTOFF64LSB 0x3f /* @pltoff(sym + add), data8 LSB */ ++#define R_IA64_FPTR64I 0x43 /* @fptr(sym + add), mov imm64 */ ++#define R_IA64_FPTR32MSB 0x44 /* @fptr(sym + add), data4 MSB */ ++#define R_IA64_FPTR32LSB 0x45 /* @fptr(sym + add), data4 LSB */ ++#define R_IA64_FPTR64MSB 0x46 /* @fptr(sym + add), data8 MSB */ ++#define R_IA64_FPTR64LSB 0x47 /* @fptr(sym + add), data8 LSB */ ++#define R_IA64_PCREL60B 0x48 /* @pcrel(sym + add), brl */ ++#define R_IA64_PCREL21B 0x49 /* @pcrel(sym + add), ptb, call */ ++#define R_IA64_PCREL21M 0x4a /* @pcrel(sym + add), chk.s */ ++#define R_IA64_PCREL21F 0x4b /* @pcrel(sym + add), fchkf */ ++#define R_IA64_PCREL32MSB 0x4c /* @pcrel(sym + add), data4 MSB */ ++#define R_IA64_PCREL32LSB 0x4d /* @pcrel(sym + add), data4 LSB */ ++#define R_IA64_PCREL64MSB 0x4e /* @pcrel(sym + add), data8 MSB */ ++#define R_IA64_PCREL64LSB 0x4f /* @pcrel(sym + add), data8 LSB */ ++#define R_IA64_LTOFF_FPTR22 0x52 /* @ltoff(@fptr(s+a)), imm22 */ ++#define R_IA64_LTOFF_FPTR64I 0x53 /* @ltoff(@fptr(s+a)), imm64 */ ++#define R_IA64_LTOFF_FPTR32MSB 0x54 /* @ltoff(@fptr(s+a)), data4 MSB */ ++#define R_IA64_LTOFF_FPTR32LSB 0x55 /* @ltoff(@fptr(s+a)), data4 LSB */ ++#define R_IA64_LTOFF_FPTR64MSB 0x56 /* @ltoff(@fptr(s+a)), data8 MSB */ ++#define R_IA64_LTOFF_FPTR64LSB 0x57 /* @ltoff(@fptr(s+a)), data8 LSB */ ++#define R_IA64_SEGREL32MSB 0x5c /* @segrel(sym + add), data4 MSB */ ++#define R_IA64_SEGREL32LSB 0x5d /* @segrel(sym + add), data4 LSB */ ++#define R_IA64_SEGREL64MSB 0x5e /* @segrel(sym + add), data8 MSB */ ++#define R_IA64_SEGREL64LSB 0x5f /* @segrel(sym + add), data8 LSB */ ++#define R_IA64_SECREL32MSB 0x64 /* @secrel(sym + add), data4 MSB */ ++#define R_IA64_SECREL32LSB 0x65 /* @secrel(sym + add), data4 LSB */ ++#define R_IA64_SECREL64MSB 0x66 /* @secrel(sym + add), data8 MSB */ ++#define R_IA64_SECREL64LSB 0x67 /* @secrel(sym + add), data8 LSB */ ++#define R_IA64_REL32MSB 0x6c /* data 4 + REL */ ++#define R_IA64_REL32LSB 0x6d /* data 4 + REL */ ++#define R_IA64_REL64MSB 0x6e /* data 8 + REL */ ++#define R_IA64_REL64LSB 0x6f /* data 8 + REL */ ++#define R_IA64_LTV32MSB 0x74 /* symbol + addend, data4 MSB */ ++#define R_IA64_LTV32LSB 0x75 /* symbol + addend, data4 LSB */ ++#define R_IA64_LTV64MSB 0x76 /* symbol + addend, data8 MSB */ ++#define R_IA64_LTV64LSB 0x77 /* symbol + addend, data8 LSB */ ++#define R_IA64_PCREL21BI 0x79 /* @pcrel(sym + add), 21bit inst */ ++#define R_IA64_PCREL22 0x7a /* @pcrel(sym + add), 22bit inst */ ++#define R_IA64_PCREL64I 0x7b /* @pcrel(sym + add), 64bit inst */ ++#define R_IA64_IPLTMSB 0x80 /* dynamic reloc, imported PLT, MSB */ ++#define R_IA64_IPLTLSB 0x81 /* dynamic reloc, imported PLT, LSB */ ++#define R_IA64_COPY 0x84 /* copy relocation */ ++#define R_IA64_SUB 0x85 /* Addend and symbol difference */ ++#define R_IA64_LTOFF22X 0x86 /* LTOFF22, relaxable. */ ++#define R_IA64_LDXMOV 0x87 /* Use of LTOFF22X. */ ++#define R_IA64_TPREL14 0x91 /* @tprel(sym + add), imm14 */ ++#define R_IA64_TPREL22 0x92 /* @tprel(sym + add), imm22 */ ++#define R_IA64_TPREL64I 0x93 /* @tprel(sym + add), imm64 */ ++#define R_IA64_TPREL64MSB 0x96 /* @tprel(sym + add), data8 MSB */ ++#define R_IA64_TPREL64LSB 0x97 /* @tprel(sym + add), data8 LSB */ ++#define R_IA64_LTOFF_TPREL22 0x9a /* @ltoff(@tprel(s+a)), imm2 */ ++#define R_IA64_DTPMOD64MSB 0xa6 /* @dtpmod(sym + add), data8 MSB */ ++#define R_IA64_DTPMOD64LSB 0xa7 /* @dtpmod(sym + add), data8 LSB */ ++#define R_IA64_LTOFF_DTPMOD22 0xaa /* @ltoff(@dtpmod(sym + add)), imm22 */ ++#define R_IA64_DTPREL14 0xb1 /* @dtprel(sym + add), imm14 */ ++#define R_IA64_DTPREL22 0xb2 /* @dtprel(sym + add), imm22 */ ++#define R_IA64_DTPREL64I 0xb3 /* @dtprel(sym + add), imm64 */ ++#define R_IA64_DTPREL32MSB 0xb4 /* @dtprel(sym + add), data4 MSB */ ++#define R_IA64_DTPREL32LSB 0xb5 /* @dtprel(sym + add), data4 LSB */ ++#define R_IA64_DTPREL64MSB 0xb6 /* @dtprel(sym + add), data8 MSB */ ++#define R_IA64_DTPREL64LSB 0xb7 /* @dtprel(sym + add), data8 LSB */ ++#define R_IA64_LTOFF_DTPREL22 0xba /* @ltoff(@dtprel(s+a)), imm22 */ ++ ++/* SH specific declarations */ ++ ++/* Processor specific flags for the ELF header e_flags field. */ ++#define EF_SH_MACH_MASK 0x1f ++#define EF_SH_UNKNOWN 0x0 ++#define EF_SH1 0x1 ++#define EF_SH2 0x2 ++#define EF_SH3 0x3 ++#define EF_SH_DSP 0x4 ++#define EF_SH3_DSP 0x5 ++#define EF_SH4AL_DSP 0x6 ++#define EF_SH3E 0x8 ++#define EF_SH4 0x9 ++#define EF_SH2E 0xb ++#define EF_SH4A 0xc ++#define EF_SH2A 0xd ++#define EF_SH4_NOFPU 0x10 ++#define EF_SH4A_NOFPU 0x11 ++#define EF_SH4_NOMMU_NOFPU 0x12 ++#define EF_SH2A_NOFPU 0x13 ++#define EF_SH3_NOMMU 0x14 ++#define EF_SH2A_SH4_NOFPU 0x15 ++#define EF_SH2A_SH3_NOFPU 0x16 ++#define EF_SH2A_SH4 0x17 ++#define EF_SH2A_SH3E 0x18 ++ ++/* SH relocs. */ ++#define R_SH_NONE 0 ++#define R_SH_DIR32 1 ++#define R_SH_REL32 2 ++#define R_SH_DIR8WPN 3 ++#define R_SH_IND12W 4 ++#define R_SH_DIR8WPL 5 ++#define R_SH_DIR8WPZ 6 ++#define R_SH_DIR8BP 7 ++#define R_SH_DIR8W 8 ++#define R_SH_DIR8L 9 ++#define R_SH_SWITCH16 25 ++#define R_SH_SWITCH32 26 ++#define R_SH_USES 27 ++#define R_SH_COUNT 28 ++#define R_SH_ALIGN 29 ++#define R_SH_CODE 30 ++#define R_SH_DATA 31 ++#define R_SH_LABEL 32 ++#define R_SH_SWITCH8 33 ++#define R_SH_GNU_VTINHERIT 34 ++#define R_SH_GNU_VTENTRY 35 ++#define R_SH_TLS_GD_32 144 ++#define R_SH_TLS_LD_32 145 ++#define R_SH_TLS_LDO_32 146 ++#define R_SH_TLS_IE_32 147 ++#define R_SH_TLS_LE_32 148 ++#define R_SH_TLS_DTPMOD32 149 ++#define R_SH_TLS_DTPOFF32 150 ++#define R_SH_TLS_TPOFF32 151 ++#define R_SH_GOT32 160 ++#define R_SH_PLT32 161 ++#define R_SH_COPY 162 ++#define R_SH_GLOB_DAT 163 ++#define R_SH_JMP_SLOT 164 ++#define R_SH_RELATIVE 165 ++#define R_SH_GOTOFF 166 ++#define R_SH_GOTPC 167 ++/* Keep this the last entry. */ ++#define R_SH_NUM 256 ++ ++/* S/390 specific definitions. */ ++ ++/* Valid values for the e_flags field. */ ++ ++#define EF_S390_HIGH_GPRS 0x00000001 /* High GPRs kernel facility needed. */ ++ ++/* Additional s390 relocs */ ++ ++#define R_390_NONE 0 /* No reloc. */ ++#define R_390_8 1 /* Direct 8 bit. */ ++#define R_390_12 2 /* Direct 12 bit. */ ++#define R_390_16 3 /* Direct 16 bit. */ ++#define R_390_32 4 /* Direct 32 bit. */ ++#define R_390_PC32 5 /* PC relative 32 bit. */ ++#define R_390_GOT12 6 /* 12 bit GOT offset. */ ++#define R_390_GOT32 7 /* 32 bit GOT offset. */ ++#define R_390_PLT32 8 /* 32 bit PC relative PLT address. */ ++#define R_390_COPY 9 /* Copy symbol at runtime. */ ++#define R_390_GLOB_DAT 10 /* Create GOT entry. */ ++#define R_390_JMP_SLOT 11 /* Create PLT entry. */ ++#define R_390_RELATIVE 12 /* Adjust by program base. */ ++#define R_390_GOTOFF32 13 /* 32 bit offset to GOT. */ ++#define R_390_GOTPC 14 /* 32 bit PC relative offset to GOT. */ ++#define R_390_GOT16 15 /* 16 bit GOT offset. */ ++#define R_390_PC16 16 /* PC relative 16 bit. */ ++#define R_390_PC16DBL 17 /* PC relative 16 bit shifted by 1. */ ++#define R_390_PLT16DBL 18 /* 16 bit PC rel. PLT shifted by 1. */ ++#define R_390_PC32DBL 19 /* PC relative 32 bit shifted by 1. */ ++#define R_390_PLT32DBL 20 /* 32 bit PC rel. PLT shifted by 1. */ ++#define R_390_GOTPCDBL 21 /* 32 bit PC rel. GOT shifted by 1. */ ++#define R_390_64 22 /* Direct 64 bit. */ ++#define R_390_PC64 23 /* PC relative 64 bit. */ ++#define R_390_GOT64 24 /* 64 bit GOT offset. */ ++#define R_390_PLT64 25 /* 64 bit PC relative PLT address. */ ++#define R_390_GOTENT 26 /* 32 bit PC rel. to GOT entry >> 1. */ ++#define R_390_GOTOFF16 27 /* 16 bit offset to GOT. */ ++#define R_390_GOTOFF64 28 /* 64 bit offset to GOT. */ ++#define R_390_GOTPLT12 29 /* 12 bit offset to jump slot. */ ++#define R_390_GOTPLT16 30 /* 16 bit offset to jump slot. */ ++#define R_390_GOTPLT32 31 /* 32 bit offset to jump slot. */ ++#define R_390_GOTPLT64 32 /* 64 bit offset to jump slot. */ ++#define R_390_GOTPLTENT 33 /* 32 bit rel. offset to jump slot. */ ++#define R_390_PLTOFF16 34 /* 16 bit offset from GOT to PLT. */ ++#define R_390_PLTOFF32 35 /* 32 bit offset from GOT to PLT. */ ++#define R_390_PLTOFF64 36 /* 16 bit offset from GOT to PLT. */ ++#define R_390_TLS_LOAD 37 /* Tag for load insn in TLS code. */ ++#define R_390_TLS_GDCALL 38 /* Tag for function call in general ++ dynamic TLS code. */ ++#define R_390_TLS_LDCALL 39 /* Tag for function call in local ++ dynamic TLS code. */ ++#define R_390_TLS_GD32 40 /* Direct 32 bit for general dynamic ++ thread local data. */ ++#define R_390_TLS_GD64 41 /* Direct 64 bit for general dynamic ++ thread local data. */ ++#define R_390_TLS_GOTIE12 42 /* 12 bit GOT offset for static TLS ++ block offset. */ ++#define R_390_TLS_GOTIE32 43 /* 32 bit GOT offset for static TLS ++ block offset. */ ++#define R_390_TLS_GOTIE64 44 /* 64 bit GOT offset for static TLS ++ block offset. */ ++#define R_390_TLS_LDM32 45 /* Direct 32 bit for local dynamic ++ thread local data in LE code. */ ++#define R_390_TLS_LDM64 46 /* Direct 64 bit for local dynamic ++ thread local data in LE code. */ ++#define R_390_TLS_IE32 47 /* 32 bit address of GOT entry for ++ negated static TLS block offset. */ ++#define R_390_TLS_IE64 48 /* 64 bit address of GOT entry for ++ negated static TLS block offset. */ ++#define R_390_TLS_IEENT 49 /* 32 bit rel. offset to GOT entry for ++ negated static TLS block offset. */ ++#define R_390_TLS_LE32 50 /* 32 bit negated offset relative to ++ static TLS block. */ ++#define R_390_TLS_LE64 51 /* 64 bit negated offset relative to ++ static TLS block. */ ++#define R_390_TLS_LDO32 52 /* 32 bit offset relative to TLS ++ block. */ ++#define R_390_TLS_LDO64 53 /* 64 bit offset relative to TLS ++ block. */ ++#define R_390_TLS_DTPMOD 54 /* ID of module containing symbol. */ ++#define R_390_TLS_DTPOFF 55 /* Offset in TLS block. */ ++#define R_390_TLS_TPOFF 56 /* Negated offset in static TLS ++ block. */ ++#define R_390_20 57 /* Direct 20 bit. */ ++#define R_390_GOT20 58 /* 20 bit GOT offset. */ ++#define R_390_GOTPLT20 59 /* 20 bit offset to jump slot. */ ++#define R_390_TLS_GOTIE20 60 /* 20 bit GOT offset for static TLS ++ block offset. */ ++#define R_390_IRELATIVE 61 /* STT_GNU_IFUNC relocation. */ ++/* Keep this the last entry. */ ++#define R_390_NUM 62 ++ ++ ++/* CRIS relocations. */ ++#define R_CRIS_NONE 0 ++#define R_CRIS_8 1 ++#define R_CRIS_16 2 ++#define R_CRIS_32 3 ++#define R_CRIS_8_PCREL 4 ++#define R_CRIS_16_PCREL 5 ++#define R_CRIS_32_PCREL 6 ++#define R_CRIS_GNU_VTINHERIT 7 ++#define R_CRIS_GNU_VTENTRY 8 ++#define R_CRIS_COPY 9 ++#define R_CRIS_GLOB_DAT 10 ++#define R_CRIS_JUMP_SLOT 11 ++#define R_CRIS_RELATIVE 12 ++#define R_CRIS_16_GOT 13 ++#define R_CRIS_32_GOT 14 ++#define R_CRIS_16_GOTPLT 15 ++#define R_CRIS_32_GOTPLT 16 ++#define R_CRIS_32_GOTREL 17 ++#define R_CRIS_32_PLT_GOTREL 18 ++#define R_CRIS_32_PLT_PCREL 19 ++ ++#define R_CRIS_NUM 20 ++ ++ ++/* AMD x86-64 relocations. */ ++#define R_X86_64_NONE 0 /* No reloc */ ++#define R_X86_64_64 1 /* Direct 64 bit */ ++#define R_X86_64_PC32 2 /* PC relative 32 bit signed */ ++#define R_X86_64_GOT32 3 /* 32 bit GOT entry */ ++#define R_X86_64_PLT32 4 /* 32 bit PLT address */ ++#define R_X86_64_COPY 5 /* Copy symbol at runtime */ ++#define R_X86_64_GLOB_DAT 6 /* Create GOT entry */ ++#define R_X86_64_JUMP_SLOT 7 /* Create PLT entry */ ++#define R_X86_64_RELATIVE 8 /* Adjust by program base */ ++#define R_X86_64_GOTPCREL 9 /* 32 bit signed PC relative ++ offset to GOT */ ++#define R_X86_64_32 10 /* Direct 32 bit zero extended */ ++#define R_X86_64_32S 11 /* Direct 32 bit sign extended */ ++#define R_X86_64_16 12 /* Direct 16 bit zero extended */ ++#define R_X86_64_PC16 13 /* 16 bit sign extended pc relative */ ++#define R_X86_64_8 14 /* Direct 8 bit sign extended */ ++#define R_X86_64_PC8 15 /* 8 bit sign extended pc relative */ ++#define R_X86_64_DTPMOD64 16 /* ID of module containing symbol */ ++#define R_X86_64_DTPOFF64 17 /* Offset in module's TLS block */ ++#define R_X86_64_TPOFF64 18 /* Offset in initial TLS block */ ++#define R_X86_64_TLSGD 19 /* 32 bit signed PC relative offset ++ to two GOT entries for GD symbol */ ++#define R_X86_64_TLSLD 20 /* 32 bit signed PC relative offset ++ to two GOT entries for LD symbol */ ++#define R_X86_64_DTPOFF32 21 /* Offset in TLS block */ ++#define R_X86_64_GOTTPOFF 22 /* 32 bit signed PC relative offset ++ to GOT entry for IE symbol */ ++#define R_X86_64_TPOFF32 23 /* Offset in initial TLS block */ ++#define R_X86_64_PC64 24 /* PC relative 64 bit */ ++#define R_X86_64_GOTOFF64 25 /* 64 bit offset to GOT */ ++#define R_X86_64_GOTPC32 26 /* 32 bit signed pc relative ++ offset to GOT */ ++#define R_X86_64_GOT64 27 /* 64-bit GOT entry offset */ ++#define R_X86_64_GOTPCREL64 28 /* 64-bit PC relative offset ++ to GOT entry */ ++#define R_X86_64_GOTPC64 29 /* 64-bit PC relative offset to GOT */ ++#define R_X86_64_GOTPLT64 30 /* like GOT64, says PLT entry needed */ ++#define R_X86_64_PLTOFF64 31 /* 64-bit GOT relative offset ++ to PLT entry */ ++#define R_X86_64_SIZE32 32 /* Size of symbol plus 32-bit addend */ ++#define R_X86_64_SIZE64 33 /* Size of symbol plus 64-bit addend */ ++#define R_X86_64_GOTPC32_TLSDESC 34 /* GOT offset for TLS descriptor. */ ++#define R_X86_64_TLSDESC_CALL 35 /* Marker for call through TLS ++ descriptor. */ ++#define R_X86_64_TLSDESC 36 /* TLS descriptor. */ ++#define R_X86_64_IRELATIVE 37 /* Adjust indirectly by program base */ ++#define R_X86_64_RELATIVE64 38 /* 64-bit adjust by program base */ ++ ++#define R_X86_64_NUM 39 ++ ++ ++/* AM33 relocations. */ ++#define R_MN10300_NONE 0 /* No reloc. */ ++#define R_MN10300_32 1 /* Direct 32 bit. */ ++#define R_MN10300_16 2 /* Direct 16 bit. */ ++#define R_MN10300_8 3 /* Direct 8 bit. */ ++#define R_MN10300_PCREL32 4 /* PC-relative 32-bit. */ ++#define R_MN10300_PCREL16 5 /* PC-relative 16-bit signed. */ ++#define R_MN10300_PCREL8 6 /* PC-relative 8-bit signed. */ ++#define R_MN10300_GNU_VTINHERIT 7 /* Ancient C++ vtable garbage... */ ++#define R_MN10300_GNU_VTENTRY 8 /* ... collection annotation. */ ++#define R_MN10300_24 9 /* Direct 24 bit. */ ++#define R_MN10300_GOTPC32 10 /* 32-bit PCrel offset to GOT. */ ++#define R_MN10300_GOTPC16 11 /* 16-bit PCrel offset to GOT. */ ++#define R_MN10300_GOTOFF32 12 /* 32-bit offset from GOT. */ ++#define R_MN10300_GOTOFF24 13 /* 24-bit offset from GOT. */ ++#define R_MN10300_GOTOFF16 14 /* 16-bit offset from GOT. */ ++#define R_MN10300_PLT32 15 /* 32-bit PCrel to PLT entry. */ ++#define R_MN10300_PLT16 16 /* 16-bit PCrel to PLT entry. */ ++#define R_MN10300_GOT32 17 /* 32-bit offset to GOT entry. */ ++#define R_MN10300_GOT24 18 /* 24-bit offset to GOT entry. */ ++#define R_MN10300_GOT16 19 /* 16-bit offset to GOT entry. */ ++#define R_MN10300_COPY 20 /* Copy symbol at runtime. */ ++#define R_MN10300_GLOB_DAT 21 /* Create GOT entry. */ ++#define R_MN10300_JMP_SLOT 22 /* Create PLT entry. */ ++#define R_MN10300_RELATIVE 23 /* Adjust by program base. */ ++ ++#define R_MN10300_NUM 24 ++ ++ ++/* M32R relocs. */ ++#define R_M32R_NONE 0 /* No reloc. */ ++#define R_M32R_16 1 /* Direct 16 bit. */ ++#define R_M32R_32 2 /* Direct 32 bit. */ ++#define R_M32R_24 3 /* Direct 24 bit. */ ++#define R_M32R_10_PCREL 4 /* PC relative 10 bit shifted. */ ++#define R_M32R_18_PCREL 5 /* PC relative 18 bit shifted. */ ++#define R_M32R_26_PCREL 6 /* PC relative 26 bit shifted. */ ++#define R_M32R_HI16_ULO 7 /* High 16 bit with unsigned low. */ ++#define R_M32R_HI16_SLO 8 /* High 16 bit with signed low. */ ++#define R_M32R_LO16 9 /* Low 16 bit. */ ++#define R_M32R_SDA16 10 /* 16 bit offset in SDA. */ ++#define R_M32R_GNU_VTINHERIT 11 ++#define R_M32R_GNU_VTENTRY 12 ++/* M32R relocs use SHT_RELA. */ ++#define R_M32R_16_RELA 33 /* Direct 16 bit. */ ++#define R_M32R_32_RELA 34 /* Direct 32 bit. */ ++#define R_M32R_24_RELA 35 /* Direct 24 bit. */ ++#define R_M32R_10_PCREL_RELA 36 /* PC relative 10 bit shifted. */ ++#define R_M32R_18_PCREL_RELA 37 /* PC relative 18 bit shifted. */ ++#define R_M32R_26_PCREL_RELA 38 /* PC relative 26 bit shifted. */ ++#define R_M32R_HI16_ULO_RELA 39 /* High 16 bit with unsigned low */ ++#define R_M32R_HI16_SLO_RELA 40 /* High 16 bit with signed low */ ++#define R_M32R_LO16_RELA 41 /* Low 16 bit */ ++#define R_M32R_SDA16_RELA 42 /* 16 bit offset in SDA */ ++#define R_M32R_RELA_GNU_VTINHERIT 43 ++#define R_M32R_RELA_GNU_VTENTRY 44 ++#define R_M32R_REL32 45 /* PC relative 32 bit. */ ++ ++#define R_M32R_GOT24 48 /* 24 bit GOT entry */ ++#define R_M32R_26_PLTREL 49 /* 26 bit PC relative to PLT shifted */ ++#define R_M32R_COPY 50 /* Copy symbol at runtime */ ++#define R_M32R_GLOB_DAT 51 /* Create GOT entry */ ++#define R_M32R_JMP_SLOT 52 /* Create PLT entry */ ++#define R_M32R_RELATIVE 53 /* Adjust by program base */ ++#define R_M32R_GOTOFF 54 /* 24 bit offset to GOT */ ++#define R_M32R_GOTPC24 55 /* 24 bit PC relative offset to GOT */ ++#define R_M32R_GOT16_HI_ULO 56 /* High 16 bit GOT entry with unsigned ++ low */ ++#define R_M32R_GOT16_HI_SLO 57 /* High 16 bit GOT entry with signed ++ low */ ++#define R_M32R_GOT16_LO 58 /* Low 16 bit GOT entry */ ++#define R_M32R_GOTPC_HI_ULO 59 /* High 16 bit PC relative offset to ++ GOT with unsigned low */ ++#define R_M32R_GOTPC_HI_SLO 60 /* High 16 bit PC relative offset to ++ GOT with signed low */ ++#define R_M32R_GOTPC_LO 61 /* Low 16 bit PC relative offset to ++ GOT */ ++#define R_M32R_GOTOFF_HI_ULO 62 /* High 16 bit offset to GOT ++ with unsigned low */ ++#define R_M32R_GOTOFF_HI_SLO 63 /* High 16 bit offset to GOT ++ with signed low */ ++#define R_M32R_GOTOFF_LO 64 /* Low 16 bit offset to GOT */ ++#define R_M32R_NUM 256 /* Keep this the last entry. */ ++ ++ ++/* TILEPro relocations. */ ++#define R_TILEPRO_NONE 0 /* No reloc */ ++#define R_TILEPRO_32 1 /* Direct 32 bit */ ++#define R_TILEPRO_16 2 /* Direct 16 bit */ ++#define R_TILEPRO_8 3 /* Direct 8 bit */ ++#define R_TILEPRO_32_PCREL 4 /* PC relative 32 bit */ ++#define R_TILEPRO_16_PCREL 5 /* PC relative 16 bit */ ++#define R_TILEPRO_8_PCREL 6 /* PC relative 8 bit */ ++#define R_TILEPRO_LO16 7 /* Low 16 bit */ ++#define R_TILEPRO_HI16 8 /* High 16 bit */ ++#define R_TILEPRO_HA16 9 /* High 16 bit, adjusted */ ++#define R_TILEPRO_COPY 10 /* Copy relocation */ ++#define R_TILEPRO_GLOB_DAT 11 /* Create GOT entry */ ++#define R_TILEPRO_JMP_SLOT 12 /* Create PLT entry */ ++#define R_TILEPRO_RELATIVE 13 /* Adjust by program base */ ++#define R_TILEPRO_BROFF_X1 14 /* X1 pipe branch offset */ ++#define R_TILEPRO_JOFFLONG_X1 15 /* X1 pipe jump offset */ ++#define R_TILEPRO_JOFFLONG_X1_PLT 16 /* X1 pipe jump offset to PLT */ ++#define R_TILEPRO_IMM8_X0 17 /* X0 pipe 8-bit */ ++#define R_TILEPRO_IMM8_Y0 18 /* Y0 pipe 8-bit */ ++#define R_TILEPRO_IMM8_X1 19 /* X1 pipe 8-bit */ ++#define R_TILEPRO_IMM8_Y1 20 /* Y1 pipe 8-bit */ ++#define R_TILEPRO_MT_IMM15_X1 21 /* X1 pipe mtspr */ ++#define R_TILEPRO_MF_IMM15_X1 22 /* X1 pipe mfspr */ ++#define R_TILEPRO_IMM16_X0 23 /* X0 pipe 16-bit */ ++#define R_TILEPRO_IMM16_X1 24 /* X1 pipe 16-bit */ ++#define R_TILEPRO_IMM16_X0_LO 25 /* X0 pipe low 16-bit */ ++#define R_TILEPRO_IMM16_X1_LO 26 /* X1 pipe low 16-bit */ ++#define R_TILEPRO_IMM16_X0_HI 27 /* X0 pipe high 16-bit */ ++#define R_TILEPRO_IMM16_X1_HI 28 /* X1 pipe high 16-bit */ ++#define R_TILEPRO_IMM16_X0_HA 29 /* X0 pipe high 16-bit, adjusted */ ++#define R_TILEPRO_IMM16_X1_HA 30 /* X1 pipe high 16-bit, adjusted */ ++#define R_TILEPRO_IMM16_X0_PCREL 31 /* X0 pipe PC relative 16 bit */ ++#define R_TILEPRO_IMM16_X1_PCREL 32 /* X1 pipe PC relative 16 bit */ ++#define R_TILEPRO_IMM16_X0_LO_PCREL 33 /* X0 pipe PC relative low 16 bit */ ++#define R_TILEPRO_IMM16_X1_LO_PCREL 34 /* X1 pipe PC relative low 16 bit */ ++#define R_TILEPRO_IMM16_X0_HI_PCREL 35 /* X0 pipe PC relative high 16 bit */ ++#define R_TILEPRO_IMM16_X1_HI_PCREL 36 /* X1 pipe PC relative high 16 bit */ ++#define R_TILEPRO_IMM16_X0_HA_PCREL 37 /* X0 pipe PC relative ha() 16 bit */ ++#define R_TILEPRO_IMM16_X1_HA_PCREL 38 /* X1 pipe PC relative ha() 16 bit */ ++#define R_TILEPRO_IMM16_X0_GOT 39 /* X0 pipe 16-bit GOT offset */ ++#define R_TILEPRO_IMM16_X1_GOT 40 /* X1 pipe 16-bit GOT offset */ ++#define R_TILEPRO_IMM16_X0_GOT_LO 41 /* X0 pipe low 16-bit GOT offset */ ++#define R_TILEPRO_IMM16_X1_GOT_LO 42 /* X1 pipe low 16-bit GOT offset */ ++#define R_TILEPRO_IMM16_X0_GOT_HI 43 /* X0 pipe high 16-bit GOT offset */ ++#define R_TILEPRO_IMM16_X1_GOT_HI 44 /* X1 pipe high 16-bit GOT offset */ ++#define R_TILEPRO_IMM16_X0_GOT_HA 45 /* X0 pipe ha() 16-bit GOT offset */ ++#define R_TILEPRO_IMM16_X1_GOT_HA 46 /* X1 pipe ha() 16-bit GOT offset */ ++#define R_TILEPRO_MMSTART_X0 47 /* X0 pipe mm "start" */ ++#define R_TILEPRO_MMEND_X0 48 /* X0 pipe mm "end" */ ++#define R_TILEPRO_MMSTART_X1 49 /* X1 pipe mm "start" */ ++#define R_TILEPRO_MMEND_X1 50 /* X1 pipe mm "end" */ ++#define R_TILEPRO_SHAMT_X0 51 /* X0 pipe shift amount */ ++#define R_TILEPRO_SHAMT_X1 52 /* X1 pipe shift amount */ ++#define R_TILEPRO_SHAMT_Y0 53 /* Y0 pipe shift amount */ ++#define R_TILEPRO_SHAMT_Y1 54 /* Y1 pipe shift amount */ ++#define R_TILEPRO_DEST_IMM8_X1 55 /* X1 pipe destination 8-bit */ ++/* Relocs 56-59 are currently not defined. */ ++#define R_TILEPRO_TLS_GD_CALL 60 /* "jal" for TLS GD */ ++#define R_TILEPRO_IMM8_X0_TLS_GD_ADD 61 /* X0 pipe "addi" for TLS GD */ ++#define R_TILEPRO_IMM8_X1_TLS_GD_ADD 62 /* X1 pipe "addi" for TLS GD */ ++#define R_TILEPRO_IMM8_Y0_TLS_GD_ADD 63 /* Y0 pipe "addi" for TLS GD */ ++#define R_TILEPRO_IMM8_Y1_TLS_GD_ADD 64 /* Y1 pipe "addi" for TLS GD */ ++#define R_TILEPRO_TLS_IE_LOAD 65 /* "lw_tls" for TLS IE */ ++#define R_TILEPRO_IMM16_X0_TLS_GD 66 /* X0 pipe 16-bit TLS GD offset */ ++#define R_TILEPRO_IMM16_X1_TLS_GD 67 /* X1 pipe 16-bit TLS GD offset */ ++#define R_TILEPRO_IMM16_X0_TLS_GD_LO 68 /* X0 pipe low 16-bit TLS GD offset */ ++#define R_TILEPRO_IMM16_X1_TLS_GD_LO 69 /* X1 pipe low 16-bit TLS GD offset */ ++#define R_TILEPRO_IMM16_X0_TLS_GD_HI 70 /* X0 pipe high 16-bit TLS GD offset */ ++#define R_TILEPRO_IMM16_X1_TLS_GD_HI 71 /* X1 pipe high 16-bit TLS GD offset */ ++#define R_TILEPRO_IMM16_X0_TLS_GD_HA 72 /* X0 pipe ha() 16-bit TLS GD offset */ ++#define R_TILEPRO_IMM16_X1_TLS_GD_HA 73 /* X1 pipe ha() 16-bit TLS GD offset */ ++#define R_TILEPRO_IMM16_X0_TLS_IE 74 /* X0 pipe 16-bit TLS IE offset */ ++#define R_TILEPRO_IMM16_X1_TLS_IE 75 /* X1 pipe 16-bit TLS IE offset */ ++#define R_TILEPRO_IMM16_X0_TLS_IE_LO 76 /* X0 pipe low 16-bit TLS IE offset */ ++#define R_TILEPRO_IMM16_X1_TLS_IE_LO 77 /* X1 pipe low 16-bit TLS IE offset */ ++#define R_TILEPRO_IMM16_X0_TLS_IE_HI 78 /* X0 pipe high 16-bit TLS IE offset */ ++#define R_TILEPRO_IMM16_X1_TLS_IE_HI 79 /* X1 pipe high 16-bit TLS IE offset */ ++#define R_TILEPRO_IMM16_X0_TLS_IE_HA 80 /* X0 pipe ha() 16-bit TLS IE offset */ ++#define R_TILEPRO_IMM16_X1_TLS_IE_HA 81 /* X1 pipe ha() 16-bit TLS IE offset */ ++#define R_TILEPRO_TLS_DTPMOD32 82 /* ID of module containing symbol */ ++#define R_TILEPRO_TLS_DTPOFF32 83 /* Offset in TLS block */ ++#define R_TILEPRO_TLS_TPOFF32 84 /* Offset in static TLS block */ ++#define R_TILEPRO_IMM16_X0_TLS_LE 85 /* X0 pipe 16-bit TLS LE offset */ ++#define R_TILEPRO_IMM16_X1_TLS_LE 86 /* X1 pipe 16-bit TLS LE offset */ ++#define R_TILEPRO_IMM16_X0_TLS_LE_LO 87 /* X0 pipe low 16-bit TLS LE offset */ ++#define R_TILEPRO_IMM16_X1_TLS_LE_LO 88 /* X1 pipe low 16-bit TLS LE offset */ ++#define R_TILEPRO_IMM16_X0_TLS_LE_HI 89 /* X0 pipe high 16-bit TLS LE offset */ ++#define R_TILEPRO_IMM16_X1_TLS_LE_HI 90 /* X1 pipe high 16-bit TLS LE offset */ ++#define R_TILEPRO_IMM16_X0_TLS_LE_HA 91 /* X0 pipe ha() 16-bit TLS LE offset */ ++#define R_TILEPRO_IMM16_X1_TLS_LE_HA 92 /* X1 pipe ha() 16-bit TLS LE offset */ ++ ++#define R_TILEPRO_GNU_VTINHERIT 128 /* GNU C++ vtable hierarchy */ ++#define R_TILEPRO_GNU_VTENTRY 129 /* GNU C++ vtable member usage */ ++ ++#define R_TILEPRO_NUM 130 ++ ++ ++/* TILE-Gx relocations. */ ++#define R_TILEGX_NONE 0 /* No reloc */ ++#define R_TILEGX_64 1 /* Direct 64 bit */ ++#define R_TILEGX_32 2 /* Direct 32 bit */ ++#define R_TILEGX_16 3 /* Direct 16 bit */ ++#define R_TILEGX_8 4 /* Direct 8 bit */ ++#define R_TILEGX_64_PCREL 5 /* PC relative 64 bit */ ++#define R_TILEGX_32_PCREL 6 /* PC relative 32 bit */ ++#define R_TILEGX_16_PCREL 7 /* PC relative 16 bit */ ++#define R_TILEGX_8_PCREL 8 /* PC relative 8 bit */ ++#define R_TILEGX_HW0 9 /* hword 0 16-bit */ ++#define R_TILEGX_HW1 10 /* hword 1 16-bit */ ++#define R_TILEGX_HW2 11 /* hword 2 16-bit */ ++#define R_TILEGX_HW3 12 /* hword 3 16-bit */ ++#define R_TILEGX_HW0_LAST 13 /* last hword 0 16-bit */ ++#define R_TILEGX_HW1_LAST 14 /* last hword 1 16-bit */ ++#define R_TILEGX_HW2_LAST 15 /* last hword 2 16-bit */ ++#define R_TILEGX_COPY 16 /* Copy relocation */ ++#define R_TILEGX_GLOB_DAT 17 /* Create GOT entry */ ++#define R_TILEGX_JMP_SLOT 18 /* Create PLT entry */ ++#define R_TILEGX_RELATIVE 19 /* Adjust by program base */ ++#define R_TILEGX_BROFF_X1 20 /* X1 pipe branch offset */ ++#define R_TILEGX_JUMPOFF_X1 21 /* X1 pipe jump offset */ ++#define R_TILEGX_JUMPOFF_X1_PLT 22 /* X1 pipe jump offset to PLT */ ++#define R_TILEGX_IMM8_X0 23 /* X0 pipe 8-bit */ ++#define R_TILEGX_IMM8_Y0 24 /* Y0 pipe 8-bit */ ++#define R_TILEGX_IMM8_X1 25 /* X1 pipe 8-bit */ ++#define R_TILEGX_IMM8_Y1 26 /* Y1 pipe 8-bit */ ++#define R_TILEGX_DEST_IMM8_X1 27 /* X1 pipe destination 8-bit */ ++#define R_TILEGX_MT_IMM14_X1 28 /* X1 pipe mtspr */ ++#define R_TILEGX_MF_IMM14_X1 29 /* X1 pipe mfspr */ ++#define R_TILEGX_MMSTART_X0 30 /* X0 pipe mm "start" */ ++#define R_TILEGX_MMEND_X0 31 /* X0 pipe mm "end" */ ++#define R_TILEGX_SHAMT_X0 32 /* X0 pipe shift amount */ ++#define R_TILEGX_SHAMT_X1 33 /* X1 pipe shift amount */ ++#define R_TILEGX_SHAMT_Y0 34 /* Y0 pipe shift amount */ ++#define R_TILEGX_SHAMT_Y1 35 /* Y1 pipe shift amount */ ++#define R_TILEGX_IMM16_X0_HW0 36 /* X0 pipe hword 0 */ ++#define R_TILEGX_IMM16_X1_HW0 37 /* X1 pipe hword 0 */ ++#define R_TILEGX_IMM16_X0_HW1 38 /* X0 pipe hword 1 */ ++#define R_TILEGX_IMM16_X1_HW1 39 /* X1 pipe hword 1 */ ++#define R_TILEGX_IMM16_X0_HW2 40 /* X0 pipe hword 2 */ ++#define R_TILEGX_IMM16_X1_HW2 41 /* X1 pipe hword 2 */ ++#define R_TILEGX_IMM16_X0_HW3 42 /* X0 pipe hword 3 */ ++#define R_TILEGX_IMM16_X1_HW3 43 /* X1 pipe hword 3 */ ++#define R_TILEGX_IMM16_X0_HW0_LAST 44 /* X0 pipe last hword 0 */ ++#define R_TILEGX_IMM16_X1_HW0_LAST 45 /* X1 pipe last hword 0 */ ++#define R_TILEGX_IMM16_X0_HW1_LAST 46 /* X0 pipe last hword 1 */ ++#define R_TILEGX_IMM16_X1_HW1_LAST 47 /* X1 pipe last hword 1 */ ++#define R_TILEGX_IMM16_X0_HW2_LAST 48 /* X0 pipe last hword 2 */ ++#define R_TILEGX_IMM16_X1_HW2_LAST 49 /* X1 pipe last hword 2 */ ++#define R_TILEGX_IMM16_X0_HW0_PCREL 50 /* X0 pipe PC relative hword 0 */ ++#define R_TILEGX_IMM16_X1_HW0_PCREL 51 /* X1 pipe PC relative hword 0 */ ++#define R_TILEGX_IMM16_X0_HW1_PCREL 52 /* X0 pipe PC relative hword 1 */ ++#define R_TILEGX_IMM16_X1_HW1_PCREL 53 /* X1 pipe PC relative hword 1 */ ++#define R_TILEGX_IMM16_X0_HW2_PCREL 54 /* X0 pipe PC relative hword 2 */ ++#define R_TILEGX_IMM16_X1_HW2_PCREL 55 /* X1 pipe PC relative hword 2 */ ++#define R_TILEGX_IMM16_X0_HW3_PCREL 56 /* X0 pipe PC relative hword 3 */ ++#define R_TILEGX_IMM16_X1_HW3_PCREL 57 /* X1 pipe PC relative hword 3 */ ++#define R_TILEGX_IMM16_X0_HW0_LAST_PCREL 58 /* X0 pipe PC-rel last hword 0 */ ++#define R_TILEGX_IMM16_X1_HW0_LAST_PCREL 59 /* X1 pipe PC-rel last hword 0 */ ++#define R_TILEGX_IMM16_X0_HW1_LAST_PCREL 60 /* X0 pipe PC-rel last hword 1 */ ++#define R_TILEGX_IMM16_X1_HW1_LAST_PCREL 61 /* X1 pipe PC-rel last hword 1 */ ++#define R_TILEGX_IMM16_X0_HW2_LAST_PCREL 62 /* X0 pipe PC-rel last hword 2 */ ++#define R_TILEGX_IMM16_X1_HW2_LAST_PCREL 63 /* X1 pipe PC-rel last hword 2 */ ++#define R_TILEGX_IMM16_X0_HW0_GOT 64 /* X0 pipe hword 0 GOT offset */ ++#define R_TILEGX_IMM16_X1_HW0_GOT 65 /* X1 pipe hword 0 GOT offset */ ++/* Relocs 66-71 are currently not defined. */ ++#define R_TILEGX_IMM16_X0_HW0_LAST_GOT 72 /* X0 pipe last hword 0 GOT offset */ ++#define R_TILEGX_IMM16_X1_HW0_LAST_GOT 73 /* X1 pipe last hword 0 GOT offset */ ++#define R_TILEGX_IMM16_X0_HW1_LAST_GOT 74 /* X0 pipe last hword 1 GOT offset */ ++#define R_TILEGX_IMM16_X1_HW1_LAST_GOT 75 /* X1 pipe last hword 1 GOT offset */ ++/* Relocs 76-77 are currently not defined. */ ++#define R_TILEGX_IMM16_X0_HW0_TLS_GD 78 /* X0 pipe hword 0 TLS GD offset */ ++#define R_TILEGX_IMM16_X1_HW0_TLS_GD 79 /* X1 pipe hword 0 TLS GD offset */ ++#define R_TILEGX_IMM16_X0_HW0_TLS_LE 80 /* X0 pipe hword 0 TLS LE offset */ ++#define R_TILEGX_IMM16_X1_HW0_TLS_LE 81 /* X1 pipe hword 0 TLS LE offset */ ++#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_LE 82 /* X0 pipe last hword 0 LE off */ ++#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_LE 83 /* X1 pipe last hword 0 LE off */ ++#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_LE 84 /* X0 pipe last hword 1 LE off */ ++#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_LE 85 /* X1 pipe last hword 1 LE off */ ++#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD 86 /* X0 pipe last hword 0 GD off */ ++#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD 87 /* X1 pipe last hword 0 GD off */ ++#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD 88 /* X0 pipe last hword 1 GD off */ ++#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD 89 /* X1 pipe last hword 1 GD off */ ++/* Relocs 90-91 are currently not defined. */ ++#define R_TILEGX_IMM16_X0_HW0_TLS_IE 92 /* X0 pipe hword 0 TLS IE offset */ ++#define R_TILEGX_IMM16_X1_HW0_TLS_IE 93 /* X1 pipe hword 0 TLS IE offset */ ++/* Relocs 94-99 are currently not defined. */ ++#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE 100 /* X0 pipe last hword 0 IE off */ ++#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE 101 /* X1 pipe last hword 0 IE off */ ++#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE 102 /* X0 pipe last hword 1 IE off */ ++#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE 103 /* X1 pipe last hword 1 IE off */ ++/* Relocs 104-105 are currently not defined. */ ++#define R_TILEGX_TLS_DTPMOD64 106 /* 64-bit ID of symbol's module */ ++#define R_TILEGX_TLS_DTPOFF64 107 /* 64-bit offset in TLS block */ ++#define R_TILEGX_TLS_TPOFF64 108 /* 64-bit offset in static TLS block */ ++#define R_TILEGX_TLS_DTPMOD32 109 /* 32-bit ID of symbol's module */ ++#define R_TILEGX_TLS_DTPOFF32 110 /* 32-bit offset in TLS block */ ++#define R_TILEGX_TLS_TPOFF32 111 /* 32-bit offset in static TLS block */ ++#define R_TILEGX_TLS_GD_CALL 112 /* "jal" for TLS GD */ ++#define R_TILEGX_IMM8_X0_TLS_GD_ADD 113 /* X0 pipe "addi" for TLS GD */ ++#define R_TILEGX_IMM8_X1_TLS_GD_ADD 114 /* X1 pipe "addi" for TLS GD */ ++#define R_TILEGX_IMM8_Y0_TLS_GD_ADD 115 /* Y0 pipe "addi" for TLS GD */ ++#define R_TILEGX_IMM8_Y1_TLS_GD_ADD 116 /* Y1 pipe "addi" for TLS GD */ ++#define R_TILEGX_TLS_IE_LOAD 117 /* "ld_tls" for TLS IE */ ++#define R_TILEGX_IMM8_X0_TLS_ADD 118 /* X0 pipe "addi" for TLS GD/IE */ ++#define R_TILEGX_IMM8_X1_TLS_ADD 119 /* X1 pipe "addi" for TLS GD/IE */ ++#define R_TILEGX_IMM8_Y0_TLS_ADD 120 /* Y0 pipe "addi" for TLS GD/IE */ ++#define R_TILEGX_IMM8_Y1_TLS_ADD 121 /* Y1 pipe "addi" for TLS GD/IE */ ++ ++#define R_TILEGX_GNU_VTINHERIT 128 /* GNU C++ vtable hierarchy */ ++#define R_TILEGX_GNU_VTENTRY 129 /* GNU C++ vtable member usage */ ++ ++#define R_TILEGX_NUM 130 ++ ++#endif /* elf.h */ diff --git a/target/linux/generic/patches-4.0/212-byteshift_portability.patch b/target/linux/generic/patches-4.0/212-byteshift_portability.patch new file mode 100644 index 0000000..0f23ba9 --- /dev/null +++ b/target/linux/generic/patches-4.0/212-byteshift_portability.patch @@ -0,0 +1,51 @@ +--- a/tools/include/tools/be_byteshift.h ++++ b/tools/include/tools/be_byteshift.h +@@ -1,6 +1,10 @@ + #ifndef _TOOLS_BE_BYTESHIFT_H + #define _TOOLS_BE_BYTESHIFT_H + ++#ifndef __linux__ ++#include "linux_types.h" ++#endif ++ + #include + + static inline uint16_t __get_unaligned_be16(const uint8_t *p) +--- a/tools/include/tools/le_byteshift.h ++++ b/tools/include/tools/le_byteshift.h +@@ -1,6 +1,10 @@ + #ifndef _TOOLS_LE_BYTESHIFT_H + #define _TOOLS_LE_BYTESHIFT_H + ++#ifndef __linux__ ++#include "linux_types.h" ++#endif ++ + #include + + static inline uint16_t __get_unaligned_le16(const uint8_t *p) +--- /dev/null ++++ b/tools/include/tools/linux_types.h +@@ -0,0 +1,22 @@ ++#ifndef __LINUX_TYPES_H ++#define __LINUX_TYPES_H ++ ++#include ++ ++typedef uint8_t __u8; ++typedef uint8_t __be8; ++typedef uint8_t __le8; ++ ++typedef uint16_t __u16; ++typedef uint16_t __be16; ++typedef uint16_t __le16; ++ ++typedef uint32_t __u32; ++typedef uint32_t __be32; ++typedef uint32_t __le32; ++ ++typedef uint64_t __u64; ++typedef uint64_t __be64; ++typedef uint64_t __le64; ++ ++#endif diff --git a/target/linux/generic/patches-4.0/214-spidev_h_portability.patch b/target/linux/generic/patches-4.0/214-spidev_h_portability.patch new file mode 100644 index 0000000..dbee090 --- /dev/null +++ b/target/linux/generic/patches-4.0/214-spidev_h_portability.patch @@ -0,0 +1,11 @@ +--- a/include/uapi/linux/spi/spidev.h ++++ b/include/uapi/linux/spi/spidev.h +@@ -111,7 +111,7 @@ struct spi_ioc_transfer { + + /* not all platforms use or _IOC_TYPECHECK() ... */ + #define SPI_MSGSIZE(N) \ +- ((((N)*(sizeof (struct spi_ioc_transfer))) < (1 << _IOC_SIZEBITS)) \ ++ ((((N)*(sizeof (struct spi_ioc_transfer))) < (1 << 13)) \ + ? ((N)*(sizeof (struct spi_ioc_transfer))) : 0) + #define SPI_IOC_MESSAGE(N) _IOW(SPI_IOC_MAGIC, 0, char[SPI_MSGSIZE(N)]) + diff --git a/target/linux/generic/patches-4.0/220-gc_sections.patch b/target/linux/generic/patches-4.0/220-gc_sections.patch new file mode 100644 index 0000000..102c18f --- /dev/null +++ b/target/linux/generic/patches-4.0/220-gc_sections.patch @@ -0,0 +1,532 @@ +From: Felix Fietkau + +use -ffunction-sections, -fdata-sections and --gc-sections + +In combination with kernel symbol export stripping this significantly reduces +the kernel image size. Used on both ARM and MIPS architectures. + +Signed-off-by: Felix Fietkau +Signed-off-by: Jonas Gorski +Signed-off-by: Gabor Juhos +--- + +--- a/arch/mips/Makefile ++++ b/arch/mips/Makefile +@@ -89,10 +89,14 @@ all-$(CONFIG_SYS_SUPPORTS_ZBOOT)+= vmlin + # + cflags-y += -G 0 -mno-abicalls -fno-pic -pipe + cflags-y += -msoft-float +-LDFLAGS_vmlinux += -G 0 -static -n -nostdlib ++LDFLAGS_vmlinux += -G 0 -static -n -nostdlib --gc-sections + KBUILD_AFLAGS_MODULE += -mlong-calls + KBUILD_CFLAGS_MODULE += -mlong-calls + ++ifndef CONFIG_FUNCTION_TRACER ++KBUILD_CFLAGS_KERNEL += -ffunction-sections -fdata-sections ++endif ++ + # + # pass -msoft-float to GAS if it supports it. However on newer binutils + # (specifically newer than 2.24.51.20140728) we then also need to explicitly +--- a/arch/mips/kernel/vmlinux.lds.S ++++ b/arch/mips/kernel/vmlinux.lds.S +@@ -67,7 +67,7 @@ SECTIONS + /* Exception table for data bus errors */ + __dbe_table : { + __start___dbe_table = .; +- *(__dbe_table) ++ KEEP(*(__dbe_table)) + __stop___dbe_table = .; + } + +@@ -112,7 +112,7 @@ SECTIONS + . = ALIGN(4); + .mips.machines.init : AT(ADDR(.mips.machines.init) - LOAD_OFFSET) { + __mips_machines_start = .; +- *(.mips.machines.init) ++ KEEP(*(.mips.machines.init)) + __mips_machines_end = .; + } + +--- a/include/asm-generic/vmlinux.lds.h ++++ b/include/asm-generic/vmlinux.lds.h +@@ -89,7 +89,7 @@ + #ifdef CONFIG_FTRACE_MCOUNT_RECORD + #define MCOUNT_REC() . = ALIGN(8); \ + VMLINUX_SYMBOL(__start_mcount_loc) = .; \ +- *(__mcount_loc) \ ++ KEEP(*(__mcount_loc)) \ + VMLINUX_SYMBOL(__stop_mcount_loc) = .; + #else + #define MCOUNT_REC() +@@ -97,7 +97,7 @@ + + #ifdef CONFIG_TRACE_BRANCH_PROFILING + #define LIKELY_PROFILE() VMLINUX_SYMBOL(__start_annotated_branch_profile) = .; \ +- *(_ftrace_annotated_branch) \ ++ KEEP(*(_ftrace_annotated_branch)) \ + VMLINUX_SYMBOL(__stop_annotated_branch_profile) = .; + #else + #define LIKELY_PROFILE() +@@ -105,7 +105,7 @@ + + #ifdef CONFIG_PROFILE_ALL_BRANCHES + #define BRANCH_PROFILE() VMLINUX_SYMBOL(__start_branch_profile) = .; \ +- *(_ftrace_branch) \ ++ KEEP(*(_ftrace_branch)) \ + VMLINUX_SYMBOL(__stop_branch_profile) = .; + #else + #define BRANCH_PROFILE() +@@ -114,7 +114,7 @@ + #ifdef CONFIG_KPROBES + #define KPROBE_BLACKLIST() . = ALIGN(8); \ + VMLINUX_SYMBOL(__start_kprobe_blacklist) = .; \ +- *(_kprobe_blacklist) \ ++ KEEP(*(_kprobe_blacklist)) \ + VMLINUX_SYMBOL(__stop_kprobe_blacklist) = .; + #else + #define KPROBE_BLACKLIST() +@@ -123,7 +123,7 @@ + #ifdef CONFIG_EVENT_TRACING + #define FTRACE_EVENTS() . = ALIGN(8); \ + VMLINUX_SYMBOL(__start_ftrace_events) = .; \ +- *(_ftrace_events) \ ++ KEEP(*(_ftrace_events)) \ + VMLINUX_SYMBOL(__stop_ftrace_events) = .; + #else + #define FTRACE_EVENTS() +@@ -131,7 +131,7 @@ + + #ifdef CONFIG_TRACING + #define TRACE_PRINTKS() VMLINUX_SYMBOL(__start___trace_bprintk_fmt) = .; \ +- *(__trace_printk_fmt) /* Trace_printk fmt' pointer */ \ ++ KEEP(*(__trace_printk_fmt)) /* Trace_printk fmt' pointer */ \ + VMLINUX_SYMBOL(__stop___trace_bprintk_fmt) = .; + #define TRACEPOINT_STR() VMLINUX_SYMBOL(__start___tracepoint_str) = .; \ + *(__tracepoint_str) /* Trace_printk fmt' pointer */ \ +@@ -144,7 +144,7 @@ + #ifdef CONFIG_FTRACE_SYSCALLS + #define TRACE_SYSCALLS() . = ALIGN(8); \ + VMLINUX_SYMBOL(__start_syscalls_metadata) = .; \ +- *(__syscalls_metadata) \ ++ KEEP(*(__syscalls_metadata)) \ + VMLINUX_SYMBOL(__stop_syscalls_metadata) = .; + #else + #define TRACE_SYSCALLS() +@@ -158,8 +158,8 @@ + #define _OF_TABLE_1(name) \ + . = ALIGN(8); \ + VMLINUX_SYMBOL(__##name##_of_table) = .; \ +- *(__##name##_of_table) \ +- *(__##name##_of_table_end) ++ KEEP(*(__##name##_of_table)) \ ++ KEEP(*(__##name##_of_table_end)) + + #define CLKSRC_OF_TABLES() OF_TABLE(CONFIG_CLKSRC_OF, clksrc) + #define IRQCHIP_OF_MATCH_TABLE() OF_TABLE(CONFIG_IRQCHIP, irqchip) +@@ -172,7 +172,7 @@ + #define KERNEL_DTB() \ + STRUCT_ALIGN(); \ + VMLINUX_SYMBOL(__dtb_start) = .; \ +- *(.dtb.init.rodata) \ ++ KEEP(*(.dtb.init.rodata)) \ + VMLINUX_SYMBOL(__dtb_end) = .; + + /* .data section */ +@@ -188,16 +188,17 @@ + /* implement dynamic printk debug */ \ + . = ALIGN(8); \ + VMLINUX_SYMBOL(__start___jump_table) = .; \ +- *(__jump_table) \ ++ KEEP(*(__jump_table)) \ + VMLINUX_SYMBOL(__stop___jump_table) = .; \ + . = ALIGN(8); \ + VMLINUX_SYMBOL(__start___verbose) = .; \ +- *(__verbose) \ ++ KEEP(*(__verbose)) \ + VMLINUX_SYMBOL(__stop___verbose) = .; \ + LIKELY_PROFILE() \ + BRANCH_PROFILE() \ + TRACE_PRINTKS() \ +- TRACEPOINT_STR() ++ TRACEPOINT_STR() \ ++ *(.data.[a-zA-Z_]*) + + /* + * Data section helpers +@@ -251,35 +252,35 @@ + /* PCI quirks */ \ + .pci_fixup : AT(ADDR(.pci_fixup) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start_pci_fixups_early) = .; \ +- *(.pci_fixup_early) \ ++ KEEP(*(.pci_fixup_early)) \ + VMLINUX_SYMBOL(__end_pci_fixups_early) = .; \ + VMLINUX_SYMBOL(__start_pci_fixups_header) = .; \ +- *(.pci_fixup_header) \ ++ KEEP(*(.pci_fixup_header)) \ + VMLINUX_SYMBOL(__end_pci_fixups_header) = .; \ + VMLINUX_SYMBOL(__start_pci_fixups_final) = .; \ +- *(.pci_fixup_final) \ ++ KEEP(*(.pci_fixup_final)) \ + VMLINUX_SYMBOL(__end_pci_fixups_final) = .; \ + VMLINUX_SYMBOL(__start_pci_fixups_enable) = .; \ +- *(.pci_fixup_enable) \ ++ KEEP(*(.pci_fixup_enable)) \ + VMLINUX_SYMBOL(__end_pci_fixups_enable) = .; \ + VMLINUX_SYMBOL(__start_pci_fixups_resume) = .; \ +- *(.pci_fixup_resume) \ ++ KEEP(*(.pci_fixup_resume)) \ + VMLINUX_SYMBOL(__end_pci_fixups_resume) = .; \ + VMLINUX_SYMBOL(__start_pci_fixups_resume_early) = .; \ +- *(.pci_fixup_resume_early) \ ++ KEEP(*(.pci_fixup_resume_early)) \ + VMLINUX_SYMBOL(__end_pci_fixups_resume_early) = .; \ + VMLINUX_SYMBOL(__start_pci_fixups_suspend) = .; \ +- *(.pci_fixup_suspend) \ ++ KEEP(*(.pci_fixup_suspend)) \ + VMLINUX_SYMBOL(__end_pci_fixups_suspend) = .; \ + VMLINUX_SYMBOL(__start_pci_fixups_suspend_late) = .; \ +- *(.pci_fixup_suspend_late) \ ++ KEEP(*(.pci_fixup_suspend_late)) \ + VMLINUX_SYMBOL(__end_pci_fixups_suspend_late) = .; \ + } \ + \ + /* Built-in firmware blobs */ \ + .builtin_fw : AT(ADDR(.builtin_fw) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start_builtin_fw) = .; \ +- *(.builtin_fw) \ ++ KEEP(*(.builtin_fw)) \ + VMLINUX_SYMBOL(__end_builtin_fw) = .; \ + } \ + \ +@@ -288,49 +289,49 @@ + /* Kernel symbol table: Normal symbols */ \ + __ksymtab : AT(ADDR(__ksymtab) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___ksymtab) = .; \ +- *(SORT(___ksymtab+*)) \ ++ KEEP(*(SORT(___ksymtab+*))) \ + VMLINUX_SYMBOL(__stop___ksymtab) = .; \ + } \ + \ + /* Kernel symbol table: GPL-only symbols */ \ + __ksymtab_gpl : AT(ADDR(__ksymtab_gpl) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___ksymtab_gpl) = .; \ +- *(SORT(___ksymtab_gpl+*)) \ ++ KEEP(*(SORT(___ksymtab_gpl+*))) \ + VMLINUX_SYMBOL(__stop___ksymtab_gpl) = .; \ + } \ + \ + /* Kernel symbol table: Normal unused symbols */ \ + __ksymtab_unused : AT(ADDR(__ksymtab_unused) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___ksymtab_unused) = .; \ +- *(SORT(___ksymtab_unused+*)) \ ++ KEEP(*(SORT(___ksymtab_unused+*))) \ + VMLINUX_SYMBOL(__stop___ksymtab_unused) = .; \ + } \ + \ + /* Kernel symbol table: GPL-only unused symbols */ \ + __ksymtab_unused_gpl : AT(ADDR(__ksymtab_unused_gpl) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___ksymtab_unused_gpl) = .; \ +- *(SORT(___ksymtab_unused_gpl+*)) \ ++ KEEP(*(SORT(___ksymtab_unused_gpl+*))) \ + VMLINUX_SYMBOL(__stop___ksymtab_unused_gpl) = .; \ + } \ + \ + /* Kernel symbol table: GPL-future-only symbols */ \ + __ksymtab_gpl_future : AT(ADDR(__ksymtab_gpl_future) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___ksymtab_gpl_future) = .; \ +- *(SORT(___ksymtab_gpl_future+*)) \ ++ KEEP(*(SORT(___ksymtab_gpl_future+*))) \ + VMLINUX_SYMBOL(__stop___ksymtab_gpl_future) = .; \ + } \ + \ + /* Kernel symbol table: Normal symbols */ \ + __kcrctab : AT(ADDR(__kcrctab) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___kcrctab) = .; \ +- *(SORT(___kcrctab+*)) \ ++ KEEP(*(SORT(___kcrctab+*))) \ + VMLINUX_SYMBOL(__stop___kcrctab) = .; \ + } \ + \ + /* Kernel symbol table: GPL-only symbols */ \ + __kcrctab_gpl : AT(ADDR(__kcrctab_gpl) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___kcrctab_gpl) = .; \ +- *(SORT(___kcrctab_gpl+*)) \ ++ KEEP(*(SORT(___kcrctab_gpl+*))) \ + VMLINUX_SYMBOL(__stop___kcrctab_gpl) = .; \ + } \ + \ +@@ -344,14 +345,14 @@ + /* Kernel symbol table: GPL-only unused symbols */ \ + __kcrctab_unused_gpl : AT(ADDR(__kcrctab_unused_gpl) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___kcrctab_unused_gpl) = .; \ +- *(SORT(___kcrctab_unused_gpl+*)) \ ++ KEEP(*(SORT(___kcrctab_unused_gpl+*))) \ + VMLINUX_SYMBOL(__stop___kcrctab_unused_gpl) = .; \ + } \ + \ + /* Kernel symbol table: GPL-future-only symbols */ \ + __kcrctab_gpl_future : AT(ADDR(__kcrctab_gpl_future) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___kcrctab_gpl_future) = .; \ +- *(SORT(___kcrctab_gpl_future+*)) \ ++ KEEP(*(SORT(___kcrctab_gpl_future+*))) \ + VMLINUX_SYMBOL(__stop___kcrctab_gpl_future) = .; \ + } \ + \ +@@ -370,14 +371,14 @@ + /* Built-in module parameters. */ \ + __param : AT(ADDR(__param) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___param) = .; \ +- *(__param) \ ++ KEEP(*(__param)) \ + VMLINUX_SYMBOL(__stop___param) = .; \ + } \ + \ + /* Built-in module versions. */ \ + __modver : AT(ADDR(__modver) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___modver) = .; \ +- *(__modver) \ ++ KEEP(*(__modver)) \ + VMLINUX_SYMBOL(__stop___modver) = .; \ + . = ALIGN((align)); \ + VMLINUX_SYMBOL(__end_rodata) = .; \ +@@ -433,7 +434,7 @@ + #define ENTRY_TEXT \ + ALIGN_FUNCTION(); \ + VMLINUX_SYMBOL(__entry_text_start) = .; \ +- *(.entry.text) \ ++ KEEP(*(.entry.text)) \ + VMLINUX_SYMBOL(__entry_text_end) = .; + + #ifdef CONFIG_FUNCTION_GRAPH_TRACER +@@ -461,7 +462,7 @@ + . = ALIGN(align); \ + __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___ex_table) = .; \ +- *(__ex_table) \ ++ KEEP(*(__ex_table)) \ + VMLINUX_SYMBOL(__stop___ex_table) = .; \ + } + +@@ -477,9 +478,9 @@ + #ifdef CONFIG_CONSTRUCTORS + #define KERNEL_CTORS() . = ALIGN(8); \ + VMLINUX_SYMBOL(__ctors_start) = .; \ +- *(.ctors) \ ++ KEEP(*(.ctors)) \ + *(SORT(.init_array.*)) \ +- *(.init_array) \ ++ KEEP(*(.init_array)) \ + VMLINUX_SYMBOL(__ctors_end) = .; + #else + #define KERNEL_CTORS() +@@ -528,7 +529,7 @@ + #define SBSS(sbss_align) \ + . = ALIGN(sbss_align); \ + .sbss : AT(ADDR(.sbss) - LOAD_OFFSET) { \ +- *(.sbss) \ ++ *(.sbss .sbss.*) \ + *(.scommon) \ + } + +@@ -546,7 +547,7 @@ + BSS_FIRST_SECTIONS \ + *(.bss..page_aligned) \ + *(.dynbss) \ +- *(.bss) \ ++ *(.bss .bss.*) \ + *(COMMON) \ + } + +@@ -595,7 +596,7 @@ + . = ALIGN(8); \ + __bug_table : AT(ADDR(__bug_table) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___bug_table) = .; \ +- *(__bug_table) \ ++ KEEP(*(__bug_table)) \ + VMLINUX_SYMBOL(__stop___bug_table) = .; \ + } + #else +@@ -607,7 +608,7 @@ + . = ALIGN(4); \ + .tracedata : AT(ADDR(.tracedata) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__tracedata_start) = .; \ +- *(.tracedata) \ ++ KEEP(*(.tracedata)) \ + VMLINUX_SYMBOL(__tracedata_end) = .; \ + } + #else +@@ -624,17 +625,17 @@ + #define INIT_SETUP(initsetup_align) \ + . = ALIGN(initsetup_align); \ + VMLINUX_SYMBOL(__setup_start) = .; \ +- *(.init.setup) \ ++ KEEP(*(.init.setup)) \ + VMLINUX_SYMBOL(__setup_end) = .; + + #define INIT_CALLS_LEVEL(level) \ + VMLINUX_SYMBOL(__initcall##level##_start) = .; \ +- *(.initcall##level##.init) \ +- *(.initcall##level##s.init) \ ++ KEEP(*(.initcall##level##.init)) \ ++ KEEP(*(.initcall##level##s.init)) \ + + #define INIT_CALLS \ + VMLINUX_SYMBOL(__initcall_start) = .; \ +- *(.initcallearly.init) \ ++ KEEP(*(.initcallearly.init)) \ + INIT_CALLS_LEVEL(0) \ + INIT_CALLS_LEVEL(1) \ + INIT_CALLS_LEVEL(2) \ +@@ -648,21 +649,21 @@ + + #define CON_INITCALL \ + VMLINUX_SYMBOL(__con_initcall_start) = .; \ +- *(.con_initcall.init) \ ++ KEEP(*(.con_initcall.init)) \ + VMLINUX_SYMBOL(__con_initcall_end) = .; + + #define SECURITY_INITCALL \ + VMLINUX_SYMBOL(__security_initcall_start) = .; \ +- *(.security_initcall.init) \ ++ KEEP(*(.security_initcall.init)) \ + VMLINUX_SYMBOL(__security_initcall_end) = .; + + #ifdef CONFIG_BLK_DEV_INITRD + #define INIT_RAM_FS \ + . = ALIGN(4); \ + VMLINUX_SYMBOL(__initramfs_start) = .; \ +- *(.init.ramfs) \ ++ KEEP(*(.init.ramfs)) \ + . = ALIGN(8); \ +- *(.init.ramfs.info) ++ KEEP(*(.init.ramfs.info)) + #else + #define INIT_RAM_FS + #endif +--- a/arch/arm/Makefile ++++ b/arch/arm/Makefile +@@ -18,11 +18,16 @@ ifeq ($(CONFIG_CPU_ENDIAN_BE8),y) + LDFLAGS_vmlinux += --be8 + LDFLAGS_MODULE += --be8 + endif ++LDFLAGS_vmlinux += --gc-sections + + OBJCOPYFLAGS :=-O binary -R .comment -S + GZFLAGS :=-9 + #KBUILD_CFLAGS +=-pipe + ++ifndef CONFIG_FUNCTION_TRACER ++KBUILD_CFLAGS_KERNEL += -ffunction-sections -fdata-sections ++endif ++ + # Never generate .eh_frame + KBUILD_CFLAGS += $(call cc-option,-fno-dwarf2-cfi-asm) + +--- a/arch/arm/kernel/vmlinux.lds.S ++++ b/arch/arm/kernel/vmlinux.lds.S +@@ -15,13 +15,13 @@ + #define PROC_INFO \ + . = ALIGN(4); \ + VMLINUX_SYMBOL(__proc_info_begin) = .; \ +- *(.proc.info.init) \ ++ KEEP(*(.proc.info.init)) \ + VMLINUX_SYMBOL(__proc_info_end) = .; + + #define IDMAP_TEXT \ + ALIGN_FUNCTION(); \ + VMLINUX_SYMBOL(__idmap_text_start) = .; \ +- *(.idmap.text) \ ++ KEEP(*(.idmap.text)) \ + VMLINUX_SYMBOL(__idmap_text_end) = .; \ + . = ALIGN(32); \ + VMLINUX_SYMBOL(__hyp_idmap_text_start) = .; \ +@@ -101,7 +101,7 @@ SECTIONS + .text : { /* Real text segment */ + _stext = .; /* Text and read-only data */ + __exception_text_start = .; +- *(.exception.text) ++ KEEP(*(.exception.text)) + __exception_text_end = .; + IRQENTRY_TEXT + TEXT_TEXT +@@ -129,7 +129,7 @@ SECTIONS + __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) { + __start___ex_table = .; + #ifdef CONFIG_MMU +- *(__ex_table) ++ KEEP(*(__ex_table)) + #endif + __stop___ex_table = .; + } +@@ -141,12 +141,12 @@ SECTIONS + . = ALIGN(8); + .ARM.unwind_idx : { + __start_unwind_idx = .; +- *(.ARM.exidx*) ++ KEEP(*(.ARM.exidx*)) + __stop_unwind_idx = .; + } + .ARM.unwind_tab : { + __start_unwind_tab = .; +- *(.ARM.extab*) ++ KEEP(*(.ARM.extab*)) + __stop_unwind_tab = .; + } + #endif +@@ -169,14 +169,14 @@ SECTIONS + */ + __vectors_start = .; + .vectors 0 : AT(__vectors_start) { +- *(.vectors) ++ KEEP(*(.vectors)) + } + . = __vectors_start + SIZEOF(.vectors); + __vectors_end = .; + + __stubs_start = .; + .stubs 0x1000 : AT(__stubs_start) { +- *(.stubs) ++ KEEP(*(.stubs)) + } + . = __stubs_start + SIZEOF(.stubs); + __stubs_end = .; +@@ -190,24 +190,24 @@ SECTIONS + } + .init.arch.info : { + __arch_info_begin = .; +- *(.arch.info.init) ++ KEEP(*(.arch.info.init)) + __arch_info_end = .; + } + .init.tagtable : { + __tagtable_begin = .; +- *(.taglist.init) ++ KEEP(*(.taglist.init)) + __tagtable_end = .; + } + #ifdef CONFIG_SMP_ON_UP + .init.smpalt : { + __smpalt_begin = .; +- *(.alt.smp.init) ++ KEEP(*(.alt.smp.init)) + __smpalt_end = .; + } + #endif + .init.pv_table : { + __pv_table_begin = .; +- *(.pv_table) ++ KEEP(*(.pv_table)) + __pv_table_end = .; + } + .init.data : { +--- a/arch/arm/boot/compressed/Makefile ++++ b/arch/arm/boot/compressed/Makefile +@@ -122,6 +122,7 @@ ifeq ($(CONFIG_FUNCTION_TRACER),y) + ORIG_CFLAGS := $(KBUILD_CFLAGS) + KBUILD_CFLAGS = $(subst -pg, , $(ORIG_CFLAGS)) + endif ++KBUILD_CFLAGS_KERNEL := $(patsubst -f%-sections,,$(KBUILD_CFLAGS_KERNEL)) + + ccflags-y := -fpic -mno-single-pic-base -fno-builtin -I$(obj) + asflags-y := -DZIMAGE diff --git a/target/linux/generic/patches-4.0/221-module_exports.patch b/target/linux/generic/patches-4.0/221-module_exports.patch new file mode 100644 index 0000000..daf50fb --- /dev/null +++ b/target/linux/generic/patches-4.0/221-module_exports.patch @@ -0,0 +1,88 @@ +--- a/include/asm-generic/vmlinux.lds.h ++++ b/include/asm-generic/vmlinux.lds.h +@@ -54,6 +54,16 @@ + #define LOAD_OFFSET 0 + #endif + ++#ifndef SYMTAB_KEEP ++#define SYMTAB_KEEP KEEP(*(SORT(___ksymtab+*))) ++#define SYMTAB_KEEP_GPL KEEP(*(SORT(___ksymtab_gpl+*))) ++#endif ++ ++#ifndef SYMTAB_DISCARD ++#define SYMTAB_DISCARD ++#define SYMTAB_DISCARD_GPL ++#endif ++ + #include + + /* Align . to a 8 byte boundary equals to maximum function alignment. */ +@@ -289,14 +299,14 @@ + /* Kernel symbol table: Normal symbols */ \ + __ksymtab : AT(ADDR(__ksymtab) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___ksymtab) = .; \ +- KEEP(*(SORT(___ksymtab+*))) \ ++ SYMTAB_KEEP \ + VMLINUX_SYMBOL(__stop___ksymtab) = .; \ + } \ + \ + /* Kernel symbol table: GPL-only symbols */ \ + __ksymtab_gpl : AT(ADDR(__ksymtab_gpl) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___ksymtab_gpl) = .; \ +- KEEP(*(SORT(___ksymtab_gpl+*))) \ ++ SYMTAB_KEEP_GPL \ + VMLINUX_SYMBOL(__stop___ksymtab_gpl) = .; \ + } \ + \ +@@ -358,7 +368,7 @@ + \ + /* Kernel symbol table: strings */ \ + __ksymtab_strings : AT(ADDR(__ksymtab_strings) - LOAD_OFFSET) { \ +- *(__ksymtab_strings) \ ++ *(__ksymtab_strings+*) \ + } \ + \ + /* __*init sections */ \ +@@ -682,6 +692,8 @@ + EXIT_TEXT \ + EXIT_DATA \ + EXIT_CALL \ ++ SYMTAB_DISCARD \ ++ SYMTAB_DISCARD_GPL \ + *(.discard) \ + *(.discard.*) \ + } +--- a/scripts/Makefile.build ++++ b/scripts/Makefile.build +@@ -299,7 +299,7 @@ targets += $(extra-y) $(MAKECMDGOALS) $( + # Linker scripts preprocessor (.lds.S -> .lds) + # --------------------------------------------------------------------------- + quiet_cmd_cpp_lds_S = LDS $@ +- cmd_cpp_lds_S = $(CPP) $(cpp_flags) -P -C -U$(ARCH) \ ++ cmd_cpp_lds_S = $(CPP) $(EXTRA_LDSFLAGS) $(cpp_flags) -P -C -U$(ARCH) \ + -D__ASSEMBLY__ -DLINKER_SCRIPT -o $@ $< + + $(obj)/%.lds: $(src)/%.lds.S FORCE +--- a/include/linux/export.h ++++ b/include/linux/export.h +@@ -52,12 +52,19 @@ extern struct module __this_module; + #define __CRC_SYMBOL(sym, sec) + #endif + ++#ifdef MODULE ++#define __EXPORT_SUFFIX(sym) ++#else ++#define __EXPORT_SUFFIX(sym) "+" #sym ++#endif ++ + /* For every exported symbol, place a struct in the __ksymtab section */ + #define __EXPORT_SYMBOL(sym, sec) \ + extern typeof(sym) sym; \ + __CRC_SYMBOL(sym, sec) \ + static const char __kstrtab_##sym[] \ +- __attribute__((section("__ksymtab_strings"), aligned(1))) \ ++ __attribute__((section("__ksymtab_strings" \ ++ __EXPORT_SUFFIX(sym)), aligned(1))) \ + = VMLINUX_SYMBOL_STR(sym); \ + extern const struct kernel_symbol __ksymtab_##sym; \ + __visible const struct kernel_symbol __ksymtab_##sym \ diff --git a/target/linux/generic/patches-4.0/230-openwrt_lzma_options.patch b/target/linux/generic/patches-4.0/230-openwrt_lzma_options.patch new file mode 100644 index 0000000..993fce4 --- /dev/null +++ b/target/linux/generic/patches-4.0/230-openwrt_lzma_options.patch @@ -0,0 +1,58 @@ +--- a/scripts/Makefile.lib ++++ b/scripts/Makefile.lib +@@ -323,7 +323,7 @@ cmd_bzip2 = (cat $(filter-out FORCE,$^) + + quiet_cmd_lzma = LZMA $@ + cmd_lzma = (cat $(filter-out FORCE,$^) | \ +- lzma -9 && $(call size_append, $(filter-out FORCE,$^))) > $@ || \ ++ lzma e -d20 -lc1 -lp2 -pb2 -eos -si -so && $(call size_append, $(filter-out FORCE,$^))) > $@ || \ + (rm -f $@ ; false) + + quiet_cmd_lzo = LZO $@ +--- a/scripts/gen_initramfs_list.sh ++++ b/scripts/gen_initramfs_list.sh +@@ -226,7 +226,7 @@ cpio_list= + output="/dev/stdout" + output_file="" + is_cpio_compressed= +-compr="gzip -n -9 -f" ++compr="gzip -n -9 -f -" + + arg="$1" + case "$arg" in +@@ -242,13 +242,13 @@ case "$arg" in + output=${cpio_list} + echo "$output_file" | grep -q "\.gz$" \ + && [ -x "`which gzip 2> /dev/null`" ] \ +- && compr="gzip -n -9 -f" ++ && compr="gzip -n -9 -f -" + echo "$output_file" | grep -q "\.bz2$" \ + && [ -x "`which bzip2 2> /dev/null`" ] \ +- && compr="bzip2 -9 -f" ++ && compr="bzip2 -9 -f -" + echo "$output_file" | grep -q "\.lzma$" \ + && [ -x "`which lzma 2> /dev/null`" ] \ +- && compr="lzma -9 -f" ++ && compr="lzma e -d20 -lc1 -lp2 -pb2 -eos -si -so" + echo "$output_file" | grep -q "\.xz$" \ + && [ -x "`which xz 2> /dev/null`" ] \ + && compr="xz --check=crc32 --lzma2=dict=1MiB" +@@ -315,7 +315,7 @@ if [ ! -z ${output_file} ]; then + if [ "${is_cpio_compressed}" = "compressed" ]; then + cat ${cpio_tfile} > ${output_file} + else +- (cat ${cpio_tfile} | ${compr} - > ${output_file}) \ ++ (cat ${cpio_tfile} | ${compr} > ${output_file}) \ + || (rm -f ${output_file} ; false) + fi + [ -z ${cpio_file} ] && rm ${cpio_tfile} +--- a/lib/decompress.c ++++ b/lib/decompress.c +@@ -48,6 +48,7 @@ static const struct compress_format comp + { {0x1f, 0x9e}, "gzip", gunzip }, + { {0x42, 0x5a}, "bzip2", bunzip2 }, + { {0x5d, 0x00}, "lzma", unlzma }, ++ { {0x6d, 0x00}, "lzma-openwrt", unlzma }, + { {0xfd, 0x37}, "xz", unxz }, + { {0x89, 0x4c}, "lzo", unlzo }, + { {0x02, 0x21}, "lz4", unlz4 }, diff --git a/target/linux/generic/patches-4.0/250-netfilter_depends.patch b/target/linux/generic/patches-4.0/250-netfilter_depends.patch new file mode 100644 index 0000000..d4b6d73 --- /dev/null +++ b/target/linux/generic/patches-4.0/250-netfilter_depends.patch @@ -0,0 +1,18 @@ +--- a/net/netfilter/Kconfig ++++ b/net/netfilter/Kconfig +@@ -210,7 +210,6 @@ config NF_CONNTRACK_FTP + + config NF_CONNTRACK_H323 + tristate "H.323 protocol support" +- depends on (IPV6 || IPV6=n) + depends on NETFILTER_ADVANCED + help + H.323 is a VoIP signalling protocol from ITU-T. As one of the most +@@ -924,7 +923,6 @@ config NETFILTER_XT_TARGET_SECMARK + + config NETFILTER_XT_TARGET_TCPMSS + tristate '"TCPMSS" target support' +- depends on (IPV6 || IPV6=n) + default m if NETFILTER_ADVANCED=n + ---help--- + This option adds a `TCPMSS' target, which allows you to alter the diff --git a/target/linux/generic/patches-4.0/251-sound_kconfig.patch b/target/linux/generic/patches-4.0/251-sound_kconfig.patch new file mode 100644 index 0000000..c2ebace --- /dev/null +++ b/target/linux/generic/patches-4.0/251-sound_kconfig.patch @@ -0,0 +1,18 @@ +--- a/sound/core/Kconfig ++++ b/sound/core/Kconfig +@@ -10,13 +10,13 @@ config SND_DMAENGINE_PCM + tristate + + config SND_HWDEP +- tristate ++ tristate "Sound hardware support" + + config SND_RAWMIDI + tristate + + config SND_COMPRESS_OFFLOAD +- tristate ++ tristate "Compression offloading support" + + # To be effective this also requires INPUT - users should say: + # select SND_JACK if INPUT=y || INPUT=SND diff --git a/target/linux/generic/patches-4.0/252-mv_cesa_depends.patch b/target/linux/generic/patches-4.0/252-mv_cesa_depends.patch new file mode 100644 index 0000000..fee28db --- /dev/null +++ b/target/linux/generic/patches-4.0/252-mv_cesa_depends.patch @@ -0,0 +1,10 @@ +--- a/drivers/crypto/Kconfig ++++ b/drivers/crypto/Kconfig +@@ -164,6 +164,7 @@ config CRYPTO_DEV_MV_CESA + depends on PLAT_ORION + select CRYPTO_ALGAPI + select CRYPTO_AES ++ select CRYPTO_HASH2 + select CRYPTO_BLKCIPHER2 + select CRYPTO_HASH + help diff --git a/target/linux/generic/patches-4.0/253-ssb_b43_default_on.patch b/target/linux/generic/patches-4.0/253-ssb_b43_default_on.patch new file mode 100644 index 0000000..29d2a41 --- /dev/null +++ b/target/linux/generic/patches-4.0/253-ssb_b43_default_on.patch @@ -0,0 +1,29 @@ +--- a/drivers/ssb/Kconfig ++++ b/drivers/ssb/Kconfig +@@ -29,6 +29,7 @@ config SSB_SPROM + config SSB_BLOCKIO + bool + depends on SSB ++ default y + + config SSB_PCIHOST_POSSIBLE + bool +@@ -49,7 +50,7 @@ config SSB_PCIHOST + config SSB_B43_PCI_BRIDGE + bool + depends on SSB_PCIHOST +- default n ++ default y + + config SSB_PCMCIAHOST_POSSIBLE + bool +--- a/drivers/bcma/Kconfig ++++ b/drivers/bcma/Kconfig +@@ -17,6 +17,7 @@ config BCMA + config BCMA_BLOCKIO + bool + depends on BCMA ++ default y + + config BCMA_HOST_PCI_POSSIBLE + bool diff --git a/target/linux/generic/patches-4.0/254-textsearch_kconfig_hacks.patch b/target/linux/generic/patches-4.0/254-textsearch_kconfig_hacks.patch new file mode 100644 index 0000000..cf75400 --- /dev/null +++ b/target/linux/generic/patches-4.0/254-textsearch_kconfig_hacks.patch @@ -0,0 +1,23 @@ +--- a/lib/Kconfig ++++ b/lib/Kconfig +@@ -329,16 +329,16 @@ config BCH_CONST_T + # Textsearch support is select'ed if needed + # + config TEXTSEARCH +- bool ++ boolean "Textsearch support" + + config TEXTSEARCH_KMP +- tristate ++ tristate "Textsearch KMP" + + config TEXTSEARCH_BM +- tristate ++ tristate "Textsearch BM" + + config TEXTSEARCH_FSM +- tristate ++ tristate "Textsearch FSM" + + config BTREE + bool diff --git a/target/linux/generic/patches-4.0/255-lib80211_kconfig_hacks.patch b/target/linux/generic/patches-4.0/255-lib80211_kconfig_hacks.patch new file mode 100644 index 0000000..d875235 --- /dev/null +++ b/target/linux/generic/patches-4.0/255-lib80211_kconfig_hacks.patch @@ -0,0 +1,31 @@ +--- a/net/wireless/Kconfig ++++ b/net/wireless/Kconfig +@@ -183,7 +183,7 @@ config CFG80211_WEXT + extensions with cfg80211-based drivers. + + config LIB80211 +- tristate ++ tristate "LIB80211" + default n + help + This options enables a library of common routines used +@@ -192,13 +192,16 @@ config LIB80211 + Drivers should select this themselves if needed. + + config LIB80211_CRYPT_WEP +- tristate ++ tristate "LIB80211_CRYPT_WEP" ++ select LIB80211 + + config LIB80211_CRYPT_CCMP +- tristate ++ tristate "LIB80211_CRYPT_CCMP" ++ select LIB80211 + + config LIB80211_CRYPT_TKIP +- tristate ++ tristate "LIB80211_CRYPT_TKIP" ++ select LIB80211 + + config LIB80211_DEBUG + bool "lib80211 debugging messages" diff --git a/target/linux/generic/patches-4.0/256-crypto_add_kconfig_prompts.patch b/target/linux/generic/patches-4.0/256-crypto_add_kconfig_prompts.patch new file mode 100644 index 0000000..f9f6c0e --- /dev/null +++ b/target/linux/generic/patches-4.0/256-crypto_add_kconfig_prompts.patch @@ -0,0 +1,47 @@ +--- a/crypto/Kconfig ++++ b/crypto/Kconfig +@@ -32,7 +32,7 @@ config CRYPTO_FIPS + this is. + + config CRYPTO_ALGAPI +- tristate ++ tristate "ALGAPI" + select CRYPTO_ALGAPI2 + help + This option provides the API for cryptographic algorithms. +@@ -41,7 +41,7 @@ config CRYPTO_ALGAPI2 + tristate + + config CRYPTO_AEAD +- tristate ++ tristate "AEAD" + select CRYPTO_AEAD2 + select CRYPTO_ALGAPI + +@@ -50,7 +50,7 @@ config CRYPTO_AEAD2 + select CRYPTO_ALGAPI2 + + config CRYPTO_BLKCIPHER +- tristate ++ tristate "BLKCIPHER" + select CRYPTO_BLKCIPHER2 + select CRYPTO_ALGAPI + +@@ -61,7 +61,7 @@ config CRYPTO_BLKCIPHER2 + select CRYPTO_WORKQUEUE + + config CRYPTO_HASH +- tristate ++ tristate "HASH" + select CRYPTO_HASH2 + select CRYPTO_ALGAPI + +@@ -70,7 +70,7 @@ config CRYPTO_HASH2 + select CRYPTO_ALGAPI2 + + config CRYPTO_RNG +- tristate ++ tristate "RNG" + select CRYPTO_RNG2 + select CRYPTO_ALGAPI + diff --git a/target/linux/generic/patches-4.0/257-wireless_ext_kconfig_hack.patch b/target/linux/generic/patches-4.0/257-wireless_ext_kconfig_hack.patch new file mode 100644 index 0000000..daac589 --- /dev/null +++ b/target/linux/generic/patches-4.0/257-wireless_ext_kconfig_hack.patch @@ -0,0 +1,22 @@ +--- a/net/wireless/Kconfig ++++ b/net/wireless/Kconfig +@@ -1,5 +1,5 @@ + config WIRELESS_EXT +- bool ++ bool "Wireless extensions" + + config WEXT_CORE + def_bool y +@@ -11,10 +11,10 @@ config WEXT_PROC + depends on WEXT_CORE + + config WEXT_SPY +- bool ++ bool "WEXT_SPY" + + config WEXT_PRIV +- bool ++ bool "WEXT_PRIV" + + config CFG80211 + tristate "cfg80211 - wireless configuration API" diff --git a/target/linux/generic/patches-4.0/258-netfilter_netlink_kconfig_hack.patch b/target/linux/generic/patches-4.0/258-netfilter_netlink_kconfig_hack.patch new file mode 100644 index 0000000..9d827c2 --- /dev/null +++ b/target/linux/generic/patches-4.0/258-netfilter_netlink_kconfig_hack.patch @@ -0,0 +1,11 @@ +--- a/net/netfilter/Kconfig ++++ b/net/netfilter/Kconfig +@@ -2,7 +2,7 @@ menu "Core Netfilter Configuration" + depends on NET && INET && NETFILTER + + config NETFILTER_NETLINK +- tristate ++ tristate "Netfilter NFNETLINK interface" + + config NETFILTER_NETLINK_ACCT + tristate "Netfilter NFACCT over NFNETLINK interface" diff --git a/target/linux/generic/patches-4.0/259-regmap_dynamic.patch b/target/linux/generic/patches-4.0/259-regmap_dynamic.patch new file mode 100644 index 0000000..084b3b4 --- /dev/null +++ b/target/linux/generic/patches-4.0/259-regmap_dynamic.patch @@ -0,0 +1,84 @@ +--- a/drivers/base/regmap/Kconfig ++++ b/drivers/base/regmap/Kconfig +@@ -3,29 +3,35 @@ + # subsystems should select the appropriate symbols. + + config REGMAP +- default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ) + select LZO_COMPRESS + select LZO_DECOMPRESS + select IRQ_DOMAIN if REGMAP_IRQ +- bool ++ tristate "Regmap" + + config REGMAP_AC97 ++ select REGMAP + tristate + + config REGMAP_I2C +- tristate ++ tristate "Regmap I2C" ++ select REGMAP + depends on I2C + + config REGMAP_SPI +- tristate ++ tristate "Regmap SPI" ++ select REGMAP ++ depends on SPI_MASTER + depends on SPI + + config REGMAP_SPMI ++ select REGMAP + tristate + depends on SPMI + + config REGMAP_MMIO +- tristate ++ tristate "Regmap MMIO" ++ select REGMAP + + config REGMAP_IRQ ++ select REGMAP + bool +--- a/include/linux/regmap.h ++++ b/include/linux/regmap.h +@@ -50,7 +50,7 @@ struct reg_default { + unsigned int def; + }; + +-#ifdef CONFIG_REGMAP ++#if IS_ENABLED(CONFIG_REGMAP) + + enum regmap_endian { + /* Unspecified -> 0 -> Backwards compatible default */ +--- a/drivers/base/regmap/Makefile ++++ b/drivers/base/regmap/Makefile +@@ -1,6 +1,8 @@ +-obj-$(CONFIG_REGMAP) += regmap.o regcache.o +-obj-$(CONFIG_REGMAP) += regcache-rbtree.o regcache-lzo.o regcache-flat.o +-obj-$(CONFIG_DEBUG_FS) += regmap-debugfs.o ++regmap-core-objs = regmap.o regcache.o regcache-rbtree.o regcache-lzo.o regcache-flat.o ++ifdef CONFIG_DEBUG_FS ++regmap-core-objs += regmap-debugfs.o ++endif ++obj-$(CONFIG_REGMAP) += regmap-core.o + obj-$(CONFIG_REGMAP_AC97) += regmap-ac97.o + obj-$(CONFIG_REGMAP_I2C) += regmap-i2c.o + obj-$(CONFIG_REGMAP_SPI) += regmap-spi.o +--- a/drivers/base/regmap/regmap.c ++++ b/drivers/base/regmap/regmap.c +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -2631,3 +2632,5 @@ static int __init regmap_initcall(void) + return 0; + } + postcore_initcall(regmap_initcall); ++ ++MODULE_LICENSE("GPL"); diff --git a/target/linux/generic/patches-4.0/260-crypto_test_dependencies.patch b/target/linux/generic/patches-4.0/260-crypto_test_dependencies.patch new file mode 100644 index 0000000..8a96fd9 --- /dev/null +++ b/target/linux/generic/patches-4.0/260-crypto_test_dependencies.patch @@ -0,0 +1,37 @@ +--- a/crypto/Kconfig ++++ b/crypto/Kconfig +@@ -96,10 +96,10 @@ config CRYPTO_MANAGER + + config CRYPTO_MANAGER2 + def_tristate CRYPTO_MANAGER || (CRYPTO_MANAGER!=n && CRYPTO_ALGAPI=y) +- select CRYPTO_AEAD2 +- select CRYPTO_HASH2 +- select CRYPTO_BLKCIPHER2 +- select CRYPTO_PCOMP2 ++ select CRYPTO_AEAD2 if !CRYPTO_MANAGER_DISABLE_TESTS ++ select CRYPTO_HASH2 if !CRYPTO_MANAGER_DISABLE_TESTS ++ select CRYPTO_BLKCIPHER2 if !CRYPTO_MANAGER_DISABLE_TESTS ++ select CRYPTO_PCOMP2 if !CRYPTO_MANAGER_DISABLE_TESTS + + config CRYPTO_USER + tristate "Userspace cryptographic algorithm configuration" +--- a/crypto/algboss.c ++++ b/crypto/algboss.c +@@ -248,6 +248,9 @@ static int cryptomgr_schedule_test(struc + type = alg->cra_flags; + + /* This piece of crap needs to disappear into per-type test hooks. */ ++#ifdef CONFIG_CRYPTO_MANAGER_DISABLE_TESTS ++ type |= CRYPTO_ALG_TESTED; ++#else + if ((!((type ^ CRYPTO_ALG_TYPE_BLKCIPHER) & + CRYPTO_ALG_TYPE_BLKCIPHER_MASK) && !(type & CRYPTO_ALG_GENIV) && + ((alg->cra_flags & CRYPTO_ALG_TYPE_MASK) == +@@ -256,6 +259,7 @@ static int cryptomgr_schedule_test(struc + (!((type ^ CRYPTO_ALG_TYPE_AEAD) & CRYPTO_ALG_TYPE_MASK) && + alg->cra_type == &crypto_nivaead_type && alg->cra_aead.ivsize)) + type |= CRYPTO_ALG_TESTED; ++#endif + + param->type = type; + diff --git a/target/linux/generic/patches-4.0/262-compressor_kconfig_hack.patch b/target/linux/generic/patches-4.0/262-compressor_kconfig_hack.patch new file mode 100644 index 0000000..64db082 --- /dev/null +++ b/target/linux/generic/patches-4.0/262-compressor_kconfig_hack.patch @@ -0,0 +1,35 @@ +--- a/lib/Kconfig ++++ b/lib/Kconfig +@@ -214,25 +214,25 @@ config RANDOM32_SELFTEST + # compression support is select'ed if needed + # + config ZLIB_INFLATE +- tristate ++ tristate "ZLIB inflate support" + + config ZLIB_DEFLATE +- tristate ++ tristate "ZLIB deflate support" + + config LZO_COMPRESS +- tristate ++ tristate "LZO compress support" + + config LZO_DECOMPRESS +- tristate ++ tristate "LZO decompress support" + + config LZ4_COMPRESS +- tristate ++ tristate "LZ4 compress support" + + config LZ4HC_COMPRESS +- tristate ++ tristate "LZ4HC compress support" + + config LZ4_DECOMPRESS +- tristate ++ tristate "LZ4 decompress support" + + source "lib/xz/Kconfig" + diff --git a/target/linux/generic/patches-4.0/270-uapi-kernel.h-glibc-specific-inclusion-of-sysinfo.h.patch b/target/linux/generic/patches-4.0/270-uapi-kernel.h-glibc-specific-inclusion-of-sysinfo.h.patch new file mode 100644 index 0000000..762f498 --- /dev/null +++ b/target/linux/generic/patches-4.0/270-uapi-kernel.h-glibc-specific-inclusion-of-sysinfo.h.patch @@ -0,0 +1,34 @@ +From 8b05e325824d3b38e52a7748b3b5dc34dc1c0f6d Mon Sep 17 00:00:00 2001 +From: David Heidelberger +Date: Mon, 29 Jun 2015 14:37:54 +0200 +Subject: [PATCH 1/3] uapi/kernel.h: glibc specific inclusion of sysinfo.h + +including sysinfo.h from kernel.h makes no sense whatsoever, +but removing it breaks glibc's userspace header, +which includes kernel.h instead of sysinfo.h from their sys/sysinfo.h. +this seems to be a historical mistake. +on musl, including any header that uses kernel.h directly or indirectly +plus sys/sysinfo.h will produce a compile error due to redefinition of +struct sysinfo from sys/sysinfo.h. +so for now, only include it on glibc or when including from kernel +in order not to break their headers. + +Signed-off-by: John Spencer +Signed-off-by: David Heidelberger +Signed-off-by: Jonas Gorski +--- + include/uapi/linux/kernel.h | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/include/uapi/linux/kernel.h ++++ b/include/uapi/linux/kernel.h +@@ -1,7 +1,9 @@ + #ifndef _UAPI_LINUX_KERNEL_H + #define _UAPI_LINUX_KERNEL_H + ++#if defined(__KERNEL__) || defined( __GLIBC__) + #include ++#endif + + /* + * 'kernel.h' contains some often-used function prototypes etc diff --git a/target/linux/generic/patches-4.0/271-uapi-libc-compat.h-do-not-rely-on-__GLIBC__.patch b/target/linux/generic/patches-4.0/271-uapi-libc-compat.h-do-not-rely-on-__GLIBC__.patch new file mode 100644 index 0000000..61d3873 --- /dev/null +++ b/target/linux/generic/patches-4.0/271-uapi-libc-compat.h-do-not-rely-on-__GLIBC__.patch @@ -0,0 +1,81 @@ +From f972afc2509eebcb00d370256c55b112a3b5ffca Mon Sep 17 00:00:00 2001 +From: David Heidelberger +Date: Mon, 29 Jun 2015 16:50:40 +0200 +Subject: [PATCH 2/3] uapi/libc-compat.h: do not rely on __GLIBC__ + +Musl provides the same structs as glibc, but does not provide a define to +allow its detection. Since the absence of __GLIBC__ also can mean that it +is included from the kernel, change the __GLIBC__ detection to +!__KERNEL__, which should always be true when included from userspace. + +Signed-off-by: John Spencer +Tested-by: David Heidelberger +Signed-off-by: Jonas Gorski +--- + include/uapi/linux/libc-compat.h | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +--- a/include/uapi/linux/libc-compat.h ++++ b/include/uapi/linux/libc-compat.h +@@ -48,13 +48,13 @@ + #ifndef _UAPI_LIBC_COMPAT_H + #define _UAPI_LIBC_COMPAT_H + +-/* We have included glibc headers... */ +-#if defined(__GLIBC__) ++/* We have included libc headers... */ ++#if !defined(__KERNEL__) + +-/* Coordinate with glibc netinet/in.h header. */ ++/* Coordinate with libc netinet/in.h header. */ + #if defined(_NETINET_IN_H) + +-/* GLIBC headers included first so don't define anything ++/* LIBC headers included first so don't define anything + * that would already be defined. */ + #define __UAPI_DEF_IN_ADDR 0 + #define __UAPI_DEF_IN_IPPROTO 0 +@@ -68,7 +68,7 @@ + * if the glibc code didn't define them. This guard matches + * the guard in glibc/inet/netinet/in.h which defines the + * additional in6_addr macros e.g. s6_addr16, and s6_addr32. */ +-#if defined(__USE_MISC) || defined (__USE_GNU) ++#if !defined(__GLIBC__) || defined(__USE_MISC) || defined (__USE_GNU) + #define __UAPI_DEF_IN6_ADDR_ALT 0 + #else + #define __UAPI_DEF_IN6_ADDR_ALT 1 +@@ -83,7 +83,7 @@ + #else + + /* Linux headers included first, and we must define everything +- * we need. The expectation is that glibc will check the ++ * we need. The expectation is that the libc will check the + * __UAPI_DEF_* defines and adjust appropriately. */ + #define __UAPI_DEF_IN_ADDR 1 + #define __UAPI_DEF_IN_IPPROTO 1 +@@ -93,7 +93,7 @@ + #define __UAPI_DEF_IN_CLASS 1 + + #define __UAPI_DEF_IN6_ADDR 1 +-/* We unconditionally define the in6_addr macros and glibc must ++/* We unconditionally define the in6_addr macros and the libc must + * coordinate. */ + #define __UAPI_DEF_IN6_ADDR_ALT 1 + #define __UAPI_DEF_SOCKADDR_IN6 1 +@@ -115,7 +115,7 @@ + /* If we did not see any headers from any supported C libraries, + * or we are being included in the kernel, then define everything + * that we need. */ +-#else /* !defined(__GLIBC__) */ ++#else /* defined(__KERNEL__) */ + + /* Definitions for in.h */ + #define __UAPI_DEF_IN_ADDR 1 +@@ -138,6 +138,6 @@ + /* Definitions for xattr.h */ + #define __UAPI_DEF_XATTR 1 + +-#endif /* __GLIBC__ */ ++#endif /* __KERNEL__ */ + + #endif /* _UAPI_LIBC_COMPAT_H */ diff --git a/target/linux/generic/patches-4.0/272-uapi-if_ether.h-prevent-redefinition-of-struct-ethhd.patch b/target/linux/generic/patches-4.0/272-uapi-if_ether.h-prevent-redefinition-of-struct-ethhd.patch new file mode 100644 index 0000000..257c9d7 --- /dev/null +++ b/target/linux/generic/patches-4.0/272-uapi-if_ether.h-prevent-redefinition-of-struct-ethhd.patch @@ -0,0 +1,67 @@ +From fcbb6fed85ea9ff4feb4f1ebd4f0f235fdaf06b6 Mon Sep 17 00:00:00 2001 +From: David Heidelberger +Date: Mon, 29 Jun 2015 16:53:03 +0200 +Subject: [PATCH 3/3] uapi/if_ether.h: prevent redefinition of struct ethhdr + +Musl provides its own ethhdr struct definition. Add a guard to prevent +its definition of the appropriate musl header has already been included. + +Signed-off-by: John Spencer +Tested-by: David Heidelberger +Signed-off-by: Jonas Gorski +--- + include/uapi/linux/if_ether.h | 3 +++ + include/uapi/linux/libc-compat.h | 11 +++++++++++ + 2 files changed, 14 insertions(+) + +--- a/include/uapi/linux/if_ether.h ++++ b/include/uapi/linux/if_ether.h +@@ -22,6 +22,7 @@ + #define _UAPI_LINUX_IF_ETHER_H + + #include ++#include + + /* + * IEEE 802.3 Ethernet magic constants. The frame sizes omit the preamble +@@ -134,11 +135,13 @@ + * This is an Ethernet frame header. + */ + ++#if __UAPI_DEF_ETHHDR + struct ethhdr { + unsigned char h_dest[ETH_ALEN]; /* destination eth addr */ + unsigned char h_source[ETH_ALEN]; /* source ether addr */ + __be16 h_proto; /* packet type ID field */ + } __attribute__((packed)); ++#endif + + + #endif /* _UAPI_LINUX_IF_ETHER_H */ +--- a/include/uapi/linux/libc-compat.h ++++ b/include/uapi/linux/libc-compat.h +@@ -51,6 +51,14 @@ + /* We have included libc headers... */ + #if !defined(__KERNEL__) + ++/* musl defines the ethhdr struct itself in its netinet/if_ether.h. ++ * Glibc just includes the kernel header and uses a different guard. */ ++#if defined(_NETINET_IF_ETHER_H) ++#define __UAPI_DEF_ETHHDR 0 ++#else ++#define __UAPI_DEF_ETHHDR 1 ++#endif ++ + /* Coordinate with libc netinet/in.h header. */ + #if defined(_NETINET_IN_H) + +@@ -117,6 +125,9 @@ + * that we need. */ + #else /* defined(__KERNEL__) */ + ++/* Definitions for if_ether.h */ ++#define __UAPI_DEF_ETHHDR 1 ++ + /* Definitions for in.h */ + #define __UAPI_DEF_IN_ADDR 1 + #define __UAPI_DEF_IN_IPPROTO 1 diff --git a/target/linux/generic/patches-4.0/300-mips_expose_boot_raw.patch b/target/linux/generic/patches-4.0/300-mips_expose_boot_raw.patch new file mode 100644 index 0000000..a609450 --- /dev/null +++ b/target/linux/generic/patches-4.0/300-mips_expose_boot_raw.patch @@ -0,0 +1,39 @@ +From: Mark Miller + +This exposes the CONFIG_BOOT_RAW symbol in Kconfig. This is needed on +certain Broadcom chipsets running CFE in order to load the kernel. + +Signed-off-by: Mark Miller +Acked-by: Rob Landley +--- +--- a/arch/mips/Kconfig ++++ b/arch/mips/Kconfig +@@ -941,9 +941,6 @@ config FW_ARC + config ARCH_MAY_HAVE_PC_FDC + bool + +-config BOOT_RAW +- bool +- + config CEVT_BCM1480 + bool + +@@ -2594,6 +2591,18 @@ config USE_OF + config BUILTIN_DTB + bool + ++config BOOT_RAW ++ bool "Enable the kernel to be executed from the load address" ++ default n ++ help ++ Allow the kernel to be executed from the load address for ++ bootloaders which cannot read the ELF format. This places ++ a jump to start_kernel at the load address. ++ ++ If unsure, say N. ++ ++ ++ + endmenu + + config LOCKDEP_SUPPORT diff --git a/target/linux/generic/patches-4.0/301-mips_image_cmdline_hack.patch b/target/linux/generic/patches-4.0/301-mips_image_cmdline_hack.patch new file mode 100644 index 0000000..b5032e2 --- /dev/null +++ b/target/linux/generic/patches-4.0/301-mips_image_cmdline_hack.patch @@ -0,0 +1,28 @@ +--- a/arch/mips/Kconfig ++++ b/arch/mips/Kconfig +@@ -1030,6 +1030,10 @@ config SYNC_R4K + config MIPS_MACHINE + def_bool n + ++config IMAGE_CMDLINE_HACK ++ bool "OpenWrt specific image command line hack" ++ default n ++ + config NO_IOPORT_MAP + def_bool n + +--- a/arch/mips/kernel/head.S ++++ b/arch/mips/kernel/head.S +@@ -80,6 +80,12 @@ FEXPORT(__kernel_entry) + j kernel_entry + #endif + ++#ifdef CONFIG_IMAGE_CMDLINE_HACK ++ .ascii "CMDLINE:" ++EXPORT(__image_cmdline) ++ .fill 0x400 ++#endif /* CONFIG_IMAGE_CMDLINE_HACK */ ++ + __REF + + NESTED(kernel_entry, 16, sp) # kernel entry point diff --git a/target/linux/generic/patches-4.0/302-mips_no_branch_likely.patch b/target/linux/generic/patches-4.0/302-mips_no_branch_likely.patch new file mode 100644 index 0000000..44c6b04 --- /dev/null +++ b/target/linux/generic/patches-4.0/302-mips_no_branch_likely.patch @@ -0,0 +1,11 @@ +--- a/arch/mips/Makefile ++++ b/arch/mips/Makefile +@@ -87,7 +87,7 @@ all-$(CONFIG_SYS_SUPPORTS_ZBOOT)+= vmlin + # machines may also. Since BFD is incredibly buggy with respect to + # crossformat linking we rely on the elf2ecoff tool for format conversion. + # +-cflags-y += -G 0 -mno-abicalls -fno-pic -pipe ++cflags-y += -G 0 -mno-abicalls -fno-pic -pipe -mno-branch-likely + cflags-y += -msoft-float + LDFLAGS_vmlinux += -G 0 -static -n -nostdlib --gc-sections + KBUILD_AFLAGS_MODULE += -mlong-calls diff --git a/target/linux/generic/patches-4.0/304-mips_disable_fpu.patch b/target/linux/generic/patches-4.0/304-mips_disable_fpu.patch new file mode 100644 index 0000000..080afa3 --- /dev/null +++ b/target/linux/generic/patches-4.0/304-mips_disable_fpu.patch @@ -0,0 +1,105 @@ +From: Manuel Lauss +Subject: [RFC PATCH v4 2/2] MIPS: make FPU emulator optional +Date: Mon, 7 Apr 2014 12:57:04 +0200 +Message-Id: <1396868224-252888-2-git-send-email-manuel.lauss@gmail.com> + +This small patch makes the MIPS FPU emulator optional. The kernel +kills float-users on systems without a hardware FPU by sending a SIGILL. + +Disabling the emulator shrinks vmlinux by about 54kBytes (32bit, +optimizing for size). + +Signed-off-by: Manuel Lauss +--- +v4: rediffed because of patch 1/2, should now work with micromips as well +v3: updated patch description with size savings. +v2: incorporated changes suggested by Jonas Gorski + force the fpu emulator on for micromips: relocating the parts + of the mmips code in the emulator to other areas would be a + much larger change; I went the cheap route instead with this. + + arch/mips/Kbuild | 2 +- + arch/mips/Kconfig | 14 ++++++++++++++ + arch/mips/include/asm/fpu.h | 5 +++-- + arch/mips/include/asm/fpu_emulator.h | 15 +++++++++++++++ + 4 files changed, 33 insertions(+), 3 deletions(-) + +--- a/arch/mips/Kconfig ++++ b/arch/mips/Kconfig +@@ -2586,6 +2586,20 @@ config MIPS_O32_FP64_SUPPORT + + If unsure, say N. + ++config MIPS_FPU_EMULATOR ++ bool "MIPS FPU Emulator" ++ default y ++ help ++ This option lets you disable the built-in MIPS FPU (Coprocessor 1) ++ emulator, which handles floating-point instructions on processors ++ without a hardware FPU. It is generally a good idea to keep the ++ emulator built-in, unless you are perfectly sure you have a ++ complete soft-float environment. With the emulator disabled, all ++ users of float operations will be killed with an illegal instr- ++ uction exception. ++ ++ Say Y, please. ++ + config USE_OF + bool + select OF +--- a/arch/mips/Makefile ++++ b/arch/mips/Makefile +@@ -292,7 +292,7 @@ OBJCOPYFLAGS += --remove-section=.regin + head-y := arch/mips/kernel/head.o + + libs-y += arch/mips/lib/ +-libs-y += arch/mips/math-emu/ ++libs-$(CONFIG_MIPS_FPU_EMULATOR) += arch/mips/math-emu/ + + # See arch/mips/Kbuild for content of core part of the kernel + core-y += arch/mips/ +--- a/arch/mips/include/asm/fpu.h ++++ b/arch/mips/include/asm/fpu.h +@@ -212,8 +212,10 @@ static inline int init_fpu(void) + /* Restore FRE */ + write_c0_config5(config5); + enable_fpu_hazard(); +- } else ++ } else if (IS_ENABLED(CONFIG_MIPS_FPU_EMULATOR)) + fpu_emulator_init_fpu(); ++ else ++ ret = SIGILL; + + return ret; + } +--- a/arch/mips/include/asm/fpu_emulator.h ++++ b/arch/mips/include/asm/fpu_emulator.h +@@ -30,6 +30,7 @@ + #include + #include + ++#ifdef CONFIG_MIPS_FPU_EMULATOR + #ifdef CONFIG_DEBUG_FS + + struct mips_fpu_emulator_stats { +@@ -65,6 +66,20 @@ extern int do_dsemulret(struct pt_regs * + extern int fpu_emulator_cop1Handler(struct pt_regs *xcp, + struct mips_fpu_struct *ctx, int has_fpu, + void *__user *fault_addr); ++#else /* no CONFIG_MIPS_FPU_EMULATOR */ ++static inline int do_dsemulret(struct pt_regs *xcp) ++{ ++ return 0; /* 0 means error, should never get here anyway */ ++} ++ ++static inline int fpu_emulator_cop1Handler(struct pt_regs *xcp, ++ struct mips_fpu_struct *ctx, int has_fpu, ++ void *__user *fault_addr) ++{ ++ return SIGILL; /* we don't speak MIPS FPU */ ++} ++#endif /* CONFIG_MIPS_FPU_EMULATOR */ ++ + int process_fpemu_return(int sig, void __user *fault_addr); + int mm_isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, + unsigned long *contpc); diff --git a/target/linux/generic/patches-4.0/305-mips_module_reloc.patch b/target/linux/generic/patches-4.0/305-mips_module_reloc.patch new file mode 100644 index 0000000..8b3975f --- /dev/null +++ b/target/linux/generic/patches-4.0/305-mips_module_reloc.patch @@ -0,0 +1,352 @@ +--- a/arch/mips/Makefile ++++ b/arch/mips/Makefile +@@ -90,8 +90,13 @@ all-$(CONFIG_SYS_SUPPORTS_ZBOOT)+= vmlin + cflags-y += -G 0 -mno-abicalls -fno-pic -pipe -mno-branch-likely + cflags-y += -msoft-float + LDFLAGS_vmlinux += -G 0 -static -n -nostdlib --gc-sections ++ifdef CONFIG_64BIT + KBUILD_AFLAGS_MODULE += -mlong-calls + KBUILD_CFLAGS_MODULE += -mlong-calls ++else ++KBUILD_AFLAGS_MODULE += -mno-long-calls ++KBUILD_CFLAGS_MODULE += -mno-long-calls ++endif + + ifndef CONFIG_FUNCTION_TRACER + KBUILD_CFLAGS_KERNEL += -ffunction-sections -fdata-sections +--- a/arch/mips/include/asm/module.h ++++ b/arch/mips/include/asm/module.h +@@ -11,6 +11,11 @@ struct mod_arch_specific { + const struct exception_table_entry *dbe_start; + const struct exception_table_entry *dbe_end; + struct mips_hi16 *r_mips_hi16_list; ++ ++ void *phys_plt_tbl; ++ void *virt_plt_tbl; ++ unsigned int phys_plt_offset; ++ unsigned int virt_plt_offset; + }; + + typedef uint8_t Elf64_Byte; /* Type for a 8-bit quantity. */ +--- a/arch/mips/kernel/module.c ++++ b/arch/mips/kernel/module.c +@@ -43,14 +43,221 @@ struct mips_hi16 { + static LIST_HEAD(dbe_list); + static DEFINE_SPINLOCK(dbe_lock); + +-#ifdef MODULE_START ++/* ++ * Get the potential max trampolines size required of the init and ++ * non-init sections. Only used if we cannot find enough contiguous ++ * physically mapped memory to put the module into. ++ */ ++static unsigned int ++get_plt_size(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, ++ const char *secstrings, unsigned int symindex, bool is_init) ++{ ++ unsigned long ret = 0; ++ unsigned int i, j; ++ Elf_Sym *syms; ++ ++ /* Everything marked ALLOC (this includes the exported symbols) */ ++ for (i = 1; i < hdr->e_shnum; ++i) { ++ unsigned int info = sechdrs[i].sh_info; ++ ++ if (sechdrs[i].sh_type != SHT_REL ++ && sechdrs[i].sh_type != SHT_RELA) ++ continue; ++ ++ /* Not a valid relocation section? */ ++ if (info >= hdr->e_shnum) ++ continue; ++ ++ /* Don't bother with non-allocated sections */ ++ if (!(sechdrs[info].sh_flags & SHF_ALLOC)) ++ continue; ++ ++ /* If it's called *.init*, and we're not init, we're ++ not interested */ ++ if ((strstr(secstrings + sechdrs[i].sh_name, ".init") != 0) ++ != is_init) ++ continue; ++ ++ syms = (Elf_Sym *) sechdrs[symindex].sh_addr; ++ if (sechdrs[i].sh_type == SHT_REL) { ++ Elf_Mips_Rel *rel = (void *) sechdrs[i].sh_addr; ++ unsigned int size = sechdrs[i].sh_size / sizeof(*rel); ++ ++ for (j = 0; j < size; ++j) { ++ Elf_Sym *sym; ++ ++ if (ELF_MIPS_R_TYPE(rel[j]) != R_MIPS_26) ++ continue; ++ ++ sym = syms + ELF_MIPS_R_SYM(rel[j]); ++ if (!is_init && sym->st_shndx != SHN_UNDEF) ++ continue; ++ ++ ret += 4 * sizeof(int); ++ } ++ } else { ++ Elf_Mips_Rela *rela = (void *) sechdrs[i].sh_addr; ++ unsigned int size = sechdrs[i].sh_size / sizeof(*rela); ++ ++ for (j = 0; j < size; ++j) { ++ Elf_Sym *sym; ++ ++ if (ELF_MIPS_R_TYPE(rela[j]) != R_MIPS_26) ++ continue; ++ ++ sym = syms + ELF_MIPS_R_SYM(rela[j]); ++ if (!is_init && sym->st_shndx != SHN_UNDEF) ++ continue; ++ ++ ret += 4 * sizeof(int); ++ } ++ } ++ } ++ ++ return ret; ++} ++ ++#ifndef MODULE_START ++static void *alloc_phys(unsigned long size) ++{ ++ unsigned order; ++ struct page *page; ++ struct page *p; ++ ++ size = PAGE_ALIGN(size); ++ order = get_order(size); ++ ++ page = alloc_pages(GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN | ++ __GFP_THISNODE, order); ++ if (!page) ++ return NULL; ++ ++ split_page(page, order); ++ ++ /* mark all pages except for the last one */ ++ for (p = page; p + 1 < page + (size >> PAGE_SHIFT); ++p) ++ set_bit(PG_owner_priv_1, &p->flags); ++ ++ for (p = page + (size >> PAGE_SHIFT); p < page + (1 << order); ++p) ++ __free_page(p); ++ ++ return page_address(page); ++} ++#endif ++ ++static void free_phys(void *ptr) ++{ ++ struct page *page; ++ bool free; ++ ++ page = virt_to_page(ptr); ++ do { ++ free = test_and_clear_bit(PG_owner_priv_1, &page->flags); ++ __free_page(page); ++ page++; ++ } while (free); ++} ++ ++ + void *module_alloc(unsigned long size) + { ++#ifdef MODULE_START + return __vmalloc_node_range(size, 1, MODULE_START, MODULE_END, + GFP_KERNEL, PAGE_KERNEL, 0, NUMA_NO_NODE, + __builtin_return_address(0)); ++#else ++ void *ptr; ++ ++ if (size == 0) ++ return NULL; ++ ++ ptr = alloc_phys(size); ++ ++ /* If we failed to allocate physically contiguous memory, ++ * fall back to regular vmalloc. The module loader code will ++ * create jump tables to handle long jumps */ ++ if (!ptr) ++ return vmalloc(size); ++ ++ return ptr; ++#endif + } ++ ++static inline bool is_phys_addr(void *ptr) ++{ ++#ifdef CONFIG_64BIT ++ return (KSEGX((unsigned long)ptr) == CKSEG0); ++#else ++ return (KSEGX(ptr) == KSEG0); + #endif ++} ++ ++/* Free memory returned from module_alloc */ ++void module_memfree(void *module_region) ++{ ++ if (is_phys_addr(module_region)) ++ free_phys(module_region); ++ else ++ vfree(module_region); ++} ++ ++static void *__module_alloc(int size, bool phys) ++{ ++ void *ptr; ++ ++ if (phys) ++ ptr = kmalloc(size, GFP_KERNEL); ++ else ++ ptr = vmalloc(size); ++ return ptr; ++} ++ ++static void __module_free(void *ptr) ++{ ++ if (is_phys_addr(ptr)) ++ kfree(ptr); ++ else ++ vfree(ptr); ++} ++ ++int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs, ++ char *secstrings, struct module *mod) ++{ ++ unsigned int symindex = 0; ++ unsigned int core_size, init_size; ++ int i; ++ ++ mod->arch.phys_plt_offset = 0; ++ mod->arch.virt_plt_offset = 0; ++ mod->arch.phys_plt_tbl = NULL; ++ mod->arch.virt_plt_tbl = NULL; ++ ++ if (IS_ENABLED(CONFIG_64BIT)) ++ return 0; ++ ++ for (i = 1; i < hdr->e_shnum; i++) ++ if (sechdrs[i].sh_type == SHT_SYMTAB) ++ symindex = i; ++ ++ core_size = get_plt_size(hdr, sechdrs, secstrings, symindex, false); ++ init_size = get_plt_size(hdr, sechdrs, secstrings, symindex, true); ++ ++ if ((core_size + init_size) == 0) ++ return 0; ++ ++ mod->arch.phys_plt_tbl = __module_alloc(core_size + init_size, 1); ++ if (!mod->arch.phys_plt_tbl) ++ return -ENOMEM; ++ ++ mod->arch.virt_plt_tbl = __module_alloc(core_size + init_size, 0); ++ if (!mod->arch.virt_plt_tbl) { ++ __module_free(mod->arch.phys_plt_tbl); ++ mod->arch.phys_plt_tbl = NULL; ++ return -ENOMEM; ++ } ++ ++ return 0; ++} + + int apply_r_mips_none(struct module *me, u32 *location, Elf_Addr v) + { +@@ -64,8 +271,39 @@ static int apply_r_mips_32_rel(struct mo + return 0; + } + ++static Elf_Addr add_plt_entry_to(unsigned *plt_offset, ++ void *start, Elf_Addr v) ++{ ++ unsigned *tramp = start + *plt_offset; ++ *plt_offset += 4 * sizeof(int); ++ ++ /* adjust carry for addiu */ ++ if (v & 0x00008000) ++ v += 0x10000; ++ ++ tramp[0] = 0x3c190000 | (v >> 16); /* lui t9, hi16 */ ++ tramp[1] = 0x27390000 | (v & 0xffff); /* addiu t9, t9, lo16 */ ++ tramp[2] = 0x03200008; /* jr t9 */ ++ tramp[3] = 0x00000000; /* nop */ ++ ++ return (Elf_Addr) tramp; ++} ++ ++static Elf_Addr add_plt_entry(struct module *me, void *location, Elf_Addr v) ++{ ++ if (is_phys_addr(location)) ++ return add_plt_entry_to(&me->arch.phys_plt_offset, ++ me->arch.phys_plt_tbl, v); ++ else ++ return add_plt_entry_to(&me->arch.virt_plt_offset, ++ me->arch.virt_plt_tbl, v); ++ ++} ++ + static int apply_r_mips_26_rel(struct module *me, u32 *location, Elf_Addr v) + { ++ u32 ofs = *location & 0x03ffffff; ++ + if (v % 4) { + pr_err("module %s: dangerous R_MIPS_26 REL relocation\n", + me->name); +@@ -73,14 +311,17 @@ static int apply_r_mips_26_rel(struct mo + } + + if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) { +- printk(KERN_ERR +- "module %s: relocation overflow\n", +- me->name); +- return -ENOEXEC; ++ v = add_plt_entry(me, location, v + (ofs << 2)); ++ if (!v) { ++ printk(KERN_ERR ++ "module %s: relocation overflow\n", me->name); ++ return -ENOEXEC; ++ } ++ ofs = 0; + } + + *location = (*location & ~0x03ffffff) | +- ((*location + (v >> 2)) & 0x03ffffff); ++ ((ofs + (v >> 2)) & 0x03ffffff); + + return 0; + } +@@ -287,9 +528,33 @@ int module_finalize(const Elf_Ehdr *hdr, + list_add(&me->arch.dbe_list, &dbe_list); + spin_unlock_irq(&dbe_lock); + } ++ ++ /* Get rid of the fixup trampoline if we're running the module ++ * from physically mapped address space */ ++ if (me->arch.phys_plt_offset == 0) { ++ __module_free(me->arch.phys_plt_tbl); ++ me->arch.phys_plt_tbl = NULL; ++ } ++ if (me->arch.virt_plt_offset == 0) { ++ __module_free(me->arch.virt_plt_tbl); ++ me->arch.virt_plt_tbl = NULL; ++ } ++ + return 0; + } + ++void module_arch_freeing_init(struct module *mod) ++{ ++ if (mod->arch.phys_plt_tbl) { ++ __module_free(mod->arch.phys_plt_tbl); ++ mod->arch.phys_plt_tbl = NULL; ++ } ++ if (mod->arch.virt_plt_tbl) { ++ __module_free(mod->arch.virt_plt_tbl); ++ mod->arch.virt_plt_tbl = NULL; ++ } ++} ++ + void module_arch_cleanup(struct module *mod) + { + spin_lock_irq(&dbe_lock); diff --git a/target/linux/generic/patches-4.0/306-mips_mem_functions_performance.patch b/target/linux/generic/patches-4.0/306-mips_mem_functions_performance.patch new file mode 100644 index 0000000..9818677 --- /dev/null +++ b/target/linux/generic/patches-4.0/306-mips_mem_functions_performance.patch @@ -0,0 +1,83 @@ +--- a/arch/mips/include/asm/string.h ++++ b/arch/mips/include/asm/string.h +@@ -133,11 +133,44 @@ strncmp(__const__ char *__cs, __const__ + + #define __HAVE_ARCH_MEMSET + extern void *memset(void *__s, int __c, size_t __count); ++#define memset(__s, __c, len) \ ++({ \ ++ size_t __len = (len); \ ++ void *__ret; \ ++ if (__builtin_constant_p(len) && __len >= 64) \ ++ __ret = memset((__s), (__c), __len); \ ++ else \ ++ __ret = __builtin_memset((__s), (__c), __len); \ ++ __ret; \ ++}) + + #define __HAVE_ARCH_MEMCPY + extern void *memcpy(void *__to, __const__ void *__from, size_t __n); ++#define memcpy(dst, src, len) \ ++({ \ ++ size_t __len = (len); \ ++ void *__ret; \ ++ if (__builtin_constant_p(len) && __len >= 64) \ ++ __ret = memcpy((dst), (src), __len); \ ++ else \ ++ __ret = __builtin_memcpy((dst), (src), __len); \ ++ __ret; \ ++}) + + #define __HAVE_ARCH_MEMMOVE + extern void *memmove(void *__dest, __const__ void *__src, size_t __n); ++#define memmove(dst, src, len) \ ++({ \ ++ size_t __len = (len); \ ++ void *__ret; \ ++ if (__builtin_constant_p(len) && __len >= 64) \ ++ __ret = memmove((dst), (src), __len); \ ++ else \ ++ __ret = __builtin_memmove((dst), (src), __len); \ ++ __ret; \ ++}) ++ ++#define __HAVE_ARCH_MEMCMP ++#define memcmp(src1, src2, len) __builtin_memcmp((src1), (src2), (len)) + + #endif /* _ASM_STRING_H */ +--- a/arch/mips/lib/Makefile ++++ b/arch/mips/lib/Makefile +@@ -4,7 +4,7 @@ + + lib-y += bitops.o csum_partial.o delay.o memcpy.o memset.o \ + mips-atomic.o strlen_user.o strncpy_user.o \ +- strnlen_user.o uncached.o ++ strnlen_user.o uncached.o memcmp.o + + obj-y += iomap.o + obj-$(CONFIG_PCI) += iomap-pci.o +--- /dev/null ++++ b/arch/mips/lib/memcmp.c +@@ -0,0 +1,22 @@ ++/* ++ * copied from linux/lib/string.c ++ * ++ * Copyright (C) 1991, 1992 Linus Torvalds ++ */ ++ ++#include ++#include ++ ++#undef memcmp ++int memcmp(const void *cs, const void *ct, size_t count) ++{ ++ const unsigned char *su1, *su2; ++ int res = 0; ++ ++ for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--) ++ if ((res = *su1 - *su2) != 0) ++ break; ++ return res; ++} ++EXPORT_SYMBOL(memcmp); ++ diff --git a/target/linux/generic/patches-4.0/307-mips_highmem_offset.patch b/target/linux/generic/patches-4.0/307-mips_highmem_offset.patch new file mode 100644 index 0000000..c9f0c84 --- /dev/null +++ b/target/linux/generic/patches-4.0/307-mips_highmem_offset.patch @@ -0,0 +1,17 @@ +Adjust highmem offset to 0x10000000 to ensure that all kmalloc allocations +stay within the same 256M boundary. This ensures that -mlong-calls is not +needed on systems with more than 256M RAM. + +Signed-off-by: Felix Fietkau +--- +--- a/arch/mips/include/asm/mach-generic/spaces.h ++++ b/arch/mips/include/asm/mach-generic/spaces.h +@@ -44,7 +44,7 @@ + * Memory above this physical address will be considered highmem. + */ + #ifndef HIGHMEM_START +-#define HIGHMEM_START _AC(0x20000000, UL) ++#define HIGHMEM_START _AC(0x10000000, UL) + #endif + + #endif /* CONFIG_32BIT */ diff --git a/target/linux/generic/patches-4.0/309-mips_fuse_workaround.patch b/target/linux/generic/patches-4.0/309-mips_fuse_workaround.patch new file mode 100644 index 0000000..dc9d89f --- /dev/null +++ b/target/linux/generic/patches-4.0/309-mips_fuse_workaround.patch @@ -0,0 +1,32 @@ +--- a/arch/mips/mm/cache.c ++++ b/arch/mips/mm/cache.c +@@ -38,6 +38,7 @@ void (*__flush_cache_vunmap)(void); + + void (*__flush_kernel_vmap_range)(unsigned long vaddr, int size); + EXPORT_SYMBOL_GPL(__flush_kernel_vmap_range); ++EXPORT_SYMBOL(__flush_cache_all); + void (*__invalidate_kernel_vmap_range)(unsigned long vaddr, int size); + + /* MIPS specific cache operations */ +--- a/fs/fuse/dev.c ++++ b/fs/fuse/dev.c +@@ -20,6 +20,9 @@ + #include + #include + #include ++#ifdef CONFIG_MIPS ++#include ++#endif + + MODULE_ALIAS_MISCDEV(FUSE_MINOR); + MODULE_ALIAS("devname:fuse"); +@@ -825,6 +828,9 @@ static int fuse_copy_fill(struct fuse_co + static int fuse_copy_do(struct fuse_copy_state *cs, void **val, unsigned *size) + { + unsigned ncpy = min(*size, cs->len); ++#ifdef CONFIG_MIPS ++ __flush_cache_all(); ++#endif + if (val) { + void *pgaddr = kmap_atomic(cs->pg); + void *buf = pgaddr + cs->offset; diff --git a/target/linux/generic/patches-4.0/310-arm_module_unresolved_weak_sym.patch b/target/linux/generic/patches-4.0/310-arm_module_unresolved_weak_sym.patch new file mode 100644 index 0000000..9210c1d --- /dev/null +++ b/target/linux/generic/patches-4.0/310-arm_module_unresolved_weak_sym.patch @@ -0,0 +1,13 @@ +--- a/arch/arm/kernel/module.c ++++ b/arch/arm/kernel/module.c +@@ -83,6 +83,10 @@ apply_relocate(Elf32_Shdr *sechdrs, cons + return -ENOEXEC; + } + ++ if ((IS_ERR_VALUE(sym->st_value) || !sym->st_value) && ++ ELF_ST_BIND(sym->st_info) == STB_WEAK) ++ continue; ++ + loc = dstsec->sh_addr + rel->r_offset; + + switch (ELF32_R_TYPE(rel->r_info)) { diff --git a/target/linux/generic/patches-4.0/320-ppc4xx_optimization.patch b/target/linux/generic/patches-4.0/320-ppc4xx_optimization.patch new file mode 100644 index 0000000..8673de4 --- /dev/null +++ b/target/linux/generic/patches-4.0/320-ppc4xx_optimization.patch @@ -0,0 +1,31 @@ +Upstream doesn't optimize the kernel and bootwrappers for ppc44x because +they still want to support gcc 3.3 -- well, we don't. + +--- a/arch/powerpc/Makefile ++++ b/arch/powerpc/Makefile +@@ -203,7 +203,8 @@ ifeq ($(CONFIG_FUNCTION_TRACER),y) + KBUILD_CFLAGS += -mno-sched-epilog + endif + +-cpu-as-$(CONFIG_4xx) += -Wa,-m405 ++cpu-as-$(CONFIG_40x) += -Wa,-m405 ++cpu-as-$(CONFIG_44x) += -Wa,-m440 + cpu-as-$(CONFIG_ALTIVEC) += -Wa,-maltivec + cpu-as-$(CONFIG_E200) += -Wa,-me200 + +--- a/arch/powerpc/boot/Makefile ++++ b/arch/powerpc/boot/Makefile +@@ -45,10 +45,10 @@ BOOTCFLAGS += -I$(obj) -I$(srctree)/$(ob + DTC_FLAGS ?= -p 1024 + + $(obj)/4xx.o: BOOTCFLAGS += -mcpu=405 +-$(obj)/ebony.o: BOOTCFLAGS += -mcpu=405 ++$(obj)/ebony.o: BOOTCFLAGS += -mcpu=440 + $(obj)/cuboot-hotfoot.o: BOOTCFLAGS += -mcpu=405 +-$(obj)/cuboot-taishan.o: BOOTCFLAGS += -mcpu=405 +-$(obj)/cuboot-katmai.o: BOOTCFLAGS += -mcpu=405 ++$(obj)/cuboot-taishan.o: BOOTCFLAGS += -mcpu=440 ++$(obj)/cuboot-katmai.o: BOOTCFLAGS += -mcpu=440 + $(obj)/cuboot-acadia.o: BOOTCFLAGS += -mcpu=405 + $(obj)/treeboot-walnut.o: BOOTCFLAGS += -mcpu=405 + $(obj)/treeboot-iss4xx.o: BOOTCFLAGS += -mcpu=405 diff --git a/target/linux/generic/patches-4.0/321-powerpc_crtsavres_prereq.patch b/target/linux/generic/patches-4.0/321-powerpc_crtsavres_prereq.patch new file mode 100644 index 0000000..ab6ea7b --- /dev/null +++ b/target/linux/generic/patches-4.0/321-powerpc_crtsavres_prereq.patch @@ -0,0 +1,10 @@ +--- a/arch/powerpc/Makefile ++++ b/arch/powerpc/Makefile +@@ -165,7 +165,6 @@ CPP = $(CC) -E $(KBUILD_CFLAGS) + + CHECKFLAGS += -m$(CONFIG_WORD_SIZE) -D__powerpc__ -D__powerpc$(CONFIG_WORD_SIZE)__ + +-KBUILD_LDFLAGS_MODULE += arch/powerpc/lib/crtsavres.o + + ifeq ($(CONFIG_476FPE_ERR46),y) + KBUILD_LDFLAGS_MODULE += --ppc476-workaround \ diff --git a/target/linux/generic/patches-4.0/330-MIPS-kexec-Accept-command-line-parameters-from-users.patch b/target/linux/generic/patches-4.0/330-MIPS-kexec-Accept-command-line-parameters-from-users.patch new file mode 100644 index 0000000..a69d197 --- /dev/null +++ b/target/linux/generic/patches-4.0/330-MIPS-kexec-Accept-command-line-parameters-from-users.patch @@ -0,0 +1,298 @@ +From d8582dcf1ed66eee88a11e4760f42c0d6c8822be Mon Sep 17 00:00:00 2001 +From: Yousong Zhou +Date: Sat, 31 Jan 2015 22:26:03 +0800 +Subject: [PATCH 331/331] MIPS: kexec: Accept command line parameters from + userspace. + +Signed-off-by: Yousong Zhou +--- + arch/mips/kernel/machine_kexec.c | 153 +++++++++++++++++++++++++++++++----- + arch/mips/kernel/machine_kexec.h | 20 +++++ + arch/mips/kernel/relocate_kernel.S | 21 +++-- + 3 files changed, 167 insertions(+), 27 deletions(-) + create mode 100644 arch/mips/kernel/machine_kexec.h + +--- a/arch/mips/kernel/machine_kexec.c ++++ b/arch/mips/kernel/machine_kexec.c +@@ -10,45 +10,145 @@ + #include + #include + ++#include + #include + #include +- +-extern const unsigned char relocate_new_kernel[]; +-extern const size_t relocate_new_kernel_size; +- +-extern unsigned long kexec_start_address; +-extern unsigned long kexec_indirection_page; ++#include ++#include "machine_kexec.h" + + int (*_machine_kexec_prepare)(struct kimage *) = NULL; + void (*_machine_kexec_shutdown)(void) = NULL; + void (*_machine_crash_shutdown)(struct pt_regs *regs) = NULL; ++ + #ifdef CONFIG_SMP + void (*relocated_kexec_smp_wait) (void *); + atomic_t kexec_ready_to_reboot = ATOMIC_INIT(0); + #endif + +-int +-machine_kexec_prepare(struct kimage *kimage) ++static void machine_kexec_print_args(void) + { ++ unsigned long argc = (int)kexec_args[0]; ++ int i; ++ ++ pr_info("kexec_args[0] (argc): %lu\n", argc); ++ pr_info("kexec_args[1] (argv): %p\n", (void *)kexec_args[1]); ++ pr_info("kexec_args[2] (env ): %p\n", (void *)kexec_args[2]); ++ pr_info("kexec_args[3] (desc): %p\n", (void *)kexec_args[3]); ++ ++ for (i = 0; i < argc; i++) { ++ pr_info("kexec_argv[%d] = %p, %s\n", ++ i, kexec_argv[i], kexec_argv[i]); ++ } ++} ++ ++static void machine_kexec_init_argv(struct kimage *image) ++{ ++ void __user *buf = NULL; ++ size_t bufsz; ++ size_t size; ++ int i; ++ ++ bufsz = 0; ++ for (i = 0; i < image->nr_segments; i++) { ++ struct kexec_segment *seg; ++ ++ seg = &image->segment[i]; ++ if (seg->bufsz < 6) ++ continue; ++ ++ if (strncmp((char *) seg->buf, "kexec ", 6)) ++ continue; ++ ++ buf = seg->buf; ++ bufsz = seg->bufsz; ++ break; ++ } ++ ++ if (!buf) ++ return; ++ ++ size = KEXEC_COMMAND_LINE_SIZE; ++ size = min(size, bufsz); ++ if (size < bufsz) ++ pr_warn("kexec command line truncated to %zd bytes\n", size); ++ ++ /* Copy to kernel space */ ++ copy_from_user(kexec_argv_buf, buf, size); ++ kexec_argv_buf[size - 1] = 0; ++} ++ ++static void machine_kexec_parse_argv(struct kimage *image) ++{ ++ char *reboot_code_buffer; ++ int reloc_delta; ++ char *ptr; ++ int argc; ++ int i; ++ ++ ptr = kexec_argv_buf; ++ argc = 0; ++ ++ /* ++ * convert command line string to array of parameters ++ * (as bootloader does). ++ */ ++ while (ptr && *ptr && (KEXEC_MAX_ARGC > argc)) { ++ if (*ptr == ' ') { ++ *ptr++ = '\0'; ++ continue; ++ } ++ ++ kexec_argv[argc++] = ptr; ++ ptr = strchr(ptr, ' '); ++ } ++ ++ if (!argc) ++ return; ++ ++ kexec_args[0] = argc; ++ kexec_args[1] = (unsigned long)kexec_argv; ++ kexec_args[2] = 0; ++ kexec_args[3] = 0; ++ ++ reboot_code_buffer = page_address(image->control_code_page); ++ reloc_delta = reboot_code_buffer - (char *)kexec_relocate_new_kernel; ++ ++ kexec_args[1] += reloc_delta; ++ for (i = 0; i < argc; i++) ++ kexec_argv[i] += reloc_delta; ++} ++ ++int machine_kexec_prepare(struct kimage *kimage) ++{ ++ /* ++ * Whenever arguments passed from kexec-tools, Init the arguments as ++ * the original ones to try avoiding booting failure. ++ */ ++ ++ kexec_args[0] = fw_arg0; ++ kexec_args[1] = fw_arg1; ++ kexec_args[2] = fw_arg2; ++ kexec_args[3] = fw_arg3; ++ ++ machine_kexec_init_argv(kimage); ++ machine_kexec_parse_argv(kimage); ++ + if (_machine_kexec_prepare) + return _machine_kexec_prepare(kimage); + return 0; + } + +-void +-machine_kexec_cleanup(struct kimage *kimage) ++void machine_kexec_cleanup(struct kimage *kimage) + { + } + +-void +-machine_shutdown(void) ++void machine_shutdown(void) + { + if (_machine_kexec_shutdown) + _machine_kexec_shutdown(); + } + +-void +-machine_crash_shutdown(struct pt_regs *regs) ++void machine_crash_shutdown(struct pt_regs *regs) + { + if (_machine_crash_shutdown) + _machine_crash_shutdown(regs); +@@ -66,10 +166,12 @@ machine_kexec(struct kimage *image) + unsigned long *ptr; + + reboot_code_buffer = +- (unsigned long)page_address(image->control_code_page); ++ (unsigned long)page_address(image->control_code_page); ++ pr_info("reboot_code_buffer = %p\n", (void *)reboot_code_buffer); + + kexec_start_address = + (unsigned long) phys_to_virt(image->start); ++ pr_info("kexec_start_address = %p\n", (void *)kexec_start_address); + + if (image->type == KEXEC_TYPE_DEFAULT) { + kexec_indirection_page = +@@ -77,9 +179,19 @@ machine_kexec(struct kimage *image) + } else { + kexec_indirection_page = (unsigned long)&image->head; + } ++ pr_info("kexec_indirection_page = %p\n", (void *)kexec_indirection_page); + +- memcpy((void*)reboot_code_buffer, relocate_new_kernel, +- relocate_new_kernel_size); ++ pr_info("Where is memcpy: %p\n", memcpy); ++ pr_info("kexec_relocate_new_kernel = %p, kexec_relocate_new_kernel_end = %p\n", ++ (void *)kexec_relocate_new_kernel, &kexec_relocate_new_kernel_end); ++ pr_info("Copy %lu bytes from %p to %p\n", KEXEC_RELOCATE_NEW_KERNEL_SIZE, ++ (void *)kexec_relocate_new_kernel, (void *)reboot_code_buffer); ++ memcpy((void*)reboot_code_buffer, kexec_relocate_new_kernel, ++ KEXEC_RELOCATE_NEW_KERNEL_SIZE); ++ ++ pr_info("Before _print_args().\n"); ++ machine_kexec_print_args(); ++ pr_info("Before eval loop.\n"); + + /* + * The generic kexec code builds a page list with physical +@@ -98,15 +210,16 @@ machine_kexec(struct kimage *image) + /* + * we do not want to be bothered. + */ ++ pr_info("Before irq_disable.\n"); + local_irq_disable(); + +- printk("Will call new kernel at %08lx\n", image->start); +- printk("Bye ...\n"); ++ pr_info("Will call new kernel at %08lx\n", image->start); ++ pr_info("Bye ...\n"); + __flush_cache_all(); + #ifdef CONFIG_SMP + /* All secondary cpus now may jump to kexec_wait cycle */ + relocated_kexec_smp_wait = reboot_code_buffer + +- (void *)(kexec_smp_wait - relocate_new_kernel); ++ (void *)(kexec_smp_wait - kexec_relocate_new_kernel); + smp_wmb(); + atomic_set(&kexec_ready_to_reboot, 1); + #endif +--- /dev/null ++++ b/arch/mips/kernel/machine_kexec.h +@@ -0,0 +1,20 @@ ++#ifndef _MACHINE_KEXEC_H ++#define _MACHINE_KEXEC_H ++ ++#ifndef __ASSEMBLY__ ++extern const unsigned char kexec_relocate_new_kernel[]; ++extern unsigned long kexec_relocate_new_kernel_end; ++extern unsigned long kexec_start_address; ++extern unsigned long kexec_indirection_page; ++ ++extern char kexec_argv_buf[]; ++extern char *kexec_argv[]; ++ ++#define KEXEC_RELOCATE_NEW_KERNEL_SIZE ((unsigned long)&kexec_relocate_new_kernel_end - (unsigned long)kexec_relocate_new_kernel) ++#endif /* !__ASSEMBLY__ */ ++ ++#define KEXEC_COMMAND_LINE_SIZE 256 ++#define KEXEC_ARGV_SIZE (KEXEC_COMMAND_LINE_SIZE / 16) ++#define KEXEC_MAX_ARGC (KEXEC_ARGV_SIZE / sizeof(long)) ++ ++#endif +--- a/arch/mips/kernel/relocate_kernel.S ++++ b/arch/mips/kernel/relocate_kernel.S +@@ -12,8 +12,9 @@ + #include + #include + #include ++#include "machine_kexec.h" + +-LEAF(relocate_new_kernel) ++LEAF(kexec_relocate_new_kernel) + PTR_L a0, arg0 + PTR_L a1, arg1 + PTR_L a2, arg2 +@@ -98,7 +99,7 @@ done: + #endif + /* jump to kexec_start_address */ + j s1 +- END(relocate_new_kernel) ++ END(kexec_relocate_new_kernel) + + #ifdef CONFIG_SMP + /* +@@ -184,9 +185,15 @@ kexec_indirection_page: + PTR 0 + .size kexec_indirection_page, PTRSIZE + +-relocate_new_kernel_end: ++kexec_argv_buf: ++ EXPORT(kexec_argv_buf) ++ .skip KEXEC_COMMAND_LINE_SIZE ++ .size kexec_argv_buf, KEXEC_COMMAND_LINE_SIZE ++ ++kexec_argv: ++ EXPORT(kexec_argv) ++ .skip KEXEC_ARGV_SIZE ++ .size kexec_argv, KEXEC_ARGV_SIZE + +-relocate_new_kernel_size: +- EXPORT(relocate_new_kernel_size) +- PTR relocate_new_kernel_end - relocate_new_kernel +- .size relocate_new_kernel_size, PTRSIZE ++kexec_relocate_new_kernel_end: ++ EXPORT(kexec_relocate_new_kernel_end) diff --git a/target/linux/generic/patches-4.0/400-mtd-add-rootfs-split-support.patch b/target/linux/generic/patches-4.0/400-mtd-add-rootfs-split-support.patch new file mode 100644 index 0000000..6cb31dc --- /dev/null +++ b/target/linux/generic/patches-4.0/400-mtd-add-rootfs-split-support.patch @@ -0,0 +1,171 @@ +--- a/drivers/mtd/Kconfig ++++ b/drivers/mtd/Kconfig +@@ -12,6 +12,23 @@ menuconfig MTD + + if MTD + ++menu "OpenWrt specific MTD options" ++ ++config MTD_ROOTFS_ROOT_DEV ++ bool "Automatically set 'rootfs' partition to be root filesystem" ++ default y ++ ++config MTD_SPLIT_FIRMWARE ++ bool "Automatically split firmware partition for kernel+rootfs" ++ default y ++ ++config MTD_SPLIT_FIRMWARE_NAME ++ string "Firmware partition name" ++ depends on MTD_SPLIT_FIRMWARE ++ default "firmware" ++ ++endmenu ++ + config MTD_TESTS + tristate "MTD tests support (DANGEROUS)" + depends on m +--- a/drivers/mtd/mtdpart.c ++++ b/drivers/mtd/mtdpart.c +@@ -29,9 +29,11 @@ + #include + #include + #include ++#include + #include + + #include "mtdcore.h" ++#include "mtdsplit/mtdsplit.h" + + /* Our partition linked list */ + static LIST_HEAD(mtd_partitions); +@@ -45,13 +47,14 @@ struct mtd_part { + struct list_head list; + }; + ++static void mtd_partition_split(struct mtd_info *master, struct mtd_part *part); ++ + /* + * Given a pointer to the MTD object in the mtd_part structure, we can retrieve + * the pointer to that structure with this macro. + */ + #define PART(x) ((struct mtd_part *)(x)) + +- + /* + * MTD methods which simply translate the effective address and pass through + * to the _real_ device. +@@ -546,8 +549,10 @@ out_register: + return slave; + } + +-int mtd_add_partition(struct mtd_info *master, const char *name, +- long long offset, long long length) ++ ++static int ++__mtd_add_partition(struct mtd_info *master, const char *name, ++ long long offset, long long length, bool dup_check) + { + struct mtd_partition part; + struct mtd_part *p, *new; +@@ -579,21 +584,24 @@ int mtd_add_partition(struct mtd_info *m + end = offset + length; + + mutex_lock(&mtd_partitions_mutex); +- list_for_each_entry(p, &mtd_partitions, list) +- if (p->master == master) { +- if ((start >= p->offset) && +- (start < (p->offset + p->mtd.size))) +- goto err_inv; +- +- if ((end >= p->offset) && +- (end < (p->offset + p->mtd.size))) +- goto err_inv; +- } ++ if (dup_check) { ++ list_for_each_entry(p, &mtd_partitions, list) ++ if (p->master == master) { ++ if ((start >= p->offset) && ++ (start < (p->offset + p->mtd.size))) ++ goto err_inv; ++ ++ if ((end >= p->offset) && ++ (end < (p->offset + p->mtd.size))) ++ goto err_inv; ++ } ++ } + + list_add(&new->list, &mtd_partitions); + mutex_unlock(&mtd_partitions_mutex); + + add_mtd_device(&new->mtd); ++ mtd_partition_split(master, new); + + return ret; + err_inv: +@@ -603,6 +611,12 @@ err_inv: + } + EXPORT_SYMBOL_GPL(mtd_add_partition); + ++int mtd_add_partition(struct mtd_info *master, const char *name, ++ long long offset, long long length) ++{ ++ return __mtd_add_partition(master, name, offset, length, true); ++} ++ + int mtd_del_partition(struct mtd_info *master, int partno) + { + struct mtd_part *slave, *next; +@@ -626,6 +640,35 @@ int mtd_del_partition(struct mtd_info *m + } + EXPORT_SYMBOL_GPL(mtd_del_partition); + ++#ifdef CONFIG_MTD_SPLIT_FIRMWARE_NAME ++#define SPLIT_FIRMWARE_NAME CONFIG_MTD_SPLIT_FIRMWARE_NAME ++#else ++#define SPLIT_FIRMWARE_NAME "unused" ++#endif ++ ++static void split_firmware(struct mtd_info *master, struct mtd_part *part) ++{ ++} ++ ++void __weak arch_split_mtd_part(struct mtd_info *master, const char *name, ++ int offset, int size) ++{ ++} ++ ++static void mtd_partition_split(struct mtd_info *master, struct mtd_part *part) ++{ ++ static int rootfs_found = 0; ++ ++ if (rootfs_found) ++ return; ++ ++ if (!strcmp(part->mtd.name, SPLIT_FIRMWARE_NAME) && ++ config_enabled(CONFIG_MTD_SPLIT_FIRMWARE)) ++ split_firmware(master, part); ++ ++ arch_split_mtd_part(master, part->mtd.name, part->offset, ++ part->mtd.size); ++} + /* + * This function, given a master MTD object and a partition table, creates + * and registers slave MTD objects which are bound to the master according to +@@ -655,6 +698,7 @@ int add_mtd_partitions(struct mtd_info * + mutex_unlock(&mtd_partitions_mutex); + + add_mtd_device(&slave->mtd); ++ mtd_partition_split(master, slave); + + cur_offset = slave->offset + slave->mtd.size; + } +--- a/include/linux/mtd/partitions.h ++++ b/include/linux/mtd/partitions.h +@@ -84,5 +84,7 @@ int mtd_add_partition(struct mtd_info *m + long long offset, long long length); + int mtd_del_partition(struct mtd_info *master, int partno); + uint64_t mtd_get_device_size(const struct mtd_info *mtd); ++extern void __weak arch_split_mtd_part(struct mtd_info *master, ++ const char *name, int offset, int size); + + #endif diff --git a/target/linux/generic/patches-4.0/401-mtd-add-support-for-different-partition-parser-types.patch b/target/linux/generic/patches-4.0/401-mtd-add-support-for-different-partition-parser-types.patch new file mode 100644 index 0000000..7f28a25 --- /dev/null +++ b/target/linux/generic/patches-4.0/401-mtd-add-support-for-different-partition-parser-types.patch @@ -0,0 +1,113 @@ +From 02cff0ccaa6d364f5c1eeea83f47ac80ccc967d4 Mon Sep 17 00:00:00 2001 +From: Gabor Juhos +Date: Tue, 3 Sep 2013 18:11:50 +0200 +Subject: [PATCH] mtd: add support for different partition parser types + +Signed-off-by: Gabor Juhos +--- + drivers/mtd/mtdpart.c | 56 ++++++++++++++++++++++++++++++++++++++++ + include/linux/mtd/partitions.h | 11 ++++++++ + 2 files changed, 67 insertions(+) + +--- a/drivers/mtd/mtdpart.c ++++ b/drivers/mtd/mtdpart.c +@@ -728,6 +728,30 @@ static struct mtd_part_parser *get_parti + + #define put_partition_parser(p) do { module_put((p)->owner); } while (0) + ++static struct mtd_part_parser * ++get_partition_parser_by_type(enum mtd_parser_type type, ++ struct mtd_part_parser *start) ++{ ++ struct mtd_part_parser *p, *ret = NULL; ++ ++ spin_lock(&part_parser_lock); ++ ++ p = list_prepare_entry(start, &part_parsers, list); ++ if (start) ++ put_partition_parser(start); ++ ++ list_for_each_entry_continue(p, &part_parsers, list) { ++ if (p->type == type && try_module_get(p->owner)) { ++ ret = p; ++ break; ++ } ++ } ++ ++ spin_unlock(&part_parser_lock); ++ ++ return ret; ++} ++ + void register_mtd_parser(struct mtd_part_parser *p) + { + spin_lock(&part_parser_lock); +@@ -801,6 +825,38 @@ int parse_mtd_partitions(struct mtd_info + return ret; + } + ++int parse_mtd_partitions_by_type(struct mtd_info *master, ++ enum mtd_parser_type type, ++ struct mtd_partition **pparts, ++ struct mtd_part_parser_data *data) ++{ ++ struct mtd_part_parser *prev = NULL; ++ int ret = 0; ++ ++ while (1) { ++ struct mtd_part_parser *parser; ++ ++ parser = get_partition_parser_by_type(type, prev); ++ if (!parser) ++ break; ++ ++ ret = (*parser->parse_fn)(master, pparts, data); ++ ++ if (ret > 0) { ++ put_partition_parser(parser); ++ printk(KERN_NOTICE ++ "%d %s partitions found on MTD device %s\n", ++ ret, parser->name, master->name); ++ break; ++ } ++ ++ prev = parser; ++ } ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(parse_mtd_partitions_by_type); ++ + int mtd_is_partition(const struct mtd_info *mtd) + { + struct mtd_part *part; +--- a/include/linux/mtd/partitions.h ++++ b/include/linux/mtd/partitions.h +@@ -68,12 +68,17 @@ struct mtd_part_parser_data { + * Functions dealing with the various ways of partitioning the space + */ + ++enum mtd_parser_type { ++ MTD_PARSER_TYPE_DEVICE = 0, ++}; ++ + struct mtd_part_parser { + struct list_head list; + struct module *owner; + const char *name; + int (*parse_fn)(struct mtd_info *, struct mtd_partition **, + struct mtd_part_parser_data *); ++ enum mtd_parser_type type; + }; + + extern void register_mtd_parser(struct mtd_part_parser *parser); +@@ -87,4 +92,9 @@ uint64_t mtd_get_device_size(const struc + extern void __weak arch_split_mtd_part(struct mtd_info *master, + const char *name, int offset, int size); + ++int parse_mtd_partitions_by_type(struct mtd_info *master, ++ enum mtd_parser_type type, ++ struct mtd_partition **pparts, ++ struct mtd_part_parser_data *data); ++ + #endif diff --git a/target/linux/generic/patches-4.0/402-mtd-use-typed-mtd-parsers-for-rootfs-and-firmware-split.patch b/target/linux/generic/patches-4.0/402-mtd-use-typed-mtd-parsers-for-rootfs-and-firmware-split.patch new file mode 100644 index 0000000..ea881e1 --- /dev/null +++ b/target/linux/generic/patches-4.0/402-mtd-use-typed-mtd-parsers-for-rootfs-and-firmware-split.patch @@ -0,0 +1,72 @@ +--- a/drivers/mtd/mtdpart.c ++++ b/drivers/mtd/mtdpart.c +@@ -640,6 +640,37 @@ int mtd_del_partition(struct mtd_info *m + } + EXPORT_SYMBOL_GPL(mtd_del_partition); + ++static int ++run_parsers_by_type(struct mtd_part *slave, enum mtd_parser_type type) ++{ ++ struct mtd_partition *parts; ++ int nr_parts; ++ int i; ++ ++ nr_parts = parse_mtd_partitions_by_type(&slave->mtd, type, &parts, ++ NULL); ++ if (nr_parts <= 0) ++ return nr_parts; ++ ++ if (WARN_ON(!parts)) ++ return 0; ++ ++ for (i = 0; i < nr_parts; i++) { ++ /* adjust partition offsets */ ++ parts[i].offset += slave->offset; ++ ++ __mtd_add_partition(slave->master, ++ parts[i].name, ++ parts[i].offset, ++ parts[i].size, ++ false); ++ } ++ ++ kfree(parts); ++ ++ return nr_parts; ++} ++ + #ifdef CONFIG_MTD_SPLIT_FIRMWARE_NAME + #define SPLIT_FIRMWARE_NAME CONFIG_MTD_SPLIT_FIRMWARE_NAME + #else +@@ -648,6 +679,7 @@ EXPORT_SYMBOL_GPL(mtd_del_partition); + + static void split_firmware(struct mtd_info *master, struct mtd_part *part) + { ++ run_parsers_by_type(part, MTD_PARSER_TYPE_FIRMWARE); + } + + void __weak arch_split_mtd_part(struct mtd_info *master, const char *name, +@@ -662,6 +694,12 @@ static void mtd_partition_split(struct m + if (rootfs_found) + return; + ++ if (!strcmp(part->mtd.name, "rootfs")) { ++ run_parsers_by_type(part, MTD_PARSER_TYPE_ROOTFS); ++ ++ rootfs_found = 1; ++ } ++ + if (!strcmp(part->mtd.name, SPLIT_FIRMWARE_NAME) && + config_enabled(CONFIG_MTD_SPLIT_FIRMWARE)) + split_firmware(master, part); +--- a/include/linux/mtd/partitions.h ++++ b/include/linux/mtd/partitions.h +@@ -70,6 +70,8 @@ struct mtd_part_parser_data { + + enum mtd_parser_type { + MTD_PARSER_TYPE_DEVICE = 0, ++ MTD_PARSER_TYPE_ROOTFS, ++ MTD_PARSER_TYPE_FIRMWARE, + }; + + struct mtd_part_parser { diff --git a/target/linux/generic/patches-4.0/403-mtd-hook-mtdsplit-to-Kbuild.patch b/target/linux/generic/patches-4.0/403-mtd-hook-mtdsplit-to-Kbuild.patch new file mode 100644 index 0000000..0cf1c38 --- /dev/null +++ b/target/linux/generic/patches-4.0/403-mtd-hook-mtdsplit-to-Kbuild.patch @@ -0,0 +1,22 @@ +--- a/drivers/mtd/Kconfig ++++ b/drivers/mtd/Kconfig +@@ -27,6 +27,8 @@ config MTD_SPLIT_FIRMWARE_NAME + depends on MTD_SPLIT_FIRMWARE + default "firmware" + ++source "drivers/mtd/mtdsplit/Kconfig" ++ + endmenu + + config MTD_TESTS +--- a/drivers/mtd/Makefile ++++ b/drivers/mtd/Makefile +@@ -6,6 +6,8 @@ + obj-$(CONFIG_MTD) += mtd.o + mtd-y := mtdcore.o mtdsuper.o mtdconcat.o mtdpart.o mtdchar.o + ++obj-$(CONFIG_MTD_SPLIT) += mtdsplit/ ++ + obj-$(CONFIG_MTD_OF_PARTS) += ofpart.o + obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o + obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o diff --git a/target/linux/generic/patches-4.0/404-mtd-add-more-helper-functions.patch b/target/linux/generic/patches-4.0/404-mtd-add-more-helper-functions.patch new file mode 100644 index 0000000..3220391 --- /dev/null +++ b/target/linux/generic/patches-4.0/404-mtd-add-more-helper-functions.patch @@ -0,0 +1,101 @@ +--- a/drivers/mtd/mtdpart.c ++++ b/drivers/mtd/mtdpart.c +@@ -444,14 +444,12 @@ static struct mtd_part *allocate_partiti + if (slave->offset == MTDPART_OFS_APPEND) + slave->offset = cur_offset; + if (slave->offset == MTDPART_OFS_NXTBLK) { +- slave->offset = cur_offset; +- if (mtd_mod_by_eb(cur_offset, master) != 0) { +- /* Round up to next erasesize */ +- slave->offset = (mtd_div_by_eb(cur_offset, master) + 1) * master->erasesize; ++ /* Round up to next erasesize */ ++ slave->offset = mtd_roundup_to_eb(cur_offset, master); ++ if (slave->offset != cur_offset) + printk(KERN_NOTICE "Moving partition %d: " + "0x%012llx -> 0x%012llx\n", partno, + (unsigned long long)cur_offset, (unsigned long long)slave->offset); +- } + } + if (slave->offset == MTDPART_OFS_RETAIN) { + slave->offset = cur_offset; +@@ -671,6 +669,17 @@ run_parsers_by_type(struct mtd_part *sla + return nr_parts; + } + ++static inline unsigned long ++mtd_pad_erasesize(struct mtd_info *mtd, int offset, int len) ++{ ++ unsigned long mask = mtd->erasesize - 1; ++ ++ len += offset & mask; ++ len = (len + mask) & ~mask; ++ len -= offset & mask; ++ return len; ++} ++ + #ifdef CONFIG_MTD_SPLIT_FIRMWARE_NAME + #define SPLIT_FIRMWARE_NAME CONFIG_MTD_SPLIT_FIRMWARE_NAME + #else +@@ -912,6 +921,24 @@ int mtd_is_partition(const struct mtd_in + } + EXPORT_SYMBOL_GPL(mtd_is_partition); + ++struct mtd_info *mtdpart_get_master(const struct mtd_info *mtd) ++{ ++ if (!mtd_is_partition(mtd)) ++ return (struct mtd_info *)mtd; ++ ++ return PART(mtd)->master; ++} ++EXPORT_SYMBOL_GPL(mtdpart_get_master); ++ ++uint64_t mtdpart_get_offset(const struct mtd_info *mtd) ++{ ++ if (!mtd_is_partition(mtd)) ++ return 0; ++ ++ return PART(mtd)->offset; ++} ++EXPORT_SYMBOL_GPL(mtdpart_get_offset); ++ + /* Returns the size of the entire flash chip */ + uint64_t mtd_get_device_size(const struct mtd_info *mtd) + { +--- a/include/linux/mtd/partitions.h ++++ b/include/linux/mtd/partitions.h +@@ -90,6 +90,8 @@ int mtd_is_partition(const struct mtd_in + int mtd_add_partition(struct mtd_info *master, const char *name, + long long offset, long long length); + int mtd_del_partition(struct mtd_info *master, int partno); ++struct mtd_info *mtdpart_get_master(const struct mtd_info *mtd); ++uint64_t mtdpart_get_offset(const struct mtd_info *mtd); + uint64_t mtd_get_device_size(const struct mtd_info *mtd); + extern void __weak arch_split_mtd_part(struct mtd_info *master, + const char *name, int offset, int size); +--- a/include/linux/mtd/mtd.h ++++ b/include/linux/mtd/mtd.h +@@ -334,6 +334,24 @@ static inline uint32_t mtd_mod_by_eb(uin + return do_div(sz, mtd->erasesize); + } + ++static inline uint64_t mtd_roundup_to_eb(uint64_t sz, struct mtd_info *mtd) ++{ ++ if (mtd_mod_by_eb(sz, mtd) == 0) ++ return sz; ++ ++ /* Round up to next erase block */ ++ return (mtd_div_by_eb(sz, mtd) + 1) * mtd->erasesize; ++} ++ ++static inline uint64_t mtd_rounddown_to_eb(uint64_t sz, struct mtd_info *mtd) ++{ ++ if (mtd_mod_by_eb(sz, mtd) == 0) ++ return sz; ++ ++ /* Round down to the start of the current erase block */ ++ return (mtd_div_by_eb(sz, mtd)) * mtd->erasesize; ++} ++ + static inline uint32_t mtd_div_by_ws(uint64_t sz, struct mtd_info *mtd) + { + if (mtd->writesize_shift) diff --git a/target/linux/generic/patches-4.0/405-mtd-old-firmware-uimage-splitter.patch b/target/linux/generic/patches-4.0/405-mtd-old-firmware-uimage-splitter.patch new file mode 100644 index 0000000..fa2fdc0 --- /dev/null +++ b/target/linux/generic/patches-4.0/405-mtd-old-firmware-uimage-splitter.patch @@ -0,0 +1,70 @@ +--- a/drivers/mtd/Kconfig ++++ b/drivers/mtd/Kconfig +@@ -27,6 +27,11 @@ config MTD_SPLIT_FIRMWARE_NAME + depends on MTD_SPLIT_FIRMWARE + default "firmware" + ++config MTD_UIMAGE_SPLIT ++ bool "Enable split support for firmware partitions containing a uImage" ++ depends on MTD_SPLIT_FIRMWARE ++ default y ++ + source "drivers/mtd/mtdsplit/Kconfig" + + endmenu +--- a/drivers/mtd/mtdpart.c ++++ b/drivers/mtd/mtdpart.c +@@ -680,6 +680,37 @@ mtd_pad_erasesize(struct mtd_info *mtd, + return len; + } + ++#define UBOOT_MAGIC 0x27051956 ++ ++static void split_uimage(struct mtd_info *master, struct mtd_part *part) ++{ ++ struct { ++ __be32 magic; ++ __be32 pad[2]; ++ __be32 size; ++ } hdr; ++ size_t len; ++ ++ if (mtd_read(master, part->offset, sizeof(hdr), &len, (void *) &hdr)) ++ return; ++ ++ if (len != sizeof(hdr) || hdr.magic != cpu_to_be32(UBOOT_MAGIC)) ++ return; ++ ++ len = be32_to_cpu(hdr.size) + 0x40; ++ len = mtd_pad_erasesize(master, part->offset, len); ++ if (len + master->erasesize > part->mtd.size) ++ return; ++ ++ if (config_enabled(CONFIG_MTD_SPLIT_UIMAGE_FW)) ++ pr_err("Dedicated partitioner didn't split firmware partition, please fill a bug report!\n"); ++ else ++ pr_warn("Support for built-in firmware splitter will be removed, please use CONFIG_MTD_SPLIT_UIMAGE_FW\n"); ++ ++ __mtd_add_partition(master, "rootfs", part->offset + len, ++ part->mtd.size - len, false); ++} ++ + #ifdef CONFIG_MTD_SPLIT_FIRMWARE_NAME + #define SPLIT_FIRMWARE_NAME CONFIG_MTD_SPLIT_FIRMWARE_NAME + #else +@@ -688,7 +719,14 @@ mtd_pad_erasesize(struct mtd_info *mtd, + + static void split_firmware(struct mtd_info *master, struct mtd_part *part) + { +- run_parsers_by_type(part, MTD_PARSER_TYPE_FIRMWARE); ++ int ret; ++ ++ ret = run_parsers_by_type(part, MTD_PARSER_TYPE_FIRMWARE); ++ if (ret > 0) ++ return; ++ ++ if (config_enabled(CONFIG_MTD_UIMAGE_SPLIT)) ++ split_uimage(master, part); + } + + void __weak arch_split_mtd_part(struct mtd_info *master, const char *name, diff --git a/target/linux/generic/patches-4.0/406-mtd-old-rootfs-squashfs-splitter.patch b/target/linux/generic/patches-4.0/406-mtd-old-rootfs-squashfs-splitter.patch new file mode 100644 index 0000000..3e72cd4 --- /dev/null +++ b/target/linux/generic/patches-4.0/406-mtd-old-rootfs-squashfs-splitter.patch @@ -0,0 +1,76 @@ +--- a/drivers/mtd/Kconfig ++++ b/drivers/mtd/Kconfig +@@ -18,6 +18,11 @@ config MTD_ROOTFS_ROOT_DEV + bool "Automatically set 'rootfs' partition to be root filesystem" + default y + ++config MTD_ROOTFS_SPLIT ++ bool "Automatically split 'rootfs' partition for squashfs" ++ select MTD_SPLIT ++ default y ++ + config MTD_SPLIT_FIRMWARE + bool "Automatically split firmware partition for kernel+rootfs" + default y +--- a/drivers/mtd/mtdpart.c ++++ b/drivers/mtd/mtdpart.c +@@ -680,6 +680,47 @@ mtd_pad_erasesize(struct mtd_info *mtd, + return len; + } + ++static int split_squashfs(struct mtd_info *master, int offset, int *split_offset) ++{ ++ size_t squashfs_len; ++ int len, ret; ++ ++ ret = mtd_get_squashfs_len(master, offset, &squashfs_len); ++ if (ret) ++ return ret; ++ ++ len = mtd_pad_erasesize(master, offset, squashfs_len); ++ *split_offset = offset + len; ++ ++ return 0; ++} ++ ++static void split_rootfs_data(struct mtd_info *master, struct mtd_part *part) ++{ ++ unsigned int split_offset = 0; ++ unsigned int split_size; ++ int ret; ++ ++ ret = split_squashfs(master, part->offset, &split_offset); ++ if (ret) ++ return; ++ ++ if (split_offset <= 0) ++ return; ++ ++ if (config_enabled(CONFIG_MTD_SPLIT_SQUASHFS_ROOT)) ++ pr_err("Dedicated partitioner didn't create \"rootfs_data\" partition, please fill a bug report!\n"); ++ else ++ pr_warn("Support for built-in \"rootfs_data\" splitter will be removed, please use CONFIG_MTD_SPLIT_SQUASHFS_ROOT\n"); ++ ++ split_size = part->mtd.size - (split_offset - part->offset); ++ printk(KERN_INFO "mtd: partition \"%s\" created automatically, ofs=0x%x, len=0x%x\n", ++ ROOTFS_SPLIT_NAME, split_offset, split_size); ++ ++ __mtd_add_partition(master, ROOTFS_SPLIT_NAME, split_offset, ++ split_size, false); ++} ++ + #define UBOOT_MAGIC 0x27051956 + + static void split_uimage(struct mtd_info *master, struct mtd_part *part) +@@ -742,7 +783,10 @@ static void mtd_partition_split(struct m + return; + + if (!strcmp(part->mtd.name, "rootfs")) { +- run_parsers_by_type(part, MTD_PARSER_TYPE_ROOTFS); ++ int num = run_parsers_by_type(part, MTD_PARSER_TYPE_ROOTFS); ++ ++ if (num <= 0 && config_enabled(CONFIG_MTD_ROOTFS_SPLIT)) ++ split_rootfs_data(master, part); + + rootfs_found = 1; + } diff --git a/target/linux/generic/patches-4.0/410-mtd-move-forward-declaration-of-struct-mtd_info.patch b/target/linux/generic/patches-4.0/410-mtd-move-forward-declaration-of-struct-mtd_info.patch new file mode 100644 index 0000000..78ebbf8 --- /dev/null +++ b/target/linux/generic/patches-4.0/410-mtd-move-forward-declaration-of-struct-mtd_info.patch @@ -0,0 +1,18 @@ +--- a/include/linux/mtd/partitions.h ++++ b/include/linux/mtd/partitions.h +@@ -35,6 +35,7 @@ + * Note: writeable partitions require their size and offset be + * erasesize aligned (e.g. use MTDPART_OFS_NEXTBLK). + */ ++struct mtd_info; + + struct mtd_partition { + const char *name; /* identifier string */ +@@ -50,7 +51,6 @@ struct mtd_partition { + #define MTDPART_SIZ_FULL (0) + + +-struct mtd_info; + struct device_node; + + /** diff --git a/target/linux/generic/patches-4.0/411-mtd-partial_eraseblock_write.patch b/target/linux/generic/patches-4.0/411-mtd-partial_eraseblock_write.patch new file mode 100644 index 0000000..ada7cc1 --- /dev/null +++ b/target/linux/generic/patches-4.0/411-mtd-partial_eraseblock_write.patch @@ -0,0 +1,142 @@ +--- a/drivers/mtd/mtdpart.c ++++ b/drivers/mtd/mtdpart.c +@@ -35,6 +35,8 @@ + #include "mtdcore.h" + #include "mtdsplit/mtdsplit.h" + ++#define MTD_ERASE_PARTIAL 0x8000 /* partition only covers parts of an erase block */ ++ + /* Our partition linked list */ + static LIST_HEAD(mtd_partitions); + static DEFINE_MUTEX(mtd_partitions_mutex); +@@ -233,13 +235,61 @@ static int part_erase(struct mtd_info *m + struct mtd_part *part = PART(mtd); + int ret; + ++ ++ instr->partial_start = false; ++ if (mtd->flags & MTD_ERASE_PARTIAL) { ++ size_t readlen = 0; ++ u64 mtd_ofs; ++ ++ instr->erase_buf = kmalloc(part->master->erasesize, GFP_ATOMIC); ++ if (!instr->erase_buf) ++ return -ENOMEM; ++ ++ mtd_ofs = part->offset + instr->addr; ++ instr->erase_buf_ofs = do_div(mtd_ofs, part->master->erasesize); ++ ++ if (instr->erase_buf_ofs > 0) { ++ instr->addr -= instr->erase_buf_ofs; ++ ret = mtd_read(part->master, ++ instr->addr + part->offset, ++ part->master->erasesize, ++ &readlen, instr->erase_buf); ++ ++ instr->len += instr->erase_buf_ofs; ++ instr->partial_start = true; ++ } else { ++ mtd_ofs = part->offset + part->mtd.size; ++ instr->erase_buf_ofs = part->master->erasesize - ++ do_div(mtd_ofs, part->master->erasesize); ++ ++ if (instr->erase_buf_ofs > 0) { ++ instr->len += instr->erase_buf_ofs; ++ ret = mtd_read(part->master, ++ part->offset + instr->addr + ++ instr->len - part->master->erasesize, ++ part->master->erasesize, &readlen, ++ instr->erase_buf); ++ } else { ++ ret = 0; ++ } ++ } ++ if (ret < 0) { ++ kfree(instr->erase_buf); ++ return ret; ++ } ++ ++ } ++ + instr->addr += part->offset; + ret = part->master->_erase(part->master, instr); + if (ret) { + if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN) + instr->fail_addr -= part->offset; + instr->addr -= part->offset; ++ if (mtd->flags & MTD_ERASE_PARTIAL) ++ kfree(instr->erase_buf); + } ++ + return ret; + } + +@@ -247,7 +297,25 @@ void mtd_erase_callback(struct erase_inf + { + if (instr->mtd->_erase == part_erase) { + struct mtd_part *part = PART(instr->mtd); ++ size_t wrlen = 0; + ++ if (instr->mtd->flags & MTD_ERASE_PARTIAL) { ++ if (instr->partial_start) { ++ part->master->_write(part->master, ++ instr->addr, instr->erase_buf_ofs, ++ &wrlen, instr->erase_buf); ++ instr->addr += instr->erase_buf_ofs; ++ } else { ++ instr->len -= instr->erase_buf_ofs; ++ part->master->_write(part->master, ++ instr->addr + instr->len, ++ instr->erase_buf_ofs, &wrlen, ++ instr->erase_buf + ++ part->master->erasesize - ++ instr->erase_buf_ofs); ++ } ++ kfree(instr->erase_buf); ++ } + if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN) + instr->fail_addr -= part->offset; + instr->addr -= part->offset; +@@ -513,17 +581,20 @@ static struct mtd_part *allocate_partiti + if ((slave->mtd.flags & MTD_WRITEABLE) && + mtd_mod_by_eb(slave->offset, &slave->mtd)) { + /* Doesn't start on a boundary of major erase size */ +- /* FIXME: Let it be writable if it is on a boundary of +- * _minor_ erase size though */ +- slave->mtd.flags &= ~MTD_WRITEABLE; +- printk(KERN_WARNING"mtd: partition \"%s\" doesn't start on an erase block boundary -- force read-only\n", +- part->name); ++ slave->mtd.flags |= MTD_ERASE_PARTIAL; ++ if (((u32) slave->mtd.size) > master->erasesize) ++ slave->mtd.flags &= ~MTD_WRITEABLE; ++ else ++ slave->mtd.erasesize = slave->mtd.size; + } + if ((slave->mtd.flags & MTD_WRITEABLE) && +- mtd_mod_by_eb(slave->mtd.size, &slave->mtd)) { +- slave->mtd.flags &= ~MTD_WRITEABLE; +- printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n", +- part->name); ++ mtd_mod_by_eb(slave->offset + slave->mtd.size, &slave->mtd)) { ++ slave->mtd.flags |= MTD_ERASE_PARTIAL; ++ ++ if ((u32) slave->mtd.size > master->erasesize) ++ slave->mtd.flags &= ~MTD_WRITEABLE; ++ else ++ slave->mtd.erasesize = slave->mtd.size; + } + + slave->mtd.ecclayout = master->ecclayout; +--- a/include/linux/mtd/mtd.h ++++ b/include/linux/mtd/mtd.h +@@ -55,6 +55,10 @@ struct erase_info { + u_long priv; + u_char state; + struct erase_info *next; ++ ++ u8 *erase_buf; ++ u32 erase_buf_ofs; ++ bool partial_start; + }; + + struct mtd_erase_region_info { diff --git a/target/linux/generic/patches-4.0/412-mtd-partial_eraseblock_unlock.patch b/target/linux/generic/patches-4.0/412-mtd-partial_eraseblock_unlock.patch new file mode 100644 index 0000000..ba45acc --- /dev/null +++ b/target/linux/generic/patches-4.0/412-mtd-partial_eraseblock_unlock.patch @@ -0,0 +1,18 @@ +--- a/drivers/mtd/mtdpart.c ++++ b/drivers/mtd/mtdpart.c +@@ -334,7 +334,14 @@ static int part_lock(struct mtd_info *mt + static int part_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) + { + struct mtd_part *part = PART(mtd); +- return part->master->_unlock(part->master, ofs + part->offset, len); ++ ++ ofs += part->offset; ++ if (mtd->flags & MTD_ERASE_PARTIAL) { ++ /* round up len to next erasesize and round down offset to prev block */ ++ len = (mtd_div_by_eb(len, part->master) + 1) * part->master->erasesize; ++ ofs &= ~(part->master->erasesize - 1); ++ } ++ return part->master->_unlock(part->master, ofs, len); + } + + static int part_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len) diff --git a/target/linux/generic/patches-4.0/420-mtd-redboot_space.patch b/target/linux/generic/patches-4.0/420-mtd-redboot_space.patch new file mode 100644 index 0000000..f74affc --- /dev/null +++ b/target/linux/generic/patches-4.0/420-mtd-redboot_space.patch @@ -0,0 +1,30 @@ +--- a/drivers/mtd/redboot.c ++++ b/drivers/mtd/redboot.c +@@ -265,14 +265,21 @@ static int parse_redboot_partitions(stru + #endif + names += strlen(names)+1; + +-#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED + if(fl->next && fl->img->flash_base + fl->img->size + master->erasesize <= fl->next->img->flash_base) { +- i++; +- parts[i].offset = parts[i-1].size + parts[i-1].offset; +- parts[i].size = fl->next->img->flash_base - parts[i].offset; +- parts[i].name = nullname; +- } ++ if (!strcmp(parts[i].name, "rootfs")) { ++ parts[i].size = fl->next->img->flash_base; ++ parts[i].size &= ~(master->erasesize - 1); ++ parts[i].size -= parts[i].offset; ++#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED ++ nrparts--; ++ } else { ++ i++; ++ parts[i].offset = parts[i-1].size + parts[i-1].offset; ++ parts[i].size = fl->next->img->flash_base - parts[i].offset; ++ parts[i].name = nullname; + #endif ++ } ++ } + tmp_fl = fl; + fl = fl->next; + kfree(tmp_fl); diff --git a/target/linux/generic/patches-4.0/430-mtd-add-myloader-partition-parser.patch b/target/linux/generic/patches-4.0/430-mtd-add-myloader-partition-parser.patch new file mode 100644 index 0000000..25e0ecd --- /dev/null +++ b/target/linux/generic/patches-4.0/430-mtd-add-myloader-partition-parser.patch @@ -0,0 +1,35 @@ +--- a/drivers/mtd/Kconfig ++++ b/drivers/mtd/Kconfig +@@ -184,6 +184,22 @@ config MTD_BCM47XX_PARTS + This provides partitions parser for devices based on BCM47xx + boards. + ++config MTD_MYLOADER_PARTS ++ tristate "MyLoader partition parsing" ++ depends on ADM5120 || ATH25 || ATH79 ++ ---help--- ++ MyLoader is a bootloader which allows the user to define partitions ++ in flash devices, by putting a table in the second erase block ++ on the device, similar to a partition table. This table gives the ++ offsets and lengths of the user defined partitions. ++ ++ If you need code which can detect and parse these tables, and ++ register MTD 'partitions' corresponding to each image detected, ++ enable this option. ++ ++ You will still need the parsing functions to be called by the driver ++ for your particular device. It won't happen automatically. ++ + comment "User Modules And Translation Layers" + + # +--- a/drivers/mtd/Makefile ++++ b/drivers/mtd/Makefile +@@ -15,6 +15,7 @@ obj-$(CONFIG_MTD_AFS_PARTS) += afs.o + obj-$(CONFIG_MTD_AR7_PARTS) += ar7part.o + obj-$(CONFIG_MTD_BCM63XX_PARTS) += bcm63xxpart.o + obj-$(CONFIG_MTD_BCM47XX_PARTS) += bcm47xxpart.o ++obj-$(CONFIG_MTD_MYLOADER_PARTS) += myloader.o + + # 'Users' - code which presents functionality to userspace. + obj-$(CONFIG_MTD_BLKDEVS) += mtd_blkdevs.o diff --git a/target/linux/generic/patches-4.0/431-mtd-bcm47xxpart-support-for-Xiaomi-specific-board_da.patch b/target/linux/generic/patches-4.0/431-mtd-bcm47xxpart-support-for-Xiaomi-specific-board_da.patch new file mode 100644 index 0000000..a30e698 --- /dev/null +++ b/target/linux/generic/patches-4.0/431-mtd-bcm47xxpart-support-for-Xiaomi-specific-board_da.patch @@ -0,0 +1,34 @@ +From 841e59ba3e496d86ca5f069204d5e5c1ad43c01d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Tue, 27 Jan 2015 22:29:21 +0100 +Subject: [PATCH] mtd: bcm47xxpart: support for Xiaomi specific board_data + partition +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Rafał Miłecki +--- + drivers/mtd/bcm47xxpart.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/mtd/bcm47xxpart.c ++++ b/drivers/mtd/bcm47xxpart.c +@@ -33,6 +33,7 @@ + /* Magics */ + #define BOARD_DATA_MAGIC 0x5246504D /* MPFR */ + #define BOARD_DATA_MAGIC2 0xBD0D0BBD ++#define BOARD_DATA_XIAOMI_MAGIC 0x474D4442 /* GMDB */ + #define CFE_MAGIC 0x43464531 /* 1EFC */ + #define FACTORY_MAGIC 0x59544346 /* FCTY */ + #define NVRAM_HEADER 0x48534C46 /* FLSH */ +@@ -262,7 +263,8 @@ static int bcm47xxpart_parse(struct mtd_ + } + + /* Some devices (ex. WNDR3700v3) don't have a standard 'MPFR' */ +- if (buf[0x000 / 4] == BOARD_DATA_MAGIC2) { ++ if (buf[0x000 / 4] == BOARD_DATA_MAGIC2 || ++ le32_to_cpu(buf[0x000 / 4]) == BOARD_DATA_XIAOMI_MAGIC) { + bcm47xxpart_add_part(&parts[curr_part++], "board_data", + offset, MTD_WRITEABLE); + continue; diff --git a/target/linux/generic/patches-4.0/432-mtd-bcm47xxpart-detect-T_Meter-partition.patch b/target/linux/generic/patches-4.0/432-mtd-bcm47xxpart-detect-T_Meter-partition.patch new file mode 100644 index 0000000..1edc995 --- /dev/null +++ b/target/linux/generic/patches-4.0/432-mtd-bcm47xxpart-detect-T_Meter-partition.patch @@ -0,0 +1,42 @@ +From fd54aa583296f9adfb1f519affbc10ba521eb809 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Wed, 28 Jan 2015 22:14:41 +0100 +Subject: [PATCH] mtd: bcm47xxpart: detect T_Meter partition +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +It can be found on many Netgear devices. It consists of many 0x30 blocks +starting with 4D 54. + +Signed-off-by: Rafał Miłecki +--- + drivers/mtd/bcm47xxpart.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +--- a/drivers/mtd/bcm47xxpart.c ++++ b/drivers/mtd/bcm47xxpart.c +@@ -39,6 +39,7 @@ + #define NVRAM_HEADER 0x48534C46 /* FLSH */ + #define POT_MAGIC1 0x54544f50 /* POTT */ + #define POT_MAGIC2 0x504f /* OP */ ++#define T_METER_MAGIC 0x4D540000 /* MT */ + #define ML_MAGIC1 0x39685a42 + #define ML_MAGIC2 0x26594131 + #define TRX_MAGIC 0x30524448 +@@ -176,6 +177,15 @@ static int bcm47xxpart_parse(struct mtd_ + MTD_WRITEABLE); + continue; + } ++ ++ /* T_Meter */ ++ if ((le32_to_cpu(buf[0x000 / 4]) & 0xFFFF0000) == T_METER_MAGIC && ++ (le32_to_cpu(buf[0x030 / 4]) & 0xFFFF0000) == T_METER_MAGIC && ++ (le32_to_cpu(buf[0x060 / 4]) & 0xFFFF0000) == T_METER_MAGIC) { ++ bcm47xxpart_add_part(&parts[curr_part++], "T_Meter", offset, ++ MTD_WRITEABLE); ++ continue; ++ } + + /* TRX */ + if (buf[0x000 / 4] == TRX_MAGIC) { diff --git a/target/linux/generic/patches-4.0/440-block2mtd_init.patch b/target/linux/generic/patches-4.0/440-block2mtd_init.patch new file mode 100644 index 0000000..5ab6026 --- /dev/null +++ b/target/linux/generic/patches-4.0/440-block2mtd_init.patch @@ -0,0 +1,107 @@ +--- a/drivers/mtd/devices/block2mtd.c ++++ b/drivers/mtd/devices/block2mtd.c +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -209,11 +210,12 @@ static void block2mtd_free_device(struct + } + + +-static struct block2mtd_dev *add_device(char *devname, int erase_size) ++static struct block2mtd_dev *add_device(char *devname, int erase_size, const char *mtdname) + { + const fmode_t mode = FMODE_READ | FMODE_WRITE | FMODE_EXCL; + struct block_device *bdev; + struct block2mtd_dev *dev; ++ struct mtd_partition *part; + char *name; + + if (!devname) +@@ -257,13 +259,16 @@ static struct block2mtd_dev *add_device( + + /* Setup the MTD structure */ + /* make the name contain the block device in */ +- name = kasprintf(GFP_KERNEL, "block2mtd: %s", devname); ++ if (!mtdname) ++ mtdname = devname; ++ name = kmalloc(strlen(mtdname) + 1, GFP_KERNEL); + if (!name) + goto err_destroy_mutex; + ++ strcpy(name, mtdname); + dev->mtd.name = name; + +- dev->mtd.size = dev->blkdev->bd_inode->i_size & PAGE_MASK; ++ dev->mtd.size = dev->blkdev->bd_inode->i_size & PAGE_MASK & ~(erase_size - 1); + dev->mtd.erasesize = erase_size; + dev->mtd.writesize = 1; + dev->mtd.writebufsize = PAGE_SIZE; +@@ -276,15 +281,18 @@ static struct block2mtd_dev *add_device( + dev->mtd.priv = dev; + dev->mtd.owner = THIS_MODULE; + +- if (mtd_device_register(&dev->mtd, NULL, 0)) { ++ part = kzalloc(sizeof(struct mtd_partition), GFP_KERNEL); ++ part->name = name; ++ part->offset = 0; ++ part->size = dev->mtd.size; ++ if (mtd_device_register(&dev->mtd, part, 1)) { + /* Device didn't get added, so free the entry */ + goto err_destroy_mutex; + } + list_add(&dev->list, &blkmtd_device_list); + pr_info("mtd%d: [%s] erase_size = %dKiB [%d]\n", + dev->mtd.index, +- dev->mtd.name + strlen("block2mtd: "), +- dev->mtd.erasesize >> 10, dev->mtd.erasesize); ++ mtdname, dev->mtd.erasesize >> 10, dev->mtd.erasesize); + return dev; + + err_destroy_mutex: +@@ -353,9 +361,9 @@ static char block2mtd_paramline[80 + 12] + + static int block2mtd_setup2(const char *val) + { +- char buf[80 + 12]; /* 80 for device, 12 for erase size */ ++ char buf[80 + 12 + 80]; /* 80 for device, 12 for erase size, 80 for name */ + char *str = buf; +- char *token[2]; ++ char *token[3]; + char *name; + size_t erase_size = PAGE_SIZE; + int i, ret; +@@ -368,7 +376,7 @@ static int block2mtd_setup2(const char * + strcpy(str, val); + kill_final_newline(str); + +- for (i = 0; i < 2; i++) ++ for (i = 0; i < 3; i++) + token[i] = strsep(&str, ","); + + if (str) { +@@ -394,8 +402,10 @@ static int block2mtd_setup2(const char * + return 0; + } + } ++ if (token[2] && (strlen(token[2]) + 1 > 80)) ++ pr_err("mtd device name too long\n"); + +- add_device(name, erase_size); ++ add_device(name, erase_size, token[2]); + + return 0; + } +@@ -429,7 +439,7 @@ static int block2mtd_setup(const char *v + + + module_param_call(block2mtd, block2mtd_setup, NULL, NULL, 0200); +-MODULE_PARM_DESC(block2mtd, "Device to use. \"block2mtd=[,]\""); ++MODULE_PARM_DESC(block2mtd, "Device to use. \"block2mtd=[,[,]]\""); + + static int __init block2mtd_init(void) + { diff --git a/target/linux/generic/patches-4.0/441-block2mtd_probe.patch b/target/linux/generic/patches-4.0/441-block2mtd_probe.patch new file mode 100644 index 0000000..6836a48 --- /dev/null +++ b/target/linux/generic/patches-4.0/441-block2mtd_probe.patch @@ -0,0 +1,110 @@ +--- a/drivers/mtd/devices/block2mtd.c ++++ b/drivers/mtd/devices/block2mtd.c +@@ -10,6 +10,7 @@ + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + + #include ++#include + #include + #include + #include +@@ -210,13 +211,16 @@ static void block2mtd_free_device(struct + } + + +-static struct block2mtd_dev *add_device(char *devname, int erase_size, const char *mtdname) ++static struct block2mtd_dev *add_device(char *devname, int erase_size, const char *mtdname, int timeout) + { + const fmode_t mode = FMODE_READ | FMODE_WRITE | FMODE_EXCL; +- struct block_device *bdev; ++ struct block_device *bdev = ERR_PTR(-ENODEV); + struct block2mtd_dev *dev; + struct mtd_partition *part; + char *name; ++#ifndef MODULE ++ int i; ++#endif + + if (!devname) + return NULL; +@@ -227,15 +231,20 @@ static struct block2mtd_dev *add_device( + + /* Get a handle on the device */ + bdev = blkdev_get_by_path(devname, mode, dev); ++ + #ifndef MODULE +- if (IS_ERR(bdev)) { ++ for (i = 0; IS_ERR(bdev) && i <= timeout; i++) { ++ dev_t devt; + +- /* We might not have rootfs mounted at this point. Try +- to resolve the device name by other means. */ ++ if (i) ++ msleep(1000); ++ wait_for_device_probe(); ++ ++ devt = name_to_dev_t(devname); ++ if (!devt) ++ continue; + +- dev_t devt = name_to_dev_t(devname); +- if (devt) +- bdev = blkdev_get_by_dev(devt, mode, dev); ++ bdev = blkdev_get_by_dev(devt, mode, dev); + } + #endif + +@@ -361,11 +370,12 @@ static char block2mtd_paramline[80 + 12] + + static int block2mtd_setup2(const char *val) + { +- char buf[80 + 12 + 80]; /* 80 for device, 12 for erase size, 80 for name */ ++ char buf[80 + 12 + 80 + 8]; /* 80 for device, 12 for erase size, 80 for name, 8 for timeout */ + char *str = buf; +- char *token[3]; ++ char *token[4]; + char *name; + size_t erase_size = PAGE_SIZE; ++ unsigned long timeout = 0; + int i, ret; + + if (strnlen(val, sizeof(buf)) >= sizeof(buf)) { +@@ -376,7 +386,7 @@ static int block2mtd_setup2(const char * + strcpy(str, val); + kill_final_newline(str); + +- for (i = 0; i < 3; i++) ++ for (i = 0; i < 4; i++) + token[i] = strsep(&str, ","); + + if (str) { +@@ -405,7 +415,10 @@ static int block2mtd_setup2(const char * + if (token[2] && (strlen(token[2]) + 1 > 80)) + pr_err("mtd device name too long\n"); + +- add_device(name, erase_size, token[2]); ++ if (token[3] && kstrtoul(token[3], 0, &timeout)) ++ pr_err("invalid timeout\n"); ++ ++ add_device(name, erase_size, token[2], timeout); + + return 0; + } +@@ -439,7 +452,7 @@ static int block2mtd_setup(const char *v + + + module_param_call(block2mtd, block2mtd_setup, NULL, NULL, 0200); +-MODULE_PARM_DESC(block2mtd, "Device to use. \"block2mtd=[,[,]]\""); ++MODULE_PARM_DESC(block2mtd, "Device to use. \"block2mtd=[,[,[,]]]\""); + + static int __init block2mtd_init(void) + { +@@ -474,7 +487,7 @@ static void block2mtd_exit(void) + } + + +-module_init(block2mtd_init); ++late_initcall(block2mtd_init); + module_exit(block2mtd_exit); + + MODULE_LICENSE("GPL"); diff --git a/target/linux/generic/patches-4.0/450-mtd-nand-allow-to-use-platform-specific-chip-fixup.patch b/target/linux/generic/patches-4.0/450-mtd-nand-allow-to-use-platform-specific-chip-fixup.patch new file mode 100644 index 0000000..ffaf706 --- /dev/null +++ b/target/linux/generic/patches-4.0/450-mtd-nand-allow-to-use-platform-specific-chip-fixup.patch @@ -0,0 +1,37 @@ +--- + drivers/mtd/nand/plat_nand.c | 13 ++++++++++++- + include/linux/mtd/nand.h | 1 + + 2 files changed, 13 insertions(+), 1 deletion(-) + +--- a/include/linux/mtd/nand.h ++++ b/include/linux/mtd/nand.h +@@ -865,6 +865,7 @@ struct platform_nand_chip { + unsigned int options; + unsigned int bbt_options; + const char **part_probe_types; ++ int (*chip_fixup)(struct mtd_info *mtd); + }; + + /* Keep gcc happy */ +--- a/drivers/mtd/nand/plat_nand.c ++++ b/drivers/mtd/nand/plat_nand.c +@@ -90,7 +90,18 @@ static int plat_nand_probe(struct platfo + } + + /* Scan to find existence of the device */ +- if (nand_scan(&data->mtd, pdata->chip.nr_chips)) { ++ if (nand_scan_ident(&data->mtd, pdata->chip.nr_chips, NULL)) { ++ err = -ENXIO; ++ goto out; ++ } ++ ++ if (pdata->chip.chip_fixup) { ++ err = pdata->chip.chip_fixup(&data->mtd); ++ if (err) ++ goto out; ++ } ++ ++ if (nand_scan_tail(&data->mtd)) { + err = -ENXIO; + goto out; + } diff --git a/target/linux/generic/patches-4.0/451-mtd-nand-fix-return-code-of-nand_correct_data-function.patch b/target/linux/generic/patches-4.0/451-mtd-nand-fix-return-code-of-nand_correct_data-function.patch new file mode 100644 index 0000000..6a2092c --- /dev/null +++ b/target/linux/generic/patches-4.0/451-mtd-nand-fix-return-code-of-nand_correct_data-function.patch @@ -0,0 +1,11 @@ +--- a/drivers/mtd/nand/nand_ecc.c ++++ b/drivers/mtd/nand/nand_ecc.c +@@ -507,7 +507,7 @@ int __nand_correct_data(unsigned char *b + return 1; /* error in ECC data; no action needed */ + + pr_err("%s: uncorrectable ECC error\n", __func__); +- return -1; ++ return -EBADMSG; + } + EXPORT_SYMBOL(__nand_correct_data); + diff --git a/target/linux/generic/patches-4.0/460-mtd-cfi_cmdset_0002-no-erase_suspend.patch b/target/linux/generic/patches-4.0/460-mtd-cfi_cmdset_0002-no-erase_suspend.patch new file mode 100644 index 0000000..68fbd12 --- /dev/null +++ b/target/linux/generic/patches-4.0/460-mtd-cfi_cmdset_0002-no-erase_suspend.patch @@ -0,0 +1,11 @@ +--- a/drivers/mtd/chips/cfi_cmdset_0002.c ++++ b/drivers/mtd/chips/cfi_cmdset_0002.c +@@ -809,7 +809,7 @@ static int get_chip(struct map_info *map + return 0; + + case FL_ERASING: +- if (!cfip || !(cfip->EraseSuspend & (0x1|0x2)) || ++ if (1 /* no suspend */ || !cfip || !(cfip->EraseSuspend & (0x1|0x2)) || + !(mode == FL_READY || mode == FL_POINT || + (mode == FL_WRITING && (cfip->EraseSuspend & 0x2)))) + goto sleep; diff --git a/target/linux/generic/patches-4.0/461-mtd-cfi_cmdset_0002-add-buffer-write-cmd-timeout.patch b/target/linux/generic/patches-4.0/461-mtd-cfi_cmdset_0002-add-buffer-write-cmd-timeout.patch new file mode 100644 index 0000000..c437a14 --- /dev/null +++ b/target/linux/generic/patches-4.0/461-mtd-cfi_cmdset_0002-add-buffer-write-cmd-timeout.patch @@ -0,0 +1,18 @@ +From: George Kashperko + +Issue map read after Write Buffer Load command to ensure chip is ready +to receive data. +Signed-off-by: George Kashperko +--- + drivers/mtd/chips/cfi_cmdset_0002.c | 1 + + 1 file changed, 1 insertion(+) +--- a/drivers/mtd/chips/cfi_cmdset_0002.c ++++ b/drivers/mtd/chips/cfi_cmdset_0002.c +@@ -1830,6 +1830,7 @@ static int __xipram do_write_buffer(stru + + /* Write Buffer Load */ + map_write(map, CMD(0x25), cmd_adr); ++ (void) map_read(map, cmd_adr); + + chip->state = FL_WRITING_TO_BUFFER; + diff --git a/target/linux/generic/patches-4.0/472-mtd-m25p80-add-support-for-Winbond-W25X05-flash.patch b/target/linux/generic/patches-4.0/472-mtd-m25p80-add-support-for-Winbond-W25X05-flash.patch new file mode 100644 index 0000000..37ecfb9 --- /dev/null +++ b/target/linux/generic/patches-4.0/472-mtd-m25p80-add-support-for-Winbond-W25X05-flash.patch @@ -0,0 +1,20 @@ +From eef9dfc4e821408af1af13aa0cc707fc496fb7c6 Mon Sep 17 00:00:00 2001 +From: Gabor Juhos +Date: Wed, 11 Dec 2013 19:05:59 +0100 +Subject: [PATCH] m25p80: add support for the Winbond W25X05 flash + +Signed-off-by: Gabor Juhos +--- + drivers/mtd/devices/m25p80.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/mtd/spi-nor/spi-nor.c ++++ b/drivers/mtd/spi-nor/spi-nor.c +@@ -649,6 +649,7 @@ static const struct spi_device_id spi_no + { "m25px80", INFO(0x207114, 0, 64 * 1024, 16, 0) }, + + /* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */ ++ { "w25x05", INFO(0xef3010, 0, 64 * 1024, 1, SECT_4K) }, + { "w25x10", INFO(0xef3011, 0, 64 * 1024, 2, SECT_4K) }, + { "w25x20", INFO(0xef3012, 0, 64 * 1024, 4, SECT_4K) }, + { "w25x40", INFO(0xef3013, 0, 64 * 1024, 8, SECT_4K) }, diff --git a/target/linux/generic/patches-4.0/473-mtd-spi-nor-add-support-for-the-Macronix-MX25L512E-S.patch b/target/linux/generic/patches-4.0/473-mtd-spi-nor-add-support-for-the-Macronix-MX25L512E-S.patch new file mode 100644 index 0000000..81ec0c5 --- /dev/null +++ b/target/linux/generic/patches-4.0/473-mtd-spi-nor-add-support-for-the-Macronix-MX25L512E-S.patch @@ -0,0 +1,21 @@ +From 0d7388de0911c1a4fc4a8a3898ef9d0ab818ca08 Mon Sep 17 00:00:00 2001 +From: Gabor Juhos +Date: Tue, 7 Apr 2015 18:35:15 +0200 +Subject: [PATCH] mtd: spi-nor: add support for the Macronix MX25L512E SPI + flash chip + +Signed-off-by: Gabor Juhos +--- + drivers/mtd/spi-nor/spi-nor.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/mtd/spi-nor/spi-nor.c ++++ b/drivers/mtd/spi-nor/spi-nor.c +@@ -546,6 +546,7 @@ static const struct spi_device_id spi_no + { "640s33b", INFO(0x898913, 0, 64 * 1024, 128, 0) }, + + /* Macronix */ ++ { "mx25l512e", INFO(0xc22010, 0, 64 * 1024, 1, SECT_4K) }, + { "mx25l2005a", INFO(0xc22012, 0, 64 * 1024, 4, SECT_4K) }, + { "mx25l4005a", INFO(0xc22013, 0, 64 * 1024, 8, SECT_4K) }, + { "mx25l8005", INFO(0xc22014, 0, 64 * 1024, 16, 0) }, diff --git a/target/linux/generic/patches-4.0/474-mtd-spi-nor-add-support-for-the-ISSI-SI25CD512-SPI-f.patch b/target/linux/generic/patches-4.0/474-mtd-spi-nor-add-support-for-the-ISSI-SI25CD512-SPI-f.patch new file mode 100644 index 0000000..eb082e0 --- /dev/null +++ b/target/linux/generic/patches-4.0/474-mtd-spi-nor-add-support-for-the-ISSI-SI25CD512-SPI-f.patch @@ -0,0 +1,22 @@ +From 34e2b403040a2f9d3ba071d95a7f42457e2950f9 Mon Sep 17 00:00:00 2001 +From: Gabor Juhos +Date: Tue, 7 Apr 2015 18:35:15 +0200 +Subject: [PATCH] mtd: spi-nor: add support for the ISSI SI25CD512 SPI flash + +Signed-off-by: Gabor Juhos +--- + drivers/mtd/spi-nor/spi-nor.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/mtd/spi-nor/spi-nor.c ++++ b/drivers/mtd/spi-nor/spi-nor.c +@@ -545,6 +545,9 @@ static const struct spi_device_id spi_no + { "320s33b", INFO(0x898912, 0, 64 * 1024, 64, 0) }, + { "640s33b", INFO(0x898913, 0, 64 * 1024, 128, 0) }, + ++ /* ISSI */ ++ { "is25cd512", INFO(0x7f9d20, 0, 32 * 1024, 2, SECT_4K) }, ++ + /* Macronix */ + { "mx25l512e", INFO(0xc22010, 0, 64 * 1024, 1, SECT_4K) }, + { "mx25l2005a", INFO(0xc22012, 0, 64 * 1024, 4, SECT_4K) }, diff --git a/target/linux/generic/patches-4.0/480-mtd-set-rootfs-to-be-root-dev.patch b/target/linux/generic/patches-4.0/480-mtd-set-rootfs-to-be-root-dev.patch new file mode 100644 index 0000000..4b89412 --- /dev/null +++ b/target/linux/generic/patches-4.0/480-mtd-set-rootfs-to-be-root-dev.patch @@ -0,0 +1,26 @@ +--- a/drivers/mtd/mtdcore.c ++++ b/drivers/mtd/mtdcore.c +@@ -38,6 +38,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -447,6 +448,15 @@ int add_mtd_device(struct mtd_info *mtd) + of this try_ nonsense, and no bitching about it + either. :) */ + __module_get(THIS_MODULE); ++ ++ if (!strcmp(mtd->name, "rootfs") && ++ config_enabled(CONFIG_MTD_ROOTFS_ROOT_DEV) && ++ ROOT_DEV == 0) { ++ pr_notice("mtd: device %d (%s) set to be root filesystem\n", ++ mtd->index, mtd->name); ++ ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, mtd->index); ++ } ++ + return 0; + + fail_added: diff --git a/target/linux/generic/patches-4.0/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch b/target/linux/generic/patches-4.0/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch new file mode 100644 index 0000000..bb28538 --- /dev/null +++ b/target/linux/generic/patches-4.0/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch @@ -0,0 +1,76 @@ +From 8a52e4100d7c3a4a1dfddfa02b8864a9b0068c13 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Sat, 17 May 2014 03:36:18 +0200 +Subject: [PATCH 1/5] ubi: auto-attach mtd device named "ubi" or "data" on boot +To: openwrt-devel@lists.openwrt.org + +Signed-off-by: Daniel Golle +--- + drivers/mtd/ubi/build.c | 36 ++++++++++++++++++++++++++++++++++++ + 1 file changed, 36 insertions(+) + +--- a/drivers/mtd/ubi/build.c ++++ b/drivers/mtd/ubi/build.c +@@ -1213,6 +1213,49 @@ static struct mtd_info * __init open_mtd + return mtd; + } + ++/* ++ * This function tries attaching mtd partitions named either "ubi" or "data" ++ * during boot. ++ */ ++static void __init ubi_auto_attach(void) ++{ ++ int err; ++ struct mtd_info *mtd; ++ ++ /* try attaching mtd device named "ubi" or "data" */ ++ mtd = open_mtd_device("ubi"); ++ if (IS_ERR(mtd)) ++ mtd = open_mtd_device("data"); ++ ++ if (!IS_ERR(mtd)) { ++ size_t len; ++ char magic[4]; ++ ++ /* check for a valid ubi magic */ ++ err = mtd_read(mtd, 0, 4, &len, (void *) magic); ++ if (!err && len == 4 && strncmp(magic, "UBI#", 4)) { ++ pr_err("UBI error: no valid UBI magic found inside mtd%d", mtd->index); ++ put_mtd_device(mtd); ++ return; ++ } ++ ++ /* auto-add only media types where UBI makes sense */ ++ if (mtd->type == MTD_NANDFLASH || ++ mtd->type == MTD_NORFLASH || ++ mtd->type == MTD_DATAFLASH || ++ mtd->type == MTD_MLCNANDFLASH) { ++ mutex_lock(&ubi_devices_mutex); ++ pr_notice("UBI: auto-attach mtd%d", mtd->index); ++ err = ubi_attach_mtd_dev(mtd, UBI_DEV_NUM_AUTO, 0, 0); ++ mutex_unlock(&ubi_devices_mutex); ++ if (err < 0) { ++ pr_err("UBI error: cannot attach mtd%d", mtd->index); ++ put_mtd_device(mtd); ++ } ++ } ++ } ++} ++ + static int __init ubi_init(void) + { + int err, i, k; +@@ -1305,6 +1348,12 @@ static int __init ubi_init(void) + } + } + ++ /* auto-attach mtd devices only if built-in to the kernel and no ubi.mtd ++ * parameter was given */ ++ if (config_enabled(CONFIG_MTD_ROOTFS_ROOT_DEV) && ++ !ubi_is_module() && !mtd_devs) ++ ubi_auto_attach(); ++ + err = ubiblock_init(); + if (err) { + pr_err("UBI error: block: cannot initialize, error %d", err); diff --git a/target/linux/generic/patches-4.0/491-ubi-auto-create-ubiblock-device-for-rootfs.patch b/target/linux/generic/patches-4.0/491-ubi-auto-create-ubiblock-device-for-rootfs.patch new file mode 100644 index 0000000..433d77b --- /dev/null +++ b/target/linux/generic/patches-4.0/491-ubi-auto-create-ubiblock-device-for-rootfs.patch @@ -0,0 +1,69 @@ +From 0f3966579815f889bb2fcb4846152c35f65e79c4 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Thu, 15 May 2014 21:06:33 +0200 +Subject: [PATCH 2/5] ubi: auto-create ubiblock device for rootfs +To: openwrt-devel@lists.openwrt.org + +Signed-off-by: Daniel Golle +--- + drivers/mtd/ubi/block.c | 42 ++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 42 insertions(+) + +--- a/drivers/mtd/ubi/block.c ++++ b/drivers/mtd/ubi/block.c +@@ -616,6 +616,44 @@ static void __init ubiblock_create_from_ + } + } + ++#define UBIFS_NODE_MAGIC 0x06101831 ++static inline int ubi_vol_is_ubifs(struct ubi_volume_desc *desc) ++{ ++ int ret; ++ uint32_t magic_of, magic; ++ ret = ubi_read(desc, 0, (char *)&magic_of, 0, 4); ++ if (ret) ++ return 0; ++ magic = le32_to_cpu(magic_of); ++ return magic == UBIFS_NODE_MAGIC; ++} ++ ++static void __init ubiblock_create_auto_rootfs(void) ++{ ++ int ubi_num, ret, is_ubifs; ++ struct ubi_volume_desc *desc; ++ struct ubi_volume_info vi; ++ ++ for (ubi_num = 0; ubi_num < UBI_MAX_DEVICES; ubi_num++) { ++ desc = ubi_open_volume_nm(ubi_num, "rootfs", UBI_READONLY); ++ if (IS_ERR(desc)) ++ continue; ++ ++ ubi_get_volume_info(desc, &vi); ++ is_ubifs = ubi_vol_is_ubifs(desc); ++ ubi_close_volume(desc); ++ if (is_ubifs) ++ break; ++ ++ ret = ubiblock_create(&vi); ++ if (ret) ++ pr_err("UBI error: block: can't add '%s' volume, err=%d\n", ++ vi.name, ret); ++ /* always break if we get here */ ++ break; ++ } ++} ++ + static void ubiblock_remove_all(void) + { + struct ubiblock *next; +@@ -646,6 +684,10 @@ int __init ubiblock_init(void) + */ + ubiblock_create_from_param(); + ++ /* auto-attach "rootfs" volume if existing and non-ubifs */ ++ if (config_enabled(CONFIG_MTD_ROOTFS_ROOT_DEV)) ++ ubiblock_create_auto_rootfs(); ++ + /* + * Block devices are only created upon user requests, so we ignore + * existing volumes. diff --git a/target/linux/generic/patches-4.0/492-try-auto-mounting-ubi0-rootfs-in-init-do_mounts.c.patch b/target/linux/generic/patches-4.0/492-try-auto-mounting-ubi0-rootfs-in-init-do_mounts.c.patch new file mode 100644 index 0000000..406737e --- /dev/null +++ b/target/linux/generic/patches-4.0/492-try-auto-mounting-ubi0-rootfs-in-init-do_mounts.c.patch @@ -0,0 +1,53 @@ +From eea9e1785e4c05c2a3444506aabafa0ae958538f Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Sat, 17 May 2014 03:35:02 +0200 +Subject: [PATCH 4/5] try auto-mounting ubi0:rootfs in init/do_mounts.c +To: openwrt-devel@lists.openwrt.org + +Signed-off-by: Daniel Golle +--- + init/do_mounts.c | 26 +++++++++++++++++++++++++- + 1 file changed, 25 insertions(+), 1 deletion(-) + +--- a/init/do_mounts.c ++++ b/init/do_mounts.c +@@ -435,7 +435,27 @@ retry: + out: + put_page(page); + } +- ++ ++static int __init mount_ubi_rootfs(void) ++{ ++ int flags = MS_SILENT; ++ int err, tried = 0; ++ ++ while (tried < 2) { ++ err = do_mount_root("ubi0:rootfs", "ubifs", flags, \ ++ root_mount_data); ++ switch (err) { ++ case -EACCES: ++ flags |= MS_RDONLY; ++ tried++; ++ default: ++ return err; ++ } ++ } ++ ++ return -EINVAL; ++} ++ + #ifdef CONFIG_ROOT_NFS + + #define NFSROOT_TIMEOUT_MIN 5 +@@ -529,6 +549,10 @@ void __init mount_root(void) + change_floppy("root floppy"); + } + #endif ++#ifdef CONFIG_MTD_ROOTFS_ROOT_DEV ++ if (!mount_ubi_rootfs()) ++ return; ++#endif + #ifdef CONFIG_BLOCK + create_dev("/dev/root", ROOT_DEV); + mount_block_root("/dev/root", root_mountflags); diff --git a/target/linux/generic/patches-4.0/493-ubi-set-ROOT_DEV-to-ubiblock-rootfs-if-unset.patch b/target/linux/generic/patches-4.0/493-ubi-set-ROOT_DEV-to-ubiblock-rootfs-if-unset.patch new file mode 100644 index 0000000..1873752 --- /dev/null +++ b/target/linux/generic/patches-4.0/493-ubi-set-ROOT_DEV-to-ubiblock-rootfs-if-unset.patch @@ -0,0 +1,37 @@ +From cd68d1b12b5ea4c01a664c064179ada42bf55d3d Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Thu, 15 May 2014 20:55:42 +0200 +Subject: [PATCH 5/5] ubi: set ROOT_DEV to ubiblock "rootfs" if unset +To: openwrt-devel@lists.openwrt.org + +Signed-off-by: Daniel Golle +--- + drivers/mtd/ubi/block.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +--- a/drivers/mtd/ubi/block.c ++++ b/drivers/mtd/ubi/block.c +@@ -49,6 +49,7 @@ + #include + #include + #include ++#include + + #include "ubi-media.h" + #include "ubi.h" +@@ -439,6 +440,15 @@ int ubiblock_create(struct ubi_volume_in + add_disk(dev->gd); + dev_info(disk_to_dev(dev->gd), "created from ubi%d:%d(%s)", + dev->ubi_num, dev->vol_id, vi->name); ++ ++ if (!strcmp(vi->name, "rootfs") && ++ config_enabled(CONFIG_MTD_ROOTFS_ROOT_DEV) && ++ ROOT_DEV == 0) { ++ pr_notice("ubiblock: device ubiblock%d_%d (%s) set to be root filesystem\n", ++ dev->ubi_num, dev->vol_id, vi->name); ++ ROOT_DEV = MKDEV(gd->major, gd->first_minor); ++ } ++ + return 0; + + out_free_queue: diff --git a/target/linux/generic/patches-4.0/494-mtd-ubi-add-EOF-marker-support.patch b/target/linux/generic/patches-4.0/494-mtd-ubi-add-EOF-marker-support.patch new file mode 100644 index 0000000..3763c2f --- /dev/null +++ b/target/linux/generic/patches-4.0/494-mtd-ubi-add-EOF-marker-support.patch @@ -0,0 +1,51 @@ +--- a/drivers/mtd/ubi/attach.c ++++ b/drivers/mtd/ubi/attach.c +@@ -803,6 +803,13 @@ out_unlock: + return err; + } + ++static bool ec_hdr_has_eof(struct ubi_ec_hdr *ech) ++{ ++ return ech->padding1[0] == 'E' && ++ ech->padding1[1] == 'O' && ++ ech->padding1[2] == 'F'; ++} ++ + /** + * scan_peb - scan and process UBI headers of a PEB. + * @ubi: UBI device description object +@@ -833,9 +840,21 @@ static int scan_peb(struct ubi_device *u + return 0; + } + +- err = ubi_io_read_ec_hdr(ubi, pnum, ech, 0); +- if (err < 0) +- return err; ++ if (!ai->eof_found) { ++ err = ubi_io_read_ec_hdr(ubi, pnum, ech, 0); ++ if (err < 0) ++ return err; ++ ++ if (ec_hdr_has_eof(ech)) { ++ pr_notice("UBI: EOF marker found, PEBs from %d will be erased", ++ pnum); ++ ai->eof_found = true; ++ } ++ } ++ ++ if (ai->eof_found) ++ err = UBI_IO_FF_BITFLIPS; ++ + switch (err) { + case 0: + break; +--- a/drivers/mtd/ubi/ubi.h ++++ b/drivers/mtd/ubi/ubi.h +@@ -706,6 +706,7 @@ struct ubi_attach_info { + int mean_ec; + uint64_t ec_sum; + int ec_count; ++ bool eof_found; + struct kmem_cache *aeb_slab_cache; + }; + diff --git a/target/linux/generic/patches-4.0/500-yaffs-Kbuild-integration.patch b/target/linux/generic/patches-4.0/500-yaffs-Kbuild-integration.patch new file mode 100644 index 0000000..3f5b0cc --- /dev/null +++ b/target/linux/generic/patches-4.0/500-yaffs-Kbuild-integration.patch @@ -0,0 +1,18 @@ +--- a/fs/Kconfig ++++ b/fs/Kconfig +@@ -32,6 +32,7 @@ source "fs/gfs2/Kconfig" + source "fs/ocfs2/Kconfig" + source "fs/btrfs/Kconfig" + source "fs/nilfs2/Kconfig" ++source "fs/yaffs2/Kconfig" + + config FS_DAX + bool "Direct Access (DAX) support" +--- a/fs/Makefile ++++ b/fs/Makefile +@@ -126,3 +126,5 @@ obj-y += exofs/ # Multiple modules + obj-$(CONFIG_CEPH_FS) += ceph/ + obj-$(CONFIG_PSTORE) += pstore/ + obj-$(CONFIG_EFIVAR_FS) += efivarfs/ ++obj-$(CONFIG_YAFFS_FS) += yaffs2/ ++ diff --git a/target/linux/generic/patches-4.0/502-yaffs-fix-compat-tags-handling.patch b/target/linux/generic/patches-4.0/502-yaffs-fix-compat-tags-handling.patch new file mode 100644 index 0000000..a18cf6f --- /dev/null +++ b/target/linux/generic/patches-4.0/502-yaffs-fix-compat-tags-handling.patch @@ -0,0 +1,239 @@ +Subject: yaffs: fix compat tags handling + +Signed-off-by: Gabor Juhos +--- +--- a/fs/yaffs2/yaffs_tagscompat.c ++++ b/fs/yaffs2/yaffs_tagscompat.c +@@ -17,7 +17,9 @@ + #include "yaffs_getblockinfo.h" + #include "yaffs_trace.h" + ++#if 0 + static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk); ++#endif + + + /********** Tags ECC calculations *********/ +@@ -71,6 +73,7 @@ int yaffs_check_tags_ecc(struct yaffs_ta + return 0; + } + ++#if 0 + /********** Tags **********/ + + static void yaffs_load_tags_to_spare(struct yaffs_spare *spare_ptr, +@@ -379,3 +382,214 @@ void yaffs_tags_compat_install(struct ya + if(!dev->tagger.mark_bad_fn) + dev->tagger.mark_bad_fn = yaffs_tags_compat_mark_bad; + } ++#else ++ ++#include "yaffs_packedtags1.h" ++ ++static int yaffs_tags_compat_write(struct yaffs_dev *dev, ++ int nand_chunk, ++ const u8 *data, ++ const struct yaffs_ext_tags *tags) ++{ ++ struct yaffs_packed_tags1 pt1; ++ u8 tag_buf[9]; ++ int retval; ++ ++ /* we assume that yaffs_packed_tags1 and yaffs_tags are compatible */ ++ compile_time_assertion(sizeof(struct yaffs_packed_tags1) == 12); ++ compile_time_assertion(sizeof(struct yaffs_tags) == 8); ++ ++ yaffs_pack_tags1(&pt1, tags); ++ yaffs_calc_tags_ecc((struct yaffs_tags *)&pt1); ++ ++ /* When deleting a chunk, the upper layer provides only skeletal ++ * tags, one with is_deleted set. However, we need to update the ++ * tags, not erase them completely. So we use the NAND write property ++ * that only zeroed-bits stick and set tag bytes to all-ones and ++ * zero just the (not) deleted bit. ++ */ ++ if (!dev->param.tags_9bytes) { ++ if (tags->is_deleted) { ++ memset(&pt1, 0xff, 8); ++ /* clear delete status bit to indicate deleted */ ++ pt1.deleted = 0; ++ } ++ memcpy(tag_buf, &pt1, 8); ++ } else { ++ if (tags->is_deleted) { ++ memset(tag_buf, 0xff, 8); ++ tag_buf[8] = 0; ++ } else { ++ memcpy(tag_buf, &pt1, 8); ++ tag_buf[8] = 0xff; ++ } ++ } ++ ++ retval = dev->drv.drv_write_chunk_fn(dev, nand_chunk, ++ data, ++ (data) ? dev->data_bytes_per_chunk : 0, ++ tag_buf, ++ (dev->param.tags_9bytes) ? 9 : 8); ++ ++ return retval; ++} ++ ++/* Return with empty extended tags but add ecc_result. ++ */ ++static int return_empty_tags(struct yaffs_ext_tags *tags, ++ enum yaffs_ecc_result ecc_result, ++ int retval) ++{ ++ if (tags) { ++ memset(tags, 0, sizeof(*tags)); ++ tags->ecc_result = ecc_result; ++ } ++ ++ return retval; ++} ++ ++static int yaffs_tags_compat_read(struct yaffs_dev *dev, ++ int nand_chunk, ++ u8 *data, ++ struct yaffs_ext_tags *tags) ++{ ++ struct yaffs_packed_tags1 pt1; ++ enum yaffs_ecc_result ecc_result; ++ int retval; ++ int deleted; ++ u8 tag_buf[9]; ++ ++ retval = dev->drv.drv_read_chunk_fn(dev, nand_chunk, ++ data, dev->param.total_bytes_per_chunk, ++ tag_buf, ++ (dev->param.tags_9bytes) ? 9 : 8, ++ &ecc_result); ++ ++ switch (ecc_result) { ++ case YAFFS_ECC_RESULT_NO_ERROR: ++ case YAFFS_ECC_RESULT_FIXED: ++ break; ++ ++ case YAFFS_ECC_RESULT_UNFIXED: ++ default: ++ return_empty_tags(tags, YAFFS_ECC_RESULT_UNFIXED, 0); ++ tags->block_bad = dev->drv.drv_check_bad_fn(dev, nand_chunk); ++ return YAFFS_FAIL; ++ } ++ ++ /* Check for a blank/erased chunk. */ ++ if (yaffs_check_ff(tag_buf, 8)) { ++ /* when blank, upper layers want ecc_result to be <= NO_ERROR */ ++ return return_empty_tags(tags, YAFFS_ECC_RESULT_NO_ERROR, ++ YAFFS_OK); ++ } ++ ++ memcpy(&pt1, tag_buf, 8); ++ ++ if (!dev->param.tags_9bytes) { ++ /* Read deleted status (bit) then return it to it's non-deleted ++ * state before performing tags mini-ECC check. pt1.deleted is ++ * inverted. ++ */ ++ deleted = !pt1.deleted; ++ pt1.deleted = 1; ++ } else { ++ deleted = (hweight8(tag_buf[8]) < 7) ? 1 : 0; ++ } ++ ++ /* Check the packed tags mini-ECC and correct if necessary/possible. */ ++ retval = yaffs_check_tags_ecc((struct yaffs_tags *)&pt1); ++ switch (retval) { ++ case 0: ++ /* no tags error, use MTD result */ ++ break; ++ case 1: ++ /* recovered tags-ECC error */ ++ dev->n_tags_ecc_fixed++; ++ if (ecc_result == YAFFS_ECC_RESULT_NO_ERROR) ++ ecc_result = YAFFS_ECC_RESULT_FIXED; ++ break; ++ default: ++ /* unrecovered tags-ECC error */ ++ dev->n_tags_ecc_unfixed++; ++ return return_empty_tags(tags, YAFFS_ECC_RESULT_UNFIXED, ++ YAFFS_FAIL); ++ } ++ ++ /* Unpack the tags to extended form and set ECC result. ++ * [set should_be_ff just to keep yaffs_unpack_tags1 happy] ++ */ ++ pt1.should_be_ff = 0xffffffff; ++ yaffs_unpack_tags1(tags, &pt1); ++ tags->ecc_result = ecc_result; ++ ++ /* Set deleted state */ ++ tags->is_deleted = deleted; ++ return YAFFS_OK; ++} ++ ++static int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int block_no) ++{ ++ return dev->drv.drv_mark_bad_fn(dev, block_no); ++} ++ ++static int yaffs_tags_compat_query_block(struct yaffs_dev *dev, ++ int block_no, ++ enum yaffs_block_state *state, ++ u32 *seq_number) ++{ ++ struct yaffs_ext_tags tags; ++ int retval; ++ ++ yaffs_trace(YAFFS_TRACE_MTD, "%s %d", __func__, block_no); ++ ++ *seq_number = 0; ++ ++ retval = dev->drv.drv_check_bad_fn(dev, block_no); ++ if (retval == YAFFS_FAIL) { ++ *state = YAFFS_BLOCK_STATE_DEAD; ++ goto out; ++ } ++ ++ yaffs_tags_compat_read(dev, block_no * dev->param.chunks_per_block, ++ NULL, &tags); ++ ++ if (tags.ecc_result != YAFFS_ECC_RESULT_NO_ERROR) { ++ yaffs_trace(YAFFS_TRACE_MTD, "block %d is marked bad", ++ block_no); ++ *state = YAFFS_BLOCK_STATE_NEEDS_SCAN; ++ } else if (tags.chunk_used) { ++ *seq_number = tags.seq_number; ++ *state = YAFFS_BLOCK_STATE_NEEDS_SCAN; ++ } else { ++ *state = YAFFS_BLOCK_STATE_EMPTY; ++ } ++ ++ retval = YAFFS_OK; ++ ++out: ++ yaffs_trace(YAFFS_TRACE_MTD, ++ "block query returns seq %u state %d", ++ *seq_number, *state); ++ ++ return retval; ++} ++ ++void yaffs_tags_compat_install(struct yaffs_dev *dev) ++{ ++ if (dev->param.is_yaffs2) ++ return; ++ ++ if (!dev->tagger.write_chunk_tags_fn) ++ dev->tagger.write_chunk_tags_fn = yaffs_tags_compat_write; ++ ++ if (!dev->tagger.read_chunk_tags_fn) ++ dev->tagger.read_chunk_tags_fn = yaffs_tags_compat_read; ++ ++ if (!dev->tagger.query_block_fn) ++ dev->tagger.query_block_fn = yaffs_tags_compat_query_block; ++ ++ if (!dev->tagger.mark_bad_fn) ++ dev->tagger.mark_bad_fn = yaffs_tags_compat_mark_bad; ++} ++#endif diff --git a/target/linux/generic/patches-4.0/503-yaffs-add-tags-9bytes-mount-option.patch b/target/linux/generic/patches-4.0/503-yaffs-add-tags-9bytes-mount-option.patch new file mode 100644 index 0000000..3f51baf --- /dev/null +++ b/target/linux/generic/patches-4.0/503-yaffs-add-tags-9bytes-mount-option.patch @@ -0,0 +1,115 @@ +Subject: yaffs: add support for tags-9bytes mount option + +Signed-off-by: Gabor Juhos +--- +--- a/fs/yaffs2/yaffs_vfs.c ++++ b/fs/yaffs2/yaffs_vfs.c +@@ -2644,6 +2644,7 @@ static const struct super_operations yaf + + struct yaffs_options { + int inband_tags; ++ int tags_9bytes; + int skip_checkpoint_read; + int skip_checkpoint_write; + int no_cache; +@@ -2683,6 +2684,8 @@ static int yaffs_parse_options(struct ya + + if (!strcmp(cur_opt, "inband-tags")) { + options->inband_tags = 1; ++ } else if (!strcmp(cur_opt, "tags-9bytes")) { ++ options->tags_9bytes = 1; + } else if (!strcmp(cur_opt, "tags-ecc-off")) { + options->tags_ecc_on = 0; + options->tags_ecc_overridden = 1; +@@ -2756,7 +2759,6 @@ static struct super_block *yaffs_interna + struct yaffs_param *param; + + int read_only = 0; +- int inband_tags = 0; + + struct yaffs_options options; + +@@ -2796,6 +2798,9 @@ static struct super_block *yaffs_interna + + memset(&options, 0, sizeof(options)); + ++ if (IS_ENABLED(CONFIG_YAFFS_9BYTE_TAGS)) ++ options.tags_9bytes = 1; ++ + if (yaffs_parse_options(&options, data_str)) { + /* Option parsing failed */ + return NULL; +@@ -2829,17 +2834,22 @@ static struct super_block *yaffs_interna + } + + /* Added NCB 26/5/2006 for completeness */ +- if (yaffs_version == 2 && !options.inband_tags +- && WRITE_SIZE(mtd) == 512) { ++ if (yaffs_version == 2 && ++ (!options.inband_tags || options.tags_9bytes) && ++ WRITE_SIZE(mtd) == 512) { + yaffs_trace(YAFFS_TRACE_ALWAYS, "auto selecting yaffs1"); + yaffs_version = 1; + } + +- if (mtd->oobavail < sizeof(struct yaffs_packed_tags2) || +- options.inband_tags) +- inband_tags = 1; ++ if (yaffs_version == 2 && ++ mtd->oobavail < sizeof(struct yaffs_packed_tags2)) { ++ yaffs_trace(YAFFS_TRACE_ALWAYS, "auto selecting inband tags"); ++ options.inband_tags = 1; ++ } + +- if(yaffs_verify_mtd(mtd, yaffs_version, inband_tags) < 0) ++ err = yaffs_verify_mtd(mtd, yaffs_version, options.inband_tags, ++ options.tags_9bytes); ++ if (err < 0) + return NULL; + + /* OK, so if we got here, we have an MTD that's NAND and looks +@@ -2896,7 +2906,8 @@ static struct super_block *yaffs_interna + + param->n_reserved_blocks = 5; + param->n_caches = (options.no_cache) ? 0 : 10; +- param->inband_tags = inband_tags; ++ param->inband_tags = options.inband_tags; ++ param->tags_9bytes = options.tags_9bytes; + + param->enable_xattr = 1; + if (options.lazy_loading_overridden) +--- a/fs/yaffs2/yaffs_mtdif.c ++++ b/fs/yaffs2/yaffs_mtdif.c +@@ -278,7 +278,8 @@ struct mtd_info * yaffs_get_mtd_device(d + return mtd; + } + +-int yaffs_verify_mtd(struct mtd_info *mtd, int yaffs_version, int inband_tags) ++int yaffs_verify_mtd(struct mtd_info *mtd, int yaffs_version, int inband_tags, ++ int tags_9bytes) + { + if (yaffs_version == 2) { + if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE || +@@ -297,6 +298,12 @@ int yaffs_verify_mtd(struct mtd_info *mt + ); + return -1; + } ++ ++ if (tags_9bytes && mtd->oobavail < 9) { ++ yaffs_trace(YAFFS_TRACE_ALWAYS, ++ "MTD device does not support 9-byte tags"); ++ return -1; ++ } + } + + return 0; +--- a/fs/yaffs2/yaffs_mtdif.h ++++ b/fs/yaffs2/yaffs_mtdif.h +@@ -21,5 +21,6 @@ + void yaffs_mtd_drv_install(struct yaffs_dev *dev); + struct mtd_info * yaffs_get_mtd_device(dev_t sdev); + void yaffs_put_mtd_device(struct mtd_info *mtd); +-int yaffs_verify_mtd(struct mtd_info *mtd, int yaffs_version, int inband_tags); ++int yaffs_verify_mtd(struct mtd_info *mtd, int yaffs_version, int inband_tags, ++ int tags_9bytes); + #endif diff --git a/target/linux/generic/patches-4.0/504-yaffs-3.16-new-fops.patch b/target/linux/generic/patches-4.0/504-yaffs-3.16-new-fops.patch new file mode 100644 index 0000000..11c6da0 --- /dev/null +++ b/target/linux/generic/patches-4.0/504-yaffs-3.16-new-fops.patch @@ -0,0 +1,25 @@ +--- a/fs/yaffs2/yaffs_vfs.c ++++ b/fs/yaffs2/yaffs_vfs.c +@@ -774,7 +774,21 @@ static int yaffs_sync_object(struct file + } + + +-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22)) ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) ++static const struct file_operations yaffs_file_operations = { ++ .read = new_sync_read, ++ .read_iter = generic_file_read_iter, ++ .write = new_sync_write, ++ .write_iter = generic_file_write_iter, ++ .mmap = generic_file_mmap, ++ .flush = yaffs_file_flush, ++ .fsync = yaffs_sync_object, ++ .splice_read = generic_file_splice_read, ++ .splice_write = iter_file_splice_write, ++ .llseek = generic_file_llseek, ++}; ++ ++#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22)) + static const struct file_operations yaffs_file_operations = { + .read = do_sync_read, + .write = do_sync_write, diff --git a/target/linux/generic/patches-4.0/505-yaffs-3.19-f_dentry-remove.patch b/target/linux/generic/patches-4.0/505-yaffs-3.19-f_dentry-remove.patch new file mode 100644 index 0000000..4dd2afe --- /dev/null +++ b/target/linux/generic/patches-4.0/505-yaffs-3.19-f_dentry-remove.patch @@ -0,0 +1,95 @@ +--- a/fs/yaffs2/yaffs_vfs.c ++++ b/fs/yaffs2/yaffs_vfs.c +@@ -283,7 +283,7 @@ static int yaffs_readpage_nolock(struct + (long long)pos, + (unsigned)PAGE_CACHE_SIZE); + +- obj = yaffs_dentry_to_obj(f->f_dentry); ++ obj = yaffs_dentry_to_obj(f->f_path.dentry); + + dev = obj->my_dev; + +@@ -481,7 +481,7 @@ static ssize_t yaffs_hold_space(struct f + + int n_free_chunks; + +- obj = yaffs_dentry_to_obj(f->f_dentry); ++ obj = yaffs_dentry_to_obj(f->f_path.dentry); + + dev = obj->my_dev; + +@@ -499,7 +499,7 @@ static void yaffs_release_space(struct f + struct yaffs_obj *obj; + struct yaffs_dev *dev; + +- obj = yaffs_dentry_to_obj(f->f_dentry); ++ obj = yaffs_dentry_to_obj(f->f_path.dentry); + + dev = obj->my_dev; + +@@ -591,7 +591,7 @@ static ssize_t yaffs_file_write(struct f + struct inode *inode; + struct yaffs_dev *dev; + +- obj = yaffs_dentry_to_obj(f->f_dentry); ++ obj = yaffs_dentry_to_obj(f->f_path.dentry); + + if (!obj) { + yaffs_trace(YAFFS_TRACE_OS, +@@ -603,7 +603,7 @@ static ssize_t yaffs_file_write(struct f + + yaffs_gross_lock(dev); + +- inode = f->f_dentry->d_inode; ++ inode = f->f_path.dentry->d_inode; + + if (!S_ISBLK(inode->i_mode) && f->f_flags & O_APPEND) + ipos = inode->i_size; +@@ -727,7 +727,7 @@ static int yaffs_file_flush(struct file + static int yaffs_file_flush(struct file *file) + #endif + { +- struct yaffs_obj *obj = yaffs_dentry_to_obj(file->f_dentry); ++ struct yaffs_obj *obj = yaffs_dentry_to_obj(file->f_path.dentry); + + struct yaffs_dev *dev = obj->my_dev; + +@@ -1730,7 +1730,7 @@ static int yaffs_iterate(struct file *f, + + char name[YAFFS_MAX_NAME_LENGTH + 1]; + +- obj = yaffs_dentry_to_obj(f->f_dentry); ++ obj = yaffs_dentry_to_obj(f->f_path.dentry); + dev = obj->my_dev; + + yaffs_gross_lock(dev); +@@ -1794,14 +1794,14 @@ static int yaffs_readdir(struct file *f, + struct yaffs_obj *obj; + struct yaffs_dev *dev; + struct yaffs_search_context *sc; +- struct inode *inode = f->f_dentry->d_inode; ++ struct inode *inode = f->f_path.dentry->d_inode; + unsigned long offset, curoffs; + struct yaffs_obj *l; + int ret_val = 0; + + char name[YAFFS_MAX_NAME_LENGTH + 1]; + +- obj = yaffs_dentry_to_obj(f->f_dentry); ++ obj = yaffs_dentry_to_obj(f->f_path.dentry); + dev = obj->my_dev; + + yaffs_gross_lock(dev); +@@ -1835,10 +1835,10 @@ static int yaffs_readdir(struct file *f, + if (offset == 1) { + yaffs_trace(YAFFS_TRACE_OS, + "yaffs_readdir: entry .. ino %d", +- (int)f->f_dentry->d_parent->d_inode->i_ino); ++ (int)f->f_path.dentry->d_parent->d_inode->i_ino); + yaffs_gross_unlock(dev); + if (filldir(dirent, "..", 2, offset, +- f->f_dentry->d_parent->d_inode->i_ino, ++ f->f_path.dentry->d_parent->d_inode->i_ino, + DT_DIR) < 0) { + yaffs_gross_lock(dev); + goto out; diff --git a/target/linux/generic/patches-4.0/520-squashfs_update_xz_comp_opts.patch b/target/linux/generic/patches-4.0/520-squashfs_update_xz_comp_opts.patch new file mode 100644 index 0000000..ad11b30 --- /dev/null +++ b/target/linux/generic/patches-4.0/520-squashfs_update_xz_comp_opts.patch @@ -0,0 +1,25 @@ +From f31b7c0efa255dd17a5f584022a319387f09b0d8 Mon Sep 17 00:00:00 2001 +From: Jonas Gorski +Date: Tue, 12 Apr 2011 19:55:41 +0200 +Subject: [PATCH] squashfs: update xz compressor options struct. + +Update the xz compressor options struct to match the squashfs userspace +one. +--- + fs/squashfs/xz_wrapper.c | 4 +++- + 1 files changed, 3 insertions(+), 1 deletions(-) + +--- a/fs/squashfs/xz_wrapper.c ++++ b/fs/squashfs/xz_wrapper.c +@@ -40,8 +40,10 @@ struct squashfs_xz { + }; + + struct disk_comp_opts { +- __le32 dictionary_size; + __le32 flags; ++ __le16 bit_opts; ++ __le16 fb; ++ __le32 dictionary_size; + }; + + struct comp_opts { diff --git a/target/linux/generic/patches-4.0/530-jffs2_make_lzma_available.patch b/target/linux/generic/patches-4.0/530-jffs2_make_lzma_available.patch new file mode 100644 index 0000000..6a500cd --- /dev/null +++ b/target/linux/generic/patches-4.0/530-jffs2_make_lzma_available.patch @@ -0,0 +1,5142 @@ +--- a/fs/jffs2/Kconfig ++++ b/fs/jffs2/Kconfig +@@ -139,6 +139,15 @@ config JFFS2_LZO + This feature was added in July, 2007. Say 'N' if you need + compatibility with older bootloaders or kernels. + ++config JFFS2_LZMA ++ bool "JFFS2 LZMA compression support" if JFFS2_COMPRESSION_OPTIONS ++ select LZMA_COMPRESS ++ select LZMA_DECOMPRESS ++ depends on JFFS2_FS ++ default n ++ help ++ JFFS2 wrapper to the LZMA C SDK ++ + config JFFS2_RTIME + bool "JFFS2 RTIME compression support" if JFFS2_COMPRESSION_OPTIONS + depends on JFFS2_FS +--- a/fs/jffs2/Makefile ++++ b/fs/jffs2/Makefile +@@ -18,4 +18,7 @@ jffs2-$(CONFIG_JFFS2_RUBIN) += compr_rub + jffs2-$(CONFIG_JFFS2_RTIME) += compr_rtime.o + jffs2-$(CONFIG_JFFS2_ZLIB) += compr_zlib.o + jffs2-$(CONFIG_JFFS2_LZO) += compr_lzo.o ++jffs2-$(CONFIG_JFFS2_LZMA) += compr_lzma.o + jffs2-$(CONFIG_JFFS2_SUMMARY) += summary.o ++ ++CFLAGS_compr_lzma.o += -Iinclude/linux -Ilib/lzma +--- a/fs/jffs2/compr.c ++++ b/fs/jffs2/compr.c +@@ -378,6 +378,9 @@ int __init jffs2_compressors_init(void) + #ifdef CONFIG_JFFS2_LZO + jffs2_lzo_init(); + #endif ++#ifdef CONFIG_JFFS2_LZMA ++ jffs2_lzma_init(); ++#endif + /* Setting default compression mode */ + #ifdef CONFIG_JFFS2_CMODE_NONE + jffs2_compression_mode = JFFS2_COMPR_MODE_NONE; +@@ -401,6 +404,9 @@ int __init jffs2_compressors_init(void) + int jffs2_compressors_exit(void) + { + /* Unregistering compressors */ ++#ifdef CONFIG_JFFS2_LZMA ++ jffs2_lzma_exit(); ++#endif + #ifdef CONFIG_JFFS2_LZO + jffs2_lzo_exit(); + #endif +--- a/fs/jffs2/compr.h ++++ b/fs/jffs2/compr.h +@@ -29,9 +29,9 @@ + #define JFFS2_DYNRUBIN_PRIORITY 20 + #define JFFS2_LZARI_PRIORITY 30 + #define JFFS2_RTIME_PRIORITY 50 +-#define JFFS2_ZLIB_PRIORITY 60 +-#define JFFS2_LZO_PRIORITY 80 +- ++#define JFFS2_LZMA_PRIORITY 70 ++#define JFFS2_ZLIB_PRIORITY 80 ++#define JFFS2_LZO_PRIORITY 90 + + #define JFFS2_RUBINMIPS_DISABLED /* RUBINs will be used only */ + #define JFFS2_DYNRUBIN_DISABLED /* for decompression */ +@@ -101,5 +101,9 @@ void jffs2_zlib_exit(void); + int jffs2_lzo_init(void); + void jffs2_lzo_exit(void); + #endif ++#ifdef CONFIG_JFFS2_LZMA ++int jffs2_lzma_init(void); ++void jffs2_lzma_exit(void); ++#endif + + #endif /* __JFFS2_COMPR_H__ */ +--- /dev/null ++++ b/fs/jffs2/compr_lzma.c +@@ -0,0 +1,128 @@ ++/* ++ * JFFS2 -- Journalling Flash File System, Version 2. ++ * ++ * For licensing information, see the file 'LICENCE' in this directory. ++ * ++ * JFFS2 wrapper to the LZMA C SDK ++ * ++ */ ++ ++#include ++#include "compr.h" ++ ++#ifdef __KERNEL__ ++ static DEFINE_MUTEX(deflate_mutex); ++#endif ++ ++CLzmaEncHandle *p; ++Byte propsEncoded[LZMA_PROPS_SIZE]; ++SizeT propsSize = sizeof(propsEncoded); ++ ++STATIC void lzma_free_workspace(void) ++{ ++ LzmaEnc_Destroy(p, &lzma_alloc, &lzma_alloc); ++} ++ ++STATIC int INIT lzma_alloc_workspace(CLzmaEncProps *props) ++{ ++ if ((p = (CLzmaEncHandle *)LzmaEnc_Create(&lzma_alloc)) == NULL) ++ { ++ PRINT_ERROR("Failed to allocate lzma deflate workspace\n"); ++ return -ENOMEM; ++ } ++ ++ if (LzmaEnc_SetProps(p, props) != SZ_OK) ++ { ++ lzma_free_workspace(); ++ return -1; ++ } ++ ++ if (LzmaEnc_WriteProperties(p, propsEncoded, &propsSize) != SZ_OK) ++ { ++ lzma_free_workspace(); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++STATIC int jffs2_lzma_compress(unsigned char *data_in, unsigned char *cpage_out, ++ uint32_t *sourcelen, uint32_t *dstlen) ++{ ++ SizeT compress_size = (SizeT)(*dstlen); ++ int ret; ++ ++ #ifdef __KERNEL__ ++ mutex_lock(&deflate_mutex); ++ #endif ++ ++ ret = LzmaEnc_MemEncode(p, cpage_out, &compress_size, data_in, *sourcelen, ++ 0, NULL, &lzma_alloc, &lzma_alloc); ++ ++ #ifdef __KERNEL__ ++ mutex_unlock(&deflate_mutex); ++ #endif ++ ++ if (ret != SZ_OK) ++ return -1; ++ ++ *dstlen = (uint32_t)compress_size; ++ ++ return 0; ++} ++ ++STATIC int jffs2_lzma_decompress(unsigned char *data_in, unsigned char *cpage_out, ++ uint32_t srclen, uint32_t destlen) ++{ ++ int ret; ++ SizeT dl = (SizeT)destlen; ++ SizeT sl = (SizeT)srclen; ++ ELzmaStatus status; ++ ++ ret = LzmaDecode(cpage_out, &dl, data_in, &sl, propsEncoded, ++ propsSize, LZMA_FINISH_ANY, &status, &lzma_alloc); ++ ++ if (ret != SZ_OK || status == LZMA_STATUS_NOT_FINISHED || dl != (SizeT)destlen) ++ return -1; ++ ++ return 0; ++} ++ ++static struct jffs2_compressor jffs2_lzma_comp = { ++ .priority = JFFS2_LZMA_PRIORITY, ++ .name = "lzma", ++ .compr = JFFS2_COMPR_LZMA, ++ .compress = &jffs2_lzma_compress, ++ .decompress = &jffs2_lzma_decompress, ++ .disabled = 0, ++}; ++ ++int INIT jffs2_lzma_init(void) ++{ ++ int ret; ++ CLzmaEncProps props; ++ LzmaEncProps_Init(&props); ++ ++ props.dictSize = LZMA_BEST_DICT(0x2000); ++ props.level = LZMA_BEST_LEVEL; ++ props.lc = LZMA_BEST_LC; ++ props.lp = LZMA_BEST_LP; ++ props.pb = LZMA_BEST_PB; ++ props.fb = LZMA_BEST_FB; ++ ++ ret = lzma_alloc_workspace(&props); ++ if (ret < 0) ++ return ret; ++ ++ ret = jffs2_register_compressor(&jffs2_lzma_comp); ++ if (ret) ++ lzma_free_workspace(); ++ ++ return ret; ++} ++ ++void jffs2_lzma_exit(void) ++{ ++ jffs2_unregister_compressor(&jffs2_lzma_comp); ++ lzma_free_workspace(); ++} +--- a/fs/jffs2/super.c ++++ b/fs/jffs2/super.c +@@ -375,14 +375,41 @@ static int __init init_jffs2_fs(void) + BUILD_BUG_ON(sizeof(struct jffs2_raw_inode) != 68); + BUILD_BUG_ON(sizeof(struct jffs2_raw_summary) != 32); + +- pr_info("version 2.2." ++ pr_info("version 2.2" + #ifdef CONFIG_JFFS2_FS_WRITEBUFFER + " (NAND)" + #endif + #ifdef CONFIG_JFFS2_SUMMARY +- " (SUMMARY) " ++ " (SUMMARY)" + #endif +- " © 2001-2006 Red Hat, Inc.\n"); ++#ifdef CONFIG_JFFS2_ZLIB ++ " (ZLIB)" ++#endif ++#ifdef CONFIG_JFFS2_LZO ++ " (LZO)" ++#endif ++#ifdef CONFIG_JFFS2_LZMA ++ " (LZMA)" ++#endif ++#ifdef CONFIG_JFFS2_RTIME ++ " (RTIME)" ++#endif ++#ifdef CONFIG_JFFS2_RUBIN ++ " (RUBIN)" ++#endif ++#ifdef CONFIG_JFFS2_CMODE_NONE ++ " (CMODE_NONE)" ++#endif ++#ifdef CONFIG_JFFS2_CMODE_PRIORITY ++ " (CMODE_PRIORITY)" ++#endif ++#ifdef CONFIG_JFFS2_CMODE_SIZE ++ " (CMODE_SIZE)" ++#endif ++#ifdef CONFIG_JFFS2_CMODE_FAVOURLZO ++ " (CMODE_FAVOURLZO)" ++#endif ++ " (c) 2001-2006 Red Hat, Inc.\n"); + + jffs2_inode_cachep = kmem_cache_create("jffs2_i", + sizeof(struct jffs2_inode_info), +--- a/include/uapi/linux/jffs2.h ++++ b/include/uapi/linux/jffs2.h +@@ -46,6 +46,7 @@ + #define JFFS2_COMPR_DYNRUBIN 0x05 + #define JFFS2_COMPR_ZLIB 0x06 + #define JFFS2_COMPR_LZO 0x07 ++#define JFFS2_COMPR_LZMA 0x08 + /* Compatibility flags. */ + #define JFFS2_COMPAT_MASK 0xc000 /* What do to if an unknown nodetype is found */ + #define JFFS2_NODE_ACCURATE 0x2000 +--- /dev/null ++++ b/include/linux/lzma.h +@@ -0,0 +1,62 @@ ++#ifndef __LZMA_H__ ++#define __LZMA_H__ ++ ++#ifdef __KERNEL__ ++ #include ++ #include ++ #include ++ #include ++ #include ++ #define LZMA_MALLOC vmalloc ++ #define LZMA_FREE vfree ++ #define PRINT_ERROR(msg) printk(KERN_WARNING #msg) ++ #define INIT __init ++ #define STATIC static ++#else ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ #ifndef PAGE_SIZE ++ extern int page_size; ++ #define PAGE_SIZE page_size ++ #endif ++ #define LZMA_MALLOC malloc ++ #define LZMA_FREE free ++ #define PRINT_ERROR(msg) fprintf(stderr, msg) ++ #define INIT ++ #define STATIC ++#endif ++ ++#include "lzma/LzmaDec.h" ++#include "lzma/LzmaEnc.h" ++ ++#define LZMA_BEST_LEVEL (9) ++#define LZMA_BEST_LC (0) ++#define LZMA_BEST_LP (0) ++#define LZMA_BEST_PB (0) ++#define LZMA_BEST_FB (273) ++ ++#define LZMA_BEST_DICT(n) (((int)((n) / 2)) * 2) ++ ++static void *p_lzma_malloc(void *p, size_t size) ++{ ++ if (size == 0) ++ return NULL; ++ ++ return LZMA_MALLOC(size); ++} ++ ++static void p_lzma_free(void *p, void *address) ++{ ++ if (address != NULL) ++ LZMA_FREE(address); ++} ++ ++static ISzAlloc lzma_alloc = {p_lzma_malloc, p_lzma_free}; ++ ++#endif +--- /dev/null ++++ b/include/linux/lzma/LzFind.h +@@ -0,0 +1,115 @@ ++/* LzFind.h -- Match finder for LZ algorithms ++2009-04-22 : Igor Pavlov : Public domain */ ++ ++#ifndef __LZ_FIND_H ++#define __LZ_FIND_H ++ ++#include "Types.h" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++typedef UInt32 CLzRef; ++ ++typedef struct _CMatchFinder ++{ ++ Byte *buffer; ++ UInt32 pos; ++ UInt32 posLimit; ++ UInt32 streamPos; ++ UInt32 lenLimit; ++ ++ UInt32 cyclicBufferPos; ++ UInt32 cyclicBufferSize; /* it must be = (historySize + 1) */ ++ ++ UInt32 matchMaxLen; ++ CLzRef *hash; ++ CLzRef *son; ++ UInt32 hashMask; ++ UInt32 cutValue; ++ ++ Byte *bufferBase; ++ ISeqInStream *stream; ++ int streamEndWasReached; ++ ++ UInt32 blockSize; ++ UInt32 keepSizeBefore; ++ UInt32 keepSizeAfter; ++ ++ UInt32 numHashBytes; ++ int directInput; ++ size_t directInputRem; ++ int btMode; ++ int bigHash; ++ UInt32 historySize; ++ UInt32 fixedHashSize; ++ UInt32 hashSizeSum; ++ UInt32 numSons; ++ SRes result; ++ UInt32 crc[256]; ++} CMatchFinder; ++ ++#define Inline_MatchFinder_GetPointerToCurrentPos(p) ((p)->buffer) ++#define Inline_MatchFinder_GetIndexByte(p, index) ((p)->buffer[(Int32)(index)]) ++ ++#define Inline_MatchFinder_GetNumAvailableBytes(p) ((p)->streamPos - (p)->pos) ++ ++int MatchFinder_NeedMove(CMatchFinder *p); ++Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p); ++void MatchFinder_MoveBlock(CMatchFinder *p); ++void MatchFinder_ReadIfRequired(CMatchFinder *p); ++ ++void MatchFinder_Construct(CMatchFinder *p); ++ ++/* Conditions: ++ historySize <= 3 GB ++ keepAddBufferBefore + matchMaxLen + keepAddBufferAfter < 511MB ++*/ ++int MatchFinder_Create(CMatchFinder *p, UInt32 historySize, ++ UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ++ ISzAlloc *alloc); ++void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc); ++void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems); ++void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue); ++ ++UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *buffer, CLzRef *son, ++ UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue, ++ UInt32 *distances, UInt32 maxLen); ++ ++/* ++Conditions: ++ Mf_GetNumAvailableBytes_Func must be called before each Mf_GetMatchLen_Func. ++ Mf_GetPointerToCurrentPos_Func's result must be used only before any other function ++*/ ++ ++typedef void (*Mf_Init_Func)(void *object); ++typedef Byte (*Mf_GetIndexByte_Func)(void *object, Int32 index); ++typedef UInt32 (*Mf_GetNumAvailableBytes_Func)(void *object); ++typedef const Byte * (*Mf_GetPointerToCurrentPos_Func)(void *object); ++typedef UInt32 (*Mf_GetMatches_Func)(void *object, UInt32 *distances); ++typedef void (*Mf_Skip_Func)(void *object, UInt32); ++ ++typedef struct _IMatchFinder ++{ ++ Mf_Init_Func Init; ++ Mf_GetIndexByte_Func GetIndexByte; ++ Mf_GetNumAvailableBytes_Func GetNumAvailableBytes; ++ Mf_GetPointerToCurrentPos_Func GetPointerToCurrentPos; ++ Mf_GetMatches_Func GetMatches; ++ Mf_Skip_Func Skip; ++} IMatchFinder; ++ ++void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable); ++ ++void MatchFinder_Init(CMatchFinder *p); ++UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances); ++UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances); ++void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num); ++void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif +--- /dev/null ++++ b/include/linux/lzma/LzHash.h +@@ -0,0 +1,54 @@ ++/* LzHash.h -- HASH functions for LZ algorithms ++2009-02-07 : Igor Pavlov : Public domain */ ++ ++#ifndef __LZ_HASH_H ++#define __LZ_HASH_H ++ ++#define kHash2Size (1 << 10) ++#define kHash3Size (1 << 16) ++#define kHash4Size (1 << 20) ++ ++#define kFix3HashSize (kHash2Size) ++#define kFix4HashSize (kHash2Size + kHash3Size) ++#define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size) ++ ++#define HASH2_CALC hashValue = cur[0] | ((UInt32)cur[1] << 8); ++ ++#define HASH3_CALC { \ ++ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ ++ hash2Value = temp & (kHash2Size - 1); \ ++ hashValue = (temp ^ ((UInt32)cur[2] << 8)) & p->hashMask; } ++ ++#define HASH4_CALC { \ ++ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ ++ hash2Value = temp & (kHash2Size - 1); \ ++ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \ ++ hashValue = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & p->hashMask; } ++ ++#define HASH5_CALC { \ ++ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ ++ hash2Value = temp & (kHash2Size - 1); \ ++ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \ ++ hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)); \ ++ hashValue = (hash4Value ^ (p->crc[cur[4]] << 3)) & p->hashMask; \ ++ hash4Value &= (kHash4Size - 1); } ++ ++/* #define HASH_ZIP_CALC hashValue = ((cur[0] | ((UInt32)cur[1] << 8)) ^ p->crc[cur[2]]) & 0xFFFF; */ ++#define HASH_ZIP_CALC hashValue = ((cur[2] | ((UInt32)cur[0] << 8)) ^ p->crc[cur[1]]) & 0xFFFF; ++ ++ ++#define MT_HASH2_CALC \ ++ hash2Value = (p->crc[cur[0]] ^ cur[1]) & (kHash2Size - 1); ++ ++#define MT_HASH3_CALC { \ ++ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ ++ hash2Value = temp & (kHash2Size - 1); \ ++ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); } ++ ++#define MT_HASH4_CALC { \ ++ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ ++ hash2Value = temp & (kHash2Size - 1); \ ++ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \ ++ hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & (kHash4Size - 1); } ++ ++#endif +--- /dev/null ++++ b/include/linux/lzma/LzmaDec.h +@@ -0,0 +1,231 @@ ++/* LzmaDec.h -- LZMA Decoder ++2009-02-07 : Igor Pavlov : Public domain */ ++ ++#ifndef __LZMA_DEC_H ++#define __LZMA_DEC_H ++ ++#include "Types.h" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/* #define _LZMA_PROB32 */ ++/* _LZMA_PROB32 can increase the speed on some CPUs, ++ but memory usage for CLzmaDec::probs will be doubled in that case */ ++ ++#ifdef _LZMA_PROB32 ++#define CLzmaProb UInt32 ++#else ++#define CLzmaProb UInt16 ++#endif ++ ++ ++/* ---------- LZMA Properties ---------- */ ++ ++#define LZMA_PROPS_SIZE 5 ++ ++typedef struct _CLzmaProps ++{ ++ unsigned lc, lp, pb; ++ UInt32 dicSize; ++} CLzmaProps; ++ ++/* LzmaProps_Decode - decodes properties ++Returns: ++ SZ_OK ++ SZ_ERROR_UNSUPPORTED - Unsupported properties ++*/ ++ ++SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size); ++ ++ ++/* ---------- LZMA Decoder state ---------- */ ++ ++/* LZMA_REQUIRED_INPUT_MAX = number of required input bytes for worst case. ++ Num bits = log2((2^11 / 31) ^ 22) + 26 < 134 + 26 = 160; */ ++ ++#define LZMA_REQUIRED_INPUT_MAX 20 ++ ++typedef struct ++{ ++ CLzmaProps prop; ++ CLzmaProb *probs; ++ Byte *dic; ++ const Byte *buf; ++ UInt32 range, code; ++ SizeT dicPos; ++ SizeT dicBufSize; ++ UInt32 processedPos; ++ UInt32 checkDicSize; ++ unsigned state; ++ UInt32 reps[4]; ++ unsigned remainLen; ++ int needFlush; ++ int needInitState; ++ UInt32 numProbs; ++ unsigned tempBufSize; ++ Byte tempBuf[LZMA_REQUIRED_INPUT_MAX]; ++} CLzmaDec; ++ ++#define LzmaDec_Construct(p) { (p)->dic = 0; (p)->probs = 0; } ++ ++void LzmaDec_Init(CLzmaDec *p); ++ ++/* There are two types of LZMA streams: ++ 0) Stream with end mark. That end mark adds about 6 bytes to compressed size. ++ 1) Stream without end mark. You must know exact uncompressed size to decompress such stream. */ ++ ++typedef enum ++{ ++ LZMA_FINISH_ANY, /* finish at any point */ ++ LZMA_FINISH_END /* block must be finished at the end */ ++} ELzmaFinishMode; ++ ++/* ELzmaFinishMode has meaning only if the decoding reaches output limit !!! ++ ++ You must use LZMA_FINISH_END, when you know that current output buffer ++ covers last bytes of block. In other cases you must use LZMA_FINISH_ANY. ++ ++ If LZMA decoder sees end marker before reaching output limit, it returns SZ_OK, ++ and output value of destLen will be less than output buffer size limit. ++ You can check status result also. ++ ++ You can use multiple checks to test data integrity after full decompression: ++ 1) Check Result and "status" variable. ++ 2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize. ++ 3) Check that output(srcLen) = compressedSize, if you know real compressedSize. ++ You must use correct finish mode in that case. */ ++ ++typedef enum ++{ ++ LZMA_STATUS_NOT_SPECIFIED, /* use main error code instead */ ++ LZMA_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */ ++ LZMA_STATUS_NOT_FINISHED, /* stream was not finished */ ++ LZMA_STATUS_NEEDS_MORE_INPUT, /* you must provide more input bytes */ ++ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK /* there is probability that stream was finished without end mark */ ++} ELzmaStatus; ++ ++/* ELzmaStatus is used only as output value for function call */ ++ ++ ++/* ---------- Interfaces ---------- */ ++ ++/* There are 3 levels of interfaces: ++ 1) Dictionary Interface ++ 2) Buffer Interface ++ 3) One Call Interface ++ You can select any of these interfaces, but don't mix functions from different ++ groups for same object. */ ++ ++ ++/* There are two variants to allocate state for Dictionary Interface: ++ 1) LzmaDec_Allocate / LzmaDec_Free ++ 2) LzmaDec_AllocateProbs / LzmaDec_FreeProbs ++ You can use variant 2, if you set dictionary buffer manually. ++ For Buffer Interface you must always use variant 1. ++ ++LzmaDec_Allocate* can return: ++ SZ_OK ++ SZ_ERROR_MEM - Memory allocation error ++ SZ_ERROR_UNSUPPORTED - Unsupported properties ++*/ ++ ++SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc); ++void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc); ++ ++SRes LzmaDec_Allocate(CLzmaDec *state, const Byte *prop, unsigned propsSize, ISzAlloc *alloc); ++void LzmaDec_Free(CLzmaDec *state, ISzAlloc *alloc); ++ ++/* ---------- Dictionary Interface ---------- */ ++ ++/* You can use it, if you want to eliminate the overhead for data copying from ++ dictionary to some other external buffer. ++ You must work with CLzmaDec variables directly in this interface. ++ ++ STEPS: ++ LzmaDec_Constr() ++ LzmaDec_Allocate() ++ for (each new stream) ++ { ++ LzmaDec_Init() ++ while (it needs more decompression) ++ { ++ LzmaDec_DecodeToDic() ++ use data from CLzmaDec::dic and update CLzmaDec::dicPos ++ } ++ } ++ LzmaDec_Free() ++*/ ++ ++/* LzmaDec_DecodeToDic ++ ++ The decoding to internal dictionary buffer (CLzmaDec::dic). ++ You must manually update CLzmaDec::dicPos, if it reaches CLzmaDec::dicBufSize !!! ++ ++finishMode: ++ It has meaning only if the decoding reaches output limit (dicLimit). ++ LZMA_FINISH_ANY - Decode just dicLimit bytes. ++ LZMA_FINISH_END - Stream must be finished after dicLimit. ++ ++Returns: ++ SZ_OK ++ status: ++ LZMA_STATUS_FINISHED_WITH_MARK ++ LZMA_STATUS_NOT_FINISHED ++ LZMA_STATUS_NEEDS_MORE_INPUT ++ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK ++ SZ_ERROR_DATA - Data error ++*/ ++ ++SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, ++ const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); ++ ++ ++/* ---------- Buffer Interface ---------- */ ++ ++/* It's zlib-like interface. ++ See LzmaDec_DecodeToDic description for information about STEPS and return results, ++ but you must use LzmaDec_DecodeToBuf instead of LzmaDec_DecodeToDic and you don't need ++ to work with CLzmaDec variables manually. ++ ++finishMode: ++ It has meaning only if the decoding reaches output limit (*destLen). ++ LZMA_FINISH_ANY - Decode just destLen bytes. ++ LZMA_FINISH_END - Stream must be finished after (*destLen). ++*/ ++ ++SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, ++ const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); ++ ++ ++/* ---------- One Call Interface ---------- */ ++ ++/* LzmaDecode ++ ++finishMode: ++ It has meaning only if the decoding reaches output limit (*destLen). ++ LZMA_FINISH_ANY - Decode just destLen bytes. ++ LZMA_FINISH_END - Stream must be finished after (*destLen). ++ ++Returns: ++ SZ_OK ++ status: ++ LZMA_STATUS_FINISHED_WITH_MARK ++ LZMA_STATUS_NOT_FINISHED ++ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK ++ SZ_ERROR_DATA - Data error ++ SZ_ERROR_MEM - Memory allocation error ++ SZ_ERROR_UNSUPPORTED - Unsupported properties ++ SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src). ++*/ ++ ++SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ++ const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, ++ ELzmaStatus *status, ISzAlloc *alloc); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif +--- /dev/null ++++ b/include/linux/lzma/LzmaEnc.h +@@ -0,0 +1,80 @@ ++/* LzmaEnc.h -- LZMA Encoder ++2009-02-07 : Igor Pavlov : Public domain */ ++ ++#ifndef __LZMA_ENC_H ++#define __LZMA_ENC_H ++ ++#include "Types.h" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++#define LZMA_PROPS_SIZE 5 ++ ++typedef struct _CLzmaEncProps ++{ ++ int level; /* 0 <= level <= 9 */ ++ UInt32 dictSize; /* (1 << 12) <= dictSize <= (1 << 27) for 32-bit version ++ (1 << 12) <= dictSize <= (1 << 30) for 64-bit version ++ default = (1 << 24) */ ++ int lc; /* 0 <= lc <= 8, default = 3 */ ++ int lp; /* 0 <= lp <= 4, default = 0 */ ++ int pb; /* 0 <= pb <= 4, default = 2 */ ++ int algo; /* 0 - fast, 1 - normal, default = 1 */ ++ int fb; /* 5 <= fb <= 273, default = 32 */ ++ int btMode; /* 0 - hashChain Mode, 1 - binTree mode - normal, default = 1 */ ++ int numHashBytes; /* 2, 3 or 4, default = 4 */ ++ UInt32 mc; /* 1 <= mc <= (1 << 30), default = 32 */ ++ unsigned writeEndMark; /* 0 - do not write EOPM, 1 - write EOPM, default = 0 */ ++ int numThreads; /* 1 or 2, default = 2 */ ++} CLzmaEncProps; ++ ++void LzmaEncProps_Init(CLzmaEncProps *p); ++void LzmaEncProps_Normalize(CLzmaEncProps *p); ++UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2); ++ ++ ++/* ---------- CLzmaEncHandle Interface ---------- */ ++ ++/* LzmaEnc_* functions can return the following exit codes: ++Returns: ++ SZ_OK - OK ++ SZ_ERROR_MEM - Memory allocation error ++ SZ_ERROR_PARAM - Incorrect paramater in props ++ SZ_ERROR_WRITE - Write callback error. ++ SZ_ERROR_PROGRESS - some break from progress callback ++ SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version) ++*/ ++ ++typedef void * CLzmaEncHandle; ++ ++CLzmaEncHandle LzmaEnc_Create(ISzAlloc *alloc); ++void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAlloc *alloc, ISzAlloc *allocBig); ++SRes LzmaEnc_SetProps(CLzmaEncHandle p, const CLzmaEncProps *props); ++SRes LzmaEnc_WriteProperties(CLzmaEncHandle p, Byte *properties, SizeT *size); ++SRes LzmaEnc_Encode(CLzmaEncHandle p, ISeqOutStream *outStream, ISeqInStream *inStream, ++ ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig); ++SRes LzmaEnc_MemEncode(CLzmaEncHandle p, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, ++ int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig); ++ ++/* ---------- One Call Interface ---------- */ ++ ++/* LzmaEncode ++Return code: ++ SZ_OK - OK ++ SZ_ERROR_MEM - Memory allocation error ++ SZ_ERROR_PARAM - Incorrect paramater ++ SZ_ERROR_OUTPUT_EOF - output buffer overflow ++ SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version) ++*/ ++ ++SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, ++ const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark, ++ ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif +--- /dev/null ++++ b/include/linux/lzma/Types.h +@@ -0,0 +1,226 @@ ++/* Types.h -- Basic types ++2009-11-23 : Igor Pavlov : Public domain */ ++ ++#ifndef __7Z_TYPES_H ++#define __7Z_TYPES_H ++ ++#include ++ ++#ifdef _WIN32 ++#include ++#endif ++ ++#ifndef EXTERN_C_BEGIN ++#ifdef __cplusplus ++#define EXTERN_C_BEGIN extern "C" { ++#define EXTERN_C_END } ++#else ++#define EXTERN_C_BEGIN ++#define EXTERN_C_END ++#endif ++#endif ++ ++EXTERN_C_BEGIN ++ ++#define SZ_OK 0 ++ ++#define SZ_ERROR_DATA 1 ++#define SZ_ERROR_MEM 2 ++#define SZ_ERROR_CRC 3 ++#define SZ_ERROR_UNSUPPORTED 4 ++#define SZ_ERROR_PARAM 5 ++#define SZ_ERROR_INPUT_EOF 6 ++#define SZ_ERROR_OUTPUT_EOF 7 ++#define SZ_ERROR_READ 8 ++#define SZ_ERROR_WRITE 9 ++#define SZ_ERROR_PROGRESS 10 ++#define SZ_ERROR_FAIL 11 ++#define SZ_ERROR_THREAD 12 ++ ++#define SZ_ERROR_ARCHIVE 16 ++#define SZ_ERROR_NO_ARCHIVE 17 ++ ++typedef int SRes; ++ ++#ifdef _WIN32 ++typedef DWORD WRes; ++#else ++typedef int WRes; ++#endif ++ ++#ifndef RINOK ++#define RINOK(x) { int __result__ = (x); if (__result__ != 0) return __result__; } ++#endif ++ ++typedef unsigned char Byte; ++typedef short Int16; ++typedef unsigned short UInt16; ++ ++#ifdef _LZMA_UINT32_IS_ULONG ++typedef long Int32; ++typedef unsigned long UInt32; ++#else ++typedef int Int32; ++typedef unsigned int UInt32; ++#endif ++ ++#ifdef _SZ_NO_INT_64 ++ ++/* define _SZ_NO_INT_64, if your compiler doesn't support 64-bit integers. ++ NOTES: Some code will work incorrectly in that case! */ ++ ++typedef long Int64; ++typedef unsigned long UInt64; ++ ++#else ++ ++#if defined(_MSC_VER) || defined(__BORLANDC__) ++typedef __int64 Int64; ++typedef unsigned __int64 UInt64; ++#else ++typedef long long int Int64; ++typedef unsigned long long int UInt64; ++#endif ++ ++#endif ++ ++#ifdef _LZMA_NO_SYSTEM_SIZE_T ++typedef UInt32 SizeT; ++#else ++typedef size_t SizeT; ++#endif ++ ++typedef int Bool; ++#define True 1 ++#define False 0 ++ ++ ++#ifdef _WIN32 ++#define MY_STD_CALL __stdcall ++#else ++#define MY_STD_CALL ++#endif ++ ++#ifdef _MSC_VER ++ ++#if _MSC_VER >= 1300 ++#define MY_NO_INLINE __declspec(noinline) ++#else ++#define MY_NO_INLINE ++#endif ++ ++#define MY_CDECL __cdecl ++#define MY_FAST_CALL __fastcall ++ ++#else ++ ++#define MY_CDECL ++#define MY_FAST_CALL ++ ++#endif ++ ++ ++/* The following interfaces use first parameter as pointer to structure */ ++ ++typedef struct ++{ ++ SRes (*Read)(void *p, void *buf, size_t *size); ++ /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. ++ (output(*size) < input(*size)) is allowed */ ++} ISeqInStream; ++ ++/* it can return SZ_ERROR_INPUT_EOF */ ++SRes SeqInStream_Read(ISeqInStream *stream, void *buf, size_t size); ++SRes SeqInStream_Read2(ISeqInStream *stream, void *buf, size_t size, SRes errorType); ++SRes SeqInStream_ReadByte(ISeqInStream *stream, Byte *buf); ++ ++typedef struct ++{ ++ size_t (*Write)(void *p, const void *buf, size_t size); ++ /* Returns: result - the number of actually written bytes. ++ (result < size) means error */ ++} ISeqOutStream; ++ ++typedef enum ++{ ++ SZ_SEEK_SET = 0, ++ SZ_SEEK_CUR = 1, ++ SZ_SEEK_END = 2 ++} ESzSeek; ++ ++typedef struct ++{ ++ SRes (*Read)(void *p, void *buf, size_t *size); /* same as ISeqInStream::Read */ ++ SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin); ++} ISeekInStream; ++ ++typedef struct ++{ ++ SRes (*Look)(void *p, void **buf, size_t *size); ++ /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. ++ (output(*size) > input(*size)) is not allowed ++ (output(*size) < input(*size)) is allowed */ ++ SRes (*Skip)(void *p, size_t offset); ++ /* offset must be <= output(*size) of Look */ ++ ++ SRes (*Read)(void *p, void *buf, size_t *size); ++ /* reads directly (without buffer). It's same as ISeqInStream::Read */ ++ SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin); ++} ILookInStream; ++ ++SRes LookInStream_LookRead(ILookInStream *stream, void *buf, size_t *size); ++SRes LookInStream_SeekTo(ILookInStream *stream, UInt64 offset); ++ ++/* reads via ILookInStream::Read */ ++SRes LookInStream_Read2(ILookInStream *stream, void *buf, size_t size, SRes errorType); ++SRes LookInStream_Read(ILookInStream *stream, void *buf, size_t size); ++ ++#define LookToRead_BUF_SIZE (1 << 14) ++ ++typedef struct ++{ ++ ILookInStream s; ++ ISeekInStream *realStream; ++ size_t pos; ++ size_t size; ++ Byte buf[LookToRead_BUF_SIZE]; ++} CLookToRead; ++ ++void LookToRead_CreateVTable(CLookToRead *p, int lookahead); ++void LookToRead_Init(CLookToRead *p); ++ ++typedef struct ++{ ++ ISeqInStream s; ++ ILookInStream *realStream; ++} CSecToLook; ++ ++void SecToLook_CreateVTable(CSecToLook *p); ++ ++typedef struct ++{ ++ ISeqInStream s; ++ ILookInStream *realStream; ++} CSecToRead; ++ ++void SecToRead_CreateVTable(CSecToRead *p); ++ ++typedef struct ++{ ++ SRes (*Progress)(void *p, UInt64 inSize, UInt64 outSize); ++ /* Returns: result. (result != SZ_OK) means break. ++ Value (UInt64)(Int64)-1 for size means unknown value. */ ++} ICompressProgress; ++ ++typedef struct ++{ ++ void *(*Alloc)(void *p, size_t size); ++ void (*Free)(void *p, void *address); /* address can be 0 */ ++} ISzAlloc; ++ ++#define IAlloc_Alloc(p, size) (p)->Alloc((p), size) ++#define IAlloc_Free(p, a) (p)->Free((p), a) ++ ++EXTERN_C_END ++ ++#endif +--- a/lib/Kconfig ++++ b/lib/Kconfig +@@ -236,6 +236,12 @@ config LZ4_DECOMPRESS + + source "lib/xz/Kconfig" + ++config LZMA_COMPRESS ++ tristate ++ ++config LZMA_DECOMPRESS ++ tristate ++ + # + # These all provide a common interface (hence the apparent duplication with + # ZLIB_INFLATE; DECOMPRESS_GZIP is just a wrapper.) +--- a/lib/Makefile ++++ b/lib/Makefile +@@ -2,6 +2,16 @@ + # Makefile for some libs needed in the kernel. + # + ++ifdef CONFIG_JFFS2_ZLIB ++ CONFIG_ZLIB_INFLATE:=y ++ CONFIG_ZLIB_DEFLATE:=y ++endif ++ ++ifdef CONFIG_JFFS2_LZMA ++ CONFIG_LZMA_DECOMPRESS:=y ++ CONFIG_LZMA_COMPRESS:=y ++endif ++ + ifdef CONFIG_FUNCTION_TRACER + ORIG_CFLAGS := $(KBUILD_CFLAGS) + KBUILD_CFLAGS = $(subst $(CC_FLAGS_FTRACE),,$(ORIG_CFLAGS)) +@@ -89,6 +99,8 @@ obj-$(CONFIG_LZ4HC_COMPRESS) += lz4/ + obj-$(CONFIG_LZ4_DECOMPRESS) += lz4/ + obj-$(CONFIG_XZ_DEC) += xz/ + obj-$(CONFIG_RAID6_PQ) += raid6/ ++obj-$(CONFIG_LZMA_COMPRESS) += lzma/ ++obj-$(CONFIG_LZMA_DECOMPRESS) += lzma/ + + lib-$(CONFIG_DECOMPRESS_GZIP) += decompress_inflate.o + lib-$(CONFIG_DECOMPRESS_BZIP2) += decompress_bunzip2.o +--- /dev/null ++++ b/lib/lzma/LzFind.c +@@ -0,0 +1,761 @@ ++/* LzFind.c -- Match finder for LZ algorithms ++2009-04-22 : Igor Pavlov : Public domain */ ++ ++#include ++ ++#include "LzFind.h" ++#include "LzHash.h" ++ ++#define kEmptyHashValue 0 ++#define kMaxValForNormalize ((UInt32)0xFFFFFFFF) ++#define kNormalizeStepMin (1 << 10) /* it must be power of 2 */ ++#define kNormalizeMask (~(kNormalizeStepMin - 1)) ++#define kMaxHistorySize ((UInt32)3 << 30) ++ ++#define kStartMaxLen 3 ++ ++static void LzInWindow_Free(CMatchFinder *p, ISzAlloc *alloc) ++{ ++ if (!p->directInput) ++ { ++ alloc->Free(alloc, p->bufferBase); ++ p->bufferBase = 0; ++ } ++} ++ ++/* keepSizeBefore + keepSizeAfter + keepSizeReserv must be < 4G) */ ++ ++static int LzInWindow_Create(CMatchFinder *p, UInt32 keepSizeReserv, ISzAlloc *alloc) ++{ ++ UInt32 blockSize = p->keepSizeBefore + p->keepSizeAfter + keepSizeReserv; ++ if (p->directInput) ++ { ++ p->blockSize = blockSize; ++ return 1; ++ } ++ if (p->bufferBase == 0 || p->blockSize != blockSize) ++ { ++ LzInWindow_Free(p, alloc); ++ p->blockSize = blockSize; ++ p->bufferBase = (Byte *)alloc->Alloc(alloc, (size_t)blockSize); ++ } ++ return (p->bufferBase != 0); ++} ++ ++Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; } ++Byte MatchFinder_GetIndexByte(CMatchFinder *p, Int32 index) { return p->buffer[index]; } ++ ++UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return p->streamPos - p->pos; } ++ ++void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue) ++{ ++ p->posLimit -= subValue; ++ p->pos -= subValue; ++ p->streamPos -= subValue; ++} ++ ++static void MatchFinder_ReadBlock(CMatchFinder *p) ++{ ++ if (p->streamEndWasReached || p->result != SZ_OK) ++ return; ++ if (p->directInput) ++ { ++ UInt32 curSize = 0xFFFFFFFF - p->streamPos; ++ if (curSize > p->directInputRem) ++ curSize = (UInt32)p->directInputRem; ++ p->directInputRem -= curSize; ++ p->streamPos += curSize; ++ if (p->directInputRem == 0) ++ p->streamEndWasReached = 1; ++ return; ++ } ++ for (;;) ++ { ++ Byte *dest = p->buffer + (p->streamPos - p->pos); ++ size_t size = (p->bufferBase + p->blockSize - dest); ++ if (size == 0) ++ return; ++ p->result = p->stream->Read(p->stream, dest, &size); ++ if (p->result != SZ_OK) ++ return; ++ if (size == 0) ++ { ++ p->streamEndWasReached = 1; ++ return; ++ } ++ p->streamPos += (UInt32)size; ++ if (p->streamPos - p->pos > p->keepSizeAfter) ++ return; ++ } ++} ++ ++void MatchFinder_MoveBlock(CMatchFinder *p) ++{ ++ memmove(p->bufferBase, ++ p->buffer - p->keepSizeBefore, ++ (size_t)(p->streamPos - p->pos + p->keepSizeBefore)); ++ p->buffer = p->bufferBase + p->keepSizeBefore; ++} ++ ++int MatchFinder_NeedMove(CMatchFinder *p) ++{ ++ if (p->directInput) ++ return 0; ++ /* if (p->streamEndWasReached) return 0; */ ++ return ((size_t)(p->bufferBase + p->blockSize - p->buffer) <= p->keepSizeAfter); ++} ++ ++void MatchFinder_ReadIfRequired(CMatchFinder *p) ++{ ++ if (p->streamEndWasReached) ++ return; ++ if (p->keepSizeAfter >= p->streamPos - p->pos) ++ MatchFinder_ReadBlock(p); ++} ++ ++static void MatchFinder_CheckAndMoveAndRead(CMatchFinder *p) ++{ ++ if (MatchFinder_NeedMove(p)) ++ MatchFinder_MoveBlock(p); ++ MatchFinder_ReadBlock(p); ++} ++ ++static void MatchFinder_SetDefaultSettings(CMatchFinder *p) ++{ ++ p->cutValue = 32; ++ p->btMode = 1; ++ p->numHashBytes = 4; ++ p->bigHash = 0; ++} ++ ++#define kCrcPoly 0xEDB88320 ++ ++void MatchFinder_Construct(CMatchFinder *p) ++{ ++ UInt32 i; ++ p->bufferBase = 0; ++ p->directInput = 0; ++ p->hash = 0; ++ MatchFinder_SetDefaultSettings(p); ++ ++ for (i = 0; i < 256; i++) ++ { ++ UInt32 r = i; ++ int j; ++ for (j = 0; j < 8; j++) ++ r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1)); ++ p->crc[i] = r; ++ } ++} ++ ++static void MatchFinder_FreeThisClassMemory(CMatchFinder *p, ISzAlloc *alloc) ++{ ++ alloc->Free(alloc, p->hash); ++ p->hash = 0; ++} ++ ++void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc) ++{ ++ MatchFinder_FreeThisClassMemory(p, alloc); ++ LzInWindow_Free(p, alloc); ++} ++ ++static CLzRef* AllocRefs(UInt32 num, ISzAlloc *alloc) ++{ ++ size_t sizeInBytes = (size_t)num * sizeof(CLzRef); ++ if (sizeInBytes / sizeof(CLzRef) != num) ++ return 0; ++ return (CLzRef *)alloc->Alloc(alloc, sizeInBytes); ++} ++ ++int MatchFinder_Create(CMatchFinder *p, UInt32 historySize, ++ UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ++ ISzAlloc *alloc) ++{ ++ UInt32 sizeReserv; ++ if (historySize > kMaxHistorySize) ++ { ++ MatchFinder_Free(p, alloc); ++ return 0; ++ } ++ sizeReserv = historySize >> 1; ++ if (historySize > ((UInt32)2 << 30)) ++ sizeReserv = historySize >> 2; ++ sizeReserv += (keepAddBufferBefore + matchMaxLen + keepAddBufferAfter) / 2 + (1 << 19); ++ ++ p->keepSizeBefore = historySize + keepAddBufferBefore + 1; ++ p->keepSizeAfter = matchMaxLen + keepAddBufferAfter; ++ /* we need one additional byte, since we use MoveBlock after pos++ and before dictionary using */ ++ if (LzInWindow_Create(p, sizeReserv, alloc)) ++ { ++ UInt32 newCyclicBufferSize = historySize + 1; ++ UInt32 hs; ++ p->matchMaxLen = matchMaxLen; ++ { ++ p->fixedHashSize = 0; ++ if (p->numHashBytes == 2) ++ hs = (1 << 16) - 1; ++ else ++ { ++ hs = historySize - 1; ++ hs |= (hs >> 1); ++ hs |= (hs >> 2); ++ hs |= (hs >> 4); ++ hs |= (hs >> 8); ++ hs >>= 1; ++ hs |= 0xFFFF; /* don't change it! It's required for Deflate */ ++ if (hs > (1 << 24)) ++ { ++ if (p->numHashBytes == 3) ++ hs = (1 << 24) - 1; ++ else ++ hs >>= 1; ++ } ++ } ++ p->hashMask = hs; ++ hs++; ++ if (p->numHashBytes > 2) p->fixedHashSize += kHash2Size; ++ if (p->numHashBytes > 3) p->fixedHashSize += kHash3Size; ++ if (p->numHashBytes > 4) p->fixedHashSize += kHash4Size; ++ hs += p->fixedHashSize; ++ } ++ ++ { ++ UInt32 prevSize = p->hashSizeSum + p->numSons; ++ UInt32 newSize; ++ p->historySize = historySize; ++ p->hashSizeSum = hs; ++ p->cyclicBufferSize = newCyclicBufferSize; ++ p->numSons = (p->btMode ? newCyclicBufferSize * 2 : newCyclicBufferSize); ++ newSize = p->hashSizeSum + p->numSons; ++ if (p->hash != 0 && prevSize == newSize) ++ return 1; ++ MatchFinder_FreeThisClassMemory(p, alloc); ++ p->hash = AllocRefs(newSize, alloc); ++ if (p->hash != 0) ++ { ++ p->son = p->hash + p->hashSizeSum; ++ return 1; ++ } ++ } ++ } ++ MatchFinder_Free(p, alloc); ++ return 0; ++} ++ ++static void MatchFinder_SetLimits(CMatchFinder *p) ++{ ++ UInt32 limit = kMaxValForNormalize - p->pos; ++ UInt32 limit2 = p->cyclicBufferSize - p->cyclicBufferPos; ++ if (limit2 < limit) ++ limit = limit2; ++ limit2 = p->streamPos - p->pos; ++ if (limit2 <= p->keepSizeAfter) ++ { ++ if (limit2 > 0) ++ limit2 = 1; ++ } ++ else ++ limit2 -= p->keepSizeAfter; ++ if (limit2 < limit) ++ limit = limit2; ++ { ++ UInt32 lenLimit = p->streamPos - p->pos; ++ if (lenLimit > p->matchMaxLen) ++ lenLimit = p->matchMaxLen; ++ p->lenLimit = lenLimit; ++ } ++ p->posLimit = p->pos + limit; ++} ++ ++void MatchFinder_Init(CMatchFinder *p) ++{ ++ UInt32 i; ++ for (i = 0; i < p->hashSizeSum; i++) ++ p->hash[i] = kEmptyHashValue; ++ p->cyclicBufferPos = 0; ++ p->buffer = p->bufferBase; ++ p->pos = p->streamPos = p->cyclicBufferSize; ++ p->result = SZ_OK; ++ p->streamEndWasReached = 0; ++ MatchFinder_ReadBlock(p); ++ MatchFinder_SetLimits(p); ++} ++ ++static UInt32 MatchFinder_GetSubValue(CMatchFinder *p) ++{ ++ return (p->pos - p->historySize - 1) & kNormalizeMask; ++} ++ ++void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems) ++{ ++ UInt32 i; ++ for (i = 0; i < numItems; i++) ++ { ++ UInt32 value = items[i]; ++ if (value <= subValue) ++ value = kEmptyHashValue; ++ else ++ value -= subValue; ++ items[i] = value; ++ } ++} ++ ++static void MatchFinder_Normalize(CMatchFinder *p) ++{ ++ UInt32 subValue = MatchFinder_GetSubValue(p); ++ MatchFinder_Normalize3(subValue, p->hash, p->hashSizeSum + p->numSons); ++ MatchFinder_ReduceOffsets(p, subValue); ++} ++ ++static void MatchFinder_CheckLimits(CMatchFinder *p) ++{ ++ if (p->pos == kMaxValForNormalize) ++ MatchFinder_Normalize(p); ++ if (!p->streamEndWasReached && p->keepSizeAfter == p->streamPos - p->pos) ++ MatchFinder_CheckAndMoveAndRead(p); ++ if (p->cyclicBufferPos == p->cyclicBufferSize) ++ p->cyclicBufferPos = 0; ++ MatchFinder_SetLimits(p); ++} ++ ++static UInt32 * Hc_GetMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, ++ UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue, ++ UInt32 *distances, UInt32 maxLen) ++{ ++ son[_cyclicBufferPos] = curMatch; ++ for (;;) ++ { ++ UInt32 delta = pos - curMatch; ++ if (cutValue-- == 0 || delta >= _cyclicBufferSize) ++ return distances; ++ { ++ const Byte *pb = cur - delta; ++ curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)]; ++ if (pb[maxLen] == cur[maxLen] && *pb == *cur) ++ { ++ UInt32 len = 0; ++ while (++len != lenLimit) ++ if (pb[len] != cur[len]) ++ break; ++ if (maxLen < len) ++ { ++ *distances++ = maxLen = len; ++ *distances++ = delta - 1; ++ if (len == lenLimit) ++ return distances; ++ } ++ } ++ } ++ } ++} ++ ++UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, ++ UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue, ++ UInt32 *distances, UInt32 maxLen) ++{ ++ CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1; ++ CLzRef *ptr1 = son + (_cyclicBufferPos << 1); ++ UInt32 len0 = 0, len1 = 0; ++ for (;;) ++ { ++ UInt32 delta = pos - curMatch; ++ if (cutValue-- == 0 || delta >= _cyclicBufferSize) ++ { ++ *ptr0 = *ptr1 = kEmptyHashValue; ++ return distances; ++ } ++ { ++ CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1); ++ const Byte *pb = cur - delta; ++ UInt32 len = (len0 < len1 ? len0 : len1); ++ if (pb[len] == cur[len]) ++ { ++ if (++len != lenLimit && pb[len] == cur[len]) ++ while (++len != lenLimit) ++ if (pb[len] != cur[len]) ++ break; ++ if (maxLen < len) ++ { ++ *distances++ = maxLen = len; ++ *distances++ = delta - 1; ++ if (len == lenLimit) ++ { ++ *ptr1 = pair[0]; ++ *ptr0 = pair[1]; ++ return distances; ++ } ++ } ++ } ++ if (pb[len] < cur[len]) ++ { ++ *ptr1 = curMatch; ++ ptr1 = pair + 1; ++ curMatch = *ptr1; ++ len1 = len; ++ } ++ else ++ { ++ *ptr0 = curMatch; ++ ptr0 = pair; ++ curMatch = *ptr0; ++ len0 = len; ++ } ++ } ++ } ++} ++ ++static void SkipMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, ++ UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue) ++{ ++ CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1; ++ CLzRef *ptr1 = son + (_cyclicBufferPos << 1); ++ UInt32 len0 = 0, len1 = 0; ++ for (;;) ++ { ++ UInt32 delta = pos - curMatch; ++ if (cutValue-- == 0 || delta >= _cyclicBufferSize) ++ { ++ *ptr0 = *ptr1 = kEmptyHashValue; ++ return; ++ } ++ { ++ CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1); ++ const Byte *pb = cur - delta; ++ UInt32 len = (len0 < len1 ? len0 : len1); ++ if (pb[len] == cur[len]) ++ { ++ while (++len != lenLimit) ++ if (pb[len] != cur[len]) ++ break; ++ { ++ if (len == lenLimit) ++ { ++ *ptr1 = pair[0]; ++ *ptr0 = pair[1]; ++ return; ++ } ++ } ++ } ++ if (pb[len] < cur[len]) ++ { ++ *ptr1 = curMatch; ++ ptr1 = pair + 1; ++ curMatch = *ptr1; ++ len1 = len; ++ } ++ else ++ { ++ *ptr0 = curMatch; ++ ptr0 = pair; ++ curMatch = *ptr0; ++ len0 = len; ++ } ++ } ++ } ++} ++ ++#define MOVE_POS \ ++ ++p->cyclicBufferPos; \ ++ p->buffer++; \ ++ if (++p->pos == p->posLimit) MatchFinder_CheckLimits(p); ++ ++#define MOVE_POS_RET MOVE_POS return offset; ++ ++static void MatchFinder_MovePos(CMatchFinder *p) { MOVE_POS; } ++ ++#define GET_MATCHES_HEADER2(minLen, ret_op) \ ++ UInt32 lenLimit; UInt32 hashValue; const Byte *cur; UInt32 curMatch; \ ++ lenLimit = p->lenLimit; { if (lenLimit < minLen) { MatchFinder_MovePos(p); ret_op; }} \ ++ cur = p->buffer; ++ ++#define GET_MATCHES_HEADER(minLen) GET_MATCHES_HEADER2(minLen, return 0) ++#define SKIP_HEADER(minLen) GET_MATCHES_HEADER2(minLen, continue) ++ ++#define MF_PARAMS(p) p->pos, p->buffer, p->son, p->cyclicBufferPos, p->cyclicBufferSize, p->cutValue ++ ++#define GET_MATCHES_FOOTER(offset, maxLen) \ ++ offset = (UInt32)(GetMatchesSpec1(lenLimit, curMatch, MF_PARAMS(p), \ ++ distances + offset, maxLen) - distances); MOVE_POS_RET; ++ ++#define SKIP_FOOTER \ ++ SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); MOVE_POS; ++ ++static UInt32 Bt2_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) ++{ ++ UInt32 offset; ++ GET_MATCHES_HEADER(2) ++ HASH2_CALC; ++ curMatch = p->hash[hashValue]; ++ p->hash[hashValue] = p->pos; ++ offset = 0; ++ GET_MATCHES_FOOTER(offset, 1) ++} ++ ++UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) ++{ ++ UInt32 offset; ++ GET_MATCHES_HEADER(3) ++ HASH_ZIP_CALC; ++ curMatch = p->hash[hashValue]; ++ p->hash[hashValue] = p->pos; ++ offset = 0; ++ GET_MATCHES_FOOTER(offset, 2) ++} ++ ++static UInt32 Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) ++{ ++ UInt32 hash2Value, delta2, maxLen, offset; ++ GET_MATCHES_HEADER(3) ++ ++ HASH3_CALC; ++ ++ delta2 = p->pos - p->hash[hash2Value]; ++ curMatch = p->hash[kFix3HashSize + hashValue]; ++ ++ p->hash[hash2Value] = ++ p->hash[kFix3HashSize + hashValue] = p->pos; ++ ++ ++ maxLen = 2; ++ offset = 0; ++ if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur) ++ { ++ for (; maxLen != lenLimit; maxLen++) ++ if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen]) ++ break; ++ distances[0] = maxLen; ++ distances[1] = delta2 - 1; ++ offset = 2; ++ if (maxLen == lenLimit) ++ { ++ SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); ++ MOVE_POS_RET; ++ } ++ } ++ GET_MATCHES_FOOTER(offset, maxLen) ++} ++ ++static UInt32 Bt4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) ++{ ++ UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset; ++ GET_MATCHES_HEADER(4) ++ ++ HASH4_CALC; ++ ++ delta2 = p->pos - p->hash[ hash2Value]; ++ delta3 = p->pos - p->hash[kFix3HashSize + hash3Value]; ++ curMatch = p->hash[kFix4HashSize + hashValue]; ++ ++ p->hash[ hash2Value] = ++ p->hash[kFix3HashSize + hash3Value] = ++ p->hash[kFix4HashSize + hashValue] = p->pos; ++ ++ maxLen = 1; ++ offset = 0; ++ if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur) ++ { ++ distances[0] = maxLen = 2; ++ distances[1] = delta2 - 1; ++ offset = 2; ++ } ++ if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur) ++ { ++ maxLen = 3; ++ distances[offset + 1] = delta3 - 1; ++ offset += 2; ++ delta2 = delta3; ++ } ++ if (offset != 0) ++ { ++ for (; maxLen != lenLimit; maxLen++) ++ if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen]) ++ break; ++ distances[offset - 2] = maxLen; ++ if (maxLen == lenLimit) ++ { ++ SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); ++ MOVE_POS_RET; ++ } ++ } ++ if (maxLen < 3) ++ maxLen = 3; ++ GET_MATCHES_FOOTER(offset, maxLen) ++} ++ ++static UInt32 Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) ++{ ++ UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset; ++ GET_MATCHES_HEADER(4) ++ ++ HASH4_CALC; ++ ++ delta2 = p->pos - p->hash[ hash2Value]; ++ delta3 = p->pos - p->hash[kFix3HashSize + hash3Value]; ++ curMatch = p->hash[kFix4HashSize + hashValue]; ++ ++ p->hash[ hash2Value] = ++ p->hash[kFix3HashSize + hash3Value] = ++ p->hash[kFix4HashSize + hashValue] = p->pos; ++ ++ maxLen = 1; ++ offset = 0; ++ if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur) ++ { ++ distances[0] = maxLen = 2; ++ distances[1] = delta2 - 1; ++ offset = 2; ++ } ++ if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur) ++ { ++ maxLen = 3; ++ distances[offset + 1] = delta3 - 1; ++ offset += 2; ++ delta2 = delta3; ++ } ++ if (offset != 0) ++ { ++ for (; maxLen != lenLimit; maxLen++) ++ if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen]) ++ break; ++ distances[offset - 2] = maxLen; ++ if (maxLen == lenLimit) ++ { ++ p->son[p->cyclicBufferPos] = curMatch; ++ MOVE_POS_RET; ++ } ++ } ++ if (maxLen < 3) ++ maxLen = 3; ++ offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p), ++ distances + offset, maxLen) - (distances)); ++ MOVE_POS_RET ++} ++ ++UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) ++{ ++ UInt32 offset; ++ GET_MATCHES_HEADER(3) ++ HASH_ZIP_CALC; ++ curMatch = p->hash[hashValue]; ++ p->hash[hashValue] = p->pos; ++ offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p), ++ distances, 2) - (distances)); ++ MOVE_POS_RET ++} ++ ++static void Bt2_MatchFinder_Skip(CMatchFinder *p, UInt32 num) ++{ ++ do ++ { ++ SKIP_HEADER(2) ++ HASH2_CALC; ++ curMatch = p->hash[hashValue]; ++ p->hash[hashValue] = p->pos; ++ SKIP_FOOTER ++ } ++ while (--num != 0); ++} ++ ++void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num) ++{ ++ do ++ { ++ SKIP_HEADER(3) ++ HASH_ZIP_CALC; ++ curMatch = p->hash[hashValue]; ++ p->hash[hashValue] = p->pos; ++ SKIP_FOOTER ++ } ++ while (--num != 0); ++} ++ ++static void Bt3_MatchFinder_Skip(CMatchFinder *p, UInt32 num) ++{ ++ do ++ { ++ UInt32 hash2Value; ++ SKIP_HEADER(3) ++ HASH3_CALC; ++ curMatch = p->hash[kFix3HashSize + hashValue]; ++ p->hash[hash2Value] = ++ p->hash[kFix3HashSize + hashValue] = p->pos; ++ SKIP_FOOTER ++ } ++ while (--num != 0); ++} ++ ++static void Bt4_MatchFinder_Skip(CMatchFinder *p, UInt32 num) ++{ ++ do ++ { ++ UInt32 hash2Value, hash3Value; ++ SKIP_HEADER(4) ++ HASH4_CALC; ++ curMatch = p->hash[kFix4HashSize + hashValue]; ++ p->hash[ hash2Value] = ++ p->hash[kFix3HashSize + hash3Value] = p->pos; ++ p->hash[kFix4HashSize + hashValue] = p->pos; ++ SKIP_FOOTER ++ } ++ while (--num != 0); ++} ++ ++static void Hc4_MatchFinder_Skip(CMatchFinder *p, UInt32 num) ++{ ++ do ++ { ++ UInt32 hash2Value, hash3Value; ++ SKIP_HEADER(4) ++ HASH4_CALC; ++ curMatch = p->hash[kFix4HashSize + hashValue]; ++ p->hash[ hash2Value] = ++ p->hash[kFix3HashSize + hash3Value] = ++ p->hash[kFix4HashSize + hashValue] = p->pos; ++ p->son[p->cyclicBufferPos] = curMatch; ++ MOVE_POS ++ } ++ while (--num != 0); ++} ++ ++void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num) ++{ ++ do ++ { ++ SKIP_HEADER(3) ++ HASH_ZIP_CALC; ++ curMatch = p->hash[hashValue]; ++ p->hash[hashValue] = p->pos; ++ p->son[p->cyclicBufferPos] = curMatch; ++ MOVE_POS ++ } ++ while (--num != 0); ++} ++ ++void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable) ++{ ++ vTable->Init = (Mf_Init_Func)MatchFinder_Init; ++ vTable->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinder_GetIndexByte; ++ vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinder_GetNumAvailableBytes; ++ vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinder_GetPointerToCurrentPos; ++ if (!p->btMode) ++ { ++ vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches; ++ vTable->Skip = (Mf_Skip_Func)Hc4_MatchFinder_Skip; ++ } ++ else if (p->numHashBytes == 2) ++ { ++ vTable->GetMatches = (Mf_GetMatches_Func)Bt2_MatchFinder_GetMatches; ++ vTable->Skip = (Mf_Skip_Func)Bt2_MatchFinder_Skip; ++ } ++ else if (p->numHashBytes == 3) ++ { ++ vTable->GetMatches = (Mf_GetMatches_Func)Bt3_MatchFinder_GetMatches; ++ vTable->Skip = (Mf_Skip_Func)Bt3_MatchFinder_Skip; ++ } ++ else ++ { ++ vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches; ++ vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip; ++ } ++} +--- /dev/null ++++ b/lib/lzma/LzmaDec.c +@@ -0,0 +1,999 @@ ++/* LzmaDec.c -- LZMA Decoder ++2009-09-20 : Igor Pavlov : Public domain */ ++ ++#include "LzmaDec.h" ++ ++#include ++ ++#define kNumTopBits 24 ++#define kTopValue ((UInt32)1 << kNumTopBits) ++ ++#define kNumBitModelTotalBits 11 ++#define kBitModelTotal (1 << kNumBitModelTotalBits) ++#define kNumMoveBits 5 ++ ++#define RC_INIT_SIZE 5 ++ ++#define NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); } ++ ++#define IF_BIT_0(p) ttt = *(p); NORMALIZE; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) ++#define UPDATE_0(p) range = bound; *(p) = (CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); ++#define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CLzmaProb)(ttt - (ttt >> kNumMoveBits)); ++#define GET_BIT2(p, i, A0, A1) IF_BIT_0(p) \ ++ { UPDATE_0(p); i = (i + i); A0; } else \ ++ { UPDATE_1(p); i = (i + i) + 1; A1; } ++#define GET_BIT(p, i) GET_BIT2(p, i, ; , ;) ++ ++#define TREE_GET_BIT(probs, i) { GET_BIT((probs + i), i); } ++#define TREE_DECODE(probs, limit, i) \ ++ { i = 1; do { TREE_GET_BIT(probs, i); } while (i < limit); i -= limit; } ++ ++/* #define _LZMA_SIZE_OPT */ ++ ++#ifdef _LZMA_SIZE_OPT ++#define TREE_6_DECODE(probs, i) TREE_DECODE(probs, (1 << 6), i) ++#else ++#define TREE_6_DECODE(probs, i) \ ++ { i = 1; \ ++ TREE_GET_BIT(probs, i); \ ++ TREE_GET_BIT(probs, i); \ ++ TREE_GET_BIT(probs, i); \ ++ TREE_GET_BIT(probs, i); \ ++ TREE_GET_BIT(probs, i); \ ++ TREE_GET_BIT(probs, i); \ ++ i -= 0x40; } ++#endif ++ ++#define NORMALIZE_CHECK if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_ERROR; range <<= 8; code = (code << 8) | (*buf++); } ++ ++#define IF_BIT_0_CHECK(p) ttt = *(p); NORMALIZE_CHECK; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) ++#define UPDATE_0_CHECK range = bound; ++#define UPDATE_1_CHECK range -= bound; code -= bound; ++#define GET_BIT2_CHECK(p, i, A0, A1) IF_BIT_0_CHECK(p) \ ++ { UPDATE_0_CHECK; i = (i + i); A0; } else \ ++ { UPDATE_1_CHECK; i = (i + i) + 1; A1; } ++#define GET_BIT_CHECK(p, i) GET_BIT2_CHECK(p, i, ; , ;) ++#define TREE_DECODE_CHECK(probs, limit, i) \ ++ { i = 1; do { GET_BIT_CHECK(probs + i, i) } while (i < limit); i -= limit; } ++ ++ ++#define kNumPosBitsMax 4 ++#define kNumPosStatesMax (1 << kNumPosBitsMax) ++ ++#define kLenNumLowBits 3 ++#define kLenNumLowSymbols (1 << kLenNumLowBits) ++#define kLenNumMidBits 3 ++#define kLenNumMidSymbols (1 << kLenNumMidBits) ++#define kLenNumHighBits 8 ++#define kLenNumHighSymbols (1 << kLenNumHighBits) ++ ++#define LenChoice 0 ++#define LenChoice2 (LenChoice + 1) ++#define LenLow (LenChoice2 + 1) ++#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits)) ++#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits)) ++#define kNumLenProbs (LenHigh + kLenNumHighSymbols) ++ ++ ++#define kNumStates 12 ++#define kNumLitStates 7 ++ ++#define kStartPosModelIndex 4 ++#define kEndPosModelIndex 14 ++#define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) ++ ++#define kNumPosSlotBits 6 ++#define kNumLenToPosStates 4 ++ ++#define kNumAlignBits 4 ++#define kAlignTableSize (1 << kNumAlignBits) ++ ++#define kMatchMinLen 2 ++#define kMatchSpecLenStart (kMatchMinLen + kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols) ++ ++#define IsMatch 0 ++#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax)) ++#define IsRepG0 (IsRep + kNumStates) ++#define IsRepG1 (IsRepG0 + kNumStates) ++#define IsRepG2 (IsRepG1 + kNumStates) ++#define IsRep0Long (IsRepG2 + kNumStates) ++#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax)) ++#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits)) ++#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex) ++#define LenCoder (Align + kAlignTableSize) ++#define RepLenCoder (LenCoder + kNumLenProbs) ++#define Literal (RepLenCoder + kNumLenProbs) ++ ++#define LZMA_BASE_SIZE 1846 ++#define LZMA_LIT_SIZE 768 ++ ++#define LzmaProps_GetNumProbs(p) ((UInt32)LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((p)->lc + (p)->lp))) ++ ++#if Literal != LZMA_BASE_SIZE ++StopCompilingDueBUG ++#endif ++ ++#define LZMA_DIC_MIN (1 << 12) ++ ++/* First LZMA-symbol is always decoded. ++And it decodes new LZMA-symbols while (buf < bufLimit), but "buf" is without last normalization ++Out: ++ Result: ++ SZ_OK - OK ++ SZ_ERROR_DATA - Error ++ p->remainLen: ++ < kMatchSpecLenStart : normal remain ++ = kMatchSpecLenStart : finished ++ = kMatchSpecLenStart + 1 : Flush marker ++ = kMatchSpecLenStart + 2 : State Init Marker ++*/ ++ ++static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte *bufLimit) ++{ ++ CLzmaProb *probs = p->probs; ++ ++ unsigned state = p->state; ++ UInt32 rep0 = p->reps[0], rep1 = p->reps[1], rep2 = p->reps[2], rep3 = p->reps[3]; ++ unsigned pbMask = ((unsigned)1 << (p->prop.pb)) - 1; ++ unsigned lpMask = ((unsigned)1 << (p->prop.lp)) - 1; ++ unsigned lc = p->prop.lc; ++ ++ Byte *dic = p->dic; ++ SizeT dicBufSize = p->dicBufSize; ++ SizeT dicPos = p->dicPos; ++ ++ UInt32 processedPos = p->processedPos; ++ UInt32 checkDicSize = p->checkDicSize; ++ unsigned len = 0; ++ ++ const Byte *buf = p->buf; ++ UInt32 range = p->range; ++ UInt32 code = p->code; ++ ++ do ++ { ++ CLzmaProb *prob; ++ UInt32 bound; ++ unsigned ttt; ++ unsigned posState = processedPos & pbMask; ++ ++ prob = probs + IsMatch + (state << kNumPosBitsMax) + posState; ++ IF_BIT_0(prob) ++ { ++ unsigned symbol; ++ UPDATE_0(prob); ++ prob = probs + Literal; ++ if (checkDicSize != 0 || processedPos != 0) ++ prob += (LZMA_LIT_SIZE * (((processedPos & lpMask) << lc) + ++ (dic[(dicPos == 0 ? dicBufSize : dicPos) - 1] >> (8 - lc)))); ++ ++ if (state < kNumLitStates) ++ { ++ state -= (state < 4) ? state : 3; ++ symbol = 1; ++ do { GET_BIT(prob + symbol, symbol) } while (symbol < 0x100); ++ } ++ else ++ { ++ unsigned matchByte = p->dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; ++ unsigned offs = 0x100; ++ state -= (state < 10) ? 3 : 6; ++ symbol = 1; ++ do ++ { ++ unsigned bit; ++ CLzmaProb *probLit; ++ matchByte <<= 1; ++ bit = (matchByte & offs); ++ probLit = prob + offs + bit + symbol; ++ GET_BIT2(probLit, symbol, offs &= ~bit, offs &= bit) ++ } ++ while (symbol < 0x100); ++ } ++ dic[dicPos++] = (Byte)symbol; ++ processedPos++; ++ continue; ++ } ++ else ++ { ++ UPDATE_1(prob); ++ prob = probs + IsRep + state; ++ IF_BIT_0(prob) ++ { ++ UPDATE_0(prob); ++ state += kNumStates; ++ prob = probs + LenCoder; ++ } ++ else ++ { ++ UPDATE_1(prob); ++ if (checkDicSize == 0 && processedPos == 0) ++ return SZ_ERROR_DATA; ++ prob = probs + IsRepG0 + state; ++ IF_BIT_0(prob) ++ { ++ UPDATE_0(prob); ++ prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState; ++ IF_BIT_0(prob) ++ { ++ UPDATE_0(prob); ++ dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; ++ dicPos++; ++ processedPos++; ++ state = state < kNumLitStates ? 9 : 11; ++ continue; ++ } ++ UPDATE_1(prob); ++ } ++ else ++ { ++ UInt32 distance; ++ UPDATE_1(prob); ++ prob = probs + IsRepG1 + state; ++ IF_BIT_0(prob) ++ { ++ UPDATE_0(prob); ++ distance = rep1; ++ } ++ else ++ { ++ UPDATE_1(prob); ++ prob = probs + IsRepG2 + state; ++ IF_BIT_0(prob) ++ { ++ UPDATE_0(prob); ++ distance = rep2; ++ } ++ else ++ { ++ UPDATE_1(prob); ++ distance = rep3; ++ rep3 = rep2; ++ } ++ rep2 = rep1; ++ } ++ rep1 = rep0; ++ rep0 = distance; ++ } ++ state = state < kNumLitStates ? 8 : 11; ++ prob = probs + RepLenCoder; ++ } ++ { ++ unsigned limit, offset; ++ CLzmaProb *probLen = prob + LenChoice; ++ IF_BIT_0(probLen) ++ { ++ UPDATE_0(probLen); ++ probLen = prob + LenLow + (posState << kLenNumLowBits); ++ offset = 0; ++ limit = (1 << kLenNumLowBits); ++ } ++ else ++ { ++ UPDATE_1(probLen); ++ probLen = prob + LenChoice2; ++ IF_BIT_0(probLen) ++ { ++ UPDATE_0(probLen); ++ probLen = prob + LenMid + (posState << kLenNumMidBits); ++ offset = kLenNumLowSymbols; ++ limit = (1 << kLenNumMidBits); ++ } ++ else ++ { ++ UPDATE_1(probLen); ++ probLen = prob + LenHigh; ++ offset = kLenNumLowSymbols + kLenNumMidSymbols; ++ limit = (1 << kLenNumHighBits); ++ } ++ } ++ TREE_DECODE(probLen, limit, len); ++ len += offset; ++ } ++ ++ if (state >= kNumStates) ++ { ++ UInt32 distance; ++ prob = probs + PosSlot + ++ ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits); ++ TREE_6_DECODE(prob, distance); ++ if (distance >= kStartPosModelIndex) ++ { ++ unsigned posSlot = (unsigned)distance; ++ int numDirectBits = (int)(((distance >> 1) - 1)); ++ distance = (2 | (distance & 1)); ++ if (posSlot < kEndPosModelIndex) ++ { ++ distance <<= numDirectBits; ++ prob = probs + SpecPos + distance - posSlot - 1; ++ { ++ UInt32 mask = 1; ++ unsigned i = 1; ++ do ++ { ++ GET_BIT2(prob + i, i, ; , distance |= mask); ++ mask <<= 1; ++ } ++ while (--numDirectBits != 0); ++ } ++ } ++ else ++ { ++ numDirectBits -= kNumAlignBits; ++ do ++ { ++ NORMALIZE ++ range >>= 1; ++ ++ { ++ UInt32 t; ++ code -= range; ++ t = (0 - ((UInt32)code >> 31)); /* (UInt32)((Int32)code >> 31) */ ++ distance = (distance << 1) + (t + 1); ++ code += range & t; ++ } ++ /* ++ distance <<= 1; ++ if (code >= range) ++ { ++ code -= range; ++ distance |= 1; ++ } ++ */ ++ } ++ while (--numDirectBits != 0); ++ prob = probs + Align; ++ distance <<= kNumAlignBits; ++ { ++ unsigned i = 1; ++ GET_BIT2(prob + i, i, ; , distance |= 1); ++ GET_BIT2(prob + i, i, ; , distance |= 2); ++ GET_BIT2(prob + i, i, ; , distance |= 4); ++ GET_BIT2(prob + i, i, ; , distance |= 8); ++ } ++ if (distance == (UInt32)0xFFFFFFFF) ++ { ++ len += kMatchSpecLenStart; ++ state -= kNumStates; ++ break; ++ } ++ } ++ } ++ rep3 = rep2; ++ rep2 = rep1; ++ rep1 = rep0; ++ rep0 = distance + 1; ++ if (checkDicSize == 0) ++ { ++ if (distance >= processedPos) ++ return SZ_ERROR_DATA; ++ } ++ else if (distance >= checkDicSize) ++ return SZ_ERROR_DATA; ++ state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3; ++ } ++ ++ len += kMatchMinLen; ++ ++ if (limit == dicPos) ++ return SZ_ERROR_DATA; ++ { ++ SizeT rem = limit - dicPos; ++ unsigned curLen = ((rem < len) ? (unsigned)rem : len); ++ SizeT pos = (dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0); ++ ++ processedPos += curLen; ++ ++ len -= curLen; ++ if (pos + curLen <= dicBufSize) ++ { ++ Byte *dest = dic + dicPos; ++ ptrdiff_t src = (ptrdiff_t)pos - (ptrdiff_t)dicPos; ++ const Byte *lim = dest + curLen; ++ dicPos += curLen; ++ do ++ *(dest) = (Byte)*(dest + src); ++ while (++dest != lim); ++ } ++ else ++ { ++ do ++ { ++ dic[dicPos++] = dic[pos]; ++ if (++pos == dicBufSize) ++ pos = 0; ++ } ++ while (--curLen != 0); ++ } ++ } ++ } ++ } ++ while (dicPos < limit && buf < bufLimit); ++ NORMALIZE; ++ p->buf = buf; ++ p->range = range; ++ p->code = code; ++ p->remainLen = len; ++ p->dicPos = dicPos; ++ p->processedPos = processedPos; ++ p->reps[0] = rep0; ++ p->reps[1] = rep1; ++ p->reps[2] = rep2; ++ p->reps[3] = rep3; ++ p->state = state; ++ ++ return SZ_OK; ++} ++ ++static void MY_FAST_CALL LzmaDec_WriteRem(CLzmaDec *p, SizeT limit) ++{ ++ if (p->remainLen != 0 && p->remainLen < kMatchSpecLenStart) ++ { ++ Byte *dic = p->dic; ++ SizeT dicPos = p->dicPos; ++ SizeT dicBufSize = p->dicBufSize; ++ unsigned len = p->remainLen; ++ UInt32 rep0 = p->reps[0]; ++ if (limit - dicPos < len) ++ len = (unsigned)(limit - dicPos); ++ ++ if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= len) ++ p->checkDicSize = p->prop.dicSize; ++ ++ p->processedPos += len; ++ p->remainLen -= len; ++ while (len-- != 0) ++ { ++ dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; ++ dicPos++; ++ } ++ p->dicPos = dicPos; ++ } ++} ++ ++static int MY_FAST_CALL LzmaDec_DecodeReal2(CLzmaDec *p, SizeT limit, const Byte *bufLimit) ++{ ++ do ++ { ++ SizeT limit2 = limit; ++ if (p->checkDicSize == 0) ++ { ++ UInt32 rem = p->prop.dicSize - p->processedPos; ++ if (limit - p->dicPos > rem) ++ limit2 = p->dicPos + rem; ++ } ++ RINOK(LzmaDec_DecodeReal(p, limit2, bufLimit)); ++ if (p->processedPos >= p->prop.dicSize) ++ p->checkDicSize = p->prop.dicSize; ++ LzmaDec_WriteRem(p, limit); ++ } ++ while (p->dicPos < limit && p->buf < bufLimit && p->remainLen < kMatchSpecLenStart); ++ ++ if (p->remainLen > kMatchSpecLenStart) ++ { ++ p->remainLen = kMatchSpecLenStart; ++ } ++ return 0; ++} ++ ++typedef enum ++{ ++ DUMMY_ERROR, /* unexpected end of input stream */ ++ DUMMY_LIT, ++ DUMMY_MATCH, ++ DUMMY_REP ++} ELzmaDummy; ++ ++static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inSize) ++{ ++ UInt32 range = p->range; ++ UInt32 code = p->code; ++ const Byte *bufLimit = buf + inSize; ++ CLzmaProb *probs = p->probs; ++ unsigned state = p->state; ++ ELzmaDummy res; ++ ++ { ++ CLzmaProb *prob; ++ UInt32 bound; ++ unsigned ttt; ++ unsigned posState = (p->processedPos) & ((1 << p->prop.pb) - 1); ++ ++ prob = probs + IsMatch + (state << kNumPosBitsMax) + posState; ++ IF_BIT_0_CHECK(prob) ++ { ++ UPDATE_0_CHECK ++ ++ /* if (bufLimit - buf >= 7) return DUMMY_LIT; */ ++ ++ prob = probs + Literal; ++ if (p->checkDicSize != 0 || p->processedPos != 0) ++ prob += (LZMA_LIT_SIZE * ++ ((((p->processedPos) & ((1 << (p->prop.lp)) - 1)) << p->prop.lc) + ++ (p->dic[(p->dicPos == 0 ? p->dicBufSize : p->dicPos) - 1] >> (8 - p->prop.lc)))); ++ ++ if (state < kNumLitStates) ++ { ++ unsigned symbol = 1; ++ do { GET_BIT_CHECK(prob + symbol, symbol) } while (symbol < 0x100); ++ } ++ else ++ { ++ unsigned matchByte = p->dic[p->dicPos - p->reps[0] + ++ ((p->dicPos < p->reps[0]) ? p->dicBufSize : 0)]; ++ unsigned offs = 0x100; ++ unsigned symbol = 1; ++ do ++ { ++ unsigned bit; ++ CLzmaProb *probLit; ++ matchByte <<= 1; ++ bit = (matchByte & offs); ++ probLit = prob + offs + bit + symbol; ++ GET_BIT2_CHECK(probLit, symbol, offs &= ~bit, offs &= bit) ++ } ++ while (symbol < 0x100); ++ } ++ res = DUMMY_LIT; ++ } ++ else ++ { ++ unsigned len; ++ UPDATE_1_CHECK; ++ ++ prob = probs + IsRep + state; ++ IF_BIT_0_CHECK(prob) ++ { ++ UPDATE_0_CHECK; ++ state = 0; ++ prob = probs + LenCoder; ++ res = DUMMY_MATCH; ++ } ++ else ++ { ++ UPDATE_1_CHECK; ++ res = DUMMY_REP; ++ prob = probs + IsRepG0 + state; ++ IF_BIT_0_CHECK(prob) ++ { ++ UPDATE_0_CHECK; ++ prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState; ++ IF_BIT_0_CHECK(prob) ++ { ++ UPDATE_0_CHECK; ++ NORMALIZE_CHECK; ++ return DUMMY_REP; ++ } ++ else ++ { ++ UPDATE_1_CHECK; ++ } ++ } ++ else ++ { ++ UPDATE_1_CHECK; ++ prob = probs + IsRepG1 + state; ++ IF_BIT_0_CHECK(prob) ++ { ++ UPDATE_0_CHECK; ++ } ++ else ++ { ++ UPDATE_1_CHECK; ++ prob = probs + IsRepG2 + state; ++ IF_BIT_0_CHECK(prob) ++ { ++ UPDATE_0_CHECK; ++ } ++ else ++ { ++ UPDATE_1_CHECK; ++ } ++ } ++ } ++ state = kNumStates; ++ prob = probs + RepLenCoder; ++ } ++ { ++ unsigned limit, offset; ++ CLzmaProb *probLen = prob + LenChoice; ++ IF_BIT_0_CHECK(probLen) ++ { ++ UPDATE_0_CHECK; ++ probLen = prob + LenLow + (posState << kLenNumLowBits); ++ offset = 0; ++ limit = 1 << kLenNumLowBits; ++ } ++ else ++ { ++ UPDATE_1_CHECK; ++ probLen = prob + LenChoice2; ++ IF_BIT_0_CHECK(probLen) ++ { ++ UPDATE_0_CHECK; ++ probLen = prob + LenMid + (posState << kLenNumMidBits); ++ offset = kLenNumLowSymbols; ++ limit = 1 << kLenNumMidBits; ++ } ++ else ++ { ++ UPDATE_1_CHECK; ++ probLen = prob + LenHigh; ++ offset = kLenNumLowSymbols + kLenNumMidSymbols; ++ limit = 1 << kLenNumHighBits; ++ } ++ } ++ TREE_DECODE_CHECK(probLen, limit, len); ++ len += offset; ++ } ++ ++ if (state < 4) ++ { ++ unsigned posSlot; ++ prob = probs + PosSlot + ++ ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << ++ kNumPosSlotBits); ++ TREE_DECODE_CHECK(prob, 1 << kNumPosSlotBits, posSlot); ++ if (posSlot >= kStartPosModelIndex) ++ { ++ int numDirectBits = ((posSlot >> 1) - 1); ++ ++ /* if (bufLimit - buf >= 8) return DUMMY_MATCH; */ ++ ++ if (posSlot < kEndPosModelIndex) ++ { ++ prob = probs + SpecPos + ((2 | (posSlot & 1)) << numDirectBits) - posSlot - 1; ++ } ++ else ++ { ++ numDirectBits -= kNumAlignBits; ++ do ++ { ++ NORMALIZE_CHECK ++ range >>= 1; ++ code -= range & (((code - range) >> 31) - 1); ++ /* if (code >= range) code -= range; */ ++ } ++ while (--numDirectBits != 0); ++ prob = probs + Align; ++ numDirectBits = kNumAlignBits; ++ } ++ { ++ unsigned i = 1; ++ do ++ { ++ GET_BIT_CHECK(prob + i, i); ++ } ++ while (--numDirectBits != 0); ++ } ++ } ++ } ++ } ++ } ++ NORMALIZE_CHECK; ++ return res; ++} ++ ++ ++static void LzmaDec_InitRc(CLzmaDec *p, const Byte *data) ++{ ++ p->code = ((UInt32)data[1] << 24) | ((UInt32)data[2] << 16) | ((UInt32)data[3] << 8) | ((UInt32)data[4]); ++ p->range = 0xFFFFFFFF; ++ p->needFlush = 0; ++} ++ ++void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState) ++{ ++ p->needFlush = 1; ++ p->remainLen = 0; ++ p->tempBufSize = 0; ++ ++ if (initDic) ++ { ++ p->processedPos = 0; ++ p->checkDicSize = 0; ++ p->needInitState = 1; ++ } ++ if (initState) ++ p->needInitState = 1; ++} ++ ++void LzmaDec_Init(CLzmaDec *p) ++{ ++ p->dicPos = 0; ++ LzmaDec_InitDicAndState(p, True, True); ++} ++ ++static void LzmaDec_InitStateReal(CLzmaDec *p) ++{ ++ UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (p->prop.lc + p->prop.lp)); ++ UInt32 i; ++ CLzmaProb *probs = p->probs; ++ for (i = 0; i < numProbs; i++) ++ probs[i] = kBitModelTotal >> 1; ++ p->reps[0] = p->reps[1] = p->reps[2] = p->reps[3] = 1; ++ p->state = 0; ++ p->needInitState = 0; ++} ++ ++SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen, ++ ELzmaFinishMode finishMode, ELzmaStatus *status) ++{ ++ SizeT inSize = *srcLen; ++ (*srcLen) = 0; ++ LzmaDec_WriteRem(p, dicLimit); ++ ++ *status = LZMA_STATUS_NOT_SPECIFIED; ++ ++ while (p->remainLen != kMatchSpecLenStart) ++ { ++ int checkEndMarkNow; ++ ++ if (p->needFlush != 0) ++ { ++ for (; inSize > 0 && p->tempBufSize < RC_INIT_SIZE; (*srcLen)++, inSize--) ++ p->tempBuf[p->tempBufSize++] = *src++; ++ if (p->tempBufSize < RC_INIT_SIZE) ++ { ++ *status = LZMA_STATUS_NEEDS_MORE_INPUT; ++ return SZ_OK; ++ } ++ if (p->tempBuf[0] != 0) ++ return SZ_ERROR_DATA; ++ ++ LzmaDec_InitRc(p, p->tempBuf); ++ p->tempBufSize = 0; ++ } ++ ++ checkEndMarkNow = 0; ++ if (p->dicPos >= dicLimit) ++ { ++ if (p->remainLen == 0 && p->code == 0) ++ { ++ *status = LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK; ++ return SZ_OK; ++ } ++ if (finishMode == LZMA_FINISH_ANY) ++ { ++ *status = LZMA_STATUS_NOT_FINISHED; ++ return SZ_OK; ++ } ++ if (p->remainLen != 0) ++ { ++ *status = LZMA_STATUS_NOT_FINISHED; ++ return SZ_ERROR_DATA; ++ } ++ checkEndMarkNow = 1; ++ } ++ ++ if (p->needInitState) ++ LzmaDec_InitStateReal(p); ++ ++ if (p->tempBufSize == 0) ++ { ++ SizeT processed; ++ const Byte *bufLimit; ++ if (inSize < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) ++ { ++ int dummyRes = LzmaDec_TryDummy(p, src, inSize); ++ if (dummyRes == DUMMY_ERROR) ++ { ++ memcpy(p->tempBuf, src, inSize); ++ p->tempBufSize = (unsigned)inSize; ++ (*srcLen) += inSize; ++ *status = LZMA_STATUS_NEEDS_MORE_INPUT; ++ return SZ_OK; ++ } ++ if (checkEndMarkNow && dummyRes != DUMMY_MATCH) ++ { ++ *status = LZMA_STATUS_NOT_FINISHED; ++ return SZ_ERROR_DATA; ++ } ++ bufLimit = src; ++ } ++ else ++ bufLimit = src + inSize - LZMA_REQUIRED_INPUT_MAX; ++ p->buf = src; ++ if (LzmaDec_DecodeReal2(p, dicLimit, bufLimit) != 0) ++ return SZ_ERROR_DATA; ++ processed = (SizeT)(p->buf - src); ++ (*srcLen) += processed; ++ src += processed; ++ inSize -= processed; ++ } ++ else ++ { ++ unsigned rem = p->tempBufSize, lookAhead = 0; ++ while (rem < LZMA_REQUIRED_INPUT_MAX && lookAhead < inSize) ++ p->tempBuf[rem++] = src[lookAhead++]; ++ p->tempBufSize = rem; ++ if (rem < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) ++ { ++ int dummyRes = LzmaDec_TryDummy(p, p->tempBuf, rem); ++ if (dummyRes == DUMMY_ERROR) ++ { ++ (*srcLen) += lookAhead; ++ *status = LZMA_STATUS_NEEDS_MORE_INPUT; ++ return SZ_OK; ++ } ++ if (checkEndMarkNow && dummyRes != DUMMY_MATCH) ++ { ++ *status = LZMA_STATUS_NOT_FINISHED; ++ return SZ_ERROR_DATA; ++ } ++ } ++ p->buf = p->tempBuf; ++ if (LzmaDec_DecodeReal2(p, dicLimit, p->buf) != 0) ++ return SZ_ERROR_DATA; ++ lookAhead -= (rem - (unsigned)(p->buf - p->tempBuf)); ++ (*srcLen) += lookAhead; ++ src += lookAhead; ++ inSize -= lookAhead; ++ p->tempBufSize = 0; ++ } ++ } ++ if (p->code == 0) ++ *status = LZMA_STATUS_FINISHED_WITH_MARK; ++ return (p->code == 0) ? SZ_OK : SZ_ERROR_DATA; ++} ++ ++SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) ++{ ++ SizeT outSize = *destLen; ++ SizeT inSize = *srcLen; ++ *srcLen = *destLen = 0; ++ for (;;) ++ { ++ SizeT inSizeCur = inSize, outSizeCur, dicPos; ++ ELzmaFinishMode curFinishMode; ++ SRes res; ++ if (p->dicPos == p->dicBufSize) ++ p->dicPos = 0; ++ dicPos = p->dicPos; ++ if (outSize > p->dicBufSize - dicPos) ++ { ++ outSizeCur = p->dicBufSize; ++ curFinishMode = LZMA_FINISH_ANY; ++ } ++ else ++ { ++ outSizeCur = dicPos + outSize; ++ curFinishMode = finishMode; ++ } ++ ++ res = LzmaDec_DecodeToDic(p, outSizeCur, src, &inSizeCur, curFinishMode, status); ++ src += inSizeCur; ++ inSize -= inSizeCur; ++ *srcLen += inSizeCur; ++ outSizeCur = p->dicPos - dicPos; ++ memcpy(dest, p->dic + dicPos, outSizeCur); ++ dest += outSizeCur; ++ outSize -= outSizeCur; ++ *destLen += outSizeCur; ++ if (res != 0) ++ return res; ++ if (outSizeCur == 0 || outSize == 0) ++ return SZ_OK; ++ } ++} ++ ++void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc) ++{ ++ alloc->Free(alloc, p->probs); ++ p->probs = 0; ++} ++ ++static void LzmaDec_FreeDict(CLzmaDec *p, ISzAlloc *alloc) ++{ ++ alloc->Free(alloc, p->dic); ++ p->dic = 0; ++} ++ ++void LzmaDec_Free(CLzmaDec *p, ISzAlloc *alloc) ++{ ++ LzmaDec_FreeProbs(p, alloc); ++ LzmaDec_FreeDict(p, alloc); ++} ++ ++SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size) ++{ ++ UInt32 dicSize; ++ Byte d; ++ ++ if (size < LZMA_PROPS_SIZE) ++ return SZ_ERROR_UNSUPPORTED; ++ else ++ dicSize = data[1] | ((UInt32)data[2] << 8) | ((UInt32)data[3] << 16) | ((UInt32)data[4] << 24); ++ ++ if (dicSize < LZMA_DIC_MIN) ++ dicSize = LZMA_DIC_MIN; ++ p->dicSize = dicSize; ++ ++ d = data[0]; ++ if (d >= (9 * 5 * 5)) ++ return SZ_ERROR_UNSUPPORTED; ++ ++ p->lc = d % 9; ++ d /= 9; ++ p->pb = d / 5; ++ p->lp = d % 5; ++ ++ return SZ_OK; ++} ++ ++static SRes LzmaDec_AllocateProbs2(CLzmaDec *p, const CLzmaProps *propNew, ISzAlloc *alloc) ++{ ++ UInt32 numProbs = LzmaProps_GetNumProbs(propNew); ++ if (p->probs == 0 || numProbs != p->numProbs) ++ { ++ LzmaDec_FreeProbs(p, alloc); ++ p->probs = (CLzmaProb *)alloc->Alloc(alloc, numProbs * sizeof(CLzmaProb)); ++ p->numProbs = numProbs; ++ if (p->probs == 0) ++ return SZ_ERROR_MEM; ++ } ++ return SZ_OK; ++} ++ ++SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) ++{ ++ CLzmaProps propNew; ++ RINOK(LzmaProps_Decode(&propNew, props, propsSize)); ++ RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); ++ p->prop = propNew; ++ return SZ_OK; ++} ++ ++SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) ++{ ++ CLzmaProps propNew; ++ SizeT dicBufSize; ++ RINOK(LzmaProps_Decode(&propNew, props, propsSize)); ++ RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); ++ dicBufSize = propNew.dicSize; ++ if (p->dic == 0 || dicBufSize != p->dicBufSize) ++ { ++ LzmaDec_FreeDict(p, alloc); ++ p->dic = (Byte *)alloc->Alloc(alloc, dicBufSize); ++ if (p->dic == 0) ++ { ++ LzmaDec_FreeProbs(p, alloc); ++ return SZ_ERROR_MEM; ++ } ++ } ++ p->dicBufSize = dicBufSize; ++ p->prop = propNew; ++ return SZ_OK; ++} ++ ++SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ++ const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, ++ ELzmaStatus *status, ISzAlloc *alloc) ++{ ++ CLzmaDec p; ++ SRes res; ++ SizeT inSize = *srcLen; ++ SizeT outSize = *destLen; ++ *srcLen = *destLen = 0; ++ if (inSize < RC_INIT_SIZE) ++ return SZ_ERROR_INPUT_EOF; ++ ++ LzmaDec_Construct(&p); ++ res = LzmaDec_AllocateProbs(&p, propData, propSize, alloc); ++ if (res != 0) ++ return res; ++ p.dic = dest; ++ p.dicBufSize = outSize; ++ ++ LzmaDec_Init(&p); ++ ++ *srcLen = inSize; ++ res = LzmaDec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status); ++ ++ if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT) ++ res = SZ_ERROR_INPUT_EOF; ++ ++ (*destLen) = p.dicPos; ++ LzmaDec_FreeProbs(&p, alloc); ++ return res; ++} +--- /dev/null ++++ b/lib/lzma/LzmaEnc.c +@@ -0,0 +1,2271 @@ ++/* LzmaEnc.c -- LZMA Encoder ++2009-11-24 : Igor Pavlov : Public domain */ ++ ++#include ++ ++/* #define SHOW_STAT */ ++/* #define SHOW_STAT2 */ ++ ++#if defined(SHOW_STAT) || defined(SHOW_STAT2) ++#include ++#endif ++ ++#include "LzmaEnc.h" ++ ++/* disable MT */ ++#define _7ZIP_ST ++ ++#include "LzFind.h" ++#ifndef _7ZIP_ST ++#include "LzFindMt.h" ++#endif ++ ++#ifdef SHOW_STAT ++static int ttt = 0; ++#endif ++ ++#define kBlockSizeMax ((1 << LZMA_NUM_BLOCK_SIZE_BITS) - 1) ++ ++#define kBlockSize (9 << 10) ++#define kUnpackBlockSize (1 << 18) ++#define kMatchArraySize (1 << 21) ++#define kMatchRecordMaxSize ((LZMA_MATCH_LEN_MAX * 2 + 3) * LZMA_MATCH_LEN_MAX) ++ ++#define kNumMaxDirectBits (31) ++ ++#define kNumTopBits 24 ++#define kTopValue ((UInt32)1 << kNumTopBits) ++ ++#define kNumBitModelTotalBits 11 ++#define kBitModelTotal (1 << kNumBitModelTotalBits) ++#define kNumMoveBits 5 ++#define kProbInitValue (kBitModelTotal >> 1) ++ ++#define kNumMoveReducingBits 4 ++#define kNumBitPriceShiftBits 4 ++#define kBitPrice (1 << kNumBitPriceShiftBits) ++ ++void LzmaEncProps_Init(CLzmaEncProps *p) ++{ ++ p->level = 5; ++ p->dictSize = p->mc = 0; ++ p->lc = p->lp = p->pb = p->algo = p->fb = p->btMode = p->numHashBytes = p->numThreads = -1; ++ p->writeEndMark = 0; ++} ++ ++void LzmaEncProps_Normalize(CLzmaEncProps *p) ++{ ++ int level = p->level; ++ if (level < 0) level = 5; ++ p->level = level; ++ if (p->dictSize == 0) p->dictSize = (level <= 5 ? (1 << (level * 2 + 14)) : (level == 6 ? (1 << 25) : (1 << 26))); ++ if (p->lc < 0) p->lc = 3; ++ if (p->lp < 0) p->lp = 0; ++ if (p->pb < 0) p->pb = 2; ++ if (p->algo < 0) p->algo = (level < 5 ? 0 : 1); ++ if (p->fb < 0) p->fb = (level < 7 ? 32 : 64); ++ if (p->btMode < 0) p->btMode = (p->algo == 0 ? 0 : 1); ++ if (p->numHashBytes < 0) p->numHashBytes = 4; ++ if (p->mc == 0) p->mc = (16 + (p->fb >> 1)) >> (p->btMode ? 0 : 1); ++ if (p->numThreads < 0) ++ p->numThreads = ++ #ifndef _7ZIP_ST ++ ((p->btMode && p->algo) ? 2 : 1); ++ #else ++ 1; ++ #endif ++} ++ ++UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2) ++{ ++ CLzmaEncProps props = *props2; ++ LzmaEncProps_Normalize(&props); ++ return props.dictSize; ++} ++ ++/* #define LZMA_LOG_BSR */ ++/* Define it for Intel's CPU */ ++ ++ ++#ifdef LZMA_LOG_BSR ++ ++#define kDicLogSizeMaxCompress 30 ++ ++#define BSR2_RET(pos, res) { unsigned long i; _BitScanReverse(&i, (pos)); res = (i + i) + ((pos >> (i - 1)) & 1); } ++ ++UInt32 GetPosSlot1(UInt32 pos) ++{ ++ UInt32 res; ++ BSR2_RET(pos, res); ++ return res; ++} ++#define GetPosSlot2(pos, res) { BSR2_RET(pos, res); } ++#define GetPosSlot(pos, res) { if (pos < 2) res = pos; else BSR2_RET(pos, res); } ++ ++#else ++ ++#define kNumLogBits (9 + (int)sizeof(size_t) / 2) ++#define kDicLogSizeMaxCompress ((kNumLogBits - 1) * 2 + 7) ++ ++void LzmaEnc_FastPosInit(Byte *g_FastPos) ++{ ++ int c = 2, slotFast; ++ g_FastPos[0] = 0; ++ g_FastPos[1] = 1; ++ ++ for (slotFast = 2; slotFast < kNumLogBits * 2; slotFast++) ++ { ++ UInt32 k = (1 << ((slotFast >> 1) - 1)); ++ UInt32 j; ++ for (j = 0; j < k; j++, c++) ++ g_FastPos[c] = (Byte)slotFast; ++ } ++} ++ ++#define BSR2_RET(pos, res) { UInt32 i = 6 + ((kNumLogBits - 1) & \ ++ (0 - (((((UInt32)1 << (kNumLogBits + 6)) - 1) - pos) >> 31))); \ ++ res = p->g_FastPos[pos >> i] + (i * 2); } ++/* ++#define BSR2_RET(pos, res) { res = (pos < (1 << (kNumLogBits + 6))) ? \ ++ p->g_FastPos[pos >> 6] + 12 : \ ++ p->g_FastPos[pos >> (6 + kNumLogBits - 1)] + (6 + (kNumLogBits - 1)) * 2; } ++*/ ++ ++#define GetPosSlot1(pos) p->g_FastPos[pos] ++#define GetPosSlot2(pos, res) { BSR2_RET(pos, res); } ++#define GetPosSlot(pos, res) { if (pos < kNumFullDistances) res = p->g_FastPos[pos]; else BSR2_RET(pos, res); } ++ ++#endif ++ ++ ++#define LZMA_NUM_REPS 4 ++ ++typedef unsigned CState; ++ ++typedef struct ++{ ++ UInt32 price; ++ ++ CState state; ++ int prev1IsChar; ++ int prev2; ++ ++ UInt32 posPrev2; ++ UInt32 backPrev2; ++ ++ UInt32 posPrev; ++ UInt32 backPrev; ++ UInt32 backs[LZMA_NUM_REPS]; ++} COptimal; ++ ++#define kNumOpts (1 << 12) ++ ++#define kNumLenToPosStates 4 ++#define kNumPosSlotBits 6 ++#define kDicLogSizeMin 0 ++#define kDicLogSizeMax 32 ++#define kDistTableSizeMax (kDicLogSizeMax * 2) ++ ++ ++#define kNumAlignBits 4 ++#define kAlignTableSize (1 << kNumAlignBits) ++#define kAlignMask (kAlignTableSize - 1) ++ ++#define kStartPosModelIndex 4 ++#define kEndPosModelIndex 14 ++#define kNumPosModels (kEndPosModelIndex - kStartPosModelIndex) ++ ++#define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) ++ ++#ifdef _LZMA_PROB32 ++#define CLzmaProb UInt32 ++#else ++#define CLzmaProb UInt16 ++#endif ++ ++#define LZMA_PB_MAX 4 ++#define LZMA_LC_MAX 8 ++#define LZMA_LP_MAX 4 ++ ++#define LZMA_NUM_PB_STATES_MAX (1 << LZMA_PB_MAX) ++ ++ ++#define kLenNumLowBits 3 ++#define kLenNumLowSymbols (1 << kLenNumLowBits) ++#define kLenNumMidBits 3 ++#define kLenNumMidSymbols (1 << kLenNumMidBits) ++#define kLenNumHighBits 8 ++#define kLenNumHighSymbols (1 << kLenNumHighBits) ++ ++#define kLenNumSymbolsTotal (kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols) ++ ++#define LZMA_MATCH_LEN_MIN 2 ++#define LZMA_MATCH_LEN_MAX (LZMA_MATCH_LEN_MIN + kLenNumSymbolsTotal - 1) ++ ++#define kNumStates 12 ++ ++typedef struct ++{ ++ CLzmaProb choice; ++ CLzmaProb choice2; ++ CLzmaProb low[LZMA_NUM_PB_STATES_MAX << kLenNumLowBits]; ++ CLzmaProb mid[LZMA_NUM_PB_STATES_MAX << kLenNumMidBits]; ++ CLzmaProb high[kLenNumHighSymbols]; ++} CLenEnc; ++ ++typedef struct ++{ ++ CLenEnc p; ++ UInt32 prices[LZMA_NUM_PB_STATES_MAX][kLenNumSymbolsTotal]; ++ UInt32 tableSize; ++ UInt32 counters[LZMA_NUM_PB_STATES_MAX]; ++} CLenPriceEnc; ++ ++typedef struct ++{ ++ UInt32 range; ++ Byte cache; ++ UInt64 low; ++ UInt64 cacheSize; ++ Byte *buf; ++ Byte *bufLim; ++ Byte *bufBase; ++ ISeqOutStream *outStream; ++ UInt64 processed; ++ SRes res; ++} CRangeEnc; ++ ++typedef struct ++{ ++ CLzmaProb *litProbs; ++ ++ CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX]; ++ CLzmaProb isRep[kNumStates]; ++ CLzmaProb isRepG0[kNumStates]; ++ CLzmaProb isRepG1[kNumStates]; ++ CLzmaProb isRepG2[kNumStates]; ++ CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX]; ++ ++ CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits]; ++ CLzmaProb posEncoders[kNumFullDistances - kEndPosModelIndex]; ++ CLzmaProb posAlignEncoder[1 << kNumAlignBits]; ++ ++ CLenPriceEnc lenEnc; ++ CLenPriceEnc repLenEnc; ++ ++ UInt32 reps[LZMA_NUM_REPS]; ++ UInt32 state; ++} CSaveState; ++ ++typedef struct ++{ ++ IMatchFinder matchFinder; ++ void *matchFinderObj; ++ ++ #ifndef _7ZIP_ST ++ Bool mtMode; ++ CMatchFinderMt matchFinderMt; ++ #endif ++ ++ CMatchFinder matchFinderBase; ++ ++ #ifndef _7ZIP_ST ++ Byte pad[128]; ++ #endif ++ ++ UInt32 optimumEndIndex; ++ UInt32 optimumCurrentIndex; ++ ++ UInt32 longestMatchLength; ++ UInt32 numPairs; ++ UInt32 numAvail; ++ COptimal opt[kNumOpts]; ++ ++ #ifndef LZMA_LOG_BSR ++ Byte g_FastPos[1 << kNumLogBits]; ++ #endif ++ ++ UInt32 ProbPrices[kBitModelTotal >> kNumMoveReducingBits]; ++ UInt32 matches[LZMA_MATCH_LEN_MAX * 2 + 2 + 1]; ++ UInt32 numFastBytes; ++ UInt32 additionalOffset; ++ UInt32 reps[LZMA_NUM_REPS]; ++ UInt32 state; ++ ++ UInt32 posSlotPrices[kNumLenToPosStates][kDistTableSizeMax]; ++ UInt32 distancesPrices[kNumLenToPosStates][kNumFullDistances]; ++ UInt32 alignPrices[kAlignTableSize]; ++ UInt32 alignPriceCount; ++ ++ UInt32 distTableSize; ++ ++ unsigned lc, lp, pb; ++ unsigned lpMask, pbMask; ++ ++ CLzmaProb *litProbs; ++ ++ CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX]; ++ CLzmaProb isRep[kNumStates]; ++ CLzmaProb isRepG0[kNumStates]; ++ CLzmaProb isRepG1[kNumStates]; ++ CLzmaProb isRepG2[kNumStates]; ++ CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX]; ++ ++ CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits]; ++ CLzmaProb posEncoders[kNumFullDistances - kEndPosModelIndex]; ++ CLzmaProb posAlignEncoder[1 << kNumAlignBits]; ++ ++ CLenPriceEnc lenEnc; ++ CLenPriceEnc repLenEnc; ++ ++ unsigned lclp; ++ ++ Bool fastMode; ++ ++ CRangeEnc rc; ++ ++ Bool writeEndMark; ++ UInt64 nowPos64; ++ UInt32 matchPriceCount; ++ Bool finished; ++ Bool multiThread; ++ ++ SRes result; ++ UInt32 dictSize; ++ UInt32 matchFinderCycles; ++ ++ int needInit; ++ ++ CSaveState saveState; ++} CLzmaEnc; ++ ++void LzmaEnc_SaveState(CLzmaEncHandle pp) ++{ ++ CLzmaEnc *p = (CLzmaEnc *)pp; ++ CSaveState *dest = &p->saveState; ++ int i; ++ dest->lenEnc = p->lenEnc; ++ dest->repLenEnc = p->repLenEnc; ++ dest->state = p->state; ++ ++ for (i = 0; i < kNumStates; i++) ++ { ++ memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i])); ++ memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i])); ++ } ++ for (i = 0; i < kNumLenToPosStates; i++) ++ memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i])); ++ memcpy(dest->isRep, p->isRep, sizeof(p->isRep)); ++ memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0)); ++ memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1)); ++ memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2)); ++ memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders)); ++ memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder)); ++ memcpy(dest->reps, p->reps, sizeof(p->reps)); ++ memcpy(dest->litProbs, p->litProbs, (0x300 << p->lclp) * sizeof(CLzmaProb)); ++} ++ ++void LzmaEnc_RestoreState(CLzmaEncHandle pp) ++{ ++ CLzmaEnc *dest = (CLzmaEnc *)pp; ++ const CSaveState *p = &dest->saveState; ++ int i; ++ dest->lenEnc = p->lenEnc; ++ dest->repLenEnc = p->repLenEnc; ++ dest->state = p->state; ++ ++ for (i = 0; i < kNumStates; i++) ++ { ++ memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i])); ++ memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i])); ++ } ++ for (i = 0; i < kNumLenToPosStates; i++) ++ memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i])); ++ memcpy(dest->isRep, p->isRep, sizeof(p->isRep)); ++ memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0)); ++ memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1)); ++ memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2)); ++ memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders)); ++ memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder)); ++ memcpy(dest->reps, p->reps, sizeof(p->reps)); ++ memcpy(dest->litProbs, p->litProbs, (0x300 << dest->lclp) * sizeof(CLzmaProb)); ++} ++ ++SRes LzmaEnc_SetProps(CLzmaEncHandle pp, const CLzmaEncProps *props2) ++{ ++ CLzmaEnc *p = (CLzmaEnc *)pp; ++ CLzmaEncProps props = *props2; ++ LzmaEncProps_Normalize(&props); ++ ++ if (props.lc > LZMA_LC_MAX || props.lp > LZMA_LP_MAX || props.pb > LZMA_PB_MAX || ++ props.dictSize > (1 << kDicLogSizeMaxCompress) || props.dictSize > (1 << 30)) ++ return SZ_ERROR_PARAM; ++ p->dictSize = props.dictSize; ++ p->matchFinderCycles = props.mc; ++ { ++ unsigned fb = props.fb; ++ if (fb < 5) ++ fb = 5; ++ if (fb > LZMA_MATCH_LEN_MAX) ++ fb = LZMA_MATCH_LEN_MAX; ++ p->numFastBytes = fb; ++ } ++ p->lc = props.lc; ++ p->lp = props.lp; ++ p->pb = props.pb; ++ p->fastMode = (props.algo == 0); ++ p->matchFinderBase.btMode = props.btMode; ++ { ++ UInt32 numHashBytes = 4; ++ if (props.btMode) ++ { ++ if (props.numHashBytes < 2) ++ numHashBytes = 2; ++ else if (props.numHashBytes < 4) ++ numHashBytes = props.numHashBytes; ++ } ++ p->matchFinderBase.numHashBytes = numHashBytes; ++ } ++ ++ p->matchFinderBase.cutValue = props.mc; ++ ++ p->writeEndMark = props.writeEndMark; ++ ++ #ifndef _7ZIP_ST ++ /* ++ if (newMultiThread != _multiThread) ++ { ++ ReleaseMatchFinder(); ++ _multiThread = newMultiThread; ++ } ++ */ ++ p->multiThread = (props.numThreads > 1); ++ #endif ++ ++ return SZ_OK; ++} ++ ++static const int kLiteralNextStates[kNumStates] = {0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5}; ++static const int kMatchNextStates[kNumStates] = {7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10}; ++static const int kRepNextStates[kNumStates] = {8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11}; ++static const int kShortRepNextStates[kNumStates]= {9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11}; ++ ++#define IsCharState(s) ((s) < 7) ++ ++#define GetLenToPosState(len) (((len) < kNumLenToPosStates + 1) ? (len) - 2 : kNumLenToPosStates - 1) ++ ++#define kInfinityPrice (1 << 30) ++ ++static void RangeEnc_Construct(CRangeEnc *p) ++{ ++ p->outStream = 0; ++ p->bufBase = 0; ++} ++ ++#define RangeEnc_GetProcessed(p) ((p)->processed + ((p)->buf - (p)->bufBase) + (p)->cacheSize) ++ ++#define RC_BUF_SIZE (1 << 16) ++static int RangeEnc_Alloc(CRangeEnc *p, ISzAlloc *alloc) ++{ ++ if (p->bufBase == 0) ++ { ++ p->bufBase = (Byte *)alloc->Alloc(alloc, RC_BUF_SIZE); ++ if (p->bufBase == 0) ++ return 0; ++ p->bufLim = p->bufBase + RC_BUF_SIZE; ++ } ++ return 1; ++} ++ ++static void RangeEnc_Free(CRangeEnc *p, ISzAlloc *alloc) ++{ ++ alloc->Free(alloc, p->bufBase); ++ p->bufBase = 0; ++} ++ ++static void RangeEnc_Init(CRangeEnc *p) ++{ ++ /* Stream.Init(); */ ++ p->low = 0; ++ p->range = 0xFFFFFFFF; ++ p->cacheSize = 1; ++ p->cache = 0; ++ ++ p->buf = p->bufBase; ++ ++ p->processed = 0; ++ p->res = SZ_OK; ++} ++ ++static void RangeEnc_FlushStream(CRangeEnc *p) ++{ ++ size_t num; ++ if (p->res != SZ_OK) ++ return; ++ num = p->buf - p->bufBase; ++ if (num != p->outStream->Write(p->outStream, p->bufBase, num)) ++ p->res = SZ_ERROR_WRITE; ++ p->processed += num; ++ p->buf = p->bufBase; ++} ++ ++static void MY_FAST_CALL RangeEnc_ShiftLow(CRangeEnc *p) ++{ ++ if ((UInt32)p->low < (UInt32)0xFF000000 || (int)(p->low >> 32) != 0) ++ { ++ Byte temp = p->cache; ++ do ++ { ++ Byte *buf = p->buf; ++ *buf++ = (Byte)(temp + (Byte)(p->low >> 32)); ++ p->buf = buf; ++ if (buf == p->bufLim) ++ RangeEnc_FlushStream(p); ++ temp = 0xFF; ++ } ++ while (--p->cacheSize != 0); ++ p->cache = (Byte)((UInt32)p->low >> 24); ++ } ++ p->cacheSize++; ++ p->low = (UInt32)p->low << 8; ++} ++ ++static void RangeEnc_FlushData(CRangeEnc *p) ++{ ++ int i; ++ for (i = 0; i < 5; i++) ++ RangeEnc_ShiftLow(p); ++} ++ ++static void RangeEnc_EncodeDirectBits(CRangeEnc *p, UInt32 value, int numBits) ++{ ++ do ++ { ++ p->range >>= 1; ++ p->low += p->range & (0 - ((value >> --numBits) & 1)); ++ if (p->range < kTopValue) ++ { ++ p->range <<= 8; ++ RangeEnc_ShiftLow(p); ++ } ++ } ++ while (numBits != 0); ++} ++ ++static void RangeEnc_EncodeBit(CRangeEnc *p, CLzmaProb *prob, UInt32 symbol) ++{ ++ UInt32 ttt = *prob; ++ UInt32 newBound = (p->range >> kNumBitModelTotalBits) * ttt; ++ if (symbol == 0) ++ { ++ p->range = newBound; ++ ttt += (kBitModelTotal - ttt) >> kNumMoveBits; ++ } ++ else ++ { ++ p->low += newBound; ++ p->range -= newBound; ++ ttt -= ttt >> kNumMoveBits; ++ } ++ *prob = (CLzmaProb)ttt; ++ if (p->range < kTopValue) ++ { ++ p->range <<= 8; ++ RangeEnc_ShiftLow(p); ++ } ++} ++ ++static void LitEnc_Encode(CRangeEnc *p, CLzmaProb *probs, UInt32 symbol) ++{ ++ symbol |= 0x100; ++ do ++ { ++ RangeEnc_EncodeBit(p, probs + (symbol >> 8), (symbol >> 7) & 1); ++ symbol <<= 1; ++ } ++ while (symbol < 0x10000); ++} ++ ++static void LitEnc_EncodeMatched(CRangeEnc *p, CLzmaProb *probs, UInt32 symbol, UInt32 matchByte) ++{ ++ UInt32 offs = 0x100; ++ symbol |= 0x100; ++ do ++ { ++ matchByte <<= 1; ++ RangeEnc_EncodeBit(p, probs + (offs + (matchByte & offs) + (symbol >> 8)), (symbol >> 7) & 1); ++ symbol <<= 1; ++ offs &= ~(matchByte ^ symbol); ++ } ++ while (symbol < 0x10000); ++} ++ ++void LzmaEnc_InitPriceTables(UInt32 *ProbPrices) ++{ ++ UInt32 i; ++ for (i = (1 << kNumMoveReducingBits) / 2; i < kBitModelTotal; i += (1 << kNumMoveReducingBits)) ++ { ++ const int kCyclesBits = kNumBitPriceShiftBits; ++ UInt32 w = i; ++ UInt32 bitCount = 0; ++ int j; ++ for (j = 0; j < kCyclesBits; j++) ++ { ++ w = w * w; ++ bitCount <<= 1; ++ while (w >= ((UInt32)1 << 16)) ++ { ++ w >>= 1; ++ bitCount++; ++ } ++ } ++ ProbPrices[i >> kNumMoveReducingBits] = ((kNumBitModelTotalBits << kCyclesBits) - 15 - bitCount); ++ } ++} ++ ++ ++#define GET_PRICE(prob, symbol) \ ++ p->ProbPrices[((prob) ^ (((-(int)(symbol))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits]; ++ ++#define GET_PRICEa(prob, symbol) \ ++ ProbPrices[((prob) ^ ((-((int)(symbol))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits]; ++ ++#define GET_PRICE_0(prob) p->ProbPrices[(prob) >> kNumMoveReducingBits] ++#define GET_PRICE_1(prob) p->ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits] ++ ++#define GET_PRICE_0a(prob) ProbPrices[(prob) >> kNumMoveReducingBits] ++#define GET_PRICE_1a(prob) ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits] ++ ++static UInt32 LitEnc_GetPrice(const CLzmaProb *probs, UInt32 symbol, UInt32 *ProbPrices) ++{ ++ UInt32 price = 0; ++ symbol |= 0x100; ++ do ++ { ++ price += GET_PRICEa(probs[symbol >> 8], (symbol >> 7) & 1); ++ symbol <<= 1; ++ } ++ while (symbol < 0x10000); ++ return price; ++} ++ ++static UInt32 LitEnc_GetPriceMatched(const CLzmaProb *probs, UInt32 symbol, UInt32 matchByte, UInt32 *ProbPrices) ++{ ++ UInt32 price = 0; ++ UInt32 offs = 0x100; ++ symbol |= 0x100; ++ do ++ { ++ matchByte <<= 1; ++ price += GET_PRICEa(probs[offs + (matchByte & offs) + (symbol >> 8)], (symbol >> 7) & 1); ++ symbol <<= 1; ++ offs &= ~(matchByte ^ symbol); ++ } ++ while (symbol < 0x10000); ++ return price; ++} ++ ++ ++static void RcTree_Encode(CRangeEnc *rc, CLzmaProb *probs, int numBitLevels, UInt32 symbol) ++{ ++ UInt32 m = 1; ++ int i; ++ for (i = numBitLevels; i != 0;) ++ { ++ UInt32 bit; ++ i--; ++ bit = (symbol >> i) & 1; ++ RangeEnc_EncodeBit(rc, probs + m, bit); ++ m = (m << 1) | bit; ++ } ++} ++ ++static void RcTree_ReverseEncode(CRangeEnc *rc, CLzmaProb *probs, int numBitLevels, UInt32 symbol) ++{ ++ UInt32 m = 1; ++ int i; ++ for (i = 0; i < numBitLevels; i++) ++ { ++ UInt32 bit = symbol & 1; ++ RangeEnc_EncodeBit(rc, probs + m, bit); ++ m = (m << 1) | bit; ++ symbol >>= 1; ++ } ++} ++ ++static UInt32 RcTree_GetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, UInt32 *ProbPrices) ++{ ++ UInt32 price = 0; ++ symbol |= (1 << numBitLevels); ++ while (symbol != 1) ++ { ++ price += GET_PRICEa(probs[symbol >> 1], symbol & 1); ++ symbol >>= 1; ++ } ++ return price; ++} ++ ++static UInt32 RcTree_ReverseGetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, UInt32 *ProbPrices) ++{ ++ UInt32 price = 0; ++ UInt32 m = 1; ++ int i; ++ for (i = numBitLevels; i != 0; i--) ++ { ++ UInt32 bit = symbol & 1; ++ symbol >>= 1; ++ price += GET_PRICEa(probs[m], bit); ++ m = (m << 1) | bit; ++ } ++ return price; ++} ++ ++ ++static void LenEnc_Init(CLenEnc *p) ++{ ++ unsigned i; ++ p->choice = p->choice2 = kProbInitValue; ++ for (i = 0; i < (LZMA_NUM_PB_STATES_MAX << kLenNumLowBits); i++) ++ p->low[i] = kProbInitValue; ++ for (i = 0; i < (LZMA_NUM_PB_STATES_MAX << kLenNumMidBits); i++) ++ p->mid[i] = kProbInitValue; ++ for (i = 0; i < kLenNumHighSymbols; i++) ++ p->high[i] = kProbInitValue; ++} ++ ++static void LenEnc_Encode(CLenEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 posState) ++{ ++ if (symbol < kLenNumLowSymbols) ++ { ++ RangeEnc_EncodeBit(rc, &p->choice, 0); ++ RcTree_Encode(rc, p->low + (posState << kLenNumLowBits), kLenNumLowBits, symbol); ++ } ++ else ++ { ++ RangeEnc_EncodeBit(rc, &p->choice, 1); ++ if (symbol < kLenNumLowSymbols + kLenNumMidSymbols) ++ { ++ RangeEnc_EncodeBit(rc, &p->choice2, 0); ++ RcTree_Encode(rc, p->mid + (posState << kLenNumMidBits), kLenNumMidBits, symbol - kLenNumLowSymbols); ++ } ++ else ++ { ++ RangeEnc_EncodeBit(rc, &p->choice2, 1); ++ RcTree_Encode(rc, p->high, kLenNumHighBits, symbol - kLenNumLowSymbols - kLenNumMidSymbols); ++ } ++ } ++} ++ ++static void LenEnc_SetPrices(CLenEnc *p, UInt32 posState, UInt32 numSymbols, UInt32 *prices, UInt32 *ProbPrices) ++{ ++ UInt32 a0 = GET_PRICE_0a(p->choice); ++ UInt32 a1 = GET_PRICE_1a(p->choice); ++ UInt32 b0 = a1 + GET_PRICE_0a(p->choice2); ++ UInt32 b1 = a1 + GET_PRICE_1a(p->choice2); ++ UInt32 i = 0; ++ for (i = 0; i < kLenNumLowSymbols; i++) ++ { ++ if (i >= numSymbols) ++ return; ++ prices[i] = a0 + RcTree_GetPrice(p->low + (posState << kLenNumLowBits), kLenNumLowBits, i, ProbPrices); ++ } ++ for (; i < kLenNumLowSymbols + kLenNumMidSymbols; i++) ++ { ++ if (i >= numSymbols) ++ return; ++ prices[i] = b0 + RcTree_GetPrice(p->mid + (posState << kLenNumMidBits), kLenNumMidBits, i - kLenNumLowSymbols, ProbPrices); ++ } ++ for (; i < numSymbols; i++) ++ prices[i] = b1 + RcTree_GetPrice(p->high, kLenNumHighBits, i - kLenNumLowSymbols - kLenNumMidSymbols, ProbPrices); ++} ++ ++static void MY_FAST_CALL LenPriceEnc_UpdateTable(CLenPriceEnc *p, UInt32 posState, UInt32 *ProbPrices) ++{ ++ LenEnc_SetPrices(&p->p, posState, p->tableSize, p->prices[posState], ProbPrices); ++ p->counters[posState] = p->tableSize; ++} ++ ++static void LenPriceEnc_UpdateTables(CLenPriceEnc *p, UInt32 numPosStates, UInt32 *ProbPrices) ++{ ++ UInt32 posState; ++ for (posState = 0; posState < numPosStates; posState++) ++ LenPriceEnc_UpdateTable(p, posState, ProbPrices); ++} ++ ++static void LenEnc_Encode2(CLenPriceEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 posState, Bool updatePrice, UInt32 *ProbPrices) ++{ ++ LenEnc_Encode(&p->p, rc, symbol, posState); ++ if (updatePrice) ++ if (--p->counters[posState] == 0) ++ LenPriceEnc_UpdateTable(p, posState, ProbPrices); ++} ++ ++ ++ ++ ++static void MovePos(CLzmaEnc *p, UInt32 num) ++{ ++ #ifdef SHOW_STAT ++ ttt += num; ++ printf("\n MovePos %d", num); ++ #endif ++ if (num != 0) ++ { ++ p->additionalOffset += num; ++ p->matchFinder.Skip(p->matchFinderObj, num); ++ } ++} ++ ++static UInt32 ReadMatchDistances(CLzmaEnc *p, UInt32 *numDistancePairsRes) ++{ ++ UInt32 lenRes = 0, numPairs; ++ p->numAvail = p->matchFinder.GetNumAvailableBytes(p->matchFinderObj); ++ numPairs = p->matchFinder.GetMatches(p->matchFinderObj, p->matches); ++ #ifdef SHOW_STAT ++ printf("\n i = %d numPairs = %d ", ttt, numPairs / 2); ++ ttt++; ++ { ++ UInt32 i; ++ for (i = 0; i < numPairs; i += 2) ++ printf("%2d %6d | ", p->matches[i], p->matches[i + 1]); ++ } ++ #endif ++ if (numPairs > 0) ++ { ++ lenRes = p->matches[numPairs - 2]; ++ if (lenRes == p->numFastBytes) ++ { ++ const Byte *pby = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; ++ UInt32 distance = p->matches[numPairs - 1] + 1; ++ UInt32 numAvail = p->numAvail; ++ if (numAvail > LZMA_MATCH_LEN_MAX) ++ numAvail = LZMA_MATCH_LEN_MAX; ++ { ++ const Byte *pby2 = pby - distance; ++ for (; lenRes < numAvail && pby[lenRes] == pby2[lenRes]; lenRes++); ++ } ++ } ++ } ++ p->additionalOffset++; ++ *numDistancePairsRes = numPairs; ++ return lenRes; ++} ++ ++ ++#define MakeAsChar(p) (p)->backPrev = (UInt32)(-1); (p)->prev1IsChar = False; ++#define MakeAsShortRep(p) (p)->backPrev = 0; (p)->prev1IsChar = False; ++#define IsShortRep(p) ((p)->backPrev == 0) ++ ++static UInt32 GetRepLen1Price(CLzmaEnc *p, UInt32 state, UInt32 posState) ++{ ++ return ++ GET_PRICE_0(p->isRepG0[state]) + ++ GET_PRICE_0(p->isRep0Long[state][posState]); ++} ++ ++static UInt32 GetPureRepPrice(CLzmaEnc *p, UInt32 repIndex, UInt32 state, UInt32 posState) ++{ ++ UInt32 price; ++ if (repIndex == 0) ++ { ++ price = GET_PRICE_0(p->isRepG0[state]); ++ price += GET_PRICE_1(p->isRep0Long[state][posState]); ++ } ++ else ++ { ++ price = GET_PRICE_1(p->isRepG0[state]); ++ if (repIndex == 1) ++ price += GET_PRICE_0(p->isRepG1[state]); ++ else ++ { ++ price += GET_PRICE_1(p->isRepG1[state]); ++ price += GET_PRICE(p->isRepG2[state], repIndex - 2); ++ } ++ } ++ return price; ++} ++ ++static UInt32 GetRepPrice(CLzmaEnc *p, UInt32 repIndex, UInt32 len, UInt32 state, UInt32 posState) ++{ ++ return p->repLenEnc.prices[posState][len - LZMA_MATCH_LEN_MIN] + ++ GetPureRepPrice(p, repIndex, state, posState); ++} ++ ++static UInt32 Backward(CLzmaEnc *p, UInt32 *backRes, UInt32 cur) ++{ ++ UInt32 posMem = p->opt[cur].posPrev; ++ UInt32 backMem = p->opt[cur].backPrev; ++ p->optimumEndIndex = cur; ++ do ++ { ++ if (p->opt[cur].prev1IsChar) ++ { ++ MakeAsChar(&p->opt[posMem]) ++ p->opt[posMem].posPrev = posMem - 1; ++ if (p->opt[cur].prev2) ++ { ++ p->opt[posMem - 1].prev1IsChar = False; ++ p->opt[posMem - 1].posPrev = p->opt[cur].posPrev2; ++ p->opt[posMem - 1].backPrev = p->opt[cur].backPrev2; ++ } ++ } ++ { ++ UInt32 posPrev = posMem; ++ UInt32 backCur = backMem; ++ ++ backMem = p->opt[posPrev].backPrev; ++ posMem = p->opt[posPrev].posPrev; ++ ++ p->opt[posPrev].backPrev = backCur; ++ p->opt[posPrev].posPrev = cur; ++ cur = posPrev; ++ } ++ } ++ while (cur != 0); ++ *backRes = p->opt[0].backPrev; ++ p->optimumCurrentIndex = p->opt[0].posPrev; ++ return p->optimumCurrentIndex; ++} ++ ++#define LIT_PROBS(pos, prevByte) (p->litProbs + ((((pos) & p->lpMask) << p->lc) + ((prevByte) >> (8 - p->lc))) * 0x300) ++ ++static UInt32 GetOptimum(CLzmaEnc *p, UInt32 position, UInt32 *backRes) ++{ ++ UInt32 numAvail, mainLen, numPairs, repMaxIndex, i, posState, lenEnd, len, cur; ++ UInt32 matchPrice, repMatchPrice, normalMatchPrice; ++ UInt32 reps[LZMA_NUM_REPS], repLens[LZMA_NUM_REPS]; ++ UInt32 *matches; ++ const Byte *data; ++ Byte curByte, matchByte; ++ if (p->optimumEndIndex != p->optimumCurrentIndex) ++ { ++ const COptimal *opt = &p->opt[p->optimumCurrentIndex]; ++ UInt32 lenRes = opt->posPrev - p->optimumCurrentIndex; ++ *backRes = opt->backPrev; ++ p->optimumCurrentIndex = opt->posPrev; ++ return lenRes; ++ } ++ p->optimumCurrentIndex = p->optimumEndIndex = 0; ++ ++ if (p->additionalOffset == 0) ++ mainLen = ReadMatchDistances(p, &numPairs); ++ else ++ { ++ mainLen = p->longestMatchLength; ++ numPairs = p->numPairs; ++ } ++ ++ numAvail = p->numAvail; ++ if (numAvail < 2) ++ { ++ *backRes = (UInt32)(-1); ++ return 1; ++ } ++ if (numAvail > LZMA_MATCH_LEN_MAX) ++ numAvail = LZMA_MATCH_LEN_MAX; ++ ++ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; ++ repMaxIndex = 0; ++ for (i = 0; i < LZMA_NUM_REPS; i++) ++ { ++ UInt32 lenTest; ++ const Byte *data2; ++ reps[i] = p->reps[i]; ++ data2 = data - (reps[i] + 1); ++ if (data[0] != data2[0] || data[1] != data2[1]) ++ { ++ repLens[i] = 0; ++ continue; ++ } ++ for (lenTest = 2; lenTest < numAvail && data[lenTest] == data2[lenTest]; lenTest++); ++ repLens[i] = lenTest; ++ if (lenTest > repLens[repMaxIndex]) ++ repMaxIndex = i; ++ } ++ if (repLens[repMaxIndex] >= p->numFastBytes) ++ { ++ UInt32 lenRes; ++ *backRes = repMaxIndex; ++ lenRes = repLens[repMaxIndex]; ++ MovePos(p, lenRes - 1); ++ return lenRes; ++ } ++ ++ matches = p->matches; ++ if (mainLen >= p->numFastBytes) ++ { ++ *backRes = matches[numPairs - 1] + LZMA_NUM_REPS; ++ MovePos(p, mainLen - 1); ++ return mainLen; ++ } ++ curByte = *data; ++ matchByte = *(data - (reps[0] + 1)); ++ ++ if (mainLen < 2 && curByte != matchByte && repLens[repMaxIndex] < 2) ++ { ++ *backRes = (UInt32)-1; ++ return 1; ++ } ++ ++ p->opt[0].state = (CState)p->state; ++ ++ posState = (position & p->pbMask); ++ ++ { ++ const CLzmaProb *probs = LIT_PROBS(position, *(data - 1)); ++ p->opt[1].price = GET_PRICE_0(p->isMatch[p->state][posState]) + ++ (!IsCharState(p->state) ? ++ LitEnc_GetPriceMatched(probs, curByte, matchByte, p->ProbPrices) : ++ LitEnc_GetPrice(probs, curByte, p->ProbPrices)); ++ } ++ ++ MakeAsChar(&p->opt[1]); ++ ++ matchPrice = GET_PRICE_1(p->isMatch[p->state][posState]); ++ repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[p->state]); ++ ++ if (matchByte == curByte) ++ { ++ UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(p, p->state, posState); ++ if (shortRepPrice < p->opt[1].price) ++ { ++ p->opt[1].price = shortRepPrice; ++ MakeAsShortRep(&p->opt[1]); ++ } ++ } ++ lenEnd = ((mainLen >= repLens[repMaxIndex]) ? mainLen : repLens[repMaxIndex]); ++ ++ if (lenEnd < 2) ++ { ++ *backRes = p->opt[1].backPrev; ++ return 1; ++ } ++ ++ p->opt[1].posPrev = 0; ++ for (i = 0; i < LZMA_NUM_REPS; i++) ++ p->opt[0].backs[i] = reps[i]; ++ ++ len = lenEnd; ++ do ++ p->opt[len--].price = kInfinityPrice; ++ while (len >= 2); ++ ++ for (i = 0; i < LZMA_NUM_REPS; i++) ++ { ++ UInt32 repLen = repLens[i]; ++ UInt32 price; ++ if (repLen < 2) ++ continue; ++ price = repMatchPrice + GetPureRepPrice(p, i, p->state, posState); ++ do ++ { ++ UInt32 curAndLenPrice = price + p->repLenEnc.prices[posState][repLen - 2]; ++ COptimal *opt = &p->opt[repLen]; ++ if (curAndLenPrice < opt->price) ++ { ++ opt->price = curAndLenPrice; ++ opt->posPrev = 0; ++ opt->backPrev = i; ++ opt->prev1IsChar = False; ++ } ++ } ++ while (--repLen >= 2); ++ } ++ ++ normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[p->state]); ++ ++ len = ((repLens[0] >= 2) ? repLens[0] + 1 : 2); ++ if (len <= mainLen) ++ { ++ UInt32 offs = 0; ++ while (len > matches[offs]) ++ offs += 2; ++ for (; ; len++) ++ { ++ COptimal *opt; ++ UInt32 distance = matches[offs + 1]; ++ ++ UInt32 curAndLenPrice = normalMatchPrice + p->lenEnc.prices[posState][len - LZMA_MATCH_LEN_MIN]; ++ UInt32 lenToPosState = GetLenToPosState(len); ++ if (distance < kNumFullDistances) ++ curAndLenPrice += p->distancesPrices[lenToPosState][distance]; ++ else ++ { ++ UInt32 slot; ++ GetPosSlot2(distance, slot); ++ curAndLenPrice += p->alignPrices[distance & kAlignMask] + p->posSlotPrices[lenToPosState][slot]; ++ } ++ opt = &p->opt[len]; ++ if (curAndLenPrice < opt->price) ++ { ++ opt->price = curAndLenPrice; ++ opt->posPrev = 0; ++ opt->backPrev = distance + LZMA_NUM_REPS; ++ opt->prev1IsChar = False; ++ } ++ if (len == matches[offs]) ++ { ++ offs += 2; ++ if (offs == numPairs) ++ break; ++ } ++ } ++ } ++ ++ cur = 0; ++ ++ #ifdef SHOW_STAT2 ++ if (position >= 0) ++ { ++ unsigned i; ++ printf("\n pos = %4X", position); ++ for (i = cur; i <= lenEnd; i++) ++ printf("\nprice[%4X] = %d", position - cur + i, p->opt[i].price); ++ } ++ #endif ++ ++ for (;;) ++ { ++ UInt32 numAvailFull, newLen, numPairs, posPrev, state, posState, startLen; ++ UInt32 curPrice, curAnd1Price, matchPrice, repMatchPrice; ++ Bool nextIsChar; ++ Byte curByte, matchByte; ++ const Byte *data; ++ COptimal *curOpt; ++ COptimal *nextOpt; ++ ++ cur++; ++ if (cur == lenEnd) ++ return Backward(p, backRes, cur); ++ ++ newLen = ReadMatchDistances(p, &numPairs); ++ if (newLen >= p->numFastBytes) ++ { ++ p->numPairs = numPairs; ++ p->longestMatchLength = newLen; ++ return Backward(p, backRes, cur); ++ } ++ position++; ++ curOpt = &p->opt[cur]; ++ posPrev = curOpt->posPrev; ++ if (curOpt->prev1IsChar) ++ { ++ posPrev--; ++ if (curOpt->prev2) ++ { ++ state = p->opt[curOpt->posPrev2].state; ++ if (curOpt->backPrev2 < LZMA_NUM_REPS) ++ state = kRepNextStates[state]; ++ else ++ state = kMatchNextStates[state]; ++ } ++ else ++ state = p->opt[posPrev].state; ++ state = kLiteralNextStates[state]; ++ } ++ else ++ state = p->opt[posPrev].state; ++ if (posPrev == cur - 1) ++ { ++ if (IsShortRep(curOpt)) ++ state = kShortRepNextStates[state]; ++ else ++ state = kLiteralNextStates[state]; ++ } ++ else ++ { ++ UInt32 pos; ++ const COptimal *prevOpt; ++ if (curOpt->prev1IsChar && curOpt->prev2) ++ { ++ posPrev = curOpt->posPrev2; ++ pos = curOpt->backPrev2; ++ state = kRepNextStates[state]; ++ } ++ else ++ { ++ pos = curOpt->backPrev; ++ if (pos < LZMA_NUM_REPS) ++ state = kRepNextStates[state]; ++ else ++ state = kMatchNextStates[state]; ++ } ++ prevOpt = &p->opt[posPrev]; ++ if (pos < LZMA_NUM_REPS) ++ { ++ UInt32 i; ++ reps[0] = prevOpt->backs[pos]; ++ for (i = 1; i <= pos; i++) ++ reps[i] = prevOpt->backs[i - 1]; ++ for (; i < LZMA_NUM_REPS; i++) ++ reps[i] = prevOpt->backs[i]; ++ } ++ else ++ { ++ UInt32 i; ++ reps[0] = (pos - LZMA_NUM_REPS); ++ for (i = 1; i < LZMA_NUM_REPS; i++) ++ reps[i] = prevOpt->backs[i - 1]; ++ } ++ } ++ curOpt->state = (CState)state; ++ ++ curOpt->backs[0] = reps[0]; ++ curOpt->backs[1] = reps[1]; ++ curOpt->backs[2] = reps[2]; ++ curOpt->backs[3] = reps[3]; ++ ++ curPrice = curOpt->price; ++ nextIsChar = False; ++ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; ++ curByte = *data; ++ matchByte = *(data - (reps[0] + 1)); ++ ++ posState = (position & p->pbMask); ++ ++ curAnd1Price = curPrice + GET_PRICE_0(p->isMatch[state][posState]); ++ { ++ const CLzmaProb *probs = LIT_PROBS(position, *(data - 1)); ++ curAnd1Price += ++ (!IsCharState(state) ? ++ LitEnc_GetPriceMatched(probs, curByte, matchByte, p->ProbPrices) : ++ LitEnc_GetPrice(probs, curByte, p->ProbPrices)); ++ } ++ ++ nextOpt = &p->opt[cur + 1]; ++ ++ if (curAnd1Price < nextOpt->price) ++ { ++ nextOpt->price = curAnd1Price; ++ nextOpt->posPrev = cur; ++ MakeAsChar(nextOpt); ++ nextIsChar = True; ++ } ++ ++ matchPrice = curPrice + GET_PRICE_1(p->isMatch[state][posState]); ++ repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[state]); ++ ++ if (matchByte == curByte && !(nextOpt->posPrev < cur && nextOpt->backPrev == 0)) ++ { ++ UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(p, state, posState); ++ if (shortRepPrice <= nextOpt->price) ++ { ++ nextOpt->price = shortRepPrice; ++ nextOpt->posPrev = cur; ++ MakeAsShortRep(nextOpt); ++ nextIsChar = True; ++ } ++ } ++ numAvailFull = p->numAvail; ++ { ++ UInt32 temp = kNumOpts - 1 - cur; ++ if (temp < numAvailFull) ++ numAvailFull = temp; ++ } ++ ++ if (numAvailFull < 2) ++ continue; ++ numAvail = (numAvailFull <= p->numFastBytes ? numAvailFull : p->numFastBytes); ++ ++ if (!nextIsChar && matchByte != curByte) /* speed optimization */ ++ { ++ /* try Literal + rep0 */ ++ UInt32 temp; ++ UInt32 lenTest2; ++ const Byte *data2 = data - (reps[0] + 1); ++ UInt32 limit = p->numFastBytes + 1; ++ if (limit > numAvailFull) ++ limit = numAvailFull; ++ ++ for (temp = 1; temp < limit && data[temp] == data2[temp]; temp++); ++ lenTest2 = temp - 1; ++ if (lenTest2 >= 2) ++ { ++ UInt32 state2 = kLiteralNextStates[state]; ++ UInt32 posStateNext = (position + 1) & p->pbMask; ++ UInt32 nextRepMatchPrice = curAnd1Price + ++ GET_PRICE_1(p->isMatch[state2][posStateNext]) + ++ GET_PRICE_1(p->isRep[state2]); ++ /* for (; lenTest2 >= 2; lenTest2--) */ ++ { ++ UInt32 curAndLenPrice; ++ COptimal *opt; ++ UInt32 offset = cur + 1 + lenTest2; ++ while (lenEnd < offset) ++ p->opt[++lenEnd].price = kInfinityPrice; ++ curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext); ++ opt = &p->opt[offset]; ++ if (curAndLenPrice < opt->price) ++ { ++ opt->price = curAndLenPrice; ++ opt->posPrev = cur + 1; ++ opt->backPrev = 0; ++ opt->prev1IsChar = True; ++ opt->prev2 = False; ++ } ++ } ++ } ++ } ++ ++ startLen = 2; /* speed optimization */ ++ { ++ UInt32 repIndex; ++ for (repIndex = 0; repIndex < LZMA_NUM_REPS; repIndex++) ++ { ++ UInt32 lenTest; ++ UInt32 lenTestTemp; ++ UInt32 price; ++ const Byte *data2 = data - (reps[repIndex] + 1); ++ if (data[0] != data2[0] || data[1] != data2[1]) ++ continue; ++ for (lenTest = 2; lenTest < numAvail && data[lenTest] == data2[lenTest]; lenTest++); ++ while (lenEnd < cur + lenTest) ++ p->opt[++lenEnd].price = kInfinityPrice; ++ lenTestTemp = lenTest; ++ price = repMatchPrice + GetPureRepPrice(p, repIndex, state, posState); ++ do ++ { ++ UInt32 curAndLenPrice = price + p->repLenEnc.prices[posState][lenTest - 2]; ++ COptimal *opt = &p->opt[cur + lenTest]; ++ if (curAndLenPrice < opt->price) ++ { ++ opt->price = curAndLenPrice; ++ opt->posPrev = cur; ++ opt->backPrev = repIndex; ++ opt->prev1IsChar = False; ++ } ++ } ++ while (--lenTest >= 2); ++ lenTest = lenTestTemp; ++ ++ if (repIndex == 0) ++ startLen = lenTest + 1; ++ ++ /* if (_maxMode) */ ++ { ++ UInt32 lenTest2 = lenTest + 1; ++ UInt32 limit = lenTest2 + p->numFastBytes; ++ UInt32 nextRepMatchPrice; ++ if (limit > numAvailFull) ++ limit = numAvailFull; ++ for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++); ++ lenTest2 -= lenTest + 1; ++ if (lenTest2 >= 2) ++ { ++ UInt32 state2 = kRepNextStates[state]; ++ UInt32 posStateNext = (position + lenTest) & p->pbMask; ++ UInt32 curAndLenCharPrice = ++ price + p->repLenEnc.prices[posState][lenTest - 2] + ++ GET_PRICE_0(p->isMatch[state2][posStateNext]) + ++ LitEnc_GetPriceMatched(LIT_PROBS(position + lenTest, data[lenTest - 1]), ++ data[lenTest], data2[lenTest], p->ProbPrices); ++ state2 = kLiteralNextStates[state2]; ++ posStateNext = (position + lenTest + 1) & p->pbMask; ++ nextRepMatchPrice = curAndLenCharPrice + ++ GET_PRICE_1(p->isMatch[state2][posStateNext]) + ++ GET_PRICE_1(p->isRep[state2]); ++ ++ /* for (; lenTest2 >= 2; lenTest2--) */ ++ { ++ UInt32 curAndLenPrice; ++ COptimal *opt; ++ UInt32 offset = cur + lenTest + 1 + lenTest2; ++ while (lenEnd < offset) ++ p->opt[++lenEnd].price = kInfinityPrice; ++ curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext); ++ opt = &p->opt[offset]; ++ if (curAndLenPrice < opt->price) ++ { ++ opt->price = curAndLenPrice; ++ opt->posPrev = cur + lenTest + 1; ++ opt->backPrev = 0; ++ opt->prev1IsChar = True; ++ opt->prev2 = True; ++ opt->posPrev2 = cur; ++ opt->backPrev2 = repIndex; ++ } ++ } ++ } ++ } ++ } ++ } ++ /* for (UInt32 lenTest = 2; lenTest <= newLen; lenTest++) */ ++ if (newLen > numAvail) ++ { ++ newLen = numAvail; ++ for (numPairs = 0; newLen > matches[numPairs]; numPairs += 2); ++ matches[numPairs] = newLen; ++ numPairs += 2; ++ } ++ if (newLen >= startLen) ++ { ++ UInt32 normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[state]); ++ UInt32 offs, curBack, posSlot; ++ UInt32 lenTest; ++ while (lenEnd < cur + newLen) ++ p->opt[++lenEnd].price = kInfinityPrice; ++ ++ offs = 0; ++ while (startLen > matches[offs]) ++ offs += 2; ++ curBack = matches[offs + 1]; ++ GetPosSlot2(curBack, posSlot); ++ for (lenTest = /*2*/ startLen; ; lenTest++) ++ { ++ UInt32 curAndLenPrice = normalMatchPrice + p->lenEnc.prices[posState][lenTest - LZMA_MATCH_LEN_MIN]; ++ UInt32 lenToPosState = GetLenToPosState(lenTest); ++ COptimal *opt; ++ if (curBack < kNumFullDistances) ++ curAndLenPrice += p->distancesPrices[lenToPosState][curBack]; ++ else ++ curAndLenPrice += p->posSlotPrices[lenToPosState][posSlot] + p->alignPrices[curBack & kAlignMask]; ++ ++ opt = &p->opt[cur + lenTest]; ++ if (curAndLenPrice < opt->price) ++ { ++ opt->price = curAndLenPrice; ++ opt->posPrev = cur; ++ opt->backPrev = curBack + LZMA_NUM_REPS; ++ opt->prev1IsChar = False; ++ } ++ ++ if (/*_maxMode && */lenTest == matches[offs]) ++ { ++ /* Try Match + Literal + Rep0 */ ++ const Byte *data2 = data - (curBack + 1); ++ UInt32 lenTest2 = lenTest + 1; ++ UInt32 limit = lenTest2 + p->numFastBytes; ++ UInt32 nextRepMatchPrice; ++ if (limit > numAvailFull) ++ limit = numAvailFull; ++ for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++); ++ lenTest2 -= lenTest + 1; ++ if (lenTest2 >= 2) ++ { ++ UInt32 state2 = kMatchNextStates[state]; ++ UInt32 posStateNext = (position + lenTest) & p->pbMask; ++ UInt32 curAndLenCharPrice = curAndLenPrice + ++ GET_PRICE_0(p->isMatch[state2][posStateNext]) + ++ LitEnc_GetPriceMatched(LIT_PROBS(position + lenTest, data[lenTest - 1]), ++ data[lenTest], data2[lenTest], p->ProbPrices); ++ state2 = kLiteralNextStates[state2]; ++ posStateNext = (posStateNext + 1) & p->pbMask; ++ nextRepMatchPrice = curAndLenCharPrice + ++ GET_PRICE_1(p->isMatch[state2][posStateNext]) + ++ GET_PRICE_1(p->isRep[state2]); ++ ++ /* for (; lenTest2 >= 2; lenTest2--) */ ++ { ++ UInt32 offset = cur + lenTest + 1 + lenTest2; ++ UInt32 curAndLenPrice; ++ COptimal *opt; ++ while (lenEnd < offset) ++ p->opt[++lenEnd].price = kInfinityPrice; ++ curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext); ++ opt = &p->opt[offset]; ++ if (curAndLenPrice < opt->price) ++ { ++ opt->price = curAndLenPrice; ++ opt->posPrev = cur + lenTest + 1; ++ opt->backPrev = 0; ++ opt->prev1IsChar = True; ++ opt->prev2 = True; ++ opt->posPrev2 = cur; ++ opt->backPrev2 = curBack + LZMA_NUM_REPS; ++ } ++ } ++ } ++ offs += 2; ++ if (offs == numPairs) ++ break; ++ curBack = matches[offs + 1]; ++ if (curBack >= kNumFullDistances) ++ GetPosSlot2(curBack, posSlot); ++ } ++ } ++ } ++ } ++} ++ ++#define ChangePair(smallDist, bigDist) (((bigDist) >> 7) > (smallDist)) ++ ++static UInt32 GetOptimumFast(CLzmaEnc *p, UInt32 *backRes) ++{ ++ UInt32 numAvail, mainLen, mainDist, numPairs, repIndex, repLen, i; ++ const Byte *data; ++ const UInt32 *matches; ++ ++ if (p->additionalOffset == 0) ++ mainLen = ReadMatchDistances(p, &numPairs); ++ else ++ { ++ mainLen = p->longestMatchLength; ++ numPairs = p->numPairs; ++ } ++ ++ numAvail = p->numAvail; ++ *backRes = (UInt32)-1; ++ if (numAvail < 2) ++ return 1; ++ if (numAvail > LZMA_MATCH_LEN_MAX) ++ numAvail = LZMA_MATCH_LEN_MAX; ++ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; ++ ++ repLen = repIndex = 0; ++ for (i = 0; i < LZMA_NUM_REPS; i++) ++ { ++ UInt32 len; ++ const Byte *data2 = data - (p->reps[i] + 1); ++ if (data[0] != data2[0] || data[1] != data2[1]) ++ continue; ++ for (len = 2; len < numAvail && data[len] == data2[len]; len++); ++ if (len >= p->numFastBytes) ++ { ++ *backRes = i; ++ MovePos(p, len - 1); ++ return len; ++ } ++ if (len > repLen) ++ { ++ repIndex = i; ++ repLen = len; ++ } ++ } ++ ++ matches = p->matches; ++ if (mainLen >= p->numFastBytes) ++ { ++ *backRes = matches[numPairs - 1] + LZMA_NUM_REPS; ++ MovePos(p, mainLen - 1); ++ return mainLen; ++ } ++ ++ mainDist = 0; /* for GCC */ ++ if (mainLen >= 2) ++ { ++ mainDist = matches[numPairs - 1]; ++ while (numPairs > 2 && mainLen == matches[numPairs - 4] + 1) ++ { ++ if (!ChangePair(matches[numPairs - 3], mainDist)) ++ break; ++ numPairs -= 2; ++ mainLen = matches[numPairs - 2]; ++ mainDist = matches[numPairs - 1]; ++ } ++ if (mainLen == 2 && mainDist >= 0x80) ++ mainLen = 1; ++ } ++ ++ if (repLen >= 2 && ( ++ (repLen + 1 >= mainLen) || ++ (repLen + 2 >= mainLen && mainDist >= (1 << 9)) || ++ (repLen + 3 >= mainLen && mainDist >= (1 << 15)))) ++ { ++ *backRes = repIndex; ++ MovePos(p, repLen - 1); ++ return repLen; ++ } ++ ++ if (mainLen < 2 || numAvail <= 2) ++ return 1; ++ ++ p->longestMatchLength = ReadMatchDistances(p, &p->numPairs); ++ if (p->longestMatchLength >= 2) ++ { ++ UInt32 newDistance = matches[p->numPairs - 1]; ++ if ((p->longestMatchLength >= mainLen && newDistance < mainDist) || ++ (p->longestMatchLength == mainLen + 1 && !ChangePair(mainDist, newDistance)) || ++ (p->longestMatchLength > mainLen + 1) || ++ (p->longestMatchLength + 1 >= mainLen && mainLen >= 3 && ChangePair(newDistance, mainDist))) ++ return 1; ++ } ++ ++ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; ++ for (i = 0; i < LZMA_NUM_REPS; i++) ++ { ++ UInt32 len, limit; ++ const Byte *data2 = data - (p->reps[i] + 1); ++ if (data[0] != data2[0] || data[1] != data2[1]) ++ continue; ++ limit = mainLen - 1; ++ for (len = 2; len < limit && data[len] == data2[len]; len++); ++ if (len >= limit) ++ return 1; ++ } ++ *backRes = mainDist + LZMA_NUM_REPS; ++ MovePos(p, mainLen - 2); ++ return mainLen; ++} ++ ++static void WriteEndMarker(CLzmaEnc *p, UInt32 posState) ++{ ++ UInt32 len; ++ RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 1); ++ RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 0); ++ p->state = kMatchNextStates[p->state]; ++ len = LZMA_MATCH_LEN_MIN; ++ LenEnc_Encode2(&p->lenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices); ++ RcTree_Encode(&p->rc, p->posSlotEncoder[GetLenToPosState(len)], kNumPosSlotBits, (1 << kNumPosSlotBits) - 1); ++ RangeEnc_EncodeDirectBits(&p->rc, (((UInt32)1 << 30) - 1) >> kNumAlignBits, 30 - kNumAlignBits); ++ RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, kAlignMask); ++} ++ ++static SRes CheckErrors(CLzmaEnc *p) ++{ ++ if (p->result != SZ_OK) ++ return p->result; ++ if (p->rc.res != SZ_OK) ++ p->result = SZ_ERROR_WRITE; ++ if (p->matchFinderBase.result != SZ_OK) ++ p->result = SZ_ERROR_READ; ++ if (p->result != SZ_OK) ++ p->finished = True; ++ return p->result; ++} ++ ++static SRes Flush(CLzmaEnc *p, UInt32 nowPos) ++{ ++ /* ReleaseMFStream(); */ ++ p->finished = True; ++ if (p->writeEndMark) ++ WriteEndMarker(p, nowPos & p->pbMask); ++ RangeEnc_FlushData(&p->rc); ++ RangeEnc_FlushStream(&p->rc); ++ return CheckErrors(p); ++} ++ ++static void FillAlignPrices(CLzmaEnc *p) ++{ ++ UInt32 i; ++ for (i = 0; i < kAlignTableSize; i++) ++ p->alignPrices[i] = RcTree_ReverseGetPrice(p->posAlignEncoder, kNumAlignBits, i, p->ProbPrices); ++ p->alignPriceCount = 0; ++} ++ ++static void FillDistancesPrices(CLzmaEnc *p) ++{ ++ UInt32 tempPrices[kNumFullDistances]; ++ UInt32 i, lenToPosState; ++ for (i = kStartPosModelIndex; i < kNumFullDistances; i++) ++ { ++ UInt32 posSlot = GetPosSlot1(i); ++ UInt32 footerBits = ((posSlot >> 1) - 1); ++ UInt32 base = ((2 | (posSlot & 1)) << footerBits); ++ tempPrices[i] = RcTree_ReverseGetPrice(p->posEncoders + base - posSlot - 1, footerBits, i - base, p->ProbPrices); ++ } ++ ++ for (lenToPosState = 0; lenToPosState < kNumLenToPosStates; lenToPosState++) ++ { ++ UInt32 posSlot; ++ const CLzmaProb *encoder = p->posSlotEncoder[lenToPosState]; ++ UInt32 *posSlotPrices = p->posSlotPrices[lenToPosState]; ++ for (posSlot = 0; posSlot < p->distTableSize; posSlot++) ++ posSlotPrices[posSlot] = RcTree_GetPrice(encoder, kNumPosSlotBits, posSlot, p->ProbPrices); ++ for (posSlot = kEndPosModelIndex; posSlot < p->distTableSize; posSlot++) ++ posSlotPrices[posSlot] += ((((posSlot >> 1) - 1) - kNumAlignBits) << kNumBitPriceShiftBits); ++ ++ { ++ UInt32 *distancesPrices = p->distancesPrices[lenToPosState]; ++ UInt32 i; ++ for (i = 0; i < kStartPosModelIndex; i++) ++ distancesPrices[i] = posSlotPrices[i]; ++ for (; i < kNumFullDistances; i++) ++ distancesPrices[i] = posSlotPrices[GetPosSlot1(i)] + tempPrices[i]; ++ } ++ } ++ p->matchPriceCount = 0; ++} ++ ++void LzmaEnc_Construct(CLzmaEnc *p) ++{ ++ RangeEnc_Construct(&p->rc); ++ MatchFinder_Construct(&p->matchFinderBase); ++ #ifndef _7ZIP_ST ++ MatchFinderMt_Construct(&p->matchFinderMt); ++ p->matchFinderMt.MatchFinder = &p->matchFinderBase; ++ #endif ++ ++ { ++ CLzmaEncProps props; ++ LzmaEncProps_Init(&props); ++ LzmaEnc_SetProps(p, &props); ++ } ++ ++ #ifndef LZMA_LOG_BSR ++ LzmaEnc_FastPosInit(p->g_FastPos); ++ #endif ++ ++ LzmaEnc_InitPriceTables(p->ProbPrices); ++ p->litProbs = 0; ++ p->saveState.litProbs = 0; ++} ++ ++CLzmaEncHandle LzmaEnc_Create(ISzAlloc *alloc) ++{ ++ void *p; ++ p = alloc->Alloc(alloc, sizeof(CLzmaEnc)); ++ if (p != 0) ++ LzmaEnc_Construct((CLzmaEnc *)p); ++ return p; ++} ++ ++void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAlloc *alloc) ++{ ++ alloc->Free(alloc, p->litProbs); ++ alloc->Free(alloc, p->saveState.litProbs); ++ p->litProbs = 0; ++ p->saveState.litProbs = 0; ++} ++ ++void LzmaEnc_Destruct(CLzmaEnc *p, ISzAlloc *alloc, ISzAlloc *allocBig) ++{ ++ #ifndef _7ZIP_ST ++ MatchFinderMt_Destruct(&p->matchFinderMt, allocBig); ++ #endif ++ MatchFinder_Free(&p->matchFinderBase, allocBig); ++ LzmaEnc_FreeLits(p, alloc); ++ RangeEnc_Free(&p->rc, alloc); ++} ++ ++void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAlloc *alloc, ISzAlloc *allocBig) ++{ ++ LzmaEnc_Destruct((CLzmaEnc *)p, alloc, allocBig); ++ alloc->Free(alloc, p); ++} ++ ++static SRes LzmaEnc_CodeOneBlock(CLzmaEnc *p, Bool useLimits, UInt32 maxPackSize, UInt32 maxUnpackSize) ++{ ++ UInt32 nowPos32, startPos32; ++ if (p->needInit) ++ { ++ p->matchFinder.Init(p->matchFinderObj); ++ p->needInit = 0; ++ } ++ ++ if (p->finished) ++ return p->result; ++ RINOK(CheckErrors(p)); ++ ++ nowPos32 = (UInt32)p->nowPos64; ++ startPos32 = nowPos32; ++ ++ if (p->nowPos64 == 0) ++ { ++ UInt32 numPairs; ++ Byte curByte; ++ if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0) ++ return Flush(p, nowPos32); ++ ReadMatchDistances(p, &numPairs); ++ RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][0], 0); ++ p->state = kLiteralNextStates[p->state]; ++ curByte = p->matchFinder.GetIndexByte(p->matchFinderObj, 0 - p->additionalOffset); ++ LitEnc_Encode(&p->rc, p->litProbs, curByte); ++ p->additionalOffset--; ++ nowPos32++; ++ } ++ ++ if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) != 0) ++ for (;;) ++ { ++ UInt32 pos, len, posState; ++ ++ if (p->fastMode) ++ len = GetOptimumFast(p, &pos); ++ else ++ len = GetOptimum(p, nowPos32, &pos); ++ ++ #ifdef SHOW_STAT2 ++ printf("\n pos = %4X, len = %d pos = %d", nowPos32, len, pos); ++ #endif ++ ++ posState = nowPos32 & p->pbMask; ++ if (len == 1 && pos == (UInt32)-1) ++ { ++ Byte curByte; ++ CLzmaProb *probs; ++ const Byte *data; ++ ++ RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 0); ++ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset; ++ curByte = *data; ++ probs = LIT_PROBS(nowPos32, *(data - 1)); ++ if (IsCharState(p->state)) ++ LitEnc_Encode(&p->rc, probs, curByte); ++ else ++ LitEnc_EncodeMatched(&p->rc, probs, curByte, *(data - p->reps[0] - 1)); ++ p->state = kLiteralNextStates[p->state]; ++ } ++ else ++ { ++ RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 1); ++ if (pos < LZMA_NUM_REPS) ++ { ++ RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 1); ++ if (pos == 0) ++ { ++ RangeEnc_EncodeBit(&p->rc, &p->isRepG0[p->state], 0); ++ RangeEnc_EncodeBit(&p->rc, &p->isRep0Long[p->state][posState], ((len == 1) ? 0 : 1)); ++ } ++ else ++ { ++ UInt32 distance = p->reps[pos]; ++ RangeEnc_EncodeBit(&p->rc, &p->isRepG0[p->state], 1); ++ if (pos == 1) ++ RangeEnc_EncodeBit(&p->rc, &p->isRepG1[p->state], 0); ++ else ++ { ++ RangeEnc_EncodeBit(&p->rc, &p->isRepG1[p->state], 1); ++ RangeEnc_EncodeBit(&p->rc, &p->isRepG2[p->state], pos - 2); ++ if (pos == 3) ++ p->reps[3] = p->reps[2]; ++ p->reps[2] = p->reps[1]; ++ } ++ p->reps[1] = p->reps[0]; ++ p->reps[0] = distance; ++ } ++ if (len == 1) ++ p->state = kShortRepNextStates[p->state]; ++ else ++ { ++ LenEnc_Encode2(&p->repLenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices); ++ p->state = kRepNextStates[p->state]; ++ } ++ } ++ else ++ { ++ UInt32 posSlot; ++ RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 0); ++ p->state = kMatchNextStates[p->state]; ++ LenEnc_Encode2(&p->lenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices); ++ pos -= LZMA_NUM_REPS; ++ GetPosSlot(pos, posSlot); ++ RcTree_Encode(&p->rc, p->posSlotEncoder[GetLenToPosState(len)], kNumPosSlotBits, posSlot); ++ ++ if (posSlot >= kStartPosModelIndex) ++ { ++ UInt32 footerBits = ((posSlot >> 1) - 1); ++ UInt32 base = ((2 | (posSlot & 1)) << footerBits); ++ UInt32 posReduced = pos - base; ++ ++ if (posSlot < kEndPosModelIndex) ++ RcTree_ReverseEncode(&p->rc, p->posEncoders + base - posSlot - 1, footerBits, posReduced); ++ else ++ { ++ RangeEnc_EncodeDirectBits(&p->rc, posReduced >> kNumAlignBits, footerBits - kNumAlignBits); ++ RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, posReduced & kAlignMask); ++ p->alignPriceCount++; ++ } ++ } ++ p->reps[3] = p->reps[2]; ++ p->reps[2] = p->reps[1]; ++ p->reps[1] = p->reps[0]; ++ p->reps[0] = pos; ++ p->matchPriceCount++; ++ } ++ } ++ p->additionalOffset -= len; ++ nowPos32 += len; ++ if (p->additionalOffset == 0) ++ { ++ UInt32 processed; ++ if (!p->fastMode) ++ { ++ if (p->matchPriceCount >= (1 << 7)) ++ FillDistancesPrices(p); ++ if (p->alignPriceCount >= kAlignTableSize) ++ FillAlignPrices(p); ++ } ++ if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0) ++ break; ++ processed = nowPos32 - startPos32; ++ if (useLimits) ++ { ++ if (processed + kNumOpts + 300 >= maxUnpackSize || ++ RangeEnc_GetProcessed(&p->rc) + kNumOpts * 2 >= maxPackSize) ++ break; ++ } ++ else if (processed >= (1 << 15)) ++ { ++ p->nowPos64 += nowPos32 - startPos32; ++ return CheckErrors(p); ++ } ++ } ++ } ++ p->nowPos64 += nowPos32 - startPos32; ++ return Flush(p, nowPos32); ++} ++ ++#define kBigHashDicLimit ((UInt32)1 << 24) ++ ++static SRes LzmaEnc_Alloc(CLzmaEnc *p, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig) ++{ ++ UInt32 beforeSize = kNumOpts; ++ Bool btMode; ++ if (!RangeEnc_Alloc(&p->rc, alloc)) ++ return SZ_ERROR_MEM; ++ btMode = (p->matchFinderBase.btMode != 0); ++ #ifndef _7ZIP_ST ++ p->mtMode = (p->multiThread && !p->fastMode && btMode); ++ #endif ++ ++ { ++ unsigned lclp = p->lc + p->lp; ++ if (p->litProbs == 0 || p->saveState.litProbs == 0 || p->lclp != lclp) ++ { ++ LzmaEnc_FreeLits(p, alloc); ++ p->litProbs = (CLzmaProb *)alloc->Alloc(alloc, (0x300 << lclp) * sizeof(CLzmaProb)); ++ p->saveState.litProbs = (CLzmaProb *)alloc->Alloc(alloc, (0x300 << lclp) * sizeof(CLzmaProb)); ++ if (p->litProbs == 0 || p->saveState.litProbs == 0) ++ { ++ LzmaEnc_FreeLits(p, alloc); ++ return SZ_ERROR_MEM; ++ } ++ p->lclp = lclp; ++ } ++ } ++ ++ p->matchFinderBase.bigHash = (p->dictSize > kBigHashDicLimit); ++ ++ if (beforeSize + p->dictSize < keepWindowSize) ++ beforeSize = keepWindowSize - p->dictSize; ++ ++ #ifndef _7ZIP_ST ++ if (p->mtMode) ++ { ++ RINOK(MatchFinderMt_Create(&p->matchFinderMt, p->dictSize, beforeSize, p->numFastBytes, LZMA_MATCH_LEN_MAX, allocBig)); ++ p->matchFinderObj = &p->matchFinderMt; ++ MatchFinderMt_CreateVTable(&p->matchFinderMt, &p->matchFinder); ++ } ++ else ++ #endif ++ { ++ if (!MatchFinder_Create(&p->matchFinderBase, p->dictSize, beforeSize, p->numFastBytes, LZMA_MATCH_LEN_MAX, allocBig)) ++ return SZ_ERROR_MEM; ++ p->matchFinderObj = &p->matchFinderBase; ++ MatchFinder_CreateVTable(&p->matchFinderBase, &p->matchFinder); ++ } ++ return SZ_OK; ++} ++ ++void LzmaEnc_Init(CLzmaEnc *p) ++{ ++ UInt32 i; ++ p->state = 0; ++ for (i = 0 ; i < LZMA_NUM_REPS; i++) ++ p->reps[i] = 0; ++ ++ RangeEnc_Init(&p->rc); ++ ++ ++ for (i = 0; i < kNumStates; i++) ++ { ++ UInt32 j; ++ for (j = 0; j < LZMA_NUM_PB_STATES_MAX; j++) ++ { ++ p->isMatch[i][j] = kProbInitValue; ++ p->isRep0Long[i][j] = kProbInitValue; ++ } ++ p->isRep[i] = kProbInitValue; ++ p->isRepG0[i] = kProbInitValue; ++ p->isRepG1[i] = kProbInitValue; ++ p->isRepG2[i] = kProbInitValue; ++ } ++ ++ { ++ UInt32 num = 0x300 << (p->lp + p->lc); ++ for (i = 0; i < num; i++) ++ p->litProbs[i] = kProbInitValue; ++ } ++ ++ { ++ for (i = 0; i < kNumLenToPosStates; i++) ++ { ++ CLzmaProb *probs = p->posSlotEncoder[i]; ++ UInt32 j; ++ for (j = 0; j < (1 << kNumPosSlotBits); j++) ++ probs[j] = kProbInitValue; ++ } ++ } ++ { ++ for (i = 0; i < kNumFullDistances - kEndPosModelIndex; i++) ++ p->posEncoders[i] = kProbInitValue; ++ } ++ ++ LenEnc_Init(&p->lenEnc.p); ++ LenEnc_Init(&p->repLenEnc.p); ++ ++ for (i = 0; i < (1 << kNumAlignBits); i++) ++ p->posAlignEncoder[i] = kProbInitValue; ++ ++ p->optimumEndIndex = 0; ++ p->optimumCurrentIndex = 0; ++ p->additionalOffset = 0; ++ ++ p->pbMask = (1 << p->pb) - 1; ++ p->lpMask = (1 << p->lp) - 1; ++} ++ ++void LzmaEnc_InitPrices(CLzmaEnc *p) ++{ ++ if (!p->fastMode) ++ { ++ FillDistancesPrices(p); ++ FillAlignPrices(p); ++ } ++ ++ p->lenEnc.tableSize = ++ p->repLenEnc.tableSize = ++ p->numFastBytes + 1 - LZMA_MATCH_LEN_MIN; ++ LenPriceEnc_UpdateTables(&p->lenEnc, 1 << p->pb, p->ProbPrices); ++ LenPriceEnc_UpdateTables(&p->repLenEnc, 1 << p->pb, p->ProbPrices); ++} ++ ++static SRes LzmaEnc_AllocAndInit(CLzmaEnc *p, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig) ++{ ++ UInt32 i; ++ for (i = 0; i < (UInt32)kDicLogSizeMaxCompress; i++) ++ if (p->dictSize <= ((UInt32)1 << i)) ++ break; ++ p->distTableSize = i * 2; ++ ++ p->finished = False; ++ p->result = SZ_OK; ++ RINOK(LzmaEnc_Alloc(p, keepWindowSize, alloc, allocBig)); ++ LzmaEnc_Init(p); ++ LzmaEnc_InitPrices(p); ++ p->nowPos64 = 0; ++ return SZ_OK; ++} ++ ++static SRes LzmaEnc_Prepare(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ++ ISzAlloc *alloc, ISzAlloc *allocBig) ++{ ++ CLzmaEnc *p = (CLzmaEnc *)pp; ++ p->matchFinderBase.stream = inStream; ++ p->needInit = 1; ++ p->rc.outStream = outStream; ++ return LzmaEnc_AllocAndInit(p, 0, alloc, allocBig); ++} ++ ++SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle pp, ++ ISeqInStream *inStream, UInt32 keepWindowSize, ++ ISzAlloc *alloc, ISzAlloc *allocBig) ++{ ++ CLzmaEnc *p = (CLzmaEnc *)pp; ++ p->matchFinderBase.stream = inStream; ++ p->needInit = 1; ++ return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig); ++} ++ ++static void LzmaEnc_SetInputBuf(CLzmaEnc *p, const Byte *src, SizeT srcLen) ++{ ++ p->matchFinderBase.directInput = 1; ++ p->matchFinderBase.bufferBase = (Byte *)src; ++ p->matchFinderBase.directInputRem = srcLen; ++} ++ ++SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen, ++ UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig) ++{ ++ CLzmaEnc *p = (CLzmaEnc *)pp; ++ LzmaEnc_SetInputBuf(p, src, srcLen); ++ p->needInit = 1; ++ ++ return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig); ++} ++ ++void LzmaEnc_Finish(CLzmaEncHandle pp) ++{ ++ #ifndef _7ZIP_ST ++ CLzmaEnc *p = (CLzmaEnc *)pp; ++ if (p->mtMode) ++ MatchFinderMt_ReleaseStream(&p->matchFinderMt); ++ #else ++ pp = pp; ++ #endif ++} ++ ++typedef struct ++{ ++ ISeqOutStream funcTable; ++ Byte *data; ++ SizeT rem; ++ Bool overflow; ++} CSeqOutStreamBuf; ++ ++static size_t MyWrite(void *pp, const void *data, size_t size) ++{ ++ CSeqOutStreamBuf *p = (CSeqOutStreamBuf *)pp; ++ if (p->rem < size) ++ { ++ size = p->rem; ++ p->overflow = True; ++ } ++ memcpy(p->data, data, size); ++ p->rem -= size; ++ p->data += size; ++ return size; ++} ++ ++ ++UInt32 LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle pp) ++{ ++ const CLzmaEnc *p = (CLzmaEnc *)pp; ++ return p->matchFinder.GetNumAvailableBytes(p->matchFinderObj); ++} ++ ++const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp) ++{ ++ const CLzmaEnc *p = (CLzmaEnc *)pp; ++ return p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset; ++} ++ ++SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, Bool reInit, ++ Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize) ++{ ++ CLzmaEnc *p = (CLzmaEnc *)pp; ++ UInt64 nowPos64; ++ SRes res; ++ CSeqOutStreamBuf outStream; ++ ++ outStream.funcTable.Write = MyWrite; ++ outStream.data = dest; ++ outStream.rem = *destLen; ++ outStream.overflow = False; ++ ++ p->writeEndMark = False; ++ p->finished = False; ++ p->result = SZ_OK; ++ ++ if (reInit) ++ LzmaEnc_Init(p); ++ LzmaEnc_InitPrices(p); ++ nowPos64 = p->nowPos64; ++ RangeEnc_Init(&p->rc); ++ p->rc.outStream = &outStream.funcTable; ++ ++ res = LzmaEnc_CodeOneBlock(p, True, desiredPackSize, *unpackSize); ++ ++ *unpackSize = (UInt32)(p->nowPos64 - nowPos64); ++ *destLen -= outStream.rem; ++ if (outStream.overflow) ++ return SZ_ERROR_OUTPUT_EOF; ++ ++ return res; ++} ++ ++static SRes LzmaEnc_Encode2(CLzmaEnc *p, ICompressProgress *progress) ++{ ++ SRes res = SZ_OK; ++ ++ #ifndef _7ZIP_ST ++ Byte allocaDummy[0x300]; ++ int i = 0; ++ for (i = 0; i < 16; i++) ++ allocaDummy[i] = (Byte)i; ++ #endif ++ ++ for (;;) ++ { ++ res = LzmaEnc_CodeOneBlock(p, False, 0, 0); ++ if (res != SZ_OK || p->finished != 0) ++ break; ++ if (progress != 0) ++ { ++ res = progress->Progress(progress, p->nowPos64, RangeEnc_GetProcessed(&p->rc)); ++ if (res != SZ_OK) ++ { ++ res = SZ_ERROR_PROGRESS; ++ break; ++ } ++ } ++ } ++ LzmaEnc_Finish(p); ++ return res; ++} ++ ++SRes LzmaEnc_Encode(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress, ++ ISzAlloc *alloc, ISzAlloc *allocBig) ++{ ++ RINOK(LzmaEnc_Prepare(pp, outStream, inStream, alloc, allocBig)); ++ return LzmaEnc_Encode2((CLzmaEnc *)pp, progress); ++} ++ ++SRes LzmaEnc_WriteProperties(CLzmaEncHandle pp, Byte *props, SizeT *size) ++{ ++ CLzmaEnc *p = (CLzmaEnc *)pp; ++ int i; ++ UInt32 dictSize = p->dictSize; ++ if (*size < LZMA_PROPS_SIZE) ++ return SZ_ERROR_PARAM; ++ *size = LZMA_PROPS_SIZE; ++ props[0] = (Byte)((p->pb * 5 + p->lp) * 9 + p->lc); ++ ++ for (i = 11; i <= 30; i++) ++ { ++ if (dictSize <= ((UInt32)2 << i)) ++ { ++ dictSize = (2 << i); ++ break; ++ } ++ if (dictSize <= ((UInt32)3 << i)) ++ { ++ dictSize = (3 << i); ++ break; ++ } ++ } ++ ++ for (i = 0; i < 4; i++) ++ props[1 + i] = (Byte)(dictSize >> (8 * i)); ++ return SZ_OK; ++} ++ ++SRes LzmaEnc_MemEncode(CLzmaEncHandle pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, ++ int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig) ++{ ++ SRes res; ++ CLzmaEnc *p = (CLzmaEnc *)pp; ++ ++ CSeqOutStreamBuf outStream; ++ ++ LzmaEnc_SetInputBuf(p, src, srcLen); ++ ++ outStream.funcTable.Write = MyWrite; ++ outStream.data = dest; ++ outStream.rem = *destLen; ++ outStream.overflow = False; ++ ++ p->writeEndMark = writeEndMark; ++ ++ p->rc.outStream = &outStream.funcTable; ++ res = LzmaEnc_MemPrepare(pp, src, srcLen, 0, alloc, allocBig); ++ if (res == SZ_OK) ++ res = LzmaEnc_Encode2(p, progress); ++ ++ *destLen -= outStream.rem; ++ if (outStream.overflow) ++ return SZ_ERROR_OUTPUT_EOF; ++ return res; ++} ++ ++SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, ++ const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark, ++ ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig) ++{ ++ CLzmaEnc *p = (CLzmaEnc *)LzmaEnc_Create(alloc); ++ SRes res; ++ if (p == 0) ++ return SZ_ERROR_MEM; ++ ++ res = LzmaEnc_SetProps(p, props); ++ if (res == SZ_OK) ++ { ++ res = LzmaEnc_WriteProperties(p, propsEncoded, propsSize); ++ if (res == SZ_OK) ++ res = LzmaEnc_MemEncode(p, dest, destLen, src, srcLen, ++ writeEndMark, progress, alloc, allocBig); ++ } ++ ++ LzmaEnc_Destroy(p, alloc, allocBig); ++ return res; ++} +--- /dev/null ++++ b/lib/lzma/Makefile +@@ -0,0 +1,7 @@ ++lzma_compress-objs := LzFind.o LzmaEnc.o ++lzma_decompress-objs := LzmaDec.o ++ ++obj-$(CONFIG_LZMA_COMPRESS) += lzma_compress.o ++obj-$(CONFIG_LZMA_DECOMPRESS) += lzma_decompress.o ++ ++EXTRA_CFLAGS += -Iinclude/linux -Iinclude/linux/lzma -include types.h diff --git a/target/linux/generic/patches-4.0/531-debloat_lzma.patch b/target/linux/generic/patches-4.0/531-debloat_lzma.patch new file mode 100644 index 0000000..aa3c498 --- /dev/null +++ b/target/linux/generic/patches-4.0/531-debloat_lzma.patch @@ -0,0 +1,1024 @@ +--- a/include/linux/lzma/LzmaDec.h ++++ b/include/linux/lzma/LzmaDec.h +@@ -31,14 +31,6 @@ typedef struct _CLzmaProps + UInt32 dicSize; + } CLzmaProps; + +-/* LzmaProps_Decode - decodes properties +-Returns: +- SZ_OK +- SZ_ERROR_UNSUPPORTED - Unsupported properties +-*/ +- +-SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size); +- + + /* ---------- LZMA Decoder state ---------- */ + +@@ -70,8 +62,6 @@ typedef struct + + #define LzmaDec_Construct(p) { (p)->dic = 0; (p)->probs = 0; } + +-void LzmaDec_Init(CLzmaDec *p); +- + /* There are two types of LZMA streams: + 0) Stream with end mark. That end mark adds about 6 bytes to compressed size. + 1) Stream without end mark. You must know exact uncompressed size to decompress such stream. */ +@@ -108,97 +98,6 @@ typedef enum + + /* ELzmaStatus is used only as output value for function call */ + +- +-/* ---------- Interfaces ---------- */ +- +-/* There are 3 levels of interfaces: +- 1) Dictionary Interface +- 2) Buffer Interface +- 3) One Call Interface +- You can select any of these interfaces, but don't mix functions from different +- groups for same object. */ +- +- +-/* There are two variants to allocate state for Dictionary Interface: +- 1) LzmaDec_Allocate / LzmaDec_Free +- 2) LzmaDec_AllocateProbs / LzmaDec_FreeProbs +- You can use variant 2, if you set dictionary buffer manually. +- For Buffer Interface you must always use variant 1. +- +-LzmaDec_Allocate* can return: +- SZ_OK +- SZ_ERROR_MEM - Memory allocation error +- SZ_ERROR_UNSUPPORTED - Unsupported properties +-*/ +- +-SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc); +-void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc); +- +-SRes LzmaDec_Allocate(CLzmaDec *state, const Byte *prop, unsigned propsSize, ISzAlloc *alloc); +-void LzmaDec_Free(CLzmaDec *state, ISzAlloc *alloc); +- +-/* ---------- Dictionary Interface ---------- */ +- +-/* You can use it, if you want to eliminate the overhead for data copying from +- dictionary to some other external buffer. +- You must work with CLzmaDec variables directly in this interface. +- +- STEPS: +- LzmaDec_Constr() +- LzmaDec_Allocate() +- for (each new stream) +- { +- LzmaDec_Init() +- while (it needs more decompression) +- { +- LzmaDec_DecodeToDic() +- use data from CLzmaDec::dic and update CLzmaDec::dicPos +- } +- } +- LzmaDec_Free() +-*/ +- +-/* LzmaDec_DecodeToDic +- +- The decoding to internal dictionary buffer (CLzmaDec::dic). +- You must manually update CLzmaDec::dicPos, if it reaches CLzmaDec::dicBufSize !!! +- +-finishMode: +- It has meaning only if the decoding reaches output limit (dicLimit). +- LZMA_FINISH_ANY - Decode just dicLimit bytes. +- LZMA_FINISH_END - Stream must be finished after dicLimit. +- +-Returns: +- SZ_OK +- status: +- LZMA_STATUS_FINISHED_WITH_MARK +- LZMA_STATUS_NOT_FINISHED +- LZMA_STATUS_NEEDS_MORE_INPUT +- LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK +- SZ_ERROR_DATA - Data error +-*/ +- +-SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, +- const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); +- +- +-/* ---------- Buffer Interface ---------- */ +- +-/* It's zlib-like interface. +- See LzmaDec_DecodeToDic description for information about STEPS and return results, +- but you must use LzmaDec_DecodeToBuf instead of LzmaDec_DecodeToDic and you don't need +- to work with CLzmaDec variables manually. +- +-finishMode: +- It has meaning only if the decoding reaches output limit (*destLen). +- LZMA_FINISH_ANY - Decode just destLen bytes. +- LZMA_FINISH_END - Stream must be finished after (*destLen). +-*/ +- +-SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, +- const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); +- +- + /* ---------- One Call Interface ---------- */ + + /* LzmaDecode +--- a/lib/lzma/LzmaDec.c ++++ b/lib/lzma/LzmaDec.c +@@ -682,7 +682,7 @@ static void LzmaDec_InitRc(CLzmaDec *p, + p->needFlush = 0; + } + +-void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState) ++static void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState) + { + p->needFlush = 1; + p->remainLen = 0; +@@ -698,7 +698,7 @@ void LzmaDec_InitDicAndState(CLzmaDec *p + p->needInitState = 1; + } + +-void LzmaDec_Init(CLzmaDec *p) ++static void LzmaDec_Init(CLzmaDec *p) + { + p->dicPos = 0; + LzmaDec_InitDicAndState(p, True, True); +@@ -716,7 +716,7 @@ static void LzmaDec_InitStateReal(CLzmaD + p->needInitState = 0; + } + +-SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen, ++static SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen, + ELzmaFinishMode finishMode, ELzmaStatus *status) + { + SizeT inSize = *srcLen; +@@ -837,65 +837,13 @@ SRes LzmaDec_DecodeToDic(CLzmaDec *p, Si + return (p->code == 0) ? SZ_OK : SZ_ERROR_DATA; + } + +-SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) +-{ +- SizeT outSize = *destLen; +- SizeT inSize = *srcLen; +- *srcLen = *destLen = 0; +- for (;;) +- { +- SizeT inSizeCur = inSize, outSizeCur, dicPos; +- ELzmaFinishMode curFinishMode; +- SRes res; +- if (p->dicPos == p->dicBufSize) +- p->dicPos = 0; +- dicPos = p->dicPos; +- if (outSize > p->dicBufSize - dicPos) +- { +- outSizeCur = p->dicBufSize; +- curFinishMode = LZMA_FINISH_ANY; +- } +- else +- { +- outSizeCur = dicPos + outSize; +- curFinishMode = finishMode; +- } +- +- res = LzmaDec_DecodeToDic(p, outSizeCur, src, &inSizeCur, curFinishMode, status); +- src += inSizeCur; +- inSize -= inSizeCur; +- *srcLen += inSizeCur; +- outSizeCur = p->dicPos - dicPos; +- memcpy(dest, p->dic + dicPos, outSizeCur); +- dest += outSizeCur; +- outSize -= outSizeCur; +- *destLen += outSizeCur; +- if (res != 0) +- return res; +- if (outSizeCur == 0 || outSize == 0) +- return SZ_OK; +- } +-} +- +-void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc) ++static void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc) + { + alloc->Free(alloc, p->probs); + p->probs = 0; + } + +-static void LzmaDec_FreeDict(CLzmaDec *p, ISzAlloc *alloc) +-{ +- alloc->Free(alloc, p->dic); +- p->dic = 0; +-} +- +-void LzmaDec_Free(CLzmaDec *p, ISzAlloc *alloc) +-{ +- LzmaDec_FreeProbs(p, alloc); +- LzmaDec_FreeDict(p, alloc); +-} +- +-SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size) ++static SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size) + { + UInt32 dicSize; + Byte d; +@@ -935,7 +883,7 @@ static SRes LzmaDec_AllocateProbs2(CLzma + return SZ_OK; + } + +-SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) ++static SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) + { + CLzmaProps propNew; + RINOK(LzmaProps_Decode(&propNew, props, propsSize)); +@@ -943,28 +891,6 @@ SRes LzmaDec_AllocateProbs(CLzmaDec *p, + p->prop = propNew; + return SZ_OK; + } +- +-SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) +-{ +- CLzmaProps propNew; +- SizeT dicBufSize; +- RINOK(LzmaProps_Decode(&propNew, props, propsSize)); +- RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); +- dicBufSize = propNew.dicSize; +- if (p->dic == 0 || dicBufSize != p->dicBufSize) +- { +- LzmaDec_FreeDict(p, alloc); +- p->dic = (Byte *)alloc->Alloc(alloc, dicBufSize); +- if (p->dic == 0) +- { +- LzmaDec_FreeProbs(p, alloc); +- return SZ_ERROR_MEM; +- } +- } +- p->dicBufSize = dicBufSize; +- p->prop = propNew; +- return SZ_OK; +-} + + SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, + const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, +--- a/include/linux/lzma/LzmaEnc.h ++++ b/include/linux/lzma/LzmaEnc.h +@@ -31,9 +31,6 @@ typedef struct _CLzmaEncProps + } CLzmaEncProps; + + void LzmaEncProps_Init(CLzmaEncProps *p); +-void LzmaEncProps_Normalize(CLzmaEncProps *p); +-UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2); +- + + /* ---------- CLzmaEncHandle Interface ---------- */ + +@@ -53,26 +50,9 @@ CLzmaEncHandle LzmaEnc_Create(ISzAlloc * + void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAlloc *alloc, ISzAlloc *allocBig); + SRes LzmaEnc_SetProps(CLzmaEncHandle p, const CLzmaEncProps *props); + SRes LzmaEnc_WriteProperties(CLzmaEncHandle p, Byte *properties, SizeT *size); +-SRes LzmaEnc_Encode(CLzmaEncHandle p, ISeqOutStream *outStream, ISeqInStream *inStream, +- ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig); + SRes LzmaEnc_MemEncode(CLzmaEncHandle p, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, + int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig); + +-/* ---------- One Call Interface ---------- */ +- +-/* LzmaEncode +-Return code: +- SZ_OK - OK +- SZ_ERROR_MEM - Memory allocation error +- SZ_ERROR_PARAM - Incorrect paramater +- SZ_ERROR_OUTPUT_EOF - output buffer overflow +- SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version) +-*/ +- +-SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, +- const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark, +- ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig); +- + #ifdef __cplusplus + } + #endif +--- a/lib/lzma/LzmaEnc.c ++++ b/lib/lzma/LzmaEnc.c +@@ -53,7 +53,7 @@ void LzmaEncProps_Init(CLzmaEncProps *p) + p->writeEndMark = 0; + } + +-void LzmaEncProps_Normalize(CLzmaEncProps *p) ++static void LzmaEncProps_Normalize(CLzmaEncProps *p) + { + int level = p->level; + if (level < 0) level = 5; +@@ -76,7 +76,7 @@ void LzmaEncProps_Normalize(CLzmaEncProp + #endif + } + +-UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2) ++static UInt32 __maybe_unused LzmaEncProps_GetDictSize(const CLzmaEncProps *props2) + { + CLzmaEncProps props = *props2; + LzmaEncProps_Normalize(&props); +@@ -93,7 +93,7 @@ UInt32 LzmaEncProps_GetDictSize(const CL + + #define BSR2_RET(pos, res) { unsigned long i; _BitScanReverse(&i, (pos)); res = (i + i) + ((pos >> (i - 1)) & 1); } + +-UInt32 GetPosSlot1(UInt32 pos) ++static UInt32 GetPosSlot1(UInt32 pos) + { + UInt32 res; + BSR2_RET(pos, res); +@@ -107,7 +107,7 @@ UInt32 GetPosSlot1(UInt32 pos) + #define kNumLogBits (9 + (int)sizeof(size_t) / 2) + #define kDicLogSizeMaxCompress ((kNumLogBits - 1) * 2 + 7) + +-void LzmaEnc_FastPosInit(Byte *g_FastPos) ++static void LzmaEnc_FastPosInit(Byte *g_FastPos) + { + int c = 2, slotFast; + g_FastPos[0] = 0; +@@ -339,58 +339,6 @@ typedef struct + CSaveState saveState; + } CLzmaEnc; + +-void LzmaEnc_SaveState(CLzmaEncHandle pp) +-{ +- CLzmaEnc *p = (CLzmaEnc *)pp; +- CSaveState *dest = &p->saveState; +- int i; +- dest->lenEnc = p->lenEnc; +- dest->repLenEnc = p->repLenEnc; +- dest->state = p->state; +- +- for (i = 0; i < kNumStates; i++) +- { +- memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i])); +- memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i])); +- } +- for (i = 0; i < kNumLenToPosStates; i++) +- memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i])); +- memcpy(dest->isRep, p->isRep, sizeof(p->isRep)); +- memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0)); +- memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1)); +- memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2)); +- memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders)); +- memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder)); +- memcpy(dest->reps, p->reps, sizeof(p->reps)); +- memcpy(dest->litProbs, p->litProbs, (0x300 << p->lclp) * sizeof(CLzmaProb)); +-} +- +-void LzmaEnc_RestoreState(CLzmaEncHandle pp) +-{ +- CLzmaEnc *dest = (CLzmaEnc *)pp; +- const CSaveState *p = &dest->saveState; +- int i; +- dest->lenEnc = p->lenEnc; +- dest->repLenEnc = p->repLenEnc; +- dest->state = p->state; +- +- for (i = 0; i < kNumStates; i++) +- { +- memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i])); +- memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i])); +- } +- for (i = 0; i < kNumLenToPosStates; i++) +- memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i])); +- memcpy(dest->isRep, p->isRep, sizeof(p->isRep)); +- memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0)); +- memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1)); +- memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2)); +- memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders)); +- memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder)); +- memcpy(dest->reps, p->reps, sizeof(p->reps)); +- memcpy(dest->litProbs, p->litProbs, (0x300 << dest->lclp) * sizeof(CLzmaProb)); +-} +- + SRes LzmaEnc_SetProps(CLzmaEncHandle pp, const CLzmaEncProps *props2) + { + CLzmaEnc *p = (CLzmaEnc *)pp; +@@ -600,7 +548,7 @@ static void LitEnc_EncodeMatched(CRangeE + while (symbol < 0x10000); + } + +-void LzmaEnc_InitPriceTables(UInt32 *ProbPrices) ++static void LzmaEnc_InitPriceTables(UInt32 *ProbPrices) + { + UInt32 i; + for (i = (1 << kNumMoveReducingBits) / 2; i < kBitModelTotal; i += (1 << kNumMoveReducingBits)) +@@ -1676,7 +1624,7 @@ static void FillDistancesPrices(CLzmaEnc + p->matchPriceCount = 0; + } + +-void LzmaEnc_Construct(CLzmaEnc *p) ++static void LzmaEnc_Construct(CLzmaEnc *p) + { + RangeEnc_Construct(&p->rc); + MatchFinder_Construct(&p->matchFinderBase); +@@ -1709,7 +1657,7 @@ CLzmaEncHandle LzmaEnc_Create(ISzAlloc * + return p; + } + +-void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAlloc *alloc) ++static void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAlloc *alloc) + { + alloc->Free(alloc, p->litProbs); + alloc->Free(alloc, p->saveState.litProbs); +@@ -1717,7 +1665,7 @@ void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAl + p->saveState.litProbs = 0; + } + +-void LzmaEnc_Destruct(CLzmaEnc *p, ISzAlloc *alloc, ISzAlloc *allocBig) ++static void LzmaEnc_Destruct(CLzmaEnc *p, ISzAlloc *alloc, ISzAlloc *allocBig) + { + #ifndef _7ZIP_ST + MatchFinderMt_Destruct(&p->matchFinderMt, allocBig); +@@ -1947,7 +1895,7 @@ static SRes LzmaEnc_Alloc(CLzmaEnc *p, U + return SZ_OK; + } + +-void LzmaEnc_Init(CLzmaEnc *p) ++static void LzmaEnc_Init(CLzmaEnc *p) + { + UInt32 i; + p->state = 0; +@@ -2005,7 +1953,7 @@ void LzmaEnc_Init(CLzmaEnc *p) + p->lpMask = (1 << p->lp) - 1; + } + +-void LzmaEnc_InitPrices(CLzmaEnc *p) ++static void LzmaEnc_InitPrices(CLzmaEnc *p) + { + if (!p->fastMode) + { +@@ -2037,26 +1985,6 @@ static SRes LzmaEnc_AllocAndInit(CLzmaEn + return SZ_OK; + } + +-static SRes LzmaEnc_Prepare(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, +- ISzAlloc *alloc, ISzAlloc *allocBig) +-{ +- CLzmaEnc *p = (CLzmaEnc *)pp; +- p->matchFinderBase.stream = inStream; +- p->needInit = 1; +- p->rc.outStream = outStream; +- return LzmaEnc_AllocAndInit(p, 0, alloc, allocBig); +-} +- +-SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle pp, +- ISeqInStream *inStream, UInt32 keepWindowSize, +- ISzAlloc *alloc, ISzAlloc *allocBig) +-{ +- CLzmaEnc *p = (CLzmaEnc *)pp; +- p->matchFinderBase.stream = inStream; +- p->needInit = 1; +- return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig); +-} +- + static void LzmaEnc_SetInputBuf(CLzmaEnc *p, const Byte *src, SizeT srcLen) + { + p->matchFinderBase.directInput = 1; +@@ -2064,7 +1992,7 @@ static void LzmaEnc_SetInputBuf(CLzmaEnc + p->matchFinderBase.directInputRem = srcLen; + } + +-SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen, ++static SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen, + UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig) + { + CLzmaEnc *p = (CLzmaEnc *)pp; +@@ -2074,7 +2002,7 @@ SRes LzmaEnc_MemPrepare(CLzmaEncHandle p + return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig); + } + +-void LzmaEnc_Finish(CLzmaEncHandle pp) ++static void LzmaEnc_Finish(CLzmaEncHandle pp) + { + #ifndef _7ZIP_ST + CLzmaEnc *p = (CLzmaEnc *)pp; +@@ -2107,53 +2035,6 @@ static size_t MyWrite(void *pp, const vo + return size; + } + +- +-UInt32 LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle pp) +-{ +- const CLzmaEnc *p = (CLzmaEnc *)pp; +- return p->matchFinder.GetNumAvailableBytes(p->matchFinderObj); +-} +- +-const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp) +-{ +- const CLzmaEnc *p = (CLzmaEnc *)pp; +- return p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset; +-} +- +-SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, Bool reInit, +- Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize) +-{ +- CLzmaEnc *p = (CLzmaEnc *)pp; +- UInt64 nowPos64; +- SRes res; +- CSeqOutStreamBuf outStream; +- +- outStream.funcTable.Write = MyWrite; +- outStream.data = dest; +- outStream.rem = *destLen; +- outStream.overflow = False; +- +- p->writeEndMark = False; +- p->finished = False; +- p->result = SZ_OK; +- +- if (reInit) +- LzmaEnc_Init(p); +- LzmaEnc_InitPrices(p); +- nowPos64 = p->nowPos64; +- RangeEnc_Init(&p->rc); +- p->rc.outStream = &outStream.funcTable; +- +- res = LzmaEnc_CodeOneBlock(p, True, desiredPackSize, *unpackSize); +- +- *unpackSize = (UInt32)(p->nowPos64 - nowPos64); +- *destLen -= outStream.rem; +- if (outStream.overflow) +- return SZ_ERROR_OUTPUT_EOF; +- +- return res; +-} +- + static SRes LzmaEnc_Encode2(CLzmaEnc *p, ICompressProgress *progress) + { + SRes res = SZ_OK; +@@ -2184,13 +2065,6 @@ static SRes LzmaEnc_Encode2(CLzmaEnc *p, + return res; + } + +-SRes LzmaEnc_Encode(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress, +- ISzAlloc *alloc, ISzAlloc *allocBig) +-{ +- RINOK(LzmaEnc_Prepare(pp, outStream, inStream, alloc, allocBig)); +- return LzmaEnc_Encode2((CLzmaEnc *)pp, progress); +-} +- + SRes LzmaEnc_WriteProperties(CLzmaEncHandle pp, Byte *props, SizeT *size) + { + CLzmaEnc *p = (CLzmaEnc *)pp; +@@ -2247,25 +2121,3 @@ SRes LzmaEnc_MemEncode(CLzmaEncHandle pp + return SZ_ERROR_OUTPUT_EOF; + return res; + } +- +-SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, +- const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark, +- ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig) +-{ +- CLzmaEnc *p = (CLzmaEnc *)LzmaEnc_Create(alloc); +- SRes res; +- if (p == 0) +- return SZ_ERROR_MEM; +- +- res = LzmaEnc_SetProps(p, props); +- if (res == SZ_OK) +- { +- res = LzmaEnc_WriteProperties(p, propsEncoded, propsSize); +- if (res == SZ_OK) +- res = LzmaEnc_MemEncode(p, dest, destLen, src, srcLen, +- writeEndMark, progress, alloc, allocBig); +- } +- +- LzmaEnc_Destroy(p, alloc, allocBig); +- return res; +-} +--- a/include/linux/lzma/LzFind.h ++++ b/include/linux/lzma/LzFind.h +@@ -55,11 +55,6 @@ typedef struct _CMatchFinder + + #define Inline_MatchFinder_GetNumAvailableBytes(p) ((p)->streamPos - (p)->pos) + +-int MatchFinder_NeedMove(CMatchFinder *p); +-Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p); +-void MatchFinder_MoveBlock(CMatchFinder *p); +-void MatchFinder_ReadIfRequired(CMatchFinder *p); +- + void MatchFinder_Construct(CMatchFinder *p); + + /* Conditions: +@@ -70,12 +65,6 @@ int MatchFinder_Create(CMatchFinder *p, + UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter, + ISzAlloc *alloc); + void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc); +-void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems); +-void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue); +- +-UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *buffer, CLzRef *son, +- UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue, +- UInt32 *distances, UInt32 maxLen); + + /* + Conditions: +@@ -102,12 +91,6 @@ typedef struct _IMatchFinder + + void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable); + +-void MatchFinder_Init(CMatchFinder *p); +-UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances); +-UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances); +-void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num); +-void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num); +- + #ifdef __cplusplus + } + #endif +--- a/lib/lzma/LzFind.c ++++ b/lib/lzma/LzFind.c +@@ -14,9 +14,15 @@ + + #define kStartMaxLen 3 + ++#if 0 ++#define DIRECT_INPUT p->directInput ++#else ++#define DIRECT_INPUT 1 ++#endif ++ + static void LzInWindow_Free(CMatchFinder *p, ISzAlloc *alloc) + { +- if (!p->directInput) ++ if (!DIRECT_INPUT) + { + alloc->Free(alloc, p->bufferBase); + p->bufferBase = 0; +@@ -28,7 +34,7 @@ static void LzInWindow_Free(CMatchFinder + static int LzInWindow_Create(CMatchFinder *p, UInt32 keepSizeReserv, ISzAlloc *alloc) + { + UInt32 blockSize = p->keepSizeBefore + p->keepSizeAfter + keepSizeReserv; +- if (p->directInput) ++ if (DIRECT_INPUT) + { + p->blockSize = blockSize; + return 1; +@@ -42,12 +48,12 @@ static int LzInWindow_Create(CMatchFinde + return (p->bufferBase != 0); + } + +-Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; } +-Byte MatchFinder_GetIndexByte(CMatchFinder *p, Int32 index) { return p->buffer[index]; } ++static Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; } ++static Byte MatchFinder_GetIndexByte(CMatchFinder *p, Int32 index) { return p->buffer[index]; } + +-UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return p->streamPos - p->pos; } ++static UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return p->streamPos - p->pos; } + +-void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue) ++static void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue) + { + p->posLimit -= subValue; + p->pos -= subValue; +@@ -58,7 +64,7 @@ static void MatchFinder_ReadBlock(CMatch + { + if (p->streamEndWasReached || p->result != SZ_OK) + return; +- if (p->directInput) ++ if (DIRECT_INPUT) + { + UInt32 curSize = 0xFFFFFFFF - p->streamPos; + if (curSize > p->directInputRem) +@@ -89,7 +95,7 @@ static void MatchFinder_ReadBlock(CMatch + } + } + +-void MatchFinder_MoveBlock(CMatchFinder *p) ++static void MatchFinder_MoveBlock(CMatchFinder *p) + { + memmove(p->bufferBase, + p->buffer - p->keepSizeBefore, +@@ -97,22 +103,14 @@ void MatchFinder_MoveBlock(CMatchFinder + p->buffer = p->bufferBase + p->keepSizeBefore; + } + +-int MatchFinder_NeedMove(CMatchFinder *p) ++static int MatchFinder_NeedMove(CMatchFinder *p) + { +- if (p->directInput) ++ if (DIRECT_INPUT) + return 0; + /* if (p->streamEndWasReached) return 0; */ + return ((size_t)(p->bufferBase + p->blockSize - p->buffer) <= p->keepSizeAfter); + } + +-void MatchFinder_ReadIfRequired(CMatchFinder *p) +-{ +- if (p->streamEndWasReached) +- return; +- if (p->keepSizeAfter >= p->streamPos - p->pos) +- MatchFinder_ReadBlock(p); +-} +- + static void MatchFinder_CheckAndMoveAndRead(CMatchFinder *p) + { + if (MatchFinder_NeedMove(p)) +@@ -268,7 +266,7 @@ static void MatchFinder_SetLimits(CMatch + p->posLimit = p->pos + limit; + } + +-void MatchFinder_Init(CMatchFinder *p) ++static void MatchFinder_Init(CMatchFinder *p) + { + UInt32 i; + for (i = 0; i < p->hashSizeSum; i++) +@@ -287,7 +285,7 @@ static UInt32 MatchFinder_GetSubValue(CM + return (p->pos - p->historySize - 1) & kNormalizeMask; + } + +-void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems) ++static void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems) + { + UInt32 i; + for (i = 0; i < numItems; i++) +@@ -319,38 +317,7 @@ static void MatchFinder_CheckLimits(CMat + MatchFinder_SetLimits(p); + } + +-static UInt32 * Hc_GetMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, +- UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue, +- UInt32 *distances, UInt32 maxLen) +-{ +- son[_cyclicBufferPos] = curMatch; +- for (;;) +- { +- UInt32 delta = pos - curMatch; +- if (cutValue-- == 0 || delta >= _cyclicBufferSize) +- return distances; +- { +- const Byte *pb = cur - delta; +- curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)]; +- if (pb[maxLen] == cur[maxLen] && *pb == *cur) +- { +- UInt32 len = 0; +- while (++len != lenLimit) +- if (pb[len] != cur[len]) +- break; +- if (maxLen < len) +- { +- *distances++ = maxLen = len; +- *distances++ = delta - 1; +- if (len == lenLimit) +- return distances; +- } +- } +- } +- } +-} +- +-UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, ++static UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, + UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue, + UInt32 *distances, UInt32 maxLen) + { +@@ -460,10 +427,10 @@ static void SkipMatchesSpec(UInt32 lenLi + p->buffer++; \ + if (++p->pos == p->posLimit) MatchFinder_CheckLimits(p); + +-#define MOVE_POS_RET MOVE_POS return offset; +- + static void MatchFinder_MovePos(CMatchFinder *p) { MOVE_POS; } + ++#define MOVE_POS_RET MatchFinder_MovePos(p); return offset; ++ + #define GET_MATCHES_HEADER2(minLen, ret_op) \ + UInt32 lenLimit; UInt32 hashValue; const Byte *cur; UInt32 curMatch; \ + lenLimit = p->lenLimit; { if (lenLimit < minLen) { MatchFinder_MovePos(p); ret_op; }} \ +@@ -479,62 +446,7 @@ static void MatchFinder_MovePos(CMatchFi + distances + offset, maxLen) - distances); MOVE_POS_RET; + + #define SKIP_FOOTER \ +- SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); MOVE_POS; +- +-static UInt32 Bt2_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +-{ +- UInt32 offset; +- GET_MATCHES_HEADER(2) +- HASH2_CALC; +- curMatch = p->hash[hashValue]; +- p->hash[hashValue] = p->pos; +- offset = 0; +- GET_MATCHES_FOOTER(offset, 1) +-} +- +-UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +-{ +- UInt32 offset; +- GET_MATCHES_HEADER(3) +- HASH_ZIP_CALC; +- curMatch = p->hash[hashValue]; +- p->hash[hashValue] = p->pos; +- offset = 0; +- GET_MATCHES_FOOTER(offset, 2) +-} +- +-static UInt32 Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +-{ +- UInt32 hash2Value, delta2, maxLen, offset; +- GET_MATCHES_HEADER(3) +- +- HASH3_CALC; +- +- delta2 = p->pos - p->hash[hash2Value]; +- curMatch = p->hash[kFix3HashSize + hashValue]; +- +- p->hash[hash2Value] = +- p->hash[kFix3HashSize + hashValue] = p->pos; +- +- +- maxLen = 2; +- offset = 0; +- if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur) +- { +- for (; maxLen != lenLimit; maxLen++) +- if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen]) +- break; +- distances[0] = maxLen; +- distances[1] = delta2 - 1; +- offset = 2; +- if (maxLen == lenLimit) +- { +- SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); +- MOVE_POS_RET; +- } +- } +- GET_MATCHES_FOOTER(offset, maxLen) +-} ++ SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); MatchFinder_MovePos(p); + + static UInt32 Bt4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) + { +@@ -583,108 +495,6 @@ static UInt32 Bt4_MatchFinder_GetMatches + GET_MATCHES_FOOTER(offset, maxLen) + } + +-static UInt32 Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +-{ +- UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset; +- GET_MATCHES_HEADER(4) +- +- HASH4_CALC; +- +- delta2 = p->pos - p->hash[ hash2Value]; +- delta3 = p->pos - p->hash[kFix3HashSize + hash3Value]; +- curMatch = p->hash[kFix4HashSize + hashValue]; +- +- p->hash[ hash2Value] = +- p->hash[kFix3HashSize + hash3Value] = +- p->hash[kFix4HashSize + hashValue] = p->pos; +- +- maxLen = 1; +- offset = 0; +- if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur) +- { +- distances[0] = maxLen = 2; +- distances[1] = delta2 - 1; +- offset = 2; +- } +- if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur) +- { +- maxLen = 3; +- distances[offset + 1] = delta3 - 1; +- offset += 2; +- delta2 = delta3; +- } +- if (offset != 0) +- { +- for (; maxLen != lenLimit; maxLen++) +- if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen]) +- break; +- distances[offset - 2] = maxLen; +- if (maxLen == lenLimit) +- { +- p->son[p->cyclicBufferPos] = curMatch; +- MOVE_POS_RET; +- } +- } +- if (maxLen < 3) +- maxLen = 3; +- offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p), +- distances + offset, maxLen) - (distances)); +- MOVE_POS_RET +-} +- +-UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +-{ +- UInt32 offset; +- GET_MATCHES_HEADER(3) +- HASH_ZIP_CALC; +- curMatch = p->hash[hashValue]; +- p->hash[hashValue] = p->pos; +- offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p), +- distances, 2) - (distances)); +- MOVE_POS_RET +-} +- +-static void Bt2_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +-{ +- do +- { +- SKIP_HEADER(2) +- HASH2_CALC; +- curMatch = p->hash[hashValue]; +- p->hash[hashValue] = p->pos; +- SKIP_FOOTER +- } +- while (--num != 0); +-} +- +-void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +-{ +- do +- { +- SKIP_HEADER(3) +- HASH_ZIP_CALC; +- curMatch = p->hash[hashValue]; +- p->hash[hashValue] = p->pos; +- SKIP_FOOTER +- } +- while (--num != 0); +-} +- +-static void Bt3_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +-{ +- do +- { +- UInt32 hash2Value; +- SKIP_HEADER(3) +- HASH3_CALC; +- curMatch = p->hash[kFix3HashSize + hashValue]; +- p->hash[hash2Value] = +- p->hash[kFix3HashSize + hashValue] = p->pos; +- SKIP_FOOTER +- } +- while (--num != 0); +-} +- + static void Bt4_MatchFinder_Skip(CMatchFinder *p, UInt32 num) + { + do +@@ -701,61 +511,12 @@ static void Bt4_MatchFinder_Skip(CMatchF + while (--num != 0); + } + +-static void Hc4_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +-{ +- do +- { +- UInt32 hash2Value, hash3Value; +- SKIP_HEADER(4) +- HASH4_CALC; +- curMatch = p->hash[kFix4HashSize + hashValue]; +- p->hash[ hash2Value] = +- p->hash[kFix3HashSize + hash3Value] = +- p->hash[kFix4HashSize + hashValue] = p->pos; +- p->son[p->cyclicBufferPos] = curMatch; +- MOVE_POS +- } +- while (--num != 0); +-} +- +-void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +-{ +- do +- { +- SKIP_HEADER(3) +- HASH_ZIP_CALC; +- curMatch = p->hash[hashValue]; +- p->hash[hashValue] = p->pos; +- p->son[p->cyclicBufferPos] = curMatch; +- MOVE_POS +- } +- while (--num != 0); +-} +- + void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable) + { + vTable->Init = (Mf_Init_Func)MatchFinder_Init; + vTable->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinder_GetIndexByte; + vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinder_GetNumAvailableBytes; + vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinder_GetPointerToCurrentPos; +- if (!p->btMode) +- { +- vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches; +- vTable->Skip = (Mf_Skip_Func)Hc4_MatchFinder_Skip; +- } +- else if (p->numHashBytes == 2) +- { +- vTable->GetMatches = (Mf_GetMatches_Func)Bt2_MatchFinder_GetMatches; +- vTable->Skip = (Mf_Skip_Func)Bt2_MatchFinder_Skip; +- } +- else if (p->numHashBytes == 3) +- { +- vTable->GetMatches = (Mf_GetMatches_Func)Bt3_MatchFinder_GetMatches; +- vTable->Skip = (Mf_Skip_Func)Bt3_MatchFinder_Skip; +- } +- else +- { +- vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches; +- vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip; +- } ++ vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches; ++ vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip; + } diff --git a/target/linux/generic/patches-4.0/532-jffs2_eofdetect.patch b/target/linux/generic/patches-4.0/532-jffs2_eofdetect.patch new file mode 100644 index 0000000..9cbe183 --- /dev/null +++ b/target/linux/generic/patches-4.0/532-jffs2_eofdetect.patch @@ -0,0 +1,56 @@ +--- a/fs/jffs2/build.c ++++ b/fs/jffs2/build.c +@@ -114,6 +114,16 @@ static int jffs2_build_filesystem(struct + dbg_fsbuild("scanned flash completely\n"); + jffs2_dbg_dump_block_lists_nolock(c); + ++ if (c->flags & (1 << 7)) { ++ printk("%s(): unlocking the mtd device... ", __func__); ++ mtd_unlock(c->mtd, 0, c->mtd->size); ++ printk("done.\n"); ++ ++ printk("%s(): erasing all blocks after the end marker... ", __func__); ++ jffs2_erase_pending_blocks(c, -1); ++ printk("done.\n"); ++ } ++ + dbg_fsbuild("pass 1 starting\n"); + c->flags |= JFFS2_SB_FLAG_BUILDING; + /* Now scan the directory tree, increasing nlink according to every dirent found. */ +--- a/fs/jffs2/scan.c ++++ b/fs/jffs2/scan.c +@@ -148,8 +148,14 @@ int jffs2_scan_medium(struct jffs2_sb_in + /* reset summary info for next eraseblock scan */ + jffs2_sum_reset_collected(s); + +- ret = jffs2_scan_eraseblock(c, jeb, buf_size?flashbuf:(flashbuf+jeb->offset), +- buf_size, s); ++ if (c->flags & (1 << 7)) { ++ if (mtd_block_isbad(c->mtd, jeb->offset)) ++ ret = BLK_STATE_BADBLOCK; ++ else ++ ret = BLK_STATE_ALLFF; ++ } else ++ ret = jffs2_scan_eraseblock(c, jeb, buf_size?flashbuf:(flashbuf+jeb->offset), ++ buf_size, s); + + if (ret < 0) + goto out; +@@ -561,6 +567,17 @@ full_scan: + return err; + } + ++ if ((buf[0] == 0xde) && ++ (buf[1] == 0xad) && ++ (buf[2] == 0xc0) && ++ (buf[3] == 0xde)) { ++ /* end of filesystem. erase everything after this point */ ++ printk("%s(): End of filesystem marker found at 0x%x\n", __func__, jeb->offset); ++ c->flags |= (1 << 7); ++ ++ return BLK_STATE_ALLFF; ++ } ++ + /* We temporarily use 'ofs' as a pointer into the buffer/jeb */ + ofs = 0; + max_ofs = EMPTY_SCAN_SIZE(c->sector_size); diff --git a/target/linux/generic/patches-4.0/540-crypto-xz-decompression-support.patch b/target/linux/generic/patches-4.0/540-crypto-xz-decompression-support.patch new file mode 100644 index 0000000..97c5a89 --- /dev/null +++ b/target/linux/generic/patches-4.0/540-crypto-xz-decompression-support.patch @@ -0,0 +1,146 @@ +--- a/crypto/Kconfig ++++ b/crypto/Kconfig +@@ -1446,6 +1446,13 @@ config CRYPTO_LZ4HC + help + This is the LZ4 high compression mode algorithm. + ++config CRYPTO_XZ ++ tristate "XZ compression algorithm" ++ select CRYPTO_ALGAPI ++ select XZ_DEC ++ help ++ This is the XZ algorithm. Only decompression is supported for now. ++ + comment "Random Number Generation" + + config CRYPTO_ANSI_CPRNG +--- a/crypto/Makefile ++++ b/crypto/Makefile +@@ -89,6 +89,7 @@ obj-$(CONFIG_CRYPTO_AUTHENC) += authenc. + obj-$(CONFIG_CRYPTO_LZO) += lzo.o + obj-$(CONFIG_CRYPTO_LZ4) += lz4.o + obj-$(CONFIG_CRYPTO_LZ4HC) += lz4hc.o ++obj-$(CONFIG_CRYPTO_XZ) += xz.o + obj-$(CONFIG_CRYPTO_842) += 842.o + obj-$(CONFIG_CRYPTO_RNG2) += rng.o + obj-$(CONFIG_CRYPTO_RNG2) += krng.o +--- /dev/null ++++ b/crypto/xz.c +@@ -0,0 +1,117 @@ ++/* ++ * Cryptographic API. ++ * ++ * XZ decompression support. ++ * ++ * Copyright (c) 2012 Gabor Juhos ++ * ++ * 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. ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++struct xz_comp_ctx { ++ struct xz_dec *decomp_state; ++ struct xz_buf decomp_buf; ++}; ++ ++static int crypto_xz_decomp_init(struct xz_comp_ctx *ctx) ++{ ++ ctx->decomp_state = xz_dec_init(XZ_SINGLE, 0); ++ if (!ctx->decomp_state) ++ return -ENOMEM; ++ ++ return 0; ++} ++ ++static void crypto_xz_decomp_exit(struct xz_comp_ctx *ctx) ++{ ++ xz_dec_end(ctx->decomp_state); ++} ++ ++static int crypto_xz_init(struct crypto_tfm *tfm) ++{ ++ struct xz_comp_ctx *ctx = crypto_tfm_ctx(tfm); ++ ++ return crypto_xz_decomp_init(ctx); ++} ++ ++static void crypto_xz_exit(struct crypto_tfm *tfm) ++{ ++ struct xz_comp_ctx *ctx = crypto_tfm_ctx(tfm); ++ ++ crypto_xz_decomp_exit(ctx); ++} ++ ++static int crypto_xz_compress(struct crypto_tfm *tfm, const u8 *src, ++ unsigned int slen, u8 *dst, unsigned int *dlen) ++{ ++ return -EOPNOTSUPP; ++} ++ ++static int crypto_xz_decompress(struct crypto_tfm *tfm, const u8 *src, ++ unsigned int slen, u8 *dst, unsigned int *dlen) ++{ ++ struct xz_comp_ctx *dctx = crypto_tfm_ctx(tfm); ++ struct xz_buf *xz_buf = &dctx->decomp_buf; ++ int ret; ++ ++ memset(xz_buf, '\0', sizeof(struct xz_buf)); ++ ++ xz_buf->in = (u8 *) src; ++ xz_buf->in_pos = 0; ++ xz_buf->in_size = slen; ++ xz_buf->out = (u8 *) dst; ++ xz_buf->out_pos = 0; ++ xz_buf->out_size = *dlen; ++ ++ ret = xz_dec_run(dctx->decomp_state, xz_buf); ++ if (ret != XZ_STREAM_END) { ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ *dlen = xz_buf->out_pos; ++ ret = 0; ++ ++out: ++ return ret; ++} ++ ++static struct crypto_alg crypto_xz_alg = { ++ .cra_name = "xz", ++ .cra_flags = CRYPTO_ALG_TYPE_COMPRESS, ++ .cra_ctxsize = sizeof(struct xz_comp_ctx), ++ .cra_module = THIS_MODULE, ++ .cra_list = LIST_HEAD_INIT(crypto_xz_alg.cra_list), ++ .cra_init = crypto_xz_init, ++ .cra_exit = crypto_xz_exit, ++ .cra_u = { .compress = { ++ .coa_compress = crypto_xz_compress, ++ .coa_decompress = crypto_xz_decompress } } ++}; ++ ++static int __init crypto_xz_mod_init(void) ++{ ++ return crypto_register_alg(&crypto_xz_alg); ++} ++ ++static void __exit crypto_xz_mod_exit(void) ++{ ++ crypto_unregister_alg(&crypto_xz_alg); ++} ++ ++module_init(crypto_xz_mod_init); ++module_exit(crypto_xz_mod_exit); ++ ++MODULE_LICENSE("GPL v2"); ++MODULE_DESCRIPTION("Crypto XZ decompression support"); ++MODULE_AUTHOR("Gabor Juhos "); diff --git a/target/linux/generic/patches-4.0/541-ubifs-xz-decompression-support.patch b/target/linux/generic/patches-4.0/541-ubifs-xz-decompression-support.patch new file mode 100644 index 0000000..f85689c --- /dev/null +++ b/target/linux/generic/patches-4.0/541-ubifs-xz-decompression-support.patch @@ -0,0 +1,92 @@ +--- a/fs/ubifs/Kconfig ++++ b/fs/ubifs/Kconfig +@@ -5,8 +5,10 @@ config UBIFS_FS + select CRYPTO if UBIFS_FS_ADVANCED_COMPR + select CRYPTO if UBIFS_FS_LZO + select CRYPTO if UBIFS_FS_ZLIB ++ select CRYPTO if UBIFS_FS_XZ + select CRYPTO_LZO if UBIFS_FS_LZO + select CRYPTO_DEFLATE if UBIFS_FS_ZLIB ++ select CRYPTO_XZ if UBIFS_FS_XZ + depends on MTD_UBI + help + UBIFS is a file system for flash devices which works on top of UBI. +@@ -35,3 +37,12 @@ config UBIFS_FS_ZLIB + default y + help + Zlib compresses better than LZO but it is slower. Say 'Y' if unsure. ++ ++config UBIFS_FS_XZ ++ bool "XZ decompression support" if UBIFS_FS_ADVANCED_COMPR ++ depends on UBIFS_FS ++ default y ++ help ++ XZ compresses better the ZLIB but it is slower.. ++ Say 'Y' if unsure. ++ +--- a/fs/ubifs/compress.c ++++ b/fs/ubifs/compress.c +@@ -71,6 +71,24 @@ static struct ubifs_compressor zlib_comp + }; + #endif + ++#ifdef CONFIG_UBIFS_FS_XZ ++static DEFINE_MUTEX(xz_enc_mutex); ++static DEFINE_MUTEX(xz_dec_mutex); ++ ++static struct ubifs_compressor xz_compr = { ++ .compr_type = UBIFS_COMPR_XZ, ++ .comp_mutex = &xz_enc_mutex, ++ .decomp_mutex = &xz_dec_mutex, ++ .name = "xz", ++ .capi_name = "xz", ++}; ++#else ++static struct ubifs_compressor xz_compr = { ++ .compr_type = UBIFS_COMPR_XZ, ++ .name = "xz", ++}; ++#endif ++ + /* All UBIFS compressors */ + struct ubifs_compressor *ubifs_compressors[UBIFS_COMPR_TYPES_CNT]; + +@@ -232,9 +250,15 @@ int __init ubifs_compressors_init(void) + if (err) + goto out_lzo; + ++ err = compr_init(&xz_compr); ++ if (err) ++ goto out_zlib; ++ + ubifs_compressors[UBIFS_COMPR_NONE] = &none_compr; + return 0; + ++out_zlib: ++ compr_exit(&zlib_compr); + out_lzo: + compr_exit(&lzo_compr); + return err; +@@ -247,4 +271,5 @@ void ubifs_compressors_exit(void) + { + compr_exit(&lzo_compr); + compr_exit(&zlib_compr); ++ compr_exit(&xz_compr); + } +--- a/fs/ubifs/ubifs-media.h ++++ b/fs/ubifs/ubifs-media.h +@@ -332,12 +332,14 @@ enum { + * UBIFS_COMPR_NONE: no compression + * UBIFS_COMPR_LZO: LZO compression + * UBIFS_COMPR_ZLIB: ZLIB compression ++ * UBIFS_COMPR_XZ: XZ compression + * UBIFS_COMPR_TYPES_CNT: count of supported compression types + */ + enum { + UBIFS_COMPR_NONE, + UBIFS_COMPR_LZO, + UBIFS_COMPR_ZLIB, ++ UBIFS_COMPR_XZ, + UBIFS_COMPR_TYPES_CNT, + }; + diff --git a/target/linux/generic/patches-4.0/551-ubifs-fix-default-compression-selection.patch b/target/linux/generic/patches-4.0/551-ubifs-fix-default-compression-selection.patch new file mode 100644 index 0000000..1b0f307 --- /dev/null +++ b/target/linux/generic/patches-4.0/551-ubifs-fix-default-compression-selection.patch @@ -0,0 +1,29 @@ +--- a/fs/ubifs/sb.c ++++ b/fs/ubifs/sb.c +@@ -63,6 +63,17 @@ + /* Default time granularity in nanoseconds */ + #define DEFAULT_TIME_GRAN 1000000000 + ++static int get_default_compressor(void) ++{ ++ if (ubifs_compr_present(UBIFS_COMPR_LZO)) ++ return UBIFS_COMPR_LZO; ++ ++ if (ubifs_compr_present(UBIFS_COMPR_ZLIB)) ++ return UBIFS_COMPR_ZLIB; ++ ++ return UBIFS_COMPR_NONE; ++} ++ + /** + * create_default_filesystem - format empty UBI volume. + * @c: UBIFS file-system description object +@@ -183,7 +194,7 @@ static int create_default_filesystem(str + if (c->mount_opts.override_compr) + sup->default_compr = cpu_to_le16(c->mount_opts.compr_type); + else +- sup->default_compr = cpu_to_le16(UBIFS_COMPR_LZO); ++ sup->default_compr = cpu_to_le16(get_default_compressor()); + + generate_random_uuid(sup->uuid); + diff --git a/target/linux/generic/patches-4.0/600-netfilter_conntrack_flush.patch b/target/linux/generic/patches-4.0/600-netfilter_conntrack_flush.patch new file mode 100644 index 0000000..bd7a7ff --- /dev/null +++ b/target/linux/generic/patches-4.0/600-netfilter_conntrack_flush.patch @@ -0,0 +1,86 @@ +--- a/net/netfilter/nf_conntrack_standalone.c ++++ b/net/netfilter/nf_conntrack_standalone.c +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + #include + #ifdef CONFIG_SYSCTL + #include +@@ -259,10 +260,66 @@ static int ct_open(struct inode *inode, + sizeof(struct ct_iter_state)); + } + ++struct kill_request { ++ u16 family; ++ union nf_inet_addr addr; ++}; ++ ++static int kill_matching(struct nf_conn *i, void *data) ++{ ++ struct kill_request *kr = data; ++ struct nf_conntrack_tuple *t1 = &i->tuplehash[IP_CT_DIR_ORIGINAL].tuple; ++ struct nf_conntrack_tuple *t2 = &i->tuplehash[IP_CT_DIR_REPLY].tuple; ++ ++ if (!kr->family) ++ return 1; ++ ++ if (t1->src.l3num != kr->family) ++ return 0; ++ ++ return (nf_inet_addr_cmp(&kr->addr, &t1->src.u3) || ++ nf_inet_addr_cmp(&kr->addr, &t1->dst.u3) || ++ nf_inet_addr_cmp(&kr->addr, &t2->src.u3) || ++ nf_inet_addr_cmp(&kr->addr, &t2->dst.u3)); ++} ++ ++static ssize_t ct_file_write(struct file *file, const char __user *buf, ++ size_t count, loff_t *ppos) ++{ ++ struct seq_file *seq = file->private_data; ++ struct net *net = seq_file_net(seq); ++ struct kill_request kr = { }; ++ char req[INET6_ADDRSTRLEN] = { }; ++ ++ if (count == 0) ++ return 0; ++ ++ if (count >= INET6_ADDRSTRLEN) ++ count = INET6_ADDRSTRLEN - 1; ++ ++ if (copy_from_user(req, buf, count)) ++ return -EFAULT; ++ ++ if (strnchr(req, count, ':')) { ++ kr.family = AF_INET6; ++ if (!in6_pton(req, count, (void *)&kr.addr, '\n', NULL)) ++ return -EINVAL; ++ } else if (strnchr(req, count, '.')) { ++ kr.family = AF_INET; ++ if (!in4_pton(req, count, (void *)&kr.addr, '\n', NULL)) ++ return -EINVAL; ++ } ++ ++ nf_ct_iterate_cleanup(net, kill_matching, &kr, 0, 0); ++ ++ return count; ++} ++ + static const struct file_operations ct_file_ops = { + .owner = THIS_MODULE, + .open = ct_open, + .read = seq_read, ++ .write = ct_file_write, + .llseek = seq_lseek, + .release = seq_release_net, + }; +@@ -364,7 +421,7 @@ static int nf_conntrack_standalone_init_ + { + struct proc_dir_entry *pde; + +- pde = proc_create("nf_conntrack", 0440, net->proc_net, &ct_file_ops); ++ pde = proc_create("nf_conntrack", 0660, net->proc_net, &ct_file_ops); + if (!pde) + goto out_nf_conntrack; + diff --git a/target/linux/generic/patches-4.0/610-netfilter_match_bypass_default_checks.patch b/target/linux/generic/patches-4.0/610-netfilter_match_bypass_default_checks.patch new file mode 100644 index 0000000..358d64b --- /dev/null +++ b/target/linux/generic/patches-4.0/610-netfilter_match_bypass_default_checks.patch @@ -0,0 +1,93 @@ +--- a/include/uapi/linux/netfilter_ipv4/ip_tables.h ++++ b/include/uapi/linux/netfilter_ipv4/ip_tables.h +@@ -87,6 +87,7 @@ struct ipt_ip { + #define IPT_F_FRAG 0x01 /* Set if rule is a fragment rule */ + #define IPT_F_GOTO 0x02 /* Set if jump is a goto */ + #define IPT_F_MASK 0x03 /* All possible flag bits mask. */ ++#define IPT_F_NO_DEF_MATCH 0x80 /* Internal: no default match rules present */ + + /* Values for "inv" field in struct ipt_ip. */ + #define IPT_INV_VIA_IN 0x01 /* Invert the sense of IN IFACE. */ +--- a/net/ipv4/netfilter/ip_tables.c ++++ b/net/ipv4/netfilter/ip_tables.c +@@ -82,6 +82,9 @@ ip_packet_match(const struct iphdr *ip, + + #define FWINV(bool, invflg) ((bool) ^ !!(ipinfo->invflags & (invflg))) + ++ if (ipinfo->flags & IPT_F_NO_DEF_MATCH) ++ return true; ++ + if (FWINV((ip->saddr&ipinfo->smsk.s_addr) != ipinfo->src.s_addr, + IPT_INV_SRCIP) || + FWINV((ip->daddr&ipinfo->dmsk.s_addr) != ipinfo->dst.s_addr, +@@ -135,6 +138,29 @@ ip_packet_match(const struct iphdr *ip, + return true; + } + ++static void ++ip_checkdefault(struct ipt_ip *ip) ++{ ++ static const char iface_mask[IFNAMSIZ] = {}; ++ ++ if (ip->invflags || ip->flags & IPT_F_FRAG) ++ return; ++ ++ if (memcmp(ip->iniface_mask, iface_mask, IFNAMSIZ) != 0) ++ return; ++ ++ if (memcmp(ip->outiface_mask, iface_mask, IFNAMSIZ) != 0) ++ return; ++ ++ if (ip->smsk.s_addr || ip->dmsk.s_addr) ++ return; ++ ++ if (ip->proto) ++ return; ++ ++ ip->flags |= IPT_F_NO_DEF_MATCH; ++} ++ + static bool + ip_checkentry(const struct ipt_ip *ip) + { +@@ -565,7 +591,7 @@ static void cleanup_match(struct xt_entr + } + + static int +-check_entry(const struct ipt_entry *e, const char *name) ++check_entry(struct ipt_entry *e, const char *name) + { + const struct xt_entry_target *t; + +@@ -574,6 +600,8 @@ check_entry(const struct ipt_entry *e, c + return -EINVAL; + } + ++ ip_checkdefault(&e->ip); ++ + if (e->target_offset + sizeof(struct xt_entry_target) > + e->next_offset) + return -EINVAL; +@@ -935,6 +963,7 @@ copy_entries_to_user(unsigned int total_ + const struct xt_table_info *private = table->private; + int ret = 0; + const void *loc_cpu_entry; ++ u8 flags; + + counters = alloc_counters(table); + if (IS_ERR(counters)) +@@ -965,6 +994,14 @@ copy_entries_to_user(unsigned int total_ + ret = -EFAULT; + goto free_counters; + } ++ ++ flags = e->ip.flags & IPT_F_MASK; ++ if (copy_to_user(userptr + off ++ + offsetof(struct ipt_entry, ip.flags), ++ &flags, sizeof(flags)) != 0) { ++ ret = -EFAULT; ++ goto free_counters; ++ } + + for (i = sizeof(struct ipt_entry); + i < e->target_offset; diff --git a/target/linux/generic/patches-4.0/611-netfilter_match_bypass_default_table.patch b/target/linux/generic/patches-4.0/611-netfilter_match_bypass_default_table.patch new file mode 100644 index 0000000..ef993c8 --- /dev/null +++ b/target/linux/generic/patches-4.0/611-netfilter_match_bypass_default_table.patch @@ -0,0 +1,94 @@ +--- a/net/ipv4/netfilter/ip_tables.c ++++ b/net/ipv4/netfilter/ip_tables.c +@@ -310,6 +310,33 @@ struct ipt_entry *ipt_next_entry(const s + return (void *)entry + entry->next_offset; + } + ++static bool ++ipt_handle_default_rule(struct ipt_entry *e, unsigned int *verdict) ++{ ++ struct xt_entry_target *t; ++ struct xt_standard_target *st; ++ ++ if (e->target_offset != sizeof(struct ipt_entry)) ++ return false; ++ ++ if (!(e->ip.flags & IPT_F_NO_DEF_MATCH)) ++ return false; ++ ++ t = ipt_get_target(e); ++ if (t->u.kernel.target->target) ++ return false; ++ ++ st = (struct xt_standard_target *) t; ++ if (st->verdict == XT_RETURN) ++ return false; ++ ++ if (st->verdict >= 0) ++ return false; ++ ++ *verdict = (unsigned)(-st->verdict) - 1; ++ return true; ++} ++ + /* Returns one of the generic firewall policies, like NF_ACCEPT. */ + unsigned int + ipt_do_table(struct sk_buff *skb, +@@ -331,9 +358,33 @@ ipt_do_table(struct sk_buff *skb, + unsigned int addend; + + /* Initialization */ ++ IP_NF_ASSERT(table->valid_hooks & (1 << hook)); ++ local_bh_disable(); ++ private = table->private; ++ cpu = smp_processor_id(); ++ /* ++ * Ensure we load private-> members after we've fetched the base ++ * pointer. ++ */ ++ smp_read_barrier_depends(); ++ table_base = private->entries[cpu]; ++ ++ e = get_entry(table_base, private->hook_entry[hook]); ++ if (ipt_handle_default_rule(e, &verdict)) { ++ ADD_COUNTER(e->counters, skb->len, 1); ++ local_bh_enable(); ++ return verdict; ++ } ++ + ip = ip_hdr(skb); + indev = in ? in->name : nulldevname; + outdev = out ? out->name : nulldevname; ++ ++ addend = xt_write_recseq_begin(); ++ jumpstack = (struct ipt_entry **)private->jumpstack[cpu]; ++ stackptr = per_cpu_ptr(private->stackptr, cpu); ++ origptr = *stackptr; ++ + /* We handle fragments by dealing with the first fragment as + * if it was a normal packet. All other fragments are treated + * normally, except that they will NEVER match rules that ask +@@ -348,23 +399,6 @@ ipt_do_table(struct sk_buff *skb, + acpar.family = NFPROTO_IPV4; + acpar.hooknum = hook; + +- IP_NF_ASSERT(table->valid_hooks & (1 << hook)); +- local_bh_disable(); +- addend = xt_write_recseq_begin(); +- private = table->private; +- cpu = smp_processor_id(); +- /* +- * Ensure we load private-> members after we've fetched the base +- * pointer. +- */ +- smp_read_barrier_depends(); +- table_base = private->entries[cpu]; +- jumpstack = (struct ipt_entry **)private->jumpstack[cpu]; +- stackptr = per_cpu_ptr(private->stackptr, cpu); +- origptr = *stackptr; +- +- e = get_entry(table_base, private->hook_entry[hook]); +- + pr_debug("Entering %s(hook %u); sp at %u (UF %p)\n", + table->name, hook, origptr, + get_entry(table_base, private->underflow[hook])); diff --git a/target/linux/generic/patches-4.0/612-netfilter_match_reduce_memory_access.patch b/target/linux/generic/patches-4.0/612-netfilter_match_reduce_memory_access.patch new file mode 100644 index 0000000..72172d8 --- /dev/null +++ b/target/linux/generic/patches-4.0/612-netfilter_match_reduce_memory_access.patch @@ -0,0 +1,16 @@ +--- a/net/ipv4/netfilter/ip_tables.c ++++ b/net/ipv4/netfilter/ip_tables.c +@@ -85,9 +85,11 @@ ip_packet_match(const struct iphdr *ip, + if (ipinfo->flags & IPT_F_NO_DEF_MATCH) + return true; + +- if (FWINV((ip->saddr&ipinfo->smsk.s_addr) != ipinfo->src.s_addr, ++ if (FWINV(ipinfo->smsk.s_addr && ++ (ip->saddr&ipinfo->smsk.s_addr) != ipinfo->src.s_addr, + IPT_INV_SRCIP) || +- FWINV((ip->daddr&ipinfo->dmsk.s_addr) != ipinfo->dst.s_addr, ++ FWINV(ipinfo->dmsk.s_addr && ++ (ip->daddr&ipinfo->dmsk.s_addr) != ipinfo->dst.s_addr, + IPT_INV_DSTIP)) { + dprintf("Source or dest mismatch.\n"); + diff --git a/target/linux/generic/patches-4.0/613-netfilter_optional_tcp_window_check.patch b/target/linux/generic/patches-4.0/613-netfilter_optional_tcp_window_check.patch new file mode 100644 index 0000000..1d3b37c --- /dev/null +++ b/target/linux/generic/patches-4.0/613-netfilter_optional_tcp_window_check.patch @@ -0,0 +1,36 @@ +--- a/net/netfilter/nf_conntrack_proto_tcp.c ++++ b/net/netfilter/nf_conntrack_proto_tcp.c +@@ -33,6 +33,9 @@ + #include + #include + ++/* Do not check the TCP window for incoming packets */ ++static int nf_ct_tcp_no_window_check __read_mostly = 1; ++ + /* "Be conservative in what you do, + be liberal in what you accept from others." + If it's non-zero, we mark only out of window RST segments as INVALID. */ +@@ -515,6 +518,9 @@ static bool tcp_in_window(const struct n + s32 receiver_offset; + bool res, in_recv_win; + ++ if (nf_ct_tcp_no_window_check) ++ return true; ++ + /* + * Get the required data from the packet. + */ +@@ -1452,6 +1458,13 @@ static struct ctl_table tcp_sysctl_table + .mode = 0644, + .proc_handler = proc_dointvec, + }, ++ { ++ .procname = "nf_conntrack_tcp_no_window_check", ++ .data = &nf_ct_tcp_no_window_check, ++ .maxlen = sizeof(unsigned int), ++ .mode = 0644, ++ .proc_handler = proc_dointvec, ++ }, + { } + }; + diff --git a/target/linux/generic/patches-4.0/615-netfilter_add_xt_id_match.patch b/target/linux/generic/patches-4.0/615-netfilter_add_xt_id_match.patch new file mode 100644 index 0000000..50607ca --- /dev/null +++ b/target/linux/generic/patches-4.0/615-netfilter_add_xt_id_match.patch @@ -0,0 +1,95 @@ +--- a/include/uapi/linux/netfilter/Kbuild ++++ b/include/uapi/linux/netfilter/Kbuild +@@ -55,6 +55,7 @@ header-y += xt_ecn.h + header-y += xt_esp.h + header-y += xt_hashlimit.h + header-y += xt_helper.h ++header-y += xt_id.h + header-y += xt_ipcomp.h + header-y += xt_iprange.h + header-y += xt_ipvs.h +--- /dev/null ++++ b/include/uapi/linux/netfilter/xt_id.h +@@ -0,0 +1,8 @@ ++#ifndef _XT_ID_H ++#define _XT_ID_H ++ ++struct xt_id_info { ++ u32 id; ++}; ++ ++#endif /* XT_ID_H */ +--- a/net/netfilter/Kconfig ++++ b/net/netfilter/Kconfig +@@ -1174,6 +1174,13 @@ config NETFILTER_XT_MATCH_IPCOMP + + To compile it as a module, choose M here. If unsure, say N. + ++config NETFILTER_XT_MATCH_ID ++ tristate '"id" match support' ++ depends on NETFILTER_ADVANCED ++ ---help--- ++ This option adds a `id' dummy-match, which allows you to put ++ numeric IDs into your iptables ruleset. ++ + config NETFILTER_XT_MATCH_IPRANGE + tristate '"iprange" address range match support' + depends on NETFILTER_ADVANCED +--- a/net/netfilter/Makefile ++++ b/net/netfilter/Makefile +@@ -145,6 +145,7 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_ESP) += + obj-$(CONFIG_NETFILTER_XT_MATCH_HASHLIMIT) += xt_hashlimit.o + obj-$(CONFIG_NETFILTER_XT_MATCH_HELPER) += xt_helper.o + obj-$(CONFIG_NETFILTER_XT_MATCH_HL) += xt_hl.o ++obj-$(CONFIG_NETFILTER_XT_MATCH_ID) += xt_id.o + obj-$(CONFIG_NETFILTER_XT_MATCH_IPCOMP) += xt_ipcomp.o + obj-$(CONFIG_NETFILTER_XT_MATCH_IPRANGE) += xt_iprange.o + obj-$(CONFIG_NETFILTER_XT_MATCH_IPVS) += xt_ipvs.o +--- /dev/null ++++ b/net/netfilter/xt_id.c +@@ -0,0 +1,45 @@ ++/* ++ * Implements a dummy match to allow attaching IDs to rules ++ * ++ * 2014-08-01 Jo-Philipp Wich ++ */ ++ ++#include ++#include ++#include ++#include ++ ++MODULE_AUTHOR("Jo-Philipp Wich "); ++MODULE_DESCRIPTION("Xtables: No-op match which can be tagged with a 32bit ID"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("ipt_id"); ++MODULE_ALIAS("ip6t_id"); ++ ++static bool ++id_mt(const struct sk_buff *skb, struct xt_action_param *par) ++{ ++ /* We always match */ ++ return true; ++} ++ ++static struct xt_match id_mt_reg __read_mostly = { ++ .name = "id", ++ .revision = 0, ++ .family = NFPROTO_UNSPEC, ++ .match = id_mt, ++ .matchsize = sizeof(struct xt_id_info), ++ .me = THIS_MODULE, ++}; ++ ++static int __init id_mt_init(void) ++{ ++ return xt_register_match(&id_mt_reg); ++} ++ ++static void __exit id_mt_exit(void) ++{ ++ xt_unregister_match(&id_mt_reg); ++} ++ ++module_init(id_mt_init); ++module_exit(id_mt_exit); diff --git a/target/linux/generic/patches-4.0/616-net_optimize_xfrm_calls.patch b/target/linux/generic/patches-4.0/616-net_optimize_xfrm_calls.patch new file mode 100644 index 0000000..2a64d54 --- /dev/null +++ b/target/linux/generic/patches-4.0/616-net_optimize_xfrm_calls.patch @@ -0,0 +1,12 @@ +--- a/net/netfilter/nf_nat_core.c ++++ b/net/netfilter/nf_nat_core.c +@@ -90,6 +90,9 @@ int nf_xfrm_me_harder(struct sk_buff *sk + struct dst_entry *dst; + int err; + ++ if (skb->dev && !dev_net(skb->dev)->xfrm.policy_count[XFRM_POLICY_OUT]) ++ return 0; ++ + err = xfrm_decode_session(skb, &fl, family); + if (err < 0) + return err; diff --git a/target/linux/generic/patches-4.0/620-sched_esfq.patch b/target/linux/generic/patches-4.0/620-sched_esfq.patch new file mode 100644 index 0000000..e1b473b --- /dev/null +++ b/target/linux/generic/patches-4.0/620-sched_esfq.patch @@ -0,0 +1,791 @@ +--- a/include/uapi/linux/pkt_sched.h ++++ b/include/uapi/linux/pkt_sched.h +@@ -226,6 +226,33 @@ struct tc_sfq_xstats { + __s32 allot; + }; + ++/* ESFQ section */ ++ ++enum ++{ ++ /* traditional */ ++ TCA_SFQ_HASH_CLASSIC, ++ TCA_SFQ_HASH_DST, ++ TCA_SFQ_HASH_SRC, ++ TCA_SFQ_HASH_FWMARK, ++ /* conntrack */ ++ TCA_SFQ_HASH_CTORIGDST, ++ TCA_SFQ_HASH_CTORIGSRC, ++ TCA_SFQ_HASH_CTREPLDST, ++ TCA_SFQ_HASH_CTREPLSRC, ++ TCA_SFQ_HASH_CTNATCHG, ++}; ++ ++struct tc_esfq_qopt ++{ ++ unsigned quantum; /* Bytes per round allocated to flow */ ++ int perturb_period; /* Period of hash perturbation */ ++ __u32 limit; /* Maximal packets in queue */ ++ unsigned divisor; /* Hash divisor */ ++ unsigned flows; /* Maximal number of flows */ ++ unsigned hash_kind; /* Hash function to use for flow identification */ ++}; ++ + /* RED section */ + + enum { +--- a/net/sched/Kconfig ++++ b/net/sched/Kconfig +@@ -149,6 +149,37 @@ config NET_SCH_SFQ + To compile this code as a module, choose M here: the + module will be called sch_sfq. + ++config NET_SCH_ESFQ ++ tristate "Enhanced Stochastic Fairness Queueing (ESFQ)" ++ ---help--- ++ Say Y here if you want to use the Enhanced Stochastic Fairness ++ Queueing (ESFQ) packet scheduling algorithm for some of your network ++ devices or as a leaf discipline for a classful qdisc such as HTB or ++ CBQ (see the top of for details and ++ references to the SFQ algorithm). ++ ++ This is an enchanced SFQ version which allows you to control some ++ hardcoded values in the SFQ scheduler. ++ ++ ESFQ also adds control of the hash function used to identify packet ++ flows. The original SFQ discipline hashes by connection; ESFQ add ++ several other hashing methods, such as by src IP or by dst IP, which ++ can be more fair to users in some networking situations. ++ ++ To compile this code as a module, choose M here: the ++ module will be called sch_esfq. ++ ++config NET_SCH_ESFQ_NFCT ++ bool "Connection Tracking Hash Types" ++ depends on NET_SCH_ESFQ && NF_CONNTRACK ++ ---help--- ++ Say Y here to enable support for hashing based on netfilter connection ++ tracking information. This is useful for a router that is also using ++ NAT to connect privately-addressed hosts to the Internet. If you want ++ to provide fair distribution of upstream bandwidth, ESFQ must use ++ connection tracking information, since all outgoing packets will share ++ the same source address. ++ + config NET_SCH_TEQL + tristate "True Link Equalizer (TEQL)" + ---help--- +--- a/net/sched/Makefile ++++ b/net/sched/Makefile +@@ -29,6 +29,7 @@ obj-$(CONFIG_NET_SCH_INGRESS) += sch_ing + obj-$(CONFIG_NET_SCH_DSMARK) += sch_dsmark.o + obj-$(CONFIG_NET_SCH_SFB) += sch_sfb.o + obj-$(CONFIG_NET_SCH_SFQ) += sch_sfq.o ++obj-$(CONFIG_NET_SCH_ESFQ) += sch_esfq.o + obj-$(CONFIG_NET_SCH_TBF) += sch_tbf.o + obj-$(CONFIG_NET_SCH_TEQL) += sch_teql.o + obj-$(CONFIG_NET_SCH_PRIO) += sch_prio.o +--- /dev/null ++++ b/net/sched/sch_esfq.c +@@ -0,0 +1,702 @@ ++/* ++ * net/sched/sch_esfq.c Extended Stochastic Fairness Queueing discipline. ++ * ++ * 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. ++ * ++ * Authors: Alexey Kuznetsov, ++ * ++ * Changes: Alexander Atanasov, ++ * Added dynamic depth,limit,divisor,hash_kind options. ++ * Added dst and src hashes. ++ * ++ * Alexander Clouter, ++ * Ported ESFQ to Linux 2.6. ++ * ++ * Corey Hickey, ++ * Maintenance of the Linux 2.6 port. ++ * Added fwmark hash (thanks to Robert Kurjata). ++ * Added usage of jhash. ++ * Added conntrack support. ++ * Added ctnatchg hash (thanks to Ben Pfountz). ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#ifdef CONFIG_NET_SCH_ESFQ_NFCT ++#include ++#endif ++ ++/* Stochastic Fairness Queuing algorithm. ++ For more comments look at sch_sfq.c. ++ The difference is that you can change limit, depth, ++ hash table size and choose alternate hash types. ++ ++ classic: same as in sch_sfq.c ++ dst: destination IP address ++ src: source IP address ++ fwmark: netfilter mark value ++ ctorigdst: original destination IP address ++ ctorigsrc: original source IP address ++ ctrepldst: reply destination IP address ++ ctreplsrc: reply source IP ++ ++*/ ++ ++#define ESFQ_HEAD 0 ++#define ESFQ_TAIL 1 ++ ++/* This type should contain at least SFQ_DEPTH*2 values */ ++typedef unsigned int esfq_index; ++ ++struct esfq_head ++{ ++ esfq_index next; ++ esfq_index prev; ++}; ++ ++struct esfq_sched_data ++{ ++/* Parameters */ ++ int perturb_period; ++ unsigned quantum; /* Allotment per round: MUST BE >= MTU */ ++ int limit; ++ unsigned depth; ++ unsigned hash_divisor; ++ unsigned hash_kind; ++/* Variables */ ++ struct timer_list perturb_timer; ++ int perturbation; ++ esfq_index tail; /* Index of current slot in round */ ++ esfq_index max_depth; /* Maximal depth */ ++ ++ esfq_index *ht; /* Hash table */ ++ esfq_index *next; /* Active slots link */ ++ short *allot; /* Current allotment per slot */ ++ unsigned short *hash; /* Hash value indexed by slots */ ++ struct sk_buff_head *qs; /* Slot queue */ ++ struct esfq_head *dep; /* Linked list of slots, indexed by depth */ ++}; ++ ++/* This contains the info we will hash. */ ++struct esfq_packet_info ++{ ++ u32 proto; /* protocol or port */ ++ u32 src; /* source from packet header */ ++ u32 dst; /* destination from packet header */ ++ u32 ctorigsrc; /* original source from conntrack */ ++ u32 ctorigdst; /* original destination from conntrack */ ++ u32 ctreplsrc; /* reply source from conntrack */ ++ u32 ctrepldst; /* reply destination from conntrack */ ++ u32 mark; /* netfilter mark (fwmark) */ ++}; ++ ++static __inline__ unsigned esfq_jhash_1word(struct esfq_sched_data *q,u32 a) ++{ ++ return jhash_1word(a, q->perturbation) & (q->hash_divisor-1); ++} ++ ++static __inline__ unsigned esfq_jhash_2words(struct esfq_sched_data *q, u32 a, u32 b) ++{ ++ return jhash_2words(a, b, q->perturbation) & (q->hash_divisor-1); ++} ++ ++static __inline__ unsigned esfq_jhash_3words(struct esfq_sched_data *q, u32 a, u32 b, u32 c) ++{ ++ return jhash_3words(a, b, c, q->perturbation) & (q->hash_divisor-1); ++} ++ ++static unsigned esfq_hash(struct esfq_sched_data *q, struct sk_buff *skb) ++{ ++ struct esfq_packet_info info; ++#ifdef CONFIG_NET_SCH_ESFQ_NFCT ++ enum ip_conntrack_info ctinfo; ++ struct nf_conn *ct = nf_ct_get(skb, &ctinfo); ++#endif ++ ++ switch (skb->protocol) { ++ case __constant_htons(ETH_P_IP): ++ { ++ struct iphdr *iph = ip_hdr(skb); ++ info.dst = iph->daddr; ++ info.src = iph->saddr; ++ if (!(iph->frag_off&htons(IP_MF|IP_OFFSET)) && ++ (iph->protocol == IPPROTO_TCP || ++ iph->protocol == IPPROTO_UDP || ++ iph->protocol == IPPROTO_SCTP || ++ iph->protocol == IPPROTO_DCCP || ++ iph->protocol == IPPROTO_ESP)) ++ info.proto = *(((u32*)iph) + iph->ihl); ++ else ++ info.proto = iph->protocol; ++ break; ++ } ++ case __constant_htons(ETH_P_IPV6): ++ { ++ struct ipv6hdr *iph = ipv6_hdr(skb); ++ /* Hash ipv6 addresses into a u32. This isn't ideal, ++ * but the code is simple. */ ++ info.dst = jhash2(iph->daddr.s6_addr32, 4, q->perturbation); ++ info.src = jhash2(iph->saddr.s6_addr32, 4, q->perturbation); ++ if (iph->nexthdr == IPPROTO_TCP || ++ iph->nexthdr == IPPROTO_UDP || ++ iph->nexthdr == IPPROTO_SCTP || ++ iph->nexthdr == IPPROTO_DCCP || ++ iph->nexthdr == IPPROTO_ESP) ++ info.proto = *(u32*)&iph[1]; ++ else ++ info.proto = iph->nexthdr; ++ break; ++ } ++ default: ++ info.dst = (u32)(unsigned long)skb_dst(skb); ++ info.src = (u32)(unsigned long)skb->sk; ++ info.proto = skb->protocol; ++ } ++ ++ info.mark = skb->mark; ++ ++#ifdef CONFIG_NET_SCH_ESFQ_NFCT ++ /* defaults if there is no conntrack info */ ++ info.ctorigsrc = info.src; ++ info.ctorigdst = info.dst; ++ info.ctreplsrc = info.dst; ++ info.ctrepldst = info.src; ++ /* collect conntrack info */ ++ if (ct && ct != &nf_conntrack_untracked) { ++ if (skb->protocol == __constant_htons(ETH_P_IP)) { ++ info.ctorigsrc = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip; ++ info.ctorigdst = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.ip; ++ info.ctreplsrc = ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip; ++ info.ctrepldst = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip; ++ } ++ else if (skb->protocol == __constant_htons(ETH_P_IPV6)) { ++ /* Again, hash ipv6 addresses into a single u32. */ ++ info.ctorigsrc = jhash2(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip6, 4, q->perturbation); ++ info.ctorigdst = jhash2(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.ip6, 4, q->perturbation); ++ info.ctreplsrc = jhash2(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip6, 4, q->perturbation); ++ info.ctrepldst = jhash2(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip6, 4, q->perturbation); ++ } ++ ++ } ++#endif ++ ++ switch(q->hash_kind) { ++ case TCA_SFQ_HASH_CLASSIC: ++ return esfq_jhash_3words(q, info.dst, info.src, info.proto); ++ case TCA_SFQ_HASH_DST: ++ return esfq_jhash_1word(q, info.dst); ++ case TCA_SFQ_HASH_SRC: ++ return esfq_jhash_1word(q, info.src); ++ case TCA_SFQ_HASH_FWMARK: ++ return esfq_jhash_1word(q, info.mark); ++#ifdef CONFIG_NET_SCH_ESFQ_NFCT ++ case TCA_SFQ_HASH_CTORIGDST: ++ return esfq_jhash_1word(q, info.ctorigdst); ++ case TCA_SFQ_HASH_CTORIGSRC: ++ return esfq_jhash_1word(q, info.ctorigsrc); ++ case TCA_SFQ_HASH_CTREPLDST: ++ return esfq_jhash_1word(q, info.ctrepldst); ++ case TCA_SFQ_HASH_CTREPLSRC: ++ return esfq_jhash_1word(q, info.ctreplsrc); ++ case TCA_SFQ_HASH_CTNATCHG: ++ { ++ if (info.ctorigdst == info.ctreplsrc) ++ return esfq_jhash_1word(q, info.ctorigsrc); ++ return esfq_jhash_1word(q, info.ctreplsrc); ++ } ++#endif ++ default: ++ if (net_ratelimit()) ++ printk(KERN_WARNING "ESFQ: Unknown hash method. Falling back to classic.\n"); ++ } ++ return esfq_jhash_3words(q, info.dst, info.src, info.proto); ++} ++ ++static inline void esfq_link(struct esfq_sched_data *q, esfq_index x) ++{ ++ esfq_index p, n; ++ int d = q->qs[x].qlen + q->depth; ++ ++ p = d; ++ n = q->dep[d].next; ++ q->dep[x].next = n; ++ q->dep[x].prev = p; ++ q->dep[p].next = q->dep[n].prev = x; ++} ++ ++static inline void esfq_dec(struct esfq_sched_data *q, esfq_index x) ++{ ++ esfq_index p, n; ++ ++ n = q->dep[x].next; ++ p = q->dep[x].prev; ++ q->dep[p].next = n; ++ q->dep[n].prev = p; ++ ++ if (n == p && q->max_depth == q->qs[x].qlen + 1) ++ q->max_depth--; ++ ++ esfq_link(q, x); ++} ++ ++static inline void esfq_inc(struct esfq_sched_data *q, esfq_index x) ++{ ++ esfq_index p, n; ++ int d; ++ ++ n = q->dep[x].next; ++ p = q->dep[x].prev; ++ q->dep[p].next = n; ++ q->dep[n].prev = p; ++ d = q->qs[x].qlen; ++ if (q->max_depth < d) ++ q->max_depth = d; ++ ++ esfq_link(q, x); ++} ++ ++static unsigned int esfq_drop(struct Qdisc *sch) ++{ ++ struct esfq_sched_data *q = qdisc_priv(sch); ++ esfq_index d = q->max_depth; ++ struct sk_buff *skb; ++ unsigned int len; ++ ++ /* Queue is full! Find the longest slot and ++ drop a packet from it */ ++ ++ if (d > 1) { ++ esfq_index x = q->dep[d+q->depth].next; ++ skb = q->qs[x].prev; ++ len = skb->len; ++ __skb_unlink(skb, &q->qs[x]); ++ kfree_skb(skb); ++ esfq_dec(q, x); ++ sch->q.qlen--; ++ sch->qstats.drops++; ++ sch->qstats.backlog -= len; ++ return len; ++ } ++ ++ if (d == 1) { ++ /* It is difficult to believe, but ALL THE SLOTS HAVE LENGTH 1. */ ++ d = q->next[q->tail]; ++ q->next[q->tail] = q->next[d]; ++ q->allot[q->next[d]] += q->quantum; ++ skb = q->qs[d].prev; ++ len = skb->len; ++ __skb_unlink(skb, &q->qs[d]); ++ kfree_skb(skb); ++ esfq_dec(q, d); ++ sch->q.qlen--; ++ q->ht[q->hash[d]] = q->depth; ++ sch->qstats.drops++; ++ sch->qstats.backlog -= len; ++ return len; ++ } ++ ++ return 0; ++} ++ ++static void esfq_q_enqueue(struct sk_buff *skb, struct esfq_sched_data *q, unsigned int end) ++{ ++ unsigned hash = esfq_hash(q, skb); ++ unsigned depth = q->depth; ++ esfq_index x; ++ ++ x = q->ht[hash]; ++ if (x == depth) { ++ q->ht[hash] = x = q->dep[depth].next; ++ q->hash[x] = hash; ++ } ++ ++ if (end == ESFQ_TAIL) ++ __skb_queue_tail(&q->qs[x], skb); ++ else ++ __skb_queue_head(&q->qs[x], skb); ++ ++ esfq_inc(q, x); ++ if (q->qs[x].qlen == 1) { /* The flow is new */ ++ if (q->tail == depth) { /* It is the first flow */ ++ q->tail = x; ++ q->next[x] = x; ++ q->allot[x] = q->quantum; ++ } else { ++ q->next[x] = q->next[q->tail]; ++ q->next[q->tail] = x; ++ q->tail = x; ++ } ++ } ++} ++ ++static int esfq_enqueue(struct sk_buff *skb, struct Qdisc* sch) ++{ ++ struct esfq_sched_data *q = qdisc_priv(sch); ++ esfq_q_enqueue(skb, q, ESFQ_TAIL); ++ sch->qstats.backlog += skb->len; ++ if (++sch->q.qlen < q->limit-1) { ++ sch->bstats.bytes += skb->len; ++ sch->bstats.packets++; ++ return 0; ++ } ++ ++ sch->qstats.drops++; ++ esfq_drop(sch); ++ return NET_XMIT_CN; ++} ++ ++static struct sk_buff *esfq_peek(struct Qdisc* sch) ++{ ++ struct esfq_sched_data *q = qdisc_priv(sch); ++ esfq_index a; ++ ++ /* No active slots */ ++ if (q->tail == q->depth) ++ return NULL; ++ ++ a = q->next[q->tail]; ++ return skb_peek(&q->qs[a]); ++} ++ ++static struct sk_buff *esfq_q_dequeue(struct esfq_sched_data *q) ++{ ++ struct sk_buff *skb; ++ unsigned depth = q->depth; ++ esfq_index a, old_a; ++ ++ /* No active slots */ ++ if (q->tail == depth) ++ return NULL; ++ ++ a = old_a = q->next[q->tail]; ++ ++ /* Grab packet */ ++ skb = __skb_dequeue(&q->qs[a]); ++ esfq_dec(q, a); ++ ++ /* Is the slot empty? */ ++ if (q->qs[a].qlen == 0) { ++ q->ht[q->hash[a]] = depth; ++ a = q->next[a]; ++ if (a == old_a) { ++ q->tail = depth; ++ return skb; ++ } ++ q->next[q->tail] = a; ++ q->allot[a] += q->quantum; ++ } else if ((q->allot[a] -= skb->len) <= 0) { ++ q->tail = a; ++ a = q->next[a]; ++ q->allot[a] += q->quantum; ++ } ++ ++ return skb; ++} ++ ++static struct sk_buff *esfq_dequeue(struct Qdisc* sch) ++{ ++ struct esfq_sched_data *q = qdisc_priv(sch); ++ struct sk_buff *skb; ++ ++ skb = esfq_q_dequeue(q); ++ if (skb == NULL) ++ return NULL; ++ sch->q.qlen--; ++ sch->qstats.backlog -= skb->len; ++ return skb; ++} ++ ++static void esfq_q_destroy(struct esfq_sched_data *q) ++{ ++ del_timer(&q->perturb_timer); ++ if(q->ht) ++ kfree(q->ht); ++ if(q->dep) ++ kfree(q->dep); ++ if(q->next) ++ kfree(q->next); ++ if(q->allot) ++ kfree(q->allot); ++ if(q->hash) ++ kfree(q->hash); ++ if(q->qs) ++ kfree(q->qs); ++} ++ ++static void esfq_destroy(struct Qdisc *sch) ++{ ++ struct esfq_sched_data *q = qdisc_priv(sch); ++ esfq_q_destroy(q); ++} ++ ++ ++static void esfq_reset(struct Qdisc* sch) ++{ ++ struct sk_buff *skb; ++ ++ while ((skb = esfq_dequeue(sch)) != NULL) ++ kfree_skb(skb); ++} ++ ++static void esfq_perturbation(unsigned long arg) ++{ ++ struct Qdisc *sch = (struct Qdisc*)arg; ++ struct esfq_sched_data *q = qdisc_priv(sch); ++ ++ q->perturbation = prandom_u32()&0x1F; ++ ++ if (q->perturb_period) { ++ q->perturb_timer.expires = jiffies + q->perturb_period; ++ add_timer(&q->perturb_timer); ++ } ++} ++ ++static unsigned int esfq_check_hash(unsigned int kind) ++{ ++ switch (kind) { ++ case TCA_SFQ_HASH_CTORIGDST: ++ case TCA_SFQ_HASH_CTORIGSRC: ++ case TCA_SFQ_HASH_CTREPLDST: ++ case TCA_SFQ_HASH_CTREPLSRC: ++ case TCA_SFQ_HASH_CTNATCHG: ++#ifndef CONFIG_NET_SCH_ESFQ_NFCT ++ { ++ if (net_ratelimit()) ++ printk(KERN_WARNING "ESFQ: Conntrack hash types disabled in kernel config. Falling back to classic.\n"); ++ return TCA_SFQ_HASH_CLASSIC; ++ } ++#endif ++ case TCA_SFQ_HASH_CLASSIC: ++ case TCA_SFQ_HASH_DST: ++ case TCA_SFQ_HASH_SRC: ++ case TCA_SFQ_HASH_FWMARK: ++ return kind; ++ default: ++ { ++ if (net_ratelimit()) ++ printk(KERN_WARNING "ESFQ: Unknown hash type. Falling back to classic.\n"); ++ return TCA_SFQ_HASH_CLASSIC; ++ } ++ } ++} ++ ++static int esfq_q_init(struct esfq_sched_data *q, struct nlattr *opt) ++{ ++ struct tc_esfq_qopt *ctl = nla_data(opt); ++ esfq_index p = ~0U/2; ++ int i; ++ ++ if (opt && opt->nla_len < nla_attr_size(sizeof(*ctl))) ++ return -EINVAL; ++ ++ q->perturbation = 0; ++ q->hash_kind = TCA_SFQ_HASH_CLASSIC; ++ q->max_depth = 0; ++ if (opt == NULL) { ++ q->perturb_period = 0; ++ q->hash_divisor = 1024; ++ q->tail = q->limit = q->depth = 128; ++ ++ } else { ++ struct tc_esfq_qopt *ctl = nla_data(opt); ++ if (ctl->quantum) ++ q->quantum = ctl->quantum; ++ q->perturb_period = ctl->perturb_period*HZ; ++ q->hash_divisor = ctl->divisor ? : 1024; ++ q->tail = q->limit = q->depth = ctl->flows ? : 128; ++ ++ if ( q->depth > p - 1 ) ++ return -EINVAL; ++ ++ if (ctl->limit) ++ q->limit = min_t(u32, ctl->limit, q->depth); ++ ++ if (ctl->hash_kind) { ++ q->hash_kind = esfq_check_hash(ctl->hash_kind); ++ } ++ } ++ ++ q->ht = kmalloc(q->hash_divisor*sizeof(esfq_index), GFP_KERNEL); ++ if (!q->ht) ++ goto err_case; ++ q->dep = kmalloc((1+q->depth*2)*sizeof(struct esfq_head), GFP_KERNEL); ++ if (!q->dep) ++ goto err_case; ++ q->next = kmalloc(q->depth*sizeof(esfq_index), GFP_KERNEL); ++ if (!q->next) ++ goto err_case; ++ q->allot = kmalloc(q->depth*sizeof(short), GFP_KERNEL); ++ if (!q->allot) ++ goto err_case; ++ q->hash = kmalloc(q->depth*sizeof(unsigned short), GFP_KERNEL); ++ if (!q->hash) ++ goto err_case; ++ q->qs = kmalloc(q->depth*sizeof(struct sk_buff_head), GFP_KERNEL); ++ if (!q->qs) ++ goto err_case; ++ ++ for (i=0; i< q->hash_divisor; i++) ++ q->ht[i] = q->depth; ++ for (i=0; idepth; i++) { ++ skb_queue_head_init(&q->qs[i]); ++ q->dep[i+q->depth].next = i+q->depth; ++ q->dep[i+q->depth].prev = i+q->depth; ++ } ++ ++ for (i=0; idepth; i++) ++ esfq_link(q, i); ++ return 0; ++err_case: ++ esfq_q_destroy(q); ++ return -ENOBUFS; ++} ++ ++static int esfq_init(struct Qdisc *sch, struct nlattr *opt) ++{ ++ struct esfq_sched_data *q = qdisc_priv(sch); ++ int err; ++ ++ q->quantum = psched_mtu(qdisc_dev(sch)); /* default */ ++ if ((err = esfq_q_init(q, opt))) ++ return err; ++ ++ init_timer(&q->perturb_timer); ++ q->perturb_timer.data = (unsigned long)sch; ++ q->perturb_timer.function = esfq_perturbation; ++ if (q->perturb_period) { ++ q->perturb_timer.expires = jiffies + q->perturb_period; ++ add_timer(&q->perturb_timer); ++ } ++ ++ return 0; ++} ++ ++static int esfq_change(struct Qdisc *sch, struct nlattr *opt) ++{ ++ struct esfq_sched_data *q = qdisc_priv(sch); ++ struct esfq_sched_data new; ++ struct sk_buff *skb; ++ int err; ++ ++ /* set up new queue */ ++ memset(&new, 0, sizeof(struct esfq_sched_data)); ++ new.quantum = psched_mtu(qdisc_dev(sch)); /* default */ ++ if ((err = esfq_q_init(&new, opt))) ++ return err; ++ ++ /* copy all packets from the old queue to the new queue */ ++ sch_tree_lock(sch); ++ while ((skb = esfq_q_dequeue(q)) != NULL) ++ esfq_q_enqueue(skb, &new, ESFQ_TAIL); ++ ++ /* clean up the old queue */ ++ esfq_q_destroy(q); ++ ++ /* copy elements of the new queue into the old queue */ ++ q->perturb_period = new.perturb_period; ++ q->quantum = new.quantum; ++ q->limit = new.limit; ++ q->depth = new.depth; ++ q->hash_divisor = new.hash_divisor; ++ q->hash_kind = new.hash_kind; ++ q->tail = new.tail; ++ q->max_depth = new.max_depth; ++ q->ht = new.ht; ++ q->dep = new.dep; ++ q->next = new.next; ++ q->allot = new.allot; ++ q->hash = new.hash; ++ q->qs = new.qs; ++ ++ /* finish up */ ++ if (q->perturb_period) { ++ q->perturb_timer.expires = jiffies + q->perturb_period; ++ add_timer(&q->perturb_timer); ++ } else { ++ q->perturbation = 0; ++ } ++ sch_tree_unlock(sch); ++ return 0; ++} ++ ++static int esfq_dump(struct Qdisc *sch, struct sk_buff *skb) ++{ ++ struct esfq_sched_data *q = qdisc_priv(sch); ++ unsigned char *b = skb_tail_pointer(skb); ++ struct tc_esfq_qopt opt; ++ ++ opt.quantum = q->quantum; ++ opt.perturb_period = q->perturb_period/HZ; ++ ++ opt.limit = q->limit; ++ opt.divisor = q->hash_divisor; ++ opt.flows = q->depth; ++ opt.hash_kind = q->hash_kind; ++ ++ if (nla_put(skb, TCA_OPTIONS, sizeof(opt), &opt)) ++ goto nla_put_failure; ++ ++ return skb->len; ++ ++nla_put_failure: ++ nlmsg_trim(skb, b); ++ return -1; ++} ++ ++static struct Qdisc_ops esfq_qdisc_ops = ++{ ++ .next = NULL, ++ .cl_ops = NULL, ++ .id = "esfq", ++ .priv_size = sizeof(struct esfq_sched_data), ++ .enqueue = esfq_enqueue, ++ .dequeue = esfq_dequeue, ++ .peek = esfq_peek, ++ .drop = esfq_drop, ++ .init = esfq_init, ++ .reset = esfq_reset, ++ .destroy = esfq_destroy, ++ .change = esfq_change, ++ .dump = esfq_dump, ++ .owner = THIS_MODULE, ++}; ++ ++static int __init esfq_module_init(void) ++{ ++ return register_qdisc(&esfq_qdisc_ops); ++} ++static void __exit esfq_module_exit(void) ++{ ++ unregister_qdisc(&esfq_qdisc_ops); ++} ++module_init(esfq_module_init) ++module_exit(esfq_module_exit) ++MODULE_LICENSE("GPL"); diff --git a/target/linux/generic/patches-4.0/630-packet_socket_type.patch b/target/linux/generic/patches-4.0/630-packet_socket_type.patch new file mode 100644 index 0000000..3a39f2a --- /dev/null +++ b/target/linux/generic/patches-4.0/630-packet_socket_type.patch @@ -0,0 +1,134 @@ +This patch allows the user to specify desired packet types (outgoing, +broadcast, unicast, etc.) on packet sockets via setsockopt. +This can reduce the load in situations where only a limited number +of packet types are necessary + +Signed-off-by: Felix Fietkau + +--- a/include/uapi/linux/if_packet.h ++++ b/include/uapi/linux/if_packet.h +@@ -31,6 +31,8 @@ struct sockaddr_ll { + #define PACKET_KERNEL 7 /* To kernel space */ + /* Unused, PACKET_FASTROUTE and PACKET_LOOPBACK are invisible to user space */ + #define PACKET_FASTROUTE 6 /* Fastrouted frame */ ++#define PACKET_MASK_ANY 0xffffffff /* mask for packet type bits */ ++ + + /* Packet socket options */ + +@@ -54,6 +56,7 @@ struct sockaddr_ll { + #define PACKET_FANOUT 18 + #define PACKET_TX_HAS_OFF 19 + #define PACKET_QDISC_BYPASS 20 ++#define PACKET_RECV_TYPE 21 + + #define PACKET_FANOUT_HASH 0 + #define PACKET_FANOUT_LB 1 +--- a/net/packet/af_packet.c ++++ b/net/packet/af_packet.c +@@ -1527,6 +1527,7 @@ static int packet_rcv_spkt(struct sk_buf + { + struct sock *sk; + struct sockaddr_pkt *spkt; ++ struct packet_sock *po; + + /* + * When we registered the protocol we saved the socket in the data +@@ -1534,6 +1535,7 @@ static int packet_rcv_spkt(struct sk_buf + */ + + sk = pt->af_packet_priv; ++ po = pkt_sk(sk); + + /* + * Yank back the headers [hope the device set this +@@ -1546,7 +1548,7 @@ static int packet_rcv_spkt(struct sk_buf + * so that this procedure is noop. + */ + +- if (skb->pkt_type == PACKET_LOOPBACK) ++ if (!(po->pkt_type & (1 << skb->pkt_type))) + goto out; + + if (!net_eq(dev_net(dev), sock_net(sk))) +@@ -1753,12 +1755,12 @@ static int packet_rcv(struct sk_buff *sk + int skb_len = skb->len; + unsigned int snaplen, res; + +- if (skb->pkt_type == PACKET_LOOPBACK) +- goto drop; +- + sk = pt->af_packet_priv; + po = pkt_sk(sk); + ++ if (!(po->pkt_type & (1 << skb->pkt_type))) ++ goto drop; ++ + if (!net_eq(dev_net(dev), sock_net(sk))) + goto drop; + +@@ -1878,12 +1880,12 @@ static int tpacket_rcv(struct sk_buff *s + BUILD_BUG_ON(TPACKET_ALIGN(sizeof(*h.h2)) != 32); + BUILD_BUG_ON(TPACKET_ALIGN(sizeof(*h.h3)) != 48); + +- if (skb->pkt_type == PACKET_LOOPBACK) +- goto drop; +- + sk = pt->af_packet_priv; + po = pkt_sk(sk); + ++ if (!(po->pkt_type & (1 << skb->pkt_type))) ++ goto drop; ++ + if (!net_eq(dev_net(dev), sock_net(sk))) + goto drop; + +@@ -2839,6 +2841,7 @@ static int packet_create(struct net *net + spin_lock_init(&po->bind_lock); + mutex_init(&po->pg_vec_lock); + po->prot_hook.func = packet_rcv; ++ po->pkt_type = PACKET_MASK_ANY & ~(1 << PACKET_LOOPBACK); + + if (sock->type == SOCK_PACKET) + po->prot_hook.func = packet_rcv_spkt; +@@ -3428,6 +3431,16 @@ packet_setsockopt(struct socket *sock, i + po->xmit = val ? packet_direct_xmit : dev_queue_xmit; + return 0; + } ++ case PACKET_RECV_TYPE: ++ { ++ unsigned int val; ++ if (optlen != sizeof(val)) ++ return -EINVAL; ++ if (copy_from_user(&val, optval, sizeof(val))) ++ return -EFAULT; ++ po->pkt_type = val & ~BIT(PACKET_LOOPBACK); ++ return 0; ++ } + default: + return -ENOPROTOOPT; + } +@@ -3479,6 +3492,13 @@ static int packet_getsockopt(struct sock + case PACKET_VNET_HDR: + val = po->has_vnet_hdr; + break; ++ case PACKET_RECV_TYPE: ++ if (len > sizeof(unsigned int)) ++ len = sizeof(unsigned int); ++ val = po->pkt_type; ++ ++ data = &val; ++ break; + case PACKET_VERSION: + val = po->tp_version; + break; +--- a/net/packet/internal.h ++++ b/net/packet/internal.h +@@ -117,6 +117,7 @@ struct packet_sock { + struct net_device __rcu *cached_dev; + int (*xmit)(struct sk_buff *skb); + struct packet_type prot_hook ____cacheline_aligned_in_smp; ++ unsigned int pkt_type; + }; + + static struct packet_sock *pkt_sk(struct sock *sk) diff --git a/target/linux/generic/patches-4.0/640-bridge_no_eap_forward.patch b/target/linux/generic/patches-4.0/640-bridge_no_eap_forward.patch new file mode 100644 index 0000000..fadb645 --- /dev/null +++ b/target/linux/generic/patches-4.0/640-bridge_no_eap_forward.patch @@ -0,0 +1,23 @@ +From: Felix Fietkau +Subject: [PATCH] bridge: no EAP forward + +When bridging, do not forward EAP frames to other ports, only deliver +them locally. +Fixes WPA authentication issues with multiples APs that are connected to +each other via bridges. +--- +--- a/net/bridge/br_input.c ++++ b/net/bridge/br_input.c +@@ -153,7 +153,11 @@ int br_handle_frame_finish(struct sk_buf + + dst = NULL; + +- if (is_broadcast_ether_addr(dest)) { ++ if (skb->protocol == htons(ETH_P_PAE)) { ++ skb2 = skb; ++ /* Do not forward 802.1x/EAP frames */ ++ skb = NULL; ++ } else if (is_broadcast_ether_addr(dest)) { + if (IS_ENABLED(CONFIG_INET) && + p->flags & BR_PROXYARP && + skb->protocol == htons(ETH_P_ARP)) diff --git a/target/linux/generic/patches-4.0/641-bridge_always_accept_eap.patch b/target/linux/generic/patches-4.0/641-bridge_always_accept_eap.patch new file mode 100644 index 0000000..16deda4 --- /dev/null +++ b/target/linux/generic/patches-4.0/641-bridge_always_accept_eap.patch @@ -0,0 +1,17 @@ +From: Felix Fietkau +Subject: [PATCH] bridge: always accept EAP + +Allow EAP frames to pass through bridges even in learning state. Fixes +issues with WDS. +--- +--- a/net/bridge/br_input.c ++++ b/net/bridge/br_input.c +@@ -140,7 +140,7 @@ int br_handle_frame_finish(struct sk_buf + br_multicast_rcv(br, p, skb, vid)) + goto drop; + +- if (p->state == BR_STATE_LEARNING) ++ if ((p->state == BR_STATE_LEARNING) && skb->protocol != htons(ETH_P_PAE)) + goto drop; + + BR_INPUT_SKB_CB(skb)->brdev = br->dev; diff --git a/target/linux/generic/patches-4.0/642-bridge_port_isolate.patch b/target/linux/generic/patches-4.0/642-bridge_port_isolate.patch new file mode 100644 index 0000000..aacce56 --- /dev/null +++ b/target/linux/generic/patches-4.0/642-bridge_port_isolate.patch @@ -0,0 +1,107 @@ +From: Felix Fietkau +Subject: [PATCH] bridge: port isolate + +Isolating individual bridge ports +--- +--- a/include/linux/if_bridge.h ++++ b/include/linux/if_bridge.h +@@ -44,6 +44,7 @@ struct br_ip_list { + #define BR_PROMISC BIT(7) + #define BR_PROXYARP BIT(8) + #define BR_LEARNING_SYNC BIT(9) ++#define BR_ISOLATE_MODE BIT(10) + + extern void brioctl_set(int (*ioctl_hook)(struct net *, unsigned int, void __user *)); + +--- a/net/bridge/br_sysfs_if.c ++++ b/net/bridge/br_sysfs_if.c +@@ -172,6 +172,22 @@ BRPORT_ATTR_FLAG(learning, BR_LEARNING); + BRPORT_ATTR_FLAG(unicast_flood, BR_FLOOD); + BRPORT_ATTR_FLAG(proxyarp, BR_PROXYARP); + ++static ssize_t show_isolate_mode(struct net_bridge_port *p, char *buf) ++{ ++ int isolate_mode = (p->flags & BR_ISOLATE_MODE) ? 1 : 0; ++ return sprintf(buf, "%d\n", isolate_mode); ++} ++static ssize_t store_isolate_mode(struct net_bridge_port *p, unsigned long v) ++{ ++ if (v) ++ p->flags |= BR_ISOLATE_MODE; ++ else ++ p->flags &= ~BR_ISOLATE_MODE; ++ return 0; ++} ++static BRPORT_ATTR(isolate_mode, S_IRUGO | S_IWUSR, ++ show_isolate_mode, store_isolate_mode); ++ + #ifdef CONFIG_BRIDGE_IGMP_SNOOPING + static ssize_t show_multicast_router(struct net_bridge_port *p, char *buf) + { +@@ -215,6 +231,7 @@ static const struct brport_attribute *br + &brport_attr_multicast_fast_leave, + #endif + &brport_attr_proxyarp, ++ &brport_attr_isolate_mode, + NULL + }; + +--- a/net/bridge/br_input.c ++++ b/net/bridge/br_input.c +@@ -181,8 +181,8 @@ int br_handle_frame_finish(struct sk_buf + + unicast = false; + br->dev->stats.multicast++; +- } else if ((dst = __br_fdb_get(br, dest, vid)) && +- dst->is_local) { ++ } else if ((p->flags & BR_ISOLATE_MODE) || ++ ((dst = __br_fdb_get(br, dest, vid)) && dst->is_local)) { + skb2 = skb; + /* Do not forward the packet since it's local. */ + skb = NULL; +--- a/net/bridge/br_forward.c ++++ b/net/bridge/br_forward.c +@@ -117,7 +117,7 @@ EXPORT_SYMBOL_GPL(br_deliver); + /* called with rcu_read_lock */ + void br_forward(const struct net_bridge_port *to, struct sk_buff *skb, struct sk_buff *skb0) + { +- if (should_deliver(to, skb)) { ++ if (should_deliver(to, skb) && !(to->flags & BR_ISOLATE_MODE)) { + if (skb0) + deliver_clone(to, skb, __br_forward); + else +@@ -173,7 +173,7 @@ static void br_flood(struct net_bridge * + struct sk_buff *skb0, + void (*__packet_hook)(const struct net_bridge_port *p, + struct sk_buff *skb), +- bool unicast) ++ bool unicast, bool forward) + { + struct net_bridge_port *p; + struct net_bridge_port *prev; +@@ -181,6 +181,8 @@ static void br_flood(struct net_bridge * + prev = NULL; + + list_for_each_entry_rcu(p, &br->port_list, list) { ++ if (forward && (p->flags & BR_ISOLATE_MODE)) ++ continue; + /* Do not flood unicast traffic to ports that turn it off */ + if (unicast && !(p->flags & BR_FLOOD)) + continue; +@@ -212,14 +214,14 @@ out: + /* called with rcu_read_lock */ + void br_flood_deliver(struct net_bridge *br, struct sk_buff *skb, bool unicast) + { +- br_flood(br, skb, NULL, __br_deliver, unicast); ++ br_flood(br, skb, NULL, __br_deliver, unicast, false); + } + + /* called under bridge lock */ + void br_flood_forward(struct net_bridge *br, struct sk_buff *skb, + struct sk_buff *skb2, bool unicast) + { +- br_flood(br, skb, skb2, __br_forward, unicast); ++ br_flood(br, skb, skb2, __br_forward, unicast, true); + } + + #ifdef CONFIG_BRIDGE_IGMP_SNOOPING diff --git a/target/linux/generic/patches-4.0/643-bridge_remove_ipv6_dependency.patch b/target/linux/generic/patches-4.0/643-bridge_remove_ipv6_dependency.patch new file mode 100644 index 0000000..6842d97 --- /dev/null +++ b/target/linux/generic/patches-4.0/643-bridge_remove_ipv6_dependency.patch @@ -0,0 +1,123 @@ +From: Jonas Gorski +Subject: [PATCH] bridge: remove IPv6 depependency of bridge in 2.6.38+ + +Since 2.6.38 the bridge module has a dependency to IPv6 if IPv6 is +enabled. Since the IPv6 module isn't exactly lightweight and bridge also +only needs a single function from IPv6, it's rather easy to create a +common "lib" module with a RCU pointer to the actual implementation, if +the IPv6 module is loaded (although slightly hackish). + +The codepath seems to be only taken when using IPv6, so there should be +no negative side effects when IPv6 isn't loaded. I did not measure how +big the performance impact is. +--- +--- a/include/net/addrconf.h ++++ b/include/net/addrconf.h +@@ -91,6 +91,12 @@ int ipv6_rcv_saddr_equal(const struct so + void addrconf_join_solict(struct net_device *dev, const struct in6_addr *addr); + void addrconf_leave_solict(struct inet6_dev *idev, const struct in6_addr *addr); + ++extern int (*ipv6_dev_get_saddr_hook)(struct net *net, ++ const struct net_device *dev, ++ const struct in6_addr *daddr, ++ unsigned int prefs, ++ struct in6_addr *saddr); ++ + static inline unsigned long addrconf_timeout_fixup(u32 timeout, + unsigned int unit) + { +--- a/net/bridge/Kconfig ++++ b/net/bridge/Kconfig +@@ -6,7 +6,6 @@ config BRIDGE + tristate "802.1d Ethernet Bridging" + select LLC + select STP +- depends on IPV6 || IPV6=n + ---help--- + If you say Y here, then your Linux box will be able to act as an + Ethernet bridge, which means that the different Ethernet segments it +--- a/net/ipv6/Makefile ++++ b/net/ipv6/Makefile +@@ -45,6 +45,7 @@ obj-y += addrconf_core.o exthdrs_core.o + obj-$(CONFIG_INET) += output_core.o protocol.o $(ipv6-offload) + + obj-$(subst m,y,$(CONFIG_IPV6)) += inet6_hashtables.o ++obj-$(subst m,y,$(CONFIG_IPV6)) += inet6_stubs.o + + ifneq ($(CONFIG_IPV6),) + obj-$(CONFIG_NET_UDP_TUNNEL) += ip6_udp_tunnel.o +--- a/net/ipv6/addrconf.c ++++ b/net/ipv6/addrconf.c +@@ -1346,7 +1346,7 @@ out: + return ret; + } + +-int ipv6_dev_get_saddr(struct net *net, const struct net_device *dst_dev, ++static int __ipv6_dev_get_saddr(struct net *net, const struct net_device *dst_dev, + const struct in6_addr *daddr, unsigned int prefs, + struct in6_addr *saddr) + { +@@ -1469,7 +1469,6 @@ try_nextdev: + in6_ifa_put(hiscore->ifa); + return 0; + } +-EXPORT_SYMBOL(ipv6_dev_get_saddr); + + int __ipv6_get_lladdr(struct inet6_dev *idev, struct in6_addr *addr, + u32 banned_flags) +@@ -5539,6 +5538,9 @@ int __init addrconf_init(void) + + ipv6_addr_label_rtnl_register(); + ++ BUG_ON(ipv6_dev_get_saddr_hook != NULL); ++ rcu_assign_pointer(ipv6_dev_get_saddr_hook, __ipv6_dev_get_saddr); ++ + return 0; + errout: + rtnl_af_unregister(&inet6_ops); +@@ -5558,6 +5560,9 @@ void addrconf_cleanup(void) + struct net_device *dev; + int i; + ++ rcu_assign_pointer(ipv6_dev_get_saddr_hook, NULL); ++ synchronize_rcu(); ++ + unregister_netdevice_notifier(&ipv6_dev_notf); + unregister_pernet_subsys(&addrconf_ops); + ipv6_addr_label_cleanup(); +--- /dev/null ++++ b/net/ipv6/inet6_stubs.c +@@ -0,0 +1,33 @@ ++/* ++ * 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. ++ */ ++#include ++#include ++ ++int (*ipv6_dev_get_saddr_hook)(struct net *net, const struct net_device *dev, ++ const struct in6_addr *daddr, unsigned int prefs, ++ struct in6_addr *saddr); ++ ++EXPORT_SYMBOL(ipv6_dev_get_saddr_hook); ++ ++int ipv6_dev_get_saddr(struct net *net, const struct net_device *dst_dev, ++ const struct in6_addr *daddr, unsigned int prefs, ++ struct in6_addr *saddr) ++{ ++ int ret = -EADDRNOTAVAIL; ++ typeof(ipv6_dev_get_saddr_hook) dev_get_saddr; ++ ++ rcu_read_lock(); ++ dev_get_saddr = rcu_dereference(ipv6_dev_get_saddr_hook); ++ ++ if (dev_get_saddr) ++ ret = dev_get_saddr(net, dst_dev, daddr, prefs, saddr); ++ ++ rcu_read_unlock(); ++ return ret; ++} ++EXPORT_SYMBOL(ipv6_dev_get_saddr); ++ diff --git a/target/linux/generic/patches-4.0/645-bridge_multicast_to_unicast.patch b/target/linux/generic/patches-4.0/645-bridge_multicast_to_unicast.patch new file mode 100644 index 0000000..a8e22c4 --- /dev/null +++ b/target/linux/generic/patches-4.0/645-bridge_multicast_to_unicast.patch @@ -0,0 +1,383 @@ +From: Felix Fietkau +Subject: [PATCH] bridge: multicast to unicast + +Implement optinal multicast->unicast conversion for igmp snooping +--- +--- a/include/linux/if_bridge.h ++++ b/include/linux/if_bridge.h +@@ -45,6 +45,7 @@ struct br_ip_list { + #define BR_PROXYARP BIT(8) + #define BR_LEARNING_SYNC BIT(9) + #define BR_ISOLATE_MODE BIT(10) ++#define BR_MULTICAST_TO_UCAST BIT(11) + + extern void brioctl_set(int (*ioctl_hook)(struct net *, unsigned int, void __user *)); + +--- a/net/bridge/br_multicast.c ++++ b/net/bridge/br_multicast.c +@@ -635,7 +635,8 @@ struct net_bridge_port_group *br_multica + struct net_bridge_port *port, + struct br_ip *group, + struct net_bridge_port_group __rcu *next, +- unsigned char state) ++ unsigned char state, ++ const unsigned char *src) + { + struct net_bridge_port_group *p; + +@@ -650,12 +651,33 @@ struct net_bridge_port_group *br_multica + hlist_add_head(&p->mglist, &port->mglist); + setup_timer(&p->timer, br_multicast_port_group_expired, + (unsigned long)p); ++ if ((port->flags & BR_MULTICAST_TO_UCAST) && src) { ++ memcpy(p->eth_addr, src, ETH_ALEN); ++ p->unicast = true; ++ } + return p; + } + ++static bool br_port_group_equal(struct net_bridge_port_group *p, ++ struct net_bridge_port *port, ++ const unsigned char *src) ++{ ++ if (p->port != port) ++ return false; ++ ++ if (!p->unicast) ++ return true; ++ ++ if (!src) ++ return false; ++ ++ return ether_addr_equal(src, p->eth_addr); ++} ++ + static int br_multicast_add_group(struct net_bridge *br, + struct net_bridge_port *port, +- struct br_ip *group) ++ struct br_ip *group, ++ const unsigned char *src) + { + struct net_bridge_mdb_entry *mp; + struct net_bridge_port_group *p; +@@ -682,13 +704,13 @@ static int br_multicast_add_group(struct + for (pp = &mp->ports; + (p = mlock_dereference(*pp, br)) != NULL; + pp = &p->next) { +- if (p->port == port) ++ if (br_port_group_equal(p, port, src)) + goto found; + if ((unsigned long)p->port < (unsigned long)port) + break; + } + +- p = br_multicast_new_port_group(port, group, *pp, MDB_TEMPORARY); ++ p = br_multicast_new_port_group(port, group, *pp, MDB_TEMPORARY, src); + if (unlikely(!p)) + goto err; + rcu_assign_pointer(*pp, p); +@@ -707,7 +729,7 @@ err: + static int br_ip4_multicast_add_group(struct net_bridge *br, + struct net_bridge_port *port, + __be32 group, +- __u16 vid) ++ __u16 vid, const unsigned char *src) + { + struct br_ip br_group; + +@@ -718,14 +740,14 @@ static int br_ip4_multicast_add_group(st + br_group.proto = htons(ETH_P_IP); + br_group.vid = vid; + +- return br_multicast_add_group(br, port, &br_group); ++ return br_multicast_add_group(br, port, &br_group, src); + } + + #if IS_ENABLED(CONFIG_IPV6) + static int br_ip6_multicast_add_group(struct net_bridge *br, + struct net_bridge_port *port, + const struct in6_addr *group, +- __u16 vid) ++ __u16 vid, const unsigned char *src) + { + struct br_ip br_group; + +@@ -736,7 +758,10 @@ static int br_ip6_multicast_add_group(st + br_group.proto = htons(ETH_P_IPV6); + br_group.vid = vid; + +- return br_multicast_add_group(br, port, &br_group); ++ if (ipv6_addr_is_solict_mult(group)) ++ src = NULL; ++ ++ return br_multicast_add_group(br, port, &br_group, src); + } + #endif + +@@ -965,6 +990,7 @@ static int br_ip4_multicast_igmp3_report + struct sk_buff *skb, + u16 vid) + { ++ const unsigned char *src = eth_hdr(skb)->h_source; + struct igmpv3_report *ih; + struct igmpv3_grec *grec; + int i; +@@ -1008,7 +1034,7 @@ static int br_ip4_multicast_igmp3_report + continue; + } + +- err = br_ip4_multicast_add_group(br, port, group, vid); ++ err = br_ip4_multicast_add_group(br, port, group, vid, src); + if (err) + break; + } +@@ -1022,6 +1048,7 @@ static int br_ip6_multicast_mld2_report( + struct sk_buff *skb, + u16 vid) + { ++ const unsigned char *src = eth_hdr(skb)->h_source; + struct icmp6hdr *icmp6h; + struct mld2_grec *grec; + int i; +@@ -1070,7 +1097,7 @@ static int br_ip6_multicast_mld2_report( + } + + err = br_ip6_multicast_add_group(br, port, &grec->grec_mca, +- vid); ++ vid, src); + if (err) + break; + } +@@ -1406,7 +1433,8 @@ br_multicast_leave_group(struct net_brid + struct net_bridge_port *port, + struct br_ip *group, + struct bridge_mcast_other_query *other_query, +- struct bridge_mcast_own_query *own_query) ++ struct bridge_mcast_own_query *own_query, ++ const unsigned char *src) + { + struct net_bridge_mdb_htable *mdb; + struct net_bridge_mdb_entry *mp; +@@ -1456,7 +1484,7 @@ br_multicast_leave_group(struct net_brid + for (pp = &mp->ports; + (p = mlock_dereference(*pp, br)) != NULL; + pp = &p->next) { +- if (p->port != port) ++ if (!br_port_group_equal(p, port, src)) + continue; + + rcu_assign_pointer(*pp, p->next); +@@ -1490,7 +1518,7 @@ br_multicast_leave_group(struct net_brid + for (p = mlock_dereference(mp->ports, br); + p != NULL; + p = mlock_dereference(p->next, br)) { +- if (p->port != port) ++ if (!br_port_group_equal(p, port, src)) + continue; + + if (!hlist_unhashed(&p->mglist) && +@@ -1508,8 +1536,8 @@ out: + + static void br_ip4_multicast_leave_group(struct net_bridge *br, + struct net_bridge_port *port, +- __be32 group, +- __u16 vid) ++ __be32 group, __u16 vid, ++ const unsigned char *src) + { + struct br_ip br_group; + struct bridge_mcast_own_query *own_query; +@@ -1524,14 +1552,14 @@ static void br_ip4_multicast_leave_group + br_group.vid = vid; + + br_multicast_leave_group(br, port, &br_group, &br->ip4_other_query, +- own_query); ++ own_query, src); + } + + #if IS_ENABLED(CONFIG_IPV6) + static void br_ip6_multicast_leave_group(struct net_bridge *br, + struct net_bridge_port *port, + const struct in6_addr *group, +- __u16 vid) ++ __u16 vid, const unsigned char *src) + { + struct br_ip br_group; + struct bridge_mcast_own_query *own_query; +@@ -1546,7 +1574,7 @@ static void br_ip6_multicast_leave_group + br_group.vid = vid; + + br_multicast_leave_group(br, port, &br_group, &br->ip6_other_query, +- own_query); ++ own_query, src); + } + #endif + +@@ -1555,6 +1583,7 @@ static int br_multicast_ipv4_rcv(struct + struct sk_buff *skb, + u16 vid) + { ++ const unsigned char *src = eth_hdr(skb)->h_source; + struct sk_buff *skb2 = skb; + const struct iphdr *iph; + struct igmphdr *ih; +@@ -1628,7 +1657,7 @@ static int br_multicast_ipv4_rcv(struct + case IGMP_HOST_MEMBERSHIP_REPORT: + case IGMPV2_HOST_MEMBERSHIP_REPORT: + BR_INPUT_SKB_CB(skb)->mrouters_only = 1; +- err = br_ip4_multicast_add_group(br, port, ih->group, vid); ++ err = br_ip4_multicast_add_group(br, port, ih->group, vid, src); + break; + case IGMPV3_HOST_MEMBERSHIP_REPORT: + err = br_ip4_multicast_igmp3_report(br, port, skb2, vid); +@@ -1637,7 +1666,7 @@ static int br_multicast_ipv4_rcv(struct + err = br_ip4_multicast_query(br, port, skb2, vid); + break; + case IGMP_HOST_LEAVE_MESSAGE: +- br_ip4_multicast_leave_group(br, port, ih->group, vid); ++ br_ip4_multicast_leave_group(br, port, ih->group, vid, src); + break; + } + +@@ -1655,6 +1684,7 @@ static int br_multicast_ipv6_rcv(struct + struct sk_buff *skb, + u16 vid) + { ++ const unsigned char *src = eth_hdr(skb)->h_source; + struct sk_buff *skb2; + const struct ipv6hdr *ip6h; + u8 icmp6_type; +@@ -1764,7 +1794,8 @@ static int br_multicast_ipv6_rcv(struct + } + mld = (struct mld_msg *)skb_transport_header(skb2); + BR_INPUT_SKB_CB(skb)->mrouters_only = 1; +- err = br_ip6_multicast_add_group(br, port, &mld->mld_mca, vid); ++ err = br_ip6_multicast_add_group(br, port, &mld->mld_mca, vid, ++ src); + break; + } + case ICMPV6_MLD2_REPORT: +@@ -1781,7 +1812,7 @@ static int br_multicast_ipv6_rcv(struct + goto out; + } + mld = (struct mld_msg *)skb_transport_header(skb2); +- br_ip6_multicast_leave_group(br, port, &mld->mld_mca, vid); ++ br_ip6_multicast_leave_group(br, port, &mld->mld_mca, vid, src); + } + } + +--- a/net/bridge/br_private.h ++++ b/net/bridge/br_private.h +@@ -113,6 +113,9 @@ struct net_bridge_port_group { + struct timer_list timer; + struct br_ip addr; + unsigned char state; ++ ++ unsigned char eth_addr[ETH_ALEN]; ++ bool unicast; + }; + + struct net_bridge_mdb_entry +@@ -480,7 +483,8 @@ void br_multicast_free_pg(struct rcu_hea + struct net_bridge_port_group * + br_multicast_new_port_group(struct net_bridge_port *port, struct br_ip *group, + struct net_bridge_port_group __rcu *next, +- unsigned char state); ++ unsigned char state, ++ const unsigned char *src); + void br_mdb_init(void); + void br_mdb_uninit(void); + void br_mdb_notify(struct net_device *dev, struct net_bridge_port *port, +--- a/net/bridge/br_mdb.c ++++ b/net/bridge/br_mdb.c +@@ -343,7 +343,7 @@ static int br_mdb_add_group(struct net_b + break; + } + +- p = br_multicast_new_port_group(port, group, *pp, state); ++ p = br_multicast_new_port_group(port, group, *pp, state, NULL); + if (unlikely(!p)) + return -ENOMEM; + rcu_assign_pointer(*pp, p); +--- a/net/bridge/br_forward.c ++++ b/net/bridge/br_forward.c +@@ -168,6 +168,29 @@ out: + return p; + } + ++static struct net_bridge_port *maybe_deliver_addr( ++ struct net_bridge_port *prev, struct net_bridge_port *p, ++ struct sk_buff *skb, const unsigned char *addr, ++ void (*__packet_hook)(const struct net_bridge_port *p, ++ struct sk_buff *skb)) ++{ ++ struct net_device *dev = BR_INPUT_SKB_CB(skb)->brdev; ++ ++ if (!should_deliver(p, skb)) ++ return prev; ++ ++ skb = skb_copy(skb, GFP_ATOMIC); ++ if (!skb) { ++ dev->stats.tx_dropped++; ++ return prev; ++ } ++ ++ memcpy(eth_hdr(skb)->h_dest, addr, ETH_ALEN); ++ __packet_hook(p, skb); ++ ++ return prev; ++} ++ + /* called under bridge lock */ + static void br_flood(struct net_bridge *br, struct sk_buff *skb, + struct sk_buff *skb0, +@@ -237,6 +260,7 @@ static void br_multicast_flood(struct ne + struct net_bridge_port *prev = NULL; + struct net_bridge_port_group *p; + struct hlist_node *rp; ++ const unsigned char *addr; + + rp = rcu_dereference(hlist_first_rcu(&br->router_list)); + p = mdst ? rcu_dereference(mdst->ports) : NULL; +@@ -247,10 +271,19 @@ static void br_multicast_flood(struct ne + rport = rp ? hlist_entry(rp, struct net_bridge_port, rlist) : + NULL; + +- port = (unsigned long)lport > (unsigned long)rport ? +- lport : rport; +- +- prev = maybe_deliver(prev, port, skb, __packet_hook); ++ if ((unsigned long)lport > (unsigned long)rport) { ++ port = lport; ++ addr = p->unicast ? p->eth_addr : NULL; ++ } else { ++ port = rport; ++ addr = NULL; ++ } ++ ++ if (addr) ++ prev = maybe_deliver_addr(prev, port, skb, addr, ++ __packet_hook); ++ else ++ prev = maybe_deliver(prev, port, skb, __packet_hook); + if (IS_ERR(prev)) + goto out; + +--- a/net/bridge/br_sysfs_if.c ++++ b/net/bridge/br_sysfs_if.c +@@ -203,6 +203,7 @@ static BRPORT_ATTR(multicast_router, S_I + store_multicast_router); + + BRPORT_ATTR_FLAG(multicast_fast_leave, BR_MULTICAST_FAST_LEAVE); ++BRPORT_ATTR_FLAG(multicast_to_unicast, BR_MULTICAST_TO_UCAST); + #endif + + static const struct brport_attribute *brport_attrs[] = { +@@ -229,6 +230,7 @@ static const struct brport_attribute *br + #ifdef CONFIG_BRIDGE_IGMP_SNOOPING + &brport_attr_multicast_router, + &brport_attr_multicast_fast_leave, ++ &brport_attr_multicast_to_unicast, + #endif + &brport_attr_proxyarp, + &brport_attr_isolate_mode, diff --git a/target/linux/generic/patches-4.0/650-pppoe_header_pad.patch b/target/linux/generic/patches-4.0/650-pppoe_header_pad.patch new file mode 100644 index 0000000..3b4978b --- /dev/null +++ b/target/linux/generic/patches-4.0/650-pppoe_header_pad.patch @@ -0,0 +1,20 @@ +--- a/drivers/net/ppp/pppoe.c ++++ b/drivers/net/ppp/pppoe.c +@@ -869,7 +869,7 @@ static int pppoe_sendmsg(struct kiocb *i + goto end; + + +- skb = sock_wmalloc(sk, total_len + dev->hard_header_len + 32, ++ skb = sock_wmalloc(sk, total_len + dev->hard_header_len + 32 + NET_SKB_PAD, + 0, GFP_KERNEL); + if (!skb) { + error = -ENOMEM; +@@ -877,7 +877,7 @@ static int pppoe_sendmsg(struct kiocb *i + } + + /* Reserve space for headers. */ +- skb_reserve(skb, dev->hard_header_len); ++ skb_reserve(skb, dev->hard_header_len + NET_SKB_PAD); + skb_reset_network_header(skb); + + skb->dev = dev; diff --git a/target/linux/generic/patches-4.0/651-wireless_mesh_header.patch b/target/linux/generic/patches-4.0/651-wireless_mesh_header.patch new file mode 100644 index 0000000..17bcb6d --- /dev/null +++ b/target/linux/generic/patches-4.0/651-wireless_mesh_header.patch @@ -0,0 +1,11 @@ +--- a/include/linux/netdevice.h ++++ b/include/linux/netdevice.h +@@ -133,7 +133,7 @@ static inline bool dev_xmit_complete(int + */ + + #if defined(CONFIG_WLAN) || IS_ENABLED(CONFIG_AX25) +-# if defined(CONFIG_MAC80211_MESH) ++# if 1 || defined(CONFIG_MAC80211_MESH) + # define LL_MAX_HEADER 128 + # else + # define LL_MAX_HEADER 96 diff --git a/target/linux/generic/patches-4.0/653-disable_netlink_trim.patch b/target/linux/generic/patches-4.0/653-disable_netlink_trim.patch new file mode 100644 index 0000000..02ab826 --- /dev/null +++ b/target/linux/generic/patches-4.0/653-disable_netlink_trim.patch @@ -0,0 +1,30 @@ +--- a/net/netlink/af_netlink.c ++++ b/net/netlink/af_netlink.c +@@ -1713,27 +1713,7 @@ void netlink_detachskb(struct sock *sk, + + static struct sk_buff *netlink_trim(struct sk_buff *skb, gfp_t allocation) + { +- int delta; +- + WARN_ON(skb->sk != NULL); +- if (netlink_skb_is_mmaped(skb)) +- return skb; +- +- delta = skb->end - skb->tail; +- if (is_vmalloc_addr(skb->head) || delta * 2 < skb->truesize) +- return skb; +- +- if (skb_shared(skb)) { +- struct sk_buff *nskb = skb_clone(skb, allocation); +- if (!nskb) +- return skb; +- consume_skb(skb); +- skb = nskb; +- } +- +- if (!pskb_expand_head(skb, 0, -delta, allocation)) +- skb->truesize -= delta; +- + return skb; + } + diff --git a/target/linux/generic/patches-4.0/655-increase_skb_pad.patch b/target/linux/generic/patches-4.0/655-increase_skb_pad.patch new file mode 100644 index 0000000..c4aee07 --- /dev/null +++ b/target/linux/generic/patches-4.0/655-increase_skb_pad.patch @@ -0,0 +1,11 @@ +--- a/include/linux/skbuff.h ++++ b/include/linux/skbuff.h +@@ -2027,7 +2027,7 @@ static inline int pskb_network_may_pull( + * NET_IP_ALIGN(2) + ethernet_header(14) + IP_header(20/40) + ports(8) + */ + #ifndef NET_SKB_PAD +-#define NET_SKB_PAD max(32, L1_CACHE_BYTES) ++#define NET_SKB_PAD max(64, L1_CACHE_BYTES) + #endif + + int ___pskb_trim(struct sk_buff *skb, unsigned int len); diff --git a/target/linux/generic/patches-4.0/656-skb_reduce_truesize-helper.patch b/target/linux/generic/patches-4.0/656-skb_reduce_truesize-helper.patch new file mode 100644 index 0000000..72e5c26 --- /dev/null +++ b/target/linux/generic/patches-4.0/656-skb_reduce_truesize-helper.patch @@ -0,0 +1,41 @@ +From 4593a806e31119c5bd3faa00c7210ad862d515af Mon Sep 17 00:00:00 2001 +From: Dave Taht +Date: Mon, 31 Dec 2012 10:02:21 -0800 +Subject: [PATCH 3/7] skb_reduce_truesize: helper function for shrinking skbs + whenever needed + +On embedded devices in particular, large queues of small packets from the rx +path with a large truesize can exist. Reducing their size can reduce +memory pressure. skb_reduce_truesize is a helper function for doing this, +when needed. +--- + include/linux/skbuff.h | 18 ++++++++++++++++++ + 1 file changed, 18 insertions(+) + +--- a/include/linux/skbuff.h ++++ b/include/linux/skbuff.h +@@ -2072,6 +2072,24 @@ static inline void pskb_trim_unique(stru + BUG_ON(err); + } + ++/* ++ * Caller wants to reduce memory needs before queueing skb ++ * The (expensive) copy should not be be done in fast path. ++ */ ++static inline struct sk_buff *skb_reduce_truesize(struct sk_buff *skb) ++{ ++ if (skb->truesize > 2 * SKB_TRUESIZE(skb->len)) { ++ struct sk_buff *nskb; ++ nskb = skb_copy_expand(skb, skb_headroom(skb), 0, ++ GFP_ATOMIC | __GFP_NOWARN); ++ if (nskb) { ++ __kfree_skb(skb); ++ skb = nskb; ++ } ++ } ++ return skb; ++} ++ + /** + * skb_orphan - orphan a buffer + * @skb: buffer to orphan diff --git a/target/linux/generic/patches-4.0/657-qdisc_reduce_truesize.patch b/target/linux/generic/patches-4.0/657-qdisc_reduce_truesize.patch new file mode 100644 index 0000000..6777eec --- /dev/null +++ b/target/linux/generic/patches-4.0/657-qdisc_reduce_truesize.patch @@ -0,0 +1,63 @@ +From bc9fec2f87d57bdbff30d296605e24504513f65c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Dave=20T=C3=A4ht?= +Date: Mon, 17 Sep 2012 19:20:22 -0700 +Subject: [PATCH 4/7] net: add skb_reduce_truesize support to common qdiscs + +Reduce skb size under load when queues begin to fill on the +commont qdiscs. +--- + net/sched/sch_codel.c | 2 ++ + net/sched/sch_fifo.c | 12 ++++++++---- + net/sched/sch_fq_codel.c | 2 ++ + 3 files changed, 12 insertions(+), 4 deletions(-) + +--- a/net/sched/sch_codel.c ++++ b/net/sched/sch_codel.c +@@ -96,6 +96,8 @@ static int codel_qdisc_enqueue(struct sk + struct codel_sched_data *q; + + if (likely(qdisc_qlen(sch) < sch->limit)) { ++ if(qdisc_qlen(sch) > 128) ++ skb = skb_reduce_truesize(skb); + codel_set_enqueue_time(skb); + return qdisc_enqueue_tail(skb, sch); + } +--- a/net/sched/sch_fifo.c ++++ b/net/sched/sch_fifo.c +@@ -29,17 +29,21 @@ static int bfifo_enqueue(struct sk_buff + + static int pfifo_enqueue(struct sk_buff *skb, struct Qdisc *sch) + { +- if (likely(skb_queue_len(&sch->q) < sch->limit)) ++ if (likely(skb_queue_len(&sch->q) < sch->limit)) { ++ if (skb_queue_len(&sch->q) > 128) ++ skb = skb_reduce_truesize(skb); + return qdisc_enqueue_tail(skb, sch); +- ++ } + return qdisc_reshape_fail(skb, sch); + } + + static int pfifo_tail_enqueue(struct sk_buff *skb, struct Qdisc *sch) + { +- if (likely(skb_queue_len(&sch->q) < sch->limit)) ++ if (likely(skb_queue_len(&sch->q) < sch->limit)) { ++ if (skb_queue_len(&sch->q) > 128) ++ skb = skb_reduce_truesize(skb); + return qdisc_enqueue_tail(skb, sch); +- ++ } + /* queue full, remove one skb to fulfill the limit */ + __qdisc_queue_drop_head(sch, &sch->q); + qdisc_qstats_drop(sch); +--- a/net/sched/sch_fq_codel.c ++++ b/net/sched/sch_fq_codel.c +@@ -185,6 +185,8 @@ static int fq_codel_enqueue(struct sk_bu + return ret; + } + idx--; ++ if (sch->q.qlen > 128) ++ skb = skb_reduce_truesize(skb); + + codel_set_enqueue_time(skb); + flow = &q->flows[idx]; diff --git a/target/linux/generic/patches-4.0/660-fq_codel_defaults.patch b/target/linux/generic/patches-4.0/660-fq_codel_defaults.patch new file mode 100644 index 0000000..f7f4659 --- /dev/null +++ b/target/linux/generic/patches-4.0/660-fq_codel_defaults.patch @@ -0,0 +1,14 @@ +--- a/net/sched/sch_fq_codel.c ++++ b/net/sched/sch_fq_codel.c +@@ -387,9 +387,9 @@ static int fq_codel_init(struct Qdisc *s + struct fq_codel_sched_data *q = qdisc_priv(sch); + int i; + +- sch->limit = 10*1024; ++ sch->limit = 1024; + q->flows_cnt = 1024; +- q->quantum = psched_mtu(qdisc_dev(sch)); ++ q->quantum = 300; + q->perturbation = prandom_u32(); + INIT_LIST_HEAD(&q->new_flows); + INIT_LIST_HEAD(&q->old_flows); diff --git a/target/linux/generic/patches-4.0/661-fq_codel_keep_dropped_stats.patch b/target/linux/generic/patches-4.0/661-fq_codel_keep_dropped_stats.patch new file mode 100644 index 0000000..45a8d68 --- /dev/null +++ b/target/linux/generic/patches-4.0/661-fq_codel_keep_dropped_stats.patch @@ -0,0 +1,10 @@ +--- a/net/sched/sch_fq_codel.c ++++ b/net/sched/sch_fq_codel.c +@@ -198,7 +198,6 @@ static int fq_codel_enqueue(struct sk_bu + list_add_tail(&flow->flowchain, &q->new_flows); + q->new_flow_count++; + flow->deficit = q->quantum; +- flow->dropped = 0; + } + if (++sch->q.qlen <= sch->limit) + return NET_XMIT_SUCCESS; diff --git a/target/linux/generic/patches-4.0/662-use_fq_codel_by_default.patch b/target/linux/generic/patches-4.0/662-use_fq_codel_by_default.patch new file mode 100644 index 0000000..e7b781b --- /dev/null +++ b/target/linux/generic/patches-4.0/662-use_fq_codel_by_default.patch @@ -0,0 +1,75 @@ +--- a/net/sched/Kconfig ++++ b/net/sched/Kconfig +@@ -3,8 +3,9 @@ + # + + menuconfig NET_SCHED +- bool "QoS and/or fair queueing" ++ def_bool y + select NET_SCH_FIFO ++ select NET_SCH_FQ_CODEL + ---help--- + When the kernel has several packets to send out over a network + device, it has to decide which ones to send first, which ones to +--- a/net/sched/sch_fq_codel.c ++++ b/net/sched/sch_fq_codel.c +@@ -592,7 +592,7 @@ static const struct Qdisc_class_ops fq_c + .walk = fq_codel_walk, + }; + +-static struct Qdisc_ops fq_codel_qdisc_ops __read_mostly = { ++struct Qdisc_ops fq_codel_qdisc_ops __read_mostly = { + .cl_ops = &fq_codel_class_ops, + .id = "fq_codel", + .priv_size = sizeof(struct fq_codel_sched_data), +@@ -608,6 +608,7 @@ static struct Qdisc_ops fq_codel_qdisc_o + .dump_stats = fq_codel_dump_stats, + .owner = THIS_MODULE, + }; ++EXPORT_SYMBOL(fq_codel_qdisc_ops); + + static int __init fq_codel_module_init(void) + { +--- a/include/net/sch_generic.h ++++ b/include/net/sch_generic.h +@@ -340,6 +340,7 @@ extern struct Qdisc noop_qdisc; + extern struct Qdisc_ops noop_qdisc_ops; + extern struct Qdisc_ops pfifo_fast_ops; + extern struct Qdisc_ops mq_qdisc_ops; ++extern struct Qdisc_ops fq_codel_qdisc_ops; + extern const struct Qdisc_ops *default_qdisc_ops; + + struct Qdisc_class_common { +--- a/net/sched/sch_generic.c ++++ b/net/sched/sch_generic.c +@@ -737,7 +737,7 @@ static void attach_one_default_qdisc(str + + if (dev->tx_queue_len) { + qdisc = qdisc_create_dflt(dev_queue, +- default_qdisc_ops, TC_H_ROOT); ++ &fq_codel_qdisc_ops, TC_H_ROOT); + if (!qdisc) { + netdev_info(dev, "activation failed\n"); + return; +--- a/net/sched/sch_mq.c ++++ b/net/sched/sch_mq.c +@@ -57,7 +57,7 @@ static int mq_init(struct Qdisc *sch, st + + for (ntx = 0; ntx < dev->num_tx_queues; ntx++) { + dev_queue = netdev_get_tx_queue(dev, ntx); +- qdisc = qdisc_create_dflt(dev_queue, default_qdisc_ops, ++ qdisc = qdisc_create_dflt(dev_queue, &fq_codel_qdisc_ops, + TC_H_MAKE(TC_H_MAJ(sch->handle), + TC_H_MIN(ntx + 1))); + if (qdisc == NULL) +--- a/net/sched/sch_mqprio.c ++++ b/net/sched/sch_mqprio.c +@@ -124,7 +124,7 @@ static int mqprio_init(struct Qdisc *sch + + for (i = 0; i < dev->num_tx_queues; i++) { + dev_queue = netdev_get_tx_queue(dev, i); +- qdisc = qdisc_create_dflt(dev_queue, default_qdisc_ops, ++ qdisc = qdisc_create_dflt(dev_queue, &fq_codel_qdisc_ops, + TC_H_MAKE(TC_H_MAJ(sch->handle), + TC_H_MIN(i + 1))); + if (qdisc == NULL) { diff --git a/target/linux/generic/patches-4.0/663-remove_pfifo_fast.patch b/target/linux/generic/patches-4.0/663-remove_pfifo_fast.patch new file mode 100644 index 0000000..5b26ca3 --- /dev/null +++ b/target/linux/generic/patches-4.0/663-remove_pfifo_fast.patch @@ -0,0 +1,143 @@ +--- a/net/sched/sch_generic.c ++++ b/net/sched/sch_generic.c +@@ -442,140 +442,6 @@ static struct Qdisc noqueue_qdisc = { + .busylock = __SPIN_LOCK_UNLOCKED(noqueue_qdisc.busylock), + }; + +- +-static const u8 prio2band[TC_PRIO_MAX + 1] = { +- 1, 2, 2, 2, 1, 2, 0, 0 , 1, 1, 1, 1, 1, 1, 1, 1 +-}; +- +-/* 3-band FIFO queue: old style, but should be a bit faster than +- generic prio+fifo combination. +- */ +- +-#define PFIFO_FAST_BANDS 3 +- +-/* +- * Private data for a pfifo_fast scheduler containing: +- * - queues for the three band +- * - bitmap indicating which of the bands contain skbs +- */ +-struct pfifo_fast_priv { +- u32 bitmap; +- struct sk_buff_head q[PFIFO_FAST_BANDS]; +-}; +- +-/* +- * Convert a bitmap to the first band number where an skb is queued, where: +- * bitmap=0 means there are no skbs on any band. +- * bitmap=1 means there is an skb on band 0. +- * bitmap=7 means there are skbs on all 3 bands, etc. +- */ +-static const int bitmap2band[] = {-1, 0, 1, 0, 2, 0, 1, 0}; +- +-static inline struct sk_buff_head *band2list(struct pfifo_fast_priv *priv, +- int band) +-{ +- return priv->q + band; +-} +- +-static int pfifo_fast_enqueue(struct sk_buff *skb, struct Qdisc *qdisc) +-{ +- if (skb_queue_len(&qdisc->q) < qdisc_dev(qdisc)->tx_queue_len) { +- int band = prio2band[skb->priority & TC_PRIO_MAX]; +- struct pfifo_fast_priv *priv = qdisc_priv(qdisc); +- struct sk_buff_head *list = band2list(priv, band); +- +- priv->bitmap |= (1 << band); +- qdisc->q.qlen++; +- return __qdisc_enqueue_tail(skb, qdisc, list); +- } +- +- return qdisc_drop(skb, qdisc); +-} +- +-static struct sk_buff *pfifo_fast_dequeue(struct Qdisc *qdisc) +-{ +- struct pfifo_fast_priv *priv = qdisc_priv(qdisc); +- int band = bitmap2band[priv->bitmap]; +- +- if (likely(band >= 0)) { +- struct sk_buff_head *list = band2list(priv, band); +- struct sk_buff *skb = __qdisc_dequeue_head(qdisc, list); +- +- qdisc->q.qlen--; +- if (skb_queue_empty(list)) +- priv->bitmap &= ~(1 << band); +- +- return skb; +- } +- +- return NULL; +-} +- +-static struct sk_buff *pfifo_fast_peek(struct Qdisc *qdisc) +-{ +- struct pfifo_fast_priv *priv = qdisc_priv(qdisc); +- int band = bitmap2band[priv->bitmap]; +- +- if (band >= 0) { +- struct sk_buff_head *list = band2list(priv, band); +- +- return skb_peek(list); +- } +- +- return NULL; +-} +- +-static void pfifo_fast_reset(struct Qdisc *qdisc) +-{ +- int prio; +- struct pfifo_fast_priv *priv = qdisc_priv(qdisc); +- +- for (prio = 0; prio < PFIFO_FAST_BANDS; prio++) +- __qdisc_reset_queue(qdisc, band2list(priv, prio)); +- +- priv->bitmap = 0; +- qdisc->qstats.backlog = 0; +- qdisc->q.qlen = 0; +-} +- +-static int pfifo_fast_dump(struct Qdisc *qdisc, struct sk_buff *skb) +-{ +- struct tc_prio_qopt opt = { .bands = PFIFO_FAST_BANDS }; +- +- memcpy(&opt.priomap, prio2band, TC_PRIO_MAX + 1); +- if (nla_put(skb, TCA_OPTIONS, sizeof(opt), &opt)) +- goto nla_put_failure; +- return skb->len; +- +-nla_put_failure: +- return -1; +-} +- +-static int pfifo_fast_init(struct Qdisc *qdisc, struct nlattr *opt) +-{ +- int prio; +- struct pfifo_fast_priv *priv = qdisc_priv(qdisc); +- +- for (prio = 0; prio < PFIFO_FAST_BANDS; prio++) +- __skb_queue_head_init(band2list(priv, prio)); +- +- /* Can by-pass the queue discipline */ +- qdisc->flags |= TCQ_F_CAN_BYPASS; +- return 0; +-} +- +-struct Qdisc_ops pfifo_fast_ops __read_mostly = { +- .id = "pfifo_fast", +- .priv_size = sizeof(struct pfifo_fast_priv), +- .enqueue = pfifo_fast_enqueue, +- .dequeue = pfifo_fast_dequeue, +- .peek = pfifo_fast_peek, +- .init = pfifo_fast_init, +- .reset = pfifo_fast_reset, +- .dump = pfifo_fast_dump, +- .owner = THIS_MODULE, +-}; +- + static struct lock_class_key qdisc_tx_busylock; + + struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue, diff --git a/target/linux/generic/patches-4.0/664-codel_fix_3_12.patch b/target/linux/generic/patches-4.0/664-codel_fix_3_12.patch new file mode 100644 index 0000000..726c428 --- /dev/null +++ b/target/linux/generic/patches-4.0/664-codel_fix_3_12.patch @@ -0,0 +1,22 @@ +--- a/net/sched/sch_api.c ++++ b/net/sched/sch_api.c +@@ -1947,7 +1947,7 @@ static int __init pktsched_init(void) + return err; + } + +- register_qdisc(&pfifo_fast_ops); ++ register_qdisc(&fq_codel_qdisc_ops); + register_qdisc(&pfifo_qdisc_ops); + register_qdisc(&bfifo_qdisc_ops); + register_qdisc(&pfifo_head_drop_qdisc_ops); +--- a/net/sched/sch_generic.c ++++ b/net/sched/sch_generic.c +@@ -31,7 +31,7 @@ + #include + + /* Qdisc to use by default */ +-const struct Qdisc_ops *default_qdisc_ops = &pfifo_fast_ops; ++const struct Qdisc_ops *default_qdisc_ops = &fq_codel_qdisc_ops; + EXPORT_SYMBOL(default_qdisc_ops); + + /* Main transmission queue. */ diff --git a/target/linux/generic/patches-4.0/666-Add-support-for-MAP-E-FMRs-mesh-mode.patch b/target/linux/generic/patches-4.0/666-Add-support-for-MAP-E-FMRs-mesh-mode.patch new file mode 100644 index 0000000..41454c9 --- /dev/null +++ b/target/linux/generic/patches-4.0/666-Add-support-for-MAP-E-FMRs-mesh-mode.patch @@ -0,0 +1,495 @@ +From 775d6fe74d1eaec2ba387535b068dde2dc89de9e Mon Sep 17 00:00:00 2001 +From: Steven Barth +Date: Thu, 22 May 2014 09:49:05 +0200 +Subject: [PATCH] Add support for MAP-E FMRs (mesh mode) + +MAP-E FMRs (draft-ietf-softwire-map-10) are rules for IPv4-communication +between MAP CEs (mesh mode) without the need to forward such data to a +border relay. This is similar to how 6rd works but for IPv4 over IPv6. + +Signed-off-by: Steven Barth +--- + include/net/ip6_tunnel.h | 13 ++ + include/uapi/linux/if_tunnel.h | 13 ++ + net/ipv6/ip6_tunnel.c | 276 +++++++++++++++++++++++++++++++++++++++-- + 3 files changed, 291 insertions(+), 11 deletions(-) + +--- a/include/net/ip6_tunnel.h ++++ b/include/net/ip6_tunnel.h +@@ -15,6 +15,18 @@ + /* determine capability on a per-packet basis */ + #define IP6_TNL_F_CAP_PER_PACKET 0x40000 + ++/* IPv6 tunnel FMR */ ++struct __ip6_tnl_fmr { ++ struct __ip6_tnl_fmr *next; /* next fmr in list */ ++ struct in6_addr ip6_prefix; ++ struct in_addr ip4_prefix; ++ ++ __u8 ip6_prefix_len; ++ __u8 ip4_prefix_len; ++ __u8 ea_len; ++ __u8 offset; ++}; ++ + struct __ip6_tnl_parm { + char name[IFNAMSIZ]; /* name of tunnel device */ + int link; /* ifindex of underlying L2 interface */ +@@ -25,6 +37,7 @@ struct __ip6_tnl_parm { + __u32 flags; /* tunnel flags */ + struct in6_addr laddr; /* local tunnel end-point address */ + struct in6_addr raddr; /* remote tunnel end-point address */ ++ struct __ip6_tnl_fmr *fmrs; /* FMRs */ + + __be16 i_flags; + __be16 o_flags; +--- a/include/uapi/linux/if_tunnel.h ++++ b/include/uapi/linux/if_tunnel.h +@@ -57,10 +57,23 @@ enum { + IFLA_IPTUN_ENCAP_FLAGS, + IFLA_IPTUN_ENCAP_SPORT, + IFLA_IPTUN_ENCAP_DPORT, ++ IFLA_IPTUN_FMRS, + __IFLA_IPTUN_MAX, + }; + #define IFLA_IPTUN_MAX (__IFLA_IPTUN_MAX - 1) + ++enum { ++ IFLA_IPTUN_FMR_UNSPEC, ++ IFLA_IPTUN_FMR_IP6_PREFIX, ++ IFLA_IPTUN_FMR_IP4_PREFIX, ++ IFLA_IPTUN_FMR_IP6_PREFIX_LEN, ++ IFLA_IPTUN_FMR_IP4_PREFIX_LEN, ++ IFLA_IPTUN_FMR_EA_LEN, ++ IFLA_IPTUN_FMR_OFFSET, ++ __IFLA_IPTUN_FMR_MAX, ++}; ++#define IFLA_IPTUN_FMR_MAX (__IFLA_IPTUN_FMR_MAX - 1) ++ + enum tunnel_encap_types { + TUNNEL_ENCAP_NONE, + TUNNEL_ENCAP_FOU, +--- a/net/ipv6/ip6_tunnel.c ++++ b/net/ipv6/ip6_tunnel.c +@@ -16,6 +16,8 @@ + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * ++ * Changes: ++ * Steven Barth : MAP-E FMR support + */ + + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +@@ -77,11 +79,9 @@ static bool log_ecn_error = true; + module_param(log_ecn_error, bool, 0644); + MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN"); + +-static u32 HASH(const struct in6_addr *addr1, const struct in6_addr *addr2) ++static u32 HASH(const struct in6_addr *addr) + { +- u32 hash = ipv6_addr_hash(addr1) ^ ipv6_addr_hash(addr2); +- +- return hash_32(hash, HASH_SIZE_SHIFT); ++ return hash_32(ipv6_addr_hash(addr), HASH_SIZE_SHIFT); + } + + static int ip6_tnl_dev_init(struct net_device *dev); +@@ -180,27 +180,36 @@ EXPORT_SYMBOL_GPL(ip6_tnl_dst_store); + static struct ip6_tnl * + ip6_tnl_lookup(struct net *net, const struct in6_addr *remote, const struct in6_addr *local) + { +- unsigned int hash = HASH(remote, local); ++ unsigned int hash = HASH(local); + struct ip6_tnl *t; + struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); + struct in6_addr any; ++ struct __ip6_tnl_fmr *fmr; + + for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) { +- if (ipv6_addr_equal(local, &t->parms.laddr) && +- ipv6_addr_equal(remote, &t->parms.raddr) && +- (t->dev->flags & IFF_UP)) ++ if (!ipv6_addr_equal(local, &t->parms.laddr) || ++ !(t->dev->flags & IFF_UP)) ++ continue; ++ ++ if (ipv6_addr_equal(remote, &t->parms.raddr)) + return t; ++ ++ for (fmr = t->parms.fmrs; fmr; fmr = fmr->next) { ++ if (ipv6_prefix_equal(remote, &fmr->ip6_prefix, ++ fmr->ip6_prefix_len)) ++ return t; ++ } + } + + memset(&any, 0, sizeof(any)); +- hash = HASH(&any, local); ++ hash = HASH(local); + for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) { + if (ipv6_addr_equal(local, &t->parms.laddr) && + (t->dev->flags & IFF_UP)) + return t; + } + +- hash = HASH(remote, &any); ++ hash = HASH(&any); + for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) { + if (ipv6_addr_equal(remote, &t->parms.raddr) && + (t->dev->flags & IFF_UP)) +@@ -235,7 +244,7 @@ ip6_tnl_bucket(struct ip6_tnl_net *ip6n, + + if (!ipv6_addr_any(remote) || !ipv6_addr_any(local)) { + prio = 1; +- h = HASH(remote, local); ++ h = HASH(local); + } + return &ip6n->tnls[prio][h]; + } +@@ -405,6 +414,12 @@ ip6_tnl_dev_uninit(struct net_device *de + struct net *net = t->net; + struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); + ++ while (t->parms.fmrs) { ++ struct __ip6_tnl_fmr *next = t->parms.fmrs->next; ++ kfree(t->parms.fmrs); ++ t->parms.fmrs = next; ++ } ++ + if (dev == ip6n->fb_tnl_dev) + RCU_INIT_POINTER(ip6n->tnls_wc[0], NULL); + else +@@ -791,6 +806,108 @@ int ip6_tnl_rcv_ctl(struct ip6_tnl *t, + } + EXPORT_SYMBOL_GPL(ip6_tnl_rcv_ctl); + ++ ++/** ++ * ip4ip6_fmr_calc - calculate target / source IPv6-address based on FMR ++ * @dest: destination IPv6 address buffer ++ * @skb: received socket buffer ++ * @fmr: MAP FMR ++ * @xmit: Calculate for xmit or rcv ++ **/ ++static void ip4ip6_fmr_calc(struct in6_addr *dest, ++ const struct iphdr *iph, const uint8_t *end, ++ const struct __ip6_tnl_fmr *fmr, bool xmit) ++{ ++ int psidlen = fmr->ea_len - (32 - fmr->ip4_prefix_len); ++ u8 *portp = NULL; ++ bool use_dest_addr; ++ const struct iphdr *dsth = iph; ++ ++ if ((u8*)dsth >= end) ++ return; ++ ++ /* find significant IP header */ ++ if (iph->protocol == IPPROTO_ICMP) { ++ struct icmphdr *ih = (struct icmphdr*)(((u8*)dsth) + dsth->ihl * 4); ++ if (ih && ((u8*)&ih[1]) <= end && ( ++ ih->type == ICMP_DEST_UNREACH || ++ ih->type == ICMP_SOURCE_QUENCH || ++ ih->type == ICMP_TIME_EXCEEDED || ++ ih->type == ICMP_PARAMETERPROB || ++ ih->type == ICMP_REDIRECT)) ++ dsth = (const struct iphdr*)&ih[1]; ++ } ++ ++ /* in xmit-path use dest port by default and source port only if ++ this is an ICMP reply to something else; vice versa in rcv-path */ ++ use_dest_addr = (xmit && dsth == iph) || (!xmit && dsth != iph); ++ ++ /* get dst port */ ++ if (((u8*)&dsth[1]) <= end && ( ++ dsth->protocol == IPPROTO_UDP || ++ dsth->protocol == IPPROTO_TCP || ++ dsth->protocol == IPPROTO_SCTP || ++ dsth->protocol == IPPROTO_DCCP)) { ++ /* for UDP, TCP, SCTP and DCCP source and dest port ++ follow IPv4 header directly */ ++ portp = ((u8*)dsth) + dsth->ihl * 4; ++ ++ if (use_dest_addr) ++ portp += sizeof(u16); ++ } else if (iph->protocol == IPPROTO_ICMP) { ++ struct icmphdr *ih = (struct icmphdr*)(((u8*)dsth) + dsth->ihl * 4); ++ ++ /* use icmp identifier as port */ ++ if (((u8*)&ih) <= end && ( ++ (use_dest_addr && ( ++ ih->type == ICMP_ECHOREPLY || ++ ih->type == ICMP_TIMESTAMPREPLY || ++ ih->type == ICMP_INFO_REPLY || ++ ih->type == ICMP_ADDRESSREPLY)) || ++ (!use_dest_addr && ( ++ ih->type == ICMP_ECHO || ++ ih->type == ICMP_TIMESTAMP || ++ ih->type == ICMP_INFO_REQUEST || ++ ih->type == ICMP_ADDRESS) ++ ))) ++ portp = (u8*)&ih->un.echo.id; ++ } ++ ++ if ((portp && &portp[2] <= end) || psidlen == 0) { ++ int frombyte = fmr->ip6_prefix_len / 8; ++ int fromrem = fmr->ip6_prefix_len % 8; ++ int bytes = sizeof(struct in6_addr) - frombyte; ++ const u32 *addr = (use_dest_addr) ? &iph->daddr : &iph->saddr; ++ u64 eabits = ((u64)ntohl(*addr)) << (32 + fmr->ip4_prefix_len); ++ u64 t = 0; ++ ++ /* extract PSID from port and add it to eabits */ ++ u16 psidbits = 0; ++ if (psidlen > 0) { ++ psidbits = ((u16)portp[0]) << 8 | ((u16)portp[1]); ++ psidbits >>= 16 - psidlen - fmr->offset; ++ psidbits = (u16)(psidbits << (16 - psidlen)); ++ eabits |= ((u64)psidbits) << (48 - (fmr->ea_len - psidlen)); ++ } ++ ++ /* rewrite destination address */ ++ *dest = fmr->ip6_prefix; ++ memcpy(&dest->s6_addr[10], addr, sizeof(*addr)); ++ dest->s6_addr16[7] = htons(psidbits >> (16 - psidlen)); ++ ++ if (bytes > sizeof(u64)) ++ bytes = sizeof(u64); ++ ++ /* insert eabits */ ++ memcpy(&t, &dest->s6_addr[frombyte], bytes); ++ t = be64_to_cpu(t) & ~(((((u64)1) << fmr->ea_len) - 1) ++ << (64 - fmr->ea_len - fromrem)); ++ t = cpu_to_be64(t | (eabits >> fromrem)); ++ memcpy(&dest->s6_addr[frombyte], &t, bytes); ++ } ++} ++ ++ + /** + * ip6_tnl_rcv - decapsulate IPv6 packet and retransmit it locally + * @skb: received socket buffer +@@ -836,6 +953,26 @@ static int ip6_tnl_rcv(struct sk_buff *s + skb_reset_network_header(skb); + skb->protocol = htons(protocol); + memset(skb->cb, 0, sizeof(struct inet6_skb_parm)); ++ if (protocol == ETH_P_IP && ++ !ipv6_addr_equal(&ipv6h->saddr, &t->parms.raddr)) { ++ /* Packet didn't come from BR, so lookup FMR */ ++ struct __ip6_tnl_fmr *fmr; ++ struct in6_addr expected = t->parms.raddr; ++ for (fmr = t->parms.fmrs; fmr; fmr = fmr->next) ++ if (ipv6_prefix_equal(&ipv6h->saddr, ++ &fmr->ip6_prefix, fmr->ip6_prefix_len)) ++ break; ++ ++ /* Check that IPv6 matches IPv4 source to prevent spoofing */ ++ if (fmr) ++ ip4ip6_fmr_calc(&expected, ip_hdr(skb), ++ skb_tail_pointer(skb), fmr, false); ++ ++ if (!ipv6_addr_equal(&ipv6h->saddr, &expected)) { ++ rcu_read_unlock(); ++ goto discard; ++ } ++ } + + __skb_tunnel_rx(skb, t->dev, t->net); + +@@ -1129,6 +1266,7 @@ ip4ip6_tnl_xmit(struct sk_buff *skb, str + __u32 mtu; + u8 tproto; + int err; ++ struct __ip6_tnl_fmr *fmr; + + tproto = ACCESS_ONCE(t->parms.proto); + if (tproto != IPPROTO_IPIP && tproto != 0) +@@ -1148,6 +1286,18 @@ ip4ip6_tnl_xmit(struct sk_buff *skb, str + if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK) + fl6.flowi6_mark = skb->mark; + ++ /* try to find matching FMR */ ++ for (fmr = t->parms.fmrs; fmr; fmr = fmr->next) { ++ unsigned mshift = 32 - fmr->ip4_prefix_len; ++ if (ntohl(fmr->ip4_prefix.s_addr) >> mshift == ++ ntohl(iph->daddr) >> mshift) ++ break; ++ } ++ ++ /* change dstaddr according to FMR */ ++ if (fmr) ++ ip4ip6_fmr_calc(&fl6.daddr, iph, skb_tail_pointer(skb), fmr, true); ++ + err = ip6_tnl_xmit2(skb, dev, dsfield, &fl6, encap_limit, &mtu); + if (err != 0) { + /* XXX: send ICMP error even if DF is not set. */ +@@ -1318,6 +1468,14 @@ ip6_tnl_change(struct ip6_tnl *t, const + t->parms.flowinfo = p->flowinfo; + t->parms.link = p->link; + t->parms.proto = p->proto; ++ ++ while (t->parms.fmrs) { ++ struct __ip6_tnl_fmr *next = t->parms.fmrs->next; ++ kfree(t->parms.fmrs); ++ t->parms.fmrs = next; ++ } ++ t->parms.fmrs = p->fmrs; ++ + ip6_tnl_dst_reset(t); + ip6_tnl_link_config(t); + return 0; +@@ -1356,6 +1514,7 @@ ip6_tnl_parm_from_user(struct __ip6_tnl_ + p->flowinfo = u->flowinfo; + p->link = u->link; + p->proto = u->proto; ++ p->fmrs = NULL; + memcpy(p->name, u->name, sizeof(u->name)); + } + +@@ -1634,6 +1793,15 @@ static int ip6_tnl_validate(struct nlatt + return 0; + } + ++static const struct nla_policy ip6_tnl_fmr_policy[IFLA_IPTUN_FMR_MAX + 1] = { ++ [IFLA_IPTUN_FMR_IP6_PREFIX] = { .len = sizeof(struct in6_addr) }, ++ [IFLA_IPTUN_FMR_IP4_PREFIX] = { .len = sizeof(struct in_addr) }, ++ [IFLA_IPTUN_FMR_IP6_PREFIX_LEN] = { .type = NLA_U8 }, ++ [IFLA_IPTUN_FMR_IP4_PREFIX_LEN] = { .type = NLA_U8 }, ++ [IFLA_IPTUN_FMR_EA_LEN] = { .type = NLA_U8 }, ++ [IFLA_IPTUN_FMR_OFFSET] = { .type = NLA_U8 } ++}; ++ + static void ip6_tnl_netlink_parms(struct nlattr *data[], + struct __ip6_tnl_parm *parms) + { +@@ -1667,6 +1835,46 @@ static void ip6_tnl_netlink_parms(struct + + if (data[IFLA_IPTUN_PROTO]) + parms->proto = nla_get_u8(data[IFLA_IPTUN_PROTO]); ++ ++ if (data[IFLA_IPTUN_FMRS]) { ++ unsigned rem; ++ struct nlattr *fmr; ++ nla_for_each_nested(fmr, data[IFLA_IPTUN_FMRS], rem) { ++ struct nlattr *fmrd[IFLA_IPTUN_FMR_MAX + 1], *c; ++ struct __ip6_tnl_fmr *nfmr; ++ ++ nla_parse_nested(fmrd, IFLA_IPTUN_FMR_MAX, ++ fmr, ip6_tnl_fmr_policy); ++ ++ if (!(nfmr = kzalloc(sizeof(*nfmr), GFP_KERNEL))) ++ continue; ++ ++ nfmr->offset = 6; ++ ++ if ((c = fmrd[IFLA_IPTUN_FMR_IP6_PREFIX])) ++ nla_memcpy(&nfmr->ip6_prefix, fmrd[IFLA_IPTUN_FMR_IP6_PREFIX], ++ sizeof(nfmr->ip6_prefix)); ++ ++ if ((c = fmrd[IFLA_IPTUN_FMR_IP4_PREFIX])) ++ nla_memcpy(&nfmr->ip4_prefix, fmrd[IFLA_IPTUN_FMR_IP4_PREFIX], ++ sizeof(nfmr->ip4_prefix)); ++ ++ if ((c = fmrd[IFLA_IPTUN_FMR_IP6_PREFIX_LEN])) ++ nfmr->ip6_prefix_len = nla_get_u8(c); ++ ++ if ((c = fmrd[IFLA_IPTUN_FMR_IP4_PREFIX_LEN])) ++ nfmr->ip4_prefix_len = nla_get_u8(c); ++ ++ if ((c = fmrd[IFLA_IPTUN_FMR_EA_LEN])) ++ nfmr->ea_len = nla_get_u8(c); ++ ++ if ((c = fmrd[IFLA_IPTUN_FMR_OFFSET])) ++ nfmr->offset = nla_get_u8(c); ++ ++ nfmr->next = parms->fmrs; ++ parms->fmrs = nfmr; ++ } ++ } + } + + static int ip6_tnl_newlink(struct net *src_net, struct net_device *dev, +@@ -1719,6 +1927,12 @@ static void ip6_tnl_dellink(struct net_d + + static size_t ip6_tnl_get_size(const struct net_device *dev) + { ++ const struct ip6_tnl *t = netdev_priv(dev); ++ struct __ip6_tnl_fmr *c; ++ int fmrs = 0; ++ for (c = t->parms.fmrs; c; c = c->next) ++ ++fmrs; ++ + return + /* IFLA_IPTUN_LINK */ + nla_total_size(4) + +@@ -1736,6 +1950,24 @@ static size_t ip6_tnl_get_size(const str + nla_total_size(4) + + /* IFLA_IPTUN_PROTO */ + nla_total_size(1) + ++ /* IFLA_IPTUN_FMRS */ ++ nla_total_size(0) + ++ ( ++ /* nest */ ++ nla_total_size(0) + ++ /* IFLA_IPTUN_FMR_IP6_PREFIX */ ++ nla_total_size(sizeof(struct in6_addr)) + ++ /* IFLA_IPTUN_FMR_IP4_PREFIX */ ++ nla_total_size(sizeof(struct in_addr)) + ++ /* IFLA_IPTUN_FMR_EA_LEN */ ++ nla_total_size(1) + ++ /* IFLA_IPTUN_FMR_IP6_PREFIX_LEN */ ++ nla_total_size(1) + ++ /* IFLA_IPTUN_FMR_IP4_PREFIX_LEN */ ++ nla_total_size(1) + ++ /* IFLA_IPTUN_FMR_OFFSET */ ++ nla_total_size(1) ++ ) * fmrs + + 0; + } + +@@ -1743,6 +1975,9 @@ static int ip6_tnl_fill_info(struct sk_b + { + struct ip6_tnl *tunnel = netdev_priv(dev); + struct __ip6_tnl_parm *parm = &tunnel->parms; ++ struct __ip6_tnl_fmr *c; ++ int fmrcnt = 0; ++ struct nlattr *fmrs; + + if (nla_put_u32(skb, IFLA_IPTUN_LINK, parm->link) || + nla_put(skb, IFLA_IPTUN_LOCAL, sizeof(struct in6_addr), +@@ -1753,8 +1988,27 @@ static int ip6_tnl_fill_info(struct sk_b + nla_put_u8(skb, IFLA_IPTUN_ENCAP_LIMIT, parm->encap_limit) || + nla_put_be32(skb, IFLA_IPTUN_FLOWINFO, parm->flowinfo) || + nla_put_u32(skb, IFLA_IPTUN_FLAGS, parm->flags) || +- nla_put_u8(skb, IFLA_IPTUN_PROTO, parm->proto)) ++ nla_put_u8(skb, IFLA_IPTUN_PROTO, parm->proto) || ++ !(fmrs = nla_nest_start(skb, IFLA_IPTUN_FMRS))) + goto nla_put_failure; ++ ++ for (c = parm->fmrs; c; c = c->next) { ++ struct nlattr *fmr = nla_nest_start(skb, ++fmrcnt); ++ if (!fmr || ++ nla_put(skb, IFLA_IPTUN_FMR_IP6_PREFIX, ++ sizeof(c->ip6_prefix), &c->ip6_prefix) || ++ nla_put(skb, IFLA_IPTUN_FMR_IP4_PREFIX, ++ sizeof(c->ip4_prefix), &c->ip4_prefix) || ++ nla_put_u8(skb, IFLA_IPTUN_FMR_IP6_PREFIX_LEN, c->ip6_prefix_len) || ++ nla_put_u8(skb, IFLA_IPTUN_FMR_IP4_PREFIX_LEN, c->ip4_prefix_len) || ++ nla_put_u8(skb, IFLA_IPTUN_FMR_EA_LEN, c->ea_len) || ++ nla_put_u8(skb, IFLA_IPTUN_FMR_OFFSET, c->offset)) ++ goto nla_put_failure; ++ ++ nla_nest_end(skb, fmr); ++ } ++ nla_nest_end(skb, fmrs); ++ + return 0; + + nla_put_failure: +@@ -1778,6 +2032,7 @@ static const struct nla_policy ip6_tnl_p + [IFLA_IPTUN_FLOWINFO] = { .type = NLA_U32 }, + [IFLA_IPTUN_FLAGS] = { .type = NLA_U32 }, + [IFLA_IPTUN_PROTO] = { .type = NLA_U8 }, ++ [IFLA_IPTUN_FMRS] = { .type = NLA_NESTED }, + }; + + static struct rtnl_link_ops ip6_link_ops __read_mostly = { diff --git a/target/linux/generic/patches-4.0/667-ipv6-Fixed-source-specific-default-route-handling.patch b/target/linux/generic/patches-4.0/667-ipv6-Fixed-source-specific-default-route-handling.patch new file mode 100644 index 0000000..50ac1db --- /dev/null +++ b/target/linux/generic/patches-4.0/667-ipv6-Fixed-source-specific-default-route-handling.patch @@ -0,0 +1,97 @@ +From e16e888b525503be05b3aea64190e8b3bdef44d0 Mon Sep 17 00:00:00 2001 +From: Markus Stenberg +Date: Tue, 5 May 2015 13:36:59 +0300 +Subject: [PATCH] ipv6: Fixed source specific default route handling. + +If there are only IPv6 source specific default routes present, the +host gets -ENETUNREACH on e.g. connect() because ip6_dst_lookup_tail +calls ip6_route_output first, and given source address any, it fails, +and ip6_route_get_saddr is never called. + +The change is to use the ip6_route_get_saddr, even if the initial +ip6_route_output fails, and then doing ip6_route_output _again_ after +we have appropriate source address available. + +Note that this is '99% fix' to the problem; a correct fix would be to +do route lookups only within addrconf.c when picking a source address, +and never call ip6_route_output before source address has been +populated. + +Signed-off-by: Markus Stenberg +Signed-off-by: David S. Miller +--- + net/ipv6/ip6_output.c | 39 +++++++++++++++++++++++++++++++-------- + net/ipv6/route.c | 5 +++-- + 2 files changed, 34 insertions(+), 10 deletions(-) + +--- a/net/ipv6/ip6_output.c ++++ b/net/ipv6/ip6_output.c +@@ -883,22 +883,45 @@ static int ip6_dst_lookup_tail(struct so + #endif + int err; + +- if (*dst == NULL) +- *dst = ip6_route_output(net, sk, fl6); +- +- err = (*dst)->error; +- if (err) +- goto out_err_release; ++ /* The correct way to handle this would be to do ++ * ip6_route_get_saddr, and then ip6_route_output; however, ++ * the route-specific preferred source forces the ++ * ip6_route_output call _before_ ip6_route_get_saddr. ++ * ++ * In source specific routing (no src=any default route), ++ * ip6_route_output will fail given src=any saddr, though, so ++ * that's why we try it again later. ++ */ ++ if (ipv6_addr_any(&fl6->saddr) && (!*dst || !(*dst)->error)) { ++ struct rt6_info *rt; ++ bool had_dst = *dst != NULL; + +- if (ipv6_addr_any(&fl6->saddr)) { +- struct rt6_info *rt = (struct rt6_info *) *dst; ++ if (!had_dst) ++ *dst = ip6_route_output(net, sk, fl6); ++ rt = (*dst)->error ? NULL : (struct rt6_info *)*dst; + err = ip6_route_get_saddr(net, rt, &fl6->daddr, + sk ? inet6_sk(sk)->srcprefs : 0, + &fl6->saddr); + if (err) + goto out_err_release; ++ ++ /* If we had an erroneous initial result, pretend it ++ * never existed and let the SA-enabled version take ++ * over. ++ */ ++ if (!had_dst && (*dst)->error) { ++ dst_release(*dst); ++ *dst = NULL; ++ } + } + ++ if (!*dst) ++ *dst = ip6_route_output(net, sk, fl6); ++ ++ err = (*dst)->error; ++ if (err) ++ goto out_err_release; ++ + #ifdef CONFIG_IPV6_OPTIMISTIC_DAD + /* + * Here if the dst entry we've looked up +--- a/net/ipv6/route.c ++++ b/net/ipv6/route.c +@@ -2247,9 +2247,10 @@ int ip6_route_get_saddr(struct net *net, + unsigned int prefs, + struct in6_addr *saddr) + { +- struct inet6_dev *idev = ip6_dst_idev((struct dst_entry *)rt); ++ struct inet6_dev *idev = ++ rt ? ip6_dst_idev((struct dst_entry *)rt) : NULL; + int err = 0; +- if (rt->rt6i_prefsrc.plen) ++ if (rt && rt->rt6i_prefsrc.plen) + *saddr = rt->rt6i_prefsrc.addr; + else + err = ipv6_dev_get_saddr(net, idev ? idev->dev : NULL, diff --git a/target/linux/generic/patches-4.0/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch b/target/linux/generic/patches-4.0/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch new file mode 100644 index 0000000..7447760 --- /dev/null +++ b/target/linux/generic/patches-4.0/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch @@ -0,0 +1,249 @@ +From 1b5aaa4b16f6e6471ab1c07b38068197a1b4c395 Mon Sep 17 00:00:00 2001 +From: Jonas Gorski +Date: Fri, 24 May 2013 14:40:54 +0200 +Subject: [PATCH 1/2] ipv6: allow rejecting with "source address failed policy" + +RFC6204 L-14 requires rejecting traffic from invalid addresses with +ICMPv6 Destination Unreachable, Code 5 (Source address failed ingress/ +egress policy) on the LAN side, so add an appropriate rule for that. + +Signed-off-by: Jonas Gorski +--- + include/net/netns/ipv6.h | 1 + + include/uapi/linux/fib_rules.h | 4 +++ + include/uapi/linux/rtnetlink.h | 1 + + net/ipv4/fib_semantics.c | 4 +++ + net/ipv4/fib_trie.c | 1 + + net/ipv4/ipmr.c | 1 + + net/ipv6/fib6_rules.c | 4 +++ + net/ipv6/ip6mr.c | 2 ++ + net/ipv6/route.c | 58 +++++++++++++++++++++++++++++++++++++++++- + 9 files changed, 75 insertions(+), 1 deletion(-) + +--- a/include/net/netns/ipv6.h ++++ b/include/net/netns/ipv6.h +@@ -59,6 +59,7 @@ struct netns_ipv6 { + unsigned long ip6_rt_last_gc; + #ifdef CONFIG_IPV6_MULTIPLE_TABLES + struct rt6_info *ip6_prohibit_entry; ++ struct rt6_info *ip6_policy_failed_entry; + struct rt6_info *ip6_blk_hole_entry; + struct fib6_table *fib6_local_tbl; + struct fib_rules_ops *fib6_rules_ops; +--- a/include/uapi/linux/fib_rules.h ++++ b/include/uapi/linux/fib_rules.h +@@ -64,6 +64,10 @@ enum { + FR_ACT_BLACKHOLE, /* Drop without notification */ + FR_ACT_UNREACHABLE, /* Drop with ENETUNREACH */ + FR_ACT_PROHIBIT, /* Drop with EACCES */ ++ FR_ACT_RES9, ++ FR_ACT_RES10, ++ FR_ACT_RES11, ++ FR_ACT_POLICY_FAILED, /* Drop with EACCES */ + __FR_ACT_MAX, + }; + +--- a/include/uapi/linux/rtnetlink.h ++++ b/include/uapi/linux/rtnetlink.h +@@ -208,6 +208,7 @@ enum { + RTN_THROW, /* Not in this table */ + RTN_NAT, /* Translate this address */ + RTN_XRESOLVE, /* Use external resolver */ ++ RTN_POLICY_FAILED, /* Failed ingress/egress policy */ + __RTN_MAX + }; + +--- a/net/ipv4/fib_semantics.c ++++ b/net/ipv4/fib_semantics.c +@@ -138,6 +138,10 @@ const struct fib_prop fib_props[RTN_MAX + .error = -EINVAL, + .scope = RT_SCOPE_NOWHERE, + }, ++ [RTN_POLICY_FAILED] = { ++ .error = -EACCES, ++ .scope = RT_SCOPE_UNIVERSE, ++ }, + }; + + static void rt_fibinfo_free(struct rtable __rcu **rtp) +--- a/net/ipv4/fib_trie.c ++++ b/net/ipv4/fib_trie.c +@@ -2236,6 +2236,7 @@ static const char *const rtn_type_names[ + [RTN_THROW] = "THROW", + [RTN_NAT] = "NAT", + [RTN_XRESOLVE] = "XRESOLVE", ++ [RTN_POLICY_FAILED] = "POLICY_FAILED", + }; + + static inline const char *rtn_type(char *buf, size_t len, unsigned int t) +--- a/net/ipv4/ipmr.c ++++ b/net/ipv4/ipmr.c +@@ -184,6 +184,7 @@ static int ipmr_rule_action(struct fib_r + case FR_ACT_UNREACHABLE: + return -ENETUNREACH; + case FR_ACT_PROHIBIT: ++ case FR_ACT_POLICY_FAILED: + return -EACCES; + case FR_ACT_BLACKHOLE: + default: +--- a/net/ipv6/fib6_rules.c ++++ b/net/ipv6/fib6_rules.c +@@ -73,6 +73,10 @@ static int fib6_rule_action(struct fib_r + err = -EACCES; + rt = net->ipv6.ip6_prohibit_entry; + goto discard_pkt; ++ case FR_ACT_POLICY_FAILED: ++ err = -EACCES; ++ rt = net->ipv6.ip6_policy_failed_entry; ++ goto discard_pkt; + } + + table = fib6_get_table(net, rule->table); +--- a/net/ipv6/ip6mr.c ++++ b/net/ipv6/ip6mr.c +@@ -169,6 +169,8 @@ static int ip6mr_rule_action(struct fib_ + return -ENETUNREACH; + case FR_ACT_PROHIBIT: + return -EACCES; ++ case FR_ACT_POLICY_FAILED: ++ return -EACCES; + case FR_ACT_BLACKHOLE: + default: + return -EINVAL; +--- a/net/ipv6/route.c ++++ b/net/ipv6/route.c +@@ -87,6 +87,8 @@ static int ip6_pkt_discard(struct sk_bu + static int ip6_pkt_discard_out(struct sock *sk, struct sk_buff *skb); + static int ip6_pkt_prohibit(struct sk_buff *skb); + static int ip6_pkt_prohibit_out(struct sock *sk, struct sk_buff *skb); ++static int ip6_pkt_policy_failed(struct sk_buff *skb); ++static int ip6_pkt_policy_failed_out(struct sock *sk, struct sk_buff *skb); + static void ip6_link_failure(struct sk_buff *skb); + static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk, + struct sk_buff *skb, u32 mtu); +@@ -283,6 +285,21 @@ static const struct rt6_info ip6_prohibi + .rt6i_ref = ATOMIC_INIT(1), + }; + ++static const struct rt6_info ip6_policy_failed_entry_template = { ++ .dst = { ++ .__refcnt = ATOMIC_INIT(1), ++ .__use = 1, ++ .obsolete = DST_OBSOLETE_FORCE_CHK, ++ .error = -EACCES, ++ .input = ip6_pkt_policy_failed, ++ .output = ip6_pkt_policy_failed_out, ++ }, ++ .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP), ++ .rt6i_protocol = RTPROT_KERNEL, ++ .rt6i_metric = ~(u32) 0, ++ .rt6i_ref = ATOMIC_INIT(1), ++}; ++ + static const struct rt6_info ip6_blk_hole_entry_template = { + .dst = { + .__refcnt = ATOMIC_INIT(1), +@@ -1637,6 +1654,11 @@ int ip6_route_add(struct fib6_config *cf + rt->dst.output = ip6_pkt_prohibit_out; + rt->dst.input = ip6_pkt_prohibit; + break; ++ case RTN_POLICY_FAILED: ++ rt->dst.error = -EACCES; ++ rt->dst.output = ip6_pkt_policy_failed_out; ++ rt->dst.input = ip6_pkt_policy_failed; ++ break; + case RTN_THROW: + default: + rt->dst.error = (cfg->fc_type == RTN_THROW) ? -EAGAIN +@@ -2204,6 +2226,17 @@ static int ip6_pkt_prohibit_out(struct s + return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES); + } + ++static int ip6_pkt_policy_failed(struct sk_buff *skb) ++{ ++ return ip6_pkt_drop(skb, ICMPV6_POLICY_FAIL, IPSTATS_MIB_INNOROUTES); ++} ++ ++static int ip6_pkt_policy_failed_out(struct sock *sk, struct sk_buff *skb) ++{ ++ skb->dev = skb_dst(skb)->dev; ++ return ip6_pkt_drop(skb, ICMPV6_POLICY_FAIL, IPSTATS_MIB_OUTNOROUTES); ++} ++ + /* + * Allocate a dst for local (unicast / anycast) address. + */ +@@ -2428,7 +2461,8 @@ static int rtm_to_fib6_config(struct sk_ + if (rtm->rtm_type == RTN_UNREACHABLE || + rtm->rtm_type == RTN_BLACKHOLE || + rtm->rtm_type == RTN_PROHIBIT || +- rtm->rtm_type == RTN_THROW) ++ rtm->rtm_type == RTN_THROW || ++ rtm->rtm_type == RTN_POLICY_FAILED) + cfg->fc_flags |= RTF_REJECT; + + if (rtm->rtm_type == RTN_LOCAL) +@@ -2631,6 +2665,9 @@ static int rt6_fill_node(struct net *net + case -EACCES: + rtm->rtm_type = RTN_PROHIBIT; + break; ++ case -EPERM: ++ rtm->rtm_type = RTN_POLICY_FAILED; ++ break; + case -EAGAIN: + rtm->rtm_type = RTN_THROW; + break; +@@ -2885,6 +2922,8 @@ static int ip6_route_dev_notify(struct n + #ifdef CONFIG_IPV6_MULTIPLE_TABLES + net->ipv6.ip6_prohibit_entry->dst.dev = dev; + net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev); ++ net->ipv6.ip6_policy_failed_entry->dst.dev = dev; ++ net->ipv6.ip6_policy_failed_entry->rt6i_idev = in6_dev_get(dev); + net->ipv6.ip6_blk_hole_entry->dst.dev = dev; + net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev); + #endif +@@ -3101,6 +3140,17 @@ static int __net_init ip6_route_net_init + net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops; + dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst, + ip6_template_metrics, true); ++ ++ net->ipv6.ip6_policy_failed_entry = ++ kmemdup(&ip6_policy_failed_entry_template, ++ sizeof(*net->ipv6.ip6_policy_failed_entry), GFP_KERNEL); ++ if (!net->ipv6.ip6_policy_failed_entry) ++ goto out_ip6_blk_hole_entry; ++ net->ipv6.ip6_policy_failed_entry->dst.path = ++ (struct dst_entry *)net->ipv6.ip6_policy_failed_entry; ++ net->ipv6.ip6_policy_failed_entry->dst.ops = &net->ipv6.ip6_dst_ops; ++ dst_init_metrics(&net->ipv6.ip6_policy_failed_entry->dst, ++ ip6_template_metrics, true); + #endif + + net->ipv6.sysctl.flush_delay = 0; +@@ -3119,6 +3169,8 @@ out: + return ret; + + #ifdef CONFIG_IPV6_MULTIPLE_TABLES ++out_ip6_blk_hole_entry: ++ kfree(net->ipv6.ip6_blk_hole_entry); + out_ip6_prohibit_entry: + kfree(net->ipv6.ip6_prohibit_entry); + out_ip6_null_entry: +@@ -3136,6 +3188,7 @@ static void __net_exit ip6_route_net_exi + #ifdef CONFIG_IPV6_MULTIPLE_TABLES + kfree(net->ipv6.ip6_prohibit_entry); + kfree(net->ipv6.ip6_blk_hole_entry); ++ kfree(net->ipv6.ip6_policy_failed_entry); + #endif + dst_entries_destroy(&net->ipv6.ip6_dst_ops); + } +@@ -3232,6 +3285,9 @@ int __init ip6_route_init(void) + init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); + init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev; + init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); ++ init_net.ipv6.ip6_policy_failed_entry->dst.dev = init_net.loopback_dev; ++ init_net.ipv6.ip6_policy_failed_entry->rt6i_idev = ++ in6_dev_get(init_net.loopback_dev); + #endif + ret = fib6_init(); + if (ret) diff --git a/target/linux/generic/patches-4.0/671-net-provide-defines-for-_POLICY_FAILED-until-all-cod.patch b/target/linux/generic/patches-4.0/671-net-provide-defines-for-_POLICY_FAILED-until-all-cod.patch new file mode 100644 index 0000000..6866f78 --- /dev/null +++ b/target/linux/generic/patches-4.0/671-net-provide-defines-for-_POLICY_FAILED-until-all-cod.patch @@ -0,0 +1,53 @@ +From 7749b481ce5d7e232b1f7da5e6b2c44816f51681 Mon Sep 17 00:00:00 2001 +From: Jonas Gorski +Date: Sun, 19 Jan 2014 20:45:51 +0100 +Subject: [PATCH 2/2] net: provide defines for _POLICY_FAILED until all code is + updated + +Upstream introduced ICMPV6_POLICY_FAIL for code 5 of destination +unreachable, conflicting with our name. + +Add appropriate defines to allow our code to build with the new +name until we have updated our local patches for older kernels +and userspace packages. + +Signed-off-by: Jonas Gorski +--- + include/uapi/linux/fib_rules.h | 2 ++ + include/uapi/linux/icmpv6.h | 2 ++ + include/uapi/linux/rtnetlink.h | 2 ++ + 3 files changed, 6 insertions(+) + +--- a/include/uapi/linux/fib_rules.h ++++ b/include/uapi/linux/fib_rules.h +@@ -71,6 +71,8 @@ enum { + __FR_ACT_MAX, + }; + ++#define FR_ACT_FAILED_POLICY FR_ACT_POLICY_FAILED ++ + #define FR_ACT_MAX (__FR_ACT_MAX - 1) + + #endif +--- a/include/uapi/linux/icmpv6.h ++++ b/include/uapi/linux/icmpv6.h +@@ -118,6 +118,8 @@ struct icmp6hdr { + #define ICMPV6_POLICY_FAIL 5 + #define ICMPV6_REJECT_ROUTE 6 + ++#define ICMPV6_FAILED_POLICY ICMPV6_POLICY_FAIL ++ + /* + * Codes for Time Exceeded + */ +--- a/include/uapi/linux/rtnetlink.h ++++ b/include/uapi/linux/rtnetlink.h +@@ -212,6 +212,8 @@ enum { + __RTN_MAX + }; + ++#define RTN_FAILED_POLICY RTN_POLICY_FAILED ++ + #define RTN_MAX (__RTN_MAX - 1) + + diff --git a/target/linux/generic/patches-4.0/680-NET-skip-GRO-for-foreign-MAC-addresses.patch b/target/linux/generic/patches-4.0/680-NET-skip-GRO-for-foreign-MAC-addresses.patch new file mode 100644 index 0000000..f0d5b47 --- /dev/null +++ b/target/linux/generic/patches-4.0/680-NET-skip-GRO-for-foreign-MAC-addresses.patch @@ -0,0 +1,160 @@ +Subject: NET: skip GRO for foreign MAC addresses + +For network drivers using napi_gro_receive, packets are run through GRO, +even when the destination MAC address does not match, and they're supposed +to be delivered to another host behind a different bridge port. + +This can be very expensive, because for drivers without TSO or scatter- +gather, this can only be undone by copying the skb and checksumming it +again. + +To be able to track foreign MAC addresses in an inexpensive way, create +a mask of changed bits in MAC addresses of upper devices. This allows +handling VLANs and bridge devices with different addresses (as long as +they are not too different). + +Signed-off-by: Felix Fietkau + +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -4007,6 +4007,9 @@ static enum gro_result dev_gro_receive(s + enum gro_result ret; + int grow; + ++ if (skb->gro_skip) ++ goto normal; ++ + if (!(skb->dev->features & NETIF_F_GRO)) + goto normal; + +@@ -5154,6 +5157,48 @@ static void __netdev_adjacent_dev_unlink + &upper_dev->adj_list.lower); + } + ++static void __netdev_addr_mask(unsigned char *mask, const unsigned char *addr, ++ struct net_device *dev) ++{ ++ int i; ++ ++ for (i = 0; i < dev->addr_len; i++) ++ mask[i] |= addr[i] ^ dev->dev_addr[i]; ++} ++ ++static void __netdev_upper_mask(unsigned char *mask, struct net_device *dev, ++ struct net_device *lower) ++{ ++ struct net_device *cur; ++ struct list_head *iter; ++ ++ netdev_for_each_upper_dev_rcu(dev, cur, iter) { ++ __netdev_addr_mask(mask, cur->dev_addr, lower); ++ __netdev_upper_mask(mask, cur, lower); ++ } ++} ++ ++static void __netdev_update_addr_mask(struct net_device *dev) ++{ ++ unsigned char mask[MAX_ADDR_LEN]; ++ struct net_device *cur; ++ struct list_head *iter; ++ ++ memset(mask, 0, sizeof(mask)); ++ __netdev_upper_mask(mask, dev, dev); ++ memcpy(dev->local_addr_mask, mask, dev->addr_len); ++ ++ netdev_for_each_lower_dev(dev, cur, iter) ++ __netdev_update_addr_mask(cur); ++} ++ ++static void netdev_update_addr_mask(struct net_device *dev) ++{ ++ rcu_read_lock(); ++ __netdev_update_addr_mask(dev); ++ rcu_read_unlock(); ++} ++ + static int __netdev_upper_dev_link(struct net_device *dev, + struct net_device *upper_dev, bool master, + void *private) +@@ -5214,6 +5259,7 @@ static int __netdev_upper_dev_link(struc + goto rollback_lower_mesh; + } + ++ netdev_update_addr_mask(dev); + call_netdevice_notifiers(NETDEV_CHANGEUPPER, dev); + return 0; + +@@ -5331,6 +5377,7 @@ void netdev_upper_dev_unlink(struct net_ + list_for_each_entry(i, &upper_dev->all_adj_list.upper, list) + __netdev_adjacent_dev_unlink(dev, i->dev); + ++ netdev_update_addr_mask(dev); + call_netdevice_notifiers(NETDEV_CHANGEUPPER, dev); + } + EXPORT_SYMBOL(netdev_upper_dev_unlink); +@@ -5870,6 +5917,7 @@ int dev_set_mac_address(struct net_devic + if (err) + return err; + dev->addr_assign_type = NET_ADDR_SET; ++ netdev_update_addr_mask(dev); + call_netdevice_notifiers(NETDEV_CHANGEADDR, dev); + add_device_randomness(dev->dev_addr, dev->addr_len); + return 0; +--- a/include/linux/netdevice.h ++++ b/include/linux/netdevice.h +@@ -1592,6 +1592,8 @@ struct net_device { + struct netdev_hw_addr_list mc; + struct netdev_hw_addr_list dev_addrs; + ++ unsigned char local_addr_mask[MAX_ADDR_LEN]; ++ + #ifdef CONFIG_SYSFS + struct kset *queues_kset; + #endif +--- a/include/linux/skbuff.h ++++ b/include/linux/skbuff.h +@@ -609,7 +609,8 @@ struct sk_buff { + __u8 ipvs_property:1; + __u8 inner_protocol_type:1; + __u8 remcsum_offload:1; +- /* 3 or 5 bit hole */ ++ __u8 gro_skip:1; ++ /* 2 or 4 bit hole */ + + #ifdef CONFIG_NET_SCHED + __u16 tc_index; /* traffic control index */ +--- a/net/ethernet/eth.c ++++ b/net/ethernet/eth.c +@@ -172,6 +172,18 @@ u32 eth_get_headlen(void *data, unsigned + } + EXPORT_SYMBOL(eth_get_headlen); + ++static inline bool ++eth_check_local_mask(const void *addr1, const void *addr2, const void *mask) ++{ ++ const u16 *a1 = addr1; ++ const u16 *a2 = addr2; ++ const u16 *m = mask; ++ ++ return (((a1[0] ^ a2[0]) & ~m[0]) | ++ ((a1[1] ^ a2[1]) & ~m[1]) | ++ ((a1[2] ^ a2[2]) & ~m[2])); ++} ++ + /** + * eth_type_trans - determine the packet's protocol ID. + * @skb: received socket data +@@ -199,8 +211,12 @@ __be16 eth_type_trans(struct sk_buff *sk + skb->pkt_type = PACKET_MULTICAST; + } + else if (unlikely(!ether_addr_equal_64bits(eth->h_dest, +- dev->dev_addr))) ++ dev->dev_addr))) { + skb->pkt_type = PACKET_OTHERHOST; ++ if (eth_check_local_mask(eth->h_dest, dev->dev_addr, ++ dev->local_addr_mask)) ++ skb->gro_skip = 1; ++ } + + /* + * Some variants of DSA tagging don't have an ethertype field diff --git a/target/linux/generic/patches-4.0/681-NET-add-of_get_mac_address_mtd.patch b/target/linux/generic/patches-4.0/681-NET-add-of_get_mac_address_mtd.patch new file mode 100644 index 0000000..a836eed --- /dev/null +++ b/target/linux/generic/patches-4.0/681-NET-add-of_get_mac_address_mtd.patch @@ -0,0 +1,88 @@ +From: John Crispin +Date: Sun, 27 Jul 2014 09:40:01 +0100 +Subject: NET: add of_get_mac_address_mtd() + +Many embedded devices have information such as mac addresses stored inside mtd +devices. This patch allows us to add a property inside a node describing a +network interface. The new property points at a mtd partition with an offset +where the mac address can be found. + +Signed-off-by: John Crispin +--- + drivers/of/of_net.c | 37 +++++++++++++++++++++++++++++++++++++ + include/linux/of_net.h | 1 + + 2 files changed, 38 insertions(+) + +--- a/drivers/of/of_net.c ++++ b/drivers/of/of_net.c +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + + /** + * of_get_phy_mode - Get phy mode for given device_node +@@ -75,3 +76,45 @@ const void *of_get_mac_address(struct de + return NULL; + } + EXPORT_SYMBOL(of_get_mac_address); ++ ++#ifdef CONFIG_MTD ++int of_get_mac_address_mtd(struct device_node *np, unsigned char *mac) ++{ ++ struct device_node *mtd_np = NULL; ++ size_t retlen; ++ int size, ret; ++ struct mtd_info *mtd; ++ const char *part; ++ const __be32 *list; ++ phandle phandle; ++ u32 mac_inc = 0; ++ ++ list = of_get_property(np, "mtd-mac-address", &size); ++ if (!list || (size != (2 * sizeof(*list)))) ++ return -ENOENT; ++ ++ phandle = be32_to_cpup(list++); ++ if (phandle) ++ mtd_np = of_find_node_by_phandle(phandle); ++ ++ if (!mtd_np) ++ return -ENOENT; ++ ++ part = of_get_property(mtd_np, "label", NULL); ++ if (!part) ++ part = mtd_np->name; ++ ++ mtd = get_mtd_device_nm(part); ++ if (IS_ERR(mtd)) ++ return PTR_ERR(mtd); ++ ++ ret = mtd_read(mtd, be32_to_cpup(list), 6, &retlen, mac); ++ put_mtd_device(mtd); ++ ++ if (!of_property_read_u32(np, "mtd-mac-address-increment", &mac_inc)) ++ mac[5] += mac_inc; ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(of_get_mac_address_mtd); ++#endif +--- a/include/linux/of_net.h ++++ b/include/linux/of_net.h +@@ -11,6 +11,14 @@ + #include + extern int of_get_phy_mode(struct device_node *np); + extern const void *of_get_mac_address(struct device_node *np); ++#ifdef CONFIG_MTD ++extern int of_get_mac_address_mtd(struct device_node *np, unsigned char *mac); ++#else ++static inline int of_get_mac_address_mtd(struct device_node *np, unsigned char *mac) ++{ ++ return -ENOENT; ++} ++#endif + #else + static inline int of_get_phy_mode(struct device_node *np) + { diff --git a/target/linux/generic/patches-4.0/700-swconfig.patch b/target/linux/generic/patches-4.0/700-swconfig.patch new file mode 100644 index 0000000..bf62025 --- /dev/null +++ b/target/linux/generic/patches-4.0/700-swconfig.patch @@ -0,0 +1,39 @@ +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -12,6 +12,16 @@ menuconfig PHYLIB + + if PHYLIB + ++config SWCONFIG ++ tristate "Switch configuration API" ++ ---help--- ++ Switch configuration API using netlink. This allows ++ you to configure the VLAN features of certain switches. ++ ++config SWCONFIG_LEDS ++ bool "Switch LED trigger support" ++ depends on (SWCONFIG && LEDS_TRIGGERS) ++ + comment "MII PHY device drivers" + + config AT803X_PHY +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -3,6 +3,7 @@ + libphy-objs := phy.o phy_device.o mdio_bus.o + + obj-$(CONFIG_PHYLIB) += libphy.o ++obj-$(CONFIG_SWCONFIG) += swconfig.o + obj-$(CONFIG_MARVELL_PHY) += marvell.o + obj-$(CONFIG_DAVICOM_PHY) += davicom.o + obj-$(CONFIG_CICADA_PHY) += cicada.o +--- a/include/uapi/linux/Kbuild ++++ b/include/uapi/linux/Kbuild +@@ -379,6 +379,7 @@ header-y += stddef.h + header-y += string.h + header-y += suspend_ioctls.h + header-y += swab.h ++header-y += switch.h + header-y += synclink.h + header-y += sysctl.h + header-y += sysinfo.h diff --git a/target/linux/generic/patches-4.0/701-phy_extension.patch b/target/linux/generic/patches-4.0/701-phy_extension.patch new file mode 100644 index 0000000..55b37ba --- /dev/null +++ b/target/linux/generic/patches-4.0/701-phy_extension.patch @@ -0,0 +1,63 @@ +--- a/drivers/net/phy/phy.c ++++ b/drivers/net/phy/phy.c +@@ -357,6 +357,50 @@ int phy_ethtool_gset(struct phy_device * + } + EXPORT_SYMBOL(phy_ethtool_gset); + ++int phy_ethtool_ioctl(struct phy_device *phydev, void *useraddr) ++{ ++ u32 cmd; ++ int tmp; ++ struct ethtool_cmd ecmd = { ETHTOOL_GSET }; ++ struct ethtool_value edata = { ETHTOOL_GLINK }; ++ ++ if (get_user(cmd, (u32 *) useraddr)) ++ return -EFAULT; ++ ++ switch (cmd) { ++ case ETHTOOL_GSET: ++ phy_ethtool_gset(phydev, &ecmd); ++ if (copy_to_user(useraddr, &ecmd, sizeof(ecmd))) ++ return -EFAULT; ++ return 0; ++ ++ case ETHTOOL_SSET: ++ if (copy_from_user(&ecmd, useraddr, sizeof(ecmd))) ++ return -EFAULT; ++ return phy_ethtool_sset(phydev, &ecmd); ++ ++ case ETHTOOL_NWAY_RST: ++ /* if autoneg is off, it's an error */ ++ tmp = phy_read(phydev, MII_BMCR); ++ if (tmp & BMCR_ANENABLE) { ++ tmp |= (BMCR_ANRESTART); ++ phy_write(phydev, MII_BMCR, tmp); ++ return 0; ++ } ++ return -EINVAL; ++ ++ case ETHTOOL_GLINK: ++ edata.data = (phy_read(phydev, ++ MII_BMSR) & BMSR_LSTATUS) ? 1 : 0; ++ if (copy_to_user(useraddr, &edata, sizeof(edata))) ++ return -EFAULT; ++ return 0; ++ } ++ ++ return -EOPNOTSUPP; ++} ++EXPORT_SYMBOL(phy_ethtool_ioctl); ++ + /** + * phy_mii_ioctl - generic PHY MII ioctl interface + * @phydev: the phy_device struct +--- a/include/linux/phy.h ++++ b/include/linux/phy.h +@@ -762,6 +762,7 @@ void phy_start_machine(struct phy_device + void phy_stop_machine(struct phy_device *phydev); + int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd); + int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd); ++int phy_ethtool_ioctl(struct phy_device *phydev, void *useraddr); + int phy_mii_ioctl(struct phy_device *phydev, struct ifreq *ifr, int cmd); + int phy_start_interrupts(struct phy_device *phydev); + void phy_print_status(struct phy_device *phydev); diff --git a/target/linux/generic/patches-4.0/702-phy_add_aneg_done_function.patch b/target/linux/generic/patches-4.0/702-phy_add_aneg_done_function.patch new file mode 100644 index 0000000..c743cef --- /dev/null +++ b/target/linux/generic/patches-4.0/702-phy_add_aneg_done_function.patch @@ -0,0 +1,27 @@ +--- a/include/linux/phy.h ++++ b/include/linux/phy.h +@@ -489,6 +489,12 @@ struct phy_driver { + /* Determines the negotiated speed and duplex */ + int (*read_status)(struct phy_device *phydev); + ++ /* ++ * Update the value in phydev->link to reflect the ++ * current link value ++ */ ++ int (*update_link)(struct phy_device *phydev); ++ + /* Clears any pending interrupts */ + int (*ack_interrupt)(struct phy_device *phydev); + +--- a/drivers/net/phy/phy_device.c ++++ b/drivers/net/phy/phy_device.c +@@ -929,6 +929,9 @@ int genphy_update_link(struct phy_device + { + int status; + ++ if (phydev->drv->update_link) ++ return phydev->drv->update_link(phydev); ++ + /* Do a fake read */ + status = phy_read(phydev, MII_BMSR); + if (status < 0) diff --git a/target/linux/generic/patches-4.0/703-phy-add-detach-callback-to-struct-phy_driver.patch b/target/linux/generic/patches-4.0/703-phy-add-detach-callback-to-struct-phy_driver.patch new file mode 100644 index 0000000..85888f7 --- /dev/null +++ b/target/linux/generic/patches-4.0/703-phy-add-detach-callback-to-struct-phy_driver.patch @@ -0,0 +1,27 @@ +--- a/drivers/net/phy/phy_device.c ++++ b/drivers/net/phy/phy_device.c +@@ -674,6 +674,9 @@ void phy_detach(struct phy_device *phyde + { + int i; + ++ if (phydev->drv && phydev->drv->detach) ++ phydev->drv->detach(phydev); ++ + if (phydev->bus->dev.driver) + module_put(phydev->bus->dev.driver->owner); + +--- a/include/linux/phy.h ++++ b/include/linux/phy.h +@@ -507,6 +507,12 @@ struct phy_driver { + */ + int (*did_interrupt)(struct phy_device *phydev); + ++ /* ++ * Called before an ethernet device is detached ++ * from the PHY. ++ */ ++ void (*detach)(struct phy_device *phydev); ++ + /* Clears up any memory if needed */ + void (*remove)(struct phy_device *phydev); + diff --git a/target/linux/generic/patches-4.0/704-phy-no-genphy-soft-reset.patch b/target/linux/generic/patches-4.0/704-phy-no-genphy-soft-reset.patch new file mode 100644 index 0000000..41a6d91 --- /dev/null +++ b/target/linux/generic/patches-4.0/704-phy-no-genphy-soft-reset.patch @@ -0,0 +1,29 @@ +--- a/drivers/net/phy/phy_device.c ++++ b/drivers/net/phy/phy_device.c +@@ -1147,7 +1147,7 @@ int genphy_config_init(struct phy_device + return 0; + } + +-static int gen10g_soft_reset(struct phy_device *phydev) ++static int no_soft_reset(struct phy_device *phydev) + { + /* Do nothing for now */ + return 0; +@@ -1361,7 +1361,7 @@ static struct phy_driver genphy_driver[] + .phy_id = 0xffffffff, + .phy_id_mask = 0xffffffff, + .name = "Generic PHY", +- .soft_reset = genphy_soft_reset, ++ .soft_reset = no_soft_reset, + .config_init = genphy_config_init, + .features = PHY_GBIT_FEATURES | SUPPORTED_MII | + SUPPORTED_AUI | SUPPORTED_FIBRE | +@@ -1376,7 +1376,7 @@ static struct phy_driver genphy_driver[] + .phy_id = 0xffffffff, + .phy_id_mask = 0xffffffff, + .name = "Generic 10G PHY", +- .soft_reset = gen10g_soft_reset, ++ .soft_reset = no_soft_reset, + .config_init = gen10g_config_init, + .features = 0, + .config_aneg = gen10g_config_aneg, diff --git a/target/linux/generic/patches-4.0/710-phy-add-mdio_register_board_info.patch b/target/linux/generic/patches-4.0/710-phy-add-mdio_register_board_info.patch new file mode 100644 index 0000000..2bc91d5 --- /dev/null +++ b/target/linux/generic/patches-4.0/710-phy-add-mdio_register_board_info.patch @@ -0,0 +1,193 @@ +--- a/drivers/net/phy/mdio_bus.c ++++ b/drivers/net/phy/mdio_bus.c +@@ -38,6 +38,8 @@ + + #include + ++#include "mdio-boardinfo.h" ++ + /** + * mdiobus_alloc_size - allocate a mii_bus structure + * @size: extra amount of memory to allocate for private storage. +@@ -335,9 +337,21 @@ void mdiobus_free(struct mii_bus *bus) + } + EXPORT_SYMBOL(mdiobus_free); + ++static void mdiobus_setup_phydev_from_boardinfo(struct mii_bus *bus, ++ struct phy_device *phydev, ++ struct mdio_board_info *bi) ++{ ++ if (strcmp(bus->id, bi->bus_id) || ++ bi->phy_addr != phydev->addr) ++ return; ++ ++ phydev->dev.platform_data = (void *) bi->platform_data; ++} ++ + struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr) + { + struct phy_device *phydev; ++ struct mdio_board_entry *be; + int err; + + phydev = get_phy_device(bus, addr, false); +@@ -350,6 +364,12 @@ struct phy_device *mdiobus_scan(struct m + */ + of_mdiobus_link_phydev(bus, phydev); + ++ mutex_lock(&__mdio_board_lock); ++ list_for_each_entry(be, &__mdio_board_list, list) ++ mdiobus_setup_phydev_from_boardinfo(bus, phydev, ++ &be->board_info); ++ mutex_unlock(&__mdio_board_lock); ++ + err = phy_device_register(phydev); + if (err) { + phy_device_free(phydev); +--- a/include/linux/phy.h ++++ b/include/linux/phy.h +@@ -800,6 +800,23 @@ void mdio_bus_exit(void); + + extern struct bus_type mdio_bus_type; + ++struct mdio_board_info { ++ const char *bus_id; ++ int phy_addr; ++ ++ const void *platform_data; ++}; ++ ++#ifdef CONFIG_MDIO_BOARDINFO ++int mdiobus_register_board_info(const struct mdio_board_info *info, unsigned n); ++#else ++static inline int ++mdiobus_register_board_info(const struct mdio_board_info *info, unsigned n) ++{ ++ return 0; ++} ++#endif ++ + /** + * module_phy_driver() - Helper macro for registering PHY drivers + * @__phy_drivers: array of PHY drivers to register +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -12,6 +12,10 @@ menuconfig PHYLIB + + if PHYLIB + ++config MDIO_BOARDINFO ++ bool ++ default y ++ + config SWCONFIG + tristate "Switch configuration API" + ---help--- +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -2,6 +2,8 @@ + + libphy-objs := phy.o phy_device.o mdio_bus.o + ++obj-$(CONFIG_MDIO_BOARDINFO) += mdio-boardinfo.o ++ + obj-$(CONFIG_PHYLIB) += libphy.o + obj-$(CONFIG_SWCONFIG) += swconfig.o + obj-$(CONFIG_MARVELL_PHY) += marvell.o +--- /dev/null ++++ b/drivers/net/phy/mdio-boardinfo.c +@@ -0,0 +1,58 @@ ++/* ++ * mdio-boardinfo.c - collect pre-declarations of PHY devices ++ * ++ * 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. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "mdio-boardinfo.h" ++ ++/* ++ * These symbols are exported ONLY FOR the mdio_bus component. ++ * No other users will be supported. ++ */ ++ ++LIST_HEAD(__mdio_board_list); ++EXPORT_SYMBOL_GPL(__mdio_board_list); ++ ++DEFINE_MUTEX(__mdio_board_lock); ++EXPORT_SYMBOL_GPL(__mdio_board_lock); ++ ++/** ++ * mdio_register_board_info - register PHY devices for a given board ++ * @info: array of chip descriptors ++ * @n: how many descriptors are provided ++ * Context: can sleep ++ * ++ * The board info passed can safely be __initdata ... but be careful of ++ * any embedded pointers (platform_data, etc), they're copied as-is. ++ */ ++int __init ++mdiobus_register_board_info(struct mdio_board_info const *info, unsigned n) ++{ ++ struct mdio_board_entry *be; ++ int i; ++ ++ be = kzalloc(n * sizeof(*be), GFP_KERNEL); ++ if (!be) ++ return -ENOMEM; ++ ++ for (i = 0; i < n; i++, be++, info++) { ++ memcpy(&be->board_info, info, sizeof(*info)); ++ mutex_lock(&__mdio_board_lock); ++ list_add_tail(&be->list, &__mdio_board_list); ++ mutex_unlock(&__mdio_board_lock); ++ } ++ ++ return 0; ++} +--- /dev/null ++++ b/drivers/net/phy/mdio-boardinfo.h +@@ -0,0 +1,22 @@ ++/* ++ * mdio-boardinfo.h - boardinfo interface internal to the mdio_bus component ++ * ++ * 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. ++ * ++ */ ++ ++#include ++ ++struct mdio_board_entry { ++ struct list_head list; ++ struct mdio_board_info board_info; ++}; ++ ++/* __mdio_board_lock protects __mdio_board_list ++ * only mdio_bus components are allowed to use these symbols. ++ */ ++extern struct mutex __mdio_board_lock; ++extern struct list_head __mdio_board_list; +--- a/drivers/net/Makefile ++++ b/drivers/net/Makefile +@@ -16,7 +16,7 @@ obj-$(CONFIG_MII) += mii.o + obj-$(CONFIG_MDIO) += mdio.o + obj-$(CONFIG_NET) += Space.o loopback.o + obj-$(CONFIG_NETCONSOLE) += netconsole.o +-obj-$(CONFIG_PHYLIB) += phy/ ++obj-y += phy/ + obj-$(CONFIG_RIONET) += rionet.o + obj-$(CONFIG_NET_TEAM) += team/ + obj-$(CONFIG_TUN) += tun.o diff --git a/target/linux/generic/patches-4.0/720-phy_adm6996.patch b/target/linux/generic/patches-4.0/720-phy_adm6996.patch new file mode 100644 index 0000000..0f8b261 --- /dev/null +++ b/target/linux/generic/patches-4.0/720-phy_adm6996.patch @@ -0,0 +1,26 @@ +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -132,6 +132,13 @@ config MICREL_PHY + ---help--- + Supports the KSZ9021, VSC8201, KS8001 PHYs. + ++config ADM6996_PHY ++ tristate "Driver for ADM6996 switches" ++ select SWCONFIG ++ ---help--- ++ Currently supports the ADM6996FC and ADM6996M switches. ++ Support for FC is very limited. ++ + config FIXED_PHY + tristate "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs" + depends on PHYLIB +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -18,6 +18,7 @@ obj-$(CONFIG_BCM63XX_PHY) += bcm63xx.o + obj-$(CONFIG_BCM7XXX_PHY) += bcm7xxx.o + obj-$(CONFIG_BCM87XX_PHY) += bcm87xx.o + obj-$(CONFIG_ICPLUS_PHY) += icplus.o ++obj-$(CONFIG_ADM6996_PHY) += adm6996.o + obj-$(CONFIG_REALTEK_PHY) += realtek.o + obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o + obj-$(CONFIG_FIXED_PHY) += fixed_phy.o diff --git a/target/linux/generic/patches-4.0/721-phy_packets.patch b/target/linux/generic/patches-4.0/721-phy_packets.patch new file mode 100644 index 0000000..f3ee626 --- /dev/null +++ b/target/linux/generic/patches-4.0/721-phy_packets.patch @@ -0,0 +1,161 @@ +--- a/include/linux/netdevice.h ++++ b/include/linux/netdevice.h +@@ -1260,6 +1260,7 @@ enum netdev_priv_flags { + IFF_XMIT_DST_RELEASE_PERM = 1<<22, + IFF_IPVLAN_MASTER = 1<<23, + IFF_IPVLAN_SLAVE = 1<<24, ++ IFF_NO_IP_ALIGN = 1<<25, + }; + + #define IFF_802_1Q_VLAN IFF_802_1Q_VLAN +@@ -1287,6 +1288,7 @@ enum netdev_priv_flags { + #define IFF_XMIT_DST_RELEASE_PERM IFF_XMIT_DST_RELEASE_PERM + #define IFF_IPVLAN_MASTER IFF_IPVLAN_MASTER + #define IFF_IPVLAN_SLAVE IFF_IPVLAN_SLAVE ++#define IFF_NO_IP_ALIGN IFF_NO_IP_ALIGN + + /** + * struct net_device - The DEVICE structure. +@@ -1559,6 +1561,11 @@ struct net_device { + const struct ethtool_ops *ethtool_ops; + const struct forwarding_accel_ops *fwd_ops; + ++#ifdef CONFIG_ETHERNET_PACKET_MANGLE ++ void (*eth_mangle_rx)(struct net_device *dev, struct sk_buff *skb); ++ struct sk_buff *(*eth_mangle_tx)(struct net_device *dev, struct sk_buff *skb); ++#endif ++ + const struct header_ops *header_ops; + + unsigned int flags; +@@ -1624,6 +1631,10 @@ struct net_device { + struct wireless_dev *ieee80211_ptr; + struct wpan_dev *ieee802154_ptr; + ++#ifdef CONFIG_ETHERNET_PACKET_MANGLE ++ void *phy_ptr; /* PHY device specific data */ ++#endif ++ + /* + * Cache lines mostly used on receive path (including eth_type_trans()) + */ +--- a/include/linux/skbuff.h ++++ b/include/linux/skbuff.h +@@ -2058,6 +2058,10 @@ static inline int pskb_trim(struct sk_bu + return (len < skb->len) ? __pskb_trim(skb, len) : 0; + } + ++extern struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev, ++ unsigned int length, gfp_t gfp); ++ ++ + /** + * pskb_trim_unique - remove end from a paged unique (not cloned) buffer + * @skb: buffer to alter +@@ -2184,16 +2188,6 @@ static inline struct sk_buff *dev_alloc_ + } + + +-static inline struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev, +- unsigned int length, gfp_t gfp) +-{ +- struct sk_buff *skb = __netdev_alloc_skb(dev, length + NET_IP_ALIGN, gfp); +- +- if (NET_IP_ALIGN && skb) +- skb_reserve(skb, NET_IP_ALIGN); +- return skb; +-} +- + static inline struct sk_buff *netdev_alloc_skb_ip_align(struct net_device *dev, + unsigned int length) + { +--- a/net/Kconfig ++++ b/net/Kconfig +@@ -25,6 +25,12 @@ menuconfig NET + + if NET + ++config ETHERNET_PACKET_MANGLE ++ bool ++ help ++ This option can be selected by phy drivers that need to mangle ++ packets going in or out of an ethernet device. ++ + config WANT_COMPAT_NETLINK_MESSAGES + bool + help +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -2618,10 +2618,20 @@ static int xmit_one(struct sk_buff *skb, + if (!list_empty(&ptype_all) || !list_empty(&dev->ptype_all)) + dev_queue_xmit_nit(skb, dev); + +- len = skb->len; +- trace_net_dev_start_xmit(skb, dev); +- rc = netdev_start_xmit(skb, dev, txq, more); +- trace_net_dev_xmit(skb, rc, dev, len); ++#ifdef CONFIG_ETHERNET_PACKET_MANGLE ++ if (!dev->eth_mangle_tx || ++ (skb = dev->eth_mangle_tx(dev, skb)) != NULL) ++#else ++ if (1) ++#endif ++ { ++ len = skb->len; ++ trace_net_dev_start_xmit(skb, dev); ++ rc = netdev_start_xmit(skb, dev, txq, more); ++ trace_net_dev_xmit(skb, rc, dev, len); ++ } else { ++ rc = NETDEV_TX_OK; ++ } + + return rc; + } +--- a/net/core/skbuff.c ++++ b/net/core/skbuff.c +@@ -63,6 +63,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -568,6 +569,22 @@ struct sk_buff *__napi_alloc_skb(struct + } + EXPORT_SYMBOL(__napi_alloc_skb); + ++struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev, ++ unsigned int length, gfp_t gfp) ++{ ++ struct sk_buff *skb = __netdev_alloc_skb(dev, length + NET_IP_ALIGN, gfp); ++ ++#ifdef CONFIG_ETHERNET_PACKET_MANGLE ++ if (dev && (dev->priv_flags & IFF_NO_IP_ALIGN)) ++ return skb; ++#endif ++ ++ if (NET_IP_ALIGN && skb) ++ skb_reserve(skb, NET_IP_ALIGN); ++ return skb; ++} ++EXPORT_SYMBOL(__netdev_alloc_skb_ip_align); ++ + void skb_add_rx_frag(struct sk_buff *skb, int i, struct page *page, int off, + int size, unsigned int truesize) + { +--- a/net/ethernet/eth.c ++++ b/net/ethernet/eth.c +@@ -200,6 +200,12 @@ __be16 eth_type_trans(struct sk_buff *sk + const struct ethhdr *eth; + + skb->dev = dev; ++ ++#ifdef CONFIG_ETHERNET_PACKET_MANGLE ++ if (dev->eth_mangle_rx) ++ dev->eth_mangle_rx(dev, skb); ++#endif ++ + skb_reset_mac_header(skb); + skb_pull_inline(skb, ETH_HLEN); + eth = eth_hdr(skb); diff --git a/target/linux/generic/patches-4.0/722-phy_mvswitch.patch b/target/linux/generic/patches-4.0/722-phy_mvswitch.patch new file mode 100644 index 0000000..27faa7c --- /dev/null +++ b/target/linux/generic/patches-4.0/722-phy_mvswitch.patch @@ -0,0 +1,23 @@ +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -139,6 +139,10 @@ config ADM6996_PHY + Currently supports the ADM6996FC and ADM6996M switches. + Support for FC is very limited. + ++config MVSWITCH_PHY ++ tristate "Driver for Marvell 88E6060 switches" ++ select ETHERNET_PACKET_MANGLE ++ + config FIXED_PHY + tristate "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs" + depends on PHYLIB +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -19,6 +19,7 @@ obj-$(CONFIG_BCM7XXX_PHY) += bcm7xxx.o + obj-$(CONFIG_BCM87XX_PHY) += bcm87xx.o + obj-$(CONFIG_ICPLUS_PHY) += icplus.o + obj-$(CONFIG_ADM6996_PHY) += adm6996.o ++obj-$(CONFIG_MVSWITCH_PHY) += mvswitch.o + obj-$(CONFIG_REALTEK_PHY) += realtek.o + obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o + obj-$(CONFIG_FIXED_PHY) += fixed_phy.o diff --git a/target/linux/generic/patches-4.0/723-phy_ip175c.patch b/target/linux/generic/patches-4.0/723-phy_ip175c.patch new file mode 100644 index 0000000..c8e1dcb --- /dev/null +++ b/target/linux/generic/patches-4.0/723-phy_ip175c.patch @@ -0,0 +1,23 @@ +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -143,6 +143,10 @@ config MVSWITCH_PHY + tristate "Driver for Marvell 88E6060 switches" + select ETHERNET_PACKET_MANGLE + ++config IP17XX_PHY ++ tristate "Driver for IC+ IP17xx switches" ++ select SWCONFIG ++ + config FIXED_PHY + tristate "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs" + depends on PHYLIB +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -20,6 +20,7 @@ obj-$(CONFIG_BCM87XX_PHY) += bcm87xx.o + obj-$(CONFIG_ICPLUS_PHY) += icplus.o + obj-$(CONFIG_ADM6996_PHY) += adm6996.o + obj-$(CONFIG_MVSWITCH_PHY) += mvswitch.o ++obj-$(CONFIG_IP17XX_PHY) += ip17xx.o + obj-$(CONFIG_REALTEK_PHY) += realtek.o + obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o + obj-$(CONFIG_FIXED_PHY) += fixed_phy.o diff --git a/target/linux/generic/patches-4.0/724-phy_ar8216.patch b/target/linux/generic/patches-4.0/724-phy_ar8216.patch new file mode 100644 index 0000000..37602fa --- /dev/null +++ b/target/linux/generic/patches-4.0/724-phy_ar8216.patch @@ -0,0 +1,24 @@ +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -147,6 +147,11 @@ config IP17XX_PHY + tristate "Driver for IC+ IP17xx switches" + select SWCONFIG + ++config AR8216_PHY ++ tristate "Driver for Atheros AR8216 switches" ++ select ETHERNET_PACKET_MANGLE ++ select SWCONFIG ++ + config FIXED_PHY + tristate "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs" + depends on PHYLIB +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -22,6 +22,7 @@ obj-$(CONFIG_ADM6996_PHY) += adm6996.o + obj-$(CONFIG_MVSWITCH_PHY) += mvswitch.o + obj-$(CONFIG_IP17XX_PHY) += ip17xx.o + obj-$(CONFIG_REALTEK_PHY) += realtek.o ++obj-$(CONFIG_AR8216_PHY) += ar8216.o ar8327.o + obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o + obj-$(CONFIG_FIXED_PHY) += fixed_phy.o + obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o diff --git a/target/linux/generic/patches-4.0/725-phy_rtl8306.patch b/target/linux/generic/patches-4.0/725-phy_rtl8306.patch new file mode 100644 index 0000000..af6083b --- /dev/null +++ b/target/linux/generic/patches-4.0/725-phy_rtl8306.patch @@ -0,0 +1,23 @@ +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -152,6 +152,10 @@ config AR8216_PHY + select ETHERNET_PACKET_MANGLE + select SWCONFIG + ++config RTL8306_PHY ++ tristate "Driver for Realtek RTL8306S switches" ++ select SWCONFIG ++ + config FIXED_PHY + tristate "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs" + depends on PHYLIB +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -23,6 +23,7 @@ obj-$(CONFIG_MVSWITCH_PHY) += mvswitch.o + obj-$(CONFIG_IP17XX_PHY) += ip17xx.o + obj-$(CONFIG_REALTEK_PHY) += realtek.o + obj-$(CONFIG_AR8216_PHY) += ar8216.o ar8327.o ++obj-$(CONFIG_RTL8306_PHY) += rtl8306.o + obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o + obj-$(CONFIG_FIXED_PHY) += fixed_phy.o + obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o diff --git a/target/linux/generic/patches-4.0/726-phy_rtl8366.patch b/target/linux/generic/patches-4.0/726-phy_rtl8366.patch new file mode 100644 index 0000000..3213f1e --- /dev/null +++ b/target/linux/generic/patches-4.0/726-phy_rtl8366.patch @@ -0,0 +1,45 @@ +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -250,6 +250,30 @@ config MDIO_BCM_UNIMAC + controllers as well as some Broadcom Ethernet switches such as the + Starfighter 2 switches. + ++config RTL8366_SMI ++ tristate "Driver for the RTL8366 SMI interface" ++ depends on GPIOLIB ++ ---help--- ++ This module implements the SMI interface protocol which is used ++ by some RTL8366 ethernet switch devices via the generic GPIO API. ++ ++if RTL8366_SMI ++ ++config RTL8366_SMI_DEBUG_FS ++ bool "RTL8366 SMI interface debugfs support" ++ depends on DEBUG_FS ++ default n ++ ++config RTL8366S_PHY ++ tristate "Driver for the Realtek RTL8366S switch" ++ select SWCONFIG ++ ++config RTL8366RB_PHY ++ tristate "Driver for the Realtek RTL8366RB switch" ++ select SWCONFIG ++ ++endif # RTL8366_SMI ++ + endif # PHYLIB + + config MICREL_KS8995MA +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -24,6 +24,9 @@ obj-$(CONFIG_IP17XX_PHY) += ip17xx.o + obj-$(CONFIG_REALTEK_PHY) += realtek.o + obj-$(CONFIG_AR8216_PHY) += ar8216.o ar8327.o + obj-$(CONFIG_RTL8306_PHY) += rtl8306.o ++obj-$(CONFIG_RTL8366_SMI) += rtl8366_smi.o ++obj-$(CONFIG_RTL8366S_PHY) += rtl8366s.o ++obj-$(CONFIG_RTL8366RB_PHY) += rtl8366rb.o + obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o + obj-$(CONFIG_FIXED_PHY) += fixed_phy.o + obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o diff --git a/target/linux/generic/patches-4.0/727-phy-rtl8367.patch b/target/linux/generic/patches-4.0/727-phy-rtl8367.patch new file mode 100644 index 0000000..6fbe34c --- /dev/null +++ b/target/linux/generic/patches-4.0/727-phy-rtl8367.patch @@ -0,0 +1,23 @@ +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -272,6 +272,10 @@ config RTL8366RB_PHY + tristate "Driver for the Realtek RTL8366RB switch" + select SWCONFIG + ++config RTL8367_PHY ++ tristate "Driver for the Realtek RTL8367R/M switches" ++ select SWCONFIG ++ + endif # RTL8366_SMI + + endif # PHYLIB +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -27,6 +27,7 @@ obj-$(CONFIG_RTL8306_PHY) += rtl8306.o + obj-$(CONFIG_RTL8366_SMI) += rtl8366_smi.o + obj-$(CONFIG_RTL8366S_PHY) += rtl8366s.o + obj-$(CONFIG_RTL8366RB_PHY) += rtl8366rb.o ++obj-$(CONFIG_RTL8367_PHY) += rtl8367.o + obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o + obj-$(CONFIG_FIXED_PHY) += fixed_phy.o + obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o diff --git a/target/linux/generic/patches-4.0/728-phy-rtl8367b.patch b/target/linux/generic/patches-4.0/728-phy-rtl8367b.patch new file mode 100644 index 0000000..2053b52 --- /dev/null +++ b/target/linux/generic/patches-4.0/728-phy-rtl8367b.patch @@ -0,0 +1,23 @@ +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -276,6 +276,10 @@ config RTL8367_PHY + tristate "Driver for the Realtek RTL8367R/M switches" + select SWCONFIG + ++config RTL8367B_PHY ++ tristate "Driver fot the Realtek RTL8367R-VB switch" ++ select SWCONFIG ++ + endif # RTL8366_SMI + + endif # PHYLIB +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -28,6 +28,7 @@ obj-$(CONFIG_RTL8366_SMI) += rtl8366_smi + obj-$(CONFIG_RTL8366S_PHY) += rtl8366s.o + obj-$(CONFIG_RTL8366RB_PHY) += rtl8366rb.o + obj-$(CONFIG_RTL8367_PHY) += rtl8367.o ++obj-$(CONFIG_RTL8367B_PHY) += rtl8367b.o + obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o + obj-$(CONFIG_FIXED_PHY) += fixed_phy.o + obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o diff --git a/target/linux/generic/patches-4.0/729-phy-tantos.patch b/target/linux/generic/patches-4.0/729-phy-tantos.patch new file mode 100644 index 0000000..fca3ceb --- /dev/null +++ b/target/linux/generic/patches-4.0/729-phy-tantos.patch @@ -0,0 +1,21 @@ +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -287,3 +287,8 @@ endif # PHYLIB + config MICREL_KS8995MA + tristate "Micrel KS8995MA 5-ports 10/100 managed Ethernet switch" + depends on SPI ++ ++config PSB6970_PHY ++ tristate "Lantiq XWAY Tantos (PSB6970) Ethernet switch" ++ select SWCONFIG ++ select ETHERNET_PACKET_MANGLE +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -30,6 +30,7 @@ obj-$(CONFIG_RTL8366RB_PHY) += rtl8366rb + obj-$(CONFIG_RTL8367_PHY) += rtl8367.o + obj-$(CONFIG_RTL8367B_PHY) += rtl8367b.o + obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o ++obj-$(CONFIG_PSB6970_PHY) += psb6970.o + obj-$(CONFIG_FIXED_PHY) += fixed_phy.o + obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o + obj-$(CONFIG_MDIO_GPIO) += mdio-gpio.o diff --git a/target/linux/generic/patches-4.0/730-phy_b53.patch b/target/linux/generic/patches-4.0/730-phy_b53.patch new file mode 100644 index 0000000..7e3a117 --- /dev/null +++ b/target/linux/generic/patches-4.0/730-phy_b53.patch @@ -0,0 +1,21 @@ +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -282,6 +282,8 @@ config RTL8367B_PHY + + endif # RTL8366_SMI + ++source "drivers/net/phy/b53/Kconfig" ++ + endif # PHYLIB + + config MICREL_KS8995MA +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -31,6 +31,7 @@ obj-$(CONFIG_RTL8367_PHY) += rtl8367.o + obj-$(CONFIG_RTL8367B_PHY) += rtl8367b.o + obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o + obj-$(CONFIG_PSB6970_PHY) += psb6970.o ++obj-$(CONFIG_B53) += b53/ + obj-$(CONFIG_FIXED_PHY) += fixed_phy.o + obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o + obj-$(CONFIG_MDIO_GPIO) += mdio-gpio.o diff --git a/target/linux/generic/patches-4.0/731-phy_mvswitch_3.10_compilation.patch b/target/linux/generic/patches-4.0/731-phy_mvswitch_3.10_compilation.patch new file mode 100644 index 0000000..2053bd2 --- /dev/null +++ b/target/linux/generic/patches-4.0/731-phy_mvswitch_3.10_compilation.patch @@ -0,0 +1,35 @@ +From e6a5abb9a02be0bceb4782d9f736bfb4ae217505 Mon Sep 17 00:00:00 2001 +From: Jonas Gorski +Date: Sat, 21 Sep 2013 13:56:51 +0200 +Subject: [PATCH] phy: mvswitch: fix 3.10 compilation + +Update to API changes in 3.10. + +Signed-off-by: Jonas Gorsi +--- + target/linux/generic/files/drivers/net/phy/mvswitch.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/drivers/net/phy/mvswitch.c ++++ b/drivers/net/phy/mvswitch.c +@@ -173,7 +173,7 @@ mvswitch_mangle_rx(struct net_device *de + if (vlan == -1) + return; + +- __vlan_hwaccel_put_tag(skb, vlan); ++ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan); + } + + +@@ -307,9 +307,9 @@ mvswitch_config_init(struct phy_device * + + #ifdef HEADER_MODE + dev->priv_flags |= IFF_NO_IP_ALIGN; +- dev->features |= NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_TX; ++ dev->features |= NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_TX; + #else +- dev->features |= NETIF_F_HW_VLAN_RX; ++ dev->features |= NETIF_F_HW_VLAN_CTAG_RX; + #endif + + return 0; diff --git a/target/linux/generic/patches-4.0/732-phy-ar8216-led-support.patch b/target/linux/generic/patches-4.0/732-phy-ar8216-led-support.patch new file mode 100644 index 0000000..c753967 --- /dev/null +++ b/target/linux/generic/patches-4.0/732-phy-ar8216-led-support.patch @@ -0,0 +1,13 @@ +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -152,6 +152,10 @@ config AR8216_PHY + select ETHERNET_PACKET_MANGLE + select SWCONFIG + ++config AR8216_PHY_LEDS ++ bool "Atheros AR8216 switch LED support" ++ depends on (AR8216_PHY && LEDS_CLASS) ++ + config RTL8306_PHY + tristate "Driver for Realtek RTL8306S switches" + select SWCONFIG diff --git a/target/linux/generic/patches-4.0/733-phy_mvsw61xx.patch b/target/linux/generic/patches-4.0/733-phy_mvsw61xx.patch new file mode 100644 index 0000000..041d168 --- /dev/null +++ b/target/linux/generic/patches-4.0/733-phy_mvsw61xx.patch @@ -0,0 +1,23 @@ +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -143,6 +143,10 @@ config MVSWITCH_PHY + tristate "Driver for Marvell 88E6060 switches" + select ETHERNET_PACKET_MANGLE + ++config MVSW61XX_PHY ++ tristate "Driver for Marvell 88E6171/6172 switches" ++ select SWCONFIG ++ + config IP17XX_PHY + tristate "Driver for IC+ IP17xx switches" + select SWCONFIG +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -20,6 +20,7 @@ obj-$(CONFIG_BCM87XX_PHY) += bcm87xx.o + obj-$(CONFIG_ICPLUS_PHY) += icplus.o + obj-$(CONFIG_ADM6996_PHY) += adm6996.o + obj-$(CONFIG_MVSWITCH_PHY) += mvswitch.o ++obj-$(CONFIG_MVSW61XX_PHY) += mvsw61xx.o + obj-$(CONFIG_IP17XX_PHY) += ip17xx.o + obj-$(CONFIG_REALTEK_PHY) += realtek.o + obj-$(CONFIG_AR8216_PHY) += ar8216.o ar8327.o diff --git a/target/linux/generic/patches-4.0/750-hostap_txpower.patch b/target/linux/generic/patches-4.0/750-hostap_txpower.patch new file mode 100644 index 0000000..768c80f --- /dev/null +++ b/target/linux/generic/patches-4.0/750-hostap_txpower.patch @@ -0,0 +1,154 @@ +--- a/drivers/net/wireless/hostap/hostap_ap.c ++++ b/drivers/net/wireless/hostap/hostap_ap.c +@@ -2403,13 +2403,13 @@ int prism2_ap_get_sta_qual(local_info_t + addr[count].sa_family = ARPHRD_ETHER; + memcpy(addr[count].sa_data, sta->addr, ETH_ALEN); + if (sta->last_rx_silence == 0) +- qual[count].qual = sta->last_rx_signal < 27 ? +- 0 : (sta->last_rx_signal - 27) * 92 / 127; ++ qual[count].qual = (sta->last_rx_signal - 156) == 0 ? ++ 0 : (sta->last_rx_signal - 156) * 92 / 64; + else +- qual[count].qual = sta->last_rx_signal - +- sta->last_rx_silence - 35; +- qual[count].level = HFA384X_LEVEL_TO_dBm(sta->last_rx_signal); +- qual[count].noise = HFA384X_LEVEL_TO_dBm(sta->last_rx_silence); ++ qual[count].qual = (sta->last_rx_signal - ++ sta->last_rx_silence) * 92 / 64; ++ qual[count].level = sta->last_rx_signal; ++ qual[count].noise = sta->last_rx_silence; + qual[count].updated = sta->last_rx_updated; + + sta->last_rx_updated = IW_QUAL_DBM; +@@ -2475,13 +2475,13 @@ int prism2_ap_translate_scan(struct net_ + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = IWEVQUAL; + if (sta->last_rx_silence == 0) +- iwe.u.qual.qual = sta->last_rx_signal < 27 ? +- 0 : (sta->last_rx_signal - 27) * 92 / 127; ++ iwe.u.qual.qual = (sta->last_rx_signal -156) == 0 ? ++ 0 : (sta->last_rx_signal - 156) * 92 / 64; + else +- iwe.u.qual.qual = sta->last_rx_signal - +- sta->last_rx_silence - 35; +- iwe.u.qual.level = HFA384X_LEVEL_TO_dBm(sta->last_rx_signal); +- iwe.u.qual.noise = HFA384X_LEVEL_TO_dBm(sta->last_rx_silence); ++ iwe.u.qual.qual = (sta->last_rx_signal - ++ sta->last_rx_silence) * 92 / 64; ++ iwe.u.qual.level = sta->last_rx_signal; ++ iwe.u.qual.noise = sta->last_rx_silence; + iwe.u.qual.updated = sta->last_rx_updated; + iwe.len = IW_EV_QUAL_LEN; + current_ev = iwe_stream_add_event(info, current_ev, end_buf, +--- a/drivers/net/wireless/hostap/hostap_config.h ++++ b/drivers/net/wireless/hostap/hostap_config.h +@@ -45,4 +45,9 @@ + */ + /* #define PRISM2_NO_STATION_MODES */ + ++/* Enable TX power Setting functions ++ * (min att = -128 , max att = 127) ++ */ ++#define RAW_TXPOWER_SETTING ++ + #endif /* HOSTAP_CONFIG_H */ +--- a/drivers/net/wireless/hostap/hostap.h ++++ b/drivers/net/wireless/hostap/hostap.h +@@ -90,6 +90,7 @@ extern const struct iw_handler_def hosta + extern const struct ethtool_ops prism2_ethtool_ops; + + int hostap_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); ++int hostap_restore_power(struct net_device *dev); + + + #endif /* HOSTAP_H */ +--- a/drivers/net/wireless/hostap/hostap_hw.c ++++ b/drivers/net/wireless/hostap/hostap_hw.c +@@ -928,6 +928,7 @@ static int hfa384x_set_rid(struct net_de + prism2_hw_reset(dev); + } + ++ hostap_restore_power(dev); + return res; + } + +--- a/drivers/net/wireless/hostap/hostap_info.c ++++ b/drivers/net/wireless/hostap/hostap_info.c +@@ -435,6 +435,11 @@ static void handle_info_queue_linkstatus + } + + /* Get BSSID if we have a valid AP address */ ++ ++ if ( val == HFA384X_LINKSTATUS_CONNECTED || ++ val == HFA384X_LINKSTATUS_DISCONNECTED ) ++ hostap_restore_power(local->dev); ++ + if (connected) { + netif_carrier_on(local->dev); + netif_carrier_on(local->ddev); +--- a/drivers/net/wireless/hostap/hostap_ioctl.c ++++ b/drivers/net/wireless/hostap/hostap_ioctl.c +@@ -1479,23 +1479,20 @@ static int prism2_txpower_hfa386x_to_dBm + val = 255; + + tmp = val; +- tmp >>= 2; + +- return -12 - tmp; ++ return tmp; + } + + static u16 prism2_txpower_dBm_to_hfa386x(int val) + { + signed char tmp; + +- if (val > 20) +- return 128; +- else if (val < -43) ++ if (val > 127) + return 127; ++ else if (val < -128) ++ return 128; + + tmp = val; +- tmp = -12 - tmp; +- tmp <<= 2; + + return (unsigned char) tmp; + } +@@ -4052,3 +4049,35 @@ int hostap_ioctl(struct net_device *dev, + + return ret; + } ++ ++/* BUG FIX: Restore power setting value when lost due to F/W bug */ ++ ++int hostap_restore_power(struct net_device *dev) ++{ ++ struct hostap_interface *iface = netdev_priv(dev); ++ local_info_t *local = iface->local; ++ ++ u16 val; ++ int ret = 0; ++ ++ if (local->txpower_type == PRISM2_TXPOWER_OFF) { ++ val = 0xff; /* use all standby and sleep modes */ ++ ret = local->func->cmd(dev, HFA384X_CMDCODE_WRITEMIF, ++ HFA386X_CR_A_D_TEST_MODES2, ++ &val, NULL); ++ } ++ ++#ifdef RAW_TXPOWER_SETTING ++ if (local->txpower_type == PRISM2_TXPOWER_FIXED) { ++ val = HFA384X_TEST_CFG_BIT_ALC; ++ local->func->cmd(dev, HFA384X_CMDCODE_TEST | ++ (HFA384X_TEST_CFG_BITS << 8), 0, &val, NULL); ++ val = prism2_txpower_dBm_to_hfa386x(local->txpower); ++ ret = (local->func->cmd(dev, HFA384X_CMDCODE_WRITEMIF, ++ HFA386X_CR_MANUAL_TX_POWER, &val, NULL)); ++ } ++#endif /* RAW_TXPOWER_SETTING */ ++ return (ret ? -EOPNOTSUPP : 0); ++} ++ ++EXPORT_SYMBOL(hostap_restore_power); diff --git a/target/linux/generic/patches-4.0/773-bgmac-add-srab-switch.patch b/target/linux/generic/patches-4.0/773-bgmac-add-srab-switch.patch new file mode 100644 index 0000000..b883d73 --- /dev/null +++ b/target/linux/generic/patches-4.0/773-bgmac-add-srab-switch.patch @@ -0,0 +1,72 @@ +Register switch connected to srab + +Signed-off-by: Hauke Mehrtens + +--- a/drivers/net/ethernet/broadcom/bgmac.c ++++ b/drivers/net/ethernet/broadcom/bgmac.c +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + #include + + static const struct bcma_device_id bgmac_bcma_tbl[] = { +@@ -1538,6 +1539,17 @@ static void bgmac_mii_unregister(struct + mdiobus_free(mii_bus); + } + ++static struct b53_platform_data bgmac_b53_pdata = { ++}; ++ ++static struct platform_device bgmac_b53_dev = { ++ .name = "b53-srab-switch", ++ .id = -1, ++ .dev = { ++ .platform_data = &bgmac_b53_pdata, ++ }, ++}; ++ + /************************************************** + * BCMA bus ops + **************************************************/ +@@ -1664,6 +1676,16 @@ static int bgmac_probe(struct bcma_devic + net_dev->hw_features = net_dev->features; + net_dev->vlan_features = net_dev->features; + ++ if ((ci->id == BCMA_CHIP_ID_BCM4707 || ++ ci->id == BCMA_CHIP_ID_BCM53018) && ++ !bgmac_b53_pdata.regs) { ++ bgmac_b53_pdata.regs = ioremap_nocache(0x18007000, 0x1000); ++ ++ err = platform_device_register(&bgmac_b53_dev); ++ if (!err) ++ bgmac->b53_device = &bgmac_b53_dev; ++ } ++ + err = register_netdev(bgmac->net_dev); + if (err) { + bgmac_err(bgmac, "Cannot register net device\n"); +@@ -1690,6 +1712,10 @@ static void bgmac_remove(struct bcma_dev + { + struct bgmac *bgmac = bcma_get_drvdata(core); + ++ if (bgmac->b53_device) ++ platform_device_unregister(&bgmac_b53_dev); ++ bgmac->b53_device = NULL; ++ + unregister_netdev(bgmac->net_dev); + bgmac_mii_unregister(bgmac); + netif_napi_del(&bgmac->napi); +--- a/drivers/net/ethernet/broadcom/bgmac.h ++++ b/drivers/net/ethernet/broadcom/bgmac.h +@@ -462,6 +462,9 @@ struct bgmac { + bool has_robosw; + + bool loopback; ++ ++ /* platform device for associated switch */ ++ struct platform_device *b53_device; + }; + + static inline u32 bgmac_read(struct bgmac *bgmac, u16 offset) diff --git a/target/linux/generic/patches-4.0/780-igb-Fix-Null-pointer-dereference-in-igb_reset_q_vect.patch b/target/linux/generic/patches-4.0/780-igb-Fix-Null-pointer-dereference-in-igb_reset_q_vect.patch new file mode 100644 index 0000000..2603d6c --- /dev/null +++ b/target/linux/generic/patches-4.0/780-igb-Fix-Null-pointer-dereference-in-igb_reset_q_vect.patch @@ -0,0 +1,40 @@ +From cb06d102327eadcd1bdc480bfd9f8876251d1007 Mon Sep 17 00:00:00 2001 +From: Christoph Paasch +Date: Fri, 21 Mar 2014 03:48:19 -0700 +Subject: [PATCH] igb: Fix Null-pointer dereference in igb_reset_q_vector + +When igb_set_interrupt_capability() calls +igb_reset_interrupt_capability() (e.g., because CONFIG_PCI_MSI is unset), +num_q_vectors has been set but no vector has yet been allocated. + +igb_reset_interrupt_capability() will then call igb_reset_q_vector, +which assumes that the vector is allocated. As this is not the case, we +are accessing a NULL-pointer. + +This patch fixes it by checking that q_vector is indeed different from +NULL. + +Fixes: 02ef6e1d0b0023 (igb: Fix queue allocation method to accommodate changing during runtime) +Cc: Carolyn Wyborny +Signed-off-by: Christoph Paasch +Tested-by: Jeff Pieper +Signed-off-by: Jeff Kirsher +--- + drivers/net/ethernet/intel/igb/igb_main.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/drivers/net/ethernet/intel/igb/igb_main.c ++++ b/drivers/net/ethernet/intel/igb/igb_main.c +@@ -1032,6 +1032,12 @@ static void igb_reset_q_vector(struct ig + if (!q_vector) + return; + ++ /* Coming from igb_set_interrupt_capability, the vectors are not yet ++ * allocated. So, q_vector is NULL so we should stop here. ++ */ ++ if (!q_vector) ++ return; ++ + if (q_vector->tx.ring) + adapter->tx_ring[q_vector->tx.ring->queue_index] = NULL; + diff --git a/target/linux/generic/patches-4.0/785-hso-support-0af0-9300.patch b/target/linux/generic/patches-4.0/785-hso-support-0af0-9300.patch new file mode 100644 index 0000000..621d08f --- /dev/null +++ b/target/linux/generic/patches-4.0/785-hso-support-0af0-9300.patch @@ -0,0 +1,25 @@ +--- a/drivers/net/usb/hso.c ++++ b/drivers/net/usb/hso.c +@@ -466,6 +466,7 @@ static const struct usb_device_id hso_id + {USB_DEVICE(0x0af0, 0x8900)}, + {USB_DEVICE(0x0af0, 0x9000)}, + {USB_DEVICE(0x0af0, 0x9200)}, /* Option GTM671WFS */ ++ {USB_DEVICE(0x0af0, 0x9300)}, /* GTM 66xxWFS */ + {USB_DEVICE(0x0af0, 0xd035)}, + {USB_DEVICE(0x0af0, 0xd055)}, + {USB_DEVICE(0x0af0, 0xd155)}, +--- a/drivers/usb/storage/unusual_devs.h ++++ b/drivers/usb/storage/unusual_devs.h +@@ -1330,6 +1330,12 @@ UNUSUAL_DEV( 0x0af0, 0x8304, 0x0000, 0x0 + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + 0 ), + ++UNUSUAL_DEV( 0x0af0, 0x9300, 0x0000, 0x0000, ++ "Option", ++ "Globetrotter 66xxWFS SD-Card", ++ USB_SC_DEVICE, USB_PR_DEVICE, NULL, ++ 0 ), ++ + UNUSUAL_DEV( 0x0af0, 0xc100, 0x0000, 0x0000, + "Option", + "GI 070x SD-Card", diff --git a/target/linux/generic/patches-4.0/810-pci_disable_common_quirks.patch b/target/linux/generic/patches-4.0/810-pci_disable_common_quirks.patch new file mode 100644 index 0000000..8f72637 --- /dev/null +++ b/target/linux/generic/patches-4.0/810-pci_disable_common_quirks.patch @@ -0,0 +1,51 @@ +--- a/drivers/pci/Kconfig ++++ b/drivers/pci/Kconfig +@@ -68,6 +68,12 @@ config XEN_PCIDEV_FRONTEND + The PCI device frontend driver allows the kernel to import arbitrary + PCI devices from a PCI backend to support PCI driver domains. + ++config PCI_DISABLE_COMMON_QUIRKS ++ bool "PCI disable common quirks" ++ depends on PCI ++ help ++ If you don't know what to do here, say N. ++ + config HT_IRQ + bool "Interrupts on hypertransport devices" + default y +--- a/drivers/pci/quirks.c ++++ b/drivers/pci/quirks.c +@@ -41,6 +41,7 @@ static void quirk_mmio_always_on(struct + DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_BRIDGE_HOST, 8, quirk_mmio_always_on); + ++#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS + /* The Mellanox Tavor device gives false positive parity errors + * Mark this device with a broken_parity_status, to allow + * PCI scanning code to "skip" this now blacklisted device. +@@ -2925,6 +2926,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_I + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x65f9, quirk_intel_mc_errata); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x65fa, quirk_intel_mc_errata); + ++#endif /* !CONFIG_PCI_DISABLE_COMMON_QUIRKS */ + + /* + * Ivytown NTB BAR sizes are misreported by the hardware due to an erratum. To +@@ -2981,6 +2983,8 @@ static void fixup_debug_report(struct pc + } + } + ++#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS ++ + /* + * Some BIOS implementations leave the Intel GPU interrupts enabled, + * even though no one is handling them (f.e. i915 driver is never loaded). +@@ -3015,6 +3019,8 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_IN + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x010a, disable_igfx_irq); + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0152, disable_igfx_irq); + ++#endif /* !CONFIG_PCI_DISABLE_COMMON_QUIRKS */ ++ + /* + * PCI devices which are on Intel chips can skip the 10ms delay + * before entering D3 mode. diff --git a/target/linux/generic/patches-4.0/811-pci_disable_usb_common_quirks.patch b/target/linux/generic/patches-4.0/811-pci_disable_usb_common_quirks.patch new file mode 100644 index 0000000..6de4f6b --- /dev/null +++ b/target/linux/generic/patches-4.0/811-pci_disable_usb_common_quirks.patch @@ -0,0 +1,101 @@ + +--- a/drivers/usb/host/pci-quirks.c ++++ b/drivers/usb/host/pci-quirks.c +@@ -97,6 +97,8 @@ struct amd_chipset_type { + u8 rev; + }; + ++#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS ++ + static struct amd_chipset_info { + struct pci_dev *nb_dev; + struct pci_dev *smbus_dev; +@@ -450,6 +452,10 @@ void usb_amd_dev_put(void) + } + EXPORT_SYMBOL_GPL(usb_amd_dev_put); + ++#endif /* CONFIG_PCI_DISABLE_COMMON_QUIRKS */ ++ ++#if IS_ENABLED(CONFIG_USB_UHCI_HCD) ++ + /* + * Make sure the controller is completely inactive, unable to + * generate interrupts or do DMA. +@@ -529,8 +535,17 @@ reset_needed: + uhci_reset_hc(pdev, base); + return 1; + } ++#else ++int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base) ++{ ++ return 0; ++} ++ ++#endif + EXPORT_SYMBOL_GPL(uhci_check_and_reset_hc); + ++#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS ++ + static inline int io_type_enabled(struct pci_dev *pdev, unsigned int mask) + { + u16 cmd; +@@ -1095,3 +1110,4 @@ static void quirk_usb_early_handoff(stru + } + DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_SERIAL_USB, 8, quirk_usb_early_handoff); ++#endif +--- a/drivers/usb/host/pci-quirks.h ++++ b/drivers/usb/host/pci-quirks.h +@@ -4,6 +4,9 @@ + #ifdef CONFIG_PCI + void uhci_reset_hc(struct pci_dev *pdev, unsigned long base); + int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base); ++#endif /* CONFIG_PCI */ ++ ++#if defined(CONFIG_PCI) && !defined(CONFIG_PCI_DISABLE_COMMON_QUIRKS) + int usb_amd_find_chipset_info(void); + int usb_hcd_amd_remote_wakeup_quirk(struct pci_dev *pdev); + bool usb_amd_hang_symptom_quirk(void); +@@ -16,11 +19,24 @@ void usb_disable_xhci_ports(struct pci_d + void sb800_prefetch(struct device *dev, int on); + #else + struct pci_dev; ++static inline int usb_amd_find_chipset_info(void) ++{ ++ return 0; ++} ++static inline bool usb_amd_hang_symptom_quirk(void) ++{ ++ return false; ++} ++static inline bool usb_amd_prefetch_quirk(void) ++{ ++ return false; ++} + static inline void usb_amd_quirk_pll_disable(void) {} + static inline void usb_amd_quirk_pll_enable(void) {} + static inline void usb_amd_dev_put(void) {} + static inline void usb_disable_xhci_ports(struct pci_dev *xhci_pdev) {} + static inline void sb800_prefetch(struct device *dev, int on) {} +-#endif /* CONFIG_PCI */ ++static inline void usb_enable_intel_xhci_ports(struct pci_dev *xhci_pdev) {} ++#endif + + #endif /* __LINUX_USB_PCI_QUIRKS_H */ +--- a/include/linux/usb/hcd.h ++++ b/include/linux/usb/hcd.h +@@ -447,7 +447,14 @@ extern int usb_hcd_pci_probe(struct pci_ + extern void usb_hcd_pci_remove(struct pci_dev *dev); + extern void usb_hcd_pci_shutdown(struct pci_dev *dev); + ++#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS + extern int usb_hcd_amd_remote_wakeup_quirk(struct pci_dev *dev); ++#else ++static inline int usb_hcd_amd_remote_wakeup_quirk(struct pci_dev *dev) ++{ ++ return 0; ++} ++#endif + + #ifdef CONFIG_PM + extern const struct dev_pm_ops usb_hcd_pci_pm_ops; diff --git a/target/linux/generic/patches-4.0/820-usb_add_usb_find_device_by_name.patch b/target/linux/generic/patches-4.0/820-usb_add_usb_find_device_by_name.patch new file mode 100644 index 0000000..96cadf3 --- /dev/null +++ b/target/linux/generic/patches-4.0/820-usb_add_usb_find_device_by_name.patch @@ -0,0 +1,84 @@ +--- a/drivers/usb/core/usb.c ++++ b/drivers/usb/core/usb.c +@@ -688,6 +688,71 @@ int __usb_get_extra_descriptor(char *buf + } + EXPORT_SYMBOL_GPL(__usb_get_extra_descriptor); + ++static struct usb_device *match_device_name(struct usb_device *dev, ++ const char *name) ++{ ++ struct usb_device *ret_dev = NULL; ++ struct usb_device *childdev = NULL; ++ int child; ++ ++ dev_dbg(&dev->dev, "check for name %s ...\n", name); ++ ++ /* see if this device matches */ ++ if (strcmp(dev_name(&dev->dev), name) == 0 ) { ++ dev_dbg(&dev->dev, "matched this device!\n"); ++ ret_dev = usb_get_dev(dev); ++ goto exit; ++ } ++ /* look through all of the children of this device */ ++ usb_hub_for_each_child(dev, child, childdev) { ++ if (childdev) { ++ usb_lock_device(childdev); ++ ret_dev = match_device_name(childdev, name); ++ usb_unlock_device(childdev); ++ if (ret_dev) ++ goto exit; ++ } ++ } ++exit: ++ return ret_dev; ++} ++ ++/** ++ * usb_find_device_by_name - find a specific usb device in the system ++ * @name: the name of the device to find ++ * ++ * Returns a pointer to a struct usb_device if such a specified usb ++ * device is present in the system currently. The usage count of the ++ * device will be incremented if a device is found. Make sure to call ++ * usb_put_dev() when the caller is finished with the device. ++ * ++ * If a device with the specified bus id is not found, NULL is returned. ++ */ ++struct usb_device *usb_find_device_by_name(const char *name) ++{ ++ struct list_head *buslist; ++ struct usb_bus *bus; ++ struct usb_device *dev = NULL; ++ ++ mutex_lock(&usb_bus_list_lock); ++ for (buslist = usb_bus_list.next; ++ buslist != &usb_bus_list; ++ buslist = buslist->next) { ++ bus = container_of(buslist, struct usb_bus, bus_list); ++ if (!bus->root_hub) ++ continue; ++ usb_lock_device(bus->root_hub); ++ dev = match_device_name(bus->root_hub, name); ++ usb_unlock_device(bus->root_hub); ++ if (dev) ++ goto exit; ++ } ++exit: ++ mutex_unlock(&usb_bus_list_lock); ++ return dev; ++} ++EXPORT_SYMBOL_GPL(usb_find_device_by_name); ++ + /** + * usb_alloc_coherent - allocate dma-consistent buffer for URB_NO_xxx_DMA_MAP + * @dev: device the buffer will be used with +--- a/include/linux/usb.h ++++ b/include/linux/usb.h +@@ -721,6 +721,7 @@ static inline bool usb_device_no_sg_cons + return udev && udev->bus && udev->bus->no_sg_constraint; + } + ++extern struct usb_device *usb_find_device_by_name(const char *name); + + /*-------------------------------------------------------------------------*/ + diff --git a/target/linux/generic/patches-4.0/830-ledtrig_morse.patch b/target/linux/generic/patches-4.0/830-ledtrig_morse.patch new file mode 100644 index 0000000..97cc33c --- /dev/null +++ b/target/linux/generic/patches-4.0/830-ledtrig_morse.patch @@ -0,0 +1,28 @@ +--- a/drivers/leds/trigger/Kconfig ++++ b/drivers/leds/trigger/Kconfig +@@ -108,4 +108,8 @@ config LEDS_TRIGGER_CAMERA + This enables direct flash/torch on/off by the driver, kernel space. + If unsure, say Y. + ++config LEDS_TRIGGER_MORSE ++ tristate "LED Morse Trigger" ++ depends on LEDS_TRIGGERS ++ + endif # LEDS_TRIGGERS +--- a/drivers/leds/Makefile ++++ b/drivers/leds/Makefile +@@ -64,3 +64,4 @@ obj-$(CONFIG_LEDS_DAC124S085) += leds-d + + # LED Triggers + obj-$(CONFIG_LEDS_TRIGGERS) += trigger/ ++obj-$(CONFIG_LEDS_TRIGGER_MORSE) += ledtrig-morse.o +--- a/drivers/leds/ledtrig-morse.c ++++ b/drivers/leds/ledtrig-morse.c +@@ -26,7 +26,6 @@ + #include + #include + #include +-#include + #include + #include + #include diff --git a/target/linux/generic/patches-4.0/831-ledtrig_netdev.patch b/target/linux/generic/patches-4.0/831-ledtrig_netdev.patch new file mode 100644 index 0000000..29a2cca --- /dev/null +++ b/target/linux/generic/patches-4.0/831-ledtrig_netdev.patch @@ -0,0 +1,60 @@ +--- a/drivers/leds/trigger/Kconfig ++++ b/drivers/leds/trigger/Kconfig +@@ -112,4 +112,11 @@ config LEDS_TRIGGER_MORSE + tristate "LED Morse Trigger" + depends on LEDS_TRIGGERS + ++config LEDS_TRIGGER_NETDEV ++ tristate "LED Netdev Trigger" ++ depends on NET && LEDS_TRIGGERS ++ help ++ This allows LEDs to be controlled by network device activity. ++ If unsure, say Y. ++ + endif # LEDS_TRIGGERS +--- a/drivers/leds/Makefile ++++ b/drivers/leds/Makefile +@@ -65,3 +65,4 @@ obj-$(CONFIG_LEDS_DAC124S085) += leds-d + # LED Triggers + obj-$(CONFIG_LEDS_TRIGGERS) += trigger/ + obj-$(CONFIG_LEDS_TRIGGER_MORSE) += ledtrig-morse.o ++obj-$(CONFIG_LEDS_TRIGGER_NETDEV) += ledtrig-netdev.o +--- a/drivers/leds/ledtrig-netdev.c ++++ b/drivers/leds/ledtrig-netdev.c +@@ -22,7 +22,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -254,7 +253,7 @@ static int netdev_trig_notify(struct not + unsigned long evt, + void *dv) + { +- struct net_device *dev = dv; ++ struct net_device *dev = netdev_notifier_info_to_dev((struct netdev_notifier_info *) dv); + struct led_netdev_data *trigger_data = container_of(nb, struct led_netdev_data, notifier); + + if (evt != NETDEV_UP && evt != NETDEV_DOWN && evt != NETDEV_CHANGE && evt != NETDEV_REGISTER && evt != NETDEV_UNREGISTER) +@@ -294,8 +293,9 @@ done: + static void netdev_trig_timer(unsigned long arg) + { + struct led_netdev_data *trigger_data = (struct led_netdev_data *)arg; +- const struct net_device_stats *dev_stats; ++ struct rtnl_link_stats64 *dev_stats; + unsigned new_activity; ++ struct rtnl_link_stats64 temp; + + write_lock(&trigger_data->lock); + +@@ -305,7 +305,7 @@ static void netdev_trig_timer(unsigned l + goto no_restart; + } + +- dev_stats = dev_get_stats(trigger_data->net_dev); ++ dev_stats = dev_get_stats(trigger_data->net_dev, &temp); + new_activity = + ((trigger_data->mode & MODE_TX) ? dev_stats->tx_packets : 0) + + ((trigger_data->mode & MODE_RX) ? dev_stats->rx_packets : 0); diff --git a/target/linux/generic/patches-4.0/832-ledtrig_usbdev.patch b/target/linux/generic/patches-4.0/832-ledtrig_usbdev.patch new file mode 100644 index 0000000..25593fd --- /dev/null +++ b/target/linux/generic/patches-4.0/832-ledtrig_usbdev.patch @@ -0,0 +1,31 @@ +--- a/drivers/leds/trigger/Kconfig ++++ b/drivers/leds/trigger/Kconfig +@@ -119,4 +119,11 @@ config LEDS_TRIGGER_NETDEV + This allows LEDs to be controlled by network device activity. + If unsure, say Y. + ++config LEDS_TRIGGER_USBDEV ++ tristate "LED USB device Trigger" ++ depends on USB && LEDS_TRIGGERS ++ help ++ This allows LEDs to be controlled by the presence/activity of ++ an USB device. If unsure, say N. ++ + endif # LEDS_TRIGGERS +--- a/drivers/leds/Makefile ++++ b/drivers/leds/Makefile +@@ -66,3 +66,4 @@ obj-$(CONFIG_LEDS_DAC124S085) += leds-d + obj-$(CONFIG_LEDS_TRIGGERS) += trigger/ + obj-$(CONFIG_LEDS_TRIGGER_MORSE) += ledtrig-morse.o + obj-$(CONFIG_LEDS_TRIGGER_NETDEV) += ledtrig-netdev.o ++obj-$(CONFIG_LEDS_TRIGGER_USBDEV) += ledtrig-usbdev.o +--- a/drivers/leds/ledtrig-usbdev.c ++++ b/drivers/leds/ledtrig-usbdev.c +@@ -24,7 +24,6 @@ + #include + #include + #include +-#include + #include + #include + #include diff --git a/target/linux/generic/patches-4.0/834-ledtrig-libata.patch b/target/linux/generic/patches-4.0/834-ledtrig-libata.patch new file mode 100644 index 0000000..dcb80c8 --- /dev/null +++ b/target/linux/generic/patches-4.0/834-ledtrig-libata.patch @@ -0,0 +1,153 @@ +From 52cfd51cdf6a6e14d4fb270c6343abac3bac00f4 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Fri, 12 Dec 2014 13:38:33 +0100 +Subject: [PATCH] libata: add ledtrig support +To: linux-ide@vger.kernel.org, + Tejun Heo + +This adds a LED trigger for each ATA port indicating disk activity. + +As this is needed only on specific platforms (NAS SoCs and such), +these platforms should define ARCH_WANTS_LIBATA_LEDS if there +are boards with LED(s) intended to indicate ATA disk activity and +need the OS to take care of that. +In that way, if not selected, LED trigger support not will be +included in libata-core and both, codepaths and structures remain +untouched. + +Signed-off-by: Daniel Golle +--- + drivers/ata/Kconfig | 16 ++++++++++++++++ + drivers/ata/libata-core.c | 41 +++++++++++++++++++++++++++++++++++++++++ + include/linux/libata.h | 9 +++++++++ + 3 files changed, 66 insertions(+) + +--- a/drivers/ata/Kconfig ++++ b/drivers/ata/Kconfig +@@ -46,6 +46,22 @@ config ATA_VERBOSE_ERROR + + If unsure, say Y. + ++config ARCH_WANT_LIBATA_LEDS ++ bool ++ ++config ATA_LEDS ++ bool "support ATA port LED triggers" ++ depends on ARCH_WANT_LIBATA_LEDS ++ select NEW_LEDS ++ select LEDS_CLASS ++ select LEDS_TRIGGERS ++ default y ++ help ++ This option adds a LED trigger for each registered ATA port. ++ It is used to drive disk activity leds connected via GPIO. ++ ++ If unsure, say N. ++ + config ATA_ACPI + bool "ATA ACPI Support" + depends on ACPI && PCI +--- a/drivers/ata/libata-core.c ++++ b/drivers/ata/libata-core.c +@@ -725,6 +725,19 @@ u64 ata_tf_read_block(struct ata_taskfil + return block; + } + ++#ifdef CONFIG_ATA_LEDS ++#define LIBATA_BLINK_DELAY 20 /* ms */ ++static inline void ata_led_act(struct ata_port *ap) ++{ ++ unsigned long led_delay = LIBATA_BLINK_DELAY; ++ ++ if (unlikely(!ap->ledtrig)) ++ return; ++ ++ led_trigger_blink_oneshot(ap->ledtrig, &led_delay, &led_delay, 0); ++} ++#endif ++ + /** + * ata_build_rw_tf - Build ATA taskfile for given read/write request + * @tf: Target ATA taskfile +@@ -4753,6 +4766,9 @@ struct ata_queued_cmd *ata_qc_new_init(s + if (tag < 0) + return NULL; + } ++#ifdef CONFIG_ATA_LEDS ++ ata_led_act(ap); ++#endif + + qc = __ata_qc_from_tag(ap, tag); + qc->tag = tag; +@@ -5647,6 +5663,9 @@ struct ata_port *ata_port_alloc(struct a + ap->stats.unhandled_irq = 1; + ap->stats.idle_irq = 1; + #endif ++#ifdef CONFIG_ATA_LEDS ++ ap->ledtrig = kzalloc(sizeof(struct led_trigger), GFP_KERNEL); ++#endif + ata_sff_port_init(ap); + + return ap; +@@ -5668,6 +5687,12 @@ static void ata_host_release(struct devi + + kfree(ap->pmp_link); + kfree(ap->slave_link); ++#ifdef CONFIG_ATA_LEDS ++ if (ap->ledtrig) { ++ led_trigger_unregister(ap->ledtrig); ++ kfree(ap->ledtrig); ++ }; ++#endif + kfree(ap); + host->ports[i] = NULL; + } +@@ -6114,7 +6139,23 @@ int ata_host_register(struct ata_host *h + host->ports[i]->print_id = atomic_inc_return(&ata_print_id); + host->ports[i]->local_port_no = i + 1; + } ++#ifdef CONFIG_ATA_LEDS ++ for (i = 0; i < host->n_ports; i++) { ++ if (unlikely(!host->ports[i]->ledtrig)) ++ continue; + ++ snprintf(host->ports[i]->ledtrig_name, ++ sizeof(host->ports[i]->ledtrig_name), "ata%u", ++ host->ports[i]->print_id); ++ ++ host->ports[i]->ledtrig->name = host->ports[i]->ledtrig_name; ++ ++ if (led_trigger_register(host->ports[i]->ledtrig)) { ++ kfree(host->ports[i]->ledtrig); ++ host->ports[i]->ledtrig = NULL; ++ } ++ } ++#endif + /* Create associated sysfs transport objects */ + for (i = 0; i < host->n_ports; i++) { + rc = ata_tport_add(host->dev,host->ports[i]); +--- a/include/linux/libata.h ++++ b/include/linux/libata.h +@@ -38,6 +38,9 @@ + #include + #include + #include ++#ifdef CONFIG_ATA_LEDS ++#include ++#endif + + /* + * Define if arch has non-standard setup. This is a _PCI_ standard +@@ -874,6 +877,12 @@ struct ata_port { + #ifdef CONFIG_ATA_ACPI + struct ata_acpi_gtm __acpi_init_gtm; /* use ata_acpi_init_gtm() */ + #endif ++ ++#ifdef CONFIG_ATA_LEDS ++ struct led_trigger *ledtrig; ++ char ledtrig_name[8]; ++#endif ++ + /* owned by EH */ + u8 sector_buf[ATA_SECT_SIZE] ____cacheline_aligned; + }; diff --git a/target/linux/generic/patches-4.0/840-rtc7301.patch b/target/linux/generic/patches-4.0/840-rtc7301.patch new file mode 100644 index 0000000..252a0c2 --- /dev/null +++ b/target/linux/generic/patches-4.0/840-rtc7301.patch @@ -0,0 +1,250 @@ +--- a/drivers/rtc/Kconfig ++++ b/drivers/rtc/Kconfig +@@ -1099,6 +1099,15 @@ config RTC_DRV_OPAL + This driver can also be built as a module. If so, the module + will be called rtc-opal. + ++config RTC_DRV_RTC7301 ++ tristate "Epson RTC-7301 SF/DG" ++ help ++ If you say Y here you will get support for the ++ Epson RTC-7301 SF/DG RTC chips. ++ ++ This driver can also be built as a module. If so, the module ++ will be called rtc-7301. ++ + comment "on-CPU RTC drivers" + + config RTC_DRV_DAVINCI +--- a/drivers/rtc/Makefile ++++ b/drivers/rtc/Makefile +@@ -119,6 +119,7 @@ obj-$(CONFIG_RTC_DRV_RP5C01) += rtc-rp5c + obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o + obj-$(CONFIG_RTC_DRV_RS5C348) += rtc-rs5c348.o + obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o ++obj-$(CONFIG_RTC_DRV_RTC7301) += rtc-rtc7301.o + obj-$(CONFIG_RTC_DRV_RV3029C2) += rtc-rv3029c2.o + obj-$(CONFIG_RTC_DRV_RX4581) += rtc-rx4581.o + obj-$(CONFIG_RTC_DRV_RX8025) += rtc-rx8025.o +--- /dev/null ++++ b/drivers/rtc/rtc-rtc7301.c +@@ -0,0 +1,219 @@ ++/* ++ * Driver for Epson RTC-7301SF/DG ++ * ++ * Copyright (C) 2009 Jose Vasconcellos ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define RTC_NAME "rtc7301" ++#define RTC_VERSION "0.1" ++ ++/* Epson RTC-7301 register addresses */ ++#define RTC7301_SEC 0x00 ++#define RTC7301_SEC10 0x01 ++#define RTC7301_MIN 0x02 ++#define RTC7301_MIN10 0x03 ++#define RTC7301_HOUR 0x04 ++#define RTC7301_HOUR10 0x05 ++#define RTC7301_WEEKDAY 0x06 ++#define RTC7301_DAY 0x07 ++#define RTC7301_DAY10 0x08 ++#define RTC7301_MON 0x09 ++#define RTC7301_MON10 0x0A ++#define RTC7301_YEAR 0x0B ++#define RTC7301_YEAR10 0x0C ++#define RTC7301_YEAR100 0x0D ++#define RTC7301_YEAR1000 0x0E ++#define RTC7301_CTRLREG 0x0F ++ ++static uint8_t __iomem *rtc7301_base; ++ ++#define read_reg(offset) (readb(rtc7301_base + offset) & 0xf) ++#define write_reg(offset, data) writeb(data, rtc7301_base + (offset)) ++ ++#define rtc7301_isbusy() (read_reg(RTC7301_CTRLREG) & 1) ++ ++static void rtc7301_init_settings(void) ++{ ++ int i; ++ ++ write_reg(RTC7301_CTRLREG, 2); ++ write_reg(RTC7301_YEAR1000, 2); ++ udelay(122); ++ ++ /* bank 1 */ ++ write_reg(RTC7301_CTRLREG, 6); ++ for (i=0; i<15; i++) ++ write_reg(i, 0); ++ ++ /* bank 2 */ ++ write_reg(RTC7301_CTRLREG, 14); ++ for (i=0; i<15; i++) ++ write_reg(i, 0); ++ write_reg(RTC7301_CTRLREG, 0); ++} ++ ++static int rtc7301_get_datetime(struct device *dev, struct rtc_time *dt) ++{ ++ int cnt; ++ uint8_t buf[16]; ++ ++ cnt = 0; ++ while (rtc7301_isbusy()) { ++ udelay(244); ++ if (cnt++ > 100) { ++ dev_err(dev, "%s: timeout error %x\n", __func__, rtc7301_base[RTC7301_CTRLREG]); ++ return -EIO; ++ } ++ } ++ ++ for (cnt=0; cnt<16; cnt++) ++ buf[cnt] = read_reg(cnt); ++ ++ if (buf[RTC7301_SEC10] & 8) { ++ dev_err(dev, "%s: RTC not set\n", __func__); ++ return -EINVAL; ++ } ++ ++ memset(dt, 0, sizeof(*dt)); ++ ++ dt->tm_sec = buf[RTC7301_SEC] + buf[RTC7301_SEC10]*10; ++ dt->tm_min = buf[RTC7301_MIN] + buf[RTC7301_MIN10]*10; ++ dt->tm_hour = buf[RTC7301_HOUR] + buf[RTC7301_HOUR10]*10; ++ ++ dt->tm_mday = buf[RTC7301_DAY] + buf[RTC7301_DAY10]*10; ++ dt->tm_mon = buf[RTC7301_MON] + buf[RTC7301_MON10]*10 - 1; ++ dt->tm_year = buf[RTC7301_YEAR] + buf[RTC7301_YEAR10]*10 + ++ buf[RTC7301_YEAR100]*100 + ++ ((buf[RTC7301_YEAR1000] & 3)*1000) - 1900; ++ ++ /* the rtc device may contain illegal values on power up ++ * according to the data sheet. make sure they are valid. ++ */ ++ ++ return rtc_valid_tm(dt); ++} ++ ++static int rtc7301_set_datetime(struct device *dev, struct rtc_time *dt) ++{ ++ int data; ++ ++ data = dt->tm_year + 1900; ++ if (data >= 2100 || data < 1900) ++ return -EINVAL; ++ ++ write_reg(RTC7301_CTRLREG, 2); ++ udelay(122); ++ ++ data = bin2bcd(dt->tm_sec); ++ write_reg(RTC7301_SEC, data); ++ write_reg(RTC7301_SEC10, (data >> 4)); ++ ++ data = bin2bcd(dt->tm_min); ++ write_reg(RTC7301_MIN, data ); ++ write_reg(RTC7301_MIN10, (data >> 4)); ++ ++ data = bin2bcd(dt->tm_hour); ++ write_reg(RTC7301_HOUR, data); ++ write_reg(RTC7301_HOUR10, (data >> 4)); ++ ++ data = bin2bcd(dt->tm_mday); ++ write_reg(RTC7301_DAY, data); ++ write_reg(RTC7301_DAY10, (data>> 4)); ++ ++ data = bin2bcd(dt->tm_mon + 1); ++ write_reg(RTC7301_MON, data); ++ write_reg(RTC7301_MON10, (data >> 4)); ++ ++ data = bin2bcd(dt->tm_year % 100); ++ write_reg(RTC7301_YEAR, data); ++ write_reg(RTC7301_YEAR10, (data >> 4)); ++ data = bin2bcd((1900 + dt->tm_year) / 100); ++ write_reg(RTC7301_YEAR100, data); ++ ++ data = bin2bcd(dt->tm_wday); ++ write_reg(RTC7301_WEEKDAY, data); ++ ++ write_reg(RTC7301_CTRLREG, 0); ++ ++ return 0; ++} ++ ++static const struct rtc_class_ops rtc7301_rtc_ops = { ++ .read_time = rtc7301_get_datetime, ++ .set_time = rtc7301_set_datetime, ++}; ++ ++static int rtc7301_probe(struct platform_device *pdev) ++{ ++ struct rtc_device *rtc; ++ struct resource *res; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) ++ return -ENOENT; ++ ++ rtc7301_base = ioremap_nocache(res->start, 0x1000 /*res->end - res->start + 1*/); ++ if (!rtc7301_base) ++ return -EINVAL; ++ ++ rtc = rtc_device_register(RTC_NAME, &pdev->dev, ++ &rtc7301_rtc_ops, THIS_MODULE); ++ if (IS_ERR(rtc)) { ++ iounmap(rtc7301_base); ++ return PTR_ERR(rtc); ++ } ++ ++ platform_set_drvdata(pdev, rtc); ++ ++ rtc7301_init_settings(); ++ return 0; ++} ++ ++static int rtc7301_remove(struct platform_device *pdev) ++{ ++ struct rtc_device *rtc = platform_get_drvdata(pdev); ++ ++ if (rtc) ++ rtc_device_unregister(rtc); ++ if (rtc7301_base) ++ iounmap(rtc7301_base); ++ return 0; ++} ++ ++static struct platform_driver rtc7301_driver = { ++ .driver = { ++ .name = RTC_NAME, ++ .owner = THIS_MODULE, ++ }, ++ .probe = rtc7301_probe, ++ .remove = rtc7301_remove, ++}; ++ ++static __init int rtc7301_init(void) ++{ ++ return platform_driver_register(&rtc7301_driver); ++} ++module_init(rtc7301_init); ++ ++static __exit void rtc7301_exit(void) ++{ ++ platform_driver_unregister(&rtc7301_driver); ++} ++module_exit(rtc7301_exit); ++ ++MODULE_DESCRIPTION("Epson 7301 RTC driver"); ++MODULE_AUTHOR("Jose Vasconcellos "); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:" RTC_NAME); ++MODULE_VERSION(RTC_VERSION); diff --git a/target/linux/generic/patches-4.0/841-rtc_pt7c4338.patch b/target/linux/generic/patches-4.0/841-rtc_pt7c4338.patch new file mode 100644 index 0000000..83ce771 --- /dev/null +++ b/target/linux/generic/patches-4.0/841-rtc_pt7c4338.patch @@ -0,0 +1,247 @@ +--- a/drivers/rtc/Kconfig ++++ b/drivers/rtc/Kconfig +@@ -586,6 +586,15 @@ config RTC_DRV_S5M + This driver can also be built as a module. If so, the module + will be called rtc-s5m. + ++config RTC_DRV_PT7C4338 ++ tristate "Pericom Technology Inc. PT7C4338 RTC" ++ help ++ If you say yes here you get support for the Pericom Technology ++ Inc. PT7C4338 RTC chip. ++ ++ This driver can also be built as a module. If so, the module ++ will be called rtc-pt7c4338. ++ + endif # I2C + + comment "SPI RTC drivers" +--- a/drivers/rtc/Makefile ++++ b/drivers/rtc/Makefile +@@ -110,6 +110,7 @@ obj-$(CONFIG_RTC_DRV_PL030) += rtc-pl030 + obj-$(CONFIG_RTC_DRV_PL031) += rtc-pl031.o + obj-$(CONFIG_RTC_DRV_PM8XXX) += rtc-pm8xxx.o + obj-$(CONFIG_RTC_DRV_PS3) += rtc-ps3.o ++obj-$(CONFIG_RTC_DRV_PT7C4338) += rtc-pt7c4338.o + obj-$(CONFIG_RTC_DRV_PUV3) += rtc-puv3.o + obj-$(CONFIG_RTC_DRV_PXA) += rtc-pxa.o + obj-$(CONFIG_RTC_DRV_R9701) += rtc-r9701.o +--- /dev/null ++++ b/drivers/rtc/rtc-pt7c4338.c +@@ -0,0 +1,216 @@ ++/* ++ * Copyright 2010 Freescale Semiconductor, Inc. ++ * ++ * Author: Priyanka Jain ++ * ++ * 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 Date & Time support (no alarms) for PT7C4338 chip. ++ * ++ * This file is based on drivers/rtc/rtc-ds1307.c ++ * ++ * PT7C4338 chip is manufactured by Pericom Technology Inc. ++ * It is a serial real-time clock which provides ++ * 1)Low-power clock/calendar. ++ * 2)Programmable square-wave output. ++ * It has 56 bytes of nonvolatile RAM. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* RTC register addresses */ ++#define PT7C4338_REG_SECONDS 0x00 ++#define PT7C4338_REG_MINUTES 0x01 ++#define PT7C4338_REG_HOURS 0x02 ++#define PT7C4338_REG_AMPM 0x02 ++#define PT7C4338_REG_DAY 0x03 ++#define PT7C4338_REG_DATE 0x04 ++#define PT7C4338_REG_MONTH 0x05 ++#define PT7C4338_REG_YEAR 0x06 ++#define PT7C4338_REG_CTRL_STAT 0x07 ++ ++/* RTC second register address bit */ ++#define PT7C4338_SEC_BIT_CH 0x80 /*Clock Halt (in Register 0)*/ ++ ++/* RTC control and status register bits */ ++#define PT7C4338_CTRL_STAT_BIT_RS0 0x1 /*Rate select 0*/ ++#define PT7C4338_CTRL_STAT_BIT_RS1 0x2 /*Rate select 1*/ ++#define PT7C4338_CTRL_STAT_BIT_SQWE 0x10 /*Square Wave Enable*/ ++#define PT7C4338_CTRL_STAT_BIT_OSF 0x20 /*Oscillator Stop Flag*/ ++#define PT7C4338_CTRL_STAT_BIT_OUT 0x80 /*Output Level Control*/ ++ ++static const struct i2c_device_id pt7c4338_id[] = { ++ { "pt7c4338", 0 }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, pt7c4338_id); ++ ++struct pt7c4338{ ++ struct i2c_client *client; ++ struct rtc_device *rtc; ++}; ++ ++static int pt7c4338_read_time(struct device *dev, struct rtc_time *time) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ int ret; ++ u8 buf[7]; ++ u8 year, month, day, hour, minute, second; ++ u8 week, twelve_hr, am_pm; ++ ++ ret = i2c_smbus_read_i2c_block_data(client, ++ PT7C4338_REG_SECONDS, 7, buf); ++ if (ret < 0) ++ return ret; ++ if (ret < 7) ++ return -EIO; ++ ++ second = buf[0]; ++ minute = buf[1]; ++ hour = buf[2]; ++ week = buf[3]; ++ day = buf[4]; ++ month = buf[5]; ++ year = buf[6]; ++ ++ /* Extract additional information for AM/PM */ ++ twelve_hr = hour & 0x40; ++ am_pm = hour & 0x20; ++ ++ /* Write to rtc_time structure */ ++ time->tm_sec = bcd2bin(second & 0x7f); ++ time->tm_min = bcd2bin(minute & 0x7f); ++ if (twelve_hr) { ++ /* Convert to 24 hr */ ++ if (am_pm) ++ time->tm_hour = bcd2bin(hour & 0x10) + 12; ++ else ++ time->tm_hour = bcd2bin(hour & 0xBF); ++ } else { ++ time->tm_hour = bcd2bin(hour); ++ } ++ ++ time->tm_wday = bcd2bin(week & 0x07) - 1; ++ time->tm_mday = bcd2bin(day & 0x3f); ++ time->tm_mon = bcd2bin(month & 0x1F) - 1; ++ /* assume 20YY not 19YY */ ++ time->tm_year = bcd2bin(year) + 100; ++ ++ return 0; ++} ++ ++static int pt7c4338_set_time(struct device *dev, struct rtc_time *time) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ u8 buf[7]; ++ ++ /* Extract time from rtc_time and load into pt7c4338*/ ++ buf[0] = bin2bcd(time->tm_sec); ++ buf[1] = bin2bcd(time->tm_min); ++ buf[2] = bin2bcd(time->tm_hour); ++ buf[3] = bin2bcd(time->tm_wday + 1); /* Day of the week */ ++ buf[4] = bin2bcd(time->tm_mday); /* Date */ ++ buf[5] = bin2bcd(time->tm_mon + 1); ++ ++ /* assume 20YY not 19YY */ ++ if (time->tm_year >= 100) ++ buf[6] = bin2bcd(time->tm_year - 100); ++ else ++ buf[6] = bin2bcd(time->tm_year); ++ ++ return i2c_smbus_write_i2c_block_data(client, ++ PT7C4338_REG_SECONDS, 7, buf); ++} ++ ++static const struct rtc_class_ops pt7c4338_rtc_ops = { ++ .read_time = pt7c4338_read_time, ++ .set_time = pt7c4338_set_time, ++}; ++ ++static int pt7c4338_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct pt7c4338 *pt7c4338; ++ struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); ++ int ret; ++ ++ pt7c4338 = kzalloc(sizeof(struct pt7c4338), GFP_KERNEL); ++ if (!pt7c4338) ++ return -ENOMEM; ++ ++ pt7c4338->client = client; ++ i2c_set_clientdata(client, pt7c4338); ++ pt7c4338->rtc = rtc_device_register(client->name, &client->dev, ++ &pt7c4338_rtc_ops, THIS_MODULE); ++ if (IS_ERR(pt7c4338->rtc)) { ++ ret = PTR_ERR(pt7c4338->rtc); ++ dev_err(&client->dev, "unable to register the class device\n"); ++ goto out_free; ++ } ++ ++ return 0; ++out_free: ++ i2c_set_clientdata(client, NULL); ++ kfree(pt7c4338); ++ return ret; ++} ++ ++static int pt7c4338_remove(struct i2c_client *client) ++{ ++ struct pt7c4338 *pt7c4338 = i2c_get_clientdata(client); ++ ++ rtc_device_unregister(pt7c4338->rtc); ++ i2c_set_clientdata(client, NULL); ++ kfree(pt7c4338); ++ return 0; ++} ++ ++static struct i2c_driver pt7c4338_driver = { ++ .driver = { ++ .name = "rtc-pt7c4338", ++ .owner = THIS_MODULE, ++ }, ++ .probe = pt7c4338_probe, ++ .remove = pt7c4338_remove, ++ .id_table = pt7c4338_id, ++}; ++ ++static int __init pt7c4338_init(void) ++{ ++ return i2c_add_driver(&pt7c4338_driver); ++} ++ ++static void __exit pt7c4338_exit(void) ++{ ++ i2c_del_driver(&pt7c4338_driver); ++} ++ ++module_init(pt7c4338_init); ++module_exit(pt7c4338_exit); ++ ++MODULE_AUTHOR("Priyanka Jain "); ++MODULE_DESCRIPTION("pericom Technology Inc. PT7C4338 RTC Driver"); ++MODULE_LICENSE("GPL"); diff --git a/target/linux/generic/patches-4.0/861-04_spi_gpio_implement_spi_delay.patch b/target/linux/generic/patches-4.0/861-04_spi_gpio_implement_spi_delay.patch new file mode 100644 index 0000000..fc1b40c --- /dev/null +++ b/target/linux/generic/patches-4.0/861-04_spi_gpio_implement_spi_delay.patch @@ -0,0 +1,58 @@ +Implement the SPI-GPIO delay function for busses that need speed limitation. + +--mb + + + +--- a/drivers/spi/spi-gpio.c ++++ b/drivers/spi/spi-gpio.c +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -69,6 +70,7 @@ struct spi_gpio { + * #define SPI_MOSI_GPIO 120 + * #define SPI_SCK_GPIO 121 + * #define SPI_N_CHIPSEL 4 ++ * #undef NEED_SPIDELAY + * #include "spi-gpio.c" + */ + +@@ -76,6 +78,7 @@ struct spi_gpio { + #define DRIVER_NAME "spi_gpio" + + #define GENERIC_BITBANG /* vs tight inlines */ ++#define NEED_SPIDELAY 1 + + /* all functions referencing these symbols must define pdata */ + #define SPI_MISO_GPIO ((pdata)->miso) +@@ -126,12 +129,20 @@ static inline int getmiso(const struct s + #undef pdata + + /* +- * NOTE: this clocks "as fast as we can". It "should" be a function of the +- * requested device clock. Software overhead means we usually have trouble +- * reaching even one Mbit/sec (except when we can inline bitops), so for now +- * we'll just assume we never need additional per-bit slowdowns. ++ * NOTE: to clock "as fast as we can", set spi_device.max_speed_hz ++ * and spi_transfer.speed_hz to 0. ++ * Otherwise this is a function of the requested device clock. ++ * Software overhead means we usually have trouble ++ * reaching even one Mbit/sec (except when we can inline bitops). So on small ++ * embedded devices with fast SPI slaves you usually don't need a delay. + */ +-#define spidelay(nsecs) do {} while (0) ++static inline void spidelay(unsigned nsecs) ++{ ++#ifdef NEED_SPIDELAY ++ if (unlikely(nsecs)) ++ ndelay(nsecs); ++#endif /* NEED_SPIDELAY */ ++} + + #include "spi-bitbang-txrx.h" + diff --git a/target/linux/generic/patches-4.0/862-gpio_spi_driver.patch b/target/linux/generic/patches-4.0/862-gpio_spi_driver.patch new file mode 100644 index 0000000..be05938 --- /dev/null +++ b/target/linux/generic/patches-4.0/862-gpio_spi_driver.patch @@ -0,0 +1,373 @@ +THIS CODE IS DEPRECATED. + +Please use the new mainline SPI-GPIO driver, as of 2.6.29. + +--mb + + + +--- + drivers/spi/Kconfig | 9 + + drivers/spi/Makefile | 1 + drivers/spi/spi_gpio_old.c | 251 +++++++++++++++++++++++++++++++++++++++ + include/linux/spi/spi_gpio_old.h | 73 +++++++++++ + 4 files changed, 334 insertions(+) + +--- /dev/null ++++ b/include/linux/spi/spi_gpio_old.h +@@ -0,0 +1,73 @@ ++/* ++ * spi_gpio interface to platform code ++ * ++ * Copyright (c) 2008 Piotr Skamruk ++ * Copyright (c) 2008 Michael Buesch ++ * ++ * 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. ++ */ ++#ifndef _LINUX_SPI_SPI_GPIO ++#define _LINUX_SPI_SPI_GPIO ++ ++#include ++#include ++ ++ ++/** ++ * struct spi_gpio_platform_data - Data definitions for a SPI-GPIO device. ++ * ++ * This structure holds information about a GPIO-based SPI device. ++ * ++ * @pin_clk: The GPIO pin number of the CLOCK pin. ++ * ++ * @pin_miso: The GPIO pin number of the MISO pin. ++ * ++ * @pin_mosi: The GPIO pin number of the MOSI pin. ++ * ++ * @pin_cs: The GPIO pin number of the CHIPSELECT pin. ++ * ++ * @cs_activelow: If true, the chip is selected when the CS line is low. ++ * ++ * @no_spi_delay: If true, no delay is done in the lowlevel bitbanging. ++ * Note that doing no delay is not standards compliant, ++ * but it might be needed to speed up transfers on some ++ * slow embedded machines. ++ * ++ * @boardinfo_setup: This callback is called after the ++ * SPI master device was registered, but before the ++ * device is registered. ++ * @boardinfo_setup_data: Data argument passed to boardinfo_setup(). ++ */ ++struct spi_gpio_platform_data { ++ unsigned int pin_clk; ++ unsigned int pin_miso; ++ unsigned int pin_mosi; ++ unsigned int pin_cs; ++ bool cs_activelow; ++ bool no_spi_delay; ++ int (*boardinfo_setup)(struct spi_board_info *bi, ++ struct spi_master *master, ++ void *data); ++ void *boardinfo_setup_data; ++}; ++ ++/** ++ * SPI_GPIO_PLATDEV_NAME - The platform device name string. ++ * ++ * The name string that has to be used for platform_device_alloc ++ * when allocating a spi-gpio device. ++ */ ++#define SPI_GPIO_PLATDEV_NAME "spi-gpio" ++ ++/** ++ * spi_gpio_next_id - Get another platform device ID number. ++ * ++ * This returns the next platform device ID number that has to be used ++ * for platform_device_alloc. The ID is opaque and should not be used for ++ * anything else. ++ */ ++int spi_gpio_next_id(void); ++ ++#endif /* _LINUX_SPI_SPI_GPIO */ +--- /dev/null ++++ b/drivers/spi/spi_gpio_old.c +@@ -0,0 +1,251 @@ ++/* ++ * Bitbanging SPI bus driver using GPIO API ++ * ++ * Copyright (c) 2008 Piotr Skamruk ++ * Copyright (c) 2008 Michael Buesch ++ * ++ * based on spi_s3c2410_gpio.c ++ * Copyright (c) 2006 Ben Dooks ++ * Copyright (c) 2006 Simtec Electronics ++ * and on i2c-gpio.c ++ * Copyright (C) 2007 Atmel 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++struct spi_gpio { ++ struct spi_bitbang bitbang; ++ struct spi_gpio_platform_data *info; ++ struct platform_device *pdev; ++ struct spi_board_info bi; ++}; ++ ++ ++static inline struct spi_gpio *spidev_to_sg(struct spi_device *dev) ++{ ++ return dev->controller_data; ++} ++ ++static inline void setsck(struct spi_device *dev, int val) ++{ ++ struct spi_gpio *sp = spidev_to_sg(dev); ++ gpio_set_value(sp->info->pin_clk, val ? 1 : 0); ++} ++ ++static inline void setmosi(struct spi_device *dev, int val) ++{ ++ struct spi_gpio *sp = spidev_to_sg(dev); ++ gpio_set_value(sp->info->pin_mosi, val ? 1 : 0); ++} ++ ++static inline u32 getmiso(struct spi_device *dev) ++{ ++ struct spi_gpio *sp = spidev_to_sg(dev); ++ return gpio_get_value(sp->info->pin_miso) ? 1 : 0; ++} ++ ++static inline void do_spidelay(struct spi_device *dev, unsigned nsecs) ++{ ++ struct spi_gpio *sp = spidev_to_sg(dev); ++ ++ if (!sp->info->no_spi_delay) ++ ndelay(nsecs); ++} ++ ++#define spidelay(nsecs) do { \ ++ /* Steal the spi_device pointer from our caller. \ ++ * The bitbang-API should probably get fixed here... */ \ ++ do_spidelay(spi, nsecs); \ ++ } while (0) ++ ++#define EXPAND_BITBANG_TXRX ++#include "spi-bitbang-txrx.h" ++ ++static u32 spi_gpio_txrx_mode0(struct spi_device *spi, ++ unsigned nsecs, u32 word, u8 bits) ++{ ++ return bitbang_txrx_be_cpha0(spi, nsecs, 0, 0, word, bits); ++} ++ ++static u32 spi_gpio_txrx_mode1(struct spi_device *spi, ++ unsigned nsecs, u32 word, u8 bits) ++{ ++ return bitbang_txrx_be_cpha1(spi, nsecs, 0, 0, word, bits); ++} ++ ++static u32 spi_gpio_txrx_mode2(struct spi_device *spi, ++ unsigned nsecs, u32 word, u8 bits) ++{ ++ return bitbang_txrx_be_cpha0(spi, nsecs, 1, 0, word, bits); ++} ++ ++static u32 spi_gpio_txrx_mode3(struct spi_device *spi, ++ unsigned nsecs, u32 word, u8 bits) ++{ ++ return bitbang_txrx_be_cpha1(spi, nsecs, 1, 0, word, bits); ++} ++ ++static void spi_gpio_chipselect(struct spi_device *dev, int on) ++{ ++ struct spi_gpio *sp = spidev_to_sg(dev); ++ ++ if (sp->info->cs_activelow) ++ on = !on; ++ gpio_set_value(sp->info->pin_cs, on ? 1 : 0); ++} ++ ++static int spi_gpio_probe(struct platform_device *pdev) ++{ ++ struct spi_master *master; ++ struct spi_gpio_platform_data *pdata; ++ struct spi_gpio *sp; ++ struct spi_device *spidev; ++ int err; ++ ++ pdata = pdev->dev.platform_data; ++ if (!pdata) ++ return -ENXIO; ++ ++ err = -ENOMEM; ++ master = spi_alloc_master(&pdev->dev, sizeof(struct spi_gpio)); ++ if (!master) ++ goto err_alloc_master; ++ ++ sp = spi_master_get_devdata(master); ++ platform_set_drvdata(pdev, sp); ++ sp->info = pdata; ++ ++ err = gpio_request(pdata->pin_clk, "spi_clock"); ++ if (err) ++ goto err_request_clk; ++ err = gpio_request(pdata->pin_mosi, "spi_mosi"); ++ if (err) ++ goto err_request_mosi; ++ err = gpio_request(pdata->pin_miso, "spi_miso"); ++ if (err) ++ goto err_request_miso; ++ err = gpio_request(pdata->pin_cs, "spi_cs"); ++ if (err) ++ goto err_request_cs; ++ ++ sp->bitbang.master = spi_master_get(master); ++ sp->bitbang.master->bus_num = -1; ++ sp->bitbang.master->num_chipselect = 1; ++ sp->bitbang.chipselect = spi_gpio_chipselect; ++ sp->bitbang.txrx_word[SPI_MODE_0] = spi_gpio_txrx_mode0; ++ sp->bitbang.txrx_word[SPI_MODE_1] = spi_gpio_txrx_mode1; ++ sp->bitbang.txrx_word[SPI_MODE_2] = spi_gpio_txrx_mode2; ++ sp->bitbang.txrx_word[SPI_MODE_3] = spi_gpio_txrx_mode3; ++ ++ gpio_direction_output(pdata->pin_clk, 0); ++ gpio_direction_output(pdata->pin_mosi, 0); ++ gpio_direction_output(pdata->pin_cs, ++ pdata->cs_activelow ? 1 : 0); ++ gpio_direction_input(pdata->pin_miso); ++ ++ err = spi_bitbang_start(&sp->bitbang); ++ if (err) ++ goto err_no_bitbang; ++ err = pdata->boardinfo_setup(&sp->bi, master, ++ pdata->boardinfo_setup_data); ++ if (err) ++ goto err_bi_setup; ++ sp->bi.controller_data = sp; ++ spidev = spi_new_device(master, &sp->bi); ++ if (!spidev) ++ goto err_new_dev; ++ ++ return 0; ++ ++err_new_dev: ++err_bi_setup: ++ spi_bitbang_stop(&sp->bitbang); ++err_no_bitbang: ++ spi_master_put(sp->bitbang.master); ++ gpio_free(pdata->pin_cs); ++err_request_cs: ++ gpio_free(pdata->pin_miso); ++err_request_miso: ++ gpio_free(pdata->pin_mosi); ++err_request_mosi: ++ gpio_free(pdata->pin_clk); ++err_request_clk: ++ kfree(master); ++ ++err_alloc_master: ++ return err; ++} ++ ++static int spi_gpio_remove(struct platform_device *pdev) ++{ ++ struct spi_gpio *sp; ++ struct spi_gpio_platform_data *pdata; ++ ++ pdata = pdev->dev.platform_data; ++ sp = platform_get_drvdata(pdev); ++ ++ gpio_free(pdata->pin_clk); ++ gpio_free(pdata->pin_mosi); ++ gpio_free(pdata->pin_miso); ++ gpio_free(pdata->pin_cs); ++ spi_bitbang_stop(&sp->bitbang); ++ spi_master_put(sp->bitbang.master); ++ ++ return 0; ++} ++ ++static struct platform_driver spi_gpio_driver = { ++ .driver = { ++ .name = SPI_GPIO_PLATDEV_NAME, ++ .owner = THIS_MODULE, ++ }, ++ .probe = spi_gpio_probe, ++ .remove = spi_gpio_remove, ++}; ++ ++int spi_gpio_next_id(void) ++{ ++ static atomic_t counter = ATOMIC_INIT(-1); ++ ++ return atomic_inc_return(&counter); ++} ++EXPORT_SYMBOL(spi_gpio_next_id); ++ ++static int __init spi_gpio_init(void) ++{ ++ int err; ++ ++ err = platform_driver_register(&spi_gpio_driver); ++ if (err) ++ printk(KERN_ERR "spi-gpio: register failed: %d\n", err); ++ ++ return err; ++} ++module_init(spi_gpio_init); ++ ++static void __exit spi_gpio_exit(void) ++{ ++ platform_driver_unregister(&spi_gpio_driver); ++} ++module_exit(spi_gpio_exit); ++ ++MODULE_AUTHOR("Piot Skamruk "); ++MODULE_AUTHOR("Michael Buesch"); ++MODULE_DESCRIPTION("Platform independent GPIO bitbanging SPI driver"); ++MODULE_LICENSE("GPL v2"); +--- a/drivers/spi/Kconfig ++++ b/drivers/spi/Kconfig +@@ -242,6 +242,15 @@ config SPI_IMG_SPFI + This enables support for the SPFI master controller found on + IMG SoCs. + ++config SPI_GPIO_OLD ++ tristate "Old GPIO API based bitbanging SPI controller (DEPRECATED)" ++ depends on SPI_MASTER && GPIOLIB ++ select SPI_BITBANG ++ help ++ This code is deprecated. Please use the new mainline SPI-GPIO driver. ++ ++ If unsure, say N. ++ + config SPI_IMX + tristate "Freescale i.MX SPI controllers" + depends on ARCH_MXC || COMPILE_TEST +--- a/drivers/spi/Makefile ++++ b/drivers/spi/Makefile +@@ -41,6 +41,7 @@ obj-$(CONFIG_SPI_FSL_LIB) += spi-fsl-li + obj-$(CONFIG_SPI_FSL_ESPI) += spi-fsl-espi.o + obj-$(CONFIG_SPI_FSL_SPI) += spi-fsl-spi.o + obj-$(CONFIG_SPI_GPIO) += spi-gpio.o ++obj-$(CONFIG_SPI_GPIO_OLD) += spi_gpio_old.o + obj-$(CONFIG_SPI_IMG_SPFI) += spi-img-spfi.o + obj-$(CONFIG_SPI_IMX) += spi-imx.o + obj-$(CONFIG_SPI_LM70_LLP) += spi-lm70llp.o diff --git a/target/linux/generic/patches-4.0/863-gpiommc.patch b/target/linux/generic/patches-4.0/863-gpiommc.patch new file mode 100644 index 0000000..3433e20 --- /dev/null +++ b/target/linux/generic/patches-4.0/863-gpiommc.patch @@ -0,0 +1,844 @@ +--- /dev/null ++++ b/drivers/mmc/host/gpiommc.c +@@ -0,0 +1,609 @@ ++/* ++ * Driver an MMC/SD card on a bitbanging GPIO SPI bus. ++ * This module hooks up the mmc_spi and spi_gpio modules and also ++ * provides a configfs interface. ++ * ++ * Copyright 2008 Michael Buesch ++ * ++ * Licensed under the GNU/GPL. See COPYING for details. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#define PFX "gpio-mmc: " ++ ++ ++struct gpiommc_device { ++ struct platform_device *pdev; ++ struct platform_device *spi_pdev; ++ struct spi_board_info boardinfo; ++}; ++ ++ ++MODULE_DESCRIPTION("GPIO based MMC driver"); ++MODULE_AUTHOR("Michael Buesch"); ++MODULE_LICENSE("GPL"); ++ ++ ++static int gpiommc_boardinfo_setup(struct spi_board_info *bi, ++ struct spi_master *master, ++ void *data) ++{ ++ struct gpiommc_device *d = data; ++ struct gpiommc_platform_data *pdata = d->pdev->dev.platform_data; ++ ++ /* Bind the SPI master to the MMC-SPI host driver. */ ++ strlcpy(bi->modalias, "mmc_spi", sizeof(bi->modalias)); ++ ++ bi->max_speed_hz = pdata->max_bus_speed; ++ bi->bus_num = master->bus_num; ++ bi->mode = pdata->mode; ++ ++ return 0; ++} ++ ++static int gpiommc_probe(struct platform_device *pdev) ++{ ++ struct gpiommc_platform_data *mmc_pdata = pdev->dev.platform_data; ++ struct spi_gpio_platform_data spi_pdata; ++ struct gpiommc_device *d; ++ int err; ++ ++ err = -ENXIO; ++ if (!mmc_pdata) ++ goto error; ++ ++#ifdef CONFIG_MMC_SPI_MODULE ++ err = request_module("mmc_spi"); ++ if (err) { ++ printk(KERN_WARNING PFX ++ "Failed to request mmc_spi module.\n"); ++ } ++#endif /* CONFIG_MMC_SPI_MODULE */ ++ ++ /* Allocate the GPIO-MMC device */ ++ err = -ENOMEM; ++ d = kzalloc(sizeof(*d), GFP_KERNEL); ++ if (!d) ++ goto error; ++ d->pdev = pdev; ++ ++ /* Create the SPI-GPIO device */ ++ d->spi_pdev = platform_device_alloc(SPI_GPIO_PLATDEV_NAME, ++ spi_gpio_next_id()); ++ if (!d->spi_pdev) ++ goto err_free_d; ++ ++ memset(&spi_pdata, 0, sizeof(spi_pdata)); ++ spi_pdata.pin_clk = mmc_pdata->pins.gpio_clk; ++ spi_pdata.pin_miso = mmc_pdata->pins.gpio_do; ++ spi_pdata.pin_mosi = mmc_pdata->pins.gpio_di; ++ spi_pdata.pin_cs = mmc_pdata->pins.gpio_cs; ++ spi_pdata.cs_activelow = mmc_pdata->pins.cs_activelow; ++ spi_pdata.no_spi_delay = mmc_pdata->no_spi_delay; ++ spi_pdata.boardinfo_setup = gpiommc_boardinfo_setup; ++ spi_pdata.boardinfo_setup_data = d; ++ ++ err = platform_device_add_data(d->spi_pdev, &spi_pdata, ++ sizeof(spi_pdata)); ++ if (err) ++ goto err_free_pdev; ++ err = platform_device_add(d->spi_pdev); ++ if (err) ++ goto err_free_pdata; ++ platform_set_drvdata(pdev, d); ++ ++ printk(KERN_INFO PFX "MMC-Card \"%s\" " ++ "attached to GPIO pins di=%u, do=%u, clk=%u, cs=%u\n", ++ mmc_pdata->name, mmc_pdata->pins.gpio_di, ++ mmc_pdata->pins.gpio_do, ++ mmc_pdata->pins.gpio_clk, ++ mmc_pdata->pins.gpio_cs); ++ ++ return 0; ++ ++err_free_pdata: ++ kfree(d->spi_pdev->dev.platform_data); ++ d->spi_pdev->dev.platform_data = NULL; ++err_free_pdev: ++ platform_device_put(d->spi_pdev); ++err_free_d: ++ kfree(d); ++error: ++ return err; ++} ++ ++static int gpiommc_remove(struct platform_device *pdev) ++{ ++ struct gpiommc_device *d = platform_get_drvdata(pdev); ++ struct gpiommc_platform_data *pdata = d->pdev->dev.platform_data; ++ ++ platform_device_unregister(d->spi_pdev); ++ printk(KERN_INFO PFX "GPIO based MMC-Card \"%s\" removed\n", ++ pdata->name); ++ platform_device_put(d->spi_pdev); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_GPIOMMC_CONFIGFS ++ ++/* A device that was created through configfs */ ++struct gpiommc_configfs_device { ++ struct config_item item; ++ /* The platform device, after registration. */ ++ struct platform_device *pdev; ++ /* The configuration */ ++ struct gpiommc_platform_data pdata; ++}; ++ ++#define GPIO_INVALID -1 ++ ++static inline bool gpiommc_is_registered(struct gpiommc_configfs_device *dev) ++{ ++ return (dev->pdev != NULL); ++} ++ ++static inline struct gpiommc_configfs_device *ci_to_gpiommc(struct config_item *item) ++{ ++ return item ? container_of(item, struct gpiommc_configfs_device, item) : NULL; ++} ++ ++static struct configfs_attribute gpiommc_attr_DI = { ++ .ca_owner = THIS_MODULE, ++ .ca_name = "gpio_data_in", ++ .ca_mode = S_IRUGO | S_IWUSR, ++}; ++ ++static struct configfs_attribute gpiommc_attr_DO = { ++ .ca_owner = THIS_MODULE, ++ .ca_name = "gpio_data_out", ++ .ca_mode = S_IRUGO | S_IWUSR, ++}; ++ ++static struct configfs_attribute gpiommc_attr_CLK = { ++ .ca_owner = THIS_MODULE, ++ .ca_name = "gpio_clock", ++ .ca_mode = S_IRUGO | S_IWUSR, ++}; ++ ++static struct configfs_attribute gpiommc_attr_CS = { ++ .ca_owner = THIS_MODULE, ++ .ca_name = "gpio_chipselect", ++ .ca_mode = S_IRUGO | S_IWUSR, ++}; ++ ++static struct configfs_attribute gpiommc_attr_CS_activelow = { ++ .ca_owner = THIS_MODULE, ++ .ca_name = "gpio_chipselect_activelow", ++ .ca_mode = S_IRUGO | S_IWUSR, ++}; ++ ++static struct configfs_attribute gpiommc_attr_spimode = { ++ .ca_owner = THIS_MODULE, ++ .ca_name = "spi_mode", ++ .ca_mode = S_IRUGO | S_IWUSR, ++}; ++ ++static struct configfs_attribute gpiommc_attr_spidelay = { ++ .ca_owner = THIS_MODULE, ++ .ca_name = "spi_delay", ++ .ca_mode = S_IRUGO | S_IWUSR, ++}; ++ ++static struct configfs_attribute gpiommc_attr_max_bus_speed = { ++ .ca_owner = THIS_MODULE, ++ .ca_name = "max_bus_speed", ++ .ca_mode = S_IRUGO | S_IWUSR, ++}; ++ ++static struct configfs_attribute gpiommc_attr_register = { ++ .ca_owner = THIS_MODULE, ++ .ca_name = "register", ++ .ca_mode = S_IRUGO | S_IWUSR, ++}; ++ ++static struct configfs_attribute *gpiommc_config_attrs[] = { ++ &gpiommc_attr_DI, ++ &gpiommc_attr_DO, ++ &gpiommc_attr_CLK, ++ &gpiommc_attr_CS, ++ &gpiommc_attr_CS_activelow, ++ &gpiommc_attr_spimode, ++ &gpiommc_attr_spidelay, ++ &gpiommc_attr_max_bus_speed, ++ &gpiommc_attr_register, ++ NULL, ++}; ++ ++static ssize_t gpiommc_config_attr_show(struct config_item *item, ++ struct configfs_attribute *attr, ++ char *page) ++{ ++ struct gpiommc_configfs_device *dev = ci_to_gpiommc(item); ++ ssize_t count = 0; ++ unsigned int gpio; ++ int err = 0; ++ ++ if (attr == &gpiommc_attr_DI) { ++ gpio = dev->pdata.pins.gpio_di; ++ if (gpio == GPIO_INVALID) ++ count = snprintf(page, PAGE_SIZE, "not configured\n"); ++ else ++ count = snprintf(page, PAGE_SIZE, "%u\n", gpio); ++ goto out; ++ } ++ if (attr == &gpiommc_attr_DO) { ++ gpio = dev->pdata.pins.gpio_do; ++ if (gpio == GPIO_INVALID) ++ count = snprintf(page, PAGE_SIZE, "not configured\n"); ++ else ++ count = snprintf(page, PAGE_SIZE, "%u\n", gpio); ++ goto out; ++ } ++ if (attr == &gpiommc_attr_CLK) { ++ gpio = dev->pdata.pins.gpio_clk; ++ if (gpio == GPIO_INVALID) ++ count = snprintf(page, PAGE_SIZE, "not configured\n"); ++ else ++ count = snprintf(page, PAGE_SIZE, "%u\n", gpio); ++ goto out; ++ } ++ if (attr == &gpiommc_attr_CS) { ++ gpio = dev->pdata.pins.gpio_cs; ++ if (gpio == GPIO_INVALID) ++ count = snprintf(page, PAGE_SIZE, "not configured\n"); ++ else ++ count = snprintf(page, PAGE_SIZE, "%u\n", gpio); ++ goto out; ++ } ++ if (attr == &gpiommc_attr_CS_activelow) { ++ count = snprintf(page, PAGE_SIZE, "%u\n", ++ dev->pdata.pins.cs_activelow); ++ goto out; ++ } ++ if (attr == &gpiommc_attr_spimode) { ++ count = snprintf(page, PAGE_SIZE, "%u\n", ++ dev->pdata.mode); ++ goto out; ++ } ++ if (attr == &gpiommc_attr_spidelay) { ++ count = snprintf(page, PAGE_SIZE, "%u\n", ++ !dev->pdata.no_spi_delay); ++ goto out; ++ } ++ if (attr == &gpiommc_attr_max_bus_speed) { ++ count = snprintf(page, PAGE_SIZE, "%u\n", ++ dev->pdata.max_bus_speed); ++ goto out; ++ } ++ if (attr == &gpiommc_attr_register) { ++ count = snprintf(page, PAGE_SIZE, "%u\n", ++ gpiommc_is_registered(dev)); ++ goto out; ++ } ++ WARN_ON(1); ++ err = -ENOSYS; ++out: ++ return err ? err : count; ++} ++ ++static int gpiommc_do_register(struct gpiommc_configfs_device *dev, ++ const char *name) ++{ ++ int err; ++ ++ if (gpiommc_is_registered(dev)) ++ return 0; ++ ++ if (!gpio_is_valid(dev->pdata.pins.gpio_di) || ++ !gpio_is_valid(dev->pdata.pins.gpio_do) || ++ !gpio_is_valid(dev->pdata.pins.gpio_clk) || ++ !gpio_is_valid(dev->pdata.pins.gpio_cs)) { ++ printk(KERN_ERR PFX ++ "configfs: Invalid GPIO pin number(s)\n"); ++ return -EINVAL; ++ } ++ ++ strlcpy(dev->pdata.name, name, ++ sizeof(dev->pdata.name)); ++ ++ dev->pdev = platform_device_alloc(GPIOMMC_PLATDEV_NAME, ++ gpiommc_next_id()); ++ if (!dev->pdev) ++ return -ENOMEM; ++ err = platform_device_add_data(dev->pdev, &dev->pdata, ++ sizeof(dev->pdata)); ++ if (err) { ++ platform_device_put(dev->pdev); ++ return err; ++ } ++ err = platform_device_add(dev->pdev); ++ if (err) { ++ platform_device_put(dev->pdev); ++ return err; ++ } ++ ++ return 0; ++} ++ ++static void gpiommc_do_unregister(struct gpiommc_configfs_device *dev) ++{ ++ if (!gpiommc_is_registered(dev)) ++ return; ++ ++ platform_device_unregister(dev->pdev); ++ dev->pdev = NULL; ++} ++ ++static ssize_t gpiommc_config_attr_store(struct config_item *item, ++ struct configfs_attribute *attr, ++ const char *page, size_t count) ++{ ++ struct gpiommc_configfs_device *dev = ci_to_gpiommc(item); ++ int err = -EINVAL; ++ unsigned long data; ++ ++ if (attr == &gpiommc_attr_register) { ++ err = kstrtoul(page, 10, &data); ++ if (err) ++ goto out; ++ err = -EINVAL; ++ if (data == 1) ++ err = gpiommc_do_register(dev, item->ci_name); ++ if (data == 0) { ++ gpiommc_do_unregister(dev); ++ err = 0; ++ } ++ goto out; ++ } ++ ++ if (gpiommc_is_registered(dev)) { ++ /* The rest of the config parameters can only be set ++ * as long as the device is not registered, yet. */ ++ err = -EBUSY; ++ goto out; ++ } ++ ++ if (attr == &gpiommc_attr_DI) { ++ err = kstrtoul(page, 10, &data); ++ if (err) ++ goto out; ++ err = -EINVAL; ++ if (!gpio_is_valid(data)) ++ goto out; ++ dev->pdata.pins.gpio_di = data; ++ err = 0; ++ goto out; ++ } ++ if (attr == &gpiommc_attr_DO) { ++ err = kstrtoul(page, 10, &data); ++ if (err) ++ goto out; ++ err = -EINVAL; ++ if (!gpio_is_valid(data)) ++ goto out; ++ dev->pdata.pins.gpio_do = data; ++ err = 0; ++ goto out; ++ } ++ if (attr == &gpiommc_attr_CLK) { ++ err = kstrtoul(page, 10, &data); ++ if (err) ++ goto out; ++ err = -EINVAL; ++ if (!gpio_is_valid(data)) ++ goto out; ++ dev->pdata.pins.gpio_clk = data; ++ err = 0; ++ goto out; ++ } ++ if (attr == &gpiommc_attr_CS) { ++ err = kstrtoul(page, 10, &data); ++ if (err) ++ goto out; ++ err = -EINVAL; ++ if (!gpio_is_valid(data)) ++ goto out; ++ dev->pdata.pins.gpio_cs = data; ++ err = 0; ++ goto out; ++ } ++ if (attr == &gpiommc_attr_CS_activelow) { ++ err = kstrtoul(page, 10, &data); ++ if (err) ++ goto out; ++ err = -EINVAL; ++ if (data != 0 && data != 1) ++ goto out; ++ dev->pdata.pins.cs_activelow = data; ++ err = 0; ++ goto out; ++ } ++ if (attr == &gpiommc_attr_spimode) { ++ err = kstrtoul(page, 10, &data); ++ if (err) ++ goto out; ++ err = -EINVAL; ++ switch (data) { ++ case 0: ++ dev->pdata.mode = SPI_MODE_0; ++ break; ++ case 1: ++ dev->pdata.mode = SPI_MODE_1; ++ break; ++ case 2: ++ dev->pdata.mode = SPI_MODE_2; ++ break; ++ case 3: ++ dev->pdata.mode = SPI_MODE_3; ++ break; ++ default: ++ goto out; ++ } ++ err = 0; ++ goto out; ++ } ++ if (attr == &gpiommc_attr_spidelay) { ++ err = kstrtoul(page, 10, &data); ++ if (err) ++ goto out; ++ err = -EINVAL; ++ if (data != 0 && data != 1) ++ goto out; ++ dev->pdata.no_spi_delay = !data; ++ err = 0; ++ goto out; ++ } ++ if (attr == &gpiommc_attr_max_bus_speed) { ++ err = kstrtoul(page, 10, &data); ++ if (err) ++ goto out; ++ err = -EINVAL; ++ if (data > UINT_MAX) ++ goto out; ++ dev->pdata.max_bus_speed = data; ++ err = 0; ++ goto out; ++ } ++ WARN_ON(1); ++ err = -ENOSYS; ++out: ++ return err ? err : count; ++} ++ ++static void gpiommc_config_item_release(struct config_item *item) ++{ ++ struct gpiommc_configfs_device *dev = ci_to_gpiommc(item); ++ ++ kfree(dev); ++} ++ ++static struct configfs_item_operations gpiommc_config_item_ops = { ++ .release = gpiommc_config_item_release, ++ .show_attribute = gpiommc_config_attr_show, ++ .store_attribute = gpiommc_config_attr_store, ++}; ++ ++static struct config_item_type gpiommc_dev_ci_type = { ++ .ct_item_ops = &gpiommc_config_item_ops, ++ .ct_attrs = gpiommc_config_attrs, ++ .ct_owner = THIS_MODULE, ++}; ++ ++static struct config_item *gpiommc_make_item(struct config_group *group, ++ const char *name) ++{ ++ struct gpiommc_configfs_device *dev; ++ ++ if (strlen(name) > GPIOMMC_MAX_NAMELEN) { ++ printk(KERN_ERR PFX "configfs: device name too long\n"); ++ return NULL; ++ } ++ ++ dev = kzalloc(sizeof(*dev), GFP_KERNEL); ++ if (!dev) ++ return NULL; ++ ++ config_item_init_type_name(&dev->item, name, ++ &gpiommc_dev_ci_type); ++ ++ /* Assign default configuration */ ++ dev->pdata.pins.gpio_di = GPIO_INVALID; ++ dev->pdata.pins.gpio_do = GPIO_INVALID; ++ dev->pdata.pins.gpio_clk = GPIO_INVALID; ++ dev->pdata.pins.gpio_cs = GPIO_INVALID; ++ dev->pdata.pins.cs_activelow = 1; ++ dev->pdata.mode = SPI_MODE_0; ++ dev->pdata.no_spi_delay = 0; ++ dev->pdata.max_bus_speed = 5000000; /* 5 MHz */ ++ ++ return &(dev->item); ++} ++ ++static void gpiommc_drop_item(struct config_group *group, ++ struct config_item *item) ++{ ++ struct gpiommc_configfs_device *dev = ci_to_gpiommc(item); ++ ++ gpiommc_do_unregister(dev); ++ kfree(dev); ++} ++ ++static struct configfs_group_operations gpiommc_ct_group_ops = { ++ .make_item = gpiommc_make_item, ++ .drop_item = gpiommc_drop_item, ++}; ++ ++static struct config_item_type gpiommc_ci_type = { ++ .ct_group_ops = &gpiommc_ct_group_ops, ++ .ct_owner = THIS_MODULE, ++}; ++ ++static struct configfs_subsystem gpiommc_subsys = { ++ .su_group = { ++ .cg_item = { ++ .ci_namebuf = GPIOMMC_PLATDEV_NAME, ++ .ci_type = &gpiommc_ci_type, ++ }, ++ }, ++ .su_mutex = __MUTEX_INITIALIZER(gpiommc_subsys.su_mutex), ++}; ++ ++#endif /* CONFIG_GPIOMMC_CONFIGFS */ ++ ++static struct platform_driver gpiommc_plat_driver = { ++ .probe = gpiommc_probe, ++ .remove = gpiommc_remove, ++ .driver = { ++ .name = GPIOMMC_PLATDEV_NAME, ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++int gpiommc_next_id(void) ++{ ++ static atomic_t counter = ATOMIC_INIT(-1); ++ ++ return atomic_inc_return(&counter); ++} ++EXPORT_SYMBOL(gpiommc_next_id); ++ ++static int __init gpiommc_modinit(void) ++{ ++ int err; ++ ++ err = platform_driver_register(&gpiommc_plat_driver); ++ if (err) ++ return err; ++ ++#ifdef CONFIG_GPIOMMC_CONFIGFS ++ config_group_init(&gpiommc_subsys.su_group); ++ err = configfs_register_subsystem(&gpiommc_subsys); ++ if (err) { ++ platform_driver_unregister(&gpiommc_plat_driver); ++ return err; ++ } ++#endif /* CONFIG_GPIOMMC_CONFIGFS */ ++ ++ return 0; ++} ++module_init(gpiommc_modinit); ++ ++static void __exit gpiommc_modexit(void) ++{ ++#ifdef CONFIG_GPIOMMC_CONFIGFS ++ configfs_unregister_subsystem(&gpiommc_subsys); ++#endif ++ platform_driver_unregister(&gpiommc_plat_driver); ++} ++module_exit(gpiommc_modexit); +--- a/drivers/mmc/host/Kconfig ++++ b/drivers/mmc/host/Kconfig +@@ -549,6 +549,31 @@ config MMC_SDHI + This provides support for the SDHI SD/SDIO controller found in + SuperH and ARM SH-Mobile SoCs + ++config GPIOMMC ++ tristate "MMC/SD over GPIO-based SPI" ++ depends on MMC && MMC_SPI && SPI_GPIO_OLD ++ help ++ This driver hooks up the mmc_spi and spi_gpio modules so that ++ MMC/SD cards can be used on a GPIO based bus by bitbanging ++ the SPI protocol in software. ++ ++ This driver provides a configfs interface to dynamically create ++ and destroy GPIO-based MMC/SD card devices. It also provides ++ a platform device interface API. ++ See Documentation/gpiommc.txt for details. ++ ++ The module will be called gpiommc. ++ ++ If unsure, say N. ++ ++config GPIOMMC_CONFIGFS ++ bool ++ depends on GPIOMMC && CONFIGFS_FS ++ default y ++ help ++ This option automatically enables configfs support for gpiommc ++ if configfs is available. ++ + config MMC_CB710 + tristate "ENE CB710 MMC/SD Interface support" + depends on PCI +--- a/drivers/mmc/host/Makefile ++++ b/drivers/mmc/host/Makefile +@@ -41,6 +41,7 @@ tmio_mmc_core-$(subst m,y,$(CONFIG_MMC_S + obj-$(CONFIG_MMC_SDHI) += sh_mobile_sdhi.o + obj-$(CONFIG_MMC_CB710) += cb710-mmc.o + obj-$(CONFIG_MMC_VIA_SDMMC) += via-sdmmc.o ++obj-$(CONFIG_GPIOMMC) += gpiommc.o + obj-$(CONFIG_SDH_BFIN) += bfin_sdh.o + obj-$(CONFIG_MMC_DW) += dw_mmc.o + obj-$(CONFIG_MMC_DW_PLTFM) += dw_mmc-pltfm.o +--- /dev/null ++++ b/include/linux/mmc/gpiommc.h +@@ -0,0 +1,71 @@ ++/* ++ * Device driver for MMC/SD cards driven over a GPIO bus. ++ * ++ * Copyright (c) 2008 Michael Buesch ++ * ++ * Licensed under the GNU/GPL version 2. ++ */ ++#ifndef LINUX_GPIOMMC_H_ ++#define LINUX_GPIOMMC_H_ ++ ++#include ++ ++ ++#define GPIOMMC_MAX_NAMELEN 15 ++#define GPIOMMC_MAX_NAMELEN_STR __stringify(GPIOMMC_MAX_NAMELEN) ++ ++/** ++ * struct gpiommc_pins - Hardware pin assignments ++ * ++ * @gpio_di: The GPIO number of the DATA IN pin ++ * @gpio_do: The GPIO number of the DATA OUT pin ++ * @gpio_clk: The GPIO number of the CLOCK pin ++ * @gpio_cs: The GPIO number of the CHIPSELECT pin ++ * @cs_activelow: If true, the chip is considered selected if @gpio_cs is low. ++ */ ++struct gpiommc_pins { ++ unsigned int gpio_di; ++ unsigned int gpio_do; ++ unsigned int gpio_clk; ++ unsigned int gpio_cs; ++ bool cs_activelow; ++}; ++ ++/** ++ * struct gpiommc_platform_data - Platform data for a MMC-over-SPI-GPIO device. ++ * ++ * @name: The unique name string of the device. ++ * @pins: The hardware pin assignments. ++ * @mode: The hardware mode. This is either SPI_MODE_0, ++ * SPI_MODE_1, SPI_MODE_2 or SPI_MODE_3. See the SPI documentation. ++ * @no_spi_delay: Do not use delays in the lowlevel SPI bitbanging code. ++ * This is not standards compliant, but may be required for some ++ * embedded machines to gain reasonable speed. ++ * @max_bus_speed: The maximum speed of the SPI bus, in Hertz. ++ */ ++struct gpiommc_platform_data { ++ char name[GPIOMMC_MAX_NAMELEN + 1]; ++ struct gpiommc_pins pins; ++ u8 mode; ++ bool no_spi_delay; ++ unsigned int max_bus_speed; ++}; ++ ++/** ++ * GPIOMMC_PLATDEV_NAME - The platform device name string. ++ * ++ * The name string that has to be used for platform_device_alloc ++ * when allocating a gpiommc device. ++ */ ++#define GPIOMMC_PLATDEV_NAME "gpiommc" ++ ++/** ++ * gpiommc_next_id - Get another platform device ID number. ++ * ++ * This returns the next platform device ID number that has to be used ++ * for platform_device_alloc. The ID is opaque and should not be used for ++ * anything else. ++ */ ++int gpiommc_next_id(void); ++ ++#endif /* LINUX_GPIOMMC_H_ */ +--- /dev/null ++++ b/Documentation/gpiommc.txt +@@ -0,0 +1,97 @@ ++GPIOMMC - Driver for an MMC/SD card on a bitbanging GPIO SPI bus ++================================================================ ++ ++The gpiommc module hooks up the mmc_spi and spi_gpio modules for running an ++MMC or SD card on GPIO pins. ++ ++Two interfaces for registering a new MMC/SD card device are provided: ++A static platform-device based mechanism and a dynamic configfs based interface. ++ ++ ++Registering devices via platform-device ++======================================= ++ ++The platform-device interface is used for registering MMC/SD devices that are ++part of the hardware platform. This is most useful only for embedded machines ++with MMC/SD devices statically connected to the platform GPIO bus. ++ ++The data structures are declared in . ++ ++To register a new device, define an instance of struct gpiommc_platform_data. ++This structure holds any information about how the device is hooked up to the ++GPIO pins and what hardware modes the device supports. See the docbook-style ++documentation in the header file for more information on the struct fields. ++ ++Then allocate a new instance of a platform device by doing: ++ ++ pdev = platform_device_alloc(GPIOMMC_PLATDEV_NAME, gpiommc_next_id()); ++ ++This will allocate the platform device data structures and hook it up to the ++gpiommc driver. ++Then add the gpiommc_platform_data to the platform device. ++ ++ err = platform_device_add_data(pdev, pdata, sizeof(struct gpiommc_platform_data)); ++ ++You may free the local instance of struct gpiommc_platform_data now. (So the ++struct may be allocated on the stack, too). ++Now simply register the platform device. ++ ++ err = platform_device_add(pdev); ++ ++Done. The gpiommc probe routine will be invoked now and you should see a kernel ++log message for the added device. ++ ++ ++Registering devices via configfs ++================================ ++ ++MMC/SD cards connected via GPIO often are a pretty dynamic thing, as for example ++selfmade hacks for soldering an MMC/SD card to standard GPIO pins on embedded ++hardware are a common situation. ++So we provide a dynamic interface to conveniently handle adding and removing ++devices from userspace, without the need to recompile the kernel. ++ ++The "gpiommc" subdirectory at the configfs mountpoint is used for handling ++the dynamic configuration. ++ ++To create a new device, it must first be allocated with mkdir. ++The following command will allocate a device named "my_mmc": ++ mkdir /config/gpiommc/my_mmc ++ ++There are several configuration files available in the new ++/config/gpiommc/my_mmc/ directory: ++ ++gpio_data_in = The SPI data-IN GPIO pin number. ++gpio_data_out = The SPI data-OUT GPIO pin number. ++gpio_clock = The SPI Clock GPIO pin number. ++gpio_chipselect = The SPI Chipselect GPIO pin number. ++gpio_chipselect_activelow = Boolean. If 0, Chipselect is active-HIGH. ++ If 1, Chipselect is active-LOW. ++spi_mode = The SPI data mode. Can be 0-3. ++spi_delay = Enable all delays in the lowlevel bitbanging. ++max_bus_speed = The maximum SPI bus speed. In Hertz. ++ ++register = Not a configuration parameter. ++ Used to register the configured card ++ with the kernel. ++ ++The device must first get configured and then registered by writing "1" to ++the "register" file. ++The configuration parameters "gpio_data_in", "gpio_data_out", "gpio_clock" ++and "gpio_chipselect" are essential and _must_ be configured before writing ++"1" to the "register" file. The registration will fail, otherwise. ++ ++The default values for the other parameters are: ++gpio_chipselect_activelow = 1 (CS active-LOW) ++spi_mode = 0 (SPI_MODE_0) ++spi_delay = 1 (enabled) ++max_bus_speed = 5000000 (5 Mhz) ++ ++Configuration values can not be changed after registration. To unregister ++the device, write a "0" to the "register" file. The configuration can be ++changed again after unregistering. ++ ++To completely remove the device, simply rmdir the directory ++(/config/gpiommc/my_mmc in this example). ++There's no need to first unregister the device before removing it. That will ++be done automatically. +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -4481,6 +4481,11 @@ T: git git://linuxtv.org/anttip/media_tr + S: Maintained + F: drivers/media/usb/hackrf/ + ++GPIOMMC DRIVER ++P: Michael Buesch ++M: mb@bu3sch.de ++S: Maintained ++ + HARDWARE MONITORING + M: Jean Delvare + M: Guenter Roeck diff --git a/target/linux/generic/patches-4.0/864-gpiommc_configfs_locking.patch b/target/linux/generic/patches-4.0/864-gpiommc_configfs_locking.patch new file mode 100644 index 0000000..92815d9 --- /dev/null +++ b/target/linux/generic/patches-4.0/864-gpiommc_configfs_locking.patch @@ -0,0 +1,58 @@ +The gpiommc configfs context structure needs locking, as configfs +does not lock access between files. + +--- a/drivers/mmc/host/gpiommc.c ++++ b/drivers/mmc/host/gpiommc.c +@@ -144,6 +144,8 @@ struct gpiommc_configfs_device { + struct platform_device *pdev; + /* The configuration */ + struct gpiommc_platform_data pdata; ++ /* Mutex to protect this structure */ ++ struct mutex mutex; + }; + + #define GPIO_INVALID -1 +@@ -234,6 +236,8 @@ static ssize_t gpiommc_config_attr_show( + unsigned int gpio; + int err = 0; + ++ mutex_lock(&dev->mutex); ++ + if (attr == &gpiommc_attr_DI) { + gpio = dev->pdata.pins.gpio_di; + if (gpio == GPIO_INVALID) +@@ -294,6 +298,8 @@ static ssize_t gpiommc_config_attr_show( + WARN_ON(1); + err = -ENOSYS; + out: ++ mutex_unlock(&dev->mutex); ++ + return err ? err : count; + } + +@@ -353,6 +359,8 @@ static ssize_t gpiommc_config_attr_store + int err = -EINVAL; + unsigned long data; + ++ mutex_lock(&dev->mutex); ++ + if (attr == &gpiommc_attr_register) { + err = kstrtoul(page, 10, &data); + if (err) +@@ -478,6 +486,8 @@ static ssize_t gpiommc_config_attr_store + WARN_ON(1); + err = -ENOSYS; + out: ++ mutex_unlock(&dev->mutex); ++ + return err ? err : count; + } + +@@ -514,6 +524,7 @@ static struct config_item *gpiommc_make_ + if (!dev) + return NULL; + ++ mutex_init(&dev->mutex); + config_item_init_type_name(&dev->item, name, + &gpiommc_dev_ci_type); + diff --git a/target/linux/generic/patches-4.0/870-hifn795x_byteswap.patch b/target/linux/generic/patches-4.0/870-hifn795x_byteswap.patch new file mode 100644 index 0000000..3a37c95 --- /dev/null +++ b/target/linux/generic/patches-4.0/870-hifn795x_byteswap.patch @@ -0,0 +1,17 @@ +--- a/drivers/crypto/hifn_795x.c ++++ b/drivers/crypto/hifn_795x.c +@@ -682,12 +682,12 @@ static inline u32 hifn_read_1(struct hif + + static inline void hifn_write_0(struct hifn_device *dev, u32 reg, u32 val) + { +- writel((__force u32)cpu_to_le32(val), dev->bar[0] + reg); ++ writel(val, dev->bar[0] + reg); + } + + static inline void hifn_write_1(struct hifn_device *dev, u32 reg, u32 val) + { +- writel((__force u32)cpu_to_le32(val), dev->bar[1] + reg); ++ writel(val, dev->bar[1] + reg); + } + + static void hifn_wait_puc(struct hifn_device *dev) diff --git a/target/linux/generic/patches-4.0/880-gateworks_system_controller.patch b/target/linux/generic/patches-4.0/880-gateworks_system_controller.patch new file mode 100644 index 0000000..32796d5 --- /dev/null +++ b/target/linux/generic/patches-4.0/880-gateworks_system_controller.patch @@ -0,0 +1,339 @@ +--- a/drivers/hwmon/Kconfig ++++ b/drivers/hwmon/Kconfig +@@ -507,6 +507,15 @@ config SENSORS_G762 + This driver can also be built as a module. If so, the module + will be called g762. + ++config SENSORS_GSC ++ tristate "Gateworks System Controller" ++ depends on I2C ++ help ++ If you say yes here you get support for the Gateworks System Controller. ++ ++ This driver can also be built as a module. If so, the module ++ will be called gsc. ++ + config SENSORS_GPIO_FAN + tristate "GPIO fan" + depends on GPIOLIB +--- a/drivers/hwmon/Makefile ++++ b/drivers/hwmon/Makefile +@@ -155,6 +155,7 @@ obj-$(CONFIG_SENSORS_W83L785TS) += w83l7 + obj-$(CONFIG_SENSORS_W83L786NG) += w83l786ng.o + obj-$(CONFIG_SENSORS_WM831X) += wm831x-hwmon.o + obj-$(CONFIG_SENSORS_WM8350) += wm8350-hwmon.o ++obj-$(CONFIG_SENSORS_GSC) += gsc.o + + obj-$(CONFIG_PMBUS) += pmbus/ + +--- /dev/null ++++ b/drivers/hwmon/gsc.c +@@ -0,0 +1,308 @@ ++/* ++ * A hwmon driver for the Gateworks System Controller ++ * Copyright (C) 2009 Gateworks Corporation ++ * ++ * Author: Chris Lang ++ * ++ * 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 - version 2. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define DRV_VERSION "0.2" ++ ++enum chips { gsp }; ++ ++/* AD7418 registers */ ++#define GSP_REG_TEMP_IN 0x00 ++#define GSP_REG_VIN 0x02 ++#define GSP_REG_3P3 0x05 ++#define GSP_REG_BAT 0x08 ++#define GSP_REG_5P0 0x0b ++#define GSP_REG_CORE 0x0e ++#define GSP_REG_CPU1 0x11 ++#define GSP_REG_CPU2 0x14 ++#define GSP_REG_DRAM 0x17 ++#define GSP_REG_EXT_BAT 0x1a ++#define GSP_REG_IO1 0x1d ++#define GSP_REG_IO2 0x20 ++#define GSP_REG_PCIE 0x23 ++#define GSP_REG_CURRENT 0x26 ++#define GSP_FAN_0 0x2C ++#define GSP_FAN_1 0x2E ++#define GSP_FAN_2 0x30 ++#define GSP_FAN_3 0x32 ++#define GSP_FAN_4 0x34 ++#define GSP_FAN_5 0x36 ++ ++struct gsp_sensor_info { ++ const char* name; ++ int reg; ++}; ++ ++static const struct gsp_sensor_info gsp_sensors[] = { ++ {"temp", GSP_REG_TEMP_IN}, ++ {"vin", GSP_REG_VIN}, ++ {"3p3", GSP_REG_3P3}, ++ {"bat", GSP_REG_BAT}, ++ {"5p0", GSP_REG_5P0}, ++ {"core", GSP_REG_CORE}, ++ {"cpu1", GSP_REG_CPU1}, ++ {"cpu2", GSP_REG_CPU2}, ++ {"dram", GSP_REG_DRAM}, ++ {"ext_bat", GSP_REG_EXT_BAT}, ++ {"io1", GSP_REG_IO1}, ++ {"io2", GSP_REG_IO2}, ++ {"pci2", GSP_REG_PCIE}, ++ {"current", GSP_REG_CURRENT}, ++ {"fan_point0", GSP_FAN_0}, ++ {"fan_point1", GSP_FAN_1}, ++ {"fan_point2", GSP_FAN_2}, ++ {"fan_point3", GSP_FAN_3}, ++ {"fan_point4", GSP_FAN_4}, ++ {"fan_point5", GSP_FAN_5}, ++}; ++ ++struct gsp_data { ++ struct device *hwmon_dev; ++ struct attribute_group attrs; ++ enum chips type; ++}; ++ ++static int gsp_probe(struct i2c_client *client, ++ const struct i2c_device_id *id); ++static int gsp_remove(struct i2c_client *client); ++ ++static const struct i2c_device_id gsp_id[] = { ++ { "gsp", 0 }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, gsp_id); ++ ++static struct i2c_driver gsp_driver = { ++ .driver = { ++ .name = "gsp", ++ }, ++ .probe = gsp_probe, ++ .remove = gsp_remove, ++ .id_table = gsp_id, ++}; ++ ++/* All registers are word-sized, except for the configuration registers. ++ * AD7418 uses a high-byte first convention. Do NOT use those functions to ++ * access the configuration registers CONF and CONF2, as they are byte-sized. ++ */ ++static inline int gsp_read(struct i2c_client *client, u8 reg) ++{ ++ unsigned int adc = 0; ++ if (reg == GSP_REG_TEMP_IN || reg > GSP_REG_CURRENT) ++ { ++ adc |= i2c_smbus_read_byte_data(client, reg); ++ adc |= i2c_smbus_read_byte_data(client, reg + 1) << 8; ++ return adc; ++ } ++ else ++ { ++ adc |= i2c_smbus_read_byte_data(client, reg); ++ adc |= i2c_smbus_read_byte_data(client, reg + 1) << 8; ++ adc |= i2c_smbus_read_byte_data(client, reg + 2) << 16; ++ return adc; ++ } ++} ++ ++static inline int gsp_write(struct i2c_client *client, u8 reg, u16 value) ++{ ++ i2c_smbus_write_byte_data(client, reg, value & 0xff); ++ i2c_smbus_write_byte_data(client, reg + 1, ((value >> 8) & 0xff)); ++ return 1; ++} ++ ++static ssize_t show_adc(struct device *dev, struct device_attribute *devattr, ++ char *buf) ++{ ++ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); ++ struct i2c_client *client = to_i2c_client(dev); ++ return sprintf(buf, "%d\n", gsp_read(client, gsp_sensors[attr->index].reg)); ++} ++ ++static ssize_t show_label(struct device *dev, ++ struct device_attribute *devattr, char *buf) ++{ ++ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); ++ ++ return sprintf(buf, "%s\n", gsp_sensors[attr->index].name); ++} ++ ++static ssize_t store_fan(struct device *dev, ++ struct device_attribute *devattr, const char *buf, size_t count) ++{ ++ u16 val; ++ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); ++ struct i2c_client *client = to_i2c_client(dev); ++ val = simple_strtoul(buf, NULL, 10); ++ gsp_write(client, gsp_sensors[attr->index].reg, val); ++ return count; ++} ++ ++static SENSOR_DEVICE_ATTR(temp0_input, S_IRUGO, show_adc, NULL, 0); ++static SENSOR_DEVICE_ATTR(temp0_label, S_IRUGO, show_label, NULL, 0); ++ ++static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, show_adc, NULL, 1); ++static SENSOR_DEVICE_ATTR(in0_label, S_IRUGO, show_label, NULL, 1); ++static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_adc, NULL, 2); ++static SENSOR_DEVICE_ATTR(in1_label, S_IRUGO, show_label, NULL, 2); ++static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_adc, NULL, 3); ++static SENSOR_DEVICE_ATTR(in2_label, S_IRUGO, show_label, NULL, 3); ++static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_adc, NULL, 4); ++static SENSOR_DEVICE_ATTR(in3_label, S_IRUGO, show_label, NULL, 4); ++static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, show_adc, NULL, 5); ++static SENSOR_DEVICE_ATTR(in4_label, S_IRUGO, show_label, NULL, 5); ++static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, show_adc, NULL, 6); ++static SENSOR_DEVICE_ATTR(in5_label, S_IRUGO, show_label, NULL, 6); ++static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, show_adc, NULL, 7); ++static SENSOR_DEVICE_ATTR(in6_label, S_IRUGO, show_label, NULL, 7); ++static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, show_adc, NULL, 8); ++static SENSOR_DEVICE_ATTR(in7_label, S_IRUGO, show_label, NULL, 8); ++static SENSOR_DEVICE_ATTR(in8_input, S_IRUGO, show_adc, NULL, 9); ++static SENSOR_DEVICE_ATTR(in8_label, S_IRUGO, show_label, NULL, 9); ++static SENSOR_DEVICE_ATTR(in9_input, S_IRUGO, show_adc, NULL, 10); ++static SENSOR_DEVICE_ATTR(in9_label, S_IRUGO, show_label, NULL, 10); ++static SENSOR_DEVICE_ATTR(in10_input, S_IRUGO, show_adc, NULL, 11); ++static SENSOR_DEVICE_ATTR(in10_label, S_IRUGO, show_label, NULL, 11); ++static SENSOR_DEVICE_ATTR(in11_input, S_IRUGO, show_adc, NULL, 12); ++static SENSOR_DEVICE_ATTR(in11_label, S_IRUGO, show_label, NULL, 12); ++static SENSOR_DEVICE_ATTR(in12_input, S_IRUGO, show_adc, NULL, 13); ++static SENSOR_DEVICE_ATTR(in12_label, S_IRUGO, show_label, NULL, 13); ++ ++static SENSOR_DEVICE_ATTR(fan0_point0, S_IRUGO | S_IWUSR, show_adc, store_fan, 14); ++static SENSOR_DEVICE_ATTR(fan0_point1, S_IRUGO | S_IWUSR, show_adc, store_fan, 15); ++static SENSOR_DEVICE_ATTR(fan0_point2, S_IRUGO | S_IWUSR, show_adc, store_fan, 16); ++static SENSOR_DEVICE_ATTR(fan0_point3, S_IRUGO | S_IWUSR, show_adc, store_fan, 17); ++static SENSOR_DEVICE_ATTR(fan0_point4, S_IRUGO | S_IWUSR, show_adc, store_fan, 18); ++static SENSOR_DEVICE_ATTR(fan0_point5, S_IRUGO | S_IWUSR, show_adc, store_fan, 19); ++ ++static struct attribute *gsp_attributes[] = { ++ &sensor_dev_attr_temp0_input.dev_attr.attr, ++ &sensor_dev_attr_in0_input.dev_attr.attr, ++ &sensor_dev_attr_in1_input.dev_attr.attr, ++ &sensor_dev_attr_in2_input.dev_attr.attr, ++ &sensor_dev_attr_in3_input.dev_attr.attr, ++ &sensor_dev_attr_in4_input.dev_attr.attr, ++ &sensor_dev_attr_in5_input.dev_attr.attr, ++ &sensor_dev_attr_in6_input.dev_attr.attr, ++ &sensor_dev_attr_in7_input.dev_attr.attr, ++ &sensor_dev_attr_in8_input.dev_attr.attr, ++ &sensor_dev_attr_in9_input.dev_attr.attr, ++ &sensor_dev_attr_in10_input.dev_attr.attr, ++ &sensor_dev_attr_in11_input.dev_attr.attr, ++ &sensor_dev_attr_in12_input.dev_attr.attr, ++ ++ &sensor_dev_attr_temp0_label.dev_attr.attr, ++ &sensor_dev_attr_in0_label.dev_attr.attr, ++ &sensor_dev_attr_in1_label.dev_attr.attr, ++ &sensor_dev_attr_in2_label.dev_attr.attr, ++ &sensor_dev_attr_in3_label.dev_attr.attr, ++ &sensor_dev_attr_in4_label.dev_attr.attr, ++ &sensor_dev_attr_in5_label.dev_attr.attr, ++ &sensor_dev_attr_in6_label.dev_attr.attr, ++ &sensor_dev_attr_in7_label.dev_attr.attr, ++ &sensor_dev_attr_in8_label.dev_attr.attr, ++ &sensor_dev_attr_in9_label.dev_attr.attr, ++ &sensor_dev_attr_in10_label.dev_attr.attr, ++ &sensor_dev_attr_in11_label.dev_attr.attr, ++ &sensor_dev_attr_in12_label.dev_attr.attr, ++ ++ &sensor_dev_attr_fan0_point0.dev_attr.attr, ++ &sensor_dev_attr_fan0_point1.dev_attr.attr, ++ &sensor_dev_attr_fan0_point2.dev_attr.attr, ++ &sensor_dev_attr_fan0_point3.dev_attr.attr, ++ &sensor_dev_attr_fan0_point4.dev_attr.attr, ++ &sensor_dev_attr_fan0_point5.dev_attr.attr, ++ NULL ++}; ++ ++ ++static int gsp_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct i2c_adapter *adapter = client->adapter; ++ struct gsp_data *data; ++ int err; ++ ++ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | ++ I2C_FUNC_SMBUS_WORD_DATA)) { ++ err = -EOPNOTSUPP; ++ goto exit; ++ } ++ ++ if (!(data = kzalloc(sizeof(struct gsp_data), GFP_KERNEL))) { ++ err = -ENOMEM; ++ goto exit; ++ } ++ ++ i2c_set_clientdata(client, data); ++ ++ data->type = id->driver_data; ++ ++ switch (data->type) { ++ case 0: ++ data->attrs.attrs = gsp_attributes; ++ break; ++ } ++ ++ dev_info(&client->dev, "%s chip found\n", client->name); ++ ++ /* Register sysfs hooks */ ++ if ((err = sysfs_create_group(&client->dev.kobj, &data->attrs))) ++ goto exit_free; ++ ++ data->hwmon_dev = hwmon_device_register(&client->dev); ++ if (IS_ERR(data->hwmon_dev)) { ++ err = PTR_ERR(data->hwmon_dev); ++ goto exit_remove; ++ } ++ ++ return 0; ++ ++exit_remove: ++ sysfs_remove_group(&client->dev.kobj, &data->attrs); ++exit_free: ++ kfree(data); ++exit: ++ return err; ++} ++ ++static int gsp_remove(struct i2c_client *client) ++{ ++ struct gsp_data *data = i2c_get_clientdata(client); ++ hwmon_device_unregister(data->hwmon_dev); ++ sysfs_remove_group(&client->dev.kobj, &data->attrs); ++ kfree(data); ++ return 0; ++} ++ ++static int __init gsp_init(void) ++{ ++ return i2c_add_driver(&gsp_driver); ++} ++ ++static void __exit gsp_exit(void) ++{ ++ i2c_del_driver(&gsp_driver); ++} ++ ++module_init(gsp_init); ++module_exit(gsp_exit); ++ ++MODULE_AUTHOR("Chris Lang "); ++MODULE_DESCRIPTION("GSC HWMON driver"); ++MODULE_LICENSE("GPL"); ++MODULE_VERSION(DRV_VERSION); ++ diff --git a/target/linux/generic/patches-4.0/890-8250_optional_sysrq.patch b/target/linux/generic/patches-4.0/890-8250_optional_sysrq.patch new file mode 100644 index 0000000..8815e4c --- /dev/null +++ b/target/linux/generic/patches-4.0/890-8250_optional_sysrq.patch @@ -0,0 +1,24 @@ +--- a/drivers/tty/serial/8250/8250_core.c ++++ b/drivers/tty/serial/8250/8250_core.c +@@ -16,7 +16,7 @@ + * membase is an 'ioremapped' cookie. + */ + +-#if defined(CONFIG_SERIAL_8250_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) ++#if defined(CONFIG_SERIAL_8250_SYSRQ) && defined(CONFIG_MAGIC_SYSRQ) + #define SUPPORT_SYSRQ + #endif + +--- a/drivers/tty/serial/8250/Kconfig ++++ b/drivers/tty/serial/8250/Kconfig +@@ -91,6 +91,10 @@ config SERIAL_8250_CONSOLE + + If unsure, say N. + ++config SERIAL_8250_SYSRQ ++ bool "Magic sysrq support on 8250/16550 devices" ++ depends on SERIAL_8250_CONSOLE ++ + config SERIAL_8250_GSC + tristate + depends on SERIAL_8250 && GSC diff --git a/target/linux/generic/patches-4.0/900-slab_maxsize.patch b/target/linux/generic/patches-4.0/900-slab_maxsize.patch new file mode 100644 index 0000000..10133f2 --- /dev/null +++ b/target/linux/generic/patches-4.0/900-slab_maxsize.patch @@ -0,0 +1,13 @@ +--- a/include/linux/slab.h ++++ b/include/linux/slab.h +@@ -171,8 +171,8 @@ size_t ksize(const void *); + * to do various tricks to work around compiler limitations in order to + * ensure proper constant folding. + */ +-#define KMALLOC_SHIFT_HIGH ((MAX_ORDER + PAGE_SHIFT - 1) <= 25 ? \ +- (MAX_ORDER + PAGE_SHIFT - 1) : 25) ++#define KMALLOC_SHIFT_HIGH ((MAX_ORDER + PAGE_SHIFT - 1) <= 17 ? \ ++ (MAX_ORDER + PAGE_SHIFT - 1) : 17) + #define KMALLOC_SHIFT_MAX KMALLOC_SHIFT_HIGH + #ifndef KMALLOC_SHIFT_LOW + #define KMALLOC_SHIFT_LOW 5 diff --git a/target/linux/generic/patches-4.0/901-debloat_sock_diag.patch b/target/linux/generic/patches-4.0/901-debloat_sock_diag.patch new file mode 100644 index 0000000..9208d6b --- /dev/null +++ b/target/linux/generic/patches-4.0/901-debloat_sock_diag.patch @@ -0,0 +1,45 @@ +--- a/net/Kconfig ++++ b/net/Kconfig +@@ -89,6 +89,9 @@ source "net/netlabel/Kconfig" + + endif # if INET + ++config SOCK_DIAG ++ bool ++ + config NETWORK_SECMARK + bool "Security Marking" + help +--- a/net/core/Makefile ++++ b/net/core/Makefile +@@ -9,8 +9,9 @@ obj-$(CONFIG_SYSCTL) += sysctl_net_core. + + obj-y += dev.o ethtool.o dev_addr_lists.o dst.o netevent.o \ + neighbour.o rtnetlink.o utils.o link_watch.o filter.o \ +- sock_diag.o dev_ioctl.o tso.o ++ dev_ioctl.o tso.o + ++obj-$(CONFIG_SOCK_DIAG) += sock_diag.o + obj-$(CONFIG_XFRM) += flow.o + obj-y += net-sysfs.o + obj-$(CONFIG_PROC_FS) += net-procfs.o +--- a/net/ipv4/Kconfig ++++ b/net/ipv4/Kconfig +@@ -428,6 +428,7 @@ config INET_LRO + + config INET_DIAG + tristate "INET: socket monitoring interface" ++ select SOCK_DIAG + default y + ---help--- + Support for INET (TCP, DCCP, etc) socket monitoring interface used by +--- a/net/unix/Kconfig ++++ b/net/unix/Kconfig +@@ -22,6 +22,7 @@ config UNIX + config UNIX_DIAG + tristate "UNIX: socket monitoring interface" + depends on UNIX ++ select SOCK_DIAG + default n + ---help--- + Support for UNIX socket monitoring interface used by the ss tool. diff --git a/target/linux/generic/patches-4.0/902-debloat_proc.patch b/target/linux/generic/patches-4.0/902-debloat_proc.patch new file mode 100644 index 0000000..ca9fd91 --- /dev/null +++ b/target/linux/generic/patches-4.0/902-debloat_proc.patch @@ -0,0 +1,341 @@ +--- a/fs/locks.c ++++ b/fs/locks.c +@@ -2640,6 +2640,8 @@ static const struct file_operations proc + + static int __init proc_locks_init(void) + { ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return 0; + proc_create("locks", 0, NULL, &proc_locks_operations); + return 0; + } +--- a/fs/proc/Kconfig ++++ b/fs/proc/Kconfig +@@ -71,3 +71,8 @@ config PROC_PAGE_MONITOR + /proc/pid/smaps, /proc/pid/clear_refs, /proc/pid/pagemap, + /proc/kpagecount, and /proc/kpageflags. Disabling these + interfaces will reduce the size of the kernel by approximately 4kb. ++ ++config PROC_STRIPPED ++ default n ++ depends on EXPERT ++ bool "Strip non-essential /proc functionality to reduce code size" +--- a/fs/proc/consoles.c ++++ b/fs/proc/consoles.c +@@ -106,6 +106,9 @@ static const struct file_operations proc + + static int __init proc_consoles_init(void) + { ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return 0; ++ + proc_create("consoles", 0, NULL, &proc_consoles_operations); + return 0; + } +--- a/fs/proc/proc_tty.c ++++ b/fs/proc/proc_tty.c +@@ -143,7 +143,10 @@ static const struct file_operations proc + void proc_tty_register_driver(struct tty_driver *driver) + { + struct proc_dir_entry *ent; +- ++ ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return; ++ + if (!driver->driver_name || driver->proc_entry || + !driver->ops->proc_fops) + return; +@@ -160,6 +163,9 @@ void proc_tty_unregister_driver(struct t + { + struct proc_dir_entry *ent; + ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return; ++ + ent = driver->proc_entry; + if (!ent) + return; +@@ -174,6 +180,9 @@ void proc_tty_unregister_driver(struct t + */ + void __init proc_tty_init(void) + { ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return; ++ + if (!proc_mkdir("tty", NULL)) + return; + proc_mkdir("tty/ldisc", NULL); /* Preserved: it's userspace visible */ +--- a/kernel/exec_domain.c ++++ b/kernel/exec_domain.c +@@ -176,6 +176,8 @@ static const struct file_operations exec + + static int __init proc_execdomains_init(void) + { ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return 0; + proc_create("execdomains", 0, NULL, &execdomains_proc_fops); + return 0; + } +--- a/kernel/irq/proc.c ++++ b/kernel/irq/proc.c +@@ -325,6 +325,9 @@ void register_irq_proc(unsigned int irq, + { + char name [MAX_NAMELEN]; + ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED) && !IS_ENABLED(CONFIG_SMP)) ++ return; ++ + if (!root_irq_dir || (desc->irq_data.chip == &no_irq_chip) || desc->dir) + return; + +@@ -361,6 +364,9 @@ void unregister_irq_proc(unsigned int ir + { + char name [MAX_NAMELEN]; + ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED) && !IS_ENABLED(CONFIG_SMP)) ++ return; ++ + if (!root_irq_dir || !desc->dir) + return; + #ifdef CONFIG_SMP +@@ -396,6 +402,9 @@ void init_irq_proc(void) + unsigned int irq; + struct irq_desc *desc; + ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED) && !IS_ENABLED(CONFIG_SMP)) ++ return; ++ + /* create /proc/irq */ + root_irq_dir = proc_mkdir("irq", NULL); + if (!root_irq_dir) +--- a/kernel/time/timer_list.c ++++ b/kernel/time/timer_list.c +@@ -362,6 +362,8 @@ static int __init init_timer_list_procfs + { + struct proc_dir_entry *pe; + ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return 0; + pe = proc_create("timer_list", 0444, NULL, &timer_list_fops); + if (!pe) + return -ENOMEM; +--- a/mm/vmalloc.c ++++ b/mm/vmalloc.c +@@ -2662,6 +2662,8 @@ static const struct file_operations proc + + static int __init proc_vmalloc_init(void) + { ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return 0; + proc_create("vmallocinfo", S_IRUSR, NULL, &proc_vmalloc_operations); + return 0; + } +--- a/mm/vmstat.c ++++ b/mm/vmstat.c +@@ -1528,10 +1528,12 @@ static int __init setup_vmstat(void) + cpu_notifier_register_done(); + #endif + #ifdef CONFIG_PROC_FS +- proc_create("buddyinfo", S_IRUGO, NULL, &fragmentation_file_operations); +- proc_create("pagetypeinfo", S_IRUGO, NULL, &pagetypeinfo_file_ops); ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) { ++ proc_create("buddyinfo", S_IRUGO, NULL, &fragmentation_file_operations); ++ proc_create("pagetypeinfo", S_IRUGO, NULL, &pagetypeinfo_file_ops); ++ proc_create("zoneinfo", S_IRUGO, NULL, &proc_zoneinfo_file_operations); ++ } + proc_create("vmstat", S_IRUGO, NULL, &proc_vmstat_file_operations); +- proc_create("zoneinfo", S_IRUGO, NULL, &proc_zoneinfo_file_operations); + #endif + return 0; + } +--- a/net/8021q/vlanproc.c ++++ b/net/8021q/vlanproc.c +@@ -127,6 +127,9 @@ void vlan_proc_cleanup(struct net *net) + { + struct vlan_net *vn = net_generic(net, vlan_net_id); + ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return; ++ + if (vn->proc_vlan_conf) + remove_proc_entry(name_conf, vn->proc_vlan_dir); + +@@ -146,6 +149,9 @@ int __net_init vlan_proc_init(struct net + { + struct vlan_net *vn = net_generic(net, vlan_net_id); + ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return 0; ++ + vn->proc_vlan_dir = proc_net_mkdir(net, name_root, net->proc_net); + if (!vn->proc_vlan_dir) + goto err; +--- a/net/core/sock.c ++++ b/net/core/sock.c +@@ -2975,6 +2975,8 @@ static __net_initdata struct pernet_oper + + static int __init proto_init(void) + { ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return 0; + return register_pernet_subsys(&proto_net_ops); + } + +--- a/net/ipv4/fib_trie.c ++++ b/net/ipv4/fib_trie.c +@@ -2490,10 +2490,12 @@ static const struct file_operations fib_ + + int __net_init fib_proc_init(struct net *net) + { +- if (!proc_create("fib_trie", S_IRUGO, net->proc_net, &fib_trie_fops)) ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED) && ++ !proc_create("fib_trie", S_IRUGO, net->proc_net, &fib_trie_fops)) + goto out1; + +- if (!proc_create("fib_triestat", S_IRUGO, net->proc_net, ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED) && ++ !proc_create("fib_triestat", S_IRUGO, net->proc_net, + &fib_triestat_fops)) + goto out2; + +@@ -2503,17 +2505,21 @@ int __net_init fib_proc_init(struct net + return 0; + + out3: +- remove_proc_entry("fib_triestat", net->proc_net); ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ remove_proc_entry("fib_triestat", net->proc_net); + out2: +- remove_proc_entry("fib_trie", net->proc_net); ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ remove_proc_entry("fib_trie", net->proc_net); + out1: + return -ENOMEM; + } + + void __net_exit fib_proc_exit(struct net *net) + { +- remove_proc_entry("fib_trie", net->proc_net); +- remove_proc_entry("fib_triestat", net->proc_net); ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) { ++ remove_proc_entry("fib_trie", net->proc_net); ++ remove_proc_entry("fib_triestat", net->proc_net); ++ } + remove_proc_entry("route", net->proc_net); + } + +--- a/net/ipv4/proc.c ++++ b/net/ipv4/proc.c +@@ -535,6 +535,9 @@ static __net_initdata struct pernet_oper + + int __init ip_misc_proc_init(void) + { ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return 0; ++ + return register_pernet_subsys(&ip_proc_ops); + } + +--- a/net/ipv4/route.c ++++ b/net/ipv4/route.c +@@ -416,6 +416,9 @@ static struct pernet_operations ip_rt_pr + + static int __init ip_rt_proc_init(void) + { ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return 0; ++ + return register_pernet_subsys(&ip_rt_proc_ops); + } + +--- a/ipc/msg.c ++++ b/ipc/msg.c +@@ -1038,6 +1038,9 @@ void __init msg_init(void) + { + msg_init_ns(&init_ipc_ns); + ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return; ++ + ipc_init_proc_interface("sysvipc/msg", + " key msqid perms cbytes qnum lspid lrpid uid gid cuid cgid stime rtime ctime\n", + IPC_MSG_IDS, sysvipc_msg_proc_show); +--- a/ipc/sem.c ++++ b/ipc/sem.c +@@ -191,6 +191,8 @@ void sem_exit_ns(struct ipc_namespace *n + void __init sem_init(void) + { + sem_init_ns(&init_ipc_ns); ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return; + ipc_init_proc_interface("sysvipc/sem", + " key semid perms nsems uid gid cuid cgid otime ctime\n", + IPC_SEM_IDS, sysvipc_sem_proc_show); +--- a/ipc/shm.c ++++ b/ipc/shm.c +@@ -118,6 +118,8 @@ pure_initcall(ipc_ns_init); + + void __init shm_init(void) + { ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return; + ipc_init_proc_interface("sysvipc/shm", + #if BITS_PER_LONG <= 32 + " key shmid perms size cpid lpid nattch uid gid cuid cgid atime dtime ctime rss swap\n", +--- a/ipc/util.c ++++ b/ipc/util.c +@@ -121,6 +121,9 @@ void __init ipc_init_proc_interface(cons + struct proc_dir_entry *pde; + struct ipc_proc_iface *iface; + ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return; ++ + iface = kmalloc(sizeof(*iface), GFP_KERNEL); + if (!iface) + return; +--- a/net/core/net-procfs.c ++++ b/net/core/net-procfs.c +@@ -318,10 +318,12 @@ static int __net_init dev_proc_net_init( + + if (!proc_create("dev", S_IRUGO, net->proc_net, &dev_seq_fops)) + goto out; +- if (!proc_create("softnet_stat", S_IRUGO, net->proc_net, ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED) && ++ !proc_create("softnet_stat", S_IRUGO, net->proc_net, + &softnet_seq_fops)) + goto out_dev; +- if (!proc_create("ptype", S_IRUGO, net->proc_net, &ptype_seq_fops)) ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED) && ++ !proc_create("ptype", S_IRUGO, net->proc_net, &ptype_seq_fops)) + goto out_softnet; + + if (wext_proc_init(net)) +@@ -330,9 +332,11 @@ static int __net_init dev_proc_net_init( + out: + return rc; + out_ptype: +- remove_proc_entry("ptype", net->proc_net); ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ remove_proc_entry("ptype", net->proc_net); + out_softnet: +- remove_proc_entry("softnet_stat", net->proc_net); ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ remove_proc_entry("softnet_stat", net->proc_net); + out_dev: + remove_proc_entry("dev", net->proc_net); + goto out; +@@ -342,8 +346,10 @@ static void __net_exit dev_proc_net_exit + { + wext_proc_exit(net); + +- remove_proc_entry("ptype", net->proc_net); +- remove_proc_entry("softnet_stat", net->proc_net); ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) { ++ remove_proc_entry("ptype", net->proc_net); ++ remove_proc_entry("softnet_stat", net->proc_net); ++ } + remove_proc_entry("dev", net->proc_net); + } + diff --git a/target/linux/generic/patches-4.0/903-debloat_direct_io.patch b/target/linux/generic/patches-4.0/903-debloat_direct_io.patch new file mode 100644 index 0000000..1b5453b --- /dev/null +++ b/target/linux/generic/patches-4.0/903-debloat_direct_io.patch @@ -0,0 +1,79 @@ +--- a/fs/Kconfig ++++ b/fs/Kconfig +@@ -70,6 +70,11 @@ config FILE_LOCKING + for filesystems like NFS and for the flock() system + call. Disabling this option saves about 11k. + ++config DIRECT_IO ++ bool "Enable O_DIRECT support" if EXPERT ++ depends on BLOCK ++ default y ++ + source "fs/notify/Kconfig" + + source "fs/quota/Kconfig" +--- a/fs/Makefile ++++ b/fs/Makefile +@@ -14,7 +14,8 @@ obj-y := open.o read_write.o file_table. + stack.o fs_struct.o statfs.o fs_pin.o nsfs.o + + ifeq ($(CONFIG_BLOCK),y) +-obj-y += buffer.o block_dev.o direct-io.o mpage.o ++obj-y += buffer.o block_dev.o mpage.o ++obj-$(CONFIG_DIRECT_IO) += direct-io.o + else + obj-y += no-block.o + endif +--- a/include/linux/fs.h ++++ b/include/linux/fs.h +@@ -2615,12 +2615,25 @@ enum { + DIO_ASYNC_EXTEND = 0x04, + }; + ++#ifdef CONFIG_DIRECT_IO + void dio_end_io(struct bio *bio, int error); + + ssize_t __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, + struct block_device *bdev, struct iov_iter *iter, loff_t offset, + get_block_t get_block, dio_iodone_t end_io, + dio_submit_t submit_io, int flags); ++#else ++static inline void dio_end_io(struct bio *bio, int error) ++{ ++} ++static inline ssize_t __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, ++ struct block_device *bdev, struct iov_iter *iter, loff_t offset, ++ get_block_t get_block, dio_iodone_t end_io, ++ dio_submit_t submit_io, int flags) ++{ ++ return -EOPNOTSUPP; ++} ++#endif + + static inline ssize_t blockdev_direct_IO(int rw, struct kiocb *iocb, + struct inode *inode, struct iov_iter *iter, loff_t offset, +--- a/fs/fcntl.c ++++ b/fs/fcntl.c +@@ -52,8 +52,10 @@ static int setfl(int fd, struct file * f + arg |= O_NONBLOCK; + + if (arg & O_DIRECT) { ++#ifdef CONFIG_DIRECT_IO + if (!filp->f_mapping || !filp->f_mapping->a_ops || + !filp->f_mapping->a_ops->direct_IO) ++#endif + return -EINVAL; + } + +--- a/fs/open.c ++++ b/fs/open.c +@@ -667,7 +667,9 @@ int open_check_o_direct(struct file *f) + { + /* NB: we're sure to have correct a_ops only after f_op->open */ + if (f->f_flags & O_DIRECT) { ++#ifdef CONFIG_DIRECT_IO + if (!f->f_mapping->a_ops || !f->f_mapping->a_ops->direct_IO) ++#endif + return -EINVAL; + } + return 0; diff --git a/target/linux/generic/patches-4.0/910-kobject_uevent.patch b/target/linux/generic/patches-4.0/910-kobject_uevent.patch new file mode 100644 index 0000000..a2c935f --- /dev/null +++ b/target/linux/generic/patches-4.0/910-kobject_uevent.patch @@ -0,0 +1,21 @@ +--- a/lib/kobject_uevent.c ++++ b/lib/kobject_uevent.c +@@ -52,6 +52,18 @@ static const char *kobject_actions[] = { + [KOBJ_OFFLINE] = "offline", + }; + ++u64 uevent_next_seqnum(void) ++{ ++ u64 seq; ++ ++ mutex_lock(&uevent_sock_mutex); ++ seq = ++uevent_seqnum; ++ mutex_unlock(&uevent_sock_mutex); ++ ++ return seq; ++} ++EXPORT_SYMBOL_GPL(uevent_next_seqnum); ++ + /** + * kobject_action_type - translate action string to numeric type + * diff --git a/target/linux/generic/patches-4.0/911-kobject_add_broadcast_uevent.patch b/target/linux/generic/patches-4.0/911-kobject_add_broadcast_uevent.patch new file mode 100644 index 0000000..3afaac1 --- /dev/null +++ b/target/linux/generic/patches-4.0/911-kobject_add_broadcast_uevent.patch @@ -0,0 +1,65 @@ +--- a/include/linux/kobject.h ++++ b/include/linux/kobject.h +@@ -32,6 +32,8 @@ + #define UEVENT_NUM_ENVP 32 /* number of env pointers */ + #define UEVENT_BUFFER_SIZE 2048 /* buffer for the variables */ + ++struct sk_buff; ++ + #ifdef CONFIG_UEVENT_HELPER + /* path to the userspace helper executed on an event */ + extern char uevent_helper[]; +@@ -221,4 +223,7 @@ int add_uevent_var(struct kobj_uevent_en + int kobject_action_type(const char *buf, size_t count, + enum kobject_action *type); + ++int broadcast_uevent(struct sk_buff *skb, __u32 pid, __u32 group, ++ gfp_t allocation); ++ + #endif /* _KOBJECT_H_ */ +--- a/lib/kobject_uevent.c ++++ b/lib/kobject_uevent.c +@@ -423,6 +423,43 @@ int add_uevent_var(struct kobj_uevent_en + EXPORT_SYMBOL_GPL(add_uevent_var); + + #if defined(CONFIG_NET) ++int broadcast_uevent(struct sk_buff *skb, __u32 pid, __u32 group, ++ gfp_t allocation) ++{ ++ struct uevent_sock *ue_sk; ++ int err = 0; ++ ++ /* send netlink message */ ++ mutex_lock(&uevent_sock_mutex); ++ list_for_each_entry(ue_sk, &uevent_sock_list, list) { ++ struct sock *uevent_sock = ue_sk->sk; ++ struct sk_buff *skb2; ++ ++ skb2 = skb_clone(skb, allocation); ++ if (!skb2) ++ break; ++ ++ err = netlink_broadcast(uevent_sock, skb2, pid, group, ++ allocation); ++ if (err) ++ break; ++ } ++ mutex_unlock(&uevent_sock_mutex); ++ ++ kfree_skb(skb); ++ return err; ++} ++#else ++int broadcast_uevent(struct sk_buff *skb, __u32 pid, __u32 group, ++ gfp_t allocation) ++{ ++ kfree_skb(skb); ++ return 0; ++} ++#endif ++EXPORT_SYMBOL_GPL(broadcast_uevent); ++ ++#if defined(CONFIG_NET) + static int uevent_net_init(struct net *net) + { + struct uevent_sock *ue_sk; diff --git a/target/linux/generic/patches-4.0/921-use_preinit_as_init.patch b/target/linux/generic/patches-4.0/921-use_preinit_as_init.patch new file mode 100644 index 0000000..d0aa29f --- /dev/null +++ b/target/linux/generic/patches-4.0/921-use_preinit_as_init.patch @@ -0,0 +1,12 @@ +--- a/init/main.c ++++ b/init/main.c +@@ -957,7 +957,8 @@ static int __ref kernel_init(void *unuse + panic("Requested init %s failed (error %d).", + execute_command, ret); + } +- if (!try_to_run_init_process("/sbin/init") || ++ if (!try_to_run_init_process("/etc/preinit") || ++ !try_to_run_init_process("/sbin/init") || + !try_to_run_init_process("/etc/init") || + !try_to_run_init_process("/bin/init") || + !try_to_run_init_process("/bin/sh")) diff --git a/target/linux/generic/patches-4.0/922-always-create-console-node-in-initramfs.patch b/target/linux/generic/patches-4.0/922-always-create-console-node-in-initramfs.patch new file mode 100644 index 0000000..988de35 --- /dev/null +++ b/target/linux/generic/patches-4.0/922-always-create-console-node-in-initramfs.patch @@ -0,0 +1,30 @@ +--- a/scripts/gen_initramfs_list.sh ++++ b/scripts/gen_initramfs_list.sh +@@ -59,6 +59,18 @@ default_initramfs() { + EOF + } + ++list_openwrt_initramfs() { ++ : ++} ++ ++openwrt_initramfs() { ++ # make sure that /dev/console exists ++ cat <<-EOF >> ${output} ++ dir /dev 0755 0 0 ++ nod /dev/console 0600 0 0 c 5 1 ++ EOF ++} ++ + filetype() { + local argv1="$1" + +@@ -177,6 +189,8 @@ dir_filelist() { + if [ "$(echo "${dirlist}" | wc -l)" -gt 1 ]; then + ${dep_list}print_mtime "$1" + ++ ${dep_list}openwrt_initramfs ++ + echo "${dirlist}" | \ + while read x; do + ${dep_list}parse ${x} diff --git a/target/linux/generic/patches-4.0/930-crashlog.patch b/target/linux/generic/patches-4.0/930-crashlog.patch new file mode 100644 index 0000000..d9c5ecd --- /dev/null +++ b/target/linux/generic/patches-4.0/930-crashlog.patch @@ -0,0 +1,276 @@ +--- /dev/null ++++ b/include/linux/crashlog.h +@@ -0,0 +1,17 @@ ++#ifndef __CRASHLOG_H ++#define __CRASHLOG_H ++ ++#ifdef CONFIG_CRASHLOG ++void crashlog_init_bootmem(struct bootmem_data *bdata); ++void crashlog_init_memblock(phys_addr_t addr, phys_addr_t size); ++#else ++static inline void crashlog_init_bootmem(struct bootmem_data *bdata) ++{ ++} ++ ++static inline void crashlog_init_memblock(phys_addr_t addr, phys_addr_t size) ++{ ++} ++#endif ++ ++#endif +--- a/init/Kconfig ++++ b/init/Kconfig +@@ -1265,6 +1265,10 @@ config RELAY + + If unsure, say N. + ++config CRASHLOG ++ bool "Crash logging" ++ depends on (!NO_BOOTMEM || HAVE_MEMBLOCK) && !(ARM || SPARC || PPC) ++ + config BLK_DEV_INITRD + bool "Initial RAM filesystem and RAM disk (initramfs/initrd) support" + depends on BROKEN || !FRV +--- a/kernel/Makefile ++++ b/kernel/Makefile +@@ -96,6 +96,7 @@ obj-$(CONFIG_CRASH_DUMP) += crash_dump.o + obj-$(CONFIG_JUMP_LABEL) += jump_label.o + obj-$(CONFIG_CONTEXT_TRACKING) += context_tracking.o + obj-$(CONFIG_TORTURE_TEST) += torture.o ++obj-$(CONFIG_CRASHLOG) += crashlog.o + + $(obj)/configs.o: $(obj)/config_data.h + +--- /dev/null ++++ b/kernel/crashlog.c +@@ -0,0 +1,181 @@ ++/* ++ * Crash information logger ++ * Copyright (C) 2010 Felix Fietkau ++ * ++ * Based on ramoops.c ++ * Copyright (C) 2010 Marco Stornelli ++ * ++ * 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 ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define CRASHLOG_PAGES 4 ++#define CRASHLOG_SIZE (CRASHLOG_PAGES * PAGE_SIZE) ++#define CRASHLOG_MAGIC 0xa1eedead ++ ++/* ++ * Start the log at 1M before the end of RAM, as some boot loaders like ++ * to use the end of the RAM for stack usage and other things ++ * If this fails, fall back to using the last part. ++ */ ++#define CRASHLOG_OFFSET (1024 * 1024) ++ ++struct crashlog_data { ++ u32 magic; ++ u32 len; ++ u8 data[]; ++}; ++ ++static struct debugfs_blob_wrapper crashlog_blob; ++static unsigned long crashlog_addr = 0; ++static struct crashlog_data *crashlog_buf; ++static struct kmsg_dumper dump; ++static bool first = true; ++ ++extern struct list_head *crashlog_modules; ++ ++#ifndef CONFIG_NO_BOOTMEM ++void __init crashlog_init_bootmem(bootmem_data_t *bdata) ++{ ++ unsigned long addr; ++ ++ if (crashlog_addr) ++ return; ++ ++ addr = PFN_PHYS(bdata->node_low_pfn) - CRASHLOG_OFFSET; ++ if (reserve_bootmem(addr, CRASHLOG_SIZE, BOOTMEM_EXCLUSIVE) < 0) { ++ printk("Crashlog failed to allocate RAM at address 0x%lx\n", addr); ++ bdata->node_low_pfn -= CRASHLOG_PAGES; ++ addr = PFN_PHYS(bdata->node_low_pfn); ++ } ++ crashlog_addr = addr; ++} ++#endif ++ ++#ifdef CONFIG_HAVE_MEMBLOCK ++void __meminit crashlog_init_memblock(phys_addr_t addr, phys_addr_t size) ++{ ++ if (crashlog_addr) ++ return; ++ ++ addr += size - CRASHLOG_OFFSET; ++ if (memblock_reserve(addr, CRASHLOG_SIZE)) { ++ printk("Crashlog failed to allocate RAM at address 0x%lx\n", (unsigned long) addr); ++ return; ++ } ++ ++ crashlog_addr = addr; ++} ++#endif ++ ++static void __init crashlog_copy(void) ++{ ++ if (crashlog_buf->magic != CRASHLOG_MAGIC) ++ return; ++ ++ if (!crashlog_buf->len || crashlog_buf->len > ++ CRASHLOG_SIZE - sizeof(*crashlog_buf)) ++ return; ++ ++ crashlog_blob.size = crashlog_buf->len; ++ crashlog_blob.data = kmemdup(crashlog_buf->data, ++ crashlog_buf->len, GFP_KERNEL); ++ ++ debugfs_create_blob("crashlog", 0700, NULL, &crashlog_blob); ++} ++ ++static int get_maxlen(void) ++{ ++ return CRASHLOG_SIZE - sizeof(*crashlog_buf) - crashlog_buf->len; ++} ++ ++static void crashlog_printf(const char *fmt, ...) ++{ ++ va_list args; ++ int len = get_maxlen(); ++ ++ if (!len) ++ return; ++ ++ va_start(args, fmt); ++ crashlog_buf->len += vscnprintf( ++ &crashlog_buf->data[crashlog_buf->len], ++ len, fmt, args); ++ va_end(args); ++} ++ ++static void crashlog_do_dump(struct kmsg_dumper *dumper, ++ enum kmsg_dump_reason reason) ++{ ++ struct timeval tv; ++ struct module *m; ++ char *buf; ++ size_t len; ++ ++ if (!first) ++ crashlog_printf("\n===================================\n"); ++ ++ do_gettimeofday(&tv); ++ crashlog_printf("Time: %lu.%lu\n", ++ (long)tv.tv_sec, (long)tv.tv_usec); ++ ++ if (first) { ++ crashlog_printf("Modules:"); ++ list_for_each_entry(m, crashlog_modules, list) { ++ crashlog_printf("\t%s@%p+%x", m->name, ++ m->module_core, m->core_size, ++ m->module_init, m->init_size); ++ } ++ crashlog_printf("\n"); ++ first = false; ++ } ++ ++ buf = (char *)&crashlog_buf->data[crashlog_buf->len]; ++ ++ kmsg_dump_get_buffer(dumper, true, buf, get_maxlen(), &len); ++ ++ crashlog_buf->len += len; ++} ++ ++ ++int __init crashlog_init_fs(void) ++{ ++ if (!crashlog_addr) ++ return -ENOMEM; ++ ++ crashlog_buf = ioremap(crashlog_addr, CRASHLOG_SIZE); ++ ++ crashlog_copy(); ++ ++ crashlog_buf->magic = CRASHLOG_MAGIC; ++ crashlog_buf->len = 0; ++ ++ dump.max_reason = KMSG_DUMP_OOPS; ++ dump.dump = crashlog_do_dump; ++ kmsg_dump_register(&dump); ++ ++ return 0; ++} ++module_init(crashlog_init_fs); +--- a/mm/bootmem.c ++++ b/mm/bootmem.c +@@ -15,6 +15,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -177,6 +178,7 @@ static unsigned long __init free_all_boo + if (!bdata->node_bootmem_map) + return 0; + ++ crashlog_init_bootmem(bdata); + map = bdata->node_bootmem_map; + start = bdata->node_min_pfn; + end = bdata->node_low_pfn; +--- a/kernel/module.c ++++ b/kernel/module.c +@@ -104,6 +104,9 @@ static LIST_HEAD(modules); + #ifdef CONFIG_KGDB_KDB + struct list_head *kdb_modules = &modules; /* kdb needs the list of modules */ + #endif /* CONFIG_KGDB_KDB */ ++#ifdef CONFIG_CRASHLOG ++struct list_head *crashlog_modules = &modules; ++#endif + + #ifdef CONFIG_MODULE_SIG + #ifdef CONFIG_MODULE_SIG_FORCE +--- a/mm/memblock.c ++++ b/mm/memblock.c +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -477,6 +478,8 @@ static void __init_memblock memblock_ins + memblock_set_region_node(rgn, nid); + type->cnt++; + type->total_size += size; ++ if (type == &memblock.memory && idx == 0) ++ crashlog_init_memblock(base, size); + } + + /** diff --git a/target/linux/generic/patches-4.0/940-ocf_kbuild_integration.patch b/target/linux/generic/patches-4.0/940-ocf_kbuild_integration.patch new file mode 100644 index 0000000..36776a9 --- /dev/null +++ b/target/linux/generic/patches-4.0/940-ocf_kbuild_integration.patch @@ -0,0 +1,20 @@ +--- a/crypto/Kconfig ++++ b/crypto/Kconfig +@@ -1537,3 +1537,6 @@ source "drivers/crypto/Kconfig" + source crypto/asymmetric_keys/Kconfig + + endif # if CRYPTO ++ ++source "crypto/ocf/Kconfig" ++ +--- a/crypto/Makefile ++++ b/crypto/Makefile +@@ -102,6 +102,8 @@ obj-$(CONFIG_CRYPTO_USER_API_HASH) += al + obj-$(CONFIG_CRYPTO_USER_API_SKCIPHER) += algif_skcipher.o + obj-$(CONFIG_CRYPTO_USER_API_RNG) += algif_rng.o + ++obj-$(CONFIG_OCF_OCF) += ocf/ ++ + # + # generic algorithms and the async_tx api + # diff --git a/target/linux/generic/patches-4.0/941-ocf_20120127.patch b/target/linux/generic/patches-4.0/941-ocf_20120127.patch new file mode 100644 index 0000000..fad7acf --- /dev/null +++ b/target/linux/generic/patches-4.0/941-ocf_20120127.patch @@ -0,0 +1,166 @@ +--- a/drivers/char/random.c ++++ b/drivers/char/random.c +@@ -139,6 +139,9 @@ + * that might otherwise be identical and have very little entropy + * available to them (particularly common in the embedded world). + * ++ * void random_input_words(__u32 *buf, size_t wordcount, int ent_count) ++ * int random_input_wait(void); ++ * + * add_input_randomness() uses the input layer interrupt timing, as well as + * the event type information from the hardware. + * +@@ -152,6 +155,13 @@ + * seek times do not make for good sources of entropy, as their seek + * times are usually fairly consistent. + * ++ * random_input_words() just provides a raw block of entropy to the input ++ * pool, such as from a hardware entropy generator. ++ * ++ * random_input_wait() suspends the caller until such time as the ++ * entropy pool falls below the write threshold, and returns a count of how ++ * much entropy (in bits) is needed to sustain the pool. ++ * + * All of these routines try to estimate how many bits of randomness a + * particular randomness source. They do this by keeping track of the + * first and second order deltas of the event timings. +@@ -938,6 +948,63 @@ void add_disk_randomness(struct gendisk + EXPORT_SYMBOL_GPL(add_disk_randomness); + #endif + ++/* ++ * random_input_words - add bulk entropy to pool ++ * ++ * @buf: buffer to add ++ * @wordcount: number of __u32 words to add ++ * @ent_count: total amount of entropy (in bits) to credit ++ * ++ * this provides bulk input of entropy to the input pool ++ * ++ */ ++void random_input_words(__u32 *buf, size_t wordcount, int ent_count) ++{ ++ mix_pool_bytes(&input_pool, buf, wordcount*4); ++ ++ credit_entropy_bits(&input_pool, ent_count); ++ ++ pr_notice("crediting %d bits => %d\n", ++ ent_count, input_pool.entropy_count); ++ /* ++ * Wake up waiting processes if we have enough ++ * entropy. ++ */ ++ if (input_pool.entropy_count >= random_read_wakeup_bits) ++ wake_up_interruptible(&random_read_wait); ++} ++EXPORT_SYMBOL(random_input_words); ++ ++/* ++ * random_input_wait - wait until random needs entropy ++ * ++ * this function sleeps until the /dev/random subsystem actually ++ * needs more entropy, and then return the amount of entropy ++ * that it would be nice to have added to the system. ++ */ ++int random_input_wait(void) ++{ ++ int count; ++ ++ wait_event_interruptible(random_write_wait, ++ input_pool.entropy_count < random_write_wakeup_bits); ++ ++ count = random_write_wakeup_bits - input_pool.entropy_count; ++ ++ /* likely we got woken up due to a signal */ ++ if (count <= 0) count = random_read_wakeup_bits; ++ ++ pr_notice("requesting %d bits from input_wait()er %d<%d\n", ++ count, ++ input_pool.entropy_count, random_write_wakeup_bits); ++ ++ return count; ++} ++EXPORT_SYMBOL(random_input_wait); ++ ++ ++#define EXTRACT_SIZE 10 ++ + /********************************************************************* + * + * Entropy extraction routines +--- a/fs/fcntl.c ++++ b/fs/fcntl.c +@@ -140,6 +140,7 @@ pid_t f_getown(struct file *filp) + read_unlock(&filp->f_owner.lock); + return pid; + } ++EXPORT_SYMBOL(sys_dup); + + static int f_setown_ex(struct file *filp, unsigned long arg) + { +--- a/include/linux/miscdevice.h ++++ b/include/linux/miscdevice.h +@@ -19,6 +19,7 @@ + #define APOLLO_MOUSE_MINOR 7 /* unused */ + #define PC110PAD_MINOR 9 /* unused */ + /*#define ADB_MOUSE_MINOR 10 FIXME OBSOLETE */ ++#define CRYPTODEV_MINOR 70 /* /dev/crypto */ + #define WATCHDOG_MINOR 130 /* Watchdog timer */ + #define TEMP_MINOR 131 /* Temperature Sensor */ + #define RTC_MINOR 135 +--- a/include/uapi/linux/random.h ++++ b/include/uapi/linux/random.h +@@ -34,6 +34,30 @@ + /* Clear the entropy pool and associated counters. (Superuser only.) */ + #define RNDCLEARPOOL _IO( 'R', 0x06 ) + ++#ifdef CONFIG_FIPS_RNG ++ ++/* Size of seed value - equal to AES blocksize */ ++#define AES_BLOCK_SIZE_BYTES 16 ++#define SEED_SIZE_BYTES AES_BLOCK_SIZE_BYTES ++/* Size of AES key */ ++#define KEY_SIZE_BYTES 16 ++ ++/* ioctl() structure used by FIPS 140-2 Tests */ ++struct rand_fips_test { ++ unsigned char key[KEY_SIZE_BYTES]; /* Input */ ++ unsigned char datetime[SEED_SIZE_BYTES]; /* Input */ ++ unsigned char seed[SEED_SIZE_BYTES]; /* Input */ ++ unsigned char result[SEED_SIZE_BYTES]; /* Output */ ++}; ++ ++/* FIPS 140-2 RNG Variable Seed Test. (Superuser only.) */ ++#define RNDFIPSVST _IOWR('R', 0x10, struct rand_fips_test) ++ ++/* FIPS 140-2 RNG Monte Carlo Test. (Superuser only.) */ ++#define RNDFIPSMCT _IOWR('R', 0x11, struct rand_fips_test) ++ ++#endif /* #ifdef CONFIG_FIPS_RNG */ ++ + struct rand_pool_info { + int entropy_count; + int buf_size; +--- a/include/linux/random.h ++++ b/include/linux/random.h +@@ -13,6 +13,10 @@ extern void add_input_randomness(unsigne + unsigned int value); + extern void add_interrupt_randomness(int irq, int irq_flags); + ++extern void random_input_words(__u32 *buf, size_t wordcount, int ent_count); ++extern int random_input_wait(void); ++#define HAS_RANDOM_INPUT_WAIT 1 ++ + extern void get_random_bytes(void *buf, int nbytes); + extern void get_random_bytes_arch(void *buf, int nbytes); + void generate_random_uuid(unsigned char uuid_out[16]); +--- a/kernel/pid.c ++++ b/kernel/pid.c +@@ -430,6 +430,7 @@ void transfer_pid(struct task_struct *ol + new->pids[type].pid = old->pids[type].pid; + hlist_replace_rcu(&old->pids[type].node, &new->pids[type].node); + } ++EXPORT_SYMBOL(find_task_by_vpid); + + struct task_struct *pid_task(struct pid *pid, enum pid_type type) + { diff --git a/target/linux/generic/patches-4.0/960-decompress_unlzo_fix.patch b/target/linux/generic/patches-4.0/960-decompress_unlzo_fix.patch new file mode 100644 index 0000000..ee7c118 --- /dev/null +++ b/target/linux/generic/patches-4.0/960-decompress_unlzo_fix.patch @@ -0,0 +1,23 @@ +--- /dev/null ++++ b/include/linux/decompress/unlzo_mm.h +@@ -0,0 +1,10 @@ ++#ifndef UNLZO_MM_H ++#define UNLZO_MM_H ++ ++#ifdef STATIC ++#define INIT ++#else ++#define INIT __init ++#endif ++ ++#endif +--- a/lib/decompress_unlzo.c ++++ b/lib/decompress_unlzo.c +@@ -38,6 +38,7 @@ + + #include + #include ++#include + #include + + #include diff --git a/target/linux/generic/patches-4.0/970-remove-unsane-filenames-from-deps_initramfs-list.patch b/target/linux/generic/patches-4.0/970-remove-unsane-filenames-from-deps_initramfs-list.patch new file mode 100644 index 0000000..ac13c9e --- /dev/null +++ b/target/linux/generic/patches-4.0/970-remove-unsane-filenames-from-deps_initramfs-list.patch @@ -0,0 +1,29 @@ +--- a/usr/Makefile ++++ b/usr/Makefile +@@ -53,6 +53,8 @@ ifneq ($(wildcard $(obj)/.initramfs_data + include $(obj)/.initramfs_data.cpio.d + endif + ++deps_initramfs_sane := $(foreach v,$(deps_initramfs),$(if $(findstring :,$(v)),,$(v))) ++ + quiet_cmd_initfs = GEN $@ + cmd_initfs = $(initramfs) -o $@ $(ramfs-args) $(ramfs-input) + +@@ -61,14 +63,14 @@ targets := initramfs_data.cpio.gz initra + initramfs_data.cpio.lzo initramfs_data.cpio.lz4 \ + initramfs_data.cpio + # do not try to update files included in initramfs +-$(deps_initramfs): ; ++$(deps_initramfs_sane): ; + +-$(deps_initramfs): klibcdirs ++$(deps_initramfs_sane): klibcdirs + # We rebuild initramfs_data.cpio if: + # 1) Any included file is newer then initramfs_data.cpio + # 2) There are changes in which files are included (added or deleted) + # 3) If gen_init_cpio are newer than initramfs_data.cpio + # 4) arguments to gen_initramfs.sh changes +-$(obj)/initramfs_data.cpio$(suffix_y): $(obj)/gen_init_cpio $(deps_initramfs) klibcdirs ++$(obj)/initramfs_data.cpio$(suffix_y): $(obj)/gen_init_cpio $(deps_initramfs_sane) klibcdirs + $(Q)$(initramfs) -l $(ramfs-input) > $(obj)/.initramfs_data.cpio.d + $(call if_changed,initfs) diff --git a/target/linux/generic/patches-4.0/980-arm_openwrt_machtypes.patch b/target/linux/generic/patches-4.0/980-arm_openwrt_machtypes.patch new file mode 100644 index 0000000..5e9718b --- /dev/null +++ b/target/linux/generic/patches-4.0/980-arm_openwrt_machtypes.patch @@ -0,0 +1,32 @@ +--- a/arch/arm/tools/mach-types ++++ b/arch/arm/tools/mach-types +@@ -1007,3 +1007,29 @@ eco5_bx2 MACH_ECO5_BX2 ECO5_BX2 4572 + eukrea_cpuimx28sd MACH_EUKREA_CPUIMX28SD EUKREA_CPUIMX28SD 4573 + domotab MACH_DOMOTAB DOMOTAB 4574 + pfla03 MACH_PFLA03 PFLA03 4575 ++# ++# Additional mach-types supported by OpenWrt ++# ++wg302v1 MACH_WG302V1 WG302V1 889 ++pronghorn MACH_PRONGHORN PRONGHORN 928 ++pronghorn_metro MACH_PRONGHORNMETRO PRONGHORNMETRO 1040 ++sidewinder MACH_SIDEWINDER SIDEWINDER 1041 ++wrt300nv2 MACH_WRT300NV2 WRT300NV2 1077 ++compex42x MACH_COMPEXWP18 COMPEXWP18 1273 ++goldfish MACH_GOLDFISH GOLDFISH 1441 ++cambria MACH_CAMBRIA CAMBRIA 1468 ++dt2 MACH_DT2 DT2 1514 ++ap1000 MACH_AP1000 AP1000 1543 ++tw2662 MACH_TW2662 TW2662 1658 ++tw5334 MACH_TW5334 TW5334 1664 ++usr8200 MACH_USR8200 USR8200 1762 ++mi424wr MACH_MI424WR MI424WR 1778 ++gw2388 MACH_GW2388 GW2388 2635 ++iconnect MACH_ICONNECT ICONNECT 2870 ++nsb3ast MACH_NSB3AST NSB3AST 2917 ++goflexnet MACH_GOFLEXNET GOFLEXNET 3089 ++nas6210 MACH_NAS6210 NAS6210 3104 ++ns_k330 MACH_NS_K330 NS_K330 3108 ++bcm2708 MACH_BCM2708 BCM2708 3138 ++wn802t MACH_WN802T WN802T 3306 ++nsa310 MACH_NSA310 NSA310 4022 diff --git a/target/linux/generic/patches-4.0/990-gpio_wdt.patch b/target/linux/generic/patches-4.0/990-gpio_wdt.patch new file mode 100644 index 0000000..cc1906a --- /dev/null +++ b/target/linux/generic/patches-4.0/990-gpio_wdt.patch @@ -0,0 +1,360 @@ +This generic GPIO watchdog is used on Huawei E970 (brcm47xx) + +Signed-off-by: Mathias Adam + +--- a/drivers/watchdog/Kconfig ++++ b/drivers/watchdog/Kconfig +@@ -1151,6 +1151,15 @@ config WDT_MTX1 + Hardware driver for the MTX-1 boards. This is a watchdog timer that + will reboot the machine after a 100 seconds timer expired. + ++config GPIO_WDT ++ tristate "GPIO Hardware Watchdog" ++ help ++ Hardware driver for GPIO-controlled watchdogs. GPIO pin and ++ toggle interval settings are platform-specific. The driver ++ will stop toggling the GPIO (i.e. machine reboots) after a ++ 100 second timer expired and no process has written to ++ /dev/watchdog during that time. ++ + config PNX833X_WDT + tristate "PNX833x Hardware Watchdog" + depends on SOC_PNX8335 +--- a/drivers/watchdog/Makefile ++++ b/drivers/watchdog/Makefile +@@ -135,6 +135,7 @@ obj-$(CONFIG_RC32434_WDT) += rc32434_wdt + obj-$(CONFIG_INDYDOG) += indydog.o + obj-$(CONFIG_JZ4740_WDT) += jz4740_wdt.o + obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o ++obj-$(CONFIG_GPIO_WDT) += old_gpio_wdt.o + obj-$(CONFIG_PNX833X_WDT) += pnx833x_wdt.o + obj-$(CONFIG_SIBYTE_WDOG) += sb_wdog.o + obj-$(CONFIG_AR7_WDT) += ar7_wdt.o +--- /dev/null ++++ b/drivers/watchdog/old_gpio_wdt.c +@@ -0,0 +1,301 @@ ++/* ++ * Driver for GPIO-controlled Hardware Watchdogs. ++ * ++ * Copyright (C) 2013 Mathias Adam ++ * ++ * Replaces mtx1_wdt (driver for the MTX-1 Watchdog): ++ * ++ * (C) Copyright 2005 4G Systems , ++ * All Rights Reserved. ++ * http://www.4g-systems.biz ++ * ++ * (C) Copyright 2007 OpenWrt.org, Florian Fainelli ++ * ++ * 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. ++ * ++ * Neither Michael Stickel nor 4G Systems admit liability nor provide ++ * warranty for any of this software. This material is provided ++ * "AS-IS" and at no charge. ++ * ++ * (c) Copyright 2005 4G Systems ++ * ++ * Release 0.01. ++ * Author: Michael Stickel michael.stickel@4g-systems.biz ++ * ++ * Release 0.02. ++ * Author: Florian Fainelli florian@openwrt.org ++ * use the Linux watchdog/timer APIs ++ * ++ * Release 0.03. ++ * Author: Mathias Adam ++ * make it a generic gpio watchdog driver ++ * ++ * The Watchdog is configured to reset the MTX-1 ++ * if it is not triggered for 100 seconds. ++ * It should not be triggered more often than 1.6 seconds. ++ * ++ * A timer triggers the watchdog every 5 seconds, until ++ * it is opened for the first time. After the first open ++ * it MUST be triggered every 2..95 seconds. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static int ticks = 100 * HZ; ++ ++static struct { ++ struct completion stop; ++ spinlock_t lock; ++ int running; ++ struct timer_list timer; ++ int queue; ++ int default_ticks; ++ unsigned long inuse; ++ unsigned gpio; ++ unsigned int gstate; ++ int interval; ++ int first_interval; ++} gpio_wdt_device; ++ ++static void gpio_wdt_trigger(unsigned long unused) ++{ ++ spin_lock(&gpio_wdt_device.lock); ++ if (gpio_wdt_device.running && ticks > 0) ++ ticks -= gpio_wdt_device.interval; ++ ++ /* toggle wdt gpio */ ++ gpio_wdt_device.gstate = !gpio_wdt_device.gstate; ++ gpio_set_value(gpio_wdt_device.gpio, gpio_wdt_device.gstate); ++ ++ if (gpio_wdt_device.queue && ticks > 0) ++ mod_timer(&gpio_wdt_device.timer, jiffies + gpio_wdt_device.interval); ++ else ++ complete(&gpio_wdt_device.stop); ++ spin_unlock(&gpio_wdt_device.lock); ++} ++ ++static void gpio_wdt_reset(void) ++{ ++ ticks = gpio_wdt_device.default_ticks; ++} ++ ++ ++static void gpio_wdt_start(void) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&gpio_wdt_device.lock, flags); ++ if (!gpio_wdt_device.queue) { ++ gpio_wdt_device.queue = 1; ++ gpio_wdt_device.gstate = 1; ++ gpio_set_value(gpio_wdt_device.gpio, 1); ++ mod_timer(&gpio_wdt_device.timer, jiffies + gpio_wdt_device.first_interval); ++ } ++ gpio_wdt_device.running++; ++ spin_unlock_irqrestore(&gpio_wdt_device.lock, flags); ++} ++ ++static int gpio_wdt_stop(void) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&gpio_wdt_device.lock, flags); ++ if (gpio_wdt_device.queue) { ++ gpio_wdt_device.queue = 0; ++ gpio_wdt_device.gstate = 0; ++ gpio_set_value(gpio_wdt_device.gpio, 0); ++ } ++ ticks = gpio_wdt_device.default_ticks; ++ spin_unlock_irqrestore(&gpio_wdt_device.lock, flags); ++ return 0; ++} ++ ++/* Filesystem functions */ ++ ++static int gpio_wdt_open(struct inode *inode, struct file *file) ++{ ++ if (test_and_set_bit(0, &gpio_wdt_device.inuse)) ++ return -EBUSY; ++ return nonseekable_open(inode, file); ++} ++ ++ ++static int gpio_wdt_release(struct inode *inode, struct file *file) ++{ ++ clear_bit(0, &gpio_wdt_device.inuse); ++ return 0; ++} ++ ++static long gpio_wdt_ioctl(struct file *file, unsigned int cmd, ++ unsigned long arg) ++{ ++ void __user *argp = (void __user *)arg; ++ int __user *p = (int __user *)argp; ++ unsigned int value; ++ static const struct watchdog_info ident = { ++ .options = WDIOF_CARDRESET, ++ .identity = "GPIO WDT", ++ }; ++ ++ switch (cmd) { ++ case WDIOC_GETSUPPORT: ++ if (copy_to_user(argp, &ident, sizeof(ident))) ++ return -EFAULT; ++ break; ++ case WDIOC_GETSTATUS: ++ case WDIOC_GETBOOTSTATUS: ++ put_user(0, p); ++ break; ++ case WDIOC_SETOPTIONS: ++ if (get_user(value, p)) ++ return -EFAULT; ++ if (value & WDIOS_ENABLECARD) ++ gpio_wdt_start(); ++ else if (value & WDIOS_DISABLECARD) ++ gpio_wdt_stop(); ++ else ++ return -EINVAL; ++ return 0; ++ case WDIOC_KEEPALIVE: ++ gpio_wdt_reset(); ++ break; ++ default: ++ return -ENOTTY; ++ } ++ return 0; ++} ++ ++ ++static ssize_t gpio_wdt_write(struct file *file, const char *buf, ++ size_t count, loff_t *ppos) ++{ ++ if (!count) ++ return -EIO; ++ gpio_wdt_reset(); ++ return count; ++} ++ ++static const struct file_operations gpio_wdt_fops = { ++ .owner = THIS_MODULE, ++ .llseek = no_llseek, ++ .unlocked_ioctl = gpio_wdt_ioctl, ++ .open = gpio_wdt_open, ++ .write = gpio_wdt_write, ++ .release = gpio_wdt_release, ++}; ++ ++ ++static struct miscdevice gpio_wdt_misc = { ++ .minor = WATCHDOG_MINOR, ++ .name = "watchdog", ++ .fops = &gpio_wdt_fops, ++}; ++ ++ ++static int gpio_wdt_probe(struct platform_device *pdev) ++{ ++ int ret; ++ struct gpio_wdt_platform_data *gpio_wdt_data = pdev->dev.platform_data; ++ ++ gpio_wdt_device.gpio = gpio_wdt_data->gpio; ++ gpio_wdt_device.interval = gpio_wdt_data->interval; ++ gpio_wdt_device.first_interval = gpio_wdt_data->first_interval; ++ if (gpio_wdt_device.first_interval <= 0) { ++ gpio_wdt_device.first_interval = gpio_wdt_device.interval; ++ } ++ ++ ret = gpio_request(gpio_wdt_device.gpio, "gpio-wdt"); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "failed to request gpio"); ++ return ret; ++ } ++ ++ spin_lock_init(&gpio_wdt_device.lock); ++ init_completion(&gpio_wdt_device.stop); ++ gpio_wdt_device.queue = 0; ++ clear_bit(0, &gpio_wdt_device.inuse); ++ setup_timer(&gpio_wdt_device.timer, gpio_wdt_trigger, 0L); ++ gpio_wdt_device.default_ticks = ticks; ++ ++ gpio_wdt_start(); ++ dev_info(&pdev->dev, "GPIO Hardware Watchdog driver (gpio=%i interval=%i/%i)\n", ++ gpio_wdt_data->gpio, gpio_wdt_data->first_interval, gpio_wdt_data->interval); ++ return 0; ++} ++ ++static int gpio_wdt_remove(struct platform_device *pdev) ++{ ++ /* FIXME: do we need to lock this test ? */ ++ if (gpio_wdt_device.queue) { ++ gpio_wdt_device.queue = 0; ++ wait_for_completion(&gpio_wdt_device.stop); ++ } ++ ++ gpio_free(gpio_wdt_device.gpio); ++ misc_deregister(&gpio_wdt_misc); ++ return 0; ++} ++ ++static struct platform_driver gpio_wdt_driver = { ++ .probe = gpio_wdt_probe, ++ .remove = gpio_wdt_remove, ++ .driver.name = "gpio-wdt", ++ .driver.owner = THIS_MODULE, ++}; ++ ++static int __init gpio_wdt_init(void) ++{ ++ return platform_driver_register(&gpio_wdt_driver); ++} ++arch_initcall(gpio_wdt_init); ++ ++/* ++ * We do wdt initialization in two steps: arch_initcall probes the wdt ++ * very early to start pinging the watchdog (misc devices are not yet ++ * available), and later module_init() just registers the misc device. ++ */ ++static int gpio_wdt_init_late(void) ++{ ++ int ret; ++ ++ ret = misc_register(&gpio_wdt_misc); ++ if (ret < 0) { ++ pr_err("GPIO_WDT: failed to register misc device\n"); ++ return ret; ++ } ++ return 0; ++} ++#ifndef MODULE ++module_init(gpio_wdt_init_late); ++#endif ++ ++static void __exit gpio_wdt_exit(void) ++{ ++ platform_driver_unregister(&gpio_wdt_driver); ++} ++module_exit(gpio_wdt_exit); ++ ++MODULE_AUTHOR("Michael Stickel, Florian Fainelli, Mathias Adam"); ++MODULE_DESCRIPTION("Driver for GPIO hardware watchdogs"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); ++MODULE_ALIAS("platform:gpio-wdt"); +--- /dev/null ++++ b/include/linux/old_gpio_wdt.h +@@ -0,0 +1,21 @@ ++/* ++ * Definitions for the GPIO watchdog driver ++ * ++ * Copyright (C) 2013 Mathias Adam ++ * ++ * 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. ++ * ++ */ ++ ++#ifndef _GPIO_WDT_H_ ++#define _GPIO_WDT_H_ ++ ++struct gpio_wdt_platform_data { ++ int gpio; /* GPIO line number */ ++ int interval; /* watchdog reset interval in system ticks */ ++ int first_interval; /* first wd reset interval in system ticks */ ++}; ++ ++#endif /* _GPIO_WDT_H_ */ diff --git a/target/linux/generic/patches-4.0/995-mangle_bootargs.patch b/target/linux/generic/patches-4.0/995-mangle_bootargs.patch new file mode 100644 index 0000000..ebfc6d8 --- /dev/null +++ b/target/linux/generic/patches-4.0/995-mangle_bootargs.patch @@ -0,0 +1,58 @@ +--- a/init/main.c ++++ b/init/main.c +@@ -351,6 +351,29 @@ static inline void setup_nr_cpu_ids(void + static inline void smp_prepare_cpus(unsigned int maxcpus) { } + #endif + ++#ifdef CONFIG_MANGLE_BOOTARGS ++static void __init mangle_bootargs(char *command_line) ++{ ++ char *rootdev; ++ char *rootfs; ++ ++ rootdev = strstr(command_line, "root=/dev/mtdblock"); ++ ++ if (rootdev) ++ strncpy(rootdev, "mangled_rootblock=", 18); ++ ++ rootfs = strstr(command_line, "rootfstype"); ++ ++ if (rootfs) ++ strncpy(rootfs, "mangled_fs", 10); ++ ++} ++#else ++static void __init mangle_bootargs(char *command_line) ++{ ++} ++#endif ++ + /* + * We need to store the untouched command line for future reference. + * We also need to store the touched command line since the parameter +@@ -519,6 +542,7 @@ asmlinkage __visible void __init start_k + pr_notice("%s", linux_banner); + setup_arch(&command_line); + mm_init_cpumask(&init_mm); ++ mangle_bootargs(command_line); + setup_command_line(command_line); + setup_nr_cpu_ids(); + setup_per_cpu_areas(); +--- a/init/Kconfig ++++ b/init/Kconfig +@@ -1583,6 +1583,15 @@ config EMBEDDED + an embedded system so certain expert options are available + for configuration. + ++config MANGLE_BOOTARGS ++ bool "Rename offending bootargs" ++ depends on EXPERT ++ help ++ Sometimes the bootloader passed bogus root= and rootfstype= ++ parameters to the kernel, and while you want to ignore them, ++ you need to know the values f.e. to support dual firmware ++ layouts on the flash. ++ + config HAVE_PERF_EVENTS + bool + help diff --git a/target/linux/generic/patches-4.0/997-device_tree_cmdline.patch b/target/linux/generic/patches-4.0/997-device_tree_cmdline.patch new file mode 100644 index 0000000..8063809 --- /dev/null +++ b/target/linux/generic/patches-4.0/997-device_tree_cmdline.patch @@ -0,0 +1,24 @@ +--- a/drivers/of/fdt.c ++++ b/drivers/of/fdt.c +@@ -917,6 +917,9 @@ int __init early_init_dt_scan_chosen(uns + p = of_get_flat_dt_prop(node, "bootargs", &l); + if (p != NULL && l > 0) + strlcpy(data, p, min((int)l, COMMAND_LINE_SIZE)); ++ p = of_get_flat_dt_prop(node, "bootargs-append", &l); ++ if (p != NULL && l > 0) ++ strlcat(data, p, min_t(int, strlen(data) + (int)l, COMMAND_LINE_SIZE)); + + /* + * CONFIG_CMDLINE is meant to be a default in case nothing else +--- a/arch/mips/kernel/prom.c ++++ b/arch/mips/kernel/prom.c +@@ -50,6 +50,9 @@ void * __init early_init_dt_alloc_memory + + void __init __dt_setup_arch(void *bph) + { ++ if (boot_command_line[0] == '\0') ++ strcpy(boot_command_line, arcs_cmdline); ++ + if (!early_init_dt_scan(bph)) + return; + diff --git a/target/linux/generic/patches-4.0/998-enable_wilink_platform_without_drivers.patch b/target/linux/generic/patches-4.0/998-enable_wilink_platform_without_drivers.patch new file mode 100644 index 0000000..d317de1 --- /dev/null +++ b/target/linux/generic/patches-4.0/998-enable_wilink_platform_without_drivers.patch @@ -0,0 +1,15 @@ +We use backports for driver updates - make sure we can compile in the glue code regardless + +Signed-off-by: Imre Kaloz + +--- a/drivers/net/wireless/ti/Kconfig ++++ b/drivers/net/wireless/ti/Kconfig +@@ -15,7 +15,7 @@ source "drivers/net/wireless/ti/wlcore/K + + config WILINK_PLATFORM_DATA + bool "TI WiLink platform data" +- depends on WLCORE_SDIO || WL1251_SDIO ++ depends on WLCORE_SDIO || WL1251_SDIO || ARCH_OMAP2PLUS + default y + ---help--- + Small platform data bit needed to pass data to the sdio modules. diff --git a/target/linux/generic/patches-4.1/000-keep_initrafs_the_default.patch b/target/linux/generic/patches-4.1/000-keep_initrafs_the_default.patch new file mode 100644 index 0000000..5e56d44 --- /dev/null +++ b/target/linux/generic/patches-4.1/000-keep_initrafs_the_default.patch @@ -0,0 +1,25 @@ +Upstream changed the default rootfs to tmpfs when none has been passed +to the kernel - this doesn't fit our purposes, so change it back. + +Signed-off-by: Imre Kaloz + +--- a/init/do_mounts.c ++++ b/init/do_mounts.c +@@ -628,6 +628,7 @@ int __init init_rootfs(void) + if (err) + return err; + ++#if 0 + if (IS_ENABLED(CONFIG_TMPFS) && !saved_root_name[0] && + (!root_fs_names || strstr(root_fs_names, "tmpfs"))) { + err = shmem_init(); +@@ -635,6 +636,9 @@ int __init init_rootfs(void) + } else { + err = init_ramfs_fs(); + } ++#else ++ err = init_ramfs_fs(); ++#endif + + if (err) + unregister_filesystem(&rootfs_fs_type); diff --git a/target/linux/generic/patches-4.1/021-ssb_sprom.patch b/target/linux/generic/patches-4.1/021-ssb_sprom.patch new file mode 100644 index 0000000..52d8080 --- /dev/null +++ b/target/linux/generic/patches-4.1/021-ssb_sprom.patch @@ -0,0 +1,32 @@ +--- a/include/linux/ssb/ssb.h ++++ b/include/linux/ssb/ssb.h +@@ -29,10 +29,13 @@ struct ssb_sprom { + u8 il0mac[6] __aligned(sizeof(u16)); /* MAC address for 802.11b/g */ + u8 et0mac[6] __aligned(sizeof(u16)); /* MAC address for Ethernet */ + u8 et1mac[6] __aligned(sizeof(u16)); /* MAC address for 802.11a */ ++ u8 et2mac[6] __aligned(sizeof(u16)); /* MAC address for extra Ethernet */ + u8 et0phyaddr; /* MII address for enet0 */ + u8 et1phyaddr; /* MII address for enet1 */ ++ u8 et2phyaddr; /* MII address for enet2 */ + u8 et0mdcport; /* MDIO for enet0 */ + u8 et1mdcport; /* MDIO for enet1 */ ++ u8 et2mdcport; /* MDIO for enet2 */ + u16 dev_id; /* Device ID overriding e.g. PCI ID */ + u16 board_rev; /* Board revision number from SPROM. */ + u16 board_num; /* Board number from SPROM. */ +@@ -88,11 +91,14 @@ struct ssb_sprom { + u32 ofdm5glpo; /* 5.2GHz OFDM power offset */ + u32 ofdm5gpo; /* 5.3GHz OFDM power offset */ + u32 ofdm5ghpo; /* 5.8GHz OFDM power offset */ ++ u32 boardflags; ++ u32 boardflags2; ++ u32 boardflags3; ++ /* TODO: Switch all drivers to new u32 fields and drop below ones */ + u16 boardflags_lo; /* Board flags (bits 0-15) */ + u16 boardflags_hi; /* Board flags (bits 16-31) */ + u16 boardflags2_lo; /* Board flags (bits 32-47) */ + u16 boardflags2_hi; /* Board flags (bits 48-63) */ +- /* TODO store board flags in a single u64 */ + + struct ssb_sprom_core_pwr_info core_pwr_info[4]; + diff --git a/target/linux/generic/patches-4.1/022-bcma-from-4.2.patch b/target/linux/generic/patches-4.1/022-bcma-from-4.2.patch new file mode 100644 index 0000000..ba3df18 --- /dev/null +++ b/target/linux/generic/patches-4.1/022-bcma-from-4.2.patch @@ -0,0 +1,86 @@ +--- a/drivers/bcma/driver_gpio.c ++++ b/drivers/bcma/driver_gpio.c +@@ -226,6 +226,7 @@ int bcma_gpio_init(struct bcma_drv_cc *c + chip->of_node = cc->core->dev.of_node; + #endif + switch (bus->chipinfo.id) { ++ case BCMA_CHIP_ID_BCM4707: + case BCMA_CHIP_ID_BCM5357: + case BCMA_CHIP_ID_BCM53572: + chip->ngpio = 32; +@@ -235,16 +236,17 @@ int bcma_gpio_init(struct bcma_drv_cc *c + } + + /* +- * On MIPS we register GPIO devices (LEDs, buttons) using absolute GPIO +- * pin numbers. We don't have Device Tree there and we can't really use +- * relative (per chip) numbers. +- * So let's use predictable base for BCM47XX and "random" for all other. ++ * Register SoC GPIO devices with absolute GPIO pin base. ++ * On MIPS, we don't have Device Tree and we can't use relative (per chip) ++ * GPIO numbers. ++ * On some ARM devices, user space may want to access some system GPIO ++ * pins directly, which is easier to do with a predictable GPIO base. + */ +-#if IS_BUILTIN(CONFIG_BCM47XX) +- chip->base = bus->num * BCMA_GPIO_MAX_PINS; +-#else +- chip->base = -1; +-#endif ++ if (IS_BUILTIN(CONFIG_BCM47XX) || ++ cc->core->bus->hosttype == BCMA_HOSTTYPE_SOC) ++ chip->base = bus->num * BCMA_GPIO_MAX_PINS; ++ else ++ chip->base = -1; + + err = bcma_gpio_irq_domain_init(cc); + if (err) +--- a/drivers/bcma/Kconfig ++++ b/drivers/bcma/Kconfig +@@ -29,12 +29,6 @@ config BCMA_HOST_PCI + select BCMA_DRIVER_PCI + default y + +-config BCMA_DRIVER_PCI_HOSTMODE +- bool "Driver for PCI core working in hostmode" +- depends on BCMA && MIPS && BCMA_HOST_PCI +- help +- PCI core hostmode operation (external PCI bus). +- + config BCMA_HOST_SOC + bool "Support for BCMA in a SoC" + depends on BCMA +@@ -61,6 +55,12 @@ config BCMA_DRIVER_PCI + This driver is also prerequisite for a hostmode PCIe core + support. + ++config BCMA_DRIVER_PCI_HOSTMODE ++ bool "Driver for PCI core working in hostmode" ++ depends on BCMA && MIPS && BCMA_DRIVER_PCI ++ help ++ PCI core hostmode operation (external PCI bus). ++ + config BCMA_DRIVER_MIPS + bool "BCMA Broadcom MIPS core driver" + depends on BCMA && MIPS +--- a/include/linux/bcma/bcma_driver_pci.h ++++ b/include/linux/bcma/bcma_driver_pci.h +@@ -246,7 +246,18 @@ static inline void bcma_core_pci_power_s + } + #endif + ++#ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE + extern int bcma_core_pci_pcibios_map_irq(const struct pci_dev *dev); + extern int bcma_core_pci_plat_dev_init(struct pci_dev *dev); ++#else ++static inline int bcma_core_pci_pcibios_map_irq(const struct pci_dev *dev) ++{ ++ return -ENOTSUPP; ++} ++static inline int bcma_core_pci_plat_dev_init(struct pci_dev *dev) ++{ ++ return -ENOTSUPP; ++} ++#endif + + #endif /* LINUX_BCMA_DRIVER_PCI_H_ */ diff --git a/target/linux/generic/patches-4.1/050-backport_netfilter_rtcache.patch b/target/linux/generic/patches-4.1/050-backport_netfilter_rtcache.patch new file mode 100644 index 0000000..9a6d837 --- /dev/null +++ b/target/linux/generic/patches-4.1/050-backport_netfilter_rtcache.patch @@ -0,0 +1,505 @@ +Subject: netfilter: conntrack: cache route for forwarded connections + +... to avoid per-packet FIB lookup if possible. + +The cached dst is re-used provided the input interface +is the same as that of the previous packet in the same direction. + +If not, the cached dst is invalidated. + +For ipv6 we also need to store sernum, else dst_check doesn't work, +pointed out by Eric Dumazet. + +This should speed up forwarding when conntrack is already in use +anyway, especially when using reverse path filtering -- active RPF +enforces two FIB lookups for each packet. + +Before the routing cache removal this didn't matter since RPF was performed +only when route cache didn't yield a result; but without route cache it +comes at higher price. + +Julian Anastasov suggested to add NETDEV_UNREGISTER handler to +avoid holding on to dsts of 'frozen' conntracks. + +Signed-off-by: Florian Westphal + +--- a/include/net/netfilter/nf_conntrack_extend.h ++++ b/include/net/netfilter/nf_conntrack_extend.h +@@ -30,6 +30,9 @@ enum nf_ct_ext_id { + #if IS_ENABLED(CONFIG_NETFILTER_SYNPROXY) + NF_CT_EXT_SYNPROXY, + #endif ++#if IS_ENABLED(CONFIG_NF_CONNTRACK_RTCACHE) ++ NF_CT_EXT_RTCACHE, ++#endif + NF_CT_EXT_NUM, + }; + +@@ -43,6 +46,7 @@ enum nf_ct_ext_id { + #define NF_CT_EXT_TIMEOUT_TYPE struct nf_conn_timeout + #define NF_CT_EXT_LABELS_TYPE struct nf_conn_labels + #define NF_CT_EXT_SYNPROXY_TYPE struct nf_conn_synproxy ++#define NF_CT_EXT_RTCACHE_TYPE struct nf_conn_rtcache + + /* Extensions: optional stuff which isn't permanently in struct. */ + struct nf_ct_ext { +--- /dev/null ++++ b/include/net/netfilter/nf_conntrack_rtcache.h +@@ -0,0 +1,34 @@ ++#include ++#include ++#include ++ ++struct dst_entry; ++ ++struct nf_conn_dst_cache { ++ struct dst_entry *dst; ++ int iif; ++#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6) ++ u32 cookie; ++#endif ++ ++}; ++ ++struct nf_conn_rtcache { ++ struct nf_conn_dst_cache cached_dst[IP_CT_DIR_MAX]; ++}; ++ ++static inline ++struct nf_conn_rtcache *nf_ct_rtcache_find(const struct nf_conn *ct) ++{ ++#if IS_ENABLED(CONFIG_NF_CONNTRACK_RTCACHE) ++ return nf_ct_ext_find(ct, NF_CT_EXT_RTCACHE); ++#else ++ return NULL; ++#endif ++} ++ ++static inline int nf_conn_rtcache_iif_get(const struct nf_conn_rtcache *rtc, ++ enum ip_conntrack_dir dir) ++{ ++ return rtc->cached_dst[dir].iif; ++} +--- a/net/netfilter/Kconfig ++++ b/net/netfilter/Kconfig +@@ -106,6 +106,18 @@ config NF_CONNTRACK_EVENTS + + If unsure, say `N'. + ++config NF_CONNTRACK_RTCACHE ++ tristate "Cache route entries in conntrack objects" ++ depends on NETFILTER_ADVANCED ++ depends on NF_CONNTRACK ++ help ++ If this option is enabled, the connection tracking code will ++ cache routing information for each connection that is being ++ forwarded, at a cost of 32 bytes per conntrack object. ++ ++ To compile it as a module, choose M here. If unsure, say N. ++ The module will be called nf_conntrack_rtcache. ++ + config NF_CONNTRACK_TIMEOUT + bool 'Connection tracking timeout' + depends on NETFILTER_ADVANCED +--- a/net/netfilter/Makefile ++++ b/net/netfilter/Makefile +@@ -18,6 +18,9 @@ obj-$(CONFIG_NETFILTER_NETLINK_LOG) += n + # connection tracking + obj-$(CONFIG_NF_CONNTRACK) += nf_conntrack.o + ++# optional conntrack route cache extension ++obj-$(CONFIG_NF_CONNTRACK_RTCACHE) += nf_conntrack_rtcache.o ++ + # SCTP protocol connection tracking + obj-$(CONFIG_NF_CT_PROTO_DCCP) += nf_conntrack_proto_dccp.o + obj-$(CONFIG_NF_CT_PROTO_GRE) += nf_conntrack_proto_gre.o +--- /dev/null ++++ b/net/netfilter/nf_conntrack_rtcache.c +@@ -0,0 +1,387 @@ ++/* route cache for netfilter. ++ * ++ * (C) 2014 Red Hat GmbH ++ * ++ * 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. ++ */ ++ ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++#include ++#include ++#include ++ ++#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6) ++#include ++#endif ++ ++static void __nf_conn_rtcache_destroy(struct nf_conn_rtcache *rtc, ++ enum ip_conntrack_dir dir) ++{ ++ struct dst_entry *dst = rtc->cached_dst[dir].dst; ++ ++ dst_release(dst); ++} ++ ++static void nf_conn_rtcache_destroy(struct nf_conn *ct) ++{ ++ struct nf_conn_rtcache *rtc = nf_ct_rtcache_find(ct); ++ ++ if (!rtc) ++ return; ++ ++ __nf_conn_rtcache_destroy(rtc, IP_CT_DIR_ORIGINAL); ++ __nf_conn_rtcache_destroy(rtc, IP_CT_DIR_REPLY); ++} ++ ++static void nf_ct_rtcache_ext_add(struct nf_conn *ct) ++{ ++ struct nf_conn_rtcache *rtc; ++ ++ rtc = nf_ct_ext_add(ct, NF_CT_EXT_RTCACHE, GFP_ATOMIC); ++ if (rtc) { ++ rtc->cached_dst[IP_CT_DIR_ORIGINAL].iif = -1; ++ rtc->cached_dst[IP_CT_DIR_ORIGINAL].dst = NULL; ++ rtc->cached_dst[IP_CT_DIR_REPLY].iif = -1; ++ rtc->cached_dst[IP_CT_DIR_REPLY].dst = NULL; ++ } ++} ++ ++static struct nf_conn_rtcache *nf_ct_rtcache_find_usable(struct nf_conn *ct) ++{ ++ if (nf_ct_is_untracked(ct)) ++ return NULL; ++ return nf_ct_rtcache_find(ct); ++} ++ ++static struct dst_entry * ++nf_conn_rtcache_dst_get(const struct nf_conn_rtcache *rtc, ++ enum ip_conntrack_dir dir) ++{ ++ return rtc->cached_dst[dir].dst; ++} ++ ++static u32 nf_rtcache_get_cookie(int pf, const struct dst_entry *dst) ++{ ++#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6) ++ if (pf == NFPROTO_IPV6) { ++ const struct rt6_info *rt = (const struct rt6_info *)dst; ++ ++ if (rt->rt6i_node) ++ return (u32)rt->rt6i_node->fn_sernum; ++ } ++#endif ++ return 0; ++} ++ ++static void nf_conn_rtcache_dst_set(int pf, ++ struct nf_conn_rtcache *rtc, ++ struct dst_entry *dst, ++ enum ip_conntrack_dir dir, int iif) ++{ ++ if (rtc->cached_dst[dir].iif != iif) ++ rtc->cached_dst[dir].iif = iif; ++ ++ if (rtc->cached_dst[dir].dst != dst) { ++ struct dst_entry *old; ++ ++ dst_hold(dst); ++ ++ old = xchg(&rtc->cached_dst[dir].dst, dst); ++ dst_release(old); ++ ++#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6) ++ if (pf == NFPROTO_IPV6) ++ rtc->cached_dst[dir].cookie = ++ nf_rtcache_get_cookie(pf, dst); ++#endif ++ } ++} ++ ++static void nf_conn_rtcache_dst_obsolete(struct nf_conn_rtcache *rtc, ++ enum ip_conntrack_dir dir) ++{ ++ struct dst_entry *old; ++ ++ pr_debug("Invalidate iif %d for dir %d on cache %p\n", ++ rtc->cached_dst[dir].iif, dir, rtc); ++ ++ old = xchg(&rtc->cached_dst[dir].dst, NULL); ++ dst_release(old); ++ rtc->cached_dst[dir].iif = -1; ++} ++ ++static unsigned int nf_rtcache_in(const struct nf_hook_ops *ops, ++ struct sk_buff *skb, ++ const struct nf_hook_state *state) ++{ ++ struct nf_conn_rtcache *rtc; ++ enum ip_conntrack_info ctinfo; ++ enum ip_conntrack_dir dir; ++ struct dst_entry *dst; ++ struct nf_conn *ct; ++ int iif; ++ u32 cookie; ++ ++ if (skb_dst(skb) || skb->sk) ++ return NF_ACCEPT; ++ ++ ct = nf_ct_get(skb, &ctinfo); ++ if (!ct) ++ return NF_ACCEPT; ++ ++ rtc = nf_ct_rtcache_find_usable(ct); ++ if (!rtc) ++ return NF_ACCEPT; ++ ++ /* if iif changes, don't use cache and let ip stack ++ * do route lookup. ++ * ++ * If rp_filter is enabled it might toss skb, so ++ * we don't want to avoid these checks. ++ */ ++ dir = CTINFO2DIR(ctinfo); ++ iif = nf_conn_rtcache_iif_get(rtc, dir); ++ if (state->in->ifindex != iif) { ++ pr_debug("ct %p, iif %d, cached iif %d, skip cached entry\n", ++ ct, iif, state->in->ifindex); ++ return NF_ACCEPT; ++ } ++ dst = nf_conn_rtcache_dst_get(rtc, dir); ++ if (dst == NULL) ++ return NF_ACCEPT; ++ ++ cookie = nf_rtcache_get_cookie(ops->pf, dst); ++ ++ dst = dst_check(dst, cookie); ++ pr_debug("obtained dst %p for skb %p, cookie %d\n", dst, skb, cookie); ++ if (likely(dst)) ++ skb_dst_set_noref(skb, dst); ++ else ++ nf_conn_rtcache_dst_obsolete(rtc, dir); ++ ++ return NF_ACCEPT; ++} ++ ++static unsigned int nf_rtcache_forward(const struct nf_hook_ops *ops, ++ struct sk_buff *skb, ++ const struct nf_hook_state *state) ++{ ++ struct nf_conn_rtcache *rtc; ++ enum ip_conntrack_info ctinfo; ++ enum ip_conntrack_dir dir; ++ struct nf_conn *ct; ++ struct dst_entry *dst = skb_dst(skb); ++ int iif; ++ ++ ct = nf_ct_get(skb, &ctinfo); ++ if (!ct) ++ return NF_ACCEPT; ++ ++ if (dst && dst_xfrm(dst)) ++ return NF_ACCEPT; ++ ++ if (!nf_ct_is_confirmed(ct)) { ++ if (WARN_ON(nf_ct_rtcache_find(ct))) ++ return NF_ACCEPT; ++ nf_ct_rtcache_ext_add(ct); ++ return NF_ACCEPT; ++ } ++ ++ rtc = nf_ct_rtcache_find_usable(ct); ++ if (!rtc) ++ return NF_ACCEPT; ++ ++ dir = CTINFO2DIR(ctinfo); ++ iif = nf_conn_rtcache_iif_get(rtc, dir); ++ pr_debug("ct %p, skb %p, dir %d, iif %d, cached iif %d\n", ++ ct, skb, dir, iif, state->in->ifindex); ++ if (likely(state->in->ifindex == iif)) ++ return NF_ACCEPT; ++ ++ nf_conn_rtcache_dst_set(ops->pf, rtc, skb_dst(skb), dir, state->in->ifindex); ++ return NF_ACCEPT; ++} ++ ++static int nf_rtcache_dst_remove(struct nf_conn *ct, void *data) ++{ ++ struct nf_conn_rtcache *rtc = nf_ct_rtcache_find(ct); ++ struct net_device *dev = data; ++ ++ if (!rtc) ++ return 0; ++ ++ if (dev->ifindex == rtc->cached_dst[IP_CT_DIR_ORIGINAL].iif || ++ dev->ifindex == rtc->cached_dst[IP_CT_DIR_REPLY].iif) { ++ nf_conn_rtcache_dst_obsolete(rtc, IP_CT_DIR_ORIGINAL); ++ nf_conn_rtcache_dst_obsolete(rtc, IP_CT_DIR_REPLY); ++ } ++ ++ return 0; ++} ++ ++static int nf_rtcache_netdev_event(struct notifier_block *this, ++ unsigned long event, void *ptr) ++{ ++ struct net_device *dev = netdev_notifier_info_to_dev(ptr); ++ struct net *net = dev_net(dev); ++ ++ if (event == NETDEV_DOWN) ++ nf_ct_iterate_cleanup(net, nf_rtcache_dst_remove, dev, 0, 0); ++ ++ return NOTIFY_DONE; ++} ++ ++static struct notifier_block nf_rtcache_notifier = { ++ .notifier_call = nf_rtcache_netdev_event, ++}; ++ ++static struct nf_hook_ops rtcache_ops[] = { ++ { ++ .hook = nf_rtcache_in, ++ .owner = THIS_MODULE, ++ .pf = NFPROTO_IPV4, ++ .hooknum = NF_INET_PRE_ROUTING, ++ .priority = NF_IP_PRI_LAST, ++ }, ++ { ++ .hook = nf_rtcache_forward, ++ .owner = THIS_MODULE, ++ .pf = NFPROTO_IPV4, ++ .hooknum = NF_INET_FORWARD, ++ .priority = NF_IP_PRI_LAST, ++ }, ++#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6) ++ { ++ .hook = nf_rtcache_in, ++ .owner = THIS_MODULE, ++ .pf = NFPROTO_IPV6, ++ .hooknum = NF_INET_PRE_ROUTING, ++ .priority = NF_IP_PRI_LAST, ++ }, ++ { ++ .hook = nf_rtcache_forward, ++ .owner = THIS_MODULE, ++ .pf = NFPROTO_IPV6, ++ .hooknum = NF_INET_FORWARD, ++ .priority = NF_IP_PRI_LAST, ++ }, ++#endif ++}; ++ ++static struct nf_ct_ext_type rtcache_extend __read_mostly = { ++ .len = sizeof(struct nf_conn_rtcache), ++ .align = __alignof__(struct nf_conn_rtcache), ++ .id = NF_CT_EXT_RTCACHE, ++ .destroy = nf_conn_rtcache_destroy, ++}; ++ ++static int __init nf_conntrack_rtcache_init(void) ++{ ++ int ret = nf_ct_extend_register(&rtcache_extend); ++ ++ if (ret < 0) { ++ pr_err("nf_conntrack_rtcache: Unable to register extension\n"); ++ return ret; ++ } ++ ++ ret = nf_register_hooks(rtcache_ops, ARRAY_SIZE(rtcache_ops)); ++ if (ret < 0) { ++ nf_ct_extend_unregister(&rtcache_extend); ++ return ret; ++ } ++ ++ ret = register_netdevice_notifier(&nf_rtcache_notifier); ++ if (ret) { ++ nf_unregister_hooks(rtcache_ops, ARRAY_SIZE(rtcache_ops)); ++ nf_ct_extend_unregister(&rtcache_extend); ++ } ++ ++ return ret; ++} ++ ++static int nf_rtcache_ext_remove(struct nf_conn *ct, void *data) ++{ ++ struct nf_conn_rtcache *rtc = nf_ct_rtcache_find(ct); ++ ++ return rtc != NULL; ++} ++ ++static bool __exit nf_conntrack_rtcache_wait_for_dying(struct net *net) ++{ ++ bool wait = false; ++ int cpu; ++ ++ for_each_possible_cpu(cpu) { ++ struct nf_conntrack_tuple_hash *h; ++ struct hlist_nulls_node *n; ++ struct nf_conn *ct; ++ struct ct_pcpu *pcpu = per_cpu_ptr(net->ct.pcpu_lists, cpu); ++ ++ rcu_read_lock(); ++ spin_lock_bh(&pcpu->lock); ++ ++ hlist_nulls_for_each_entry(h, n, &pcpu->dying, hnnode) { ++ ct = nf_ct_tuplehash_to_ctrack(h); ++ if (nf_ct_rtcache_find(ct) != NULL) { ++ wait = true; ++ break; ++ } ++ } ++ spin_unlock_bh(&pcpu->lock); ++ rcu_read_unlock(); ++ } ++ ++ return wait; ++} ++ ++static void __exit nf_conntrack_rtcache_fini(void) ++{ ++ struct net *net; ++ int count = 0; ++ ++ /* remove hooks so no new connections get rtcache extension */ ++ nf_unregister_hooks(rtcache_ops, ARRAY_SIZE(rtcache_ops)); ++ ++ synchronize_net(); ++ ++ unregister_netdevice_notifier(&nf_rtcache_notifier); ++ ++ rtnl_lock(); ++ ++ /* zap all conntracks with rtcache extension */ ++ for_each_net(net) ++ nf_ct_iterate_cleanup(net, nf_rtcache_ext_remove, NULL, 0, 0); ++ ++ for_each_net(net) { ++ /* .. and make sure they're gone from dying list, too */ ++ while (nf_conntrack_rtcache_wait_for_dying(net)) { ++ msleep(200); ++ WARN_ONCE(++count > 25, "Waiting for all rtcache conntracks to go away\n"); ++ } ++ } ++ ++ rtnl_unlock(); ++ synchronize_net(); ++ nf_ct_extend_unregister(&rtcache_extend); ++} ++module_init(nf_conntrack_rtcache_init); ++module_exit(nf_conntrack_rtcache_fini); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Florian Westphal "); ++MODULE_DESCRIPTION("Conntrack route cache extension"); diff --git a/target/linux/generic/patches-4.1/060-mips_decompressor_memmove.patch b/target/linux/generic/patches-4.1/060-mips_decompressor_memmove.patch new file mode 100644 index 0000000..d215b80 --- /dev/null +++ b/target/linux/generic/patches-4.1/060-mips_decompressor_memmove.patch @@ -0,0 +1,22 @@ +--- a/arch/mips/boot/compressed/string.c ++++ b/arch/mips/boot/compressed/string.c +@@ -26,3 +26,19 @@ void *memset(void *s, int c, size_t n) + ss[i] = c; + return s; + } ++ ++void *memmove(void *__dest, __const void *__src, size_t count) ++{ ++ unsigned char *d = __dest; ++ const unsigned char *s = __src; ++ ++ if (__dest == __src) ++ return __dest; ++ ++ if (__dest < __src) ++ return memcpy(__dest, __src, count); ++ ++ while (count--) ++ d[count] = s[count]; ++ return __dest; ++} diff --git a/target/linux/generic/patches-4.1/072-13-bgmac-fix-MAC-soft-reset-bit-for-corerev-4.patch b/target/linux/generic/patches-4.1/072-13-bgmac-fix-MAC-soft-reset-bit-for-corerev-4.patch new file mode 100644 index 0000000..a3d9fd6 --- /dev/null +++ b/target/linux/generic/patches-4.1/072-13-bgmac-fix-MAC-soft-reset-bit-for-corerev-4.patch @@ -0,0 +1,24 @@ +From: Felix Fietkau +Date: Mon, 13 Apr 2015 15:54:04 +0200 +Subject: [PATCH] bgmac: fix MAC soft-reset bit for corerev > 4 + +Only core revisions older than 4 use BGMAC_CMDCFG_SR_REV0 + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/broadcom/bgmac.h ++++ b/drivers/net/ethernet/broadcom/bgmac.h +@@ -198,9 +198,9 @@ + #define BGMAC_CMDCFG_TAI 0x00000200 + #define BGMAC_CMDCFG_HD 0x00000400 /* Set if in half duplex mode */ + #define BGMAC_CMDCFG_HD_SHIFT 10 +-#define BGMAC_CMDCFG_SR_REV0 0x00000800 /* Set to reset mode, for other revs */ +-#define BGMAC_CMDCFG_SR_REV4 0x00002000 /* Set to reset mode, only for core rev 4 */ +-#define BGMAC_CMDCFG_SR(rev) ((rev == 4) ? BGMAC_CMDCFG_SR_REV4 : BGMAC_CMDCFG_SR_REV0) ++#define BGMAC_CMDCFG_SR_REV0 0x00000800 /* Set to reset mode, for core rev 0-3 */ ++#define BGMAC_CMDCFG_SR_REV4 0x00002000 /* Set to reset mode, for core rev >= 4 */ ++#define BGMAC_CMDCFG_SR(rev) ((rev >= 4) ? BGMAC_CMDCFG_SR_REV4 : BGMAC_CMDCFG_SR_REV0) + #define BGMAC_CMDCFG_ML 0x00008000 /* Set to activate mac loopback mode */ + #define BGMAC_CMDCFG_AE 0x00400000 + #define BGMAC_CMDCFG_CFE 0x00800000 diff --git a/target/linux/generic/patches-4.1/072-14-bgmac-reset-all-4-GMAC-cores-on-init.patch b/target/linux/generic/patches-4.1/072-14-bgmac-reset-all-4-GMAC-cores-on-init.patch new file mode 100644 index 0000000..2a913a6 --- /dev/null +++ b/target/linux/generic/patches-4.1/072-14-bgmac-reset-all-4-GMAC-cores-on-init.patch @@ -0,0 +1,28 @@ +From: Felix Fietkau +Date: Mon, 13 Apr 2015 15:56:26 +0200 +Subject: [PATCH] bgmac: reset all 4 GMAC cores on init + +On a BCM4709 based device, I found that GMAC cores may be enabled at +probe time, but only become usable after a full reset. +Disable cores before re-enabling them to ensure that they are properly +reset. + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/broadcom/bgmac.c ++++ b/drivers/net/ethernet/broadcom/bgmac.c +@@ -1623,8 +1623,11 @@ static int bgmac_probe(struct bcma_devic + ns_core = bcma_find_core_unit(core->bus, + BCMA_CORE_MAC_GBIT, + ns_gmac); +- if (ns_core && !bcma_core_is_enabled(ns_core)) +- bcma_core_enable(ns_core, 0); ++ if (!ns_core) ++ continue; ++ ++ bcma_core_disable(ns_core, 0); ++ bcma_core_enable(ns_core, 0); + } + } + diff --git a/target/linux/generic/patches-4.1/080-ipv6-ip6_fragment-fix-headroom-tests-and-skb-leak.patch b/target/linux/generic/patches-4.1/080-ipv6-ip6_fragment-fix-headroom-tests-and-skb-leak.patch new file mode 100644 index 0000000..7de8987 --- /dev/null +++ b/target/linux/generic/patches-4.1/080-ipv6-ip6_fragment-fix-headroom-tests-and-skb-leak.patch @@ -0,0 +1,101 @@ +From: Florian Westphal +Date: Thu, 17 Sep 2015 11:24:48 +0100 +Subject: [PATCH] ipv6: ip6_fragment: fix headroom tests and skb leak + +David Woodhouse reports skb_under_panic when we try to push ethernet +header to fragmented ipv6 skbs: + + skbuff: skb_under_panic: text:c1277f1e len:1294 put:14 head:dec98000 + data:dec97ffc tail:0xdec9850a end:0xdec98f40 dev:br-lan +[..] +ip6_finish_output2+0x196/0x4da + +David further debugged this: + [..] offending fragments were arriving here with skb_headroom(skb)==10. + Which is reasonable, being the Solos ADSL card's header of 8 bytes + followed by 2 bytes of PPP frame type. + +The problem is that if netfilter ipv6 defragmentation is used, skb_cow() +in ip6_forward will only see reassembled skb. + +Therefore, headroom is overestimated by 8 bytes (we pulled fragment +header) and we don't check the skbs in the frag_list either. + +We can't do these checks in netfilter defrag since outdev isn't known yet. + +Furthermore, existing tests in ip6_fragment did not consider the fragment +or ipv6 header size when checking headroom of the fraglist skbs. + +While at it, also fix a skb leak on memory allocation -- ip6_fragment +must consume the skb. + +I tested this e1000 driver hacked to not allocate additional headroom +(we end up in slowpath, since LL_RESERVED_SPACE is 16). + +If 2 bytes of headroom are allocated, fastpath is taken (14 byte +ethernet header was pulled, so 16 byte headroom available in all +fragments). + +Reported-by: David Woodhouse +Diagnosed-by: David Woodhouse +Signed-off-by: Florian Westphal +Closes 20532 +--- + +--- a/net/ipv6/ip6_output.c ++++ b/net/ipv6/ip6_output.c +@@ -584,20 +584,22 @@ int ip6_fragment(struct sock *sk, struct + } + mtu -= hlen + sizeof(struct frag_hdr); + ++ hroom = LL_RESERVED_SPACE(rt->dst.dev); + if (skb_has_frag_list(skb)) { + int first_len = skb_pagelen(skb); + struct sk_buff *frag2; + + if (first_len - hlen > mtu || + ((first_len - hlen) & 7) || +- skb_cloned(skb)) ++ skb_cloned(skb) || ++ skb_headroom(skb) < (hroom + sizeof(struct frag_hdr))) + goto slow_path; + + skb_walk_frags(skb, frag) { + /* Correct geometry. */ + if (frag->len > mtu || + ((frag->len & 7) && frag->next) || +- skb_headroom(frag) < hlen) ++ skb_headroom(frag) < (hlen + hroom + sizeof(struct frag_hdr))) + goto slow_path_clean; + + /* Partially cloned skb? */ +@@ -614,8 +616,6 @@ int ip6_fragment(struct sock *sk, struct + + err = 0; + offset = 0; +- frag = skb_shinfo(skb)->frag_list; +- skb_frag_list_init(skb); + /* BUILD HEADER */ + + *prevhdr = NEXTHDR_FRAGMENT; +@@ -623,8 +623,11 @@ int ip6_fragment(struct sock *sk, struct + if (!tmp_hdr) { + IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), + IPSTATS_MIB_FRAGFAILS); +- return -ENOMEM; ++ err = -ENOMEM; ++ goto fail; + } ++ frag = skb_shinfo(skb)->frag_list; ++ skb_frag_list_init(skb); + + __skb_pull(skb, hlen); + fh = (struct frag_hdr *)__skb_push(skb, sizeof(struct frag_hdr)); +@@ -722,7 +725,6 @@ slow_path: + */ + + *prevhdr = NEXTHDR_FRAGMENT; +- hroom = LL_RESERVED_SPACE(rt->dst.dev); + troom = rt->dst.dev->needed_tailroom; + + /* diff --git a/target/linux/generic/patches-4.1/081-solos-pci-Increase-headroom-on-received-packets.patch b/target/linux/generic/patches-4.1/081-solos-pci-Increase-headroom-on-received-packets.patch new file mode 100644 index 0000000..605f57a --- /dev/null +++ b/target/linux/generic/patches-4.1/081-solos-pci-Increase-headroom-on-received-packets.patch @@ -0,0 +1,54 @@ +From: David Woodhouse +Date: Thu, 17 Sep 2015 11:19:53 +0100 +Subject: [PATCH] solos-pci: Increase headroom on received packets +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +A comment in include/linux/skbuff.h says that: + + * Various parts of the networking layer expect at least 32 bytes of + * headroom, you should not reduce this. + +This was demonstrated by a panic when handling fragmented IPv6 packets: +http://marc.info/?l=linux-netdev&m=144236093519172&w=2 + +It's not entirely clear if that comment is still valid — and if it is, +perhaps netif_rx() ought to be enforcing it with a warning. + +But either way, it is rather stupid from a performance point of view +for us to be receiving packets into a buffer which doesn't have enough +room to prepend an Ethernet header — it means that *every* incoming +packet is going to be need to be reallocated. So let's fix that. + +Signed-off-by: David Woodhouse +--- + +--- a/drivers/atm/solos-pci.c ++++ b/drivers/atm/solos-pci.c +@@ -805,7 +805,12 @@ static void solos_bh(unsigned long card_ + continue; + } + +- skb = alloc_skb(size + 1, GFP_ATOMIC); ++ /* Use netdev_alloc_skb() because it adds NET_SKB_PAD of ++ * headroom, and ensures we can route packets back out an ++ * Ethernet interface (for example) without having to ++ * reallocate. Adding NET_IP_ALIGN also ensures that both ++ * PPPoATM and PPPoEoBR2684 packets end up aligned. */ ++ skb = netdev_alloc_skb_ip_align(NULL, size + 1); + if (!skb) { + if (net_ratelimit()) + dev_warn(&card->dev->dev, "Failed to allocate sk_buff for RX\n"); +@@ -869,7 +874,10 @@ static void solos_bh(unsigned long card_ + /* Allocate RX skbs for any ports which need them */ + if (card->using_dma && card->atmdev[port] && + !card->rx_skb[port]) { +- struct sk_buff *skb = alloc_skb(RX_DMA_SIZE, GFP_ATOMIC); ++ /* Unlike the MMIO case (qv) we can't add NET_IP_ALIGN ++ * here; the FPGA can only DMA to addresses which are ++ * aligned to 4 bytes. */ ++ struct sk_buff *skb = dev_alloc_skb(RX_DMA_SIZE); + if (skb) { + SKB_CB(skb)->dma_addr = + dma_map_single(&card->dev->dev, skb->data, diff --git a/target/linux/generic/patches-4.1/091-mtd-spi-nor-add-support-Spansion_S25FL164K b/target/linux/generic/patches-4.1/091-mtd-spi-nor-add-support-Spansion_S25FL164K new file mode 100644 index 0000000..c8aa336 --- /dev/null +++ b/target/linux/generic/patches-4.1/091-mtd-spi-nor-add-support-Spansion_S25FL164K @@ -0,0 +1,10 @@ +--- a/drivers/mtd/spi-nor/spi-nor.c ++++ b/drivers/mtd/spi-nor/spi-nor.c +@@ -614,6 +614,7 @@ static const struct spi_device_id spi_no + { "s25fl016k", INFO(0xef4015, 0, 64 * 1024, 32, SECT_4K) }, + { "s25fl064k", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) }, + { "s25fl132k", INFO(0x014016, 0, 64 * 1024, 64, 0) }, ++ { "s25fl164k", INFO(0x014017, 0, 64 * 1024, 128, SECT_4K) }, + + /* SST -- large erase sizes are "overlays", "sectors" are 4K */ + { "sst25vf040b", INFO(0xbf258d, 0, 64 * 1024, 8, SECT_4K | SST_WRITE) }, diff --git a/target/linux/generic/patches-4.1/095-api-fix-compatibility-of-linux-in.h-with-netinet-in..patch b/target/linux/generic/patches-4.1/095-api-fix-compatibility-of-linux-in.h-with-netinet-in..patch new file mode 100644 index 0000000..d0bea94 --- /dev/null +++ b/target/linux/generic/patches-4.1/095-api-fix-compatibility-of-linux-in.h-with-netinet-in..patch @@ -0,0 +1,146 @@ +From 279c6c7fa64f5763e6b9f05e7ab3840092e702e7 Mon Sep 17 00:00:00 2001 +From: Stephen Hemminger +Date: Mon, 29 Jun 2015 14:57:48 -1000 +Subject: [PATCH] api: fix compatibility of linux/in.h with netinet/in.h + +u +This fixes breakage to iproute2 build with recent kernel headers +caused by: + commit a263653ed798216c0069922d7b5237ca49436007 + Author: Pablo Neira Ayuso + Date: Wed Jun 17 10:28:27 2015 -0500 + + netfilter: don't pull include/linux/netfilter.h from netns headers + +The issue is that definitions in linux/in.h overlap with those +in netinet/in.h. This patch solves this by introducing the same +mechanism as was used to solve the same problem with linux/in6.h + +Signed-off-by: Stephen Hemminger +Signed-off-by: David S. Miller +--- + include/uapi/linux/in.h | 16 +++++++++++++--- + include/uapi/linux/libc-compat.h | 22 ++++++++++++++++++++++ + 2 files changed, 35 insertions(+), 3 deletions(-) + +--- a/include/uapi/linux/in.h ++++ b/include/uapi/linux/in.h +@@ -19,8 +19,10 @@ + #define _UAPI_LINUX_IN_H + + #include ++#include + #include + ++#if __UAPI_DEF_IN_IPPROTO + /* Standard well-defined IP protocols. */ + enum { + IPPROTO_IP = 0, /* Dummy protocol for TCP */ +@@ -73,12 +75,14 @@ enum { + #define IPPROTO_RAW IPPROTO_RAW + IPPROTO_MAX + }; ++#endif + +- ++#if __UAPI_DEF_IN_ADDR + /* Internet address. */ + struct in_addr { + __be32 s_addr; + }; ++#endif + + #define IP_TOS 1 + #define IP_TTL 2 +@@ -155,6 +159,7 @@ struct in_addr { + + /* Request struct for multicast socket ops */ + ++#if __UAPI_DEF_IP_MREQ + struct ip_mreq { + struct in_addr imr_multiaddr; /* IP multicast address of group */ + struct in_addr imr_interface; /* local IP address of interface */ +@@ -206,14 +211,18 @@ struct group_filter { + #define GROUP_FILTER_SIZE(numsrc) \ + (sizeof(struct group_filter) - sizeof(struct __kernel_sockaddr_storage) \ + + (numsrc) * sizeof(struct __kernel_sockaddr_storage)) ++#endif + ++#if __UAPI_DEF_IN_PKTINFO + struct in_pktinfo { + int ipi_ifindex; + struct in_addr ipi_spec_dst; + struct in_addr ipi_addr; + }; ++#endif + + /* Structure describing an Internet (IP) socket address. */ ++#if __UAPI_DEF_SOCKADDR_IN + #define __SOCK_SIZE__ 16 /* sizeof(struct sockaddr) */ + struct sockaddr_in { + __kernel_sa_family_t sin_family; /* Address family */ +@@ -225,8 +234,9 @@ struct sockaddr_in { + sizeof(unsigned short int) - sizeof(struct in_addr)]; + }; + #define sin_zero __pad /* for BSD UNIX comp. -FvK */ ++#endif + +- ++#if __UAPI_DEF_IN_CLASS + /* + * Definitions of the bits in an Internet address integer. + * On subnets, host and network parts are found according +@@ -277,7 +287,7 @@ struct sockaddr_in { + #define INADDR_ALLHOSTS_GROUP 0xe0000001U /* 224.0.0.1 */ + #define INADDR_ALLRTRS_GROUP 0xe0000002U /* 224.0.0.2 */ + #define INADDR_MAX_LOCAL_GROUP 0xe00000ffU /* 224.0.0.255 */ +- ++#endif + + /* contains the htonl type stuff.. */ + #include +--- a/include/uapi/linux/libc-compat.h ++++ b/include/uapi/linux/libc-compat.h +@@ -56,6 +56,13 @@ + + /* GLIBC headers included first so don't define anything + * that would already be defined. */ ++#define __UAPI_DEF_IN_ADDR 0 ++#define __UAPI_DEF_IN_IPPROTO 0 ++#define __UAPI_DEF_IN_PKTINFO 0 ++#define __UAPI_DEF_IP_MREQ 0 ++#define __UAPI_DEF_SOCKADDR_IN 0 ++#define __UAPI_DEF_IN_CLASS 0 ++ + #define __UAPI_DEF_IN6_ADDR 0 + /* The exception is the in6_addr macros which must be defined + * if the glibc code didn't define them. This guard matches +@@ -78,6 +85,13 @@ + /* Linux headers included first, and we must define everything + * we need. The expectation is that glibc will check the + * __UAPI_DEF_* defines and adjust appropriately. */ ++#define __UAPI_DEF_IN_ADDR 1 ++#define __UAPI_DEF_IN_IPPROTO 1 ++#define __UAPI_DEF_IN_PKTINFO 1 ++#define __UAPI_DEF_IP_MREQ 1 ++#define __UAPI_DEF_SOCKADDR_IN 1 ++#define __UAPI_DEF_IN_CLASS 1 ++ + #define __UAPI_DEF_IN6_ADDR 1 + /* We unconditionally define the in6_addr macros and glibc must + * coordinate. */ +@@ -103,6 +117,14 @@ + * that we need. */ + #else /* !defined(__GLIBC__) */ + ++/* Definitions for in.h */ ++#define __UAPI_DEF_IN_ADDR 1 ++#define __UAPI_DEF_IN_IPPROTO 1 ++#define __UAPI_DEF_IN_PKTINFO 1 ++#define __UAPI_DEF_IP_MREQ 1 ++#define __UAPI_DEF_SOCKADDR_IN 1 ++#define __UAPI_DEF_IN_CLASS 1 ++ + /* Definitions for in6.h */ + #define __UAPI_DEF_IN6_ADDR 1 + #define __UAPI_DEF_IN6_ADDR_ALT 1 diff --git a/target/linux/generic/patches-4.1/096-ipv4-off-by-one-in-continuation-handling-in-proc-net.patch b/target/linux/generic/patches-4.1/096-ipv4-off-by-one-in-continuation-handling-in-proc-net.patch new file mode 100644 index 0000000..aa31641 --- /dev/null +++ b/target/linux/generic/patches-4.1/096-ipv4-off-by-one-in-continuation-handling-in-proc-net.patch @@ -0,0 +1,46 @@ +From 25b97c016b26039982daaa2c11d83979f93b71ab Mon Sep 17 00:00:00 2001 +From: Andy Whitcroft +Date: Thu, 13 Aug 2015 20:49:01 +0100 +Subject: [PATCH] ipv4: off-by-one in continuation handling in /proc/net/route + +When generating /proc/net/route we emit a header followed by a line for +each route. When a short read is performed we will restart this process +based on the open file descriptor. When calculating the start point we +fail to take into account that the 0th entry is the header. This leads +us to skip the first entry when doing a continuation read. + +This can be easily seen with the comparison below: + + while read l; do echo "$l"; done A + cat /proc/net/route >B + diff -bu A B | grep '^[+-]' + +On my example machine I have approximatly 10KB of route output. There we +see the very first non-title element is lost in the while read case, +and an entry around the 8K mark in the cat case: + + +wlan0 00000000 02021EAC 0003 0 0 400 00000000 0 0 0 + -tun1 00C0AC0A 00000000 0001 0 0 950 00C0FFFF 0 0 0 + +Fix up the off-by-one when reaquiring position on continuation. + +Fixes: 8be33e955cb9 ("fib_trie: Fib walk rcu should take a tnode and key instead of a trie and a leaf") +BugLink: http://bugs.launchpad.net/bugs/1483440 +Acked-by: Alexander Duyck +Signed-off-by: Andy Whitcroft +Signed-off-by: David S. Miller +--- + net/ipv4/fib_trie.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/net/ipv4/fib_trie.c ++++ b/net/ipv4/fib_trie.c +@@ -2457,7 +2457,7 @@ static struct key_vector *fib_route_get_ + key = l->key + 1; + iter->pos++; + +- if (pos-- <= 0) ++ if (--pos <= 0) + break; + + l = NULL; diff --git a/target/linux/generic/patches-4.1/101-pppoe-fix-disconnect-crash.patch b/target/linux/generic/patches-4.1/101-pppoe-fix-disconnect-crash.patch new file mode 100644 index 0000000..f2e6e45 --- /dev/null +++ b/target/linux/generic/patches-4.1/101-pppoe-fix-disconnect-crash.patch @@ -0,0 +1,16 @@ +Fix crash with actions performed on the underlying interface (MAC address, +MTU or link state update). This triggers pppoe_flush_dev(), which cleans up +the device without announcing it in sk->sk_state. + +Patch by Guillaume Nault (pulled from netdev@vger) + +--- a/drivers/net/ppp/pppoe.c ++++ b/drivers/net/ppp/pppoe.c +@@ -313,7 +313,6 @@ static void pppoe_flush_dev(struct net_d + if (po->pppoe_dev == dev && + sk->sk_state & (PPPOX_CONNECTED | PPPOX_BOUND | PPPOX_ZOMBIE)) { + pppox_unbind_sock(sk); +- sk->sk_state = PPPOX_ZOMBIE; + sk->sk_state_change(sk); + po->pppoe_dev = NULL; + dev_put(dev); diff --git a/target/linux/generic/patches-4.1/102-ehci_hcd_ignore_oc.patch b/target/linux/generic/patches-4.1/102-ehci_hcd_ignore_oc.patch new file mode 100644 index 0000000..4da579c --- /dev/null +++ b/target/linux/generic/patches-4.1/102-ehci_hcd_ignore_oc.patch @@ -0,0 +1,82 @@ +From 1e311820ec3055e3f08e687de6564692a7cec675 Mon Sep 17 00:00:00 2001 +From: Florian Fainelli +Date: Mon, 28 Jan 2013 20:06:29 +0100 +Subject: [PATCH 11/12] USB: EHCI: add ignore_oc flag to disable overcurrent + checking + +This patch adds an ignore_oc flag which can be set by EHCI controller +not supporting or wanting to disable overcurrent checking. The EHCI +platform data in include/linux/usb/ehci_pdriver.h is also augmented to +take advantage of this new flag. + +Signed-off-by: Florian Fainelli +--- + drivers/usb/host/ehci-hcd.c | 2 +- + drivers/usb/host/ehci-hub.c | 4 ++-- + drivers/usb/host/ehci-platform.c | 1 + + drivers/usb/host/ehci.h | 1 + + include/linux/usb/ehci_pdriver.h | 1 + + 5 files changed, 6 insertions(+), 3 deletions(-) + +--- a/drivers/usb/host/ehci-hcd.c ++++ b/drivers/usb/host/ehci-hcd.c +@@ -638,7 +638,7 @@ static int ehci_run (struct usb_hcd *hcd + "USB %x.%x started, EHCI %x.%02x%s\n", + ((ehci->sbrn & 0xf0)>>4), (ehci->sbrn & 0x0f), + temp >> 8, temp & 0xff, +- ignore_oc ? ", overcurrent ignored" : ""); ++ (ignore_oc || ehci->ignore_oc) ? ", overcurrent ignored" : ""); + + ehci_writel(ehci, INTR_MASK, + &ehci->regs->intr_enable); /* Turn On Interrupts */ +--- a/drivers/usb/host/ehci-hub.c ++++ b/drivers/usb/host/ehci-hub.c +@@ -633,7 +633,7 @@ ehci_hub_status_data (struct usb_hcd *hc + * always set, seem to clear PORT_OCC and PORT_CSC when writing to + * PORT_POWER; that's surprising, but maybe within-spec. + */ +- if (!ignore_oc) ++ if (!ignore_oc && !ehci->ignore_oc) + mask = PORT_CSC | PORT_PEC | PORT_OCC; + else + mask = PORT_CSC | PORT_PEC; +@@ -995,7 +995,7 @@ int ehci_hub_control( + if (temp & PORT_PEC) + status |= USB_PORT_STAT_C_ENABLE << 16; + +- if ((temp & PORT_OCC) && !ignore_oc){ ++ if ((temp & PORT_OCC) && (!ignore_oc && !ehci->ignore_oc)){ + status |= USB_PORT_STAT_C_OVERCURRENT << 16; + + /* +--- a/drivers/usb/host/ehci-platform.c ++++ b/drivers/usb/host/ehci-platform.c +@@ -264,6 +264,8 @@ static int ehci_platform_probe(struct pl + ehci->big_endian_desc = 1; + if (pdata->big_endian_mmio) + ehci->big_endian_mmio = 1; ++ if (pdata->ignore_oc) ++ ehci->ignore_oc = 1; + + #ifndef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO + if (ehci->big_endian_mmio) { +--- a/drivers/usb/host/ehci.h ++++ b/drivers/usb/host/ehci.h +@@ -226,6 +226,7 @@ struct ehci_hcd { /* one per controlle + unsigned frame_index_bug:1; /* MosChip (AKA NetMos) */ + unsigned need_oc_pp_cycle:1; /* MPC834X port power */ + unsigned imx28_write_fix:1; /* For Freescale i.MX28 */ ++ unsigned ignore_oc:1; + + /* required for usb32 quirk */ + #define OHCI_CTRL_HCFS (3 << 6) +--- a/include/linux/usb/ehci_pdriver.h ++++ b/include/linux/usb/ehci_pdriver.h +@@ -49,6 +49,7 @@ struct usb_ehci_pdata { + unsigned no_io_watchdog:1; + unsigned reset_on_resume:1; + unsigned dma_mask_64:1; ++ unsigned ignore_oc:1; + + /* Turn on all power and clocks */ + int (*power_on)(struct platform_device *pdev); diff --git a/target/linux/generic/patches-4.1/110-jffs2-use-.rename2-and-add-RENAME_WHITEOUT-support.patch b/target/linux/generic/patches-4.1/110-jffs2-use-.rename2-and-add-RENAME_WHITEOUT-support.patch new file mode 100644 index 0000000..9d32777 --- /dev/null +++ b/target/linux/generic/patches-4.1/110-jffs2-use-.rename2-and-add-RENAME_WHITEOUT-support.patch @@ -0,0 +1,86 @@ +From: Felix Fietkau +Date: Fri, 10 Apr 2015 13:35:29 +0200 +Subject: [PATCH] jffs2: use .rename2 and add RENAME_WHITEOUT support + +It is required for renames on overlayfs + +Signed-off-by: Felix Fietkau +--- + +--- a/fs/jffs2/dir.c ++++ b/fs/jffs2/dir.c +@@ -35,7 +35,7 @@ static int jffs2_mkdir (struct inode *,s + static int jffs2_rmdir (struct inode *,struct dentry *); + static int jffs2_mknod (struct inode *,struct dentry *,umode_t,dev_t); + static int jffs2_rename (struct inode *, struct dentry *, +- struct inode *, struct dentry *); ++ struct inode *, struct dentry *, unsigned int); + + const struct file_operations jffs2_dir_operations = + { +@@ -57,7 +57,7 @@ const struct inode_operations jffs2_dir_ + .mkdir = jffs2_mkdir, + .rmdir = jffs2_rmdir, + .mknod = jffs2_mknod, +- .rename = jffs2_rename, ++ .rename2 = jffs2_rename, + .get_acl = jffs2_get_acl, + .set_acl = jffs2_set_acl, + .setattr = jffs2_setattr, +@@ -756,8 +756,27 @@ static int jffs2_mknod (struct inode *di + return ret; + } + ++static int jffs2_whiteout(struct inode *old_dir, struct dentry *old_dentry) ++{ ++ struct dentry *wh; ++ int err; ++ ++ wh = d_alloc(old_dentry->d_parent, &old_dentry->d_name); ++ if (!wh) ++ return -ENOMEM; ++ ++ err = jffs2_mknod(old_dir, wh, S_IFCHR | WHITEOUT_MODE, ++ WHITEOUT_DEV); ++ if (err) ++ return err; ++ ++ d_rehash(wh); ++ return 0; ++} ++ + static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry, +- struct inode *new_dir_i, struct dentry *new_dentry) ++ struct inode *new_dir_i, struct dentry *new_dentry, ++ unsigned int flags) + { + int ret; + struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dir_i->i_sb); +@@ -765,6 +784,9 @@ static int jffs2_rename (struct inode *o + uint8_t type; + uint32_t now; + ++ if (flags & ~RENAME_WHITEOUT) ++ return -EINVAL; ++ + /* The VFS will check for us and prevent trying to rename a + * file over a directory and vice versa, but if it's a directory, + * the VFS can't check whether the victim is empty. The filesystem +@@ -828,9 +850,14 @@ static int jffs2_rename (struct inode *o + if (d_is_dir(old_dentry) && !victim_f) + inc_nlink(new_dir_i); + +- /* Unlink the original */ +- ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i), +- old_dentry->d_name.name, old_dentry->d_name.len, NULL, now); ++ if (flags & RENAME_WHITEOUT) ++ /* Replace with whiteout */ ++ ret = jffs2_whiteout(old_dir_i, old_dentry); ++ else ++ /* Unlink the original */ ++ ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i), ++ old_dentry->d_name.name, ++ old_dentry->d_name.len, NULL, now); + + /* We don't touch inode->i_nlink */ + diff --git a/target/linux/generic/patches-4.1/111-jffs2-add-RENAME_EXCHANGE-support.patch b/target/linux/generic/patches-4.1/111-jffs2-add-RENAME_EXCHANGE-support.patch new file mode 100644 index 0000000..3cc7b90 --- /dev/null +++ b/target/linux/generic/patches-4.1/111-jffs2-add-RENAME_EXCHANGE-support.patch @@ -0,0 +1,58 @@ +From: Felix Fietkau +Date: Sat, 25 Apr 2015 12:41:32 +0200 +Subject: [PATCH] jffs2: add RENAME_EXCHANGE support + +Signed-off-by: Felix Fietkau +--- + +--- a/fs/jffs2/dir.c ++++ b/fs/jffs2/dir.c +@@ -784,7 +784,7 @@ static int jffs2_rename (struct inode *o + uint8_t type; + uint32_t now; + +- if (flags & ~RENAME_WHITEOUT) ++ if (flags & ~(RENAME_WHITEOUT | RENAME_EXCHANGE)) + return -EINVAL; + + /* The VFS will check for us and prevent trying to rename a +@@ -792,7 +792,7 @@ static int jffs2_rename (struct inode *o + * the VFS can't check whether the victim is empty. The filesystem + * needs to do that for itself. + */ +- if (d_really_is_positive(new_dentry)) { ++ if (d_really_is_positive(new_dentry) && !(flags & RENAME_EXCHANGE)) { + victim_f = JFFS2_INODE_INFO(d_inode(new_dentry)); + if (d_is_dir(new_dentry)) { + struct jffs2_full_dirent *fd; +@@ -827,7 +827,7 @@ static int jffs2_rename (struct inode *o + if (ret) + return ret; + +- if (victim_f) { ++ if (victim_f && !(flags & RENAME_EXCHANGE)) { + /* There was a victim. Kill it off nicely */ + if (d_is_dir(new_dentry)) + clear_nlink(d_inode(new_dentry)); +@@ -853,6 +853,12 @@ static int jffs2_rename (struct inode *o + if (flags & RENAME_WHITEOUT) + /* Replace with whiteout */ + ret = jffs2_whiteout(old_dir_i, old_dentry); ++ else if (flags & RENAME_EXCHANGE) ++ /* Replace the original */ ++ ret = jffs2_do_link(c, JFFS2_INODE_INFO(old_dir_i), ++ d_inode(new_dentry)->i_ino, type, ++ old_dentry->d_name.name, old_dentry->d_name.len, ++ now); + else + /* Unlink the original */ + ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i), +@@ -879,7 +885,7 @@ static int jffs2_rename (struct inode *o + return ret; + } + +- if (d_is_dir(old_dentry)) ++ if (d_is_dir(old_dentry) && !(flags & RENAME_EXCHANGE)) + drop_nlink(old_dir_i); + + new_dir_i->i_mtime = new_dir_i->i_ctime = old_dir_i->i_mtime = old_dir_i->i_ctime = ITIME(now); diff --git a/target/linux/generic/patches-4.1/120-bridge_allow_receiption_on_disabled_port.patch b/target/linux/generic/patches-4.1/120-bridge_allow_receiption_on_disabled_port.patch new file mode 100644 index 0000000..5cd2f57 --- /dev/null +++ b/target/linux/generic/patches-4.1/120-bridge_allow_receiption_on_disabled_port.patch @@ -0,0 +1,54 @@ +From: Stephen Hemminger +Subject: bridge: allow receiption on disabled port + +When an ethernet device is enslaved to a bridge, and the bridge STP +detects loss of carrier (or operational state down), then normally +packet receiption is blocked. + +This breaks control applications like WPA which maybe expecting to +receive packets to negotiate to bring link up. The bridge needs to +block forwarding packets from these disabled ports, but there is no +hard requirement to not allow local packet delivery. + +Signed-off-by: Stephen Hemminger +Signed-off-by: Felix Fietkau + +--- a/net/bridge/br_input.c ++++ b/net/bridge/br_input.c +@@ -211,11 +211,13 @@ EXPORT_SYMBOL_GPL(br_handle_frame_finish + static int br_handle_local_finish(struct sock *sk, struct sk_buff *skb) + { + struct net_bridge_port *p = br_port_get_rcu(skb->dev); +- u16 vid = 0; ++ if (p->state != BR_STATE_DISABLED) { ++ u16 vid = 0; + +- /* check if vlan is allowed, to avoid spoofing */ +- if (p->flags & BR_LEARNING && br_should_learn(p, skb, &vid)) +- br_fdb_update(p->br, p, eth_hdr(skb)->h_source, vid, false); ++ /* check if vlan is allowed, to avoid spoofing */ ++ if (p->flags & BR_LEARNING && br_should_learn(p, skb, &vid)) ++ br_fdb_update(p->br, p, eth_hdr(skb)->h_source, vid, false); ++ } + return 0; /* process further */ + } + +@@ -289,6 +291,18 @@ rx_handler_result_t br_handle_frame(stru + + forward: + switch (p->state) { ++ case BR_STATE_DISABLED: ++ if (ether_addr_equal(p->br->dev->dev_addr, dest)) ++ skb->pkt_type = PACKET_HOST; ++ ++ if (NF_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, NULL, skb, skb->dev, NULL, ++ br_handle_local_finish)) ++ break; ++ ++ BR_INPUT_SKB_CB(skb)->brdev = p->br->dev; ++ br_pass_frame_up(skb); ++ break; ++ + case BR_STATE_FORWARDING: + rhook = rcu_dereference(br_should_route_hook); + if (rhook) { diff --git a/target/linux/generic/patches-4.1/132-mips_inline_dma_ops.patch b/target/linux/generic/patches-4.1/132-mips_inline_dma_ops.patch new file mode 100644 index 0000000..f7543cc --- /dev/null +++ b/target/linux/generic/patches-4.1/132-mips_inline_dma_ops.patch @@ -0,0 +1,697 @@ +From 2c58080407554e1bac8fd50d23cb02420524caed Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Mon, 12 Aug 2013 12:50:22 +0200 +Subject: [PATCH] MIPS: partially inline dma ops + +Several DMA ops are no-op on many platforms, and the indirection through +the mips_dma_map_ops function table is causing the compiler to emit +unnecessary code. + +Inlining visibly improves network performance in my tests (on a 24Kc +based system), and also slightly reduces code size of a few drivers. + +Signed-off-by: Felix Fietkau +--- + arch/mips/Kconfig | 4 + + arch/mips/include/asm/dma-mapping.h | 360 +++++++++++++++++++++++++++++++++++- + arch/mips/mm/dma-default.c | 163 ++-------------- + 3 files changed, 373 insertions(+), 154 deletions(-) + +--- a/arch/mips/Kconfig ++++ b/arch/mips/Kconfig +@@ -1571,6 +1571,7 @@ config CPU_CAVIUM_OCTEON + select CPU_SUPPORTS_HUGEPAGES + select USB_EHCI_BIG_ENDIAN_MMIO + select MIPS_L1_CACHE_SHIFT_7 ++ select SYS_HAS_DMA_OPS + help + The Cavium Octeon processor is a highly integrated chip containing + many ethernet hardware widgets for networking tasks. The processor +@@ -1866,6 +1867,9 @@ config MIPS_MALTA_PM + bool + default y + ++config SYS_HAS_DMA_OPS ++ bool ++ + # + # CPU may reorder R->R, R->W, W->R, W->W + # Reordering beyond LL and SC is handled in WEAK_REORDERING_BEYOND_LLSC +--- a/arch/mips/include/asm/dma-mapping.h ++++ b/arch/mips/include/asm/dma-mapping.h +@@ -1,9 +1,16 @@ + #ifndef _ASM_DMA_MAPPING_H + #define _ASM_DMA_MAPPING_H + ++#include ++#include ++#include ++#include ++#include ++ + #include + #include + #include ++#include + #include + + #ifndef CONFIG_SGI_IP27 /* Kludge to fix 2.6.39 build for IP27 */ +@@ -12,12 +19,48 @@ + + extern struct dma_map_ops *mips_dma_map_ops; + ++void __dma_sync(struct page *page, unsigned long offset, size_t size, ++ enum dma_data_direction direction); ++void *mips_dma_alloc_coherent(struct device *dev, size_t size, ++ dma_addr_t *dma_handle, gfp_t gfp, ++ struct dma_attrs *attrs); ++void mips_dma_free_coherent(struct device *dev, size_t size, void *vaddr, ++ dma_addr_t dma_handle, struct dma_attrs *attrs); ++ + static inline struct dma_map_ops *get_dma_ops(struct device *dev) + { ++#ifdef CONFIG_SYS_HAS_DMA_OPS + if (dev && dev->archdata.dma_ops) + return dev->archdata.dma_ops; + else + return mips_dma_map_ops; ++#else ++ return NULL; ++#endif ++} ++ ++/* ++ * Warning on the terminology - Linux calls an uncached area coherent; ++ * MIPS terminology calls memory areas with hardware maintained coherency ++ * coherent. ++ */ ++ ++static inline int cpu_needs_post_dma_flush(struct device *dev) ++{ ++#ifndef CONFIG_SYS_HAS_CPU_R10000 ++ return 0; ++#endif ++ return !plat_device_is_coherent(dev) && ++ (boot_cpu_type() == CPU_R10000 || ++ boot_cpu_type() == CPU_R12000 || ++ boot_cpu_type() == CPU_BMIPS5000); ++} ++ ++static inline struct page *dma_addr_to_page(struct device *dev, ++ dma_addr_t dma_addr) ++{ ++ return pfn_to_page( ++ plat_dma_addr_to_phys(dev, dma_addr) >> PAGE_SHIFT); + } + + static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) +@@ -30,12 +73,306 @@ static inline bool dma_capable(struct de + + static inline void dma_mark_clean(void *addr, size_t size) {} + +-#include ++static inline dma_addr_t dma_map_single_attrs(struct device *dev, void *ptr, ++ size_t size, ++ enum dma_data_direction dir, ++ struct dma_attrs *attrs) ++{ ++ struct dma_map_ops *ops = get_dma_ops(dev); ++ unsigned long offset = (unsigned long)ptr & ~PAGE_MASK; ++ struct page *page = virt_to_page(ptr); ++ dma_addr_t addr; ++ ++ kmemcheck_mark_initialized(ptr, size); ++ BUG_ON(!valid_dma_direction(dir)); ++ if (ops) { ++ addr = ops->map_page(dev, page, offset, size, dir, attrs); ++ } else { ++ if (!plat_device_is_coherent(dev)) ++ __dma_sync(page, offset, size, dir); ++ ++ addr = plat_map_dma_mem_page(dev, page) + offset; ++ } ++ debug_dma_map_page(dev, page, offset, size, dir, addr, true); ++ return addr; ++} ++ ++static inline void dma_unmap_single_attrs(struct device *dev, dma_addr_t addr, ++ size_t size, ++ enum dma_data_direction dir, ++ struct dma_attrs *attrs) ++{ ++ struct dma_map_ops *ops = get_dma_ops(dev); ++ ++ BUG_ON(!valid_dma_direction(dir)); ++ if (ops) { ++ ops->unmap_page(dev, addr, size, dir, attrs); ++ } else { ++ if (cpu_needs_post_dma_flush(dev)) ++ __dma_sync(dma_addr_to_page(dev, addr), ++ addr & ~PAGE_MASK, size, dir); ++ ++ plat_unmap_dma_mem(dev, addr, size, dir); ++ } ++ debug_dma_unmap_page(dev, addr, size, dir, true); ++} ++ ++static inline int dma_map_sg_attrs(struct device *dev, struct scatterlist *sg, ++ int nents, enum dma_data_direction dir, ++ struct dma_attrs *attrs) ++{ ++ struct dma_map_ops *ops = get_dma_ops(dev); ++ int i, ents; ++ struct scatterlist *s; ++ ++ for_each_sg(sg, s, nents, i) ++ kmemcheck_mark_initialized(sg_virt(s), s->length); ++ BUG_ON(!valid_dma_direction(dir)); ++ if (ops) { ++ ents = ops->map_sg(dev, sg, nents, dir, attrs); ++ } else { ++ for_each_sg(sg, s, nents, i) { ++ struct page *page = sg_page(s); ++ ++ if (!plat_device_is_coherent(dev)) ++ __dma_sync(page, s->offset, s->length, dir); ++#ifdef CONFIG_NEED_SG_DMA_LENGTH ++ s->dma_length = s->length; ++#endif ++ s->dma_address = ++ plat_map_dma_mem_page(dev, page) + s->offset; ++ } ++ ents = nents; ++ } ++ debug_dma_map_sg(dev, sg, nents, ents, dir); ++ ++ return ents; ++} ++ ++static inline void dma_unmap_sg_attrs(struct device *dev, struct scatterlist *sg, ++ int nents, enum dma_data_direction dir, ++ struct dma_attrs *attrs) ++{ ++ struct dma_map_ops *ops = get_dma_ops(dev); ++ struct scatterlist *s; ++ int i; ++ ++ BUG_ON(!valid_dma_direction(dir)); ++ debug_dma_unmap_sg(dev, sg, nents, dir); ++ if (ops) { ++ ops->unmap_sg(dev, sg, nents, dir, attrs); ++ return; ++ } ++ ++ for_each_sg(sg, s, nents, i) { ++ if (!plat_device_is_coherent(dev) && dir != DMA_TO_DEVICE) ++ __dma_sync(sg_page(s), s->offset, s->length, dir); ++ plat_unmap_dma_mem(dev, s->dma_address, s->length, dir); ++ } ++} ++ ++static inline dma_addr_t dma_map_page(struct device *dev, struct page *page, ++ size_t offset, size_t size, ++ enum dma_data_direction dir) ++{ ++ struct dma_map_ops *ops = get_dma_ops(dev); ++ dma_addr_t addr; ++ ++ kmemcheck_mark_initialized(page_address(page) + offset, size); ++ BUG_ON(!valid_dma_direction(dir)); ++ if (ops) { ++ addr = ops->map_page(dev, page, offset, size, dir, NULL); ++ } else { ++ if (!plat_device_is_coherent(dev)) ++ __dma_sync(page, offset, size, dir); ++ ++ addr = plat_map_dma_mem_page(dev, page) + offset; ++ } ++ debug_dma_map_page(dev, page, offset, size, dir, addr, false); ++ ++ return addr; ++} ++ ++static inline void dma_unmap_page(struct device *dev, dma_addr_t addr, ++ size_t size, enum dma_data_direction dir) ++{ ++ struct dma_map_ops *ops = get_dma_ops(dev); ++ ++ BUG_ON(!valid_dma_direction(dir)); ++ if (ops) { ++ ops->unmap_page(dev, addr, size, dir, NULL); ++ } else { ++ if (cpu_needs_post_dma_flush(dev)) ++ __dma_sync(dma_addr_to_page(dev, addr), ++ addr & ~PAGE_MASK, size, dir); ++ plat_post_dma_flush(dev); ++ plat_unmap_dma_mem(dev, addr, size, dir); ++ } ++ debug_dma_unmap_page(dev, addr, size, dir, false); ++} ++ ++static inline void dma_sync_single_for_cpu(struct device *dev, dma_addr_t addr, ++ size_t size, ++ enum dma_data_direction dir) ++{ ++ struct dma_map_ops *ops = get_dma_ops(dev); ++ ++ BUG_ON(!valid_dma_direction(dir)); ++ if (ops) ++ ops->sync_single_for_cpu(dev, addr, size, dir); ++ else if (cpu_needs_post_dma_flush(dev)) ++ __dma_sync(dma_addr_to_page(dev, addr), ++ addr & ~PAGE_MASK, size, dir); ++ plat_post_dma_flush(dev); ++ debug_dma_sync_single_for_cpu(dev, addr, size, dir); ++} ++ ++static inline void dma_sync_single_for_device(struct device *dev, ++ dma_addr_t addr, size_t size, ++ enum dma_data_direction dir) ++{ ++ struct dma_map_ops *ops = get_dma_ops(dev); ++ ++ BUG_ON(!valid_dma_direction(dir)); ++ if (ops) ++ ops->sync_single_for_device(dev, addr, size, dir); ++ else if (!plat_device_is_coherent(dev)) ++ __dma_sync(dma_addr_to_page(dev, addr), ++ addr & ~PAGE_MASK, size, dir); ++ debug_dma_sync_single_for_device(dev, addr, size, dir); ++} ++ ++static inline void dma_sync_single_range_for_cpu(struct device *dev, ++ dma_addr_t addr, ++ unsigned long offset, ++ size_t size, ++ enum dma_data_direction dir) ++{ ++ const struct dma_map_ops *ops = get_dma_ops(dev); ++ ++ BUG_ON(!valid_dma_direction(dir)); ++ if (ops) ++ ops->sync_single_for_cpu(dev, addr + offset, size, dir); ++ else if (cpu_needs_post_dma_flush(dev)) ++ __dma_sync(dma_addr_to_page(dev, addr + offset), ++ (addr + offset) & ~PAGE_MASK, size, dir); ++ debug_dma_sync_single_range_for_cpu(dev, addr, offset, size, dir); ++} ++ ++static inline void dma_sync_single_range_for_device(struct device *dev, ++ dma_addr_t addr, ++ unsigned long offset, ++ size_t size, ++ enum dma_data_direction dir) ++{ ++ const struct dma_map_ops *ops = get_dma_ops(dev); ++ ++ BUG_ON(!valid_dma_direction(dir)); ++ if (ops) ++ ops->sync_single_for_device(dev, addr + offset, size, dir); ++ else if (!plat_device_is_coherent(dev)) ++ __dma_sync(dma_addr_to_page(dev, addr + offset), ++ (addr + offset) & ~PAGE_MASK, size, dir); ++ debug_dma_sync_single_range_for_device(dev, addr, offset, size, dir); ++} ++ ++static inline void ++dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, ++ int nelems, enum dma_data_direction dir) ++{ ++ struct dma_map_ops *ops = get_dma_ops(dev); ++ struct scatterlist *s; ++ int i; ++ ++ BUG_ON(!valid_dma_direction(dir)); ++ if (ops) ++ ops->sync_sg_for_cpu(dev, sg, nelems, dir); ++ else if (cpu_needs_post_dma_flush(dev)) { ++ for_each_sg(sg, s, nelems, i) ++ __dma_sync(sg_page(s), s->offset, s->length, dir); ++ } ++ plat_post_dma_flush(dev); ++ debug_dma_sync_sg_for_cpu(dev, sg, nelems, dir); ++} ++ ++static inline void ++dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, ++ int nelems, enum dma_data_direction dir) ++{ ++ struct dma_map_ops *ops = get_dma_ops(dev); ++ struct scatterlist *s; ++ int i; ++ ++ BUG_ON(!valid_dma_direction(dir)); ++ if (ops) ++ ops->sync_sg_for_device(dev, sg, nelems, dir); ++ else if (!plat_device_is_coherent(dev)) { ++ for_each_sg(sg, s, nelems, i) ++ __dma_sync(sg_page(s), s->offset, s->length, dir); ++ } ++ debug_dma_sync_sg_for_device(dev, sg, nelems, dir); ++ ++} ++ ++#define dma_map_single(d, a, s, r) dma_map_single_attrs(d, a, s, r, NULL) ++#define dma_unmap_single(d, a, s, r) dma_unmap_single_attrs(d, a, s, r, NULL) ++#define dma_map_sg(d, s, n, r) dma_map_sg_attrs(d, s, n, r, NULL) ++#define dma_unmap_sg(d, s, n, r) dma_unmap_sg_attrs(d, s, n, r, NULL) ++ ++extern int dma_common_mmap(struct device *dev, struct vm_area_struct *vma, ++ void *cpu_addr, dma_addr_t dma_addr, size_t size); ++ ++/** ++ * dma_mmap_attrs - map a coherent DMA allocation into user space ++ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices ++ * @vma: vm_area_struct describing requested user mapping ++ * @cpu_addr: kernel CPU-view address returned from dma_alloc_attrs ++ * @handle: device-view address returned from dma_alloc_attrs ++ * @size: size of memory originally requested in dma_alloc_attrs ++ * @attrs: attributes of mapping properties requested in dma_alloc_attrs ++ * ++ * Map a coherent DMA buffer previously allocated by dma_alloc_attrs ++ * into user space. The coherent DMA buffer must not be freed by the ++ * driver until the user space mapping has been released. ++ */ ++static inline int ++dma_mmap_attrs(struct device *dev, struct vm_area_struct *vma, void *cpu_addr, ++ dma_addr_t dma_addr, size_t size, struct dma_attrs *attrs) ++{ ++ struct dma_map_ops *ops = get_dma_ops(dev); ++ BUG_ON(!ops); ++ if (ops && ops->mmap) ++ return ops->mmap(dev, vma, cpu_addr, dma_addr, size, attrs); ++ return dma_common_mmap(dev, vma, cpu_addr, dma_addr, size); ++} ++ ++#define dma_mmap_coherent(d, v, c, h, s) dma_mmap_attrs(d, v, c, h, s, NULL) ++ ++int ++dma_common_get_sgtable(struct device *dev, struct sg_table *sgt, ++ void *cpu_addr, dma_addr_t dma_addr, size_t size); ++ ++static inline int ++dma_get_sgtable_attrs(struct device *dev, struct sg_table *sgt, void *cpu_addr, ++ dma_addr_t dma_addr, size_t size, struct dma_attrs *attrs) ++{ ++ struct dma_map_ops *ops = get_dma_ops(dev); ++ BUG_ON(!ops); ++ if (ops && ops->get_sgtable) ++ return ops->get_sgtable(dev, sgt, cpu_addr, dma_addr, size, ++ attrs); ++ return dma_common_get_sgtable(dev, sgt, cpu_addr, dma_addr, size); ++} ++ ++#define dma_get_sgtable(d, t, v, h, s) dma_get_sgtable_attrs(d, t, v, h, s, NULL) ++ + + static inline int dma_supported(struct device *dev, u64 mask) + { + struct dma_map_ops *ops = get_dma_ops(dev); +- return ops->dma_supported(dev, mask); ++ if (ops) ++ return ops->dma_supported(dev, mask); ++ return plat_dma_supported(dev, mask); + } + + static inline int dma_mapping_error(struct device *dev, u64 mask) +@@ -43,7 +380,9 @@ static inline int dma_mapping_error(stru + struct dma_map_ops *ops = get_dma_ops(dev); + + debug_dma_mapping_error(dev, mask); +- return ops->mapping_error(dev, mask); ++ if (ops) ++ return ops->mapping_error(dev, mask); ++ return 0; + } + + static inline int +@@ -54,7 +393,7 @@ dma_set_mask(struct device *dev, u64 mas + if(!dev->dma_mask || !dma_supported(dev, mask)) + return -EIO; + +- if (ops->set_dma_mask) ++ if (ops && ops->set_dma_mask) + return ops->set_dma_mask(dev, mask); + + *dev->dma_mask = mask; +@@ -74,7 +413,11 @@ static inline void *dma_alloc_attrs(stru + void *ret; + struct dma_map_ops *ops = get_dma_ops(dev); + +- ret = ops->alloc(dev, size, dma_handle, gfp, attrs); ++ if (ops) ++ ret = ops->alloc(dev, size, dma_handle, gfp, attrs); ++ else ++ ret = mips_dma_alloc_coherent(dev, size, dma_handle, gfp, ++ attrs); + + debug_dma_alloc_coherent(dev, size, *dma_handle, ret); + +@@ -89,7 +432,10 @@ static inline void dma_free_attrs(struct + { + struct dma_map_ops *ops = get_dma_ops(dev); + +- ops->free(dev, size, vaddr, dma_handle, attrs); ++ if (ops) ++ ops->free(dev, size, vaddr, dma_handle, attrs); ++ else ++ mips_dma_free_coherent(dev, size, vaddr, dma_handle, attrs); + + debug_dma_free_coherent(dev, size, vaddr, dma_handle); + } +--- a/arch/mips/mm/dma-default.c ++++ b/arch/mips/mm/dma-default.c +@@ -26,7 +26,7 @@ + + #ifdef CONFIG_DMA_MAYBE_COHERENT + int coherentio = 0; /* User defined DMA coherency from command line. */ +-EXPORT_SYMBOL_GPL(coherentio); ++EXPORT_SYMBOL(coherentio); + int hw_coherentio = 0; /* Actual hardware supported DMA coherency setting. */ + + static int __init setcoherentio(char *str) +@@ -46,35 +46,6 @@ static int __init setnocoherentio(char * + early_param("nocoherentio", setnocoherentio); + #endif + +-static inline struct page *dma_addr_to_page(struct device *dev, +- dma_addr_t dma_addr) +-{ +- return pfn_to_page( +- plat_dma_addr_to_phys(dev, dma_addr) >> PAGE_SHIFT); +-} +- +-/* +- * The affected CPUs below in 'cpu_needs_post_dma_flush()' can +- * speculatively fill random cachelines with stale data at any time, +- * requiring an extra flush post-DMA. +- * +- * Warning on the terminology - Linux calls an uncached area coherent; +- * MIPS terminology calls memory areas with hardware maintained coherency +- * coherent. +- * +- * Note that the R14000 and R16000 should also be checked for in this +- * condition. However this function is only called on non-I/O-coherent +- * systems and only the R10000 and R12000 are used in such systems, the +- * SGI IP28 Indigo² rsp. SGI IP32 aka O2. +- */ +-static inline int cpu_needs_post_dma_flush(struct device *dev) +-{ +- return !plat_device_is_coherent(dev) && +- (boot_cpu_type() == CPU_R10000 || +- boot_cpu_type() == CPU_R12000 || +- boot_cpu_type() == CPU_BMIPS5000); +-} +- + static gfp_t massage_gfp_flags(const struct device *dev, gfp_t gfp) + { + gfp_t dma_flag; +@@ -130,8 +101,9 @@ void *dma_alloc_noncoherent(struct devic + } + EXPORT_SYMBOL(dma_alloc_noncoherent); + +-static void *mips_dma_alloc_coherent(struct device *dev, size_t size, +- dma_addr_t * dma_handle, gfp_t gfp, struct dma_attrs *attrs) ++void *mips_dma_alloc_coherent(struct device *dev, size_t size, ++ dma_addr_t *dma_handle, gfp_t gfp, ++ struct dma_attrs *attrs) + { + void *ret; + struct page *page = NULL; +@@ -162,6 +134,7 @@ static void *mips_dma_alloc_coherent(str + + return ret; + } ++EXPORT_SYMBOL(mips_dma_alloc_coherent); + + + void dma_free_noncoherent(struct device *dev, size_t size, void *vaddr, +@@ -172,8 +145,8 @@ void dma_free_noncoherent(struct device + } + EXPORT_SYMBOL(dma_free_noncoherent); + +-static void mips_dma_free_coherent(struct device *dev, size_t size, void *vaddr, +- dma_addr_t dma_handle, struct dma_attrs *attrs) ++void mips_dma_free_coherent(struct device *dev, size_t size, void *vaddr, ++ dma_addr_t dma_handle, struct dma_attrs *attrs) + { + unsigned long addr = (unsigned long) vaddr; + int order = get_order(size); +@@ -193,6 +166,7 @@ static void mips_dma_free_coherent(struc + if (!dma_release_from_contiguous(dev, page, count)) + __free_pages(page, get_order(size)); + } ++EXPORT_SYMBOL(mips_dma_free_coherent); + + static inline void __dma_sync_virtual(void *addr, size_t size, + enum dma_data_direction direction) +@@ -221,8 +195,8 @@ static inline void __dma_sync_virtual(vo + * If highmem is not configured then the bulk of this loop gets + * optimized out. + */ +-static inline void __dma_sync(struct page *page, +- unsigned long offset, size_t size, enum dma_data_direction direction) ++void __dma_sync(struct page *page, unsigned long offset, size_t size, ++ enum dma_data_direction direction) + { + size_t left = size; + +@@ -251,110 +225,7 @@ static inline void __dma_sync(struct pag + left -= len; + } while (left); + } +- +-static void mips_dma_unmap_page(struct device *dev, dma_addr_t dma_addr, +- size_t size, enum dma_data_direction direction, struct dma_attrs *attrs) +-{ +- if (cpu_needs_post_dma_flush(dev)) +- __dma_sync(dma_addr_to_page(dev, dma_addr), +- dma_addr & ~PAGE_MASK, size, direction); +- plat_post_dma_flush(dev); +- plat_unmap_dma_mem(dev, dma_addr, size, direction); +-} +- +-static int mips_dma_map_sg(struct device *dev, struct scatterlist *sg, +- int nents, enum dma_data_direction direction, struct dma_attrs *attrs) +-{ +- int i; +- +- for (i = 0; i < nents; i++, sg++) { +- if (!plat_device_is_coherent(dev)) +- __dma_sync(sg_page(sg), sg->offset, sg->length, +- direction); +-#ifdef CONFIG_NEED_SG_DMA_LENGTH +- sg->dma_length = sg->length; +-#endif +- sg->dma_address = plat_map_dma_mem_page(dev, sg_page(sg)) + +- sg->offset; +- } +- +- return nents; +-} +- +-static dma_addr_t mips_dma_map_page(struct device *dev, struct page *page, +- unsigned long offset, size_t size, enum dma_data_direction direction, +- struct dma_attrs *attrs) +-{ +- if (!plat_device_is_coherent(dev)) +- __dma_sync(page, offset, size, direction); +- +- return plat_map_dma_mem_page(dev, page) + offset; +-} +- +-static void mips_dma_unmap_sg(struct device *dev, struct scatterlist *sg, +- int nhwentries, enum dma_data_direction direction, +- struct dma_attrs *attrs) +-{ +- int i; +- +- for (i = 0; i < nhwentries; i++, sg++) { +- if (!plat_device_is_coherent(dev) && +- direction != DMA_TO_DEVICE) +- __dma_sync(sg_page(sg), sg->offset, sg->length, +- direction); +- plat_unmap_dma_mem(dev, sg->dma_address, sg->length, direction); +- } +-} +- +-static void mips_dma_sync_single_for_cpu(struct device *dev, +- dma_addr_t dma_handle, size_t size, enum dma_data_direction direction) +-{ +- if (cpu_needs_post_dma_flush(dev)) +- __dma_sync(dma_addr_to_page(dev, dma_handle), +- dma_handle & ~PAGE_MASK, size, direction); +- plat_post_dma_flush(dev); +-} +- +-static void mips_dma_sync_single_for_device(struct device *dev, +- dma_addr_t dma_handle, size_t size, enum dma_data_direction direction) +-{ +- if (!plat_device_is_coherent(dev)) +- __dma_sync(dma_addr_to_page(dev, dma_handle), +- dma_handle & ~PAGE_MASK, size, direction); +-} +- +-static void mips_dma_sync_sg_for_cpu(struct device *dev, +- struct scatterlist *sg, int nelems, enum dma_data_direction direction) +-{ +- int i; +- +- if (cpu_needs_post_dma_flush(dev)) +- for (i = 0; i < nelems; i++, sg++) +- __dma_sync(sg_page(sg), sg->offset, sg->length, +- direction); +- plat_post_dma_flush(dev); +-} +- +-static void mips_dma_sync_sg_for_device(struct device *dev, +- struct scatterlist *sg, int nelems, enum dma_data_direction direction) +-{ +- int i; +- +- if (!plat_device_is_coherent(dev)) +- for (i = 0; i < nelems; i++, sg++) +- __dma_sync(sg_page(sg), sg->offset, sg->length, +- direction); +-} +- +-int mips_dma_mapping_error(struct device *dev, dma_addr_t dma_addr) +-{ +- return 0; +-} +- +-int mips_dma_supported(struct device *dev, u64 mask) +-{ +- return plat_dma_supported(dev, mask); +-} ++EXPORT_SYMBOL(__dma_sync); + + void dma_cache_sync(struct device *dev, void *vaddr, size_t size, + enum dma_data_direction direction) +@@ -367,23 +238,10 @@ void dma_cache_sync(struct device *dev, + + EXPORT_SYMBOL(dma_cache_sync); + +-static struct dma_map_ops mips_default_dma_map_ops = { +- .alloc = mips_dma_alloc_coherent, +- .free = mips_dma_free_coherent, +- .map_page = mips_dma_map_page, +- .unmap_page = mips_dma_unmap_page, +- .map_sg = mips_dma_map_sg, +- .unmap_sg = mips_dma_unmap_sg, +- .sync_single_for_cpu = mips_dma_sync_single_for_cpu, +- .sync_single_for_device = mips_dma_sync_single_for_device, +- .sync_sg_for_cpu = mips_dma_sync_sg_for_cpu, +- .sync_sg_for_device = mips_dma_sync_sg_for_device, +- .mapping_error = mips_dma_mapping_error, +- .dma_supported = mips_dma_supported +-}; +- +-struct dma_map_ops *mips_dma_map_ops = &mips_default_dma_map_ops; ++#ifdef CONFIG_SYS_HAS_DMA_OPS ++struct dma_map_ops *mips_dma_map_ops = NULL; + EXPORT_SYMBOL(mips_dma_map_ops); ++#endif + + #define PREALLOC_DMA_DEBUG_ENTRIES (1 << 16) + diff --git a/target/linux/generic/patches-4.1/140-mtd-part-add-generic-parsing-of-linux-part-probe.patch b/target/linux/generic/patches-4.1/140-mtd-part-add-generic-parsing-of-linux-part-probe.patch new file mode 100644 index 0000000..18ec833 --- /dev/null +++ b/target/linux/generic/patches-4.1/140-mtd-part-add-generic-parsing-of-linux-part-probe.patch @@ -0,0 +1,175 @@ +From 173b0add0cff6558f950c0cb1eacfb729d482711 Mon Sep 17 00:00:00 2001 +From: Hauke Mehrtens +Date: Sun, 17 May 2015 18:48:38 +0200 +Subject: [PATCH 4/8] mtd: part: add generic parsing of linux,part-probe + +This moves the linux,part-probe device tree parsing code from +physmap_of.c to mtdpart.c. Now all drivers can use this feature by just +providing a reference to their device tree node in struct +mtd_part_parser_data. + +Signed-off-by: Hauke Mehrtens +--- + Documentation/devicetree/bindings/mtd/nand.txt | 16 ++++++++++ + drivers/mtd/maps/physmap_of.c | 40 +----------------------- + drivers/mtd/mtdpart.c | 43 ++++++++++++++++++++++++++ + 3 files changed, 60 insertions(+), 39 deletions(-) + +--- a/Documentation/devicetree/bindings/mtd/nand.txt ++++ b/Documentation/devicetree/bindings/mtd/nand.txt +@@ -12,6 +12,22 @@ + - nand-ecc-step-size: integer representing the number of data bytes + that are covered by a single ECC step. + ++- linux,part-probe: list of name as strings of the partition parser ++ which should be used to parse the partition table. ++ They will be tried in the specified ordering and ++ the next one will be used if the previous one ++ failed. ++ ++ Example: linux,part-probe = "cmdlinepart", "ofpart"; ++ ++ This is also the default value, which will be used ++ if this attribute is not specified. It could be ++ that the flash driver in use overwrote the default ++ value and uses some other default. ++ ++ Possible values are: bcm47xxpart, afs, ar7part, ++ ofoldpart, ofpart, bcm63xxpart, RedBoot, cmdlinepart ++ + The ECC strength and ECC step size properties define the correction capability + of a controller. Together, they say a controller can correct "{strength} bit + errors per {size} bytes". +--- a/drivers/mtd/maps/physmap_of.c ++++ b/drivers/mtd/maps/physmap_of.c +@@ -112,45 +112,9 @@ static struct mtd_info *obsolete_probe(s + static const char * const part_probe_types_def[] = { + "cmdlinepart", "RedBoot", "ofpart", "ofoldpart", NULL }; + +-static const char * const *of_get_probes(struct device_node *dp) +-{ +- const char *cp; +- int cplen; +- unsigned int l; +- unsigned int count; +- const char **res; +- +- cp = of_get_property(dp, "linux,part-probe", &cplen); +- if (cp == NULL) +- return part_probe_types_def; +- +- count = 0; +- for (l = 0; l != cplen; l++) +- if (cp[l] == 0) +- count++; +- +- res = kzalloc((count + 1)*sizeof(*res), GFP_KERNEL); +- count = 0; +- while (cplen > 0) { +- res[count] = cp; +- l = strlen(cp) + 1; +- cp += l; +- cplen -= l; +- count++; +- } +- return res; +-} +- +-static void of_free_probes(const char * const *probes) +-{ +- if (probes != part_probe_types_def) +- kfree(probes); +-} +- + static struct of_device_id of_flash_match[]; + static int of_flash_probe(struct platform_device *dev) + { +- const char * const *part_probe_types; + const struct of_device_id *match; + struct device_node *dp = dev->dev.of_node; + struct resource res; +@@ -310,10 +274,8 @@ static int of_flash_probe(struct platfor + goto err_out; + + ppdata.of_node = dp; +- part_probe_types = of_get_probes(dp); +- mtd_device_parse_register(info->cmtd, part_probe_types, &ppdata, ++ mtd_device_parse_register(info->cmtd, part_probe_types_def, &ppdata, + NULL, 0); +- of_free_probes(part_probe_types); + + kfree(mtd_list); + +--- a/drivers/mtd/mtdpart.c ++++ b/drivers/mtd/mtdpart.c +@@ -29,6 +29,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -719,6 +720,40 @@ void deregister_mtd_parser(struct mtd_pa + EXPORT_SYMBOL_GPL(deregister_mtd_parser); + + /* ++ * Parses the linux,part-probe device tree property. ++ * When a non null value is returned it has to be freed with kfree() by ++ * the caller. ++ */ ++static const char * const *of_get_probes(struct device_node *dp) ++{ ++ const char *cp; ++ int cplen; ++ unsigned int l; ++ unsigned int count; ++ const char **res; ++ ++ cp = of_get_property(dp, "linux,part-probe", &cplen); ++ if (cp == NULL) ++ return NULL; ++ ++ count = 0; ++ for (l = 0; l != cplen; l++) ++ if (cp[l] == 0) ++ count++; ++ ++ res = kzalloc((count + 1) * sizeof(*res), GFP_KERNEL); ++ count = 0; ++ while (cplen > 0) { ++ res[count] = cp; ++ l = strlen(cp) + 1; ++ cp += l; ++ cplen -= l; ++ count++; ++ } ++ return res; ++} ++ ++/* + * Do not forget to update 'parse_mtd_partitions()' kerneldoc comment if you + * are changing this array! + */ +@@ -754,6 +789,13 @@ int parse_mtd_partitions(struct mtd_info + { + struct mtd_part_parser *parser; + int ret = 0; ++ const char *const *types_of = NULL; ++ ++ if (data && data->of_node) { ++ types_of = of_get_probes(data->of_node); ++ if (types_of != NULL) ++ types = types_of; ++ } + + if (!types) + types = default_mtd_part_types; +@@ -772,6 +814,7 @@ int parse_mtd_partitions(struct mtd_info + break; + } + } ++ kfree(types_of); + return ret; + } + diff --git a/target/linux/generic/patches-4.1/180-usb-xhci-make-USB_XHCI_PLATFORM-selectable.patch b/target/linux/generic/patches-4.1/180-usb-xhci-make-USB_XHCI_PLATFORM-selectable.patch new file mode 100644 index 0000000..a17e398 --- /dev/null +++ b/target/linux/generic/patches-4.1/180-usb-xhci-make-USB_XHCI_PLATFORM-selectable.patch @@ -0,0 +1,41 @@ +From 9612e686b235dc9e33c8dfb5e6d2ff2b2140fb9d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Tue, 16 Jun 2015 21:01:30 +0200 +Subject: [PATCH V2] usb: xhci: make USB_XHCI_PLATFORM selectable +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Right now xhci-plat-hcd can be built when using one of platform specific +drivers only (mvebu/rcar). There shouldn't be such limitation as some +platforms may not require any quirks and may want to just use a generic +driver ("generic-xhci" / "xhci-hcd"). + +Signed-off-by: Rafał Miłecki +--- +Greg/Mathias: I'm not sure if it's more like USB subsystem stuff or xHCI +Could you decide which one of you could pick that, please? + +V2: Drop useless "default n", thanks Sergei :) +--- + drivers/usb/host/Kconfig | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +--- a/drivers/usb/host/Kconfig ++++ b/drivers/usb/host/Kconfig +@@ -32,7 +32,14 @@ config USB_XHCI_PCI + default y + + config USB_XHCI_PLATFORM +- tristate ++ tristate "Generic xHCI driver for a platform device" ++ ---help--- ++ Adds an xHCI host driver for a generic platform device, which ++ provides a memory space and an irq. ++ It is also a prerequisite for platform specific drivers that ++ implement some extra quirks. ++ ++ If unsure, say N. + + config USB_XHCI_MVEBU + tristate "xHCI support for Marvell Armada 375/38x" diff --git a/target/linux/generic/patches-4.1/190-cdc_ncm_add_support_for_moving_ndp_to_end_of_ncm_frame.patch b/target/linux/generic/patches-4.1/190-cdc_ncm_add_support_for_moving_ndp_to_end_of_ncm_frame.patch new file mode 100644 index 0000000..09cbe0c --- /dev/null +++ b/target/linux/generic/patches-4.1/190-cdc_ncm_add_support_for_moving_ndp_to_end_of_ncm_frame.patch @@ -0,0 +1,228 @@ +From 4a0e3e989d66bb7204b163d9cfaa7fa96d0f2023 Mon Sep 17 00:00:00 2001 +From: Enrico Mioso +Date: Wed, 8 Jul 2015 13:05:57 +0200 +Subject: [PATCH] cdc_ncm: Add support for moving NDP to end of NCM frame + +NCM specs are not actually mandating a specific position in the frame for +the NDP (Network Datagram Pointer). However, some Huawei devices will +ignore our aggregates if it is not placed after the datagrams it points +to. Add support for doing just this, in a per-device configurable way. +While at it, update NCM subdrivers, disabling this functionality in all of +them, except in huawei_cdc_ncm where it is enabled instead. +We aren't making any distinction between different Huawei NCM devices, +based on what the vendor driver does. Standard NCM devices are left +unaffected: if they are compliant, they should be always usable, still +stay on the safe side. + +This change has been tested and working with a Huawei E3131 device (which +works regardless of NDP position), a Huawei E3531 (also working both +ways) and an E3372 (which mandates NDP to be after indexed datagrams). + +V1->V2: +- corrected wrong NDP acronym definition +- fixed possible NULL pointer dereference +- patch cleanup +V2->V3: +- Properly account for the NDP size when writing new packets to SKB + +Signed-off-by: Enrico Mioso +Signed-off-by: David S. Miller +--- + drivers/net/usb/cdc_mbim.c | 2 +- + drivers/net/usb/cdc_ncm.c | 61 ++++++++++++++++++++++++++++++++++++---- + drivers/net/usb/huawei_cdc_ncm.c | 7 +++-- + include/linux/usb/cdc_ncm.h | 7 ++++- + 4 files changed, 67 insertions(+), 10 deletions(-) + +--- a/drivers/net/usb/cdc_mbim.c ++++ b/drivers/net/usb/cdc_mbim.c +@@ -158,7 +158,7 @@ static int cdc_mbim_bind(struct usbnet * + if (!cdc_ncm_comm_intf_is_mbim(intf->cur_altsetting)) + goto err; + +- ret = cdc_ncm_bind_common(dev, intf, data_altsetting); ++ ret = cdc_ncm_bind_common(dev, intf, data_altsetting, 0); + if (ret) + goto err; + +--- a/drivers/net/usb/cdc_ncm.c ++++ b/drivers/net/usb/cdc_ncm.c +@@ -684,10 +684,12 @@ static void cdc_ncm_free(struct cdc_ncm_ + ctx->tx_curr_skb = NULL; + } + ++ kfree(ctx->delayed_ndp16); ++ + kfree(ctx); + } + +-int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_altsetting) ++int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_altsetting, int drvflags) + { + const struct usb_cdc_union_desc *union_desc = NULL; + struct cdc_ncm_ctx *ctx; +@@ -855,6 +857,17 @@ advance: + /* finish setting up the device specific data */ + cdc_ncm_setup(dev); + ++ /* Device-specific flags */ ++ ctx->drvflags = drvflags; ++ ++ /* Allocate the delayed NDP if needed. */ ++ if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END) { ++ ctx->delayed_ndp16 = kzalloc(ctx->max_ndp_size, GFP_KERNEL); ++ if (!ctx->delayed_ndp16) ++ goto error2; ++ dev_info(&intf->dev, "NDP will be placed at end of frame for this device."); ++ } ++ + /* override ethtool_ops */ + dev->net->ethtool_ops = &cdc_ncm_ethtool_ops; + +@@ -954,8 +967,11 @@ static int cdc_ncm_bind(struct usbnet *d + if (cdc_ncm_select_altsetting(intf) != CDC_NCM_COMM_ALTSETTING_NCM) + return -ENODEV; + +- /* The NCM data altsetting is fixed */ +- ret = cdc_ncm_bind_common(dev, intf, CDC_NCM_DATA_ALTSETTING_NCM); ++ /* The NCM data altsetting is fixed, so we hard-coded it. ++ * Additionally, generic NCM devices are assumed to accept arbitrarily ++ * placed NDP. ++ */ ++ ret = cdc_ncm_bind_common(dev, intf, CDC_NCM_DATA_ALTSETTING_NCM, 0); + + /* + * We should get an event when network connection is "connected" or +@@ -986,6 +1002,14 @@ static struct usb_cdc_ncm_ndp16 *cdc_ncm + struct usb_cdc_ncm_nth16 *nth16 = (void *)skb->data; + size_t ndpoffset = le16_to_cpu(nth16->wNdpIndex); + ++ /* If NDP should be moved to the end of the NCM package, we can't follow the ++ * NTH16 header as we would normally do. NDP isn't written to the SKB yet, and ++ * the wNdpIndex field in the header is actually not consistent with reality. It will be later. ++ */ ++ if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END) ++ if (ctx->delayed_ndp16->dwSignature == sign) ++ return ctx->delayed_ndp16; ++ + /* follow the chain of NDPs, looking for a match */ + while (ndpoffset) { + ndp16 = (struct usb_cdc_ncm_ndp16 *)(skb->data + ndpoffset); +@@ -995,7 +1019,8 @@ static struct usb_cdc_ncm_ndp16 *cdc_ncm + } + + /* align new NDP */ +- cdc_ncm_align_tail(skb, ctx->tx_ndp_modulus, 0, ctx->tx_max); ++ if (!(ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END)) ++ cdc_ncm_align_tail(skb, ctx->tx_ndp_modulus, 0, ctx->tx_max); + + /* verify that there is room for the NDP and the datagram (reserve) */ + if ((ctx->tx_max - skb->len - reserve) < ctx->max_ndp_size) +@@ -1008,7 +1033,11 @@ static struct usb_cdc_ncm_ndp16 *cdc_ncm + nth16->wNdpIndex = cpu_to_le16(skb->len); + + /* push a new empty NDP */ +- ndp16 = (struct usb_cdc_ncm_ndp16 *)memset(skb_put(skb, ctx->max_ndp_size), 0, ctx->max_ndp_size); ++ if (!(ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END)) ++ ndp16 = (struct usb_cdc_ncm_ndp16 *)memset(skb_put(skb, ctx->max_ndp_size), 0, ctx->max_ndp_size); ++ else ++ ndp16 = ctx->delayed_ndp16; ++ + ndp16->dwSignature = sign; + ndp16->wLength = cpu_to_le16(sizeof(struct usb_cdc_ncm_ndp16) + sizeof(struct usb_cdc_ncm_dpe16)); + return ndp16; +@@ -1023,6 +1052,15 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev + struct sk_buff *skb_out; + u16 n = 0, index, ndplen; + u8 ready2send = 0; ++ u32 delayed_ndp_size; ++ ++ /* When our NDP gets written in cdc_ncm_ndp(), then skb_out->len gets updated ++ * accordingly. Otherwise, we should check here. ++ */ ++ if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END) ++ delayed_ndp_size = ctx->max_ndp_size; ++ else ++ delayed_ndp_size = 0; + + /* if there is a remaining skb, it gets priority */ + if (skb != NULL) { +@@ -1077,7 +1115,7 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev + cdc_ncm_align_tail(skb_out, ctx->tx_modulus, ctx->tx_remainder, ctx->tx_max); + + /* check if we had enough room left for both NDP and frame */ +- if (!ndp16 || skb_out->len + skb->len > ctx->tx_max) { ++ if (!ndp16 || skb_out->len + skb->len + delayed_ndp_size > ctx->tx_max) { + if (n == 0) { + /* won't fit, MTU problem? */ + dev_kfree_skb_any(skb); +@@ -1150,6 +1188,17 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev + /* variables will be reset at next call */ + } + ++ /* If requested, put NDP at end of frame. */ ++ if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END) { ++ nth16 = (struct usb_cdc_ncm_nth16 *)skb_out->data; ++ cdc_ncm_align_tail(skb_out, ctx->tx_ndp_modulus, 0, ctx->tx_max); ++ nth16->wNdpIndex = cpu_to_le16(skb_out->len); ++ memcpy(skb_put(skb_out, ctx->max_ndp_size), ctx->delayed_ndp16, ctx->max_ndp_size); ++ ++ /* Zero out delayed NDP - signature checking will naturally fail. */ ++ ndp16 = memset(ctx->delayed_ndp16, 0, ctx->max_ndp_size); ++ } ++ + /* If collected data size is less or equal ctx->min_tx_pkt + * bytes, we send buffers as it is. If we get more data, it + * would be more efficient for USB HS mobile device with DMA +--- a/drivers/net/usb/huawei_cdc_ncm.c ++++ b/drivers/net/usb/huawei_cdc_ncm.c +@@ -73,11 +73,14 @@ static int huawei_cdc_ncm_bind(struct us + struct usb_driver *subdriver = ERR_PTR(-ENODEV); + int ret = -ENODEV; + struct huawei_cdc_ncm_state *drvstate = (void *)&usbnet_dev->data; ++ int drvflags = 0; + + /* altsetting should always be 1 for NCM devices - so we hard-coded +- * it here ++ * it here. Some huawei devices will need the NDP part of the NCM package to ++ * be at the end of the frame. + */ +- ret = cdc_ncm_bind_common(usbnet_dev, intf, 1); ++ drvflags |= CDC_NCM_FLAG_NDP_TO_END; ++ ret = cdc_ncm_bind_common(usbnet_dev, intf, 1, drvflags); + if (ret) + goto err; + +--- a/include/linux/usb/cdc_ncm.h ++++ b/include/linux/usb/cdc_ncm.h +@@ -80,6 +80,9 @@ + #define CDC_NCM_TIMER_INTERVAL_MIN 5UL + #define CDC_NCM_TIMER_INTERVAL_MAX (U32_MAX / NSEC_PER_USEC) + ++/* Driver flags */ ++#define CDC_NCM_FLAG_NDP_TO_END 0x02 /* NDP is placed at end of frame */ ++ + #define cdc_ncm_comm_intf_is_mbim(x) ((x)->desc.bInterfaceSubClass == USB_CDC_SUBCLASS_MBIM && \ + (x)->desc.bInterfaceProtocol == USB_CDC_PROTO_NONE) + #define cdc_ncm_data_intf_is_mbim(x) ((x)->desc.bInterfaceProtocol == USB_CDC_MBIM_PROTO_NTB) +@@ -103,9 +106,11 @@ struct cdc_ncm_ctx { + + spinlock_t mtx; + atomic_t stop; ++ int drvflags; + + u32 timer_interval; + u32 max_ndp_size; ++ struct usb_cdc_ncm_ndp16 *delayed_ndp16; + + u32 tx_timer_pending; + u32 tx_curr_frame_num; +@@ -133,7 +138,7 @@ struct cdc_ncm_ctx { + }; + + u8 cdc_ncm_select_altsetting(struct usb_interface *intf); +-int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_altsetting); ++int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_altsetting, int drvflags); + void cdc_ncm_unbind(struct usbnet *dev, struct usb_interface *intf); + struct sk_buff *cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign); + int cdc_ncm_rx_verify_nth16(struct cdc_ncm_ctx *ctx, struct sk_buff *skb_in); diff --git a/target/linux/generic/patches-4.1/191-usb-ehci-orion-fix-probe-for-GENERIC_PHY.patch b/target/linux/generic/patches-4.1/191-usb-ehci-orion-fix-probe-for-GENERIC_PHY.patch new file mode 100644 index 0000000..fce5d29 --- /dev/null +++ b/target/linux/generic/patches-4.1/191-usb-ehci-orion-fix-probe-for-GENERIC_PHY.patch @@ -0,0 +1,35 @@ +From a95f03e51471dbdbafd3391991d867ac2358ed02 Mon Sep 17 00:00:00 2001 +From: Jonas Gorski +Date: Sun, 23 Aug 2015 14:23:29 +0200 +Subject: [PATCH] usb: ehci-orion: fix probe for !GENERIC_PHY + +Commit d445913ce0ab7f ("usb: ehci-orion: add optional PHY support") +added support for optional phys, but devm_phy_optional_get returns +-ENOSYS if GENERIC_PHY is not enabled. + +This causes probe failures, even when there are no phys specified: + +[ 1.443365] orion-ehci f1058000.usb: init f1058000.usb fail, -38 +[ 1.449403] orion-ehci: probe of f1058000.usb failed with error -38 + +Similar to dwc3, treat -ENOSYS as no phy. + +Fixes: d445913ce0ab7f ("usb: ehci-orion: add optional PHY support") + +Signed-off-by: Jonas Gorski +--- + drivers/usb/host/ehci-orion.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/usb/host/ehci-orion.c ++++ b/drivers/usb/host/ehci-orion.c +@@ -224,7 +224,8 @@ static int ehci_orion_drv_probe(struct p + priv->phy = devm_phy_optional_get(&pdev->dev, "usb"); + if (IS_ERR(priv->phy)) { + err = PTR_ERR(priv->phy); +- goto err_phy_get; ++ if (err != -ENOSYS) ++ goto err_phy_get; + } else { + err = phy_init(priv->phy); + if (err) diff --git a/target/linux/generic/patches-4.1/200-fix_localversion.patch b/target/linux/generic/patches-4.1/200-fix_localversion.patch new file mode 100644 index 0000000..70228bb --- /dev/null +++ b/target/linux/generic/patches-4.1/200-fix_localversion.patch @@ -0,0 +1,11 @@ +--- a/scripts/setlocalversion ++++ b/scripts/setlocalversion +@@ -165,7 +165,7 @@ else + # annotated or signed tagged state (as git describe only + # looks at signed or annotated tags - git tag -a/-s) and + # LOCALVERSION= is not specified +- if test "${LOCALVERSION+set}" != "set"; then ++ if test "${CONFIG_LOCALVERSION+set}" != "set"; then + scm=$(scm_version --short) + res="$res${scm:++}" + fi diff --git a/target/linux/generic/patches-4.1/201-extra_optimization.patch b/target/linux/generic/patches-4.1/201-extra_optimization.patch new file mode 100644 index 0000000..34ded8c --- /dev/null +++ b/target/linux/generic/patches-4.1/201-extra_optimization.patch @@ -0,0 +1,14 @@ +--- a/Makefile ++++ b/Makefile +@@ -612,9 +612,9 @@ include arch/$(SRCARCH)/Makefile + KBUILD_CFLAGS += $(call cc-option,-fno-delete-null-pointer-checks,) + + ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE +-KBUILD_CFLAGS += -Os $(call cc-disable-warning,maybe-uninitialized,) ++KBUILD_CFLAGS += -Os $(EXTRA_OPTIMIZATION) $(call cc-disable-warning,maybe-uninitialized,) + else +-KBUILD_CFLAGS += -O2 ++KBUILD_CFLAGS += -O2 -fno-reorder-blocks -fno-tree-ch $(EXTRA_OPTIMIZATION) + endif + + # Tell gcc to never replace conditional load with a non-conditional one diff --git a/target/linux/generic/patches-4.1/202-reduce_module_size.patch b/target/linux/generic/patches-4.1/202-reduce_module_size.patch new file mode 100644 index 0000000..60ea5c2 --- /dev/null +++ b/target/linux/generic/patches-4.1/202-reduce_module_size.patch @@ -0,0 +1,11 @@ +--- a/Makefile ++++ b/Makefile +@@ -408,7 +408,7 @@ KBUILD_CFLAGS_KERNEL := + KBUILD_AFLAGS := -D__ASSEMBLY__ + KBUILD_AFLAGS_MODULE := -DMODULE + KBUILD_CFLAGS_MODULE := -DMODULE +-KBUILD_LDFLAGS_MODULE := -T $(srctree)/scripts/module-common.lds ++KBUILD_LDFLAGS_MODULE = -T $(srctree)/scripts/module-common.lds $(if $(CONFIG_PROFILING),,-s) + + # Read KERNELRELEASE from include/config/kernel.release (if it exists) + KERNELRELEASE = $(shell cat include/config/kernel.release 2> /dev/null) diff --git a/target/linux/generic/patches-4.1/203-kallsyms_uncompressed.patch b/target/linux/generic/patches-4.1/203-kallsyms_uncompressed.patch new file mode 100644 index 0000000..10cfc83 --- /dev/null +++ b/target/linux/generic/patches-4.1/203-kallsyms_uncompressed.patch @@ -0,0 +1,108 @@ +--- a/scripts/kallsyms.c ++++ b/scripts/kallsyms.c +@@ -58,6 +58,7 @@ static struct addr_range percpu_range = + static struct sym_entry *table; + static unsigned int table_size, table_cnt; + static int all_symbols = 0; ++static int uncompressed = 0; + static int absolute_percpu = 0; + static char symbol_prefix_char = '\0'; + static unsigned long long kernel_start_addr = 0; +@@ -403,6 +404,9 @@ static void write_src(void) + + free(markers); + ++ if (uncompressed) ++ return; ++ + output_label("kallsyms_token_table"); + off = 0; + for (i = 0; i < 256; i++) { +@@ -461,6 +465,9 @@ static void *find_token(unsigned char *s + { + int i; + ++ if (uncompressed) ++ return NULL; ++ + for (i = 0; i < len - 1; i++) { + if (str[i] == token[0] && str[i+1] == token[1]) + return &str[i]; +@@ -533,6 +540,9 @@ static void optimize_result(void) + { + int i, best; + ++ if (uncompressed) ++ return; ++ + /* using the '\0' symbol last allows compress_symbols to use standard + * fast string functions */ + for (i = 255; i >= 0; i--) { +@@ -703,7 +713,9 @@ int main(int argc, char **argv) + } else if (strncmp(argv[i], "--page-offset=", 14) == 0) { + const char *p = &argv[i][14]; + kernel_start_addr = strtoull(p, NULL, 16); +- } else ++ } else if (strcmp(argv[i], "--uncompressed") == 0) ++ uncompressed = 1; ++ else + usage(); + } + } else if (argc != 1) +--- a/init/Kconfig ++++ b/init/Kconfig +@@ -1334,6 +1334,17 @@ config SYSCTL_ARCH_UNALIGN_ALLOW + the unaligned access emulation. + see arch/parisc/kernel/unaligned.c for reference + ++config KALLSYMS_UNCOMPRESSED ++ bool "Keep kallsyms uncompressed" ++ depends on KALLSYMS ++ help ++ Normally kallsyms contains compressed symbols (using a token table), ++ reducing the uncompressed kernel image size. Keeping the symbol table ++ uncompressed significantly improves the size of this part in compressed ++ kernel images. ++ ++ Say N unless you need compressed kernel images to be small. ++ + config HAVE_PCSPKR_PLATFORM + bool + +--- a/scripts/link-vmlinux.sh ++++ b/scripts/link-vmlinux.sh +@@ -90,6 +90,10 @@ kallsyms() + kallsymopt="${kallsymopt} --absolute-percpu" + fi + ++ if [ -n "${CONFIG_KALLSYMS_UNCOMPRESSED}" ]; then ++ kallsymopt="${kallsymopt} --uncompressed" ++ fi ++ + local aflags="${KBUILD_AFLAGS} ${KBUILD_AFLAGS_KERNEL} \ + ${NOSTDINC_FLAGS} ${LINUXINCLUDE} ${KBUILD_CPPFLAGS}" + +--- a/kernel/kallsyms.c ++++ b/kernel/kallsyms.c +@@ -109,6 +109,11 @@ static unsigned int kallsyms_expand_symb + * For every byte on the compressed symbol data, copy the table + * entry for that byte. + */ ++#ifdef CONFIG_KALLSYMS_UNCOMPRESSED ++ memcpy(result, data + 1, len - 1); ++ result += len - 1; ++ len = 0; ++#endif + while (len) { + tptr = &kallsyms_token_table[kallsyms_token_index[*data]]; + data++; +@@ -141,6 +146,9 @@ tail: + */ + static char kallsyms_get_symbol_type(unsigned int off) + { ++#ifdef CONFIG_KALLSYMS_UNCOMPRESSED ++ return kallsyms_names[off + 1]; ++#endif + /* + * Get just the first code, look it up in the token table, + * and return the first char from this token. diff --git a/target/linux/generic/patches-4.1/204-module_strip.patch b/target/linux/generic/patches-4.1/204-module_strip.patch new file mode 100644 index 0000000..0fdc8e1 --- /dev/null +++ b/target/linux/generic/patches-4.1/204-module_strip.patch @@ -0,0 +1,194 @@ +From: Felix Fietkau +Subject: [PATCH] build: add a hack for removing non-essential module info + +Signed-off-by: Felix Fietkau +--- +--- a/include/linux/module.h ++++ b/include/linux/module.h +@@ -84,9 +84,10 @@ void trim_init_extable(struct module *m) + + /* Generic info of form tag = "info" */ + #define MODULE_INFO(tag, info) __MODULE_INFO(tag, tag, info) ++#define MODULE_INFO_STRIP(tag, info) __MODULE_INFO_STRIP(tag, tag, info) + + /* For userspace: you can also call me... */ +-#define MODULE_ALIAS(_alias) MODULE_INFO(alias, _alias) ++#define MODULE_ALIAS(_alias) MODULE_INFO_STRIP(alias, _alias) + + /* Soft module dependencies. See man modprobe.d for details. + * Example: MODULE_SOFTDEP("pre: module-foo module-bar post: module-baz") +@@ -127,12 +128,12 @@ void trim_init_extable(struct module *m) + * Author(s), use "Name " or just "Name", for multiple + * authors use multiple MODULE_AUTHOR() statements/lines. + */ +-#define MODULE_AUTHOR(_author) MODULE_INFO(author, _author) ++#define MODULE_AUTHOR(_author) MODULE_INFO_STRIP(author, _author) + + /* What your module does. */ +-#define MODULE_DESCRIPTION(_description) MODULE_INFO(description, _description) ++#define MODULE_DESCRIPTION(_description) MODULE_INFO_STRIP(description, _description) + +-#ifdef MODULE ++#if defined(MODULE) && !defined(CONFIG_MODULE_STRIPPED) + /* Creates an alias so file2alias.c can find device table. */ + #define MODULE_DEVICE_TABLE(type, name) \ + extern const typeof(name) __mod_##type##__##name##_device_table \ +@@ -159,7 +160,9 @@ extern const typeof(name) __mod_##type## + */ + + #if defined(MODULE) || !defined(CONFIG_SYSFS) +-#define MODULE_VERSION(_version) MODULE_INFO(version, _version) ++#define MODULE_VERSION(_version) MODULE_INFO_STRIP(version, _version) ++#elif defined(CONFIG_MODULE_STRIPPED) ++#define MODULE_VERSION(_version) __MODULE_INFO_DISABLED(version) + #else + #define MODULE_VERSION(_version) \ + static struct module_version_attribute ___modver_attr = { \ +@@ -181,7 +184,7 @@ extern const typeof(name) __mod_##type## + /* Optional firmware file (or files) needed by the module + * format is simply firmware file name. Multiple firmware + * files require multiple MODULE_FIRMWARE() specifiers */ +-#define MODULE_FIRMWARE(_firmware) MODULE_INFO(firmware, _firmware) ++#define MODULE_FIRMWARE(_firmware) MODULE_INFO_STRIP(firmware, _firmware) + + /* Given an address, look for it in the exception tables */ + const struct exception_table_entry *search_exception_tables(unsigned long add); +--- a/include/linux/moduleparam.h ++++ b/include/linux/moduleparam.h +@@ -16,6 +16,16 @@ + /* Chosen so that structs with an unsigned long line up. */ + #define MAX_PARAM_PREFIX_LEN (64 - sizeof(unsigned long)) + ++/* This struct is here for syntactic coherency, it is not used */ ++#define __MODULE_INFO_DISABLED(name) \ ++ struct __UNIQUE_ID(name) {} ++ ++#ifdef CONFIG_MODULE_STRIPPED ++#define __MODULE_INFO_STRIP(tag, name, info) __MODULE_INFO_DISABLED(name) ++#else ++#define __MODULE_INFO_STRIP(tag, name, info) __MODULE_INFO(tag, name, info) ++#endif ++ + #ifdef MODULE + #define __MODULE_INFO(tag, name, info) \ + static const char __UNIQUE_ID(name)[] \ +@@ -23,8 +33,7 @@ static const char __UNIQUE_ID(name)[] + = __stringify(tag) "=" info + #else /* !MODULE */ + /* This struct is here for syntactic coherency, it is not used */ +-#define __MODULE_INFO(tag, name, info) \ +- struct __UNIQUE_ID(name) {} ++#define __MODULE_INFO(tag, name, info) __MODULE_INFO_DISABLED(name) + #endif + #define __MODULE_PARM_TYPE(name, _type) \ + __MODULE_INFO(parmtype, name##type, #name ":" _type) +@@ -32,7 +41,7 @@ static const char __UNIQUE_ID(name)[] + /* One for each parameter, describing how to use it. Some files do + multiple of these per line, so can't just use MODULE_INFO. */ + #define MODULE_PARM_DESC(_parm, desc) \ +- __MODULE_INFO(parm, _parm, #_parm ":" desc) ++ __MODULE_INFO_STRIP(parm, _parm, #_parm ":" desc) + + struct kernel_param; + +--- a/init/Kconfig ++++ b/init/Kconfig +@@ -1998,6 +1998,13 @@ config MODULE_COMPRESS_XZ + + endchoice + ++config MODULE_STRIPPED ++ bool "Reduce module size" ++ depends on MODULES ++ help ++ Remove module parameter descriptions, author info, version, aliases, ++ device tables, etc. ++ + endif # MODULES + + config INIT_ALL_POSSIBLE +--- a/kernel/module.c ++++ b/kernel/module.c +@@ -2681,6 +2681,7 @@ static struct module *setup_load_info(st + + static int check_modinfo(struct module *mod, struct load_info *info, int flags) + { ++#ifndef CONFIG_MODULE_STRIPPED + const char *modmagic = get_modinfo(info, "vermagic"); + int err; + +@@ -2706,6 +2707,7 @@ static int check_modinfo(struct module * + pr_warn("%s: module is from the staging directory, the quality " + "is unknown, you have been warned.\n", mod->name); + } ++#endif + + /* Set up license info based on the info section */ + set_license(mod, get_modinfo(info, "license")); +--- a/scripts/mod/modpost.c ++++ b/scripts/mod/modpost.c +@@ -1959,7 +1959,9 @@ static void read_symbols(char *modname) + symname = remove_dot(info.strtab + sym->st_name); + + handle_modversions(mod, &info, sym, symname); ++#ifndef CONFIG_MODULE_STRIPPED + handle_moddevtable(mod, &info, sym, symname); ++#endif + } + if (!is_vmlinux(modname) || + (is_vmlinux(modname) && vmlinux_section_warnings)) +@@ -2103,7 +2105,9 @@ static void add_header(struct buffer *b, + buf_printf(b, "#include \n"); + buf_printf(b, "#include \n"); + buf_printf(b, "\n"); ++#ifndef CONFIG_MODULE_STRIPPED + buf_printf(b, "MODULE_INFO(vermagic, VERMAGIC_STRING);\n"); ++#endif + buf_printf(b, "\n"); + buf_printf(b, "__visible struct module __this_module\n"); + buf_printf(b, "__attribute__((section(\".gnu.linkonce.this_module\"))) = {\n"); +@@ -2120,16 +2124,20 @@ static void add_header(struct buffer *b, + + static void add_intree_flag(struct buffer *b, int is_intree) + { ++#ifndef CONFIG_MODULE_STRIPPED + if (is_intree) + buf_printf(b, "\nMODULE_INFO(intree, \"Y\");\n"); ++#endif + } + + static void add_staging_flag(struct buffer *b, const char *name) + { ++#ifndef CONFIG_MODULE_STRIPPED + static const char *staging_dir = "drivers/staging"; + + if (strncmp(staging_dir, name, strlen(staging_dir)) == 0) + buf_printf(b, "\nMODULE_INFO(staging, \"Y\");\n"); ++#endif + } + + /** +@@ -2222,11 +2230,13 @@ static void add_depends(struct buffer *b + + static void add_srcversion(struct buffer *b, struct module *mod) + { ++#ifndef CONFIG_MODULE_STRIPPED + if (mod->srcversion[0]) { + buf_printf(b, "\n"); + buf_printf(b, "MODULE_INFO(srcversion, \"%s\");\n", + mod->srcversion); + } ++#endif + } + + static void write_if_changed(struct buffer *b, const char *fname) +@@ -2457,7 +2467,9 @@ int main(int argc, char **argv) + add_staging_flag(&buf, mod->name); + err |= add_versions(&buf, mod); + add_depends(&buf, mod, modules); ++#ifndef CONFIG_MODULE_STRIPPED + add_moddevtable(&buf, mod); ++#endif + add_srcversion(&buf, mod); + + sprintf(fname, "%s.mod.c", mod->name); diff --git a/target/linux/generic/patches-4.1/205-backtrace_module_info.patch b/target/linux/generic/patches-4.1/205-backtrace_module_info.patch new file mode 100644 index 0000000..48b2204 --- /dev/null +++ b/target/linux/generic/patches-4.1/205-backtrace_module_info.patch @@ -0,0 +1,36 @@ +--- a/lib/vsprintf.c ++++ b/lib/vsprintf.c +@@ -617,8 +617,10 @@ char *symbol_string(char *buf, char *end + struct printf_spec spec, const char *fmt) + { + unsigned long value; +-#ifdef CONFIG_KALLSYMS + char sym[KSYM_SYMBOL_LEN]; ++#ifndef CONFIG_KALLSYMS ++ struct module *mod; ++ int len; + #endif + + if (fmt[1] == 'R') +@@ -632,15 +634,15 @@ char *symbol_string(char *buf, char *end + sprint_symbol(sym, value); + else + sprint_symbol_no_offset(sym, value); +- +- return string(buf, end, sym, spec); + #else +- spec.field_width = 2 * sizeof(void *); +- spec.flags |= SPECIAL | SMALL | ZEROPAD; +- spec.base = 16; ++ len = snprintf(sym, sizeof(sym), "0x%lx", value); + +- return number(buf, end, value, spec); ++ mod = __module_address(value); ++ if (mod) ++ snprintf(sym + len, sizeof(sym) - len, " [%s@%p+0x%x]", ++ mod->name, mod->module_core, mod->core_size); + #endif ++ return string(buf, end, sym, spec); + } + + static noinline_for_stack diff --git a/target/linux/generic/patches-4.1/210-darwin_scripts_include.patch b/target/linux/generic/patches-4.1/210-darwin_scripts_include.patch new file mode 100644 index 0000000..ef548c7 --- /dev/null +++ b/target/linux/generic/patches-4.1/210-darwin_scripts_include.patch @@ -0,0 +1,3088 @@ +--- a/scripts/kallsyms.c ++++ b/scripts/kallsyms.c +@@ -22,6 +22,35 @@ + #include + #include + #include ++#ifdef __APPLE__ ++/* Darwin has no memmem implementation, this one is ripped of the uClibc-0.9.28 source */ ++void *memmem (const void *haystack, size_t haystack_len, ++ const void *needle, size_t needle_len) ++{ ++ const char *begin; ++ const char *const last_possible ++ = (const char *) haystack + haystack_len - needle_len; ++ ++ if (needle_len == 0) ++ /* The first occurrence of the empty string is deemed to occur at ++ the beginning of the string. */ ++ return (void *) haystack; ++ ++ /* Sanity check, otherwise the loop might search through the whole ++ memory. */ ++ if (__builtin_expect (haystack_len < needle_len, 0)) ++ return NULL; ++ ++ for (begin = (const char *) haystack; begin <= last_possible; ++begin) ++ if (begin[0] == ((const char *) needle)[0] && ++ !memcmp ((const void *) &begin[1], ++ (const void *) ((const char *) needle + 1), ++ needle_len - 1)) ++ return (void *) begin; ++ ++ return NULL; ++} ++#endif + + #ifndef ARRAY_SIZE + #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) +--- a/scripts/kconfig/Makefile ++++ b/scripts/kconfig/Makefile +@@ -149,6 +149,9 @@ check-lxdialog := $(srctree)/$(src)/lxd + # we really need to do so. (Do not call gcc as part of make mrproper) + HOST_EXTRACFLAGS += $(shell $(CONFIG_SHELL) $(check-lxdialog) -ccflags) \ + -DLOCALE ++ifeq ($(shell uname -s),Darwin) ++HOST_LOADLIBES += -lncurses ++endif + + # =========================================================================== + # Shared Makefile for the various kconfig executables: +--- a/scripts/mod/mk_elfconfig.c ++++ b/scripts/mod/mk_elfconfig.c +@@ -1,7 +1,11 @@ + #include + #include + #include ++#ifndef __APPLE__ + #include ++#else ++#include "elf.h" ++#endif + + int + main(int argc, char **argv) +--- a/scripts/mod/modpost.h ++++ b/scripts/mod/modpost.h +@@ -7,7 +7,11 @@ + #include + #include + #include ++#if !(defined(__APPLE__) || defined(__CYGWIN__)) + #include ++#else ++#include "elf.h" ++#endif + + #include "elfconfig.h" + +--- /dev/null ++++ b/scripts/mod/elf.h +@@ -0,0 +1,3007 @@ ++/* This file defines standard ELF types, structures, and macros. ++ Copyright (C) 1995-2012 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#ifndef _ELF_H ++#define _ELF_H 1 ++ ++/* Standard ELF types. */ ++ ++#include ++ ++/* Type for a 16-bit quantity. */ ++typedef uint16_t Elf32_Half; ++typedef uint16_t Elf64_Half; ++ ++/* Types for signed and unsigned 32-bit quantities. */ ++typedef uint32_t Elf32_Word; ++typedef int32_t Elf32_Sword; ++typedef uint32_t Elf64_Word; ++typedef int32_t Elf64_Sword; ++ ++/* Types for signed and unsigned 64-bit quantities. */ ++typedef uint64_t Elf32_Xword; ++typedef int64_t Elf32_Sxword; ++typedef uint64_t Elf64_Xword; ++typedef int64_t Elf64_Sxword; ++ ++/* Type of addresses. */ ++typedef uint32_t Elf32_Addr; ++typedef uint64_t Elf64_Addr; ++ ++/* Type of file offsets. */ ++typedef uint32_t Elf32_Off; ++typedef uint64_t Elf64_Off; ++ ++/* Type for section indices, which are 16-bit quantities. */ ++typedef uint16_t Elf32_Section; ++typedef uint16_t Elf64_Section; ++ ++/* Type for version symbol information. */ ++typedef Elf32_Half Elf32_Versym; ++typedef Elf64_Half Elf64_Versym; ++ ++ ++/* The ELF file header. This appears at the start of every ELF file. */ ++ ++#define EI_NIDENT (16) ++ ++typedef struct ++{ ++ unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ ++ Elf32_Half e_type; /* Object file type */ ++ Elf32_Half e_machine; /* Architecture */ ++ Elf32_Word e_version; /* Object file version */ ++ Elf32_Addr e_entry; /* Entry point virtual address */ ++ Elf32_Off e_phoff; /* Program header table file offset */ ++ Elf32_Off e_shoff; /* Section header table file offset */ ++ Elf32_Word e_flags; /* Processor-specific flags */ ++ Elf32_Half e_ehsize; /* ELF header size in bytes */ ++ Elf32_Half e_phentsize; /* Program header table entry size */ ++ Elf32_Half e_phnum; /* Program header table entry count */ ++ Elf32_Half e_shentsize; /* Section header table entry size */ ++ Elf32_Half e_shnum; /* Section header table entry count */ ++ Elf32_Half e_shstrndx; /* Section header string table index */ ++} Elf32_Ehdr; ++ ++typedef struct ++{ ++ unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ ++ Elf64_Half e_type; /* Object file type */ ++ Elf64_Half e_machine; /* Architecture */ ++ Elf64_Word e_version; /* Object file version */ ++ Elf64_Addr e_entry; /* Entry point virtual address */ ++ Elf64_Off e_phoff; /* Program header table file offset */ ++ Elf64_Off e_shoff; /* Section header table file offset */ ++ Elf64_Word e_flags; /* Processor-specific flags */ ++ Elf64_Half e_ehsize; /* ELF header size in bytes */ ++ Elf64_Half e_phentsize; /* Program header table entry size */ ++ Elf64_Half e_phnum; /* Program header table entry count */ ++ Elf64_Half e_shentsize; /* Section header table entry size */ ++ Elf64_Half e_shnum; /* Section header table entry count */ ++ Elf64_Half e_shstrndx; /* Section header string table index */ ++} Elf64_Ehdr; ++ ++/* Fields in the e_ident array. The EI_* macros are indices into the ++ array. The macros under each EI_* macro are the values the byte ++ may have. */ ++ ++#define EI_MAG0 0 /* File identification byte 0 index */ ++#define ELFMAG0 0x7f /* Magic number byte 0 */ ++ ++#define EI_MAG1 1 /* File identification byte 1 index */ ++#define ELFMAG1 'E' /* Magic number byte 1 */ ++ ++#define EI_MAG2 2 /* File identification byte 2 index */ ++#define ELFMAG2 'L' /* Magic number byte 2 */ ++ ++#define EI_MAG3 3 /* File identification byte 3 index */ ++#define ELFMAG3 'F' /* Magic number byte 3 */ ++ ++/* Conglomeration of the identification bytes, for easy testing as a word. */ ++#define ELFMAG "\177ELF" ++#define SELFMAG 4 ++ ++#define EI_CLASS 4 /* File class byte index */ ++#define ELFCLASSNONE 0 /* Invalid class */ ++#define ELFCLASS32 1 /* 32-bit objects */ ++#define ELFCLASS64 2 /* 64-bit objects */ ++#define ELFCLASSNUM 3 ++ ++#define EI_DATA 5 /* Data encoding byte index */ ++#define ELFDATANONE 0 /* Invalid data encoding */ ++#define ELFDATA2LSB 1 /* 2's complement, little endian */ ++#define ELFDATA2MSB 2 /* 2's complement, big endian */ ++#define ELFDATANUM 3 ++ ++#define EI_VERSION 6 /* File version byte index */ ++ /* Value must be EV_CURRENT */ ++ ++#define EI_OSABI 7 /* OS ABI identification */ ++#define ELFOSABI_NONE 0 /* UNIX System V ABI */ ++#define ELFOSABI_SYSV 0 /* Alias. */ ++#define ELFOSABI_HPUX 1 /* HP-UX */ ++#define ELFOSABI_NETBSD 2 /* NetBSD. */ ++#define ELFOSABI_GNU 3 /* Object uses GNU ELF extensions. */ ++#define ELFOSABI_LINUX ELFOSABI_GNU /* Compatibility alias. */ ++#define ELFOSABI_SOLARIS 6 /* Sun Solaris. */ ++#define ELFOSABI_AIX 7 /* IBM AIX. */ ++#define ELFOSABI_IRIX 8 /* SGI Irix. */ ++#define ELFOSABI_FREEBSD 9 /* FreeBSD. */ ++#define ELFOSABI_TRU64 10 /* Compaq TRU64 UNIX. */ ++#define ELFOSABI_MODESTO 11 /* Novell Modesto. */ ++#define ELFOSABI_OPENBSD 12 /* OpenBSD. */ ++#define ELFOSABI_ARM_AEABI 64 /* ARM EABI */ ++#define ELFOSABI_ARM 97 /* ARM */ ++#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ ++ ++#define EI_ABIVERSION 8 /* ABI version */ ++ ++#define EI_PAD 9 /* Byte index of padding bytes */ ++ ++/* Legal values for e_type (object file type). */ ++ ++#define ET_NONE 0 /* No file type */ ++#define ET_REL 1 /* Relocatable file */ ++#define ET_EXEC 2 /* Executable file */ ++#define ET_DYN 3 /* Shared object file */ ++#define ET_CORE 4 /* Core file */ ++#define ET_NUM 5 /* Number of defined types */ ++#define ET_LOOS 0xfe00 /* OS-specific range start */ ++#define ET_HIOS 0xfeff /* OS-specific range end */ ++#define ET_LOPROC 0xff00 /* Processor-specific range start */ ++#define ET_HIPROC 0xffff /* Processor-specific range end */ ++ ++/* Legal values for e_machine (architecture). */ ++ ++#define EM_NONE 0 /* No machine */ ++#define EM_M32 1 /* AT&T WE 32100 */ ++#define EM_SPARC 2 /* SUN SPARC */ ++#define EM_386 3 /* Intel 80386 */ ++#define EM_68K 4 /* Motorola m68k family */ ++#define EM_88K 5 /* Motorola m88k family */ ++#define EM_860 7 /* Intel 80860 */ ++#define EM_MIPS 8 /* MIPS R3000 big-endian */ ++#define EM_S370 9 /* IBM System/370 */ ++#define EM_MIPS_RS3_LE 10 /* MIPS R3000 little-endian */ ++ ++#define EM_PARISC 15 /* HPPA */ ++#define EM_VPP500 17 /* Fujitsu VPP500 */ ++#define EM_SPARC32PLUS 18 /* Sun's "v8plus" */ ++#define EM_960 19 /* Intel 80960 */ ++#define EM_PPC 20 /* PowerPC */ ++#define EM_PPC64 21 /* PowerPC 64-bit */ ++#define EM_S390 22 /* IBM S390 */ ++ ++#define EM_V800 36 /* NEC V800 series */ ++#define EM_FR20 37 /* Fujitsu FR20 */ ++#define EM_RH32 38 /* TRW RH-32 */ ++#define EM_RCE 39 /* Motorola RCE */ ++#define EM_ARM 40 /* ARM */ ++#define EM_FAKE_ALPHA 41 /* Digital Alpha */ ++#define EM_SH 42 /* Hitachi SH */ ++#define EM_SPARCV9 43 /* SPARC v9 64-bit */ ++#define EM_TRICORE 44 /* Siemens Tricore */ ++#define EM_ARC 45 /* Argonaut RISC Core */ ++#define EM_H8_300 46 /* Hitachi H8/300 */ ++#define EM_H8_300H 47 /* Hitachi H8/300H */ ++#define EM_H8S 48 /* Hitachi H8S */ ++#define EM_H8_500 49 /* Hitachi H8/500 */ ++#define EM_IA_64 50 /* Intel Merced */ ++#define EM_MIPS_X 51 /* Stanford MIPS-X */ ++#define EM_COLDFIRE 52 /* Motorola Coldfire */ ++#define EM_68HC12 53 /* Motorola M68HC12 */ ++#define EM_MMA 54 /* Fujitsu MMA Multimedia Accelerator*/ ++#define EM_PCP 55 /* Siemens PCP */ ++#define EM_NCPU 56 /* Sony nCPU embeeded RISC */ ++#define EM_NDR1 57 /* Denso NDR1 microprocessor */ ++#define EM_STARCORE 58 /* Motorola Start*Core processor */ ++#define EM_ME16 59 /* Toyota ME16 processor */ ++#define EM_ST100 60 /* STMicroelectronic ST100 processor */ ++#define EM_TINYJ 61 /* Advanced Logic Corp. Tinyj emb.fam*/ ++#define EM_X86_64 62 /* AMD x86-64 architecture */ ++#define EM_PDSP 63 /* Sony DSP Processor */ ++ ++#define EM_FX66 66 /* Siemens FX66 microcontroller */ ++#define EM_ST9PLUS 67 /* STMicroelectronics ST9+ 8/16 mc */ ++#define EM_ST7 68 /* STmicroelectronics ST7 8 bit mc */ ++#define EM_68HC16 69 /* Motorola MC68HC16 microcontroller */ ++#define EM_68HC11 70 /* Motorola MC68HC11 microcontroller */ ++#define EM_68HC08 71 /* Motorola MC68HC08 microcontroller */ ++#define EM_68HC05 72 /* Motorola MC68HC05 microcontroller */ ++#define EM_SVX 73 /* Silicon Graphics SVx */ ++#define EM_ST19 74 /* STMicroelectronics ST19 8 bit mc */ ++#define EM_VAX 75 /* Digital VAX */ ++#define EM_CRIS 76 /* Axis Communications 32-bit embedded processor */ ++#define EM_JAVELIN 77 /* Infineon Technologies 32-bit embedded processor */ ++#define EM_FIREPATH 78 /* Element 14 64-bit DSP Processor */ ++#define EM_ZSP 79 /* LSI Logic 16-bit DSP Processor */ ++#define EM_MMIX 80 /* Donald Knuth's educational 64-bit processor */ ++#define EM_HUANY 81 /* Harvard University machine-independent object files */ ++#define EM_PRISM 82 /* SiTera Prism */ ++#define EM_AVR 83 /* Atmel AVR 8-bit microcontroller */ ++#define EM_FR30 84 /* Fujitsu FR30 */ ++#define EM_D10V 85 /* Mitsubishi D10V */ ++#define EM_D30V 86 /* Mitsubishi D30V */ ++#define EM_V850 87 /* NEC v850 */ ++#define EM_M32R 88 /* Mitsubishi M32R */ ++#define EM_MN10300 89 /* Matsushita MN10300 */ ++#define EM_MN10200 90 /* Matsushita MN10200 */ ++#define EM_PJ 91 /* picoJava */ ++#define EM_OPENRISC 92 /* OpenRISC 32-bit embedded processor */ ++#define EM_ARC_A5 93 /* ARC Cores Tangent-A5 */ ++#define EM_XTENSA 94 /* Tensilica Xtensa Architecture */ ++#define EM_TILEPRO 188 /* Tilera TILEPro */ ++#define EM_TILEGX 191 /* Tilera TILE-Gx */ ++#define EM_NUM 192 ++ ++/* If it is necessary to assign new unofficial EM_* values, please ++ pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the ++ chances of collision with official or non-GNU unofficial values. */ ++ ++#define EM_ALPHA 0x9026 ++ ++/* Legal values for e_version (version). */ ++ ++#define EV_NONE 0 /* Invalid ELF version */ ++#define EV_CURRENT 1 /* Current version */ ++#define EV_NUM 2 ++ ++/* Section header. */ ++ ++typedef struct ++{ ++ Elf32_Word sh_name; /* Section name (string tbl index) */ ++ Elf32_Word sh_type; /* Section type */ ++ Elf32_Word sh_flags; /* Section flags */ ++ Elf32_Addr sh_addr; /* Section virtual addr at execution */ ++ Elf32_Off sh_offset; /* Section file offset */ ++ Elf32_Word sh_size; /* Section size in bytes */ ++ Elf32_Word sh_link; /* Link to another section */ ++ Elf32_Word sh_info; /* Additional section information */ ++ Elf32_Word sh_addralign; /* Section alignment */ ++ Elf32_Word sh_entsize; /* Entry size if section holds table */ ++} Elf32_Shdr; ++ ++typedef struct ++{ ++ Elf64_Word sh_name; /* Section name (string tbl index) */ ++ Elf64_Word sh_type; /* Section type */ ++ Elf64_Xword sh_flags; /* Section flags */ ++ Elf64_Addr sh_addr; /* Section virtual addr at execution */ ++ Elf64_Off sh_offset; /* Section file offset */ ++ Elf64_Xword sh_size; /* Section size in bytes */ ++ Elf64_Word sh_link; /* Link to another section */ ++ Elf64_Word sh_info; /* Additional section information */ ++ Elf64_Xword sh_addralign; /* Section alignment */ ++ Elf64_Xword sh_entsize; /* Entry size if section holds table */ ++} Elf64_Shdr; ++ ++/* Special section indices. */ ++ ++#define SHN_UNDEF 0 /* Undefined section */ ++#define SHN_LORESERVE 0xff00 /* Start of reserved indices */ ++#define SHN_LOPROC 0xff00 /* Start of processor-specific */ ++#define SHN_BEFORE 0xff00 /* Order section before all others ++ (Solaris). */ ++#define SHN_AFTER 0xff01 /* Order section after all others ++ (Solaris). */ ++#define SHN_HIPROC 0xff1f /* End of processor-specific */ ++#define SHN_LOOS 0xff20 /* Start of OS-specific */ ++#define SHN_HIOS 0xff3f /* End of OS-specific */ ++#define SHN_ABS 0xfff1 /* Associated symbol is absolute */ ++#define SHN_COMMON 0xfff2 /* Associated symbol is common */ ++#define SHN_XINDEX 0xffff /* Index is in extra table. */ ++#define SHN_HIRESERVE 0xffff /* End of reserved indices */ ++ ++/* Legal values for sh_type (section type). */ ++ ++#define SHT_NULL 0 /* Section header table entry unused */ ++#define SHT_PROGBITS 1 /* Program data */ ++#define SHT_SYMTAB 2 /* Symbol table */ ++#define SHT_STRTAB 3 /* String table */ ++#define SHT_RELA 4 /* Relocation entries with addends */ ++#define SHT_HASH 5 /* Symbol hash table */ ++#define SHT_DYNAMIC 6 /* Dynamic linking information */ ++#define SHT_NOTE 7 /* Notes */ ++#define SHT_NOBITS 8 /* Program space with no data (bss) */ ++#define SHT_REL 9 /* Relocation entries, no addends */ ++#define SHT_SHLIB 10 /* Reserved */ ++#define SHT_DYNSYM 11 /* Dynamic linker symbol table */ ++#define SHT_INIT_ARRAY 14 /* Array of constructors */ ++#define SHT_FINI_ARRAY 15 /* Array of destructors */ ++#define SHT_PREINIT_ARRAY 16 /* Array of pre-constructors */ ++#define SHT_GROUP 17 /* Section group */ ++#define SHT_SYMTAB_SHNDX 18 /* Extended section indeces */ ++#define SHT_NUM 19 /* Number of defined types. */ ++#define SHT_LOOS 0x60000000 /* Start OS-specific. */ ++#define SHT_GNU_ATTRIBUTES 0x6ffffff5 /* Object attributes. */ ++#define SHT_GNU_HASH 0x6ffffff6 /* GNU-style hash table. */ ++#define SHT_GNU_LIBLIST 0x6ffffff7 /* Prelink library list */ ++#define SHT_CHECKSUM 0x6ffffff8 /* Checksum for DSO content. */ ++#define SHT_LOSUNW 0x6ffffffa /* Sun-specific low bound. */ ++#define SHT_SUNW_move 0x6ffffffa ++#define SHT_SUNW_COMDAT 0x6ffffffb ++#define SHT_SUNW_syminfo 0x6ffffffc ++#define SHT_GNU_verdef 0x6ffffffd /* Version definition section. */ ++#define SHT_GNU_verneed 0x6ffffffe /* Version needs section. */ ++#define SHT_GNU_versym 0x6fffffff /* Version symbol table. */ ++#define SHT_HISUNW 0x6fffffff /* Sun-specific high bound. */ ++#define SHT_HIOS 0x6fffffff /* End OS-specific type */ ++#define SHT_LOPROC 0x70000000 /* Start of processor-specific */ ++#define SHT_HIPROC 0x7fffffff /* End of processor-specific */ ++#define SHT_LOUSER 0x80000000 /* Start of application-specific */ ++#define SHT_HIUSER 0x8fffffff /* End of application-specific */ ++ ++/* Legal values for sh_flags (section flags). */ ++ ++#define SHF_WRITE (1 << 0) /* Writable */ ++#define SHF_ALLOC (1 << 1) /* Occupies memory during execution */ ++#define SHF_EXECINSTR (1 << 2) /* Executable */ ++#define SHF_MERGE (1 << 4) /* Might be merged */ ++#define SHF_STRINGS (1 << 5) /* Contains nul-terminated strings */ ++#define SHF_INFO_LINK (1 << 6) /* `sh_info' contains SHT index */ ++#define SHF_LINK_ORDER (1 << 7) /* Preserve order after combining */ ++#define SHF_OS_NONCONFORMING (1 << 8) /* Non-standard OS specific handling ++ required */ ++#define SHF_GROUP (1 << 9) /* Section is member of a group. */ ++#define SHF_TLS (1 << 10) /* Section hold thread-local data. */ ++#define SHF_MASKOS 0x0ff00000 /* OS-specific. */ ++#define SHF_MASKPROC 0xf0000000 /* Processor-specific */ ++#define SHF_ORDERED (1 << 30) /* Special ordering requirement ++ (Solaris). */ ++#define SHF_EXCLUDE (1 << 31) /* Section is excluded unless ++ referenced or allocated (Solaris).*/ ++ ++/* Section group handling. */ ++#define GRP_COMDAT 0x1 /* Mark group as COMDAT. */ ++ ++/* Symbol table entry. */ ++ ++typedef struct ++{ ++ Elf32_Word st_name; /* Symbol name (string tbl index) */ ++ Elf32_Addr st_value; /* Symbol value */ ++ Elf32_Word st_size; /* Symbol size */ ++ unsigned char st_info; /* Symbol type and binding */ ++ unsigned char st_other; /* Symbol visibility */ ++ Elf32_Section st_shndx; /* Section index */ ++} Elf32_Sym; ++ ++typedef struct ++{ ++ Elf64_Word st_name; /* Symbol name (string tbl index) */ ++ unsigned char st_info; /* Symbol type and binding */ ++ unsigned char st_other; /* Symbol visibility */ ++ Elf64_Section st_shndx; /* Section index */ ++ Elf64_Addr st_value; /* Symbol value */ ++ Elf64_Xword st_size; /* Symbol size */ ++} Elf64_Sym; ++ ++/* The syminfo section if available contains additional information about ++ every dynamic symbol. */ ++ ++typedef struct ++{ ++ Elf32_Half si_boundto; /* Direct bindings, symbol bound to */ ++ Elf32_Half si_flags; /* Per symbol flags */ ++} Elf32_Syminfo; ++ ++typedef struct ++{ ++ Elf64_Half si_boundto; /* Direct bindings, symbol bound to */ ++ Elf64_Half si_flags; /* Per symbol flags */ ++} Elf64_Syminfo; ++ ++/* Possible values for si_boundto. */ ++#define SYMINFO_BT_SELF 0xffff /* Symbol bound to self */ ++#define SYMINFO_BT_PARENT 0xfffe /* Symbol bound to parent */ ++#define SYMINFO_BT_LOWRESERVE 0xff00 /* Beginning of reserved entries */ ++ ++/* Possible bitmasks for si_flags. */ ++#define SYMINFO_FLG_DIRECT 0x0001 /* Direct bound symbol */ ++#define SYMINFO_FLG_PASSTHRU 0x0002 /* Pass-thru symbol for translator */ ++#define SYMINFO_FLG_COPY 0x0004 /* Symbol is a copy-reloc */ ++#define SYMINFO_FLG_LAZYLOAD 0x0008 /* Symbol bound to object to be lazy ++ loaded */ ++/* Syminfo version values. */ ++#define SYMINFO_NONE 0 ++#define SYMINFO_CURRENT 1 ++#define SYMINFO_NUM 2 ++ ++ ++/* How to extract and insert information held in the st_info field. */ ++ ++#define ELF32_ST_BIND(val) (((unsigned char) (val)) >> 4) ++#define ELF32_ST_TYPE(val) ((val) & 0xf) ++#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) ++ ++/* Both Elf32_Sym and Elf64_Sym use the same one-byte st_info field. */ ++#define ELF64_ST_BIND(val) ELF32_ST_BIND (val) ++#define ELF64_ST_TYPE(val) ELF32_ST_TYPE (val) ++#define ELF64_ST_INFO(bind, type) ELF32_ST_INFO ((bind), (type)) ++ ++/* Legal values for ST_BIND subfield of st_info (symbol binding). */ ++ ++#define STB_LOCAL 0 /* Local symbol */ ++#define STB_GLOBAL 1 /* Global symbol */ ++#define STB_WEAK 2 /* Weak symbol */ ++#define STB_NUM 3 /* Number of defined types. */ ++#define STB_LOOS 10 /* Start of OS-specific */ ++#define STB_GNU_UNIQUE 10 /* Unique symbol. */ ++#define STB_HIOS 12 /* End of OS-specific */ ++#define STB_LOPROC 13 /* Start of processor-specific */ ++#define STB_HIPROC 15 /* End of processor-specific */ ++ ++/* Legal values for ST_TYPE subfield of st_info (symbol type). */ ++ ++#define STT_NOTYPE 0 /* Symbol type is unspecified */ ++#define STT_OBJECT 1 /* Symbol is a data object */ ++#define STT_FUNC 2 /* Symbol is a code object */ ++#define STT_SECTION 3 /* Symbol associated with a section */ ++#define STT_FILE 4 /* Symbol's name is file name */ ++#define STT_COMMON 5 /* Symbol is a common data object */ ++#define STT_TLS 6 /* Symbol is thread-local data object*/ ++#define STT_NUM 7 /* Number of defined types. */ ++#define STT_LOOS 10 /* Start of OS-specific */ ++#define STT_GNU_IFUNC 10 /* Symbol is indirect code object */ ++#define STT_HIOS 12 /* End of OS-specific */ ++#define STT_LOPROC 13 /* Start of processor-specific */ ++#define STT_HIPROC 15 /* End of processor-specific */ ++ ++ ++/* Symbol table indices are found in the hash buckets and chain table ++ of a symbol hash table section. This special index value indicates ++ the end of a chain, meaning no further symbols are found in that bucket. */ ++ ++#define STN_UNDEF 0 /* End of a chain. */ ++ ++ ++/* How to extract and insert information held in the st_other field. */ ++ ++#define ELF32_ST_VISIBILITY(o) ((o) & 0x03) ++ ++/* For ELF64 the definitions are the same. */ ++#define ELF64_ST_VISIBILITY(o) ELF32_ST_VISIBILITY (o) ++ ++/* Symbol visibility specification encoded in the st_other field. */ ++#define STV_DEFAULT 0 /* Default symbol visibility rules */ ++#define STV_INTERNAL 1 /* Processor specific hidden class */ ++#define STV_HIDDEN 2 /* Sym unavailable in other modules */ ++#define STV_PROTECTED 3 /* Not preemptible, not exported */ ++ ++ ++/* Relocation table entry without addend (in section of type SHT_REL). */ ++ ++typedef struct ++{ ++ Elf32_Addr r_offset; /* Address */ ++ Elf32_Word r_info; /* Relocation type and symbol index */ ++} Elf32_Rel; ++ ++/* I have seen two different definitions of the Elf64_Rel and ++ Elf64_Rela structures, so we'll leave them out until Novell (or ++ whoever) gets their act together. */ ++/* The following, at least, is used on Sparc v9, MIPS, and Alpha. */ ++ ++typedef struct ++{ ++ Elf64_Addr r_offset; /* Address */ ++ Elf64_Xword r_info; /* Relocation type and symbol index */ ++} Elf64_Rel; ++ ++/* Relocation table entry with addend (in section of type SHT_RELA). */ ++ ++typedef struct ++{ ++ Elf32_Addr r_offset; /* Address */ ++ Elf32_Word r_info; /* Relocation type and symbol index */ ++ Elf32_Sword r_addend; /* Addend */ ++} Elf32_Rela; ++ ++typedef struct ++{ ++ Elf64_Addr r_offset; /* Address */ ++ Elf64_Xword r_info; /* Relocation type and symbol index */ ++ Elf64_Sxword r_addend; /* Addend */ ++} Elf64_Rela; ++ ++/* How to extract and insert information held in the r_info field. */ ++ ++#define ELF32_R_SYM(val) ((val) >> 8) ++#define ELF32_R_TYPE(val) ((val) & 0xff) ++#define ELF32_R_INFO(sym, type) (((sym) << 8) + ((type) & 0xff)) ++ ++#define ELF64_R_SYM(i) ((i) >> 32) ++#define ELF64_R_TYPE(i) ((i) & 0xffffffff) ++#define ELF64_R_INFO(sym,type) ((((Elf64_Xword) (sym)) << 32) + (type)) ++ ++/* Program segment header. */ ++ ++typedef struct ++{ ++ Elf32_Word p_type; /* Segment type */ ++ Elf32_Off p_offset; /* Segment file offset */ ++ Elf32_Addr p_vaddr; /* Segment virtual address */ ++ Elf32_Addr p_paddr; /* Segment physical address */ ++ Elf32_Word p_filesz; /* Segment size in file */ ++ Elf32_Word p_memsz; /* Segment size in memory */ ++ Elf32_Word p_flags; /* Segment flags */ ++ Elf32_Word p_align; /* Segment alignment */ ++} Elf32_Phdr; ++ ++typedef struct ++{ ++ Elf64_Word p_type; /* Segment type */ ++ Elf64_Word p_flags; /* Segment flags */ ++ Elf64_Off p_offset; /* Segment file offset */ ++ Elf64_Addr p_vaddr; /* Segment virtual address */ ++ Elf64_Addr p_paddr; /* Segment physical address */ ++ Elf64_Xword p_filesz; /* Segment size in file */ ++ Elf64_Xword p_memsz; /* Segment size in memory */ ++ Elf64_Xword p_align; /* Segment alignment */ ++} Elf64_Phdr; ++ ++/* Special value for e_phnum. This indicates that the real number of ++ program headers is too large to fit into e_phnum. Instead the real ++ value is in the field sh_info of section 0. */ ++ ++#define PN_XNUM 0xffff ++ ++/* Legal values for p_type (segment type). */ ++ ++#define PT_NULL 0 /* Program header table entry unused */ ++#define PT_LOAD 1 /* Loadable program segment */ ++#define PT_DYNAMIC 2 /* Dynamic linking information */ ++#define PT_INTERP 3 /* Program interpreter */ ++#define PT_NOTE 4 /* Auxiliary information */ ++#define PT_SHLIB 5 /* Reserved */ ++#define PT_PHDR 6 /* Entry for header table itself */ ++#define PT_TLS 7 /* Thread-local storage segment */ ++#define PT_NUM 8 /* Number of defined types */ ++#define PT_LOOS 0x60000000 /* Start of OS-specific */ ++#define PT_GNU_EH_FRAME 0x6474e550 /* GCC .eh_frame_hdr segment */ ++#define PT_GNU_STACK 0x6474e551 /* Indicates stack executability */ ++#define PT_GNU_RELRO 0x6474e552 /* Read-only after relocation */ ++#define PT_LOSUNW 0x6ffffffa ++#define PT_SUNWBSS 0x6ffffffa /* Sun Specific segment */ ++#define PT_SUNWSTACK 0x6ffffffb /* Stack segment */ ++#define PT_HISUNW 0x6fffffff ++#define PT_HIOS 0x6fffffff /* End of OS-specific */ ++#define PT_LOPROC 0x70000000 /* Start of processor-specific */ ++#define PT_HIPROC 0x7fffffff /* End of processor-specific */ ++ ++/* Legal values for p_flags (segment flags). */ ++ ++#define PF_X (1 << 0) /* Segment is executable */ ++#define PF_W (1 << 1) /* Segment is writable */ ++#define PF_R (1 << 2) /* Segment is readable */ ++#define PF_MASKOS 0x0ff00000 /* OS-specific */ ++#define PF_MASKPROC 0xf0000000 /* Processor-specific */ ++ ++/* Legal values for note segment descriptor types for core files. */ ++ ++#define NT_PRSTATUS 1 /* Contains copy of prstatus struct */ ++#define NT_FPREGSET 2 /* Contains copy of fpregset struct */ ++#define NT_PRPSINFO 3 /* Contains copy of prpsinfo struct */ ++#define NT_PRXREG 4 /* Contains copy of prxregset struct */ ++#define NT_TASKSTRUCT 4 /* Contains copy of task structure */ ++#define NT_PLATFORM 5 /* String from sysinfo(SI_PLATFORM) */ ++#define NT_AUXV 6 /* Contains copy of auxv array */ ++#define NT_GWINDOWS 7 /* Contains copy of gwindows struct */ ++#define NT_ASRS 8 /* Contains copy of asrset struct */ ++#define NT_PSTATUS 10 /* Contains copy of pstatus struct */ ++#define NT_PSINFO 13 /* Contains copy of psinfo struct */ ++#define NT_PRCRED 14 /* Contains copy of prcred struct */ ++#define NT_UTSNAME 15 /* Contains copy of utsname struct */ ++#define NT_LWPSTATUS 16 /* Contains copy of lwpstatus struct */ ++#define NT_LWPSINFO 17 /* Contains copy of lwpinfo struct */ ++#define NT_PRFPXREG 20 /* Contains copy of fprxregset struct */ ++#define NT_PRXFPREG 0x46e62b7f /* Contains copy of user_fxsr_struct */ ++#define NT_PPC_VMX 0x100 /* PowerPC Altivec/VMX registers */ ++#define NT_PPC_SPE 0x101 /* PowerPC SPE/EVR registers */ ++#define NT_PPC_VSX 0x102 /* PowerPC VSX registers */ ++#define NT_386_TLS 0x200 /* i386 TLS slots (struct user_desc) */ ++#define NT_386_IOPERM 0x201 /* x86 io permission bitmap (1=deny) */ ++#define NT_X86_XSTATE 0x202 /* x86 extended state using xsave */ ++ ++/* Legal values for the note segment descriptor types for object files. */ ++ ++#define NT_VERSION 1 /* Contains a version string. */ ++ ++ ++/* Dynamic section entry. */ ++ ++typedef struct ++{ ++ Elf32_Sword d_tag; /* Dynamic entry type */ ++ union ++ { ++ Elf32_Word d_val; /* Integer value */ ++ Elf32_Addr d_ptr; /* Address value */ ++ } d_un; ++} Elf32_Dyn; ++ ++typedef struct ++{ ++ Elf64_Sxword d_tag; /* Dynamic entry type */ ++ union ++ { ++ Elf64_Xword d_val; /* Integer value */ ++ Elf64_Addr d_ptr; /* Address value */ ++ } d_un; ++} Elf64_Dyn; ++ ++/* Legal values for d_tag (dynamic entry type). */ ++ ++#define DT_NULL 0 /* Marks end of dynamic section */ ++#define DT_NEEDED 1 /* Name of needed library */ ++#define DT_PLTRELSZ 2 /* Size in bytes of PLT relocs */ ++#define DT_PLTGOT 3 /* Processor defined value */ ++#define DT_HASH 4 /* Address of symbol hash table */ ++#define DT_STRTAB 5 /* Address of string table */ ++#define DT_SYMTAB 6 /* Address of symbol table */ ++#define DT_RELA 7 /* Address of Rela relocs */ ++#define DT_RELASZ 8 /* Total size of Rela relocs */ ++#define DT_RELAENT 9 /* Size of one Rela reloc */ ++#define DT_STRSZ 10 /* Size of string table */ ++#define DT_SYMENT 11 /* Size of one symbol table entry */ ++#define DT_INIT 12 /* Address of init function */ ++#define DT_FINI 13 /* Address of termination function */ ++#define DT_SONAME 14 /* Name of shared object */ ++#define DT_RPATH 15 /* Library search path (deprecated) */ ++#define DT_SYMBOLIC 16 /* Start symbol search here */ ++#define DT_REL 17 /* Address of Rel relocs */ ++#define DT_RELSZ 18 /* Total size of Rel relocs */ ++#define DT_RELENT 19 /* Size of one Rel reloc */ ++#define DT_PLTREL 20 /* Type of reloc in PLT */ ++#define DT_DEBUG 21 /* For debugging; unspecified */ ++#define DT_TEXTREL 22 /* Reloc might modify .text */ ++#define DT_JMPREL 23 /* Address of PLT relocs */ ++#define DT_BIND_NOW 24 /* Process relocations of object */ ++#define DT_INIT_ARRAY 25 /* Array with addresses of init fct */ ++#define DT_FINI_ARRAY 26 /* Array with addresses of fini fct */ ++#define DT_INIT_ARRAYSZ 27 /* Size in bytes of DT_INIT_ARRAY */ ++#define DT_FINI_ARRAYSZ 28 /* Size in bytes of DT_FINI_ARRAY */ ++#define DT_RUNPATH 29 /* Library search path */ ++#define DT_FLAGS 30 /* Flags for the object being loaded */ ++#define DT_ENCODING 32 /* Start of encoded range */ ++#define DT_PREINIT_ARRAY 32 /* Array with addresses of preinit fct*/ ++#define DT_PREINIT_ARRAYSZ 33 /* size in bytes of DT_PREINIT_ARRAY */ ++#define DT_NUM 34 /* Number used */ ++#define DT_LOOS 0x6000000d /* Start of OS-specific */ ++#define DT_HIOS 0x6ffff000 /* End of OS-specific */ ++#define DT_LOPROC 0x70000000 /* Start of processor-specific */ ++#define DT_HIPROC 0x7fffffff /* End of processor-specific */ ++#define DT_PROCNUM DT_MIPS_NUM /* Most used by any processor */ ++ ++/* DT_* entries which fall between DT_VALRNGHI & DT_VALRNGLO use the ++ Dyn.d_un.d_val field of the Elf*_Dyn structure. This follows Sun's ++ approach. */ ++#define DT_VALRNGLO 0x6ffffd00 ++#define DT_GNU_PRELINKED 0x6ffffdf5 /* Prelinking timestamp */ ++#define DT_GNU_CONFLICTSZ 0x6ffffdf6 /* Size of conflict section */ ++#define DT_GNU_LIBLISTSZ 0x6ffffdf7 /* Size of library list */ ++#define DT_CHECKSUM 0x6ffffdf8 ++#define DT_PLTPADSZ 0x6ffffdf9 ++#define DT_MOVEENT 0x6ffffdfa ++#define DT_MOVESZ 0x6ffffdfb ++#define DT_FEATURE_1 0x6ffffdfc /* Feature selection (DTF_*). */ ++#define DT_POSFLAG_1 0x6ffffdfd /* Flags for DT_* entries, effecting ++ the following DT_* entry. */ ++#define DT_SYMINSZ 0x6ffffdfe /* Size of syminfo table (in bytes) */ ++#define DT_SYMINENT 0x6ffffdff /* Entry size of syminfo */ ++#define DT_VALRNGHI 0x6ffffdff ++#define DT_VALTAGIDX(tag) (DT_VALRNGHI - (tag)) /* Reverse order! */ ++#define DT_VALNUM 12 ++ ++/* DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the ++ Dyn.d_un.d_ptr field of the Elf*_Dyn structure. ++ ++ If any adjustment is made to the ELF object after it has been ++ built these entries will need to be adjusted. */ ++#define DT_ADDRRNGLO 0x6ffffe00 ++#define DT_GNU_HASH 0x6ffffef5 /* GNU-style hash table. */ ++#define DT_TLSDESC_PLT 0x6ffffef6 ++#define DT_TLSDESC_GOT 0x6ffffef7 ++#define DT_GNU_CONFLICT 0x6ffffef8 /* Start of conflict section */ ++#define DT_GNU_LIBLIST 0x6ffffef9 /* Library list */ ++#define DT_CONFIG 0x6ffffefa /* Configuration information. */ ++#define DT_DEPAUDIT 0x6ffffefb /* Dependency auditing. */ ++#define DT_AUDIT 0x6ffffefc /* Object auditing. */ ++#define DT_PLTPAD 0x6ffffefd /* PLT padding. */ ++#define DT_MOVETAB 0x6ffffefe /* Move table. */ ++#define DT_SYMINFO 0x6ffffeff /* Syminfo table. */ ++#define DT_ADDRRNGHI 0x6ffffeff ++#define DT_ADDRTAGIDX(tag) (DT_ADDRRNGHI - (tag)) /* Reverse order! */ ++#define DT_ADDRNUM 11 ++ ++/* The versioning entry types. The next are defined as part of the ++ GNU extension. */ ++#define DT_VERSYM 0x6ffffff0 ++ ++#define DT_RELACOUNT 0x6ffffff9 ++#define DT_RELCOUNT 0x6ffffffa ++ ++/* These were chosen by Sun. */ ++#define DT_FLAGS_1 0x6ffffffb /* State flags, see DF_1_* below. */ ++#define DT_VERDEF 0x6ffffffc /* Address of version definition ++ table */ ++#define DT_VERDEFNUM 0x6ffffffd /* Number of version definitions */ ++#define DT_VERNEED 0x6ffffffe /* Address of table with needed ++ versions */ ++#define DT_VERNEEDNUM 0x6fffffff /* Number of needed versions */ ++#define DT_VERSIONTAGIDX(tag) (DT_VERNEEDNUM - (tag)) /* Reverse order! */ ++#define DT_VERSIONTAGNUM 16 ++ ++/* Sun added these machine-independent extensions in the "processor-specific" ++ range. Be compatible. */ ++#define DT_AUXILIARY 0x7ffffffd /* Shared object to load before self */ ++#define DT_FILTER 0x7fffffff /* Shared object to get values from */ ++#define DT_EXTRATAGIDX(tag) ((Elf32_Word)-((Elf32_Sword) (tag) <<1>>1)-1) ++#define DT_EXTRANUM 3 ++ ++/* Values of `d_un.d_val' in the DT_FLAGS entry. */ ++#define DF_ORIGIN 0x00000001 /* Object may use DF_ORIGIN */ ++#define DF_SYMBOLIC 0x00000002 /* Symbol resolutions starts here */ ++#define DF_TEXTREL 0x00000004 /* Object contains text relocations */ ++#define DF_BIND_NOW 0x00000008 /* No lazy binding for this object */ ++#define DF_STATIC_TLS 0x00000010 /* Module uses the static TLS model */ ++ ++/* State flags selectable in the `d_un.d_val' element of the DT_FLAGS_1 ++ entry in the dynamic section. */ ++#define DF_1_NOW 0x00000001 /* Set RTLD_NOW for this object. */ ++#define DF_1_GLOBAL 0x00000002 /* Set RTLD_GLOBAL for this object. */ ++#define DF_1_GROUP 0x00000004 /* Set RTLD_GROUP for this object. */ ++#define DF_1_NODELETE 0x00000008 /* Set RTLD_NODELETE for this object.*/ ++#define DF_1_LOADFLTR 0x00000010 /* Trigger filtee loading at runtime.*/ ++#define DF_1_INITFIRST 0x00000020 /* Set RTLD_INITFIRST for this object*/ ++#define DF_1_NOOPEN 0x00000040 /* Set RTLD_NOOPEN for this object. */ ++#define DF_1_ORIGIN 0x00000080 /* $ORIGIN must be handled. */ ++#define DF_1_DIRECT 0x00000100 /* Direct binding enabled. */ ++#define DF_1_TRANS 0x00000200 ++#define DF_1_INTERPOSE 0x00000400 /* Object is used to interpose. */ ++#define DF_1_NODEFLIB 0x00000800 /* Ignore default lib search path. */ ++#define DF_1_NODUMP 0x00001000 /* Object can't be dldump'ed. */ ++#define DF_1_CONFALT 0x00002000 /* Configuration alternative created.*/ ++#define DF_1_ENDFILTEE 0x00004000 /* Filtee terminates filters search. */ ++#define DF_1_DISPRELDNE 0x00008000 /* Disp reloc applied at build time. */ ++#define DF_1_DISPRELPND 0x00010000 /* Disp reloc applied at run-time. */ ++ ++/* Flags for the feature selection in DT_FEATURE_1. */ ++#define DTF_1_PARINIT 0x00000001 ++#define DTF_1_CONFEXP 0x00000002 ++ ++/* Flags in the DT_POSFLAG_1 entry effecting only the next DT_* entry. */ ++#define DF_P1_LAZYLOAD 0x00000001 /* Lazyload following object. */ ++#define DF_P1_GROUPPERM 0x00000002 /* Symbols from next object are not ++ generally available. */ ++ ++/* Version definition sections. */ ++ ++typedef struct ++{ ++ Elf32_Half vd_version; /* Version revision */ ++ Elf32_Half vd_flags; /* Version information */ ++ Elf32_Half vd_ndx; /* Version Index */ ++ Elf32_Half vd_cnt; /* Number of associated aux entries */ ++ Elf32_Word vd_hash; /* Version name hash value */ ++ Elf32_Word vd_aux; /* Offset in bytes to verdaux array */ ++ Elf32_Word vd_next; /* Offset in bytes to next verdef ++ entry */ ++} Elf32_Verdef; ++ ++typedef struct ++{ ++ Elf64_Half vd_version; /* Version revision */ ++ Elf64_Half vd_flags; /* Version information */ ++ Elf64_Half vd_ndx; /* Version Index */ ++ Elf64_Half vd_cnt; /* Number of associated aux entries */ ++ Elf64_Word vd_hash; /* Version name hash value */ ++ Elf64_Word vd_aux; /* Offset in bytes to verdaux array */ ++ Elf64_Word vd_next; /* Offset in bytes to next verdef ++ entry */ ++} Elf64_Verdef; ++ ++ ++/* Legal values for vd_version (version revision). */ ++#define VER_DEF_NONE 0 /* No version */ ++#define VER_DEF_CURRENT 1 /* Current version */ ++#define VER_DEF_NUM 2 /* Given version number */ ++ ++/* Legal values for vd_flags (version information flags). */ ++#define VER_FLG_BASE 0x1 /* Version definition of file itself */ ++#define VER_FLG_WEAK 0x2 /* Weak version identifier */ ++ ++/* Versym symbol index values. */ ++#define VER_NDX_LOCAL 0 /* Symbol is local. */ ++#define VER_NDX_GLOBAL 1 /* Symbol is global. */ ++#define VER_NDX_LORESERVE 0xff00 /* Beginning of reserved entries. */ ++#define VER_NDX_ELIMINATE 0xff01 /* Symbol is to be eliminated. */ ++ ++/* Auxialiary version information. */ ++ ++typedef struct ++{ ++ Elf32_Word vda_name; /* Version or dependency names */ ++ Elf32_Word vda_next; /* Offset in bytes to next verdaux ++ entry */ ++} Elf32_Verdaux; ++ ++typedef struct ++{ ++ Elf64_Word vda_name; /* Version or dependency names */ ++ Elf64_Word vda_next; /* Offset in bytes to next verdaux ++ entry */ ++} Elf64_Verdaux; ++ ++ ++/* Version dependency section. */ ++ ++typedef struct ++{ ++ Elf32_Half vn_version; /* Version of structure */ ++ Elf32_Half vn_cnt; /* Number of associated aux entries */ ++ Elf32_Word vn_file; /* Offset of filename for this ++ dependency */ ++ Elf32_Word vn_aux; /* Offset in bytes to vernaux array */ ++ Elf32_Word vn_next; /* Offset in bytes to next verneed ++ entry */ ++} Elf32_Verneed; ++ ++typedef struct ++{ ++ Elf64_Half vn_version; /* Version of structure */ ++ Elf64_Half vn_cnt; /* Number of associated aux entries */ ++ Elf64_Word vn_file; /* Offset of filename for this ++ dependency */ ++ Elf64_Word vn_aux; /* Offset in bytes to vernaux array */ ++ Elf64_Word vn_next; /* Offset in bytes to next verneed ++ entry */ ++} Elf64_Verneed; ++ ++ ++/* Legal values for vn_version (version revision). */ ++#define VER_NEED_NONE 0 /* No version */ ++#define VER_NEED_CURRENT 1 /* Current version */ ++#define VER_NEED_NUM 2 /* Given version number */ ++ ++/* Auxiliary needed version information. */ ++ ++typedef struct ++{ ++ Elf32_Word vna_hash; /* Hash value of dependency name */ ++ Elf32_Half vna_flags; /* Dependency specific information */ ++ Elf32_Half vna_other; /* Unused */ ++ Elf32_Word vna_name; /* Dependency name string offset */ ++ Elf32_Word vna_next; /* Offset in bytes to next vernaux ++ entry */ ++} Elf32_Vernaux; ++ ++typedef struct ++{ ++ Elf64_Word vna_hash; /* Hash value of dependency name */ ++ Elf64_Half vna_flags; /* Dependency specific information */ ++ Elf64_Half vna_other; /* Unused */ ++ Elf64_Word vna_name; /* Dependency name string offset */ ++ Elf64_Word vna_next; /* Offset in bytes to next vernaux ++ entry */ ++} Elf64_Vernaux; ++ ++ ++/* Legal values for vna_flags. */ ++#define VER_FLG_WEAK 0x2 /* Weak version identifier */ ++ ++ ++/* Auxiliary vector. */ ++ ++/* This vector is normally only used by the program interpreter. The ++ usual definition in an ABI supplement uses the name auxv_t. The ++ vector is not usually defined in a standard file, but it ++ can't hurt. We rename it to avoid conflicts. The sizes of these ++ types are an arrangement between the exec server and the program ++ interpreter, so we don't fully specify them here. */ ++ ++typedef struct ++{ ++ uint32_t a_type; /* Entry type */ ++ union ++ { ++ uint32_t a_val; /* Integer value */ ++ /* We use to have pointer elements added here. We cannot do that, ++ though, since it does not work when using 32-bit definitions ++ on 64-bit platforms and vice versa. */ ++ } a_un; ++} Elf32_auxv_t; ++ ++typedef struct ++{ ++ uint64_t a_type; /* Entry type */ ++ union ++ { ++ uint64_t a_val; /* Integer value */ ++ /* We use to have pointer elements added here. We cannot do that, ++ though, since it does not work when using 32-bit definitions ++ on 64-bit platforms and vice versa. */ ++ } a_un; ++} Elf64_auxv_t; ++ ++/* Legal values for a_type (entry type). */ ++ ++#define AT_NULL 0 /* End of vector */ ++#define AT_IGNORE 1 /* Entry should be ignored */ ++#define AT_EXECFD 2 /* File descriptor of program */ ++#define AT_PHDR 3 /* Program headers for program */ ++#define AT_PHENT 4 /* Size of program header entry */ ++#define AT_PHNUM 5 /* Number of program headers */ ++#define AT_PAGESZ 6 /* System page size */ ++#define AT_BASE 7 /* Base address of interpreter */ ++#define AT_FLAGS 8 /* Flags */ ++#define AT_ENTRY 9 /* Entry point of program */ ++#define AT_NOTELF 10 /* Program is not ELF */ ++#define AT_UID 11 /* Real uid */ ++#define AT_EUID 12 /* Effective uid */ ++#define AT_GID 13 /* Real gid */ ++#define AT_EGID 14 /* Effective gid */ ++#define AT_CLKTCK 17 /* Frequency of times() */ ++ ++/* Some more special a_type values describing the hardware. */ ++#define AT_PLATFORM 15 /* String identifying platform. */ ++#define AT_HWCAP 16 /* Machine dependent hints about ++ processor capabilities. */ ++ ++/* This entry gives some information about the FPU initialization ++ performed by the kernel. */ ++#define AT_FPUCW 18 /* Used FPU control word. */ ++ ++/* Cache block sizes. */ ++#define AT_DCACHEBSIZE 19 /* Data cache block size. */ ++#define AT_ICACHEBSIZE 20 /* Instruction cache block size. */ ++#define AT_UCACHEBSIZE 21 /* Unified cache block size. */ ++ ++/* A special ignored value for PPC, used by the kernel to control the ++ interpretation of the AUXV. Must be > 16. */ ++#define AT_IGNOREPPC 22 /* Entry should be ignored. */ ++ ++#define AT_SECURE 23 /* Boolean, was exec setuid-like? */ ++ ++#define AT_BASE_PLATFORM 24 /* String identifying real platforms.*/ ++ ++#define AT_RANDOM 25 /* Address of 16 random bytes. */ ++ ++#define AT_EXECFN 31 /* Filename of executable. */ ++ ++/* Pointer to the global system page used for system calls and other ++ nice things. */ ++#define AT_SYSINFO 32 ++#define AT_SYSINFO_EHDR 33 ++ ++/* Shapes of the caches. Bits 0-3 contains associativity; bits 4-7 contains ++ log2 of line size; mask those to get cache size. */ ++#define AT_L1I_CACHESHAPE 34 ++#define AT_L1D_CACHESHAPE 35 ++#define AT_L2_CACHESHAPE 36 ++#define AT_L3_CACHESHAPE 37 ++ ++/* Note section contents. Each entry in the note section begins with ++ a header of a fixed form. */ ++ ++typedef struct ++{ ++ Elf32_Word n_namesz; /* Length of the note's name. */ ++ Elf32_Word n_descsz; /* Length of the note's descriptor. */ ++ Elf32_Word n_type; /* Type of the note. */ ++} Elf32_Nhdr; ++ ++typedef struct ++{ ++ Elf64_Word n_namesz; /* Length of the note's name. */ ++ Elf64_Word n_descsz; /* Length of the note's descriptor. */ ++ Elf64_Word n_type; /* Type of the note. */ ++} Elf64_Nhdr; ++ ++/* Known names of notes. */ ++ ++/* Solaris entries in the note section have this name. */ ++#define ELF_NOTE_SOLARIS "SUNW Solaris" ++ ++/* Note entries for GNU systems have this name. */ ++#define ELF_NOTE_GNU "GNU" ++ ++ ++/* Defined types of notes for Solaris. */ ++ ++/* Value of descriptor (one word) is desired pagesize for the binary. */ ++#define ELF_NOTE_PAGESIZE_HINT 1 ++ ++ ++/* Defined note types for GNU systems. */ ++ ++/* ABI information. The descriptor consists of words: ++ word 0: OS descriptor ++ word 1: major version of the ABI ++ word 2: minor version of the ABI ++ word 3: subminor version of the ABI ++*/ ++#define NT_GNU_ABI_TAG 1 ++#define ELF_NOTE_ABI NT_GNU_ABI_TAG /* Old name. */ ++ ++/* Known OSes. These values can appear in word 0 of an ++ NT_GNU_ABI_TAG note section entry. */ ++#define ELF_NOTE_OS_LINUX 0 ++#define ELF_NOTE_OS_GNU 1 ++#define ELF_NOTE_OS_SOLARIS2 2 ++#define ELF_NOTE_OS_FREEBSD 3 ++ ++/* Synthetic hwcap information. The descriptor begins with two words: ++ word 0: number of entries ++ word 1: bitmask of enabled entries ++ Then follow variable-length entries, one byte followed by a ++ '\0'-terminated hwcap name string. The byte gives the bit ++ number to test if enabled, (1U << bit) & bitmask. */ ++#define NT_GNU_HWCAP 2 ++ ++/* Build ID bits as generated by ld --build-id. ++ The descriptor consists of any nonzero number of bytes. */ ++#define NT_GNU_BUILD_ID 3 ++ ++/* Version note generated by GNU gold containing a version string. */ ++#define NT_GNU_GOLD_VERSION 4 ++ ++ ++/* Move records. */ ++typedef struct ++{ ++ Elf32_Xword m_value; /* Symbol value. */ ++ Elf32_Word m_info; /* Size and index. */ ++ Elf32_Word m_poffset; /* Symbol offset. */ ++ Elf32_Half m_repeat; /* Repeat count. */ ++ Elf32_Half m_stride; /* Stride info. */ ++} Elf32_Move; ++ ++typedef struct ++{ ++ Elf64_Xword m_value; /* Symbol value. */ ++ Elf64_Xword m_info; /* Size and index. */ ++ Elf64_Xword m_poffset; /* Symbol offset. */ ++ Elf64_Half m_repeat; /* Repeat count. */ ++ Elf64_Half m_stride; /* Stride info. */ ++} Elf64_Move; ++ ++/* Macro to construct move records. */ ++#define ELF32_M_SYM(info) ((info) >> 8) ++#define ELF32_M_SIZE(info) ((unsigned char) (info)) ++#define ELF32_M_INFO(sym, size) (((sym) << 8) + (unsigned char) (size)) ++ ++#define ELF64_M_SYM(info) ELF32_M_SYM (info) ++#define ELF64_M_SIZE(info) ELF32_M_SIZE (info) ++#define ELF64_M_INFO(sym, size) ELF32_M_INFO (sym, size) ++ ++ ++/* Motorola 68k specific definitions. */ ++ ++/* Values for Elf32_Ehdr.e_flags. */ ++#define EF_CPU32 0x00810000 ++ ++/* m68k relocs. */ ++ ++#define R_68K_NONE 0 /* No reloc */ ++#define R_68K_32 1 /* Direct 32 bit */ ++#define R_68K_16 2 /* Direct 16 bit */ ++#define R_68K_8 3 /* Direct 8 bit */ ++#define R_68K_PC32 4 /* PC relative 32 bit */ ++#define R_68K_PC16 5 /* PC relative 16 bit */ ++#define R_68K_PC8 6 /* PC relative 8 bit */ ++#define R_68K_GOT32 7 /* 32 bit PC relative GOT entry */ ++#define R_68K_GOT16 8 /* 16 bit PC relative GOT entry */ ++#define R_68K_GOT8 9 /* 8 bit PC relative GOT entry */ ++#define R_68K_GOT32O 10 /* 32 bit GOT offset */ ++#define R_68K_GOT16O 11 /* 16 bit GOT offset */ ++#define R_68K_GOT8O 12 /* 8 bit GOT offset */ ++#define R_68K_PLT32 13 /* 32 bit PC relative PLT address */ ++#define R_68K_PLT16 14 /* 16 bit PC relative PLT address */ ++#define R_68K_PLT8 15 /* 8 bit PC relative PLT address */ ++#define R_68K_PLT32O 16 /* 32 bit PLT offset */ ++#define R_68K_PLT16O 17 /* 16 bit PLT offset */ ++#define R_68K_PLT8O 18 /* 8 bit PLT offset */ ++#define R_68K_COPY 19 /* Copy symbol at runtime */ ++#define R_68K_GLOB_DAT 20 /* Create GOT entry */ ++#define R_68K_JMP_SLOT 21 /* Create PLT entry */ ++#define R_68K_RELATIVE 22 /* Adjust by program base */ ++#define R_68K_TLS_GD32 25 /* 32 bit GOT offset for GD */ ++#define R_68K_TLS_GD16 26 /* 16 bit GOT offset for GD */ ++#define R_68K_TLS_GD8 27 /* 8 bit GOT offset for GD */ ++#define R_68K_TLS_LDM32 28 /* 32 bit GOT offset for LDM */ ++#define R_68K_TLS_LDM16 29 /* 16 bit GOT offset for LDM */ ++#define R_68K_TLS_LDM8 30 /* 8 bit GOT offset for LDM */ ++#define R_68K_TLS_LDO32 31 /* 32 bit module-relative offset */ ++#define R_68K_TLS_LDO16 32 /* 16 bit module-relative offset */ ++#define R_68K_TLS_LDO8 33 /* 8 bit module-relative offset */ ++#define R_68K_TLS_IE32 34 /* 32 bit GOT offset for IE */ ++#define R_68K_TLS_IE16 35 /* 16 bit GOT offset for IE */ ++#define R_68K_TLS_IE8 36 /* 8 bit GOT offset for IE */ ++#define R_68K_TLS_LE32 37 /* 32 bit offset relative to ++ static TLS block */ ++#define R_68K_TLS_LE16 38 /* 16 bit offset relative to ++ static TLS block */ ++#define R_68K_TLS_LE8 39 /* 8 bit offset relative to ++ static TLS block */ ++#define R_68K_TLS_DTPMOD32 40 /* 32 bit module number */ ++#define R_68K_TLS_DTPREL32 41 /* 32 bit module-relative offset */ ++#define R_68K_TLS_TPREL32 42 /* 32 bit TP-relative offset */ ++/* Keep this the last entry. */ ++#define R_68K_NUM 43 ++ ++/* Intel 80386 specific definitions. */ ++ ++/* i386 relocs. */ ++ ++#define R_386_NONE 0 /* No reloc */ ++#define R_386_32 1 /* Direct 32 bit */ ++#define R_386_PC32 2 /* PC relative 32 bit */ ++#define R_386_GOT32 3 /* 32 bit GOT entry */ ++#define R_386_PLT32 4 /* 32 bit PLT address */ ++#define R_386_COPY 5 /* Copy symbol at runtime */ ++#define R_386_GLOB_DAT 6 /* Create GOT entry */ ++#define R_386_JMP_SLOT 7 /* Create PLT entry */ ++#define R_386_RELATIVE 8 /* Adjust by program base */ ++#define R_386_GOTOFF 9 /* 32 bit offset to GOT */ ++#define R_386_GOTPC 10 /* 32 bit PC relative offset to GOT */ ++#define R_386_32PLT 11 ++#define R_386_TLS_TPOFF 14 /* Offset in static TLS block */ ++#define R_386_TLS_IE 15 /* Address of GOT entry for static TLS ++ block offset */ ++#define R_386_TLS_GOTIE 16 /* GOT entry for static TLS block ++ offset */ ++#define R_386_TLS_LE 17 /* Offset relative to static TLS ++ block */ ++#define R_386_TLS_GD 18 /* Direct 32 bit for GNU version of ++ general dynamic thread local data */ ++#define R_386_TLS_LDM 19 /* Direct 32 bit for GNU version of ++ local dynamic thread local data ++ in LE code */ ++#define R_386_16 20 ++#define R_386_PC16 21 ++#define R_386_8 22 ++#define R_386_PC8 23 ++#define R_386_TLS_GD_32 24 /* Direct 32 bit for general dynamic ++ thread local data */ ++#define R_386_TLS_GD_PUSH 25 /* Tag for pushl in GD TLS code */ ++#define R_386_TLS_GD_CALL 26 /* Relocation for call to ++ __tls_get_addr() */ ++#define R_386_TLS_GD_POP 27 /* Tag for popl in GD TLS code */ ++#define R_386_TLS_LDM_32 28 /* Direct 32 bit for local dynamic ++ thread local data in LE code */ ++#define R_386_TLS_LDM_PUSH 29 /* Tag for pushl in LDM TLS code */ ++#define R_386_TLS_LDM_CALL 30 /* Relocation for call to ++ __tls_get_addr() in LDM code */ ++#define R_386_TLS_LDM_POP 31 /* Tag for popl in LDM TLS code */ ++#define R_386_TLS_LDO_32 32 /* Offset relative to TLS block */ ++#define R_386_TLS_IE_32 33 /* GOT entry for negated static TLS ++ block offset */ ++#define R_386_TLS_LE_32 34 /* Negated offset relative to static ++ TLS block */ ++#define R_386_TLS_DTPMOD32 35 /* ID of module containing symbol */ ++#define R_386_TLS_DTPOFF32 36 /* Offset in TLS block */ ++#define R_386_TLS_TPOFF32 37 /* Negated offset in static TLS block */ ++/* 38? */ ++#define R_386_TLS_GOTDESC 39 /* GOT offset for TLS descriptor. */ ++#define R_386_TLS_DESC_CALL 40 /* Marker of call through TLS ++ descriptor for ++ relaxation. */ ++#define R_386_TLS_DESC 41 /* TLS descriptor containing ++ pointer to code and to ++ argument, returning the TLS ++ offset for the symbol. */ ++#define R_386_IRELATIVE 42 /* Adjust indirectly by program base */ ++/* Keep this the last entry. */ ++#define R_386_NUM 43 ++ ++/* SUN SPARC specific definitions. */ ++ ++/* Legal values for ST_TYPE subfield of st_info (symbol type). */ ++ ++#define STT_SPARC_REGISTER 13 /* Global register reserved to app. */ ++ ++/* Values for Elf64_Ehdr.e_flags. */ ++ ++#define EF_SPARCV9_MM 3 ++#define EF_SPARCV9_TSO 0 ++#define EF_SPARCV9_PSO 1 ++#define EF_SPARCV9_RMO 2 ++#define EF_SPARC_LEDATA 0x800000 /* little endian data */ ++#define EF_SPARC_EXT_MASK 0xFFFF00 ++#define EF_SPARC_32PLUS 0x000100 /* generic V8+ features */ ++#define EF_SPARC_SUN_US1 0x000200 /* Sun UltraSPARC1 extensions */ ++#define EF_SPARC_HAL_R1 0x000400 /* HAL R1 extensions */ ++#define EF_SPARC_SUN_US3 0x000800 /* Sun UltraSPARCIII extensions */ ++ ++/* SPARC relocs. */ ++ ++#define R_SPARC_NONE 0 /* No reloc */ ++#define R_SPARC_8 1 /* Direct 8 bit */ ++#define R_SPARC_16 2 /* Direct 16 bit */ ++#define R_SPARC_32 3 /* Direct 32 bit */ ++#define R_SPARC_DISP8 4 /* PC relative 8 bit */ ++#define R_SPARC_DISP16 5 /* PC relative 16 bit */ ++#define R_SPARC_DISP32 6 /* PC relative 32 bit */ ++#define R_SPARC_WDISP30 7 /* PC relative 30 bit shifted */ ++#define R_SPARC_WDISP22 8 /* PC relative 22 bit shifted */ ++#define R_SPARC_HI22 9 /* High 22 bit */ ++#define R_SPARC_22 10 /* Direct 22 bit */ ++#define R_SPARC_13 11 /* Direct 13 bit */ ++#define R_SPARC_LO10 12 /* Truncated 10 bit */ ++#define R_SPARC_GOT10 13 /* Truncated 10 bit GOT entry */ ++#define R_SPARC_GOT13 14 /* 13 bit GOT entry */ ++#define R_SPARC_GOT22 15 /* 22 bit GOT entry shifted */ ++#define R_SPARC_PC10 16 /* PC relative 10 bit truncated */ ++#define R_SPARC_PC22 17 /* PC relative 22 bit shifted */ ++#define R_SPARC_WPLT30 18 /* 30 bit PC relative PLT address */ ++#define R_SPARC_COPY 19 /* Copy symbol at runtime */ ++#define R_SPARC_GLOB_DAT 20 /* Create GOT entry */ ++#define R_SPARC_JMP_SLOT 21 /* Create PLT entry */ ++#define R_SPARC_RELATIVE 22 /* Adjust by program base */ ++#define R_SPARC_UA32 23 /* Direct 32 bit unaligned */ ++ ++/* Additional Sparc64 relocs. */ ++ ++#define R_SPARC_PLT32 24 /* Direct 32 bit ref to PLT entry */ ++#define R_SPARC_HIPLT22 25 /* High 22 bit PLT entry */ ++#define R_SPARC_LOPLT10 26 /* Truncated 10 bit PLT entry */ ++#define R_SPARC_PCPLT32 27 /* PC rel 32 bit ref to PLT entry */ ++#define R_SPARC_PCPLT22 28 /* PC rel high 22 bit PLT entry */ ++#define R_SPARC_PCPLT10 29 /* PC rel trunc 10 bit PLT entry */ ++#define R_SPARC_10 30 /* Direct 10 bit */ ++#define R_SPARC_11 31 /* Direct 11 bit */ ++#define R_SPARC_64 32 /* Direct 64 bit */ ++#define R_SPARC_OLO10 33 /* 10bit with secondary 13bit addend */ ++#define R_SPARC_HH22 34 /* Top 22 bits of direct 64 bit */ ++#define R_SPARC_HM10 35 /* High middle 10 bits of ... */ ++#define R_SPARC_LM22 36 /* Low middle 22 bits of ... */ ++#define R_SPARC_PC_HH22 37 /* Top 22 bits of pc rel 64 bit */ ++#define R_SPARC_PC_HM10 38 /* High middle 10 bit of ... */ ++#define R_SPARC_PC_LM22 39 /* Low miggle 22 bits of ... */ ++#define R_SPARC_WDISP16 40 /* PC relative 16 bit shifted */ ++#define R_SPARC_WDISP19 41 /* PC relative 19 bit shifted */ ++#define R_SPARC_GLOB_JMP 42 /* was part of v9 ABI but was removed */ ++#define R_SPARC_7 43 /* Direct 7 bit */ ++#define R_SPARC_5 44 /* Direct 5 bit */ ++#define R_SPARC_6 45 /* Direct 6 bit */ ++#define R_SPARC_DISP64 46 /* PC relative 64 bit */ ++#define R_SPARC_PLT64 47 /* Direct 64 bit ref to PLT entry */ ++#define R_SPARC_HIX22 48 /* High 22 bit complemented */ ++#define R_SPARC_LOX10 49 /* Truncated 11 bit complemented */ ++#define R_SPARC_H44 50 /* Direct high 12 of 44 bit */ ++#define R_SPARC_M44 51 /* Direct mid 22 of 44 bit */ ++#define R_SPARC_L44 52 /* Direct low 10 of 44 bit */ ++#define R_SPARC_REGISTER 53 /* Global register usage */ ++#define R_SPARC_UA64 54 /* Direct 64 bit unaligned */ ++#define R_SPARC_UA16 55 /* Direct 16 bit unaligned */ ++#define R_SPARC_TLS_GD_HI22 56 ++#define R_SPARC_TLS_GD_LO10 57 ++#define R_SPARC_TLS_GD_ADD 58 ++#define R_SPARC_TLS_GD_CALL 59 ++#define R_SPARC_TLS_LDM_HI22 60 ++#define R_SPARC_TLS_LDM_LO10 61 ++#define R_SPARC_TLS_LDM_ADD 62 ++#define R_SPARC_TLS_LDM_CALL 63 ++#define R_SPARC_TLS_LDO_HIX22 64 ++#define R_SPARC_TLS_LDO_LOX10 65 ++#define R_SPARC_TLS_LDO_ADD 66 ++#define R_SPARC_TLS_IE_HI22 67 ++#define R_SPARC_TLS_IE_LO10 68 ++#define R_SPARC_TLS_IE_LD 69 ++#define R_SPARC_TLS_IE_LDX 70 ++#define R_SPARC_TLS_IE_ADD 71 ++#define R_SPARC_TLS_LE_HIX22 72 ++#define R_SPARC_TLS_LE_LOX10 73 ++#define R_SPARC_TLS_DTPMOD32 74 ++#define R_SPARC_TLS_DTPMOD64 75 ++#define R_SPARC_TLS_DTPOFF32 76 ++#define R_SPARC_TLS_DTPOFF64 77 ++#define R_SPARC_TLS_TPOFF32 78 ++#define R_SPARC_TLS_TPOFF64 79 ++#define R_SPARC_GOTDATA_HIX22 80 ++#define R_SPARC_GOTDATA_LOX10 81 ++#define R_SPARC_GOTDATA_OP_HIX22 82 ++#define R_SPARC_GOTDATA_OP_LOX10 83 ++#define R_SPARC_GOTDATA_OP 84 ++#define R_SPARC_H34 85 ++#define R_SPARC_SIZE32 86 ++#define R_SPARC_SIZE64 87 ++#define R_SPARC_WDISP10 88 ++#define R_SPARC_JMP_IREL 248 ++#define R_SPARC_IRELATIVE 249 ++#define R_SPARC_GNU_VTINHERIT 250 ++#define R_SPARC_GNU_VTENTRY 251 ++#define R_SPARC_REV32 252 ++/* Keep this the last entry. */ ++#define R_SPARC_NUM 253 ++ ++/* For Sparc64, legal values for d_tag of Elf64_Dyn. */ ++ ++#define DT_SPARC_REGISTER 0x70000001 ++#define DT_SPARC_NUM 2 ++ ++/* MIPS R3000 specific definitions. */ ++ ++/* Legal values for e_flags field of Elf32_Ehdr. */ ++ ++#define EF_MIPS_NOREORDER 1 /* A .noreorder directive was used */ ++#define EF_MIPS_PIC 2 /* Contains PIC code */ ++#define EF_MIPS_CPIC 4 /* Uses PIC calling sequence */ ++#define EF_MIPS_XGOT 8 ++#define EF_MIPS_64BIT_WHIRL 16 ++#define EF_MIPS_ABI2 32 ++#define EF_MIPS_ABI_ON32 64 ++#define EF_MIPS_ARCH 0xf0000000 /* MIPS architecture level */ ++ ++/* Legal values for MIPS architecture level. */ ++ ++#define EF_MIPS_ARCH_1 0x00000000 /* -mips1 code. */ ++#define EF_MIPS_ARCH_2 0x10000000 /* -mips2 code. */ ++#define EF_MIPS_ARCH_3 0x20000000 /* -mips3 code. */ ++#define EF_MIPS_ARCH_4 0x30000000 /* -mips4 code. */ ++#define EF_MIPS_ARCH_5 0x40000000 /* -mips5 code. */ ++#define EF_MIPS_ARCH_32 0x60000000 /* MIPS32 code. */ ++#define EF_MIPS_ARCH_64 0x70000000 /* MIPS64 code. */ ++ ++/* The following are non-official names and should not be used. */ ++ ++#define E_MIPS_ARCH_1 0x00000000 /* -mips1 code. */ ++#define E_MIPS_ARCH_2 0x10000000 /* -mips2 code. */ ++#define E_MIPS_ARCH_3 0x20000000 /* -mips3 code. */ ++#define E_MIPS_ARCH_4 0x30000000 /* -mips4 code. */ ++#define E_MIPS_ARCH_5 0x40000000 /* -mips5 code. */ ++#define E_MIPS_ARCH_32 0x60000000 /* MIPS32 code. */ ++#define E_MIPS_ARCH_64 0x70000000 /* MIPS64 code. */ ++ ++/* Special section indices. */ ++ ++#define SHN_MIPS_ACOMMON 0xff00 /* Allocated common symbols */ ++#define SHN_MIPS_TEXT 0xff01 /* Allocated test symbols. */ ++#define SHN_MIPS_DATA 0xff02 /* Allocated data symbols. */ ++#define SHN_MIPS_SCOMMON 0xff03 /* Small common symbols */ ++#define SHN_MIPS_SUNDEFINED 0xff04 /* Small undefined symbols */ ++ ++/* Legal values for sh_type field of Elf32_Shdr. */ ++ ++#define SHT_MIPS_LIBLIST 0x70000000 /* Shared objects used in link */ ++#define SHT_MIPS_MSYM 0x70000001 ++#define SHT_MIPS_CONFLICT 0x70000002 /* Conflicting symbols */ ++#define SHT_MIPS_GPTAB 0x70000003 /* Global data area sizes */ ++#define SHT_MIPS_UCODE 0x70000004 /* Reserved for SGI/MIPS compilers */ ++#define SHT_MIPS_DEBUG 0x70000005 /* MIPS ECOFF debugging information*/ ++#define SHT_MIPS_REGINFO 0x70000006 /* Register usage information */ ++#define SHT_MIPS_PACKAGE 0x70000007 ++#define SHT_MIPS_PACKSYM 0x70000008 ++#define SHT_MIPS_RELD 0x70000009 ++#define SHT_MIPS_IFACE 0x7000000b ++#define SHT_MIPS_CONTENT 0x7000000c ++#define SHT_MIPS_OPTIONS 0x7000000d /* Miscellaneous options. */ ++#define SHT_MIPS_SHDR 0x70000010 ++#define SHT_MIPS_FDESC 0x70000011 ++#define SHT_MIPS_EXTSYM 0x70000012 ++#define SHT_MIPS_DENSE 0x70000013 ++#define SHT_MIPS_PDESC 0x70000014 ++#define SHT_MIPS_LOCSYM 0x70000015 ++#define SHT_MIPS_AUXSYM 0x70000016 ++#define SHT_MIPS_OPTSYM 0x70000017 ++#define SHT_MIPS_LOCSTR 0x70000018 ++#define SHT_MIPS_LINE 0x70000019 ++#define SHT_MIPS_RFDESC 0x7000001a ++#define SHT_MIPS_DELTASYM 0x7000001b ++#define SHT_MIPS_DELTAINST 0x7000001c ++#define SHT_MIPS_DELTACLASS 0x7000001d ++#define SHT_MIPS_DWARF 0x7000001e /* DWARF debugging information. */ ++#define SHT_MIPS_DELTADECL 0x7000001f ++#define SHT_MIPS_SYMBOL_LIB 0x70000020 ++#define SHT_MIPS_EVENTS 0x70000021 /* Event section. */ ++#define SHT_MIPS_TRANSLATE 0x70000022 ++#define SHT_MIPS_PIXIE 0x70000023 ++#define SHT_MIPS_XLATE 0x70000024 ++#define SHT_MIPS_XLATE_DEBUG 0x70000025 ++#define SHT_MIPS_WHIRL 0x70000026 ++#define SHT_MIPS_EH_REGION 0x70000027 ++#define SHT_MIPS_XLATE_OLD 0x70000028 ++#define SHT_MIPS_PDR_EXCEPTION 0x70000029 ++ ++/* Legal values for sh_flags field of Elf32_Shdr. */ ++ ++#define SHF_MIPS_GPREL 0x10000000 /* Must be part of global data area */ ++#define SHF_MIPS_MERGE 0x20000000 ++#define SHF_MIPS_ADDR 0x40000000 ++#define SHF_MIPS_STRINGS 0x80000000 ++#define SHF_MIPS_NOSTRIP 0x08000000 ++#define SHF_MIPS_LOCAL 0x04000000 ++#define SHF_MIPS_NAMES 0x02000000 ++#define SHF_MIPS_NODUPE 0x01000000 ++ ++ ++/* Symbol tables. */ ++ ++/* MIPS specific values for `st_other'. */ ++#define STO_MIPS_DEFAULT 0x0 ++#define STO_MIPS_INTERNAL 0x1 ++#define STO_MIPS_HIDDEN 0x2 ++#define STO_MIPS_PROTECTED 0x3 ++#define STO_MIPS_PLT 0x8 ++#define STO_MIPS_SC_ALIGN_UNUSED 0xff ++ ++/* MIPS specific values for `st_info'. */ ++#define STB_MIPS_SPLIT_COMMON 13 ++ ++/* Entries found in sections of type SHT_MIPS_GPTAB. */ ++ ++typedef union ++{ ++ struct ++ { ++ Elf32_Word gt_current_g_value; /* -G value used for compilation */ ++ Elf32_Word gt_unused; /* Not used */ ++ } gt_header; /* First entry in section */ ++ struct ++ { ++ Elf32_Word gt_g_value; /* If this value were used for -G */ ++ Elf32_Word gt_bytes; /* This many bytes would be used */ ++ } gt_entry; /* Subsequent entries in section */ ++} Elf32_gptab; ++ ++/* Entry found in sections of type SHT_MIPS_REGINFO. */ ++ ++typedef struct ++{ ++ Elf32_Word ri_gprmask; /* General registers used */ ++ Elf32_Word ri_cprmask[4]; /* Coprocessor registers used */ ++ Elf32_Sword ri_gp_value; /* $gp register value */ ++} Elf32_RegInfo; ++ ++/* Entries found in sections of type SHT_MIPS_OPTIONS. */ ++ ++typedef struct ++{ ++ unsigned char kind; /* Determines interpretation of the ++ variable part of descriptor. */ ++ unsigned char size; /* Size of descriptor, including header. */ ++ Elf32_Section section; /* Section header index of section affected, ++ 0 for global options. */ ++ Elf32_Word info; /* Kind-specific information. */ ++} Elf_Options; ++ ++/* Values for `kind' field in Elf_Options. */ ++ ++#define ODK_NULL 0 /* Undefined. */ ++#define ODK_REGINFO 1 /* Register usage information. */ ++#define ODK_EXCEPTIONS 2 /* Exception processing options. */ ++#define ODK_PAD 3 /* Section padding options. */ ++#define ODK_HWPATCH 4 /* Hardware workarounds performed */ ++#define ODK_FILL 5 /* record the fill value used by the linker. */ ++#define ODK_TAGS 6 /* reserve space for desktop tools to write. */ ++#define ODK_HWAND 7 /* HW workarounds. 'AND' bits when merging. */ ++#define ODK_HWOR 8 /* HW workarounds. 'OR' bits when merging. */ ++ ++/* Values for `info' in Elf_Options for ODK_EXCEPTIONS entries. */ ++ ++#define OEX_FPU_MIN 0x1f /* FPE's which MUST be enabled. */ ++#define OEX_FPU_MAX 0x1f00 /* FPE's which MAY be enabled. */ ++#define OEX_PAGE0 0x10000 /* page zero must be mapped. */ ++#define OEX_SMM 0x20000 /* Force sequential memory mode? */ ++#define OEX_FPDBUG 0x40000 /* Force floating point debug mode? */ ++#define OEX_PRECISEFP OEX_FPDBUG ++#define OEX_DISMISS 0x80000 /* Dismiss invalid address faults? */ ++ ++#define OEX_FPU_INVAL 0x10 ++#define OEX_FPU_DIV0 0x08 ++#define OEX_FPU_OFLO 0x04 ++#define OEX_FPU_UFLO 0x02 ++#define OEX_FPU_INEX 0x01 ++ ++/* Masks for `info' in Elf_Options for an ODK_HWPATCH entry. */ ++ ++#define OHW_R4KEOP 0x1 /* R4000 end-of-page patch. */ ++#define OHW_R8KPFETCH 0x2 /* may need R8000 prefetch patch. */ ++#define OHW_R5KEOP 0x4 /* R5000 end-of-page patch. */ ++#define OHW_R5KCVTL 0x8 /* R5000 cvt.[ds].l bug. clean=1. */ ++ ++#define OPAD_PREFIX 0x1 ++#define OPAD_POSTFIX 0x2 ++#define OPAD_SYMBOL 0x4 ++ ++/* Entry found in `.options' section. */ ++ ++typedef struct ++{ ++ Elf32_Word hwp_flags1; /* Extra flags. */ ++ Elf32_Word hwp_flags2; /* Extra flags. */ ++} Elf_Options_Hw; ++ ++/* Masks for `info' in ElfOptions for ODK_HWAND and ODK_HWOR entries. */ ++ ++#define OHWA0_R4KEOP_CHECKED 0x00000001 ++#define OHWA1_R4KEOP_CLEAN 0x00000002 ++ ++/* MIPS relocs. */ ++ ++#define R_MIPS_NONE 0 /* No reloc */ ++#define R_MIPS_16 1 /* Direct 16 bit */ ++#define R_MIPS_32 2 /* Direct 32 bit */ ++#define R_MIPS_REL32 3 /* PC relative 32 bit */ ++#define R_MIPS_26 4 /* Direct 26 bit shifted */ ++#define R_MIPS_HI16 5 /* High 16 bit */ ++#define R_MIPS_LO16 6 /* Low 16 bit */ ++#define R_MIPS_GPREL16 7 /* GP relative 16 bit */ ++#define R_MIPS_LITERAL 8 /* 16 bit literal entry */ ++#define R_MIPS_GOT16 9 /* 16 bit GOT entry */ ++#define R_MIPS_PC16 10 /* PC relative 16 bit */ ++#define R_MIPS_CALL16 11 /* 16 bit GOT entry for function */ ++#define R_MIPS_GPREL32 12 /* GP relative 32 bit */ ++ ++#define R_MIPS_SHIFT5 16 ++#define R_MIPS_SHIFT6 17 ++#define R_MIPS_64 18 ++#define R_MIPS_GOT_DISP 19 ++#define R_MIPS_GOT_PAGE 20 ++#define R_MIPS_GOT_OFST 21 ++#define R_MIPS_GOT_HI16 22 ++#define R_MIPS_GOT_LO16 23 ++#define R_MIPS_SUB 24 ++#define R_MIPS_INSERT_A 25 ++#define R_MIPS_INSERT_B 26 ++#define R_MIPS_DELETE 27 ++#define R_MIPS_HIGHER 28 ++#define R_MIPS_HIGHEST 29 ++#define R_MIPS_CALL_HI16 30 ++#define R_MIPS_CALL_LO16 31 ++#define R_MIPS_SCN_DISP 32 ++#define R_MIPS_REL16 33 ++#define R_MIPS_ADD_IMMEDIATE 34 ++#define R_MIPS_PJUMP 35 ++#define R_MIPS_RELGOT 36 ++#define R_MIPS_JALR 37 ++#define R_MIPS_TLS_DTPMOD32 38 /* Module number 32 bit */ ++#define R_MIPS_TLS_DTPREL32 39 /* Module-relative offset 32 bit */ ++#define R_MIPS_TLS_DTPMOD64 40 /* Module number 64 bit */ ++#define R_MIPS_TLS_DTPREL64 41 /* Module-relative offset 64 bit */ ++#define R_MIPS_TLS_GD 42 /* 16 bit GOT offset for GD */ ++#define R_MIPS_TLS_LDM 43 /* 16 bit GOT offset for LDM */ ++#define R_MIPS_TLS_DTPREL_HI16 44 /* Module-relative offset, high 16 bits */ ++#define R_MIPS_TLS_DTPREL_LO16 45 /* Module-relative offset, low 16 bits */ ++#define R_MIPS_TLS_GOTTPREL 46 /* 16 bit GOT offset for IE */ ++#define R_MIPS_TLS_TPREL32 47 /* TP-relative offset, 32 bit */ ++#define R_MIPS_TLS_TPREL64 48 /* TP-relative offset, 64 bit */ ++#define R_MIPS_TLS_TPREL_HI16 49 /* TP-relative offset, high 16 bits */ ++#define R_MIPS_TLS_TPREL_LO16 50 /* TP-relative offset, low 16 bits */ ++#define R_MIPS_GLOB_DAT 51 ++#define R_MIPS_COPY 126 ++#define R_MIPS_JUMP_SLOT 127 ++/* Keep this the last entry. */ ++#define R_MIPS_NUM 128 ++ ++/* Legal values for p_type field of Elf32_Phdr. */ ++ ++#define PT_MIPS_REGINFO 0x70000000 /* Register usage information */ ++#define PT_MIPS_RTPROC 0x70000001 /* Runtime procedure table. */ ++#define PT_MIPS_OPTIONS 0x70000002 ++ ++/* Special program header types. */ ++ ++#define PF_MIPS_LOCAL 0x10000000 ++ ++/* Legal values for d_tag field of Elf32_Dyn. */ ++ ++#define DT_MIPS_RLD_VERSION 0x70000001 /* Runtime linker interface version */ ++#define DT_MIPS_TIME_STAMP 0x70000002 /* Timestamp */ ++#define DT_MIPS_ICHECKSUM 0x70000003 /* Checksum */ ++#define DT_MIPS_IVERSION 0x70000004 /* Version string (string tbl index) */ ++#define DT_MIPS_FLAGS 0x70000005 /* Flags */ ++#define DT_MIPS_BASE_ADDRESS 0x70000006 /* Base address */ ++#define DT_MIPS_MSYM 0x70000007 ++#define DT_MIPS_CONFLICT 0x70000008 /* Address of CONFLICT section */ ++#define DT_MIPS_LIBLIST 0x70000009 /* Address of LIBLIST section */ ++#define DT_MIPS_LOCAL_GOTNO 0x7000000a /* Number of local GOT entries */ ++#define DT_MIPS_CONFLICTNO 0x7000000b /* Number of CONFLICT entries */ ++#define DT_MIPS_LIBLISTNO 0x70000010 /* Number of LIBLIST entries */ ++#define DT_MIPS_SYMTABNO 0x70000011 /* Number of DYNSYM entries */ ++#define DT_MIPS_UNREFEXTNO 0x70000012 /* First external DYNSYM */ ++#define DT_MIPS_GOTSYM 0x70000013 /* First GOT entry in DYNSYM */ ++#define DT_MIPS_HIPAGENO 0x70000014 /* Number of GOT page table entries */ ++#define DT_MIPS_RLD_MAP 0x70000016 /* Address of run time loader map. */ ++#define DT_MIPS_DELTA_CLASS 0x70000017 /* Delta C++ class definition. */ ++#define DT_MIPS_DELTA_CLASS_NO 0x70000018 /* Number of entries in ++ DT_MIPS_DELTA_CLASS. */ ++#define DT_MIPS_DELTA_INSTANCE 0x70000019 /* Delta C++ class instances. */ ++#define DT_MIPS_DELTA_INSTANCE_NO 0x7000001a /* Number of entries in ++ DT_MIPS_DELTA_INSTANCE. */ ++#define DT_MIPS_DELTA_RELOC 0x7000001b /* Delta relocations. */ ++#define DT_MIPS_DELTA_RELOC_NO 0x7000001c /* Number of entries in ++ DT_MIPS_DELTA_RELOC. */ ++#define DT_MIPS_DELTA_SYM 0x7000001d /* Delta symbols that Delta ++ relocations refer to. */ ++#define DT_MIPS_DELTA_SYM_NO 0x7000001e /* Number of entries in ++ DT_MIPS_DELTA_SYM. */ ++#define DT_MIPS_DELTA_CLASSSYM 0x70000020 /* Delta symbols that hold the ++ class declaration. */ ++#define DT_MIPS_DELTA_CLASSSYM_NO 0x70000021 /* Number of entries in ++ DT_MIPS_DELTA_CLASSSYM. */ ++#define DT_MIPS_CXX_FLAGS 0x70000022 /* Flags indicating for C++ flavor. */ ++#define DT_MIPS_PIXIE_INIT 0x70000023 ++#define DT_MIPS_SYMBOL_LIB 0x70000024 ++#define DT_MIPS_LOCALPAGE_GOTIDX 0x70000025 ++#define DT_MIPS_LOCAL_GOTIDX 0x70000026 ++#define DT_MIPS_HIDDEN_GOTIDX 0x70000027 ++#define DT_MIPS_PROTECTED_GOTIDX 0x70000028 ++#define DT_MIPS_OPTIONS 0x70000029 /* Address of .options. */ ++#define DT_MIPS_INTERFACE 0x7000002a /* Address of .interface. */ ++#define DT_MIPS_DYNSTR_ALIGN 0x7000002b ++#define DT_MIPS_INTERFACE_SIZE 0x7000002c /* Size of the .interface section. */ ++#define DT_MIPS_RLD_TEXT_RESOLVE_ADDR 0x7000002d /* Address of rld_text_rsolve ++ function stored in GOT. */ ++#define DT_MIPS_PERF_SUFFIX 0x7000002e /* Default suffix of dso to be added ++ by rld on dlopen() calls. */ ++#define DT_MIPS_COMPACT_SIZE 0x7000002f /* (O32)Size of compact rel section. */ ++#define DT_MIPS_GP_VALUE 0x70000030 /* GP value for aux GOTs. */ ++#define DT_MIPS_AUX_DYNAMIC 0x70000031 /* Address of aux .dynamic. */ ++/* The address of .got.plt in an executable using the new non-PIC ABI. */ ++#define DT_MIPS_PLTGOT 0x70000032 ++/* The base of the PLT in an executable using the new non-PIC ABI if that ++ PLT is writable. For a non-writable PLT, this is omitted or has a zero ++ value. */ ++#define DT_MIPS_RWPLT 0x70000034 ++#define DT_MIPS_NUM 0x35 ++ ++/* Legal values for DT_MIPS_FLAGS Elf32_Dyn entry. */ ++ ++#define RHF_NONE 0 /* No flags */ ++#define RHF_QUICKSTART (1 << 0) /* Use quickstart */ ++#define RHF_NOTPOT (1 << 1) /* Hash size not power of 2 */ ++#define RHF_NO_LIBRARY_REPLACEMENT (1 << 2) /* Ignore LD_LIBRARY_PATH */ ++#define RHF_NO_MOVE (1 << 3) ++#define RHF_SGI_ONLY (1 << 4) ++#define RHF_GUARANTEE_INIT (1 << 5) ++#define RHF_DELTA_C_PLUS_PLUS (1 << 6) ++#define RHF_GUARANTEE_START_INIT (1 << 7) ++#define RHF_PIXIE (1 << 8) ++#define RHF_DEFAULT_DELAY_LOAD (1 << 9) ++#define RHF_REQUICKSTART (1 << 10) ++#define RHF_REQUICKSTARTED (1 << 11) ++#define RHF_CORD (1 << 12) ++#define RHF_NO_UNRES_UNDEF (1 << 13) ++#define RHF_RLD_ORDER_SAFE (1 << 14) ++ ++/* Entries found in sections of type SHT_MIPS_LIBLIST. */ ++ ++typedef struct ++{ ++ Elf32_Word l_name; /* Name (string table index) */ ++ Elf32_Word l_time_stamp; /* Timestamp */ ++ Elf32_Word l_checksum; /* Checksum */ ++ Elf32_Word l_version; /* Interface version */ ++ Elf32_Word l_flags; /* Flags */ ++} Elf32_Lib; ++ ++typedef struct ++{ ++ Elf64_Word l_name; /* Name (string table index) */ ++ Elf64_Word l_time_stamp; /* Timestamp */ ++ Elf64_Word l_checksum; /* Checksum */ ++ Elf64_Word l_version; /* Interface version */ ++ Elf64_Word l_flags; /* Flags */ ++} Elf64_Lib; ++ ++ ++/* Legal values for l_flags. */ ++ ++#define LL_NONE 0 ++#define LL_EXACT_MATCH (1 << 0) /* Require exact match */ ++#define LL_IGNORE_INT_VER (1 << 1) /* Ignore interface version */ ++#define LL_REQUIRE_MINOR (1 << 2) ++#define LL_EXPORTS (1 << 3) ++#define LL_DELAY_LOAD (1 << 4) ++#define LL_DELTA (1 << 5) ++ ++/* Entries found in sections of type SHT_MIPS_CONFLICT. */ ++ ++typedef Elf32_Addr Elf32_Conflict; ++ ++ ++/* HPPA specific definitions. */ ++ ++/* Legal values for e_flags field of Elf32_Ehdr. */ ++ ++#define EF_PARISC_TRAPNIL 0x00010000 /* Trap nil pointer dereference. */ ++#define EF_PARISC_EXT 0x00020000 /* Program uses arch. extensions. */ ++#define EF_PARISC_LSB 0x00040000 /* Program expects little endian. */ ++#define EF_PARISC_WIDE 0x00080000 /* Program expects wide mode. */ ++#define EF_PARISC_NO_KABP 0x00100000 /* No kernel assisted branch ++ prediction. */ ++#define EF_PARISC_LAZYSWAP 0x00400000 /* Allow lazy swapping. */ ++#define EF_PARISC_ARCH 0x0000ffff /* Architecture version. */ ++ ++/* Defined values for `e_flags & EF_PARISC_ARCH' are: */ ++ ++#define EFA_PARISC_1_0 0x020b /* PA-RISC 1.0 big-endian. */ ++#define EFA_PARISC_1_1 0x0210 /* PA-RISC 1.1 big-endian. */ ++#define EFA_PARISC_2_0 0x0214 /* PA-RISC 2.0 big-endian. */ ++ ++/* Additional section indeces. */ ++ ++#define SHN_PARISC_ANSI_COMMON 0xff00 /* Section for tenatively declared ++ symbols in ANSI C. */ ++#define SHN_PARISC_HUGE_COMMON 0xff01 /* Common blocks in huge model. */ ++ ++/* Legal values for sh_type field of Elf32_Shdr. */ ++ ++#define SHT_PARISC_EXT 0x70000000 /* Contains product specific ext. */ ++#define SHT_PARISC_UNWIND 0x70000001 /* Unwind information. */ ++#define SHT_PARISC_DOC 0x70000002 /* Debug info for optimized code. */ ++ ++/* Legal values for sh_flags field of Elf32_Shdr. */ ++ ++#define SHF_PARISC_SHORT 0x20000000 /* Section with short addressing. */ ++#define SHF_PARISC_HUGE 0x40000000 /* Section far from gp. */ ++#define SHF_PARISC_SBP 0x80000000 /* Static branch prediction code. */ ++ ++/* Legal values for ST_TYPE subfield of st_info (symbol type). */ ++ ++#define STT_PARISC_MILLICODE 13 /* Millicode function entry point. */ ++ ++#define STT_HP_OPAQUE (STT_LOOS + 0x1) ++#define STT_HP_STUB (STT_LOOS + 0x2) ++ ++/* HPPA relocs. */ ++ ++#define R_PARISC_NONE 0 /* No reloc. */ ++#define R_PARISC_DIR32 1 /* Direct 32-bit reference. */ ++#define R_PARISC_DIR21L 2 /* Left 21 bits of eff. address. */ ++#define R_PARISC_DIR17R 3 /* Right 17 bits of eff. address. */ ++#define R_PARISC_DIR17F 4 /* 17 bits of eff. address. */ ++#define R_PARISC_DIR14R 6 /* Right 14 bits of eff. address. */ ++#define R_PARISC_PCREL32 9 /* 32-bit rel. address. */ ++#define R_PARISC_PCREL21L 10 /* Left 21 bits of rel. address. */ ++#define R_PARISC_PCREL17R 11 /* Right 17 bits of rel. address. */ ++#define R_PARISC_PCREL17F 12 /* 17 bits of rel. address. */ ++#define R_PARISC_PCREL14R 14 /* Right 14 bits of rel. address. */ ++#define R_PARISC_DPREL21L 18 /* Left 21 bits of rel. address. */ ++#define R_PARISC_DPREL14R 22 /* Right 14 bits of rel. address. */ ++#define R_PARISC_GPREL21L 26 /* GP-relative, left 21 bits. */ ++#define R_PARISC_GPREL14R 30 /* GP-relative, right 14 bits. */ ++#define R_PARISC_LTOFF21L 34 /* LT-relative, left 21 bits. */ ++#define R_PARISC_LTOFF14R 38 /* LT-relative, right 14 bits. */ ++#define R_PARISC_SECREL32 41 /* 32 bits section rel. address. */ ++#define R_PARISC_SEGBASE 48 /* No relocation, set segment base. */ ++#define R_PARISC_SEGREL32 49 /* 32 bits segment rel. address. */ ++#define R_PARISC_PLTOFF21L 50 /* PLT rel. address, left 21 bits. */ ++#define R_PARISC_PLTOFF14R 54 /* PLT rel. address, right 14 bits. */ ++#define R_PARISC_LTOFF_FPTR32 57 /* 32 bits LT-rel. function pointer. */ ++#define R_PARISC_LTOFF_FPTR21L 58 /* LT-rel. fct ptr, left 21 bits. */ ++#define R_PARISC_LTOFF_FPTR14R 62 /* LT-rel. fct ptr, right 14 bits. */ ++#define R_PARISC_FPTR64 64 /* 64 bits function address. */ ++#define R_PARISC_PLABEL32 65 /* 32 bits function address. */ ++#define R_PARISC_PLABEL21L 66 /* Left 21 bits of fdesc address. */ ++#define R_PARISC_PLABEL14R 70 /* Right 14 bits of fdesc address. */ ++#define R_PARISC_PCREL64 72 /* 64 bits PC-rel. address. */ ++#define R_PARISC_PCREL22F 74 /* 22 bits PC-rel. address. */ ++#define R_PARISC_PCREL14WR 75 /* PC-rel. address, right 14 bits. */ ++#define R_PARISC_PCREL14DR 76 /* PC rel. address, right 14 bits. */ ++#define R_PARISC_PCREL16F 77 /* 16 bits PC-rel. address. */ ++#define R_PARISC_PCREL16WF 78 /* 16 bits PC-rel. address. */ ++#define R_PARISC_PCREL16DF 79 /* 16 bits PC-rel. address. */ ++#define R_PARISC_DIR64 80 /* 64 bits of eff. address. */ ++#define R_PARISC_DIR14WR 83 /* 14 bits of eff. address. */ ++#define R_PARISC_DIR14DR 84 /* 14 bits of eff. address. */ ++#define R_PARISC_DIR16F 85 /* 16 bits of eff. address. */ ++#define R_PARISC_DIR16WF 86 /* 16 bits of eff. address. */ ++#define R_PARISC_DIR16DF 87 /* 16 bits of eff. address. */ ++#define R_PARISC_GPREL64 88 /* 64 bits of GP-rel. address. */ ++#define R_PARISC_GPREL14WR 91 /* GP-rel. address, right 14 bits. */ ++#define R_PARISC_GPREL14DR 92 /* GP-rel. address, right 14 bits. */ ++#define R_PARISC_GPREL16F 93 /* 16 bits GP-rel. address. */ ++#define R_PARISC_GPREL16WF 94 /* 16 bits GP-rel. address. */ ++#define R_PARISC_GPREL16DF 95 /* 16 bits GP-rel. address. */ ++#define R_PARISC_LTOFF64 96 /* 64 bits LT-rel. address. */ ++#define R_PARISC_LTOFF14WR 99 /* LT-rel. address, right 14 bits. */ ++#define R_PARISC_LTOFF14DR 100 /* LT-rel. address, right 14 bits. */ ++#define R_PARISC_LTOFF16F 101 /* 16 bits LT-rel. address. */ ++#define R_PARISC_LTOFF16WF 102 /* 16 bits LT-rel. address. */ ++#define R_PARISC_LTOFF16DF 103 /* 16 bits LT-rel. address. */ ++#define R_PARISC_SECREL64 104 /* 64 bits section rel. address. */ ++#define R_PARISC_SEGREL64 112 /* 64 bits segment rel. address. */ ++#define R_PARISC_PLTOFF14WR 115 /* PLT-rel. address, right 14 bits. */ ++#define R_PARISC_PLTOFF14DR 116 /* PLT-rel. address, right 14 bits. */ ++#define R_PARISC_PLTOFF16F 117 /* 16 bits LT-rel. address. */ ++#define R_PARISC_PLTOFF16WF 118 /* 16 bits PLT-rel. address. */ ++#define R_PARISC_PLTOFF16DF 119 /* 16 bits PLT-rel. address. */ ++#define R_PARISC_LTOFF_FPTR64 120 /* 64 bits LT-rel. function ptr. */ ++#define R_PARISC_LTOFF_FPTR14WR 123 /* LT-rel. fct. ptr., right 14 bits. */ ++#define R_PARISC_LTOFF_FPTR14DR 124 /* LT-rel. fct. ptr., right 14 bits. */ ++#define R_PARISC_LTOFF_FPTR16F 125 /* 16 bits LT-rel. function ptr. */ ++#define R_PARISC_LTOFF_FPTR16WF 126 /* 16 bits LT-rel. function ptr. */ ++#define R_PARISC_LTOFF_FPTR16DF 127 /* 16 bits LT-rel. function ptr. */ ++#define R_PARISC_LORESERVE 128 ++#define R_PARISC_COPY 128 /* Copy relocation. */ ++#define R_PARISC_IPLT 129 /* Dynamic reloc, imported PLT */ ++#define R_PARISC_EPLT 130 /* Dynamic reloc, exported PLT */ ++#define R_PARISC_TPREL32 153 /* 32 bits TP-rel. address. */ ++#define R_PARISC_TPREL21L 154 /* TP-rel. address, left 21 bits. */ ++#define R_PARISC_TPREL14R 158 /* TP-rel. address, right 14 bits. */ ++#define R_PARISC_LTOFF_TP21L 162 /* LT-TP-rel. address, left 21 bits. */ ++#define R_PARISC_LTOFF_TP14R 166 /* LT-TP-rel. address, right 14 bits.*/ ++#define R_PARISC_LTOFF_TP14F 167 /* 14 bits LT-TP-rel. address. */ ++#define R_PARISC_TPREL64 216 /* 64 bits TP-rel. address. */ ++#define R_PARISC_TPREL14WR 219 /* TP-rel. address, right 14 bits. */ ++#define R_PARISC_TPREL14DR 220 /* TP-rel. address, right 14 bits. */ ++#define R_PARISC_TPREL16F 221 /* 16 bits TP-rel. address. */ ++#define R_PARISC_TPREL16WF 222 /* 16 bits TP-rel. address. */ ++#define R_PARISC_TPREL16DF 223 /* 16 bits TP-rel. address. */ ++#define R_PARISC_LTOFF_TP64 224 /* 64 bits LT-TP-rel. address. */ ++#define R_PARISC_LTOFF_TP14WR 227 /* LT-TP-rel. address, right 14 bits.*/ ++#define R_PARISC_LTOFF_TP14DR 228 /* LT-TP-rel. address, right 14 bits.*/ ++#define R_PARISC_LTOFF_TP16F 229 /* 16 bits LT-TP-rel. address. */ ++#define R_PARISC_LTOFF_TP16WF 230 /* 16 bits LT-TP-rel. address. */ ++#define R_PARISC_LTOFF_TP16DF 231 /* 16 bits LT-TP-rel. address. */ ++#define R_PARISC_GNU_VTENTRY 232 ++#define R_PARISC_GNU_VTINHERIT 233 ++#define R_PARISC_TLS_GD21L 234 /* GD 21-bit left. */ ++#define R_PARISC_TLS_GD14R 235 /* GD 14-bit right. */ ++#define R_PARISC_TLS_GDCALL 236 /* GD call to __t_g_a. */ ++#define R_PARISC_TLS_LDM21L 237 /* LD module 21-bit left. */ ++#define R_PARISC_TLS_LDM14R 238 /* LD module 14-bit right. */ ++#define R_PARISC_TLS_LDMCALL 239 /* LD module call to __t_g_a. */ ++#define R_PARISC_TLS_LDO21L 240 /* LD offset 21-bit left. */ ++#define R_PARISC_TLS_LDO14R 241 /* LD offset 14-bit right. */ ++#define R_PARISC_TLS_DTPMOD32 242 /* DTP module 32-bit. */ ++#define R_PARISC_TLS_DTPMOD64 243 /* DTP module 64-bit. */ ++#define R_PARISC_TLS_DTPOFF32 244 /* DTP offset 32-bit. */ ++#define R_PARISC_TLS_DTPOFF64 245 /* DTP offset 32-bit. */ ++#define R_PARISC_TLS_LE21L R_PARISC_TPREL21L ++#define R_PARISC_TLS_LE14R R_PARISC_TPREL14R ++#define R_PARISC_TLS_IE21L R_PARISC_LTOFF_TP21L ++#define R_PARISC_TLS_IE14R R_PARISC_LTOFF_TP14R ++#define R_PARISC_TLS_TPREL32 R_PARISC_TPREL32 ++#define R_PARISC_TLS_TPREL64 R_PARISC_TPREL64 ++#define R_PARISC_HIRESERVE 255 ++ ++/* Legal values for p_type field of Elf32_Phdr/Elf64_Phdr. */ ++ ++#define PT_HP_TLS (PT_LOOS + 0x0) ++#define PT_HP_CORE_NONE (PT_LOOS + 0x1) ++#define PT_HP_CORE_VERSION (PT_LOOS + 0x2) ++#define PT_HP_CORE_KERNEL (PT_LOOS + 0x3) ++#define PT_HP_CORE_COMM (PT_LOOS + 0x4) ++#define PT_HP_CORE_PROC (PT_LOOS + 0x5) ++#define PT_HP_CORE_LOADABLE (PT_LOOS + 0x6) ++#define PT_HP_CORE_STACK (PT_LOOS + 0x7) ++#define PT_HP_CORE_SHM (PT_LOOS + 0x8) ++#define PT_HP_CORE_MMF (PT_LOOS + 0x9) ++#define PT_HP_PARALLEL (PT_LOOS + 0x10) ++#define PT_HP_FASTBIND (PT_LOOS + 0x11) ++#define PT_HP_OPT_ANNOT (PT_LOOS + 0x12) ++#define PT_HP_HSL_ANNOT (PT_LOOS + 0x13) ++#define PT_HP_STACK (PT_LOOS + 0x14) ++ ++#define PT_PARISC_ARCHEXT 0x70000000 ++#define PT_PARISC_UNWIND 0x70000001 ++ ++/* Legal values for p_flags field of Elf32_Phdr/Elf64_Phdr. */ ++ ++#define PF_PARISC_SBP 0x08000000 ++ ++#define PF_HP_PAGE_SIZE 0x00100000 ++#define PF_HP_FAR_SHARED 0x00200000 ++#define PF_HP_NEAR_SHARED 0x00400000 ++#define PF_HP_CODE 0x01000000 ++#define PF_HP_MODIFY 0x02000000 ++#define PF_HP_LAZYSWAP 0x04000000 ++#define PF_HP_SBP 0x08000000 ++ ++ ++/* Alpha specific definitions. */ ++ ++/* Legal values for e_flags field of Elf64_Ehdr. */ ++ ++#define EF_ALPHA_32BIT 1 /* All addresses must be < 2GB. */ ++#define EF_ALPHA_CANRELAX 2 /* Relocations for relaxing exist. */ ++ ++/* Legal values for sh_type field of Elf64_Shdr. */ ++ ++/* These two are primerily concerned with ECOFF debugging info. */ ++#define SHT_ALPHA_DEBUG 0x70000001 ++#define SHT_ALPHA_REGINFO 0x70000002 ++ ++/* Legal values for sh_flags field of Elf64_Shdr. */ ++ ++#define SHF_ALPHA_GPREL 0x10000000 ++ ++/* Legal values for st_other field of Elf64_Sym. */ ++#define STO_ALPHA_NOPV 0x80 /* No PV required. */ ++#define STO_ALPHA_STD_GPLOAD 0x88 /* PV only used for initial ldgp. */ ++ ++/* Alpha relocs. */ ++ ++#define R_ALPHA_NONE 0 /* No reloc */ ++#define R_ALPHA_REFLONG 1 /* Direct 32 bit */ ++#define R_ALPHA_REFQUAD 2 /* Direct 64 bit */ ++#define R_ALPHA_GPREL32 3 /* GP relative 32 bit */ ++#define R_ALPHA_LITERAL 4 /* GP relative 16 bit w/optimization */ ++#define R_ALPHA_LITUSE 5 /* Optimization hint for LITERAL */ ++#define R_ALPHA_GPDISP 6 /* Add displacement to GP */ ++#define R_ALPHA_BRADDR 7 /* PC+4 relative 23 bit shifted */ ++#define R_ALPHA_HINT 8 /* PC+4 relative 16 bit shifted */ ++#define R_ALPHA_SREL16 9 /* PC relative 16 bit */ ++#define R_ALPHA_SREL32 10 /* PC relative 32 bit */ ++#define R_ALPHA_SREL64 11 /* PC relative 64 bit */ ++#define R_ALPHA_GPRELHIGH 17 /* GP relative 32 bit, high 16 bits */ ++#define R_ALPHA_GPRELLOW 18 /* GP relative 32 bit, low 16 bits */ ++#define R_ALPHA_GPREL16 19 /* GP relative 16 bit */ ++#define R_ALPHA_COPY 24 /* Copy symbol at runtime */ ++#define R_ALPHA_GLOB_DAT 25 /* Create GOT entry */ ++#define R_ALPHA_JMP_SLOT 26 /* Create PLT entry */ ++#define R_ALPHA_RELATIVE 27 /* Adjust by program base */ ++#define R_ALPHA_TLS_GD_HI 28 ++#define R_ALPHA_TLSGD 29 ++#define R_ALPHA_TLS_LDM 30 ++#define R_ALPHA_DTPMOD64 31 ++#define R_ALPHA_GOTDTPREL 32 ++#define R_ALPHA_DTPREL64 33 ++#define R_ALPHA_DTPRELHI 34 ++#define R_ALPHA_DTPRELLO 35 ++#define R_ALPHA_DTPREL16 36 ++#define R_ALPHA_GOTTPREL 37 ++#define R_ALPHA_TPREL64 38 ++#define R_ALPHA_TPRELHI 39 ++#define R_ALPHA_TPRELLO 40 ++#define R_ALPHA_TPREL16 41 ++/* Keep this the last entry. */ ++#define R_ALPHA_NUM 46 ++ ++/* Magic values of the LITUSE relocation addend. */ ++#define LITUSE_ALPHA_ADDR 0 ++#define LITUSE_ALPHA_BASE 1 ++#define LITUSE_ALPHA_BYTOFF 2 ++#define LITUSE_ALPHA_JSR 3 ++#define LITUSE_ALPHA_TLS_GD 4 ++#define LITUSE_ALPHA_TLS_LDM 5 ++ ++/* Legal values for d_tag of Elf64_Dyn. */ ++#define DT_ALPHA_PLTRO (DT_LOPROC + 0) ++#define DT_ALPHA_NUM 1 ++ ++/* PowerPC specific declarations */ ++ ++/* Values for Elf32/64_Ehdr.e_flags. */ ++#define EF_PPC_EMB 0x80000000 /* PowerPC embedded flag */ ++ ++/* Cygnus local bits below */ ++#define EF_PPC_RELOCATABLE 0x00010000 /* PowerPC -mrelocatable flag*/ ++#define EF_PPC_RELOCATABLE_LIB 0x00008000 /* PowerPC -mrelocatable-lib ++ flag */ ++ ++/* PowerPC relocations defined by the ABIs */ ++#define R_PPC_NONE 0 ++#define R_PPC_ADDR32 1 /* 32bit absolute address */ ++#define R_PPC_ADDR24 2 /* 26bit address, 2 bits ignored. */ ++#define R_PPC_ADDR16 3 /* 16bit absolute address */ ++#define R_PPC_ADDR16_LO 4 /* lower 16bit of absolute address */ ++#define R_PPC_ADDR16_HI 5 /* high 16bit of absolute address */ ++#define R_PPC_ADDR16_HA 6 /* adjusted high 16bit */ ++#define R_PPC_ADDR14 7 /* 16bit address, 2 bits ignored */ ++#define R_PPC_ADDR14_BRTAKEN 8 ++#define R_PPC_ADDR14_BRNTAKEN 9 ++#define R_PPC_REL24 10 /* PC relative 26 bit */ ++#define R_PPC_REL14 11 /* PC relative 16 bit */ ++#define R_PPC_REL14_BRTAKEN 12 ++#define R_PPC_REL14_BRNTAKEN 13 ++#define R_PPC_GOT16 14 ++#define R_PPC_GOT16_LO 15 ++#define R_PPC_GOT16_HI 16 ++#define R_PPC_GOT16_HA 17 ++#define R_PPC_PLTREL24 18 ++#define R_PPC_COPY 19 ++#define R_PPC_GLOB_DAT 20 ++#define R_PPC_JMP_SLOT 21 ++#define R_PPC_RELATIVE 22 ++#define R_PPC_LOCAL24PC 23 ++#define R_PPC_UADDR32 24 ++#define R_PPC_UADDR16 25 ++#define R_PPC_REL32 26 ++#define R_PPC_PLT32 27 ++#define R_PPC_PLTREL32 28 ++#define R_PPC_PLT16_LO 29 ++#define R_PPC_PLT16_HI 30 ++#define R_PPC_PLT16_HA 31 ++#define R_PPC_SDAREL16 32 ++#define R_PPC_SECTOFF 33 ++#define R_PPC_SECTOFF_LO 34 ++#define R_PPC_SECTOFF_HI 35 ++#define R_PPC_SECTOFF_HA 36 ++ ++/* PowerPC relocations defined for the TLS access ABI. */ ++#define R_PPC_TLS 67 /* none (sym+add)@tls */ ++#define R_PPC_DTPMOD32 68 /* word32 (sym+add)@dtpmod */ ++#define R_PPC_TPREL16 69 /* half16* (sym+add)@tprel */ ++#define R_PPC_TPREL16_LO 70 /* half16 (sym+add)@tprel@l */ ++#define R_PPC_TPREL16_HI 71 /* half16 (sym+add)@tprel@h */ ++#define R_PPC_TPREL16_HA 72 /* half16 (sym+add)@tprel@ha */ ++#define R_PPC_TPREL32 73 /* word32 (sym+add)@tprel */ ++#define R_PPC_DTPREL16 74 /* half16* (sym+add)@dtprel */ ++#define R_PPC_DTPREL16_LO 75 /* half16 (sym+add)@dtprel@l */ ++#define R_PPC_DTPREL16_HI 76 /* half16 (sym+add)@dtprel@h */ ++#define R_PPC_DTPREL16_HA 77 /* half16 (sym+add)@dtprel@ha */ ++#define R_PPC_DTPREL32 78 /* word32 (sym+add)@dtprel */ ++#define R_PPC_GOT_TLSGD16 79 /* half16* (sym+add)@got@tlsgd */ ++#define R_PPC_GOT_TLSGD16_LO 80 /* half16 (sym+add)@got@tlsgd@l */ ++#define R_PPC_GOT_TLSGD16_HI 81 /* half16 (sym+add)@got@tlsgd@h */ ++#define R_PPC_GOT_TLSGD16_HA 82 /* half16 (sym+add)@got@tlsgd@ha */ ++#define R_PPC_GOT_TLSLD16 83 /* half16* (sym+add)@got@tlsld */ ++#define R_PPC_GOT_TLSLD16_LO 84 /* half16 (sym+add)@got@tlsld@l */ ++#define R_PPC_GOT_TLSLD16_HI 85 /* half16 (sym+add)@got@tlsld@h */ ++#define R_PPC_GOT_TLSLD16_HA 86 /* half16 (sym+add)@got@tlsld@ha */ ++#define R_PPC_GOT_TPREL16 87 /* half16* (sym+add)@got@tprel */ ++#define R_PPC_GOT_TPREL16_LO 88 /* half16 (sym+add)@got@tprel@l */ ++#define R_PPC_GOT_TPREL16_HI 89 /* half16 (sym+add)@got@tprel@h */ ++#define R_PPC_GOT_TPREL16_HA 90 /* half16 (sym+add)@got@tprel@ha */ ++#define R_PPC_GOT_DTPREL16 91 /* half16* (sym+add)@got@dtprel */ ++#define R_PPC_GOT_DTPREL16_LO 92 /* half16* (sym+add)@got@dtprel@l */ ++#define R_PPC_GOT_DTPREL16_HI 93 /* half16* (sym+add)@got@dtprel@h */ ++#define R_PPC_GOT_DTPREL16_HA 94 /* half16* (sym+add)@got@dtprel@ha */ ++ ++/* The remaining relocs are from the Embedded ELF ABI, and are not ++ in the SVR4 ELF ABI. */ ++#define R_PPC_EMB_NADDR32 101 ++#define R_PPC_EMB_NADDR16 102 ++#define R_PPC_EMB_NADDR16_LO 103 ++#define R_PPC_EMB_NADDR16_HI 104 ++#define R_PPC_EMB_NADDR16_HA 105 ++#define R_PPC_EMB_SDAI16 106 ++#define R_PPC_EMB_SDA2I16 107 ++#define R_PPC_EMB_SDA2REL 108 ++#define R_PPC_EMB_SDA21 109 /* 16 bit offset in SDA */ ++#define R_PPC_EMB_MRKREF 110 ++#define R_PPC_EMB_RELSEC16 111 ++#define R_PPC_EMB_RELST_LO 112 ++#define R_PPC_EMB_RELST_HI 113 ++#define R_PPC_EMB_RELST_HA 114 ++#define R_PPC_EMB_BIT_FLD 115 ++#define R_PPC_EMB_RELSDA 116 /* 16 bit relative offset in SDA */ ++ ++/* Diab tool relocations. */ ++#define R_PPC_DIAB_SDA21_LO 180 /* like EMB_SDA21, but lower 16 bit */ ++#define R_PPC_DIAB_SDA21_HI 181 /* like EMB_SDA21, but high 16 bit */ ++#define R_PPC_DIAB_SDA21_HA 182 /* like EMB_SDA21, adjusted high 16 */ ++#define R_PPC_DIAB_RELSDA_LO 183 /* like EMB_RELSDA, but lower 16 bit */ ++#define R_PPC_DIAB_RELSDA_HI 184 /* like EMB_RELSDA, but high 16 bit */ ++#define R_PPC_DIAB_RELSDA_HA 185 /* like EMB_RELSDA, adjusted high 16 */ ++ ++/* GNU extension to support local ifunc. */ ++#define R_PPC_IRELATIVE 248 ++ ++/* GNU relocs used in PIC code sequences. */ ++#define R_PPC_REL16 249 /* half16 (sym+add-.) */ ++#define R_PPC_REL16_LO 250 /* half16 (sym+add-.)@l */ ++#define R_PPC_REL16_HI 251 /* half16 (sym+add-.)@h */ ++#define R_PPC_REL16_HA 252 /* half16 (sym+add-.)@ha */ ++ ++/* This is a phony reloc to handle any old fashioned TOC16 references ++ that may still be in object files. */ ++#define R_PPC_TOC16 255 ++ ++/* PowerPC specific values for the Dyn d_tag field. */ ++#define DT_PPC_GOT (DT_LOPROC + 0) ++#define DT_PPC_NUM 1 ++ ++/* PowerPC64 relocations defined by the ABIs */ ++#define R_PPC64_NONE R_PPC_NONE ++#define R_PPC64_ADDR32 R_PPC_ADDR32 /* 32bit absolute address */ ++#define R_PPC64_ADDR24 R_PPC_ADDR24 /* 26bit address, word aligned */ ++#define R_PPC64_ADDR16 R_PPC_ADDR16 /* 16bit absolute address */ ++#define R_PPC64_ADDR16_LO R_PPC_ADDR16_LO /* lower 16bits of address */ ++#define R_PPC64_ADDR16_HI R_PPC_ADDR16_HI /* high 16bits of address. */ ++#define R_PPC64_ADDR16_HA R_PPC_ADDR16_HA /* adjusted high 16bits. */ ++#define R_PPC64_ADDR14 R_PPC_ADDR14 /* 16bit address, word aligned */ ++#define R_PPC64_ADDR14_BRTAKEN R_PPC_ADDR14_BRTAKEN ++#define R_PPC64_ADDR14_BRNTAKEN R_PPC_ADDR14_BRNTAKEN ++#define R_PPC64_REL24 R_PPC_REL24 /* PC-rel. 26 bit, word aligned */ ++#define R_PPC64_REL14 R_PPC_REL14 /* PC relative 16 bit */ ++#define R_PPC64_REL14_BRTAKEN R_PPC_REL14_BRTAKEN ++#define R_PPC64_REL14_BRNTAKEN R_PPC_REL14_BRNTAKEN ++#define R_PPC64_GOT16 R_PPC_GOT16 ++#define R_PPC64_GOT16_LO R_PPC_GOT16_LO ++#define R_PPC64_GOT16_HI R_PPC_GOT16_HI ++#define R_PPC64_GOT16_HA R_PPC_GOT16_HA ++ ++#define R_PPC64_COPY R_PPC_COPY ++#define R_PPC64_GLOB_DAT R_PPC_GLOB_DAT ++#define R_PPC64_JMP_SLOT R_PPC_JMP_SLOT ++#define R_PPC64_RELATIVE R_PPC_RELATIVE ++ ++#define R_PPC64_UADDR32 R_PPC_UADDR32 ++#define R_PPC64_UADDR16 R_PPC_UADDR16 ++#define R_PPC64_REL32 R_PPC_REL32 ++#define R_PPC64_PLT32 R_PPC_PLT32 ++#define R_PPC64_PLTREL32 R_PPC_PLTREL32 ++#define R_PPC64_PLT16_LO R_PPC_PLT16_LO ++#define R_PPC64_PLT16_HI R_PPC_PLT16_HI ++#define R_PPC64_PLT16_HA R_PPC_PLT16_HA ++ ++#define R_PPC64_SECTOFF R_PPC_SECTOFF ++#define R_PPC64_SECTOFF_LO R_PPC_SECTOFF_LO ++#define R_PPC64_SECTOFF_HI R_PPC_SECTOFF_HI ++#define R_PPC64_SECTOFF_HA R_PPC_SECTOFF_HA ++#define R_PPC64_ADDR30 37 /* word30 (S + A - P) >> 2 */ ++#define R_PPC64_ADDR64 38 /* doubleword64 S + A */ ++#define R_PPC64_ADDR16_HIGHER 39 /* half16 #higher(S + A) */ ++#define R_PPC64_ADDR16_HIGHERA 40 /* half16 #highera(S + A) */ ++#define R_PPC64_ADDR16_HIGHEST 41 /* half16 #highest(S + A) */ ++#define R_PPC64_ADDR16_HIGHESTA 42 /* half16 #highesta(S + A) */ ++#define R_PPC64_UADDR64 43 /* doubleword64 S + A */ ++#define R_PPC64_REL64 44 /* doubleword64 S + A - P */ ++#define R_PPC64_PLT64 45 /* doubleword64 L + A */ ++#define R_PPC64_PLTREL64 46 /* doubleword64 L + A - P */ ++#define R_PPC64_TOC16 47 /* half16* S + A - .TOC */ ++#define R_PPC64_TOC16_LO 48 /* half16 #lo(S + A - .TOC.) */ ++#define R_PPC64_TOC16_HI 49 /* half16 #hi(S + A - .TOC.) */ ++#define R_PPC64_TOC16_HA 50 /* half16 #ha(S + A - .TOC.) */ ++#define R_PPC64_TOC 51 /* doubleword64 .TOC */ ++#define R_PPC64_PLTGOT16 52 /* half16* M + A */ ++#define R_PPC64_PLTGOT16_LO 53 /* half16 #lo(M + A) */ ++#define R_PPC64_PLTGOT16_HI 54 /* half16 #hi(M + A) */ ++#define R_PPC64_PLTGOT16_HA 55 /* half16 #ha(M + A) */ ++ ++#define R_PPC64_ADDR16_DS 56 /* half16ds* (S + A) >> 2 */ ++#define R_PPC64_ADDR16_LO_DS 57 /* half16ds #lo(S + A) >> 2 */ ++#define R_PPC64_GOT16_DS 58 /* half16ds* (G + A) >> 2 */ ++#define R_PPC64_GOT16_LO_DS 59 /* half16ds #lo(G + A) >> 2 */ ++#define R_PPC64_PLT16_LO_DS 60 /* half16ds #lo(L + A) >> 2 */ ++#define R_PPC64_SECTOFF_DS 61 /* half16ds* (R + A) >> 2 */ ++#define R_PPC64_SECTOFF_LO_DS 62 /* half16ds #lo(R + A) >> 2 */ ++#define R_PPC64_TOC16_DS 63 /* half16ds* (S + A - .TOC.) >> 2 */ ++#define R_PPC64_TOC16_LO_DS 64 /* half16ds #lo(S + A - .TOC.) >> 2 */ ++#define R_PPC64_PLTGOT16_DS 65 /* half16ds* (M + A) >> 2 */ ++#define R_PPC64_PLTGOT16_LO_DS 66 /* half16ds #lo(M + A) >> 2 */ ++ ++/* PowerPC64 relocations defined for the TLS access ABI. */ ++#define R_PPC64_TLS 67 /* none (sym+add)@tls */ ++#define R_PPC64_DTPMOD64 68 /* doubleword64 (sym+add)@dtpmod */ ++#define R_PPC64_TPREL16 69 /* half16* (sym+add)@tprel */ ++#define R_PPC64_TPREL16_LO 70 /* half16 (sym+add)@tprel@l */ ++#define R_PPC64_TPREL16_HI 71 /* half16 (sym+add)@tprel@h */ ++#define R_PPC64_TPREL16_HA 72 /* half16 (sym+add)@tprel@ha */ ++#define R_PPC64_TPREL64 73 /* doubleword64 (sym+add)@tprel */ ++#define R_PPC64_DTPREL16 74 /* half16* (sym+add)@dtprel */ ++#define R_PPC64_DTPREL16_LO 75 /* half16 (sym+add)@dtprel@l */ ++#define R_PPC64_DTPREL16_HI 76 /* half16 (sym+add)@dtprel@h */ ++#define R_PPC64_DTPREL16_HA 77 /* half16 (sym+add)@dtprel@ha */ ++#define R_PPC64_DTPREL64 78 /* doubleword64 (sym+add)@dtprel */ ++#define R_PPC64_GOT_TLSGD16 79 /* half16* (sym+add)@got@tlsgd */ ++#define R_PPC64_GOT_TLSGD16_LO 80 /* half16 (sym+add)@got@tlsgd@l */ ++#define R_PPC64_GOT_TLSGD16_HI 81 /* half16 (sym+add)@got@tlsgd@h */ ++#define R_PPC64_GOT_TLSGD16_HA 82 /* half16 (sym+add)@got@tlsgd@ha */ ++#define R_PPC64_GOT_TLSLD16 83 /* half16* (sym+add)@got@tlsld */ ++#define R_PPC64_GOT_TLSLD16_LO 84 /* half16 (sym+add)@got@tlsld@l */ ++#define R_PPC64_GOT_TLSLD16_HI 85 /* half16 (sym+add)@got@tlsld@h */ ++#define R_PPC64_GOT_TLSLD16_HA 86 /* half16 (sym+add)@got@tlsld@ha */ ++#define R_PPC64_GOT_TPREL16_DS 87 /* half16ds* (sym+add)@got@tprel */ ++#define R_PPC64_GOT_TPREL16_LO_DS 88 /* half16ds (sym+add)@got@tprel@l */ ++#define R_PPC64_GOT_TPREL16_HI 89 /* half16 (sym+add)@got@tprel@h */ ++#define R_PPC64_GOT_TPREL16_HA 90 /* half16 (sym+add)@got@tprel@ha */ ++#define R_PPC64_GOT_DTPREL16_DS 91 /* half16ds* (sym+add)@got@dtprel */ ++#define R_PPC64_GOT_DTPREL16_LO_DS 92 /* half16ds (sym+add)@got@dtprel@l */ ++#define R_PPC64_GOT_DTPREL16_HI 93 /* half16 (sym+add)@got@dtprel@h */ ++#define R_PPC64_GOT_DTPREL16_HA 94 /* half16 (sym+add)@got@dtprel@ha */ ++#define R_PPC64_TPREL16_DS 95 /* half16ds* (sym+add)@tprel */ ++#define R_PPC64_TPREL16_LO_DS 96 /* half16ds (sym+add)@tprel@l */ ++#define R_PPC64_TPREL16_HIGHER 97 /* half16 (sym+add)@tprel@higher */ ++#define R_PPC64_TPREL16_HIGHERA 98 /* half16 (sym+add)@tprel@highera */ ++#define R_PPC64_TPREL16_HIGHEST 99 /* half16 (sym+add)@tprel@highest */ ++#define R_PPC64_TPREL16_HIGHESTA 100 /* half16 (sym+add)@tprel@highesta */ ++#define R_PPC64_DTPREL16_DS 101 /* half16ds* (sym+add)@dtprel */ ++#define R_PPC64_DTPREL16_LO_DS 102 /* half16ds (sym+add)@dtprel@l */ ++#define R_PPC64_DTPREL16_HIGHER 103 /* half16 (sym+add)@dtprel@higher */ ++#define R_PPC64_DTPREL16_HIGHERA 104 /* half16 (sym+add)@dtprel@highera */ ++#define R_PPC64_DTPREL16_HIGHEST 105 /* half16 (sym+add)@dtprel@highest */ ++#define R_PPC64_DTPREL16_HIGHESTA 106 /* half16 (sym+add)@dtprel@highesta */ ++ ++/* GNU extension to support local ifunc. */ ++#define R_PPC64_JMP_IREL 247 ++#define R_PPC64_IRELATIVE 248 ++#define R_PPC64_REL16 249 /* half16 (sym+add-.) */ ++#define R_PPC64_REL16_LO 250 /* half16 (sym+add-.)@l */ ++#define R_PPC64_REL16_HI 251 /* half16 (sym+add-.)@h */ ++#define R_PPC64_REL16_HA 252 /* half16 (sym+add-.)@ha */ ++ ++/* PowerPC64 specific values for the Dyn d_tag field. */ ++#define DT_PPC64_GLINK (DT_LOPROC + 0) ++#define DT_PPC64_OPD (DT_LOPROC + 1) ++#define DT_PPC64_OPDSZ (DT_LOPROC + 2) ++#define DT_PPC64_NUM 3 ++ ++ ++/* ARM specific declarations */ ++ ++/* Processor specific flags for the ELF header e_flags field. */ ++#define EF_ARM_RELEXEC 0x01 ++#define EF_ARM_HASENTRY 0x02 ++#define EF_ARM_INTERWORK 0x04 ++#define EF_ARM_APCS_26 0x08 ++#define EF_ARM_APCS_FLOAT 0x10 ++#define EF_ARM_PIC 0x20 ++#define EF_ARM_ALIGN8 0x40 /* 8-bit structure alignment is in use */ ++#define EF_ARM_NEW_ABI 0x80 ++#define EF_ARM_OLD_ABI 0x100 ++#define EF_ARM_SOFT_FLOAT 0x200 ++#define EF_ARM_VFP_FLOAT 0x400 ++#define EF_ARM_MAVERICK_FLOAT 0x800 ++ ++ ++/* Other constants defined in the ARM ELF spec. version B-01. */ ++/* NB. These conflict with values defined above. */ ++#define EF_ARM_SYMSARESORTED 0x04 ++#define EF_ARM_DYNSYMSUSESEGIDX 0x08 ++#define EF_ARM_MAPSYMSFIRST 0x10 ++#define EF_ARM_EABIMASK 0XFF000000 ++ ++/* Constants defined in AAELF. */ ++#define EF_ARM_BE8 0x00800000 ++#define EF_ARM_LE8 0x00400000 ++ ++#define EF_ARM_EABI_VERSION(flags) ((flags) & EF_ARM_EABIMASK) ++#define EF_ARM_EABI_UNKNOWN 0x00000000 ++#define EF_ARM_EABI_VER1 0x01000000 ++#define EF_ARM_EABI_VER2 0x02000000 ++#define EF_ARM_EABI_VER3 0x03000000 ++#define EF_ARM_EABI_VER4 0x04000000 ++#define EF_ARM_EABI_VER5 0x05000000 ++ ++/* Additional symbol types for Thumb. */ ++#define STT_ARM_TFUNC STT_LOPROC /* A Thumb function. */ ++#define STT_ARM_16BIT STT_HIPROC /* A Thumb label. */ ++ ++/* ARM-specific values for sh_flags */ ++#define SHF_ARM_ENTRYSECT 0x10000000 /* Section contains an entry point */ ++#define SHF_ARM_COMDEF 0x80000000 /* Section may be multiply defined ++ in the input to a link step. */ ++ ++/* ARM-specific program header flags */ ++#define PF_ARM_SB 0x10000000 /* Segment contains the location ++ addressed by the static base. */ ++#define PF_ARM_PI 0x20000000 /* Position-independent segment. */ ++#define PF_ARM_ABS 0x40000000 /* Absolute segment. */ ++ ++/* Processor specific values for the Phdr p_type field. */ ++#define PT_ARM_EXIDX (PT_LOPROC + 1) /* ARM unwind segment. */ ++ ++/* Processor specific values for the Shdr sh_type field. */ ++#define SHT_ARM_EXIDX (SHT_LOPROC + 1) /* ARM unwind section. */ ++#define SHT_ARM_PREEMPTMAP (SHT_LOPROC + 2) /* Preemption details. */ ++#define SHT_ARM_ATTRIBUTES (SHT_LOPROC + 3) /* ARM attributes section. */ ++ ++ ++/* ARM relocs. */ ++ ++#define R_ARM_NONE 0 /* No reloc */ ++#define R_ARM_PC24 1 /* PC relative 26 bit branch */ ++#define R_ARM_ABS32 2 /* Direct 32 bit */ ++#define R_ARM_REL32 3 /* PC relative 32 bit */ ++#define R_ARM_PC13 4 ++#define R_ARM_ABS16 5 /* Direct 16 bit */ ++#define R_ARM_ABS12 6 /* Direct 12 bit */ ++#define R_ARM_THM_ABS5 7 ++#define R_ARM_ABS8 8 /* Direct 8 bit */ ++#define R_ARM_SBREL32 9 ++#define R_ARM_THM_PC22 10 ++#define R_ARM_THM_PC8 11 ++#define R_ARM_AMP_VCALL9 12 ++#define R_ARM_SWI24 13 /* Obsolete static relocation. */ ++#define R_ARM_TLS_DESC 13 /* Dynamic relocation. */ ++#define R_ARM_THM_SWI8 14 ++#define R_ARM_XPC25 15 ++#define R_ARM_THM_XPC22 16 ++#define R_ARM_TLS_DTPMOD32 17 /* ID of module containing symbol */ ++#define R_ARM_TLS_DTPOFF32 18 /* Offset in TLS block */ ++#define R_ARM_TLS_TPOFF32 19 /* Offset in static TLS block */ ++#define R_ARM_COPY 20 /* Copy symbol at runtime */ ++#define R_ARM_GLOB_DAT 21 /* Create GOT entry */ ++#define R_ARM_JUMP_SLOT 22 /* Create PLT entry */ ++#define R_ARM_RELATIVE 23 /* Adjust by program base */ ++#define R_ARM_GOTOFF 24 /* 32 bit offset to GOT */ ++#define R_ARM_GOTPC 25 /* 32 bit PC relative offset to GOT */ ++#define R_ARM_GOT32 26 /* 32 bit GOT entry */ ++#define R_ARM_PLT32 27 /* 32 bit PLT address */ ++#define R_ARM_ALU_PCREL_7_0 32 ++#define R_ARM_ALU_PCREL_15_8 33 ++#define R_ARM_ALU_PCREL_23_15 34 ++#define R_ARM_LDR_SBREL_11_0 35 ++#define R_ARM_ALU_SBREL_19_12 36 ++#define R_ARM_ALU_SBREL_27_20 37 ++#define R_ARM_TLS_GOTDESC 90 ++#define R_ARM_TLS_CALL 91 ++#define R_ARM_TLS_DESCSEQ 92 ++#define R_ARM_THM_TLS_CALL 93 ++#define R_ARM_GNU_VTENTRY 100 ++#define R_ARM_GNU_VTINHERIT 101 ++#define R_ARM_THM_PC11 102 /* thumb unconditional branch */ ++#define R_ARM_THM_PC9 103 /* thumb conditional branch */ ++#define R_ARM_TLS_GD32 104 /* PC-rel 32 bit for global dynamic ++ thread local data */ ++#define R_ARM_TLS_LDM32 105 /* PC-rel 32 bit for local dynamic ++ thread local data */ ++#define R_ARM_TLS_LDO32 106 /* 32 bit offset relative to TLS ++ block */ ++#define R_ARM_TLS_IE32 107 /* PC-rel 32 bit for GOT entry of ++ static TLS block offset */ ++#define R_ARM_TLS_LE32 108 /* 32 bit offset relative to static ++ TLS block */ ++#define R_ARM_THM_TLS_DESCSEQ 129 ++#define R_ARM_IRELATIVE 160 ++#define R_ARM_RXPC25 249 ++#define R_ARM_RSBREL32 250 ++#define R_ARM_THM_RPC22 251 ++#define R_ARM_RREL32 252 ++#define R_ARM_RABS22 253 ++#define R_ARM_RPC24 254 ++#define R_ARM_RBASE 255 ++/* Keep this the last entry. */ ++#define R_ARM_NUM 256 ++ ++/* IA-64 specific declarations. */ ++ ++/* Processor specific flags for the Ehdr e_flags field. */ ++#define EF_IA_64_MASKOS 0x0000000f /* os-specific flags */ ++#define EF_IA_64_ABI64 0x00000010 /* 64-bit ABI */ ++#define EF_IA_64_ARCH 0xff000000 /* arch. version mask */ ++ ++/* Processor specific values for the Phdr p_type field. */ ++#define PT_IA_64_ARCHEXT (PT_LOPROC + 0) /* arch extension bits */ ++#define PT_IA_64_UNWIND (PT_LOPROC + 1) /* ia64 unwind bits */ ++#define PT_IA_64_HP_OPT_ANOT (PT_LOOS + 0x12) ++#define PT_IA_64_HP_HSL_ANOT (PT_LOOS + 0x13) ++#define PT_IA_64_HP_STACK (PT_LOOS + 0x14) ++ ++/* Processor specific flags for the Phdr p_flags field. */ ++#define PF_IA_64_NORECOV 0x80000000 /* spec insns w/o recovery */ ++ ++/* Processor specific values for the Shdr sh_type field. */ ++#define SHT_IA_64_EXT (SHT_LOPROC + 0) /* extension bits */ ++#define SHT_IA_64_UNWIND (SHT_LOPROC + 1) /* unwind bits */ ++ ++/* Processor specific flags for the Shdr sh_flags field. */ ++#define SHF_IA_64_SHORT 0x10000000 /* section near gp */ ++#define SHF_IA_64_NORECOV 0x20000000 /* spec insns w/o recovery */ ++ ++/* Processor specific values for the Dyn d_tag field. */ ++#define DT_IA_64_PLT_RESERVE (DT_LOPROC + 0) ++#define DT_IA_64_NUM 1 ++ ++/* IA-64 relocations. */ ++#define R_IA64_NONE 0x00 /* none */ ++#define R_IA64_IMM14 0x21 /* symbol + addend, add imm14 */ ++#define R_IA64_IMM22 0x22 /* symbol + addend, add imm22 */ ++#define R_IA64_IMM64 0x23 /* symbol + addend, mov imm64 */ ++#define R_IA64_DIR32MSB 0x24 /* symbol + addend, data4 MSB */ ++#define R_IA64_DIR32LSB 0x25 /* symbol + addend, data4 LSB */ ++#define R_IA64_DIR64MSB 0x26 /* symbol + addend, data8 MSB */ ++#define R_IA64_DIR64LSB 0x27 /* symbol + addend, data8 LSB */ ++#define R_IA64_GPREL22 0x2a /* @gprel(sym + add), add imm22 */ ++#define R_IA64_GPREL64I 0x2b /* @gprel(sym + add), mov imm64 */ ++#define R_IA64_GPREL32MSB 0x2c /* @gprel(sym + add), data4 MSB */ ++#define R_IA64_GPREL32LSB 0x2d /* @gprel(sym + add), data4 LSB */ ++#define R_IA64_GPREL64MSB 0x2e /* @gprel(sym + add), data8 MSB */ ++#define R_IA64_GPREL64LSB 0x2f /* @gprel(sym + add), data8 LSB */ ++#define R_IA64_LTOFF22 0x32 /* @ltoff(sym + add), add imm22 */ ++#define R_IA64_LTOFF64I 0x33 /* @ltoff(sym + add), mov imm64 */ ++#define R_IA64_PLTOFF22 0x3a /* @pltoff(sym + add), add imm22 */ ++#define R_IA64_PLTOFF64I 0x3b /* @pltoff(sym + add), mov imm64 */ ++#define R_IA64_PLTOFF64MSB 0x3e /* @pltoff(sym + add), data8 MSB */ ++#define R_IA64_PLTOFF64LSB 0x3f /* @pltoff(sym + add), data8 LSB */ ++#define R_IA64_FPTR64I 0x43 /* @fptr(sym + add), mov imm64 */ ++#define R_IA64_FPTR32MSB 0x44 /* @fptr(sym + add), data4 MSB */ ++#define R_IA64_FPTR32LSB 0x45 /* @fptr(sym + add), data4 LSB */ ++#define R_IA64_FPTR64MSB 0x46 /* @fptr(sym + add), data8 MSB */ ++#define R_IA64_FPTR64LSB 0x47 /* @fptr(sym + add), data8 LSB */ ++#define R_IA64_PCREL60B 0x48 /* @pcrel(sym + add), brl */ ++#define R_IA64_PCREL21B 0x49 /* @pcrel(sym + add), ptb, call */ ++#define R_IA64_PCREL21M 0x4a /* @pcrel(sym + add), chk.s */ ++#define R_IA64_PCREL21F 0x4b /* @pcrel(sym + add), fchkf */ ++#define R_IA64_PCREL32MSB 0x4c /* @pcrel(sym + add), data4 MSB */ ++#define R_IA64_PCREL32LSB 0x4d /* @pcrel(sym + add), data4 LSB */ ++#define R_IA64_PCREL64MSB 0x4e /* @pcrel(sym + add), data8 MSB */ ++#define R_IA64_PCREL64LSB 0x4f /* @pcrel(sym + add), data8 LSB */ ++#define R_IA64_LTOFF_FPTR22 0x52 /* @ltoff(@fptr(s+a)), imm22 */ ++#define R_IA64_LTOFF_FPTR64I 0x53 /* @ltoff(@fptr(s+a)), imm64 */ ++#define R_IA64_LTOFF_FPTR32MSB 0x54 /* @ltoff(@fptr(s+a)), data4 MSB */ ++#define R_IA64_LTOFF_FPTR32LSB 0x55 /* @ltoff(@fptr(s+a)), data4 LSB */ ++#define R_IA64_LTOFF_FPTR64MSB 0x56 /* @ltoff(@fptr(s+a)), data8 MSB */ ++#define R_IA64_LTOFF_FPTR64LSB 0x57 /* @ltoff(@fptr(s+a)), data8 LSB */ ++#define R_IA64_SEGREL32MSB 0x5c /* @segrel(sym + add), data4 MSB */ ++#define R_IA64_SEGREL32LSB 0x5d /* @segrel(sym + add), data4 LSB */ ++#define R_IA64_SEGREL64MSB 0x5e /* @segrel(sym + add), data8 MSB */ ++#define R_IA64_SEGREL64LSB 0x5f /* @segrel(sym + add), data8 LSB */ ++#define R_IA64_SECREL32MSB 0x64 /* @secrel(sym + add), data4 MSB */ ++#define R_IA64_SECREL32LSB 0x65 /* @secrel(sym + add), data4 LSB */ ++#define R_IA64_SECREL64MSB 0x66 /* @secrel(sym + add), data8 MSB */ ++#define R_IA64_SECREL64LSB 0x67 /* @secrel(sym + add), data8 LSB */ ++#define R_IA64_REL32MSB 0x6c /* data 4 + REL */ ++#define R_IA64_REL32LSB 0x6d /* data 4 + REL */ ++#define R_IA64_REL64MSB 0x6e /* data 8 + REL */ ++#define R_IA64_REL64LSB 0x6f /* data 8 + REL */ ++#define R_IA64_LTV32MSB 0x74 /* symbol + addend, data4 MSB */ ++#define R_IA64_LTV32LSB 0x75 /* symbol + addend, data4 LSB */ ++#define R_IA64_LTV64MSB 0x76 /* symbol + addend, data8 MSB */ ++#define R_IA64_LTV64LSB 0x77 /* symbol + addend, data8 LSB */ ++#define R_IA64_PCREL21BI 0x79 /* @pcrel(sym + add), 21bit inst */ ++#define R_IA64_PCREL22 0x7a /* @pcrel(sym + add), 22bit inst */ ++#define R_IA64_PCREL64I 0x7b /* @pcrel(sym + add), 64bit inst */ ++#define R_IA64_IPLTMSB 0x80 /* dynamic reloc, imported PLT, MSB */ ++#define R_IA64_IPLTLSB 0x81 /* dynamic reloc, imported PLT, LSB */ ++#define R_IA64_COPY 0x84 /* copy relocation */ ++#define R_IA64_SUB 0x85 /* Addend and symbol difference */ ++#define R_IA64_LTOFF22X 0x86 /* LTOFF22, relaxable. */ ++#define R_IA64_LDXMOV 0x87 /* Use of LTOFF22X. */ ++#define R_IA64_TPREL14 0x91 /* @tprel(sym + add), imm14 */ ++#define R_IA64_TPREL22 0x92 /* @tprel(sym + add), imm22 */ ++#define R_IA64_TPREL64I 0x93 /* @tprel(sym + add), imm64 */ ++#define R_IA64_TPREL64MSB 0x96 /* @tprel(sym + add), data8 MSB */ ++#define R_IA64_TPREL64LSB 0x97 /* @tprel(sym + add), data8 LSB */ ++#define R_IA64_LTOFF_TPREL22 0x9a /* @ltoff(@tprel(s+a)), imm2 */ ++#define R_IA64_DTPMOD64MSB 0xa6 /* @dtpmod(sym + add), data8 MSB */ ++#define R_IA64_DTPMOD64LSB 0xa7 /* @dtpmod(sym + add), data8 LSB */ ++#define R_IA64_LTOFF_DTPMOD22 0xaa /* @ltoff(@dtpmod(sym + add)), imm22 */ ++#define R_IA64_DTPREL14 0xb1 /* @dtprel(sym + add), imm14 */ ++#define R_IA64_DTPREL22 0xb2 /* @dtprel(sym + add), imm22 */ ++#define R_IA64_DTPREL64I 0xb3 /* @dtprel(sym + add), imm64 */ ++#define R_IA64_DTPREL32MSB 0xb4 /* @dtprel(sym + add), data4 MSB */ ++#define R_IA64_DTPREL32LSB 0xb5 /* @dtprel(sym + add), data4 LSB */ ++#define R_IA64_DTPREL64MSB 0xb6 /* @dtprel(sym + add), data8 MSB */ ++#define R_IA64_DTPREL64LSB 0xb7 /* @dtprel(sym + add), data8 LSB */ ++#define R_IA64_LTOFF_DTPREL22 0xba /* @ltoff(@dtprel(s+a)), imm22 */ ++ ++/* SH specific declarations */ ++ ++/* Processor specific flags for the ELF header e_flags field. */ ++#define EF_SH_MACH_MASK 0x1f ++#define EF_SH_UNKNOWN 0x0 ++#define EF_SH1 0x1 ++#define EF_SH2 0x2 ++#define EF_SH3 0x3 ++#define EF_SH_DSP 0x4 ++#define EF_SH3_DSP 0x5 ++#define EF_SH4AL_DSP 0x6 ++#define EF_SH3E 0x8 ++#define EF_SH4 0x9 ++#define EF_SH2E 0xb ++#define EF_SH4A 0xc ++#define EF_SH2A 0xd ++#define EF_SH4_NOFPU 0x10 ++#define EF_SH4A_NOFPU 0x11 ++#define EF_SH4_NOMMU_NOFPU 0x12 ++#define EF_SH2A_NOFPU 0x13 ++#define EF_SH3_NOMMU 0x14 ++#define EF_SH2A_SH4_NOFPU 0x15 ++#define EF_SH2A_SH3_NOFPU 0x16 ++#define EF_SH2A_SH4 0x17 ++#define EF_SH2A_SH3E 0x18 ++ ++/* SH relocs. */ ++#define R_SH_NONE 0 ++#define R_SH_DIR32 1 ++#define R_SH_REL32 2 ++#define R_SH_DIR8WPN 3 ++#define R_SH_IND12W 4 ++#define R_SH_DIR8WPL 5 ++#define R_SH_DIR8WPZ 6 ++#define R_SH_DIR8BP 7 ++#define R_SH_DIR8W 8 ++#define R_SH_DIR8L 9 ++#define R_SH_SWITCH16 25 ++#define R_SH_SWITCH32 26 ++#define R_SH_USES 27 ++#define R_SH_COUNT 28 ++#define R_SH_ALIGN 29 ++#define R_SH_CODE 30 ++#define R_SH_DATA 31 ++#define R_SH_LABEL 32 ++#define R_SH_SWITCH8 33 ++#define R_SH_GNU_VTINHERIT 34 ++#define R_SH_GNU_VTENTRY 35 ++#define R_SH_TLS_GD_32 144 ++#define R_SH_TLS_LD_32 145 ++#define R_SH_TLS_LDO_32 146 ++#define R_SH_TLS_IE_32 147 ++#define R_SH_TLS_LE_32 148 ++#define R_SH_TLS_DTPMOD32 149 ++#define R_SH_TLS_DTPOFF32 150 ++#define R_SH_TLS_TPOFF32 151 ++#define R_SH_GOT32 160 ++#define R_SH_PLT32 161 ++#define R_SH_COPY 162 ++#define R_SH_GLOB_DAT 163 ++#define R_SH_JMP_SLOT 164 ++#define R_SH_RELATIVE 165 ++#define R_SH_GOTOFF 166 ++#define R_SH_GOTPC 167 ++/* Keep this the last entry. */ ++#define R_SH_NUM 256 ++ ++/* S/390 specific definitions. */ ++ ++/* Valid values for the e_flags field. */ ++ ++#define EF_S390_HIGH_GPRS 0x00000001 /* High GPRs kernel facility needed. */ ++ ++/* Additional s390 relocs */ ++ ++#define R_390_NONE 0 /* No reloc. */ ++#define R_390_8 1 /* Direct 8 bit. */ ++#define R_390_12 2 /* Direct 12 bit. */ ++#define R_390_16 3 /* Direct 16 bit. */ ++#define R_390_32 4 /* Direct 32 bit. */ ++#define R_390_PC32 5 /* PC relative 32 bit. */ ++#define R_390_GOT12 6 /* 12 bit GOT offset. */ ++#define R_390_GOT32 7 /* 32 bit GOT offset. */ ++#define R_390_PLT32 8 /* 32 bit PC relative PLT address. */ ++#define R_390_COPY 9 /* Copy symbol at runtime. */ ++#define R_390_GLOB_DAT 10 /* Create GOT entry. */ ++#define R_390_JMP_SLOT 11 /* Create PLT entry. */ ++#define R_390_RELATIVE 12 /* Adjust by program base. */ ++#define R_390_GOTOFF32 13 /* 32 bit offset to GOT. */ ++#define R_390_GOTPC 14 /* 32 bit PC relative offset to GOT. */ ++#define R_390_GOT16 15 /* 16 bit GOT offset. */ ++#define R_390_PC16 16 /* PC relative 16 bit. */ ++#define R_390_PC16DBL 17 /* PC relative 16 bit shifted by 1. */ ++#define R_390_PLT16DBL 18 /* 16 bit PC rel. PLT shifted by 1. */ ++#define R_390_PC32DBL 19 /* PC relative 32 bit shifted by 1. */ ++#define R_390_PLT32DBL 20 /* 32 bit PC rel. PLT shifted by 1. */ ++#define R_390_GOTPCDBL 21 /* 32 bit PC rel. GOT shifted by 1. */ ++#define R_390_64 22 /* Direct 64 bit. */ ++#define R_390_PC64 23 /* PC relative 64 bit. */ ++#define R_390_GOT64 24 /* 64 bit GOT offset. */ ++#define R_390_PLT64 25 /* 64 bit PC relative PLT address. */ ++#define R_390_GOTENT 26 /* 32 bit PC rel. to GOT entry >> 1. */ ++#define R_390_GOTOFF16 27 /* 16 bit offset to GOT. */ ++#define R_390_GOTOFF64 28 /* 64 bit offset to GOT. */ ++#define R_390_GOTPLT12 29 /* 12 bit offset to jump slot. */ ++#define R_390_GOTPLT16 30 /* 16 bit offset to jump slot. */ ++#define R_390_GOTPLT32 31 /* 32 bit offset to jump slot. */ ++#define R_390_GOTPLT64 32 /* 64 bit offset to jump slot. */ ++#define R_390_GOTPLTENT 33 /* 32 bit rel. offset to jump slot. */ ++#define R_390_PLTOFF16 34 /* 16 bit offset from GOT to PLT. */ ++#define R_390_PLTOFF32 35 /* 32 bit offset from GOT to PLT. */ ++#define R_390_PLTOFF64 36 /* 16 bit offset from GOT to PLT. */ ++#define R_390_TLS_LOAD 37 /* Tag for load insn in TLS code. */ ++#define R_390_TLS_GDCALL 38 /* Tag for function call in general ++ dynamic TLS code. */ ++#define R_390_TLS_LDCALL 39 /* Tag for function call in local ++ dynamic TLS code. */ ++#define R_390_TLS_GD32 40 /* Direct 32 bit for general dynamic ++ thread local data. */ ++#define R_390_TLS_GD64 41 /* Direct 64 bit for general dynamic ++ thread local data. */ ++#define R_390_TLS_GOTIE12 42 /* 12 bit GOT offset for static TLS ++ block offset. */ ++#define R_390_TLS_GOTIE32 43 /* 32 bit GOT offset for static TLS ++ block offset. */ ++#define R_390_TLS_GOTIE64 44 /* 64 bit GOT offset for static TLS ++ block offset. */ ++#define R_390_TLS_LDM32 45 /* Direct 32 bit for local dynamic ++ thread local data in LE code. */ ++#define R_390_TLS_LDM64 46 /* Direct 64 bit for local dynamic ++ thread local data in LE code. */ ++#define R_390_TLS_IE32 47 /* 32 bit address of GOT entry for ++ negated static TLS block offset. */ ++#define R_390_TLS_IE64 48 /* 64 bit address of GOT entry for ++ negated static TLS block offset. */ ++#define R_390_TLS_IEENT 49 /* 32 bit rel. offset to GOT entry for ++ negated static TLS block offset. */ ++#define R_390_TLS_LE32 50 /* 32 bit negated offset relative to ++ static TLS block. */ ++#define R_390_TLS_LE64 51 /* 64 bit negated offset relative to ++ static TLS block. */ ++#define R_390_TLS_LDO32 52 /* 32 bit offset relative to TLS ++ block. */ ++#define R_390_TLS_LDO64 53 /* 64 bit offset relative to TLS ++ block. */ ++#define R_390_TLS_DTPMOD 54 /* ID of module containing symbol. */ ++#define R_390_TLS_DTPOFF 55 /* Offset in TLS block. */ ++#define R_390_TLS_TPOFF 56 /* Negated offset in static TLS ++ block. */ ++#define R_390_20 57 /* Direct 20 bit. */ ++#define R_390_GOT20 58 /* 20 bit GOT offset. */ ++#define R_390_GOTPLT20 59 /* 20 bit offset to jump slot. */ ++#define R_390_TLS_GOTIE20 60 /* 20 bit GOT offset for static TLS ++ block offset. */ ++#define R_390_IRELATIVE 61 /* STT_GNU_IFUNC relocation. */ ++/* Keep this the last entry. */ ++#define R_390_NUM 62 ++ ++ ++/* CRIS relocations. */ ++#define R_CRIS_NONE 0 ++#define R_CRIS_8 1 ++#define R_CRIS_16 2 ++#define R_CRIS_32 3 ++#define R_CRIS_8_PCREL 4 ++#define R_CRIS_16_PCREL 5 ++#define R_CRIS_32_PCREL 6 ++#define R_CRIS_GNU_VTINHERIT 7 ++#define R_CRIS_GNU_VTENTRY 8 ++#define R_CRIS_COPY 9 ++#define R_CRIS_GLOB_DAT 10 ++#define R_CRIS_JUMP_SLOT 11 ++#define R_CRIS_RELATIVE 12 ++#define R_CRIS_16_GOT 13 ++#define R_CRIS_32_GOT 14 ++#define R_CRIS_16_GOTPLT 15 ++#define R_CRIS_32_GOTPLT 16 ++#define R_CRIS_32_GOTREL 17 ++#define R_CRIS_32_PLT_GOTREL 18 ++#define R_CRIS_32_PLT_PCREL 19 ++ ++#define R_CRIS_NUM 20 ++ ++ ++/* AMD x86-64 relocations. */ ++#define R_X86_64_NONE 0 /* No reloc */ ++#define R_X86_64_64 1 /* Direct 64 bit */ ++#define R_X86_64_PC32 2 /* PC relative 32 bit signed */ ++#define R_X86_64_GOT32 3 /* 32 bit GOT entry */ ++#define R_X86_64_PLT32 4 /* 32 bit PLT address */ ++#define R_X86_64_COPY 5 /* Copy symbol at runtime */ ++#define R_X86_64_GLOB_DAT 6 /* Create GOT entry */ ++#define R_X86_64_JUMP_SLOT 7 /* Create PLT entry */ ++#define R_X86_64_RELATIVE 8 /* Adjust by program base */ ++#define R_X86_64_GOTPCREL 9 /* 32 bit signed PC relative ++ offset to GOT */ ++#define R_X86_64_32 10 /* Direct 32 bit zero extended */ ++#define R_X86_64_32S 11 /* Direct 32 bit sign extended */ ++#define R_X86_64_16 12 /* Direct 16 bit zero extended */ ++#define R_X86_64_PC16 13 /* 16 bit sign extended pc relative */ ++#define R_X86_64_8 14 /* Direct 8 bit sign extended */ ++#define R_X86_64_PC8 15 /* 8 bit sign extended pc relative */ ++#define R_X86_64_DTPMOD64 16 /* ID of module containing symbol */ ++#define R_X86_64_DTPOFF64 17 /* Offset in module's TLS block */ ++#define R_X86_64_TPOFF64 18 /* Offset in initial TLS block */ ++#define R_X86_64_TLSGD 19 /* 32 bit signed PC relative offset ++ to two GOT entries for GD symbol */ ++#define R_X86_64_TLSLD 20 /* 32 bit signed PC relative offset ++ to two GOT entries for LD symbol */ ++#define R_X86_64_DTPOFF32 21 /* Offset in TLS block */ ++#define R_X86_64_GOTTPOFF 22 /* 32 bit signed PC relative offset ++ to GOT entry for IE symbol */ ++#define R_X86_64_TPOFF32 23 /* Offset in initial TLS block */ ++#define R_X86_64_PC64 24 /* PC relative 64 bit */ ++#define R_X86_64_GOTOFF64 25 /* 64 bit offset to GOT */ ++#define R_X86_64_GOTPC32 26 /* 32 bit signed pc relative ++ offset to GOT */ ++#define R_X86_64_GOT64 27 /* 64-bit GOT entry offset */ ++#define R_X86_64_GOTPCREL64 28 /* 64-bit PC relative offset ++ to GOT entry */ ++#define R_X86_64_GOTPC64 29 /* 64-bit PC relative offset to GOT */ ++#define R_X86_64_GOTPLT64 30 /* like GOT64, says PLT entry needed */ ++#define R_X86_64_PLTOFF64 31 /* 64-bit GOT relative offset ++ to PLT entry */ ++#define R_X86_64_SIZE32 32 /* Size of symbol plus 32-bit addend */ ++#define R_X86_64_SIZE64 33 /* Size of symbol plus 64-bit addend */ ++#define R_X86_64_GOTPC32_TLSDESC 34 /* GOT offset for TLS descriptor. */ ++#define R_X86_64_TLSDESC_CALL 35 /* Marker for call through TLS ++ descriptor. */ ++#define R_X86_64_TLSDESC 36 /* TLS descriptor. */ ++#define R_X86_64_IRELATIVE 37 /* Adjust indirectly by program base */ ++#define R_X86_64_RELATIVE64 38 /* 64-bit adjust by program base */ ++ ++#define R_X86_64_NUM 39 ++ ++ ++/* AM33 relocations. */ ++#define R_MN10300_NONE 0 /* No reloc. */ ++#define R_MN10300_32 1 /* Direct 32 bit. */ ++#define R_MN10300_16 2 /* Direct 16 bit. */ ++#define R_MN10300_8 3 /* Direct 8 bit. */ ++#define R_MN10300_PCREL32 4 /* PC-relative 32-bit. */ ++#define R_MN10300_PCREL16 5 /* PC-relative 16-bit signed. */ ++#define R_MN10300_PCREL8 6 /* PC-relative 8-bit signed. */ ++#define R_MN10300_GNU_VTINHERIT 7 /* Ancient C++ vtable garbage... */ ++#define R_MN10300_GNU_VTENTRY 8 /* ... collection annotation. */ ++#define R_MN10300_24 9 /* Direct 24 bit. */ ++#define R_MN10300_GOTPC32 10 /* 32-bit PCrel offset to GOT. */ ++#define R_MN10300_GOTPC16 11 /* 16-bit PCrel offset to GOT. */ ++#define R_MN10300_GOTOFF32 12 /* 32-bit offset from GOT. */ ++#define R_MN10300_GOTOFF24 13 /* 24-bit offset from GOT. */ ++#define R_MN10300_GOTOFF16 14 /* 16-bit offset from GOT. */ ++#define R_MN10300_PLT32 15 /* 32-bit PCrel to PLT entry. */ ++#define R_MN10300_PLT16 16 /* 16-bit PCrel to PLT entry. */ ++#define R_MN10300_GOT32 17 /* 32-bit offset to GOT entry. */ ++#define R_MN10300_GOT24 18 /* 24-bit offset to GOT entry. */ ++#define R_MN10300_GOT16 19 /* 16-bit offset to GOT entry. */ ++#define R_MN10300_COPY 20 /* Copy symbol at runtime. */ ++#define R_MN10300_GLOB_DAT 21 /* Create GOT entry. */ ++#define R_MN10300_JMP_SLOT 22 /* Create PLT entry. */ ++#define R_MN10300_RELATIVE 23 /* Adjust by program base. */ ++ ++#define R_MN10300_NUM 24 ++ ++ ++/* M32R relocs. */ ++#define R_M32R_NONE 0 /* No reloc. */ ++#define R_M32R_16 1 /* Direct 16 bit. */ ++#define R_M32R_32 2 /* Direct 32 bit. */ ++#define R_M32R_24 3 /* Direct 24 bit. */ ++#define R_M32R_10_PCREL 4 /* PC relative 10 bit shifted. */ ++#define R_M32R_18_PCREL 5 /* PC relative 18 bit shifted. */ ++#define R_M32R_26_PCREL 6 /* PC relative 26 bit shifted. */ ++#define R_M32R_HI16_ULO 7 /* High 16 bit with unsigned low. */ ++#define R_M32R_HI16_SLO 8 /* High 16 bit with signed low. */ ++#define R_M32R_LO16 9 /* Low 16 bit. */ ++#define R_M32R_SDA16 10 /* 16 bit offset in SDA. */ ++#define R_M32R_GNU_VTINHERIT 11 ++#define R_M32R_GNU_VTENTRY 12 ++/* M32R relocs use SHT_RELA. */ ++#define R_M32R_16_RELA 33 /* Direct 16 bit. */ ++#define R_M32R_32_RELA 34 /* Direct 32 bit. */ ++#define R_M32R_24_RELA 35 /* Direct 24 bit. */ ++#define R_M32R_10_PCREL_RELA 36 /* PC relative 10 bit shifted. */ ++#define R_M32R_18_PCREL_RELA 37 /* PC relative 18 bit shifted. */ ++#define R_M32R_26_PCREL_RELA 38 /* PC relative 26 bit shifted. */ ++#define R_M32R_HI16_ULO_RELA 39 /* High 16 bit with unsigned low */ ++#define R_M32R_HI16_SLO_RELA 40 /* High 16 bit with signed low */ ++#define R_M32R_LO16_RELA 41 /* Low 16 bit */ ++#define R_M32R_SDA16_RELA 42 /* 16 bit offset in SDA */ ++#define R_M32R_RELA_GNU_VTINHERIT 43 ++#define R_M32R_RELA_GNU_VTENTRY 44 ++#define R_M32R_REL32 45 /* PC relative 32 bit. */ ++ ++#define R_M32R_GOT24 48 /* 24 bit GOT entry */ ++#define R_M32R_26_PLTREL 49 /* 26 bit PC relative to PLT shifted */ ++#define R_M32R_COPY 50 /* Copy symbol at runtime */ ++#define R_M32R_GLOB_DAT 51 /* Create GOT entry */ ++#define R_M32R_JMP_SLOT 52 /* Create PLT entry */ ++#define R_M32R_RELATIVE 53 /* Adjust by program base */ ++#define R_M32R_GOTOFF 54 /* 24 bit offset to GOT */ ++#define R_M32R_GOTPC24 55 /* 24 bit PC relative offset to GOT */ ++#define R_M32R_GOT16_HI_ULO 56 /* High 16 bit GOT entry with unsigned ++ low */ ++#define R_M32R_GOT16_HI_SLO 57 /* High 16 bit GOT entry with signed ++ low */ ++#define R_M32R_GOT16_LO 58 /* Low 16 bit GOT entry */ ++#define R_M32R_GOTPC_HI_ULO 59 /* High 16 bit PC relative offset to ++ GOT with unsigned low */ ++#define R_M32R_GOTPC_HI_SLO 60 /* High 16 bit PC relative offset to ++ GOT with signed low */ ++#define R_M32R_GOTPC_LO 61 /* Low 16 bit PC relative offset to ++ GOT */ ++#define R_M32R_GOTOFF_HI_ULO 62 /* High 16 bit offset to GOT ++ with unsigned low */ ++#define R_M32R_GOTOFF_HI_SLO 63 /* High 16 bit offset to GOT ++ with signed low */ ++#define R_M32R_GOTOFF_LO 64 /* Low 16 bit offset to GOT */ ++#define R_M32R_NUM 256 /* Keep this the last entry. */ ++ ++ ++/* TILEPro relocations. */ ++#define R_TILEPRO_NONE 0 /* No reloc */ ++#define R_TILEPRO_32 1 /* Direct 32 bit */ ++#define R_TILEPRO_16 2 /* Direct 16 bit */ ++#define R_TILEPRO_8 3 /* Direct 8 bit */ ++#define R_TILEPRO_32_PCREL 4 /* PC relative 32 bit */ ++#define R_TILEPRO_16_PCREL 5 /* PC relative 16 bit */ ++#define R_TILEPRO_8_PCREL 6 /* PC relative 8 bit */ ++#define R_TILEPRO_LO16 7 /* Low 16 bit */ ++#define R_TILEPRO_HI16 8 /* High 16 bit */ ++#define R_TILEPRO_HA16 9 /* High 16 bit, adjusted */ ++#define R_TILEPRO_COPY 10 /* Copy relocation */ ++#define R_TILEPRO_GLOB_DAT 11 /* Create GOT entry */ ++#define R_TILEPRO_JMP_SLOT 12 /* Create PLT entry */ ++#define R_TILEPRO_RELATIVE 13 /* Adjust by program base */ ++#define R_TILEPRO_BROFF_X1 14 /* X1 pipe branch offset */ ++#define R_TILEPRO_JOFFLONG_X1 15 /* X1 pipe jump offset */ ++#define R_TILEPRO_JOFFLONG_X1_PLT 16 /* X1 pipe jump offset to PLT */ ++#define R_TILEPRO_IMM8_X0 17 /* X0 pipe 8-bit */ ++#define R_TILEPRO_IMM8_Y0 18 /* Y0 pipe 8-bit */ ++#define R_TILEPRO_IMM8_X1 19 /* X1 pipe 8-bit */ ++#define R_TILEPRO_IMM8_Y1 20 /* Y1 pipe 8-bit */ ++#define R_TILEPRO_MT_IMM15_X1 21 /* X1 pipe mtspr */ ++#define R_TILEPRO_MF_IMM15_X1 22 /* X1 pipe mfspr */ ++#define R_TILEPRO_IMM16_X0 23 /* X0 pipe 16-bit */ ++#define R_TILEPRO_IMM16_X1 24 /* X1 pipe 16-bit */ ++#define R_TILEPRO_IMM16_X0_LO 25 /* X0 pipe low 16-bit */ ++#define R_TILEPRO_IMM16_X1_LO 26 /* X1 pipe low 16-bit */ ++#define R_TILEPRO_IMM16_X0_HI 27 /* X0 pipe high 16-bit */ ++#define R_TILEPRO_IMM16_X1_HI 28 /* X1 pipe high 16-bit */ ++#define R_TILEPRO_IMM16_X0_HA 29 /* X0 pipe high 16-bit, adjusted */ ++#define R_TILEPRO_IMM16_X1_HA 30 /* X1 pipe high 16-bit, adjusted */ ++#define R_TILEPRO_IMM16_X0_PCREL 31 /* X0 pipe PC relative 16 bit */ ++#define R_TILEPRO_IMM16_X1_PCREL 32 /* X1 pipe PC relative 16 bit */ ++#define R_TILEPRO_IMM16_X0_LO_PCREL 33 /* X0 pipe PC relative low 16 bit */ ++#define R_TILEPRO_IMM16_X1_LO_PCREL 34 /* X1 pipe PC relative low 16 bit */ ++#define R_TILEPRO_IMM16_X0_HI_PCREL 35 /* X0 pipe PC relative high 16 bit */ ++#define R_TILEPRO_IMM16_X1_HI_PCREL 36 /* X1 pipe PC relative high 16 bit */ ++#define R_TILEPRO_IMM16_X0_HA_PCREL 37 /* X0 pipe PC relative ha() 16 bit */ ++#define R_TILEPRO_IMM16_X1_HA_PCREL 38 /* X1 pipe PC relative ha() 16 bit */ ++#define R_TILEPRO_IMM16_X0_GOT 39 /* X0 pipe 16-bit GOT offset */ ++#define R_TILEPRO_IMM16_X1_GOT 40 /* X1 pipe 16-bit GOT offset */ ++#define R_TILEPRO_IMM16_X0_GOT_LO 41 /* X0 pipe low 16-bit GOT offset */ ++#define R_TILEPRO_IMM16_X1_GOT_LO 42 /* X1 pipe low 16-bit GOT offset */ ++#define R_TILEPRO_IMM16_X0_GOT_HI 43 /* X0 pipe high 16-bit GOT offset */ ++#define R_TILEPRO_IMM16_X1_GOT_HI 44 /* X1 pipe high 16-bit GOT offset */ ++#define R_TILEPRO_IMM16_X0_GOT_HA 45 /* X0 pipe ha() 16-bit GOT offset */ ++#define R_TILEPRO_IMM16_X1_GOT_HA 46 /* X1 pipe ha() 16-bit GOT offset */ ++#define R_TILEPRO_MMSTART_X0 47 /* X0 pipe mm "start" */ ++#define R_TILEPRO_MMEND_X0 48 /* X0 pipe mm "end" */ ++#define R_TILEPRO_MMSTART_X1 49 /* X1 pipe mm "start" */ ++#define R_TILEPRO_MMEND_X1 50 /* X1 pipe mm "end" */ ++#define R_TILEPRO_SHAMT_X0 51 /* X0 pipe shift amount */ ++#define R_TILEPRO_SHAMT_X1 52 /* X1 pipe shift amount */ ++#define R_TILEPRO_SHAMT_Y0 53 /* Y0 pipe shift amount */ ++#define R_TILEPRO_SHAMT_Y1 54 /* Y1 pipe shift amount */ ++#define R_TILEPRO_DEST_IMM8_X1 55 /* X1 pipe destination 8-bit */ ++/* Relocs 56-59 are currently not defined. */ ++#define R_TILEPRO_TLS_GD_CALL 60 /* "jal" for TLS GD */ ++#define R_TILEPRO_IMM8_X0_TLS_GD_ADD 61 /* X0 pipe "addi" for TLS GD */ ++#define R_TILEPRO_IMM8_X1_TLS_GD_ADD 62 /* X1 pipe "addi" for TLS GD */ ++#define R_TILEPRO_IMM8_Y0_TLS_GD_ADD 63 /* Y0 pipe "addi" for TLS GD */ ++#define R_TILEPRO_IMM8_Y1_TLS_GD_ADD 64 /* Y1 pipe "addi" for TLS GD */ ++#define R_TILEPRO_TLS_IE_LOAD 65 /* "lw_tls" for TLS IE */ ++#define R_TILEPRO_IMM16_X0_TLS_GD 66 /* X0 pipe 16-bit TLS GD offset */ ++#define R_TILEPRO_IMM16_X1_TLS_GD 67 /* X1 pipe 16-bit TLS GD offset */ ++#define R_TILEPRO_IMM16_X0_TLS_GD_LO 68 /* X0 pipe low 16-bit TLS GD offset */ ++#define R_TILEPRO_IMM16_X1_TLS_GD_LO 69 /* X1 pipe low 16-bit TLS GD offset */ ++#define R_TILEPRO_IMM16_X0_TLS_GD_HI 70 /* X0 pipe high 16-bit TLS GD offset */ ++#define R_TILEPRO_IMM16_X1_TLS_GD_HI 71 /* X1 pipe high 16-bit TLS GD offset */ ++#define R_TILEPRO_IMM16_X0_TLS_GD_HA 72 /* X0 pipe ha() 16-bit TLS GD offset */ ++#define R_TILEPRO_IMM16_X1_TLS_GD_HA 73 /* X1 pipe ha() 16-bit TLS GD offset */ ++#define R_TILEPRO_IMM16_X0_TLS_IE 74 /* X0 pipe 16-bit TLS IE offset */ ++#define R_TILEPRO_IMM16_X1_TLS_IE 75 /* X1 pipe 16-bit TLS IE offset */ ++#define R_TILEPRO_IMM16_X0_TLS_IE_LO 76 /* X0 pipe low 16-bit TLS IE offset */ ++#define R_TILEPRO_IMM16_X1_TLS_IE_LO 77 /* X1 pipe low 16-bit TLS IE offset */ ++#define R_TILEPRO_IMM16_X0_TLS_IE_HI 78 /* X0 pipe high 16-bit TLS IE offset */ ++#define R_TILEPRO_IMM16_X1_TLS_IE_HI 79 /* X1 pipe high 16-bit TLS IE offset */ ++#define R_TILEPRO_IMM16_X0_TLS_IE_HA 80 /* X0 pipe ha() 16-bit TLS IE offset */ ++#define R_TILEPRO_IMM16_X1_TLS_IE_HA 81 /* X1 pipe ha() 16-bit TLS IE offset */ ++#define R_TILEPRO_TLS_DTPMOD32 82 /* ID of module containing symbol */ ++#define R_TILEPRO_TLS_DTPOFF32 83 /* Offset in TLS block */ ++#define R_TILEPRO_TLS_TPOFF32 84 /* Offset in static TLS block */ ++#define R_TILEPRO_IMM16_X0_TLS_LE 85 /* X0 pipe 16-bit TLS LE offset */ ++#define R_TILEPRO_IMM16_X1_TLS_LE 86 /* X1 pipe 16-bit TLS LE offset */ ++#define R_TILEPRO_IMM16_X0_TLS_LE_LO 87 /* X0 pipe low 16-bit TLS LE offset */ ++#define R_TILEPRO_IMM16_X1_TLS_LE_LO 88 /* X1 pipe low 16-bit TLS LE offset */ ++#define R_TILEPRO_IMM16_X0_TLS_LE_HI 89 /* X0 pipe high 16-bit TLS LE offset */ ++#define R_TILEPRO_IMM16_X1_TLS_LE_HI 90 /* X1 pipe high 16-bit TLS LE offset */ ++#define R_TILEPRO_IMM16_X0_TLS_LE_HA 91 /* X0 pipe ha() 16-bit TLS LE offset */ ++#define R_TILEPRO_IMM16_X1_TLS_LE_HA 92 /* X1 pipe ha() 16-bit TLS LE offset */ ++ ++#define R_TILEPRO_GNU_VTINHERIT 128 /* GNU C++ vtable hierarchy */ ++#define R_TILEPRO_GNU_VTENTRY 129 /* GNU C++ vtable member usage */ ++ ++#define R_TILEPRO_NUM 130 ++ ++ ++/* TILE-Gx relocations. */ ++#define R_TILEGX_NONE 0 /* No reloc */ ++#define R_TILEGX_64 1 /* Direct 64 bit */ ++#define R_TILEGX_32 2 /* Direct 32 bit */ ++#define R_TILEGX_16 3 /* Direct 16 bit */ ++#define R_TILEGX_8 4 /* Direct 8 bit */ ++#define R_TILEGX_64_PCREL 5 /* PC relative 64 bit */ ++#define R_TILEGX_32_PCREL 6 /* PC relative 32 bit */ ++#define R_TILEGX_16_PCREL 7 /* PC relative 16 bit */ ++#define R_TILEGX_8_PCREL 8 /* PC relative 8 bit */ ++#define R_TILEGX_HW0 9 /* hword 0 16-bit */ ++#define R_TILEGX_HW1 10 /* hword 1 16-bit */ ++#define R_TILEGX_HW2 11 /* hword 2 16-bit */ ++#define R_TILEGX_HW3 12 /* hword 3 16-bit */ ++#define R_TILEGX_HW0_LAST 13 /* last hword 0 16-bit */ ++#define R_TILEGX_HW1_LAST 14 /* last hword 1 16-bit */ ++#define R_TILEGX_HW2_LAST 15 /* last hword 2 16-bit */ ++#define R_TILEGX_COPY 16 /* Copy relocation */ ++#define R_TILEGX_GLOB_DAT 17 /* Create GOT entry */ ++#define R_TILEGX_JMP_SLOT 18 /* Create PLT entry */ ++#define R_TILEGX_RELATIVE 19 /* Adjust by program base */ ++#define R_TILEGX_BROFF_X1 20 /* X1 pipe branch offset */ ++#define R_TILEGX_JUMPOFF_X1 21 /* X1 pipe jump offset */ ++#define R_TILEGX_JUMPOFF_X1_PLT 22 /* X1 pipe jump offset to PLT */ ++#define R_TILEGX_IMM8_X0 23 /* X0 pipe 8-bit */ ++#define R_TILEGX_IMM8_Y0 24 /* Y0 pipe 8-bit */ ++#define R_TILEGX_IMM8_X1 25 /* X1 pipe 8-bit */ ++#define R_TILEGX_IMM8_Y1 26 /* Y1 pipe 8-bit */ ++#define R_TILEGX_DEST_IMM8_X1 27 /* X1 pipe destination 8-bit */ ++#define R_TILEGX_MT_IMM14_X1 28 /* X1 pipe mtspr */ ++#define R_TILEGX_MF_IMM14_X1 29 /* X1 pipe mfspr */ ++#define R_TILEGX_MMSTART_X0 30 /* X0 pipe mm "start" */ ++#define R_TILEGX_MMEND_X0 31 /* X0 pipe mm "end" */ ++#define R_TILEGX_SHAMT_X0 32 /* X0 pipe shift amount */ ++#define R_TILEGX_SHAMT_X1 33 /* X1 pipe shift amount */ ++#define R_TILEGX_SHAMT_Y0 34 /* Y0 pipe shift amount */ ++#define R_TILEGX_SHAMT_Y1 35 /* Y1 pipe shift amount */ ++#define R_TILEGX_IMM16_X0_HW0 36 /* X0 pipe hword 0 */ ++#define R_TILEGX_IMM16_X1_HW0 37 /* X1 pipe hword 0 */ ++#define R_TILEGX_IMM16_X0_HW1 38 /* X0 pipe hword 1 */ ++#define R_TILEGX_IMM16_X1_HW1 39 /* X1 pipe hword 1 */ ++#define R_TILEGX_IMM16_X0_HW2 40 /* X0 pipe hword 2 */ ++#define R_TILEGX_IMM16_X1_HW2 41 /* X1 pipe hword 2 */ ++#define R_TILEGX_IMM16_X0_HW3 42 /* X0 pipe hword 3 */ ++#define R_TILEGX_IMM16_X1_HW3 43 /* X1 pipe hword 3 */ ++#define R_TILEGX_IMM16_X0_HW0_LAST 44 /* X0 pipe last hword 0 */ ++#define R_TILEGX_IMM16_X1_HW0_LAST 45 /* X1 pipe last hword 0 */ ++#define R_TILEGX_IMM16_X0_HW1_LAST 46 /* X0 pipe last hword 1 */ ++#define R_TILEGX_IMM16_X1_HW1_LAST 47 /* X1 pipe last hword 1 */ ++#define R_TILEGX_IMM16_X0_HW2_LAST 48 /* X0 pipe last hword 2 */ ++#define R_TILEGX_IMM16_X1_HW2_LAST 49 /* X1 pipe last hword 2 */ ++#define R_TILEGX_IMM16_X0_HW0_PCREL 50 /* X0 pipe PC relative hword 0 */ ++#define R_TILEGX_IMM16_X1_HW0_PCREL 51 /* X1 pipe PC relative hword 0 */ ++#define R_TILEGX_IMM16_X0_HW1_PCREL 52 /* X0 pipe PC relative hword 1 */ ++#define R_TILEGX_IMM16_X1_HW1_PCREL 53 /* X1 pipe PC relative hword 1 */ ++#define R_TILEGX_IMM16_X0_HW2_PCREL 54 /* X0 pipe PC relative hword 2 */ ++#define R_TILEGX_IMM16_X1_HW2_PCREL 55 /* X1 pipe PC relative hword 2 */ ++#define R_TILEGX_IMM16_X0_HW3_PCREL 56 /* X0 pipe PC relative hword 3 */ ++#define R_TILEGX_IMM16_X1_HW3_PCREL 57 /* X1 pipe PC relative hword 3 */ ++#define R_TILEGX_IMM16_X0_HW0_LAST_PCREL 58 /* X0 pipe PC-rel last hword 0 */ ++#define R_TILEGX_IMM16_X1_HW0_LAST_PCREL 59 /* X1 pipe PC-rel last hword 0 */ ++#define R_TILEGX_IMM16_X0_HW1_LAST_PCREL 60 /* X0 pipe PC-rel last hword 1 */ ++#define R_TILEGX_IMM16_X1_HW1_LAST_PCREL 61 /* X1 pipe PC-rel last hword 1 */ ++#define R_TILEGX_IMM16_X0_HW2_LAST_PCREL 62 /* X0 pipe PC-rel last hword 2 */ ++#define R_TILEGX_IMM16_X1_HW2_LAST_PCREL 63 /* X1 pipe PC-rel last hword 2 */ ++#define R_TILEGX_IMM16_X0_HW0_GOT 64 /* X0 pipe hword 0 GOT offset */ ++#define R_TILEGX_IMM16_X1_HW0_GOT 65 /* X1 pipe hword 0 GOT offset */ ++/* Relocs 66-71 are currently not defined. */ ++#define R_TILEGX_IMM16_X0_HW0_LAST_GOT 72 /* X0 pipe last hword 0 GOT offset */ ++#define R_TILEGX_IMM16_X1_HW0_LAST_GOT 73 /* X1 pipe last hword 0 GOT offset */ ++#define R_TILEGX_IMM16_X0_HW1_LAST_GOT 74 /* X0 pipe last hword 1 GOT offset */ ++#define R_TILEGX_IMM16_X1_HW1_LAST_GOT 75 /* X1 pipe last hword 1 GOT offset */ ++/* Relocs 76-77 are currently not defined. */ ++#define R_TILEGX_IMM16_X0_HW0_TLS_GD 78 /* X0 pipe hword 0 TLS GD offset */ ++#define R_TILEGX_IMM16_X1_HW0_TLS_GD 79 /* X1 pipe hword 0 TLS GD offset */ ++#define R_TILEGX_IMM16_X0_HW0_TLS_LE 80 /* X0 pipe hword 0 TLS LE offset */ ++#define R_TILEGX_IMM16_X1_HW0_TLS_LE 81 /* X1 pipe hword 0 TLS LE offset */ ++#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_LE 82 /* X0 pipe last hword 0 LE off */ ++#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_LE 83 /* X1 pipe last hword 0 LE off */ ++#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_LE 84 /* X0 pipe last hword 1 LE off */ ++#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_LE 85 /* X1 pipe last hword 1 LE off */ ++#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD 86 /* X0 pipe last hword 0 GD off */ ++#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD 87 /* X1 pipe last hword 0 GD off */ ++#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD 88 /* X0 pipe last hword 1 GD off */ ++#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD 89 /* X1 pipe last hword 1 GD off */ ++/* Relocs 90-91 are currently not defined. */ ++#define R_TILEGX_IMM16_X0_HW0_TLS_IE 92 /* X0 pipe hword 0 TLS IE offset */ ++#define R_TILEGX_IMM16_X1_HW0_TLS_IE 93 /* X1 pipe hword 0 TLS IE offset */ ++/* Relocs 94-99 are currently not defined. */ ++#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE 100 /* X0 pipe last hword 0 IE off */ ++#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE 101 /* X1 pipe last hword 0 IE off */ ++#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE 102 /* X0 pipe last hword 1 IE off */ ++#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE 103 /* X1 pipe last hword 1 IE off */ ++/* Relocs 104-105 are currently not defined. */ ++#define R_TILEGX_TLS_DTPMOD64 106 /* 64-bit ID of symbol's module */ ++#define R_TILEGX_TLS_DTPOFF64 107 /* 64-bit offset in TLS block */ ++#define R_TILEGX_TLS_TPOFF64 108 /* 64-bit offset in static TLS block */ ++#define R_TILEGX_TLS_DTPMOD32 109 /* 32-bit ID of symbol's module */ ++#define R_TILEGX_TLS_DTPOFF32 110 /* 32-bit offset in TLS block */ ++#define R_TILEGX_TLS_TPOFF32 111 /* 32-bit offset in static TLS block */ ++#define R_TILEGX_TLS_GD_CALL 112 /* "jal" for TLS GD */ ++#define R_TILEGX_IMM8_X0_TLS_GD_ADD 113 /* X0 pipe "addi" for TLS GD */ ++#define R_TILEGX_IMM8_X1_TLS_GD_ADD 114 /* X1 pipe "addi" for TLS GD */ ++#define R_TILEGX_IMM8_Y0_TLS_GD_ADD 115 /* Y0 pipe "addi" for TLS GD */ ++#define R_TILEGX_IMM8_Y1_TLS_GD_ADD 116 /* Y1 pipe "addi" for TLS GD */ ++#define R_TILEGX_TLS_IE_LOAD 117 /* "ld_tls" for TLS IE */ ++#define R_TILEGX_IMM8_X0_TLS_ADD 118 /* X0 pipe "addi" for TLS GD/IE */ ++#define R_TILEGX_IMM8_X1_TLS_ADD 119 /* X1 pipe "addi" for TLS GD/IE */ ++#define R_TILEGX_IMM8_Y0_TLS_ADD 120 /* Y0 pipe "addi" for TLS GD/IE */ ++#define R_TILEGX_IMM8_Y1_TLS_ADD 121 /* Y1 pipe "addi" for TLS GD/IE */ ++ ++#define R_TILEGX_GNU_VTINHERIT 128 /* GNU C++ vtable hierarchy */ ++#define R_TILEGX_GNU_VTENTRY 129 /* GNU C++ vtable member usage */ ++ ++#define R_TILEGX_NUM 130 ++ ++#endif /* elf.h */ diff --git a/target/linux/generic/patches-4.1/212-byteshift_portability.patch b/target/linux/generic/patches-4.1/212-byteshift_portability.patch new file mode 100644 index 0000000..0f23ba9 --- /dev/null +++ b/target/linux/generic/patches-4.1/212-byteshift_portability.patch @@ -0,0 +1,51 @@ +--- a/tools/include/tools/be_byteshift.h ++++ b/tools/include/tools/be_byteshift.h +@@ -1,6 +1,10 @@ + #ifndef _TOOLS_BE_BYTESHIFT_H + #define _TOOLS_BE_BYTESHIFT_H + ++#ifndef __linux__ ++#include "linux_types.h" ++#endif ++ + #include + + static inline uint16_t __get_unaligned_be16(const uint8_t *p) +--- a/tools/include/tools/le_byteshift.h ++++ b/tools/include/tools/le_byteshift.h +@@ -1,6 +1,10 @@ + #ifndef _TOOLS_LE_BYTESHIFT_H + #define _TOOLS_LE_BYTESHIFT_H + ++#ifndef __linux__ ++#include "linux_types.h" ++#endif ++ + #include + + static inline uint16_t __get_unaligned_le16(const uint8_t *p) +--- /dev/null ++++ b/tools/include/tools/linux_types.h +@@ -0,0 +1,22 @@ ++#ifndef __LINUX_TYPES_H ++#define __LINUX_TYPES_H ++ ++#include ++ ++typedef uint8_t __u8; ++typedef uint8_t __be8; ++typedef uint8_t __le8; ++ ++typedef uint16_t __u16; ++typedef uint16_t __be16; ++typedef uint16_t __le16; ++ ++typedef uint32_t __u32; ++typedef uint32_t __be32; ++typedef uint32_t __le32; ++ ++typedef uint64_t __u64; ++typedef uint64_t __be64; ++typedef uint64_t __le64; ++ ++#endif diff --git a/target/linux/generic/patches-4.1/214-spidev_h_portability.patch b/target/linux/generic/patches-4.1/214-spidev_h_portability.patch new file mode 100644 index 0000000..dbee090 --- /dev/null +++ b/target/linux/generic/patches-4.1/214-spidev_h_portability.patch @@ -0,0 +1,11 @@ +--- a/include/uapi/linux/spi/spidev.h ++++ b/include/uapi/linux/spi/spidev.h +@@ -111,7 +111,7 @@ struct spi_ioc_transfer { + + /* not all platforms use or _IOC_TYPECHECK() ... */ + #define SPI_MSGSIZE(N) \ +- ((((N)*(sizeof (struct spi_ioc_transfer))) < (1 << _IOC_SIZEBITS)) \ ++ ((((N)*(sizeof (struct spi_ioc_transfer))) < (1 << 13)) \ + ? ((N)*(sizeof (struct spi_ioc_transfer))) : 0) + #define SPI_IOC_MESSAGE(N) _IOW(SPI_IOC_MAGIC, 0, char[SPI_MSGSIZE(N)]) + diff --git a/target/linux/generic/patches-4.1/220-gc_sections.patch b/target/linux/generic/patches-4.1/220-gc_sections.patch new file mode 100644 index 0000000..98e1193 --- /dev/null +++ b/target/linux/generic/patches-4.1/220-gc_sections.patch @@ -0,0 +1,536 @@ +From: Felix Fietkau + +use -ffunction-sections, -fdata-sections and --gc-sections + +In combination with kernel symbol export stripping this significantly reduces +the kernel image size. Used on both ARM and MIPS architectures. + +Signed-off-by: Felix Fietkau +Signed-off-by: Jonas Gorski +Signed-off-by: Gabor Juhos +--- + +--- a/arch/mips/Makefile ++++ b/arch/mips/Makefile +@@ -89,10 +89,14 @@ all-$(CONFIG_SYS_SUPPORTS_ZBOOT)+= vmlin + # + cflags-y += -G 0 -mno-abicalls -fno-pic -pipe + cflags-y += -msoft-float +-LDFLAGS_vmlinux += -G 0 -static -n -nostdlib ++LDFLAGS_vmlinux += -G 0 -static -n -nostdlib --gc-sections + KBUILD_AFLAGS_MODULE += -mlong-calls + KBUILD_CFLAGS_MODULE += -mlong-calls + ++ifndef CONFIG_FUNCTION_TRACER ++KBUILD_CFLAGS_KERNEL += -ffunction-sections -fdata-sections ++endif ++ + # + # pass -msoft-float to GAS if it supports it. However on newer binutils + # (specifically newer than 2.24.51.20140728) we then also need to explicitly +--- a/arch/mips/kernel/vmlinux.lds.S ++++ b/arch/mips/kernel/vmlinux.lds.S +@@ -67,7 +67,7 @@ SECTIONS + /* Exception table for data bus errors */ + __dbe_table : { + __start___dbe_table = .; +- *(__dbe_table) ++ KEEP(*(__dbe_table)) + __stop___dbe_table = .; + } + +@@ -112,7 +112,7 @@ SECTIONS + . = ALIGN(4); + .mips.machines.init : AT(ADDR(.mips.machines.init) - LOAD_OFFSET) { + __mips_machines_start = .; +- *(.mips.machines.init) ++ KEEP(*(.mips.machines.init)) + __mips_machines_end = .; + } + +--- a/include/asm-generic/vmlinux.lds.h ++++ b/include/asm-generic/vmlinux.lds.h +@@ -89,7 +89,7 @@ + #ifdef CONFIG_FTRACE_MCOUNT_RECORD + #define MCOUNT_REC() . = ALIGN(8); \ + VMLINUX_SYMBOL(__start_mcount_loc) = .; \ +- *(__mcount_loc) \ ++ KEEP(*(__mcount_loc)) \ + VMLINUX_SYMBOL(__stop_mcount_loc) = .; + #else + #define MCOUNT_REC() +@@ -97,7 +97,7 @@ + + #ifdef CONFIG_TRACE_BRANCH_PROFILING + #define LIKELY_PROFILE() VMLINUX_SYMBOL(__start_annotated_branch_profile) = .; \ +- *(_ftrace_annotated_branch) \ ++ KEEP(*(_ftrace_annotated_branch)) \ + VMLINUX_SYMBOL(__stop_annotated_branch_profile) = .; + #else + #define LIKELY_PROFILE() +@@ -105,7 +105,7 @@ + + #ifdef CONFIG_PROFILE_ALL_BRANCHES + #define BRANCH_PROFILE() VMLINUX_SYMBOL(__start_branch_profile) = .; \ +- *(_ftrace_branch) \ ++ KEEP(*(_ftrace_branch)) \ + VMLINUX_SYMBOL(__stop_branch_profile) = .; + #else + #define BRANCH_PROFILE() +@@ -114,7 +114,7 @@ + #ifdef CONFIG_KPROBES + #define KPROBE_BLACKLIST() . = ALIGN(8); \ + VMLINUX_SYMBOL(__start_kprobe_blacklist) = .; \ +- *(_kprobe_blacklist) \ ++ KEEP(*(_kprobe_blacklist)) \ + VMLINUX_SYMBOL(__stop_kprobe_blacklist) = .; + #else + #define KPROBE_BLACKLIST() +@@ -123,10 +123,10 @@ + #ifdef CONFIG_EVENT_TRACING + #define FTRACE_EVENTS() . = ALIGN(8); \ + VMLINUX_SYMBOL(__start_ftrace_events) = .; \ +- *(_ftrace_events) \ ++ KEEP(*(_ftrace_events)) \ + VMLINUX_SYMBOL(__stop_ftrace_events) = .; \ + VMLINUX_SYMBOL(__start_ftrace_enum_maps) = .; \ +- *(_ftrace_enum_map) \ ++ KEEP(*(_ftrace_enum_map)) \ + VMLINUX_SYMBOL(__stop_ftrace_enum_maps) = .; + #else + #define FTRACE_EVENTS() +@@ -134,7 +134,7 @@ + + #ifdef CONFIG_TRACING + #define TRACE_PRINTKS() VMLINUX_SYMBOL(__start___trace_bprintk_fmt) = .; \ +- *(__trace_printk_fmt) /* Trace_printk fmt' pointer */ \ ++ KEEP(*(__trace_printk_fmt)) /* Trace_printk fmt' pointer */ \ + VMLINUX_SYMBOL(__stop___trace_bprintk_fmt) = .; + #define TRACEPOINT_STR() VMLINUX_SYMBOL(__start___tracepoint_str) = .; \ + *(__tracepoint_str) /* Trace_printk fmt' pointer */ \ +@@ -147,7 +147,7 @@ + #ifdef CONFIG_FTRACE_SYSCALLS + #define TRACE_SYSCALLS() . = ALIGN(8); \ + VMLINUX_SYMBOL(__start_syscalls_metadata) = .; \ +- *(__syscalls_metadata) \ ++ KEEP(*(__syscalls_metadata)) \ + VMLINUX_SYMBOL(__stop_syscalls_metadata) = .; + #else + #define TRACE_SYSCALLS() +@@ -169,8 +169,8 @@ + #define _OF_TABLE_1(name) \ + . = ALIGN(8); \ + VMLINUX_SYMBOL(__##name##_of_table) = .; \ +- *(__##name##_of_table) \ +- *(__##name##_of_table_end) ++ KEEP(*(__##name##_of_table)) \ ++ KEEP(*(__##name##_of_table_end)) + + #define CLKSRC_OF_TABLES() OF_TABLE(CONFIG_CLKSRC_OF, clksrc) + #define IRQCHIP_OF_MATCH_TABLE() OF_TABLE(CONFIG_IRQCHIP, irqchip) +@@ -184,7 +184,7 @@ + #define KERNEL_DTB() \ + STRUCT_ALIGN(); \ + VMLINUX_SYMBOL(__dtb_start) = .; \ +- *(.dtb.init.rodata) \ ++ KEEP(*(.dtb.init.rodata)) \ + VMLINUX_SYMBOL(__dtb_end) = .; + + /* .data section */ +@@ -200,16 +200,17 @@ + /* implement dynamic printk debug */ \ + . = ALIGN(8); \ + VMLINUX_SYMBOL(__start___jump_table) = .; \ +- *(__jump_table) \ ++ KEEP(*(__jump_table)) \ + VMLINUX_SYMBOL(__stop___jump_table) = .; \ + . = ALIGN(8); \ + VMLINUX_SYMBOL(__start___verbose) = .; \ +- *(__verbose) \ ++ KEEP(*(__verbose)) \ + VMLINUX_SYMBOL(__stop___verbose) = .; \ + LIKELY_PROFILE() \ + BRANCH_PROFILE() \ + TRACE_PRINTKS() \ +- TRACEPOINT_STR() ++ TRACEPOINT_STR() \ ++ *(.data.[a-zA-Z_]*) + + /* + * Data section helpers +@@ -263,35 +264,35 @@ + /* PCI quirks */ \ + .pci_fixup : AT(ADDR(.pci_fixup) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start_pci_fixups_early) = .; \ +- *(.pci_fixup_early) \ ++ KEEP(*(.pci_fixup_early)) \ + VMLINUX_SYMBOL(__end_pci_fixups_early) = .; \ + VMLINUX_SYMBOL(__start_pci_fixups_header) = .; \ +- *(.pci_fixup_header) \ ++ KEEP(*(.pci_fixup_header)) \ + VMLINUX_SYMBOL(__end_pci_fixups_header) = .; \ + VMLINUX_SYMBOL(__start_pci_fixups_final) = .; \ +- *(.pci_fixup_final) \ ++ KEEP(*(.pci_fixup_final)) \ + VMLINUX_SYMBOL(__end_pci_fixups_final) = .; \ + VMLINUX_SYMBOL(__start_pci_fixups_enable) = .; \ +- *(.pci_fixup_enable) \ ++ KEEP(*(.pci_fixup_enable)) \ + VMLINUX_SYMBOL(__end_pci_fixups_enable) = .; \ + VMLINUX_SYMBOL(__start_pci_fixups_resume) = .; \ +- *(.pci_fixup_resume) \ ++ KEEP(*(.pci_fixup_resume)) \ + VMLINUX_SYMBOL(__end_pci_fixups_resume) = .; \ + VMLINUX_SYMBOL(__start_pci_fixups_resume_early) = .; \ +- *(.pci_fixup_resume_early) \ ++ KEEP(*(.pci_fixup_resume_early)) \ + VMLINUX_SYMBOL(__end_pci_fixups_resume_early) = .; \ + VMLINUX_SYMBOL(__start_pci_fixups_suspend) = .; \ +- *(.pci_fixup_suspend) \ ++ KEEP(*(.pci_fixup_suspend)) \ + VMLINUX_SYMBOL(__end_pci_fixups_suspend) = .; \ + VMLINUX_SYMBOL(__start_pci_fixups_suspend_late) = .; \ +- *(.pci_fixup_suspend_late) \ ++ KEEP(*(.pci_fixup_suspend_late)) \ + VMLINUX_SYMBOL(__end_pci_fixups_suspend_late) = .; \ + } \ + \ + /* Built-in firmware blobs */ \ + .builtin_fw : AT(ADDR(.builtin_fw) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start_builtin_fw) = .; \ +- *(.builtin_fw) \ ++ KEEP(*(.builtin_fw)) \ + VMLINUX_SYMBOL(__end_builtin_fw) = .; \ + } \ + \ +@@ -300,49 +301,49 @@ + /* Kernel symbol table: Normal symbols */ \ + __ksymtab : AT(ADDR(__ksymtab) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___ksymtab) = .; \ +- *(SORT(___ksymtab+*)) \ ++ KEEP(*(SORT(___ksymtab+*))) \ + VMLINUX_SYMBOL(__stop___ksymtab) = .; \ + } \ + \ + /* Kernel symbol table: GPL-only symbols */ \ + __ksymtab_gpl : AT(ADDR(__ksymtab_gpl) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___ksymtab_gpl) = .; \ +- *(SORT(___ksymtab_gpl+*)) \ ++ KEEP(*(SORT(___ksymtab_gpl+*))) \ + VMLINUX_SYMBOL(__stop___ksymtab_gpl) = .; \ + } \ + \ + /* Kernel symbol table: Normal unused symbols */ \ + __ksymtab_unused : AT(ADDR(__ksymtab_unused) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___ksymtab_unused) = .; \ +- *(SORT(___ksymtab_unused+*)) \ ++ KEEP(*(SORT(___ksymtab_unused+*))) \ + VMLINUX_SYMBOL(__stop___ksymtab_unused) = .; \ + } \ + \ + /* Kernel symbol table: GPL-only unused symbols */ \ + __ksymtab_unused_gpl : AT(ADDR(__ksymtab_unused_gpl) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___ksymtab_unused_gpl) = .; \ +- *(SORT(___ksymtab_unused_gpl+*)) \ ++ KEEP(*(SORT(___ksymtab_unused_gpl+*))) \ + VMLINUX_SYMBOL(__stop___ksymtab_unused_gpl) = .; \ + } \ + \ + /* Kernel symbol table: GPL-future-only symbols */ \ + __ksymtab_gpl_future : AT(ADDR(__ksymtab_gpl_future) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___ksymtab_gpl_future) = .; \ +- *(SORT(___ksymtab_gpl_future+*)) \ ++ KEEP(*(SORT(___ksymtab_gpl_future+*))) \ + VMLINUX_SYMBOL(__stop___ksymtab_gpl_future) = .; \ + } \ + \ + /* Kernel symbol table: Normal symbols */ \ + __kcrctab : AT(ADDR(__kcrctab) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___kcrctab) = .; \ +- *(SORT(___kcrctab+*)) \ ++ KEEP(*(SORT(___kcrctab+*))) \ + VMLINUX_SYMBOL(__stop___kcrctab) = .; \ + } \ + \ + /* Kernel symbol table: GPL-only symbols */ \ + __kcrctab_gpl : AT(ADDR(__kcrctab_gpl) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___kcrctab_gpl) = .; \ +- *(SORT(___kcrctab_gpl+*)) \ ++ KEEP(*(SORT(___kcrctab_gpl+*))) \ + VMLINUX_SYMBOL(__stop___kcrctab_gpl) = .; \ + } \ + \ +@@ -356,14 +357,14 @@ + /* Kernel symbol table: GPL-only unused symbols */ \ + __kcrctab_unused_gpl : AT(ADDR(__kcrctab_unused_gpl) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___kcrctab_unused_gpl) = .; \ +- *(SORT(___kcrctab_unused_gpl+*)) \ ++ KEEP(*(SORT(___kcrctab_unused_gpl+*))) \ + VMLINUX_SYMBOL(__stop___kcrctab_unused_gpl) = .; \ + } \ + \ + /* Kernel symbol table: GPL-future-only symbols */ \ + __kcrctab_gpl_future : AT(ADDR(__kcrctab_gpl_future) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___kcrctab_gpl_future) = .; \ +- *(SORT(___kcrctab_gpl_future+*)) \ ++ KEEP(*(SORT(___kcrctab_gpl_future+*))) \ + VMLINUX_SYMBOL(__stop___kcrctab_gpl_future) = .; \ + } \ + \ +@@ -382,14 +383,14 @@ + /* Built-in module parameters. */ \ + __param : AT(ADDR(__param) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___param) = .; \ +- *(__param) \ ++ KEEP(*(__param)) \ + VMLINUX_SYMBOL(__stop___param) = .; \ + } \ + \ + /* Built-in module versions. */ \ + __modver : AT(ADDR(__modver) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___modver) = .; \ +- *(__modver) \ ++ KEEP(*(__modver)) \ + VMLINUX_SYMBOL(__stop___modver) = .; \ + . = ALIGN((align)); \ + VMLINUX_SYMBOL(__end_rodata) = .; \ +@@ -445,7 +446,7 @@ + #define ENTRY_TEXT \ + ALIGN_FUNCTION(); \ + VMLINUX_SYMBOL(__entry_text_start) = .; \ +- *(.entry.text) \ ++ KEEP(*(.entry.text)) \ + VMLINUX_SYMBOL(__entry_text_end) = .; + + #ifdef CONFIG_FUNCTION_GRAPH_TRACER +@@ -473,7 +474,7 @@ + . = ALIGN(align); \ + __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___ex_table) = .; \ +- *(__ex_table) \ ++ KEEP(*(__ex_table)) \ + VMLINUX_SYMBOL(__stop___ex_table) = .; \ + } + +@@ -489,9 +490,9 @@ + #ifdef CONFIG_CONSTRUCTORS + #define KERNEL_CTORS() . = ALIGN(8); \ + VMLINUX_SYMBOL(__ctors_start) = .; \ +- *(.ctors) \ ++ KEEP(*(.ctors)) \ + *(SORT(.init_array.*)) \ +- *(.init_array) \ ++ KEEP(*(.init_array)) \ + VMLINUX_SYMBOL(__ctors_end) = .; + #else + #define KERNEL_CTORS() +@@ -542,7 +543,7 @@ + #define SBSS(sbss_align) \ + . = ALIGN(sbss_align); \ + .sbss : AT(ADDR(.sbss) - LOAD_OFFSET) { \ +- *(.sbss) \ ++ *(.sbss .sbss.*) \ + *(.scommon) \ + } + +@@ -560,7 +561,7 @@ + BSS_FIRST_SECTIONS \ + *(.bss..page_aligned) \ + *(.dynbss) \ +- *(.bss) \ ++ *(.bss .bss.*) \ + *(COMMON) \ + } + +@@ -609,7 +610,7 @@ + . = ALIGN(8); \ + __bug_table : AT(ADDR(__bug_table) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___bug_table) = .; \ +- *(__bug_table) \ ++ KEEP(*(__bug_table)) \ + VMLINUX_SYMBOL(__stop___bug_table) = .; \ + } + #else +@@ -621,7 +622,7 @@ + . = ALIGN(4); \ + .tracedata : AT(ADDR(.tracedata) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__tracedata_start) = .; \ +- *(.tracedata) \ ++ KEEP(*(.tracedata)) \ + VMLINUX_SYMBOL(__tracedata_end) = .; \ + } + #else +@@ -638,17 +639,17 @@ + #define INIT_SETUP(initsetup_align) \ + . = ALIGN(initsetup_align); \ + VMLINUX_SYMBOL(__setup_start) = .; \ +- *(.init.setup) \ ++ KEEP(*(.init.setup)) \ + VMLINUX_SYMBOL(__setup_end) = .; + + #define INIT_CALLS_LEVEL(level) \ + VMLINUX_SYMBOL(__initcall##level##_start) = .; \ +- *(.initcall##level##.init) \ +- *(.initcall##level##s.init) \ ++ KEEP(*(.initcall##level##.init)) \ ++ KEEP(*(.initcall##level##s.init)) \ + + #define INIT_CALLS \ + VMLINUX_SYMBOL(__initcall_start) = .; \ +- *(.initcallearly.init) \ ++ KEEP(*(.initcallearly.init)) \ + INIT_CALLS_LEVEL(0) \ + INIT_CALLS_LEVEL(1) \ + INIT_CALLS_LEVEL(2) \ +@@ -662,21 +663,21 @@ + + #define CON_INITCALL \ + VMLINUX_SYMBOL(__con_initcall_start) = .; \ +- *(.con_initcall.init) \ ++ KEEP(*(.con_initcall.init)) \ + VMLINUX_SYMBOL(__con_initcall_end) = .; + + #define SECURITY_INITCALL \ + VMLINUX_SYMBOL(__security_initcall_start) = .; \ +- *(.security_initcall.init) \ ++ KEEP(*(.security_initcall.init)) \ + VMLINUX_SYMBOL(__security_initcall_end) = .; + + #ifdef CONFIG_BLK_DEV_INITRD + #define INIT_RAM_FS \ + . = ALIGN(4); \ + VMLINUX_SYMBOL(__initramfs_start) = .; \ +- *(.init.ramfs) \ ++ KEEP(*(.init.ramfs)) \ + . = ALIGN(8); \ +- *(.init.ramfs.info) ++ KEEP(*(.init.ramfs.info)) + #else + #define INIT_RAM_FS + #endif +--- a/arch/arm/Makefile ++++ b/arch/arm/Makefile +@@ -18,11 +18,16 @@ ifeq ($(CONFIG_CPU_ENDIAN_BE8),y) + LDFLAGS_vmlinux += --be8 + LDFLAGS_MODULE += --be8 + endif ++LDFLAGS_vmlinux += --gc-sections + + OBJCOPYFLAGS :=-O binary -R .comment -S + GZFLAGS :=-9 + #KBUILD_CFLAGS +=-pipe + ++ifndef CONFIG_FUNCTION_TRACER ++KBUILD_CFLAGS_KERNEL += -ffunction-sections -fdata-sections ++endif ++ + # Never generate .eh_frame + KBUILD_CFLAGS += $(call cc-option,-fno-dwarf2-cfi-asm) + +--- a/arch/arm/kernel/vmlinux.lds.S ++++ b/arch/arm/kernel/vmlinux.lds.S +@@ -15,13 +15,13 @@ + #define PROC_INFO \ + . = ALIGN(4); \ + VMLINUX_SYMBOL(__proc_info_begin) = .; \ +- *(.proc.info.init) \ ++ KEEP(*(.proc.info.init)) \ + VMLINUX_SYMBOL(__proc_info_end) = .; + + #define IDMAP_TEXT \ + ALIGN_FUNCTION(); \ + VMLINUX_SYMBOL(__idmap_text_start) = .; \ +- *(.idmap.text) \ ++ KEEP(*(.idmap.text)) \ + VMLINUX_SYMBOL(__idmap_text_end) = .; \ + . = ALIGN(PAGE_SIZE); \ + VMLINUX_SYMBOL(__hyp_idmap_text_start) = .; \ +@@ -102,7 +102,7 @@ SECTIONS + _stext = .; /* Text and read-only data */ + IDMAP_TEXT + __exception_text_start = .; +- *(.exception.text) ++ KEEP(*(.exception.text)) + __exception_text_end = .; + IRQENTRY_TEXT + TEXT_TEXT +@@ -126,7 +126,7 @@ SECTIONS + __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) { + __start___ex_table = .; + #ifdef CONFIG_MMU +- *(__ex_table) ++ KEEP(*(__ex_table)) + #endif + __stop___ex_table = .; + } +@@ -138,12 +138,12 @@ SECTIONS + . = ALIGN(8); + .ARM.unwind_idx : { + __start_unwind_idx = .; +- *(.ARM.exidx*) ++ KEEP(*(.ARM.exidx*)) + __stop_unwind_idx = .; + } + .ARM.unwind_tab : { + __start_unwind_tab = .; +- *(.ARM.extab*) ++ KEEP(*(.ARM.extab*)) + __stop_unwind_tab = .; + } + #endif +@@ -166,14 +166,14 @@ SECTIONS + */ + __vectors_start = .; + .vectors 0 : AT(__vectors_start) { +- *(.vectors) ++ KEEP(*(.vectors)) + } + . = __vectors_start + SIZEOF(.vectors); + __vectors_end = .; + + __stubs_start = .; + .stubs 0x1000 : AT(__stubs_start) { +- *(.stubs) ++ KEEP(*(.stubs)) + } + . = __stubs_start + SIZEOF(.stubs); + __stubs_end = .; +@@ -187,24 +187,24 @@ SECTIONS + } + .init.arch.info : { + __arch_info_begin = .; +- *(.arch.info.init) ++ KEEP(*(.arch.info.init)) + __arch_info_end = .; + } + .init.tagtable : { + __tagtable_begin = .; +- *(.taglist.init) ++ KEEP(*(.taglist.init)) + __tagtable_end = .; + } + #ifdef CONFIG_SMP_ON_UP + .init.smpalt : { + __smpalt_begin = .; +- *(.alt.smp.init) ++ KEEP(*(.alt.smp.init)) + __smpalt_end = .; + } + #endif + .init.pv_table : { + __pv_table_begin = .; +- *(.pv_table) ++ KEEP(*(.pv_table)) + __pv_table_end = .; + } + .init.data : { +--- a/arch/arm/boot/compressed/Makefile ++++ b/arch/arm/boot/compressed/Makefile +@@ -107,6 +107,7 @@ ifeq ($(CONFIG_FUNCTION_TRACER),y) + ORIG_CFLAGS := $(KBUILD_CFLAGS) + KBUILD_CFLAGS = $(subst -pg, , $(ORIG_CFLAGS)) + endif ++KBUILD_CFLAGS_KERNEL := $(patsubst -f%-sections,,$(KBUILD_CFLAGS_KERNEL)) + + ccflags-y := -fpic -mno-single-pic-base -fno-builtin -I$(obj) + asflags-y := -DZIMAGE diff --git a/target/linux/generic/patches-4.1/221-module_exports.patch b/target/linux/generic/patches-4.1/221-module_exports.patch new file mode 100644 index 0000000..57e2549 --- /dev/null +++ b/target/linux/generic/patches-4.1/221-module_exports.patch @@ -0,0 +1,88 @@ +--- a/include/asm-generic/vmlinux.lds.h ++++ b/include/asm-generic/vmlinux.lds.h +@@ -54,6 +54,16 @@ + #define LOAD_OFFSET 0 + #endif + ++#ifndef SYMTAB_KEEP ++#define SYMTAB_KEEP KEEP(*(SORT(___ksymtab+*))) ++#define SYMTAB_KEEP_GPL KEEP(*(SORT(___ksymtab_gpl+*))) ++#endif ++ ++#ifndef SYMTAB_DISCARD ++#define SYMTAB_DISCARD ++#define SYMTAB_DISCARD_GPL ++#endif ++ + #include + + /* Align . to a 8 byte boundary equals to maximum function alignment. */ +@@ -301,14 +311,14 @@ + /* Kernel symbol table: Normal symbols */ \ + __ksymtab : AT(ADDR(__ksymtab) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___ksymtab) = .; \ +- KEEP(*(SORT(___ksymtab+*))) \ ++ SYMTAB_KEEP \ + VMLINUX_SYMBOL(__stop___ksymtab) = .; \ + } \ + \ + /* Kernel symbol table: GPL-only symbols */ \ + __ksymtab_gpl : AT(ADDR(__ksymtab_gpl) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___ksymtab_gpl) = .; \ +- KEEP(*(SORT(___ksymtab_gpl+*))) \ ++ SYMTAB_KEEP_GPL \ + VMLINUX_SYMBOL(__stop___ksymtab_gpl) = .; \ + } \ + \ +@@ -370,7 +380,7 @@ + \ + /* Kernel symbol table: strings */ \ + __ksymtab_strings : AT(ADDR(__ksymtab_strings) - LOAD_OFFSET) { \ +- *(__ksymtab_strings) \ ++ *(__ksymtab_strings+*) \ + } \ + \ + /* __*init sections */ \ +@@ -696,6 +706,8 @@ + EXIT_TEXT \ + EXIT_DATA \ + EXIT_CALL \ ++ SYMTAB_DISCARD \ ++ SYMTAB_DISCARD_GPL \ + *(.discard) \ + *(.discard.*) \ + } +--- a/scripts/Makefile.build ++++ b/scripts/Makefile.build +@@ -299,7 +299,7 @@ targets += $(extra-y) $(MAKECMDGOALS) $( + # Linker scripts preprocessor (.lds.S -> .lds) + # --------------------------------------------------------------------------- + quiet_cmd_cpp_lds_S = LDS $@ +- cmd_cpp_lds_S = $(CPP) $(cpp_flags) -P -C -U$(ARCH) \ ++ cmd_cpp_lds_S = $(CPP) $(EXTRA_LDSFLAGS) $(cpp_flags) -P -C -U$(ARCH) \ + -D__ASSEMBLY__ -DLINKER_SCRIPT -o $@ $< + + $(obj)/%.lds: $(src)/%.lds.S FORCE +--- a/include/linux/export.h ++++ b/include/linux/export.h +@@ -52,12 +52,19 @@ extern struct module __this_module; + #define __CRC_SYMBOL(sym, sec) + #endif + ++#ifdef MODULE ++#define __EXPORT_SUFFIX(sym) ++#else ++#define __EXPORT_SUFFIX(sym) "+" #sym ++#endif ++ + /* For every exported symbol, place a struct in the __ksymtab section */ + #define __EXPORT_SYMBOL(sym, sec) \ + extern typeof(sym) sym; \ + __CRC_SYMBOL(sym, sec) \ + static const char __kstrtab_##sym[] \ +- __attribute__((section("__ksymtab_strings"), aligned(1))) \ ++ __attribute__((section("__ksymtab_strings" \ ++ __EXPORT_SUFFIX(sym)), aligned(1))) \ + = VMLINUX_SYMBOL_STR(sym); \ + extern const struct kernel_symbol __ksymtab_##sym; \ + __visible const struct kernel_symbol __ksymtab_##sym \ diff --git a/target/linux/generic/patches-4.1/230-openwrt_lzma_options.patch b/target/linux/generic/patches-4.1/230-openwrt_lzma_options.patch new file mode 100644 index 0000000..d5bbb19 --- /dev/null +++ b/target/linux/generic/patches-4.1/230-openwrt_lzma_options.patch @@ -0,0 +1,58 @@ +--- a/scripts/Makefile.lib ++++ b/scripts/Makefile.lib +@@ -324,7 +324,7 @@ cmd_bzip2 = (cat $(filter-out FORCE,$^) + + quiet_cmd_lzma = LZMA $@ + cmd_lzma = (cat $(filter-out FORCE,$^) | \ +- lzma -9 && $(call size_append, $(filter-out FORCE,$^))) > $@ || \ ++ lzma e -d20 -lc1 -lp2 -pb2 -eos -si -so && $(call size_append, $(filter-out FORCE,$^))) > $@ || \ + (rm -f $@ ; false) + + quiet_cmd_lzo = LZO $@ +--- a/scripts/gen_initramfs_list.sh ++++ b/scripts/gen_initramfs_list.sh +@@ -226,7 +226,7 @@ cpio_list= + output="/dev/stdout" + output_file="" + is_cpio_compressed= +-compr="gzip -n -9 -f" ++compr="gzip -n -9 -f -" + + arg="$1" + case "$arg" in +@@ -242,13 +242,13 @@ case "$arg" in + output=${cpio_list} + echo "$output_file" | grep -q "\.gz$" \ + && [ -x "`which gzip 2> /dev/null`" ] \ +- && compr="gzip -n -9 -f" ++ && compr="gzip -n -9 -f -" + echo "$output_file" | grep -q "\.bz2$" \ + && [ -x "`which bzip2 2> /dev/null`" ] \ +- && compr="bzip2 -9 -f" ++ && compr="bzip2 -9 -f -" + echo "$output_file" | grep -q "\.lzma$" \ + && [ -x "`which lzma 2> /dev/null`" ] \ +- && compr="lzma -9 -f" ++ && compr="lzma e -d20 -lc1 -lp2 -pb2 -eos -si -so" + echo "$output_file" | grep -q "\.xz$" \ + && [ -x "`which xz 2> /dev/null`" ] \ + && compr="xz --check=crc32 --lzma2=dict=1MiB" +@@ -315,7 +315,7 @@ if [ ! -z ${output_file} ]; then + if [ "${is_cpio_compressed}" = "compressed" ]; then + cat ${cpio_tfile} > ${output_file} + else +- (cat ${cpio_tfile} | ${compr} - > ${output_file}) \ ++ (cat ${cpio_tfile} | ${compr} > ${output_file}) \ + || (rm -f ${output_file} ; false) + fi + [ -z ${cpio_file} ] && rm ${cpio_tfile} +--- a/lib/decompress.c ++++ b/lib/decompress.c +@@ -48,6 +48,7 @@ static const struct compress_format comp + { {0x1f, 0x9e}, "gzip", gunzip }, + { {0x42, 0x5a}, "bzip2", bunzip2 }, + { {0x5d, 0x00}, "lzma", unlzma }, ++ { {0x6d, 0x00}, "lzma-openwrt", unlzma }, + { {0xfd, 0x37}, "xz", unxz }, + { {0x89, 0x4c}, "lzo", unlzo }, + { {0x02, 0x21}, "lz4", unlz4 }, diff --git a/target/linux/generic/patches-4.1/250-netfilter_depends.patch b/target/linux/generic/patches-4.1/250-netfilter_depends.patch new file mode 100644 index 0000000..2b0815d --- /dev/null +++ b/target/linux/generic/patches-4.1/250-netfilter_depends.patch @@ -0,0 +1,18 @@ +--- a/net/netfilter/Kconfig ++++ b/net/netfilter/Kconfig +@@ -210,7 +210,6 @@ config NF_CONNTRACK_FTP + + config NF_CONNTRACK_H323 + tristate "H.323 protocol support" +- depends on (IPV6 || IPV6=n) + depends on NETFILTER_ADVANCED + help + H.323 is a VoIP signalling protocol from ITU-T. As one of the most +@@ -914,7 +913,6 @@ config NETFILTER_XT_TARGET_SECMARK + + config NETFILTER_XT_TARGET_TCPMSS + tristate '"TCPMSS" target support' +- depends on (IPV6 || IPV6=n) + default m if NETFILTER_ADVANCED=n + ---help--- + This option adds a `TCPMSS' target, which allows you to alter the diff --git a/target/linux/generic/patches-4.1/251-sound_kconfig.patch b/target/linux/generic/patches-4.1/251-sound_kconfig.patch new file mode 100644 index 0000000..c2ebace --- /dev/null +++ b/target/linux/generic/patches-4.1/251-sound_kconfig.patch @@ -0,0 +1,18 @@ +--- a/sound/core/Kconfig ++++ b/sound/core/Kconfig +@@ -10,13 +10,13 @@ config SND_DMAENGINE_PCM + tristate + + config SND_HWDEP +- tristate ++ tristate "Sound hardware support" + + config SND_RAWMIDI + tristate + + config SND_COMPRESS_OFFLOAD +- tristate ++ tristate "Compression offloading support" + + # To be effective this also requires INPUT - users should say: + # select SND_JACK if INPUT=y || INPUT=SND diff --git a/target/linux/generic/patches-4.1/252-mv_cesa_depends.patch b/target/linux/generic/patches-4.1/252-mv_cesa_depends.patch new file mode 100644 index 0000000..fee28db --- /dev/null +++ b/target/linux/generic/patches-4.1/252-mv_cesa_depends.patch @@ -0,0 +1,10 @@ +--- a/drivers/crypto/Kconfig ++++ b/drivers/crypto/Kconfig +@@ -164,6 +164,7 @@ config CRYPTO_DEV_MV_CESA + depends on PLAT_ORION + select CRYPTO_ALGAPI + select CRYPTO_AES ++ select CRYPTO_HASH2 + select CRYPTO_BLKCIPHER2 + select CRYPTO_HASH + help diff --git a/target/linux/generic/patches-4.1/253-ssb_b43_default_on.patch b/target/linux/generic/patches-4.1/253-ssb_b43_default_on.patch new file mode 100644 index 0000000..29d2a41 --- /dev/null +++ b/target/linux/generic/patches-4.1/253-ssb_b43_default_on.patch @@ -0,0 +1,29 @@ +--- a/drivers/ssb/Kconfig ++++ b/drivers/ssb/Kconfig +@@ -29,6 +29,7 @@ config SSB_SPROM + config SSB_BLOCKIO + bool + depends on SSB ++ default y + + config SSB_PCIHOST_POSSIBLE + bool +@@ -49,7 +50,7 @@ config SSB_PCIHOST + config SSB_B43_PCI_BRIDGE + bool + depends on SSB_PCIHOST +- default n ++ default y + + config SSB_PCMCIAHOST_POSSIBLE + bool +--- a/drivers/bcma/Kconfig ++++ b/drivers/bcma/Kconfig +@@ -17,6 +17,7 @@ config BCMA + config BCMA_BLOCKIO + bool + depends on BCMA ++ default y + + config BCMA_HOST_PCI_POSSIBLE + bool diff --git a/target/linux/generic/patches-4.1/254-textsearch_kconfig_hacks.patch b/target/linux/generic/patches-4.1/254-textsearch_kconfig_hacks.patch new file mode 100644 index 0000000..d682d4e --- /dev/null +++ b/target/linux/generic/patches-4.1/254-textsearch_kconfig_hacks.patch @@ -0,0 +1,23 @@ +--- a/lib/Kconfig ++++ b/lib/Kconfig +@@ -328,16 +328,16 @@ config BCH_CONST_T + # Textsearch support is select'ed if needed + # + config TEXTSEARCH +- bool ++ boolean "Textsearch support" + + config TEXTSEARCH_KMP +- tristate ++ tristate "Textsearch KMP" + + config TEXTSEARCH_BM +- tristate ++ tristate "Textsearch BM" + + config TEXTSEARCH_FSM +- tristate ++ tristate "Textsearch FSM" + + config BTREE + bool diff --git a/target/linux/generic/patches-4.1/255-lib80211_kconfig_hacks.patch b/target/linux/generic/patches-4.1/255-lib80211_kconfig_hacks.patch new file mode 100644 index 0000000..8064b02 --- /dev/null +++ b/target/linux/generic/patches-4.1/255-lib80211_kconfig_hacks.patch @@ -0,0 +1,31 @@ +--- a/net/wireless/Kconfig ++++ b/net/wireless/Kconfig +@@ -191,7 +191,7 @@ config CFG80211_WEXT_EXPORT + wext compatibility symbols to be exported. + + config LIB80211 +- tristate ++ tristate "LIB80211" + default n + help + This options enables a library of common routines used +@@ -200,13 +200,16 @@ config LIB80211 + Drivers should select this themselves if needed. + + config LIB80211_CRYPT_WEP +- tristate ++ tristate "LIB80211_CRYPT_WEP" ++ select LIB80211 + + config LIB80211_CRYPT_CCMP +- tristate ++ tristate "LIB80211_CRYPT_CCMP" ++ select LIB80211 + + config LIB80211_CRYPT_TKIP +- tristate ++ tristate "LIB80211_CRYPT_TKIP" ++ select LIB80211 + + config LIB80211_DEBUG + bool "lib80211 debugging messages" diff --git a/target/linux/generic/patches-4.1/256-crypto_add_kconfig_prompts.patch b/target/linux/generic/patches-4.1/256-crypto_add_kconfig_prompts.patch new file mode 100644 index 0000000..f9f6c0e --- /dev/null +++ b/target/linux/generic/patches-4.1/256-crypto_add_kconfig_prompts.patch @@ -0,0 +1,47 @@ +--- a/crypto/Kconfig ++++ b/crypto/Kconfig +@@ -32,7 +32,7 @@ config CRYPTO_FIPS + this is. + + config CRYPTO_ALGAPI +- tristate ++ tristate "ALGAPI" + select CRYPTO_ALGAPI2 + help + This option provides the API for cryptographic algorithms. +@@ -41,7 +41,7 @@ config CRYPTO_ALGAPI2 + tristate + + config CRYPTO_AEAD +- tristate ++ tristate "AEAD" + select CRYPTO_AEAD2 + select CRYPTO_ALGAPI + +@@ -50,7 +50,7 @@ config CRYPTO_AEAD2 + select CRYPTO_ALGAPI2 + + config CRYPTO_BLKCIPHER +- tristate ++ tristate "BLKCIPHER" + select CRYPTO_BLKCIPHER2 + select CRYPTO_ALGAPI + +@@ -61,7 +61,7 @@ config CRYPTO_BLKCIPHER2 + select CRYPTO_WORKQUEUE + + config CRYPTO_HASH +- tristate ++ tristate "HASH" + select CRYPTO_HASH2 + select CRYPTO_ALGAPI + +@@ -70,7 +70,7 @@ config CRYPTO_HASH2 + select CRYPTO_ALGAPI2 + + config CRYPTO_RNG +- tristate ++ tristate "RNG" + select CRYPTO_RNG2 + select CRYPTO_ALGAPI + diff --git a/target/linux/generic/patches-4.1/257-wireless_ext_kconfig_hack.patch b/target/linux/generic/patches-4.1/257-wireless_ext_kconfig_hack.patch new file mode 100644 index 0000000..daac589 --- /dev/null +++ b/target/linux/generic/patches-4.1/257-wireless_ext_kconfig_hack.patch @@ -0,0 +1,22 @@ +--- a/net/wireless/Kconfig ++++ b/net/wireless/Kconfig +@@ -1,5 +1,5 @@ + config WIRELESS_EXT +- bool ++ bool "Wireless extensions" + + config WEXT_CORE + def_bool y +@@ -11,10 +11,10 @@ config WEXT_PROC + depends on WEXT_CORE + + config WEXT_SPY +- bool ++ bool "WEXT_SPY" + + config WEXT_PRIV +- bool ++ bool "WEXT_PRIV" + + config CFG80211 + tristate "cfg80211 - wireless configuration API" diff --git a/target/linux/generic/patches-4.1/258-netfilter_netlink_kconfig_hack.patch b/target/linux/generic/patches-4.1/258-netfilter_netlink_kconfig_hack.patch new file mode 100644 index 0000000..9d827c2 --- /dev/null +++ b/target/linux/generic/patches-4.1/258-netfilter_netlink_kconfig_hack.patch @@ -0,0 +1,11 @@ +--- a/net/netfilter/Kconfig ++++ b/net/netfilter/Kconfig +@@ -2,7 +2,7 @@ menu "Core Netfilter Configuration" + depends on NET && INET && NETFILTER + + config NETFILTER_NETLINK +- tristate ++ tristate "Netfilter NFNETLINK interface" + + config NETFILTER_NETLINK_ACCT + tristate "Netfilter NFACCT over NFNETLINK interface" diff --git a/target/linux/generic/patches-4.1/259-regmap_dynamic.patch b/target/linux/generic/patches-4.1/259-regmap_dynamic.patch new file mode 100644 index 0000000..a4bdae6 --- /dev/null +++ b/target/linux/generic/patches-4.1/259-regmap_dynamic.patch @@ -0,0 +1,87 @@ +--- a/drivers/base/regmap/Kconfig ++++ b/drivers/base/regmap/Kconfig +@@ -3,29 +3,35 @@ + # subsystems should select the appropriate symbols. + + config REGMAP +- default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ) + select LZO_COMPRESS + select LZO_DECOMPRESS + select IRQ_DOMAIN if REGMAP_IRQ +- bool ++ tristate "Regmap" + + config REGMAP_AC97 ++ select REGMAP + tristate + + config REGMAP_I2C +- tristate ++ tristate "Regmap I2C" ++ select REGMAP + depends on I2C + + config REGMAP_SPI +- tristate ++ tristate "Regmap SPI" ++ select REGMAP ++ depends on SPI_MASTER + depends on SPI + + config REGMAP_SPMI ++ select REGMAP + tristate + depends on SPMI + + config REGMAP_MMIO +- tristate ++ tristate "Regmap MMIO" ++ select REGMAP + + config REGMAP_IRQ ++ select REGMAP + bool +--- a/include/linux/regmap.h ++++ b/include/linux/regmap.h +@@ -50,7 +50,7 @@ struct reg_default { + unsigned int def; + }; + +-#ifdef CONFIG_REGMAP ++#if IS_ENABLED(CONFIG_REGMAP) + + enum regmap_endian { + /* Unspecified -> 0 -> Backwards compatible default */ +--- a/drivers/base/regmap/Makefile ++++ b/drivers/base/regmap/Makefile +@@ -1,9 +1,11 @@ + # For include/trace/define_trace.h to include trace.h + CFLAGS_regmap.o := -I$(src) + +-obj-$(CONFIG_REGMAP) += regmap.o regcache.o +-obj-$(CONFIG_REGMAP) += regcache-rbtree.o regcache-lzo.o regcache-flat.o +-obj-$(CONFIG_DEBUG_FS) += regmap-debugfs.o ++regmap-core-objs = regmap.o regcache.o regcache-rbtree.o regcache-lzo.o regcache-flat.o ++ifdef CONFIG_DEBUG_FS ++regmap-core-objs += regmap-debugfs.o ++endif ++obj-$(CONFIG_REGMAP) += regmap-core.o + obj-$(CONFIG_REGMAP_AC97) += regmap-ac97.o + obj-$(CONFIG_REGMAP_I2C) += regmap-i2c.o + obj-$(CONFIG_REGMAP_SPI) += regmap-spi.o +--- a/drivers/base/regmap/regmap.c ++++ b/drivers/base/regmap/regmap.c +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -2631,3 +2632,5 @@ static int __init regmap_initcall(void) + return 0; + } + postcore_initcall(regmap_initcall); ++ ++MODULE_LICENSE("GPL"); diff --git a/target/linux/generic/patches-4.1/260-crypto_test_dependencies.patch b/target/linux/generic/patches-4.1/260-crypto_test_dependencies.patch new file mode 100644 index 0000000..8a96fd9 --- /dev/null +++ b/target/linux/generic/patches-4.1/260-crypto_test_dependencies.patch @@ -0,0 +1,37 @@ +--- a/crypto/Kconfig ++++ b/crypto/Kconfig +@@ -96,10 +96,10 @@ config CRYPTO_MANAGER + + config CRYPTO_MANAGER2 + def_tristate CRYPTO_MANAGER || (CRYPTO_MANAGER!=n && CRYPTO_ALGAPI=y) +- select CRYPTO_AEAD2 +- select CRYPTO_HASH2 +- select CRYPTO_BLKCIPHER2 +- select CRYPTO_PCOMP2 ++ select CRYPTO_AEAD2 if !CRYPTO_MANAGER_DISABLE_TESTS ++ select CRYPTO_HASH2 if !CRYPTO_MANAGER_DISABLE_TESTS ++ select CRYPTO_BLKCIPHER2 if !CRYPTO_MANAGER_DISABLE_TESTS ++ select CRYPTO_PCOMP2 if !CRYPTO_MANAGER_DISABLE_TESTS + + config CRYPTO_USER + tristate "Userspace cryptographic algorithm configuration" +--- a/crypto/algboss.c ++++ b/crypto/algboss.c +@@ -248,6 +248,9 @@ static int cryptomgr_schedule_test(struc + type = alg->cra_flags; + + /* This piece of crap needs to disappear into per-type test hooks. */ ++#ifdef CONFIG_CRYPTO_MANAGER_DISABLE_TESTS ++ type |= CRYPTO_ALG_TESTED; ++#else + if ((!((type ^ CRYPTO_ALG_TYPE_BLKCIPHER) & + CRYPTO_ALG_TYPE_BLKCIPHER_MASK) && !(type & CRYPTO_ALG_GENIV) && + ((alg->cra_flags & CRYPTO_ALG_TYPE_MASK) == +@@ -256,6 +259,7 @@ static int cryptomgr_schedule_test(struc + (!((type ^ CRYPTO_ALG_TYPE_AEAD) & CRYPTO_ALG_TYPE_MASK) && + alg->cra_type == &crypto_nivaead_type && alg->cra_aead.ivsize)) + type |= CRYPTO_ALG_TESTED; ++#endif + + param->type = type; + diff --git a/target/linux/generic/patches-4.1/262-compressor_kconfig_hack.patch b/target/linux/generic/patches-4.1/262-compressor_kconfig_hack.patch new file mode 100644 index 0000000..771c167 --- /dev/null +++ b/target/linux/generic/patches-4.1/262-compressor_kconfig_hack.patch @@ -0,0 +1,35 @@ +--- a/lib/Kconfig ++++ b/lib/Kconfig +@@ -213,25 +213,25 @@ config RANDOM32_SELFTEST + # compression support is select'ed if needed + # + config ZLIB_INFLATE +- tristate ++ tristate "ZLIB inflate support" + + config ZLIB_DEFLATE +- tristate ++ tristate "ZLIB deflate support" + + config LZO_COMPRESS +- tristate ++ tristate "LZO compress support" + + config LZO_DECOMPRESS +- tristate ++ tristate "LZO decompress support" + + config LZ4_COMPRESS +- tristate ++ tristate "LZ4 compress support" + + config LZ4HC_COMPRESS +- tristate ++ tristate "LZ4HC compress support" + + config LZ4_DECOMPRESS +- tristate ++ tristate "LZ4 decompress support" + + source "lib/xz/Kconfig" + diff --git a/target/linux/generic/patches-4.1/270-uapi-kernel.h-glibc-specific-inclusion-of-sysinfo.h.patch b/target/linux/generic/patches-4.1/270-uapi-kernel.h-glibc-specific-inclusion-of-sysinfo.h.patch new file mode 100644 index 0000000..762f498 --- /dev/null +++ b/target/linux/generic/patches-4.1/270-uapi-kernel.h-glibc-specific-inclusion-of-sysinfo.h.patch @@ -0,0 +1,34 @@ +From 8b05e325824d3b38e52a7748b3b5dc34dc1c0f6d Mon Sep 17 00:00:00 2001 +From: David Heidelberger +Date: Mon, 29 Jun 2015 14:37:54 +0200 +Subject: [PATCH 1/3] uapi/kernel.h: glibc specific inclusion of sysinfo.h + +including sysinfo.h from kernel.h makes no sense whatsoever, +but removing it breaks glibc's userspace header, +which includes kernel.h instead of sysinfo.h from their sys/sysinfo.h. +this seems to be a historical mistake. +on musl, including any header that uses kernel.h directly or indirectly +plus sys/sysinfo.h will produce a compile error due to redefinition of +struct sysinfo from sys/sysinfo.h. +so for now, only include it on glibc or when including from kernel +in order not to break their headers. + +Signed-off-by: John Spencer +Signed-off-by: David Heidelberger +Signed-off-by: Jonas Gorski +--- + include/uapi/linux/kernel.h | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/include/uapi/linux/kernel.h ++++ b/include/uapi/linux/kernel.h +@@ -1,7 +1,9 @@ + #ifndef _UAPI_LINUX_KERNEL_H + #define _UAPI_LINUX_KERNEL_H + ++#if defined(__KERNEL__) || defined( __GLIBC__) + #include ++#endif + + /* + * 'kernel.h' contains some often-used function prototypes etc diff --git a/target/linux/generic/patches-4.1/271-uapi-libc-compat.h-do-not-rely-on-__GLIBC__.patch b/target/linux/generic/patches-4.1/271-uapi-libc-compat.h-do-not-rely-on-__GLIBC__.patch new file mode 100644 index 0000000..61d3873 --- /dev/null +++ b/target/linux/generic/patches-4.1/271-uapi-libc-compat.h-do-not-rely-on-__GLIBC__.patch @@ -0,0 +1,81 @@ +From f972afc2509eebcb00d370256c55b112a3b5ffca Mon Sep 17 00:00:00 2001 +From: David Heidelberger +Date: Mon, 29 Jun 2015 16:50:40 +0200 +Subject: [PATCH 2/3] uapi/libc-compat.h: do not rely on __GLIBC__ + +Musl provides the same structs as glibc, but does not provide a define to +allow its detection. Since the absence of __GLIBC__ also can mean that it +is included from the kernel, change the __GLIBC__ detection to +!__KERNEL__, which should always be true when included from userspace. + +Signed-off-by: John Spencer +Tested-by: David Heidelberger +Signed-off-by: Jonas Gorski +--- + include/uapi/linux/libc-compat.h | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +--- a/include/uapi/linux/libc-compat.h ++++ b/include/uapi/linux/libc-compat.h +@@ -48,13 +48,13 @@ + #ifndef _UAPI_LIBC_COMPAT_H + #define _UAPI_LIBC_COMPAT_H + +-/* We have included glibc headers... */ +-#if defined(__GLIBC__) ++/* We have included libc headers... */ ++#if !defined(__KERNEL__) + +-/* Coordinate with glibc netinet/in.h header. */ ++/* Coordinate with libc netinet/in.h header. */ + #if defined(_NETINET_IN_H) + +-/* GLIBC headers included first so don't define anything ++/* LIBC headers included first so don't define anything + * that would already be defined. */ + #define __UAPI_DEF_IN_ADDR 0 + #define __UAPI_DEF_IN_IPPROTO 0 +@@ -68,7 +68,7 @@ + * if the glibc code didn't define them. This guard matches + * the guard in glibc/inet/netinet/in.h which defines the + * additional in6_addr macros e.g. s6_addr16, and s6_addr32. */ +-#if defined(__USE_MISC) || defined (__USE_GNU) ++#if !defined(__GLIBC__) || defined(__USE_MISC) || defined (__USE_GNU) + #define __UAPI_DEF_IN6_ADDR_ALT 0 + #else + #define __UAPI_DEF_IN6_ADDR_ALT 1 +@@ -83,7 +83,7 @@ + #else + + /* Linux headers included first, and we must define everything +- * we need. The expectation is that glibc will check the ++ * we need. The expectation is that the libc will check the + * __UAPI_DEF_* defines and adjust appropriately. */ + #define __UAPI_DEF_IN_ADDR 1 + #define __UAPI_DEF_IN_IPPROTO 1 +@@ -93,7 +93,7 @@ + #define __UAPI_DEF_IN_CLASS 1 + + #define __UAPI_DEF_IN6_ADDR 1 +-/* We unconditionally define the in6_addr macros and glibc must ++/* We unconditionally define the in6_addr macros and the libc must + * coordinate. */ + #define __UAPI_DEF_IN6_ADDR_ALT 1 + #define __UAPI_DEF_SOCKADDR_IN6 1 +@@ -115,7 +115,7 @@ + /* If we did not see any headers from any supported C libraries, + * or we are being included in the kernel, then define everything + * that we need. */ +-#else /* !defined(__GLIBC__) */ ++#else /* defined(__KERNEL__) */ + + /* Definitions for in.h */ + #define __UAPI_DEF_IN_ADDR 1 +@@ -138,6 +138,6 @@ + /* Definitions for xattr.h */ + #define __UAPI_DEF_XATTR 1 + +-#endif /* __GLIBC__ */ ++#endif /* __KERNEL__ */ + + #endif /* _UAPI_LIBC_COMPAT_H */ diff --git a/target/linux/generic/patches-4.1/272-uapi-if_ether.h-prevent-redefinition-of-struct-ethhd.patch b/target/linux/generic/patches-4.1/272-uapi-if_ether.h-prevent-redefinition-of-struct-ethhd.patch new file mode 100644 index 0000000..257c9d7 --- /dev/null +++ b/target/linux/generic/patches-4.1/272-uapi-if_ether.h-prevent-redefinition-of-struct-ethhd.patch @@ -0,0 +1,67 @@ +From fcbb6fed85ea9ff4feb4f1ebd4f0f235fdaf06b6 Mon Sep 17 00:00:00 2001 +From: David Heidelberger +Date: Mon, 29 Jun 2015 16:53:03 +0200 +Subject: [PATCH 3/3] uapi/if_ether.h: prevent redefinition of struct ethhdr + +Musl provides its own ethhdr struct definition. Add a guard to prevent +its definition of the appropriate musl header has already been included. + +Signed-off-by: John Spencer +Tested-by: David Heidelberger +Signed-off-by: Jonas Gorski +--- + include/uapi/linux/if_ether.h | 3 +++ + include/uapi/linux/libc-compat.h | 11 +++++++++++ + 2 files changed, 14 insertions(+) + +--- a/include/uapi/linux/if_ether.h ++++ b/include/uapi/linux/if_ether.h +@@ -22,6 +22,7 @@ + #define _UAPI_LINUX_IF_ETHER_H + + #include ++#include + + /* + * IEEE 802.3 Ethernet magic constants. The frame sizes omit the preamble +@@ -134,11 +135,13 @@ + * This is an Ethernet frame header. + */ + ++#if __UAPI_DEF_ETHHDR + struct ethhdr { + unsigned char h_dest[ETH_ALEN]; /* destination eth addr */ + unsigned char h_source[ETH_ALEN]; /* source ether addr */ + __be16 h_proto; /* packet type ID field */ + } __attribute__((packed)); ++#endif + + + #endif /* _UAPI_LINUX_IF_ETHER_H */ +--- a/include/uapi/linux/libc-compat.h ++++ b/include/uapi/linux/libc-compat.h +@@ -51,6 +51,14 @@ + /* We have included libc headers... */ + #if !defined(__KERNEL__) + ++/* musl defines the ethhdr struct itself in its netinet/if_ether.h. ++ * Glibc just includes the kernel header and uses a different guard. */ ++#if defined(_NETINET_IF_ETHER_H) ++#define __UAPI_DEF_ETHHDR 0 ++#else ++#define __UAPI_DEF_ETHHDR 1 ++#endif ++ + /* Coordinate with libc netinet/in.h header. */ + #if defined(_NETINET_IN_H) + +@@ -117,6 +125,9 @@ + * that we need. */ + #else /* defined(__KERNEL__) */ + ++/* Definitions for if_ether.h */ ++#define __UAPI_DEF_ETHHDR 1 ++ + /* Definitions for in.h */ + #define __UAPI_DEF_IN_ADDR 1 + #define __UAPI_DEF_IN_IPPROTO 1 diff --git a/target/linux/generic/patches-4.1/300-mips_expose_boot_raw.patch b/target/linux/generic/patches-4.1/300-mips_expose_boot_raw.patch new file mode 100644 index 0000000..49f2ded --- /dev/null +++ b/target/linux/generic/patches-4.1/300-mips_expose_boot_raw.patch @@ -0,0 +1,39 @@ +From: Mark Miller + +This exposes the CONFIG_BOOT_RAW symbol in Kconfig. This is needed on +certain Broadcom chipsets running CFE in order to load the kernel. + +Signed-off-by: Mark Miller +Acked-by: Rob Landley +--- +--- a/arch/mips/Kconfig ++++ b/arch/mips/Kconfig +@@ -984,9 +984,6 @@ config FW_ARC + config ARCH_MAY_HAVE_PC_FDC + bool + +-config BOOT_RAW +- bool +- + config CEVT_BCM1480 + bool + +@@ -2676,6 +2673,18 @@ config USE_OF + config BUILTIN_DTB + bool + ++config BOOT_RAW ++ bool "Enable the kernel to be executed from the load address" ++ default n ++ help ++ Allow the kernel to be executed from the load address for ++ bootloaders which cannot read the ELF format. This places ++ a jump to start_kernel at the load address. ++ ++ If unsure, say N. ++ ++ ++ + endmenu + + config LOCKDEP_SUPPORT diff --git a/target/linux/generic/patches-4.1/301-mips_image_cmdline_hack.patch b/target/linux/generic/patches-4.1/301-mips_image_cmdline_hack.patch new file mode 100644 index 0000000..f853104 --- /dev/null +++ b/target/linux/generic/patches-4.1/301-mips_image_cmdline_hack.patch @@ -0,0 +1,28 @@ +--- a/arch/mips/Kconfig ++++ b/arch/mips/Kconfig +@@ -1073,6 +1073,10 @@ config SYNC_R4K + config MIPS_MACHINE + def_bool n + ++config IMAGE_CMDLINE_HACK ++ bool "OpenWrt specific image command line hack" ++ default n ++ + config NO_IOPORT_MAP + def_bool n + +--- a/arch/mips/kernel/head.S ++++ b/arch/mips/kernel/head.S +@@ -80,6 +80,12 @@ FEXPORT(__kernel_entry) + j kernel_entry + #endif + ++#ifdef CONFIG_IMAGE_CMDLINE_HACK ++ .ascii "CMDLINE:" ++EXPORT(__image_cmdline) ++ .fill 0x400 ++#endif /* CONFIG_IMAGE_CMDLINE_HACK */ ++ + __REF + + NESTED(kernel_entry, 16, sp) # kernel entry point diff --git a/target/linux/generic/patches-4.1/302-mips_no_branch_likely.patch b/target/linux/generic/patches-4.1/302-mips_no_branch_likely.patch new file mode 100644 index 0000000..44c6b04 --- /dev/null +++ b/target/linux/generic/patches-4.1/302-mips_no_branch_likely.patch @@ -0,0 +1,11 @@ +--- a/arch/mips/Makefile ++++ b/arch/mips/Makefile +@@ -87,7 +87,7 @@ all-$(CONFIG_SYS_SUPPORTS_ZBOOT)+= vmlin + # machines may also. Since BFD is incredibly buggy with respect to + # crossformat linking we rely on the elf2ecoff tool for format conversion. + # +-cflags-y += -G 0 -mno-abicalls -fno-pic -pipe ++cflags-y += -G 0 -mno-abicalls -fno-pic -pipe -mno-branch-likely + cflags-y += -msoft-float + LDFLAGS_vmlinux += -G 0 -static -n -nostdlib --gc-sections + KBUILD_AFLAGS_MODULE += -mlong-calls diff --git a/target/linux/generic/patches-4.1/304-mips_disable_fpu.patch b/target/linux/generic/patches-4.1/304-mips_disable_fpu.patch new file mode 100644 index 0000000..7dc2ac9 --- /dev/null +++ b/target/linux/generic/patches-4.1/304-mips_disable_fpu.patch @@ -0,0 +1,106 @@ +From: Manuel Lauss +Subject: [RFC PATCH v4 2/2] MIPS: make FPU emulator optional +Date: Mon, 7 Apr 2014 12:57:04 +0200 +Message-Id: <1396868224-252888-2-git-send-email-manuel.lauss@gmail.com> + +This small patch makes the MIPS FPU emulator optional. The kernel +kills float-users on systems without a hardware FPU by sending a SIGILL. + +Disabling the emulator shrinks vmlinux by about 54kBytes (32bit, +optimizing for size). + +Signed-off-by: Manuel Lauss +--- +v4: rediffed because of patch 1/2, should now work with micromips as well +v3: updated patch description with size savings. +v2: incorporated changes suggested by Jonas Gorski + force the fpu emulator on for micromips: relocating the parts + of the mmips code in the emulator to other areas would be a + much larger change; I went the cheap route instead with this. + + arch/mips/Kbuild | 2 +- + arch/mips/Kconfig | 14 ++++++++++++++ + arch/mips/include/asm/fpu.h | 5 +++-- + arch/mips/include/asm/fpu_emulator.h | 15 +++++++++++++++ + 4 files changed, 33 insertions(+), 3 deletions(-) + +--- a/arch/mips/Kconfig ++++ b/arch/mips/Kconfig +@@ -2668,6 +2668,20 @@ config MIPS_O32_FP64_SUPPORT + + If unsure, say N. + ++config MIPS_FPU_EMULATOR ++ bool "MIPS FPU Emulator" ++ default y ++ help ++ This option lets you disable the built-in MIPS FPU (Coprocessor 1) ++ emulator, which handles floating-point instructions on processors ++ without a hardware FPU. It is generally a good idea to keep the ++ emulator built-in, unless you are perfectly sure you have a ++ complete soft-float environment. With the emulator disabled, all ++ users of float operations will be killed with an illegal instr- ++ uction exception. ++ ++ Say Y, please. ++ + config USE_OF + bool + select OF +--- a/arch/mips/Makefile ++++ b/arch/mips/Makefile +@@ -292,7 +292,7 @@ OBJCOPYFLAGS += --remove-section=.regin + head-y := arch/mips/kernel/head.o + + libs-y += arch/mips/lib/ +-libs-y += arch/mips/math-emu/ ++libs-$(CONFIG_MIPS_FPU_EMULATOR) += arch/mips/math-emu/ + + # See arch/mips/Kbuild for content of core part of the kernel + core-y += arch/mips/ +--- a/arch/mips/include/asm/fpu.h ++++ b/arch/mips/include/asm/fpu.h +@@ -218,8 +218,10 @@ static inline int init_fpu(void) + /* Restore FRE */ + write_c0_config5(config5); + enable_fpu_hazard(); +- } else ++ } else if (IS_ENABLED(CONFIG_MIPS_FPU_EMULATOR)) + fpu_emulator_init_fpu(); ++ else ++ ret = SIGILL; + + return ret; + } +--- a/arch/mips/include/asm/fpu_emulator.h ++++ b/arch/mips/include/asm/fpu_emulator.h +@@ -30,6 +30,7 @@ + #include + #include + ++#ifdef CONFIG_MIPS_FPU_EMULATOR + #ifdef CONFIG_DEBUG_FS + + struct mips_fpu_emulator_stats { +@@ -66,6 +67,21 @@ extern int do_dsemulret(struct pt_regs * + extern int fpu_emulator_cop1Handler(struct pt_regs *xcp, + struct mips_fpu_struct *ctx, int has_fpu, + void *__user *fault_addr); ++#else /* no CONFIG_MIPS_FPU_EMULATOR */ ++static inline int do_dsemulret(struct pt_regs *xcp) ++{ ++ return 0; /* 0 means error, should never get here anyway */ ++} ++ ++static inline int fpu_emulator_cop1Handler(struct pt_regs *xcp, ++ struct mips_fpu_struct *ctx, int has_fpu, ++ void *__user *fault_addr) ++{ ++ *fault_addr = NULL; ++ return SIGILL; /* we don't speak MIPS FPU */ ++} ++#endif /* CONFIG_MIPS_FPU_EMULATOR */ ++ + int process_fpemu_return(int sig, void __user *fault_addr, + unsigned long fcr31); + int mm_isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, diff --git a/target/linux/generic/patches-4.1/305-mips_module_reloc.patch b/target/linux/generic/patches-4.1/305-mips_module_reloc.patch new file mode 100644 index 0000000..8b3975f --- /dev/null +++ b/target/linux/generic/patches-4.1/305-mips_module_reloc.patch @@ -0,0 +1,352 @@ +--- a/arch/mips/Makefile ++++ b/arch/mips/Makefile +@@ -90,8 +90,13 @@ all-$(CONFIG_SYS_SUPPORTS_ZBOOT)+= vmlin + cflags-y += -G 0 -mno-abicalls -fno-pic -pipe -mno-branch-likely + cflags-y += -msoft-float + LDFLAGS_vmlinux += -G 0 -static -n -nostdlib --gc-sections ++ifdef CONFIG_64BIT + KBUILD_AFLAGS_MODULE += -mlong-calls + KBUILD_CFLAGS_MODULE += -mlong-calls ++else ++KBUILD_AFLAGS_MODULE += -mno-long-calls ++KBUILD_CFLAGS_MODULE += -mno-long-calls ++endif + + ifndef CONFIG_FUNCTION_TRACER + KBUILD_CFLAGS_KERNEL += -ffunction-sections -fdata-sections +--- a/arch/mips/include/asm/module.h ++++ b/arch/mips/include/asm/module.h +@@ -11,6 +11,11 @@ struct mod_arch_specific { + const struct exception_table_entry *dbe_start; + const struct exception_table_entry *dbe_end; + struct mips_hi16 *r_mips_hi16_list; ++ ++ void *phys_plt_tbl; ++ void *virt_plt_tbl; ++ unsigned int phys_plt_offset; ++ unsigned int virt_plt_offset; + }; + + typedef uint8_t Elf64_Byte; /* Type for a 8-bit quantity. */ +--- a/arch/mips/kernel/module.c ++++ b/arch/mips/kernel/module.c +@@ -43,14 +43,221 @@ struct mips_hi16 { + static LIST_HEAD(dbe_list); + static DEFINE_SPINLOCK(dbe_lock); + +-#ifdef MODULE_START ++/* ++ * Get the potential max trampolines size required of the init and ++ * non-init sections. Only used if we cannot find enough contiguous ++ * physically mapped memory to put the module into. ++ */ ++static unsigned int ++get_plt_size(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, ++ const char *secstrings, unsigned int symindex, bool is_init) ++{ ++ unsigned long ret = 0; ++ unsigned int i, j; ++ Elf_Sym *syms; ++ ++ /* Everything marked ALLOC (this includes the exported symbols) */ ++ for (i = 1; i < hdr->e_shnum; ++i) { ++ unsigned int info = sechdrs[i].sh_info; ++ ++ if (sechdrs[i].sh_type != SHT_REL ++ && sechdrs[i].sh_type != SHT_RELA) ++ continue; ++ ++ /* Not a valid relocation section? */ ++ if (info >= hdr->e_shnum) ++ continue; ++ ++ /* Don't bother with non-allocated sections */ ++ if (!(sechdrs[info].sh_flags & SHF_ALLOC)) ++ continue; ++ ++ /* If it's called *.init*, and we're not init, we're ++ not interested */ ++ if ((strstr(secstrings + sechdrs[i].sh_name, ".init") != 0) ++ != is_init) ++ continue; ++ ++ syms = (Elf_Sym *) sechdrs[symindex].sh_addr; ++ if (sechdrs[i].sh_type == SHT_REL) { ++ Elf_Mips_Rel *rel = (void *) sechdrs[i].sh_addr; ++ unsigned int size = sechdrs[i].sh_size / sizeof(*rel); ++ ++ for (j = 0; j < size; ++j) { ++ Elf_Sym *sym; ++ ++ if (ELF_MIPS_R_TYPE(rel[j]) != R_MIPS_26) ++ continue; ++ ++ sym = syms + ELF_MIPS_R_SYM(rel[j]); ++ if (!is_init && sym->st_shndx != SHN_UNDEF) ++ continue; ++ ++ ret += 4 * sizeof(int); ++ } ++ } else { ++ Elf_Mips_Rela *rela = (void *) sechdrs[i].sh_addr; ++ unsigned int size = sechdrs[i].sh_size / sizeof(*rela); ++ ++ for (j = 0; j < size; ++j) { ++ Elf_Sym *sym; ++ ++ if (ELF_MIPS_R_TYPE(rela[j]) != R_MIPS_26) ++ continue; ++ ++ sym = syms + ELF_MIPS_R_SYM(rela[j]); ++ if (!is_init && sym->st_shndx != SHN_UNDEF) ++ continue; ++ ++ ret += 4 * sizeof(int); ++ } ++ } ++ } ++ ++ return ret; ++} ++ ++#ifndef MODULE_START ++static void *alloc_phys(unsigned long size) ++{ ++ unsigned order; ++ struct page *page; ++ struct page *p; ++ ++ size = PAGE_ALIGN(size); ++ order = get_order(size); ++ ++ page = alloc_pages(GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN | ++ __GFP_THISNODE, order); ++ if (!page) ++ return NULL; ++ ++ split_page(page, order); ++ ++ /* mark all pages except for the last one */ ++ for (p = page; p + 1 < page + (size >> PAGE_SHIFT); ++p) ++ set_bit(PG_owner_priv_1, &p->flags); ++ ++ for (p = page + (size >> PAGE_SHIFT); p < page + (1 << order); ++p) ++ __free_page(p); ++ ++ return page_address(page); ++} ++#endif ++ ++static void free_phys(void *ptr) ++{ ++ struct page *page; ++ bool free; ++ ++ page = virt_to_page(ptr); ++ do { ++ free = test_and_clear_bit(PG_owner_priv_1, &page->flags); ++ __free_page(page); ++ page++; ++ } while (free); ++} ++ ++ + void *module_alloc(unsigned long size) + { ++#ifdef MODULE_START + return __vmalloc_node_range(size, 1, MODULE_START, MODULE_END, + GFP_KERNEL, PAGE_KERNEL, 0, NUMA_NO_NODE, + __builtin_return_address(0)); ++#else ++ void *ptr; ++ ++ if (size == 0) ++ return NULL; ++ ++ ptr = alloc_phys(size); ++ ++ /* If we failed to allocate physically contiguous memory, ++ * fall back to regular vmalloc. The module loader code will ++ * create jump tables to handle long jumps */ ++ if (!ptr) ++ return vmalloc(size); ++ ++ return ptr; ++#endif + } ++ ++static inline bool is_phys_addr(void *ptr) ++{ ++#ifdef CONFIG_64BIT ++ return (KSEGX((unsigned long)ptr) == CKSEG0); ++#else ++ return (KSEGX(ptr) == KSEG0); + #endif ++} ++ ++/* Free memory returned from module_alloc */ ++void module_memfree(void *module_region) ++{ ++ if (is_phys_addr(module_region)) ++ free_phys(module_region); ++ else ++ vfree(module_region); ++} ++ ++static void *__module_alloc(int size, bool phys) ++{ ++ void *ptr; ++ ++ if (phys) ++ ptr = kmalloc(size, GFP_KERNEL); ++ else ++ ptr = vmalloc(size); ++ return ptr; ++} ++ ++static void __module_free(void *ptr) ++{ ++ if (is_phys_addr(ptr)) ++ kfree(ptr); ++ else ++ vfree(ptr); ++} ++ ++int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs, ++ char *secstrings, struct module *mod) ++{ ++ unsigned int symindex = 0; ++ unsigned int core_size, init_size; ++ int i; ++ ++ mod->arch.phys_plt_offset = 0; ++ mod->arch.virt_plt_offset = 0; ++ mod->arch.phys_plt_tbl = NULL; ++ mod->arch.virt_plt_tbl = NULL; ++ ++ if (IS_ENABLED(CONFIG_64BIT)) ++ return 0; ++ ++ for (i = 1; i < hdr->e_shnum; i++) ++ if (sechdrs[i].sh_type == SHT_SYMTAB) ++ symindex = i; ++ ++ core_size = get_plt_size(hdr, sechdrs, secstrings, symindex, false); ++ init_size = get_plt_size(hdr, sechdrs, secstrings, symindex, true); ++ ++ if ((core_size + init_size) == 0) ++ return 0; ++ ++ mod->arch.phys_plt_tbl = __module_alloc(core_size + init_size, 1); ++ if (!mod->arch.phys_plt_tbl) ++ return -ENOMEM; ++ ++ mod->arch.virt_plt_tbl = __module_alloc(core_size + init_size, 0); ++ if (!mod->arch.virt_plt_tbl) { ++ __module_free(mod->arch.phys_plt_tbl); ++ mod->arch.phys_plt_tbl = NULL; ++ return -ENOMEM; ++ } ++ ++ return 0; ++} + + int apply_r_mips_none(struct module *me, u32 *location, Elf_Addr v) + { +@@ -64,8 +271,39 @@ static int apply_r_mips_32_rel(struct mo + return 0; + } + ++static Elf_Addr add_plt_entry_to(unsigned *plt_offset, ++ void *start, Elf_Addr v) ++{ ++ unsigned *tramp = start + *plt_offset; ++ *plt_offset += 4 * sizeof(int); ++ ++ /* adjust carry for addiu */ ++ if (v & 0x00008000) ++ v += 0x10000; ++ ++ tramp[0] = 0x3c190000 | (v >> 16); /* lui t9, hi16 */ ++ tramp[1] = 0x27390000 | (v & 0xffff); /* addiu t9, t9, lo16 */ ++ tramp[2] = 0x03200008; /* jr t9 */ ++ tramp[3] = 0x00000000; /* nop */ ++ ++ return (Elf_Addr) tramp; ++} ++ ++static Elf_Addr add_plt_entry(struct module *me, void *location, Elf_Addr v) ++{ ++ if (is_phys_addr(location)) ++ return add_plt_entry_to(&me->arch.phys_plt_offset, ++ me->arch.phys_plt_tbl, v); ++ else ++ return add_plt_entry_to(&me->arch.virt_plt_offset, ++ me->arch.virt_plt_tbl, v); ++ ++} ++ + static int apply_r_mips_26_rel(struct module *me, u32 *location, Elf_Addr v) + { ++ u32 ofs = *location & 0x03ffffff; ++ + if (v % 4) { + pr_err("module %s: dangerous R_MIPS_26 REL relocation\n", + me->name); +@@ -73,14 +311,17 @@ static int apply_r_mips_26_rel(struct mo + } + + if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) { +- printk(KERN_ERR +- "module %s: relocation overflow\n", +- me->name); +- return -ENOEXEC; ++ v = add_plt_entry(me, location, v + (ofs << 2)); ++ if (!v) { ++ printk(KERN_ERR ++ "module %s: relocation overflow\n", me->name); ++ return -ENOEXEC; ++ } ++ ofs = 0; + } + + *location = (*location & ~0x03ffffff) | +- ((*location + (v >> 2)) & 0x03ffffff); ++ ((ofs + (v >> 2)) & 0x03ffffff); + + return 0; + } +@@ -287,9 +528,33 @@ int module_finalize(const Elf_Ehdr *hdr, + list_add(&me->arch.dbe_list, &dbe_list); + spin_unlock_irq(&dbe_lock); + } ++ ++ /* Get rid of the fixup trampoline if we're running the module ++ * from physically mapped address space */ ++ if (me->arch.phys_plt_offset == 0) { ++ __module_free(me->arch.phys_plt_tbl); ++ me->arch.phys_plt_tbl = NULL; ++ } ++ if (me->arch.virt_plt_offset == 0) { ++ __module_free(me->arch.virt_plt_tbl); ++ me->arch.virt_plt_tbl = NULL; ++ } ++ + return 0; + } + ++void module_arch_freeing_init(struct module *mod) ++{ ++ if (mod->arch.phys_plt_tbl) { ++ __module_free(mod->arch.phys_plt_tbl); ++ mod->arch.phys_plt_tbl = NULL; ++ } ++ if (mod->arch.virt_plt_tbl) { ++ __module_free(mod->arch.virt_plt_tbl); ++ mod->arch.virt_plt_tbl = NULL; ++ } ++} ++ + void module_arch_cleanup(struct module *mod) + { + spin_lock_irq(&dbe_lock); diff --git a/target/linux/generic/patches-4.1/306-mips_mem_functions_performance.patch b/target/linux/generic/patches-4.1/306-mips_mem_functions_performance.patch new file mode 100644 index 0000000..9818677 --- /dev/null +++ b/target/linux/generic/patches-4.1/306-mips_mem_functions_performance.patch @@ -0,0 +1,83 @@ +--- a/arch/mips/include/asm/string.h ++++ b/arch/mips/include/asm/string.h +@@ -133,11 +133,44 @@ strncmp(__const__ char *__cs, __const__ + + #define __HAVE_ARCH_MEMSET + extern void *memset(void *__s, int __c, size_t __count); ++#define memset(__s, __c, len) \ ++({ \ ++ size_t __len = (len); \ ++ void *__ret; \ ++ if (__builtin_constant_p(len) && __len >= 64) \ ++ __ret = memset((__s), (__c), __len); \ ++ else \ ++ __ret = __builtin_memset((__s), (__c), __len); \ ++ __ret; \ ++}) + + #define __HAVE_ARCH_MEMCPY + extern void *memcpy(void *__to, __const__ void *__from, size_t __n); ++#define memcpy(dst, src, len) \ ++({ \ ++ size_t __len = (len); \ ++ void *__ret; \ ++ if (__builtin_constant_p(len) && __len >= 64) \ ++ __ret = memcpy((dst), (src), __len); \ ++ else \ ++ __ret = __builtin_memcpy((dst), (src), __len); \ ++ __ret; \ ++}) + + #define __HAVE_ARCH_MEMMOVE + extern void *memmove(void *__dest, __const__ void *__src, size_t __n); ++#define memmove(dst, src, len) \ ++({ \ ++ size_t __len = (len); \ ++ void *__ret; \ ++ if (__builtin_constant_p(len) && __len >= 64) \ ++ __ret = memmove((dst), (src), __len); \ ++ else \ ++ __ret = __builtin_memmove((dst), (src), __len); \ ++ __ret; \ ++}) ++ ++#define __HAVE_ARCH_MEMCMP ++#define memcmp(src1, src2, len) __builtin_memcmp((src1), (src2), (len)) + + #endif /* _ASM_STRING_H */ +--- a/arch/mips/lib/Makefile ++++ b/arch/mips/lib/Makefile +@@ -4,7 +4,7 @@ + + lib-y += bitops.o csum_partial.o delay.o memcpy.o memset.o \ + mips-atomic.o strlen_user.o strncpy_user.o \ +- strnlen_user.o uncached.o ++ strnlen_user.o uncached.o memcmp.o + + obj-y += iomap.o + obj-$(CONFIG_PCI) += iomap-pci.o +--- /dev/null ++++ b/arch/mips/lib/memcmp.c +@@ -0,0 +1,22 @@ ++/* ++ * copied from linux/lib/string.c ++ * ++ * Copyright (C) 1991, 1992 Linus Torvalds ++ */ ++ ++#include ++#include ++ ++#undef memcmp ++int memcmp(const void *cs, const void *ct, size_t count) ++{ ++ const unsigned char *su1, *su2; ++ int res = 0; ++ ++ for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--) ++ if ((res = *su1 - *su2) != 0) ++ break; ++ return res; ++} ++EXPORT_SYMBOL(memcmp); ++ diff --git a/target/linux/generic/patches-4.1/307-mips_highmem_offset.patch b/target/linux/generic/patches-4.1/307-mips_highmem_offset.patch new file mode 100644 index 0000000..c9f0c84 --- /dev/null +++ b/target/linux/generic/patches-4.1/307-mips_highmem_offset.patch @@ -0,0 +1,17 @@ +Adjust highmem offset to 0x10000000 to ensure that all kmalloc allocations +stay within the same 256M boundary. This ensures that -mlong-calls is not +needed on systems with more than 256M RAM. + +Signed-off-by: Felix Fietkau +--- +--- a/arch/mips/include/asm/mach-generic/spaces.h ++++ b/arch/mips/include/asm/mach-generic/spaces.h +@@ -44,7 +44,7 @@ + * Memory above this physical address will be considered highmem. + */ + #ifndef HIGHMEM_START +-#define HIGHMEM_START _AC(0x20000000, UL) ++#define HIGHMEM_START _AC(0x10000000, UL) + #endif + + #endif /* CONFIG_32BIT */ diff --git a/target/linux/generic/patches-4.1/309-mips_fuse_workaround.patch b/target/linux/generic/patches-4.1/309-mips_fuse_workaround.patch new file mode 100644 index 0000000..7a3aa34 --- /dev/null +++ b/target/linux/generic/patches-4.1/309-mips_fuse_workaround.patch @@ -0,0 +1,32 @@ +--- a/arch/mips/mm/cache.c ++++ b/arch/mips/mm/cache.c +@@ -38,6 +38,7 @@ void (*__flush_cache_vunmap)(void); + + void (*__flush_kernel_vmap_range)(unsigned long vaddr, int size); + EXPORT_SYMBOL_GPL(__flush_kernel_vmap_range); ++EXPORT_SYMBOL(__flush_cache_all); + void (*__invalidate_kernel_vmap_range)(unsigned long vaddr, int size); + + /* MIPS specific cache operations */ +--- a/fs/fuse/dev.c ++++ b/fs/fuse/dev.c +@@ -19,6 +19,9 @@ + #include + #include + #include ++#ifdef CONFIG_MIPS ++#include ++#endif + + MODULE_ALIAS_MISCDEV(FUSE_MINOR); + MODULE_ALIAS("devname:fuse"); +@@ -816,6 +819,9 @@ static int fuse_copy_fill(struct fuse_co + static int fuse_copy_do(struct fuse_copy_state *cs, void **val, unsigned *size) + { + unsigned ncpy = min(*size, cs->len); ++#ifdef CONFIG_MIPS ++ __flush_cache_all(); ++#endif + if (val) { + void *pgaddr = kmap_atomic(cs->pg); + void *buf = pgaddr + cs->offset; diff --git a/target/linux/generic/patches-4.1/310-arm_module_unresolved_weak_sym.patch b/target/linux/generic/patches-4.1/310-arm_module_unresolved_weak_sym.patch new file mode 100644 index 0000000..9210c1d --- /dev/null +++ b/target/linux/generic/patches-4.1/310-arm_module_unresolved_weak_sym.patch @@ -0,0 +1,13 @@ +--- a/arch/arm/kernel/module.c ++++ b/arch/arm/kernel/module.c +@@ -83,6 +83,10 @@ apply_relocate(Elf32_Shdr *sechdrs, cons + return -ENOEXEC; + } + ++ if ((IS_ERR_VALUE(sym->st_value) || !sym->st_value) && ++ ELF_ST_BIND(sym->st_info) == STB_WEAK) ++ continue; ++ + loc = dstsec->sh_addr + rel->r_offset; + + switch (ELF32_R_TYPE(rel->r_info)) { diff --git a/target/linux/generic/patches-4.1/320-ppc4xx_optimization.patch b/target/linux/generic/patches-4.1/320-ppc4xx_optimization.patch new file mode 100644 index 0000000..8673de4 --- /dev/null +++ b/target/linux/generic/patches-4.1/320-ppc4xx_optimization.patch @@ -0,0 +1,31 @@ +Upstream doesn't optimize the kernel and bootwrappers for ppc44x because +they still want to support gcc 3.3 -- well, we don't. + +--- a/arch/powerpc/Makefile ++++ b/arch/powerpc/Makefile +@@ -203,7 +203,8 @@ ifeq ($(CONFIG_FUNCTION_TRACER),y) + KBUILD_CFLAGS += -mno-sched-epilog + endif + +-cpu-as-$(CONFIG_4xx) += -Wa,-m405 ++cpu-as-$(CONFIG_40x) += -Wa,-m405 ++cpu-as-$(CONFIG_44x) += -Wa,-m440 + cpu-as-$(CONFIG_ALTIVEC) += -Wa,-maltivec + cpu-as-$(CONFIG_E200) += -Wa,-me200 + +--- a/arch/powerpc/boot/Makefile ++++ b/arch/powerpc/boot/Makefile +@@ -45,10 +45,10 @@ BOOTCFLAGS += -I$(obj) -I$(srctree)/$(ob + DTC_FLAGS ?= -p 1024 + + $(obj)/4xx.o: BOOTCFLAGS += -mcpu=405 +-$(obj)/ebony.o: BOOTCFLAGS += -mcpu=405 ++$(obj)/ebony.o: BOOTCFLAGS += -mcpu=440 + $(obj)/cuboot-hotfoot.o: BOOTCFLAGS += -mcpu=405 +-$(obj)/cuboot-taishan.o: BOOTCFLAGS += -mcpu=405 +-$(obj)/cuboot-katmai.o: BOOTCFLAGS += -mcpu=405 ++$(obj)/cuboot-taishan.o: BOOTCFLAGS += -mcpu=440 ++$(obj)/cuboot-katmai.o: BOOTCFLAGS += -mcpu=440 + $(obj)/cuboot-acadia.o: BOOTCFLAGS += -mcpu=405 + $(obj)/treeboot-walnut.o: BOOTCFLAGS += -mcpu=405 + $(obj)/treeboot-iss4xx.o: BOOTCFLAGS += -mcpu=405 diff --git a/target/linux/generic/patches-4.1/321-powerpc_crtsavres_prereq.patch b/target/linux/generic/patches-4.1/321-powerpc_crtsavres_prereq.patch new file mode 100644 index 0000000..ab6ea7b --- /dev/null +++ b/target/linux/generic/patches-4.1/321-powerpc_crtsavres_prereq.patch @@ -0,0 +1,10 @@ +--- a/arch/powerpc/Makefile ++++ b/arch/powerpc/Makefile +@@ -165,7 +165,6 @@ CPP = $(CC) -E $(KBUILD_CFLAGS) + + CHECKFLAGS += -m$(CONFIG_WORD_SIZE) -D__powerpc__ -D__powerpc$(CONFIG_WORD_SIZE)__ + +-KBUILD_LDFLAGS_MODULE += arch/powerpc/lib/crtsavres.o + + ifeq ($(CONFIG_476FPE_ERR46),y) + KBUILD_LDFLAGS_MODULE += --ppc476-workaround \ diff --git a/target/linux/generic/patches-4.1/330-MIPS-kexec-Accept-command-line-parameters-from-users.patch b/target/linux/generic/patches-4.1/330-MIPS-kexec-Accept-command-line-parameters-from-users.patch new file mode 100644 index 0000000..a69d197 --- /dev/null +++ b/target/linux/generic/patches-4.1/330-MIPS-kexec-Accept-command-line-parameters-from-users.patch @@ -0,0 +1,298 @@ +From d8582dcf1ed66eee88a11e4760f42c0d6c8822be Mon Sep 17 00:00:00 2001 +From: Yousong Zhou +Date: Sat, 31 Jan 2015 22:26:03 +0800 +Subject: [PATCH 331/331] MIPS: kexec: Accept command line parameters from + userspace. + +Signed-off-by: Yousong Zhou +--- + arch/mips/kernel/machine_kexec.c | 153 +++++++++++++++++++++++++++++++----- + arch/mips/kernel/machine_kexec.h | 20 +++++ + arch/mips/kernel/relocate_kernel.S | 21 +++-- + 3 files changed, 167 insertions(+), 27 deletions(-) + create mode 100644 arch/mips/kernel/machine_kexec.h + +--- a/arch/mips/kernel/machine_kexec.c ++++ b/arch/mips/kernel/machine_kexec.c +@@ -10,45 +10,145 @@ + #include + #include + ++#include + #include + #include +- +-extern const unsigned char relocate_new_kernel[]; +-extern const size_t relocate_new_kernel_size; +- +-extern unsigned long kexec_start_address; +-extern unsigned long kexec_indirection_page; ++#include ++#include "machine_kexec.h" + + int (*_machine_kexec_prepare)(struct kimage *) = NULL; + void (*_machine_kexec_shutdown)(void) = NULL; + void (*_machine_crash_shutdown)(struct pt_regs *regs) = NULL; ++ + #ifdef CONFIG_SMP + void (*relocated_kexec_smp_wait) (void *); + atomic_t kexec_ready_to_reboot = ATOMIC_INIT(0); + #endif + +-int +-machine_kexec_prepare(struct kimage *kimage) ++static void machine_kexec_print_args(void) + { ++ unsigned long argc = (int)kexec_args[0]; ++ int i; ++ ++ pr_info("kexec_args[0] (argc): %lu\n", argc); ++ pr_info("kexec_args[1] (argv): %p\n", (void *)kexec_args[1]); ++ pr_info("kexec_args[2] (env ): %p\n", (void *)kexec_args[2]); ++ pr_info("kexec_args[3] (desc): %p\n", (void *)kexec_args[3]); ++ ++ for (i = 0; i < argc; i++) { ++ pr_info("kexec_argv[%d] = %p, %s\n", ++ i, kexec_argv[i], kexec_argv[i]); ++ } ++} ++ ++static void machine_kexec_init_argv(struct kimage *image) ++{ ++ void __user *buf = NULL; ++ size_t bufsz; ++ size_t size; ++ int i; ++ ++ bufsz = 0; ++ for (i = 0; i < image->nr_segments; i++) { ++ struct kexec_segment *seg; ++ ++ seg = &image->segment[i]; ++ if (seg->bufsz < 6) ++ continue; ++ ++ if (strncmp((char *) seg->buf, "kexec ", 6)) ++ continue; ++ ++ buf = seg->buf; ++ bufsz = seg->bufsz; ++ break; ++ } ++ ++ if (!buf) ++ return; ++ ++ size = KEXEC_COMMAND_LINE_SIZE; ++ size = min(size, bufsz); ++ if (size < bufsz) ++ pr_warn("kexec command line truncated to %zd bytes\n", size); ++ ++ /* Copy to kernel space */ ++ copy_from_user(kexec_argv_buf, buf, size); ++ kexec_argv_buf[size - 1] = 0; ++} ++ ++static void machine_kexec_parse_argv(struct kimage *image) ++{ ++ char *reboot_code_buffer; ++ int reloc_delta; ++ char *ptr; ++ int argc; ++ int i; ++ ++ ptr = kexec_argv_buf; ++ argc = 0; ++ ++ /* ++ * convert command line string to array of parameters ++ * (as bootloader does). ++ */ ++ while (ptr && *ptr && (KEXEC_MAX_ARGC > argc)) { ++ if (*ptr == ' ') { ++ *ptr++ = '\0'; ++ continue; ++ } ++ ++ kexec_argv[argc++] = ptr; ++ ptr = strchr(ptr, ' '); ++ } ++ ++ if (!argc) ++ return; ++ ++ kexec_args[0] = argc; ++ kexec_args[1] = (unsigned long)kexec_argv; ++ kexec_args[2] = 0; ++ kexec_args[3] = 0; ++ ++ reboot_code_buffer = page_address(image->control_code_page); ++ reloc_delta = reboot_code_buffer - (char *)kexec_relocate_new_kernel; ++ ++ kexec_args[1] += reloc_delta; ++ for (i = 0; i < argc; i++) ++ kexec_argv[i] += reloc_delta; ++} ++ ++int machine_kexec_prepare(struct kimage *kimage) ++{ ++ /* ++ * Whenever arguments passed from kexec-tools, Init the arguments as ++ * the original ones to try avoiding booting failure. ++ */ ++ ++ kexec_args[0] = fw_arg0; ++ kexec_args[1] = fw_arg1; ++ kexec_args[2] = fw_arg2; ++ kexec_args[3] = fw_arg3; ++ ++ machine_kexec_init_argv(kimage); ++ machine_kexec_parse_argv(kimage); ++ + if (_machine_kexec_prepare) + return _machine_kexec_prepare(kimage); + return 0; + } + +-void +-machine_kexec_cleanup(struct kimage *kimage) ++void machine_kexec_cleanup(struct kimage *kimage) + { + } + +-void +-machine_shutdown(void) ++void machine_shutdown(void) + { + if (_machine_kexec_shutdown) + _machine_kexec_shutdown(); + } + +-void +-machine_crash_shutdown(struct pt_regs *regs) ++void machine_crash_shutdown(struct pt_regs *regs) + { + if (_machine_crash_shutdown) + _machine_crash_shutdown(regs); +@@ -66,10 +166,12 @@ machine_kexec(struct kimage *image) + unsigned long *ptr; + + reboot_code_buffer = +- (unsigned long)page_address(image->control_code_page); ++ (unsigned long)page_address(image->control_code_page); ++ pr_info("reboot_code_buffer = %p\n", (void *)reboot_code_buffer); + + kexec_start_address = + (unsigned long) phys_to_virt(image->start); ++ pr_info("kexec_start_address = %p\n", (void *)kexec_start_address); + + if (image->type == KEXEC_TYPE_DEFAULT) { + kexec_indirection_page = +@@ -77,9 +179,19 @@ machine_kexec(struct kimage *image) + } else { + kexec_indirection_page = (unsigned long)&image->head; + } ++ pr_info("kexec_indirection_page = %p\n", (void *)kexec_indirection_page); + +- memcpy((void*)reboot_code_buffer, relocate_new_kernel, +- relocate_new_kernel_size); ++ pr_info("Where is memcpy: %p\n", memcpy); ++ pr_info("kexec_relocate_new_kernel = %p, kexec_relocate_new_kernel_end = %p\n", ++ (void *)kexec_relocate_new_kernel, &kexec_relocate_new_kernel_end); ++ pr_info("Copy %lu bytes from %p to %p\n", KEXEC_RELOCATE_NEW_KERNEL_SIZE, ++ (void *)kexec_relocate_new_kernel, (void *)reboot_code_buffer); ++ memcpy((void*)reboot_code_buffer, kexec_relocate_new_kernel, ++ KEXEC_RELOCATE_NEW_KERNEL_SIZE); ++ ++ pr_info("Before _print_args().\n"); ++ machine_kexec_print_args(); ++ pr_info("Before eval loop.\n"); + + /* + * The generic kexec code builds a page list with physical +@@ -98,15 +210,16 @@ machine_kexec(struct kimage *image) + /* + * we do not want to be bothered. + */ ++ pr_info("Before irq_disable.\n"); + local_irq_disable(); + +- printk("Will call new kernel at %08lx\n", image->start); +- printk("Bye ...\n"); ++ pr_info("Will call new kernel at %08lx\n", image->start); ++ pr_info("Bye ...\n"); + __flush_cache_all(); + #ifdef CONFIG_SMP + /* All secondary cpus now may jump to kexec_wait cycle */ + relocated_kexec_smp_wait = reboot_code_buffer + +- (void *)(kexec_smp_wait - relocate_new_kernel); ++ (void *)(kexec_smp_wait - kexec_relocate_new_kernel); + smp_wmb(); + atomic_set(&kexec_ready_to_reboot, 1); + #endif +--- /dev/null ++++ b/arch/mips/kernel/machine_kexec.h +@@ -0,0 +1,20 @@ ++#ifndef _MACHINE_KEXEC_H ++#define _MACHINE_KEXEC_H ++ ++#ifndef __ASSEMBLY__ ++extern const unsigned char kexec_relocate_new_kernel[]; ++extern unsigned long kexec_relocate_new_kernel_end; ++extern unsigned long kexec_start_address; ++extern unsigned long kexec_indirection_page; ++ ++extern char kexec_argv_buf[]; ++extern char *kexec_argv[]; ++ ++#define KEXEC_RELOCATE_NEW_KERNEL_SIZE ((unsigned long)&kexec_relocate_new_kernel_end - (unsigned long)kexec_relocate_new_kernel) ++#endif /* !__ASSEMBLY__ */ ++ ++#define KEXEC_COMMAND_LINE_SIZE 256 ++#define KEXEC_ARGV_SIZE (KEXEC_COMMAND_LINE_SIZE / 16) ++#define KEXEC_MAX_ARGC (KEXEC_ARGV_SIZE / sizeof(long)) ++ ++#endif +--- a/arch/mips/kernel/relocate_kernel.S ++++ b/arch/mips/kernel/relocate_kernel.S +@@ -12,8 +12,9 @@ + #include + #include + #include ++#include "machine_kexec.h" + +-LEAF(relocate_new_kernel) ++LEAF(kexec_relocate_new_kernel) + PTR_L a0, arg0 + PTR_L a1, arg1 + PTR_L a2, arg2 +@@ -98,7 +99,7 @@ done: + #endif + /* jump to kexec_start_address */ + j s1 +- END(relocate_new_kernel) ++ END(kexec_relocate_new_kernel) + + #ifdef CONFIG_SMP + /* +@@ -184,9 +185,15 @@ kexec_indirection_page: + PTR 0 + .size kexec_indirection_page, PTRSIZE + +-relocate_new_kernel_end: ++kexec_argv_buf: ++ EXPORT(kexec_argv_buf) ++ .skip KEXEC_COMMAND_LINE_SIZE ++ .size kexec_argv_buf, KEXEC_COMMAND_LINE_SIZE ++ ++kexec_argv: ++ EXPORT(kexec_argv) ++ .skip KEXEC_ARGV_SIZE ++ .size kexec_argv, KEXEC_ARGV_SIZE + +-relocate_new_kernel_size: +- EXPORT(relocate_new_kernel_size) +- PTR relocate_new_kernel_end - relocate_new_kernel +- .size relocate_new_kernel_size, PTRSIZE ++kexec_relocate_new_kernel_end: ++ EXPORT(kexec_relocate_new_kernel_end) diff --git a/target/linux/generic/patches-4.1/400-mtd-add-rootfs-split-support.patch b/target/linux/generic/patches-4.1/400-mtd-add-rootfs-split-support.patch new file mode 100644 index 0000000..ba64e09 --- /dev/null +++ b/target/linux/generic/patches-4.1/400-mtd-add-rootfs-split-support.patch @@ -0,0 +1,146 @@ +--- a/drivers/mtd/Kconfig ++++ b/drivers/mtd/Kconfig +@@ -12,6 +12,23 @@ menuconfig MTD + + if MTD + ++menu "OpenWrt specific MTD options" ++ ++config MTD_ROOTFS_ROOT_DEV ++ bool "Automatically set 'rootfs' partition to be root filesystem" ++ default y ++ ++config MTD_SPLIT_FIRMWARE ++ bool "Automatically split firmware partition for kernel+rootfs" ++ default y ++ ++config MTD_SPLIT_FIRMWARE_NAME ++ string "Firmware partition name" ++ depends on MTD_SPLIT_FIRMWARE ++ default "firmware" ++ ++endmenu ++ + config MTD_TESTS + tristate "MTD tests support (DANGEROUS)" + depends on m +--- a/drivers/mtd/mtdpart.c ++++ b/drivers/mtd/mtdpart.c +@@ -29,11 +29,13 @@ + #include + #include + #include ++#include + #include + #include + #include + + #include "mtdcore.h" ++#include "mtdsplit/mtdsplit.h" + + /* Our partition linked list */ + static LIST_HEAD(mtd_partitions); +@@ -47,13 +49,14 @@ struct mtd_part { + struct list_head list; + }; + ++static void mtd_partition_split(struct mtd_info *master, struct mtd_part *part); ++ + /* + * Given a pointer to the MTD object in the mtd_part structure, we can retrieve + * the pointer to that structure with this macro. + */ + #define PART(x) ((struct mtd_part *)(x)) + +- + /* + * MTD methods which simply translate the effective address and pass through + * to the _real_ device. +@@ -579,8 +582,10 @@ static int mtd_add_partition_attrs(struc + return ret; + } + +-int mtd_add_partition(struct mtd_info *master, const char *name, +- long long offset, long long length) ++ ++static int ++__mtd_add_partition(struct mtd_info *master, const char *name, ++ long long offset, long long length, bool dup_check) + { + struct mtd_partition part; + struct mtd_part *new; +@@ -612,6 +617,7 @@ int mtd_add_partition(struct mtd_info *m + mutex_unlock(&mtd_partitions_mutex); + + add_mtd_device(&new->mtd); ++ mtd_partition_split(master, new); + + mtd_add_partition_attrs(new); + +@@ -619,6 +625,12 @@ int mtd_add_partition(struct mtd_info *m + } + EXPORT_SYMBOL_GPL(mtd_add_partition); + ++int mtd_add_partition(struct mtd_info *master, const char *name, ++ long long offset, long long length) ++{ ++ return __mtd_add_partition(master, name, offset, length, true); ++} ++ + int mtd_del_partition(struct mtd_info *master, int partno) + { + struct mtd_part *slave, *next; +@@ -644,6 +656,35 @@ int mtd_del_partition(struct mtd_info *m + } + EXPORT_SYMBOL_GPL(mtd_del_partition); + ++#ifdef CONFIG_MTD_SPLIT_FIRMWARE_NAME ++#define SPLIT_FIRMWARE_NAME CONFIG_MTD_SPLIT_FIRMWARE_NAME ++#else ++#define SPLIT_FIRMWARE_NAME "unused" ++#endif ++ ++static void split_firmware(struct mtd_info *master, struct mtd_part *part) ++{ ++} ++ ++void __weak arch_split_mtd_part(struct mtd_info *master, const char *name, ++ int offset, int size) ++{ ++} ++ ++static void mtd_partition_split(struct mtd_info *master, struct mtd_part *part) ++{ ++ static int rootfs_found = 0; ++ ++ if (rootfs_found) ++ return; ++ ++ if (!strcmp(part->mtd.name, SPLIT_FIRMWARE_NAME) && ++ config_enabled(CONFIG_MTD_SPLIT_FIRMWARE)) ++ split_firmware(master, part); ++ ++ arch_split_mtd_part(master, part->mtd.name, part->offset, ++ part->mtd.size); ++} + /* + * This function, given a master MTD object and a partition table, creates + * and registers slave MTD objects which are bound to the master according to +@@ -673,6 +714,7 @@ int add_mtd_partitions(struct mtd_info * + mutex_unlock(&mtd_partitions_mutex); + + add_mtd_device(&slave->mtd); ++ mtd_partition_split(master, slave); + mtd_add_partition_attrs(slave); + + cur_offset = slave->offset + slave->mtd.size; +--- a/include/linux/mtd/partitions.h ++++ b/include/linux/mtd/partitions.h +@@ -84,5 +84,7 @@ int mtd_add_partition(struct mtd_info *m + long long offset, long long length); + int mtd_del_partition(struct mtd_info *master, int partno); + uint64_t mtd_get_device_size(const struct mtd_info *mtd); ++extern void __weak arch_split_mtd_part(struct mtd_info *master, ++ const char *name, int offset, int size); + + #endif diff --git a/target/linux/generic/patches-4.1/401-mtd-add-support-for-different-partition-parser-types.patch b/target/linux/generic/patches-4.1/401-mtd-add-support-for-different-partition-parser-types.patch new file mode 100644 index 0000000..31dee98 --- /dev/null +++ b/target/linux/generic/patches-4.1/401-mtd-add-support-for-different-partition-parser-types.patch @@ -0,0 +1,113 @@ +From 02cff0ccaa6d364f5c1eeea83f47ac80ccc967d4 Mon Sep 17 00:00:00 2001 +From: Gabor Juhos +Date: Tue, 3 Sep 2013 18:11:50 +0200 +Subject: [PATCH] mtd: add support for different partition parser types + +Signed-off-by: Gabor Juhos +--- + drivers/mtd/mtdpart.c | 56 ++++++++++++++++++++++++++++++++++++++++ + include/linux/mtd/partitions.h | 11 ++++++++ + 2 files changed, 67 insertions(+) + +--- a/drivers/mtd/mtdpart.c ++++ b/drivers/mtd/mtdpart.c +@@ -745,6 +745,30 @@ static struct mtd_part_parser *get_parti + + #define put_partition_parser(p) do { module_put((p)->owner); } while (0) + ++static struct mtd_part_parser * ++get_partition_parser_by_type(enum mtd_parser_type type, ++ struct mtd_part_parser *start) ++{ ++ struct mtd_part_parser *p, *ret = NULL; ++ ++ spin_lock(&part_parser_lock); ++ ++ p = list_prepare_entry(start, &part_parsers, list); ++ if (start) ++ put_partition_parser(start); ++ ++ list_for_each_entry_continue(p, &part_parsers, list) { ++ if (p->type == type && try_module_get(p->owner)) { ++ ret = p; ++ break; ++ } ++ } ++ ++ spin_unlock(&part_parser_lock); ++ ++ return ret; ++} ++ + void register_mtd_parser(struct mtd_part_parser *p) + { + spin_lock(&part_parser_lock); +@@ -860,6 +884,38 @@ int parse_mtd_partitions(struct mtd_info + return ret; + } + ++int parse_mtd_partitions_by_type(struct mtd_info *master, ++ enum mtd_parser_type type, ++ struct mtd_partition **pparts, ++ struct mtd_part_parser_data *data) ++{ ++ struct mtd_part_parser *prev = NULL; ++ int ret = 0; ++ ++ while (1) { ++ struct mtd_part_parser *parser; ++ ++ parser = get_partition_parser_by_type(type, prev); ++ if (!parser) ++ break; ++ ++ ret = (*parser->parse_fn)(master, pparts, data); ++ ++ if (ret > 0) { ++ put_partition_parser(parser); ++ printk(KERN_NOTICE ++ "%d %s partitions found on MTD device %s\n", ++ ret, parser->name, master->name); ++ break; ++ } ++ ++ prev = parser; ++ } ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(parse_mtd_partitions_by_type); ++ + int mtd_is_partition(const struct mtd_info *mtd) + { + struct mtd_part *part; +--- a/include/linux/mtd/partitions.h ++++ b/include/linux/mtd/partitions.h +@@ -68,12 +68,17 @@ struct mtd_part_parser_data { + * Functions dealing with the various ways of partitioning the space + */ + ++enum mtd_parser_type { ++ MTD_PARSER_TYPE_DEVICE = 0, ++}; ++ + struct mtd_part_parser { + struct list_head list; + struct module *owner; + const char *name; + int (*parse_fn)(struct mtd_info *, struct mtd_partition **, + struct mtd_part_parser_data *); ++ enum mtd_parser_type type; + }; + + extern void register_mtd_parser(struct mtd_part_parser *parser); +@@ -87,4 +92,9 @@ uint64_t mtd_get_device_size(const struc + extern void __weak arch_split_mtd_part(struct mtd_info *master, + const char *name, int offset, int size); + ++int parse_mtd_partitions_by_type(struct mtd_info *master, ++ enum mtd_parser_type type, ++ struct mtd_partition **pparts, ++ struct mtd_part_parser_data *data); ++ + #endif diff --git a/target/linux/generic/patches-4.1/402-mtd-use-typed-mtd-parsers-for-rootfs-and-firmware-split.patch b/target/linux/generic/patches-4.1/402-mtd-use-typed-mtd-parsers-for-rootfs-and-firmware-split.patch new file mode 100644 index 0000000..725dbe8 --- /dev/null +++ b/target/linux/generic/patches-4.1/402-mtd-use-typed-mtd-parsers-for-rootfs-and-firmware-split.patch @@ -0,0 +1,72 @@ +--- a/drivers/mtd/mtdpart.c ++++ b/drivers/mtd/mtdpart.c +@@ -656,6 +656,37 @@ int mtd_del_partition(struct mtd_info *m + } + EXPORT_SYMBOL_GPL(mtd_del_partition); + ++static int ++run_parsers_by_type(struct mtd_part *slave, enum mtd_parser_type type) ++{ ++ struct mtd_partition *parts; ++ int nr_parts; ++ int i; ++ ++ nr_parts = parse_mtd_partitions_by_type(&slave->mtd, type, &parts, ++ NULL); ++ if (nr_parts <= 0) ++ return nr_parts; ++ ++ if (WARN_ON(!parts)) ++ return 0; ++ ++ for (i = 0; i < nr_parts; i++) { ++ /* adjust partition offsets */ ++ parts[i].offset += slave->offset; ++ ++ __mtd_add_partition(slave->master, ++ parts[i].name, ++ parts[i].offset, ++ parts[i].size, ++ false); ++ } ++ ++ kfree(parts); ++ ++ return nr_parts; ++} ++ + #ifdef CONFIG_MTD_SPLIT_FIRMWARE_NAME + #define SPLIT_FIRMWARE_NAME CONFIG_MTD_SPLIT_FIRMWARE_NAME + #else +@@ -664,6 +695,7 @@ EXPORT_SYMBOL_GPL(mtd_del_partition); + + static void split_firmware(struct mtd_info *master, struct mtd_part *part) + { ++ run_parsers_by_type(part, MTD_PARSER_TYPE_FIRMWARE); + } + + void __weak arch_split_mtd_part(struct mtd_info *master, const char *name, +@@ -678,6 +710,12 @@ static void mtd_partition_split(struct m + if (rootfs_found) + return; + ++ if (!strcmp(part->mtd.name, "rootfs")) { ++ run_parsers_by_type(part, MTD_PARSER_TYPE_ROOTFS); ++ ++ rootfs_found = 1; ++ } ++ + if (!strcmp(part->mtd.name, SPLIT_FIRMWARE_NAME) && + config_enabled(CONFIG_MTD_SPLIT_FIRMWARE)) + split_firmware(master, part); +--- a/include/linux/mtd/partitions.h ++++ b/include/linux/mtd/partitions.h +@@ -70,6 +70,8 @@ struct mtd_part_parser_data { + + enum mtd_parser_type { + MTD_PARSER_TYPE_DEVICE = 0, ++ MTD_PARSER_TYPE_ROOTFS, ++ MTD_PARSER_TYPE_FIRMWARE, + }; + + struct mtd_part_parser { diff --git a/target/linux/generic/patches-4.1/403-mtd-hook-mtdsplit-to-Kbuild.patch b/target/linux/generic/patches-4.1/403-mtd-hook-mtdsplit-to-Kbuild.patch new file mode 100644 index 0000000..0cf1c38 --- /dev/null +++ b/target/linux/generic/patches-4.1/403-mtd-hook-mtdsplit-to-Kbuild.patch @@ -0,0 +1,22 @@ +--- a/drivers/mtd/Kconfig ++++ b/drivers/mtd/Kconfig +@@ -27,6 +27,8 @@ config MTD_SPLIT_FIRMWARE_NAME + depends on MTD_SPLIT_FIRMWARE + default "firmware" + ++source "drivers/mtd/mtdsplit/Kconfig" ++ + endmenu + + config MTD_TESTS +--- a/drivers/mtd/Makefile ++++ b/drivers/mtd/Makefile +@@ -6,6 +6,8 @@ + obj-$(CONFIG_MTD) += mtd.o + mtd-y := mtdcore.o mtdsuper.o mtdconcat.o mtdpart.o mtdchar.o + ++obj-$(CONFIG_MTD_SPLIT) += mtdsplit/ ++ + obj-$(CONFIG_MTD_OF_PARTS) += ofpart.o + obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o + obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o diff --git a/target/linux/generic/patches-4.1/404-mtd-add-more-helper-functions.patch b/target/linux/generic/patches-4.1/404-mtd-add-more-helper-functions.patch new file mode 100644 index 0000000..42e5cfd --- /dev/null +++ b/target/linux/generic/patches-4.1/404-mtd-add-more-helper-functions.patch @@ -0,0 +1,101 @@ +--- a/drivers/mtd/mtdpart.c ++++ b/drivers/mtd/mtdpart.c +@@ -453,14 +453,12 @@ static struct mtd_part *allocate_partiti + if (slave->offset == MTDPART_OFS_APPEND) + slave->offset = cur_offset; + if (slave->offset == MTDPART_OFS_NXTBLK) { +- slave->offset = cur_offset; +- if (mtd_mod_by_eb(cur_offset, master) != 0) { +- /* Round up to next erasesize */ +- slave->offset = (mtd_div_by_eb(cur_offset, master) + 1) * master->erasesize; ++ /* Round up to next erasesize */ ++ slave->offset = mtd_roundup_to_eb(cur_offset, master); ++ if (slave->offset != cur_offset) + printk(KERN_NOTICE "Moving partition %d: " + "0x%012llx -> 0x%012llx\n", partno, + (unsigned long long)cur_offset, (unsigned long long)slave->offset); +- } + } + if (slave->offset == MTDPART_OFS_RETAIN) { + slave->offset = cur_offset; +@@ -687,6 +685,17 @@ run_parsers_by_type(struct mtd_part *sla + return nr_parts; + } + ++static inline unsigned long ++mtd_pad_erasesize(struct mtd_info *mtd, int offset, int len) ++{ ++ unsigned long mask = mtd->erasesize - 1; ++ ++ len += offset & mask; ++ len = (len + mask) & ~mask; ++ len -= offset & mask; ++ return len; ++} ++ + #ifdef CONFIG_MTD_SPLIT_FIRMWARE_NAME + #define SPLIT_FIRMWARE_NAME CONFIG_MTD_SPLIT_FIRMWARE_NAME + #else +@@ -971,6 +980,24 @@ int mtd_is_partition(const struct mtd_in + } + EXPORT_SYMBOL_GPL(mtd_is_partition); + ++struct mtd_info *mtdpart_get_master(const struct mtd_info *mtd) ++{ ++ if (!mtd_is_partition(mtd)) ++ return (struct mtd_info *)mtd; ++ ++ return PART(mtd)->master; ++} ++EXPORT_SYMBOL_GPL(mtdpart_get_master); ++ ++uint64_t mtdpart_get_offset(const struct mtd_info *mtd) ++{ ++ if (!mtd_is_partition(mtd)) ++ return 0; ++ ++ return PART(mtd)->offset; ++} ++EXPORT_SYMBOL_GPL(mtdpart_get_offset); ++ + /* Returns the size of the entire flash chip */ + uint64_t mtd_get_device_size(const struct mtd_info *mtd) + { +--- a/include/linux/mtd/partitions.h ++++ b/include/linux/mtd/partitions.h +@@ -90,6 +90,8 @@ int mtd_is_partition(const struct mtd_in + int mtd_add_partition(struct mtd_info *master, const char *name, + long long offset, long long length); + int mtd_del_partition(struct mtd_info *master, int partno); ++struct mtd_info *mtdpart_get_master(const struct mtd_info *mtd); ++uint64_t mtdpart_get_offset(const struct mtd_info *mtd); + uint64_t mtd_get_device_size(const struct mtd_info *mtd); + extern void __weak arch_split_mtd_part(struct mtd_info *master, + const char *name, int offset, int size); +--- a/include/linux/mtd/mtd.h ++++ b/include/linux/mtd/mtd.h +@@ -334,6 +334,24 @@ static inline uint32_t mtd_mod_by_eb(uin + return do_div(sz, mtd->erasesize); + } + ++static inline uint64_t mtd_roundup_to_eb(uint64_t sz, struct mtd_info *mtd) ++{ ++ if (mtd_mod_by_eb(sz, mtd) == 0) ++ return sz; ++ ++ /* Round up to next erase block */ ++ return (mtd_div_by_eb(sz, mtd) + 1) * mtd->erasesize; ++} ++ ++static inline uint64_t mtd_rounddown_to_eb(uint64_t sz, struct mtd_info *mtd) ++{ ++ if (mtd_mod_by_eb(sz, mtd) == 0) ++ return sz; ++ ++ /* Round down to the start of the current erase block */ ++ return (mtd_div_by_eb(sz, mtd)) * mtd->erasesize; ++} ++ + static inline uint32_t mtd_div_by_ws(uint64_t sz, struct mtd_info *mtd) + { + if (mtd->writesize_shift) diff --git a/target/linux/generic/patches-4.1/405-mtd-old-firmware-uimage-splitter.patch b/target/linux/generic/patches-4.1/405-mtd-old-firmware-uimage-splitter.patch new file mode 100644 index 0000000..430fd6f --- /dev/null +++ b/target/linux/generic/patches-4.1/405-mtd-old-firmware-uimage-splitter.patch @@ -0,0 +1,70 @@ +--- a/drivers/mtd/Kconfig ++++ b/drivers/mtd/Kconfig +@@ -27,6 +27,11 @@ config MTD_SPLIT_FIRMWARE_NAME + depends on MTD_SPLIT_FIRMWARE + default "firmware" + ++config MTD_UIMAGE_SPLIT ++ bool "Enable split support for firmware partitions containing a uImage" ++ depends on MTD_SPLIT_FIRMWARE ++ default y ++ + source "drivers/mtd/mtdsplit/Kconfig" + + endmenu +--- a/drivers/mtd/mtdpart.c ++++ b/drivers/mtd/mtdpart.c +@@ -696,6 +696,37 @@ mtd_pad_erasesize(struct mtd_info *mtd, + return len; + } + ++#define UBOOT_MAGIC 0x27051956 ++ ++static void split_uimage(struct mtd_info *master, struct mtd_part *part) ++{ ++ struct { ++ __be32 magic; ++ __be32 pad[2]; ++ __be32 size; ++ } hdr; ++ size_t len; ++ ++ if (mtd_read(master, part->offset, sizeof(hdr), &len, (void *) &hdr)) ++ return; ++ ++ if (len != sizeof(hdr) || hdr.magic != cpu_to_be32(UBOOT_MAGIC)) ++ return; ++ ++ len = be32_to_cpu(hdr.size) + 0x40; ++ len = mtd_pad_erasesize(master, part->offset, len); ++ if (len + master->erasesize > part->mtd.size) ++ return; ++ ++ if (config_enabled(CONFIG_MTD_SPLIT_UIMAGE_FW)) ++ pr_err("Dedicated partitioner didn't split firmware partition, please fill a bug report!\n"); ++ else ++ pr_warn("Support for built-in firmware splitter will be removed, please use CONFIG_MTD_SPLIT_UIMAGE_FW\n"); ++ ++ __mtd_add_partition(master, "rootfs", part->offset + len, ++ part->mtd.size - len, false); ++} ++ + #ifdef CONFIG_MTD_SPLIT_FIRMWARE_NAME + #define SPLIT_FIRMWARE_NAME CONFIG_MTD_SPLIT_FIRMWARE_NAME + #else +@@ -704,7 +735,14 @@ mtd_pad_erasesize(struct mtd_info *mtd, + + static void split_firmware(struct mtd_info *master, struct mtd_part *part) + { +- run_parsers_by_type(part, MTD_PARSER_TYPE_FIRMWARE); ++ int ret; ++ ++ ret = run_parsers_by_type(part, MTD_PARSER_TYPE_FIRMWARE); ++ if (ret > 0) ++ return; ++ ++ if (config_enabled(CONFIG_MTD_UIMAGE_SPLIT)) ++ split_uimage(master, part); + } + + void __weak arch_split_mtd_part(struct mtd_info *master, const char *name, diff --git a/target/linux/generic/patches-4.1/410-mtd-move-forward-declaration-of-struct-mtd_info.patch b/target/linux/generic/patches-4.1/410-mtd-move-forward-declaration-of-struct-mtd_info.patch new file mode 100644 index 0000000..78ebbf8 --- /dev/null +++ b/target/linux/generic/patches-4.1/410-mtd-move-forward-declaration-of-struct-mtd_info.patch @@ -0,0 +1,18 @@ +--- a/include/linux/mtd/partitions.h ++++ b/include/linux/mtd/partitions.h +@@ -35,6 +35,7 @@ + * Note: writeable partitions require their size and offset be + * erasesize aligned (e.g. use MTDPART_OFS_NEXTBLK). + */ ++struct mtd_info; + + struct mtd_partition { + const char *name; /* identifier string */ +@@ -50,7 +51,6 @@ struct mtd_partition { + #define MTDPART_SIZ_FULL (0) + + +-struct mtd_info; + struct device_node; + + /** diff --git a/target/linux/generic/patches-4.1/411-mtd-partial_eraseblock_write.patch b/target/linux/generic/patches-4.1/411-mtd-partial_eraseblock_write.patch new file mode 100644 index 0000000..e6e809c --- /dev/null +++ b/target/linux/generic/patches-4.1/411-mtd-partial_eraseblock_write.patch @@ -0,0 +1,142 @@ +--- a/drivers/mtd/mtdpart.c ++++ b/drivers/mtd/mtdpart.c +@@ -37,6 +37,8 @@ + #include "mtdcore.h" + #include "mtdsplit/mtdsplit.h" + ++#define MTD_ERASE_PARTIAL 0x8000 /* partition only covers parts of an erase block */ ++ + /* Our partition linked list */ + static LIST_HEAD(mtd_partitions); + static DEFINE_MUTEX(mtd_partitions_mutex); +@@ -235,13 +237,61 @@ static int part_erase(struct mtd_info *m + struct mtd_part *part = PART(mtd); + int ret; + ++ ++ instr->partial_start = false; ++ if (mtd->flags & MTD_ERASE_PARTIAL) { ++ size_t readlen = 0; ++ u64 mtd_ofs; ++ ++ instr->erase_buf = kmalloc(part->master->erasesize, GFP_ATOMIC); ++ if (!instr->erase_buf) ++ return -ENOMEM; ++ ++ mtd_ofs = part->offset + instr->addr; ++ instr->erase_buf_ofs = do_div(mtd_ofs, part->master->erasesize); ++ ++ if (instr->erase_buf_ofs > 0) { ++ instr->addr -= instr->erase_buf_ofs; ++ ret = mtd_read(part->master, ++ instr->addr + part->offset, ++ part->master->erasesize, ++ &readlen, instr->erase_buf); ++ ++ instr->len += instr->erase_buf_ofs; ++ instr->partial_start = true; ++ } else { ++ mtd_ofs = part->offset + part->mtd.size; ++ instr->erase_buf_ofs = part->master->erasesize - ++ do_div(mtd_ofs, part->master->erasesize); ++ ++ if (instr->erase_buf_ofs > 0) { ++ instr->len += instr->erase_buf_ofs; ++ ret = mtd_read(part->master, ++ part->offset + instr->addr + ++ instr->len - part->master->erasesize, ++ part->master->erasesize, &readlen, ++ instr->erase_buf); ++ } else { ++ ret = 0; ++ } ++ } ++ if (ret < 0) { ++ kfree(instr->erase_buf); ++ return ret; ++ } ++ ++ } ++ + instr->addr += part->offset; + ret = part->master->_erase(part->master, instr); + if (ret) { + if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN) + instr->fail_addr -= part->offset; + instr->addr -= part->offset; ++ if (mtd->flags & MTD_ERASE_PARTIAL) ++ kfree(instr->erase_buf); + } ++ + return ret; + } + +@@ -249,7 +299,25 @@ void mtd_erase_callback(struct erase_inf + { + if (instr->mtd->_erase == part_erase) { + struct mtd_part *part = PART(instr->mtd); ++ size_t wrlen = 0; + ++ if (instr->mtd->flags & MTD_ERASE_PARTIAL) { ++ if (instr->partial_start) { ++ part->master->_write(part->master, ++ instr->addr, instr->erase_buf_ofs, ++ &wrlen, instr->erase_buf); ++ instr->addr += instr->erase_buf_ofs; ++ } else { ++ instr->len -= instr->erase_buf_ofs; ++ part->master->_write(part->master, ++ instr->addr + instr->len, ++ instr->erase_buf_ofs, &wrlen, ++ instr->erase_buf + ++ part->master->erasesize - ++ instr->erase_buf_ofs); ++ } ++ kfree(instr->erase_buf); ++ } + if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN) + instr->fail_addr -= part->offset; + instr->addr -= part->offset; +@@ -522,17 +590,20 @@ static struct mtd_part *allocate_partiti + if ((slave->mtd.flags & MTD_WRITEABLE) && + mtd_mod_by_eb(slave->offset, &slave->mtd)) { + /* Doesn't start on a boundary of major erase size */ +- /* FIXME: Let it be writable if it is on a boundary of +- * _minor_ erase size though */ +- slave->mtd.flags &= ~MTD_WRITEABLE; +- printk(KERN_WARNING"mtd: partition \"%s\" doesn't start on an erase block boundary -- force read-only\n", +- part->name); ++ slave->mtd.flags |= MTD_ERASE_PARTIAL; ++ if (((u32) slave->mtd.size) > master->erasesize) ++ slave->mtd.flags &= ~MTD_WRITEABLE; ++ else ++ slave->mtd.erasesize = slave->mtd.size; + } + if ((slave->mtd.flags & MTD_WRITEABLE) && +- mtd_mod_by_eb(slave->mtd.size, &slave->mtd)) { +- slave->mtd.flags &= ~MTD_WRITEABLE; +- printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n", +- part->name); ++ mtd_mod_by_eb(slave->offset + slave->mtd.size, &slave->mtd)) { ++ slave->mtd.flags |= MTD_ERASE_PARTIAL; ++ ++ if ((u32) slave->mtd.size > master->erasesize) ++ slave->mtd.flags &= ~MTD_WRITEABLE; ++ else ++ slave->mtd.erasesize = slave->mtd.size; + } + + slave->mtd.ecclayout = master->ecclayout; +--- a/include/linux/mtd/mtd.h ++++ b/include/linux/mtd/mtd.h +@@ -55,6 +55,10 @@ struct erase_info { + u_long priv; + u_char state; + struct erase_info *next; ++ ++ u8 *erase_buf; ++ u32 erase_buf_ofs; ++ bool partial_start; + }; + + struct mtd_erase_region_info { diff --git a/target/linux/generic/patches-4.1/412-mtd-partial_eraseblock_unlock.patch b/target/linux/generic/patches-4.1/412-mtd-partial_eraseblock_unlock.patch new file mode 100644 index 0000000..b7964e2 --- /dev/null +++ b/target/linux/generic/patches-4.1/412-mtd-partial_eraseblock_unlock.patch @@ -0,0 +1,18 @@ +--- a/drivers/mtd/mtdpart.c ++++ b/drivers/mtd/mtdpart.c +@@ -336,7 +336,14 @@ static int part_lock(struct mtd_info *mt + static int part_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) + { + struct mtd_part *part = PART(mtd); +- return part->master->_unlock(part->master, ofs + part->offset, len); ++ ++ ofs += part->offset; ++ if (mtd->flags & MTD_ERASE_PARTIAL) { ++ /* round up len to next erasesize and round down offset to prev block */ ++ len = (mtd_div_by_eb(len, part->master) + 1) * part->master->erasesize; ++ ofs &= ~(part->master->erasesize - 1); ++ } ++ return part->master->_unlock(part->master, ofs, len); + } + + static int part_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len) diff --git a/target/linux/generic/patches-4.1/420-mtd-redboot_space.patch b/target/linux/generic/patches-4.1/420-mtd-redboot_space.patch new file mode 100644 index 0000000..f74affc --- /dev/null +++ b/target/linux/generic/patches-4.1/420-mtd-redboot_space.patch @@ -0,0 +1,30 @@ +--- a/drivers/mtd/redboot.c ++++ b/drivers/mtd/redboot.c +@@ -265,14 +265,21 @@ static int parse_redboot_partitions(stru + #endif + names += strlen(names)+1; + +-#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED + if(fl->next && fl->img->flash_base + fl->img->size + master->erasesize <= fl->next->img->flash_base) { +- i++; +- parts[i].offset = parts[i-1].size + parts[i-1].offset; +- parts[i].size = fl->next->img->flash_base - parts[i].offset; +- parts[i].name = nullname; +- } ++ if (!strcmp(parts[i].name, "rootfs")) { ++ parts[i].size = fl->next->img->flash_base; ++ parts[i].size &= ~(master->erasesize - 1); ++ parts[i].size -= parts[i].offset; ++#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED ++ nrparts--; ++ } else { ++ i++; ++ parts[i].offset = parts[i-1].size + parts[i-1].offset; ++ parts[i].size = fl->next->img->flash_base - parts[i].offset; ++ parts[i].name = nullname; + #endif ++ } ++ } + tmp_fl = fl; + fl = fl->next; + kfree(tmp_fl); diff --git a/target/linux/generic/patches-4.1/430-mtd-add-myloader-partition-parser.patch b/target/linux/generic/patches-4.1/430-mtd-add-myloader-partition-parser.patch new file mode 100644 index 0000000..fe74ad5 --- /dev/null +++ b/target/linux/generic/patches-4.1/430-mtd-add-myloader-partition-parser.patch @@ -0,0 +1,35 @@ +--- a/drivers/mtd/Kconfig ++++ b/drivers/mtd/Kconfig +@@ -179,6 +179,22 @@ config MTD_BCM47XX_PARTS + This provides partitions parser for devices based on BCM47xx + boards. + ++config MTD_MYLOADER_PARTS ++ tristate "MyLoader partition parsing" ++ depends on ADM5120 || ATH25 || ATH79 ++ ---help--- ++ MyLoader is a bootloader which allows the user to define partitions ++ in flash devices, by putting a table in the second erase block ++ on the device, similar to a partition table. This table gives the ++ offsets and lengths of the user defined partitions. ++ ++ If you need code which can detect and parse these tables, and ++ register MTD 'partitions' corresponding to each image detected, ++ enable this option. ++ ++ You will still need the parsing functions to be called by the driver ++ for your particular device. It won't happen automatically. ++ + comment "User Modules And Translation Layers" + + # +--- a/drivers/mtd/Makefile ++++ b/drivers/mtd/Makefile +@@ -15,6 +15,7 @@ obj-$(CONFIG_MTD_AFS_PARTS) += afs.o + obj-$(CONFIG_MTD_AR7_PARTS) += ar7part.o + obj-$(CONFIG_MTD_BCM63XX_PARTS) += bcm63xxpart.o + obj-$(CONFIG_MTD_BCM47XX_PARTS) += bcm47xxpart.o ++obj-$(CONFIG_MTD_MYLOADER_PARTS) += myloader.o + + # 'Users' - code which presents functionality to userspace. + obj-$(CONFIG_MTD_BLKDEVS) += mtd_blkdevs.o diff --git a/target/linux/generic/patches-4.1/431-mtd-bcm47xxpart-support-for-Xiaomi-specific-board_da.patch b/target/linux/generic/patches-4.1/431-mtd-bcm47xxpart-support-for-Xiaomi-specific-board_da.patch new file mode 100644 index 0000000..a30e698 --- /dev/null +++ b/target/linux/generic/patches-4.1/431-mtd-bcm47xxpart-support-for-Xiaomi-specific-board_da.patch @@ -0,0 +1,34 @@ +From 841e59ba3e496d86ca5f069204d5e5c1ad43c01d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Tue, 27 Jan 2015 22:29:21 +0100 +Subject: [PATCH] mtd: bcm47xxpart: support for Xiaomi specific board_data + partition +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Rafał Miłecki +--- + drivers/mtd/bcm47xxpart.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/mtd/bcm47xxpart.c ++++ b/drivers/mtd/bcm47xxpart.c +@@ -33,6 +33,7 @@ + /* Magics */ + #define BOARD_DATA_MAGIC 0x5246504D /* MPFR */ + #define BOARD_DATA_MAGIC2 0xBD0D0BBD ++#define BOARD_DATA_XIAOMI_MAGIC 0x474D4442 /* GMDB */ + #define CFE_MAGIC 0x43464531 /* 1EFC */ + #define FACTORY_MAGIC 0x59544346 /* FCTY */ + #define NVRAM_HEADER 0x48534C46 /* FLSH */ +@@ -262,7 +263,8 @@ static int bcm47xxpart_parse(struct mtd_ + } + + /* Some devices (ex. WNDR3700v3) don't have a standard 'MPFR' */ +- if (buf[0x000 / 4] == BOARD_DATA_MAGIC2) { ++ if (buf[0x000 / 4] == BOARD_DATA_MAGIC2 || ++ le32_to_cpu(buf[0x000 / 4]) == BOARD_DATA_XIAOMI_MAGIC) { + bcm47xxpart_add_part(&parts[curr_part++], "board_data", + offset, MTD_WRITEABLE); + continue; diff --git a/target/linux/generic/patches-4.1/432-mtd-bcm47xxpart-detect-T_Meter-partition.patch b/target/linux/generic/patches-4.1/432-mtd-bcm47xxpart-detect-T_Meter-partition.patch new file mode 100644 index 0000000..1edc995 --- /dev/null +++ b/target/linux/generic/patches-4.1/432-mtd-bcm47xxpart-detect-T_Meter-partition.patch @@ -0,0 +1,42 @@ +From fd54aa583296f9adfb1f519affbc10ba521eb809 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Wed, 28 Jan 2015 22:14:41 +0100 +Subject: [PATCH] mtd: bcm47xxpart: detect T_Meter partition +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +It can be found on many Netgear devices. It consists of many 0x30 blocks +starting with 4D 54. + +Signed-off-by: Rafał Miłecki +--- + drivers/mtd/bcm47xxpart.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +--- a/drivers/mtd/bcm47xxpart.c ++++ b/drivers/mtd/bcm47xxpart.c +@@ -39,6 +39,7 @@ + #define NVRAM_HEADER 0x48534C46 /* FLSH */ + #define POT_MAGIC1 0x54544f50 /* POTT */ + #define POT_MAGIC2 0x504f /* OP */ ++#define T_METER_MAGIC 0x4D540000 /* MT */ + #define ML_MAGIC1 0x39685a42 + #define ML_MAGIC2 0x26594131 + #define TRX_MAGIC 0x30524448 +@@ -176,6 +177,15 @@ static int bcm47xxpart_parse(struct mtd_ + MTD_WRITEABLE); + continue; + } ++ ++ /* T_Meter */ ++ if ((le32_to_cpu(buf[0x000 / 4]) & 0xFFFF0000) == T_METER_MAGIC && ++ (le32_to_cpu(buf[0x030 / 4]) & 0xFFFF0000) == T_METER_MAGIC && ++ (le32_to_cpu(buf[0x060 / 4]) & 0xFFFF0000) == T_METER_MAGIC) { ++ bcm47xxpart_add_part(&parts[curr_part++], "T_Meter", offset, ++ MTD_WRITEABLE); ++ continue; ++ } + + /* TRX */ + if (buf[0x000 / 4] == TRX_MAGIC) { diff --git a/target/linux/generic/patches-4.1/440-block2mtd_init.patch b/target/linux/generic/patches-4.1/440-block2mtd_init.patch new file mode 100644 index 0000000..eddb593 --- /dev/null +++ b/target/linux/generic/patches-4.1/440-block2mtd_init.patch @@ -0,0 +1,108 @@ +--- a/drivers/mtd/devices/block2mtd.c ++++ b/drivers/mtd/devices/block2mtd.c +@@ -25,6 +25,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -218,7 +219,7 @@ static void block2mtd_free_device(struct + + + static struct block2mtd_dev *add_device(char *devname, int erase_size, +- int timeout) ++ const char *mtdname, int timeout) + { + #ifndef MODULE + int i; +@@ -226,6 +227,7 @@ static struct block2mtd_dev *add_device( + const fmode_t mode = FMODE_READ | FMODE_WRITE | FMODE_EXCL; + struct block_device *bdev = ERR_PTR(-ENODEV); + struct block2mtd_dev *dev; ++ struct mtd_partition *part; + char *name; + + if (!devname) +@@ -282,13 +284,16 @@ static struct block2mtd_dev *add_device( + + /* Setup the MTD structure */ + /* make the name contain the block device in */ +- name = kasprintf(GFP_KERNEL, "block2mtd: %s", devname); ++ if (!mtdname) ++ mtdname = devname; ++ name = kmalloc(strlen(mtdname) + 1, GFP_KERNEL); + if (!name) + goto err_destroy_mutex; + ++ strcpy(name, mtdname); + dev->mtd.name = name; + +- dev->mtd.size = dev->blkdev->bd_inode->i_size & PAGE_MASK; ++ dev->mtd.size = dev->blkdev->bd_inode->i_size & PAGE_MASK & ~(erase_size - 1); + dev->mtd.erasesize = erase_size; + dev->mtd.writesize = 1; + dev->mtd.writebufsize = PAGE_SIZE; +@@ -301,7 +306,11 @@ static struct block2mtd_dev *add_device( + dev->mtd.priv = dev; + dev->mtd.owner = THIS_MODULE; + +- if (mtd_device_register(&dev->mtd, NULL, 0)) { ++ part = kzalloc(sizeof(struct mtd_partition), GFP_KERNEL); ++ part->name = name; ++ part->offset = 0; ++ part->size = dev->mtd.size; ++ if (mtd_device_register(&dev->mtd, part, 1)) { + /* Device didn't get added, so free the entry */ + goto err_destroy_mutex; + } +@@ -309,8 +318,7 @@ static struct block2mtd_dev *add_device( + list_add(&dev->list, &blkmtd_device_list); + pr_info("mtd%d: [%s] erase_size = %dKiB [%d]\n", + dev->mtd.index, +- dev->mtd.name + strlen("block2mtd: "), +- dev->mtd.erasesize >> 10, dev->mtd.erasesize); ++ mtdname, dev->mtd.erasesize >> 10, dev->mtd.erasesize); + return dev; + + err_destroy_mutex: +@@ -383,7 +391,7 @@ static int block2mtd_setup2(const char * + /* 80 for device, 12 for erase size, 80 for name, 8 for timeout */ + char buf[80 + 12 + 80 + 8]; + char *str = buf; +- char *token[2]; ++ char *token[3]; + char *name; + size_t erase_size = PAGE_SIZE; + unsigned long timeout = MTD_DEFAULT_TIMEOUT; +@@ -397,7 +405,7 @@ static int block2mtd_setup2(const char * + strcpy(str, val); + kill_final_newline(str); + +- for (i = 0; i < 2; i++) ++ for (i = 0; i < 3; i++) + token[i] = strsep(&str, ","); + + if (str) { +@@ -423,8 +431,10 @@ static int block2mtd_setup2(const char * + return 0; + } + } ++ if (token[2] && (strlen(token[2]) + 1 > 80)) ++ pr_err("mtd device name too long\n"); + +- add_device(name, erase_size, timeout); ++ add_device(name, erase_size, token[2], timeout); + + return 0; + } +@@ -458,7 +468,7 @@ static int block2mtd_setup(const char *v + + + module_param_call(block2mtd, block2mtd_setup, NULL, NULL, 0200); +-MODULE_PARM_DESC(block2mtd, "Device to use. \"block2mtd=[,]\""); ++MODULE_PARM_DESC(block2mtd, "Device to use. \"block2mtd=[,[,]]\""); + + static int __init block2mtd_init(void) + { diff --git a/target/linux/generic/patches-4.1/441-block2mtd_probe.patch b/target/linux/generic/patches-4.1/441-block2mtd_probe.patch new file mode 100644 index 0000000..f78e80a --- /dev/null +++ b/target/linux/generic/patches-4.1/441-block2mtd_probe.patch @@ -0,0 +1,39 @@ +--- a/drivers/mtd/devices/block2mtd.c ++++ b/drivers/mtd/devices/block2mtd.c +@@ -391,7 +391,7 @@ static int block2mtd_setup2(const char * + /* 80 for device, 12 for erase size, 80 for name, 8 for timeout */ + char buf[80 + 12 + 80 + 8]; + char *str = buf; +- char *token[3]; ++ char *token[4]; + char *name; + size_t erase_size = PAGE_SIZE; + unsigned long timeout = MTD_DEFAULT_TIMEOUT; +@@ -405,7 +405,7 @@ static int block2mtd_setup2(const char * + strcpy(str, val); + kill_final_newline(str); + +- for (i = 0; i < 3; i++) ++ for (i = 0; i < 4; i++) + token[i] = strsep(&str, ","); + + if (str) { +@@ -434,6 +434,9 @@ static int block2mtd_setup2(const char * + if (token[2] && (strlen(token[2]) + 1 > 80)) + pr_err("mtd device name too long\n"); + ++ if (token[3] && kstrtoul(token[3], 0, &timeout)) ++ pr_err("invalid timeout\n"); ++ + add_device(name, erase_size, token[2], timeout); + + return 0; +@@ -468,7 +471,7 @@ static int block2mtd_setup(const char *v + + + module_param_call(block2mtd, block2mtd_setup, NULL, NULL, 0200); +-MODULE_PARM_DESC(block2mtd, "Device to use. \"block2mtd=[,[,]]\""); ++MODULE_PARM_DESC(block2mtd, "Device to use. \"block2mtd=[,[,[,]]]\""); + + static int __init block2mtd_init(void) + { diff --git a/target/linux/generic/patches-4.1/450-mtd-nand-allow-to-use-platform-specific-chip-fixup.patch b/target/linux/generic/patches-4.1/450-mtd-nand-allow-to-use-platform-specific-chip-fixup.patch new file mode 100644 index 0000000..ffaf706 --- /dev/null +++ b/target/linux/generic/patches-4.1/450-mtd-nand-allow-to-use-platform-specific-chip-fixup.patch @@ -0,0 +1,37 @@ +--- + drivers/mtd/nand/plat_nand.c | 13 ++++++++++++- + include/linux/mtd/nand.h | 1 + + 2 files changed, 13 insertions(+), 1 deletion(-) + +--- a/include/linux/mtd/nand.h ++++ b/include/linux/mtd/nand.h +@@ -865,6 +865,7 @@ struct platform_nand_chip { + unsigned int options; + unsigned int bbt_options; + const char **part_probe_types; ++ int (*chip_fixup)(struct mtd_info *mtd); + }; + + /* Keep gcc happy */ +--- a/drivers/mtd/nand/plat_nand.c ++++ b/drivers/mtd/nand/plat_nand.c +@@ -90,7 +90,18 @@ static int plat_nand_probe(struct platfo + } + + /* Scan to find existence of the device */ +- if (nand_scan(&data->mtd, pdata->chip.nr_chips)) { ++ if (nand_scan_ident(&data->mtd, pdata->chip.nr_chips, NULL)) { ++ err = -ENXIO; ++ goto out; ++ } ++ ++ if (pdata->chip.chip_fixup) { ++ err = pdata->chip.chip_fixup(&data->mtd); ++ if (err) ++ goto out; ++ } ++ ++ if (nand_scan_tail(&data->mtd)) { + err = -ENXIO; + goto out; + } diff --git a/target/linux/generic/patches-4.1/451-mtd-nand-fix-return-code-of-nand_correct_data-function.patch b/target/linux/generic/patches-4.1/451-mtd-nand-fix-return-code-of-nand_correct_data-function.patch new file mode 100644 index 0000000..6a2092c --- /dev/null +++ b/target/linux/generic/patches-4.1/451-mtd-nand-fix-return-code-of-nand_correct_data-function.patch @@ -0,0 +1,11 @@ +--- a/drivers/mtd/nand/nand_ecc.c ++++ b/drivers/mtd/nand/nand_ecc.c +@@ -507,7 +507,7 @@ int __nand_correct_data(unsigned char *b + return 1; /* error in ECC data; no action needed */ + + pr_err("%s: uncorrectable ECC error\n", __func__); +- return -1; ++ return -EBADMSG; + } + EXPORT_SYMBOL(__nand_correct_data); + diff --git a/target/linux/generic/patches-4.1/460-mtd-cfi_cmdset_0002-no-erase_suspend.patch b/target/linux/generic/patches-4.1/460-mtd-cfi_cmdset_0002-no-erase_suspend.patch new file mode 100644 index 0000000..68fbd12 --- /dev/null +++ b/target/linux/generic/patches-4.1/460-mtd-cfi_cmdset_0002-no-erase_suspend.patch @@ -0,0 +1,11 @@ +--- a/drivers/mtd/chips/cfi_cmdset_0002.c ++++ b/drivers/mtd/chips/cfi_cmdset_0002.c +@@ -809,7 +809,7 @@ static int get_chip(struct map_info *map + return 0; + + case FL_ERASING: +- if (!cfip || !(cfip->EraseSuspend & (0x1|0x2)) || ++ if (1 /* no suspend */ || !cfip || !(cfip->EraseSuspend & (0x1|0x2)) || + !(mode == FL_READY || mode == FL_POINT || + (mode == FL_WRITING && (cfip->EraseSuspend & 0x2)))) + goto sleep; diff --git a/target/linux/generic/patches-4.1/461-mtd-cfi_cmdset_0002-add-buffer-write-cmd-timeout.patch b/target/linux/generic/patches-4.1/461-mtd-cfi_cmdset_0002-add-buffer-write-cmd-timeout.patch new file mode 100644 index 0000000..c437a14 --- /dev/null +++ b/target/linux/generic/patches-4.1/461-mtd-cfi_cmdset_0002-add-buffer-write-cmd-timeout.patch @@ -0,0 +1,18 @@ +From: George Kashperko + +Issue map read after Write Buffer Load command to ensure chip is ready +to receive data. +Signed-off-by: George Kashperko +--- + drivers/mtd/chips/cfi_cmdset_0002.c | 1 + + 1 file changed, 1 insertion(+) +--- a/drivers/mtd/chips/cfi_cmdset_0002.c ++++ b/drivers/mtd/chips/cfi_cmdset_0002.c +@@ -1830,6 +1830,7 @@ static int __xipram do_write_buffer(stru + + /* Write Buffer Load */ + map_write(map, CMD(0x25), cmd_adr); ++ (void) map_read(map, cmd_adr); + + chip->state = FL_WRITING_TO_BUFFER; + diff --git a/target/linux/generic/patches-4.1/473-mtd-spi-nor-add-support-for-the-Macronix-MX25L512E-S.patch b/target/linux/generic/patches-4.1/473-mtd-spi-nor-add-support-for-the-Macronix-MX25L512E-S.patch new file mode 100644 index 0000000..a828b7d --- /dev/null +++ b/target/linux/generic/patches-4.1/473-mtd-spi-nor-add-support-for-the-Macronix-MX25L512E-S.patch @@ -0,0 +1,21 @@ +From 0d7388de0911c1a4fc4a8a3898ef9d0ab818ca08 Mon Sep 17 00:00:00 2001 +From: Gabor Juhos +Date: Tue, 7 Apr 2015 18:35:15 +0200 +Subject: [PATCH] mtd: spi-nor: add support for the Macronix MX25L512E SPI + flash chip + +Signed-off-by: Gabor Juhos +--- + drivers/mtd/spi-nor/spi-nor.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/mtd/spi-nor/spi-nor.c ++++ b/drivers/mtd/spi-nor/spi-nor.c +@@ -561,6 +561,7 @@ static const struct spi_device_id spi_no + { "640s33b", INFO(0x898913, 0, 64 * 1024, 128, 0) }, + + /* Macronix */ ++ { "mx25l512e", INFO(0xc22010, 0, 64 * 1024, 1, SECT_4K) }, + { "mx25l2005a", INFO(0xc22012, 0, 64 * 1024, 4, SECT_4K) }, + { "mx25l4005a", INFO(0xc22013, 0, 64 * 1024, 8, SECT_4K) }, + { "mx25l8005", INFO(0xc22014, 0, 64 * 1024, 16, 0) }, diff --git a/target/linux/generic/patches-4.1/474-mtd-spi-nor-add-support-for-the-ISSI-SI25CD512-SPI-f.patch b/target/linux/generic/patches-4.1/474-mtd-spi-nor-add-support-for-the-ISSI-SI25CD512-SPI-f.patch new file mode 100644 index 0000000..62e0ce8 --- /dev/null +++ b/target/linux/generic/patches-4.1/474-mtd-spi-nor-add-support-for-the-ISSI-SI25CD512-SPI-f.patch @@ -0,0 +1,22 @@ +From 34e2b403040a2f9d3ba071d95a7f42457e2950f9 Mon Sep 17 00:00:00 2001 +From: Gabor Juhos +Date: Tue, 7 Apr 2015 18:35:15 +0200 +Subject: [PATCH] mtd: spi-nor: add support for the ISSI SI25CD512 SPI flash + +Signed-off-by: Gabor Juhos +--- + drivers/mtd/spi-nor/spi-nor.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/mtd/spi-nor/spi-nor.c ++++ b/drivers/mtd/spi-nor/spi-nor.c +@@ -560,6 +560,9 @@ static const struct spi_device_id spi_no + { "320s33b", INFO(0x898912, 0, 64 * 1024, 64, 0) }, + { "640s33b", INFO(0x898913, 0, 64 * 1024, 128, 0) }, + ++ /* ISSI */ ++ { "is25cd512", INFO(0x7f9d20, 0, 32 * 1024, 2, SECT_4K) }, ++ + /* Macronix */ + { "mx25l512e", INFO(0xc22010, 0, 64 * 1024, 1, SECT_4K) }, + { "mx25l2005a", INFO(0xc22012, 0, 64 * 1024, 4, SECT_4K) }, diff --git a/target/linux/generic/patches-4.1/480-mtd-set-rootfs-to-be-root-dev.patch b/target/linux/generic/patches-4.1/480-mtd-set-rootfs-to-be-root-dev.patch new file mode 100644 index 0000000..8d3a1f4 --- /dev/null +++ b/target/linux/generic/patches-4.1/480-mtd-set-rootfs-to-be-root-dev.patch @@ -0,0 +1,26 @@ +--- a/drivers/mtd/mtdcore.c ++++ b/drivers/mtd/mtdcore.c +@@ -39,6 +39,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -448,6 +449,15 @@ int add_mtd_device(struct mtd_info *mtd) + of this try_ nonsense, and no bitching about it + either. :) */ + __module_get(THIS_MODULE); ++ ++ if (!strcmp(mtd->name, "rootfs") && ++ config_enabled(CONFIG_MTD_ROOTFS_ROOT_DEV) && ++ ROOT_DEV == 0) { ++ pr_notice("mtd: device %d (%s) set to be root filesystem\n", ++ mtd->index, mtd->name); ++ ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, mtd->index); ++ } ++ + return 0; + + fail_added: diff --git a/target/linux/generic/patches-4.1/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch b/target/linux/generic/patches-4.1/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch new file mode 100644 index 0000000..d2fb802 --- /dev/null +++ b/target/linux/generic/patches-4.1/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch @@ -0,0 +1,76 @@ +From 8a52e4100d7c3a4a1dfddfa02b8864a9b0068c13 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Sat, 17 May 2014 03:36:18 +0200 +Subject: [PATCH 1/5] ubi: auto-attach mtd device named "ubi" or "data" on boot +To: openwrt-devel@lists.openwrt.org + +Signed-off-by: Daniel Golle +--- + drivers/mtd/ubi/build.c | 36 ++++++++++++++++++++++++++++++++++++ + 1 file changed, 36 insertions(+) + +--- a/drivers/mtd/ubi/build.c ++++ b/drivers/mtd/ubi/build.c +@@ -1218,6 +1218,49 @@ static struct mtd_info * __init open_mtd + return mtd; + } + ++/* ++ * This function tries attaching mtd partitions named either "ubi" or "data" ++ * during boot. ++ */ ++static void __init ubi_auto_attach(void) ++{ ++ int err; ++ struct mtd_info *mtd; ++ ++ /* try attaching mtd device named "ubi" or "data" */ ++ mtd = open_mtd_device("ubi"); ++ if (IS_ERR(mtd)) ++ mtd = open_mtd_device("data"); ++ ++ if (!IS_ERR(mtd)) { ++ size_t len; ++ char magic[4]; ++ ++ /* check for a valid ubi magic */ ++ err = mtd_read(mtd, 0, 4, &len, (void *) magic); ++ if (!err && len == 4 && strncmp(magic, "UBI#", 4)) { ++ pr_err("UBI error: no valid UBI magic found inside mtd%d", mtd->index); ++ put_mtd_device(mtd); ++ return; ++ } ++ ++ /* auto-add only media types where UBI makes sense */ ++ if (mtd->type == MTD_NANDFLASH || ++ mtd->type == MTD_NORFLASH || ++ mtd->type == MTD_DATAFLASH || ++ mtd->type == MTD_MLCNANDFLASH) { ++ mutex_lock(&ubi_devices_mutex); ++ pr_notice("UBI: auto-attach mtd%d", mtd->index); ++ err = ubi_attach_mtd_dev(mtd, UBI_DEV_NUM_AUTO, 0, 0); ++ mutex_unlock(&ubi_devices_mutex); ++ if (err < 0) { ++ pr_err("UBI error: cannot attach mtd%d", mtd->index); ++ put_mtd_device(mtd); ++ } ++ } ++ } ++} ++ + static int __init ubi_init(void) + { + int err, i, k; +@@ -1310,6 +1353,12 @@ static int __init ubi_init(void) + } + } + ++ /* auto-attach mtd devices only if built-in to the kernel and no ubi.mtd ++ * parameter was given */ ++ if (config_enabled(CONFIG_MTD_ROOTFS_ROOT_DEV) && ++ !ubi_is_module() && !mtd_devs) ++ ubi_auto_attach(); ++ + err = ubiblock_init(); + if (err) { + pr_err("UBI error: block: cannot initialize, error %d", err); diff --git a/target/linux/generic/patches-4.1/491-ubi-auto-create-ubiblock-device-for-rootfs.patch b/target/linux/generic/patches-4.1/491-ubi-auto-create-ubiblock-device-for-rootfs.patch new file mode 100644 index 0000000..433d77b --- /dev/null +++ b/target/linux/generic/patches-4.1/491-ubi-auto-create-ubiblock-device-for-rootfs.patch @@ -0,0 +1,69 @@ +From 0f3966579815f889bb2fcb4846152c35f65e79c4 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Thu, 15 May 2014 21:06:33 +0200 +Subject: [PATCH 2/5] ubi: auto-create ubiblock device for rootfs +To: openwrt-devel@lists.openwrt.org + +Signed-off-by: Daniel Golle +--- + drivers/mtd/ubi/block.c | 42 ++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 42 insertions(+) + +--- a/drivers/mtd/ubi/block.c ++++ b/drivers/mtd/ubi/block.c +@@ -616,6 +616,44 @@ static void __init ubiblock_create_from_ + } + } + ++#define UBIFS_NODE_MAGIC 0x06101831 ++static inline int ubi_vol_is_ubifs(struct ubi_volume_desc *desc) ++{ ++ int ret; ++ uint32_t magic_of, magic; ++ ret = ubi_read(desc, 0, (char *)&magic_of, 0, 4); ++ if (ret) ++ return 0; ++ magic = le32_to_cpu(magic_of); ++ return magic == UBIFS_NODE_MAGIC; ++} ++ ++static void __init ubiblock_create_auto_rootfs(void) ++{ ++ int ubi_num, ret, is_ubifs; ++ struct ubi_volume_desc *desc; ++ struct ubi_volume_info vi; ++ ++ for (ubi_num = 0; ubi_num < UBI_MAX_DEVICES; ubi_num++) { ++ desc = ubi_open_volume_nm(ubi_num, "rootfs", UBI_READONLY); ++ if (IS_ERR(desc)) ++ continue; ++ ++ ubi_get_volume_info(desc, &vi); ++ is_ubifs = ubi_vol_is_ubifs(desc); ++ ubi_close_volume(desc); ++ if (is_ubifs) ++ break; ++ ++ ret = ubiblock_create(&vi); ++ if (ret) ++ pr_err("UBI error: block: can't add '%s' volume, err=%d\n", ++ vi.name, ret); ++ /* always break if we get here */ ++ break; ++ } ++} ++ + static void ubiblock_remove_all(void) + { + struct ubiblock *next; +@@ -646,6 +684,10 @@ int __init ubiblock_init(void) + */ + ubiblock_create_from_param(); + ++ /* auto-attach "rootfs" volume if existing and non-ubifs */ ++ if (config_enabled(CONFIG_MTD_ROOTFS_ROOT_DEV)) ++ ubiblock_create_auto_rootfs(); ++ + /* + * Block devices are only created upon user requests, so we ignore + * existing volumes. diff --git a/target/linux/generic/patches-4.1/492-try-auto-mounting-ubi0-rootfs-in-init-do_mounts.c.patch b/target/linux/generic/patches-4.1/492-try-auto-mounting-ubi0-rootfs-in-init-do_mounts.c.patch new file mode 100644 index 0000000..005de3f --- /dev/null +++ b/target/linux/generic/patches-4.1/492-try-auto-mounting-ubi0-rootfs-in-init-do_mounts.c.patch @@ -0,0 +1,53 @@ +From eea9e1785e4c05c2a3444506aabafa0ae958538f Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Sat, 17 May 2014 03:35:02 +0200 +Subject: [PATCH 4/5] try auto-mounting ubi0:rootfs in init/do_mounts.c +To: openwrt-devel@lists.openwrt.org + +Signed-off-by: Daniel Golle +--- + init/do_mounts.c | 26 +++++++++++++++++++++++++- + 1 file changed, 25 insertions(+), 1 deletion(-) + +--- a/init/do_mounts.c ++++ b/init/do_mounts.c +@@ -438,7 +438,27 @@ retry: + out: + put_page(page); + } +- ++ ++static int __init mount_ubi_rootfs(void) ++{ ++ int flags = MS_SILENT; ++ int err, tried = 0; ++ ++ while (tried < 2) { ++ err = do_mount_root("ubi0:rootfs", "ubifs", flags, \ ++ root_mount_data); ++ switch (err) { ++ case -EACCES: ++ flags |= MS_RDONLY; ++ tried++; ++ default: ++ return err; ++ } ++ } ++ ++ return -EINVAL; ++} ++ + #ifdef CONFIG_ROOT_NFS + + #define NFSROOT_TIMEOUT_MIN 5 +@@ -532,6 +552,10 @@ void __init mount_root(void) + change_floppy("root floppy"); + } + #endif ++#ifdef CONFIG_MTD_ROOTFS_ROOT_DEV ++ if (!mount_ubi_rootfs()) ++ return; ++#endif + #ifdef CONFIG_BLOCK + create_dev("/dev/root", ROOT_DEV); + mount_block_root("/dev/root", root_mountflags); diff --git a/target/linux/generic/patches-4.1/493-ubi-set-ROOT_DEV-to-ubiblock-rootfs-if-unset.patch b/target/linux/generic/patches-4.1/493-ubi-set-ROOT_DEV-to-ubiblock-rootfs-if-unset.patch new file mode 100644 index 0000000..1873752 --- /dev/null +++ b/target/linux/generic/patches-4.1/493-ubi-set-ROOT_DEV-to-ubiblock-rootfs-if-unset.patch @@ -0,0 +1,37 @@ +From cd68d1b12b5ea4c01a664c064179ada42bf55d3d Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Thu, 15 May 2014 20:55:42 +0200 +Subject: [PATCH 5/5] ubi: set ROOT_DEV to ubiblock "rootfs" if unset +To: openwrt-devel@lists.openwrt.org + +Signed-off-by: Daniel Golle +--- + drivers/mtd/ubi/block.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +--- a/drivers/mtd/ubi/block.c ++++ b/drivers/mtd/ubi/block.c +@@ -49,6 +49,7 @@ + #include + #include + #include ++#include + + #include "ubi-media.h" + #include "ubi.h" +@@ -439,6 +440,15 @@ int ubiblock_create(struct ubi_volume_in + add_disk(dev->gd); + dev_info(disk_to_dev(dev->gd), "created from ubi%d:%d(%s)", + dev->ubi_num, dev->vol_id, vi->name); ++ ++ if (!strcmp(vi->name, "rootfs") && ++ config_enabled(CONFIG_MTD_ROOTFS_ROOT_DEV) && ++ ROOT_DEV == 0) { ++ pr_notice("ubiblock: device ubiblock%d_%d (%s) set to be root filesystem\n", ++ dev->ubi_num, dev->vol_id, vi->name); ++ ROOT_DEV = MKDEV(gd->major, gd->first_minor); ++ } ++ + return 0; + + out_free_queue: diff --git a/target/linux/generic/patches-4.1/494-mtd-ubi-add-EOF-marker-support.patch b/target/linux/generic/patches-4.1/494-mtd-ubi-add-EOF-marker-support.patch new file mode 100644 index 0000000..14fae76 --- /dev/null +++ b/target/linux/generic/patches-4.1/494-mtd-ubi-add-EOF-marker-support.patch @@ -0,0 +1,51 @@ +--- a/drivers/mtd/ubi/attach.c ++++ b/drivers/mtd/ubi/attach.c +@@ -803,6 +803,13 @@ out_unlock: + return err; + } + ++static bool ec_hdr_has_eof(struct ubi_ec_hdr *ech) ++{ ++ return ech->padding1[0] == 'E' && ++ ech->padding1[1] == 'O' && ++ ech->padding1[2] == 'F'; ++} ++ + /** + * scan_peb - scan and process UBI headers of a PEB. + * @ubi: UBI device description object +@@ -833,9 +840,21 @@ static int scan_peb(struct ubi_device *u + return 0; + } + +- err = ubi_io_read_ec_hdr(ubi, pnum, ech, 0); +- if (err < 0) +- return err; ++ if (!ai->eof_found) { ++ err = ubi_io_read_ec_hdr(ubi, pnum, ech, 0); ++ if (err < 0) ++ return err; ++ ++ if (ec_hdr_has_eof(ech)) { ++ pr_notice("UBI: EOF marker found, PEBs from %d will be erased", ++ pnum); ++ ai->eof_found = true; ++ } ++ } ++ ++ if (ai->eof_found) ++ err = UBI_IO_FF_BITFLIPS; ++ + switch (err) { + case 0: + break; +--- a/drivers/mtd/ubi/ubi.h ++++ b/drivers/mtd/ubi/ubi.h +@@ -739,6 +739,7 @@ struct ubi_attach_info { + int mean_ec; + uint64_t ec_sum; + int ec_count; ++ bool eof_found; + struct kmem_cache *aeb_slab_cache; + }; + diff --git a/target/linux/generic/patches-4.1/500-yaffs-Kbuild-integration.patch b/target/linux/generic/patches-4.1/500-yaffs-Kbuild-integration.patch new file mode 100644 index 0000000..2754c1a --- /dev/null +++ b/target/linux/generic/patches-4.1/500-yaffs-Kbuild-integration.patch @@ -0,0 +1,18 @@ +--- a/fs/Kconfig ++++ b/fs/Kconfig +@@ -33,6 +33,7 @@ source "fs/ocfs2/Kconfig" + source "fs/btrfs/Kconfig" + source "fs/nilfs2/Kconfig" + source "fs/f2fs/Kconfig" ++source "fs/yaffs2/Kconfig" + + config FS_DAX + bool "Direct Access (DAX) support" +--- a/fs/Makefile ++++ b/fs/Makefile +@@ -127,3 +127,5 @@ obj-y += exofs/ # Multiple modules + obj-$(CONFIG_CEPH_FS) += ceph/ + obj-$(CONFIG_PSTORE) += pstore/ + obj-$(CONFIG_EFIVAR_FS) += efivarfs/ ++obj-$(CONFIG_YAFFS_FS) += yaffs2/ ++ diff --git a/target/linux/generic/patches-4.1/502-yaffs-fix-compat-tags-handling.patch b/target/linux/generic/patches-4.1/502-yaffs-fix-compat-tags-handling.patch new file mode 100644 index 0000000..a18cf6f --- /dev/null +++ b/target/linux/generic/patches-4.1/502-yaffs-fix-compat-tags-handling.patch @@ -0,0 +1,239 @@ +Subject: yaffs: fix compat tags handling + +Signed-off-by: Gabor Juhos +--- +--- a/fs/yaffs2/yaffs_tagscompat.c ++++ b/fs/yaffs2/yaffs_tagscompat.c +@@ -17,7 +17,9 @@ + #include "yaffs_getblockinfo.h" + #include "yaffs_trace.h" + ++#if 0 + static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk); ++#endif + + + /********** Tags ECC calculations *********/ +@@ -71,6 +73,7 @@ int yaffs_check_tags_ecc(struct yaffs_ta + return 0; + } + ++#if 0 + /********** Tags **********/ + + static void yaffs_load_tags_to_spare(struct yaffs_spare *spare_ptr, +@@ -379,3 +382,214 @@ void yaffs_tags_compat_install(struct ya + if(!dev->tagger.mark_bad_fn) + dev->tagger.mark_bad_fn = yaffs_tags_compat_mark_bad; + } ++#else ++ ++#include "yaffs_packedtags1.h" ++ ++static int yaffs_tags_compat_write(struct yaffs_dev *dev, ++ int nand_chunk, ++ const u8 *data, ++ const struct yaffs_ext_tags *tags) ++{ ++ struct yaffs_packed_tags1 pt1; ++ u8 tag_buf[9]; ++ int retval; ++ ++ /* we assume that yaffs_packed_tags1 and yaffs_tags are compatible */ ++ compile_time_assertion(sizeof(struct yaffs_packed_tags1) == 12); ++ compile_time_assertion(sizeof(struct yaffs_tags) == 8); ++ ++ yaffs_pack_tags1(&pt1, tags); ++ yaffs_calc_tags_ecc((struct yaffs_tags *)&pt1); ++ ++ /* When deleting a chunk, the upper layer provides only skeletal ++ * tags, one with is_deleted set. However, we need to update the ++ * tags, not erase them completely. So we use the NAND write property ++ * that only zeroed-bits stick and set tag bytes to all-ones and ++ * zero just the (not) deleted bit. ++ */ ++ if (!dev->param.tags_9bytes) { ++ if (tags->is_deleted) { ++ memset(&pt1, 0xff, 8); ++ /* clear delete status bit to indicate deleted */ ++ pt1.deleted = 0; ++ } ++ memcpy(tag_buf, &pt1, 8); ++ } else { ++ if (tags->is_deleted) { ++ memset(tag_buf, 0xff, 8); ++ tag_buf[8] = 0; ++ } else { ++ memcpy(tag_buf, &pt1, 8); ++ tag_buf[8] = 0xff; ++ } ++ } ++ ++ retval = dev->drv.drv_write_chunk_fn(dev, nand_chunk, ++ data, ++ (data) ? dev->data_bytes_per_chunk : 0, ++ tag_buf, ++ (dev->param.tags_9bytes) ? 9 : 8); ++ ++ return retval; ++} ++ ++/* Return with empty extended tags but add ecc_result. ++ */ ++static int return_empty_tags(struct yaffs_ext_tags *tags, ++ enum yaffs_ecc_result ecc_result, ++ int retval) ++{ ++ if (tags) { ++ memset(tags, 0, sizeof(*tags)); ++ tags->ecc_result = ecc_result; ++ } ++ ++ return retval; ++} ++ ++static int yaffs_tags_compat_read(struct yaffs_dev *dev, ++ int nand_chunk, ++ u8 *data, ++ struct yaffs_ext_tags *tags) ++{ ++ struct yaffs_packed_tags1 pt1; ++ enum yaffs_ecc_result ecc_result; ++ int retval; ++ int deleted; ++ u8 tag_buf[9]; ++ ++ retval = dev->drv.drv_read_chunk_fn(dev, nand_chunk, ++ data, dev->param.total_bytes_per_chunk, ++ tag_buf, ++ (dev->param.tags_9bytes) ? 9 : 8, ++ &ecc_result); ++ ++ switch (ecc_result) { ++ case YAFFS_ECC_RESULT_NO_ERROR: ++ case YAFFS_ECC_RESULT_FIXED: ++ break; ++ ++ case YAFFS_ECC_RESULT_UNFIXED: ++ default: ++ return_empty_tags(tags, YAFFS_ECC_RESULT_UNFIXED, 0); ++ tags->block_bad = dev->drv.drv_check_bad_fn(dev, nand_chunk); ++ return YAFFS_FAIL; ++ } ++ ++ /* Check for a blank/erased chunk. */ ++ if (yaffs_check_ff(tag_buf, 8)) { ++ /* when blank, upper layers want ecc_result to be <= NO_ERROR */ ++ return return_empty_tags(tags, YAFFS_ECC_RESULT_NO_ERROR, ++ YAFFS_OK); ++ } ++ ++ memcpy(&pt1, tag_buf, 8); ++ ++ if (!dev->param.tags_9bytes) { ++ /* Read deleted status (bit) then return it to it's non-deleted ++ * state before performing tags mini-ECC check. pt1.deleted is ++ * inverted. ++ */ ++ deleted = !pt1.deleted; ++ pt1.deleted = 1; ++ } else { ++ deleted = (hweight8(tag_buf[8]) < 7) ? 1 : 0; ++ } ++ ++ /* Check the packed tags mini-ECC and correct if necessary/possible. */ ++ retval = yaffs_check_tags_ecc((struct yaffs_tags *)&pt1); ++ switch (retval) { ++ case 0: ++ /* no tags error, use MTD result */ ++ break; ++ case 1: ++ /* recovered tags-ECC error */ ++ dev->n_tags_ecc_fixed++; ++ if (ecc_result == YAFFS_ECC_RESULT_NO_ERROR) ++ ecc_result = YAFFS_ECC_RESULT_FIXED; ++ break; ++ default: ++ /* unrecovered tags-ECC error */ ++ dev->n_tags_ecc_unfixed++; ++ return return_empty_tags(tags, YAFFS_ECC_RESULT_UNFIXED, ++ YAFFS_FAIL); ++ } ++ ++ /* Unpack the tags to extended form and set ECC result. ++ * [set should_be_ff just to keep yaffs_unpack_tags1 happy] ++ */ ++ pt1.should_be_ff = 0xffffffff; ++ yaffs_unpack_tags1(tags, &pt1); ++ tags->ecc_result = ecc_result; ++ ++ /* Set deleted state */ ++ tags->is_deleted = deleted; ++ return YAFFS_OK; ++} ++ ++static int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int block_no) ++{ ++ return dev->drv.drv_mark_bad_fn(dev, block_no); ++} ++ ++static int yaffs_tags_compat_query_block(struct yaffs_dev *dev, ++ int block_no, ++ enum yaffs_block_state *state, ++ u32 *seq_number) ++{ ++ struct yaffs_ext_tags tags; ++ int retval; ++ ++ yaffs_trace(YAFFS_TRACE_MTD, "%s %d", __func__, block_no); ++ ++ *seq_number = 0; ++ ++ retval = dev->drv.drv_check_bad_fn(dev, block_no); ++ if (retval == YAFFS_FAIL) { ++ *state = YAFFS_BLOCK_STATE_DEAD; ++ goto out; ++ } ++ ++ yaffs_tags_compat_read(dev, block_no * dev->param.chunks_per_block, ++ NULL, &tags); ++ ++ if (tags.ecc_result != YAFFS_ECC_RESULT_NO_ERROR) { ++ yaffs_trace(YAFFS_TRACE_MTD, "block %d is marked bad", ++ block_no); ++ *state = YAFFS_BLOCK_STATE_NEEDS_SCAN; ++ } else if (tags.chunk_used) { ++ *seq_number = tags.seq_number; ++ *state = YAFFS_BLOCK_STATE_NEEDS_SCAN; ++ } else { ++ *state = YAFFS_BLOCK_STATE_EMPTY; ++ } ++ ++ retval = YAFFS_OK; ++ ++out: ++ yaffs_trace(YAFFS_TRACE_MTD, ++ "block query returns seq %u state %d", ++ *seq_number, *state); ++ ++ return retval; ++} ++ ++void yaffs_tags_compat_install(struct yaffs_dev *dev) ++{ ++ if (dev->param.is_yaffs2) ++ return; ++ ++ if (!dev->tagger.write_chunk_tags_fn) ++ dev->tagger.write_chunk_tags_fn = yaffs_tags_compat_write; ++ ++ if (!dev->tagger.read_chunk_tags_fn) ++ dev->tagger.read_chunk_tags_fn = yaffs_tags_compat_read; ++ ++ if (!dev->tagger.query_block_fn) ++ dev->tagger.query_block_fn = yaffs_tags_compat_query_block; ++ ++ if (!dev->tagger.mark_bad_fn) ++ dev->tagger.mark_bad_fn = yaffs_tags_compat_mark_bad; ++} ++#endif diff --git a/target/linux/generic/patches-4.1/503-yaffs-add-tags-9bytes-mount-option.patch b/target/linux/generic/patches-4.1/503-yaffs-add-tags-9bytes-mount-option.patch new file mode 100644 index 0000000..3f51baf --- /dev/null +++ b/target/linux/generic/patches-4.1/503-yaffs-add-tags-9bytes-mount-option.patch @@ -0,0 +1,115 @@ +Subject: yaffs: add support for tags-9bytes mount option + +Signed-off-by: Gabor Juhos +--- +--- a/fs/yaffs2/yaffs_vfs.c ++++ b/fs/yaffs2/yaffs_vfs.c +@@ -2644,6 +2644,7 @@ static const struct super_operations yaf + + struct yaffs_options { + int inband_tags; ++ int tags_9bytes; + int skip_checkpoint_read; + int skip_checkpoint_write; + int no_cache; +@@ -2683,6 +2684,8 @@ static int yaffs_parse_options(struct ya + + if (!strcmp(cur_opt, "inband-tags")) { + options->inband_tags = 1; ++ } else if (!strcmp(cur_opt, "tags-9bytes")) { ++ options->tags_9bytes = 1; + } else if (!strcmp(cur_opt, "tags-ecc-off")) { + options->tags_ecc_on = 0; + options->tags_ecc_overridden = 1; +@@ -2756,7 +2759,6 @@ static struct super_block *yaffs_interna + struct yaffs_param *param; + + int read_only = 0; +- int inband_tags = 0; + + struct yaffs_options options; + +@@ -2796,6 +2798,9 @@ static struct super_block *yaffs_interna + + memset(&options, 0, sizeof(options)); + ++ if (IS_ENABLED(CONFIG_YAFFS_9BYTE_TAGS)) ++ options.tags_9bytes = 1; ++ + if (yaffs_parse_options(&options, data_str)) { + /* Option parsing failed */ + return NULL; +@@ -2829,17 +2834,22 @@ static struct super_block *yaffs_interna + } + + /* Added NCB 26/5/2006 for completeness */ +- if (yaffs_version == 2 && !options.inband_tags +- && WRITE_SIZE(mtd) == 512) { ++ if (yaffs_version == 2 && ++ (!options.inband_tags || options.tags_9bytes) && ++ WRITE_SIZE(mtd) == 512) { + yaffs_trace(YAFFS_TRACE_ALWAYS, "auto selecting yaffs1"); + yaffs_version = 1; + } + +- if (mtd->oobavail < sizeof(struct yaffs_packed_tags2) || +- options.inband_tags) +- inband_tags = 1; ++ if (yaffs_version == 2 && ++ mtd->oobavail < sizeof(struct yaffs_packed_tags2)) { ++ yaffs_trace(YAFFS_TRACE_ALWAYS, "auto selecting inband tags"); ++ options.inband_tags = 1; ++ } + +- if(yaffs_verify_mtd(mtd, yaffs_version, inband_tags) < 0) ++ err = yaffs_verify_mtd(mtd, yaffs_version, options.inband_tags, ++ options.tags_9bytes); ++ if (err < 0) + return NULL; + + /* OK, so if we got here, we have an MTD that's NAND and looks +@@ -2896,7 +2906,8 @@ static struct super_block *yaffs_interna + + param->n_reserved_blocks = 5; + param->n_caches = (options.no_cache) ? 0 : 10; +- param->inband_tags = inband_tags; ++ param->inband_tags = options.inband_tags; ++ param->tags_9bytes = options.tags_9bytes; + + param->enable_xattr = 1; + if (options.lazy_loading_overridden) +--- a/fs/yaffs2/yaffs_mtdif.c ++++ b/fs/yaffs2/yaffs_mtdif.c +@@ -278,7 +278,8 @@ struct mtd_info * yaffs_get_mtd_device(d + return mtd; + } + +-int yaffs_verify_mtd(struct mtd_info *mtd, int yaffs_version, int inband_tags) ++int yaffs_verify_mtd(struct mtd_info *mtd, int yaffs_version, int inband_tags, ++ int tags_9bytes) + { + if (yaffs_version == 2) { + if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE || +@@ -297,6 +298,12 @@ int yaffs_verify_mtd(struct mtd_info *mt + ); + return -1; + } ++ ++ if (tags_9bytes && mtd->oobavail < 9) { ++ yaffs_trace(YAFFS_TRACE_ALWAYS, ++ "MTD device does not support 9-byte tags"); ++ return -1; ++ } + } + + return 0; +--- a/fs/yaffs2/yaffs_mtdif.h ++++ b/fs/yaffs2/yaffs_mtdif.h +@@ -21,5 +21,6 @@ + void yaffs_mtd_drv_install(struct yaffs_dev *dev); + struct mtd_info * yaffs_get_mtd_device(dev_t sdev); + void yaffs_put_mtd_device(struct mtd_info *mtd); +-int yaffs_verify_mtd(struct mtd_info *mtd, int yaffs_version, int inband_tags); ++int yaffs_verify_mtd(struct mtd_info *mtd, int yaffs_version, int inband_tags, ++ int tags_9bytes); + #endif diff --git a/target/linux/generic/patches-4.1/504-yaffs-3.16-new-fops.patch b/target/linux/generic/patches-4.1/504-yaffs-3.16-new-fops.patch new file mode 100644 index 0000000..32b4fdf --- /dev/null +++ b/target/linux/generic/patches-4.1/504-yaffs-3.16-new-fops.patch @@ -0,0 +1,29 @@ +--- a/fs/yaffs2/yaffs_vfs.c ++++ b/fs/yaffs2/yaffs_vfs.c +@@ -774,7 +774,25 @@ static int yaffs_sync_object(struct file + } + + +-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22)) ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) ++static const struct file_operations yaffs_file_operations = { ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0)) ++ .read = new_sync_read, ++#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0) */ ++ .read_iter = generic_file_read_iter, ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0)) ++ .write = new_sync_write, ++#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0) */ ++ .write_iter = generic_file_write_iter, ++ .mmap = generic_file_mmap, ++ .flush = yaffs_file_flush, ++ .fsync = yaffs_sync_object, ++ .splice_read = generic_file_splice_read, ++ .splice_write = iter_file_splice_write, ++ .llseek = generic_file_llseek, ++}; ++ ++#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22)) + static const struct file_operations yaffs_file_operations = { + .read = do_sync_read, + .write = do_sync_write, diff --git a/target/linux/generic/patches-4.1/505-yaffs-3.19-f_dentry-remove.patch b/target/linux/generic/patches-4.1/505-yaffs-3.19-f_dentry-remove.patch new file mode 100644 index 0000000..0d4b6bf --- /dev/null +++ b/target/linux/generic/patches-4.1/505-yaffs-3.19-f_dentry-remove.patch @@ -0,0 +1,95 @@ +--- a/fs/yaffs2/yaffs_vfs.c ++++ b/fs/yaffs2/yaffs_vfs.c +@@ -283,7 +283,7 @@ static int yaffs_readpage_nolock(struct + (long long)pos, + (unsigned)PAGE_CACHE_SIZE); + +- obj = yaffs_dentry_to_obj(f->f_dentry); ++ obj = yaffs_dentry_to_obj(f->f_path.dentry); + + dev = obj->my_dev; + +@@ -481,7 +481,7 @@ static ssize_t yaffs_hold_space(struct f + + int n_free_chunks; + +- obj = yaffs_dentry_to_obj(f->f_dentry); ++ obj = yaffs_dentry_to_obj(f->f_path.dentry); + + dev = obj->my_dev; + +@@ -499,7 +499,7 @@ static void yaffs_release_space(struct f + struct yaffs_obj *obj; + struct yaffs_dev *dev; + +- obj = yaffs_dentry_to_obj(f->f_dentry); ++ obj = yaffs_dentry_to_obj(f->f_path.dentry); + + dev = obj->my_dev; + +@@ -591,7 +591,7 @@ static ssize_t yaffs_file_write(struct f + struct inode *inode; + struct yaffs_dev *dev; + +- obj = yaffs_dentry_to_obj(f->f_dentry); ++ obj = yaffs_dentry_to_obj(f->f_path.dentry); + + if (!obj) { + yaffs_trace(YAFFS_TRACE_OS, +@@ -603,7 +603,7 @@ static ssize_t yaffs_file_write(struct f + + yaffs_gross_lock(dev); + +- inode = f->f_dentry->d_inode; ++ inode = f->f_path.dentry->d_inode; + + if (!S_ISBLK(inode->i_mode) && f->f_flags & O_APPEND) + ipos = inode->i_size; +@@ -727,7 +727,7 @@ static int yaffs_file_flush(struct file + static int yaffs_file_flush(struct file *file) + #endif + { +- struct yaffs_obj *obj = yaffs_dentry_to_obj(file->f_dentry); ++ struct yaffs_obj *obj = yaffs_dentry_to_obj(file->f_path.dentry); + + struct yaffs_dev *dev = obj->my_dev; + +@@ -1734,7 +1734,7 @@ static int yaffs_iterate(struct file *f, + + char name[YAFFS_MAX_NAME_LENGTH + 1]; + +- obj = yaffs_dentry_to_obj(f->f_dentry); ++ obj = yaffs_dentry_to_obj(f->f_path.dentry); + dev = obj->my_dev; + + yaffs_gross_lock(dev); +@@ -1798,14 +1798,14 @@ static int yaffs_readdir(struct file *f, + struct yaffs_obj *obj; + struct yaffs_dev *dev; + struct yaffs_search_context *sc; +- struct inode *inode = f->f_dentry->d_inode; ++ struct inode *inode = f->f_path.dentry->d_inode; + unsigned long offset, curoffs; + struct yaffs_obj *l; + int ret_val = 0; + + char name[YAFFS_MAX_NAME_LENGTH + 1]; + +- obj = yaffs_dentry_to_obj(f->f_dentry); ++ obj = yaffs_dentry_to_obj(f->f_path.dentry); + dev = obj->my_dev; + + yaffs_gross_lock(dev); +@@ -1839,10 +1839,10 @@ static int yaffs_readdir(struct file *f, + if (offset == 1) { + yaffs_trace(YAFFS_TRACE_OS, + "yaffs_readdir: entry .. ino %d", +- (int)f->f_dentry->d_parent->d_inode->i_ino); ++ (int)f->f_path.dentry->d_parent->d_inode->i_ino); + yaffs_gross_unlock(dev); + if (filldir(dirent, "..", 2, offset, +- f->f_dentry->d_parent->d_inode->i_ino, ++ f->f_path.dentry->d_parent->d_inode->i_ino, + DT_DIR) < 0) { + yaffs_gross_lock(dev); + goto out; diff --git a/target/linux/generic/patches-4.1/520-squashfs_update_xz_comp_opts.patch b/target/linux/generic/patches-4.1/520-squashfs_update_xz_comp_opts.patch new file mode 100644 index 0000000..ad11b30 --- /dev/null +++ b/target/linux/generic/patches-4.1/520-squashfs_update_xz_comp_opts.patch @@ -0,0 +1,25 @@ +From f31b7c0efa255dd17a5f584022a319387f09b0d8 Mon Sep 17 00:00:00 2001 +From: Jonas Gorski +Date: Tue, 12 Apr 2011 19:55:41 +0200 +Subject: [PATCH] squashfs: update xz compressor options struct. + +Update the xz compressor options struct to match the squashfs userspace +one. +--- + fs/squashfs/xz_wrapper.c | 4 +++- + 1 files changed, 3 insertions(+), 1 deletions(-) + +--- a/fs/squashfs/xz_wrapper.c ++++ b/fs/squashfs/xz_wrapper.c +@@ -40,8 +40,10 @@ struct squashfs_xz { + }; + + struct disk_comp_opts { +- __le32 dictionary_size; + __le32 flags; ++ __le16 bit_opts; ++ __le16 fb; ++ __le32 dictionary_size; + }; + + struct comp_opts { diff --git a/target/linux/generic/patches-4.1/530-jffs2_make_lzma_available.patch b/target/linux/generic/patches-4.1/530-jffs2_make_lzma_available.patch new file mode 100644 index 0000000..c8301f0 --- /dev/null +++ b/target/linux/generic/patches-4.1/530-jffs2_make_lzma_available.patch @@ -0,0 +1,5142 @@ +--- a/fs/jffs2/Kconfig ++++ b/fs/jffs2/Kconfig +@@ -139,6 +139,15 @@ config JFFS2_LZO + This feature was added in July, 2007. Say 'N' if you need + compatibility with older bootloaders or kernels. + ++config JFFS2_LZMA ++ bool "JFFS2 LZMA compression support" if JFFS2_COMPRESSION_OPTIONS ++ select LZMA_COMPRESS ++ select LZMA_DECOMPRESS ++ depends on JFFS2_FS ++ default n ++ help ++ JFFS2 wrapper to the LZMA C SDK ++ + config JFFS2_RTIME + bool "JFFS2 RTIME compression support" if JFFS2_COMPRESSION_OPTIONS + depends on JFFS2_FS +--- a/fs/jffs2/Makefile ++++ b/fs/jffs2/Makefile +@@ -18,4 +18,7 @@ jffs2-$(CONFIG_JFFS2_RUBIN) += compr_rub + jffs2-$(CONFIG_JFFS2_RTIME) += compr_rtime.o + jffs2-$(CONFIG_JFFS2_ZLIB) += compr_zlib.o + jffs2-$(CONFIG_JFFS2_LZO) += compr_lzo.o ++jffs2-$(CONFIG_JFFS2_LZMA) += compr_lzma.o + jffs2-$(CONFIG_JFFS2_SUMMARY) += summary.o ++ ++CFLAGS_compr_lzma.o += -Iinclude/linux -Ilib/lzma +--- a/fs/jffs2/compr.c ++++ b/fs/jffs2/compr.c +@@ -378,6 +378,9 @@ int __init jffs2_compressors_init(void) + #ifdef CONFIG_JFFS2_LZO + jffs2_lzo_init(); + #endif ++#ifdef CONFIG_JFFS2_LZMA ++ jffs2_lzma_init(); ++#endif + /* Setting default compression mode */ + #ifdef CONFIG_JFFS2_CMODE_NONE + jffs2_compression_mode = JFFS2_COMPR_MODE_NONE; +@@ -401,6 +404,9 @@ int __init jffs2_compressors_init(void) + int jffs2_compressors_exit(void) + { + /* Unregistering compressors */ ++#ifdef CONFIG_JFFS2_LZMA ++ jffs2_lzma_exit(); ++#endif + #ifdef CONFIG_JFFS2_LZO + jffs2_lzo_exit(); + #endif +--- a/fs/jffs2/compr.h ++++ b/fs/jffs2/compr.h +@@ -29,9 +29,9 @@ + #define JFFS2_DYNRUBIN_PRIORITY 20 + #define JFFS2_LZARI_PRIORITY 30 + #define JFFS2_RTIME_PRIORITY 50 +-#define JFFS2_ZLIB_PRIORITY 60 +-#define JFFS2_LZO_PRIORITY 80 +- ++#define JFFS2_LZMA_PRIORITY 70 ++#define JFFS2_ZLIB_PRIORITY 80 ++#define JFFS2_LZO_PRIORITY 90 + + #define JFFS2_RUBINMIPS_DISABLED /* RUBINs will be used only */ + #define JFFS2_DYNRUBIN_DISABLED /* for decompression */ +@@ -101,5 +101,9 @@ void jffs2_zlib_exit(void); + int jffs2_lzo_init(void); + void jffs2_lzo_exit(void); + #endif ++#ifdef CONFIG_JFFS2_LZMA ++int jffs2_lzma_init(void); ++void jffs2_lzma_exit(void); ++#endif + + #endif /* __JFFS2_COMPR_H__ */ +--- /dev/null ++++ b/fs/jffs2/compr_lzma.c +@@ -0,0 +1,128 @@ ++/* ++ * JFFS2 -- Journalling Flash File System, Version 2. ++ * ++ * For licensing information, see the file 'LICENCE' in this directory. ++ * ++ * JFFS2 wrapper to the LZMA C SDK ++ * ++ */ ++ ++#include ++#include "compr.h" ++ ++#ifdef __KERNEL__ ++ static DEFINE_MUTEX(deflate_mutex); ++#endif ++ ++CLzmaEncHandle *p; ++Byte propsEncoded[LZMA_PROPS_SIZE]; ++SizeT propsSize = sizeof(propsEncoded); ++ ++STATIC void lzma_free_workspace(void) ++{ ++ LzmaEnc_Destroy(p, &lzma_alloc, &lzma_alloc); ++} ++ ++STATIC int INIT lzma_alloc_workspace(CLzmaEncProps *props) ++{ ++ if ((p = (CLzmaEncHandle *)LzmaEnc_Create(&lzma_alloc)) == NULL) ++ { ++ PRINT_ERROR("Failed to allocate lzma deflate workspace\n"); ++ return -ENOMEM; ++ } ++ ++ if (LzmaEnc_SetProps(p, props) != SZ_OK) ++ { ++ lzma_free_workspace(); ++ return -1; ++ } ++ ++ if (LzmaEnc_WriteProperties(p, propsEncoded, &propsSize) != SZ_OK) ++ { ++ lzma_free_workspace(); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++STATIC int jffs2_lzma_compress(unsigned char *data_in, unsigned char *cpage_out, ++ uint32_t *sourcelen, uint32_t *dstlen) ++{ ++ SizeT compress_size = (SizeT)(*dstlen); ++ int ret; ++ ++ #ifdef __KERNEL__ ++ mutex_lock(&deflate_mutex); ++ #endif ++ ++ ret = LzmaEnc_MemEncode(p, cpage_out, &compress_size, data_in, *sourcelen, ++ 0, NULL, &lzma_alloc, &lzma_alloc); ++ ++ #ifdef __KERNEL__ ++ mutex_unlock(&deflate_mutex); ++ #endif ++ ++ if (ret != SZ_OK) ++ return -1; ++ ++ *dstlen = (uint32_t)compress_size; ++ ++ return 0; ++} ++ ++STATIC int jffs2_lzma_decompress(unsigned char *data_in, unsigned char *cpage_out, ++ uint32_t srclen, uint32_t destlen) ++{ ++ int ret; ++ SizeT dl = (SizeT)destlen; ++ SizeT sl = (SizeT)srclen; ++ ELzmaStatus status; ++ ++ ret = LzmaDecode(cpage_out, &dl, data_in, &sl, propsEncoded, ++ propsSize, LZMA_FINISH_ANY, &status, &lzma_alloc); ++ ++ if (ret != SZ_OK || status == LZMA_STATUS_NOT_FINISHED || dl != (SizeT)destlen) ++ return -1; ++ ++ return 0; ++} ++ ++static struct jffs2_compressor jffs2_lzma_comp = { ++ .priority = JFFS2_LZMA_PRIORITY, ++ .name = "lzma", ++ .compr = JFFS2_COMPR_LZMA, ++ .compress = &jffs2_lzma_compress, ++ .decompress = &jffs2_lzma_decompress, ++ .disabled = 0, ++}; ++ ++int INIT jffs2_lzma_init(void) ++{ ++ int ret; ++ CLzmaEncProps props; ++ LzmaEncProps_Init(&props); ++ ++ props.dictSize = LZMA_BEST_DICT(0x2000); ++ props.level = LZMA_BEST_LEVEL; ++ props.lc = LZMA_BEST_LC; ++ props.lp = LZMA_BEST_LP; ++ props.pb = LZMA_BEST_PB; ++ props.fb = LZMA_BEST_FB; ++ ++ ret = lzma_alloc_workspace(&props); ++ if (ret < 0) ++ return ret; ++ ++ ret = jffs2_register_compressor(&jffs2_lzma_comp); ++ if (ret) ++ lzma_free_workspace(); ++ ++ return ret; ++} ++ ++void jffs2_lzma_exit(void) ++{ ++ jffs2_unregister_compressor(&jffs2_lzma_comp); ++ lzma_free_workspace(); ++} +--- a/fs/jffs2/super.c ++++ b/fs/jffs2/super.c +@@ -375,14 +375,41 @@ static int __init init_jffs2_fs(void) + BUILD_BUG_ON(sizeof(struct jffs2_raw_inode) != 68); + BUILD_BUG_ON(sizeof(struct jffs2_raw_summary) != 32); + +- pr_info("version 2.2." ++ pr_info("version 2.2" + #ifdef CONFIG_JFFS2_FS_WRITEBUFFER + " (NAND)" + #endif + #ifdef CONFIG_JFFS2_SUMMARY +- " (SUMMARY) " ++ " (SUMMARY)" + #endif +- " © 2001-2006 Red Hat, Inc.\n"); ++#ifdef CONFIG_JFFS2_ZLIB ++ " (ZLIB)" ++#endif ++#ifdef CONFIG_JFFS2_LZO ++ " (LZO)" ++#endif ++#ifdef CONFIG_JFFS2_LZMA ++ " (LZMA)" ++#endif ++#ifdef CONFIG_JFFS2_RTIME ++ " (RTIME)" ++#endif ++#ifdef CONFIG_JFFS2_RUBIN ++ " (RUBIN)" ++#endif ++#ifdef CONFIG_JFFS2_CMODE_NONE ++ " (CMODE_NONE)" ++#endif ++#ifdef CONFIG_JFFS2_CMODE_PRIORITY ++ " (CMODE_PRIORITY)" ++#endif ++#ifdef CONFIG_JFFS2_CMODE_SIZE ++ " (CMODE_SIZE)" ++#endif ++#ifdef CONFIG_JFFS2_CMODE_FAVOURLZO ++ " (CMODE_FAVOURLZO)" ++#endif ++ " (c) 2001-2006 Red Hat, Inc.\n"); + + jffs2_inode_cachep = kmem_cache_create("jffs2_i", + sizeof(struct jffs2_inode_info), +--- a/include/uapi/linux/jffs2.h ++++ b/include/uapi/linux/jffs2.h +@@ -46,6 +46,7 @@ + #define JFFS2_COMPR_DYNRUBIN 0x05 + #define JFFS2_COMPR_ZLIB 0x06 + #define JFFS2_COMPR_LZO 0x07 ++#define JFFS2_COMPR_LZMA 0x08 + /* Compatibility flags. */ + #define JFFS2_COMPAT_MASK 0xc000 /* What do to if an unknown nodetype is found */ + #define JFFS2_NODE_ACCURATE 0x2000 +--- /dev/null ++++ b/include/linux/lzma.h +@@ -0,0 +1,62 @@ ++#ifndef __LZMA_H__ ++#define __LZMA_H__ ++ ++#ifdef __KERNEL__ ++ #include ++ #include ++ #include ++ #include ++ #include ++ #define LZMA_MALLOC vmalloc ++ #define LZMA_FREE vfree ++ #define PRINT_ERROR(msg) printk(KERN_WARNING #msg) ++ #define INIT __init ++ #define STATIC static ++#else ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ #ifndef PAGE_SIZE ++ extern int page_size; ++ #define PAGE_SIZE page_size ++ #endif ++ #define LZMA_MALLOC malloc ++ #define LZMA_FREE free ++ #define PRINT_ERROR(msg) fprintf(stderr, msg) ++ #define INIT ++ #define STATIC ++#endif ++ ++#include "lzma/LzmaDec.h" ++#include "lzma/LzmaEnc.h" ++ ++#define LZMA_BEST_LEVEL (9) ++#define LZMA_BEST_LC (0) ++#define LZMA_BEST_LP (0) ++#define LZMA_BEST_PB (0) ++#define LZMA_BEST_FB (273) ++ ++#define LZMA_BEST_DICT(n) (((int)((n) / 2)) * 2) ++ ++static void *p_lzma_malloc(void *p, size_t size) ++{ ++ if (size == 0) ++ return NULL; ++ ++ return LZMA_MALLOC(size); ++} ++ ++static void p_lzma_free(void *p, void *address) ++{ ++ if (address != NULL) ++ LZMA_FREE(address); ++} ++ ++static ISzAlloc lzma_alloc = {p_lzma_malloc, p_lzma_free}; ++ ++#endif +--- /dev/null ++++ b/include/linux/lzma/LzFind.h +@@ -0,0 +1,115 @@ ++/* LzFind.h -- Match finder for LZ algorithms ++2009-04-22 : Igor Pavlov : Public domain */ ++ ++#ifndef __LZ_FIND_H ++#define __LZ_FIND_H ++ ++#include "Types.h" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++typedef UInt32 CLzRef; ++ ++typedef struct _CMatchFinder ++{ ++ Byte *buffer; ++ UInt32 pos; ++ UInt32 posLimit; ++ UInt32 streamPos; ++ UInt32 lenLimit; ++ ++ UInt32 cyclicBufferPos; ++ UInt32 cyclicBufferSize; /* it must be = (historySize + 1) */ ++ ++ UInt32 matchMaxLen; ++ CLzRef *hash; ++ CLzRef *son; ++ UInt32 hashMask; ++ UInt32 cutValue; ++ ++ Byte *bufferBase; ++ ISeqInStream *stream; ++ int streamEndWasReached; ++ ++ UInt32 blockSize; ++ UInt32 keepSizeBefore; ++ UInt32 keepSizeAfter; ++ ++ UInt32 numHashBytes; ++ int directInput; ++ size_t directInputRem; ++ int btMode; ++ int bigHash; ++ UInt32 historySize; ++ UInt32 fixedHashSize; ++ UInt32 hashSizeSum; ++ UInt32 numSons; ++ SRes result; ++ UInt32 crc[256]; ++} CMatchFinder; ++ ++#define Inline_MatchFinder_GetPointerToCurrentPos(p) ((p)->buffer) ++#define Inline_MatchFinder_GetIndexByte(p, index) ((p)->buffer[(Int32)(index)]) ++ ++#define Inline_MatchFinder_GetNumAvailableBytes(p) ((p)->streamPos - (p)->pos) ++ ++int MatchFinder_NeedMove(CMatchFinder *p); ++Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p); ++void MatchFinder_MoveBlock(CMatchFinder *p); ++void MatchFinder_ReadIfRequired(CMatchFinder *p); ++ ++void MatchFinder_Construct(CMatchFinder *p); ++ ++/* Conditions: ++ historySize <= 3 GB ++ keepAddBufferBefore + matchMaxLen + keepAddBufferAfter < 511MB ++*/ ++int MatchFinder_Create(CMatchFinder *p, UInt32 historySize, ++ UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ++ ISzAlloc *alloc); ++void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc); ++void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems); ++void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue); ++ ++UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *buffer, CLzRef *son, ++ UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue, ++ UInt32 *distances, UInt32 maxLen); ++ ++/* ++Conditions: ++ Mf_GetNumAvailableBytes_Func must be called before each Mf_GetMatchLen_Func. ++ Mf_GetPointerToCurrentPos_Func's result must be used only before any other function ++*/ ++ ++typedef void (*Mf_Init_Func)(void *object); ++typedef Byte (*Mf_GetIndexByte_Func)(void *object, Int32 index); ++typedef UInt32 (*Mf_GetNumAvailableBytes_Func)(void *object); ++typedef const Byte * (*Mf_GetPointerToCurrentPos_Func)(void *object); ++typedef UInt32 (*Mf_GetMatches_Func)(void *object, UInt32 *distances); ++typedef void (*Mf_Skip_Func)(void *object, UInt32); ++ ++typedef struct _IMatchFinder ++{ ++ Mf_Init_Func Init; ++ Mf_GetIndexByte_Func GetIndexByte; ++ Mf_GetNumAvailableBytes_Func GetNumAvailableBytes; ++ Mf_GetPointerToCurrentPos_Func GetPointerToCurrentPos; ++ Mf_GetMatches_Func GetMatches; ++ Mf_Skip_Func Skip; ++} IMatchFinder; ++ ++void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable); ++ ++void MatchFinder_Init(CMatchFinder *p); ++UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances); ++UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances); ++void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num); ++void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif +--- /dev/null ++++ b/include/linux/lzma/LzHash.h +@@ -0,0 +1,54 @@ ++/* LzHash.h -- HASH functions for LZ algorithms ++2009-02-07 : Igor Pavlov : Public domain */ ++ ++#ifndef __LZ_HASH_H ++#define __LZ_HASH_H ++ ++#define kHash2Size (1 << 10) ++#define kHash3Size (1 << 16) ++#define kHash4Size (1 << 20) ++ ++#define kFix3HashSize (kHash2Size) ++#define kFix4HashSize (kHash2Size + kHash3Size) ++#define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size) ++ ++#define HASH2_CALC hashValue = cur[0] | ((UInt32)cur[1] << 8); ++ ++#define HASH3_CALC { \ ++ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ ++ hash2Value = temp & (kHash2Size - 1); \ ++ hashValue = (temp ^ ((UInt32)cur[2] << 8)) & p->hashMask; } ++ ++#define HASH4_CALC { \ ++ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ ++ hash2Value = temp & (kHash2Size - 1); \ ++ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \ ++ hashValue = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & p->hashMask; } ++ ++#define HASH5_CALC { \ ++ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ ++ hash2Value = temp & (kHash2Size - 1); \ ++ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \ ++ hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)); \ ++ hashValue = (hash4Value ^ (p->crc[cur[4]] << 3)) & p->hashMask; \ ++ hash4Value &= (kHash4Size - 1); } ++ ++/* #define HASH_ZIP_CALC hashValue = ((cur[0] | ((UInt32)cur[1] << 8)) ^ p->crc[cur[2]]) & 0xFFFF; */ ++#define HASH_ZIP_CALC hashValue = ((cur[2] | ((UInt32)cur[0] << 8)) ^ p->crc[cur[1]]) & 0xFFFF; ++ ++ ++#define MT_HASH2_CALC \ ++ hash2Value = (p->crc[cur[0]] ^ cur[1]) & (kHash2Size - 1); ++ ++#define MT_HASH3_CALC { \ ++ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ ++ hash2Value = temp & (kHash2Size - 1); \ ++ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); } ++ ++#define MT_HASH4_CALC { \ ++ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ ++ hash2Value = temp & (kHash2Size - 1); \ ++ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \ ++ hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & (kHash4Size - 1); } ++ ++#endif +--- /dev/null ++++ b/include/linux/lzma/LzmaDec.h +@@ -0,0 +1,231 @@ ++/* LzmaDec.h -- LZMA Decoder ++2009-02-07 : Igor Pavlov : Public domain */ ++ ++#ifndef __LZMA_DEC_H ++#define __LZMA_DEC_H ++ ++#include "Types.h" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/* #define _LZMA_PROB32 */ ++/* _LZMA_PROB32 can increase the speed on some CPUs, ++ but memory usage for CLzmaDec::probs will be doubled in that case */ ++ ++#ifdef _LZMA_PROB32 ++#define CLzmaProb UInt32 ++#else ++#define CLzmaProb UInt16 ++#endif ++ ++ ++/* ---------- LZMA Properties ---------- */ ++ ++#define LZMA_PROPS_SIZE 5 ++ ++typedef struct _CLzmaProps ++{ ++ unsigned lc, lp, pb; ++ UInt32 dicSize; ++} CLzmaProps; ++ ++/* LzmaProps_Decode - decodes properties ++Returns: ++ SZ_OK ++ SZ_ERROR_UNSUPPORTED - Unsupported properties ++*/ ++ ++SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size); ++ ++ ++/* ---------- LZMA Decoder state ---------- */ ++ ++/* LZMA_REQUIRED_INPUT_MAX = number of required input bytes for worst case. ++ Num bits = log2((2^11 / 31) ^ 22) + 26 < 134 + 26 = 160; */ ++ ++#define LZMA_REQUIRED_INPUT_MAX 20 ++ ++typedef struct ++{ ++ CLzmaProps prop; ++ CLzmaProb *probs; ++ Byte *dic; ++ const Byte *buf; ++ UInt32 range, code; ++ SizeT dicPos; ++ SizeT dicBufSize; ++ UInt32 processedPos; ++ UInt32 checkDicSize; ++ unsigned state; ++ UInt32 reps[4]; ++ unsigned remainLen; ++ int needFlush; ++ int needInitState; ++ UInt32 numProbs; ++ unsigned tempBufSize; ++ Byte tempBuf[LZMA_REQUIRED_INPUT_MAX]; ++} CLzmaDec; ++ ++#define LzmaDec_Construct(p) { (p)->dic = 0; (p)->probs = 0; } ++ ++void LzmaDec_Init(CLzmaDec *p); ++ ++/* There are two types of LZMA streams: ++ 0) Stream with end mark. That end mark adds about 6 bytes to compressed size. ++ 1) Stream without end mark. You must know exact uncompressed size to decompress such stream. */ ++ ++typedef enum ++{ ++ LZMA_FINISH_ANY, /* finish at any point */ ++ LZMA_FINISH_END /* block must be finished at the end */ ++} ELzmaFinishMode; ++ ++/* ELzmaFinishMode has meaning only if the decoding reaches output limit !!! ++ ++ You must use LZMA_FINISH_END, when you know that current output buffer ++ covers last bytes of block. In other cases you must use LZMA_FINISH_ANY. ++ ++ If LZMA decoder sees end marker before reaching output limit, it returns SZ_OK, ++ and output value of destLen will be less than output buffer size limit. ++ You can check status result also. ++ ++ You can use multiple checks to test data integrity after full decompression: ++ 1) Check Result and "status" variable. ++ 2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize. ++ 3) Check that output(srcLen) = compressedSize, if you know real compressedSize. ++ You must use correct finish mode in that case. */ ++ ++typedef enum ++{ ++ LZMA_STATUS_NOT_SPECIFIED, /* use main error code instead */ ++ LZMA_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */ ++ LZMA_STATUS_NOT_FINISHED, /* stream was not finished */ ++ LZMA_STATUS_NEEDS_MORE_INPUT, /* you must provide more input bytes */ ++ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK /* there is probability that stream was finished without end mark */ ++} ELzmaStatus; ++ ++/* ELzmaStatus is used only as output value for function call */ ++ ++ ++/* ---------- Interfaces ---------- */ ++ ++/* There are 3 levels of interfaces: ++ 1) Dictionary Interface ++ 2) Buffer Interface ++ 3) One Call Interface ++ You can select any of these interfaces, but don't mix functions from different ++ groups for same object. */ ++ ++ ++/* There are two variants to allocate state for Dictionary Interface: ++ 1) LzmaDec_Allocate / LzmaDec_Free ++ 2) LzmaDec_AllocateProbs / LzmaDec_FreeProbs ++ You can use variant 2, if you set dictionary buffer manually. ++ For Buffer Interface you must always use variant 1. ++ ++LzmaDec_Allocate* can return: ++ SZ_OK ++ SZ_ERROR_MEM - Memory allocation error ++ SZ_ERROR_UNSUPPORTED - Unsupported properties ++*/ ++ ++SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc); ++void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc); ++ ++SRes LzmaDec_Allocate(CLzmaDec *state, const Byte *prop, unsigned propsSize, ISzAlloc *alloc); ++void LzmaDec_Free(CLzmaDec *state, ISzAlloc *alloc); ++ ++/* ---------- Dictionary Interface ---------- */ ++ ++/* You can use it, if you want to eliminate the overhead for data copying from ++ dictionary to some other external buffer. ++ You must work with CLzmaDec variables directly in this interface. ++ ++ STEPS: ++ LzmaDec_Constr() ++ LzmaDec_Allocate() ++ for (each new stream) ++ { ++ LzmaDec_Init() ++ while (it needs more decompression) ++ { ++ LzmaDec_DecodeToDic() ++ use data from CLzmaDec::dic and update CLzmaDec::dicPos ++ } ++ } ++ LzmaDec_Free() ++*/ ++ ++/* LzmaDec_DecodeToDic ++ ++ The decoding to internal dictionary buffer (CLzmaDec::dic). ++ You must manually update CLzmaDec::dicPos, if it reaches CLzmaDec::dicBufSize !!! ++ ++finishMode: ++ It has meaning only if the decoding reaches output limit (dicLimit). ++ LZMA_FINISH_ANY - Decode just dicLimit bytes. ++ LZMA_FINISH_END - Stream must be finished after dicLimit. ++ ++Returns: ++ SZ_OK ++ status: ++ LZMA_STATUS_FINISHED_WITH_MARK ++ LZMA_STATUS_NOT_FINISHED ++ LZMA_STATUS_NEEDS_MORE_INPUT ++ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK ++ SZ_ERROR_DATA - Data error ++*/ ++ ++SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, ++ const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); ++ ++ ++/* ---------- Buffer Interface ---------- */ ++ ++/* It's zlib-like interface. ++ See LzmaDec_DecodeToDic description for information about STEPS and return results, ++ but you must use LzmaDec_DecodeToBuf instead of LzmaDec_DecodeToDic and you don't need ++ to work with CLzmaDec variables manually. ++ ++finishMode: ++ It has meaning only if the decoding reaches output limit (*destLen). ++ LZMA_FINISH_ANY - Decode just destLen bytes. ++ LZMA_FINISH_END - Stream must be finished after (*destLen). ++*/ ++ ++SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, ++ const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); ++ ++ ++/* ---------- One Call Interface ---------- */ ++ ++/* LzmaDecode ++ ++finishMode: ++ It has meaning only if the decoding reaches output limit (*destLen). ++ LZMA_FINISH_ANY - Decode just destLen bytes. ++ LZMA_FINISH_END - Stream must be finished after (*destLen). ++ ++Returns: ++ SZ_OK ++ status: ++ LZMA_STATUS_FINISHED_WITH_MARK ++ LZMA_STATUS_NOT_FINISHED ++ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK ++ SZ_ERROR_DATA - Data error ++ SZ_ERROR_MEM - Memory allocation error ++ SZ_ERROR_UNSUPPORTED - Unsupported properties ++ SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src). ++*/ ++ ++SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ++ const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, ++ ELzmaStatus *status, ISzAlloc *alloc); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif +--- /dev/null ++++ b/include/linux/lzma/LzmaEnc.h +@@ -0,0 +1,80 @@ ++/* LzmaEnc.h -- LZMA Encoder ++2009-02-07 : Igor Pavlov : Public domain */ ++ ++#ifndef __LZMA_ENC_H ++#define __LZMA_ENC_H ++ ++#include "Types.h" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++#define LZMA_PROPS_SIZE 5 ++ ++typedef struct _CLzmaEncProps ++{ ++ int level; /* 0 <= level <= 9 */ ++ UInt32 dictSize; /* (1 << 12) <= dictSize <= (1 << 27) for 32-bit version ++ (1 << 12) <= dictSize <= (1 << 30) for 64-bit version ++ default = (1 << 24) */ ++ int lc; /* 0 <= lc <= 8, default = 3 */ ++ int lp; /* 0 <= lp <= 4, default = 0 */ ++ int pb; /* 0 <= pb <= 4, default = 2 */ ++ int algo; /* 0 - fast, 1 - normal, default = 1 */ ++ int fb; /* 5 <= fb <= 273, default = 32 */ ++ int btMode; /* 0 - hashChain Mode, 1 - binTree mode - normal, default = 1 */ ++ int numHashBytes; /* 2, 3 or 4, default = 4 */ ++ UInt32 mc; /* 1 <= mc <= (1 << 30), default = 32 */ ++ unsigned writeEndMark; /* 0 - do not write EOPM, 1 - write EOPM, default = 0 */ ++ int numThreads; /* 1 or 2, default = 2 */ ++} CLzmaEncProps; ++ ++void LzmaEncProps_Init(CLzmaEncProps *p); ++void LzmaEncProps_Normalize(CLzmaEncProps *p); ++UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2); ++ ++ ++/* ---------- CLzmaEncHandle Interface ---------- */ ++ ++/* LzmaEnc_* functions can return the following exit codes: ++Returns: ++ SZ_OK - OK ++ SZ_ERROR_MEM - Memory allocation error ++ SZ_ERROR_PARAM - Incorrect paramater in props ++ SZ_ERROR_WRITE - Write callback error. ++ SZ_ERROR_PROGRESS - some break from progress callback ++ SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version) ++*/ ++ ++typedef void * CLzmaEncHandle; ++ ++CLzmaEncHandle LzmaEnc_Create(ISzAlloc *alloc); ++void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAlloc *alloc, ISzAlloc *allocBig); ++SRes LzmaEnc_SetProps(CLzmaEncHandle p, const CLzmaEncProps *props); ++SRes LzmaEnc_WriteProperties(CLzmaEncHandle p, Byte *properties, SizeT *size); ++SRes LzmaEnc_Encode(CLzmaEncHandle p, ISeqOutStream *outStream, ISeqInStream *inStream, ++ ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig); ++SRes LzmaEnc_MemEncode(CLzmaEncHandle p, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, ++ int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig); ++ ++/* ---------- One Call Interface ---------- */ ++ ++/* LzmaEncode ++Return code: ++ SZ_OK - OK ++ SZ_ERROR_MEM - Memory allocation error ++ SZ_ERROR_PARAM - Incorrect paramater ++ SZ_ERROR_OUTPUT_EOF - output buffer overflow ++ SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version) ++*/ ++ ++SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, ++ const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark, ++ ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif +--- /dev/null ++++ b/include/linux/lzma/Types.h +@@ -0,0 +1,226 @@ ++/* Types.h -- Basic types ++2009-11-23 : Igor Pavlov : Public domain */ ++ ++#ifndef __7Z_TYPES_H ++#define __7Z_TYPES_H ++ ++#include ++ ++#ifdef _WIN32 ++#include ++#endif ++ ++#ifndef EXTERN_C_BEGIN ++#ifdef __cplusplus ++#define EXTERN_C_BEGIN extern "C" { ++#define EXTERN_C_END } ++#else ++#define EXTERN_C_BEGIN ++#define EXTERN_C_END ++#endif ++#endif ++ ++EXTERN_C_BEGIN ++ ++#define SZ_OK 0 ++ ++#define SZ_ERROR_DATA 1 ++#define SZ_ERROR_MEM 2 ++#define SZ_ERROR_CRC 3 ++#define SZ_ERROR_UNSUPPORTED 4 ++#define SZ_ERROR_PARAM 5 ++#define SZ_ERROR_INPUT_EOF 6 ++#define SZ_ERROR_OUTPUT_EOF 7 ++#define SZ_ERROR_READ 8 ++#define SZ_ERROR_WRITE 9 ++#define SZ_ERROR_PROGRESS 10 ++#define SZ_ERROR_FAIL 11 ++#define SZ_ERROR_THREAD 12 ++ ++#define SZ_ERROR_ARCHIVE 16 ++#define SZ_ERROR_NO_ARCHIVE 17 ++ ++typedef int SRes; ++ ++#ifdef _WIN32 ++typedef DWORD WRes; ++#else ++typedef int WRes; ++#endif ++ ++#ifndef RINOK ++#define RINOK(x) { int __result__ = (x); if (__result__ != 0) return __result__; } ++#endif ++ ++typedef unsigned char Byte; ++typedef short Int16; ++typedef unsigned short UInt16; ++ ++#ifdef _LZMA_UINT32_IS_ULONG ++typedef long Int32; ++typedef unsigned long UInt32; ++#else ++typedef int Int32; ++typedef unsigned int UInt32; ++#endif ++ ++#ifdef _SZ_NO_INT_64 ++ ++/* define _SZ_NO_INT_64, if your compiler doesn't support 64-bit integers. ++ NOTES: Some code will work incorrectly in that case! */ ++ ++typedef long Int64; ++typedef unsigned long UInt64; ++ ++#else ++ ++#if defined(_MSC_VER) || defined(__BORLANDC__) ++typedef __int64 Int64; ++typedef unsigned __int64 UInt64; ++#else ++typedef long long int Int64; ++typedef unsigned long long int UInt64; ++#endif ++ ++#endif ++ ++#ifdef _LZMA_NO_SYSTEM_SIZE_T ++typedef UInt32 SizeT; ++#else ++typedef size_t SizeT; ++#endif ++ ++typedef int Bool; ++#define True 1 ++#define False 0 ++ ++ ++#ifdef _WIN32 ++#define MY_STD_CALL __stdcall ++#else ++#define MY_STD_CALL ++#endif ++ ++#ifdef _MSC_VER ++ ++#if _MSC_VER >= 1300 ++#define MY_NO_INLINE __declspec(noinline) ++#else ++#define MY_NO_INLINE ++#endif ++ ++#define MY_CDECL __cdecl ++#define MY_FAST_CALL __fastcall ++ ++#else ++ ++#define MY_CDECL ++#define MY_FAST_CALL ++ ++#endif ++ ++ ++/* The following interfaces use first parameter as pointer to structure */ ++ ++typedef struct ++{ ++ SRes (*Read)(void *p, void *buf, size_t *size); ++ /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. ++ (output(*size) < input(*size)) is allowed */ ++} ISeqInStream; ++ ++/* it can return SZ_ERROR_INPUT_EOF */ ++SRes SeqInStream_Read(ISeqInStream *stream, void *buf, size_t size); ++SRes SeqInStream_Read2(ISeqInStream *stream, void *buf, size_t size, SRes errorType); ++SRes SeqInStream_ReadByte(ISeqInStream *stream, Byte *buf); ++ ++typedef struct ++{ ++ size_t (*Write)(void *p, const void *buf, size_t size); ++ /* Returns: result - the number of actually written bytes. ++ (result < size) means error */ ++} ISeqOutStream; ++ ++typedef enum ++{ ++ SZ_SEEK_SET = 0, ++ SZ_SEEK_CUR = 1, ++ SZ_SEEK_END = 2 ++} ESzSeek; ++ ++typedef struct ++{ ++ SRes (*Read)(void *p, void *buf, size_t *size); /* same as ISeqInStream::Read */ ++ SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin); ++} ISeekInStream; ++ ++typedef struct ++{ ++ SRes (*Look)(void *p, void **buf, size_t *size); ++ /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. ++ (output(*size) > input(*size)) is not allowed ++ (output(*size) < input(*size)) is allowed */ ++ SRes (*Skip)(void *p, size_t offset); ++ /* offset must be <= output(*size) of Look */ ++ ++ SRes (*Read)(void *p, void *buf, size_t *size); ++ /* reads directly (without buffer). It's same as ISeqInStream::Read */ ++ SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin); ++} ILookInStream; ++ ++SRes LookInStream_LookRead(ILookInStream *stream, void *buf, size_t *size); ++SRes LookInStream_SeekTo(ILookInStream *stream, UInt64 offset); ++ ++/* reads via ILookInStream::Read */ ++SRes LookInStream_Read2(ILookInStream *stream, void *buf, size_t size, SRes errorType); ++SRes LookInStream_Read(ILookInStream *stream, void *buf, size_t size); ++ ++#define LookToRead_BUF_SIZE (1 << 14) ++ ++typedef struct ++{ ++ ILookInStream s; ++ ISeekInStream *realStream; ++ size_t pos; ++ size_t size; ++ Byte buf[LookToRead_BUF_SIZE]; ++} CLookToRead; ++ ++void LookToRead_CreateVTable(CLookToRead *p, int lookahead); ++void LookToRead_Init(CLookToRead *p); ++ ++typedef struct ++{ ++ ISeqInStream s; ++ ILookInStream *realStream; ++} CSecToLook; ++ ++void SecToLook_CreateVTable(CSecToLook *p); ++ ++typedef struct ++{ ++ ISeqInStream s; ++ ILookInStream *realStream; ++} CSecToRead; ++ ++void SecToRead_CreateVTable(CSecToRead *p); ++ ++typedef struct ++{ ++ SRes (*Progress)(void *p, UInt64 inSize, UInt64 outSize); ++ /* Returns: result. (result != SZ_OK) means break. ++ Value (UInt64)(Int64)-1 for size means unknown value. */ ++} ICompressProgress; ++ ++typedef struct ++{ ++ void *(*Alloc)(void *p, size_t size); ++ void (*Free)(void *p, void *address); /* address can be 0 */ ++} ISzAlloc; ++ ++#define IAlloc_Alloc(p, size) (p)->Alloc((p), size) ++#define IAlloc_Free(p, a) (p)->Free((p), a) ++ ++EXTERN_C_END ++ ++#endif +--- a/lib/Kconfig ++++ b/lib/Kconfig +@@ -235,6 +235,12 @@ config LZ4_DECOMPRESS + + source "lib/xz/Kconfig" + ++config LZMA_COMPRESS ++ tristate ++ ++config LZMA_DECOMPRESS ++ tristate ++ + # + # These all provide a common interface (hence the apparent duplication with + # ZLIB_INFLATE; DECOMPRESS_GZIP is just a wrapper.) +--- a/lib/Makefile ++++ b/lib/Makefile +@@ -2,6 +2,16 @@ + # Makefile for some libs needed in the kernel. + # + ++ifdef CONFIG_JFFS2_ZLIB ++ CONFIG_ZLIB_INFLATE:=y ++ CONFIG_ZLIB_DEFLATE:=y ++endif ++ ++ifdef CONFIG_JFFS2_LZMA ++ CONFIG_LZMA_DECOMPRESS:=y ++ CONFIG_LZMA_COMPRESS:=y ++endif ++ + ifdef CONFIG_FUNCTION_TRACER + ORIG_CFLAGS := $(KBUILD_CFLAGS) + KBUILD_CFLAGS = $(subst $(CC_FLAGS_FTRACE),,$(ORIG_CFLAGS)) +@@ -89,6 +99,8 @@ obj-$(CONFIG_LZ4HC_COMPRESS) += lz4/ + obj-$(CONFIG_LZ4_DECOMPRESS) += lz4/ + obj-$(CONFIG_XZ_DEC) += xz/ + obj-$(CONFIG_RAID6_PQ) += raid6/ ++obj-$(CONFIG_LZMA_COMPRESS) += lzma/ ++obj-$(CONFIG_LZMA_DECOMPRESS) += lzma/ + + lib-$(CONFIG_DECOMPRESS_GZIP) += decompress_inflate.o + lib-$(CONFIG_DECOMPRESS_BZIP2) += decompress_bunzip2.o +--- /dev/null ++++ b/lib/lzma/LzFind.c +@@ -0,0 +1,761 @@ ++/* LzFind.c -- Match finder for LZ algorithms ++2009-04-22 : Igor Pavlov : Public domain */ ++ ++#include ++ ++#include "LzFind.h" ++#include "LzHash.h" ++ ++#define kEmptyHashValue 0 ++#define kMaxValForNormalize ((UInt32)0xFFFFFFFF) ++#define kNormalizeStepMin (1 << 10) /* it must be power of 2 */ ++#define kNormalizeMask (~(kNormalizeStepMin - 1)) ++#define kMaxHistorySize ((UInt32)3 << 30) ++ ++#define kStartMaxLen 3 ++ ++static void LzInWindow_Free(CMatchFinder *p, ISzAlloc *alloc) ++{ ++ if (!p->directInput) ++ { ++ alloc->Free(alloc, p->bufferBase); ++ p->bufferBase = 0; ++ } ++} ++ ++/* keepSizeBefore + keepSizeAfter + keepSizeReserv must be < 4G) */ ++ ++static int LzInWindow_Create(CMatchFinder *p, UInt32 keepSizeReserv, ISzAlloc *alloc) ++{ ++ UInt32 blockSize = p->keepSizeBefore + p->keepSizeAfter + keepSizeReserv; ++ if (p->directInput) ++ { ++ p->blockSize = blockSize; ++ return 1; ++ } ++ if (p->bufferBase == 0 || p->blockSize != blockSize) ++ { ++ LzInWindow_Free(p, alloc); ++ p->blockSize = blockSize; ++ p->bufferBase = (Byte *)alloc->Alloc(alloc, (size_t)blockSize); ++ } ++ return (p->bufferBase != 0); ++} ++ ++Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; } ++Byte MatchFinder_GetIndexByte(CMatchFinder *p, Int32 index) { return p->buffer[index]; } ++ ++UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return p->streamPos - p->pos; } ++ ++void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue) ++{ ++ p->posLimit -= subValue; ++ p->pos -= subValue; ++ p->streamPos -= subValue; ++} ++ ++static void MatchFinder_ReadBlock(CMatchFinder *p) ++{ ++ if (p->streamEndWasReached || p->result != SZ_OK) ++ return; ++ if (p->directInput) ++ { ++ UInt32 curSize = 0xFFFFFFFF - p->streamPos; ++ if (curSize > p->directInputRem) ++ curSize = (UInt32)p->directInputRem; ++ p->directInputRem -= curSize; ++ p->streamPos += curSize; ++ if (p->directInputRem == 0) ++ p->streamEndWasReached = 1; ++ return; ++ } ++ for (;;) ++ { ++ Byte *dest = p->buffer + (p->streamPos - p->pos); ++ size_t size = (p->bufferBase + p->blockSize - dest); ++ if (size == 0) ++ return; ++ p->result = p->stream->Read(p->stream, dest, &size); ++ if (p->result != SZ_OK) ++ return; ++ if (size == 0) ++ { ++ p->streamEndWasReached = 1; ++ return; ++ } ++ p->streamPos += (UInt32)size; ++ if (p->streamPos - p->pos > p->keepSizeAfter) ++ return; ++ } ++} ++ ++void MatchFinder_MoveBlock(CMatchFinder *p) ++{ ++ memmove(p->bufferBase, ++ p->buffer - p->keepSizeBefore, ++ (size_t)(p->streamPos - p->pos + p->keepSizeBefore)); ++ p->buffer = p->bufferBase + p->keepSizeBefore; ++} ++ ++int MatchFinder_NeedMove(CMatchFinder *p) ++{ ++ if (p->directInput) ++ return 0; ++ /* if (p->streamEndWasReached) return 0; */ ++ return ((size_t)(p->bufferBase + p->blockSize - p->buffer) <= p->keepSizeAfter); ++} ++ ++void MatchFinder_ReadIfRequired(CMatchFinder *p) ++{ ++ if (p->streamEndWasReached) ++ return; ++ if (p->keepSizeAfter >= p->streamPos - p->pos) ++ MatchFinder_ReadBlock(p); ++} ++ ++static void MatchFinder_CheckAndMoveAndRead(CMatchFinder *p) ++{ ++ if (MatchFinder_NeedMove(p)) ++ MatchFinder_MoveBlock(p); ++ MatchFinder_ReadBlock(p); ++} ++ ++static void MatchFinder_SetDefaultSettings(CMatchFinder *p) ++{ ++ p->cutValue = 32; ++ p->btMode = 1; ++ p->numHashBytes = 4; ++ p->bigHash = 0; ++} ++ ++#define kCrcPoly 0xEDB88320 ++ ++void MatchFinder_Construct(CMatchFinder *p) ++{ ++ UInt32 i; ++ p->bufferBase = 0; ++ p->directInput = 0; ++ p->hash = 0; ++ MatchFinder_SetDefaultSettings(p); ++ ++ for (i = 0; i < 256; i++) ++ { ++ UInt32 r = i; ++ int j; ++ for (j = 0; j < 8; j++) ++ r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1)); ++ p->crc[i] = r; ++ } ++} ++ ++static void MatchFinder_FreeThisClassMemory(CMatchFinder *p, ISzAlloc *alloc) ++{ ++ alloc->Free(alloc, p->hash); ++ p->hash = 0; ++} ++ ++void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc) ++{ ++ MatchFinder_FreeThisClassMemory(p, alloc); ++ LzInWindow_Free(p, alloc); ++} ++ ++static CLzRef* AllocRefs(UInt32 num, ISzAlloc *alloc) ++{ ++ size_t sizeInBytes = (size_t)num * sizeof(CLzRef); ++ if (sizeInBytes / sizeof(CLzRef) != num) ++ return 0; ++ return (CLzRef *)alloc->Alloc(alloc, sizeInBytes); ++} ++ ++int MatchFinder_Create(CMatchFinder *p, UInt32 historySize, ++ UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ++ ISzAlloc *alloc) ++{ ++ UInt32 sizeReserv; ++ if (historySize > kMaxHistorySize) ++ { ++ MatchFinder_Free(p, alloc); ++ return 0; ++ } ++ sizeReserv = historySize >> 1; ++ if (historySize > ((UInt32)2 << 30)) ++ sizeReserv = historySize >> 2; ++ sizeReserv += (keepAddBufferBefore + matchMaxLen + keepAddBufferAfter) / 2 + (1 << 19); ++ ++ p->keepSizeBefore = historySize + keepAddBufferBefore + 1; ++ p->keepSizeAfter = matchMaxLen + keepAddBufferAfter; ++ /* we need one additional byte, since we use MoveBlock after pos++ and before dictionary using */ ++ if (LzInWindow_Create(p, sizeReserv, alloc)) ++ { ++ UInt32 newCyclicBufferSize = historySize + 1; ++ UInt32 hs; ++ p->matchMaxLen = matchMaxLen; ++ { ++ p->fixedHashSize = 0; ++ if (p->numHashBytes == 2) ++ hs = (1 << 16) - 1; ++ else ++ { ++ hs = historySize - 1; ++ hs |= (hs >> 1); ++ hs |= (hs >> 2); ++ hs |= (hs >> 4); ++ hs |= (hs >> 8); ++ hs >>= 1; ++ hs |= 0xFFFF; /* don't change it! It's required for Deflate */ ++ if (hs > (1 << 24)) ++ { ++ if (p->numHashBytes == 3) ++ hs = (1 << 24) - 1; ++ else ++ hs >>= 1; ++ } ++ } ++ p->hashMask = hs; ++ hs++; ++ if (p->numHashBytes > 2) p->fixedHashSize += kHash2Size; ++ if (p->numHashBytes > 3) p->fixedHashSize += kHash3Size; ++ if (p->numHashBytes > 4) p->fixedHashSize += kHash4Size; ++ hs += p->fixedHashSize; ++ } ++ ++ { ++ UInt32 prevSize = p->hashSizeSum + p->numSons; ++ UInt32 newSize; ++ p->historySize = historySize; ++ p->hashSizeSum = hs; ++ p->cyclicBufferSize = newCyclicBufferSize; ++ p->numSons = (p->btMode ? newCyclicBufferSize * 2 : newCyclicBufferSize); ++ newSize = p->hashSizeSum + p->numSons; ++ if (p->hash != 0 && prevSize == newSize) ++ return 1; ++ MatchFinder_FreeThisClassMemory(p, alloc); ++ p->hash = AllocRefs(newSize, alloc); ++ if (p->hash != 0) ++ { ++ p->son = p->hash + p->hashSizeSum; ++ return 1; ++ } ++ } ++ } ++ MatchFinder_Free(p, alloc); ++ return 0; ++} ++ ++static void MatchFinder_SetLimits(CMatchFinder *p) ++{ ++ UInt32 limit = kMaxValForNormalize - p->pos; ++ UInt32 limit2 = p->cyclicBufferSize - p->cyclicBufferPos; ++ if (limit2 < limit) ++ limit = limit2; ++ limit2 = p->streamPos - p->pos; ++ if (limit2 <= p->keepSizeAfter) ++ { ++ if (limit2 > 0) ++ limit2 = 1; ++ } ++ else ++ limit2 -= p->keepSizeAfter; ++ if (limit2 < limit) ++ limit = limit2; ++ { ++ UInt32 lenLimit = p->streamPos - p->pos; ++ if (lenLimit > p->matchMaxLen) ++ lenLimit = p->matchMaxLen; ++ p->lenLimit = lenLimit; ++ } ++ p->posLimit = p->pos + limit; ++} ++ ++void MatchFinder_Init(CMatchFinder *p) ++{ ++ UInt32 i; ++ for (i = 0; i < p->hashSizeSum; i++) ++ p->hash[i] = kEmptyHashValue; ++ p->cyclicBufferPos = 0; ++ p->buffer = p->bufferBase; ++ p->pos = p->streamPos = p->cyclicBufferSize; ++ p->result = SZ_OK; ++ p->streamEndWasReached = 0; ++ MatchFinder_ReadBlock(p); ++ MatchFinder_SetLimits(p); ++} ++ ++static UInt32 MatchFinder_GetSubValue(CMatchFinder *p) ++{ ++ return (p->pos - p->historySize - 1) & kNormalizeMask; ++} ++ ++void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems) ++{ ++ UInt32 i; ++ for (i = 0; i < numItems; i++) ++ { ++ UInt32 value = items[i]; ++ if (value <= subValue) ++ value = kEmptyHashValue; ++ else ++ value -= subValue; ++ items[i] = value; ++ } ++} ++ ++static void MatchFinder_Normalize(CMatchFinder *p) ++{ ++ UInt32 subValue = MatchFinder_GetSubValue(p); ++ MatchFinder_Normalize3(subValue, p->hash, p->hashSizeSum + p->numSons); ++ MatchFinder_ReduceOffsets(p, subValue); ++} ++ ++static void MatchFinder_CheckLimits(CMatchFinder *p) ++{ ++ if (p->pos == kMaxValForNormalize) ++ MatchFinder_Normalize(p); ++ if (!p->streamEndWasReached && p->keepSizeAfter == p->streamPos - p->pos) ++ MatchFinder_CheckAndMoveAndRead(p); ++ if (p->cyclicBufferPos == p->cyclicBufferSize) ++ p->cyclicBufferPos = 0; ++ MatchFinder_SetLimits(p); ++} ++ ++static UInt32 * Hc_GetMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, ++ UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue, ++ UInt32 *distances, UInt32 maxLen) ++{ ++ son[_cyclicBufferPos] = curMatch; ++ for (;;) ++ { ++ UInt32 delta = pos - curMatch; ++ if (cutValue-- == 0 || delta >= _cyclicBufferSize) ++ return distances; ++ { ++ const Byte *pb = cur - delta; ++ curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)]; ++ if (pb[maxLen] == cur[maxLen] && *pb == *cur) ++ { ++ UInt32 len = 0; ++ while (++len != lenLimit) ++ if (pb[len] != cur[len]) ++ break; ++ if (maxLen < len) ++ { ++ *distances++ = maxLen = len; ++ *distances++ = delta - 1; ++ if (len == lenLimit) ++ return distances; ++ } ++ } ++ } ++ } ++} ++ ++UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, ++ UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue, ++ UInt32 *distances, UInt32 maxLen) ++{ ++ CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1; ++ CLzRef *ptr1 = son + (_cyclicBufferPos << 1); ++ UInt32 len0 = 0, len1 = 0; ++ for (;;) ++ { ++ UInt32 delta = pos - curMatch; ++ if (cutValue-- == 0 || delta >= _cyclicBufferSize) ++ { ++ *ptr0 = *ptr1 = kEmptyHashValue; ++ return distances; ++ } ++ { ++ CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1); ++ const Byte *pb = cur - delta; ++ UInt32 len = (len0 < len1 ? len0 : len1); ++ if (pb[len] == cur[len]) ++ { ++ if (++len != lenLimit && pb[len] == cur[len]) ++ while (++len != lenLimit) ++ if (pb[len] != cur[len]) ++ break; ++ if (maxLen < len) ++ { ++ *distances++ = maxLen = len; ++ *distances++ = delta - 1; ++ if (len == lenLimit) ++ { ++ *ptr1 = pair[0]; ++ *ptr0 = pair[1]; ++ return distances; ++ } ++ } ++ } ++ if (pb[len] < cur[len]) ++ { ++ *ptr1 = curMatch; ++ ptr1 = pair + 1; ++ curMatch = *ptr1; ++ len1 = len; ++ } ++ else ++ { ++ *ptr0 = curMatch; ++ ptr0 = pair; ++ curMatch = *ptr0; ++ len0 = len; ++ } ++ } ++ } ++} ++ ++static void SkipMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, ++ UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue) ++{ ++ CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1; ++ CLzRef *ptr1 = son + (_cyclicBufferPos << 1); ++ UInt32 len0 = 0, len1 = 0; ++ for (;;) ++ { ++ UInt32 delta = pos - curMatch; ++ if (cutValue-- == 0 || delta >= _cyclicBufferSize) ++ { ++ *ptr0 = *ptr1 = kEmptyHashValue; ++ return; ++ } ++ { ++ CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1); ++ const Byte *pb = cur - delta; ++ UInt32 len = (len0 < len1 ? len0 : len1); ++ if (pb[len] == cur[len]) ++ { ++ while (++len != lenLimit) ++ if (pb[len] != cur[len]) ++ break; ++ { ++ if (len == lenLimit) ++ { ++ *ptr1 = pair[0]; ++ *ptr0 = pair[1]; ++ return; ++ } ++ } ++ } ++ if (pb[len] < cur[len]) ++ { ++ *ptr1 = curMatch; ++ ptr1 = pair + 1; ++ curMatch = *ptr1; ++ len1 = len; ++ } ++ else ++ { ++ *ptr0 = curMatch; ++ ptr0 = pair; ++ curMatch = *ptr0; ++ len0 = len; ++ } ++ } ++ } ++} ++ ++#define MOVE_POS \ ++ ++p->cyclicBufferPos; \ ++ p->buffer++; \ ++ if (++p->pos == p->posLimit) MatchFinder_CheckLimits(p); ++ ++#define MOVE_POS_RET MOVE_POS return offset; ++ ++static void MatchFinder_MovePos(CMatchFinder *p) { MOVE_POS; } ++ ++#define GET_MATCHES_HEADER2(minLen, ret_op) \ ++ UInt32 lenLimit; UInt32 hashValue; const Byte *cur; UInt32 curMatch; \ ++ lenLimit = p->lenLimit; { if (lenLimit < minLen) { MatchFinder_MovePos(p); ret_op; }} \ ++ cur = p->buffer; ++ ++#define GET_MATCHES_HEADER(minLen) GET_MATCHES_HEADER2(minLen, return 0) ++#define SKIP_HEADER(minLen) GET_MATCHES_HEADER2(minLen, continue) ++ ++#define MF_PARAMS(p) p->pos, p->buffer, p->son, p->cyclicBufferPos, p->cyclicBufferSize, p->cutValue ++ ++#define GET_MATCHES_FOOTER(offset, maxLen) \ ++ offset = (UInt32)(GetMatchesSpec1(lenLimit, curMatch, MF_PARAMS(p), \ ++ distances + offset, maxLen) - distances); MOVE_POS_RET; ++ ++#define SKIP_FOOTER \ ++ SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); MOVE_POS; ++ ++static UInt32 Bt2_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) ++{ ++ UInt32 offset; ++ GET_MATCHES_HEADER(2) ++ HASH2_CALC; ++ curMatch = p->hash[hashValue]; ++ p->hash[hashValue] = p->pos; ++ offset = 0; ++ GET_MATCHES_FOOTER(offset, 1) ++} ++ ++UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) ++{ ++ UInt32 offset; ++ GET_MATCHES_HEADER(3) ++ HASH_ZIP_CALC; ++ curMatch = p->hash[hashValue]; ++ p->hash[hashValue] = p->pos; ++ offset = 0; ++ GET_MATCHES_FOOTER(offset, 2) ++} ++ ++static UInt32 Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) ++{ ++ UInt32 hash2Value, delta2, maxLen, offset; ++ GET_MATCHES_HEADER(3) ++ ++ HASH3_CALC; ++ ++ delta2 = p->pos - p->hash[hash2Value]; ++ curMatch = p->hash[kFix3HashSize + hashValue]; ++ ++ p->hash[hash2Value] = ++ p->hash[kFix3HashSize + hashValue] = p->pos; ++ ++ ++ maxLen = 2; ++ offset = 0; ++ if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur) ++ { ++ for (; maxLen != lenLimit; maxLen++) ++ if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen]) ++ break; ++ distances[0] = maxLen; ++ distances[1] = delta2 - 1; ++ offset = 2; ++ if (maxLen == lenLimit) ++ { ++ SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); ++ MOVE_POS_RET; ++ } ++ } ++ GET_MATCHES_FOOTER(offset, maxLen) ++} ++ ++static UInt32 Bt4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) ++{ ++ UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset; ++ GET_MATCHES_HEADER(4) ++ ++ HASH4_CALC; ++ ++ delta2 = p->pos - p->hash[ hash2Value]; ++ delta3 = p->pos - p->hash[kFix3HashSize + hash3Value]; ++ curMatch = p->hash[kFix4HashSize + hashValue]; ++ ++ p->hash[ hash2Value] = ++ p->hash[kFix3HashSize + hash3Value] = ++ p->hash[kFix4HashSize + hashValue] = p->pos; ++ ++ maxLen = 1; ++ offset = 0; ++ if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur) ++ { ++ distances[0] = maxLen = 2; ++ distances[1] = delta2 - 1; ++ offset = 2; ++ } ++ if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur) ++ { ++ maxLen = 3; ++ distances[offset + 1] = delta3 - 1; ++ offset += 2; ++ delta2 = delta3; ++ } ++ if (offset != 0) ++ { ++ for (; maxLen != lenLimit; maxLen++) ++ if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen]) ++ break; ++ distances[offset - 2] = maxLen; ++ if (maxLen == lenLimit) ++ { ++ SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); ++ MOVE_POS_RET; ++ } ++ } ++ if (maxLen < 3) ++ maxLen = 3; ++ GET_MATCHES_FOOTER(offset, maxLen) ++} ++ ++static UInt32 Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) ++{ ++ UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset; ++ GET_MATCHES_HEADER(4) ++ ++ HASH4_CALC; ++ ++ delta2 = p->pos - p->hash[ hash2Value]; ++ delta3 = p->pos - p->hash[kFix3HashSize + hash3Value]; ++ curMatch = p->hash[kFix4HashSize + hashValue]; ++ ++ p->hash[ hash2Value] = ++ p->hash[kFix3HashSize + hash3Value] = ++ p->hash[kFix4HashSize + hashValue] = p->pos; ++ ++ maxLen = 1; ++ offset = 0; ++ if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur) ++ { ++ distances[0] = maxLen = 2; ++ distances[1] = delta2 - 1; ++ offset = 2; ++ } ++ if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur) ++ { ++ maxLen = 3; ++ distances[offset + 1] = delta3 - 1; ++ offset += 2; ++ delta2 = delta3; ++ } ++ if (offset != 0) ++ { ++ for (; maxLen != lenLimit; maxLen++) ++ if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen]) ++ break; ++ distances[offset - 2] = maxLen; ++ if (maxLen == lenLimit) ++ { ++ p->son[p->cyclicBufferPos] = curMatch; ++ MOVE_POS_RET; ++ } ++ } ++ if (maxLen < 3) ++ maxLen = 3; ++ offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p), ++ distances + offset, maxLen) - (distances)); ++ MOVE_POS_RET ++} ++ ++UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) ++{ ++ UInt32 offset; ++ GET_MATCHES_HEADER(3) ++ HASH_ZIP_CALC; ++ curMatch = p->hash[hashValue]; ++ p->hash[hashValue] = p->pos; ++ offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p), ++ distances, 2) - (distances)); ++ MOVE_POS_RET ++} ++ ++static void Bt2_MatchFinder_Skip(CMatchFinder *p, UInt32 num) ++{ ++ do ++ { ++ SKIP_HEADER(2) ++ HASH2_CALC; ++ curMatch = p->hash[hashValue]; ++ p->hash[hashValue] = p->pos; ++ SKIP_FOOTER ++ } ++ while (--num != 0); ++} ++ ++void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num) ++{ ++ do ++ { ++ SKIP_HEADER(3) ++ HASH_ZIP_CALC; ++ curMatch = p->hash[hashValue]; ++ p->hash[hashValue] = p->pos; ++ SKIP_FOOTER ++ } ++ while (--num != 0); ++} ++ ++static void Bt3_MatchFinder_Skip(CMatchFinder *p, UInt32 num) ++{ ++ do ++ { ++ UInt32 hash2Value; ++ SKIP_HEADER(3) ++ HASH3_CALC; ++ curMatch = p->hash[kFix3HashSize + hashValue]; ++ p->hash[hash2Value] = ++ p->hash[kFix3HashSize + hashValue] = p->pos; ++ SKIP_FOOTER ++ } ++ while (--num != 0); ++} ++ ++static void Bt4_MatchFinder_Skip(CMatchFinder *p, UInt32 num) ++{ ++ do ++ { ++ UInt32 hash2Value, hash3Value; ++ SKIP_HEADER(4) ++ HASH4_CALC; ++ curMatch = p->hash[kFix4HashSize + hashValue]; ++ p->hash[ hash2Value] = ++ p->hash[kFix3HashSize + hash3Value] = p->pos; ++ p->hash[kFix4HashSize + hashValue] = p->pos; ++ SKIP_FOOTER ++ } ++ while (--num != 0); ++} ++ ++static void Hc4_MatchFinder_Skip(CMatchFinder *p, UInt32 num) ++{ ++ do ++ { ++ UInt32 hash2Value, hash3Value; ++ SKIP_HEADER(4) ++ HASH4_CALC; ++ curMatch = p->hash[kFix4HashSize + hashValue]; ++ p->hash[ hash2Value] = ++ p->hash[kFix3HashSize + hash3Value] = ++ p->hash[kFix4HashSize + hashValue] = p->pos; ++ p->son[p->cyclicBufferPos] = curMatch; ++ MOVE_POS ++ } ++ while (--num != 0); ++} ++ ++void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num) ++{ ++ do ++ { ++ SKIP_HEADER(3) ++ HASH_ZIP_CALC; ++ curMatch = p->hash[hashValue]; ++ p->hash[hashValue] = p->pos; ++ p->son[p->cyclicBufferPos] = curMatch; ++ MOVE_POS ++ } ++ while (--num != 0); ++} ++ ++void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable) ++{ ++ vTable->Init = (Mf_Init_Func)MatchFinder_Init; ++ vTable->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinder_GetIndexByte; ++ vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinder_GetNumAvailableBytes; ++ vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinder_GetPointerToCurrentPos; ++ if (!p->btMode) ++ { ++ vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches; ++ vTable->Skip = (Mf_Skip_Func)Hc4_MatchFinder_Skip; ++ } ++ else if (p->numHashBytes == 2) ++ { ++ vTable->GetMatches = (Mf_GetMatches_Func)Bt2_MatchFinder_GetMatches; ++ vTable->Skip = (Mf_Skip_Func)Bt2_MatchFinder_Skip; ++ } ++ else if (p->numHashBytes == 3) ++ { ++ vTable->GetMatches = (Mf_GetMatches_Func)Bt3_MatchFinder_GetMatches; ++ vTable->Skip = (Mf_Skip_Func)Bt3_MatchFinder_Skip; ++ } ++ else ++ { ++ vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches; ++ vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip; ++ } ++} +--- /dev/null ++++ b/lib/lzma/LzmaDec.c +@@ -0,0 +1,999 @@ ++/* LzmaDec.c -- LZMA Decoder ++2009-09-20 : Igor Pavlov : Public domain */ ++ ++#include "LzmaDec.h" ++ ++#include ++ ++#define kNumTopBits 24 ++#define kTopValue ((UInt32)1 << kNumTopBits) ++ ++#define kNumBitModelTotalBits 11 ++#define kBitModelTotal (1 << kNumBitModelTotalBits) ++#define kNumMoveBits 5 ++ ++#define RC_INIT_SIZE 5 ++ ++#define NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); } ++ ++#define IF_BIT_0(p) ttt = *(p); NORMALIZE; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) ++#define UPDATE_0(p) range = bound; *(p) = (CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); ++#define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CLzmaProb)(ttt - (ttt >> kNumMoveBits)); ++#define GET_BIT2(p, i, A0, A1) IF_BIT_0(p) \ ++ { UPDATE_0(p); i = (i + i); A0; } else \ ++ { UPDATE_1(p); i = (i + i) + 1; A1; } ++#define GET_BIT(p, i) GET_BIT2(p, i, ; , ;) ++ ++#define TREE_GET_BIT(probs, i) { GET_BIT((probs + i), i); } ++#define TREE_DECODE(probs, limit, i) \ ++ { i = 1; do { TREE_GET_BIT(probs, i); } while (i < limit); i -= limit; } ++ ++/* #define _LZMA_SIZE_OPT */ ++ ++#ifdef _LZMA_SIZE_OPT ++#define TREE_6_DECODE(probs, i) TREE_DECODE(probs, (1 << 6), i) ++#else ++#define TREE_6_DECODE(probs, i) \ ++ { i = 1; \ ++ TREE_GET_BIT(probs, i); \ ++ TREE_GET_BIT(probs, i); \ ++ TREE_GET_BIT(probs, i); \ ++ TREE_GET_BIT(probs, i); \ ++ TREE_GET_BIT(probs, i); \ ++ TREE_GET_BIT(probs, i); \ ++ i -= 0x40; } ++#endif ++ ++#define NORMALIZE_CHECK if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_ERROR; range <<= 8; code = (code << 8) | (*buf++); } ++ ++#define IF_BIT_0_CHECK(p) ttt = *(p); NORMALIZE_CHECK; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) ++#define UPDATE_0_CHECK range = bound; ++#define UPDATE_1_CHECK range -= bound; code -= bound; ++#define GET_BIT2_CHECK(p, i, A0, A1) IF_BIT_0_CHECK(p) \ ++ { UPDATE_0_CHECK; i = (i + i); A0; } else \ ++ { UPDATE_1_CHECK; i = (i + i) + 1; A1; } ++#define GET_BIT_CHECK(p, i) GET_BIT2_CHECK(p, i, ; , ;) ++#define TREE_DECODE_CHECK(probs, limit, i) \ ++ { i = 1; do { GET_BIT_CHECK(probs + i, i) } while (i < limit); i -= limit; } ++ ++ ++#define kNumPosBitsMax 4 ++#define kNumPosStatesMax (1 << kNumPosBitsMax) ++ ++#define kLenNumLowBits 3 ++#define kLenNumLowSymbols (1 << kLenNumLowBits) ++#define kLenNumMidBits 3 ++#define kLenNumMidSymbols (1 << kLenNumMidBits) ++#define kLenNumHighBits 8 ++#define kLenNumHighSymbols (1 << kLenNumHighBits) ++ ++#define LenChoice 0 ++#define LenChoice2 (LenChoice + 1) ++#define LenLow (LenChoice2 + 1) ++#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits)) ++#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits)) ++#define kNumLenProbs (LenHigh + kLenNumHighSymbols) ++ ++ ++#define kNumStates 12 ++#define kNumLitStates 7 ++ ++#define kStartPosModelIndex 4 ++#define kEndPosModelIndex 14 ++#define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) ++ ++#define kNumPosSlotBits 6 ++#define kNumLenToPosStates 4 ++ ++#define kNumAlignBits 4 ++#define kAlignTableSize (1 << kNumAlignBits) ++ ++#define kMatchMinLen 2 ++#define kMatchSpecLenStart (kMatchMinLen + kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols) ++ ++#define IsMatch 0 ++#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax)) ++#define IsRepG0 (IsRep + kNumStates) ++#define IsRepG1 (IsRepG0 + kNumStates) ++#define IsRepG2 (IsRepG1 + kNumStates) ++#define IsRep0Long (IsRepG2 + kNumStates) ++#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax)) ++#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits)) ++#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex) ++#define LenCoder (Align + kAlignTableSize) ++#define RepLenCoder (LenCoder + kNumLenProbs) ++#define Literal (RepLenCoder + kNumLenProbs) ++ ++#define LZMA_BASE_SIZE 1846 ++#define LZMA_LIT_SIZE 768 ++ ++#define LzmaProps_GetNumProbs(p) ((UInt32)LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((p)->lc + (p)->lp))) ++ ++#if Literal != LZMA_BASE_SIZE ++StopCompilingDueBUG ++#endif ++ ++#define LZMA_DIC_MIN (1 << 12) ++ ++/* First LZMA-symbol is always decoded. ++And it decodes new LZMA-symbols while (buf < bufLimit), but "buf" is without last normalization ++Out: ++ Result: ++ SZ_OK - OK ++ SZ_ERROR_DATA - Error ++ p->remainLen: ++ < kMatchSpecLenStart : normal remain ++ = kMatchSpecLenStart : finished ++ = kMatchSpecLenStart + 1 : Flush marker ++ = kMatchSpecLenStart + 2 : State Init Marker ++*/ ++ ++static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte *bufLimit) ++{ ++ CLzmaProb *probs = p->probs; ++ ++ unsigned state = p->state; ++ UInt32 rep0 = p->reps[0], rep1 = p->reps[1], rep2 = p->reps[2], rep3 = p->reps[3]; ++ unsigned pbMask = ((unsigned)1 << (p->prop.pb)) - 1; ++ unsigned lpMask = ((unsigned)1 << (p->prop.lp)) - 1; ++ unsigned lc = p->prop.lc; ++ ++ Byte *dic = p->dic; ++ SizeT dicBufSize = p->dicBufSize; ++ SizeT dicPos = p->dicPos; ++ ++ UInt32 processedPos = p->processedPos; ++ UInt32 checkDicSize = p->checkDicSize; ++ unsigned len = 0; ++ ++ const Byte *buf = p->buf; ++ UInt32 range = p->range; ++ UInt32 code = p->code; ++ ++ do ++ { ++ CLzmaProb *prob; ++ UInt32 bound; ++ unsigned ttt; ++ unsigned posState = processedPos & pbMask; ++ ++ prob = probs + IsMatch + (state << kNumPosBitsMax) + posState; ++ IF_BIT_0(prob) ++ { ++ unsigned symbol; ++ UPDATE_0(prob); ++ prob = probs + Literal; ++ if (checkDicSize != 0 || processedPos != 0) ++ prob += (LZMA_LIT_SIZE * (((processedPos & lpMask) << lc) + ++ (dic[(dicPos == 0 ? dicBufSize : dicPos) - 1] >> (8 - lc)))); ++ ++ if (state < kNumLitStates) ++ { ++ state -= (state < 4) ? state : 3; ++ symbol = 1; ++ do { GET_BIT(prob + symbol, symbol) } while (symbol < 0x100); ++ } ++ else ++ { ++ unsigned matchByte = p->dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; ++ unsigned offs = 0x100; ++ state -= (state < 10) ? 3 : 6; ++ symbol = 1; ++ do ++ { ++ unsigned bit; ++ CLzmaProb *probLit; ++ matchByte <<= 1; ++ bit = (matchByte & offs); ++ probLit = prob + offs + bit + symbol; ++ GET_BIT2(probLit, symbol, offs &= ~bit, offs &= bit) ++ } ++ while (symbol < 0x100); ++ } ++ dic[dicPos++] = (Byte)symbol; ++ processedPos++; ++ continue; ++ } ++ else ++ { ++ UPDATE_1(prob); ++ prob = probs + IsRep + state; ++ IF_BIT_0(prob) ++ { ++ UPDATE_0(prob); ++ state += kNumStates; ++ prob = probs + LenCoder; ++ } ++ else ++ { ++ UPDATE_1(prob); ++ if (checkDicSize == 0 && processedPos == 0) ++ return SZ_ERROR_DATA; ++ prob = probs + IsRepG0 + state; ++ IF_BIT_0(prob) ++ { ++ UPDATE_0(prob); ++ prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState; ++ IF_BIT_0(prob) ++ { ++ UPDATE_0(prob); ++ dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; ++ dicPos++; ++ processedPos++; ++ state = state < kNumLitStates ? 9 : 11; ++ continue; ++ } ++ UPDATE_1(prob); ++ } ++ else ++ { ++ UInt32 distance; ++ UPDATE_1(prob); ++ prob = probs + IsRepG1 + state; ++ IF_BIT_0(prob) ++ { ++ UPDATE_0(prob); ++ distance = rep1; ++ } ++ else ++ { ++ UPDATE_1(prob); ++ prob = probs + IsRepG2 + state; ++ IF_BIT_0(prob) ++ { ++ UPDATE_0(prob); ++ distance = rep2; ++ } ++ else ++ { ++ UPDATE_1(prob); ++ distance = rep3; ++ rep3 = rep2; ++ } ++ rep2 = rep1; ++ } ++ rep1 = rep0; ++ rep0 = distance; ++ } ++ state = state < kNumLitStates ? 8 : 11; ++ prob = probs + RepLenCoder; ++ } ++ { ++ unsigned limit, offset; ++ CLzmaProb *probLen = prob + LenChoice; ++ IF_BIT_0(probLen) ++ { ++ UPDATE_0(probLen); ++ probLen = prob + LenLow + (posState << kLenNumLowBits); ++ offset = 0; ++ limit = (1 << kLenNumLowBits); ++ } ++ else ++ { ++ UPDATE_1(probLen); ++ probLen = prob + LenChoice2; ++ IF_BIT_0(probLen) ++ { ++ UPDATE_0(probLen); ++ probLen = prob + LenMid + (posState << kLenNumMidBits); ++ offset = kLenNumLowSymbols; ++ limit = (1 << kLenNumMidBits); ++ } ++ else ++ { ++ UPDATE_1(probLen); ++ probLen = prob + LenHigh; ++ offset = kLenNumLowSymbols + kLenNumMidSymbols; ++ limit = (1 << kLenNumHighBits); ++ } ++ } ++ TREE_DECODE(probLen, limit, len); ++ len += offset; ++ } ++ ++ if (state >= kNumStates) ++ { ++ UInt32 distance; ++ prob = probs + PosSlot + ++ ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits); ++ TREE_6_DECODE(prob, distance); ++ if (distance >= kStartPosModelIndex) ++ { ++ unsigned posSlot = (unsigned)distance; ++ int numDirectBits = (int)(((distance >> 1) - 1)); ++ distance = (2 | (distance & 1)); ++ if (posSlot < kEndPosModelIndex) ++ { ++ distance <<= numDirectBits; ++ prob = probs + SpecPos + distance - posSlot - 1; ++ { ++ UInt32 mask = 1; ++ unsigned i = 1; ++ do ++ { ++ GET_BIT2(prob + i, i, ; , distance |= mask); ++ mask <<= 1; ++ } ++ while (--numDirectBits != 0); ++ } ++ } ++ else ++ { ++ numDirectBits -= kNumAlignBits; ++ do ++ { ++ NORMALIZE ++ range >>= 1; ++ ++ { ++ UInt32 t; ++ code -= range; ++ t = (0 - ((UInt32)code >> 31)); /* (UInt32)((Int32)code >> 31) */ ++ distance = (distance << 1) + (t + 1); ++ code += range & t; ++ } ++ /* ++ distance <<= 1; ++ if (code >= range) ++ { ++ code -= range; ++ distance |= 1; ++ } ++ */ ++ } ++ while (--numDirectBits != 0); ++ prob = probs + Align; ++ distance <<= kNumAlignBits; ++ { ++ unsigned i = 1; ++ GET_BIT2(prob + i, i, ; , distance |= 1); ++ GET_BIT2(prob + i, i, ; , distance |= 2); ++ GET_BIT2(prob + i, i, ; , distance |= 4); ++ GET_BIT2(prob + i, i, ; , distance |= 8); ++ } ++ if (distance == (UInt32)0xFFFFFFFF) ++ { ++ len += kMatchSpecLenStart; ++ state -= kNumStates; ++ break; ++ } ++ } ++ } ++ rep3 = rep2; ++ rep2 = rep1; ++ rep1 = rep0; ++ rep0 = distance + 1; ++ if (checkDicSize == 0) ++ { ++ if (distance >= processedPos) ++ return SZ_ERROR_DATA; ++ } ++ else if (distance >= checkDicSize) ++ return SZ_ERROR_DATA; ++ state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3; ++ } ++ ++ len += kMatchMinLen; ++ ++ if (limit == dicPos) ++ return SZ_ERROR_DATA; ++ { ++ SizeT rem = limit - dicPos; ++ unsigned curLen = ((rem < len) ? (unsigned)rem : len); ++ SizeT pos = (dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0); ++ ++ processedPos += curLen; ++ ++ len -= curLen; ++ if (pos + curLen <= dicBufSize) ++ { ++ Byte *dest = dic + dicPos; ++ ptrdiff_t src = (ptrdiff_t)pos - (ptrdiff_t)dicPos; ++ const Byte *lim = dest + curLen; ++ dicPos += curLen; ++ do ++ *(dest) = (Byte)*(dest + src); ++ while (++dest != lim); ++ } ++ else ++ { ++ do ++ { ++ dic[dicPos++] = dic[pos]; ++ if (++pos == dicBufSize) ++ pos = 0; ++ } ++ while (--curLen != 0); ++ } ++ } ++ } ++ } ++ while (dicPos < limit && buf < bufLimit); ++ NORMALIZE; ++ p->buf = buf; ++ p->range = range; ++ p->code = code; ++ p->remainLen = len; ++ p->dicPos = dicPos; ++ p->processedPos = processedPos; ++ p->reps[0] = rep0; ++ p->reps[1] = rep1; ++ p->reps[2] = rep2; ++ p->reps[3] = rep3; ++ p->state = state; ++ ++ return SZ_OK; ++} ++ ++static void MY_FAST_CALL LzmaDec_WriteRem(CLzmaDec *p, SizeT limit) ++{ ++ if (p->remainLen != 0 && p->remainLen < kMatchSpecLenStart) ++ { ++ Byte *dic = p->dic; ++ SizeT dicPos = p->dicPos; ++ SizeT dicBufSize = p->dicBufSize; ++ unsigned len = p->remainLen; ++ UInt32 rep0 = p->reps[0]; ++ if (limit - dicPos < len) ++ len = (unsigned)(limit - dicPos); ++ ++ if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= len) ++ p->checkDicSize = p->prop.dicSize; ++ ++ p->processedPos += len; ++ p->remainLen -= len; ++ while (len-- != 0) ++ { ++ dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; ++ dicPos++; ++ } ++ p->dicPos = dicPos; ++ } ++} ++ ++static int MY_FAST_CALL LzmaDec_DecodeReal2(CLzmaDec *p, SizeT limit, const Byte *bufLimit) ++{ ++ do ++ { ++ SizeT limit2 = limit; ++ if (p->checkDicSize == 0) ++ { ++ UInt32 rem = p->prop.dicSize - p->processedPos; ++ if (limit - p->dicPos > rem) ++ limit2 = p->dicPos + rem; ++ } ++ RINOK(LzmaDec_DecodeReal(p, limit2, bufLimit)); ++ if (p->processedPos >= p->prop.dicSize) ++ p->checkDicSize = p->prop.dicSize; ++ LzmaDec_WriteRem(p, limit); ++ } ++ while (p->dicPos < limit && p->buf < bufLimit && p->remainLen < kMatchSpecLenStart); ++ ++ if (p->remainLen > kMatchSpecLenStart) ++ { ++ p->remainLen = kMatchSpecLenStart; ++ } ++ return 0; ++} ++ ++typedef enum ++{ ++ DUMMY_ERROR, /* unexpected end of input stream */ ++ DUMMY_LIT, ++ DUMMY_MATCH, ++ DUMMY_REP ++} ELzmaDummy; ++ ++static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inSize) ++{ ++ UInt32 range = p->range; ++ UInt32 code = p->code; ++ const Byte *bufLimit = buf + inSize; ++ CLzmaProb *probs = p->probs; ++ unsigned state = p->state; ++ ELzmaDummy res; ++ ++ { ++ CLzmaProb *prob; ++ UInt32 bound; ++ unsigned ttt; ++ unsigned posState = (p->processedPos) & ((1 << p->prop.pb) - 1); ++ ++ prob = probs + IsMatch + (state << kNumPosBitsMax) + posState; ++ IF_BIT_0_CHECK(prob) ++ { ++ UPDATE_0_CHECK ++ ++ /* if (bufLimit - buf >= 7) return DUMMY_LIT; */ ++ ++ prob = probs + Literal; ++ if (p->checkDicSize != 0 || p->processedPos != 0) ++ prob += (LZMA_LIT_SIZE * ++ ((((p->processedPos) & ((1 << (p->prop.lp)) - 1)) << p->prop.lc) + ++ (p->dic[(p->dicPos == 0 ? p->dicBufSize : p->dicPos) - 1] >> (8 - p->prop.lc)))); ++ ++ if (state < kNumLitStates) ++ { ++ unsigned symbol = 1; ++ do { GET_BIT_CHECK(prob + symbol, symbol) } while (symbol < 0x100); ++ } ++ else ++ { ++ unsigned matchByte = p->dic[p->dicPos - p->reps[0] + ++ ((p->dicPos < p->reps[0]) ? p->dicBufSize : 0)]; ++ unsigned offs = 0x100; ++ unsigned symbol = 1; ++ do ++ { ++ unsigned bit; ++ CLzmaProb *probLit; ++ matchByte <<= 1; ++ bit = (matchByte & offs); ++ probLit = prob + offs + bit + symbol; ++ GET_BIT2_CHECK(probLit, symbol, offs &= ~bit, offs &= bit) ++ } ++ while (symbol < 0x100); ++ } ++ res = DUMMY_LIT; ++ } ++ else ++ { ++ unsigned len; ++ UPDATE_1_CHECK; ++ ++ prob = probs + IsRep + state; ++ IF_BIT_0_CHECK(prob) ++ { ++ UPDATE_0_CHECK; ++ state = 0; ++ prob = probs + LenCoder; ++ res = DUMMY_MATCH; ++ } ++ else ++ { ++ UPDATE_1_CHECK; ++ res = DUMMY_REP; ++ prob = probs + IsRepG0 + state; ++ IF_BIT_0_CHECK(prob) ++ { ++ UPDATE_0_CHECK; ++ prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState; ++ IF_BIT_0_CHECK(prob) ++ { ++ UPDATE_0_CHECK; ++ NORMALIZE_CHECK; ++ return DUMMY_REP; ++ } ++ else ++ { ++ UPDATE_1_CHECK; ++ } ++ } ++ else ++ { ++ UPDATE_1_CHECK; ++ prob = probs + IsRepG1 + state; ++ IF_BIT_0_CHECK(prob) ++ { ++ UPDATE_0_CHECK; ++ } ++ else ++ { ++ UPDATE_1_CHECK; ++ prob = probs + IsRepG2 + state; ++ IF_BIT_0_CHECK(prob) ++ { ++ UPDATE_0_CHECK; ++ } ++ else ++ { ++ UPDATE_1_CHECK; ++ } ++ } ++ } ++ state = kNumStates; ++ prob = probs + RepLenCoder; ++ } ++ { ++ unsigned limit, offset; ++ CLzmaProb *probLen = prob + LenChoice; ++ IF_BIT_0_CHECK(probLen) ++ { ++ UPDATE_0_CHECK; ++ probLen = prob + LenLow + (posState << kLenNumLowBits); ++ offset = 0; ++ limit = 1 << kLenNumLowBits; ++ } ++ else ++ { ++ UPDATE_1_CHECK; ++ probLen = prob + LenChoice2; ++ IF_BIT_0_CHECK(probLen) ++ { ++ UPDATE_0_CHECK; ++ probLen = prob + LenMid + (posState << kLenNumMidBits); ++ offset = kLenNumLowSymbols; ++ limit = 1 << kLenNumMidBits; ++ } ++ else ++ { ++ UPDATE_1_CHECK; ++ probLen = prob + LenHigh; ++ offset = kLenNumLowSymbols + kLenNumMidSymbols; ++ limit = 1 << kLenNumHighBits; ++ } ++ } ++ TREE_DECODE_CHECK(probLen, limit, len); ++ len += offset; ++ } ++ ++ if (state < 4) ++ { ++ unsigned posSlot; ++ prob = probs + PosSlot + ++ ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << ++ kNumPosSlotBits); ++ TREE_DECODE_CHECK(prob, 1 << kNumPosSlotBits, posSlot); ++ if (posSlot >= kStartPosModelIndex) ++ { ++ int numDirectBits = ((posSlot >> 1) - 1); ++ ++ /* if (bufLimit - buf >= 8) return DUMMY_MATCH; */ ++ ++ if (posSlot < kEndPosModelIndex) ++ { ++ prob = probs + SpecPos + ((2 | (posSlot & 1)) << numDirectBits) - posSlot - 1; ++ } ++ else ++ { ++ numDirectBits -= kNumAlignBits; ++ do ++ { ++ NORMALIZE_CHECK ++ range >>= 1; ++ code -= range & (((code - range) >> 31) - 1); ++ /* if (code >= range) code -= range; */ ++ } ++ while (--numDirectBits != 0); ++ prob = probs + Align; ++ numDirectBits = kNumAlignBits; ++ } ++ { ++ unsigned i = 1; ++ do ++ { ++ GET_BIT_CHECK(prob + i, i); ++ } ++ while (--numDirectBits != 0); ++ } ++ } ++ } ++ } ++ } ++ NORMALIZE_CHECK; ++ return res; ++} ++ ++ ++static void LzmaDec_InitRc(CLzmaDec *p, const Byte *data) ++{ ++ p->code = ((UInt32)data[1] << 24) | ((UInt32)data[2] << 16) | ((UInt32)data[3] << 8) | ((UInt32)data[4]); ++ p->range = 0xFFFFFFFF; ++ p->needFlush = 0; ++} ++ ++void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState) ++{ ++ p->needFlush = 1; ++ p->remainLen = 0; ++ p->tempBufSize = 0; ++ ++ if (initDic) ++ { ++ p->processedPos = 0; ++ p->checkDicSize = 0; ++ p->needInitState = 1; ++ } ++ if (initState) ++ p->needInitState = 1; ++} ++ ++void LzmaDec_Init(CLzmaDec *p) ++{ ++ p->dicPos = 0; ++ LzmaDec_InitDicAndState(p, True, True); ++} ++ ++static void LzmaDec_InitStateReal(CLzmaDec *p) ++{ ++ UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (p->prop.lc + p->prop.lp)); ++ UInt32 i; ++ CLzmaProb *probs = p->probs; ++ for (i = 0; i < numProbs; i++) ++ probs[i] = kBitModelTotal >> 1; ++ p->reps[0] = p->reps[1] = p->reps[2] = p->reps[3] = 1; ++ p->state = 0; ++ p->needInitState = 0; ++} ++ ++SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen, ++ ELzmaFinishMode finishMode, ELzmaStatus *status) ++{ ++ SizeT inSize = *srcLen; ++ (*srcLen) = 0; ++ LzmaDec_WriteRem(p, dicLimit); ++ ++ *status = LZMA_STATUS_NOT_SPECIFIED; ++ ++ while (p->remainLen != kMatchSpecLenStart) ++ { ++ int checkEndMarkNow; ++ ++ if (p->needFlush != 0) ++ { ++ for (; inSize > 0 && p->tempBufSize < RC_INIT_SIZE; (*srcLen)++, inSize--) ++ p->tempBuf[p->tempBufSize++] = *src++; ++ if (p->tempBufSize < RC_INIT_SIZE) ++ { ++ *status = LZMA_STATUS_NEEDS_MORE_INPUT; ++ return SZ_OK; ++ } ++ if (p->tempBuf[0] != 0) ++ return SZ_ERROR_DATA; ++ ++ LzmaDec_InitRc(p, p->tempBuf); ++ p->tempBufSize = 0; ++ } ++ ++ checkEndMarkNow = 0; ++ if (p->dicPos >= dicLimit) ++ { ++ if (p->remainLen == 0 && p->code == 0) ++ { ++ *status = LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK; ++ return SZ_OK; ++ } ++ if (finishMode == LZMA_FINISH_ANY) ++ { ++ *status = LZMA_STATUS_NOT_FINISHED; ++ return SZ_OK; ++ } ++ if (p->remainLen != 0) ++ { ++ *status = LZMA_STATUS_NOT_FINISHED; ++ return SZ_ERROR_DATA; ++ } ++ checkEndMarkNow = 1; ++ } ++ ++ if (p->needInitState) ++ LzmaDec_InitStateReal(p); ++ ++ if (p->tempBufSize == 0) ++ { ++ SizeT processed; ++ const Byte *bufLimit; ++ if (inSize < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) ++ { ++ int dummyRes = LzmaDec_TryDummy(p, src, inSize); ++ if (dummyRes == DUMMY_ERROR) ++ { ++ memcpy(p->tempBuf, src, inSize); ++ p->tempBufSize = (unsigned)inSize; ++ (*srcLen) += inSize; ++ *status = LZMA_STATUS_NEEDS_MORE_INPUT; ++ return SZ_OK; ++ } ++ if (checkEndMarkNow && dummyRes != DUMMY_MATCH) ++ { ++ *status = LZMA_STATUS_NOT_FINISHED; ++ return SZ_ERROR_DATA; ++ } ++ bufLimit = src; ++ } ++ else ++ bufLimit = src + inSize - LZMA_REQUIRED_INPUT_MAX; ++ p->buf = src; ++ if (LzmaDec_DecodeReal2(p, dicLimit, bufLimit) != 0) ++ return SZ_ERROR_DATA; ++ processed = (SizeT)(p->buf - src); ++ (*srcLen) += processed; ++ src += processed; ++ inSize -= processed; ++ } ++ else ++ { ++ unsigned rem = p->tempBufSize, lookAhead = 0; ++ while (rem < LZMA_REQUIRED_INPUT_MAX && lookAhead < inSize) ++ p->tempBuf[rem++] = src[lookAhead++]; ++ p->tempBufSize = rem; ++ if (rem < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) ++ { ++ int dummyRes = LzmaDec_TryDummy(p, p->tempBuf, rem); ++ if (dummyRes == DUMMY_ERROR) ++ { ++ (*srcLen) += lookAhead; ++ *status = LZMA_STATUS_NEEDS_MORE_INPUT; ++ return SZ_OK; ++ } ++ if (checkEndMarkNow && dummyRes != DUMMY_MATCH) ++ { ++ *status = LZMA_STATUS_NOT_FINISHED; ++ return SZ_ERROR_DATA; ++ } ++ } ++ p->buf = p->tempBuf; ++ if (LzmaDec_DecodeReal2(p, dicLimit, p->buf) != 0) ++ return SZ_ERROR_DATA; ++ lookAhead -= (rem - (unsigned)(p->buf - p->tempBuf)); ++ (*srcLen) += lookAhead; ++ src += lookAhead; ++ inSize -= lookAhead; ++ p->tempBufSize = 0; ++ } ++ } ++ if (p->code == 0) ++ *status = LZMA_STATUS_FINISHED_WITH_MARK; ++ return (p->code == 0) ? SZ_OK : SZ_ERROR_DATA; ++} ++ ++SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) ++{ ++ SizeT outSize = *destLen; ++ SizeT inSize = *srcLen; ++ *srcLen = *destLen = 0; ++ for (;;) ++ { ++ SizeT inSizeCur = inSize, outSizeCur, dicPos; ++ ELzmaFinishMode curFinishMode; ++ SRes res; ++ if (p->dicPos == p->dicBufSize) ++ p->dicPos = 0; ++ dicPos = p->dicPos; ++ if (outSize > p->dicBufSize - dicPos) ++ { ++ outSizeCur = p->dicBufSize; ++ curFinishMode = LZMA_FINISH_ANY; ++ } ++ else ++ { ++ outSizeCur = dicPos + outSize; ++ curFinishMode = finishMode; ++ } ++ ++ res = LzmaDec_DecodeToDic(p, outSizeCur, src, &inSizeCur, curFinishMode, status); ++ src += inSizeCur; ++ inSize -= inSizeCur; ++ *srcLen += inSizeCur; ++ outSizeCur = p->dicPos - dicPos; ++ memcpy(dest, p->dic + dicPos, outSizeCur); ++ dest += outSizeCur; ++ outSize -= outSizeCur; ++ *destLen += outSizeCur; ++ if (res != 0) ++ return res; ++ if (outSizeCur == 0 || outSize == 0) ++ return SZ_OK; ++ } ++} ++ ++void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc) ++{ ++ alloc->Free(alloc, p->probs); ++ p->probs = 0; ++} ++ ++static void LzmaDec_FreeDict(CLzmaDec *p, ISzAlloc *alloc) ++{ ++ alloc->Free(alloc, p->dic); ++ p->dic = 0; ++} ++ ++void LzmaDec_Free(CLzmaDec *p, ISzAlloc *alloc) ++{ ++ LzmaDec_FreeProbs(p, alloc); ++ LzmaDec_FreeDict(p, alloc); ++} ++ ++SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size) ++{ ++ UInt32 dicSize; ++ Byte d; ++ ++ if (size < LZMA_PROPS_SIZE) ++ return SZ_ERROR_UNSUPPORTED; ++ else ++ dicSize = data[1] | ((UInt32)data[2] << 8) | ((UInt32)data[3] << 16) | ((UInt32)data[4] << 24); ++ ++ if (dicSize < LZMA_DIC_MIN) ++ dicSize = LZMA_DIC_MIN; ++ p->dicSize = dicSize; ++ ++ d = data[0]; ++ if (d >= (9 * 5 * 5)) ++ return SZ_ERROR_UNSUPPORTED; ++ ++ p->lc = d % 9; ++ d /= 9; ++ p->pb = d / 5; ++ p->lp = d % 5; ++ ++ return SZ_OK; ++} ++ ++static SRes LzmaDec_AllocateProbs2(CLzmaDec *p, const CLzmaProps *propNew, ISzAlloc *alloc) ++{ ++ UInt32 numProbs = LzmaProps_GetNumProbs(propNew); ++ if (p->probs == 0 || numProbs != p->numProbs) ++ { ++ LzmaDec_FreeProbs(p, alloc); ++ p->probs = (CLzmaProb *)alloc->Alloc(alloc, numProbs * sizeof(CLzmaProb)); ++ p->numProbs = numProbs; ++ if (p->probs == 0) ++ return SZ_ERROR_MEM; ++ } ++ return SZ_OK; ++} ++ ++SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) ++{ ++ CLzmaProps propNew; ++ RINOK(LzmaProps_Decode(&propNew, props, propsSize)); ++ RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); ++ p->prop = propNew; ++ return SZ_OK; ++} ++ ++SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) ++{ ++ CLzmaProps propNew; ++ SizeT dicBufSize; ++ RINOK(LzmaProps_Decode(&propNew, props, propsSize)); ++ RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); ++ dicBufSize = propNew.dicSize; ++ if (p->dic == 0 || dicBufSize != p->dicBufSize) ++ { ++ LzmaDec_FreeDict(p, alloc); ++ p->dic = (Byte *)alloc->Alloc(alloc, dicBufSize); ++ if (p->dic == 0) ++ { ++ LzmaDec_FreeProbs(p, alloc); ++ return SZ_ERROR_MEM; ++ } ++ } ++ p->dicBufSize = dicBufSize; ++ p->prop = propNew; ++ return SZ_OK; ++} ++ ++SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ++ const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, ++ ELzmaStatus *status, ISzAlloc *alloc) ++{ ++ CLzmaDec p; ++ SRes res; ++ SizeT inSize = *srcLen; ++ SizeT outSize = *destLen; ++ *srcLen = *destLen = 0; ++ if (inSize < RC_INIT_SIZE) ++ return SZ_ERROR_INPUT_EOF; ++ ++ LzmaDec_Construct(&p); ++ res = LzmaDec_AllocateProbs(&p, propData, propSize, alloc); ++ if (res != 0) ++ return res; ++ p.dic = dest; ++ p.dicBufSize = outSize; ++ ++ LzmaDec_Init(&p); ++ ++ *srcLen = inSize; ++ res = LzmaDec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status); ++ ++ if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT) ++ res = SZ_ERROR_INPUT_EOF; ++ ++ (*destLen) = p.dicPos; ++ LzmaDec_FreeProbs(&p, alloc); ++ return res; ++} +--- /dev/null ++++ b/lib/lzma/LzmaEnc.c +@@ -0,0 +1,2271 @@ ++/* LzmaEnc.c -- LZMA Encoder ++2009-11-24 : Igor Pavlov : Public domain */ ++ ++#include ++ ++/* #define SHOW_STAT */ ++/* #define SHOW_STAT2 */ ++ ++#if defined(SHOW_STAT) || defined(SHOW_STAT2) ++#include ++#endif ++ ++#include "LzmaEnc.h" ++ ++/* disable MT */ ++#define _7ZIP_ST ++ ++#include "LzFind.h" ++#ifndef _7ZIP_ST ++#include "LzFindMt.h" ++#endif ++ ++#ifdef SHOW_STAT ++static int ttt = 0; ++#endif ++ ++#define kBlockSizeMax ((1 << LZMA_NUM_BLOCK_SIZE_BITS) - 1) ++ ++#define kBlockSize (9 << 10) ++#define kUnpackBlockSize (1 << 18) ++#define kMatchArraySize (1 << 21) ++#define kMatchRecordMaxSize ((LZMA_MATCH_LEN_MAX * 2 + 3) * LZMA_MATCH_LEN_MAX) ++ ++#define kNumMaxDirectBits (31) ++ ++#define kNumTopBits 24 ++#define kTopValue ((UInt32)1 << kNumTopBits) ++ ++#define kNumBitModelTotalBits 11 ++#define kBitModelTotal (1 << kNumBitModelTotalBits) ++#define kNumMoveBits 5 ++#define kProbInitValue (kBitModelTotal >> 1) ++ ++#define kNumMoveReducingBits 4 ++#define kNumBitPriceShiftBits 4 ++#define kBitPrice (1 << kNumBitPriceShiftBits) ++ ++void LzmaEncProps_Init(CLzmaEncProps *p) ++{ ++ p->level = 5; ++ p->dictSize = p->mc = 0; ++ p->lc = p->lp = p->pb = p->algo = p->fb = p->btMode = p->numHashBytes = p->numThreads = -1; ++ p->writeEndMark = 0; ++} ++ ++void LzmaEncProps_Normalize(CLzmaEncProps *p) ++{ ++ int level = p->level; ++ if (level < 0) level = 5; ++ p->level = level; ++ if (p->dictSize == 0) p->dictSize = (level <= 5 ? (1 << (level * 2 + 14)) : (level == 6 ? (1 << 25) : (1 << 26))); ++ if (p->lc < 0) p->lc = 3; ++ if (p->lp < 0) p->lp = 0; ++ if (p->pb < 0) p->pb = 2; ++ if (p->algo < 0) p->algo = (level < 5 ? 0 : 1); ++ if (p->fb < 0) p->fb = (level < 7 ? 32 : 64); ++ if (p->btMode < 0) p->btMode = (p->algo == 0 ? 0 : 1); ++ if (p->numHashBytes < 0) p->numHashBytes = 4; ++ if (p->mc == 0) p->mc = (16 + (p->fb >> 1)) >> (p->btMode ? 0 : 1); ++ if (p->numThreads < 0) ++ p->numThreads = ++ #ifndef _7ZIP_ST ++ ((p->btMode && p->algo) ? 2 : 1); ++ #else ++ 1; ++ #endif ++} ++ ++UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2) ++{ ++ CLzmaEncProps props = *props2; ++ LzmaEncProps_Normalize(&props); ++ return props.dictSize; ++} ++ ++/* #define LZMA_LOG_BSR */ ++/* Define it for Intel's CPU */ ++ ++ ++#ifdef LZMA_LOG_BSR ++ ++#define kDicLogSizeMaxCompress 30 ++ ++#define BSR2_RET(pos, res) { unsigned long i; _BitScanReverse(&i, (pos)); res = (i + i) + ((pos >> (i - 1)) & 1); } ++ ++UInt32 GetPosSlot1(UInt32 pos) ++{ ++ UInt32 res; ++ BSR2_RET(pos, res); ++ return res; ++} ++#define GetPosSlot2(pos, res) { BSR2_RET(pos, res); } ++#define GetPosSlot(pos, res) { if (pos < 2) res = pos; else BSR2_RET(pos, res); } ++ ++#else ++ ++#define kNumLogBits (9 + (int)sizeof(size_t) / 2) ++#define kDicLogSizeMaxCompress ((kNumLogBits - 1) * 2 + 7) ++ ++void LzmaEnc_FastPosInit(Byte *g_FastPos) ++{ ++ int c = 2, slotFast; ++ g_FastPos[0] = 0; ++ g_FastPos[1] = 1; ++ ++ for (slotFast = 2; slotFast < kNumLogBits * 2; slotFast++) ++ { ++ UInt32 k = (1 << ((slotFast >> 1) - 1)); ++ UInt32 j; ++ for (j = 0; j < k; j++, c++) ++ g_FastPos[c] = (Byte)slotFast; ++ } ++} ++ ++#define BSR2_RET(pos, res) { UInt32 i = 6 + ((kNumLogBits - 1) & \ ++ (0 - (((((UInt32)1 << (kNumLogBits + 6)) - 1) - pos) >> 31))); \ ++ res = p->g_FastPos[pos >> i] + (i * 2); } ++/* ++#define BSR2_RET(pos, res) { res = (pos < (1 << (kNumLogBits + 6))) ? \ ++ p->g_FastPos[pos >> 6] + 12 : \ ++ p->g_FastPos[pos >> (6 + kNumLogBits - 1)] + (6 + (kNumLogBits - 1)) * 2; } ++*/ ++ ++#define GetPosSlot1(pos) p->g_FastPos[pos] ++#define GetPosSlot2(pos, res) { BSR2_RET(pos, res); } ++#define GetPosSlot(pos, res) { if (pos < kNumFullDistances) res = p->g_FastPos[pos]; else BSR2_RET(pos, res); } ++ ++#endif ++ ++ ++#define LZMA_NUM_REPS 4 ++ ++typedef unsigned CState; ++ ++typedef struct ++{ ++ UInt32 price; ++ ++ CState state; ++ int prev1IsChar; ++ int prev2; ++ ++ UInt32 posPrev2; ++ UInt32 backPrev2; ++ ++ UInt32 posPrev; ++ UInt32 backPrev; ++ UInt32 backs[LZMA_NUM_REPS]; ++} COptimal; ++ ++#define kNumOpts (1 << 12) ++ ++#define kNumLenToPosStates 4 ++#define kNumPosSlotBits 6 ++#define kDicLogSizeMin 0 ++#define kDicLogSizeMax 32 ++#define kDistTableSizeMax (kDicLogSizeMax * 2) ++ ++ ++#define kNumAlignBits 4 ++#define kAlignTableSize (1 << kNumAlignBits) ++#define kAlignMask (kAlignTableSize - 1) ++ ++#define kStartPosModelIndex 4 ++#define kEndPosModelIndex 14 ++#define kNumPosModels (kEndPosModelIndex - kStartPosModelIndex) ++ ++#define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) ++ ++#ifdef _LZMA_PROB32 ++#define CLzmaProb UInt32 ++#else ++#define CLzmaProb UInt16 ++#endif ++ ++#define LZMA_PB_MAX 4 ++#define LZMA_LC_MAX 8 ++#define LZMA_LP_MAX 4 ++ ++#define LZMA_NUM_PB_STATES_MAX (1 << LZMA_PB_MAX) ++ ++ ++#define kLenNumLowBits 3 ++#define kLenNumLowSymbols (1 << kLenNumLowBits) ++#define kLenNumMidBits 3 ++#define kLenNumMidSymbols (1 << kLenNumMidBits) ++#define kLenNumHighBits 8 ++#define kLenNumHighSymbols (1 << kLenNumHighBits) ++ ++#define kLenNumSymbolsTotal (kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols) ++ ++#define LZMA_MATCH_LEN_MIN 2 ++#define LZMA_MATCH_LEN_MAX (LZMA_MATCH_LEN_MIN + kLenNumSymbolsTotal - 1) ++ ++#define kNumStates 12 ++ ++typedef struct ++{ ++ CLzmaProb choice; ++ CLzmaProb choice2; ++ CLzmaProb low[LZMA_NUM_PB_STATES_MAX << kLenNumLowBits]; ++ CLzmaProb mid[LZMA_NUM_PB_STATES_MAX << kLenNumMidBits]; ++ CLzmaProb high[kLenNumHighSymbols]; ++} CLenEnc; ++ ++typedef struct ++{ ++ CLenEnc p; ++ UInt32 prices[LZMA_NUM_PB_STATES_MAX][kLenNumSymbolsTotal]; ++ UInt32 tableSize; ++ UInt32 counters[LZMA_NUM_PB_STATES_MAX]; ++} CLenPriceEnc; ++ ++typedef struct ++{ ++ UInt32 range; ++ Byte cache; ++ UInt64 low; ++ UInt64 cacheSize; ++ Byte *buf; ++ Byte *bufLim; ++ Byte *bufBase; ++ ISeqOutStream *outStream; ++ UInt64 processed; ++ SRes res; ++} CRangeEnc; ++ ++typedef struct ++{ ++ CLzmaProb *litProbs; ++ ++ CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX]; ++ CLzmaProb isRep[kNumStates]; ++ CLzmaProb isRepG0[kNumStates]; ++ CLzmaProb isRepG1[kNumStates]; ++ CLzmaProb isRepG2[kNumStates]; ++ CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX]; ++ ++ CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits]; ++ CLzmaProb posEncoders[kNumFullDistances - kEndPosModelIndex]; ++ CLzmaProb posAlignEncoder[1 << kNumAlignBits]; ++ ++ CLenPriceEnc lenEnc; ++ CLenPriceEnc repLenEnc; ++ ++ UInt32 reps[LZMA_NUM_REPS]; ++ UInt32 state; ++} CSaveState; ++ ++typedef struct ++{ ++ IMatchFinder matchFinder; ++ void *matchFinderObj; ++ ++ #ifndef _7ZIP_ST ++ Bool mtMode; ++ CMatchFinderMt matchFinderMt; ++ #endif ++ ++ CMatchFinder matchFinderBase; ++ ++ #ifndef _7ZIP_ST ++ Byte pad[128]; ++ #endif ++ ++ UInt32 optimumEndIndex; ++ UInt32 optimumCurrentIndex; ++ ++ UInt32 longestMatchLength; ++ UInt32 numPairs; ++ UInt32 numAvail; ++ COptimal opt[kNumOpts]; ++ ++ #ifndef LZMA_LOG_BSR ++ Byte g_FastPos[1 << kNumLogBits]; ++ #endif ++ ++ UInt32 ProbPrices[kBitModelTotal >> kNumMoveReducingBits]; ++ UInt32 matches[LZMA_MATCH_LEN_MAX * 2 + 2 + 1]; ++ UInt32 numFastBytes; ++ UInt32 additionalOffset; ++ UInt32 reps[LZMA_NUM_REPS]; ++ UInt32 state; ++ ++ UInt32 posSlotPrices[kNumLenToPosStates][kDistTableSizeMax]; ++ UInt32 distancesPrices[kNumLenToPosStates][kNumFullDistances]; ++ UInt32 alignPrices[kAlignTableSize]; ++ UInt32 alignPriceCount; ++ ++ UInt32 distTableSize; ++ ++ unsigned lc, lp, pb; ++ unsigned lpMask, pbMask; ++ ++ CLzmaProb *litProbs; ++ ++ CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX]; ++ CLzmaProb isRep[kNumStates]; ++ CLzmaProb isRepG0[kNumStates]; ++ CLzmaProb isRepG1[kNumStates]; ++ CLzmaProb isRepG2[kNumStates]; ++ CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX]; ++ ++ CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits]; ++ CLzmaProb posEncoders[kNumFullDistances - kEndPosModelIndex]; ++ CLzmaProb posAlignEncoder[1 << kNumAlignBits]; ++ ++ CLenPriceEnc lenEnc; ++ CLenPriceEnc repLenEnc; ++ ++ unsigned lclp; ++ ++ Bool fastMode; ++ ++ CRangeEnc rc; ++ ++ Bool writeEndMark; ++ UInt64 nowPos64; ++ UInt32 matchPriceCount; ++ Bool finished; ++ Bool multiThread; ++ ++ SRes result; ++ UInt32 dictSize; ++ UInt32 matchFinderCycles; ++ ++ int needInit; ++ ++ CSaveState saveState; ++} CLzmaEnc; ++ ++void LzmaEnc_SaveState(CLzmaEncHandle pp) ++{ ++ CLzmaEnc *p = (CLzmaEnc *)pp; ++ CSaveState *dest = &p->saveState; ++ int i; ++ dest->lenEnc = p->lenEnc; ++ dest->repLenEnc = p->repLenEnc; ++ dest->state = p->state; ++ ++ for (i = 0; i < kNumStates; i++) ++ { ++ memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i])); ++ memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i])); ++ } ++ for (i = 0; i < kNumLenToPosStates; i++) ++ memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i])); ++ memcpy(dest->isRep, p->isRep, sizeof(p->isRep)); ++ memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0)); ++ memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1)); ++ memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2)); ++ memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders)); ++ memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder)); ++ memcpy(dest->reps, p->reps, sizeof(p->reps)); ++ memcpy(dest->litProbs, p->litProbs, (0x300 << p->lclp) * sizeof(CLzmaProb)); ++} ++ ++void LzmaEnc_RestoreState(CLzmaEncHandle pp) ++{ ++ CLzmaEnc *dest = (CLzmaEnc *)pp; ++ const CSaveState *p = &dest->saveState; ++ int i; ++ dest->lenEnc = p->lenEnc; ++ dest->repLenEnc = p->repLenEnc; ++ dest->state = p->state; ++ ++ for (i = 0; i < kNumStates; i++) ++ { ++ memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i])); ++ memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i])); ++ } ++ for (i = 0; i < kNumLenToPosStates; i++) ++ memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i])); ++ memcpy(dest->isRep, p->isRep, sizeof(p->isRep)); ++ memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0)); ++ memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1)); ++ memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2)); ++ memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders)); ++ memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder)); ++ memcpy(dest->reps, p->reps, sizeof(p->reps)); ++ memcpy(dest->litProbs, p->litProbs, (0x300 << dest->lclp) * sizeof(CLzmaProb)); ++} ++ ++SRes LzmaEnc_SetProps(CLzmaEncHandle pp, const CLzmaEncProps *props2) ++{ ++ CLzmaEnc *p = (CLzmaEnc *)pp; ++ CLzmaEncProps props = *props2; ++ LzmaEncProps_Normalize(&props); ++ ++ if (props.lc > LZMA_LC_MAX || props.lp > LZMA_LP_MAX || props.pb > LZMA_PB_MAX || ++ props.dictSize > (1 << kDicLogSizeMaxCompress) || props.dictSize > (1 << 30)) ++ return SZ_ERROR_PARAM; ++ p->dictSize = props.dictSize; ++ p->matchFinderCycles = props.mc; ++ { ++ unsigned fb = props.fb; ++ if (fb < 5) ++ fb = 5; ++ if (fb > LZMA_MATCH_LEN_MAX) ++ fb = LZMA_MATCH_LEN_MAX; ++ p->numFastBytes = fb; ++ } ++ p->lc = props.lc; ++ p->lp = props.lp; ++ p->pb = props.pb; ++ p->fastMode = (props.algo == 0); ++ p->matchFinderBase.btMode = props.btMode; ++ { ++ UInt32 numHashBytes = 4; ++ if (props.btMode) ++ { ++ if (props.numHashBytes < 2) ++ numHashBytes = 2; ++ else if (props.numHashBytes < 4) ++ numHashBytes = props.numHashBytes; ++ } ++ p->matchFinderBase.numHashBytes = numHashBytes; ++ } ++ ++ p->matchFinderBase.cutValue = props.mc; ++ ++ p->writeEndMark = props.writeEndMark; ++ ++ #ifndef _7ZIP_ST ++ /* ++ if (newMultiThread != _multiThread) ++ { ++ ReleaseMatchFinder(); ++ _multiThread = newMultiThread; ++ } ++ */ ++ p->multiThread = (props.numThreads > 1); ++ #endif ++ ++ return SZ_OK; ++} ++ ++static const int kLiteralNextStates[kNumStates] = {0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5}; ++static const int kMatchNextStates[kNumStates] = {7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10}; ++static const int kRepNextStates[kNumStates] = {8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11}; ++static const int kShortRepNextStates[kNumStates]= {9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11}; ++ ++#define IsCharState(s) ((s) < 7) ++ ++#define GetLenToPosState(len) (((len) < kNumLenToPosStates + 1) ? (len) - 2 : kNumLenToPosStates - 1) ++ ++#define kInfinityPrice (1 << 30) ++ ++static void RangeEnc_Construct(CRangeEnc *p) ++{ ++ p->outStream = 0; ++ p->bufBase = 0; ++} ++ ++#define RangeEnc_GetProcessed(p) ((p)->processed + ((p)->buf - (p)->bufBase) + (p)->cacheSize) ++ ++#define RC_BUF_SIZE (1 << 16) ++static int RangeEnc_Alloc(CRangeEnc *p, ISzAlloc *alloc) ++{ ++ if (p->bufBase == 0) ++ { ++ p->bufBase = (Byte *)alloc->Alloc(alloc, RC_BUF_SIZE); ++ if (p->bufBase == 0) ++ return 0; ++ p->bufLim = p->bufBase + RC_BUF_SIZE; ++ } ++ return 1; ++} ++ ++static void RangeEnc_Free(CRangeEnc *p, ISzAlloc *alloc) ++{ ++ alloc->Free(alloc, p->bufBase); ++ p->bufBase = 0; ++} ++ ++static void RangeEnc_Init(CRangeEnc *p) ++{ ++ /* Stream.Init(); */ ++ p->low = 0; ++ p->range = 0xFFFFFFFF; ++ p->cacheSize = 1; ++ p->cache = 0; ++ ++ p->buf = p->bufBase; ++ ++ p->processed = 0; ++ p->res = SZ_OK; ++} ++ ++static void RangeEnc_FlushStream(CRangeEnc *p) ++{ ++ size_t num; ++ if (p->res != SZ_OK) ++ return; ++ num = p->buf - p->bufBase; ++ if (num != p->outStream->Write(p->outStream, p->bufBase, num)) ++ p->res = SZ_ERROR_WRITE; ++ p->processed += num; ++ p->buf = p->bufBase; ++} ++ ++static void MY_FAST_CALL RangeEnc_ShiftLow(CRangeEnc *p) ++{ ++ if ((UInt32)p->low < (UInt32)0xFF000000 || (int)(p->low >> 32) != 0) ++ { ++ Byte temp = p->cache; ++ do ++ { ++ Byte *buf = p->buf; ++ *buf++ = (Byte)(temp + (Byte)(p->low >> 32)); ++ p->buf = buf; ++ if (buf == p->bufLim) ++ RangeEnc_FlushStream(p); ++ temp = 0xFF; ++ } ++ while (--p->cacheSize != 0); ++ p->cache = (Byte)((UInt32)p->low >> 24); ++ } ++ p->cacheSize++; ++ p->low = (UInt32)p->low << 8; ++} ++ ++static void RangeEnc_FlushData(CRangeEnc *p) ++{ ++ int i; ++ for (i = 0; i < 5; i++) ++ RangeEnc_ShiftLow(p); ++} ++ ++static void RangeEnc_EncodeDirectBits(CRangeEnc *p, UInt32 value, int numBits) ++{ ++ do ++ { ++ p->range >>= 1; ++ p->low += p->range & (0 - ((value >> --numBits) & 1)); ++ if (p->range < kTopValue) ++ { ++ p->range <<= 8; ++ RangeEnc_ShiftLow(p); ++ } ++ } ++ while (numBits != 0); ++} ++ ++static void RangeEnc_EncodeBit(CRangeEnc *p, CLzmaProb *prob, UInt32 symbol) ++{ ++ UInt32 ttt = *prob; ++ UInt32 newBound = (p->range >> kNumBitModelTotalBits) * ttt; ++ if (symbol == 0) ++ { ++ p->range = newBound; ++ ttt += (kBitModelTotal - ttt) >> kNumMoveBits; ++ } ++ else ++ { ++ p->low += newBound; ++ p->range -= newBound; ++ ttt -= ttt >> kNumMoveBits; ++ } ++ *prob = (CLzmaProb)ttt; ++ if (p->range < kTopValue) ++ { ++ p->range <<= 8; ++ RangeEnc_ShiftLow(p); ++ } ++} ++ ++static void LitEnc_Encode(CRangeEnc *p, CLzmaProb *probs, UInt32 symbol) ++{ ++ symbol |= 0x100; ++ do ++ { ++ RangeEnc_EncodeBit(p, probs + (symbol >> 8), (symbol >> 7) & 1); ++ symbol <<= 1; ++ } ++ while (symbol < 0x10000); ++} ++ ++static void LitEnc_EncodeMatched(CRangeEnc *p, CLzmaProb *probs, UInt32 symbol, UInt32 matchByte) ++{ ++ UInt32 offs = 0x100; ++ symbol |= 0x100; ++ do ++ { ++ matchByte <<= 1; ++ RangeEnc_EncodeBit(p, probs + (offs + (matchByte & offs) + (symbol >> 8)), (symbol >> 7) & 1); ++ symbol <<= 1; ++ offs &= ~(matchByte ^ symbol); ++ } ++ while (symbol < 0x10000); ++} ++ ++void LzmaEnc_InitPriceTables(UInt32 *ProbPrices) ++{ ++ UInt32 i; ++ for (i = (1 << kNumMoveReducingBits) / 2; i < kBitModelTotal; i += (1 << kNumMoveReducingBits)) ++ { ++ const int kCyclesBits = kNumBitPriceShiftBits; ++ UInt32 w = i; ++ UInt32 bitCount = 0; ++ int j; ++ for (j = 0; j < kCyclesBits; j++) ++ { ++ w = w * w; ++ bitCount <<= 1; ++ while (w >= ((UInt32)1 << 16)) ++ { ++ w >>= 1; ++ bitCount++; ++ } ++ } ++ ProbPrices[i >> kNumMoveReducingBits] = ((kNumBitModelTotalBits << kCyclesBits) - 15 - bitCount); ++ } ++} ++ ++ ++#define GET_PRICE(prob, symbol) \ ++ p->ProbPrices[((prob) ^ (((-(int)(symbol))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits]; ++ ++#define GET_PRICEa(prob, symbol) \ ++ ProbPrices[((prob) ^ ((-((int)(symbol))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits]; ++ ++#define GET_PRICE_0(prob) p->ProbPrices[(prob) >> kNumMoveReducingBits] ++#define GET_PRICE_1(prob) p->ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits] ++ ++#define GET_PRICE_0a(prob) ProbPrices[(prob) >> kNumMoveReducingBits] ++#define GET_PRICE_1a(prob) ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits] ++ ++static UInt32 LitEnc_GetPrice(const CLzmaProb *probs, UInt32 symbol, UInt32 *ProbPrices) ++{ ++ UInt32 price = 0; ++ symbol |= 0x100; ++ do ++ { ++ price += GET_PRICEa(probs[symbol >> 8], (symbol >> 7) & 1); ++ symbol <<= 1; ++ } ++ while (symbol < 0x10000); ++ return price; ++} ++ ++static UInt32 LitEnc_GetPriceMatched(const CLzmaProb *probs, UInt32 symbol, UInt32 matchByte, UInt32 *ProbPrices) ++{ ++ UInt32 price = 0; ++ UInt32 offs = 0x100; ++ symbol |= 0x100; ++ do ++ { ++ matchByte <<= 1; ++ price += GET_PRICEa(probs[offs + (matchByte & offs) + (symbol >> 8)], (symbol >> 7) & 1); ++ symbol <<= 1; ++ offs &= ~(matchByte ^ symbol); ++ } ++ while (symbol < 0x10000); ++ return price; ++} ++ ++ ++static void RcTree_Encode(CRangeEnc *rc, CLzmaProb *probs, int numBitLevels, UInt32 symbol) ++{ ++ UInt32 m = 1; ++ int i; ++ for (i = numBitLevels; i != 0;) ++ { ++ UInt32 bit; ++ i--; ++ bit = (symbol >> i) & 1; ++ RangeEnc_EncodeBit(rc, probs + m, bit); ++ m = (m << 1) | bit; ++ } ++} ++ ++static void RcTree_ReverseEncode(CRangeEnc *rc, CLzmaProb *probs, int numBitLevels, UInt32 symbol) ++{ ++ UInt32 m = 1; ++ int i; ++ for (i = 0; i < numBitLevels; i++) ++ { ++ UInt32 bit = symbol & 1; ++ RangeEnc_EncodeBit(rc, probs + m, bit); ++ m = (m << 1) | bit; ++ symbol >>= 1; ++ } ++} ++ ++static UInt32 RcTree_GetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, UInt32 *ProbPrices) ++{ ++ UInt32 price = 0; ++ symbol |= (1 << numBitLevels); ++ while (symbol != 1) ++ { ++ price += GET_PRICEa(probs[symbol >> 1], symbol & 1); ++ symbol >>= 1; ++ } ++ return price; ++} ++ ++static UInt32 RcTree_ReverseGetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, UInt32 *ProbPrices) ++{ ++ UInt32 price = 0; ++ UInt32 m = 1; ++ int i; ++ for (i = numBitLevels; i != 0; i--) ++ { ++ UInt32 bit = symbol & 1; ++ symbol >>= 1; ++ price += GET_PRICEa(probs[m], bit); ++ m = (m << 1) | bit; ++ } ++ return price; ++} ++ ++ ++static void LenEnc_Init(CLenEnc *p) ++{ ++ unsigned i; ++ p->choice = p->choice2 = kProbInitValue; ++ for (i = 0; i < (LZMA_NUM_PB_STATES_MAX << kLenNumLowBits); i++) ++ p->low[i] = kProbInitValue; ++ for (i = 0; i < (LZMA_NUM_PB_STATES_MAX << kLenNumMidBits); i++) ++ p->mid[i] = kProbInitValue; ++ for (i = 0; i < kLenNumHighSymbols; i++) ++ p->high[i] = kProbInitValue; ++} ++ ++static void LenEnc_Encode(CLenEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 posState) ++{ ++ if (symbol < kLenNumLowSymbols) ++ { ++ RangeEnc_EncodeBit(rc, &p->choice, 0); ++ RcTree_Encode(rc, p->low + (posState << kLenNumLowBits), kLenNumLowBits, symbol); ++ } ++ else ++ { ++ RangeEnc_EncodeBit(rc, &p->choice, 1); ++ if (symbol < kLenNumLowSymbols + kLenNumMidSymbols) ++ { ++ RangeEnc_EncodeBit(rc, &p->choice2, 0); ++ RcTree_Encode(rc, p->mid + (posState << kLenNumMidBits), kLenNumMidBits, symbol - kLenNumLowSymbols); ++ } ++ else ++ { ++ RangeEnc_EncodeBit(rc, &p->choice2, 1); ++ RcTree_Encode(rc, p->high, kLenNumHighBits, symbol - kLenNumLowSymbols - kLenNumMidSymbols); ++ } ++ } ++} ++ ++static void LenEnc_SetPrices(CLenEnc *p, UInt32 posState, UInt32 numSymbols, UInt32 *prices, UInt32 *ProbPrices) ++{ ++ UInt32 a0 = GET_PRICE_0a(p->choice); ++ UInt32 a1 = GET_PRICE_1a(p->choice); ++ UInt32 b0 = a1 + GET_PRICE_0a(p->choice2); ++ UInt32 b1 = a1 + GET_PRICE_1a(p->choice2); ++ UInt32 i = 0; ++ for (i = 0; i < kLenNumLowSymbols; i++) ++ { ++ if (i >= numSymbols) ++ return; ++ prices[i] = a0 + RcTree_GetPrice(p->low + (posState << kLenNumLowBits), kLenNumLowBits, i, ProbPrices); ++ } ++ for (; i < kLenNumLowSymbols + kLenNumMidSymbols; i++) ++ { ++ if (i >= numSymbols) ++ return; ++ prices[i] = b0 + RcTree_GetPrice(p->mid + (posState << kLenNumMidBits), kLenNumMidBits, i - kLenNumLowSymbols, ProbPrices); ++ } ++ for (; i < numSymbols; i++) ++ prices[i] = b1 + RcTree_GetPrice(p->high, kLenNumHighBits, i - kLenNumLowSymbols - kLenNumMidSymbols, ProbPrices); ++} ++ ++static void MY_FAST_CALL LenPriceEnc_UpdateTable(CLenPriceEnc *p, UInt32 posState, UInt32 *ProbPrices) ++{ ++ LenEnc_SetPrices(&p->p, posState, p->tableSize, p->prices[posState], ProbPrices); ++ p->counters[posState] = p->tableSize; ++} ++ ++static void LenPriceEnc_UpdateTables(CLenPriceEnc *p, UInt32 numPosStates, UInt32 *ProbPrices) ++{ ++ UInt32 posState; ++ for (posState = 0; posState < numPosStates; posState++) ++ LenPriceEnc_UpdateTable(p, posState, ProbPrices); ++} ++ ++static void LenEnc_Encode2(CLenPriceEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 posState, Bool updatePrice, UInt32 *ProbPrices) ++{ ++ LenEnc_Encode(&p->p, rc, symbol, posState); ++ if (updatePrice) ++ if (--p->counters[posState] == 0) ++ LenPriceEnc_UpdateTable(p, posState, ProbPrices); ++} ++ ++ ++ ++ ++static void MovePos(CLzmaEnc *p, UInt32 num) ++{ ++ #ifdef SHOW_STAT ++ ttt += num; ++ printf("\n MovePos %d", num); ++ #endif ++ if (num != 0) ++ { ++ p->additionalOffset += num; ++ p->matchFinder.Skip(p->matchFinderObj, num); ++ } ++} ++ ++static UInt32 ReadMatchDistances(CLzmaEnc *p, UInt32 *numDistancePairsRes) ++{ ++ UInt32 lenRes = 0, numPairs; ++ p->numAvail = p->matchFinder.GetNumAvailableBytes(p->matchFinderObj); ++ numPairs = p->matchFinder.GetMatches(p->matchFinderObj, p->matches); ++ #ifdef SHOW_STAT ++ printf("\n i = %d numPairs = %d ", ttt, numPairs / 2); ++ ttt++; ++ { ++ UInt32 i; ++ for (i = 0; i < numPairs; i += 2) ++ printf("%2d %6d | ", p->matches[i], p->matches[i + 1]); ++ } ++ #endif ++ if (numPairs > 0) ++ { ++ lenRes = p->matches[numPairs - 2]; ++ if (lenRes == p->numFastBytes) ++ { ++ const Byte *pby = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; ++ UInt32 distance = p->matches[numPairs - 1] + 1; ++ UInt32 numAvail = p->numAvail; ++ if (numAvail > LZMA_MATCH_LEN_MAX) ++ numAvail = LZMA_MATCH_LEN_MAX; ++ { ++ const Byte *pby2 = pby - distance; ++ for (; lenRes < numAvail && pby[lenRes] == pby2[lenRes]; lenRes++); ++ } ++ } ++ } ++ p->additionalOffset++; ++ *numDistancePairsRes = numPairs; ++ return lenRes; ++} ++ ++ ++#define MakeAsChar(p) (p)->backPrev = (UInt32)(-1); (p)->prev1IsChar = False; ++#define MakeAsShortRep(p) (p)->backPrev = 0; (p)->prev1IsChar = False; ++#define IsShortRep(p) ((p)->backPrev == 0) ++ ++static UInt32 GetRepLen1Price(CLzmaEnc *p, UInt32 state, UInt32 posState) ++{ ++ return ++ GET_PRICE_0(p->isRepG0[state]) + ++ GET_PRICE_0(p->isRep0Long[state][posState]); ++} ++ ++static UInt32 GetPureRepPrice(CLzmaEnc *p, UInt32 repIndex, UInt32 state, UInt32 posState) ++{ ++ UInt32 price; ++ if (repIndex == 0) ++ { ++ price = GET_PRICE_0(p->isRepG0[state]); ++ price += GET_PRICE_1(p->isRep0Long[state][posState]); ++ } ++ else ++ { ++ price = GET_PRICE_1(p->isRepG0[state]); ++ if (repIndex == 1) ++ price += GET_PRICE_0(p->isRepG1[state]); ++ else ++ { ++ price += GET_PRICE_1(p->isRepG1[state]); ++ price += GET_PRICE(p->isRepG2[state], repIndex - 2); ++ } ++ } ++ return price; ++} ++ ++static UInt32 GetRepPrice(CLzmaEnc *p, UInt32 repIndex, UInt32 len, UInt32 state, UInt32 posState) ++{ ++ return p->repLenEnc.prices[posState][len - LZMA_MATCH_LEN_MIN] + ++ GetPureRepPrice(p, repIndex, state, posState); ++} ++ ++static UInt32 Backward(CLzmaEnc *p, UInt32 *backRes, UInt32 cur) ++{ ++ UInt32 posMem = p->opt[cur].posPrev; ++ UInt32 backMem = p->opt[cur].backPrev; ++ p->optimumEndIndex = cur; ++ do ++ { ++ if (p->opt[cur].prev1IsChar) ++ { ++ MakeAsChar(&p->opt[posMem]) ++ p->opt[posMem].posPrev = posMem - 1; ++ if (p->opt[cur].prev2) ++ { ++ p->opt[posMem - 1].prev1IsChar = False; ++ p->opt[posMem - 1].posPrev = p->opt[cur].posPrev2; ++ p->opt[posMem - 1].backPrev = p->opt[cur].backPrev2; ++ } ++ } ++ { ++ UInt32 posPrev = posMem; ++ UInt32 backCur = backMem; ++ ++ backMem = p->opt[posPrev].backPrev; ++ posMem = p->opt[posPrev].posPrev; ++ ++ p->opt[posPrev].backPrev = backCur; ++ p->opt[posPrev].posPrev = cur; ++ cur = posPrev; ++ } ++ } ++ while (cur != 0); ++ *backRes = p->opt[0].backPrev; ++ p->optimumCurrentIndex = p->opt[0].posPrev; ++ return p->optimumCurrentIndex; ++} ++ ++#define LIT_PROBS(pos, prevByte) (p->litProbs + ((((pos) & p->lpMask) << p->lc) + ((prevByte) >> (8 - p->lc))) * 0x300) ++ ++static UInt32 GetOptimum(CLzmaEnc *p, UInt32 position, UInt32 *backRes) ++{ ++ UInt32 numAvail, mainLen, numPairs, repMaxIndex, i, posState, lenEnd, len, cur; ++ UInt32 matchPrice, repMatchPrice, normalMatchPrice; ++ UInt32 reps[LZMA_NUM_REPS], repLens[LZMA_NUM_REPS]; ++ UInt32 *matches; ++ const Byte *data; ++ Byte curByte, matchByte; ++ if (p->optimumEndIndex != p->optimumCurrentIndex) ++ { ++ const COptimal *opt = &p->opt[p->optimumCurrentIndex]; ++ UInt32 lenRes = opt->posPrev - p->optimumCurrentIndex; ++ *backRes = opt->backPrev; ++ p->optimumCurrentIndex = opt->posPrev; ++ return lenRes; ++ } ++ p->optimumCurrentIndex = p->optimumEndIndex = 0; ++ ++ if (p->additionalOffset == 0) ++ mainLen = ReadMatchDistances(p, &numPairs); ++ else ++ { ++ mainLen = p->longestMatchLength; ++ numPairs = p->numPairs; ++ } ++ ++ numAvail = p->numAvail; ++ if (numAvail < 2) ++ { ++ *backRes = (UInt32)(-1); ++ return 1; ++ } ++ if (numAvail > LZMA_MATCH_LEN_MAX) ++ numAvail = LZMA_MATCH_LEN_MAX; ++ ++ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; ++ repMaxIndex = 0; ++ for (i = 0; i < LZMA_NUM_REPS; i++) ++ { ++ UInt32 lenTest; ++ const Byte *data2; ++ reps[i] = p->reps[i]; ++ data2 = data - (reps[i] + 1); ++ if (data[0] != data2[0] || data[1] != data2[1]) ++ { ++ repLens[i] = 0; ++ continue; ++ } ++ for (lenTest = 2; lenTest < numAvail && data[lenTest] == data2[lenTest]; lenTest++); ++ repLens[i] = lenTest; ++ if (lenTest > repLens[repMaxIndex]) ++ repMaxIndex = i; ++ } ++ if (repLens[repMaxIndex] >= p->numFastBytes) ++ { ++ UInt32 lenRes; ++ *backRes = repMaxIndex; ++ lenRes = repLens[repMaxIndex]; ++ MovePos(p, lenRes - 1); ++ return lenRes; ++ } ++ ++ matches = p->matches; ++ if (mainLen >= p->numFastBytes) ++ { ++ *backRes = matches[numPairs - 1] + LZMA_NUM_REPS; ++ MovePos(p, mainLen - 1); ++ return mainLen; ++ } ++ curByte = *data; ++ matchByte = *(data - (reps[0] + 1)); ++ ++ if (mainLen < 2 && curByte != matchByte && repLens[repMaxIndex] < 2) ++ { ++ *backRes = (UInt32)-1; ++ return 1; ++ } ++ ++ p->opt[0].state = (CState)p->state; ++ ++ posState = (position & p->pbMask); ++ ++ { ++ const CLzmaProb *probs = LIT_PROBS(position, *(data - 1)); ++ p->opt[1].price = GET_PRICE_0(p->isMatch[p->state][posState]) + ++ (!IsCharState(p->state) ? ++ LitEnc_GetPriceMatched(probs, curByte, matchByte, p->ProbPrices) : ++ LitEnc_GetPrice(probs, curByte, p->ProbPrices)); ++ } ++ ++ MakeAsChar(&p->opt[1]); ++ ++ matchPrice = GET_PRICE_1(p->isMatch[p->state][posState]); ++ repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[p->state]); ++ ++ if (matchByte == curByte) ++ { ++ UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(p, p->state, posState); ++ if (shortRepPrice < p->opt[1].price) ++ { ++ p->opt[1].price = shortRepPrice; ++ MakeAsShortRep(&p->opt[1]); ++ } ++ } ++ lenEnd = ((mainLen >= repLens[repMaxIndex]) ? mainLen : repLens[repMaxIndex]); ++ ++ if (lenEnd < 2) ++ { ++ *backRes = p->opt[1].backPrev; ++ return 1; ++ } ++ ++ p->opt[1].posPrev = 0; ++ for (i = 0; i < LZMA_NUM_REPS; i++) ++ p->opt[0].backs[i] = reps[i]; ++ ++ len = lenEnd; ++ do ++ p->opt[len--].price = kInfinityPrice; ++ while (len >= 2); ++ ++ for (i = 0; i < LZMA_NUM_REPS; i++) ++ { ++ UInt32 repLen = repLens[i]; ++ UInt32 price; ++ if (repLen < 2) ++ continue; ++ price = repMatchPrice + GetPureRepPrice(p, i, p->state, posState); ++ do ++ { ++ UInt32 curAndLenPrice = price + p->repLenEnc.prices[posState][repLen - 2]; ++ COptimal *opt = &p->opt[repLen]; ++ if (curAndLenPrice < opt->price) ++ { ++ opt->price = curAndLenPrice; ++ opt->posPrev = 0; ++ opt->backPrev = i; ++ opt->prev1IsChar = False; ++ } ++ } ++ while (--repLen >= 2); ++ } ++ ++ normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[p->state]); ++ ++ len = ((repLens[0] >= 2) ? repLens[0] + 1 : 2); ++ if (len <= mainLen) ++ { ++ UInt32 offs = 0; ++ while (len > matches[offs]) ++ offs += 2; ++ for (; ; len++) ++ { ++ COptimal *opt; ++ UInt32 distance = matches[offs + 1]; ++ ++ UInt32 curAndLenPrice = normalMatchPrice + p->lenEnc.prices[posState][len - LZMA_MATCH_LEN_MIN]; ++ UInt32 lenToPosState = GetLenToPosState(len); ++ if (distance < kNumFullDistances) ++ curAndLenPrice += p->distancesPrices[lenToPosState][distance]; ++ else ++ { ++ UInt32 slot; ++ GetPosSlot2(distance, slot); ++ curAndLenPrice += p->alignPrices[distance & kAlignMask] + p->posSlotPrices[lenToPosState][slot]; ++ } ++ opt = &p->opt[len]; ++ if (curAndLenPrice < opt->price) ++ { ++ opt->price = curAndLenPrice; ++ opt->posPrev = 0; ++ opt->backPrev = distance + LZMA_NUM_REPS; ++ opt->prev1IsChar = False; ++ } ++ if (len == matches[offs]) ++ { ++ offs += 2; ++ if (offs == numPairs) ++ break; ++ } ++ } ++ } ++ ++ cur = 0; ++ ++ #ifdef SHOW_STAT2 ++ if (position >= 0) ++ { ++ unsigned i; ++ printf("\n pos = %4X", position); ++ for (i = cur; i <= lenEnd; i++) ++ printf("\nprice[%4X] = %d", position - cur + i, p->opt[i].price); ++ } ++ #endif ++ ++ for (;;) ++ { ++ UInt32 numAvailFull, newLen, numPairs, posPrev, state, posState, startLen; ++ UInt32 curPrice, curAnd1Price, matchPrice, repMatchPrice; ++ Bool nextIsChar; ++ Byte curByte, matchByte; ++ const Byte *data; ++ COptimal *curOpt; ++ COptimal *nextOpt; ++ ++ cur++; ++ if (cur == lenEnd) ++ return Backward(p, backRes, cur); ++ ++ newLen = ReadMatchDistances(p, &numPairs); ++ if (newLen >= p->numFastBytes) ++ { ++ p->numPairs = numPairs; ++ p->longestMatchLength = newLen; ++ return Backward(p, backRes, cur); ++ } ++ position++; ++ curOpt = &p->opt[cur]; ++ posPrev = curOpt->posPrev; ++ if (curOpt->prev1IsChar) ++ { ++ posPrev--; ++ if (curOpt->prev2) ++ { ++ state = p->opt[curOpt->posPrev2].state; ++ if (curOpt->backPrev2 < LZMA_NUM_REPS) ++ state = kRepNextStates[state]; ++ else ++ state = kMatchNextStates[state]; ++ } ++ else ++ state = p->opt[posPrev].state; ++ state = kLiteralNextStates[state]; ++ } ++ else ++ state = p->opt[posPrev].state; ++ if (posPrev == cur - 1) ++ { ++ if (IsShortRep(curOpt)) ++ state = kShortRepNextStates[state]; ++ else ++ state = kLiteralNextStates[state]; ++ } ++ else ++ { ++ UInt32 pos; ++ const COptimal *prevOpt; ++ if (curOpt->prev1IsChar && curOpt->prev2) ++ { ++ posPrev = curOpt->posPrev2; ++ pos = curOpt->backPrev2; ++ state = kRepNextStates[state]; ++ } ++ else ++ { ++ pos = curOpt->backPrev; ++ if (pos < LZMA_NUM_REPS) ++ state = kRepNextStates[state]; ++ else ++ state = kMatchNextStates[state]; ++ } ++ prevOpt = &p->opt[posPrev]; ++ if (pos < LZMA_NUM_REPS) ++ { ++ UInt32 i; ++ reps[0] = prevOpt->backs[pos]; ++ for (i = 1; i <= pos; i++) ++ reps[i] = prevOpt->backs[i - 1]; ++ for (; i < LZMA_NUM_REPS; i++) ++ reps[i] = prevOpt->backs[i]; ++ } ++ else ++ { ++ UInt32 i; ++ reps[0] = (pos - LZMA_NUM_REPS); ++ for (i = 1; i < LZMA_NUM_REPS; i++) ++ reps[i] = prevOpt->backs[i - 1]; ++ } ++ } ++ curOpt->state = (CState)state; ++ ++ curOpt->backs[0] = reps[0]; ++ curOpt->backs[1] = reps[1]; ++ curOpt->backs[2] = reps[2]; ++ curOpt->backs[3] = reps[3]; ++ ++ curPrice = curOpt->price; ++ nextIsChar = False; ++ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; ++ curByte = *data; ++ matchByte = *(data - (reps[0] + 1)); ++ ++ posState = (position & p->pbMask); ++ ++ curAnd1Price = curPrice + GET_PRICE_0(p->isMatch[state][posState]); ++ { ++ const CLzmaProb *probs = LIT_PROBS(position, *(data - 1)); ++ curAnd1Price += ++ (!IsCharState(state) ? ++ LitEnc_GetPriceMatched(probs, curByte, matchByte, p->ProbPrices) : ++ LitEnc_GetPrice(probs, curByte, p->ProbPrices)); ++ } ++ ++ nextOpt = &p->opt[cur + 1]; ++ ++ if (curAnd1Price < nextOpt->price) ++ { ++ nextOpt->price = curAnd1Price; ++ nextOpt->posPrev = cur; ++ MakeAsChar(nextOpt); ++ nextIsChar = True; ++ } ++ ++ matchPrice = curPrice + GET_PRICE_1(p->isMatch[state][posState]); ++ repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[state]); ++ ++ if (matchByte == curByte && !(nextOpt->posPrev < cur && nextOpt->backPrev == 0)) ++ { ++ UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(p, state, posState); ++ if (shortRepPrice <= nextOpt->price) ++ { ++ nextOpt->price = shortRepPrice; ++ nextOpt->posPrev = cur; ++ MakeAsShortRep(nextOpt); ++ nextIsChar = True; ++ } ++ } ++ numAvailFull = p->numAvail; ++ { ++ UInt32 temp = kNumOpts - 1 - cur; ++ if (temp < numAvailFull) ++ numAvailFull = temp; ++ } ++ ++ if (numAvailFull < 2) ++ continue; ++ numAvail = (numAvailFull <= p->numFastBytes ? numAvailFull : p->numFastBytes); ++ ++ if (!nextIsChar && matchByte != curByte) /* speed optimization */ ++ { ++ /* try Literal + rep0 */ ++ UInt32 temp; ++ UInt32 lenTest2; ++ const Byte *data2 = data - (reps[0] + 1); ++ UInt32 limit = p->numFastBytes + 1; ++ if (limit > numAvailFull) ++ limit = numAvailFull; ++ ++ for (temp = 1; temp < limit && data[temp] == data2[temp]; temp++); ++ lenTest2 = temp - 1; ++ if (lenTest2 >= 2) ++ { ++ UInt32 state2 = kLiteralNextStates[state]; ++ UInt32 posStateNext = (position + 1) & p->pbMask; ++ UInt32 nextRepMatchPrice = curAnd1Price + ++ GET_PRICE_1(p->isMatch[state2][posStateNext]) + ++ GET_PRICE_1(p->isRep[state2]); ++ /* for (; lenTest2 >= 2; lenTest2--) */ ++ { ++ UInt32 curAndLenPrice; ++ COptimal *opt; ++ UInt32 offset = cur + 1 + lenTest2; ++ while (lenEnd < offset) ++ p->opt[++lenEnd].price = kInfinityPrice; ++ curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext); ++ opt = &p->opt[offset]; ++ if (curAndLenPrice < opt->price) ++ { ++ opt->price = curAndLenPrice; ++ opt->posPrev = cur + 1; ++ opt->backPrev = 0; ++ opt->prev1IsChar = True; ++ opt->prev2 = False; ++ } ++ } ++ } ++ } ++ ++ startLen = 2; /* speed optimization */ ++ { ++ UInt32 repIndex; ++ for (repIndex = 0; repIndex < LZMA_NUM_REPS; repIndex++) ++ { ++ UInt32 lenTest; ++ UInt32 lenTestTemp; ++ UInt32 price; ++ const Byte *data2 = data - (reps[repIndex] + 1); ++ if (data[0] != data2[0] || data[1] != data2[1]) ++ continue; ++ for (lenTest = 2; lenTest < numAvail && data[lenTest] == data2[lenTest]; lenTest++); ++ while (lenEnd < cur + lenTest) ++ p->opt[++lenEnd].price = kInfinityPrice; ++ lenTestTemp = lenTest; ++ price = repMatchPrice + GetPureRepPrice(p, repIndex, state, posState); ++ do ++ { ++ UInt32 curAndLenPrice = price + p->repLenEnc.prices[posState][lenTest - 2]; ++ COptimal *opt = &p->opt[cur + lenTest]; ++ if (curAndLenPrice < opt->price) ++ { ++ opt->price = curAndLenPrice; ++ opt->posPrev = cur; ++ opt->backPrev = repIndex; ++ opt->prev1IsChar = False; ++ } ++ } ++ while (--lenTest >= 2); ++ lenTest = lenTestTemp; ++ ++ if (repIndex == 0) ++ startLen = lenTest + 1; ++ ++ /* if (_maxMode) */ ++ { ++ UInt32 lenTest2 = lenTest + 1; ++ UInt32 limit = lenTest2 + p->numFastBytes; ++ UInt32 nextRepMatchPrice; ++ if (limit > numAvailFull) ++ limit = numAvailFull; ++ for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++); ++ lenTest2 -= lenTest + 1; ++ if (lenTest2 >= 2) ++ { ++ UInt32 state2 = kRepNextStates[state]; ++ UInt32 posStateNext = (position + lenTest) & p->pbMask; ++ UInt32 curAndLenCharPrice = ++ price + p->repLenEnc.prices[posState][lenTest - 2] + ++ GET_PRICE_0(p->isMatch[state2][posStateNext]) + ++ LitEnc_GetPriceMatched(LIT_PROBS(position + lenTest, data[lenTest - 1]), ++ data[lenTest], data2[lenTest], p->ProbPrices); ++ state2 = kLiteralNextStates[state2]; ++ posStateNext = (position + lenTest + 1) & p->pbMask; ++ nextRepMatchPrice = curAndLenCharPrice + ++ GET_PRICE_1(p->isMatch[state2][posStateNext]) + ++ GET_PRICE_1(p->isRep[state2]); ++ ++ /* for (; lenTest2 >= 2; lenTest2--) */ ++ { ++ UInt32 curAndLenPrice; ++ COptimal *opt; ++ UInt32 offset = cur + lenTest + 1 + lenTest2; ++ while (lenEnd < offset) ++ p->opt[++lenEnd].price = kInfinityPrice; ++ curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext); ++ opt = &p->opt[offset]; ++ if (curAndLenPrice < opt->price) ++ { ++ opt->price = curAndLenPrice; ++ opt->posPrev = cur + lenTest + 1; ++ opt->backPrev = 0; ++ opt->prev1IsChar = True; ++ opt->prev2 = True; ++ opt->posPrev2 = cur; ++ opt->backPrev2 = repIndex; ++ } ++ } ++ } ++ } ++ } ++ } ++ /* for (UInt32 lenTest = 2; lenTest <= newLen; lenTest++) */ ++ if (newLen > numAvail) ++ { ++ newLen = numAvail; ++ for (numPairs = 0; newLen > matches[numPairs]; numPairs += 2); ++ matches[numPairs] = newLen; ++ numPairs += 2; ++ } ++ if (newLen >= startLen) ++ { ++ UInt32 normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[state]); ++ UInt32 offs, curBack, posSlot; ++ UInt32 lenTest; ++ while (lenEnd < cur + newLen) ++ p->opt[++lenEnd].price = kInfinityPrice; ++ ++ offs = 0; ++ while (startLen > matches[offs]) ++ offs += 2; ++ curBack = matches[offs + 1]; ++ GetPosSlot2(curBack, posSlot); ++ for (lenTest = /*2*/ startLen; ; lenTest++) ++ { ++ UInt32 curAndLenPrice = normalMatchPrice + p->lenEnc.prices[posState][lenTest - LZMA_MATCH_LEN_MIN]; ++ UInt32 lenToPosState = GetLenToPosState(lenTest); ++ COptimal *opt; ++ if (curBack < kNumFullDistances) ++ curAndLenPrice += p->distancesPrices[lenToPosState][curBack]; ++ else ++ curAndLenPrice += p->posSlotPrices[lenToPosState][posSlot] + p->alignPrices[curBack & kAlignMask]; ++ ++ opt = &p->opt[cur + lenTest]; ++ if (curAndLenPrice < opt->price) ++ { ++ opt->price = curAndLenPrice; ++ opt->posPrev = cur; ++ opt->backPrev = curBack + LZMA_NUM_REPS; ++ opt->prev1IsChar = False; ++ } ++ ++ if (/*_maxMode && */lenTest == matches[offs]) ++ { ++ /* Try Match + Literal + Rep0 */ ++ const Byte *data2 = data - (curBack + 1); ++ UInt32 lenTest2 = lenTest + 1; ++ UInt32 limit = lenTest2 + p->numFastBytes; ++ UInt32 nextRepMatchPrice; ++ if (limit > numAvailFull) ++ limit = numAvailFull; ++ for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++); ++ lenTest2 -= lenTest + 1; ++ if (lenTest2 >= 2) ++ { ++ UInt32 state2 = kMatchNextStates[state]; ++ UInt32 posStateNext = (position + lenTest) & p->pbMask; ++ UInt32 curAndLenCharPrice = curAndLenPrice + ++ GET_PRICE_0(p->isMatch[state2][posStateNext]) + ++ LitEnc_GetPriceMatched(LIT_PROBS(position + lenTest, data[lenTest - 1]), ++ data[lenTest], data2[lenTest], p->ProbPrices); ++ state2 = kLiteralNextStates[state2]; ++ posStateNext = (posStateNext + 1) & p->pbMask; ++ nextRepMatchPrice = curAndLenCharPrice + ++ GET_PRICE_1(p->isMatch[state2][posStateNext]) + ++ GET_PRICE_1(p->isRep[state2]); ++ ++ /* for (; lenTest2 >= 2; lenTest2--) */ ++ { ++ UInt32 offset = cur + lenTest + 1 + lenTest2; ++ UInt32 curAndLenPrice; ++ COptimal *opt; ++ while (lenEnd < offset) ++ p->opt[++lenEnd].price = kInfinityPrice; ++ curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext); ++ opt = &p->opt[offset]; ++ if (curAndLenPrice < opt->price) ++ { ++ opt->price = curAndLenPrice; ++ opt->posPrev = cur + lenTest + 1; ++ opt->backPrev = 0; ++ opt->prev1IsChar = True; ++ opt->prev2 = True; ++ opt->posPrev2 = cur; ++ opt->backPrev2 = curBack + LZMA_NUM_REPS; ++ } ++ } ++ } ++ offs += 2; ++ if (offs == numPairs) ++ break; ++ curBack = matches[offs + 1]; ++ if (curBack >= kNumFullDistances) ++ GetPosSlot2(curBack, posSlot); ++ } ++ } ++ } ++ } ++} ++ ++#define ChangePair(smallDist, bigDist) (((bigDist) >> 7) > (smallDist)) ++ ++static UInt32 GetOptimumFast(CLzmaEnc *p, UInt32 *backRes) ++{ ++ UInt32 numAvail, mainLen, mainDist, numPairs, repIndex, repLen, i; ++ const Byte *data; ++ const UInt32 *matches; ++ ++ if (p->additionalOffset == 0) ++ mainLen = ReadMatchDistances(p, &numPairs); ++ else ++ { ++ mainLen = p->longestMatchLength; ++ numPairs = p->numPairs; ++ } ++ ++ numAvail = p->numAvail; ++ *backRes = (UInt32)-1; ++ if (numAvail < 2) ++ return 1; ++ if (numAvail > LZMA_MATCH_LEN_MAX) ++ numAvail = LZMA_MATCH_LEN_MAX; ++ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; ++ ++ repLen = repIndex = 0; ++ for (i = 0; i < LZMA_NUM_REPS; i++) ++ { ++ UInt32 len; ++ const Byte *data2 = data - (p->reps[i] + 1); ++ if (data[0] != data2[0] || data[1] != data2[1]) ++ continue; ++ for (len = 2; len < numAvail && data[len] == data2[len]; len++); ++ if (len >= p->numFastBytes) ++ { ++ *backRes = i; ++ MovePos(p, len - 1); ++ return len; ++ } ++ if (len > repLen) ++ { ++ repIndex = i; ++ repLen = len; ++ } ++ } ++ ++ matches = p->matches; ++ if (mainLen >= p->numFastBytes) ++ { ++ *backRes = matches[numPairs - 1] + LZMA_NUM_REPS; ++ MovePos(p, mainLen - 1); ++ return mainLen; ++ } ++ ++ mainDist = 0; /* for GCC */ ++ if (mainLen >= 2) ++ { ++ mainDist = matches[numPairs - 1]; ++ while (numPairs > 2 && mainLen == matches[numPairs - 4] + 1) ++ { ++ if (!ChangePair(matches[numPairs - 3], mainDist)) ++ break; ++ numPairs -= 2; ++ mainLen = matches[numPairs - 2]; ++ mainDist = matches[numPairs - 1]; ++ } ++ if (mainLen == 2 && mainDist >= 0x80) ++ mainLen = 1; ++ } ++ ++ if (repLen >= 2 && ( ++ (repLen + 1 >= mainLen) || ++ (repLen + 2 >= mainLen && mainDist >= (1 << 9)) || ++ (repLen + 3 >= mainLen && mainDist >= (1 << 15)))) ++ { ++ *backRes = repIndex; ++ MovePos(p, repLen - 1); ++ return repLen; ++ } ++ ++ if (mainLen < 2 || numAvail <= 2) ++ return 1; ++ ++ p->longestMatchLength = ReadMatchDistances(p, &p->numPairs); ++ if (p->longestMatchLength >= 2) ++ { ++ UInt32 newDistance = matches[p->numPairs - 1]; ++ if ((p->longestMatchLength >= mainLen && newDistance < mainDist) || ++ (p->longestMatchLength == mainLen + 1 && !ChangePair(mainDist, newDistance)) || ++ (p->longestMatchLength > mainLen + 1) || ++ (p->longestMatchLength + 1 >= mainLen && mainLen >= 3 && ChangePair(newDistance, mainDist))) ++ return 1; ++ } ++ ++ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; ++ for (i = 0; i < LZMA_NUM_REPS; i++) ++ { ++ UInt32 len, limit; ++ const Byte *data2 = data - (p->reps[i] + 1); ++ if (data[0] != data2[0] || data[1] != data2[1]) ++ continue; ++ limit = mainLen - 1; ++ for (len = 2; len < limit && data[len] == data2[len]; len++); ++ if (len >= limit) ++ return 1; ++ } ++ *backRes = mainDist + LZMA_NUM_REPS; ++ MovePos(p, mainLen - 2); ++ return mainLen; ++} ++ ++static void WriteEndMarker(CLzmaEnc *p, UInt32 posState) ++{ ++ UInt32 len; ++ RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 1); ++ RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 0); ++ p->state = kMatchNextStates[p->state]; ++ len = LZMA_MATCH_LEN_MIN; ++ LenEnc_Encode2(&p->lenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices); ++ RcTree_Encode(&p->rc, p->posSlotEncoder[GetLenToPosState(len)], kNumPosSlotBits, (1 << kNumPosSlotBits) - 1); ++ RangeEnc_EncodeDirectBits(&p->rc, (((UInt32)1 << 30) - 1) >> kNumAlignBits, 30 - kNumAlignBits); ++ RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, kAlignMask); ++} ++ ++static SRes CheckErrors(CLzmaEnc *p) ++{ ++ if (p->result != SZ_OK) ++ return p->result; ++ if (p->rc.res != SZ_OK) ++ p->result = SZ_ERROR_WRITE; ++ if (p->matchFinderBase.result != SZ_OK) ++ p->result = SZ_ERROR_READ; ++ if (p->result != SZ_OK) ++ p->finished = True; ++ return p->result; ++} ++ ++static SRes Flush(CLzmaEnc *p, UInt32 nowPos) ++{ ++ /* ReleaseMFStream(); */ ++ p->finished = True; ++ if (p->writeEndMark) ++ WriteEndMarker(p, nowPos & p->pbMask); ++ RangeEnc_FlushData(&p->rc); ++ RangeEnc_FlushStream(&p->rc); ++ return CheckErrors(p); ++} ++ ++static void FillAlignPrices(CLzmaEnc *p) ++{ ++ UInt32 i; ++ for (i = 0; i < kAlignTableSize; i++) ++ p->alignPrices[i] = RcTree_ReverseGetPrice(p->posAlignEncoder, kNumAlignBits, i, p->ProbPrices); ++ p->alignPriceCount = 0; ++} ++ ++static void FillDistancesPrices(CLzmaEnc *p) ++{ ++ UInt32 tempPrices[kNumFullDistances]; ++ UInt32 i, lenToPosState; ++ for (i = kStartPosModelIndex; i < kNumFullDistances; i++) ++ { ++ UInt32 posSlot = GetPosSlot1(i); ++ UInt32 footerBits = ((posSlot >> 1) - 1); ++ UInt32 base = ((2 | (posSlot & 1)) << footerBits); ++ tempPrices[i] = RcTree_ReverseGetPrice(p->posEncoders + base - posSlot - 1, footerBits, i - base, p->ProbPrices); ++ } ++ ++ for (lenToPosState = 0; lenToPosState < kNumLenToPosStates; lenToPosState++) ++ { ++ UInt32 posSlot; ++ const CLzmaProb *encoder = p->posSlotEncoder[lenToPosState]; ++ UInt32 *posSlotPrices = p->posSlotPrices[lenToPosState]; ++ for (posSlot = 0; posSlot < p->distTableSize; posSlot++) ++ posSlotPrices[posSlot] = RcTree_GetPrice(encoder, kNumPosSlotBits, posSlot, p->ProbPrices); ++ for (posSlot = kEndPosModelIndex; posSlot < p->distTableSize; posSlot++) ++ posSlotPrices[posSlot] += ((((posSlot >> 1) - 1) - kNumAlignBits) << kNumBitPriceShiftBits); ++ ++ { ++ UInt32 *distancesPrices = p->distancesPrices[lenToPosState]; ++ UInt32 i; ++ for (i = 0; i < kStartPosModelIndex; i++) ++ distancesPrices[i] = posSlotPrices[i]; ++ for (; i < kNumFullDistances; i++) ++ distancesPrices[i] = posSlotPrices[GetPosSlot1(i)] + tempPrices[i]; ++ } ++ } ++ p->matchPriceCount = 0; ++} ++ ++void LzmaEnc_Construct(CLzmaEnc *p) ++{ ++ RangeEnc_Construct(&p->rc); ++ MatchFinder_Construct(&p->matchFinderBase); ++ #ifndef _7ZIP_ST ++ MatchFinderMt_Construct(&p->matchFinderMt); ++ p->matchFinderMt.MatchFinder = &p->matchFinderBase; ++ #endif ++ ++ { ++ CLzmaEncProps props; ++ LzmaEncProps_Init(&props); ++ LzmaEnc_SetProps(p, &props); ++ } ++ ++ #ifndef LZMA_LOG_BSR ++ LzmaEnc_FastPosInit(p->g_FastPos); ++ #endif ++ ++ LzmaEnc_InitPriceTables(p->ProbPrices); ++ p->litProbs = 0; ++ p->saveState.litProbs = 0; ++} ++ ++CLzmaEncHandle LzmaEnc_Create(ISzAlloc *alloc) ++{ ++ void *p; ++ p = alloc->Alloc(alloc, sizeof(CLzmaEnc)); ++ if (p != 0) ++ LzmaEnc_Construct((CLzmaEnc *)p); ++ return p; ++} ++ ++void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAlloc *alloc) ++{ ++ alloc->Free(alloc, p->litProbs); ++ alloc->Free(alloc, p->saveState.litProbs); ++ p->litProbs = 0; ++ p->saveState.litProbs = 0; ++} ++ ++void LzmaEnc_Destruct(CLzmaEnc *p, ISzAlloc *alloc, ISzAlloc *allocBig) ++{ ++ #ifndef _7ZIP_ST ++ MatchFinderMt_Destruct(&p->matchFinderMt, allocBig); ++ #endif ++ MatchFinder_Free(&p->matchFinderBase, allocBig); ++ LzmaEnc_FreeLits(p, alloc); ++ RangeEnc_Free(&p->rc, alloc); ++} ++ ++void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAlloc *alloc, ISzAlloc *allocBig) ++{ ++ LzmaEnc_Destruct((CLzmaEnc *)p, alloc, allocBig); ++ alloc->Free(alloc, p); ++} ++ ++static SRes LzmaEnc_CodeOneBlock(CLzmaEnc *p, Bool useLimits, UInt32 maxPackSize, UInt32 maxUnpackSize) ++{ ++ UInt32 nowPos32, startPos32; ++ if (p->needInit) ++ { ++ p->matchFinder.Init(p->matchFinderObj); ++ p->needInit = 0; ++ } ++ ++ if (p->finished) ++ return p->result; ++ RINOK(CheckErrors(p)); ++ ++ nowPos32 = (UInt32)p->nowPos64; ++ startPos32 = nowPos32; ++ ++ if (p->nowPos64 == 0) ++ { ++ UInt32 numPairs; ++ Byte curByte; ++ if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0) ++ return Flush(p, nowPos32); ++ ReadMatchDistances(p, &numPairs); ++ RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][0], 0); ++ p->state = kLiteralNextStates[p->state]; ++ curByte = p->matchFinder.GetIndexByte(p->matchFinderObj, 0 - p->additionalOffset); ++ LitEnc_Encode(&p->rc, p->litProbs, curByte); ++ p->additionalOffset--; ++ nowPos32++; ++ } ++ ++ if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) != 0) ++ for (;;) ++ { ++ UInt32 pos, len, posState; ++ ++ if (p->fastMode) ++ len = GetOptimumFast(p, &pos); ++ else ++ len = GetOptimum(p, nowPos32, &pos); ++ ++ #ifdef SHOW_STAT2 ++ printf("\n pos = %4X, len = %d pos = %d", nowPos32, len, pos); ++ #endif ++ ++ posState = nowPos32 & p->pbMask; ++ if (len == 1 && pos == (UInt32)-1) ++ { ++ Byte curByte; ++ CLzmaProb *probs; ++ const Byte *data; ++ ++ RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 0); ++ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset; ++ curByte = *data; ++ probs = LIT_PROBS(nowPos32, *(data - 1)); ++ if (IsCharState(p->state)) ++ LitEnc_Encode(&p->rc, probs, curByte); ++ else ++ LitEnc_EncodeMatched(&p->rc, probs, curByte, *(data - p->reps[0] - 1)); ++ p->state = kLiteralNextStates[p->state]; ++ } ++ else ++ { ++ RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 1); ++ if (pos < LZMA_NUM_REPS) ++ { ++ RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 1); ++ if (pos == 0) ++ { ++ RangeEnc_EncodeBit(&p->rc, &p->isRepG0[p->state], 0); ++ RangeEnc_EncodeBit(&p->rc, &p->isRep0Long[p->state][posState], ((len == 1) ? 0 : 1)); ++ } ++ else ++ { ++ UInt32 distance = p->reps[pos]; ++ RangeEnc_EncodeBit(&p->rc, &p->isRepG0[p->state], 1); ++ if (pos == 1) ++ RangeEnc_EncodeBit(&p->rc, &p->isRepG1[p->state], 0); ++ else ++ { ++ RangeEnc_EncodeBit(&p->rc, &p->isRepG1[p->state], 1); ++ RangeEnc_EncodeBit(&p->rc, &p->isRepG2[p->state], pos - 2); ++ if (pos == 3) ++ p->reps[3] = p->reps[2]; ++ p->reps[2] = p->reps[1]; ++ } ++ p->reps[1] = p->reps[0]; ++ p->reps[0] = distance; ++ } ++ if (len == 1) ++ p->state = kShortRepNextStates[p->state]; ++ else ++ { ++ LenEnc_Encode2(&p->repLenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices); ++ p->state = kRepNextStates[p->state]; ++ } ++ } ++ else ++ { ++ UInt32 posSlot; ++ RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 0); ++ p->state = kMatchNextStates[p->state]; ++ LenEnc_Encode2(&p->lenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices); ++ pos -= LZMA_NUM_REPS; ++ GetPosSlot(pos, posSlot); ++ RcTree_Encode(&p->rc, p->posSlotEncoder[GetLenToPosState(len)], kNumPosSlotBits, posSlot); ++ ++ if (posSlot >= kStartPosModelIndex) ++ { ++ UInt32 footerBits = ((posSlot >> 1) - 1); ++ UInt32 base = ((2 | (posSlot & 1)) << footerBits); ++ UInt32 posReduced = pos - base; ++ ++ if (posSlot < kEndPosModelIndex) ++ RcTree_ReverseEncode(&p->rc, p->posEncoders + base - posSlot - 1, footerBits, posReduced); ++ else ++ { ++ RangeEnc_EncodeDirectBits(&p->rc, posReduced >> kNumAlignBits, footerBits - kNumAlignBits); ++ RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, posReduced & kAlignMask); ++ p->alignPriceCount++; ++ } ++ } ++ p->reps[3] = p->reps[2]; ++ p->reps[2] = p->reps[1]; ++ p->reps[1] = p->reps[0]; ++ p->reps[0] = pos; ++ p->matchPriceCount++; ++ } ++ } ++ p->additionalOffset -= len; ++ nowPos32 += len; ++ if (p->additionalOffset == 0) ++ { ++ UInt32 processed; ++ if (!p->fastMode) ++ { ++ if (p->matchPriceCount >= (1 << 7)) ++ FillDistancesPrices(p); ++ if (p->alignPriceCount >= kAlignTableSize) ++ FillAlignPrices(p); ++ } ++ if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0) ++ break; ++ processed = nowPos32 - startPos32; ++ if (useLimits) ++ { ++ if (processed + kNumOpts + 300 >= maxUnpackSize || ++ RangeEnc_GetProcessed(&p->rc) + kNumOpts * 2 >= maxPackSize) ++ break; ++ } ++ else if (processed >= (1 << 15)) ++ { ++ p->nowPos64 += nowPos32 - startPos32; ++ return CheckErrors(p); ++ } ++ } ++ } ++ p->nowPos64 += nowPos32 - startPos32; ++ return Flush(p, nowPos32); ++} ++ ++#define kBigHashDicLimit ((UInt32)1 << 24) ++ ++static SRes LzmaEnc_Alloc(CLzmaEnc *p, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig) ++{ ++ UInt32 beforeSize = kNumOpts; ++ Bool btMode; ++ if (!RangeEnc_Alloc(&p->rc, alloc)) ++ return SZ_ERROR_MEM; ++ btMode = (p->matchFinderBase.btMode != 0); ++ #ifndef _7ZIP_ST ++ p->mtMode = (p->multiThread && !p->fastMode && btMode); ++ #endif ++ ++ { ++ unsigned lclp = p->lc + p->lp; ++ if (p->litProbs == 0 || p->saveState.litProbs == 0 || p->lclp != lclp) ++ { ++ LzmaEnc_FreeLits(p, alloc); ++ p->litProbs = (CLzmaProb *)alloc->Alloc(alloc, (0x300 << lclp) * sizeof(CLzmaProb)); ++ p->saveState.litProbs = (CLzmaProb *)alloc->Alloc(alloc, (0x300 << lclp) * sizeof(CLzmaProb)); ++ if (p->litProbs == 0 || p->saveState.litProbs == 0) ++ { ++ LzmaEnc_FreeLits(p, alloc); ++ return SZ_ERROR_MEM; ++ } ++ p->lclp = lclp; ++ } ++ } ++ ++ p->matchFinderBase.bigHash = (p->dictSize > kBigHashDicLimit); ++ ++ if (beforeSize + p->dictSize < keepWindowSize) ++ beforeSize = keepWindowSize - p->dictSize; ++ ++ #ifndef _7ZIP_ST ++ if (p->mtMode) ++ { ++ RINOK(MatchFinderMt_Create(&p->matchFinderMt, p->dictSize, beforeSize, p->numFastBytes, LZMA_MATCH_LEN_MAX, allocBig)); ++ p->matchFinderObj = &p->matchFinderMt; ++ MatchFinderMt_CreateVTable(&p->matchFinderMt, &p->matchFinder); ++ } ++ else ++ #endif ++ { ++ if (!MatchFinder_Create(&p->matchFinderBase, p->dictSize, beforeSize, p->numFastBytes, LZMA_MATCH_LEN_MAX, allocBig)) ++ return SZ_ERROR_MEM; ++ p->matchFinderObj = &p->matchFinderBase; ++ MatchFinder_CreateVTable(&p->matchFinderBase, &p->matchFinder); ++ } ++ return SZ_OK; ++} ++ ++void LzmaEnc_Init(CLzmaEnc *p) ++{ ++ UInt32 i; ++ p->state = 0; ++ for (i = 0 ; i < LZMA_NUM_REPS; i++) ++ p->reps[i] = 0; ++ ++ RangeEnc_Init(&p->rc); ++ ++ ++ for (i = 0; i < kNumStates; i++) ++ { ++ UInt32 j; ++ for (j = 0; j < LZMA_NUM_PB_STATES_MAX; j++) ++ { ++ p->isMatch[i][j] = kProbInitValue; ++ p->isRep0Long[i][j] = kProbInitValue; ++ } ++ p->isRep[i] = kProbInitValue; ++ p->isRepG0[i] = kProbInitValue; ++ p->isRepG1[i] = kProbInitValue; ++ p->isRepG2[i] = kProbInitValue; ++ } ++ ++ { ++ UInt32 num = 0x300 << (p->lp + p->lc); ++ for (i = 0; i < num; i++) ++ p->litProbs[i] = kProbInitValue; ++ } ++ ++ { ++ for (i = 0; i < kNumLenToPosStates; i++) ++ { ++ CLzmaProb *probs = p->posSlotEncoder[i]; ++ UInt32 j; ++ for (j = 0; j < (1 << kNumPosSlotBits); j++) ++ probs[j] = kProbInitValue; ++ } ++ } ++ { ++ for (i = 0; i < kNumFullDistances - kEndPosModelIndex; i++) ++ p->posEncoders[i] = kProbInitValue; ++ } ++ ++ LenEnc_Init(&p->lenEnc.p); ++ LenEnc_Init(&p->repLenEnc.p); ++ ++ for (i = 0; i < (1 << kNumAlignBits); i++) ++ p->posAlignEncoder[i] = kProbInitValue; ++ ++ p->optimumEndIndex = 0; ++ p->optimumCurrentIndex = 0; ++ p->additionalOffset = 0; ++ ++ p->pbMask = (1 << p->pb) - 1; ++ p->lpMask = (1 << p->lp) - 1; ++} ++ ++void LzmaEnc_InitPrices(CLzmaEnc *p) ++{ ++ if (!p->fastMode) ++ { ++ FillDistancesPrices(p); ++ FillAlignPrices(p); ++ } ++ ++ p->lenEnc.tableSize = ++ p->repLenEnc.tableSize = ++ p->numFastBytes + 1 - LZMA_MATCH_LEN_MIN; ++ LenPriceEnc_UpdateTables(&p->lenEnc, 1 << p->pb, p->ProbPrices); ++ LenPriceEnc_UpdateTables(&p->repLenEnc, 1 << p->pb, p->ProbPrices); ++} ++ ++static SRes LzmaEnc_AllocAndInit(CLzmaEnc *p, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig) ++{ ++ UInt32 i; ++ for (i = 0; i < (UInt32)kDicLogSizeMaxCompress; i++) ++ if (p->dictSize <= ((UInt32)1 << i)) ++ break; ++ p->distTableSize = i * 2; ++ ++ p->finished = False; ++ p->result = SZ_OK; ++ RINOK(LzmaEnc_Alloc(p, keepWindowSize, alloc, allocBig)); ++ LzmaEnc_Init(p); ++ LzmaEnc_InitPrices(p); ++ p->nowPos64 = 0; ++ return SZ_OK; ++} ++ ++static SRes LzmaEnc_Prepare(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ++ ISzAlloc *alloc, ISzAlloc *allocBig) ++{ ++ CLzmaEnc *p = (CLzmaEnc *)pp; ++ p->matchFinderBase.stream = inStream; ++ p->needInit = 1; ++ p->rc.outStream = outStream; ++ return LzmaEnc_AllocAndInit(p, 0, alloc, allocBig); ++} ++ ++SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle pp, ++ ISeqInStream *inStream, UInt32 keepWindowSize, ++ ISzAlloc *alloc, ISzAlloc *allocBig) ++{ ++ CLzmaEnc *p = (CLzmaEnc *)pp; ++ p->matchFinderBase.stream = inStream; ++ p->needInit = 1; ++ return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig); ++} ++ ++static void LzmaEnc_SetInputBuf(CLzmaEnc *p, const Byte *src, SizeT srcLen) ++{ ++ p->matchFinderBase.directInput = 1; ++ p->matchFinderBase.bufferBase = (Byte *)src; ++ p->matchFinderBase.directInputRem = srcLen; ++} ++ ++SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen, ++ UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig) ++{ ++ CLzmaEnc *p = (CLzmaEnc *)pp; ++ LzmaEnc_SetInputBuf(p, src, srcLen); ++ p->needInit = 1; ++ ++ return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig); ++} ++ ++void LzmaEnc_Finish(CLzmaEncHandle pp) ++{ ++ #ifndef _7ZIP_ST ++ CLzmaEnc *p = (CLzmaEnc *)pp; ++ if (p->mtMode) ++ MatchFinderMt_ReleaseStream(&p->matchFinderMt); ++ #else ++ pp = pp; ++ #endif ++} ++ ++typedef struct ++{ ++ ISeqOutStream funcTable; ++ Byte *data; ++ SizeT rem; ++ Bool overflow; ++} CSeqOutStreamBuf; ++ ++static size_t MyWrite(void *pp, const void *data, size_t size) ++{ ++ CSeqOutStreamBuf *p = (CSeqOutStreamBuf *)pp; ++ if (p->rem < size) ++ { ++ size = p->rem; ++ p->overflow = True; ++ } ++ memcpy(p->data, data, size); ++ p->rem -= size; ++ p->data += size; ++ return size; ++} ++ ++ ++UInt32 LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle pp) ++{ ++ const CLzmaEnc *p = (CLzmaEnc *)pp; ++ return p->matchFinder.GetNumAvailableBytes(p->matchFinderObj); ++} ++ ++const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp) ++{ ++ const CLzmaEnc *p = (CLzmaEnc *)pp; ++ return p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset; ++} ++ ++SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, Bool reInit, ++ Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize) ++{ ++ CLzmaEnc *p = (CLzmaEnc *)pp; ++ UInt64 nowPos64; ++ SRes res; ++ CSeqOutStreamBuf outStream; ++ ++ outStream.funcTable.Write = MyWrite; ++ outStream.data = dest; ++ outStream.rem = *destLen; ++ outStream.overflow = False; ++ ++ p->writeEndMark = False; ++ p->finished = False; ++ p->result = SZ_OK; ++ ++ if (reInit) ++ LzmaEnc_Init(p); ++ LzmaEnc_InitPrices(p); ++ nowPos64 = p->nowPos64; ++ RangeEnc_Init(&p->rc); ++ p->rc.outStream = &outStream.funcTable; ++ ++ res = LzmaEnc_CodeOneBlock(p, True, desiredPackSize, *unpackSize); ++ ++ *unpackSize = (UInt32)(p->nowPos64 - nowPos64); ++ *destLen -= outStream.rem; ++ if (outStream.overflow) ++ return SZ_ERROR_OUTPUT_EOF; ++ ++ return res; ++} ++ ++static SRes LzmaEnc_Encode2(CLzmaEnc *p, ICompressProgress *progress) ++{ ++ SRes res = SZ_OK; ++ ++ #ifndef _7ZIP_ST ++ Byte allocaDummy[0x300]; ++ int i = 0; ++ for (i = 0; i < 16; i++) ++ allocaDummy[i] = (Byte)i; ++ #endif ++ ++ for (;;) ++ { ++ res = LzmaEnc_CodeOneBlock(p, False, 0, 0); ++ if (res != SZ_OK || p->finished != 0) ++ break; ++ if (progress != 0) ++ { ++ res = progress->Progress(progress, p->nowPos64, RangeEnc_GetProcessed(&p->rc)); ++ if (res != SZ_OK) ++ { ++ res = SZ_ERROR_PROGRESS; ++ break; ++ } ++ } ++ } ++ LzmaEnc_Finish(p); ++ return res; ++} ++ ++SRes LzmaEnc_Encode(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress, ++ ISzAlloc *alloc, ISzAlloc *allocBig) ++{ ++ RINOK(LzmaEnc_Prepare(pp, outStream, inStream, alloc, allocBig)); ++ return LzmaEnc_Encode2((CLzmaEnc *)pp, progress); ++} ++ ++SRes LzmaEnc_WriteProperties(CLzmaEncHandle pp, Byte *props, SizeT *size) ++{ ++ CLzmaEnc *p = (CLzmaEnc *)pp; ++ int i; ++ UInt32 dictSize = p->dictSize; ++ if (*size < LZMA_PROPS_SIZE) ++ return SZ_ERROR_PARAM; ++ *size = LZMA_PROPS_SIZE; ++ props[0] = (Byte)((p->pb * 5 + p->lp) * 9 + p->lc); ++ ++ for (i = 11; i <= 30; i++) ++ { ++ if (dictSize <= ((UInt32)2 << i)) ++ { ++ dictSize = (2 << i); ++ break; ++ } ++ if (dictSize <= ((UInt32)3 << i)) ++ { ++ dictSize = (3 << i); ++ break; ++ } ++ } ++ ++ for (i = 0; i < 4; i++) ++ props[1 + i] = (Byte)(dictSize >> (8 * i)); ++ return SZ_OK; ++} ++ ++SRes LzmaEnc_MemEncode(CLzmaEncHandle pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, ++ int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig) ++{ ++ SRes res; ++ CLzmaEnc *p = (CLzmaEnc *)pp; ++ ++ CSeqOutStreamBuf outStream; ++ ++ LzmaEnc_SetInputBuf(p, src, srcLen); ++ ++ outStream.funcTable.Write = MyWrite; ++ outStream.data = dest; ++ outStream.rem = *destLen; ++ outStream.overflow = False; ++ ++ p->writeEndMark = writeEndMark; ++ ++ p->rc.outStream = &outStream.funcTable; ++ res = LzmaEnc_MemPrepare(pp, src, srcLen, 0, alloc, allocBig); ++ if (res == SZ_OK) ++ res = LzmaEnc_Encode2(p, progress); ++ ++ *destLen -= outStream.rem; ++ if (outStream.overflow) ++ return SZ_ERROR_OUTPUT_EOF; ++ return res; ++} ++ ++SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, ++ const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark, ++ ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig) ++{ ++ CLzmaEnc *p = (CLzmaEnc *)LzmaEnc_Create(alloc); ++ SRes res; ++ if (p == 0) ++ return SZ_ERROR_MEM; ++ ++ res = LzmaEnc_SetProps(p, props); ++ if (res == SZ_OK) ++ { ++ res = LzmaEnc_WriteProperties(p, propsEncoded, propsSize); ++ if (res == SZ_OK) ++ res = LzmaEnc_MemEncode(p, dest, destLen, src, srcLen, ++ writeEndMark, progress, alloc, allocBig); ++ } ++ ++ LzmaEnc_Destroy(p, alloc, allocBig); ++ return res; ++} +--- /dev/null ++++ b/lib/lzma/Makefile +@@ -0,0 +1,7 @@ ++lzma_compress-objs := LzFind.o LzmaEnc.o ++lzma_decompress-objs := LzmaDec.o ++ ++obj-$(CONFIG_LZMA_COMPRESS) += lzma_compress.o ++obj-$(CONFIG_LZMA_DECOMPRESS) += lzma_decompress.o ++ ++EXTRA_CFLAGS += -Iinclude/linux -Iinclude/linux/lzma -include types.h diff --git a/target/linux/generic/patches-4.1/531-debloat_lzma.patch b/target/linux/generic/patches-4.1/531-debloat_lzma.patch new file mode 100644 index 0000000..aa3c498 --- /dev/null +++ b/target/linux/generic/patches-4.1/531-debloat_lzma.patch @@ -0,0 +1,1024 @@ +--- a/include/linux/lzma/LzmaDec.h ++++ b/include/linux/lzma/LzmaDec.h +@@ -31,14 +31,6 @@ typedef struct _CLzmaProps + UInt32 dicSize; + } CLzmaProps; + +-/* LzmaProps_Decode - decodes properties +-Returns: +- SZ_OK +- SZ_ERROR_UNSUPPORTED - Unsupported properties +-*/ +- +-SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size); +- + + /* ---------- LZMA Decoder state ---------- */ + +@@ -70,8 +62,6 @@ typedef struct + + #define LzmaDec_Construct(p) { (p)->dic = 0; (p)->probs = 0; } + +-void LzmaDec_Init(CLzmaDec *p); +- + /* There are two types of LZMA streams: + 0) Stream with end mark. That end mark adds about 6 bytes to compressed size. + 1) Stream without end mark. You must know exact uncompressed size to decompress such stream. */ +@@ -108,97 +98,6 @@ typedef enum + + /* ELzmaStatus is used only as output value for function call */ + +- +-/* ---------- Interfaces ---------- */ +- +-/* There are 3 levels of interfaces: +- 1) Dictionary Interface +- 2) Buffer Interface +- 3) One Call Interface +- You can select any of these interfaces, but don't mix functions from different +- groups for same object. */ +- +- +-/* There are two variants to allocate state for Dictionary Interface: +- 1) LzmaDec_Allocate / LzmaDec_Free +- 2) LzmaDec_AllocateProbs / LzmaDec_FreeProbs +- You can use variant 2, if you set dictionary buffer manually. +- For Buffer Interface you must always use variant 1. +- +-LzmaDec_Allocate* can return: +- SZ_OK +- SZ_ERROR_MEM - Memory allocation error +- SZ_ERROR_UNSUPPORTED - Unsupported properties +-*/ +- +-SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc); +-void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc); +- +-SRes LzmaDec_Allocate(CLzmaDec *state, const Byte *prop, unsigned propsSize, ISzAlloc *alloc); +-void LzmaDec_Free(CLzmaDec *state, ISzAlloc *alloc); +- +-/* ---------- Dictionary Interface ---------- */ +- +-/* You can use it, if you want to eliminate the overhead for data copying from +- dictionary to some other external buffer. +- You must work with CLzmaDec variables directly in this interface. +- +- STEPS: +- LzmaDec_Constr() +- LzmaDec_Allocate() +- for (each new stream) +- { +- LzmaDec_Init() +- while (it needs more decompression) +- { +- LzmaDec_DecodeToDic() +- use data from CLzmaDec::dic and update CLzmaDec::dicPos +- } +- } +- LzmaDec_Free() +-*/ +- +-/* LzmaDec_DecodeToDic +- +- The decoding to internal dictionary buffer (CLzmaDec::dic). +- You must manually update CLzmaDec::dicPos, if it reaches CLzmaDec::dicBufSize !!! +- +-finishMode: +- It has meaning only if the decoding reaches output limit (dicLimit). +- LZMA_FINISH_ANY - Decode just dicLimit bytes. +- LZMA_FINISH_END - Stream must be finished after dicLimit. +- +-Returns: +- SZ_OK +- status: +- LZMA_STATUS_FINISHED_WITH_MARK +- LZMA_STATUS_NOT_FINISHED +- LZMA_STATUS_NEEDS_MORE_INPUT +- LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK +- SZ_ERROR_DATA - Data error +-*/ +- +-SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, +- const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); +- +- +-/* ---------- Buffer Interface ---------- */ +- +-/* It's zlib-like interface. +- See LzmaDec_DecodeToDic description for information about STEPS and return results, +- but you must use LzmaDec_DecodeToBuf instead of LzmaDec_DecodeToDic and you don't need +- to work with CLzmaDec variables manually. +- +-finishMode: +- It has meaning only if the decoding reaches output limit (*destLen). +- LZMA_FINISH_ANY - Decode just destLen bytes. +- LZMA_FINISH_END - Stream must be finished after (*destLen). +-*/ +- +-SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, +- const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); +- +- + /* ---------- One Call Interface ---------- */ + + /* LzmaDecode +--- a/lib/lzma/LzmaDec.c ++++ b/lib/lzma/LzmaDec.c +@@ -682,7 +682,7 @@ static void LzmaDec_InitRc(CLzmaDec *p, + p->needFlush = 0; + } + +-void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState) ++static void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState) + { + p->needFlush = 1; + p->remainLen = 0; +@@ -698,7 +698,7 @@ void LzmaDec_InitDicAndState(CLzmaDec *p + p->needInitState = 1; + } + +-void LzmaDec_Init(CLzmaDec *p) ++static void LzmaDec_Init(CLzmaDec *p) + { + p->dicPos = 0; + LzmaDec_InitDicAndState(p, True, True); +@@ -716,7 +716,7 @@ static void LzmaDec_InitStateReal(CLzmaD + p->needInitState = 0; + } + +-SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen, ++static SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen, + ELzmaFinishMode finishMode, ELzmaStatus *status) + { + SizeT inSize = *srcLen; +@@ -837,65 +837,13 @@ SRes LzmaDec_DecodeToDic(CLzmaDec *p, Si + return (p->code == 0) ? SZ_OK : SZ_ERROR_DATA; + } + +-SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) +-{ +- SizeT outSize = *destLen; +- SizeT inSize = *srcLen; +- *srcLen = *destLen = 0; +- for (;;) +- { +- SizeT inSizeCur = inSize, outSizeCur, dicPos; +- ELzmaFinishMode curFinishMode; +- SRes res; +- if (p->dicPos == p->dicBufSize) +- p->dicPos = 0; +- dicPos = p->dicPos; +- if (outSize > p->dicBufSize - dicPos) +- { +- outSizeCur = p->dicBufSize; +- curFinishMode = LZMA_FINISH_ANY; +- } +- else +- { +- outSizeCur = dicPos + outSize; +- curFinishMode = finishMode; +- } +- +- res = LzmaDec_DecodeToDic(p, outSizeCur, src, &inSizeCur, curFinishMode, status); +- src += inSizeCur; +- inSize -= inSizeCur; +- *srcLen += inSizeCur; +- outSizeCur = p->dicPos - dicPos; +- memcpy(dest, p->dic + dicPos, outSizeCur); +- dest += outSizeCur; +- outSize -= outSizeCur; +- *destLen += outSizeCur; +- if (res != 0) +- return res; +- if (outSizeCur == 0 || outSize == 0) +- return SZ_OK; +- } +-} +- +-void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc) ++static void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc) + { + alloc->Free(alloc, p->probs); + p->probs = 0; + } + +-static void LzmaDec_FreeDict(CLzmaDec *p, ISzAlloc *alloc) +-{ +- alloc->Free(alloc, p->dic); +- p->dic = 0; +-} +- +-void LzmaDec_Free(CLzmaDec *p, ISzAlloc *alloc) +-{ +- LzmaDec_FreeProbs(p, alloc); +- LzmaDec_FreeDict(p, alloc); +-} +- +-SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size) ++static SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size) + { + UInt32 dicSize; + Byte d; +@@ -935,7 +883,7 @@ static SRes LzmaDec_AllocateProbs2(CLzma + return SZ_OK; + } + +-SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) ++static SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) + { + CLzmaProps propNew; + RINOK(LzmaProps_Decode(&propNew, props, propsSize)); +@@ -943,28 +891,6 @@ SRes LzmaDec_AllocateProbs(CLzmaDec *p, + p->prop = propNew; + return SZ_OK; + } +- +-SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) +-{ +- CLzmaProps propNew; +- SizeT dicBufSize; +- RINOK(LzmaProps_Decode(&propNew, props, propsSize)); +- RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); +- dicBufSize = propNew.dicSize; +- if (p->dic == 0 || dicBufSize != p->dicBufSize) +- { +- LzmaDec_FreeDict(p, alloc); +- p->dic = (Byte *)alloc->Alloc(alloc, dicBufSize); +- if (p->dic == 0) +- { +- LzmaDec_FreeProbs(p, alloc); +- return SZ_ERROR_MEM; +- } +- } +- p->dicBufSize = dicBufSize; +- p->prop = propNew; +- return SZ_OK; +-} + + SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, + const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, +--- a/include/linux/lzma/LzmaEnc.h ++++ b/include/linux/lzma/LzmaEnc.h +@@ -31,9 +31,6 @@ typedef struct _CLzmaEncProps + } CLzmaEncProps; + + void LzmaEncProps_Init(CLzmaEncProps *p); +-void LzmaEncProps_Normalize(CLzmaEncProps *p); +-UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2); +- + + /* ---------- CLzmaEncHandle Interface ---------- */ + +@@ -53,26 +50,9 @@ CLzmaEncHandle LzmaEnc_Create(ISzAlloc * + void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAlloc *alloc, ISzAlloc *allocBig); + SRes LzmaEnc_SetProps(CLzmaEncHandle p, const CLzmaEncProps *props); + SRes LzmaEnc_WriteProperties(CLzmaEncHandle p, Byte *properties, SizeT *size); +-SRes LzmaEnc_Encode(CLzmaEncHandle p, ISeqOutStream *outStream, ISeqInStream *inStream, +- ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig); + SRes LzmaEnc_MemEncode(CLzmaEncHandle p, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, + int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig); + +-/* ---------- One Call Interface ---------- */ +- +-/* LzmaEncode +-Return code: +- SZ_OK - OK +- SZ_ERROR_MEM - Memory allocation error +- SZ_ERROR_PARAM - Incorrect paramater +- SZ_ERROR_OUTPUT_EOF - output buffer overflow +- SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version) +-*/ +- +-SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, +- const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark, +- ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig); +- + #ifdef __cplusplus + } + #endif +--- a/lib/lzma/LzmaEnc.c ++++ b/lib/lzma/LzmaEnc.c +@@ -53,7 +53,7 @@ void LzmaEncProps_Init(CLzmaEncProps *p) + p->writeEndMark = 0; + } + +-void LzmaEncProps_Normalize(CLzmaEncProps *p) ++static void LzmaEncProps_Normalize(CLzmaEncProps *p) + { + int level = p->level; + if (level < 0) level = 5; +@@ -76,7 +76,7 @@ void LzmaEncProps_Normalize(CLzmaEncProp + #endif + } + +-UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2) ++static UInt32 __maybe_unused LzmaEncProps_GetDictSize(const CLzmaEncProps *props2) + { + CLzmaEncProps props = *props2; + LzmaEncProps_Normalize(&props); +@@ -93,7 +93,7 @@ UInt32 LzmaEncProps_GetDictSize(const CL + + #define BSR2_RET(pos, res) { unsigned long i; _BitScanReverse(&i, (pos)); res = (i + i) + ((pos >> (i - 1)) & 1); } + +-UInt32 GetPosSlot1(UInt32 pos) ++static UInt32 GetPosSlot1(UInt32 pos) + { + UInt32 res; + BSR2_RET(pos, res); +@@ -107,7 +107,7 @@ UInt32 GetPosSlot1(UInt32 pos) + #define kNumLogBits (9 + (int)sizeof(size_t) / 2) + #define kDicLogSizeMaxCompress ((kNumLogBits - 1) * 2 + 7) + +-void LzmaEnc_FastPosInit(Byte *g_FastPos) ++static void LzmaEnc_FastPosInit(Byte *g_FastPos) + { + int c = 2, slotFast; + g_FastPos[0] = 0; +@@ -339,58 +339,6 @@ typedef struct + CSaveState saveState; + } CLzmaEnc; + +-void LzmaEnc_SaveState(CLzmaEncHandle pp) +-{ +- CLzmaEnc *p = (CLzmaEnc *)pp; +- CSaveState *dest = &p->saveState; +- int i; +- dest->lenEnc = p->lenEnc; +- dest->repLenEnc = p->repLenEnc; +- dest->state = p->state; +- +- for (i = 0; i < kNumStates; i++) +- { +- memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i])); +- memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i])); +- } +- for (i = 0; i < kNumLenToPosStates; i++) +- memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i])); +- memcpy(dest->isRep, p->isRep, sizeof(p->isRep)); +- memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0)); +- memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1)); +- memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2)); +- memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders)); +- memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder)); +- memcpy(dest->reps, p->reps, sizeof(p->reps)); +- memcpy(dest->litProbs, p->litProbs, (0x300 << p->lclp) * sizeof(CLzmaProb)); +-} +- +-void LzmaEnc_RestoreState(CLzmaEncHandle pp) +-{ +- CLzmaEnc *dest = (CLzmaEnc *)pp; +- const CSaveState *p = &dest->saveState; +- int i; +- dest->lenEnc = p->lenEnc; +- dest->repLenEnc = p->repLenEnc; +- dest->state = p->state; +- +- for (i = 0; i < kNumStates; i++) +- { +- memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i])); +- memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i])); +- } +- for (i = 0; i < kNumLenToPosStates; i++) +- memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i])); +- memcpy(dest->isRep, p->isRep, sizeof(p->isRep)); +- memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0)); +- memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1)); +- memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2)); +- memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders)); +- memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder)); +- memcpy(dest->reps, p->reps, sizeof(p->reps)); +- memcpy(dest->litProbs, p->litProbs, (0x300 << dest->lclp) * sizeof(CLzmaProb)); +-} +- + SRes LzmaEnc_SetProps(CLzmaEncHandle pp, const CLzmaEncProps *props2) + { + CLzmaEnc *p = (CLzmaEnc *)pp; +@@ -600,7 +548,7 @@ static void LitEnc_EncodeMatched(CRangeE + while (symbol < 0x10000); + } + +-void LzmaEnc_InitPriceTables(UInt32 *ProbPrices) ++static void LzmaEnc_InitPriceTables(UInt32 *ProbPrices) + { + UInt32 i; + for (i = (1 << kNumMoveReducingBits) / 2; i < kBitModelTotal; i += (1 << kNumMoveReducingBits)) +@@ -1676,7 +1624,7 @@ static void FillDistancesPrices(CLzmaEnc + p->matchPriceCount = 0; + } + +-void LzmaEnc_Construct(CLzmaEnc *p) ++static void LzmaEnc_Construct(CLzmaEnc *p) + { + RangeEnc_Construct(&p->rc); + MatchFinder_Construct(&p->matchFinderBase); +@@ -1709,7 +1657,7 @@ CLzmaEncHandle LzmaEnc_Create(ISzAlloc * + return p; + } + +-void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAlloc *alloc) ++static void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAlloc *alloc) + { + alloc->Free(alloc, p->litProbs); + alloc->Free(alloc, p->saveState.litProbs); +@@ -1717,7 +1665,7 @@ void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAl + p->saveState.litProbs = 0; + } + +-void LzmaEnc_Destruct(CLzmaEnc *p, ISzAlloc *alloc, ISzAlloc *allocBig) ++static void LzmaEnc_Destruct(CLzmaEnc *p, ISzAlloc *alloc, ISzAlloc *allocBig) + { + #ifndef _7ZIP_ST + MatchFinderMt_Destruct(&p->matchFinderMt, allocBig); +@@ -1947,7 +1895,7 @@ static SRes LzmaEnc_Alloc(CLzmaEnc *p, U + return SZ_OK; + } + +-void LzmaEnc_Init(CLzmaEnc *p) ++static void LzmaEnc_Init(CLzmaEnc *p) + { + UInt32 i; + p->state = 0; +@@ -2005,7 +1953,7 @@ void LzmaEnc_Init(CLzmaEnc *p) + p->lpMask = (1 << p->lp) - 1; + } + +-void LzmaEnc_InitPrices(CLzmaEnc *p) ++static void LzmaEnc_InitPrices(CLzmaEnc *p) + { + if (!p->fastMode) + { +@@ -2037,26 +1985,6 @@ static SRes LzmaEnc_AllocAndInit(CLzmaEn + return SZ_OK; + } + +-static SRes LzmaEnc_Prepare(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, +- ISzAlloc *alloc, ISzAlloc *allocBig) +-{ +- CLzmaEnc *p = (CLzmaEnc *)pp; +- p->matchFinderBase.stream = inStream; +- p->needInit = 1; +- p->rc.outStream = outStream; +- return LzmaEnc_AllocAndInit(p, 0, alloc, allocBig); +-} +- +-SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle pp, +- ISeqInStream *inStream, UInt32 keepWindowSize, +- ISzAlloc *alloc, ISzAlloc *allocBig) +-{ +- CLzmaEnc *p = (CLzmaEnc *)pp; +- p->matchFinderBase.stream = inStream; +- p->needInit = 1; +- return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig); +-} +- + static void LzmaEnc_SetInputBuf(CLzmaEnc *p, const Byte *src, SizeT srcLen) + { + p->matchFinderBase.directInput = 1; +@@ -2064,7 +1992,7 @@ static void LzmaEnc_SetInputBuf(CLzmaEnc + p->matchFinderBase.directInputRem = srcLen; + } + +-SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen, ++static SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen, + UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig) + { + CLzmaEnc *p = (CLzmaEnc *)pp; +@@ -2074,7 +2002,7 @@ SRes LzmaEnc_MemPrepare(CLzmaEncHandle p + return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig); + } + +-void LzmaEnc_Finish(CLzmaEncHandle pp) ++static void LzmaEnc_Finish(CLzmaEncHandle pp) + { + #ifndef _7ZIP_ST + CLzmaEnc *p = (CLzmaEnc *)pp; +@@ -2107,53 +2035,6 @@ static size_t MyWrite(void *pp, const vo + return size; + } + +- +-UInt32 LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle pp) +-{ +- const CLzmaEnc *p = (CLzmaEnc *)pp; +- return p->matchFinder.GetNumAvailableBytes(p->matchFinderObj); +-} +- +-const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp) +-{ +- const CLzmaEnc *p = (CLzmaEnc *)pp; +- return p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset; +-} +- +-SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, Bool reInit, +- Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize) +-{ +- CLzmaEnc *p = (CLzmaEnc *)pp; +- UInt64 nowPos64; +- SRes res; +- CSeqOutStreamBuf outStream; +- +- outStream.funcTable.Write = MyWrite; +- outStream.data = dest; +- outStream.rem = *destLen; +- outStream.overflow = False; +- +- p->writeEndMark = False; +- p->finished = False; +- p->result = SZ_OK; +- +- if (reInit) +- LzmaEnc_Init(p); +- LzmaEnc_InitPrices(p); +- nowPos64 = p->nowPos64; +- RangeEnc_Init(&p->rc); +- p->rc.outStream = &outStream.funcTable; +- +- res = LzmaEnc_CodeOneBlock(p, True, desiredPackSize, *unpackSize); +- +- *unpackSize = (UInt32)(p->nowPos64 - nowPos64); +- *destLen -= outStream.rem; +- if (outStream.overflow) +- return SZ_ERROR_OUTPUT_EOF; +- +- return res; +-} +- + static SRes LzmaEnc_Encode2(CLzmaEnc *p, ICompressProgress *progress) + { + SRes res = SZ_OK; +@@ -2184,13 +2065,6 @@ static SRes LzmaEnc_Encode2(CLzmaEnc *p, + return res; + } + +-SRes LzmaEnc_Encode(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress, +- ISzAlloc *alloc, ISzAlloc *allocBig) +-{ +- RINOK(LzmaEnc_Prepare(pp, outStream, inStream, alloc, allocBig)); +- return LzmaEnc_Encode2((CLzmaEnc *)pp, progress); +-} +- + SRes LzmaEnc_WriteProperties(CLzmaEncHandle pp, Byte *props, SizeT *size) + { + CLzmaEnc *p = (CLzmaEnc *)pp; +@@ -2247,25 +2121,3 @@ SRes LzmaEnc_MemEncode(CLzmaEncHandle pp + return SZ_ERROR_OUTPUT_EOF; + return res; + } +- +-SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, +- const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark, +- ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig) +-{ +- CLzmaEnc *p = (CLzmaEnc *)LzmaEnc_Create(alloc); +- SRes res; +- if (p == 0) +- return SZ_ERROR_MEM; +- +- res = LzmaEnc_SetProps(p, props); +- if (res == SZ_OK) +- { +- res = LzmaEnc_WriteProperties(p, propsEncoded, propsSize); +- if (res == SZ_OK) +- res = LzmaEnc_MemEncode(p, dest, destLen, src, srcLen, +- writeEndMark, progress, alloc, allocBig); +- } +- +- LzmaEnc_Destroy(p, alloc, allocBig); +- return res; +-} +--- a/include/linux/lzma/LzFind.h ++++ b/include/linux/lzma/LzFind.h +@@ -55,11 +55,6 @@ typedef struct _CMatchFinder + + #define Inline_MatchFinder_GetNumAvailableBytes(p) ((p)->streamPos - (p)->pos) + +-int MatchFinder_NeedMove(CMatchFinder *p); +-Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p); +-void MatchFinder_MoveBlock(CMatchFinder *p); +-void MatchFinder_ReadIfRequired(CMatchFinder *p); +- + void MatchFinder_Construct(CMatchFinder *p); + + /* Conditions: +@@ -70,12 +65,6 @@ int MatchFinder_Create(CMatchFinder *p, + UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter, + ISzAlloc *alloc); + void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc); +-void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems); +-void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue); +- +-UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *buffer, CLzRef *son, +- UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue, +- UInt32 *distances, UInt32 maxLen); + + /* + Conditions: +@@ -102,12 +91,6 @@ typedef struct _IMatchFinder + + void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable); + +-void MatchFinder_Init(CMatchFinder *p); +-UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances); +-UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances); +-void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num); +-void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num); +- + #ifdef __cplusplus + } + #endif +--- a/lib/lzma/LzFind.c ++++ b/lib/lzma/LzFind.c +@@ -14,9 +14,15 @@ + + #define kStartMaxLen 3 + ++#if 0 ++#define DIRECT_INPUT p->directInput ++#else ++#define DIRECT_INPUT 1 ++#endif ++ + static void LzInWindow_Free(CMatchFinder *p, ISzAlloc *alloc) + { +- if (!p->directInput) ++ if (!DIRECT_INPUT) + { + alloc->Free(alloc, p->bufferBase); + p->bufferBase = 0; +@@ -28,7 +34,7 @@ static void LzInWindow_Free(CMatchFinder + static int LzInWindow_Create(CMatchFinder *p, UInt32 keepSizeReserv, ISzAlloc *alloc) + { + UInt32 blockSize = p->keepSizeBefore + p->keepSizeAfter + keepSizeReserv; +- if (p->directInput) ++ if (DIRECT_INPUT) + { + p->blockSize = blockSize; + return 1; +@@ -42,12 +48,12 @@ static int LzInWindow_Create(CMatchFinde + return (p->bufferBase != 0); + } + +-Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; } +-Byte MatchFinder_GetIndexByte(CMatchFinder *p, Int32 index) { return p->buffer[index]; } ++static Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; } ++static Byte MatchFinder_GetIndexByte(CMatchFinder *p, Int32 index) { return p->buffer[index]; } + +-UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return p->streamPos - p->pos; } ++static UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return p->streamPos - p->pos; } + +-void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue) ++static void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue) + { + p->posLimit -= subValue; + p->pos -= subValue; +@@ -58,7 +64,7 @@ static void MatchFinder_ReadBlock(CMatch + { + if (p->streamEndWasReached || p->result != SZ_OK) + return; +- if (p->directInput) ++ if (DIRECT_INPUT) + { + UInt32 curSize = 0xFFFFFFFF - p->streamPos; + if (curSize > p->directInputRem) +@@ -89,7 +95,7 @@ static void MatchFinder_ReadBlock(CMatch + } + } + +-void MatchFinder_MoveBlock(CMatchFinder *p) ++static void MatchFinder_MoveBlock(CMatchFinder *p) + { + memmove(p->bufferBase, + p->buffer - p->keepSizeBefore, +@@ -97,22 +103,14 @@ void MatchFinder_MoveBlock(CMatchFinder + p->buffer = p->bufferBase + p->keepSizeBefore; + } + +-int MatchFinder_NeedMove(CMatchFinder *p) ++static int MatchFinder_NeedMove(CMatchFinder *p) + { +- if (p->directInput) ++ if (DIRECT_INPUT) + return 0; + /* if (p->streamEndWasReached) return 0; */ + return ((size_t)(p->bufferBase + p->blockSize - p->buffer) <= p->keepSizeAfter); + } + +-void MatchFinder_ReadIfRequired(CMatchFinder *p) +-{ +- if (p->streamEndWasReached) +- return; +- if (p->keepSizeAfter >= p->streamPos - p->pos) +- MatchFinder_ReadBlock(p); +-} +- + static void MatchFinder_CheckAndMoveAndRead(CMatchFinder *p) + { + if (MatchFinder_NeedMove(p)) +@@ -268,7 +266,7 @@ static void MatchFinder_SetLimits(CMatch + p->posLimit = p->pos + limit; + } + +-void MatchFinder_Init(CMatchFinder *p) ++static void MatchFinder_Init(CMatchFinder *p) + { + UInt32 i; + for (i = 0; i < p->hashSizeSum; i++) +@@ -287,7 +285,7 @@ static UInt32 MatchFinder_GetSubValue(CM + return (p->pos - p->historySize - 1) & kNormalizeMask; + } + +-void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems) ++static void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems) + { + UInt32 i; + for (i = 0; i < numItems; i++) +@@ -319,38 +317,7 @@ static void MatchFinder_CheckLimits(CMat + MatchFinder_SetLimits(p); + } + +-static UInt32 * Hc_GetMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, +- UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue, +- UInt32 *distances, UInt32 maxLen) +-{ +- son[_cyclicBufferPos] = curMatch; +- for (;;) +- { +- UInt32 delta = pos - curMatch; +- if (cutValue-- == 0 || delta >= _cyclicBufferSize) +- return distances; +- { +- const Byte *pb = cur - delta; +- curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)]; +- if (pb[maxLen] == cur[maxLen] && *pb == *cur) +- { +- UInt32 len = 0; +- while (++len != lenLimit) +- if (pb[len] != cur[len]) +- break; +- if (maxLen < len) +- { +- *distances++ = maxLen = len; +- *distances++ = delta - 1; +- if (len == lenLimit) +- return distances; +- } +- } +- } +- } +-} +- +-UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, ++static UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, + UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue, + UInt32 *distances, UInt32 maxLen) + { +@@ -460,10 +427,10 @@ static void SkipMatchesSpec(UInt32 lenLi + p->buffer++; \ + if (++p->pos == p->posLimit) MatchFinder_CheckLimits(p); + +-#define MOVE_POS_RET MOVE_POS return offset; +- + static void MatchFinder_MovePos(CMatchFinder *p) { MOVE_POS; } + ++#define MOVE_POS_RET MatchFinder_MovePos(p); return offset; ++ + #define GET_MATCHES_HEADER2(minLen, ret_op) \ + UInt32 lenLimit; UInt32 hashValue; const Byte *cur; UInt32 curMatch; \ + lenLimit = p->lenLimit; { if (lenLimit < minLen) { MatchFinder_MovePos(p); ret_op; }} \ +@@ -479,62 +446,7 @@ static void MatchFinder_MovePos(CMatchFi + distances + offset, maxLen) - distances); MOVE_POS_RET; + + #define SKIP_FOOTER \ +- SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); MOVE_POS; +- +-static UInt32 Bt2_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +-{ +- UInt32 offset; +- GET_MATCHES_HEADER(2) +- HASH2_CALC; +- curMatch = p->hash[hashValue]; +- p->hash[hashValue] = p->pos; +- offset = 0; +- GET_MATCHES_FOOTER(offset, 1) +-} +- +-UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +-{ +- UInt32 offset; +- GET_MATCHES_HEADER(3) +- HASH_ZIP_CALC; +- curMatch = p->hash[hashValue]; +- p->hash[hashValue] = p->pos; +- offset = 0; +- GET_MATCHES_FOOTER(offset, 2) +-} +- +-static UInt32 Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +-{ +- UInt32 hash2Value, delta2, maxLen, offset; +- GET_MATCHES_HEADER(3) +- +- HASH3_CALC; +- +- delta2 = p->pos - p->hash[hash2Value]; +- curMatch = p->hash[kFix3HashSize + hashValue]; +- +- p->hash[hash2Value] = +- p->hash[kFix3HashSize + hashValue] = p->pos; +- +- +- maxLen = 2; +- offset = 0; +- if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur) +- { +- for (; maxLen != lenLimit; maxLen++) +- if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen]) +- break; +- distances[0] = maxLen; +- distances[1] = delta2 - 1; +- offset = 2; +- if (maxLen == lenLimit) +- { +- SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); +- MOVE_POS_RET; +- } +- } +- GET_MATCHES_FOOTER(offset, maxLen) +-} ++ SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); MatchFinder_MovePos(p); + + static UInt32 Bt4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) + { +@@ -583,108 +495,6 @@ static UInt32 Bt4_MatchFinder_GetMatches + GET_MATCHES_FOOTER(offset, maxLen) + } + +-static UInt32 Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +-{ +- UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset; +- GET_MATCHES_HEADER(4) +- +- HASH4_CALC; +- +- delta2 = p->pos - p->hash[ hash2Value]; +- delta3 = p->pos - p->hash[kFix3HashSize + hash3Value]; +- curMatch = p->hash[kFix4HashSize + hashValue]; +- +- p->hash[ hash2Value] = +- p->hash[kFix3HashSize + hash3Value] = +- p->hash[kFix4HashSize + hashValue] = p->pos; +- +- maxLen = 1; +- offset = 0; +- if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur) +- { +- distances[0] = maxLen = 2; +- distances[1] = delta2 - 1; +- offset = 2; +- } +- if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur) +- { +- maxLen = 3; +- distances[offset + 1] = delta3 - 1; +- offset += 2; +- delta2 = delta3; +- } +- if (offset != 0) +- { +- for (; maxLen != lenLimit; maxLen++) +- if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen]) +- break; +- distances[offset - 2] = maxLen; +- if (maxLen == lenLimit) +- { +- p->son[p->cyclicBufferPos] = curMatch; +- MOVE_POS_RET; +- } +- } +- if (maxLen < 3) +- maxLen = 3; +- offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p), +- distances + offset, maxLen) - (distances)); +- MOVE_POS_RET +-} +- +-UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +-{ +- UInt32 offset; +- GET_MATCHES_HEADER(3) +- HASH_ZIP_CALC; +- curMatch = p->hash[hashValue]; +- p->hash[hashValue] = p->pos; +- offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p), +- distances, 2) - (distances)); +- MOVE_POS_RET +-} +- +-static void Bt2_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +-{ +- do +- { +- SKIP_HEADER(2) +- HASH2_CALC; +- curMatch = p->hash[hashValue]; +- p->hash[hashValue] = p->pos; +- SKIP_FOOTER +- } +- while (--num != 0); +-} +- +-void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +-{ +- do +- { +- SKIP_HEADER(3) +- HASH_ZIP_CALC; +- curMatch = p->hash[hashValue]; +- p->hash[hashValue] = p->pos; +- SKIP_FOOTER +- } +- while (--num != 0); +-} +- +-static void Bt3_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +-{ +- do +- { +- UInt32 hash2Value; +- SKIP_HEADER(3) +- HASH3_CALC; +- curMatch = p->hash[kFix3HashSize + hashValue]; +- p->hash[hash2Value] = +- p->hash[kFix3HashSize + hashValue] = p->pos; +- SKIP_FOOTER +- } +- while (--num != 0); +-} +- + static void Bt4_MatchFinder_Skip(CMatchFinder *p, UInt32 num) + { + do +@@ -701,61 +511,12 @@ static void Bt4_MatchFinder_Skip(CMatchF + while (--num != 0); + } + +-static void Hc4_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +-{ +- do +- { +- UInt32 hash2Value, hash3Value; +- SKIP_HEADER(4) +- HASH4_CALC; +- curMatch = p->hash[kFix4HashSize + hashValue]; +- p->hash[ hash2Value] = +- p->hash[kFix3HashSize + hash3Value] = +- p->hash[kFix4HashSize + hashValue] = p->pos; +- p->son[p->cyclicBufferPos] = curMatch; +- MOVE_POS +- } +- while (--num != 0); +-} +- +-void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +-{ +- do +- { +- SKIP_HEADER(3) +- HASH_ZIP_CALC; +- curMatch = p->hash[hashValue]; +- p->hash[hashValue] = p->pos; +- p->son[p->cyclicBufferPos] = curMatch; +- MOVE_POS +- } +- while (--num != 0); +-} +- + void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable) + { + vTable->Init = (Mf_Init_Func)MatchFinder_Init; + vTable->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinder_GetIndexByte; + vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinder_GetNumAvailableBytes; + vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinder_GetPointerToCurrentPos; +- if (!p->btMode) +- { +- vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches; +- vTable->Skip = (Mf_Skip_Func)Hc4_MatchFinder_Skip; +- } +- else if (p->numHashBytes == 2) +- { +- vTable->GetMatches = (Mf_GetMatches_Func)Bt2_MatchFinder_GetMatches; +- vTable->Skip = (Mf_Skip_Func)Bt2_MatchFinder_Skip; +- } +- else if (p->numHashBytes == 3) +- { +- vTable->GetMatches = (Mf_GetMatches_Func)Bt3_MatchFinder_GetMatches; +- vTable->Skip = (Mf_Skip_Func)Bt3_MatchFinder_Skip; +- } +- else +- { +- vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches; +- vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip; +- } ++ vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches; ++ vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip; + } diff --git a/target/linux/generic/patches-4.1/532-jffs2_eofdetect.patch b/target/linux/generic/patches-4.1/532-jffs2_eofdetect.patch new file mode 100644 index 0000000..9cbe183 --- /dev/null +++ b/target/linux/generic/patches-4.1/532-jffs2_eofdetect.patch @@ -0,0 +1,56 @@ +--- a/fs/jffs2/build.c ++++ b/fs/jffs2/build.c +@@ -114,6 +114,16 @@ static int jffs2_build_filesystem(struct + dbg_fsbuild("scanned flash completely\n"); + jffs2_dbg_dump_block_lists_nolock(c); + ++ if (c->flags & (1 << 7)) { ++ printk("%s(): unlocking the mtd device... ", __func__); ++ mtd_unlock(c->mtd, 0, c->mtd->size); ++ printk("done.\n"); ++ ++ printk("%s(): erasing all blocks after the end marker... ", __func__); ++ jffs2_erase_pending_blocks(c, -1); ++ printk("done.\n"); ++ } ++ + dbg_fsbuild("pass 1 starting\n"); + c->flags |= JFFS2_SB_FLAG_BUILDING; + /* Now scan the directory tree, increasing nlink according to every dirent found. */ +--- a/fs/jffs2/scan.c ++++ b/fs/jffs2/scan.c +@@ -148,8 +148,14 @@ int jffs2_scan_medium(struct jffs2_sb_in + /* reset summary info for next eraseblock scan */ + jffs2_sum_reset_collected(s); + +- ret = jffs2_scan_eraseblock(c, jeb, buf_size?flashbuf:(flashbuf+jeb->offset), +- buf_size, s); ++ if (c->flags & (1 << 7)) { ++ if (mtd_block_isbad(c->mtd, jeb->offset)) ++ ret = BLK_STATE_BADBLOCK; ++ else ++ ret = BLK_STATE_ALLFF; ++ } else ++ ret = jffs2_scan_eraseblock(c, jeb, buf_size?flashbuf:(flashbuf+jeb->offset), ++ buf_size, s); + + if (ret < 0) + goto out; +@@ -561,6 +567,17 @@ full_scan: + return err; + } + ++ if ((buf[0] == 0xde) && ++ (buf[1] == 0xad) && ++ (buf[2] == 0xc0) && ++ (buf[3] == 0xde)) { ++ /* end of filesystem. erase everything after this point */ ++ printk("%s(): End of filesystem marker found at 0x%x\n", __func__, jeb->offset); ++ c->flags |= (1 << 7); ++ ++ return BLK_STATE_ALLFF; ++ } ++ + /* We temporarily use 'ofs' as a pointer into the buffer/jeb */ + ofs = 0; + max_ofs = EMPTY_SCAN_SIZE(c->sector_size); diff --git a/target/linux/generic/patches-4.1/540-crypto-xz-decompression-support.patch b/target/linux/generic/patches-4.1/540-crypto-xz-decompression-support.patch new file mode 100644 index 0000000..c250e9f --- /dev/null +++ b/target/linux/generic/patches-4.1/540-crypto-xz-decompression-support.patch @@ -0,0 +1,146 @@ +--- a/crypto/Kconfig ++++ b/crypto/Kconfig +@@ -1435,6 +1435,13 @@ config CRYPTO_LZ4HC + help + This is the LZ4 high compression mode algorithm. + ++config CRYPTO_XZ ++ tristate "XZ compression algorithm" ++ select CRYPTO_ALGAPI ++ select XZ_DEC ++ help ++ This is the XZ algorithm. Only decompression is supported for now. ++ + comment "Random Number Generation" + + config CRYPTO_ANSI_CPRNG +--- a/crypto/Makefile ++++ b/crypto/Makefile +@@ -89,6 +89,7 @@ obj-$(CONFIG_CRYPTO_AUTHENC) += authenc. + obj-$(CONFIG_CRYPTO_LZO) += lzo.o + obj-$(CONFIG_CRYPTO_LZ4) += lz4.o + obj-$(CONFIG_CRYPTO_LZ4HC) += lz4hc.o ++obj-$(CONFIG_CRYPTO_XZ) += xz.o + obj-$(CONFIG_CRYPTO_842) += 842.o + obj-$(CONFIG_CRYPTO_RNG2) += rng.o + obj-$(CONFIG_CRYPTO_RNG2) += krng.o +--- /dev/null ++++ b/crypto/xz.c +@@ -0,0 +1,117 @@ ++/* ++ * Cryptographic API. ++ * ++ * XZ decompression support. ++ * ++ * Copyright (c) 2012 Gabor Juhos ++ * ++ * 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. ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++struct xz_comp_ctx { ++ struct xz_dec *decomp_state; ++ struct xz_buf decomp_buf; ++}; ++ ++static int crypto_xz_decomp_init(struct xz_comp_ctx *ctx) ++{ ++ ctx->decomp_state = xz_dec_init(XZ_SINGLE, 0); ++ if (!ctx->decomp_state) ++ return -ENOMEM; ++ ++ return 0; ++} ++ ++static void crypto_xz_decomp_exit(struct xz_comp_ctx *ctx) ++{ ++ xz_dec_end(ctx->decomp_state); ++} ++ ++static int crypto_xz_init(struct crypto_tfm *tfm) ++{ ++ struct xz_comp_ctx *ctx = crypto_tfm_ctx(tfm); ++ ++ return crypto_xz_decomp_init(ctx); ++} ++ ++static void crypto_xz_exit(struct crypto_tfm *tfm) ++{ ++ struct xz_comp_ctx *ctx = crypto_tfm_ctx(tfm); ++ ++ crypto_xz_decomp_exit(ctx); ++} ++ ++static int crypto_xz_compress(struct crypto_tfm *tfm, const u8 *src, ++ unsigned int slen, u8 *dst, unsigned int *dlen) ++{ ++ return -EOPNOTSUPP; ++} ++ ++static int crypto_xz_decompress(struct crypto_tfm *tfm, const u8 *src, ++ unsigned int slen, u8 *dst, unsigned int *dlen) ++{ ++ struct xz_comp_ctx *dctx = crypto_tfm_ctx(tfm); ++ struct xz_buf *xz_buf = &dctx->decomp_buf; ++ int ret; ++ ++ memset(xz_buf, '\0', sizeof(struct xz_buf)); ++ ++ xz_buf->in = (u8 *) src; ++ xz_buf->in_pos = 0; ++ xz_buf->in_size = slen; ++ xz_buf->out = (u8 *) dst; ++ xz_buf->out_pos = 0; ++ xz_buf->out_size = *dlen; ++ ++ ret = xz_dec_run(dctx->decomp_state, xz_buf); ++ if (ret != XZ_STREAM_END) { ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ *dlen = xz_buf->out_pos; ++ ret = 0; ++ ++out: ++ return ret; ++} ++ ++static struct crypto_alg crypto_xz_alg = { ++ .cra_name = "xz", ++ .cra_flags = CRYPTO_ALG_TYPE_COMPRESS, ++ .cra_ctxsize = sizeof(struct xz_comp_ctx), ++ .cra_module = THIS_MODULE, ++ .cra_list = LIST_HEAD_INIT(crypto_xz_alg.cra_list), ++ .cra_init = crypto_xz_init, ++ .cra_exit = crypto_xz_exit, ++ .cra_u = { .compress = { ++ .coa_compress = crypto_xz_compress, ++ .coa_decompress = crypto_xz_decompress } } ++}; ++ ++static int __init crypto_xz_mod_init(void) ++{ ++ return crypto_register_alg(&crypto_xz_alg); ++} ++ ++static void __exit crypto_xz_mod_exit(void) ++{ ++ crypto_unregister_alg(&crypto_xz_alg); ++} ++ ++module_init(crypto_xz_mod_init); ++module_exit(crypto_xz_mod_exit); ++ ++MODULE_LICENSE("GPL v2"); ++MODULE_DESCRIPTION("Crypto XZ decompression support"); ++MODULE_AUTHOR("Gabor Juhos "); diff --git a/target/linux/generic/patches-4.1/541-ubifs-xz-decompression-support.patch b/target/linux/generic/patches-4.1/541-ubifs-xz-decompression-support.patch new file mode 100644 index 0000000..f85689c --- /dev/null +++ b/target/linux/generic/patches-4.1/541-ubifs-xz-decompression-support.patch @@ -0,0 +1,92 @@ +--- a/fs/ubifs/Kconfig ++++ b/fs/ubifs/Kconfig +@@ -5,8 +5,10 @@ config UBIFS_FS + select CRYPTO if UBIFS_FS_ADVANCED_COMPR + select CRYPTO if UBIFS_FS_LZO + select CRYPTO if UBIFS_FS_ZLIB ++ select CRYPTO if UBIFS_FS_XZ + select CRYPTO_LZO if UBIFS_FS_LZO + select CRYPTO_DEFLATE if UBIFS_FS_ZLIB ++ select CRYPTO_XZ if UBIFS_FS_XZ + depends on MTD_UBI + help + UBIFS is a file system for flash devices which works on top of UBI. +@@ -35,3 +37,12 @@ config UBIFS_FS_ZLIB + default y + help + Zlib compresses better than LZO but it is slower. Say 'Y' if unsure. ++ ++config UBIFS_FS_XZ ++ bool "XZ decompression support" if UBIFS_FS_ADVANCED_COMPR ++ depends on UBIFS_FS ++ default y ++ help ++ XZ compresses better the ZLIB but it is slower.. ++ Say 'Y' if unsure. ++ +--- a/fs/ubifs/compress.c ++++ b/fs/ubifs/compress.c +@@ -71,6 +71,24 @@ static struct ubifs_compressor zlib_comp + }; + #endif + ++#ifdef CONFIG_UBIFS_FS_XZ ++static DEFINE_MUTEX(xz_enc_mutex); ++static DEFINE_MUTEX(xz_dec_mutex); ++ ++static struct ubifs_compressor xz_compr = { ++ .compr_type = UBIFS_COMPR_XZ, ++ .comp_mutex = &xz_enc_mutex, ++ .decomp_mutex = &xz_dec_mutex, ++ .name = "xz", ++ .capi_name = "xz", ++}; ++#else ++static struct ubifs_compressor xz_compr = { ++ .compr_type = UBIFS_COMPR_XZ, ++ .name = "xz", ++}; ++#endif ++ + /* All UBIFS compressors */ + struct ubifs_compressor *ubifs_compressors[UBIFS_COMPR_TYPES_CNT]; + +@@ -232,9 +250,15 @@ int __init ubifs_compressors_init(void) + if (err) + goto out_lzo; + ++ err = compr_init(&xz_compr); ++ if (err) ++ goto out_zlib; ++ + ubifs_compressors[UBIFS_COMPR_NONE] = &none_compr; + return 0; + ++out_zlib: ++ compr_exit(&zlib_compr); + out_lzo: + compr_exit(&lzo_compr); + return err; +@@ -247,4 +271,5 @@ void ubifs_compressors_exit(void) + { + compr_exit(&lzo_compr); + compr_exit(&zlib_compr); ++ compr_exit(&xz_compr); + } +--- a/fs/ubifs/ubifs-media.h ++++ b/fs/ubifs/ubifs-media.h +@@ -332,12 +332,14 @@ enum { + * UBIFS_COMPR_NONE: no compression + * UBIFS_COMPR_LZO: LZO compression + * UBIFS_COMPR_ZLIB: ZLIB compression ++ * UBIFS_COMPR_XZ: XZ compression + * UBIFS_COMPR_TYPES_CNT: count of supported compression types + */ + enum { + UBIFS_COMPR_NONE, + UBIFS_COMPR_LZO, + UBIFS_COMPR_ZLIB, ++ UBIFS_COMPR_XZ, + UBIFS_COMPR_TYPES_CNT, + }; + diff --git a/target/linux/generic/patches-4.1/551-ubifs-fix-default-compression-selection.patch b/target/linux/generic/patches-4.1/551-ubifs-fix-default-compression-selection.patch new file mode 100644 index 0000000..1b0f307 --- /dev/null +++ b/target/linux/generic/patches-4.1/551-ubifs-fix-default-compression-selection.patch @@ -0,0 +1,29 @@ +--- a/fs/ubifs/sb.c ++++ b/fs/ubifs/sb.c +@@ -63,6 +63,17 @@ + /* Default time granularity in nanoseconds */ + #define DEFAULT_TIME_GRAN 1000000000 + ++static int get_default_compressor(void) ++{ ++ if (ubifs_compr_present(UBIFS_COMPR_LZO)) ++ return UBIFS_COMPR_LZO; ++ ++ if (ubifs_compr_present(UBIFS_COMPR_ZLIB)) ++ return UBIFS_COMPR_ZLIB; ++ ++ return UBIFS_COMPR_NONE; ++} ++ + /** + * create_default_filesystem - format empty UBI volume. + * @c: UBIFS file-system description object +@@ -183,7 +194,7 @@ static int create_default_filesystem(str + if (c->mount_opts.override_compr) + sup->default_compr = cpu_to_le16(c->mount_opts.compr_type); + else +- sup->default_compr = cpu_to_le16(UBIFS_COMPR_LZO); ++ sup->default_compr = cpu_to_le16(get_default_compressor()); + + generate_random_uuid(sup->uuid); + diff --git a/target/linux/generic/patches-4.1/600-netfilter_conntrack_flush.patch b/target/linux/generic/patches-4.1/600-netfilter_conntrack_flush.patch new file mode 100644 index 0000000..bd7a7ff --- /dev/null +++ b/target/linux/generic/patches-4.1/600-netfilter_conntrack_flush.patch @@ -0,0 +1,86 @@ +--- a/net/netfilter/nf_conntrack_standalone.c ++++ b/net/netfilter/nf_conntrack_standalone.c +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + #include + #ifdef CONFIG_SYSCTL + #include +@@ -259,10 +260,66 @@ static int ct_open(struct inode *inode, + sizeof(struct ct_iter_state)); + } + ++struct kill_request { ++ u16 family; ++ union nf_inet_addr addr; ++}; ++ ++static int kill_matching(struct nf_conn *i, void *data) ++{ ++ struct kill_request *kr = data; ++ struct nf_conntrack_tuple *t1 = &i->tuplehash[IP_CT_DIR_ORIGINAL].tuple; ++ struct nf_conntrack_tuple *t2 = &i->tuplehash[IP_CT_DIR_REPLY].tuple; ++ ++ if (!kr->family) ++ return 1; ++ ++ if (t1->src.l3num != kr->family) ++ return 0; ++ ++ return (nf_inet_addr_cmp(&kr->addr, &t1->src.u3) || ++ nf_inet_addr_cmp(&kr->addr, &t1->dst.u3) || ++ nf_inet_addr_cmp(&kr->addr, &t2->src.u3) || ++ nf_inet_addr_cmp(&kr->addr, &t2->dst.u3)); ++} ++ ++static ssize_t ct_file_write(struct file *file, const char __user *buf, ++ size_t count, loff_t *ppos) ++{ ++ struct seq_file *seq = file->private_data; ++ struct net *net = seq_file_net(seq); ++ struct kill_request kr = { }; ++ char req[INET6_ADDRSTRLEN] = { }; ++ ++ if (count == 0) ++ return 0; ++ ++ if (count >= INET6_ADDRSTRLEN) ++ count = INET6_ADDRSTRLEN - 1; ++ ++ if (copy_from_user(req, buf, count)) ++ return -EFAULT; ++ ++ if (strnchr(req, count, ':')) { ++ kr.family = AF_INET6; ++ if (!in6_pton(req, count, (void *)&kr.addr, '\n', NULL)) ++ return -EINVAL; ++ } else if (strnchr(req, count, '.')) { ++ kr.family = AF_INET; ++ if (!in4_pton(req, count, (void *)&kr.addr, '\n', NULL)) ++ return -EINVAL; ++ } ++ ++ nf_ct_iterate_cleanup(net, kill_matching, &kr, 0, 0); ++ ++ return count; ++} ++ + static const struct file_operations ct_file_ops = { + .owner = THIS_MODULE, + .open = ct_open, + .read = seq_read, ++ .write = ct_file_write, + .llseek = seq_lseek, + .release = seq_release_net, + }; +@@ -364,7 +421,7 @@ static int nf_conntrack_standalone_init_ + { + struct proc_dir_entry *pde; + +- pde = proc_create("nf_conntrack", 0440, net->proc_net, &ct_file_ops); ++ pde = proc_create("nf_conntrack", 0660, net->proc_net, &ct_file_ops); + if (!pde) + goto out_nf_conntrack; + diff --git a/target/linux/generic/patches-4.1/610-netfilter_match_bypass_default_checks.patch b/target/linux/generic/patches-4.1/610-netfilter_match_bypass_default_checks.patch new file mode 100644 index 0000000..282cbdd --- /dev/null +++ b/target/linux/generic/patches-4.1/610-netfilter_match_bypass_default_checks.patch @@ -0,0 +1,93 @@ +--- a/include/uapi/linux/netfilter_ipv4/ip_tables.h ++++ b/include/uapi/linux/netfilter_ipv4/ip_tables.h +@@ -87,6 +87,7 @@ struct ipt_ip { + #define IPT_F_FRAG 0x01 /* Set if rule is a fragment rule */ + #define IPT_F_GOTO 0x02 /* Set if jump is a goto */ + #define IPT_F_MASK 0x03 /* All possible flag bits mask. */ ++#define IPT_F_NO_DEF_MATCH 0x80 /* Internal: no default match rules present */ + + /* Values for "inv" field in struct ipt_ip. */ + #define IPT_INV_VIA_IN 0x01 /* Invert the sense of IN IFACE. */ +--- a/net/ipv4/netfilter/ip_tables.c ++++ b/net/ipv4/netfilter/ip_tables.c +@@ -82,6 +82,9 @@ ip_packet_match(const struct iphdr *ip, + + #define FWINV(bool, invflg) ((bool) ^ !!(ipinfo->invflags & (invflg))) + ++ if (ipinfo->flags & IPT_F_NO_DEF_MATCH) ++ return true; ++ + if (FWINV((ip->saddr&ipinfo->smsk.s_addr) != ipinfo->src.s_addr, + IPT_INV_SRCIP) || + FWINV((ip->daddr&ipinfo->dmsk.s_addr) != ipinfo->dst.s_addr, +@@ -135,6 +138,29 @@ ip_packet_match(const struct iphdr *ip, + return true; + } + ++static void ++ip_checkdefault(struct ipt_ip *ip) ++{ ++ static const char iface_mask[IFNAMSIZ] = {}; ++ ++ if (ip->invflags || ip->flags & IPT_F_FRAG) ++ return; ++ ++ if (memcmp(ip->iniface_mask, iface_mask, IFNAMSIZ) != 0) ++ return; ++ ++ if (memcmp(ip->outiface_mask, iface_mask, IFNAMSIZ) != 0) ++ return; ++ ++ if (ip->smsk.s_addr || ip->dmsk.s_addr) ++ return; ++ ++ if (ip->proto) ++ return; ++ ++ ip->flags |= IPT_F_NO_DEF_MATCH; ++} ++ + static bool + ip_checkentry(const struct ipt_ip *ip) + { +@@ -564,7 +590,7 @@ static void cleanup_match(struct xt_entr + } + + static int +-check_entry(const struct ipt_entry *e, const char *name) ++check_entry(struct ipt_entry *e, const char *name) + { + const struct xt_entry_target *t; + +@@ -573,6 +599,8 @@ check_entry(const struct ipt_entry *e, c + return -EINVAL; + } + ++ ip_checkdefault(&e->ip); ++ + if (e->target_offset + sizeof(struct xt_entry_target) > + e->next_offset) + return -EINVAL; +@@ -934,6 +962,7 @@ copy_entries_to_user(unsigned int total_ + const struct xt_table_info *private = table->private; + int ret = 0; + const void *loc_cpu_entry; ++ u8 flags; + + counters = alloc_counters(table); + if (IS_ERR(counters)) +@@ -964,6 +993,14 @@ copy_entries_to_user(unsigned int total_ + ret = -EFAULT; + goto free_counters; + } ++ ++ flags = e->ip.flags & IPT_F_MASK; ++ if (copy_to_user(userptr + off ++ + offsetof(struct ipt_entry, ip.flags), ++ &flags, sizeof(flags)) != 0) { ++ ret = -EFAULT; ++ goto free_counters; ++ } + + for (i = sizeof(struct ipt_entry); + i < e->target_offset; diff --git a/target/linux/generic/patches-4.1/611-netfilter_match_bypass_default_table.patch b/target/linux/generic/patches-4.1/611-netfilter_match_bypass_default_table.patch new file mode 100644 index 0000000..9e2290d --- /dev/null +++ b/target/linux/generic/patches-4.1/611-netfilter_match_bypass_default_table.patch @@ -0,0 +1,94 @@ +--- a/net/ipv4/netfilter/ip_tables.c ++++ b/net/ipv4/netfilter/ip_tables.c +@@ -310,6 +310,33 @@ struct ipt_entry *ipt_next_entry(const s + return (void *)entry + entry->next_offset; + } + ++static bool ++ipt_handle_default_rule(struct ipt_entry *e, unsigned int *verdict) ++{ ++ struct xt_entry_target *t; ++ struct xt_standard_target *st; ++ ++ if (e->target_offset != sizeof(struct ipt_entry)) ++ return false; ++ ++ if (!(e->ip.flags & IPT_F_NO_DEF_MATCH)) ++ return false; ++ ++ t = ipt_get_target(e); ++ if (t->u.kernel.target->target) ++ return false; ++ ++ st = (struct xt_standard_target *) t; ++ if (st->verdict == XT_RETURN) ++ return false; ++ ++ if (st->verdict >= 0) ++ return false; ++ ++ *verdict = (unsigned)(-st->verdict) - 1; ++ return true; ++} ++ + /* Returns one of the generic firewall policies, like NF_ACCEPT. */ + unsigned int + ipt_do_table(struct sk_buff *skb, +@@ -330,9 +357,33 @@ ipt_do_table(struct sk_buff *skb, + unsigned int addend; + + /* Initialization */ ++ IP_NF_ASSERT(table->valid_hooks & (1 << hook)); ++ local_bh_disable(); ++ private = table->private; ++ cpu = smp_processor_id(); ++ /* ++ * Ensure we load private-> members after we've fetched the base ++ * pointer. ++ */ ++ smp_read_barrier_depends(); ++ table_base = private->entries[cpu]; ++ ++ e = get_entry(table_base, private->hook_entry[hook]); ++ if (ipt_handle_default_rule(e, &verdict)) { ++ ADD_COUNTER(e->counters, skb->len, 1); ++ local_bh_enable(); ++ return verdict; ++ } ++ + ip = ip_hdr(skb); + indev = state->in ? state->in->name : nulldevname; + outdev = state->out ? state->out->name : nulldevname; ++ ++ addend = xt_write_recseq_begin(); ++ jumpstack = (struct ipt_entry **)private->jumpstack[cpu]; ++ stackptr = per_cpu_ptr(private->stackptr, cpu); ++ origptr = *stackptr; ++ + /* We handle fragments by dealing with the first fragment as + * if it was a normal packet. All other fragments are treated + * normally, except that they will NEVER match rules that ask +@@ -347,23 +398,6 @@ ipt_do_table(struct sk_buff *skb, + acpar.family = NFPROTO_IPV4; + acpar.hooknum = hook; + +- IP_NF_ASSERT(table->valid_hooks & (1 << hook)); +- local_bh_disable(); +- addend = xt_write_recseq_begin(); +- private = table->private; +- cpu = smp_processor_id(); +- /* +- * Ensure we load private-> members after we've fetched the base +- * pointer. +- */ +- smp_read_barrier_depends(); +- table_base = private->entries[cpu]; +- jumpstack = (struct ipt_entry **)private->jumpstack[cpu]; +- stackptr = per_cpu_ptr(private->stackptr, cpu); +- origptr = *stackptr; +- +- e = get_entry(table_base, private->hook_entry[hook]); +- + pr_debug("Entering %s(hook %u); sp at %u (UF %p)\n", + table->name, hook, origptr, + get_entry(table_base, private->underflow[hook])); diff --git a/target/linux/generic/patches-4.1/612-netfilter_match_reduce_memory_access.patch b/target/linux/generic/patches-4.1/612-netfilter_match_reduce_memory_access.patch new file mode 100644 index 0000000..72172d8 --- /dev/null +++ b/target/linux/generic/patches-4.1/612-netfilter_match_reduce_memory_access.patch @@ -0,0 +1,16 @@ +--- a/net/ipv4/netfilter/ip_tables.c ++++ b/net/ipv4/netfilter/ip_tables.c +@@ -85,9 +85,11 @@ ip_packet_match(const struct iphdr *ip, + if (ipinfo->flags & IPT_F_NO_DEF_MATCH) + return true; + +- if (FWINV((ip->saddr&ipinfo->smsk.s_addr) != ipinfo->src.s_addr, ++ if (FWINV(ipinfo->smsk.s_addr && ++ (ip->saddr&ipinfo->smsk.s_addr) != ipinfo->src.s_addr, + IPT_INV_SRCIP) || +- FWINV((ip->daddr&ipinfo->dmsk.s_addr) != ipinfo->dst.s_addr, ++ FWINV(ipinfo->dmsk.s_addr && ++ (ip->daddr&ipinfo->dmsk.s_addr) != ipinfo->dst.s_addr, + IPT_INV_DSTIP)) { + dprintf("Source or dest mismatch.\n"); + diff --git a/target/linux/generic/patches-4.1/613-netfilter_optional_tcp_window_check.patch b/target/linux/generic/patches-4.1/613-netfilter_optional_tcp_window_check.patch new file mode 100644 index 0000000..3740dd7 --- /dev/null +++ b/target/linux/generic/patches-4.1/613-netfilter_optional_tcp_window_check.patch @@ -0,0 +1,36 @@ +--- a/net/netfilter/nf_conntrack_proto_tcp.c ++++ b/net/netfilter/nf_conntrack_proto_tcp.c +@@ -33,6 +33,9 @@ + #include + #include + ++/* Do not check the TCP window for incoming packets */ ++static int nf_ct_tcp_no_window_check __read_mostly = 1; ++ + /* "Be conservative in what you do, + be liberal in what you accept from others." + If it's non-zero, we mark only out of window RST segments as INVALID. */ +@@ -515,6 +518,9 @@ static bool tcp_in_window(const struct n + s32 receiver_offset; + bool res, in_recv_win; + ++ if (nf_ct_tcp_no_window_check) ++ return true; ++ + /* + * Get the required data from the packet. + */ +@@ -1481,6 +1487,13 @@ static struct ctl_table tcp_sysctl_table + .mode = 0644, + .proc_handler = proc_dointvec, + }, ++ { ++ .procname = "nf_conntrack_tcp_no_window_check", ++ .data = &nf_ct_tcp_no_window_check, ++ .maxlen = sizeof(unsigned int), ++ .mode = 0644, ++ .proc_handler = proc_dointvec, ++ }, + { } + }; + diff --git a/target/linux/generic/patches-4.1/615-netfilter_add_xt_id_match.patch b/target/linux/generic/patches-4.1/615-netfilter_add_xt_id_match.patch new file mode 100644 index 0000000..ba21d78 --- /dev/null +++ b/target/linux/generic/patches-4.1/615-netfilter_add_xt_id_match.patch @@ -0,0 +1,95 @@ +--- a/include/uapi/linux/netfilter/Kbuild ++++ b/include/uapi/linux/netfilter/Kbuild +@@ -55,6 +55,7 @@ header-y += xt_ecn.h + header-y += xt_esp.h + header-y += xt_hashlimit.h + header-y += xt_helper.h ++header-y += xt_id.h + header-y += xt_ipcomp.h + header-y += xt_iprange.h + header-y += xt_ipvs.h +--- /dev/null ++++ b/include/uapi/linux/netfilter/xt_id.h +@@ -0,0 +1,8 @@ ++#ifndef _XT_ID_H ++#define _XT_ID_H ++ ++struct xt_id_info { ++ u32 id; ++}; ++ ++#endif /* XT_ID_H */ +--- a/net/netfilter/Kconfig ++++ b/net/netfilter/Kconfig +@@ -1164,6 +1164,13 @@ config NETFILTER_XT_MATCH_IPCOMP + + To compile it as a module, choose M here. If unsure, say N. + ++config NETFILTER_XT_MATCH_ID ++ tristate '"id" match support' ++ depends on NETFILTER_ADVANCED ++ ---help--- ++ This option adds a `id' dummy-match, which allows you to put ++ numeric IDs into your iptables ruleset. ++ + config NETFILTER_XT_MATCH_IPRANGE + tristate '"iprange" address range match support' + depends on NETFILTER_ADVANCED +--- a/net/netfilter/Makefile ++++ b/net/netfilter/Makefile +@@ -145,6 +145,7 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_ESP) += + obj-$(CONFIG_NETFILTER_XT_MATCH_HASHLIMIT) += xt_hashlimit.o + obj-$(CONFIG_NETFILTER_XT_MATCH_HELPER) += xt_helper.o + obj-$(CONFIG_NETFILTER_XT_MATCH_HL) += xt_hl.o ++obj-$(CONFIG_NETFILTER_XT_MATCH_ID) += xt_id.o + obj-$(CONFIG_NETFILTER_XT_MATCH_IPCOMP) += xt_ipcomp.o + obj-$(CONFIG_NETFILTER_XT_MATCH_IPRANGE) += xt_iprange.o + obj-$(CONFIG_NETFILTER_XT_MATCH_IPVS) += xt_ipvs.o +--- /dev/null ++++ b/net/netfilter/xt_id.c +@@ -0,0 +1,45 @@ ++/* ++ * Implements a dummy match to allow attaching IDs to rules ++ * ++ * 2014-08-01 Jo-Philipp Wich ++ */ ++ ++#include ++#include ++#include ++#include ++ ++MODULE_AUTHOR("Jo-Philipp Wich "); ++MODULE_DESCRIPTION("Xtables: No-op match which can be tagged with a 32bit ID"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("ipt_id"); ++MODULE_ALIAS("ip6t_id"); ++ ++static bool ++id_mt(const struct sk_buff *skb, struct xt_action_param *par) ++{ ++ /* We always match */ ++ return true; ++} ++ ++static struct xt_match id_mt_reg __read_mostly = { ++ .name = "id", ++ .revision = 0, ++ .family = NFPROTO_UNSPEC, ++ .match = id_mt, ++ .matchsize = sizeof(struct xt_id_info), ++ .me = THIS_MODULE, ++}; ++ ++static int __init id_mt_init(void) ++{ ++ return xt_register_match(&id_mt_reg); ++} ++ ++static void __exit id_mt_exit(void) ++{ ++ xt_unregister_match(&id_mt_reg); ++} ++ ++module_init(id_mt_init); ++module_exit(id_mt_exit); diff --git a/target/linux/generic/patches-4.1/616-net_optimize_xfrm_calls.patch b/target/linux/generic/patches-4.1/616-net_optimize_xfrm_calls.patch new file mode 100644 index 0000000..2a64d54 --- /dev/null +++ b/target/linux/generic/patches-4.1/616-net_optimize_xfrm_calls.patch @@ -0,0 +1,12 @@ +--- a/net/netfilter/nf_nat_core.c ++++ b/net/netfilter/nf_nat_core.c +@@ -90,6 +90,9 @@ int nf_xfrm_me_harder(struct sk_buff *sk + struct dst_entry *dst; + int err; + ++ if (skb->dev && !dev_net(skb->dev)->xfrm.policy_count[XFRM_POLICY_OUT]) ++ return 0; ++ + err = xfrm_decode_session(skb, &fl, family); + if (err < 0) + return err; diff --git a/target/linux/generic/patches-4.1/620-sched_esfq.patch b/target/linux/generic/patches-4.1/620-sched_esfq.patch new file mode 100644 index 0000000..e1b473b --- /dev/null +++ b/target/linux/generic/patches-4.1/620-sched_esfq.patch @@ -0,0 +1,791 @@ +--- a/include/uapi/linux/pkt_sched.h ++++ b/include/uapi/linux/pkt_sched.h +@@ -226,6 +226,33 @@ struct tc_sfq_xstats { + __s32 allot; + }; + ++/* ESFQ section */ ++ ++enum ++{ ++ /* traditional */ ++ TCA_SFQ_HASH_CLASSIC, ++ TCA_SFQ_HASH_DST, ++ TCA_SFQ_HASH_SRC, ++ TCA_SFQ_HASH_FWMARK, ++ /* conntrack */ ++ TCA_SFQ_HASH_CTORIGDST, ++ TCA_SFQ_HASH_CTORIGSRC, ++ TCA_SFQ_HASH_CTREPLDST, ++ TCA_SFQ_HASH_CTREPLSRC, ++ TCA_SFQ_HASH_CTNATCHG, ++}; ++ ++struct tc_esfq_qopt ++{ ++ unsigned quantum; /* Bytes per round allocated to flow */ ++ int perturb_period; /* Period of hash perturbation */ ++ __u32 limit; /* Maximal packets in queue */ ++ unsigned divisor; /* Hash divisor */ ++ unsigned flows; /* Maximal number of flows */ ++ unsigned hash_kind; /* Hash function to use for flow identification */ ++}; ++ + /* RED section */ + + enum { +--- a/net/sched/Kconfig ++++ b/net/sched/Kconfig +@@ -149,6 +149,37 @@ config NET_SCH_SFQ + To compile this code as a module, choose M here: the + module will be called sch_sfq. + ++config NET_SCH_ESFQ ++ tristate "Enhanced Stochastic Fairness Queueing (ESFQ)" ++ ---help--- ++ Say Y here if you want to use the Enhanced Stochastic Fairness ++ Queueing (ESFQ) packet scheduling algorithm for some of your network ++ devices or as a leaf discipline for a classful qdisc such as HTB or ++ CBQ (see the top of for details and ++ references to the SFQ algorithm). ++ ++ This is an enchanced SFQ version which allows you to control some ++ hardcoded values in the SFQ scheduler. ++ ++ ESFQ also adds control of the hash function used to identify packet ++ flows. The original SFQ discipline hashes by connection; ESFQ add ++ several other hashing methods, such as by src IP or by dst IP, which ++ can be more fair to users in some networking situations. ++ ++ To compile this code as a module, choose M here: the ++ module will be called sch_esfq. ++ ++config NET_SCH_ESFQ_NFCT ++ bool "Connection Tracking Hash Types" ++ depends on NET_SCH_ESFQ && NF_CONNTRACK ++ ---help--- ++ Say Y here to enable support for hashing based on netfilter connection ++ tracking information. This is useful for a router that is also using ++ NAT to connect privately-addressed hosts to the Internet. If you want ++ to provide fair distribution of upstream bandwidth, ESFQ must use ++ connection tracking information, since all outgoing packets will share ++ the same source address. ++ + config NET_SCH_TEQL + tristate "True Link Equalizer (TEQL)" + ---help--- +--- a/net/sched/Makefile ++++ b/net/sched/Makefile +@@ -29,6 +29,7 @@ obj-$(CONFIG_NET_SCH_INGRESS) += sch_ing + obj-$(CONFIG_NET_SCH_DSMARK) += sch_dsmark.o + obj-$(CONFIG_NET_SCH_SFB) += sch_sfb.o + obj-$(CONFIG_NET_SCH_SFQ) += sch_sfq.o ++obj-$(CONFIG_NET_SCH_ESFQ) += sch_esfq.o + obj-$(CONFIG_NET_SCH_TBF) += sch_tbf.o + obj-$(CONFIG_NET_SCH_TEQL) += sch_teql.o + obj-$(CONFIG_NET_SCH_PRIO) += sch_prio.o +--- /dev/null ++++ b/net/sched/sch_esfq.c +@@ -0,0 +1,702 @@ ++/* ++ * net/sched/sch_esfq.c Extended Stochastic Fairness Queueing discipline. ++ * ++ * 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. ++ * ++ * Authors: Alexey Kuznetsov, ++ * ++ * Changes: Alexander Atanasov, ++ * Added dynamic depth,limit,divisor,hash_kind options. ++ * Added dst and src hashes. ++ * ++ * Alexander Clouter, ++ * Ported ESFQ to Linux 2.6. ++ * ++ * Corey Hickey, ++ * Maintenance of the Linux 2.6 port. ++ * Added fwmark hash (thanks to Robert Kurjata). ++ * Added usage of jhash. ++ * Added conntrack support. ++ * Added ctnatchg hash (thanks to Ben Pfountz). ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#ifdef CONFIG_NET_SCH_ESFQ_NFCT ++#include ++#endif ++ ++/* Stochastic Fairness Queuing algorithm. ++ For more comments look at sch_sfq.c. ++ The difference is that you can change limit, depth, ++ hash table size and choose alternate hash types. ++ ++ classic: same as in sch_sfq.c ++ dst: destination IP address ++ src: source IP address ++ fwmark: netfilter mark value ++ ctorigdst: original destination IP address ++ ctorigsrc: original source IP address ++ ctrepldst: reply destination IP address ++ ctreplsrc: reply source IP ++ ++*/ ++ ++#define ESFQ_HEAD 0 ++#define ESFQ_TAIL 1 ++ ++/* This type should contain at least SFQ_DEPTH*2 values */ ++typedef unsigned int esfq_index; ++ ++struct esfq_head ++{ ++ esfq_index next; ++ esfq_index prev; ++}; ++ ++struct esfq_sched_data ++{ ++/* Parameters */ ++ int perturb_period; ++ unsigned quantum; /* Allotment per round: MUST BE >= MTU */ ++ int limit; ++ unsigned depth; ++ unsigned hash_divisor; ++ unsigned hash_kind; ++/* Variables */ ++ struct timer_list perturb_timer; ++ int perturbation; ++ esfq_index tail; /* Index of current slot in round */ ++ esfq_index max_depth; /* Maximal depth */ ++ ++ esfq_index *ht; /* Hash table */ ++ esfq_index *next; /* Active slots link */ ++ short *allot; /* Current allotment per slot */ ++ unsigned short *hash; /* Hash value indexed by slots */ ++ struct sk_buff_head *qs; /* Slot queue */ ++ struct esfq_head *dep; /* Linked list of slots, indexed by depth */ ++}; ++ ++/* This contains the info we will hash. */ ++struct esfq_packet_info ++{ ++ u32 proto; /* protocol or port */ ++ u32 src; /* source from packet header */ ++ u32 dst; /* destination from packet header */ ++ u32 ctorigsrc; /* original source from conntrack */ ++ u32 ctorigdst; /* original destination from conntrack */ ++ u32 ctreplsrc; /* reply source from conntrack */ ++ u32 ctrepldst; /* reply destination from conntrack */ ++ u32 mark; /* netfilter mark (fwmark) */ ++}; ++ ++static __inline__ unsigned esfq_jhash_1word(struct esfq_sched_data *q,u32 a) ++{ ++ return jhash_1word(a, q->perturbation) & (q->hash_divisor-1); ++} ++ ++static __inline__ unsigned esfq_jhash_2words(struct esfq_sched_data *q, u32 a, u32 b) ++{ ++ return jhash_2words(a, b, q->perturbation) & (q->hash_divisor-1); ++} ++ ++static __inline__ unsigned esfq_jhash_3words(struct esfq_sched_data *q, u32 a, u32 b, u32 c) ++{ ++ return jhash_3words(a, b, c, q->perturbation) & (q->hash_divisor-1); ++} ++ ++static unsigned esfq_hash(struct esfq_sched_data *q, struct sk_buff *skb) ++{ ++ struct esfq_packet_info info; ++#ifdef CONFIG_NET_SCH_ESFQ_NFCT ++ enum ip_conntrack_info ctinfo; ++ struct nf_conn *ct = nf_ct_get(skb, &ctinfo); ++#endif ++ ++ switch (skb->protocol) { ++ case __constant_htons(ETH_P_IP): ++ { ++ struct iphdr *iph = ip_hdr(skb); ++ info.dst = iph->daddr; ++ info.src = iph->saddr; ++ if (!(iph->frag_off&htons(IP_MF|IP_OFFSET)) && ++ (iph->protocol == IPPROTO_TCP || ++ iph->protocol == IPPROTO_UDP || ++ iph->protocol == IPPROTO_SCTP || ++ iph->protocol == IPPROTO_DCCP || ++ iph->protocol == IPPROTO_ESP)) ++ info.proto = *(((u32*)iph) + iph->ihl); ++ else ++ info.proto = iph->protocol; ++ break; ++ } ++ case __constant_htons(ETH_P_IPV6): ++ { ++ struct ipv6hdr *iph = ipv6_hdr(skb); ++ /* Hash ipv6 addresses into a u32. This isn't ideal, ++ * but the code is simple. */ ++ info.dst = jhash2(iph->daddr.s6_addr32, 4, q->perturbation); ++ info.src = jhash2(iph->saddr.s6_addr32, 4, q->perturbation); ++ if (iph->nexthdr == IPPROTO_TCP || ++ iph->nexthdr == IPPROTO_UDP || ++ iph->nexthdr == IPPROTO_SCTP || ++ iph->nexthdr == IPPROTO_DCCP || ++ iph->nexthdr == IPPROTO_ESP) ++ info.proto = *(u32*)&iph[1]; ++ else ++ info.proto = iph->nexthdr; ++ break; ++ } ++ default: ++ info.dst = (u32)(unsigned long)skb_dst(skb); ++ info.src = (u32)(unsigned long)skb->sk; ++ info.proto = skb->protocol; ++ } ++ ++ info.mark = skb->mark; ++ ++#ifdef CONFIG_NET_SCH_ESFQ_NFCT ++ /* defaults if there is no conntrack info */ ++ info.ctorigsrc = info.src; ++ info.ctorigdst = info.dst; ++ info.ctreplsrc = info.dst; ++ info.ctrepldst = info.src; ++ /* collect conntrack info */ ++ if (ct && ct != &nf_conntrack_untracked) { ++ if (skb->protocol == __constant_htons(ETH_P_IP)) { ++ info.ctorigsrc = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip; ++ info.ctorigdst = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.ip; ++ info.ctreplsrc = ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip; ++ info.ctrepldst = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip; ++ } ++ else if (skb->protocol == __constant_htons(ETH_P_IPV6)) { ++ /* Again, hash ipv6 addresses into a single u32. */ ++ info.ctorigsrc = jhash2(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip6, 4, q->perturbation); ++ info.ctorigdst = jhash2(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.ip6, 4, q->perturbation); ++ info.ctreplsrc = jhash2(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip6, 4, q->perturbation); ++ info.ctrepldst = jhash2(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip6, 4, q->perturbation); ++ } ++ ++ } ++#endif ++ ++ switch(q->hash_kind) { ++ case TCA_SFQ_HASH_CLASSIC: ++ return esfq_jhash_3words(q, info.dst, info.src, info.proto); ++ case TCA_SFQ_HASH_DST: ++ return esfq_jhash_1word(q, info.dst); ++ case TCA_SFQ_HASH_SRC: ++ return esfq_jhash_1word(q, info.src); ++ case TCA_SFQ_HASH_FWMARK: ++ return esfq_jhash_1word(q, info.mark); ++#ifdef CONFIG_NET_SCH_ESFQ_NFCT ++ case TCA_SFQ_HASH_CTORIGDST: ++ return esfq_jhash_1word(q, info.ctorigdst); ++ case TCA_SFQ_HASH_CTORIGSRC: ++ return esfq_jhash_1word(q, info.ctorigsrc); ++ case TCA_SFQ_HASH_CTREPLDST: ++ return esfq_jhash_1word(q, info.ctrepldst); ++ case TCA_SFQ_HASH_CTREPLSRC: ++ return esfq_jhash_1word(q, info.ctreplsrc); ++ case TCA_SFQ_HASH_CTNATCHG: ++ { ++ if (info.ctorigdst == info.ctreplsrc) ++ return esfq_jhash_1word(q, info.ctorigsrc); ++ return esfq_jhash_1word(q, info.ctreplsrc); ++ } ++#endif ++ default: ++ if (net_ratelimit()) ++ printk(KERN_WARNING "ESFQ: Unknown hash method. Falling back to classic.\n"); ++ } ++ return esfq_jhash_3words(q, info.dst, info.src, info.proto); ++} ++ ++static inline void esfq_link(struct esfq_sched_data *q, esfq_index x) ++{ ++ esfq_index p, n; ++ int d = q->qs[x].qlen + q->depth; ++ ++ p = d; ++ n = q->dep[d].next; ++ q->dep[x].next = n; ++ q->dep[x].prev = p; ++ q->dep[p].next = q->dep[n].prev = x; ++} ++ ++static inline void esfq_dec(struct esfq_sched_data *q, esfq_index x) ++{ ++ esfq_index p, n; ++ ++ n = q->dep[x].next; ++ p = q->dep[x].prev; ++ q->dep[p].next = n; ++ q->dep[n].prev = p; ++ ++ if (n == p && q->max_depth == q->qs[x].qlen + 1) ++ q->max_depth--; ++ ++ esfq_link(q, x); ++} ++ ++static inline void esfq_inc(struct esfq_sched_data *q, esfq_index x) ++{ ++ esfq_index p, n; ++ int d; ++ ++ n = q->dep[x].next; ++ p = q->dep[x].prev; ++ q->dep[p].next = n; ++ q->dep[n].prev = p; ++ d = q->qs[x].qlen; ++ if (q->max_depth < d) ++ q->max_depth = d; ++ ++ esfq_link(q, x); ++} ++ ++static unsigned int esfq_drop(struct Qdisc *sch) ++{ ++ struct esfq_sched_data *q = qdisc_priv(sch); ++ esfq_index d = q->max_depth; ++ struct sk_buff *skb; ++ unsigned int len; ++ ++ /* Queue is full! Find the longest slot and ++ drop a packet from it */ ++ ++ if (d > 1) { ++ esfq_index x = q->dep[d+q->depth].next; ++ skb = q->qs[x].prev; ++ len = skb->len; ++ __skb_unlink(skb, &q->qs[x]); ++ kfree_skb(skb); ++ esfq_dec(q, x); ++ sch->q.qlen--; ++ sch->qstats.drops++; ++ sch->qstats.backlog -= len; ++ return len; ++ } ++ ++ if (d == 1) { ++ /* It is difficult to believe, but ALL THE SLOTS HAVE LENGTH 1. */ ++ d = q->next[q->tail]; ++ q->next[q->tail] = q->next[d]; ++ q->allot[q->next[d]] += q->quantum; ++ skb = q->qs[d].prev; ++ len = skb->len; ++ __skb_unlink(skb, &q->qs[d]); ++ kfree_skb(skb); ++ esfq_dec(q, d); ++ sch->q.qlen--; ++ q->ht[q->hash[d]] = q->depth; ++ sch->qstats.drops++; ++ sch->qstats.backlog -= len; ++ return len; ++ } ++ ++ return 0; ++} ++ ++static void esfq_q_enqueue(struct sk_buff *skb, struct esfq_sched_data *q, unsigned int end) ++{ ++ unsigned hash = esfq_hash(q, skb); ++ unsigned depth = q->depth; ++ esfq_index x; ++ ++ x = q->ht[hash]; ++ if (x == depth) { ++ q->ht[hash] = x = q->dep[depth].next; ++ q->hash[x] = hash; ++ } ++ ++ if (end == ESFQ_TAIL) ++ __skb_queue_tail(&q->qs[x], skb); ++ else ++ __skb_queue_head(&q->qs[x], skb); ++ ++ esfq_inc(q, x); ++ if (q->qs[x].qlen == 1) { /* The flow is new */ ++ if (q->tail == depth) { /* It is the first flow */ ++ q->tail = x; ++ q->next[x] = x; ++ q->allot[x] = q->quantum; ++ } else { ++ q->next[x] = q->next[q->tail]; ++ q->next[q->tail] = x; ++ q->tail = x; ++ } ++ } ++} ++ ++static int esfq_enqueue(struct sk_buff *skb, struct Qdisc* sch) ++{ ++ struct esfq_sched_data *q = qdisc_priv(sch); ++ esfq_q_enqueue(skb, q, ESFQ_TAIL); ++ sch->qstats.backlog += skb->len; ++ if (++sch->q.qlen < q->limit-1) { ++ sch->bstats.bytes += skb->len; ++ sch->bstats.packets++; ++ return 0; ++ } ++ ++ sch->qstats.drops++; ++ esfq_drop(sch); ++ return NET_XMIT_CN; ++} ++ ++static struct sk_buff *esfq_peek(struct Qdisc* sch) ++{ ++ struct esfq_sched_data *q = qdisc_priv(sch); ++ esfq_index a; ++ ++ /* No active slots */ ++ if (q->tail == q->depth) ++ return NULL; ++ ++ a = q->next[q->tail]; ++ return skb_peek(&q->qs[a]); ++} ++ ++static struct sk_buff *esfq_q_dequeue(struct esfq_sched_data *q) ++{ ++ struct sk_buff *skb; ++ unsigned depth = q->depth; ++ esfq_index a, old_a; ++ ++ /* No active slots */ ++ if (q->tail == depth) ++ return NULL; ++ ++ a = old_a = q->next[q->tail]; ++ ++ /* Grab packet */ ++ skb = __skb_dequeue(&q->qs[a]); ++ esfq_dec(q, a); ++ ++ /* Is the slot empty? */ ++ if (q->qs[a].qlen == 0) { ++ q->ht[q->hash[a]] = depth; ++ a = q->next[a]; ++ if (a == old_a) { ++ q->tail = depth; ++ return skb; ++ } ++ q->next[q->tail] = a; ++ q->allot[a] += q->quantum; ++ } else if ((q->allot[a] -= skb->len) <= 0) { ++ q->tail = a; ++ a = q->next[a]; ++ q->allot[a] += q->quantum; ++ } ++ ++ return skb; ++} ++ ++static struct sk_buff *esfq_dequeue(struct Qdisc* sch) ++{ ++ struct esfq_sched_data *q = qdisc_priv(sch); ++ struct sk_buff *skb; ++ ++ skb = esfq_q_dequeue(q); ++ if (skb == NULL) ++ return NULL; ++ sch->q.qlen--; ++ sch->qstats.backlog -= skb->len; ++ return skb; ++} ++ ++static void esfq_q_destroy(struct esfq_sched_data *q) ++{ ++ del_timer(&q->perturb_timer); ++ if(q->ht) ++ kfree(q->ht); ++ if(q->dep) ++ kfree(q->dep); ++ if(q->next) ++ kfree(q->next); ++ if(q->allot) ++ kfree(q->allot); ++ if(q->hash) ++ kfree(q->hash); ++ if(q->qs) ++ kfree(q->qs); ++} ++ ++static void esfq_destroy(struct Qdisc *sch) ++{ ++ struct esfq_sched_data *q = qdisc_priv(sch); ++ esfq_q_destroy(q); ++} ++ ++ ++static void esfq_reset(struct Qdisc* sch) ++{ ++ struct sk_buff *skb; ++ ++ while ((skb = esfq_dequeue(sch)) != NULL) ++ kfree_skb(skb); ++} ++ ++static void esfq_perturbation(unsigned long arg) ++{ ++ struct Qdisc *sch = (struct Qdisc*)arg; ++ struct esfq_sched_data *q = qdisc_priv(sch); ++ ++ q->perturbation = prandom_u32()&0x1F; ++ ++ if (q->perturb_period) { ++ q->perturb_timer.expires = jiffies + q->perturb_period; ++ add_timer(&q->perturb_timer); ++ } ++} ++ ++static unsigned int esfq_check_hash(unsigned int kind) ++{ ++ switch (kind) { ++ case TCA_SFQ_HASH_CTORIGDST: ++ case TCA_SFQ_HASH_CTORIGSRC: ++ case TCA_SFQ_HASH_CTREPLDST: ++ case TCA_SFQ_HASH_CTREPLSRC: ++ case TCA_SFQ_HASH_CTNATCHG: ++#ifndef CONFIG_NET_SCH_ESFQ_NFCT ++ { ++ if (net_ratelimit()) ++ printk(KERN_WARNING "ESFQ: Conntrack hash types disabled in kernel config. Falling back to classic.\n"); ++ return TCA_SFQ_HASH_CLASSIC; ++ } ++#endif ++ case TCA_SFQ_HASH_CLASSIC: ++ case TCA_SFQ_HASH_DST: ++ case TCA_SFQ_HASH_SRC: ++ case TCA_SFQ_HASH_FWMARK: ++ return kind; ++ default: ++ { ++ if (net_ratelimit()) ++ printk(KERN_WARNING "ESFQ: Unknown hash type. Falling back to classic.\n"); ++ return TCA_SFQ_HASH_CLASSIC; ++ } ++ } ++} ++ ++static int esfq_q_init(struct esfq_sched_data *q, struct nlattr *opt) ++{ ++ struct tc_esfq_qopt *ctl = nla_data(opt); ++ esfq_index p = ~0U/2; ++ int i; ++ ++ if (opt && opt->nla_len < nla_attr_size(sizeof(*ctl))) ++ return -EINVAL; ++ ++ q->perturbation = 0; ++ q->hash_kind = TCA_SFQ_HASH_CLASSIC; ++ q->max_depth = 0; ++ if (opt == NULL) { ++ q->perturb_period = 0; ++ q->hash_divisor = 1024; ++ q->tail = q->limit = q->depth = 128; ++ ++ } else { ++ struct tc_esfq_qopt *ctl = nla_data(opt); ++ if (ctl->quantum) ++ q->quantum = ctl->quantum; ++ q->perturb_period = ctl->perturb_period*HZ; ++ q->hash_divisor = ctl->divisor ? : 1024; ++ q->tail = q->limit = q->depth = ctl->flows ? : 128; ++ ++ if ( q->depth > p - 1 ) ++ return -EINVAL; ++ ++ if (ctl->limit) ++ q->limit = min_t(u32, ctl->limit, q->depth); ++ ++ if (ctl->hash_kind) { ++ q->hash_kind = esfq_check_hash(ctl->hash_kind); ++ } ++ } ++ ++ q->ht = kmalloc(q->hash_divisor*sizeof(esfq_index), GFP_KERNEL); ++ if (!q->ht) ++ goto err_case; ++ q->dep = kmalloc((1+q->depth*2)*sizeof(struct esfq_head), GFP_KERNEL); ++ if (!q->dep) ++ goto err_case; ++ q->next = kmalloc(q->depth*sizeof(esfq_index), GFP_KERNEL); ++ if (!q->next) ++ goto err_case; ++ q->allot = kmalloc(q->depth*sizeof(short), GFP_KERNEL); ++ if (!q->allot) ++ goto err_case; ++ q->hash = kmalloc(q->depth*sizeof(unsigned short), GFP_KERNEL); ++ if (!q->hash) ++ goto err_case; ++ q->qs = kmalloc(q->depth*sizeof(struct sk_buff_head), GFP_KERNEL); ++ if (!q->qs) ++ goto err_case; ++ ++ for (i=0; i< q->hash_divisor; i++) ++ q->ht[i] = q->depth; ++ for (i=0; idepth; i++) { ++ skb_queue_head_init(&q->qs[i]); ++ q->dep[i+q->depth].next = i+q->depth; ++ q->dep[i+q->depth].prev = i+q->depth; ++ } ++ ++ for (i=0; idepth; i++) ++ esfq_link(q, i); ++ return 0; ++err_case: ++ esfq_q_destroy(q); ++ return -ENOBUFS; ++} ++ ++static int esfq_init(struct Qdisc *sch, struct nlattr *opt) ++{ ++ struct esfq_sched_data *q = qdisc_priv(sch); ++ int err; ++ ++ q->quantum = psched_mtu(qdisc_dev(sch)); /* default */ ++ if ((err = esfq_q_init(q, opt))) ++ return err; ++ ++ init_timer(&q->perturb_timer); ++ q->perturb_timer.data = (unsigned long)sch; ++ q->perturb_timer.function = esfq_perturbation; ++ if (q->perturb_period) { ++ q->perturb_timer.expires = jiffies + q->perturb_period; ++ add_timer(&q->perturb_timer); ++ } ++ ++ return 0; ++} ++ ++static int esfq_change(struct Qdisc *sch, struct nlattr *opt) ++{ ++ struct esfq_sched_data *q = qdisc_priv(sch); ++ struct esfq_sched_data new; ++ struct sk_buff *skb; ++ int err; ++ ++ /* set up new queue */ ++ memset(&new, 0, sizeof(struct esfq_sched_data)); ++ new.quantum = psched_mtu(qdisc_dev(sch)); /* default */ ++ if ((err = esfq_q_init(&new, opt))) ++ return err; ++ ++ /* copy all packets from the old queue to the new queue */ ++ sch_tree_lock(sch); ++ while ((skb = esfq_q_dequeue(q)) != NULL) ++ esfq_q_enqueue(skb, &new, ESFQ_TAIL); ++ ++ /* clean up the old queue */ ++ esfq_q_destroy(q); ++ ++ /* copy elements of the new queue into the old queue */ ++ q->perturb_period = new.perturb_period; ++ q->quantum = new.quantum; ++ q->limit = new.limit; ++ q->depth = new.depth; ++ q->hash_divisor = new.hash_divisor; ++ q->hash_kind = new.hash_kind; ++ q->tail = new.tail; ++ q->max_depth = new.max_depth; ++ q->ht = new.ht; ++ q->dep = new.dep; ++ q->next = new.next; ++ q->allot = new.allot; ++ q->hash = new.hash; ++ q->qs = new.qs; ++ ++ /* finish up */ ++ if (q->perturb_period) { ++ q->perturb_timer.expires = jiffies + q->perturb_period; ++ add_timer(&q->perturb_timer); ++ } else { ++ q->perturbation = 0; ++ } ++ sch_tree_unlock(sch); ++ return 0; ++} ++ ++static int esfq_dump(struct Qdisc *sch, struct sk_buff *skb) ++{ ++ struct esfq_sched_data *q = qdisc_priv(sch); ++ unsigned char *b = skb_tail_pointer(skb); ++ struct tc_esfq_qopt opt; ++ ++ opt.quantum = q->quantum; ++ opt.perturb_period = q->perturb_period/HZ; ++ ++ opt.limit = q->limit; ++ opt.divisor = q->hash_divisor; ++ opt.flows = q->depth; ++ opt.hash_kind = q->hash_kind; ++ ++ if (nla_put(skb, TCA_OPTIONS, sizeof(opt), &opt)) ++ goto nla_put_failure; ++ ++ return skb->len; ++ ++nla_put_failure: ++ nlmsg_trim(skb, b); ++ return -1; ++} ++ ++static struct Qdisc_ops esfq_qdisc_ops = ++{ ++ .next = NULL, ++ .cl_ops = NULL, ++ .id = "esfq", ++ .priv_size = sizeof(struct esfq_sched_data), ++ .enqueue = esfq_enqueue, ++ .dequeue = esfq_dequeue, ++ .peek = esfq_peek, ++ .drop = esfq_drop, ++ .init = esfq_init, ++ .reset = esfq_reset, ++ .destroy = esfq_destroy, ++ .change = esfq_change, ++ .dump = esfq_dump, ++ .owner = THIS_MODULE, ++}; ++ ++static int __init esfq_module_init(void) ++{ ++ return register_qdisc(&esfq_qdisc_ops); ++} ++static void __exit esfq_module_exit(void) ++{ ++ unregister_qdisc(&esfq_qdisc_ops); ++} ++module_init(esfq_module_init) ++module_exit(esfq_module_exit) ++MODULE_LICENSE("GPL"); diff --git a/target/linux/generic/patches-4.1/630-packet_socket_type.patch b/target/linux/generic/patches-4.1/630-packet_socket_type.patch new file mode 100644 index 0000000..9fb9a40 --- /dev/null +++ b/target/linux/generic/patches-4.1/630-packet_socket_type.patch @@ -0,0 +1,134 @@ +This patch allows the user to specify desired packet types (outgoing, +broadcast, unicast, etc.) on packet sockets via setsockopt. +This can reduce the load in situations where only a limited number +of packet types are necessary + +Signed-off-by: Felix Fietkau + +--- a/include/uapi/linux/if_packet.h ++++ b/include/uapi/linux/if_packet.h +@@ -31,6 +31,8 @@ struct sockaddr_ll { + #define PACKET_KERNEL 7 /* To kernel space */ + /* Unused, PACKET_FASTROUTE and PACKET_LOOPBACK are invisible to user space */ + #define PACKET_FASTROUTE 6 /* Fastrouted frame */ ++#define PACKET_MASK_ANY 0xffffffff /* mask for packet type bits */ ++ + + /* Packet socket options */ + +@@ -54,6 +56,7 @@ struct sockaddr_ll { + #define PACKET_FANOUT 18 + #define PACKET_TX_HAS_OFF 19 + #define PACKET_QDISC_BYPASS 20 ++#define PACKET_RECV_TYPE 21 + + #define PACKET_FANOUT_HASH 0 + #define PACKET_FANOUT_LB 1 +--- a/net/packet/af_packet.c ++++ b/net/packet/af_packet.c +@@ -1533,6 +1533,7 @@ static int packet_rcv_spkt(struct sk_buf + { + struct sock *sk; + struct sockaddr_pkt *spkt; ++ struct packet_sock *po; + + /* + * When we registered the protocol we saved the socket in the data +@@ -1540,6 +1541,7 @@ static int packet_rcv_spkt(struct sk_buf + */ + + sk = pt->af_packet_priv; ++ po = pkt_sk(sk); + + /* + * Yank back the headers [hope the device set this +@@ -1552,7 +1554,7 @@ static int packet_rcv_spkt(struct sk_buf + * so that this procedure is noop. + */ + +- if (skb->pkt_type == PACKET_LOOPBACK) ++ if (!(po->pkt_type & (1 << skb->pkt_type))) + goto out; + + if (!net_eq(dev_net(dev), sock_net(sk))) +@@ -1759,12 +1761,12 @@ static int packet_rcv(struct sk_buff *sk + int skb_len = skb->len; + unsigned int snaplen, res; + +- if (skb->pkt_type == PACKET_LOOPBACK) +- goto drop; +- + sk = pt->af_packet_priv; + po = pkt_sk(sk); + ++ if (!(po->pkt_type & (1 << skb->pkt_type))) ++ goto drop; ++ + if (!net_eq(dev_net(dev), sock_net(sk))) + goto drop; + +@@ -1884,12 +1886,12 @@ static int tpacket_rcv(struct sk_buff *s + BUILD_BUG_ON(TPACKET_ALIGN(sizeof(*h.h2)) != 32); + BUILD_BUG_ON(TPACKET_ALIGN(sizeof(*h.h3)) != 48); + +- if (skb->pkt_type == PACKET_LOOPBACK) +- goto drop; +- + sk = pt->af_packet_priv; + po = pkt_sk(sk); + ++ if (!(po->pkt_type & (1 << skb->pkt_type))) ++ goto drop; ++ + if (!net_eq(dev_net(dev), sock_net(sk))) + goto drop; + +@@ -2852,6 +2854,7 @@ static int packet_create(struct net *net + spin_lock_init(&po->bind_lock); + mutex_init(&po->pg_vec_lock); + po->prot_hook.func = packet_rcv; ++ po->pkt_type = PACKET_MASK_ANY & ~(1 << PACKET_LOOPBACK); + + if (sock->type == SOCK_PACKET) + po->prot_hook.func = packet_rcv_spkt; +@@ -3457,6 +3460,16 @@ packet_setsockopt(struct socket *sock, i + po->xmit = val ? packet_direct_xmit : dev_queue_xmit; + return 0; + } ++ case PACKET_RECV_TYPE: ++ { ++ unsigned int val; ++ if (optlen != sizeof(val)) ++ return -EINVAL; ++ if (copy_from_user(&val, optval, sizeof(val))) ++ return -EFAULT; ++ po->pkt_type = val & ~BIT(PACKET_LOOPBACK); ++ return 0; ++ } + default: + return -ENOPROTOOPT; + } +@@ -3508,6 +3521,13 @@ static int packet_getsockopt(struct sock + case PACKET_VNET_HDR: + val = po->has_vnet_hdr; + break; ++ case PACKET_RECV_TYPE: ++ if (len > sizeof(unsigned int)) ++ len = sizeof(unsigned int); ++ val = po->pkt_type; ++ ++ data = &val; ++ break; + case PACKET_VERSION: + val = po->tp_version; + break; +--- a/net/packet/internal.h ++++ b/net/packet/internal.h +@@ -115,6 +115,7 @@ struct packet_sock { + struct net_device __rcu *cached_dev; + int (*xmit)(struct sk_buff *skb); + struct packet_type prot_hook ____cacheline_aligned_in_smp; ++ unsigned int pkt_type; + }; + + static struct packet_sock *pkt_sk(struct sock *sk) diff --git a/target/linux/generic/patches-4.1/640-bridge_no_eap_forward.patch b/target/linux/generic/patches-4.1/640-bridge_no_eap_forward.patch new file mode 100644 index 0000000..de52c02 --- /dev/null +++ b/target/linux/generic/patches-4.1/640-bridge_no_eap_forward.patch @@ -0,0 +1,23 @@ +From: Felix Fietkau +Subject: [PATCH] bridge: no EAP forward + +When bridging, do not forward EAP frames to other ports, only deliver +them locally. +Fixes WPA authentication issues with multiples APs that are connected to +each other via bridges. +--- +--- a/net/bridge/br_input.c ++++ b/net/bridge/br_input.c +@@ -162,7 +162,11 @@ int br_handle_frame_finish(struct sock * + if (IS_ENABLED(CONFIG_INET) && skb->protocol == htons(ETH_P_ARP)) + br_do_proxy_arp(skb, br, vid, p); + +- if (is_broadcast_ether_addr(dest)) { ++ if (skb->protocol == htons(ETH_P_PAE)) { ++ skb2 = skb; ++ /* Do not forward 802.1x/EAP frames */ ++ skb = NULL; ++ } else if (is_broadcast_ether_addr(dest)) { + skb2 = skb; + unicast = false; + } else if (is_multicast_ether_addr(dest)) { diff --git a/target/linux/generic/patches-4.1/641-bridge_always_accept_eap.patch b/target/linux/generic/patches-4.1/641-bridge_always_accept_eap.patch new file mode 100644 index 0000000..61f96e5 --- /dev/null +++ b/target/linux/generic/patches-4.1/641-bridge_always_accept_eap.patch @@ -0,0 +1,17 @@ +From: Felix Fietkau +Subject: [PATCH] bridge: always accept EAP + +Allow EAP frames to pass through bridges even in learning state. Fixes +issues with WDS. +--- +--- a/net/bridge/br_input.c ++++ b/net/bridge/br_input.c +@@ -146,7 +146,7 @@ int br_handle_frame_finish(struct sock * + br_multicast_rcv(br, p, skb, vid)) + goto drop; + +- if (p->state == BR_STATE_LEARNING) ++ if ((p->state == BR_STATE_LEARNING) && skb->protocol != htons(ETH_P_PAE)) + goto drop; + + BR_INPUT_SKB_CB(skb)->brdev = br->dev; diff --git a/target/linux/generic/patches-4.1/642-bridge_port_isolate.patch b/target/linux/generic/patches-4.1/642-bridge_port_isolate.patch new file mode 100644 index 0000000..06c368d --- /dev/null +++ b/target/linux/generic/patches-4.1/642-bridge_port_isolate.patch @@ -0,0 +1,107 @@ +From: Felix Fietkau +Subject: [PATCH] bridge: port isolate + +Isolating individual bridge ports +--- +--- a/include/linux/if_bridge.h ++++ b/include/linux/if_bridge.h +@@ -45,6 +45,7 @@ struct br_ip_list { + #define BR_PROXYARP BIT(8) + #define BR_LEARNING_SYNC BIT(9) + #define BR_PROXYARP_WIFI BIT(10) ++#define BR_ISOLATE_MODE BIT(11) + + extern void brioctl_set(int (*ioctl_hook)(struct net *, unsigned int, void __user *)); + +--- a/net/bridge/br_sysfs_if.c ++++ b/net/bridge/br_sysfs_if.c +@@ -173,6 +173,22 @@ BRPORT_ATTR_FLAG(unicast_flood, BR_FLOOD + BRPORT_ATTR_FLAG(proxyarp, BR_PROXYARP); + BRPORT_ATTR_FLAG(proxyarp_wifi, BR_PROXYARP_WIFI); + ++static ssize_t show_isolate_mode(struct net_bridge_port *p, char *buf) ++{ ++ int isolate_mode = (p->flags & BR_ISOLATE_MODE) ? 1 : 0; ++ return sprintf(buf, "%d\n", isolate_mode); ++} ++static ssize_t store_isolate_mode(struct net_bridge_port *p, unsigned long v) ++{ ++ if (v) ++ p->flags |= BR_ISOLATE_MODE; ++ else ++ p->flags &= ~BR_ISOLATE_MODE; ++ return 0; ++} ++static BRPORT_ATTR(isolate_mode, S_IRUGO | S_IWUSR, ++ show_isolate_mode, store_isolate_mode); ++ + #ifdef CONFIG_BRIDGE_IGMP_SNOOPING + static ssize_t show_multicast_router(struct net_bridge_port *p, char *buf) + { +@@ -217,6 +233,7 @@ static const struct brport_attribute *br + #endif + &brport_attr_proxyarp, + &brport_attr_proxyarp_wifi, ++ &brport_attr_isolate_mode, + NULL + }; + +--- a/net/bridge/br_input.c ++++ b/net/bridge/br_input.c +@@ -185,8 +185,8 @@ int br_handle_frame_finish(struct sock * + + unicast = false; + br->dev->stats.multicast++; +- } else if ((dst = __br_fdb_get(br, dest, vid)) && +- dst->is_local) { ++ } else if ((p->flags & BR_ISOLATE_MODE) || ++ ((dst = __br_fdb_get(br, dest, vid)) && dst->is_local)) { + skb2 = skb; + /* Do not forward the packet since it's local. */ + skb = NULL; +--- a/net/bridge/br_forward.c ++++ b/net/bridge/br_forward.c +@@ -118,7 +118,7 @@ EXPORT_SYMBOL_GPL(br_deliver); + /* called with rcu_read_lock */ + void br_forward(const struct net_bridge_port *to, struct sk_buff *skb, struct sk_buff *skb0) + { +- if (should_deliver(to, skb)) { ++ if (should_deliver(to, skb) && !(to->flags & BR_ISOLATE_MODE)) { + if (skb0) + deliver_clone(to, skb, __br_forward); + else +@@ -174,7 +174,7 @@ static void br_flood(struct net_bridge * + struct sk_buff *skb0, + void (*__packet_hook)(const struct net_bridge_port *p, + struct sk_buff *skb), +- bool unicast) ++ bool unicast, bool forward) + { + struct net_bridge_port *p; + struct net_bridge_port *prev; +@@ -182,6 +182,8 @@ static void br_flood(struct net_bridge * + prev = NULL; + + list_for_each_entry_rcu(p, &br->port_list, list) { ++ if (forward && (p->flags & BR_ISOLATE_MODE)) ++ continue; + /* Do not flood unicast traffic to ports that turn it off */ + if (unicast && !(p->flags & BR_FLOOD)) + continue; +@@ -216,14 +218,14 @@ out: + /* called with rcu_read_lock */ + void br_flood_deliver(struct net_bridge *br, struct sk_buff *skb, bool unicast) + { +- br_flood(br, skb, NULL, __br_deliver, unicast); ++ br_flood(br, skb, NULL, __br_deliver, unicast, false); + } + + /* called under bridge lock */ + void br_flood_forward(struct net_bridge *br, struct sk_buff *skb, + struct sk_buff *skb2, bool unicast) + { +- br_flood(br, skb, skb2, __br_forward, unicast); ++ br_flood(br, skb, skb2, __br_forward, unicast, true); + } + + #ifdef CONFIG_BRIDGE_IGMP_SNOOPING diff --git a/target/linux/generic/patches-4.1/643-bridge_remove_ipv6_dependency.patch b/target/linux/generic/patches-4.1/643-bridge_remove_ipv6_dependency.patch new file mode 100644 index 0000000..b18f33e --- /dev/null +++ b/target/linux/generic/patches-4.1/643-bridge_remove_ipv6_dependency.patch @@ -0,0 +1,123 @@ +From: Jonas Gorski +Subject: [PATCH] bridge: remove IPv6 depependency of bridge in 2.6.38+ + +Since 2.6.38 the bridge module has a dependency to IPv6 if IPv6 is +enabled. Since the IPv6 module isn't exactly lightweight and bridge also +only needs a single function from IPv6, it's rather easy to create a +common "lib" module with a RCU pointer to the actual implementation, if +the IPv6 module is loaded (although slightly hackish). + +The codepath seems to be only taken when using IPv6, so there should be +no negative side effects when IPv6 isn't loaded. I did not measure how +big the performance impact is. +--- +--- a/include/net/addrconf.h ++++ b/include/net/addrconf.h +@@ -91,6 +91,12 @@ int ipv6_rcv_saddr_equal(const struct so + void addrconf_join_solict(struct net_device *dev, const struct in6_addr *addr); + void addrconf_leave_solict(struct inet6_dev *idev, const struct in6_addr *addr); + ++extern int (*ipv6_dev_get_saddr_hook)(struct net *net, ++ const struct net_device *dev, ++ const struct in6_addr *daddr, ++ unsigned int prefs, ++ struct in6_addr *saddr); ++ + static inline unsigned long addrconf_timeout_fixup(u32 timeout, + unsigned int unit) + { +--- a/net/bridge/Kconfig ++++ b/net/bridge/Kconfig +@@ -6,7 +6,6 @@ config BRIDGE + tristate "802.1d Ethernet Bridging" + select LLC + select STP +- depends on IPV6 || IPV6=n + ---help--- + If you say Y here, then your Linux box will be able to act as an + Ethernet bridge, which means that the different Ethernet segments it +--- a/net/ipv6/Makefile ++++ b/net/ipv6/Makefile +@@ -45,6 +45,7 @@ obj-y += addrconf_core.o exthdrs_core.o + obj-$(CONFIG_INET) += output_core.o protocol.o $(ipv6-offload) + + obj-$(subst m,y,$(CONFIG_IPV6)) += inet6_hashtables.o ++obj-$(subst m,y,$(CONFIG_IPV6)) += inet6_stubs.o + + ifneq ($(CONFIG_IPV6),) + obj-$(CONFIG_NET_UDP_TUNNEL) += ip6_udp_tunnel.o +--- a/net/ipv6/addrconf.c ++++ b/net/ipv6/addrconf.c +@@ -1358,7 +1358,7 @@ out: + return ret; + } + +-int ipv6_dev_get_saddr(struct net *net, const struct net_device *dst_dev, ++static int __ipv6_dev_get_saddr(struct net *net, const struct net_device *dst_dev, + const struct in6_addr *daddr, unsigned int prefs, + struct in6_addr *saddr) + { +@@ -1481,7 +1481,6 @@ try_nextdev: + in6_ifa_put(hiscore->ifa); + return 0; + } +-EXPORT_SYMBOL(ipv6_dev_get_saddr); + + int __ipv6_get_lladdr(struct inet6_dev *idev, struct in6_addr *addr, + u32 banned_flags) +@@ -5810,6 +5809,9 @@ int __init addrconf_init(void) + + ipv6_addr_label_rtnl_register(); + ++ BUG_ON(ipv6_dev_get_saddr_hook != NULL); ++ rcu_assign_pointer(ipv6_dev_get_saddr_hook, __ipv6_dev_get_saddr); ++ + return 0; + errout: + rtnl_af_unregister(&inet6_ops); +@@ -5829,6 +5831,9 @@ void addrconf_cleanup(void) + struct net_device *dev; + int i; + ++ rcu_assign_pointer(ipv6_dev_get_saddr_hook, NULL); ++ synchronize_rcu(); ++ + unregister_netdevice_notifier(&ipv6_dev_notf); + unregister_pernet_subsys(&addrconf_ops); + ipv6_addr_label_cleanup(); +--- /dev/null ++++ b/net/ipv6/inet6_stubs.c +@@ -0,0 +1,33 @@ ++/* ++ * 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. ++ */ ++#include ++#include ++ ++int (*ipv6_dev_get_saddr_hook)(struct net *net, const struct net_device *dev, ++ const struct in6_addr *daddr, unsigned int prefs, ++ struct in6_addr *saddr); ++ ++EXPORT_SYMBOL(ipv6_dev_get_saddr_hook); ++ ++int ipv6_dev_get_saddr(struct net *net, const struct net_device *dst_dev, ++ const struct in6_addr *daddr, unsigned int prefs, ++ struct in6_addr *saddr) ++{ ++ int ret = -EADDRNOTAVAIL; ++ typeof(ipv6_dev_get_saddr_hook) dev_get_saddr; ++ ++ rcu_read_lock(); ++ dev_get_saddr = rcu_dereference(ipv6_dev_get_saddr_hook); ++ ++ if (dev_get_saddr) ++ ret = dev_get_saddr(net, dst_dev, daddr, prefs, saddr); ++ ++ rcu_read_unlock(); ++ return ret; ++} ++EXPORT_SYMBOL(ipv6_dev_get_saddr); ++ diff --git a/target/linux/generic/patches-4.1/645-bridge_multicast_to_unicast.patch b/target/linux/generic/patches-4.1/645-bridge_multicast_to_unicast.patch new file mode 100644 index 0000000..d11a4a8 --- /dev/null +++ b/target/linux/generic/patches-4.1/645-bridge_multicast_to_unicast.patch @@ -0,0 +1,397 @@ +From: Felix Fietkau +Subject: [PATCH] bridge: multicast to unicast + +Implement optinal multicast->unicast conversion for igmp snooping +--- +--- a/include/linux/if_bridge.h ++++ b/include/linux/if_bridge.h +@@ -46,6 +46,7 @@ struct br_ip_list { + #define BR_LEARNING_SYNC BIT(9) + #define BR_PROXYARP_WIFI BIT(10) + #define BR_ISOLATE_MODE BIT(11) ++#define BR_MULTICAST_TO_UCAST BIT(12) + + extern void brioctl_set(int (*ioctl_hook)(struct net *, unsigned int, void __user *)); + +--- a/net/bridge/br_multicast.c ++++ b/net/bridge/br_multicast.c +@@ -635,7 +635,8 @@ struct net_bridge_port_group *br_multica + struct net_bridge_port *port, + struct br_ip *group, + struct net_bridge_port_group __rcu *next, +- unsigned char state) ++ unsigned char state, ++ const unsigned char *src) + { + struct net_bridge_port_group *p; + +@@ -650,12 +651,33 @@ struct net_bridge_port_group *br_multica + hlist_add_head(&p->mglist, &port->mglist); + setup_timer(&p->timer, br_multicast_port_group_expired, + (unsigned long)p); ++ if ((port->flags & BR_MULTICAST_TO_UCAST) && src) { ++ memcpy(p->eth_addr, src, ETH_ALEN); ++ p->unicast = true; ++ } + return p; + } + ++static bool br_port_group_equal(struct net_bridge_port_group *p, ++ struct net_bridge_port *port, ++ const unsigned char *src) ++{ ++ if (p->port != port) ++ return false; ++ ++ if (!p->unicast) ++ return true; ++ ++ if (!src) ++ return false; ++ ++ return ether_addr_equal(src, p->eth_addr); ++} ++ + static int br_multicast_add_group(struct net_bridge *br, + struct net_bridge_port *port, +- struct br_ip *group) ++ struct br_ip *group, ++ const unsigned char *src) + { + struct net_bridge_mdb_entry *mp; + struct net_bridge_port_group *p; +@@ -682,13 +704,13 @@ static int br_multicast_add_group(struct + for (pp = &mp->ports; + (p = mlock_dereference(*pp, br)) != NULL; + pp = &p->next) { +- if (p->port == port) ++ if (br_port_group_equal(p, port, src)) + goto found; + if ((unsigned long)p->port < (unsigned long)port) + break; + } + +- p = br_multicast_new_port_group(port, group, *pp, MDB_TEMPORARY); ++ p = br_multicast_new_port_group(port, group, *pp, MDB_TEMPORARY, src); + if (unlikely(!p)) + goto err; + rcu_assign_pointer(*pp, p); +@@ -707,7 +729,7 @@ err: + static int br_ip4_multicast_add_group(struct net_bridge *br, + struct net_bridge_port *port, + __be32 group, +- __u16 vid) ++ __u16 vid, const unsigned char *src) + { + struct br_ip br_group; + +@@ -718,14 +740,14 @@ static int br_ip4_multicast_add_group(st + br_group.proto = htons(ETH_P_IP); + br_group.vid = vid; + +- return br_multicast_add_group(br, port, &br_group); ++ return br_multicast_add_group(br, port, &br_group, src); + } + + #if IS_ENABLED(CONFIG_IPV6) + static int br_ip6_multicast_add_group(struct net_bridge *br, + struct net_bridge_port *port, + const struct in6_addr *group, +- __u16 vid) ++ __u16 vid, const unsigned char *src) + { + struct br_ip br_group; + +@@ -736,7 +758,7 @@ static int br_ip6_multicast_add_group(st + br_group.proto = htons(ETH_P_IPV6); + br_group.vid = vid; + +- return br_multicast_add_group(br, port, &br_group); ++ return br_multicast_add_group(br, port, &br_group, src); + } + #endif + +@@ -966,6 +988,7 @@ static int br_ip4_multicast_igmp3_report + struct sk_buff *skb, + u16 vid) + { ++ const unsigned char *src; + struct igmpv3_report *ih; + struct igmpv3_grec *grec; + int i; +@@ -1009,7 +1032,8 @@ static int br_ip4_multicast_igmp3_report + continue; + } + +- err = br_ip4_multicast_add_group(br, port, group, vid); ++ src = eth_hdr(skb)->h_source; ++ err = br_ip4_multicast_add_group(br, port, group, vid, src); + if (err) + break; + } +@@ -1023,6 +1047,7 @@ static int br_ip6_multicast_mld2_report( + struct sk_buff *skb, + u16 vid) + { ++ const unsigned char *src = eth_hdr(skb)->h_source; + struct icmp6hdr *icmp6h; + struct mld2_grec *grec; + int i; +@@ -1071,7 +1096,7 @@ static int br_ip6_multicast_mld2_report( + } + + err = br_ip6_multicast_add_group(br, port, &grec->grec_mca, +- vid); ++ vid, src); + if (err) + break; + } +@@ -1407,7 +1432,8 @@ br_multicast_leave_group(struct net_brid + struct net_bridge_port *port, + struct br_ip *group, + struct bridge_mcast_other_query *other_query, +- struct bridge_mcast_own_query *own_query) ++ struct bridge_mcast_own_query *own_query, ++ const unsigned char *src) + { + struct net_bridge_mdb_htable *mdb; + struct net_bridge_mdb_entry *mp; +@@ -1457,7 +1483,7 @@ br_multicast_leave_group(struct net_brid + for (pp = &mp->ports; + (p = mlock_dereference(*pp, br)) != NULL; + pp = &p->next) { +- if (p->port != port) ++ if (!br_port_group_equal(p, port, src)) + continue; + + rcu_assign_pointer(*pp, p->next); +@@ -1491,7 +1517,7 @@ br_multicast_leave_group(struct net_brid + for (p = mlock_dereference(mp->ports, br); + p != NULL; + p = mlock_dereference(p->next, br)) { +- if (p->port != port) ++ if (!br_port_group_equal(p, port, src)) + continue; + + if (!hlist_unhashed(&p->mglist) && +@@ -1509,8 +1535,8 @@ out: + + static void br_ip4_multicast_leave_group(struct net_bridge *br, + struct net_bridge_port *port, +- __be32 group, +- __u16 vid) ++ __be32 group, __u16 vid, ++ const unsigned char *src) + { + struct br_ip br_group; + struct bridge_mcast_own_query *own_query; +@@ -1525,14 +1551,14 @@ static void br_ip4_multicast_leave_group + br_group.vid = vid; + + br_multicast_leave_group(br, port, &br_group, &br->ip4_other_query, +- own_query); ++ own_query, src); + } + + #if IS_ENABLED(CONFIG_IPV6) + static void br_ip6_multicast_leave_group(struct net_bridge *br, + struct net_bridge_port *port, + const struct in6_addr *group, +- __u16 vid) ++ __u16 vid, const unsigned char *src) + { + struct br_ip br_group; + struct bridge_mcast_own_query *own_query; +@@ -1547,7 +1573,7 @@ static void br_ip6_multicast_leave_group + br_group.vid = vid; + + br_multicast_leave_group(br, port, &br_group, &br->ip6_other_query, +- own_query); ++ own_query, src); + } + #endif + +@@ -1556,6 +1582,7 @@ static int br_multicast_ipv4_rcv(struct + struct sk_buff *skb, + u16 vid) + { ++ const unsigned char *src; + struct sk_buff *skb2 = skb; + const struct iphdr *iph; + struct igmphdr *ih; +@@ -1624,12 +1651,13 @@ static int br_multicast_ipv4_rcv(struct + + BR_INPUT_SKB_CB(skb)->igmp = 1; + ih = igmp_hdr(skb2); ++ src = eth_hdr(skb)->h_source; + + switch (ih->type) { + case IGMP_HOST_MEMBERSHIP_REPORT: + case IGMPV2_HOST_MEMBERSHIP_REPORT: + BR_INPUT_SKB_CB(skb)->mrouters_only = 1; +- err = br_ip4_multicast_add_group(br, port, ih->group, vid); ++ err = br_ip4_multicast_add_group(br, port, ih->group, vid, src); + break; + case IGMPV3_HOST_MEMBERSHIP_REPORT: + err = br_ip4_multicast_igmp3_report(br, port, skb2, vid); +@@ -1638,7 +1666,7 @@ static int br_multicast_ipv4_rcv(struct + err = br_ip4_multicast_query(br, port, skb2, vid); + break; + case IGMP_HOST_LEAVE_MESSAGE: +- br_ip4_multicast_leave_group(br, port, ih->group, vid); ++ br_ip4_multicast_leave_group(br, port, ih->group, vid, src); + break; + } + +@@ -1656,6 +1684,7 @@ static int br_multicast_ipv6_rcv(struct + struct sk_buff *skb, + u16 vid) + { ++ const unsigned char *src; + struct sk_buff *skb2; + const struct ipv6hdr *ip6h; + u8 icmp6_type; +@@ -1763,9 +1792,11 @@ static int br_multicast_ipv6_rcv(struct + err = -EINVAL; + goto out; + } ++ src = eth_hdr(skb)->h_source; + mld = (struct mld_msg *)skb_transport_header(skb2); + BR_INPUT_SKB_CB(skb)->mrouters_only = 1; +- err = br_ip6_multicast_add_group(br, port, &mld->mld_mca, vid); ++ err = br_ip6_multicast_add_group(br, port, &mld->mld_mca, vid, ++ src); + break; + } + case ICMPV6_MLD2_REPORT: +@@ -1781,8 +1812,9 @@ static int br_multicast_ipv6_rcv(struct + err = -EINVAL; + goto out; + } ++ src = eth_hdr(skb)->h_source; + mld = (struct mld_msg *)skb_transport_header(skb2); +- br_ip6_multicast_leave_group(br, port, &mld->mld_mca, vid); ++ br_ip6_multicast_leave_group(br, port, &mld->mld_mca, vid, src); + } + } + +--- a/net/bridge/br_private.h ++++ b/net/bridge/br_private.h +@@ -113,6 +113,9 @@ struct net_bridge_port_group { + struct timer_list timer; + struct br_ip addr; + unsigned char state; ++ ++ unsigned char eth_addr[ETH_ALEN]; ++ bool unicast; + }; + + struct net_bridge_mdb_entry +@@ -481,7 +484,8 @@ void br_multicast_free_pg(struct rcu_hea + struct net_bridge_port_group * + br_multicast_new_port_group(struct net_bridge_port *port, struct br_ip *group, + struct net_bridge_port_group __rcu *next, +- unsigned char state); ++ unsigned char state, ++ const unsigned char *src); + void br_mdb_init(void); + void br_mdb_uninit(void); + void br_mdb_notify(struct net_device *dev, struct net_bridge_port *port, +--- a/net/bridge/br_mdb.c ++++ b/net/bridge/br_mdb.c +@@ -343,7 +343,7 @@ static int br_mdb_add_group(struct net_b + break; + } + +- p = br_multicast_new_port_group(port, group, *pp, state); ++ p = br_multicast_new_port_group(port, group, *pp, state, NULL); + if (unlikely(!p)) + return -ENOMEM; + rcu_assign_pointer(*pp, p); +--- a/net/bridge/br_forward.c ++++ b/net/bridge/br_forward.c +@@ -169,6 +169,34 @@ out: + return p; + } + ++static struct net_bridge_port *maybe_deliver_addr( ++ struct net_bridge_port *prev, struct net_bridge_port *p, ++ struct sk_buff *skb, const unsigned char *addr, ++ void (*__packet_hook)(const struct net_bridge_port *p, ++ struct sk_buff *skb)) ++{ ++ struct net_device *dev = BR_INPUT_SKB_CB(skb)->brdev; ++ const unsigned char *src = eth_hdr(skb)->h_source; ++ ++ if (!should_deliver(p, skb)) ++ return prev; ++ ++ /* Even with hairpin, no soliloquies - prevent breaking IPv6 DAD */ ++ if (skb->dev == p->dev && ether_addr_equal(src, addr)) ++ return prev; ++ ++ skb = skb_copy(skb, GFP_ATOMIC); ++ if (!skb) { ++ dev->stats.tx_dropped++; ++ return prev; ++ } ++ ++ memcpy(eth_hdr(skb)->h_dest, addr, ETH_ALEN); ++ __packet_hook(p, skb); ++ ++ return prev; ++} ++ + /* called under bridge lock */ + static void br_flood(struct net_bridge *br, struct sk_buff *skb, + struct sk_buff *skb0, +@@ -241,6 +269,7 @@ static void br_multicast_flood(struct ne + struct net_bridge_port *prev = NULL; + struct net_bridge_port_group *p; + struct hlist_node *rp; ++ const unsigned char *addr; + + rp = rcu_dereference(hlist_first_rcu(&br->router_list)); + p = mdst ? rcu_dereference(mdst->ports) : NULL; +@@ -251,10 +280,19 @@ static void br_multicast_flood(struct ne + rport = rp ? hlist_entry(rp, struct net_bridge_port, rlist) : + NULL; + +- port = (unsigned long)lport > (unsigned long)rport ? +- lport : rport; +- +- prev = maybe_deliver(prev, port, skb, __packet_hook); ++ if ((unsigned long)lport > (unsigned long)rport) { ++ port = lport; ++ addr = p->unicast ? p->eth_addr : NULL; ++ } else { ++ port = rport; ++ addr = NULL; ++ } ++ ++ if (addr) ++ prev = maybe_deliver_addr(prev, port, skb, addr, ++ __packet_hook); ++ else ++ prev = maybe_deliver(prev, port, skb, __packet_hook); + if (IS_ERR(prev)) + goto out; + +--- a/net/bridge/br_sysfs_if.c ++++ b/net/bridge/br_sysfs_if.c +@@ -204,6 +204,7 @@ static BRPORT_ATTR(multicast_router, S_I + store_multicast_router); + + BRPORT_ATTR_FLAG(multicast_fast_leave, BR_MULTICAST_FAST_LEAVE); ++BRPORT_ATTR_FLAG(multicast_to_unicast, BR_MULTICAST_TO_UCAST); + #endif + + static const struct brport_attribute *brport_attrs[] = { +@@ -230,6 +231,7 @@ static const struct brport_attribute *br + #ifdef CONFIG_BRIDGE_IGMP_SNOOPING + &brport_attr_multicast_router, + &brport_attr_multicast_fast_leave, ++ &brport_attr_multicast_to_unicast, + #endif + &brport_attr_proxyarp, + &brport_attr_proxyarp_wifi, diff --git a/target/linux/generic/patches-4.1/650-pppoe_header_pad.patch b/target/linux/generic/patches-4.1/650-pppoe_header_pad.patch new file mode 100644 index 0000000..2804469 --- /dev/null +++ b/target/linux/generic/patches-4.1/650-pppoe_header_pad.patch @@ -0,0 +1,20 @@ +--- a/drivers/net/ppp/pppoe.c ++++ b/drivers/net/ppp/pppoe.c +@@ -871,7 +871,7 @@ static int pppoe_sendmsg(struct socket * + goto end; + + +- skb = sock_wmalloc(sk, total_len + dev->hard_header_len + 32, ++ skb = sock_wmalloc(sk, total_len + dev->hard_header_len + 32 + NET_SKB_PAD, + 0, GFP_KERNEL); + if (!skb) { + error = -ENOMEM; +@@ -879,7 +879,7 @@ static int pppoe_sendmsg(struct socket * + } + + /* Reserve space for headers. */ +- skb_reserve(skb, dev->hard_header_len); ++ skb_reserve(skb, dev->hard_header_len + NET_SKB_PAD); + skb_reset_network_header(skb); + + skb->dev = dev; diff --git a/target/linux/generic/patches-4.1/651-wireless_mesh_header.patch b/target/linux/generic/patches-4.1/651-wireless_mesh_header.patch new file mode 100644 index 0000000..17bcb6d --- /dev/null +++ b/target/linux/generic/patches-4.1/651-wireless_mesh_header.patch @@ -0,0 +1,11 @@ +--- a/include/linux/netdevice.h ++++ b/include/linux/netdevice.h +@@ -133,7 +133,7 @@ static inline bool dev_xmit_complete(int + */ + + #if defined(CONFIG_WLAN) || IS_ENABLED(CONFIG_AX25) +-# if defined(CONFIG_MAC80211_MESH) ++# if 1 || defined(CONFIG_MAC80211_MESH) + # define LL_MAX_HEADER 128 + # else + # define LL_MAX_HEADER 96 diff --git a/target/linux/generic/patches-4.1/653-disable_netlink_trim.patch b/target/linux/generic/patches-4.1/653-disable_netlink_trim.patch new file mode 100644 index 0000000..7d2e6ff --- /dev/null +++ b/target/linux/generic/patches-4.1/653-disable_netlink_trim.patch @@ -0,0 +1,30 @@ +--- a/net/netlink/af_netlink.c ++++ b/net/netlink/af_netlink.c +@@ -1724,27 +1724,7 @@ void netlink_detachskb(struct sock *sk, + + static struct sk_buff *netlink_trim(struct sk_buff *skb, gfp_t allocation) + { +- int delta; +- + WARN_ON(skb->sk != NULL); +- if (netlink_skb_is_mmaped(skb)) +- return skb; +- +- delta = skb->end - skb->tail; +- if (is_vmalloc_addr(skb->head) || delta * 2 < skb->truesize) +- return skb; +- +- if (skb_shared(skb)) { +- struct sk_buff *nskb = skb_clone(skb, allocation); +- if (!nskb) +- return skb; +- consume_skb(skb); +- skb = nskb; +- } +- +- if (!pskb_expand_head(skb, 0, -delta, allocation)) +- skb->truesize -= delta; +- + return skb; + } + diff --git a/target/linux/generic/patches-4.1/655-increase_skb_pad.patch b/target/linux/generic/patches-4.1/655-increase_skb_pad.patch new file mode 100644 index 0000000..8145372 --- /dev/null +++ b/target/linux/generic/patches-4.1/655-increase_skb_pad.patch @@ -0,0 +1,11 @@ +--- a/include/linux/skbuff.h ++++ b/include/linux/skbuff.h +@@ -2031,7 +2031,7 @@ static inline int pskb_network_may_pull( + * NET_IP_ALIGN(2) + ethernet_header(14) + IP_header(20/40) + ports(8) + */ + #ifndef NET_SKB_PAD +-#define NET_SKB_PAD max(32, L1_CACHE_BYTES) ++#define NET_SKB_PAD max(64, L1_CACHE_BYTES) + #endif + + int ___pskb_trim(struct sk_buff *skb, unsigned int len); diff --git a/target/linux/generic/patches-4.1/656-skb_reduce_truesize-helper.patch b/target/linux/generic/patches-4.1/656-skb_reduce_truesize-helper.patch new file mode 100644 index 0000000..3a59c39 --- /dev/null +++ b/target/linux/generic/patches-4.1/656-skb_reduce_truesize-helper.patch @@ -0,0 +1,41 @@ +From 4593a806e31119c5bd3faa00c7210ad862d515af Mon Sep 17 00:00:00 2001 +From: Dave Taht +Date: Mon, 31 Dec 2012 10:02:21 -0800 +Subject: [PATCH 3/7] skb_reduce_truesize: helper function for shrinking skbs + whenever needed + +On embedded devices in particular, large queues of small packets from the rx +path with a large truesize can exist. Reducing their size can reduce +memory pressure. skb_reduce_truesize is a helper function for doing this, +when needed. +--- + include/linux/skbuff.h | 18 ++++++++++++++++++ + 1 file changed, 18 insertions(+) + +--- a/include/linux/skbuff.h ++++ b/include/linux/skbuff.h +@@ -2076,6 +2076,24 @@ static inline void pskb_trim_unique(stru + BUG_ON(err); + } + ++/* ++ * Caller wants to reduce memory needs before queueing skb ++ * The (expensive) copy should not be be done in fast path. ++ */ ++static inline struct sk_buff *skb_reduce_truesize(struct sk_buff *skb) ++{ ++ if (skb->truesize > 2 * SKB_TRUESIZE(skb->len)) { ++ struct sk_buff *nskb; ++ nskb = skb_copy_expand(skb, skb_headroom(skb), 0, ++ GFP_ATOMIC | __GFP_NOWARN); ++ if (nskb) { ++ __kfree_skb(skb); ++ skb = nskb; ++ } ++ } ++ return skb; ++} ++ + /** + * skb_orphan - orphan a buffer + * @skb: buffer to orphan diff --git a/target/linux/generic/patches-4.1/657-qdisc_reduce_truesize.patch b/target/linux/generic/patches-4.1/657-qdisc_reduce_truesize.patch new file mode 100644 index 0000000..6777eec --- /dev/null +++ b/target/linux/generic/patches-4.1/657-qdisc_reduce_truesize.patch @@ -0,0 +1,63 @@ +From bc9fec2f87d57bdbff30d296605e24504513f65c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Dave=20T=C3=A4ht?= +Date: Mon, 17 Sep 2012 19:20:22 -0700 +Subject: [PATCH 4/7] net: add skb_reduce_truesize support to common qdiscs + +Reduce skb size under load when queues begin to fill on the +commont qdiscs. +--- + net/sched/sch_codel.c | 2 ++ + net/sched/sch_fifo.c | 12 ++++++++---- + net/sched/sch_fq_codel.c | 2 ++ + 3 files changed, 12 insertions(+), 4 deletions(-) + +--- a/net/sched/sch_codel.c ++++ b/net/sched/sch_codel.c +@@ -96,6 +96,8 @@ static int codel_qdisc_enqueue(struct sk + struct codel_sched_data *q; + + if (likely(qdisc_qlen(sch) < sch->limit)) { ++ if(qdisc_qlen(sch) > 128) ++ skb = skb_reduce_truesize(skb); + codel_set_enqueue_time(skb); + return qdisc_enqueue_tail(skb, sch); + } +--- a/net/sched/sch_fifo.c ++++ b/net/sched/sch_fifo.c +@@ -29,17 +29,21 @@ static int bfifo_enqueue(struct sk_buff + + static int pfifo_enqueue(struct sk_buff *skb, struct Qdisc *sch) + { +- if (likely(skb_queue_len(&sch->q) < sch->limit)) ++ if (likely(skb_queue_len(&sch->q) < sch->limit)) { ++ if (skb_queue_len(&sch->q) > 128) ++ skb = skb_reduce_truesize(skb); + return qdisc_enqueue_tail(skb, sch); +- ++ } + return qdisc_reshape_fail(skb, sch); + } + + static int pfifo_tail_enqueue(struct sk_buff *skb, struct Qdisc *sch) + { +- if (likely(skb_queue_len(&sch->q) < sch->limit)) ++ if (likely(skb_queue_len(&sch->q) < sch->limit)) { ++ if (skb_queue_len(&sch->q) > 128) ++ skb = skb_reduce_truesize(skb); + return qdisc_enqueue_tail(skb, sch); +- ++ } + /* queue full, remove one skb to fulfill the limit */ + __qdisc_queue_drop_head(sch, &sch->q); + qdisc_qstats_drop(sch); +--- a/net/sched/sch_fq_codel.c ++++ b/net/sched/sch_fq_codel.c +@@ -185,6 +185,8 @@ static int fq_codel_enqueue(struct sk_bu + return ret; + } + idx--; ++ if (sch->q.qlen > 128) ++ skb = skb_reduce_truesize(skb); + + codel_set_enqueue_time(skb); + flow = &q->flows[idx]; diff --git a/target/linux/generic/patches-4.1/660-fq_codel_defaults.patch b/target/linux/generic/patches-4.1/660-fq_codel_defaults.patch new file mode 100644 index 0000000..f7f4659 --- /dev/null +++ b/target/linux/generic/patches-4.1/660-fq_codel_defaults.patch @@ -0,0 +1,14 @@ +--- a/net/sched/sch_fq_codel.c ++++ b/net/sched/sch_fq_codel.c +@@ -387,9 +387,9 @@ static int fq_codel_init(struct Qdisc *s + struct fq_codel_sched_data *q = qdisc_priv(sch); + int i; + +- sch->limit = 10*1024; ++ sch->limit = 1024; + q->flows_cnt = 1024; +- q->quantum = psched_mtu(qdisc_dev(sch)); ++ q->quantum = 300; + q->perturbation = prandom_u32(); + INIT_LIST_HEAD(&q->new_flows); + INIT_LIST_HEAD(&q->old_flows); diff --git a/target/linux/generic/patches-4.1/661-fq_codel_keep_dropped_stats.patch b/target/linux/generic/patches-4.1/661-fq_codel_keep_dropped_stats.patch new file mode 100644 index 0000000..45a8d68 --- /dev/null +++ b/target/linux/generic/patches-4.1/661-fq_codel_keep_dropped_stats.patch @@ -0,0 +1,10 @@ +--- a/net/sched/sch_fq_codel.c ++++ b/net/sched/sch_fq_codel.c +@@ -198,7 +198,6 @@ static int fq_codel_enqueue(struct sk_bu + list_add_tail(&flow->flowchain, &q->new_flows); + q->new_flow_count++; + flow->deficit = q->quantum; +- flow->dropped = 0; + } + if (++sch->q.qlen <= sch->limit) + return NET_XMIT_SUCCESS; diff --git a/target/linux/generic/patches-4.1/662-use_fq_codel_by_default.patch b/target/linux/generic/patches-4.1/662-use_fq_codel_by_default.patch new file mode 100644 index 0000000..e7b781b --- /dev/null +++ b/target/linux/generic/patches-4.1/662-use_fq_codel_by_default.patch @@ -0,0 +1,75 @@ +--- a/net/sched/Kconfig ++++ b/net/sched/Kconfig +@@ -3,8 +3,9 @@ + # + + menuconfig NET_SCHED +- bool "QoS and/or fair queueing" ++ def_bool y + select NET_SCH_FIFO ++ select NET_SCH_FQ_CODEL + ---help--- + When the kernel has several packets to send out over a network + device, it has to decide which ones to send first, which ones to +--- a/net/sched/sch_fq_codel.c ++++ b/net/sched/sch_fq_codel.c +@@ -592,7 +592,7 @@ static const struct Qdisc_class_ops fq_c + .walk = fq_codel_walk, + }; + +-static struct Qdisc_ops fq_codel_qdisc_ops __read_mostly = { ++struct Qdisc_ops fq_codel_qdisc_ops __read_mostly = { + .cl_ops = &fq_codel_class_ops, + .id = "fq_codel", + .priv_size = sizeof(struct fq_codel_sched_data), +@@ -608,6 +608,7 @@ static struct Qdisc_ops fq_codel_qdisc_o + .dump_stats = fq_codel_dump_stats, + .owner = THIS_MODULE, + }; ++EXPORT_SYMBOL(fq_codel_qdisc_ops); + + static int __init fq_codel_module_init(void) + { +--- a/include/net/sch_generic.h ++++ b/include/net/sch_generic.h +@@ -340,6 +340,7 @@ extern struct Qdisc noop_qdisc; + extern struct Qdisc_ops noop_qdisc_ops; + extern struct Qdisc_ops pfifo_fast_ops; + extern struct Qdisc_ops mq_qdisc_ops; ++extern struct Qdisc_ops fq_codel_qdisc_ops; + extern const struct Qdisc_ops *default_qdisc_ops; + + struct Qdisc_class_common { +--- a/net/sched/sch_generic.c ++++ b/net/sched/sch_generic.c +@@ -737,7 +737,7 @@ static void attach_one_default_qdisc(str + + if (dev->tx_queue_len) { + qdisc = qdisc_create_dflt(dev_queue, +- default_qdisc_ops, TC_H_ROOT); ++ &fq_codel_qdisc_ops, TC_H_ROOT); + if (!qdisc) { + netdev_info(dev, "activation failed\n"); + return; +--- a/net/sched/sch_mq.c ++++ b/net/sched/sch_mq.c +@@ -57,7 +57,7 @@ static int mq_init(struct Qdisc *sch, st + + for (ntx = 0; ntx < dev->num_tx_queues; ntx++) { + dev_queue = netdev_get_tx_queue(dev, ntx); +- qdisc = qdisc_create_dflt(dev_queue, default_qdisc_ops, ++ qdisc = qdisc_create_dflt(dev_queue, &fq_codel_qdisc_ops, + TC_H_MAKE(TC_H_MAJ(sch->handle), + TC_H_MIN(ntx + 1))); + if (qdisc == NULL) +--- a/net/sched/sch_mqprio.c ++++ b/net/sched/sch_mqprio.c +@@ -124,7 +124,7 @@ static int mqprio_init(struct Qdisc *sch + + for (i = 0; i < dev->num_tx_queues; i++) { + dev_queue = netdev_get_tx_queue(dev, i); +- qdisc = qdisc_create_dflt(dev_queue, default_qdisc_ops, ++ qdisc = qdisc_create_dflt(dev_queue, &fq_codel_qdisc_ops, + TC_H_MAKE(TC_H_MAJ(sch->handle), + TC_H_MIN(i + 1))); + if (qdisc == NULL) { diff --git a/target/linux/generic/patches-4.1/663-remove_pfifo_fast.patch b/target/linux/generic/patches-4.1/663-remove_pfifo_fast.patch new file mode 100644 index 0000000..5b26ca3 --- /dev/null +++ b/target/linux/generic/patches-4.1/663-remove_pfifo_fast.patch @@ -0,0 +1,143 @@ +--- a/net/sched/sch_generic.c ++++ b/net/sched/sch_generic.c +@@ -442,140 +442,6 @@ static struct Qdisc noqueue_qdisc = { + .busylock = __SPIN_LOCK_UNLOCKED(noqueue_qdisc.busylock), + }; + +- +-static const u8 prio2band[TC_PRIO_MAX + 1] = { +- 1, 2, 2, 2, 1, 2, 0, 0 , 1, 1, 1, 1, 1, 1, 1, 1 +-}; +- +-/* 3-band FIFO queue: old style, but should be a bit faster than +- generic prio+fifo combination. +- */ +- +-#define PFIFO_FAST_BANDS 3 +- +-/* +- * Private data for a pfifo_fast scheduler containing: +- * - queues for the three band +- * - bitmap indicating which of the bands contain skbs +- */ +-struct pfifo_fast_priv { +- u32 bitmap; +- struct sk_buff_head q[PFIFO_FAST_BANDS]; +-}; +- +-/* +- * Convert a bitmap to the first band number where an skb is queued, where: +- * bitmap=0 means there are no skbs on any band. +- * bitmap=1 means there is an skb on band 0. +- * bitmap=7 means there are skbs on all 3 bands, etc. +- */ +-static const int bitmap2band[] = {-1, 0, 1, 0, 2, 0, 1, 0}; +- +-static inline struct sk_buff_head *band2list(struct pfifo_fast_priv *priv, +- int band) +-{ +- return priv->q + band; +-} +- +-static int pfifo_fast_enqueue(struct sk_buff *skb, struct Qdisc *qdisc) +-{ +- if (skb_queue_len(&qdisc->q) < qdisc_dev(qdisc)->tx_queue_len) { +- int band = prio2band[skb->priority & TC_PRIO_MAX]; +- struct pfifo_fast_priv *priv = qdisc_priv(qdisc); +- struct sk_buff_head *list = band2list(priv, band); +- +- priv->bitmap |= (1 << band); +- qdisc->q.qlen++; +- return __qdisc_enqueue_tail(skb, qdisc, list); +- } +- +- return qdisc_drop(skb, qdisc); +-} +- +-static struct sk_buff *pfifo_fast_dequeue(struct Qdisc *qdisc) +-{ +- struct pfifo_fast_priv *priv = qdisc_priv(qdisc); +- int band = bitmap2band[priv->bitmap]; +- +- if (likely(band >= 0)) { +- struct sk_buff_head *list = band2list(priv, band); +- struct sk_buff *skb = __qdisc_dequeue_head(qdisc, list); +- +- qdisc->q.qlen--; +- if (skb_queue_empty(list)) +- priv->bitmap &= ~(1 << band); +- +- return skb; +- } +- +- return NULL; +-} +- +-static struct sk_buff *pfifo_fast_peek(struct Qdisc *qdisc) +-{ +- struct pfifo_fast_priv *priv = qdisc_priv(qdisc); +- int band = bitmap2band[priv->bitmap]; +- +- if (band >= 0) { +- struct sk_buff_head *list = band2list(priv, band); +- +- return skb_peek(list); +- } +- +- return NULL; +-} +- +-static void pfifo_fast_reset(struct Qdisc *qdisc) +-{ +- int prio; +- struct pfifo_fast_priv *priv = qdisc_priv(qdisc); +- +- for (prio = 0; prio < PFIFO_FAST_BANDS; prio++) +- __qdisc_reset_queue(qdisc, band2list(priv, prio)); +- +- priv->bitmap = 0; +- qdisc->qstats.backlog = 0; +- qdisc->q.qlen = 0; +-} +- +-static int pfifo_fast_dump(struct Qdisc *qdisc, struct sk_buff *skb) +-{ +- struct tc_prio_qopt opt = { .bands = PFIFO_FAST_BANDS }; +- +- memcpy(&opt.priomap, prio2band, TC_PRIO_MAX + 1); +- if (nla_put(skb, TCA_OPTIONS, sizeof(opt), &opt)) +- goto nla_put_failure; +- return skb->len; +- +-nla_put_failure: +- return -1; +-} +- +-static int pfifo_fast_init(struct Qdisc *qdisc, struct nlattr *opt) +-{ +- int prio; +- struct pfifo_fast_priv *priv = qdisc_priv(qdisc); +- +- for (prio = 0; prio < PFIFO_FAST_BANDS; prio++) +- __skb_queue_head_init(band2list(priv, prio)); +- +- /* Can by-pass the queue discipline */ +- qdisc->flags |= TCQ_F_CAN_BYPASS; +- return 0; +-} +- +-struct Qdisc_ops pfifo_fast_ops __read_mostly = { +- .id = "pfifo_fast", +- .priv_size = sizeof(struct pfifo_fast_priv), +- .enqueue = pfifo_fast_enqueue, +- .dequeue = pfifo_fast_dequeue, +- .peek = pfifo_fast_peek, +- .init = pfifo_fast_init, +- .reset = pfifo_fast_reset, +- .dump = pfifo_fast_dump, +- .owner = THIS_MODULE, +-}; +- + static struct lock_class_key qdisc_tx_busylock; + + struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue, diff --git a/target/linux/generic/patches-4.1/664-codel_fix_3_12.patch b/target/linux/generic/patches-4.1/664-codel_fix_3_12.patch new file mode 100644 index 0000000..6b2cbc5 --- /dev/null +++ b/target/linux/generic/patches-4.1/664-codel_fix_3_12.patch @@ -0,0 +1,22 @@ +--- a/net/sched/sch_api.c ++++ b/net/sched/sch_api.c +@@ -1951,7 +1951,7 @@ static int __init pktsched_init(void) + return err; + } + +- register_qdisc(&pfifo_fast_ops); ++ register_qdisc(&fq_codel_qdisc_ops); + register_qdisc(&pfifo_qdisc_ops); + register_qdisc(&bfifo_qdisc_ops); + register_qdisc(&pfifo_head_drop_qdisc_ops); +--- a/net/sched/sch_generic.c ++++ b/net/sched/sch_generic.c +@@ -31,7 +31,7 @@ + #include + + /* Qdisc to use by default */ +-const struct Qdisc_ops *default_qdisc_ops = &pfifo_fast_ops; ++const struct Qdisc_ops *default_qdisc_ops = &fq_codel_qdisc_ops; + EXPORT_SYMBOL(default_qdisc_ops); + + /* Main transmission queue. */ diff --git a/target/linux/generic/patches-4.1/666-Add-support-for-MAP-E-FMRs-mesh-mode.patch b/target/linux/generic/patches-4.1/666-Add-support-for-MAP-E-FMRs-mesh-mode.patch new file mode 100644 index 0000000..f40fc38 --- /dev/null +++ b/target/linux/generic/patches-4.1/666-Add-support-for-MAP-E-FMRs-mesh-mode.patch @@ -0,0 +1,495 @@ +From 775d6fe74d1eaec2ba387535b068dde2dc89de9e Mon Sep 17 00:00:00 2001 +From: Steven Barth +Date: Thu, 22 May 2014 09:49:05 +0200 +Subject: [PATCH] Add support for MAP-E FMRs (mesh mode) + +MAP-E FMRs (draft-ietf-softwire-map-10) are rules for IPv4-communication +between MAP CEs (mesh mode) without the need to forward such data to a +border relay. This is similar to how 6rd works but for IPv4 over IPv6. + +Signed-off-by: Steven Barth +--- + include/net/ip6_tunnel.h | 13 ++ + include/uapi/linux/if_tunnel.h | 13 ++ + net/ipv6/ip6_tunnel.c | 276 +++++++++++++++++++++++++++++++++++++++-- + 3 files changed, 291 insertions(+), 11 deletions(-) + +--- a/include/net/ip6_tunnel.h ++++ b/include/net/ip6_tunnel.h +@@ -15,6 +15,18 @@ + /* determine capability on a per-packet basis */ + #define IP6_TNL_F_CAP_PER_PACKET 0x40000 + ++/* IPv6 tunnel FMR */ ++struct __ip6_tnl_fmr { ++ struct __ip6_tnl_fmr *next; /* next fmr in list */ ++ struct in6_addr ip6_prefix; ++ struct in_addr ip4_prefix; ++ ++ __u8 ip6_prefix_len; ++ __u8 ip4_prefix_len; ++ __u8 ea_len; ++ __u8 offset; ++}; ++ + struct __ip6_tnl_parm { + char name[IFNAMSIZ]; /* name of tunnel device */ + int link; /* ifindex of underlying L2 interface */ +@@ -25,6 +37,7 @@ struct __ip6_tnl_parm { + __u32 flags; /* tunnel flags */ + struct in6_addr laddr; /* local tunnel end-point address */ + struct in6_addr raddr; /* remote tunnel end-point address */ ++ struct __ip6_tnl_fmr *fmrs; /* FMRs */ + + __be16 i_flags; + __be16 o_flags; +--- a/include/uapi/linux/if_tunnel.h ++++ b/include/uapi/linux/if_tunnel.h +@@ -57,10 +57,23 @@ enum { + IFLA_IPTUN_ENCAP_FLAGS, + IFLA_IPTUN_ENCAP_SPORT, + IFLA_IPTUN_ENCAP_DPORT, ++ IFLA_IPTUN_FMRS, + __IFLA_IPTUN_MAX, + }; + #define IFLA_IPTUN_MAX (__IFLA_IPTUN_MAX - 1) + ++enum { ++ IFLA_IPTUN_FMR_UNSPEC, ++ IFLA_IPTUN_FMR_IP6_PREFIX, ++ IFLA_IPTUN_FMR_IP4_PREFIX, ++ IFLA_IPTUN_FMR_IP6_PREFIX_LEN, ++ IFLA_IPTUN_FMR_IP4_PREFIX_LEN, ++ IFLA_IPTUN_FMR_EA_LEN, ++ IFLA_IPTUN_FMR_OFFSET, ++ __IFLA_IPTUN_FMR_MAX, ++}; ++#define IFLA_IPTUN_FMR_MAX (__IFLA_IPTUN_FMR_MAX - 1) ++ + enum tunnel_encap_types { + TUNNEL_ENCAP_NONE, + TUNNEL_ENCAP_FOU, +--- a/net/ipv6/ip6_tunnel.c ++++ b/net/ipv6/ip6_tunnel.c +@@ -16,6 +16,8 @@ + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * ++ * Changes: ++ * Steven Barth : MAP-E FMR support + */ + + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +@@ -71,11 +73,9 @@ static bool log_ecn_error = true; + module_param(log_ecn_error, bool, 0644); + MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN"); + +-static u32 HASH(const struct in6_addr *addr1, const struct in6_addr *addr2) ++static u32 HASH(const struct in6_addr *addr) + { +- u32 hash = ipv6_addr_hash(addr1) ^ ipv6_addr_hash(addr2); +- +- return hash_32(hash, HASH_SIZE_SHIFT); ++ return hash_32(ipv6_addr_hash(addr), HASH_SIZE_SHIFT); + } + + static int ip6_tnl_dev_init(struct net_device *dev); +@@ -174,27 +174,36 @@ EXPORT_SYMBOL_GPL(ip6_tnl_dst_store); + static struct ip6_tnl * + ip6_tnl_lookup(struct net *net, const struct in6_addr *remote, const struct in6_addr *local) + { +- unsigned int hash = HASH(remote, local); ++ unsigned int hash = HASH(local); + struct ip6_tnl *t; + struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); + struct in6_addr any; ++ struct __ip6_tnl_fmr *fmr; + + for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) { +- if (ipv6_addr_equal(local, &t->parms.laddr) && +- ipv6_addr_equal(remote, &t->parms.raddr) && +- (t->dev->flags & IFF_UP)) ++ if (!ipv6_addr_equal(local, &t->parms.laddr) || ++ !(t->dev->flags & IFF_UP)) ++ continue; ++ ++ if (ipv6_addr_equal(remote, &t->parms.raddr)) + return t; ++ ++ for (fmr = t->parms.fmrs; fmr; fmr = fmr->next) { ++ if (ipv6_prefix_equal(remote, &fmr->ip6_prefix, ++ fmr->ip6_prefix_len)) ++ return t; ++ } + } + + memset(&any, 0, sizeof(any)); +- hash = HASH(&any, local); ++ hash = HASH(local); + for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) { + if (ipv6_addr_equal(local, &t->parms.laddr) && + (t->dev->flags & IFF_UP)) + return t; + } + +- hash = HASH(remote, &any); ++ hash = HASH(&any); + for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) { + if (ipv6_addr_equal(remote, &t->parms.raddr) && + (t->dev->flags & IFF_UP)) +@@ -229,7 +238,7 @@ ip6_tnl_bucket(struct ip6_tnl_net *ip6n, + + if (!ipv6_addr_any(remote) || !ipv6_addr_any(local)) { + prio = 1; +- h = HASH(remote, local); ++ h = HASH(local); + } + return &ip6n->tnls[prio][h]; + } +@@ -399,6 +408,12 @@ ip6_tnl_dev_uninit(struct net_device *de + struct net *net = t->net; + struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); + ++ while (t->parms.fmrs) { ++ struct __ip6_tnl_fmr *next = t->parms.fmrs->next; ++ kfree(t->parms.fmrs); ++ t->parms.fmrs = next; ++ } ++ + if (dev == ip6n->fb_tnl_dev) + RCU_INIT_POINTER(ip6n->tnls_wc[0], NULL); + else +@@ -785,6 +800,108 @@ int ip6_tnl_rcv_ctl(struct ip6_tnl *t, + } + EXPORT_SYMBOL_GPL(ip6_tnl_rcv_ctl); + ++ ++/** ++ * ip4ip6_fmr_calc - calculate target / source IPv6-address based on FMR ++ * @dest: destination IPv6 address buffer ++ * @skb: received socket buffer ++ * @fmr: MAP FMR ++ * @xmit: Calculate for xmit or rcv ++ **/ ++static void ip4ip6_fmr_calc(struct in6_addr *dest, ++ const struct iphdr *iph, const uint8_t *end, ++ const struct __ip6_tnl_fmr *fmr, bool xmit) ++{ ++ int psidlen = fmr->ea_len - (32 - fmr->ip4_prefix_len); ++ u8 *portp = NULL; ++ bool use_dest_addr; ++ const struct iphdr *dsth = iph; ++ ++ if ((u8*)dsth >= end) ++ return; ++ ++ /* find significant IP header */ ++ if (iph->protocol == IPPROTO_ICMP) { ++ struct icmphdr *ih = (struct icmphdr*)(((u8*)dsth) + dsth->ihl * 4); ++ if (ih && ((u8*)&ih[1]) <= end && ( ++ ih->type == ICMP_DEST_UNREACH || ++ ih->type == ICMP_SOURCE_QUENCH || ++ ih->type == ICMP_TIME_EXCEEDED || ++ ih->type == ICMP_PARAMETERPROB || ++ ih->type == ICMP_REDIRECT)) ++ dsth = (const struct iphdr*)&ih[1]; ++ } ++ ++ /* in xmit-path use dest port by default and source port only if ++ this is an ICMP reply to something else; vice versa in rcv-path */ ++ use_dest_addr = (xmit && dsth == iph) || (!xmit && dsth != iph); ++ ++ /* get dst port */ ++ if (((u8*)&dsth[1]) <= end && ( ++ dsth->protocol == IPPROTO_UDP || ++ dsth->protocol == IPPROTO_TCP || ++ dsth->protocol == IPPROTO_SCTP || ++ dsth->protocol == IPPROTO_DCCP)) { ++ /* for UDP, TCP, SCTP and DCCP source and dest port ++ follow IPv4 header directly */ ++ portp = ((u8*)dsth) + dsth->ihl * 4; ++ ++ if (use_dest_addr) ++ portp += sizeof(u16); ++ } else if (iph->protocol == IPPROTO_ICMP) { ++ struct icmphdr *ih = (struct icmphdr*)(((u8*)dsth) + dsth->ihl * 4); ++ ++ /* use icmp identifier as port */ ++ if (((u8*)&ih) <= end && ( ++ (use_dest_addr && ( ++ ih->type == ICMP_ECHOREPLY || ++ ih->type == ICMP_TIMESTAMPREPLY || ++ ih->type == ICMP_INFO_REPLY || ++ ih->type == ICMP_ADDRESSREPLY)) || ++ (!use_dest_addr && ( ++ ih->type == ICMP_ECHO || ++ ih->type == ICMP_TIMESTAMP || ++ ih->type == ICMP_INFO_REQUEST || ++ ih->type == ICMP_ADDRESS) ++ ))) ++ portp = (u8*)&ih->un.echo.id; ++ } ++ ++ if ((portp && &portp[2] <= end) || psidlen == 0) { ++ int frombyte = fmr->ip6_prefix_len / 8; ++ int fromrem = fmr->ip6_prefix_len % 8; ++ int bytes = sizeof(struct in6_addr) - frombyte; ++ const u32 *addr = (use_dest_addr) ? &iph->daddr : &iph->saddr; ++ u64 eabits = ((u64)ntohl(*addr)) << (32 + fmr->ip4_prefix_len); ++ u64 t = 0; ++ ++ /* extract PSID from port and add it to eabits */ ++ u16 psidbits = 0; ++ if (psidlen > 0) { ++ psidbits = ((u16)portp[0]) << 8 | ((u16)portp[1]); ++ psidbits >>= 16 - psidlen - fmr->offset; ++ psidbits = (u16)(psidbits << (16 - psidlen)); ++ eabits |= ((u64)psidbits) << (48 - (fmr->ea_len - psidlen)); ++ } ++ ++ /* rewrite destination address */ ++ *dest = fmr->ip6_prefix; ++ memcpy(&dest->s6_addr[10], addr, sizeof(*addr)); ++ dest->s6_addr16[7] = htons(psidbits >> (16 - psidlen)); ++ ++ if (bytes > sizeof(u64)) ++ bytes = sizeof(u64); ++ ++ /* insert eabits */ ++ memcpy(&t, &dest->s6_addr[frombyte], bytes); ++ t = be64_to_cpu(t) & ~(((((u64)1) << fmr->ea_len) - 1) ++ << (64 - fmr->ea_len - fromrem)); ++ t = cpu_to_be64(t | (eabits >> fromrem)); ++ memcpy(&dest->s6_addr[frombyte], &t, bytes); ++ } ++} ++ ++ + /** + * ip6_tnl_rcv - decapsulate IPv6 packet and retransmit it locally + * @skb: received socket buffer +@@ -830,6 +947,26 @@ static int ip6_tnl_rcv(struct sk_buff *s + skb_reset_network_header(skb); + skb->protocol = htons(protocol); + memset(skb->cb, 0, sizeof(struct inet6_skb_parm)); ++ if (protocol == ETH_P_IP && ++ !ipv6_addr_equal(&ipv6h->saddr, &t->parms.raddr)) { ++ /* Packet didn't come from BR, so lookup FMR */ ++ struct __ip6_tnl_fmr *fmr; ++ struct in6_addr expected = t->parms.raddr; ++ for (fmr = t->parms.fmrs; fmr; fmr = fmr->next) ++ if (ipv6_prefix_equal(&ipv6h->saddr, ++ &fmr->ip6_prefix, fmr->ip6_prefix_len)) ++ break; ++ ++ /* Check that IPv6 matches IPv4 source to prevent spoofing */ ++ if (fmr) ++ ip4ip6_fmr_calc(&expected, ip_hdr(skb), ++ skb_tail_pointer(skb), fmr, false); ++ ++ if (!ipv6_addr_equal(&ipv6h->saddr, &expected)) { ++ rcu_read_unlock(); ++ goto discard; ++ } ++ } + + __skb_tunnel_rx(skb, t->dev, t->net); + +@@ -1123,6 +1260,7 @@ ip4ip6_tnl_xmit(struct sk_buff *skb, str + __u32 mtu; + u8 tproto; + int err; ++ struct __ip6_tnl_fmr *fmr; + + tproto = ACCESS_ONCE(t->parms.proto); + if (tproto != IPPROTO_IPIP && tproto != 0) +@@ -1142,6 +1280,18 @@ ip4ip6_tnl_xmit(struct sk_buff *skb, str + if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK) + fl6.flowi6_mark = skb->mark; + ++ /* try to find matching FMR */ ++ for (fmr = t->parms.fmrs; fmr; fmr = fmr->next) { ++ unsigned mshift = 32 - fmr->ip4_prefix_len; ++ if (ntohl(fmr->ip4_prefix.s_addr) >> mshift == ++ ntohl(iph->daddr) >> mshift) ++ break; ++ } ++ ++ /* change dstaddr according to FMR */ ++ if (fmr) ++ ip4ip6_fmr_calc(&fl6.daddr, iph, skb_tail_pointer(skb), fmr, true); ++ + err = ip6_tnl_xmit2(skb, dev, dsfield, &fl6, encap_limit, &mtu); + if (err != 0) { + /* XXX: send ICMP error even if DF is not set. */ +@@ -1310,6 +1460,14 @@ ip6_tnl_change(struct ip6_tnl *t, const + t->parms.flowinfo = p->flowinfo; + t->parms.link = p->link; + t->parms.proto = p->proto; ++ ++ while (t->parms.fmrs) { ++ struct __ip6_tnl_fmr *next = t->parms.fmrs->next; ++ kfree(t->parms.fmrs); ++ t->parms.fmrs = next; ++ } ++ t->parms.fmrs = p->fmrs; ++ + ip6_tnl_dst_reset(t); + ip6_tnl_link_config(t); + return 0; +@@ -1348,6 +1506,7 @@ ip6_tnl_parm_from_user(struct __ip6_tnl_ + p->flowinfo = u->flowinfo; + p->link = u->link; + p->proto = u->proto; ++ p->fmrs = NULL; + memcpy(p->name, u->name, sizeof(u->name)); + } + +@@ -1634,6 +1793,15 @@ static int ip6_tnl_validate(struct nlatt + return 0; + } + ++static const struct nla_policy ip6_tnl_fmr_policy[IFLA_IPTUN_FMR_MAX + 1] = { ++ [IFLA_IPTUN_FMR_IP6_PREFIX] = { .len = sizeof(struct in6_addr) }, ++ [IFLA_IPTUN_FMR_IP4_PREFIX] = { .len = sizeof(struct in_addr) }, ++ [IFLA_IPTUN_FMR_IP6_PREFIX_LEN] = { .type = NLA_U8 }, ++ [IFLA_IPTUN_FMR_IP4_PREFIX_LEN] = { .type = NLA_U8 }, ++ [IFLA_IPTUN_FMR_EA_LEN] = { .type = NLA_U8 }, ++ [IFLA_IPTUN_FMR_OFFSET] = { .type = NLA_U8 } ++}; ++ + static void ip6_tnl_netlink_parms(struct nlattr *data[], + struct __ip6_tnl_parm *parms) + { +@@ -1665,6 +1833,46 @@ static void ip6_tnl_netlink_parms(struct + + if (data[IFLA_IPTUN_PROTO]) + parms->proto = nla_get_u8(data[IFLA_IPTUN_PROTO]); ++ ++ if (data[IFLA_IPTUN_FMRS]) { ++ unsigned rem; ++ struct nlattr *fmr; ++ nla_for_each_nested(fmr, data[IFLA_IPTUN_FMRS], rem) { ++ struct nlattr *fmrd[IFLA_IPTUN_FMR_MAX + 1], *c; ++ struct __ip6_tnl_fmr *nfmr; ++ ++ nla_parse_nested(fmrd, IFLA_IPTUN_FMR_MAX, ++ fmr, ip6_tnl_fmr_policy); ++ ++ if (!(nfmr = kzalloc(sizeof(*nfmr), GFP_KERNEL))) ++ continue; ++ ++ nfmr->offset = 6; ++ ++ if ((c = fmrd[IFLA_IPTUN_FMR_IP6_PREFIX])) ++ nla_memcpy(&nfmr->ip6_prefix, fmrd[IFLA_IPTUN_FMR_IP6_PREFIX], ++ sizeof(nfmr->ip6_prefix)); ++ ++ if ((c = fmrd[IFLA_IPTUN_FMR_IP4_PREFIX])) ++ nla_memcpy(&nfmr->ip4_prefix, fmrd[IFLA_IPTUN_FMR_IP4_PREFIX], ++ sizeof(nfmr->ip4_prefix)); ++ ++ if ((c = fmrd[IFLA_IPTUN_FMR_IP6_PREFIX_LEN])) ++ nfmr->ip6_prefix_len = nla_get_u8(c); ++ ++ if ((c = fmrd[IFLA_IPTUN_FMR_IP4_PREFIX_LEN])) ++ nfmr->ip4_prefix_len = nla_get_u8(c); ++ ++ if ((c = fmrd[IFLA_IPTUN_FMR_EA_LEN])) ++ nfmr->ea_len = nla_get_u8(c); ++ ++ if ((c = fmrd[IFLA_IPTUN_FMR_OFFSET])) ++ nfmr->offset = nla_get_u8(c); ++ ++ nfmr->next = parms->fmrs; ++ parms->fmrs = nfmr; ++ } ++ } + } + + static int ip6_tnl_newlink(struct net *src_net, struct net_device *dev, +@@ -1717,6 +1925,12 @@ static void ip6_tnl_dellink(struct net_d + + static size_t ip6_tnl_get_size(const struct net_device *dev) + { ++ const struct ip6_tnl *t = netdev_priv(dev); ++ struct __ip6_tnl_fmr *c; ++ int fmrs = 0; ++ for (c = t->parms.fmrs; c; c = c->next) ++ ++fmrs; ++ + return + /* IFLA_IPTUN_LINK */ + nla_total_size(4) + +@@ -1734,6 +1948,24 @@ static size_t ip6_tnl_get_size(const str + nla_total_size(4) + + /* IFLA_IPTUN_PROTO */ + nla_total_size(1) + ++ /* IFLA_IPTUN_FMRS */ ++ nla_total_size(0) + ++ ( ++ /* nest */ ++ nla_total_size(0) + ++ /* IFLA_IPTUN_FMR_IP6_PREFIX */ ++ nla_total_size(sizeof(struct in6_addr)) + ++ /* IFLA_IPTUN_FMR_IP4_PREFIX */ ++ nla_total_size(sizeof(struct in_addr)) + ++ /* IFLA_IPTUN_FMR_EA_LEN */ ++ nla_total_size(1) + ++ /* IFLA_IPTUN_FMR_IP6_PREFIX_LEN */ ++ nla_total_size(1) + ++ /* IFLA_IPTUN_FMR_IP4_PREFIX_LEN */ ++ nla_total_size(1) + ++ /* IFLA_IPTUN_FMR_OFFSET */ ++ nla_total_size(1) ++ ) * fmrs + + 0; + } + +@@ -1741,6 +1973,9 @@ static int ip6_tnl_fill_info(struct sk_b + { + struct ip6_tnl *tunnel = netdev_priv(dev); + struct __ip6_tnl_parm *parm = &tunnel->parms; ++ struct __ip6_tnl_fmr *c; ++ int fmrcnt = 0; ++ struct nlattr *fmrs; + + if (nla_put_u32(skb, IFLA_IPTUN_LINK, parm->link) || + nla_put_in6_addr(skb, IFLA_IPTUN_LOCAL, &parm->laddr) || +@@ -1749,8 +1984,27 @@ static int ip6_tnl_fill_info(struct sk_b + nla_put_u8(skb, IFLA_IPTUN_ENCAP_LIMIT, parm->encap_limit) || + nla_put_be32(skb, IFLA_IPTUN_FLOWINFO, parm->flowinfo) || + nla_put_u32(skb, IFLA_IPTUN_FLAGS, parm->flags) || +- nla_put_u8(skb, IFLA_IPTUN_PROTO, parm->proto)) ++ nla_put_u8(skb, IFLA_IPTUN_PROTO, parm->proto) || ++ !(fmrs = nla_nest_start(skb, IFLA_IPTUN_FMRS))) + goto nla_put_failure; ++ ++ for (c = parm->fmrs; c; c = c->next) { ++ struct nlattr *fmr = nla_nest_start(skb, ++fmrcnt); ++ if (!fmr || ++ nla_put(skb, IFLA_IPTUN_FMR_IP6_PREFIX, ++ sizeof(c->ip6_prefix), &c->ip6_prefix) || ++ nla_put(skb, IFLA_IPTUN_FMR_IP4_PREFIX, ++ sizeof(c->ip4_prefix), &c->ip4_prefix) || ++ nla_put_u8(skb, IFLA_IPTUN_FMR_IP6_PREFIX_LEN, c->ip6_prefix_len) || ++ nla_put_u8(skb, IFLA_IPTUN_FMR_IP4_PREFIX_LEN, c->ip4_prefix_len) || ++ nla_put_u8(skb, IFLA_IPTUN_FMR_EA_LEN, c->ea_len) || ++ nla_put_u8(skb, IFLA_IPTUN_FMR_OFFSET, c->offset)) ++ goto nla_put_failure; ++ ++ nla_nest_end(skb, fmr); ++ } ++ nla_nest_end(skb, fmrs); ++ + return 0; + + nla_put_failure: +@@ -1774,6 +2028,7 @@ static const struct nla_policy ip6_tnl_p + [IFLA_IPTUN_FLOWINFO] = { .type = NLA_U32 }, + [IFLA_IPTUN_FLAGS] = { .type = NLA_U32 }, + [IFLA_IPTUN_PROTO] = { .type = NLA_U8 }, ++ [IFLA_IPTUN_FMRS] = { .type = NLA_NESTED }, + }; + + static struct rtnl_link_ops ip6_link_ops __read_mostly = { diff --git a/target/linux/generic/patches-4.1/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch b/target/linux/generic/patches-4.1/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch new file mode 100644 index 0000000..e0bc210 --- /dev/null +++ b/target/linux/generic/patches-4.1/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch @@ -0,0 +1,249 @@ +From 1b5aaa4b16f6e6471ab1c07b38068197a1b4c395 Mon Sep 17 00:00:00 2001 +From: Jonas Gorski +Date: Fri, 24 May 2013 14:40:54 +0200 +Subject: [PATCH 1/2] ipv6: allow rejecting with "source address failed policy" + +RFC6204 L-14 requires rejecting traffic from invalid addresses with +ICMPv6 Destination Unreachable, Code 5 (Source address failed ingress/ +egress policy) on the LAN side, so add an appropriate rule for that. + +Signed-off-by: Jonas Gorski +--- + include/net/netns/ipv6.h | 1 + + include/uapi/linux/fib_rules.h | 4 +++ + include/uapi/linux/rtnetlink.h | 1 + + net/ipv4/fib_semantics.c | 4 +++ + net/ipv4/fib_trie.c | 1 + + net/ipv4/ipmr.c | 1 + + net/ipv6/fib6_rules.c | 4 +++ + net/ipv6/ip6mr.c | 2 ++ + net/ipv6/route.c | 58 +++++++++++++++++++++++++++++++++++++++++- + 9 files changed, 75 insertions(+), 1 deletion(-) + +--- a/include/net/netns/ipv6.h ++++ b/include/net/netns/ipv6.h +@@ -61,6 +61,7 @@ struct netns_ipv6 { + unsigned long ip6_rt_last_gc; + #ifdef CONFIG_IPV6_MULTIPLE_TABLES + struct rt6_info *ip6_prohibit_entry; ++ struct rt6_info *ip6_policy_failed_entry; + struct rt6_info *ip6_blk_hole_entry; + struct fib6_table *fib6_local_tbl; + struct fib_rules_ops *fib6_rules_ops; +--- a/include/uapi/linux/fib_rules.h ++++ b/include/uapi/linux/fib_rules.h +@@ -64,6 +64,10 @@ enum { + FR_ACT_BLACKHOLE, /* Drop without notification */ + FR_ACT_UNREACHABLE, /* Drop with ENETUNREACH */ + FR_ACT_PROHIBIT, /* Drop with EACCES */ ++ FR_ACT_RES9, ++ FR_ACT_RES10, ++ FR_ACT_RES11, ++ FR_ACT_POLICY_FAILED, /* Drop with EACCES */ + __FR_ACT_MAX, + }; + +--- a/include/uapi/linux/rtnetlink.h ++++ b/include/uapi/linux/rtnetlink.h +@@ -210,6 +210,7 @@ enum { + RTN_THROW, /* Not in this table */ + RTN_NAT, /* Translate this address */ + RTN_XRESOLVE, /* Use external resolver */ ++ RTN_POLICY_FAILED, /* Failed ingress/egress policy */ + __RTN_MAX + }; + +--- a/net/ipv4/fib_semantics.c ++++ b/net/ipv4/fib_semantics.c +@@ -138,6 +138,10 @@ const struct fib_prop fib_props[RTN_MAX + .error = -EINVAL, + .scope = RT_SCOPE_NOWHERE, + }, ++ [RTN_POLICY_FAILED] = { ++ .error = -EACCES, ++ .scope = RT_SCOPE_UNIVERSE, ++ }, + }; + + static void rt_fibinfo_free(struct rtable __rcu **rtp) +--- a/net/ipv4/fib_trie.c ++++ b/net/ipv4/fib_trie.c +@@ -2352,6 +2352,7 @@ static const char *const rtn_type_names[ + [RTN_THROW] = "THROW", + [RTN_NAT] = "NAT", + [RTN_XRESOLVE] = "XRESOLVE", ++ [RTN_POLICY_FAILED] = "POLICY_FAILED", + }; + + static inline const char *rtn_type(char *buf, size_t len, unsigned int t) +--- a/net/ipv4/ipmr.c ++++ b/net/ipv4/ipmr.c +@@ -182,6 +182,7 @@ static int ipmr_rule_action(struct fib_r + case FR_ACT_UNREACHABLE: + return -ENETUNREACH; + case FR_ACT_PROHIBIT: ++ case FR_ACT_POLICY_FAILED: + return -EACCES; + case FR_ACT_BLACKHOLE: + default: +--- a/net/ipv6/fib6_rules.c ++++ b/net/ipv6/fib6_rules.c +@@ -73,6 +73,10 @@ static int fib6_rule_action(struct fib_r + err = -EACCES; + rt = net->ipv6.ip6_prohibit_entry; + goto discard_pkt; ++ case FR_ACT_POLICY_FAILED: ++ err = -EACCES; ++ rt = net->ipv6.ip6_policy_failed_entry; ++ goto discard_pkt; + } + + table = fib6_get_table(net, rule->table); +--- a/net/ipv6/ip6mr.c ++++ b/net/ipv6/ip6mr.c +@@ -167,6 +167,8 @@ static int ip6mr_rule_action(struct fib_ + return -ENETUNREACH; + case FR_ACT_PROHIBIT: + return -EACCES; ++ case FR_ACT_POLICY_FAILED: ++ return -EACCES; + case FR_ACT_BLACKHOLE: + default: + return -EINVAL; +--- a/net/ipv6/route.c ++++ b/net/ipv6/route.c +@@ -87,6 +87,8 @@ static int ip6_pkt_discard(struct sk_bu + static int ip6_pkt_discard_out(struct sock *sk, struct sk_buff *skb); + static int ip6_pkt_prohibit(struct sk_buff *skb); + static int ip6_pkt_prohibit_out(struct sock *sk, struct sk_buff *skb); ++static int ip6_pkt_policy_failed(struct sk_buff *skb); ++static int ip6_pkt_policy_failed_out(struct sock *sk, struct sk_buff *skb); + static void ip6_link_failure(struct sk_buff *skb); + static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk, + struct sk_buff *skb, u32 mtu); +@@ -281,6 +283,21 @@ static const struct rt6_info ip6_prohibi + .rt6i_ref = ATOMIC_INIT(1), + }; + ++static const struct rt6_info ip6_policy_failed_entry_template = { ++ .dst = { ++ .__refcnt = ATOMIC_INIT(1), ++ .__use = 1, ++ .obsolete = DST_OBSOLETE_FORCE_CHK, ++ .error = -EACCES, ++ .input = ip6_pkt_policy_failed, ++ .output = ip6_pkt_policy_failed_out, ++ }, ++ .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP), ++ .rt6i_protocol = RTPROT_KERNEL, ++ .rt6i_metric = ~(u32) 0, ++ .rt6i_ref = ATOMIC_INIT(1), ++}; ++ + static const struct rt6_info ip6_blk_hole_entry_template = { + .dst = { + .__refcnt = ATOMIC_INIT(1), +@@ -1635,6 +1652,11 @@ int ip6_route_add(struct fib6_config *cf + rt->dst.output = ip6_pkt_prohibit_out; + rt->dst.input = ip6_pkt_prohibit; + break; ++ case RTN_POLICY_FAILED: ++ rt->dst.error = -EACCES; ++ rt->dst.output = ip6_pkt_policy_failed_out; ++ rt->dst.input = ip6_pkt_policy_failed; ++ break; + case RTN_THROW: + default: + rt->dst.error = (cfg->fc_type == RTN_THROW) ? -EAGAIN +@@ -2202,6 +2224,17 @@ static int ip6_pkt_prohibit_out(struct s + return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES); + } + ++static int ip6_pkt_policy_failed(struct sk_buff *skb) ++{ ++ return ip6_pkt_drop(skb, ICMPV6_POLICY_FAIL, IPSTATS_MIB_INNOROUTES); ++} ++ ++static int ip6_pkt_policy_failed_out(struct sock *sk, struct sk_buff *skb) ++{ ++ skb->dev = skb_dst(skb)->dev; ++ return ip6_pkt_drop(skb, ICMPV6_POLICY_FAIL, IPSTATS_MIB_OUTNOROUTES); ++} ++ + /* + * Allocate a dst for local (unicast / anycast) address. + */ +@@ -2428,7 +2461,8 @@ static int rtm_to_fib6_config(struct sk_ + if (rtm->rtm_type == RTN_UNREACHABLE || + rtm->rtm_type == RTN_BLACKHOLE || + rtm->rtm_type == RTN_PROHIBIT || +- rtm->rtm_type == RTN_THROW) ++ rtm->rtm_type == RTN_THROW || ++ rtm->rtm_type == RTN_POLICY_FAILED) + cfg->fc_flags |= RTF_REJECT; + + if (rtm->rtm_type == RTN_LOCAL) +@@ -2644,6 +2678,9 @@ static int rt6_fill_node(struct net *net + case -EACCES: + rtm->rtm_type = RTN_PROHIBIT; + break; ++ case -EPERM: ++ rtm->rtm_type = RTN_POLICY_FAILED; ++ break; + case -EAGAIN: + rtm->rtm_type = RTN_THROW; + break; +@@ -2901,6 +2938,8 @@ static int ip6_route_dev_notify(struct n + #ifdef CONFIG_IPV6_MULTIPLE_TABLES + net->ipv6.ip6_prohibit_entry->dst.dev = dev; + net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev); ++ net->ipv6.ip6_policy_failed_entry->dst.dev = dev; ++ net->ipv6.ip6_policy_failed_entry->rt6i_idev = in6_dev_get(dev); + net->ipv6.ip6_blk_hole_entry->dst.dev = dev; + net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev); + #endif +@@ -3117,6 +3156,17 @@ static int __net_init ip6_route_net_init + net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops; + dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst, + ip6_template_metrics, true); ++ ++ net->ipv6.ip6_policy_failed_entry = ++ kmemdup(&ip6_policy_failed_entry_template, ++ sizeof(*net->ipv6.ip6_policy_failed_entry), GFP_KERNEL); ++ if (!net->ipv6.ip6_policy_failed_entry) ++ goto out_ip6_blk_hole_entry; ++ net->ipv6.ip6_policy_failed_entry->dst.path = ++ (struct dst_entry *)net->ipv6.ip6_policy_failed_entry; ++ net->ipv6.ip6_policy_failed_entry->dst.ops = &net->ipv6.ip6_dst_ops; ++ dst_init_metrics(&net->ipv6.ip6_policy_failed_entry->dst, ++ ip6_template_metrics, true); + #endif + + net->ipv6.sysctl.flush_delay = 0; +@@ -3135,6 +3185,8 @@ out: + return ret; + + #ifdef CONFIG_IPV6_MULTIPLE_TABLES ++out_ip6_blk_hole_entry: ++ kfree(net->ipv6.ip6_blk_hole_entry); + out_ip6_prohibit_entry: + kfree(net->ipv6.ip6_prohibit_entry); + out_ip6_null_entry: +@@ -3152,6 +3204,7 @@ static void __net_exit ip6_route_net_exi + #ifdef CONFIG_IPV6_MULTIPLE_TABLES + kfree(net->ipv6.ip6_prohibit_entry); + kfree(net->ipv6.ip6_blk_hole_entry); ++ kfree(net->ipv6.ip6_policy_failed_entry); + #endif + dst_entries_destroy(&net->ipv6.ip6_dst_ops); + } +@@ -3248,6 +3301,9 @@ int __init ip6_route_init(void) + init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); + init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev; + init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); ++ init_net.ipv6.ip6_policy_failed_entry->dst.dev = init_net.loopback_dev; ++ init_net.ipv6.ip6_policy_failed_entry->rt6i_idev = ++ in6_dev_get(init_net.loopback_dev); + #endif + ret = fib6_init(); + if (ret) diff --git a/target/linux/generic/patches-4.1/671-net-provide-defines-for-_POLICY_FAILED-until-all-cod.patch b/target/linux/generic/patches-4.1/671-net-provide-defines-for-_POLICY_FAILED-until-all-cod.patch new file mode 100644 index 0000000..dafb56c --- /dev/null +++ b/target/linux/generic/patches-4.1/671-net-provide-defines-for-_POLICY_FAILED-until-all-cod.patch @@ -0,0 +1,53 @@ +From 7749b481ce5d7e232b1f7da5e6b2c44816f51681 Mon Sep 17 00:00:00 2001 +From: Jonas Gorski +Date: Sun, 19 Jan 2014 20:45:51 +0100 +Subject: [PATCH 2/2] net: provide defines for _POLICY_FAILED until all code is + updated + +Upstream introduced ICMPV6_POLICY_FAIL for code 5 of destination +unreachable, conflicting with our name. + +Add appropriate defines to allow our code to build with the new +name until we have updated our local patches for older kernels +and userspace packages. + +Signed-off-by: Jonas Gorski +--- + include/uapi/linux/fib_rules.h | 2 ++ + include/uapi/linux/icmpv6.h | 2 ++ + include/uapi/linux/rtnetlink.h | 2 ++ + 3 files changed, 6 insertions(+) + +--- a/include/uapi/linux/fib_rules.h ++++ b/include/uapi/linux/fib_rules.h +@@ -71,6 +71,8 @@ enum { + __FR_ACT_MAX, + }; + ++#define FR_ACT_FAILED_POLICY FR_ACT_POLICY_FAILED ++ + #define FR_ACT_MAX (__FR_ACT_MAX - 1) + + #endif +--- a/include/uapi/linux/icmpv6.h ++++ b/include/uapi/linux/icmpv6.h +@@ -118,6 +118,8 @@ struct icmp6hdr { + #define ICMPV6_POLICY_FAIL 5 + #define ICMPV6_REJECT_ROUTE 6 + ++#define ICMPV6_FAILED_POLICY ICMPV6_POLICY_FAIL ++ + /* + * Codes for Time Exceeded + */ +--- a/include/uapi/linux/rtnetlink.h ++++ b/include/uapi/linux/rtnetlink.h +@@ -214,6 +214,8 @@ enum { + __RTN_MAX + }; + ++#define RTN_FAILED_POLICY RTN_POLICY_FAILED ++ + #define RTN_MAX (__RTN_MAX - 1) + + diff --git a/target/linux/generic/patches-4.1/680-NET-skip-GRO-for-foreign-MAC-addresses.patch b/target/linux/generic/patches-4.1/680-NET-skip-GRO-for-foreign-MAC-addresses.patch new file mode 100644 index 0000000..4d82ec0 --- /dev/null +++ b/target/linux/generic/patches-4.1/680-NET-skip-GRO-for-foreign-MAC-addresses.patch @@ -0,0 +1,160 @@ +Subject: NET: skip GRO for foreign MAC addresses + +For network drivers using napi_gro_receive, packets are run through GRO, +even when the destination MAC address does not match, and they're supposed +to be delivered to another host behind a different bridge port. + +This can be very expensive, because for drivers without TSO or scatter- +gather, this can only be undone by copying the skb and checksumming it +again. + +To be able to track foreign MAC addresses in an inexpensive way, create +a mask of changed bits in MAC addresses of upper devices. This allows +handling VLANs and bridge devices with different addresses (as long as +they are not too different). + +Signed-off-by: Felix Fietkau + +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -4039,6 +4039,9 @@ static enum gro_result dev_gro_receive(s + enum gro_result ret; + int grow; + ++ if (skb->gro_skip) ++ goto normal; ++ + if (!(skb->dev->features & NETIF_F_GRO)) + goto normal; + +@@ -5186,6 +5189,48 @@ static void __netdev_adjacent_dev_unlink + &upper_dev->adj_list.lower); + } + ++static void __netdev_addr_mask(unsigned char *mask, const unsigned char *addr, ++ struct net_device *dev) ++{ ++ int i; ++ ++ for (i = 0; i < dev->addr_len; i++) ++ mask[i] |= addr[i] ^ dev->dev_addr[i]; ++} ++ ++static void __netdev_upper_mask(unsigned char *mask, struct net_device *dev, ++ struct net_device *lower) ++{ ++ struct net_device *cur; ++ struct list_head *iter; ++ ++ netdev_for_each_upper_dev_rcu(dev, cur, iter) { ++ __netdev_addr_mask(mask, cur->dev_addr, lower); ++ __netdev_upper_mask(mask, cur, lower); ++ } ++} ++ ++static void __netdev_update_addr_mask(struct net_device *dev) ++{ ++ unsigned char mask[MAX_ADDR_LEN]; ++ struct net_device *cur; ++ struct list_head *iter; ++ ++ memset(mask, 0, sizeof(mask)); ++ __netdev_upper_mask(mask, dev, dev); ++ memcpy(dev->local_addr_mask, mask, dev->addr_len); ++ ++ netdev_for_each_lower_dev(dev, cur, iter) ++ __netdev_update_addr_mask(cur); ++} ++ ++static void netdev_update_addr_mask(struct net_device *dev) ++{ ++ rcu_read_lock(); ++ __netdev_update_addr_mask(dev); ++ rcu_read_unlock(); ++} ++ + static int __netdev_upper_dev_link(struct net_device *dev, + struct net_device *upper_dev, bool master, + void *private) +@@ -5246,6 +5291,7 @@ static int __netdev_upper_dev_link(struc + goto rollback_lower_mesh; + } + ++ netdev_update_addr_mask(dev); + call_netdevice_notifiers(NETDEV_CHANGEUPPER, dev); + return 0; + +@@ -5363,6 +5409,7 @@ void netdev_upper_dev_unlink(struct net_ + list_for_each_entry(i, &upper_dev->all_adj_list.upper, list) + __netdev_adjacent_dev_unlink(dev, i->dev); + ++ netdev_update_addr_mask(dev); + call_netdevice_notifiers(NETDEV_CHANGEUPPER, dev); + } + EXPORT_SYMBOL(netdev_upper_dev_unlink); +@@ -5902,6 +5949,7 @@ int dev_set_mac_address(struct net_devic + if (err) + return err; + dev->addr_assign_type = NET_ADDR_SET; ++ netdev_update_addr_mask(dev); + call_netdevice_notifiers(NETDEV_CHANGEADDR, dev); + add_device_randomness(dev->dev_addr, dev->addr_len); + return 0; +--- a/include/linux/netdevice.h ++++ b/include/linux/netdevice.h +@@ -1602,6 +1602,8 @@ struct net_device { + struct netdev_hw_addr_list mc; + struct netdev_hw_addr_list dev_addrs; + ++ unsigned char local_addr_mask[MAX_ADDR_LEN]; ++ + #ifdef CONFIG_SYSFS + struct kset *queues_kset; + #endif +--- a/include/linux/skbuff.h ++++ b/include/linux/skbuff.h +@@ -615,7 +615,8 @@ struct sk_buff { + __u8 ipvs_property:1; + __u8 inner_protocol_type:1; + __u8 remcsum_offload:1; +- /* 3 or 5 bit hole */ ++ __u8 gro_skip:1; ++ /* 2 or 4 bit hole */ + + #ifdef CONFIG_NET_SCHED + __u16 tc_index; /* traffic control index */ +--- a/net/ethernet/eth.c ++++ b/net/ethernet/eth.c +@@ -139,6 +139,18 @@ u32 eth_get_headlen(void *data, unsigned + } + EXPORT_SYMBOL(eth_get_headlen); + ++static inline bool ++eth_check_local_mask(const void *addr1, const void *addr2, const void *mask) ++{ ++ const u16 *a1 = addr1; ++ const u16 *a2 = addr2; ++ const u16 *m = mask; ++ ++ return (((a1[0] ^ a2[0]) & ~m[0]) | ++ ((a1[1] ^ a2[1]) & ~m[1]) | ++ ((a1[2] ^ a2[2]) & ~m[2])); ++} ++ + /** + * eth_type_trans - determine the packet's protocol ID. + * @skb: received socket data +@@ -166,8 +178,12 @@ __be16 eth_type_trans(struct sk_buff *sk + skb->pkt_type = PACKET_MULTICAST; + } + else if (unlikely(!ether_addr_equal_64bits(eth->h_dest, +- dev->dev_addr))) ++ dev->dev_addr))) { + skb->pkt_type = PACKET_OTHERHOST; ++ if (eth_check_local_mask(eth->h_dest, dev->dev_addr, ++ dev->local_addr_mask)) ++ skb->gro_skip = 1; ++ } + + /* + * Some variants of DSA tagging don't have an ethertype field diff --git a/target/linux/generic/patches-4.1/681-NET-add-of_get_mac_address_mtd.patch b/target/linux/generic/patches-4.1/681-NET-add-of_get_mac_address_mtd.patch new file mode 100644 index 0000000..688cf6e --- /dev/null +++ b/target/linux/generic/patches-4.1/681-NET-add-of_get_mac_address_mtd.patch @@ -0,0 +1,88 @@ +From: John Crispin +Date: Sun, 27 Jul 2014 09:40:01 +0100 +Subject: NET: add of_get_mac_address_mtd() + +Many embedded devices have information such as mac addresses stored inside mtd +devices. This patch allows us to add a property inside a node describing a +network interface. The new property points at a mtd partition with an offset +where the mac address can be found. + +Signed-off-by: John Crispin +--- + drivers/of/of_net.c | 37 +++++++++++++++++++++++++++++++++++++ + include/linux/of_net.h | 1 + + 2 files changed, 38 insertions(+) + +--- a/drivers/of/of_net.c ++++ b/drivers/of/of_net.c +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + + /** + * of_get_phy_mode - Get phy mode for given device_node +@@ -80,3 +81,45 @@ const void *of_get_mac_address(struct de + return of_get_mac_addr(np, "address"); + } + EXPORT_SYMBOL(of_get_mac_address); ++ ++#ifdef CONFIG_MTD ++int of_get_mac_address_mtd(struct device_node *np, unsigned char *mac) ++{ ++ struct device_node *mtd_np = NULL; ++ size_t retlen; ++ int size, ret; ++ struct mtd_info *mtd; ++ const char *part; ++ const __be32 *list; ++ phandle phandle; ++ u32 mac_inc = 0; ++ ++ list = of_get_property(np, "mtd-mac-address", &size); ++ if (!list || (size != (2 * sizeof(*list)))) ++ return -ENOENT; ++ ++ phandle = be32_to_cpup(list++); ++ if (phandle) ++ mtd_np = of_find_node_by_phandle(phandle); ++ ++ if (!mtd_np) ++ return -ENOENT; ++ ++ part = of_get_property(mtd_np, "label", NULL); ++ if (!part) ++ part = mtd_np->name; ++ ++ mtd = get_mtd_device_nm(part); ++ if (IS_ERR(mtd)) ++ return PTR_ERR(mtd); ++ ++ ret = mtd_read(mtd, be32_to_cpup(list), 6, &retlen, mac); ++ put_mtd_device(mtd); ++ ++ if (!of_property_read_u32(np, "mtd-mac-address-increment", &mac_inc)) ++ mac[5] += mac_inc; ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(of_get_mac_address_mtd); ++#endif +--- a/include/linux/of_net.h ++++ b/include/linux/of_net.h +@@ -13,6 +13,14 @@ + struct net_device; + extern int of_get_phy_mode(struct device_node *np); + extern const void *of_get_mac_address(struct device_node *np); ++#ifdef CONFIG_MTD ++extern int of_get_mac_address_mtd(struct device_node *np, unsigned char *mac); ++#else ++static inline int of_get_mac_address_mtd(struct device_node *np, unsigned char *mac) ++{ ++ return -ENOENT; ++} ++#endif + extern struct net_device *of_find_net_device_by_node(struct device_node *np); + #else + static inline int of_get_phy_mode(struct device_node *np) diff --git a/target/linux/generic/patches-4.1/700-swconfig.patch b/target/linux/generic/patches-4.1/700-swconfig.patch new file mode 100644 index 0000000..cdce89e --- /dev/null +++ b/target/linux/generic/patches-4.1/700-swconfig.patch @@ -0,0 +1,39 @@ +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -12,6 +12,16 @@ menuconfig PHYLIB + + if PHYLIB + ++config SWCONFIG ++ tristate "Switch configuration API" ++ ---help--- ++ Switch configuration API using netlink. This allows ++ you to configure the VLAN features of certain switches. ++ ++config SWCONFIG_LEDS ++ bool "Switch LED trigger support" ++ depends on (SWCONFIG && LEDS_TRIGGERS) ++ + comment "MII PHY device drivers" + + config AT803X_PHY +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -3,6 +3,7 @@ + libphy-objs := phy.o phy_device.o mdio_bus.o + + obj-$(CONFIG_PHYLIB) += libphy.o ++obj-$(CONFIG_SWCONFIG) += swconfig.o + obj-$(CONFIG_MARVELL_PHY) += marvell.o + obj-$(CONFIG_DAVICOM_PHY) += davicom.o + obj-$(CONFIG_CICADA_PHY) += cicada.o +--- a/include/uapi/linux/Kbuild ++++ b/include/uapi/linux/Kbuild +@@ -380,6 +380,7 @@ header-y += stddef.h + header-y += string.h + header-y += suspend_ioctls.h + header-y += swab.h ++header-y += switch.h + header-y += synclink.h + header-y += sysctl.h + header-y += sysinfo.h diff --git a/target/linux/generic/patches-4.1/701-phy_extension.patch b/target/linux/generic/patches-4.1/701-phy_extension.patch new file mode 100644 index 0000000..55b37ba --- /dev/null +++ b/target/linux/generic/patches-4.1/701-phy_extension.patch @@ -0,0 +1,63 @@ +--- a/drivers/net/phy/phy.c ++++ b/drivers/net/phy/phy.c +@@ -357,6 +357,50 @@ int phy_ethtool_gset(struct phy_device * + } + EXPORT_SYMBOL(phy_ethtool_gset); + ++int phy_ethtool_ioctl(struct phy_device *phydev, void *useraddr) ++{ ++ u32 cmd; ++ int tmp; ++ struct ethtool_cmd ecmd = { ETHTOOL_GSET }; ++ struct ethtool_value edata = { ETHTOOL_GLINK }; ++ ++ if (get_user(cmd, (u32 *) useraddr)) ++ return -EFAULT; ++ ++ switch (cmd) { ++ case ETHTOOL_GSET: ++ phy_ethtool_gset(phydev, &ecmd); ++ if (copy_to_user(useraddr, &ecmd, sizeof(ecmd))) ++ return -EFAULT; ++ return 0; ++ ++ case ETHTOOL_SSET: ++ if (copy_from_user(&ecmd, useraddr, sizeof(ecmd))) ++ return -EFAULT; ++ return phy_ethtool_sset(phydev, &ecmd); ++ ++ case ETHTOOL_NWAY_RST: ++ /* if autoneg is off, it's an error */ ++ tmp = phy_read(phydev, MII_BMCR); ++ if (tmp & BMCR_ANENABLE) { ++ tmp |= (BMCR_ANRESTART); ++ phy_write(phydev, MII_BMCR, tmp); ++ return 0; ++ } ++ return -EINVAL; ++ ++ case ETHTOOL_GLINK: ++ edata.data = (phy_read(phydev, ++ MII_BMSR) & BMSR_LSTATUS) ? 1 : 0; ++ if (copy_to_user(useraddr, &edata, sizeof(edata))) ++ return -EFAULT; ++ return 0; ++ } ++ ++ return -EOPNOTSUPP; ++} ++EXPORT_SYMBOL(phy_ethtool_ioctl); ++ + /** + * phy_mii_ioctl - generic PHY MII ioctl interface + * @phydev: the phy_device struct +--- a/include/linux/phy.h ++++ b/include/linux/phy.h +@@ -762,6 +762,7 @@ void phy_start_machine(struct phy_device + void phy_stop_machine(struct phy_device *phydev); + int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd); + int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd); ++int phy_ethtool_ioctl(struct phy_device *phydev, void *useraddr); + int phy_mii_ioctl(struct phy_device *phydev, struct ifreq *ifr, int cmd); + int phy_start_interrupts(struct phy_device *phydev); + void phy_print_status(struct phy_device *phydev); diff --git a/target/linux/generic/patches-4.1/702-phy_add_aneg_done_function.patch b/target/linux/generic/patches-4.1/702-phy_add_aneg_done_function.patch new file mode 100644 index 0000000..c743cef --- /dev/null +++ b/target/linux/generic/patches-4.1/702-phy_add_aneg_done_function.patch @@ -0,0 +1,27 @@ +--- a/include/linux/phy.h ++++ b/include/linux/phy.h +@@ -489,6 +489,12 @@ struct phy_driver { + /* Determines the negotiated speed and duplex */ + int (*read_status)(struct phy_device *phydev); + ++ /* ++ * Update the value in phydev->link to reflect the ++ * current link value ++ */ ++ int (*update_link)(struct phy_device *phydev); ++ + /* Clears any pending interrupts */ + int (*ack_interrupt)(struct phy_device *phydev); + +--- a/drivers/net/phy/phy_device.c ++++ b/drivers/net/phy/phy_device.c +@@ -929,6 +929,9 @@ int genphy_update_link(struct phy_device + { + int status; + ++ if (phydev->drv->update_link) ++ return phydev->drv->update_link(phydev); ++ + /* Do a fake read */ + status = phy_read(phydev, MII_BMSR); + if (status < 0) diff --git a/target/linux/generic/patches-4.1/703-phy-add-detach-callback-to-struct-phy_driver.patch b/target/linux/generic/patches-4.1/703-phy-add-detach-callback-to-struct-phy_driver.patch new file mode 100644 index 0000000..85888f7 --- /dev/null +++ b/target/linux/generic/patches-4.1/703-phy-add-detach-callback-to-struct-phy_driver.patch @@ -0,0 +1,27 @@ +--- a/drivers/net/phy/phy_device.c ++++ b/drivers/net/phy/phy_device.c +@@ -674,6 +674,9 @@ void phy_detach(struct phy_device *phyde + { + int i; + ++ if (phydev->drv && phydev->drv->detach) ++ phydev->drv->detach(phydev); ++ + if (phydev->bus->dev.driver) + module_put(phydev->bus->dev.driver->owner); + +--- a/include/linux/phy.h ++++ b/include/linux/phy.h +@@ -507,6 +507,12 @@ struct phy_driver { + */ + int (*did_interrupt)(struct phy_device *phydev); + ++ /* ++ * Called before an ethernet device is detached ++ * from the PHY. ++ */ ++ void (*detach)(struct phy_device *phydev); ++ + /* Clears up any memory if needed */ + void (*remove)(struct phy_device *phydev); + diff --git a/target/linux/generic/patches-4.1/704-phy-no-genphy-soft-reset.patch b/target/linux/generic/patches-4.1/704-phy-no-genphy-soft-reset.patch new file mode 100644 index 0000000..41a6d91 --- /dev/null +++ b/target/linux/generic/patches-4.1/704-phy-no-genphy-soft-reset.patch @@ -0,0 +1,29 @@ +--- a/drivers/net/phy/phy_device.c ++++ b/drivers/net/phy/phy_device.c +@@ -1147,7 +1147,7 @@ int genphy_config_init(struct phy_device + return 0; + } + +-static int gen10g_soft_reset(struct phy_device *phydev) ++static int no_soft_reset(struct phy_device *phydev) + { + /* Do nothing for now */ + return 0; +@@ -1361,7 +1361,7 @@ static struct phy_driver genphy_driver[] + .phy_id = 0xffffffff, + .phy_id_mask = 0xffffffff, + .name = "Generic PHY", +- .soft_reset = genphy_soft_reset, ++ .soft_reset = no_soft_reset, + .config_init = genphy_config_init, + .features = PHY_GBIT_FEATURES | SUPPORTED_MII | + SUPPORTED_AUI | SUPPORTED_FIBRE | +@@ -1376,7 +1376,7 @@ static struct phy_driver genphy_driver[] + .phy_id = 0xffffffff, + .phy_id_mask = 0xffffffff, + .name = "Generic 10G PHY", +- .soft_reset = gen10g_soft_reset, ++ .soft_reset = no_soft_reset, + .config_init = gen10g_config_init, + .features = 0, + .config_aneg = gen10g_config_aneg, diff --git a/target/linux/generic/patches-4.1/710-phy-add-mdio_register_board_info.patch b/target/linux/generic/patches-4.1/710-phy-add-mdio_register_board_info.patch new file mode 100644 index 0000000..2bc91d5 --- /dev/null +++ b/target/linux/generic/patches-4.1/710-phy-add-mdio_register_board_info.patch @@ -0,0 +1,193 @@ +--- a/drivers/net/phy/mdio_bus.c ++++ b/drivers/net/phy/mdio_bus.c +@@ -38,6 +38,8 @@ + + #include + ++#include "mdio-boardinfo.h" ++ + /** + * mdiobus_alloc_size - allocate a mii_bus structure + * @size: extra amount of memory to allocate for private storage. +@@ -335,9 +337,21 @@ void mdiobus_free(struct mii_bus *bus) + } + EXPORT_SYMBOL(mdiobus_free); + ++static void mdiobus_setup_phydev_from_boardinfo(struct mii_bus *bus, ++ struct phy_device *phydev, ++ struct mdio_board_info *bi) ++{ ++ if (strcmp(bus->id, bi->bus_id) || ++ bi->phy_addr != phydev->addr) ++ return; ++ ++ phydev->dev.platform_data = (void *) bi->platform_data; ++} ++ + struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr) + { + struct phy_device *phydev; ++ struct mdio_board_entry *be; + int err; + + phydev = get_phy_device(bus, addr, false); +@@ -350,6 +364,12 @@ struct phy_device *mdiobus_scan(struct m + */ + of_mdiobus_link_phydev(bus, phydev); + ++ mutex_lock(&__mdio_board_lock); ++ list_for_each_entry(be, &__mdio_board_list, list) ++ mdiobus_setup_phydev_from_boardinfo(bus, phydev, ++ &be->board_info); ++ mutex_unlock(&__mdio_board_lock); ++ + err = phy_device_register(phydev); + if (err) { + phy_device_free(phydev); +--- a/include/linux/phy.h ++++ b/include/linux/phy.h +@@ -800,6 +800,23 @@ void mdio_bus_exit(void); + + extern struct bus_type mdio_bus_type; + ++struct mdio_board_info { ++ const char *bus_id; ++ int phy_addr; ++ ++ const void *platform_data; ++}; ++ ++#ifdef CONFIG_MDIO_BOARDINFO ++int mdiobus_register_board_info(const struct mdio_board_info *info, unsigned n); ++#else ++static inline int ++mdiobus_register_board_info(const struct mdio_board_info *info, unsigned n) ++{ ++ return 0; ++} ++#endif ++ + /** + * module_phy_driver() - Helper macro for registering PHY drivers + * @__phy_drivers: array of PHY drivers to register +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -12,6 +12,10 @@ menuconfig PHYLIB + + if PHYLIB + ++config MDIO_BOARDINFO ++ bool ++ default y ++ + config SWCONFIG + tristate "Switch configuration API" + ---help--- +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -2,6 +2,8 @@ + + libphy-objs := phy.o phy_device.o mdio_bus.o + ++obj-$(CONFIG_MDIO_BOARDINFO) += mdio-boardinfo.o ++ + obj-$(CONFIG_PHYLIB) += libphy.o + obj-$(CONFIG_SWCONFIG) += swconfig.o + obj-$(CONFIG_MARVELL_PHY) += marvell.o +--- /dev/null ++++ b/drivers/net/phy/mdio-boardinfo.c +@@ -0,0 +1,58 @@ ++/* ++ * mdio-boardinfo.c - collect pre-declarations of PHY devices ++ * ++ * 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. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "mdio-boardinfo.h" ++ ++/* ++ * These symbols are exported ONLY FOR the mdio_bus component. ++ * No other users will be supported. ++ */ ++ ++LIST_HEAD(__mdio_board_list); ++EXPORT_SYMBOL_GPL(__mdio_board_list); ++ ++DEFINE_MUTEX(__mdio_board_lock); ++EXPORT_SYMBOL_GPL(__mdio_board_lock); ++ ++/** ++ * mdio_register_board_info - register PHY devices for a given board ++ * @info: array of chip descriptors ++ * @n: how many descriptors are provided ++ * Context: can sleep ++ * ++ * The board info passed can safely be __initdata ... but be careful of ++ * any embedded pointers (platform_data, etc), they're copied as-is. ++ */ ++int __init ++mdiobus_register_board_info(struct mdio_board_info const *info, unsigned n) ++{ ++ struct mdio_board_entry *be; ++ int i; ++ ++ be = kzalloc(n * sizeof(*be), GFP_KERNEL); ++ if (!be) ++ return -ENOMEM; ++ ++ for (i = 0; i < n; i++, be++, info++) { ++ memcpy(&be->board_info, info, sizeof(*info)); ++ mutex_lock(&__mdio_board_lock); ++ list_add_tail(&be->list, &__mdio_board_list); ++ mutex_unlock(&__mdio_board_lock); ++ } ++ ++ return 0; ++} +--- /dev/null ++++ b/drivers/net/phy/mdio-boardinfo.h +@@ -0,0 +1,22 @@ ++/* ++ * mdio-boardinfo.h - boardinfo interface internal to the mdio_bus component ++ * ++ * 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. ++ * ++ */ ++ ++#include ++ ++struct mdio_board_entry { ++ struct list_head list; ++ struct mdio_board_info board_info; ++}; ++ ++/* __mdio_board_lock protects __mdio_board_list ++ * only mdio_bus components are allowed to use these symbols. ++ */ ++extern struct mutex __mdio_board_lock; ++extern struct list_head __mdio_board_list; +--- a/drivers/net/Makefile ++++ b/drivers/net/Makefile +@@ -16,7 +16,7 @@ obj-$(CONFIG_MII) += mii.o + obj-$(CONFIG_MDIO) += mdio.o + obj-$(CONFIG_NET) += Space.o loopback.o + obj-$(CONFIG_NETCONSOLE) += netconsole.o +-obj-$(CONFIG_PHYLIB) += phy/ ++obj-y += phy/ + obj-$(CONFIG_RIONET) += rionet.o + obj-$(CONFIG_NET_TEAM) += team/ + obj-$(CONFIG_TUN) += tun.o diff --git a/target/linux/generic/patches-4.1/720-phy_adm6996.patch b/target/linux/generic/patches-4.1/720-phy_adm6996.patch new file mode 100644 index 0000000..7107316 --- /dev/null +++ b/target/linux/generic/patches-4.1/720-phy_adm6996.patch @@ -0,0 +1,26 @@ +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -133,6 +133,13 @@ config MICREL_PHY + ---help--- + Supports the KSZ9021, VSC8201, KS8001 PHYs. + ++config ADM6996_PHY ++ tristate "Driver for ADM6996 switches" ++ select SWCONFIG ++ ---help--- ++ Currently supports the ADM6996FC and ADM6996M switches. ++ Support for FC is very limited. ++ + config FIXED_PHY + tristate "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs" + depends on PHYLIB +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -18,6 +18,7 @@ obj-$(CONFIG_BCM63XX_PHY) += bcm63xx.o + obj-$(CONFIG_BCM7XXX_PHY) += bcm7xxx.o + obj-$(CONFIG_BCM87XX_PHY) += bcm87xx.o + obj-$(CONFIG_ICPLUS_PHY) += icplus.o ++obj-$(CONFIG_ADM6996_PHY) += adm6996.o + obj-$(CONFIG_REALTEK_PHY) += realtek.o + obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o + obj-$(CONFIG_FIXED_PHY) += fixed_phy.o diff --git a/target/linux/generic/patches-4.1/721-phy_packets.patch b/target/linux/generic/patches-4.1/721-phy_packets.patch new file mode 100644 index 0000000..4855186 --- /dev/null +++ b/target/linux/generic/patches-4.1/721-phy_packets.patch @@ -0,0 +1,161 @@ +--- a/include/linux/netdevice.h ++++ b/include/linux/netdevice.h +@@ -1270,6 +1270,7 @@ enum netdev_priv_flags { + IFF_XMIT_DST_RELEASE_PERM = 1<<22, + IFF_IPVLAN_MASTER = 1<<23, + IFF_IPVLAN_SLAVE = 1<<24, ++ IFF_NO_IP_ALIGN = 1<<25, + }; + + #define IFF_802_1Q_VLAN IFF_802_1Q_VLAN +@@ -1297,6 +1298,7 @@ enum netdev_priv_flags { + #define IFF_XMIT_DST_RELEASE_PERM IFF_XMIT_DST_RELEASE_PERM + #define IFF_IPVLAN_MASTER IFF_IPVLAN_MASTER + #define IFF_IPVLAN_SLAVE IFF_IPVLAN_SLAVE ++#define IFF_NO_IP_ALIGN IFF_NO_IP_ALIGN + + /** + * struct net_device - The DEVICE structure. +@@ -1567,6 +1569,11 @@ struct net_device { + const struct swdev_ops *swdev_ops; + #endif + ++#ifdef CONFIG_ETHERNET_PACKET_MANGLE ++ void (*eth_mangle_rx)(struct net_device *dev, struct sk_buff *skb); ++ struct sk_buff *(*eth_mangle_tx)(struct net_device *dev, struct sk_buff *skb); ++#endif ++ + const struct header_ops *header_ops; + + unsigned int flags; +@@ -1633,6 +1640,10 @@ struct net_device { + struct mpls_dev __rcu *mpls_ptr; + #endif + ++#ifdef CONFIG_ETHERNET_PACKET_MANGLE ++ void *phy_ptr; /* PHY device specific data */ ++#endif ++ + /* + * Cache lines mostly used on receive path (including eth_type_trans()) + */ +--- a/include/linux/skbuff.h ++++ b/include/linux/skbuff.h +@@ -2062,6 +2062,10 @@ static inline int pskb_trim(struct sk_bu + return (len < skb->len) ? __pskb_trim(skb, len) : 0; + } + ++extern struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev, ++ unsigned int length, gfp_t gfp); ++ ++ + /** + * pskb_trim_unique - remove end from a paged unique (not cloned) buffer + * @skb: buffer to alter +@@ -2188,16 +2192,6 @@ static inline struct sk_buff *dev_alloc_ + } + + +-static inline struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev, +- unsigned int length, gfp_t gfp) +-{ +- struct sk_buff *skb = __netdev_alloc_skb(dev, length + NET_IP_ALIGN, gfp); +- +- if (NET_IP_ALIGN && skb) +- skb_reserve(skb, NET_IP_ALIGN); +- return skb; +-} +- + static inline struct sk_buff *netdev_alloc_skb_ip_align(struct net_device *dev, + unsigned int length) + { +--- a/net/Kconfig ++++ b/net/Kconfig +@@ -25,6 +25,12 @@ menuconfig NET + + if NET + ++config ETHERNET_PACKET_MANGLE ++ bool ++ help ++ This option can be selected by phy drivers that need to mangle ++ packets going in or out of an ethernet device. ++ + config WANT_COMPAT_NETLINK_MESSAGES + bool + help +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -2649,10 +2649,20 @@ static int xmit_one(struct sk_buff *skb, + if (!list_empty(&ptype_all) || !list_empty(&dev->ptype_all)) + dev_queue_xmit_nit(skb, dev); + +- len = skb->len; +- trace_net_dev_start_xmit(skb, dev); +- rc = netdev_start_xmit(skb, dev, txq, more); +- trace_net_dev_xmit(skb, rc, dev, len); ++#ifdef CONFIG_ETHERNET_PACKET_MANGLE ++ if (!dev->eth_mangle_tx || ++ (skb = dev->eth_mangle_tx(dev, skb)) != NULL) ++#else ++ if (1) ++#endif ++ { ++ len = skb->len; ++ trace_net_dev_start_xmit(skb, dev); ++ rc = netdev_start_xmit(skb, dev, txq, more); ++ trace_net_dev_xmit(skb, rc, dev, len); ++ } else { ++ rc = NETDEV_TX_OK; ++ } + + return rc; + } +--- a/net/core/skbuff.c ++++ b/net/core/skbuff.c +@@ -63,6 +63,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -568,6 +569,22 @@ struct sk_buff *__napi_alloc_skb(struct + } + EXPORT_SYMBOL(__napi_alloc_skb); + ++struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev, ++ unsigned int length, gfp_t gfp) ++{ ++ struct sk_buff *skb = __netdev_alloc_skb(dev, length + NET_IP_ALIGN, gfp); ++ ++#ifdef CONFIG_ETHERNET_PACKET_MANGLE ++ if (dev && (dev->priv_flags & IFF_NO_IP_ALIGN)) ++ return skb; ++#endif ++ ++ if (NET_IP_ALIGN && skb) ++ skb_reserve(skb, NET_IP_ALIGN); ++ return skb; ++} ++EXPORT_SYMBOL(__netdev_alloc_skb_ip_align); ++ + void skb_add_rx_frag(struct sk_buff *skb, int i, struct page *page, int off, + int size, unsigned int truesize) + { +--- a/net/ethernet/eth.c ++++ b/net/ethernet/eth.c +@@ -167,6 +167,12 @@ __be16 eth_type_trans(struct sk_buff *sk + const struct ethhdr *eth; + + skb->dev = dev; ++ ++#ifdef CONFIG_ETHERNET_PACKET_MANGLE ++ if (dev->eth_mangle_rx) ++ dev->eth_mangle_rx(dev, skb); ++#endif ++ + skb_reset_mac_header(skb); + skb_pull_inline(skb, ETH_HLEN); + eth = eth_hdr(skb); diff --git a/target/linux/generic/patches-4.1/722-phy_mvswitch.patch b/target/linux/generic/patches-4.1/722-phy_mvswitch.patch new file mode 100644 index 0000000..209c500 --- /dev/null +++ b/target/linux/generic/patches-4.1/722-phy_mvswitch.patch @@ -0,0 +1,23 @@ +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -140,6 +140,10 @@ config ADM6996_PHY + Currently supports the ADM6996FC and ADM6996M switches. + Support for FC is very limited. + ++config MVSWITCH_PHY ++ tristate "Driver for Marvell 88E6060 switches" ++ select ETHERNET_PACKET_MANGLE ++ + config FIXED_PHY + tristate "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs" + depends on PHYLIB +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -19,6 +19,7 @@ obj-$(CONFIG_BCM7XXX_PHY) += bcm7xxx.o + obj-$(CONFIG_BCM87XX_PHY) += bcm87xx.o + obj-$(CONFIG_ICPLUS_PHY) += icplus.o + obj-$(CONFIG_ADM6996_PHY) += adm6996.o ++obj-$(CONFIG_MVSWITCH_PHY) += mvswitch.o + obj-$(CONFIG_REALTEK_PHY) += realtek.o + obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o + obj-$(CONFIG_FIXED_PHY) += fixed_phy.o diff --git a/target/linux/generic/patches-4.1/723-phy_ip175c.patch b/target/linux/generic/patches-4.1/723-phy_ip175c.patch new file mode 100644 index 0000000..2293ca5 --- /dev/null +++ b/target/linux/generic/patches-4.1/723-phy_ip175c.patch @@ -0,0 +1,23 @@ +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -144,6 +144,10 @@ config MVSWITCH_PHY + tristate "Driver for Marvell 88E6060 switches" + select ETHERNET_PACKET_MANGLE + ++config IP17XX_PHY ++ tristate "Driver for IC+ IP17xx switches" ++ select SWCONFIG ++ + config FIXED_PHY + tristate "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs" + depends on PHYLIB +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -20,6 +20,7 @@ obj-$(CONFIG_BCM87XX_PHY) += bcm87xx.o + obj-$(CONFIG_ICPLUS_PHY) += icplus.o + obj-$(CONFIG_ADM6996_PHY) += adm6996.o + obj-$(CONFIG_MVSWITCH_PHY) += mvswitch.o ++obj-$(CONFIG_IP17XX_PHY) += ip17xx.o + obj-$(CONFIG_REALTEK_PHY) += realtek.o + obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o + obj-$(CONFIG_FIXED_PHY) += fixed_phy.o diff --git a/target/linux/generic/patches-4.1/724-phy_ar8216.patch b/target/linux/generic/patches-4.1/724-phy_ar8216.patch new file mode 100644 index 0000000..3a669ba --- /dev/null +++ b/target/linux/generic/patches-4.1/724-phy_ar8216.patch @@ -0,0 +1,24 @@ +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -148,6 +148,11 @@ config IP17XX_PHY + tristate "Driver for IC+ IP17xx switches" + select SWCONFIG + ++config AR8216_PHY ++ tristate "Driver for Atheros AR8216 switches" ++ select ETHERNET_PACKET_MANGLE ++ select SWCONFIG ++ + config FIXED_PHY + tristate "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs" + depends on PHYLIB +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -22,6 +22,7 @@ obj-$(CONFIG_ADM6996_PHY) += adm6996.o + obj-$(CONFIG_MVSWITCH_PHY) += mvswitch.o + obj-$(CONFIG_IP17XX_PHY) += ip17xx.o + obj-$(CONFIG_REALTEK_PHY) += realtek.o ++obj-$(CONFIG_AR8216_PHY) += ar8216.o ar8327.o + obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o + obj-$(CONFIG_FIXED_PHY) += fixed_phy.o + obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o diff --git a/target/linux/generic/patches-4.1/725-phy_rtl8306.patch b/target/linux/generic/patches-4.1/725-phy_rtl8306.patch new file mode 100644 index 0000000..5d4ce7c --- /dev/null +++ b/target/linux/generic/patches-4.1/725-phy_rtl8306.patch @@ -0,0 +1,23 @@ +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -153,6 +153,10 @@ config AR8216_PHY + select ETHERNET_PACKET_MANGLE + select SWCONFIG + ++config RTL8306_PHY ++ tristate "Driver for Realtek RTL8306S switches" ++ select SWCONFIG ++ + config FIXED_PHY + tristate "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs" + depends on PHYLIB +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -23,6 +23,7 @@ obj-$(CONFIG_MVSWITCH_PHY) += mvswitch.o + obj-$(CONFIG_IP17XX_PHY) += ip17xx.o + obj-$(CONFIG_REALTEK_PHY) += realtek.o + obj-$(CONFIG_AR8216_PHY) += ar8216.o ar8327.o ++obj-$(CONFIG_RTL8306_PHY) += rtl8306.o + obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o + obj-$(CONFIG_FIXED_PHY) += fixed_phy.o + obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o diff --git a/target/linux/generic/patches-4.1/726-phy_rtl8366.patch b/target/linux/generic/patches-4.1/726-phy_rtl8366.patch new file mode 100644 index 0000000..83c7c4e --- /dev/null +++ b/target/linux/generic/patches-4.1/726-phy_rtl8366.patch @@ -0,0 +1,45 @@ +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -251,6 +251,30 @@ config MDIO_BCM_UNIMAC + controllers as well as some Broadcom Ethernet switches such as the + Starfighter 2 switches. + ++config RTL8366_SMI ++ tristate "Driver for the RTL8366 SMI interface" ++ depends on GPIOLIB ++ ---help--- ++ This module implements the SMI interface protocol which is used ++ by some RTL8366 ethernet switch devices via the generic GPIO API. ++ ++if RTL8366_SMI ++ ++config RTL8366_SMI_DEBUG_FS ++ bool "RTL8366 SMI interface debugfs support" ++ depends on DEBUG_FS ++ default n ++ ++config RTL8366S_PHY ++ tristate "Driver for the Realtek RTL8366S switch" ++ select SWCONFIG ++ ++config RTL8366RB_PHY ++ tristate "Driver for the Realtek RTL8366RB switch" ++ select SWCONFIG ++ ++endif # RTL8366_SMI ++ + endif # PHYLIB + + config MICREL_KS8995MA +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -24,6 +24,9 @@ obj-$(CONFIG_IP17XX_PHY) += ip17xx.o + obj-$(CONFIG_REALTEK_PHY) += realtek.o + obj-$(CONFIG_AR8216_PHY) += ar8216.o ar8327.o + obj-$(CONFIG_RTL8306_PHY) += rtl8306.o ++obj-$(CONFIG_RTL8366_SMI) += rtl8366_smi.o ++obj-$(CONFIG_RTL8366S_PHY) += rtl8366s.o ++obj-$(CONFIG_RTL8366RB_PHY) += rtl8366rb.o + obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o + obj-$(CONFIG_FIXED_PHY) += fixed_phy.o + obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o diff --git a/target/linux/generic/patches-4.1/727-phy-rtl8367.patch b/target/linux/generic/patches-4.1/727-phy-rtl8367.patch new file mode 100644 index 0000000..7e6b035 --- /dev/null +++ b/target/linux/generic/patches-4.1/727-phy-rtl8367.patch @@ -0,0 +1,23 @@ +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -273,6 +273,10 @@ config RTL8366RB_PHY + tristate "Driver for the Realtek RTL8366RB switch" + select SWCONFIG + ++config RTL8367_PHY ++ tristate "Driver for the Realtek RTL8367R/M switches" ++ select SWCONFIG ++ + endif # RTL8366_SMI + + endif # PHYLIB +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -27,6 +27,7 @@ obj-$(CONFIG_RTL8306_PHY) += rtl8306.o + obj-$(CONFIG_RTL8366_SMI) += rtl8366_smi.o + obj-$(CONFIG_RTL8366S_PHY) += rtl8366s.o + obj-$(CONFIG_RTL8366RB_PHY) += rtl8366rb.o ++obj-$(CONFIG_RTL8367_PHY) += rtl8367.o + obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o + obj-$(CONFIG_FIXED_PHY) += fixed_phy.o + obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o diff --git a/target/linux/generic/patches-4.1/728-phy-rtl8367b.patch b/target/linux/generic/patches-4.1/728-phy-rtl8367b.patch new file mode 100644 index 0000000..670168e --- /dev/null +++ b/target/linux/generic/patches-4.1/728-phy-rtl8367b.patch @@ -0,0 +1,23 @@ +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -277,6 +277,10 @@ config RTL8367_PHY + tristate "Driver for the Realtek RTL8367R/M switches" + select SWCONFIG + ++config RTL8367B_PHY ++ tristate "Driver fot the Realtek RTL8367R-VB switch" ++ select SWCONFIG ++ + endif # RTL8366_SMI + + endif # PHYLIB +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -28,6 +28,7 @@ obj-$(CONFIG_RTL8366_SMI) += rtl8366_smi + obj-$(CONFIG_RTL8366S_PHY) += rtl8366s.o + obj-$(CONFIG_RTL8366RB_PHY) += rtl8366rb.o + obj-$(CONFIG_RTL8367_PHY) += rtl8367.o ++obj-$(CONFIG_RTL8367B_PHY) += rtl8367b.o + obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o + obj-$(CONFIG_FIXED_PHY) += fixed_phy.o + obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o diff --git a/target/linux/generic/patches-4.1/729-phy-tantos.patch b/target/linux/generic/patches-4.1/729-phy-tantos.patch new file mode 100644 index 0000000..67b879f --- /dev/null +++ b/target/linux/generic/patches-4.1/729-phy-tantos.patch @@ -0,0 +1,21 @@ +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -288,3 +288,8 @@ endif # PHYLIB + config MICREL_KS8995MA + tristate "Micrel KS8995MA 5-ports 10/100 managed Ethernet switch" + depends on SPI ++ ++config PSB6970_PHY ++ tristate "Lantiq XWAY Tantos (PSB6970) Ethernet switch" ++ select SWCONFIG ++ select ETHERNET_PACKET_MANGLE +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -30,6 +30,7 @@ obj-$(CONFIG_RTL8366RB_PHY) += rtl8366rb + obj-$(CONFIG_RTL8367_PHY) += rtl8367.o + obj-$(CONFIG_RTL8367B_PHY) += rtl8367b.o + obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o ++obj-$(CONFIG_PSB6970_PHY) += psb6970.o + obj-$(CONFIG_FIXED_PHY) += fixed_phy.o + obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o + obj-$(CONFIG_MDIO_GPIO) += mdio-gpio.o diff --git a/target/linux/generic/patches-4.1/730-phy_b53.patch b/target/linux/generic/patches-4.1/730-phy_b53.patch new file mode 100644 index 0000000..bdcfba6 --- /dev/null +++ b/target/linux/generic/patches-4.1/730-phy_b53.patch @@ -0,0 +1,21 @@ +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -283,6 +283,8 @@ config RTL8367B_PHY + + endif # RTL8366_SMI + ++source "drivers/net/phy/b53/Kconfig" ++ + endif # PHYLIB + + config MICREL_KS8995MA +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -31,6 +31,7 @@ obj-$(CONFIG_RTL8367_PHY) += rtl8367.o + obj-$(CONFIG_RTL8367B_PHY) += rtl8367b.o + obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o + obj-$(CONFIG_PSB6970_PHY) += psb6970.o ++obj-$(CONFIG_B53) += b53/ + obj-$(CONFIG_FIXED_PHY) += fixed_phy.o + obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o + obj-$(CONFIG_MDIO_GPIO) += mdio-gpio.o diff --git a/target/linux/generic/patches-4.1/731-phy_mvswitch_3.10_compilation.patch b/target/linux/generic/patches-4.1/731-phy_mvswitch_3.10_compilation.patch new file mode 100644 index 0000000..2053bd2 --- /dev/null +++ b/target/linux/generic/patches-4.1/731-phy_mvswitch_3.10_compilation.patch @@ -0,0 +1,35 @@ +From e6a5abb9a02be0bceb4782d9f736bfb4ae217505 Mon Sep 17 00:00:00 2001 +From: Jonas Gorski +Date: Sat, 21 Sep 2013 13:56:51 +0200 +Subject: [PATCH] phy: mvswitch: fix 3.10 compilation + +Update to API changes in 3.10. + +Signed-off-by: Jonas Gorsi +--- + target/linux/generic/files/drivers/net/phy/mvswitch.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/drivers/net/phy/mvswitch.c ++++ b/drivers/net/phy/mvswitch.c +@@ -173,7 +173,7 @@ mvswitch_mangle_rx(struct net_device *de + if (vlan == -1) + return; + +- __vlan_hwaccel_put_tag(skb, vlan); ++ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan); + } + + +@@ -307,9 +307,9 @@ mvswitch_config_init(struct phy_device * + + #ifdef HEADER_MODE + dev->priv_flags |= IFF_NO_IP_ALIGN; +- dev->features |= NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_TX; ++ dev->features |= NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_TX; + #else +- dev->features |= NETIF_F_HW_VLAN_RX; ++ dev->features |= NETIF_F_HW_VLAN_CTAG_RX; + #endif + + return 0; diff --git a/target/linux/generic/patches-4.1/732-phy-ar8216-led-support.patch b/target/linux/generic/patches-4.1/732-phy-ar8216-led-support.patch new file mode 100644 index 0000000..e38cf78 --- /dev/null +++ b/target/linux/generic/patches-4.1/732-phy-ar8216-led-support.patch @@ -0,0 +1,13 @@ +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -153,6 +153,10 @@ config AR8216_PHY + select ETHERNET_PACKET_MANGLE + select SWCONFIG + ++config AR8216_PHY_LEDS ++ bool "Atheros AR8216 switch LED support" ++ depends on (AR8216_PHY && LEDS_CLASS) ++ + config RTL8306_PHY + tristate "Driver for Realtek RTL8306S switches" + select SWCONFIG diff --git a/target/linux/generic/patches-4.1/733-phy_mvsw61xx.patch b/target/linux/generic/patches-4.1/733-phy_mvsw61xx.patch new file mode 100644 index 0000000..b70326b --- /dev/null +++ b/target/linux/generic/patches-4.1/733-phy_mvsw61xx.patch @@ -0,0 +1,23 @@ +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -144,6 +144,10 @@ config MVSWITCH_PHY + tristate "Driver for Marvell 88E6060 switches" + select ETHERNET_PACKET_MANGLE + ++config MVSW61XX_PHY ++ tristate "Driver for Marvell 88E6171/6172 switches" ++ select SWCONFIG ++ + config IP17XX_PHY + tristate "Driver for IC+ IP17xx switches" + select SWCONFIG +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -20,6 +20,7 @@ obj-$(CONFIG_BCM87XX_PHY) += bcm87xx.o + obj-$(CONFIG_ICPLUS_PHY) += icplus.o + obj-$(CONFIG_ADM6996_PHY) += adm6996.o + obj-$(CONFIG_MVSWITCH_PHY) += mvswitch.o ++obj-$(CONFIG_MVSW61XX_PHY) += mvsw61xx.o + obj-$(CONFIG_IP17XX_PHY) += ip17xx.o + obj-$(CONFIG_REALTEK_PHY) += realtek.o + obj-$(CONFIG_AR8216_PHY) += ar8216.o ar8327.o diff --git a/target/linux/generic/patches-4.1/750-hostap_txpower.patch b/target/linux/generic/patches-4.1/750-hostap_txpower.patch new file mode 100644 index 0000000..768c80f --- /dev/null +++ b/target/linux/generic/patches-4.1/750-hostap_txpower.patch @@ -0,0 +1,154 @@ +--- a/drivers/net/wireless/hostap/hostap_ap.c ++++ b/drivers/net/wireless/hostap/hostap_ap.c +@@ -2403,13 +2403,13 @@ int prism2_ap_get_sta_qual(local_info_t + addr[count].sa_family = ARPHRD_ETHER; + memcpy(addr[count].sa_data, sta->addr, ETH_ALEN); + if (sta->last_rx_silence == 0) +- qual[count].qual = sta->last_rx_signal < 27 ? +- 0 : (sta->last_rx_signal - 27) * 92 / 127; ++ qual[count].qual = (sta->last_rx_signal - 156) == 0 ? ++ 0 : (sta->last_rx_signal - 156) * 92 / 64; + else +- qual[count].qual = sta->last_rx_signal - +- sta->last_rx_silence - 35; +- qual[count].level = HFA384X_LEVEL_TO_dBm(sta->last_rx_signal); +- qual[count].noise = HFA384X_LEVEL_TO_dBm(sta->last_rx_silence); ++ qual[count].qual = (sta->last_rx_signal - ++ sta->last_rx_silence) * 92 / 64; ++ qual[count].level = sta->last_rx_signal; ++ qual[count].noise = sta->last_rx_silence; + qual[count].updated = sta->last_rx_updated; + + sta->last_rx_updated = IW_QUAL_DBM; +@@ -2475,13 +2475,13 @@ int prism2_ap_translate_scan(struct net_ + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = IWEVQUAL; + if (sta->last_rx_silence == 0) +- iwe.u.qual.qual = sta->last_rx_signal < 27 ? +- 0 : (sta->last_rx_signal - 27) * 92 / 127; ++ iwe.u.qual.qual = (sta->last_rx_signal -156) == 0 ? ++ 0 : (sta->last_rx_signal - 156) * 92 / 64; + else +- iwe.u.qual.qual = sta->last_rx_signal - +- sta->last_rx_silence - 35; +- iwe.u.qual.level = HFA384X_LEVEL_TO_dBm(sta->last_rx_signal); +- iwe.u.qual.noise = HFA384X_LEVEL_TO_dBm(sta->last_rx_silence); ++ iwe.u.qual.qual = (sta->last_rx_signal - ++ sta->last_rx_silence) * 92 / 64; ++ iwe.u.qual.level = sta->last_rx_signal; ++ iwe.u.qual.noise = sta->last_rx_silence; + iwe.u.qual.updated = sta->last_rx_updated; + iwe.len = IW_EV_QUAL_LEN; + current_ev = iwe_stream_add_event(info, current_ev, end_buf, +--- a/drivers/net/wireless/hostap/hostap_config.h ++++ b/drivers/net/wireless/hostap/hostap_config.h +@@ -45,4 +45,9 @@ + */ + /* #define PRISM2_NO_STATION_MODES */ + ++/* Enable TX power Setting functions ++ * (min att = -128 , max att = 127) ++ */ ++#define RAW_TXPOWER_SETTING ++ + #endif /* HOSTAP_CONFIG_H */ +--- a/drivers/net/wireless/hostap/hostap.h ++++ b/drivers/net/wireless/hostap/hostap.h +@@ -90,6 +90,7 @@ extern const struct iw_handler_def hosta + extern const struct ethtool_ops prism2_ethtool_ops; + + int hostap_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); ++int hostap_restore_power(struct net_device *dev); + + + #endif /* HOSTAP_H */ +--- a/drivers/net/wireless/hostap/hostap_hw.c ++++ b/drivers/net/wireless/hostap/hostap_hw.c +@@ -928,6 +928,7 @@ static int hfa384x_set_rid(struct net_de + prism2_hw_reset(dev); + } + ++ hostap_restore_power(dev); + return res; + } + +--- a/drivers/net/wireless/hostap/hostap_info.c ++++ b/drivers/net/wireless/hostap/hostap_info.c +@@ -435,6 +435,11 @@ static void handle_info_queue_linkstatus + } + + /* Get BSSID if we have a valid AP address */ ++ ++ if ( val == HFA384X_LINKSTATUS_CONNECTED || ++ val == HFA384X_LINKSTATUS_DISCONNECTED ) ++ hostap_restore_power(local->dev); ++ + if (connected) { + netif_carrier_on(local->dev); + netif_carrier_on(local->ddev); +--- a/drivers/net/wireless/hostap/hostap_ioctl.c ++++ b/drivers/net/wireless/hostap/hostap_ioctl.c +@@ -1479,23 +1479,20 @@ static int prism2_txpower_hfa386x_to_dBm + val = 255; + + tmp = val; +- tmp >>= 2; + +- return -12 - tmp; ++ return tmp; + } + + static u16 prism2_txpower_dBm_to_hfa386x(int val) + { + signed char tmp; + +- if (val > 20) +- return 128; +- else if (val < -43) ++ if (val > 127) + return 127; ++ else if (val < -128) ++ return 128; + + tmp = val; +- tmp = -12 - tmp; +- tmp <<= 2; + + return (unsigned char) tmp; + } +@@ -4052,3 +4049,35 @@ int hostap_ioctl(struct net_device *dev, + + return ret; + } ++ ++/* BUG FIX: Restore power setting value when lost due to F/W bug */ ++ ++int hostap_restore_power(struct net_device *dev) ++{ ++ struct hostap_interface *iface = netdev_priv(dev); ++ local_info_t *local = iface->local; ++ ++ u16 val; ++ int ret = 0; ++ ++ if (local->txpower_type == PRISM2_TXPOWER_OFF) { ++ val = 0xff; /* use all standby and sleep modes */ ++ ret = local->func->cmd(dev, HFA384X_CMDCODE_WRITEMIF, ++ HFA386X_CR_A_D_TEST_MODES2, ++ &val, NULL); ++ } ++ ++#ifdef RAW_TXPOWER_SETTING ++ if (local->txpower_type == PRISM2_TXPOWER_FIXED) { ++ val = HFA384X_TEST_CFG_BIT_ALC; ++ local->func->cmd(dev, HFA384X_CMDCODE_TEST | ++ (HFA384X_TEST_CFG_BITS << 8), 0, &val, NULL); ++ val = prism2_txpower_dBm_to_hfa386x(local->txpower); ++ ret = (local->func->cmd(dev, HFA384X_CMDCODE_WRITEMIF, ++ HFA386X_CR_MANUAL_TX_POWER, &val, NULL)); ++ } ++#endif /* RAW_TXPOWER_SETTING */ ++ return (ret ? -EOPNOTSUPP : 0); ++} ++ ++EXPORT_SYMBOL(hostap_restore_power); diff --git a/target/linux/generic/patches-4.1/773-bgmac-add-srab-switch.patch b/target/linux/generic/patches-4.1/773-bgmac-add-srab-switch.patch new file mode 100644 index 0000000..ae7cb1c --- /dev/null +++ b/target/linux/generic/patches-4.1/773-bgmac-add-srab-switch.patch @@ -0,0 +1,72 @@ +Register switch connected to srab + +Signed-off-by: Hauke Mehrtens + +--- a/drivers/net/ethernet/broadcom/bgmac.c ++++ b/drivers/net/ethernet/broadcom/bgmac.c +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + #include + + static const struct bcma_device_id bgmac_bcma_tbl[] = { +@@ -1538,6 +1539,17 @@ static void bgmac_mii_unregister(struct + mdiobus_free(mii_bus); + } + ++static struct b53_platform_data bgmac_b53_pdata = { ++}; ++ ++static struct platform_device bgmac_b53_dev = { ++ .name = "b53-srab-switch", ++ .id = -1, ++ .dev = { ++ .platform_data = &bgmac_b53_pdata, ++ }, ++}; ++ + /************************************************** + * BCMA bus ops + **************************************************/ +@@ -1664,6 +1676,16 @@ static int bgmac_probe(struct bcma_devic + net_dev->hw_features = net_dev->features; + net_dev->vlan_features = net_dev->features; + ++ if ((ci->id == BCMA_CHIP_ID_BCM4707 || ++ ci->id == BCMA_CHIP_ID_BCM53018) && ++ !bgmac_b53_pdata.regs) { ++ bgmac_b53_pdata.regs = ioremap_nocache(0x18007000, 0x1000); ++ ++ err = platform_device_register(&bgmac_b53_dev); ++ if (!err) ++ bgmac->b53_device = &bgmac_b53_dev; ++ } ++ + err = register_netdev(bgmac->net_dev); + if (err) { + bgmac_err(bgmac, "Cannot register net device\n"); +@@ -1690,6 +1712,10 @@ static void bgmac_remove(struct bcma_dev + { + struct bgmac *bgmac = bcma_get_drvdata(core); + ++ if (bgmac->b53_device) ++ platform_device_unregister(&bgmac_b53_dev); ++ bgmac->b53_device = NULL; ++ + unregister_netdev(bgmac->net_dev); + bgmac_mii_unregister(bgmac); + netif_napi_del(&bgmac->napi); +--- a/drivers/net/ethernet/broadcom/bgmac.h ++++ b/drivers/net/ethernet/broadcom/bgmac.h +@@ -462,6 +462,9 @@ struct bgmac { + bool has_robosw; + + bool loopback; ++ ++ /* platform device for associated switch */ ++ struct platform_device *b53_device; + }; + + static inline u32 bgmac_read(struct bgmac *bgmac, u16 offset) diff --git a/target/linux/generic/patches-4.1/780-igb-Fix-Null-pointer-dereference-in-igb_reset_q_vect.patch b/target/linux/generic/patches-4.1/780-igb-Fix-Null-pointer-dereference-in-igb_reset_q_vect.patch new file mode 100644 index 0000000..2603d6c --- /dev/null +++ b/target/linux/generic/patches-4.1/780-igb-Fix-Null-pointer-dereference-in-igb_reset_q_vect.patch @@ -0,0 +1,40 @@ +From cb06d102327eadcd1bdc480bfd9f8876251d1007 Mon Sep 17 00:00:00 2001 +From: Christoph Paasch +Date: Fri, 21 Mar 2014 03:48:19 -0700 +Subject: [PATCH] igb: Fix Null-pointer dereference in igb_reset_q_vector + +When igb_set_interrupt_capability() calls +igb_reset_interrupt_capability() (e.g., because CONFIG_PCI_MSI is unset), +num_q_vectors has been set but no vector has yet been allocated. + +igb_reset_interrupt_capability() will then call igb_reset_q_vector, +which assumes that the vector is allocated. As this is not the case, we +are accessing a NULL-pointer. + +This patch fixes it by checking that q_vector is indeed different from +NULL. + +Fixes: 02ef6e1d0b0023 (igb: Fix queue allocation method to accommodate changing during runtime) +Cc: Carolyn Wyborny +Signed-off-by: Christoph Paasch +Tested-by: Jeff Pieper +Signed-off-by: Jeff Kirsher +--- + drivers/net/ethernet/intel/igb/igb_main.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/drivers/net/ethernet/intel/igb/igb_main.c ++++ b/drivers/net/ethernet/intel/igb/igb_main.c +@@ -1032,6 +1032,12 @@ static void igb_reset_q_vector(struct ig + if (!q_vector) + return; + ++ /* Coming from igb_set_interrupt_capability, the vectors are not yet ++ * allocated. So, q_vector is NULL so we should stop here. ++ */ ++ if (!q_vector) ++ return; ++ + if (q_vector->tx.ring) + adapter->tx_ring[q_vector->tx.ring->queue_index] = NULL; + diff --git a/target/linux/generic/patches-4.1/785-hso-support-0af0-9300.patch b/target/linux/generic/patches-4.1/785-hso-support-0af0-9300.patch new file mode 100644 index 0000000..621d08f --- /dev/null +++ b/target/linux/generic/patches-4.1/785-hso-support-0af0-9300.patch @@ -0,0 +1,25 @@ +--- a/drivers/net/usb/hso.c ++++ b/drivers/net/usb/hso.c +@@ -466,6 +466,7 @@ static const struct usb_device_id hso_id + {USB_DEVICE(0x0af0, 0x8900)}, + {USB_DEVICE(0x0af0, 0x9000)}, + {USB_DEVICE(0x0af0, 0x9200)}, /* Option GTM671WFS */ ++ {USB_DEVICE(0x0af0, 0x9300)}, /* GTM 66xxWFS */ + {USB_DEVICE(0x0af0, 0xd035)}, + {USB_DEVICE(0x0af0, 0xd055)}, + {USB_DEVICE(0x0af0, 0xd155)}, +--- a/drivers/usb/storage/unusual_devs.h ++++ b/drivers/usb/storage/unusual_devs.h +@@ -1330,6 +1330,12 @@ UNUSUAL_DEV( 0x0af0, 0x8304, 0x0000, 0x0 + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + 0 ), + ++UNUSUAL_DEV( 0x0af0, 0x9300, 0x0000, 0x0000, ++ "Option", ++ "Globetrotter 66xxWFS SD-Card", ++ USB_SC_DEVICE, USB_PR_DEVICE, NULL, ++ 0 ), ++ + UNUSUAL_DEV( 0x0af0, 0xc100, 0x0000, 0x0000, + "Option", + "GI 070x SD-Card", diff --git a/target/linux/generic/patches-4.1/810-pci_disable_common_quirks.patch b/target/linux/generic/patches-4.1/810-pci_disable_common_quirks.patch new file mode 100644 index 0000000..8f72637 --- /dev/null +++ b/target/linux/generic/patches-4.1/810-pci_disable_common_quirks.patch @@ -0,0 +1,51 @@ +--- a/drivers/pci/Kconfig ++++ b/drivers/pci/Kconfig +@@ -68,6 +68,12 @@ config XEN_PCIDEV_FRONTEND + The PCI device frontend driver allows the kernel to import arbitrary + PCI devices from a PCI backend to support PCI driver domains. + ++config PCI_DISABLE_COMMON_QUIRKS ++ bool "PCI disable common quirks" ++ depends on PCI ++ help ++ If you don't know what to do here, say N. ++ + config HT_IRQ + bool "Interrupts on hypertransport devices" + default y +--- a/drivers/pci/quirks.c ++++ b/drivers/pci/quirks.c +@@ -41,6 +41,7 @@ static void quirk_mmio_always_on(struct + DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_BRIDGE_HOST, 8, quirk_mmio_always_on); + ++#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS + /* The Mellanox Tavor device gives false positive parity errors + * Mark this device with a broken_parity_status, to allow + * PCI scanning code to "skip" this now blacklisted device. +@@ -2925,6 +2926,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_I + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x65f9, quirk_intel_mc_errata); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x65fa, quirk_intel_mc_errata); + ++#endif /* !CONFIG_PCI_DISABLE_COMMON_QUIRKS */ + + /* + * Ivytown NTB BAR sizes are misreported by the hardware due to an erratum. To +@@ -2981,6 +2983,8 @@ static void fixup_debug_report(struct pc + } + } + ++#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS ++ + /* + * Some BIOS implementations leave the Intel GPU interrupts enabled, + * even though no one is handling them (f.e. i915 driver is never loaded). +@@ -3015,6 +3019,8 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_IN + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x010a, disable_igfx_irq); + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0152, disable_igfx_irq); + ++#endif /* !CONFIG_PCI_DISABLE_COMMON_QUIRKS */ ++ + /* + * PCI devices which are on Intel chips can skip the 10ms delay + * before entering D3 mode. diff --git a/target/linux/generic/patches-4.1/811-pci_disable_usb_common_quirks.patch b/target/linux/generic/patches-4.1/811-pci_disable_usb_common_quirks.patch new file mode 100644 index 0000000..6de4f6b --- /dev/null +++ b/target/linux/generic/patches-4.1/811-pci_disable_usb_common_quirks.patch @@ -0,0 +1,101 @@ + +--- a/drivers/usb/host/pci-quirks.c ++++ b/drivers/usb/host/pci-quirks.c +@@ -97,6 +97,8 @@ struct amd_chipset_type { + u8 rev; + }; + ++#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS ++ + static struct amd_chipset_info { + struct pci_dev *nb_dev; + struct pci_dev *smbus_dev; +@@ -450,6 +452,10 @@ void usb_amd_dev_put(void) + } + EXPORT_SYMBOL_GPL(usb_amd_dev_put); + ++#endif /* CONFIG_PCI_DISABLE_COMMON_QUIRKS */ ++ ++#if IS_ENABLED(CONFIG_USB_UHCI_HCD) ++ + /* + * Make sure the controller is completely inactive, unable to + * generate interrupts or do DMA. +@@ -529,8 +535,17 @@ reset_needed: + uhci_reset_hc(pdev, base); + return 1; + } ++#else ++int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base) ++{ ++ return 0; ++} ++ ++#endif + EXPORT_SYMBOL_GPL(uhci_check_and_reset_hc); + ++#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS ++ + static inline int io_type_enabled(struct pci_dev *pdev, unsigned int mask) + { + u16 cmd; +@@ -1095,3 +1110,4 @@ static void quirk_usb_early_handoff(stru + } + DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_SERIAL_USB, 8, quirk_usb_early_handoff); ++#endif +--- a/drivers/usb/host/pci-quirks.h ++++ b/drivers/usb/host/pci-quirks.h +@@ -4,6 +4,9 @@ + #ifdef CONFIG_PCI + void uhci_reset_hc(struct pci_dev *pdev, unsigned long base); + int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base); ++#endif /* CONFIG_PCI */ ++ ++#if defined(CONFIG_PCI) && !defined(CONFIG_PCI_DISABLE_COMMON_QUIRKS) + int usb_amd_find_chipset_info(void); + int usb_hcd_amd_remote_wakeup_quirk(struct pci_dev *pdev); + bool usb_amd_hang_symptom_quirk(void); +@@ -16,11 +19,24 @@ void usb_disable_xhci_ports(struct pci_d + void sb800_prefetch(struct device *dev, int on); + #else + struct pci_dev; ++static inline int usb_amd_find_chipset_info(void) ++{ ++ return 0; ++} ++static inline bool usb_amd_hang_symptom_quirk(void) ++{ ++ return false; ++} ++static inline bool usb_amd_prefetch_quirk(void) ++{ ++ return false; ++} + static inline void usb_amd_quirk_pll_disable(void) {} + static inline void usb_amd_quirk_pll_enable(void) {} + static inline void usb_amd_dev_put(void) {} + static inline void usb_disable_xhci_ports(struct pci_dev *xhci_pdev) {} + static inline void sb800_prefetch(struct device *dev, int on) {} +-#endif /* CONFIG_PCI */ ++static inline void usb_enable_intel_xhci_ports(struct pci_dev *xhci_pdev) {} ++#endif + + #endif /* __LINUX_USB_PCI_QUIRKS_H */ +--- a/include/linux/usb/hcd.h ++++ b/include/linux/usb/hcd.h +@@ -447,7 +447,14 @@ extern int usb_hcd_pci_probe(struct pci_ + extern void usb_hcd_pci_remove(struct pci_dev *dev); + extern void usb_hcd_pci_shutdown(struct pci_dev *dev); + ++#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS + extern int usb_hcd_amd_remote_wakeup_quirk(struct pci_dev *dev); ++#else ++static inline int usb_hcd_amd_remote_wakeup_quirk(struct pci_dev *dev) ++{ ++ return 0; ++} ++#endif + + #ifdef CONFIG_PM + extern const struct dev_pm_ops usb_hcd_pci_pm_ops; diff --git a/target/linux/generic/patches-4.1/820-usb_add_usb_find_device_by_name.patch b/target/linux/generic/patches-4.1/820-usb_add_usb_find_device_by_name.patch new file mode 100644 index 0000000..906f0e2 --- /dev/null +++ b/target/linux/generic/patches-4.1/820-usb_add_usb_find_device_by_name.patch @@ -0,0 +1,84 @@ +--- a/drivers/usb/core/usb.c ++++ b/drivers/usb/core/usb.c +@@ -704,6 +704,71 @@ int __usb_get_extra_descriptor(char *buf + } + EXPORT_SYMBOL_GPL(__usb_get_extra_descriptor); + ++static struct usb_device *match_device_name(struct usb_device *dev, ++ const char *name) ++{ ++ struct usb_device *ret_dev = NULL; ++ struct usb_device *childdev = NULL; ++ int child; ++ ++ dev_dbg(&dev->dev, "check for name %s ...\n", name); ++ ++ /* see if this device matches */ ++ if (strcmp(dev_name(&dev->dev), name) == 0 ) { ++ dev_dbg(&dev->dev, "matched this device!\n"); ++ ret_dev = usb_get_dev(dev); ++ goto exit; ++ } ++ /* look through all of the children of this device */ ++ usb_hub_for_each_child(dev, child, childdev) { ++ if (childdev) { ++ usb_lock_device(childdev); ++ ret_dev = match_device_name(childdev, name); ++ usb_unlock_device(childdev); ++ if (ret_dev) ++ goto exit; ++ } ++ } ++exit: ++ return ret_dev; ++} ++ ++/** ++ * usb_find_device_by_name - find a specific usb device in the system ++ * @name: the name of the device to find ++ * ++ * Returns a pointer to a struct usb_device if such a specified usb ++ * device is present in the system currently. The usage count of the ++ * device will be incremented if a device is found. Make sure to call ++ * usb_put_dev() when the caller is finished with the device. ++ * ++ * If a device with the specified bus id is not found, NULL is returned. ++ */ ++struct usb_device *usb_find_device_by_name(const char *name) ++{ ++ struct list_head *buslist; ++ struct usb_bus *bus; ++ struct usb_device *dev = NULL; ++ ++ mutex_lock(&usb_bus_list_lock); ++ for (buslist = usb_bus_list.next; ++ buslist != &usb_bus_list; ++ buslist = buslist->next) { ++ bus = container_of(buslist, struct usb_bus, bus_list); ++ if (!bus->root_hub) ++ continue; ++ usb_lock_device(bus->root_hub); ++ dev = match_device_name(bus->root_hub, name); ++ usb_unlock_device(bus->root_hub); ++ if (dev) ++ goto exit; ++ } ++exit: ++ mutex_unlock(&usb_bus_list_lock); ++ return dev; ++} ++EXPORT_SYMBOL_GPL(usb_find_device_by_name); ++ + /** + * usb_alloc_coherent - allocate dma-consistent buffer for URB_NO_xxx_DMA_MAP + * @dev: device the buffer will be used with +--- a/include/linux/usb.h ++++ b/include/linux/usb.h +@@ -721,6 +721,7 @@ static inline bool usb_device_no_sg_cons + return udev && udev->bus && udev->bus->no_sg_constraint; + } + ++extern struct usb_device *usb_find_device_by_name(const char *name); + + /*-------------------------------------------------------------------------*/ + diff --git a/target/linux/generic/patches-4.1/830-ledtrig_morse.patch b/target/linux/generic/patches-4.1/830-ledtrig_morse.patch new file mode 100644 index 0000000..31b5781 --- /dev/null +++ b/target/linux/generic/patches-4.1/830-ledtrig_morse.patch @@ -0,0 +1,28 @@ +--- a/drivers/leds/trigger/Kconfig ++++ b/drivers/leds/trigger/Kconfig +@@ -108,4 +108,8 @@ config LEDS_TRIGGER_CAMERA + This enables direct flash/torch on/off by the driver, kernel space. + If unsure, say Y. + ++config LEDS_TRIGGER_MORSE ++ tristate "LED Morse Trigger" ++ depends on LEDS_TRIGGERS ++ + endif # LEDS_TRIGGERS +--- a/drivers/leds/Makefile ++++ b/drivers/leds/Makefile +@@ -65,3 +65,4 @@ obj-$(CONFIG_LEDS_DAC124S085) += leds-d + + # LED Triggers + obj-$(CONFIG_LEDS_TRIGGERS) += trigger/ ++obj-$(CONFIG_LEDS_TRIGGER_MORSE) += ledtrig-morse.o +--- a/drivers/leds/ledtrig-morse.c ++++ b/drivers/leds/ledtrig-morse.c +@@ -26,7 +26,6 @@ + #include + #include + #include +-#include + #include + #include + #include diff --git a/target/linux/generic/patches-4.1/831-ledtrig_netdev.patch b/target/linux/generic/patches-4.1/831-ledtrig_netdev.patch new file mode 100644 index 0000000..f2a5a2a --- /dev/null +++ b/target/linux/generic/patches-4.1/831-ledtrig_netdev.patch @@ -0,0 +1,60 @@ +--- a/drivers/leds/trigger/Kconfig ++++ b/drivers/leds/trigger/Kconfig +@@ -112,4 +112,11 @@ config LEDS_TRIGGER_MORSE + tristate "LED Morse Trigger" + depends on LEDS_TRIGGERS + ++config LEDS_TRIGGER_NETDEV ++ tristate "LED Netdev Trigger" ++ depends on NET && LEDS_TRIGGERS ++ help ++ This allows LEDs to be controlled by network device activity. ++ If unsure, say Y. ++ + endif # LEDS_TRIGGERS +--- a/drivers/leds/Makefile ++++ b/drivers/leds/Makefile +@@ -66,3 +66,4 @@ obj-$(CONFIG_LEDS_DAC124S085) += leds-d + # LED Triggers + obj-$(CONFIG_LEDS_TRIGGERS) += trigger/ + obj-$(CONFIG_LEDS_TRIGGER_MORSE) += ledtrig-morse.o ++obj-$(CONFIG_LEDS_TRIGGER_NETDEV) += ledtrig-netdev.o +--- a/drivers/leds/ledtrig-netdev.c ++++ b/drivers/leds/ledtrig-netdev.c +@@ -22,7 +22,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -254,7 +253,7 @@ static int netdev_trig_notify(struct not + unsigned long evt, + void *dv) + { +- struct net_device *dev = dv; ++ struct net_device *dev = netdev_notifier_info_to_dev((struct netdev_notifier_info *) dv); + struct led_netdev_data *trigger_data = container_of(nb, struct led_netdev_data, notifier); + + if (evt != NETDEV_UP && evt != NETDEV_DOWN && evt != NETDEV_CHANGE && evt != NETDEV_REGISTER && evt != NETDEV_UNREGISTER) +@@ -294,8 +293,9 @@ done: + static void netdev_trig_timer(unsigned long arg) + { + struct led_netdev_data *trigger_data = (struct led_netdev_data *)arg; +- const struct net_device_stats *dev_stats; ++ struct rtnl_link_stats64 *dev_stats; + unsigned new_activity; ++ struct rtnl_link_stats64 temp; + + write_lock(&trigger_data->lock); + +@@ -305,7 +305,7 @@ static void netdev_trig_timer(unsigned l + goto no_restart; + } + +- dev_stats = dev_get_stats(trigger_data->net_dev); ++ dev_stats = dev_get_stats(trigger_data->net_dev, &temp); + new_activity = + ((trigger_data->mode & MODE_TX) ? dev_stats->tx_packets : 0) + + ((trigger_data->mode & MODE_RX) ? dev_stats->rx_packets : 0); diff --git a/target/linux/generic/patches-4.1/832-ledtrig_usbdev.patch b/target/linux/generic/patches-4.1/832-ledtrig_usbdev.patch new file mode 100644 index 0000000..564aab5 --- /dev/null +++ b/target/linux/generic/patches-4.1/832-ledtrig_usbdev.patch @@ -0,0 +1,31 @@ +--- a/drivers/leds/trigger/Kconfig ++++ b/drivers/leds/trigger/Kconfig +@@ -119,4 +119,11 @@ config LEDS_TRIGGER_NETDEV + This allows LEDs to be controlled by network device activity. + If unsure, say Y. + ++config LEDS_TRIGGER_USBDEV ++ tristate "LED USB device Trigger" ++ depends on USB && LEDS_TRIGGERS ++ help ++ This allows LEDs to be controlled by the presence/activity of ++ an USB device. If unsure, say N. ++ + endif # LEDS_TRIGGERS +--- a/drivers/leds/Makefile ++++ b/drivers/leds/Makefile +@@ -67,3 +67,4 @@ obj-$(CONFIG_LEDS_DAC124S085) += leds-d + obj-$(CONFIG_LEDS_TRIGGERS) += trigger/ + obj-$(CONFIG_LEDS_TRIGGER_MORSE) += ledtrig-morse.o + obj-$(CONFIG_LEDS_TRIGGER_NETDEV) += ledtrig-netdev.o ++obj-$(CONFIG_LEDS_TRIGGER_USBDEV) += ledtrig-usbdev.o +--- a/drivers/leds/ledtrig-usbdev.c ++++ b/drivers/leds/ledtrig-usbdev.c +@@ -24,7 +24,6 @@ + #include + #include + #include +-#include + #include + #include + #include diff --git a/target/linux/generic/patches-4.1/834-ledtrig-libata.patch b/target/linux/generic/patches-4.1/834-ledtrig-libata.patch new file mode 100644 index 0000000..b794c46 --- /dev/null +++ b/target/linux/generic/patches-4.1/834-ledtrig-libata.patch @@ -0,0 +1,153 @@ +From 52cfd51cdf6a6e14d4fb270c6343abac3bac00f4 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Fri, 12 Dec 2014 13:38:33 +0100 +Subject: [PATCH] libata: add ledtrig support +To: linux-ide@vger.kernel.org, + Tejun Heo + +This adds a LED trigger for each ATA port indicating disk activity. + +As this is needed only on specific platforms (NAS SoCs and such), +these platforms should define ARCH_WANTS_LIBATA_LEDS if there +are boards with LED(s) intended to indicate ATA disk activity and +need the OS to take care of that. +In that way, if not selected, LED trigger support not will be +included in libata-core and both, codepaths and structures remain +untouched. + +Signed-off-by: Daniel Golle +--- + drivers/ata/Kconfig | 16 ++++++++++++++++ + drivers/ata/libata-core.c | 41 +++++++++++++++++++++++++++++++++++++++++ + include/linux/libata.h | 9 +++++++++ + 3 files changed, 66 insertions(+) + +--- a/drivers/ata/Kconfig ++++ b/drivers/ata/Kconfig +@@ -46,6 +46,22 @@ config ATA_VERBOSE_ERROR + + If unsure, say Y. + ++config ARCH_WANT_LIBATA_LEDS ++ bool ++ ++config ATA_LEDS ++ bool "support ATA port LED triggers" ++ depends on ARCH_WANT_LIBATA_LEDS ++ select NEW_LEDS ++ select LEDS_CLASS ++ select LEDS_TRIGGERS ++ default y ++ help ++ This option adds a LED trigger for each registered ATA port. ++ It is used to drive disk activity leds connected via GPIO. ++ ++ If unsure, say N. ++ + config ATA_ACPI + bool "ATA ACPI Support" + depends on ACPI && PCI +--- a/drivers/ata/libata-core.c ++++ b/drivers/ata/libata-core.c +@@ -728,6 +728,19 @@ u64 ata_tf_read_block(const struct ata_t + return block; + } + ++#ifdef CONFIG_ATA_LEDS ++#define LIBATA_BLINK_DELAY 20 /* ms */ ++static inline void ata_led_act(struct ata_port *ap) ++{ ++ unsigned long led_delay = LIBATA_BLINK_DELAY; ++ ++ if (unlikely(!ap->ledtrig)) ++ return; ++ ++ led_trigger_blink_oneshot(ap->ledtrig, &led_delay, &led_delay, 0); ++} ++#endif ++ + /** + * ata_build_rw_tf - Build ATA taskfile for given read/write request + * @tf: Target ATA taskfile +@@ -4789,6 +4802,9 @@ struct ata_queued_cmd *ata_qc_new_init(s + if (tag < 0) + return NULL; + } ++#ifdef CONFIG_ATA_LEDS ++ ata_led_act(ap); ++#endif + + qc = __ata_qc_from_tag(ap, tag); + qc->tag = tag; +@@ -5686,6 +5702,9 @@ struct ata_port *ata_port_alloc(struct a + ap->stats.unhandled_irq = 1; + ap->stats.idle_irq = 1; + #endif ++#ifdef CONFIG_ATA_LEDS ++ ap->ledtrig = kzalloc(sizeof(struct led_trigger), GFP_KERNEL); ++#endif + ata_sff_port_init(ap); + + return ap; +@@ -5707,6 +5726,12 @@ static void ata_host_release(struct devi + + kfree(ap->pmp_link); + kfree(ap->slave_link); ++#ifdef CONFIG_ATA_LEDS ++ if (ap->ledtrig) { ++ led_trigger_unregister(ap->ledtrig); ++ kfree(ap->ledtrig); ++ }; ++#endif + kfree(ap); + host->ports[i] = NULL; + } +@@ -6153,7 +6178,23 @@ int ata_host_register(struct ata_host *h + host->ports[i]->print_id = atomic_inc_return(&ata_print_id); + host->ports[i]->local_port_no = i + 1; + } ++#ifdef CONFIG_ATA_LEDS ++ for (i = 0; i < host->n_ports; i++) { ++ if (unlikely(!host->ports[i]->ledtrig)) ++ continue; + ++ snprintf(host->ports[i]->ledtrig_name, ++ sizeof(host->ports[i]->ledtrig_name), "ata%u", ++ host->ports[i]->print_id); ++ ++ host->ports[i]->ledtrig->name = host->ports[i]->ledtrig_name; ++ ++ if (led_trigger_register(host->ports[i]->ledtrig)) { ++ kfree(host->ports[i]->ledtrig); ++ host->ports[i]->ledtrig = NULL; ++ } ++ } ++#endif + /* Create associated sysfs transport objects */ + for (i = 0; i < host->n_ports; i++) { + rc = ata_tport_add(host->dev,host->ports[i]); +--- a/include/linux/libata.h ++++ b/include/linux/libata.h +@@ -38,6 +38,9 @@ + #include + #include + #include ++#ifdef CONFIG_ATA_LEDS ++#include ++#endif + + /* + * Define if arch has non-standard setup. This is a _PCI_ standard +@@ -876,6 +879,12 @@ struct ata_port { + #ifdef CONFIG_ATA_ACPI + struct ata_acpi_gtm __acpi_init_gtm; /* use ata_acpi_init_gtm() */ + #endif ++ ++#ifdef CONFIG_ATA_LEDS ++ struct led_trigger *ledtrig; ++ char ledtrig_name[8]; ++#endif ++ + /* owned by EH */ + u8 sector_buf[ATA_SECT_SIZE] ____cacheline_aligned; + }; diff --git a/target/linux/generic/patches-4.1/840-rtc7301.patch b/target/linux/generic/patches-4.1/840-rtc7301.patch new file mode 100644 index 0000000..148ccaa --- /dev/null +++ b/target/linux/generic/patches-4.1/840-rtc7301.patch @@ -0,0 +1,250 @@ +--- a/drivers/rtc/Kconfig ++++ b/drivers/rtc/Kconfig +@@ -1109,6 +1109,15 @@ config RTC_DRV_OPAL + This driver can also be built as a module. If so, the module + will be called rtc-opal. + ++config RTC_DRV_RTC7301 ++ tristate "Epson RTC-7301 SF/DG" ++ help ++ If you say Y here you will get support for the ++ Epson RTC-7301 SF/DG RTC chips. ++ ++ This driver can also be built as a module. If so, the module ++ will be called rtc-7301. ++ + comment "on-CPU RTC drivers" + + config RTC_DRV_DAVINCI +--- a/drivers/rtc/Makefile ++++ b/drivers/rtc/Makefile +@@ -121,6 +121,7 @@ obj-$(CONFIG_RTC_DRV_RP5C01) += rtc-rp5c + obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o + obj-$(CONFIG_RTC_DRV_RS5C348) += rtc-rs5c348.o + obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o ++obj-$(CONFIG_RTC_DRV_RTC7301) += rtc-rtc7301.o + obj-$(CONFIG_RTC_DRV_RV3029C2) += rtc-rv3029c2.o + obj-$(CONFIG_RTC_DRV_RX4581) += rtc-rx4581.o + obj-$(CONFIG_RTC_DRV_RX8025) += rtc-rx8025.o +--- /dev/null ++++ b/drivers/rtc/rtc-rtc7301.c +@@ -0,0 +1,219 @@ ++/* ++ * Driver for Epson RTC-7301SF/DG ++ * ++ * Copyright (C) 2009 Jose Vasconcellos ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define RTC_NAME "rtc7301" ++#define RTC_VERSION "0.1" ++ ++/* Epson RTC-7301 register addresses */ ++#define RTC7301_SEC 0x00 ++#define RTC7301_SEC10 0x01 ++#define RTC7301_MIN 0x02 ++#define RTC7301_MIN10 0x03 ++#define RTC7301_HOUR 0x04 ++#define RTC7301_HOUR10 0x05 ++#define RTC7301_WEEKDAY 0x06 ++#define RTC7301_DAY 0x07 ++#define RTC7301_DAY10 0x08 ++#define RTC7301_MON 0x09 ++#define RTC7301_MON10 0x0A ++#define RTC7301_YEAR 0x0B ++#define RTC7301_YEAR10 0x0C ++#define RTC7301_YEAR100 0x0D ++#define RTC7301_YEAR1000 0x0E ++#define RTC7301_CTRLREG 0x0F ++ ++static uint8_t __iomem *rtc7301_base; ++ ++#define read_reg(offset) (readb(rtc7301_base + offset) & 0xf) ++#define write_reg(offset, data) writeb(data, rtc7301_base + (offset)) ++ ++#define rtc7301_isbusy() (read_reg(RTC7301_CTRLREG) & 1) ++ ++static void rtc7301_init_settings(void) ++{ ++ int i; ++ ++ write_reg(RTC7301_CTRLREG, 2); ++ write_reg(RTC7301_YEAR1000, 2); ++ udelay(122); ++ ++ /* bank 1 */ ++ write_reg(RTC7301_CTRLREG, 6); ++ for (i=0; i<15; i++) ++ write_reg(i, 0); ++ ++ /* bank 2 */ ++ write_reg(RTC7301_CTRLREG, 14); ++ for (i=0; i<15; i++) ++ write_reg(i, 0); ++ write_reg(RTC7301_CTRLREG, 0); ++} ++ ++static int rtc7301_get_datetime(struct device *dev, struct rtc_time *dt) ++{ ++ int cnt; ++ uint8_t buf[16]; ++ ++ cnt = 0; ++ while (rtc7301_isbusy()) { ++ udelay(244); ++ if (cnt++ > 100) { ++ dev_err(dev, "%s: timeout error %x\n", __func__, rtc7301_base[RTC7301_CTRLREG]); ++ return -EIO; ++ } ++ } ++ ++ for (cnt=0; cnt<16; cnt++) ++ buf[cnt] = read_reg(cnt); ++ ++ if (buf[RTC7301_SEC10] & 8) { ++ dev_err(dev, "%s: RTC not set\n", __func__); ++ return -EINVAL; ++ } ++ ++ memset(dt, 0, sizeof(*dt)); ++ ++ dt->tm_sec = buf[RTC7301_SEC] + buf[RTC7301_SEC10]*10; ++ dt->tm_min = buf[RTC7301_MIN] + buf[RTC7301_MIN10]*10; ++ dt->tm_hour = buf[RTC7301_HOUR] + buf[RTC7301_HOUR10]*10; ++ ++ dt->tm_mday = buf[RTC7301_DAY] + buf[RTC7301_DAY10]*10; ++ dt->tm_mon = buf[RTC7301_MON] + buf[RTC7301_MON10]*10 - 1; ++ dt->tm_year = buf[RTC7301_YEAR] + buf[RTC7301_YEAR10]*10 + ++ buf[RTC7301_YEAR100]*100 + ++ ((buf[RTC7301_YEAR1000] & 3)*1000) - 1900; ++ ++ /* the rtc device may contain illegal values on power up ++ * according to the data sheet. make sure they are valid. ++ */ ++ ++ return rtc_valid_tm(dt); ++} ++ ++static int rtc7301_set_datetime(struct device *dev, struct rtc_time *dt) ++{ ++ int data; ++ ++ data = dt->tm_year + 1900; ++ if (data >= 2100 || data < 1900) ++ return -EINVAL; ++ ++ write_reg(RTC7301_CTRLREG, 2); ++ udelay(122); ++ ++ data = bin2bcd(dt->tm_sec); ++ write_reg(RTC7301_SEC, data); ++ write_reg(RTC7301_SEC10, (data >> 4)); ++ ++ data = bin2bcd(dt->tm_min); ++ write_reg(RTC7301_MIN, data ); ++ write_reg(RTC7301_MIN10, (data >> 4)); ++ ++ data = bin2bcd(dt->tm_hour); ++ write_reg(RTC7301_HOUR, data); ++ write_reg(RTC7301_HOUR10, (data >> 4)); ++ ++ data = bin2bcd(dt->tm_mday); ++ write_reg(RTC7301_DAY, data); ++ write_reg(RTC7301_DAY10, (data>> 4)); ++ ++ data = bin2bcd(dt->tm_mon + 1); ++ write_reg(RTC7301_MON, data); ++ write_reg(RTC7301_MON10, (data >> 4)); ++ ++ data = bin2bcd(dt->tm_year % 100); ++ write_reg(RTC7301_YEAR, data); ++ write_reg(RTC7301_YEAR10, (data >> 4)); ++ data = bin2bcd((1900 + dt->tm_year) / 100); ++ write_reg(RTC7301_YEAR100, data); ++ ++ data = bin2bcd(dt->tm_wday); ++ write_reg(RTC7301_WEEKDAY, data); ++ ++ write_reg(RTC7301_CTRLREG, 0); ++ ++ return 0; ++} ++ ++static const struct rtc_class_ops rtc7301_rtc_ops = { ++ .read_time = rtc7301_get_datetime, ++ .set_time = rtc7301_set_datetime, ++}; ++ ++static int rtc7301_probe(struct platform_device *pdev) ++{ ++ struct rtc_device *rtc; ++ struct resource *res; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) ++ return -ENOENT; ++ ++ rtc7301_base = ioremap_nocache(res->start, 0x1000 /*res->end - res->start + 1*/); ++ if (!rtc7301_base) ++ return -EINVAL; ++ ++ rtc = rtc_device_register(RTC_NAME, &pdev->dev, ++ &rtc7301_rtc_ops, THIS_MODULE); ++ if (IS_ERR(rtc)) { ++ iounmap(rtc7301_base); ++ return PTR_ERR(rtc); ++ } ++ ++ platform_set_drvdata(pdev, rtc); ++ ++ rtc7301_init_settings(); ++ return 0; ++} ++ ++static int rtc7301_remove(struct platform_device *pdev) ++{ ++ struct rtc_device *rtc = platform_get_drvdata(pdev); ++ ++ if (rtc) ++ rtc_device_unregister(rtc); ++ if (rtc7301_base) ++ iounmap(rtc7301_base); ++ return 0; ++} ++ ++static struct platform_driver rtc7301_driver = { ++ .driver = { ++ .name = RTC_NAME, ++ .owner = THIS_MODULE, ++ }, ++ .probe = rtc7301_probe, ++ .remove = rtc7301_remove, ++}; ++ ++static __init int rtc7301_init(void) ++{ ++ return platform_driver_register(&rtc7301_driver); ++} ++module_init(rtc7301_init); ++ ++static __exit void rtc7301_exit(void) ++{ ++ platform_driver_unregister(&rtc7301_driver); ++} ++module_exit(rtc7301_exit); ++ ++MODULE_DESCRIPTION("Epson 7301 RTC driver"); ++MODULE_AUTHOR("Jose Vasconcellos "); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:" RTC_NAME); ++MODULE_VERSION(RTC_VERSION); diff --git a/target/linux/generic/patches-4.1/841-rtc_pt7c4338.patch b/target/linux/generic/patches-4.1/841-rtc_pt7c4338.patch new file mode 100644 index 0000000..5de1b87 --- /dev/null +++ b/target/linux/generic/patches-4.1/841-rtc_pt7c4338.patch @@ -0,0 +1,247 @@ +--- a/drivers/rtc/Kconfig ++++ b/drivers/rtc/Kconfig +@@ -596,6 +596,15 @@ config RTC_DRV_S5M + This driver can also be built as a module. If so, the module + will be called rtc-s5m. + ++config RTC_DRV_PT7C4338 ++ tristate "Pericom Technology Inc. PT7C4338 RTC" ++ help ++ If you say yes here you get support for the Pericom Technology ++ Inc. PT7C4338 RTC chip. ++ ++ This driver can also be built as a module. If so, the module ++ will be called rtc-pt7c4338. ++ + endif # I2C + + comment "SPI RTC drivers" +--- a/drivers/rtc/Makefile ++++ b/drivers/rtc/Makefile +@@ -112,6 +112,7 @@ obj-$(CONFIG_RTC_DRV_PL030) += rtc-pl030 + obj-$(CONFIG_RTC_DRV_PL031) += rtc-pl031.o + obj-$(CONFIG_RTC_DRV_PM8XXX) += rtc-pm8xxx.o + obj-$(CONFIG_RTC_DRV_PS3) += rtc-ps3.o ++obj-$(CONFIG_RTC_DRV_PT7C4338) += rtc-pt7c4338.o + obj-$(CONFIG_RTC_DRV_PUV3) += rtc-puv3.o + obj-$(CONFIG_RTC_DRV_PXA) += rtc-pxa.o + obj-$(CONFIG_RTC_DRV_R9701) += rtc-r9701.o +--- /dev/null ++++ b/drivers/rtc/rtc-pt7c4338.c +@@ -0,0 +1,216 @@ ++/* ++ * Copyright 2010 Freescale Semiconductor, Inc. ++ * ++ * Author: Priyanka Jain ++ * ++ * 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 Date & Time support (no alarms) for PT7C4338 chip. ++ * ++ * This file is based on drivers/rtc/rtc-ds1307.c ++ * ++ * PT7C4338 chip is manufactured by Pericom Technology Inc. ++ * It is a serial real-time clock which provides ++ * 1)Low-power clock/calendar. ++ * 2)Programmable square-wave output. ++ * It has 56 bytes of nonvolatile RAM. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* RTC register addresses */ ++#define PT7C4338_REG_SECONDS 0x00 ++#define PT7C4338_REG_MINUTES 0x01 ++#define PT7C4338_REG_HOURS 0x02 ++#define PT7C4338_REG_AMPM 0x02 ++#define PT7C4338_REG_DAY 0x03 ++#define PT7C4338_REG_DATE 0x04 ++#define PT7C4338_REG_MONTH 0x05 ++#define PT7C4338_REG_YEAR 0x06 ++#define PT7C4338_REG_CTRL_STAT 0x07 ++ ++/* RTC second register address bit */ ++#define PT7C4338_SEC_BIT_CH 0x80 /*Clock Halt (in Register 0)*/ ++ ++/* RTC control and status register bits */ ++#define PT7C4338_CTRL_STAT_BIT_RS0 0x1 /*Rate select 0*/ ++#define PT7C4338_CTRL_STAT_BIT_RS1 0x2 /*Rate select 1*/ ++#define PT7C4338_CTRL_STAT_BIT_SQWE 0x10 /*Square Wave Enable*/ ++#define PT7C4338_CTRL_STAT_BIT_OSF 0x20 /*Oscillator Stop Flag*/ ++#define PT7C4338_CTRL_STAT_BIT_OUT 0x80 /*Output Level Control*/ ++ ++static const struct i2c_device_id pt7c4338_id[] = { ++ { "pt7c4338", 0 }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, pt7c4338_id); ++ ++struct pt7c4338{ ++ struct i2c_client *client; ++ struct rtc_device *rtc; ++}; ++ ++static int pt7c4338_read_time(struct device *dev, struct rtc_time *time) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ int ret; ++ u8 buf[7]; ++ u8 year, month, day, hour, minute, second; ++ u8 week, twelve_hr, am_pm; ++ ++ ret = i2c_smbus_read_i2c_block_data(client, ++ PT7C4338_REG_SECONDS, 7, buf); ++ if (ret < 0) ++ return ret; ++ if (ret < 7) ++ return -EIO; ++ ++ second = buf[0]; ++ minute = buf[1]; ++ hour = buf[2]; ++ week = buf[3]; ++ day = buf[4]; ++ month = buf[5]; ++ year = buf[6]; ++ ++ /* Extract additional information for AM/PM */ ++ twelve_hr = hour & 0x40; ++ am_pm = hour & 0x20; ++ ++ /* Write to rtc_time structure */ ++ time->tm_sec = bcd2bin(second & 0x7f); ++ time->tm_min = bcd2bin(minute & 0x7f); ++ if (twelve_hr) { ++ /* Convert to 24 hr */ ++ if (am_pm) ++ time->tm_hour = bcd2bin(hour & 0x10) + 12; ++ else ++ time->tm_hour = bcd2bin(hour & 0xBF); ++ } else { ++ time->tm_hour = bcd2bin(hour); ++ } ++ ++ time->tm_wday = bcd2bin(week & 0x07) - 1; ++ time->tm_mday = bcd2bin(day & 0x3f); ++ time->tm_mon = bcd2bin(month & 0x1F) - 1; ++ /* assume 20YY not 19YY */ ++ time->tm_year = bcd2bin(year) + 100; ++ ++ return 0; ++} ++ ++static int pt7c4338_set_time(struct device *dev, struct rtc_time *time) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ u8 buf[7]; ++ ++ /* Extract time from rtc_time and load into pt7c4338*/ ++ buf[0] = bin2bcd(time->tm_sec); ++ buf[1] = bin2bcd(time->tm_min); ++ buf[2] = bin2bcd(time->tm_hour); ++ buf[3] = bin2bcd(time->tm_wday + 1); /* Day of the week */ ++ buf[4] = bin2bcd(time->tm_mday); /* Date */ ++ buf[5] = bin2bcd(time->tm_mon + 1); ++ ++ /* assume 20YY not 19YY */ ++ if (time->tm_year >= 100) ++ buf[6] = bin2bcd(time->tm_year - 100); ++ else ++ buf[6] = bin2bcd(time->tm_year); ++ ++ return i2c_smbus_write_i2c_block_data(client, ++ PT7C4338_REG_SECONDS, 7, buf); ++} ++ ++static const struct rtc_class_ops pt7c4338_rtc_ops = { ++ .read_time = pt7c4338_read_time, ++ .set_time = pt7c4338_set_time, ++}; ++ ++static int pt7c4338_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct pt7c4338 *pt7c4338; ++ struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); ++ int ret; ++ ++ pt7c4338 = kzalloc(sizeof(struct pt7c4338), GFP_KERNEL); ++ if (!pt7c4338) ++ return -ENOMEM; ++ ++ pt7c4338->client = client; ++ i2c_set_clientdata(client, pt7c4338); ++ pt7c4338->rtc = rtc_device_register(client->name, &client->dev, ++ &pt7c4338_rtc_ops, THIS_MODULE); ++ if (IS_ERR(pt7c4338->rtc)) { ++ ret = PTR_ERR(pt7c4338->rtc); ++ dev_err(&client->dev, "unable to register the class device\n"); ++ goto out_free; ++ } ++ ++ return 0; ++out_free: ++ i2c_set_clientdata(client, NULL); ++ kfree(pt7c4338); ++ return ret; ++} ++ ++static int pt7c4338_remove(struct i2c_client *client) ++{ ++ struct pt7c4338 *pt7c4338 = i2c_get_clientdata(client); ++ ++ rtc_device_unregister(pt7c4338->rtc); ++ i2c_set_clientdata(client, NULL); ++ kfree(pt7c4338); ++ return 0; ++} ++ ++static struct i2c_driver pt7c4338_driver = { ++ .driver = { ++ .name = "rtc-pt7c4338", ++ .owner = THIS_MODULE, ++ }, ++ .probe = pt7c4338_probe, ++ .remove = pt7c4338_remove, ++ .id_table = pt7c4338_id, ++}; ++ ++static int __init pt7c4338_init(void) ++{ ++ return i2c_add_driver(&pt7c4338_driver); ++} ++ ++static void __exit pt7c4338_exit(void) ++{ ++ i2c_del_driver(&pt7c4338_driver); ++} ++ ++module_init(pt7c4338_init); ++module_exit(pt7c4338_exit); ++ ++MODULE_AUTHOR("Priyanka Jain "); ++MODULE_DESCRIPTION("pericom Technology Inc. PT7C4338 RTC Driver"); ++MODULE_LICENSE("GPL"); diff --git a/target/linux/generic/patches-4.1/861-04_spi_gpio_implement_spi_delay.patch b/target/linux/generic/patches-4.1/861-04_spi_gpio_implement_spi_delay.patch new file mode 100644 index 0000000..fc1b40c --- /dev/null +++ b/target/linux/generic/patches-4.1/861-04_spi_gpio_implement_spi_delay.patch @@ -0,0 +1,58 @@ +Implement the SPI-GPIO delay function for busses that need speed limitation. + +--mb + + + +--- a/drivers/spi/spi-gpio.c ++++ b/drivers/spi/spi-gpio.c +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -69,6 +70,7 @@ struct spi_gpio { + * #define SPI_MOSI_GPIO 120 + * #define SPI_SCK_GPIO 121 + * #define SPI_N_CHIPSEL 4 ++ * #undef NEED_SPIDELAY + * #include "spi-gpio.c" + */ + +@@ -76,6 +78,7 @@ struct spi_gpio { + #define DRIVER_NAME "spi_gpio" + + #define GENERIC_BITBANG /* vs tight inlines */ ++#define NEED_SPIDELAY 1 + + /* all functions referencing these symbols must define pdata */ + #define SPI_MISO_GPIO ((pdata)->miso) +@@ -126,12 +129,20 @@ static inline int getmiso(const struct s + #undef pdata + + /* +- * NOTE: this clocks "as fast as we can". It "should" be a function of the +- * requested device clock. Software overhead means we usually have trouble +- * reaching even one Mbit/sec (except when we can inline bitops), so for now +- * we'll just assume we never need additional per-bit slowdowns. ++ * NOTE: to clock "as fast as we can", set spi_device.max_speed_hz ++ * and spi_transfer.speed_hz to 0. ++ * Otherwise this is a function of the requested device clock. ++ * Software overhead means we usually have trouble ++ * reaching even one Mbit/sec (except when we can inline bitops). So on small ++ * embedded devices with fast SPI slaves you usually don't need a delay. + */ +-#define spidelay(nsecs) do {} while (0) ++static inline void spidelay(unsigned nsecs) ++{ ++#ifdef NEED_SPIDELAY ++ if (unlikely(nsecs)) ++ ndelay(nsecs); ++#endif /* NEED_SPIDELAY */ ++} + + #include "spi-bitbang-txrx.h" + diff --git a/target/linux/generic/patches-4.1/862-gpio_spi_driver.patch b/target/linux/generic/patches-4.1/862-gpio_spi_driver.patch new file mode 100644 index 0000000..be05938 --- /dev/null +++ b/target/linux/generic/patches-4.1/862-gpio_spi_driver.patch @@ -0,0 +1,373 @@ +THIS CODE IS DEPRECATED. + +Please use the new mainline SPI-GPIO driver, as of 2.6.29. + +--mb + + + +--- + drivers/spi/Kconfig | 9 + + drivers/spi/Makefile | 1 + drivers/spi/spi_gpio_old.c | 251 +++++++++++++++++++++++++++++++++++++++ + include/linux/spi/spi_gpio_old.h | 73 +++++++++++ + 4 files changed, 334 insertions(+) + +--- /dev/null ++++ b/include/linux/spi/spi_gpio_old.h +@@ -0,0 +1,73 @@ ++/* ++ * spi_gpio interface to platform code ++ * ++ * Copyright (c) 2008 Piotr Skamruk ++ * Copyright (c) 2008 Michael Buesch ++ * ++ * 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. ++ */ ++#ifndef _LINUX_SPI_SPI_GPIO ++#define _LINUX_SPI_SPI_GPIO ++ ++#include ++#include ++ ++ ++/** ++ * struct spi_gpio_platform_data - Data definitions for a SPI-GPIO device. ++ * ++ * This structure holds information about a GPIO-based SPI device. ++ * ++ * @pin_clk: The GPIO pin number of the CLOCK pin. ++ * ++ * @pin_miso: The GPIO pin number of the MISO pin. ++ * ++ * @pin_mosi: The GPIO pin number of the MOSI pin. ++ * ++ * @pin_cs: The GPIO pin number of the CHIPSELECT pin. ++ * ++ * @cs_activelow: If true, the chip is selected when the CS line is low. ++ * ++ * @no_spi_delay: If true, no delay is done in the lowlevel bitbanging. ++ * Note that doing no delay is not standards compliant, ++ * but it might be needed to speed up transfers on some ++ * slow embedded machines. ++ * ++ * @boardinfo_setup: This callback is called after the ++ * SPI master device was registered, but before the ++ * device is registered. ++ * @boardinfo_setup_data: Data argument passed to boardinfo_setup(). ++ */ ++struct spi_gpio_platform_data { ++ unsigned int pin_clk; ++ unsigned int pin_miso; ++ unsigned int pin_mosi; ++ unsigned int pin_cs; ++ bool cs_activelow; ++ bool no_spi_delay; ++ int (*boardinfo_setup)(struct spi_board_info *bi, ++ struct spi_master *master, ++ void *data); ++ void *boardinfo_setup_data; ++}; ++ ++/** ++ * SPI_GPIO_PLATDEV_NAME - The platform device name string. ++ * ++ * The name string that has to be used for platform_device_alloc ++ * when allocating a spi-gpio device. ++ */ ++#define SPI_GPIO_PLATDEV_NAME "spi-gpio" ++ ++/** ++ * spi_gpio_next_id - Get another platform device ID number. ++ * ++ * This returns the next platform device ID number that has to be used ++ * for platform_device_alloc. The ID is opaque and should not be used for ++ * anything else. ++ */ ++int spi_gpio_next_id(void); ++ ++#endif /* _LINUX_SPI_SPI_GPIO */ +--- /dev/null ++++ b/drivers/spi/spi_gpio_old.c +@@ -0,0 +1,251 @@ ++/* ++ * Bitbanging SPI bus driver using GPIO API ++ * ++ * Copyright (c) 2008 Piotr Skamruk ++ * Copyright (c) 2008 Michael Buesch ++ * ++ * based on spi_s3c2410_gpio.c ++ * Copyright (c) 2006 Ben Dooks ++ * Copyright (c) 2006 Simtec Electronics ++ * and on i2c-gpio.c ++ * Copyright (C) 2007 Atmel 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++struct spi_gpio { ++ struct spi_bitbang bitbang; ++ struct spi_gpio_platform_data *info; ++ struct platform_device *pdev; ++ struct spi_board_info bi; ++}; ++ ++ ++static inline struct spi_gpio *spidev_to_sg(struct spi_device *dev) ++{ ++ return dev->controller_data; ++} ++ ++static inline void setsck(struct spi_device *dev, int val) ++{ ++ struct spi_gpio *sp = spidev_to_sg(dev); ++ gpio_set_value(sp->info->pin_clk, val ? 1 : 0); ++} ++ ++static inline void setmosi(struct spi_device *dev, int val) ++{ ++ struct spi_gpio *sp = spidev_to_sg(dev); ++ gpio_set_value(sp->info->pin_mosi, val ? 1 : 0); ++} ++ ++static inline u32 getmiso(struct spi_device *dev) ++{ ++ struct spi_gpio *sp = spidev_to_sg(dev); ++ return gpio_get_value(sp->info->pin_miso) ? 1 : 0; ++} ++ ++static inline void do_spidelay(struct spi_device *dev, unsigned nsecs) ++{ ++ struct spi_gpio *sp = spidev_to_sg(dev); ++ ++ if (!sp->info->no_spi_delay) ++ ndelay(nsecs); ++} ++ ++#define spidelay(nsecs) do { \ ++ /* Steal the spi_device pointer from our caller. \ ++ * The bitbang-API should probably get fixed here... */ \ ++ do_spidelay(spi, nsecs); \ ++ } while (0) ++ ++#define EXPAND_BITBANG_TXRX ++#include "spi-bitbang-txrx.h" ++ ++static u32 spi_gpio_txrx_mode0(struct spi_device *spi, ++ unsigned nsecs, u32 word, u8 bits) ++{ ++ return bitbang_txrx_be_cpha0(spi, nsecs, 0, 0, word, bits); ++} ++ ++static u32 spi_gpio_txrx_mode1(struct spi_device *spi, ++ unsigned nsecs, u32 word, u8 bits) ++{ ++ return bitbang_txrx_be_cpha1(spi, nsecs, 0, 0, word, bits); ++} ++ ++static u32 spi_gpio_txrx_mode2(struct spi_device *spi, ++ unsigned nsecs, u32 word, u8 bits) ++{ ++ return bitbang_txrx_be_cpha0(spi, nsecs, 1, 0, word, bits); ++} ++ ++static u32 spi_gpio_txrx_mode3(struct spi_device *spi, ++ unsigned nsecs, u32 word, u8 bits) ++{ ++ return bitbang_txrx_be_cpha1(spi, nsecs, 1, 0, word, bits); ++} ++ ++static void spi_gpio_chipselect(struct spi_device *dev, int on) ++{ ++ struct spi_gpio *sp = spidev_to_sg(dev); ++ ++ if (sp->info->cs_activelow) ++ on = !on; ++ gpio_set_value(sp->info->pin_cs, on ? 1 : 0); ++} ++ ++static int spi_gpio_probe(struct platform_device *pdev) ++{ ++ struct spi_master *master; ++ struct spi_gpio_platform_data *pdata; ++ struct spi_gpio *sp; ++ struct spi_device *spidev; ++ int err; ++ ++ pdata = pdev->dev.platform_data; ++ if (!pdata) ++ return -ENXIO; ++ ++ err = -ENOMEM; ++ master = spi_alloc_master(&pdev->dev, sizeof(struct spi_gpio)); ++ if (!master) ++ goto err_alloc_master; ++ ++ sp = spi_master_get_devdata(master); ++ platform_set_drvdata(pdev, sp); ++ sp->info = pdata; ++ ++ err = gpio_request(pdata->pin_clk, "spi_clock"); ++ if (err) ++ goto err_request_clk; ++ err = gpio_request(pdata->pin_mosi, "spi_mosi"); ++ if (err) ++ goto err_request_mosi; ++ err = gpio_request(pdata->pin_miso, "spi_miso"); ++ if (err) ++ goto err_request_miso; ++ err = gpio_request(pdata->pin_cs, "spi_cs"); ++ if (err) ++ goto err_request_cs; ++ ++ sp->bitbang.master = spi_master_get(master); ++ sp->bitbang.master->bus_num = -1; ++ sp->bitbang.master->num_chipselect = 1; ++ sp->bitbang.chipselect = spi_gpio_chipselect; ++ sp->bitbang.txrx_word[SPI_MODE_0] = spi_gpio_txrx_mode0; ++ sp->bitbang.txrx_word[SPI_MODE_1] = spi_gpio_txrx_mode1; ++ sp->bitbang.txrx_word[SPI_MODE_2] = spi_gpio_txrx_mode2; ++ sp->bitbang.txrx_word[SPI_MODE_3] = spi_gpio_txrx_mode3; ++ ++ gpio_direction_output(pdata->pin_clk, 0); ++ gpio_direction_output(pdata->pin_mosi, 0); ++ gpio_direction_output(pdata->pin_cs, ++ pdata->cs_activelow ? 1 : 0); ++ gpio_direction_input(pdata->pin_miso); ++ ++ err = spi_bitbang_start(&sp->bitbang); ++ if (err) ++ goto err_no_bitbang; ++ err = pdata->boardinfo_setup(&sp->bi, master, ++ pdata->boardinfo_setup_data); ++ if (err) ++ goto err_bi_setup; ++ sp->bi.controller_data = sp; ++ spidev = spi_new_device(master, &sp->bi); ++ if (!spidev) ++ goto err_new_dev; ++ ++ return 0; ++ ++err_new_dev: ++err_bi_setup: ++ spi_bitbang_stop(&sp->bitbang); ++err_no_bitbang: ++ spi_master_put(sp->bitbang.master); ++ gpio_free(pdata->pin_cs); ++err_request_cs: ++ gpio_free(pdata->pin_miso); ++err_request_miso: ++ gpio_free(pdata->pin_mosi); ++err_request_mosi: ++ gpio_free(pdata->pin_clk); ++err_request_clk: ++ kfree(master); ++ ++err_alloc_master: ++ return err; ++} ++ ++static int spi_gpio_remove(struct platform_device *pdev) ++{ ++ struct spi_gpio *sp; ++ struct spi_gpio_platform_data *pdata; ++ ++ pdata = pdev->dev.platform_data; ++ sp = platform_get_drvdata(pdev); ++ ++ gpio_free(pdata->pin_clk); ++ gpio_free(pdata->pin_mosi); ++ gpio_free(pdata->pin_miso); ++ gpio_free(pdata->pin_cs); ++ spi_bitbang_stop(&sp->bitbang); ++ spi_master_put(sp->bitbang.master); ++ ++ return 0; ++} ++ ++static struct platform_driver spi_gpio_driver = { ++ .driver = { ++ .name = SPI_GPIO_PLATDEV_NAME, ++ .owner = THIS_MODULE, ++ }, ++ .probe = spi_gpio_probe, ++ .remove = spi_gpio_remove, ++}; ++ ++int spi_gpio_next_id(void) ++{ ++ static atomic_t counter = ATOMIC_INIT(-1); ++ ++ return atomic_inc_return(&counter); ++} ++EXPORT_SYMBOL(spi_gpio_next_id); ++ ++static int __init spi_gpio_init(void) ++{ ++ int err; ++ ++ err = platform_driver_register(&spi_gpio_driver); ++ if (err) ++ printk(KERN_ERR "spi-gpio: register failed: %d\n", err); ++ ++ return err; ++} ++module_init(spi_gpio_init); ++ ++static void __exit spi_gpio_exit(void) ++{ ++ platform_driver_unregister(&spi_gpio_driver); ++} ++module_exit(spi_gpio_exit); ++ ++MODULE_AUTHOR("Piot Skamruk "); ++MODULE_AUTHOR("Michael Buesch"); ++MODULE_DESCRIPTION("Platform independent GPIO bitbanging SPI driver"); ++MODULE_LICENSE("GPL v2"); +--- a/drivers/spi/Kconfig ++++ b/drivers/spi/Kconfig +@@ -242,6 +242,15 @@ config SPI_IMG_SPFI + This enables support for the SPFI master controller found on + IMG SoCs. + ++config SPI_GPIO_OLD ++ tristate "Old GPIO API based bitbanging SPI controller (DEPRECATED)" ++ depends on SPI_MASTER && GPIOLIB ++ select SPI_BITBANG ++ help ++ This code is deprecated. Please use the new mainline SPI-GPIO driver. ++ ++ If unsure, say N. ++ + config SPI_IMX + tristate "Freescale i.MX SPI controllers" + depends on ARCH_MXC || COMPILE_TEST +--- a/drivers/spi/Makefile ++++ b/drivers/spi/Makefile +@@ -41,6 +41,7 @@ obj-$(CONFIG_SPI_FSL_LIB) += spi-fsl-li + obj-$(CONFIG_SPI_FSL_ESPI) += spi-fsl-espi.o + obj-$(CONFIG_SPI_FSL_SPI) += spi-fsl-spi.o + obj-$(CONFIG_SPI_GPIO) += spi-gpio.o ++obj-$(CONFIG_SPI_GPIO_OLD) += spi_gpio_old.o + obj-$(CONFIG_SPI_IMG_SPFI) += spi-img-spfi.o + obj-$(CONFIG_SPI_IMX) += spi-imx.o + obj-$(CONFIG_SPI_LM70_LLP) += spi-lm70llp.o diff --git a/target/linux/generic/patches-4.1/863-gpiommc.patch b/target/linux/generic/patches-4.1/863-gpiommc.patch new file mode 100644 index 0000000..bd3cc84 --- /dev/null +++ b/target/linux/generic/patches-4.1/863-gpiommc.patch @@ -0,0 +1,844 @@ +--- /dev/null ++++ b/drivers/mmc/host/gpiommc.c +@@ -0,0 +1,609 @@ ++/* ++ * Driver an MMC/SD card on a bitbanging GPIO SPI bus. ++ * This module hooks up the mmc_spi and spi_gpio modules and also ++ * provides a configfs interface. ++ * ++ * Copyright 2008 Michael Buesch ++ * ++ * Licensed under the GNU/GPL. See COPYING for details. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#define PFX "gpio-mmc: " ++ ++ ++struct gpiommc_device { ++ struct platform_device *pdev; ++ struct platform_device *spi_pdev; ++ struct spi_board_info boardinfo; ++}; ++ ++ ++MODULE_DESCRIPTION("GPIO based MMC driver"); ++MODULE_AUTHOR("Michael Buesch"); ++MODULE_LICENSE("GPL"); ++ ++ ++static int gpiommc_boardinfo_setup(struct spi_board_info *bi, ++ struct spi_master *master, ++ void *data) ++{ ++ struct gpiommc_device *d = data; ++ struct gpiommc_platform_data *pdata = d->pdev->dev.platform_data; ++ ++ /* Bind the SPI master to the MMC-SPI host driver. */ ++ strlcpy(bi->modalias, "mmc_spi", sizeof(bi->modalias)); ++ ++ bi->max_speed_hz = pdata->max_bus_speed; ++ bi->bus_num = master->bus_num; ++ bi->mode = pdata->mode; ++ ++ return 0; ++} ++ ++static int gpiommc_probe(struct platform_device *pdev) ++{ ++ struct gpiommc_platform_data *mmc_pdata = pdev->dev.platform_data; ++ struct spi_gpio_platform_data spi_pdata; ++ struct gpiommc_device *d; ++ int err; ++ ++ err = -ENXIO; ++ if (!mmc_pdata) ++ goto error; ++ ++#ifdef CONFIG_MMC_SPI_MODULE ++ err = request_module("mmc_spi"); ++ if (err) { ++ printk(KERN_WARNING PFX ++ "Failed to request mmc_spi module.\n"); ++ } ++#endif /* CONFIG_MMC_SPI_MODULE */ ++ ++ /* Allocate the GPIO-MMC device */ ++ err = -ENOMEM; ++ d = kzalloc(sizeof(*d), GFP_KERNEL); ++ if (!d) ++ goto error; ++ d->pdev = pdev; ++ ++ /* Create the SPI-GPIO device */ ++ d->spi_pdev = platform_device_alloc(SPI_GPIO_PLATDEV_NAME, ++ spi_gpio_next_id()); ++ if (!d->spi_pdev) ++ goto err_free_d; ++ ++ memset(&spi_pdata, 0, sizeof(spi_pdata)); ++ spi_pdata.pin_clk = mmc_pdata->pins.gpio_clk; ++ spi_pdata.pin_miso = mmc_pdata->pins.gpio_do; ++ spi_pdata.pin_mosi = mmc_pdata->pins.gpio_di; ++ spi_pdata.pin_cs = mmc_pdata->pins.gpio_cs; ++ spi_pdata.cs_activelow = mmc_pdata->pins.cs_activelow; ++ spi_pdata.no_spi_delay = mmc_pdata->no_spi_delay; ++ spi_pdata.boardinfo_setup = gpiommc_boardinfo_setup; ++ spi_pdata.boardinfo_setup_data = d; ++ ++ err = platform_device_add_data(d->spi_pdev, &spi_pdata, ++ sizeof(spi_pdata)); ++ if (err) ++ goto err_free_pdev; ++ err = platform_device_add(d->spi_pdev); ++ if (err) ++ goto err_free_pdata; ++ platform_set_drvdata(pdev, d); ++ ++ printk(KERN_INFO PFX "MMC-Card \"%s\" " ++ "attached to GPIO pins di=%u, do=%u, clk=%u, cs=%u\n", ++ mmc_pdata->name, mmc_pdata->pins.gpio_di, ++ mmc_pdata->pins.gpio_do, ++ mmc_pdata->pins.gpio_clk, ++ mmc_pdata->pins.gpio_cs); ++ ++ return 0; ++ ++err_free_pdata: ++ kfree(d->spi_pdev->dev.platform_data); ++ d->spi_pdev->dev.platform_data = NULL; ++err_free_pdev: ++ platform_device_put(d->spi_pdev); ++err_free_d: ++ kfree(d); ++error: ++ return err; ++} ++ ++static int gpiommc_remove(struct platform_device *pdev) ++{ ++ struct gpiommc_device *d = platform_get_drvdata(pdev); ++ struct gpiommc_platform_data *pdata = d->pdev->dev.platform_data; ++ ++ platform_device_unregister(d->spi_pdev); ++ printk(KERN_INFO PFX "GPIO based MMC-Card \"%s\" removed\n", ++ pdata->name); ++ platform_device_put(d->spi_pdev); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_GPIOMMC_CONFIGFS ++ ++/* A device that was created through configfs */ ++struct gpiommc_configfs_device { ++ struct config_item item; ++ /* The platform device, after registration. */ ++ struct platform_device *pdev; ++ /* The configuration */ ++ struct gpiommc_platform_data pdata; ++}; ++ ++#define GPIO_INVALID -1 ++ ++static inline bool gpiommc_is_registered(struct gpiommc_configfs_device *dev) ++{ ++ return (dev->pdev != NULL); ++} ++ ++static inline struct gpiommc_configfs_device *ci_to_gpiommc(struct config_item *item) ++{ ++ return item ? container_of(item, struct gpiommc_configfs_device, item) : NULL; ++} ++ ++static struct configfs_attribute gpiommc_attr_DI = { ++ .ca_owner = THIS_MODULE, ++ .ca_name = "gpio_data_in", ++ .ca_mode = S_IRUGO | S_IWUSR, ++}; ++ ++static struct configfs_attribute gpiommc_attr_DO = { ++ .ca_owner = THIS_MODULE, ++ .ca_name = "gpio_data_out", ++ .ca_mode = S_IRUGO | S_IWUSR, ++}; ++ ++static struct configfs_attribute gpiommc_attr_CLK = { ++ .ca_owner = THIS_MODULE, ++ .ca_name = "gpio_clock", ++ .ca_mode = S_IRUGO | S_IWUSR, ++}; ++ ++static struct configfs_attribute gpiommc_attr_CS = { ++ .ca_owner = THIS_MODULE, ++ .ca_name = "gpio_chipselect", ++ .ca_mode = S_IRUGO | S_IWUSR, ++}; ++ ++static struct configfs_attribute gpiommc_attr_CS_activelow = { ++ .ca_owner = THIS_MODULE, ++ .ca_name = "gpio_chipselect_activelow", ++ .ca_mode = S_IRUGO | S_IWUSR, ++}; ++ ++static struct configfs_attribute gpiommc_attr_spimode = { ++ .ca_owner = THIS_MODULE, ++ .ca_name = "spi_mode", ++ .ca_mode = S_IRUGO | S_IWUSR, ++}; ++ ++static struct configfs_attribute gpiommc_attr_spidelay = { ++ .ca_owner = THIS_MODULE, ++ .ca_name = "spi_delay", ++ .ca_mode = S_IRUGO | S_IWUSR, ++}; ++ ++static struct configfs_attribute gpiommc_attr_max_bus_speed = { ++ .ca_owner = THIS_MODULE, ++ .ca_name = "max_bus_speed", ++ .ca_mode = S_IRUGO | S_IWUSR, ++}; ++ ++static struct configfs_attribute gpiommc_attr_register = { ++ .ca_owner = THIS_MODULE, ++ .ca_name = "register", ++ .ca_mode = S_IRUGO | S_IWUSR, ++}; ++ ++static struct configfs_attribute *gpiommc_config_attrs[] = { ++ &gpiommc_attr_DI, ++ &gpiommc_attr_DO, ++ &gpiommc_attr_CLK, ++ &gpiommc_attr_CS, ++ &gpiommc_attr_CS_activelow, ++ &gpiommc_attr_spimode, ++ &gpiommc_attr_spidelay, ++ &gpiommc_attr_max_bus_speed, ++ &gpiommc_attr_register, ++ NULL, ++}; ++ ++static ssize_t gpiommc_config_attr_show(struct config_item *item, ++ struct configfs_attribute *attr, ++ char *page) ++{ ++ struct gpiommc_configfs_device *dev = ci_to_gpiommc(item); ++ ssize_t count = 0; ++ unsigned int gpio; ++ int err = 0; ++ ++ if (attr == &gpiommc_attr_DI) { ++ gpio = dev->pdata.pins.gpio_di; ++ if (gpio == GPIO_INVALID) ++ count = snprintf(page, PAGE_SIZE, "not configured\n"); ++ else ++ count = snprintf(page, PAGE_SIZE, "%u\n", gpio); ++ goto out; ++ } ++ if (attr == &gpiommc_attr_DO) { ++ gpio = dev->pdata.pins.gpio_do; ++ if (gpio == GPIO_INVALID) ++ count = snprintf(page, PAGE_SIZE, "not configured\n"); ++ else ++ count = snprintf(page, PAGE_SIZE, "%u\n", gpio); ++ goto out; ++ } ++ if (attr == &gpiommc_attr_CLK) { ++ gpio = dev->pdata.pins.gpio_clk; ++ if (gpio == GPIO_INVALID) ++ count = snprintf(page, PAGE_SIZE, "not configured\n"); ++ else ++ count = snprintf(page, PAGE_SIZE, "%u\n", gpio); ++ goto out; ++ } ++ if (attr == &gpiommc_attr_CS) { ++ gpio = dev->pdata.pins.gpio_cs; ++ if (gpio == GPIO_INVALID) ++ count = snprintf(page, PAGE_SIZE, "not configured\n"); ++ else ++ count = snprintf(page, PAGE_SIZE, "%u\n", gpio); ++ goto out; ++ } ++ if (attr == &gpiommc_attr_CS_activelow) { ++ count = snprintf(page, PAGE_SIZE, "%u\n", ++ dev->pdata.pins.cs_activelow); ++ goto out; ++ } ++ if (attr == &gpiommc_attr_spimode) { ++ count = snprintf(page, PAGE_SIZE, "%u\n", ++ dev->pdata.mode); ++ goto out; ++ } ++ if (attr == &gpiommc_attr_spidelay) { ++ count = snprintf(page, PAGE_SIZE, "%u\n", ++ !dev->pdata.no_spi_delay); ++ goto out; ++ } ++ if (attr == &gpiommc_attr_max_bus_speed) { ++ count = snprintf(page, PAGE_SIZE, "%u\n", ++ dev->pdata.max_bus_speed); ++ goto out; ++ } ++ if (attr == &gpiommc_attr_register) { ++ count = snprintf(page, PAGE_SIZE, "%u\n", ++ gpiommc_is_registered(dev)); ++ goto out; ++ } ++ WARN_ON(1); ++ err = -ENOSYS; ++out: ++ return err ? err : count; ++} ++ ++static int gpiommc_do_register(struct gpiommc_configfs_device *dev, ++ const char *name) ++{ ++ int err; ++ ++ if (gpiommc_is_registered(dev)) ++ return 0; ++ ++ if (!gpio_is_valid(dev->pdata.pins.gpio_di) || ++ !gpio_is_valid(dev->pdata.pins.gpio_do) || ++ !gpio_is_valid(dev->pdata.pins.gpio_clk) || ++ !gpio_is_valid(dev->pdata.pins.gpio_cs)) { ++ printk(KERN_ERR PFX ++ "configfs: Invalid GPIO pin number(s)\n"); ++ return -EINVAL; ++ } ++ ++ strlcpy(dev->pdata.name, name, ++ sizeof(dev->pdata.name)); ++ ++ dev->pdev = platform_device_alloc(GPIOMMC_PLATDEV_NAME, ++ gpiommc_next_id()); ++ if (!dev->pdev) ++ return -ENOMEM; ++ err = platform_device_add_data(dev->pdev, &dev->pdata, ++ sizeof(dev->pdata)); ++ if (err) { ++ platform_device_put(dev->pdev); ++ return err; ++ } ++ err = platform_device_add(dev->pdev); ++ if (err) { ++ platform_device_put(dev->pdev); ++ return err; ++ } ++ ++ return 0; ++} ++ ++static void gpiommc_do_unregister(struct gpiommc_configfs_device *dev) ++{ ++ if (!gpiommc_is_registered(dev)) ++ return; ++ ++ platform_device_unregister(dev->pdev); ++ dev->pdev = NULL; ++} ++ ++static ssize_t gpiommc_config_attr_store(struct config_item *item, ++ struct configfs_attribute *attr, ++ const char *page, size_t count) ++{ ++ struct gpiommc_configfs_device *dev = ci_to_gpiommc(item); ++ int err = -EINVAL; ++ unsigned long data; ++ ++ if (attr == &gpiommc_attr_register) { ++ err = kstrtoul(page, 10, &data); ++ if (err) ++ goto out; ++ err = -EINVAL; ++ if (data == 1) ++ err = gpiommc_do_register(dev, item->ci_name); ++ if (data == 0) { ++ gpiommc_do_unregister(dev); ++ err = 0; ++ } ++ goto out; ++ } ++ ++ if (gpiommc_is_registered(dev)) { ++ /* The rest of the config parameters can only be set ++ * as long as the device is not registered, yet. */ ++ err = -EBUSY; ++ goto out; ++ } ++ ++ if (attr == &gpiommc_attr_DI) { ++ err = kstrtoul(page, 10, &data); ++ if (err) ++ goto out; ++ err = -EINVAL; ++ if (!gpio_is_valid(data)) ++ goto out; ++ dev->pdata.pins.gpio_di = data; ++ err = 0; ++ goto out; ++ } ++ if (attr == &gpiommc_attr_DO) { ++ err = kstrtoul(page, 10, &data); ++ if (err) ++ goto out; ++ err = -EINVAL; ++ if (!gpio_is_valid(data)) ++ goto out; ++ dev->pdata.pins.gpio_do = data; ++ err = 0; ++ goto out; ++ } ++ if (attr == &gpiommc_attr_CLK) { ++ err = kstrtoul(page, 10, &data); ++ if (err) ++ goto out; ++ err = -EINVAL; ++ if (!gpio_is_valid(data)) ++ goto out; ++ dev->pdata.pins.gpio_clk = data; ++ err = 0; ++ goto out; ++ } ++ if (attr == &gpiommc_attr_CS) { ++ err = kstrtoul(page, 10, &data); ++ if (err) ++ goto out; ++ err = -EINVAL; ++ if (!gpio_is_valid(data)) ++ goto out; ++ dev->pdata.pins.gpio_cs = data; ++ err = 0; ++ goto out; ++ } ++ if (attr == &gpiommc_attr_CS_activelow) { ++ err = kstrtoul(page, 10, &data); ++ if (err) ++ goto out; ++ err = -EINVAL; ++ if (data != 0 && data != 1) ++ goto out; ++ dev->pdata.pins.cs_activelow = data; ++ err = 0; ++ goto out; ++ } ++ if (attr == &gpiommc_attr_spimode) { ++ err = kstrtoul(page, 10, &data); ++ if (err) ++ goto out; ++ err = -EINVAL; ++ switch (data) { ++ case 0: ++ dev->pdata.mode = SPI_MODE_0; ++ break; ++ case 1: ++ dev->pdata.mode = SPI_MODE_1; ++ break; ++ case 2: ++ dev->pdata.mode = SPI_MODE_2; ++ break; ++ case 3: ++ dev->pdata.mode = SPI_MODE_3; ++ break; ++ default: ++ goto out; ++ } ++ err = 0; ++ goto out; ++ } ++ if (attr == &gpiommc_attr_spidelay) { ++ err = kstrtoul(page, 10, &data); ++ if (err) ++ goto out; ++ err = -EINVAL; ++ if (data != 0 && data != 1) ++ goto out; ++ dev->pdata.no_spi_delay = !data; ++ err = 0; ++ goto out; ++ } ++ if (attr == &gpiommc_attr_max_bus_speed) { ++ err = kstrtoul(page, 10, &data); ++ if (err) ++ goto out; ++ err = -EINVAL; ++ if (data > UINT_MAX) ++ goto out; ++ dev->pdata.max_bus_speed = data; ++ err = 0; ++ goto out; ++ } ++ WARN_ON(1); ++ err = -ENOSYS; ++out: ++ return err ? err : count; ++} ++ ++static void gpiommc_config_item_release(struct config_item *item) ++{ ++ struct gpiommc_configfs_device *dev = ci_to_gpiommc(item); ++ ++ kfree(dev); ++} ++ ++static struct configfs_item_operations gpiommc_config_item_ops = { ++ .release = gpiommc_config_item_release, ++ .show_attribute = gpiommc_config_attr_show, ++ .store_attribute = gpiommc_config_attr_store, ++}; ++ ++static struct config_item_type gpiommc_dev_ci_type = { ++ .ct_item_ops = &gpiommc_config_item_ops, ++ .ct_attrs = gpiommc_config_attrs, ++ .ct_owner = THIS_MODULE, ++}; ++ ++static struct config_item *gpiommc_make_item(struct config_group *group, ++ const char *name) ++{ ++ struct gpiommc_configfs_device *dev; ++ ++ if (strlen(name) > GPIOMMC_MAX_NAMELEN) { ++ printk(KERN_ERR PFX "configfs: device name too long\n"); ++ return NULL; ++ } ++ ++ dev = kzalloc(sizeof(*dev), GFP_KERNEL); ++ if (!dev) ++ return NULL; ++ ++ config_item_init_type_name(&dev->item, name, ++ &gpiommc_dev_ci_type); ++ ++ /* Assign default configuration */ ++ dev->pdata.pins.gpio_di = GPIO_INVALID; ++ dev->pdata.pins.gpio_do = GPIO_INVALID; ++ dev->pdata.pins.gpio_clk = GPIO_INVALID; ++ dev->pdata.pins.gpio_cs = GPIO_INVALID; ++ dev->pdata.pins.cs_activelow = 1; ++ dev->pdata.mode = SPI_MODE_0; ++ dev->pdata.no_spi_delay = 0; ++ dev->pdata.max_bus_speed = 5000000; /* 5 MHz */ ++ ++ return &(dev->item); ++} ++ ++static void gpiommc_drop_item(struct config_group *group, ++ struct config_item *item) ++{ ++ struct gpiommc_configfs_device *dev = ci_to_gpiommc(item); ++ ++ gpiommc_do_unregister(dev); ++ kfree(dev); ++} ++ ++static struct configfs_group_operations gpiommc_ct_group_ops = { ++ .make_item = gpiommc_make_item, ++ .drop_item = gpiommc_drop_item, ++}; ++ ++static struct config_item_type gpiommc_ci_type = { ++ .ct_group_ops = &gpiommc_ct_group_ops, ++ .ct_owner = THIS_MODULE, ++}; ++ ++static struct configfs_subsystem gpiommc_subsys = { ++ .su_group = { ++ .cg_item = { ++ .ci_namebuf = GPIOMMC_PLATDEV_NAME, ++ .ci_type = &gpiommc_ci_type, ++ }, ++ }, ++ .su_mutex = __MUTEX_INITIALIZER(gpiommc_subsys.su_mutex), ++}; ++ ++#endif /* CONFIG_GPIOMMC_CONFIGFS */ ++ ++static struct platform_driver gpiommc_plat_driver = { ++ .probe = gpiommc_probe, ++ .remove = gpiommc_remove, ++ .driver = { ++ .name = GPIOMMC_PLATDEV_NAME, ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++int gpiommc_next_id(void) ++{ ++ static atomic_t counter = ATOMIC_INIT(-1); ++ ++ return atomic_inc_return(&counter); ++} ++EXPORT_SYMBOL(gpiommc_next_id); ++ ++static int __init gpiommc_modinit(void) ++{ ++ int err; ++ ++ err = platform_driver_register(&gpiommc_plat_driver); ++ if (err) ++ return err; ++ ++#ifdef CONFIG_GPIOMMC_CONFIGFS ++ config_group_init(&gpiommc_subsys.su_group); ++ err = configfs_register_subsystem(&gpiommc_subsys); ++ if (err) { ++ platform_driver_unregister(&gpiommc_plat_driver); ++ return err; ++ } ++#endif /* CONFIG_GPIOMMC_CONFIGFS */ ++ ++ return 0; ++} ++module_init(gpiommc_modinit); ++ ++static void __exit gpiommc_modexit(void) ++{ ++#ifdef CONFIG_GPIOMMC_CONFIGFS ++ configfs_unregister_subsystem(&gpiommc_subsys); ++#endif ++ platform_driver_unregister(&gpiommc_plat_driver); ++} ++module_exit(gpiommc_modexit); +--- a/drivers/mmc/host/Kconfig ++++ b/drivers/mmc/host/Kconfig +@@ -556,6 +556,31 @@ config MMC_SDHI + This provides support for the SDHI SD/SDIO controller found in + SuperH and ARM SH-Mobile SoCs + ++config GPIOMMC ++ tristate "MMC/SD over GPIO-based SPI" ++ depends on MMC && MMC_SPI && SPI_GPIO_OLD ++ help ++ This driver hooks up the mmc_spi and spi_gpio modules so that ++ MMC/SD cards can be used on a GPIO based bus by bitbanging ++ the SPI protocol in software. ++ ++ This driver provides a configfs interface to dynamically create ++ and destroy GPIO-based MMC/SD card devices. It also provides ++ a platform device interface API. ++ See Documentation/gpiommc.txt for details. ++ ++ The module will be called gpiommc. ++ ++ If unsure, say N. ++ ++config GPIOMMC_CONFIGFS ++ bool ++ depends on GPIOMMC && CONFIGFS_FS ++ default y ++ help ++ This option automatically enables configfs support for gpiommc ++ if configfs is available. ++ + config MMC_CB710 + tristate "ENE CB710 MMC/SD Interface support" + depends on PCI +--- a/drivers/mmc/host/Makefile ++++ b/drivers/mmc/host/Makefile +@@ -40,6 +40,7 @@ tmio_mmc_core-$(subst m,y,$(CONFIG_MMC_S + obj-$(CONFIG_MMC_SDHI) += sh_mobile_sdhi.o + obj-$(CONFIG_MMC_CB710) += cb710-mmc.o + obj-$(CONFIG_MMC_VIA_SDMMC) += via-sdmmc.o ++obj-$(CONFIG_GPIOMMC) += gpiommc.o + obj-$(CONFIG_SDH_BFIN) += bfin_sdh.o + obj-$(CONFIG_MMC_DW) += dw_mmc.o + obj-$(CONFIG_MMC_DW_PLTFM) += dw_mmc-pltfm.o +--- /dev/null ++++ b/include/linux/mmc/gpiommc.h +@@ -0,0 +1,71 @@ ++/* ++ * Device driver for MMC/SD cards driven over a GPIO bus. ++ * ++ * Copyright (c) 2008 Michael Buesch ++ * ++ * Licensed under the GNU/GPL version 2. ++ */ ++#ifndef LINUX_GPIOMMC_H_ ++#define LINUX_GPIOMMC_H_ ++ ++#include ++ ++ ++#define GPIOMMC_MAX_NAMELEN 15 ++#define GPIOMMC_MAX_NAMELEN_STR __stringify(GPIOMMC_MAX_NAMELEN) ++ ++/** ++ * struct gpiommc_pins - Hardware pin assignments ++ * ++ * @gpio_di: The GPIO number of the DATA IN pin ++ * @gpio_do: The GPIO number of the DATA OUT pin ++ * @gpio_clk: The GPIO number of the CLOCK pin ++ * @gpio_cs: The GPIO number of the CHIPSELECT pin ++ * @cs_activelow: If true, the chip is considered selected if @gpio_cs is low. ++ */ ++struct gpiommc_pins { ++ unsigned int gpio_di; ++ unsigned int gpio_do; ++ unsigned int gpio_clk; ++ unsigned int gpio_cs; ++ bool cs_activelow; ++}; ++ ++/** ++ * struct gpiommc_platform_data - Platform data for a MMC-over-SPI-GPIO device. ++ * ++ * @name: The unique name string of the device. ++ * @pins: The hardware pin assignments. ++ * @mode: The hardware mode. This is either SPI_MODE_0, ++ * SPI_MODE_1, SPI_MODE_2 or SPI_MODE_3. See the SPI documentation. ++ * @no_spi_delay: Do not use delays in the lowlevel SPI bitbanging code. ++ * This is not standards compliant, but may be required for some ++ * embedded machines to gain reasonable speed. ++ * @max_bus_speed: The maximum speed of the SPI bus, in Hertz. ++ */ ++struct gpiommc_platform_data { ++ char name[GPIOMMC_MAX_NAMELEN + 1]; ++ struct gpiommc_pins pins; ++ u8 mode; ++ bool no_spi_delay; ++ unsigned int max_bus_speed; ++}; ++ ++/** ++ * GPIOMMC_PLATDEV_NAME - The platform device name string. ++ * ++ * The name string that has to be used for platform_device_alloc ++ * when allocating a gpiommc device. ++ */ ++#define GPIOMMC_PLATDEV_NAME "gpiommc" ++ ++/** ++ * gpiommc_next_id - Get another platform device ID number. ++ * ++ * This returns the next platform device ID number that has to be used ++ * for platform_device_alloc. The ID is opaque and should not be used for ++ * anything else. ++ */ ++int gpiommc_next_id(void); ++ ++#endif /* LINUX_GPIOMMC_H_ */ +--- /dev/null ++++ b/Documentation/gpiommc.txt +@@ -0,0 +1,97 @@ ++GPIOMMC - Driver for an MMC/SD card on a bitbanging GPIO SPI bus ++================================================================ ++ ++The gpiommc module hooks up the mmc_spi and spi_gpio modules for running an ++MMC or SD card on GPIO pins. ++ ++Two interfaces for registering a new MMC/SD card device are provided: ++A static platform-device based mechanism and a dynamic configfs based interface. ++ ++ ++Registering devices via platform-device ++======================================= ++ ++The platform-device interface is used for registering MMC/SD devices that are ++part of the hardware platform. This is most useful only for embedded machines ++with MMC/SD devices statically connected to the platform GPIO bus. ++ ++The data structures are declared in . ++ ++To register a new device, define an instance of struct gpiommc_platform_data. ++This structure holds any information about how the device is hooked up to the ++GPIO pins and what hardware modes the device supports. See the docbook-style ++documentation in the header file for more information on the struct fields. ++ ++Then allocate a new instance of a platform device by doing: ++ ++ pdev = platform_device_alloc(GPIOMMC_PLATDEV_NAME, gpiommc_next_id()); ++ ++This will allocate the platform device data structures and hook it up to the ++gpiommc driver. ++Then add the gpiommc_platform_data to the platform device. ++ ++ err = platform_device_add_data(pdev, pdata, sizeof(struct gpiommc_platform_data)); ++ ++You may free the local instance of struct gpiommc_platform_data now. (So the ++struct may be allocated on the stack, too). ++Now simply register the platform device. ++ ++ err = platform_device_add(pdev); ++ ++Done. The gpiommc probe routine will be invoked now and you should see a kernel ++log message for the added device. ++ ++ ++Registering devices via configfs ++================================ ++ ++MMC/SD cards connected via GPIO often are a pretty dynamic thing, as for example ++selfmade hacks for soldering an MMC/SD card to standard GPIO pins on embedded ++hardware are a common situation. ++So we provide a dynamic interface to conveniently handle adding and removing ++devices from userspace, without the need to recompile the kernel. ++ ++The "gpiommc" subdirectory at the configfs mountpoint is used for handling ++the dynamic configuration. ++ ++To create a new device, it must first be allocated with mkdir. ++The following command will allocate a device named "my_mmc": ++ mkdir /config/gpiommc/my_mmc ++ ++There are several configuration files available in the new ++/config/gpiommc/my_mmc/ directory: ++ ++gpio_data_in = The SPI data-IN GPIO pin number. ++gpio_data_out = The SPI data-OUT GPIO pin number. ++gpio_clock = The SPI Clock GPIO pin number. ++gpio_chipselect = The SPI Chipselect GPIO pin number. ++gpio_chipselect_activelow = Boolean. If 0, Chipselect is active-HIGH. ++ If 1, Chipselect is active-LOW. ++spi_mode = The SPI data mode. Can be 0-3. ++spi_delay = Enable all delays in the lowlevel bitbanging. ++max_bus_speed = The maximum SPI bus speed. In Hertz. ++ ++register = Not a configuration parameter. ++ Used to register the configured card ++ with the kernel. ++ ++The device must first get configured and then registered by writing "1" to ++the "register" file. ++The configuration parameters "gpio_data_in", "gpio_data_out", "gpio_clock" ++and "gpio_chipselect" are essential and _must_ be configured before writing ++"1" to the "register" file. The registration will fail, otherwise. ++ ++The default values for the other parameters are: ++gpio_chipselect_activelow = 1 (CS active-LOW) ++spi_mode = 0 (SPI_MODE_0) ++spi_delay = 1 (enabled) ++max_bus_speed = 5000000 (5 Mhz) ++ ++Configuration values can not be changed after registration. To unregister ++the device, write a "0" to the "register" file. The configuration can be ++changed again after unregistering. ++ ++To completely remove the device, simply rmdir the directory ++(/config/gpiommc/my_mmc in this example). ++There's no need to first unregister the device before removing it. That will ++be done automatically. +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -4531,6 +4531,11 @@ T: git git://linuxtv.org/anttip/media_tr + S: Maintained + F: drivers/media/usb/hackrf/ + ++GPIOMMC DRIVER ++P: Michael Buesch ++M: mb@bu3sch.de ++S: Maintained ++ + HARDWARE MONITORING + M: Jean Delvare + M: Guenter Roeck diff --git a/target/linux/generic/patches-4.1/864-gpiommc_configfs_locking.patch b/target/linux/generic/patches-4.1/864-gpiommc_configfs_locking.patch new file mode 100644 index 0000000..92815d9 --- /dev/null +++ b/target/linux/generic/patches-4.1/864-gpiommc_configfs_locking.patch @@ -0,0 +1,58 @@ +The gpiommc configfs context structure needs locking, as configfs +does not lock access between files. + +--- a/drivers/mmc/host/gpiommc.c ++++ b/drivers/mmc/host/gpiommc.c +@@ -144,6 +144,8 @@ struct gpiommc_configfs_device { + struct platform_device *pdev; + /* The configuration */ + struct gpiommc_platform_data pdata; ++ /* Mutex to protect this structure */ ++ struct mutex mutex; + }; + + #define GPIO_INVALID -1 +@@ -234,6 +236,8 @@ static ssize_t gpiommc_config_attr_show( + unsigned int gpio; + int err = 0; + ++ mutex_lock(&dev->mutex); ++ + if (attr == &gpiommc_attr_DI) { + gpio = dev->pdata.pins.gpio_di; + if (gpio == GPIO_INVALID) +@@ -294,6 +298,8 @@ static ssize_t gpiommc_config_attr_show( + WARN_ON(1); + err = -ENOSYS; + out: ++ mutex_unlock(&dev->mutex); ++ + return err ? err : count; + } + +@@ -353,6 +359,8 @@ static ssize_t gpiommc_config_attr_store + int err = -EINVAL; + unsigned long data; + ++ mutex_lock(&dev->mutex); ++ + if (attr == &gpiommc_attr_register) { + err = kstrtoul(page, 10, &data); + if (err) +@@ -478,6 +486,8 @@ static ssize_t gpiommc_config_attr_store + WARN_ON(1); + err = -ENOSYS; + out: ++ mutex_unlock(&dev->mutex); ++ + return err ? err : count; + } + +@@ -514,6 +524,7 @@ static struct config_item *gpiommc_make_ + if (!dev) + return NULL; + ++ mutex_init(&dev->mutex); + config_item_init_type_name(&dev->item, name, + &gpiommc_dev_ci_type); + diff --git a/target/linux/generic/patches-4.1/870-hifn795x_byteswap.patch b/target/linux/generic/patches-4.1/870-hifn795x_byteswap.patch new file mode 100644 index 0000000..3a37c95 --- /dev/null +++ b/target/linux/generic/patches-4.1/870-hifn795x_byteswap.patch @@ -0,0 +1,17 @@ +--- a/drivers/crypto/hifn_795x.c ++++ b/drivers/crypto/hifn_795x.c +@@ -682,12 +682,12 @@ static inline u32 hifn_read_1(struct hif + + static inline void hifn_write_0(struct hifn_device *dev, u32 reg, u32 val) + { +- writel((__force u32)cpu_to_le32(val), dev->bar[0] + reg); ++ writel(val, dev->bar[0] + reg); + } + + static inline void hifn_write_1(struct hifn_device *dev, u32 reg, u32 val) + { +- writel((__force u32)cpu_to_le32(val), dev->bar[1] + reg); ++ writel(val, dev->bar[1] + reg); + } + + static void hifn_wait_puc(struct hifn_device *dev) diff --git a/target/linux/generic/patches-4.1/880-gateworks_system_controller.patch b/target/linux/generic/patches-4.1/880-gateworks_system_controller.patch new file mode 100644 index 0000000..2657723 --- /dev/null +++ b/target/linux/generic/patches-4.1/880-gateworks_system_controller.patch @@ -0,0 +1,339 @@ +--- a/drivers/hwmon/Kconfig ++++ b/drivers/hwmon/Kconfig +@@ -507,6 +507,15 @@ config SENSORS_G762 + This driver can also be built as a module. If so, the module + will be called g762. + ++config SENSORS_GSC ++ tristate "Gateworks System Controller" ++ depends on I2C ++ help ++ If you say yes here you get support for the Gateworks System Controller. ++ ++ This driver can also be built as a module. If so, the module ++ will be called gsc. ++ + config SENSORS_GPIO_FAN + tristate "GPIO fan" + depends on GPIOLIB +--- a/drivers/hwmon/Makefile ++++ b/drivers/hwmon/Makefile +@@ -156,6 +156,7 @@ obj-$(CONFIG_SENSORS_W83L785TS) += w83l7 + obj-$(CONFIG_SENSORS_W83L786NG) += w83l786ng.o + obj-$(CONFIG_SENSORS_WM831X) += wm831x-hwmon.o + obj-$(CONFIG_SENSORS_WM8350) += wm8350-hwmon.o ++obj-$(CONFIG_SENSORS_GSC) += gsc.o + + obj-$(CONFIG_PMBUS) += pmbus/ + +--- /dev/null ++++ b/drivers/hwmon/gsc.c +@@ -0,0 +1,308 @@ ++/* ++ * A hwmon driver for the Gateworks System Controller ++ * Copyright (C) 2009 Gateworks Corporation ++ * ++ * Author: Chris Lang ++ * ++ * 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 - version 2. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define DRV_VERSION "0.2" ++ ++enum chips { gsp }; ++ ++/* AD7418 registers */ ++#define GSP_REG_TEMP_IN 0x00 ++#define GSP_REG_VIN 0x02 ++#define GSP_REG_3P3 0x05 ++#define GSP_REG_BAT 0x08 ++#define GSP_REG_5P0 0x0b ++#define GSP_REG_CORE 0x0e ++#define GSP_REG_CPU1 0x11 ++#define GSP_REG_CPU2 0x14 ++#define GSP_REG_DRAM 0x17 ++#define GSP_REG_EXT_BAT 0x1a ++#define GSP_REG_IO1 0x1d ++#define GSP_REG_IO2 0x20 ++#define GSP_REG_PCIE 0x23 ++#define GSP_REG_CURRENT 0x26 ++#define GSP_FAN_0 0x2C ++#define GSP_FAN_1 0x2E ++#define GSP_FAN_2 0x30 ++#define GSP_FAN_3 0x32 ++#define GSP_FAN_4 0x34 ++#define GSP_FAN_5 0x36 ++ ++struct gsp_sensor_info { ++ const char* name; ++ int reg; ++}; ++ ++static const struct gsp_sensor_info gsp_sensors[] = { ++ {"temp", GSP_REG_TEMP_IN}, ++ {"vin", GSP_REG_VIN}, ++ {"3p3", GSP_REG_3P3}, ++ {"bat", GSP_REG_BAT}, ++ {"5p0", GSP_REG_5P0}, ++ {"core", GSP_REG_CORE}, ++ {"cpu1", GSP_REG_CPU1}, ++ {"cpu2", GSP_REG_CPU2}, ++ {"dram", GSP_REG_DRAM}, ++ {"ext_bat", GSP_REG_EXT_BAT}, ++ {"io1", GSP_REG_IO1}, ++ {"io2", GSP_REG_IO2}, ++ {"pci2", GSP_REG_PCIE}, ++ {"current", GSP_REG_CURRENT}, ++ {"fan_point0", GSP_FAN_0}, ++ {"fan_point1", GSP_FAN_1}, ++ {"fan_point2", GSP_FAN_2}, ++ {"fan_point3", GSP_FAN_3}, ++ {"fan_point4", GSP_FAN_4}, ++ {"fan_point5", GSP_FAN_5}, ++}; ++ ++struct gsp_data { ++ struct device *hwmon_dev; ++ struct attribute_group attrs; ++ enum chips type; ++}; ++ ++static int gsp_probe(struct i2c_client *client, ++ const struct i2c_device_id *id); ++static int gsp_remove(struct i2c_client *client); ++ ++static const struct i2c_device_id gsp_id[] = { ++ { "gsp", 0 }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, gsp_id); ++ ++static struct i2c_driver gsp_driver = { ++ .driver = { ++ .name = "gsp", ++ }, ++ .probe = gsp_probe, ++ .remove = gsp_remove, ++ .id_table = gsp_id, ++}; ++ ++/* All registers are word-sized, except for the configuration registers. ++ * AD7418 uses a high-byte first convention. Do NOT use those functions to ++ * access the configuration registers CONF and CONF2, as they are byte-sized. ++ */ ++static inline int gsp_read(struct i2c_client *client, u8 reg) ++{ ++ unsigned int adc = 0; ++ if (reg == GSP_REG_TEMP_IN || reg > GSP_REG_CURRENT) ++ { ++ adc |= i2c_smbus_read_byte_data(client, reg); ++ adc |= i2c_smbus_read_byte_data(client, reg + 1) << 8; ++ return adc; ++ } ++ else ++ { ++ adc |= i2c_smbus_read_byte_data(client, reg); ++ adc |= i2c_smbus_read_byte_data(client, reg + 1) << 8; ++ adc |= i2c_smbus_read_byte_data(client, reg + 2) << 16; ++ return adc; ++ } ++} ++ ++static inline int gsp_write(struct i2c_client *client, u8 reg, u16 value) ++{ ++ i2c_smbus_write_byte_data(client, reg, value & 0xff); ++ i2c_smbus_write_byte_data(client, reg + 1, ((value >> 8) & 0xff)); ++ return 1; ++} ++ ++static ssize_t show_adc(struct device *dev, struct device_attribute *devattr, ++ char *buf) ++{ ++ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); ++ struct i2c_client *client = to_i2c_client(dev); ++ return sprintf(buf, "%d\n", gsp_read(client, gsp_sensors[attr->index].reg)); ++} ++ ++static ssize_t show_label(struct device *dev, ++ struct device_attribute *devattr, char *buf) ++{ ++ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); ++ ++ return sprintf(buf, "%s\n", gsp_sensors[attr->index].name); ++} ++ ++static ssize_t store_fan(struct device *dev, ++ struct device_attribute *devattr, const char *buf, size_t count) ++{ ++ u16 val; ++ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); ++ struct i2c_client *client = to_i2c_client(dev); ++ val = simple_strtoul(buf, NULL, 10); ++ gsp_write(client, gsp_sensors[attr->index].reg, val); ++ return count; ++} ++ ++static SENSOR_DEVICE_ATTR(temp0_input, S_IRUGO, show_adc, NULL, 0); ++static SENSOR_DEVICE_ATTR(temp0_label, S_IRUGO, show_label, NULL, 0); ++ ++static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, show_adc, NULL, 1); ++static SENSOR_DEVICE_ATTR(in0_label, S_IRUGO, show_label, NULL, 1); ++static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_adc, NULL, 2); ++static SENSOR_DEVICE_ATTR(in1_label, S_IRUGO, show_label, NULL, 2); ++static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_adc, NULL, 3); ++static SENSOR_DEVICE_ATTR(in2_label, S_IRUGO, show_label, NULL, 3); ++static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_adc, NULL, 4); ++static SENSOR_DEVICE_ATTR(in3_label, S_IRUGO, show_label, NULL, 4); ++static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, show_adc, NULL, 5); ++static SENSOR_DEVICE_ATTR(in4_label, S_IRUGO, show_label, NULL, 5); ++static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, show_adc, NULL, 6); ++static SENSOR_DEVICE_ATTR(in5_label, S_IRUGO, show_label, NULL, 6); ++static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, show_adc, NULL, 7); ++static SENSOR_DEVICE_ATTR(in6_label, S_IRUGO, show_label, NULL, 7); ++static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, show_adc, NULL, 8); ++static SENSOR_DEVICE_ATTR(in7_label, S_IRUGO, show_label, NULL, 8); ++static SENSOR_DEVICE_ATTR(in8_input, S_IRUGO, show_adc, NULL, 9); ++static SENSOR_DEVICE_ATTR(in8_label, S_IRUGO, show_label, NULL, 9); ++static SENSOR_DEVICE_ATTR(in9_input, S_IRUGO, show_adc, NULL, 10); ++static SENSOR_DEVICE_ATTR(in9_label, S_IRUGO, show_label, NULL, 10); ++static SENSOR_DEVICE_ATTR(in10_input, S_IRUGO, show_adc, NULL, 11); ++static SENSOR_DEVICE_ATTR(in10_label, S_IRUGO, show_label, NULL, 11); ++static SENSOR_DEVICE_ATTR(in11_input, S_IRUGO, show_adc, NULL, 12); ++static SENSOR_DEVICE_ATTR(in11_label, S_IRUGO, show_label, NULL, 12); ++static SENSOR_DEVICE_ATTR(in12_input, S_IRUGO, show_adc, NULL, 13); ++static SENSOR_DEVICE_ATTR(in12_label, S_IRUGO, show_label, NULL, 13); ++ ++static SENSOR_DEVICE_ATTR(fan0_point0, S_IRUGO | S_IWUSR, show_adc, store_fan, 14); ++static SENSOR_DEVICE_ATTR(fan0_point1, S_IRUGO | S_IWUSR, show_adc, store_fan, 15); ++static SENSOR_DEVICE_ATTR(fan0_point2, S_IRUGO | S_IWUSR, show_adc, store_fan, 16); ++static SENSOR_DEVICE_ATTR(fan0_point3, S_IRUGO | S_IWUSR, show_adc, store_fan, 17); ++static SENSOR_DEVICE_ATTR(fan0_point4, S_IRUGO | S_IWUSR, show_adc, store_fan, 18); ++static SENSOR_DEVICE_ATTR(fan0_point5, S_IRUGO | S_IWUSR, show_adc, store_fan, 19); ++ ++static struct attribute *gsp_attributes[] = { ++ &sensor_dev_attr_temp0_input.dev_attr.attr, ++ &sensor_dev_attr_in0_input.dev_attr.attr, ++ &sensor_dev_attr_in1_input.dev_attr.attr, ++ &sensor_dev_attr_in2_input.dev_attr.attr, ++ &sensor_dev_attr_in3_input.dev_attr.attr, ++ &sensor_dev_attr_in4_input.dev_attr.attr, ++ &sensor_dev_attr_in5_input.dev_attr.attr, ++ &sensor_dev_attr_in6_input.dev_attr.attr, ++ &sensor_dev_attr_in7_input.dev_attr.attr, ++ &sensor_dev_attr_in8_input.dev_attr.attr, ++ &sensor_dev_attr_in9_input.dev_attr.attr, ++ &sensor_dev_attr_in10_input.dev_attr.attr, ++ &sensor_dev_attr_in11_input.dev_attr.attr, ++ &sensor_dev_attr_in12_input.dev_attr.attr, ++ ++ &sensor_dev_attr_temp0_label.dev_attr.attr, ++ &sensor_dev_attr_in0_label.dev_attr.attr, ++ &sensor_dev_attr_in1_label.dev_attr.attr, ++ &sensor_dev_attr_in2_label.dev_attr.attr, ++ &sensor_dev_attr_in3_label.dev_attr.attr, ++ &sensor_dev_attr_in4_label.dev_attr.attr, ++ &sensor_dev_attr_in5_label.dev_attr.attr, ++ &sensor_dev_attr_in6_label.dev_attr.attr, ++ &sensor_dev_attr_in7_label.dev_attr.attr, ++ &sensor_dev_attr_in8_label.dev_attr.attr, ++ &sensor_dev_attr_in9_label.dev_attr.attr, ++ &sensor_dev_attr_in10_label.dev_attr.attr, ++ &sensor_dev_attr_in11_label.dev_attr.attr, ++ &sensor_dev_attr_in12_label.dev_attr.attr, ++ ++ &sensor_dev_attr_fan0_point0.dev_attr.attr, ++ &sensor_dev_attr_fan0_point1.dev_attr.attr, ++ &sensor_dev_attr_fan0_point2.dev_attr.attr, ++ &sensor_dev_attr_fan0_point3.dev_attr.attr, ++ &sensor_dev_attr_fan0_point4.dev_attr.attr, ++ &sensor_dev_attr_fan0_point5.dev_attr.attr, ++ NULL ++}; ++ ++ ++static int gsp_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct i2c_adapter *adapter = client->adapter; ++ struct gsp_data *data; ++ int err; ++ ++ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | ++ I2C_FUNC_SMBUS_WORD_DATA)) { ++ err = -EOPNOTSUPP; ++ goto exit; ++ } ++ ++ if (!(data = kzalloc(sizeof(struct gsp_data), GFP_KERNEL))) { ++ err = -ENOMEM; ++ goto exit; ++ } ++ ++ i2c_set_clientdata(client, data); ++ ++ data->type = id->driver_data; ++ ++ switch (data->type) { ++ case 0: ++ data->attrs.attrs = gsp_attributes; ++ break; ++ } ++ ++ dev_info(&client->dev, "%s chip found\n", client->name); ++ ++ /* Register sysfs hooks */ ++ if ((err = sysfs_create_group(&client->dev.kobj, &data->attrs))) ++ goto exit_free; ++ ++ data->hwmon_dev = hwmon_device_register(&client->dev); ++ if (IS_ERR(data->hwmon_dev)) { ++ err = PTR_ERR(data->hwmon_dev); ++ goto exit_remove; ++ } ++ ++ return 0; ++ ++exit_remove: ++ sysfs_remove_group(&client->dev.kobj, &data->attrs); ++exit_free: ++ kfree(data); ++exit: ++ return err; ++} ++ ++static int gsp_remove(struct i2c_client *client) ++{ ++ struct gsp_data *data = i2c_get_clientdata(client); ++ hwmon_device_unregister(data->hwmon_dev); ++ sysfs_remove_group(&client->dev.kobj, &data->attrs); ++ kfree(data); ++ return 0; ++} ++ ++static int __init gsp_init(void) ++{ ++ return i2c_add_driver(&gsp_driver); ++} ++ ++static void __exit gsp_exit(void) ++{ ++ i2c_del_driver(&gsp_driver); ++} ++ ++module_init(gsp_init); ++module_exit(gsp_exit); ++ ++MODULE_AUTHOR("Chris Lang "); ++MODULE_DESCRIPTION("GSC HWMON driver"); ++MODULE_LICENSE("GPL"); ++MODULE_VERSION(DRV_VERSION); ++ diff --git a/target/linux/generic/patches-4.1/890-8250_optional_sysrq.patch b/target/linux/generic/patches-4.1/890-8250_optional_sysrq.patch new file mode 100644 index 0000000..8815e4c --- /dev/null +++ b/target/linux/generic/patches-4.1/890-8250_optional_sysrq.patch @@ -0,0 +1,24 @@ +--- a/drivers/tty/serial/8250/8250_core.c ++++ b/drivers/tty/serial/8250/8250_core.c +@@ -16,7 +16,7 @@ + * membase is an 'ioremapped' cookie. + */ + +-#if defined(CONFIG_SERIAL_8250_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) ++#if defined(CONFIG_SERIAL_8250_SYSRQ) && defined(CONFIG_MAGIC_SYSRQ) + #define SUPPORT_SYSRQ + #endif + +--- a/drivers/tty/serial/8250/Kconfig ++++ b/drivers/tty/serial/8250/Kconfig +@@ -91,6 +91,10 @@ config SERIAL_8250_CONSOLE + + If unsure, say N. + ++config SERIAL_8250_SYSRQ ++ bool "Magic sysrq support on 8250/16550 devices" ++ depends on SERIAL_8250_CONSOLE ++ + config SERIAL_8250_GSC + tristate + depends on SERIAL_8250 && GSC diff --git a/target/linux/generic/patches-4.1/900-slab_maxsize.patch b/target/linux/generic/patches-4.1/900-slab_maxsize.patch new file mode 100644 index 0000000..10133f2 --- /dev/null +++ b/target/linux/generic/patches-4.1/900-slab_maxsize.patch @@ -0,0 +1,13 @@ +--- a/include/linux/slab.h ++++ b/include/linux/slab.h +@@ -171,8 +171,8 @@ size_t ksize(const void *); + * to do various tricks to work around compiler limitations in order to + * ensure proper constant folding. + */ +-#define KMALLOC_SHIFT_HIGH ((MAX_ORDER + PAGE_SHIFT - 1) <= 25 ? \ +- (MAX_ORDER + PAGE_SHIFT - 1) : 25) ++#define KMALLOC_SHIFT_HIGH ((MAX_ORDER + PAGE_SHIFT - 1) <= 17 ? \ ++ (MAX_ORDER + PAGE_SHIFT - 1) : 17) + #define KMALLOC_SHIFT_MAX KMALLOC_SHIFT_HIGH + #ifndef KMALLOC_SHIFT_LOW + #define KMALLOC_SHIFT_LOW 5 diff --git a/target/linux/generic/patches-4.1/901-debloat_sock_diag.patch b/target/linux/generic/patches-4.1/901-debloat_sock_diag.patch new file mode 100644 index 0000000..0716169 --- /dev/null +++ b/target/linux/generic/patches-4.1/901-debloat_sock_diag.patch @@ -0,0 +1,65 @@ +--- a/net/Kconfig ++++ b/net/Kconfig +@@ -89,6 +89,9 @@ source "net/netlabel/Kconfig" + + endif # if INET + ++config SOCK_DIAG ++ bool ++ + config NETWORK_SECMARK + bool "Security Marking" + help +--- a/net/core/Makefile ++++ b/net/core/Makefile +@@ -9,8 +9,9 @@ obj-$(CONFIG_SYSCTL) += sysctl_net_core. + + obj-y += dev.o ethtool.o dev_addr_lists.o dst.o netevent.o \ + neighbour.o rtnetlink.o utils.o link_watch.o filter.o \ +- sock_diag.o dev_ioctl.o tso.o ++ dev_ioctl.o tso.o + ++obj-$(CONFIG_SOCK_DIAG) += sock_diag.o + obj-$(CONFIG_XFRM) += flow.o + obj-y += net-sysfs.o + obj-$(CONFIG_PROC_FS) += net-procfs.o +--- a/net/ipv4/Kconfig ++++ b/net/ipv4/Kconfig +@@ -428,6 +428,7 @@ config INET_LRO + + config INET_DIAG + tristate "INET: socket monitoring interface" ++ select SOCK_DIAG + default y + ---help--- + Support for INET (TCP, DCCP, etc) socket monitoring interface used by +--- a/net/unix/Kconfig ++++ b/net/unix/Kconfig +@@ -22,6 +22,7 @@ config UNIX + config UNIX_DIAG + tristate "UNIX: socket monitoring interface" + depends on UNIX ++ select SOCK_DIAG + default n + ---help--- + Support for UNIX socket monitoring interface used by the ss tool. +--- a/net/netlink/Kconfig ++++ b/net/netlink/Kconfig +@@ -13,6 +13,7 @@ config NETLINK_MMAP + + config NETLINK_DIAG + tristate "NETLINK: socket monitoring interface" ++ select SOCK_DIAG + default n + ---help--- + Support for NETLINK socket monitoring interface used by the ss tool. +--- a/net/packet/Kconfig ++++ b/net/packet/Kconfig +@@ -18,6 +18,7 @@ config PACKET + config PACKET_DIAG + tristate "Packet: sockets monitoring interface" + depends on PACKET ++ select SOCK_DIAG + default n + ---help--- + Support for PF_PACKET sockets monitoring interface used by the ss tool. diff --git a/target/linux/generic/patches-4.1/902-debloat_proc.patch b/target/linux/generic/patches-4.1/902-debloat_proc.patch new file mode 100644 index 0000000..fef5382 --- /dev/null +++ b/target/linux/generic/patches-4.1/902-debloat_proc.patch @@ -0,0 +1,341 @@ +--- a/fs/locks.c ++++ b/fs/locks.c +@@ -2676,6 +2676,8 @@ static const struct file_operations proc + + static int __init proc_locks_init(void) + { ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return 0; + proc_create("locks", 0, NULL, &proc_locks_operations); + return 0; + } +--- a/fs/proc/Kconfig ++++ b/fs/proc/Kconfig +@@ -71,3 +71,8 @@ config PROC_PAGE_MONITOR + /proc/pid/smaps, /proc/pid/clear_refs, /proc/pid/pagemap, + /proc/kpagecount, and /proc/kpageflags. Disabling these + interfaces will reduce the size of the kernel by approximately 4kb. ++ ++config PROC_STRIPPED ++ default n ++ depends on EXPERT ++ bool "Strip non-essential /proc functionality to reduce code size" +--- a/fs/proc/consoles.c ++++ b/fs/proc/consoles.c +@@ -106,6 +106,9 @@ static const struct file_operations proc + + static int __init proc_consoles_init(void) + { ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return 0; ++ + proc_create("consoles", 0, NULL, &proc_consoles_operations); + return 0; + } +--- a/fs/proc/proc_tty.c ++++ b/fs/proc/proc_tty.c +@@ -143,7 +143,10 @@ static const struct file_operations proc + void proc_tty_register_driver(struct tty_driver *driver) + { + struct proc_dir_entry *ent; +- ++ ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return; ++ + if (!driver->driver_name || driver->proc_entry || + !driver->ops->proc_fops) + return; +@@ -160,6 +163,9 @@ void proc_tty_unregister_driver(struct t + { + struct proc_dir_entry *ent; + ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return; ++ + ent = driver->proc_entry; + if (!ent) + return; +@@ -174,6 +180,9 @@ void proc_tty_unregister_driver(struct t + */ + void __init proc_tty_init(void) + { ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return; ++ + if (!proc_mkdir("tty", NULL)) + return; + proc_mkdir("tty/ldisc", NULL); /* Preserved: it's userspace visible */ +--- a/kernel/exec_domain.c ++++ b/kernel/exec_domain.c +@@ -41,6 +41,8 @@ static const struct file_operations exec + + static int __init proc_execdomains_init(void) + { ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return 0; + proc_create("execdomains", 0, NULL, &execdomains_proc_fops); + return 0; + } +--- a/kernel/irq/proc.c ++++ b/kernel/irq/proc.c +@@ -325,6 +325,9 @@ void register_irq_proc(unsigned int irq, + { + char name [MAX_NAMELEN]; + ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED) && !IS_ENABLED(CONFIG_SMP)) ++ return; ++ + if (!root_irq_dir || (desc->irq_data.chip == &no_irq_chip) || desc->dir) + return; + +@@ -361,6 +364,9 @@ void unregister_irq_proc(unsigned int ir + { + char name [MAX_NAMELEN]; + ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED) && !IS_ENABLED(CONFIG_SMP)) ++ return; ++ + if (!root_irq_dir || !desc->dir) + return; + #ifdef CONFIG_SMP +@@ -396,6 +402,9 @@ void init_irq_proc(void) + unsigned int irq; + struct irq_desc *desc; + ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED) && !IS_ENABLED(CONFIG_SMP)) ++ return; ++ + /* create /proc/irq */ + root_irq_dir = proc_mkdir("irq", NULL); + if (!root_irq_dir) +--- a/kernel/time/timer_list.c ++++ b/kernel/time/timer_list.c +@@ -388,6 +388,8 @@ static int __init init_timer_list_procfs + { + struct proc_dir_entry *pe; + ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return 0; + pe = proc_create("timer_list", 0444, NULL, &timer_list_fops); + if (!pe) + return -ENOMEM; +--- a/mm/vmalloc.c ++++ b/mm/vmalloc.c +@@ -2683,6 +2683,8 @@ static const struct file_operations proc + + static int __init proc_vmalloc_init(void) + { ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return 0; + proc_create("vmallocinfo", S_IRUSR, NULL, &proc_vmalloc_operations); + return 0; + } +--- a/mm/vmstat.c ++++ b/mm/vmstat.c +@@ -1528,10 +1528,12 @@ static int __init setup_vmstat(void) + cpu_notifier_register_done(); + #endif + #ifdef CONFIG_PROC_FS +- proc_create("buddyinfo", S_IRUGO, NULL, &fragmentation_file_operations); +- proc_create("pagetypeinfo", S_IRUGO, NULL, &pagetypeinfo_file_ops); ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) { ++ proc_create("buddyinfo", S_IRUGO, NULL, &fragmentation_file_operations); ++ proc_create("pagetypeinfo", S_IRUGO, NULL, &pagetypeinfo_file_ops); ++ proc_create("zoneinfo", S_IRUGO, NULL, &proc_zoneinfo_file_operations); ++ } + proc_create("vmstat", S_IRUGO, NULL, &proc_vmstat_file_operations); +- proc_create("zoneinfo", S_IRUGO, NULL, &proc_zoneinfo_file_operations); + #endif + return 0; + } +--- a/net/8021q/vlanproc.c ++++ b/net/8021q/vlanproc.c +@@ -127,6 +127,9 @@ void vlan_proc_cleanup(struct net *net) + { + struct vlan_net *vn = net_generic(net, vlan_net_id); + ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return; ++ + if (vn->proc_vlan_conf) + remove_proc_entry(name_conf, vn->proc_vlan_dir); + +@@ -146,6 +149,9 @@ int __net_init vlan_proc_init(struct net + { + struct vlan_net *vn = net_generic(net, vlan_net_id); + ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return 0; ++ + vn->proc_vlan_dir = proc_net_mkdir(net, name_root, net->proc_net); + if (!vn->proc_vlan_dir) + goto err; +--- a/net/core/sock.c ++++ b/net/core/sock.c +@@ -2971,6 +2971,8 @@ static __net_initdata struct pernet_oper + + static int __init proto_init(void) + { ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return 0; + return register_pernet_subsys(&proto_net_ops); + } + +--- a/net/ipv4/fib_trie.c ++++ b/net/ipv4/fib_trie.c +@@ -2630,10 +2630,12 @@ static const struct file_operations fib_ + + int __net_init fib_proc_init(struct net *net) + { +- if (!proc_create("fib_trie", S_IRUGO, net->proc_net, &fib_trie_fops)) ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED) && ++ !proc_create("fib_trie", S_IRUGO, net->proc_net, &fib_trie_fops)) + goto out1; + +- if (!proc_create("fib_triestat", S_IRUGO, net->proc_net, ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED) && ++ !proc_create("fib_triestat", S_IRUGO, net->proc_net, + &fib_triestat_fops)) + goto out2; + +@@ -2643,17 +2645,21 @@ int __net_init fib_proc_init(struct net + return 0; + + out3: +- remove_proc_entry("fib_triestat", net->proc_net); ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ remove_proc_entry("fib_triestat", net->proc_net); + out2: +- remove_proc_entry("fib_trie", net->proc_net); ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ remove_proc_entry("fib_trie", net->proc_net); + out1: + return -ENOMEM; + } + + void __net_exit fib_proc_exit(struct net *net) + { +- remove_proc_entry("fib_trie", net->proc_net); +- remove_proc_entry("fib_triestat", net->proc_net); ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) { ++ remove_proc_entry("fib_trie", net->proc_net); ++ remove_proc_entry("fib_triestat", net->proc_net); ++ } + remove_proc_entry("route", net->proc_net); + } + +--- a/net/ipv4/proc.c ++++ b/net/ipv4/proc.c +@@ -535,6 +535,9 @@ static __net_initdata struct pernet_oper + + int __init ip_misc_proc_init(void) + { ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return 0; ++ + return register_pernet_subsys(&ip_proc_ops); + } + +--- a/net/ipv4/route.c ++++ b/net/ipv4/route.c +@@ -415,6 +415,9 @@ static struct pernet_operations ip_rt_pr + + static int __init ip_rt_proc_init(void) + { ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return 0; ++ + return register_pernet_subsys(&ip_rt_proc_ops); + } + +--- a/ipc/msg.c ++++ b/ipc/msg.c +@@ -1040,6 +1040,9 @@ void __init msg_init(void) + { + msg_init_ns(&init_ipc_ns); + ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return; ++ + ipc_init_proc_interface("sysvipc/msg", + " key msqid perms cbytes qnum lspid lrpid uid gid cuid cgid stime rtime ctime\n", + IPC_MSG_IDS, sysvipc_msg_proc_show); +--- a/ipc/sem.c ++++ b/ipc/sem.c +@@ -191,6 +191,8 @@ void sem_exit_ns(struct ipc_namespace *n + void __init sem_init(void) + { + sem_init_ns(&init_ipc_ns); ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return; + ipc_init_proc_interface("sysvipc/sem", + " key semid perms nsems uid gid cuid cgid otime ctime\n", + IPC_SEM_IDS, sysvipc_sem_proc_show); +--- a/ipc/shm.c ++++ b/ipc/shm.c +@@ -118,6 +118,8 @@ pure_initcall(ipc_ns_init); + + void __init shm_init(void) + { ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return; + ipc_init_proc_interface("sysvipc/shm", + #if BITS_PER_LONG <= 32 + " key shmid perms size cpid lpid nattch uid gid cuid cgid atime dtime ctime rss swap\n", +--- a/ipc/util.c ++++ b/ipc/util.c +@@ -121,6 +121,9 @@ void __init ipc_init_proc_interface(cons + struct proc_dir_entry *pde; + struct ipc_proc_iface *iface; + ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return; ++ + iface = kmalloc(sizeof(*iface), GFP_KERNEL); + if (!iface) + return; +--- a/net/core/net-procfs.c ++++ b/net/core/net-procfs.c +@@ -318,10 +318,12 @@ static int __net_init dev_proc_net_init( + + if (!proc_create("dev", S_IRUGO, net->proc_net, &dev_seq_fops)) + goto out; +- if (!proc_create("softnet_stat", S_IRUGO, net->proc_net, ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED) && ++ !proc_create("softnet_stat", S_IRUGO, net->proc_net, + &softnet_seq_fops)) + goto out_dev; +- if (!proc_create("ptype", S_IRUGO, net->proc_net, &ptype_seq_fops)) ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED) && ++ !proc_create("ptype", S_IRUGO, net->proc_net, &ptype_seq_fops)) + goto out_softnet; + + if (wext_proc_init(net)) +@@ -330,9 +332,11 @@ static int __net_init dev_proc_net_init( + out: + return rc; + out_ptype: +- remove_proc_entry("ptype", net->proc_net); ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ remove_proc_entry("ptype", net->proc_net); + out_softnet: +- remove_proc_entry("softnet_stat", net->proc_net); ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ remove_proc_entry("softnet_stat", net->proc_net); + out_dev: + remove_proc_entry("dev", net->proc_net); + goto out; +@@ -342,8 +346,10 @@ static void __net_exit dev_proc_net_exit + { + wext_proc_exit(net); + +- remove_proc_entry("ptype", net->proc_net); +- remove_proc_entry("softnet_stat", net->proc_net); ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) { ++ remove_proc_entry("ptype", net->proc_net); ++ remove_proc_entry("softnet_stat", net->proc_net); ++ } + remove_proc_entry("dev", net->proc_net); + } + diff --git a/target/linux/generic/patches-4.1/903-debloat_direct_io.patch b/target/linux/generic/patches-4.1/903-debloat_direct_io.patch new file mode 100644 index 0000000..b428a0c --- /dev/null +++ b/target/linux/generic/patches-4.1/903-debloat_direct_io.patch @@ -0,0 +1,80 @@ +--- a/fs/Kconfig ++++ b/fs/Kconfig +@@ -71,6 +71,11 @@ config FILE_LOCKING + for filesystems like NFS and for the flock() system + call. Disabling this option saves about 11k. + ++config DIRECT_IO ++ bool "Enable O_DIRECT support" if EXPERT ++ depends on BLOCK ++ default y ++ + source "fs/notify/Kconfig" + + source "fs/quota/Kconfig" +--- a/fs/Makefile ++++ b/fs/Makefile +@@ -14,7 +14,8 @@ obj-y := open.o read_write.o file_table. + stack.o fs_struct.o statfs.o fs_pin.o nsfs.o + + ifeq ($(CONFIG_BLOCK),y) +-obj-y += buffer.o block_dev.o direct-io.o mpage.o ++obj-y += buffer.o block_dev.o mpage.o ++obj-$(CONFIG_DIRECT_IO) += direct-io.o + else + obj-y += no-block.o + endif +--- a/include/linux/fs.h ++++ b/include/linux/fs.h +@@ -2649,6 +2649,7 @@ enum { + DIO_SKIP_DIO_COUNT = 0x08, + }; + ++#ifdef CONFIG_DIRECT_IO + void dio_end_io(struct bio *bio, int error); + + ssize_t __blockdev_direct_IO(struct kiocb *iocb, struct inode *inode, +@@ -2656,6 +2657,18 @@ ssize_t __blockdev_direct_IO(struct kioc + loff_t offset, get_block_t get_block, + dio_iodone_t end_io, dio_submit_t submit_io, + int flags); ++#else ++static inline void dio_end_io(struct bio *bio, int error) ++{ ++} ++static inline ssize_t __blockdev_direct_IO(struct kiocb *iocb, struct inode *inode, ++ struct block_device *bdev, struct iov_iter *iter, loff_t offset, ++ get_block_t get_block, dio_iodone_t end_io, ++ dio_submit_t submit_io, int flags) ++{ ++ return -EOPNOTSUPP; ++} ++#endif + + static inline ssize_t blockdev_direct_IO(struct kiocb *iocb, + struct inode *inode, +--- a/fs/fcntl.c ++++ b/fs/fcntl.c +@@ -52,8 +52,10 @@ static int setfl(int fd, struct file * f + arg |= O_NONBLOCK; + + if (arg & O_DIRECT) { ++#ifdef CONFIG_DIRECT_IO + if (!filp->f_mapping || !filp->f_mapping->a_ops || + !filp->f_mapping->a_ops->direct_IO) ++#endif + return -EINVAL; + } + +--- a/fs/open.c ++++ b/fs/open.c +@@ -671,7 +671,9 @@ int open_check_o_direct(struct file *f) + { + /* NB: we're sure to have correct a_ops only after f_op->open */ + if (f->f_flags & O_DIRECT) { ++#ifdef CONFIG_DIRECT_IO + if (!f->f_mapping->a_ops || !f->f_mapping->a_ops->direct_IO) ++#endif + return -EINVAL; + } + return 0; diff --git a/target/linux/generic/patches-4.1/910-kobject_uevent.patch b/target/linux/generic/patches-4.1/910-kobject_uevent.patch new file mode 100644 index 0000000..a2c935f --- /dev/null +++ b/target/linux/generic/patches-4.1/910-kobject_uevent.patch @@ -0,0 +1,21 @@ +--- a/lib/kobject_uevent.c ++++ b/lib/kobject_uevent.c +@@ -52,6 +52,18 @@ static const char *kobject_actions[] = { + [KOBJ_OFFLINE] = "offline", + }; + ++u64 uevent_next_seqnum(void) ++{ ++ u64 seq; ++ ++ mutex_lock(&uevent_sock_mutex); ++ seq = ++uevent_seqnum; ++ mutex_unlock(&uevent_sock_mutex); ++ ++ return seq; ++} ++EXPORT_SYMBOL_GPL(uevent_next_seqnum); ++ + /** + * kobject_action_type - translate action string to numeric type + * diff --git a/target/linux/generic/patches-4.1/911-kobject_add_broadcast_uevent.patch b/target/linux/generic/patches-4.1/911-kobject_add_broadcast_uevent.patch new file mode 100644 index 0000000..3afaac1 --- /dev/null +++ b/target/linux/generic/patches-4.1/911-kobject_add_broadcast_uevent.patch @@ -0,0 +1,65 @@ +--- a/include/linux/kobject.h ++++ b/include/linux/kobject.h +@@ -32,6 +32,8 @@ + #define UEVENT_NUM_ENVP 32 /* number of env pointers */ + #define UEVENT_BUFFER_SIZE 2048 /* buffer for the variables */ + ++struct sk_buff; ++ + #ifdef CONFIG_UEVENT_HELPER + /* path to the userspace helper executed on an event */ + extern char uevent_helper[]; +@@ -221,4 +223,7 @@ int add_uevent_var(struct kobj_uevent_en + int kobject_action_type(const char *buf, size_t count, + enum kobject_action *type); + ++int broadcast_uevent(struct sk_buff *skb, __u32 pid, __u32 group, ++ gfp_t allocation); ++ + #endif /* _KOBJECT_H_ */ +--- a/lib/kobject_uevent.c ++++ b/lib/kobject_uevent.c +@@ -423,6 +423,43 @@ int add_uevent_var(struct kobj_uevent_en + EXPORT_SYMBOL_GPL(add_uevent_var); + + #if defined(CONFIG_NET) ++int broadcast_uevent(struct sk_buff *skb, __u32 pid, __u32 group, ++ gfp_t allocation) ++{ ++ struct uevent_sock *ue_sk; ++ int err = 0; ++ ++ /* send netlink message */ ++ mutex_lock(&uevent_sock_mutex); ++ list_for_each_entry(ue_sk, &uevent_sock_list, list) { ++ struct sock *uevent_sock = ue_sk->sk; ++ struct sk_buff *skb2; ++ ++ skb2 = skb_clone(skb, allocation); ++ if (!skb2) ++ break; ++ ++ err = netlink_broadcast(uevent_sock, skb2, pid, group, ++ allocation); ++ if (err) ++ break; ++ } ++ mutex_unlock(&uevent_sock_mutex); ++ ++ kfree_skb(skb); ++ return err; ++} ++#else ++int broadcast_uevent(struct sk_buff *skb, __u32 pid, __u32 group, ++ gfp_t allocation) ++{ ++ kfree_skb(skb); ++ return 0; ++} ++#endif ++EXPORT_SYMBOL_GPL(broadcast_uevent); ++ ++#if defined(CONFIG_NET) + static int uevent_net_init(struct net *net) + { + struct uevent_sock *ue_sk; diff --git a/target/linux/generic/patches-4.1/921-use_preinit_as_init.patch b/target/linux/generic/patches-4.1/921-use_preinit_as_init.patch new file mode 100644 index 0000000..73da5b3 --- /dev/null +++ b/target/linux/generic/patches-4.1/921-use_preinit_as_init.patch @@ -0,0 +1,12 @@ +--- a/init/main.c ++++ b/init/main.c +@@ -960,7 +960,8 @@ static int __ref kernel_init(void *unuse + panic("Requested init %s failed (error %d).", + execute_command, ret); + } +- if (!try_to_run_init_process("/sbin/init") || ++ if (!try_to_run_init_process("/etc/preinit") || ++ !try_to_run_init_process("/sbin/init") || + !try_to_run_init_process("/etc/init") || + !try_to_run_init_process("/bin/init") || + !try_to_run_init_process("/bin/sh")) diff --git a/target/linux/generic/patches-4.1/922-always-create-console-node-in-initramfs.patch b/target/linux/generic/patches-4.1/922-always-create-console-node-in-initramfs.patch new file mode 100644 index 0000000..988de35 --- /dev/null +++ b/target/linux/generic/patches-4.1/922-always-create-console-node-in-initramfs.patch @@ -0,0 +1,30 @@ +--- a/scripts/gen_initramfs_list.sh ++++ b/scripts/gen_initramfs_list.sh +@@ -59,6 +59,18 @@ default_initramfs() { + EOF + } + ++list_openwrt_initramfs() { ++ : ++} ++ ++openwrt_initramfs() { ++ # make sure that /dev/console exists ++ cat <<-EOF >> ${output} ++ dir /dev 0755 0 0 ++ nod /dev/console 0600 0 0 c 5 1 ++ EOF ++} ++ + filetype() { + local argv1="$1" + +@@ -177,6 +189,8 @@ dir_filelist() { + if [ "$(echo "${dirlist}" | wc -l)" -gt 1 ]; then + ${dep_list}print_mtime "$1" + ++ ${dep_list}openwrt_initramfs ++ + echo "${dirlist}" | \ + while read x; do + ${dep_list}parse ${x} diff --git a/target/linux/generic/patches-4.1/930-crashlog.patch b/target/linux/generic/patches-4.1/930-crashlog.patch new file mode 100644 index 0000000..be0f7d0 --- /dev/null +++ b/target/linux/generic/patches-4.1/930-crashlog.patch @@ -0,0 +1,276 @@ +--- /dev/null ++++ b/include/linux/crashlog.h +@@ -0,0 +1,17 @@ ++#ifndef __CRASHLOG_H ++#define __CRASHLOG_H ++ ++#ifdef CONFIG_CRASHLOG ++void crashlog_init_bootmem(struct bootmem_data *bdata); ++void crashlog_init_memblock(phys_addr_t addr, phys_addr_t size); ++#else ++static inline void crashlog_init_bootmem(struct bootmem_data *bdata) ++{ ++} ++ ++static inline void crashlog_init_memblock(phys_addr_t addr, phys_addr_t size) ++{ ++} ++#endif ++ ++#endif +--- a/init/Kconfig ++++ b/init/Kconfig +@@ -1275,6 +1275,10 @@ config RELAY + + If unsure, say N. + ++config CRASHLOG ++ bool "Crash logging" ++ depends on (!NO_BOOTMEM || HAVE_MEMBLOCK) && !(ARM || SPARC || PPC) ++ + config BLK_DEV_INITRD + bool "Initial RAM filesystem and RAM disk (initramfs/initrd) support" + depends on BROKEN || !FRV +--- a/kernel/Makefile ++++ b/kernel/Makefile +@@ -98,6 +98,7 @@ obj-$(CONFIG_CRASH_DUMP) += crash_dump.o + obj-$(CONFIG_JUMP_LABEL) += jump_label.o + obj-$(CONFIG_CONTEXT_TRACKING) += context_tracking.o + obj-$(CONFIG_TORTURE_TEST) += torture.o ++obj-$(CONFIG_CRASHLOG) += crashlog.o + + $(obj)/configs.o: $(obj)/config_data.h + +--- /dev/null ++++ b/kernel/crashlog.c +@@ -0,0 +1,181 @@ ++/* ++ * Crash information logger ++ * Copyright (C) 2010 Felix Fietkau ++ * ++ * Based on ramoops.c ++ * Copyright (C) 2010 Marco Stornelli ++ * ++ * 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 ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define CRASHLOG_PAGES 4 ++#define CRASHLOG_SIZE (CRASHLOG_PAGES * PAGE_SIZE) ++#define CRASHLOG_MAGIC 0xa1eedead ++ ++/* ++ * Start the log at 1M before the end of RAM, as some boot loaders like ++ * to use the end of the RAM for stack usage and other things ++ * If this fails, fall back to using the last part. ++ */ ++#define CRASHLOG_OFFSET (1024 * 1024) ++ ++struct crashlog_data { ++ u32 magic; ++ u32 len; ++ u8 data[]; ++}; ++ ++static struct debugfs_blob_wrapper crashlog_blob; ++static unsigned long crashlog_addr = 0; ++static struct crashlog_data *crashlog_buf; ++static struct kmsg_dumper dump; ++static bool first = true; ++ ++extern struct list_head *crashlog_modules; ++ ++#ifndef CONFIG_NO_BOOTMEM ++void __init crashlog_init_bootmem(bootmem_data_t *bdata) ++{ ++ unsigned long addr; ++ ++ if (crashlog_addr) ++ return; ++ ++ addr = PFN_PHYS(bdata->node_low_pfn) - CRASHLOG_OFFSET; ++ if (reserve_bootmem(addr, CRASHLOG_SIZE, BOOTMEM_EXCLUSIVE) < 0) { ++ printk("Crashlog failed to allocate RAM at address 0x%lx\n", addr); ++ bdata->node_low_pfn -= CRASHLOG_PAGES; ++ addr = PFN_PHYS(bdata->node_low_pfn); ++ } ++ crashlog_addr = addr; ++} ++#endif ++ ++#ifdef CONFIG_HAVE_MEMBLOCK ++void __meminit crashlog_init_memblock(phys_addr_t addr, phys_addr_t size) ++{ ++ if (crashlog_addr) ++ return; ++ ++ addr += size - CRASHLOG_OFFSET; ++ if (memblock_reserve(addr, CRASHLOG_SIZE)) { ++ printk("Crashlog failed to allocate RAM at address 0x%lx\n", (unsigned long) addr); ++ return; ++ } ++ ++ crashlog_addr = addr; ++} ++#endif ++ ++static void __init crashlog_copy(void) ++{ ++ if (crashlog_buf->magic != CRASHLOG_MAGIC) ++ return; ++ ++ if (!crashlog_buf->len || crashlog_buf->len > ++ CRASHLOG_SIZE - sizeof(*crashlog_buf)) ++ return; ++ ++ crashlog_blob.size = crashlog_buf->len; ++ crashlog_blob.data = kmemdup(crashlog_buf->data, ++ crashlog_buf->len, GFP_KERNEL); ++ ++ debugfs_create_blob("crashlog", 0700, NULL, &crashlog_blob); ++} ++ ++static int get_maxlen(void) ++{ ++ return CRASHLOG_SIZE - sizeof(*crashlog_buf) - crashlog_buf->len; ++} ++ ++static void crashlog_printf(const char *fmt, ...) ++{ ++ va_list args; ++ int len = get_maxlen(); ++ ++ if (!len) ++ return; ++ ++ va_start(args, fmt); ++ crashlog_buf->len += vscnprintf( ++ &crashlog_buf->data[crashlog_buf->len], ++ len, fmt, args); ++ va_end(args); ++} ++ ++static void crashlog_do_dump(struct kmsg_dumper *dumper, ++ enum kmsg_dump_reason reason) ++{ ++ struct timeval tv; ++ struct module *m; ++ char *buf; ++ size_t len; ++ ++ if (!first) ++ crashlog_printf("\n===================================\n"); ++ ++ do_gettimeofday(&tv); ++ crashlog_printf("Time: %lu.%lu\n", ++ (long)tv.tv_sec, (long)tv.tv_usec); ++ ++ if (first) { ++ crashlog_printf("Modules:"); ++ list_for_each_entry(m, crashlog_modules, list) { ++ crashlog_printf("\t%s@%p+%x", m->name, ++ m->module_core, m->core_size, ++ m->module_init, m->init_size); ++ } ++ crashlog_printf("\n"); ++ first = false; ++ } ++ ++ buf = (char *)&crashlog_buf->data[crashlog_buf->len]; ++ ++ kmsg_dump_get_buffer(dumper, true, buf, get_maxlen(), &len); ++ ++ crashlog_buf->len += len; ++} ++ ++ ++int __init crashlog_init_fs(void) ++{ ++ if (!crashlog_addr) ++ return -ENOMEM; ++ ++ crashlog_buf = ioremap(crashlog_addr, CRASHLOG_SIZE); ++ ++ crashlog_copy(); ++ ++ crashlog_buf->magic = CRASHLOG_MAGIC; ++ crashlog_buf->len = 0; ++ ++ dump.max_reason = KMSG_DUMP_OOPS; ++ dump.dump = crashlog_do_dump; ++ kmsg_dump_register(&dump); ++ ++ return 0; ++} ++module_init(crashlog_init_fs); +--- a/mm/bootmem.c ++++ b/mm/bootmem.c +@@ -15,6 +15,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -177,6 +178,7 @@ static unsigned long __init free_all_boo + if (!bdata->node_bootmem_map) + return 0; + ++ crashlog_init_bootmem(bdata); + map = bdata->node_bootmem_map; + start = bdata->node_min_pfn; + end = bdata->node_low_pfn; +--- a/kernel/module.c ++++ b/kernel/module.c +@@ -104,6 +104,9 @@ static LIST_HEAD(modules); + #ifdef CONFIG_KGDB_KDB + struct list_head *kdb_modules = &modules; /* kdb needs the list of modules */ + #endif /* CONFIG_KGDB_KDB */ ++#ifdef CONFIG_CRASHLOG ++struct list_head *crashlog_modules = &modules; ++#endif + + #ifdef CONFIG_MODULE_SIG + #ifdef CONFIG_MODULE_SIG_FORCE +--- a/mm/memblock.c ++++ b/mm/memblock.c +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -477,6 +478,8 @@ static void __init_memblock memblock_ins + memblock_set_region_node(rgn, nid); + type->cnt++; + type->total_size += size; ++ if (type == &memblock.memory && idx == 0) ++ crashlog_init_memblock(base, size); + } + + /** diff --git a/target/linux/generic/patches-4.1/940-ocf_kbuild_integration.patch b/target/linux/generic/patches-4.1/940-ocf_kbuild_integration.patch new file mode 100644 index 0000000..a50cd9c --- /dev/null +++ b/target/linux/generic/patches-4.1/940-ocf_kbuild_integration.patch @@ -0,0 +1,20 @@ +--- a/crypto/Kconfig ++++ b/crypto/Kconfig +@@ -1526,3 +1526,6 @@ source "drivers/crypto/Kconfig" + source crypto/asymmetric_keys/Kconfig + + endif # if CRYPTO ++ ++source "crypto/ocf/Kconfig" ++ +--- a/crypto/Makefile ++++ b/crypto/Makefile +@@ -103,6 +103,8 @@ obj-$(CONFIG_CRYPTO_USER_API_SKCIPHER) + + obj-$(CONFIG_CRYPTO_USER_API_RNG) += algif_rng.o + obj-$(CONFIG_CRYPTO_USER_API_AEAD) += algif_aead.o + ++obj-$(CONFIG_OCF_OCF) += ocf/ ++ + # + # generic algorithms and the async_tx api + # diff --git a/target/linux/generic/patches-4.1/941-ocf_20120127.patch b/target/linux/generic/patches-4.1/941-ocf_20120127.patch new file mode 100644 index 0000000..d5564b3 --- /dev/null +++ b/target/linux/generic/patches-4.1/941-ocf_20120127.patch @@ -0,0 +1,166 @@ +--- a/drivers/char/random.c ++++ b/drivers/char/random.c +@@ -139,6 +139,9 @@ + * that might otherwise be identical and have very little entropy + * available to them (particularly common in the embedded world). + * ++ * void random_input_words(__u32 *buf, size_t wordcount, int ent_count) ++ * int random_input_wait(void); ++ * + * add_input_randomness() uses the input layer interrupt timing, as well as + * the event type information from the hardware. + * +@@ -152,6 +155,13 @@ + * seek times do not make for good sources of entropy, as their seek + * times are usually fairly consistent. + * ++ * random_input_words() just provides a raw block of entropy to the input ++ * pool, such as from a hardware entropy generator. ++ * ++ * random_input_wait() suspends the caller until such time as the ++ * entropy pool falls below the write threshold, and returns a count of how ++ * much entropy (in bits) is needed to sustain the pool. ++ * + * All of these routines try to estimate how many bits of randomness a + * particular randomness source. They do this by keeping track of the + * first and second order deltas of the event timings. +@@ -938,6 +948,63 @@ void add_disk_randomness(struct gendisk + EXPORT_SYMBOL_GPL(add_disk_randomness); + #endif + ++/* ++ * random_input_words - add bulk entropy to pool ++ * ++ * @buf: buffer to add ++ * @wordcount: number of __u32 words to add ++ * @ent_count: total amount of entropy (in bits) to credit ++ * ++ * this provides bulk input of entropy to the input pool ++ * ++ */ ++void random_input_words(__u32 *buf, size_t wordcount, int ent_count) ++{ ++ mix_pool_bytes(&input_pool, buf, wordcount*4); ++ ++ credit_entropy_bits(&input_pool, ent_count); ++ ++ pr_notice("crediting %d bits => %d\n", ++ ent_count, input_pool.entropy_count); ++ /* ++ * Wake up waiting processes if we have enough ++ * entropy. ++ */ ++ if (input_pool.entropy_count >= random_read_wakeup_bits) ++ wake_up_interruptible(&random_read_wait); ++} ++EXPORT_SYMBOL(random_input_words); ++ ++/* ++ * random_input_wait - wait until random needs entropy ++ * ++ * this function sleeps until the /dev/random subsystem actually ++ * needs more entropy, and then return the amount of entropy ++ * that it would be nice to have added to the system. ++ */ ++int random_input_wait(void) ++{ ++ int count; ++ ++ wait_event_interruptible(random_write_wait, ++ input_pool.entropy_count < random_write_wakeup_bits); ++ ++ count = random_write_wakeup_bits - input_pool.entropy_count; ++ ++ /* likely we got woken up due to a signal */ ++ if (count <= 0) count = random_read_wakeup_bits; ++ ++ pr_notice("requesting %d bits from input_wait()er %d<%d\n", ++ count, ++ input_pool.entropy_count, random_write_wakeup_bits); ++ ++ return count; ++} ++EXPORT_SYMBOL(random_input_wait); ++ ++ ++#define EXTRACT_SIZE 10 ++ + /********************************************************************* + * + * Entropy extraction routines +--- a/fs/fcntl.c ++++ b/fs/fcntl.c +@@ -140,6 +140,7 @@ pid_t f_getown(struct file *filp) + read_unlock(&filp->f_owner.lock); + return pid; + } ++EXPORT_SYMBOL(sys_dup); + + static int f_setown_ex(struct file *filp, unsigned long arg) + { +--- a/include/linux/miscdevice.h ++++ b/include/linux/miscdevice.h +@@ -19,6 +19,7 @@ + #define APOLLO_MOUSE_MINOR 7 /* unused */ + #define PC110PAD_MINOR 9 /* unused */ + /*#define ADB_MOUSE_MINOR 10 FIXME OBSOLETE */ ++#define CRYPTODEV_MINOR 70 /* /dev/crypto */ + #define WATCHDOG_MINOR 130 /* Watchdog timer */ + #define TEMP_MINOR 131 /* Temperature Sensor */ + #define RTC_MINOR 135 +--- a/include/uapi/linux/random.h ++++ b/include/uapi/linux/random.h +@@ -34,6 +34,30 @@ + /* Clear the entropy pool and associated counters. (Superuser only.) */ + #define RNDCLEARPOOL _IO( 'R', 0x06 ) + ++#ifdef CONFIG_FIPS_RNG ++ ++/* Size of seed value - equal to AES blocksize */ ++#define AES_BLOCK_SIZE_BYTES 16 ++#define SEED_SIZE_BYTES AES_BLOCK_SIZE_BYTES ++/* Size of AES key */ ++#define KEY_SIZE_BYTES 16 ++ ++/* ioctl() structure used by FIPS 140-2 Tests */ ++struct rand_fips_test { ++ unsigned char key[KEY_SIZE_BYTES]; /* Input */ ++ unsigned char datetime[SEED_SIZE_BYTES]; /* Input */ ++ unsigned char seed[SEED_SIZE_BYTES]; /* Input */ ++ unsigned char result[SEED_SIZE_BYTES]; /* Output */ ++}; ++ ++/* FIPS 140-2 RNG Variable Seed Test. (Superuser only.) */ ++#define RNDFIPSVST _IOWR('R', 0x10, struct rand_fips_test) ++ ++/* FIPS 140-2 RNG Monte Carlo Test. (Superuser only.) */ ++#define RNDFIPSMCT _IOWR('R', 0x11, struct rand_fips_test) ++ ++#endif /* #ifdef CONFIG_FIPS_RNG */ ++ + struct rand_pool_info { + int entropy_count; + int buf_size; +--- a/include/linux/random.h ++++ b/include/linux/random.h +@@ -13,6 +13,10 @@ extern void add_input_randomness(unsigne + unsigned int value); + extern void add_interrupt_randomness(int irq, int irq_flags); + ++extern void random_input_words(__u32 *buf, size_t wordcount, int ent_count); ++extern int random_input_wait(void); ++#define HAS_RANDOM_INPUT_WAIT 1 ++ + extern void get_random_bytes(void *buf, int nbytes); + extern void get_random_bytes_arch(void *buf, int nbytes); + void generate_random_uuid(unsigned char uuid_out[16]); +--- a/kernel/pid.c ++++ b/kernel/pid.c +@@ -431,6 +431,7 @@ void transfer_pid(struct task_struct *ol + new->pids[type].pid = old->pids[type].pid; + hlist_replace_rcu(&old->pids[type].node, &new->pids[type].node); + } ++EXPORT_SYMBOL(find_task_by_vpid); + + struct task_struct *pid_task(struct pid *pid, enum pid_type type) + { diff --git a/target/linux/generic/patches-4.1/960-decompress_unlzo_fix.patch b/target/linux/generic/patches-4.1/960-decompress_unlzo_fix.patch new file mode 100644 index 0000000..ee7c118 --- /dev/null +++ b/target/linux/generic/patches-4.1/960-decompress_unlzo_fix.patch @@ -0,0 +1,23 @@ +--- /dev/null ++++ b/include/linux/decompress/unlzo_mm.h +@@ -0,0 +1,10 @@ ++#ifndef UNLZO_MM_H ++#define UNLZO_MM_H ++ ++#ifdef STATIC ++#define INIT ++#else ++#define INIT __init ++#endif ++ ++#endif +--- a/lib/decompress_unlzo.c ++++ b/lib/decompress_unlzo.c +@@ -38,6 +38,7 @@ + + #include + #include ++#include + #include + + #include diff --git a/target/linux/generic/patches-4.1/970-remove-unsane-filenames-from-deps_initramfs-list.patch b/target/linux/generic/patches-4.1/970-remove-unsane-filenames-from-deps_initramfs-list.patch new file mode 100644 index 0000000..ac13c9e --- /dev/null +++ b/target/linux/generic/patches-4.1/970-remove-unsane-filenames-from-deps_initramfs-list.patch @@ -0,0 +1,29 @@ +--- a/usr/Makefile ++++ b/usr/Makefile +@@ -53,6 +53,8 @@ ifneq ($(wildcard $(obj)/.initramfs_data + include $(obj)/.initramfs_data.cpio.d + endif + ++deps_initramfs_sane := $(foreach v,$(deps_initramfs),$(if $(findstring :,$(v)),,$(v))) ++ + quiet_cmd_initfs = GEN $@ + cmd_initfs = $(initramfs) -o $@ $(ramfs-args) $(ramfs-input) + +@@ -61,14 +63,14 @@ targets := initramfs_data.cpio.gz initra + initramfs_data.cpio.lzo initramfs_data.cpio.lz4 \ + initramfs_data.cpio + # do not try to update files included in initramfs +-$(deps_initramfs): ; ++$(deps_initramfs_sane): ; + +-$(deps_initramfs): klibcdirs ++$(deps_initramfs_sane): klibcdirs + # We rebuild initramfs_data.cpio if: + # 1) Any included file is newer then initramfs_data.cpio + # 2) There are changes in which files are included (added or deleted) + # 3) If gen_init_cpio are newer than initramfs_data.cpio + # 4) arguments to gen_initramfs.sh changes +-$(obj)/initramfs_data.cpio$(suffix_y): $(obj)/gen_init_cpio $(deps_initramfs) klibcdirs ++$(obj)/initramfs_data.cpio$(suffix_y): $(obj)/gen_init_cpio $(deps_initramfs_sane) klibcdirs + $(Q)$(initramfs) -l $(ramfs-input) > $(obj)/.initramfs_data.cpio.d + $(call if_changed,initfs) diff --git a/target/linux/generic/patches-4.1/980-arm_openwrt_machtypes.patch b/target/linux/generic/patches-4.1/980-arm_openwrt_machtypes.patch new file mode 100644 index 0000000..60ca07e --- /dev/null +++ b/target/linux/generic/patches-4.1/980-arm_openwrt_machtypes.patch @@ -0,0 +1,32 @@ +--- a/arch/arm/tools/mach-types ++++ b/arch/arm/tools/mach-types +@@ -1006,3 +1006,29 @@ eco5_bx2 MACH_ECO5_BX2 ECO5_BX2 4572 + eukrea_cpuimx28sd MACH_EUKREA_CPUIMX28SD EUKREA_CPUIMX28SD 4573 + domotab MACH_DOMOTAB DOMOTAB 4574 + pfla03 MACH_PFLA03 PFLA03 4575 ++# ++# Additional mach-types supported by OpenWrt ++# ++wg302v1 MACH_WG302V1 WG302V1 889 ++pronghorn MACH_PRONGHORN PRONGHORN 928 ++pronghorn_metro MACH_PRONGHORNMETRO PRONGHORNMETRO 1040 ++sidewinder MACH_SIDEWINDER SIDEWINDER 1041 ++wrt300nv2 MACH_WRT300NV2 WRT300NV2 1077 ++compex42x MACH_COMPEXWP18 COMPEXWP18 1273 ++goldfish MACH_GOLDFISH GOLDFISH 1441 ++cambria MACH_CAMBRIA CAMBRIA 1468 ++dt2 MACH_DT2 DT2 1514 ++ap1000 MACH_AP1000 AP1000 1543 ++tw2662 MACH_TW2662 TW2662 1658 ++tw5334 MACH_TW5334 TW5334 1664 ++usr8200 MACH_USR8200 USR8200 1762 ++mi424wr MACH_MI424WR MI424WR 1778 ++gw2388 MACH_GW2388 GW2388 2635 ++iconnect MACH_ICONNECT ICONNECT 2870 ++nsb3ast MACH_NSB3AST NSB3AST 2917 ++goflexnet MACH_GOFLEXNET GOFLEXNET 3089 ++nas6210 MACH_NAS6210 NAS6210 3104 ++ns_k330 MACH_NS_K330 NS_K330 3108 ++bcm2708 MACH_BCM2708 BCM2708 3138 ++wn802t MACH_WN802T WN802T 3306 ++nsa310 MACH_NSA310 NSA310 4022 diff --git a/target/linux/generic/patches-4.1/990-gpio_wdt.patch b/target/linux/generic/patches-4.1/990-gpio_wdt.patch new file mode 100644 index 0000000..9f5e7fa --- /dev/null +++ b/target/linux/generic/patches-4.1/990-gpio_wdt.patch @@ -0,0 +1,360 @@ +This generic GPIO watchdog is used on Huawei E970 (brcm47xx) + +Signed-off-by: Mathias Adam + +--- a/drivers/watchdog/Kconfig ++++ b/drivers/watchdog/Kconfig +@@ -1150,6 +1150,15 @@ config WDT_MTX1 + Hardware driver for the MTX-1 boards. This is a watchdog timer that + will reboot the machine after a 100 seconds timer expired. + ++config GPIO_WDT ++ tristate "GPIO Hardware Watchdog" ++ help ++ Hardware driver for GPIO-controlled watchdogs. GPIO pin and ++ toggle interval settings are platform-specific. The driver ++ will stop toggling the GPIO (i.e. machine reboots) after a ++ 100 second timer expired and no process has written to ++ /dev/watchdog during that time. ++ + config PNX833X_WDT + tristate "PNX833x Hardware Watchdog" + depends on SOC_PNX8335 +--- a/drivers/watchdog/Makefile ++++ b/drivers/watchdog/Makefile +@@ -135,6 +135,7 @@ obj-$(CONFIG_RC32434_WDT) += rc32434_wdt + obj-$(CONFIG_INDYDOG) += indydog.o + obj-$(CONFIG_JZ4740_WDT) += jz4740_wdt.o + obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o ++obj-$(CONFIG_GPIO_WDT) += old_gpio_wdt.o + obj-$(CONFIG_PNX833X_WDT) += pnx833x_wdt.o + obj-$(CONFIG_SIBYTE_WDOG) += sb_wdog.o + obj-$(CONFIG_AR7_WDT) += ar7_wdt.o +--- /dev/null ++++ b/drivers/watchdog/old_gpio_wdt.c +@@ -0,0 +1,301 @@ ++/* ++ * Driver for GPIO-controlled Hardware Watchdogs. ++ * ++ * Copyright (C) 2013 Mathias Adam ++ * ++ * Replaces mtx1_wdt (driver for the MTX-1 Watchdog): ++ * ++ * (C) Copyright 2005 4G Systems , ++ * All Rights Reserved. ++ * http://www.4g-systems.biz ++ * ++ * (C) Copyright 2007 OpenWrt.org, Florian Fainelli ++ * ++ * 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. ++ * ++ * Neither Michael Stickel nor 4G Systems admit liability nor provide ++ * warranty for any of this software. This material is provided ++ * "AS-IS" and at no charge. ++ * ++ * (c) Copyright 2005 4G Systems ++ * ++ * Release 0.01. ++ * Author: Michael Stickel michael.stickel@4g-systems.biz ++ * ++ * Release 0.02. ++ * Author: Florian Fainelli florian@openwrt.org ++ * use the Linux watchdog/timer APIs ++ * ++ * Release 0.03. ++ * Author: Mathias Adam ++ * make it a generic gpio watchdog driver ++ * ++ * The Watchdog is configured to reset the MTX-1 ++ * if it is not triggered for 100 seconds. ++ * It should not be triggered more often than 1.6 seconds. ++ * ++ * A timer triggers the watchdog every 5 seconds, until ++ * it is opened for the first time. After the first open ++ * it MUST be triggered every 2..95 seconds. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static int ticks = 100 * HZ; ++ ++static struct { ++ struct completion stop; ++ spinlock_t lock; ++ int running; ++ struct timer_list timer; ++ int queue; ++ int default_ticks; ++ unsigned long inuse; ++ unsigned gpio; ++ unsigned int gstate; ++ int interval; ++ int first_interval; ++} gpio_wdt_device; ++ ++static void gpio_wdt_trigger(unsigned long unused) ++{ ++ spin_lock(&gpio_wdt_device.lock); ++ if (gpio_wdt_device.running && ticks > 0) ++ ticks -= gpio_wdt_device.interval; ++ ++ /* toggle wdt gpio */ ++ gpio_wdt_device.gstate = !gpio_wdt_device.gstate; ++ gpio_set_value(gpio_wdt_device.gpio, gpio_wdt_device.gstate); ++ ++ if (gpio_wdt_device.queue && ticks > 0) ++ mod_timer(&gpio_wdt_device.timer, jiffies + gpio_wdt_device.interval); ++ else ++ complete(&gpio_wdt_device.stop); ++ spin_unlock(&gpio_wdt_device.lock); ++} ++ ++static void gpio_wdt_reset(void) ++{ ++ ticks = gpio_wdt_device.default_ticks; ++} ++ ++ ++static void gpio_wdt_start(void) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&gpio_wdt_device.lock, flags); ++ if (!gpio_wdt_device.queue) { ++ gpio_wdt_device.queue = 1; ++ gpio_wdt_device.gstate = 1; ++ gpio_set_value(gpio_wdt_device.gpio, 1); ++ mod_timer(&gpio_wdt_device.timer, jiffies + gpio_wdt_device.first_interval); ++ } ++ gpio_wdt_device.running++; ++ spin_unlock_irqrestore(&gpio_wdt_device.lock, flags); ++} ++ ++static int gpio_wdt_stop(void) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&gpio_wdt_device.lock, flags); ++ if (gpio_wdt_device.queue) { ++ gpio_wdt_device.queue = 0; ++ gpio_wdt_device.gstate = 0; ++ gpio_set_value(gpio_wdt_device.gpio, 0); ++ } ++ ticks = gpio_wdt_device.default_ticks; ++ spin_unlock_irqrestore(&gpio_wdt_device.lock, flags); ++ return 0; ++} ++ ++/* Filesystem functions */ ++ ++static int gpio_wdt_open(struct inode *inode, struct file *file) ++{ ++ if (test_and_set_bit(0, &gpio_wdt_device.inuse)) ++ return -EBUSY; ++ return nonseekable_open(inode, file); ++} ++ ++ ++static int gpio_wdt_release(struct inode *inode, struct file *file) ++{ ++ clear_bit(0, &gpio_wdt_device.inuse); ++ return 0; ++} ++ ++static long gpio_wdt_ioctl(struct file *file, unsigned int cmd, ++ unsigned long arg) ++{ ++ void __user *argp = (void __user *)arg; ++ int __user *p = (int __user *)argp; ++ unsigned int value; ++ static const struct watchdog_info ident = { ++ .options = WDIOF_CARDRESET, ++ .identity = "GPIO WDT", ++ }; ++ ++ switch (cmd) { ++ case WDIOC_GETSUPPORT: ++ if (copy_to_user(argp, &ident, sizeof(ident))) ++ return -EFAULT; ++ break; ++ case WDIOC_GETSTATUS: ++ case WDIOC_GETBOOTSTATUS: ++ put_user(0, p); ++ break; ++ case WDIOC_SETOPTIONS: ++ if (get_user(value, p)) ++ return -EFAULT; ++ if (value & WDIOS_ENABLECARD) ++ gpio_wdt_start(); ++ else if (value & WDIOS_DISABLECARD) ++ gpio_wdt_stop(); ++ else ++ return -EINVAL; ++ return 0; ++ case WDIOC_KEEPALIVE: ++ gpio_wdt_reset(); ++ break; ++ default: ++ return -ENOTTY; ++ } ++ return 0; ++} ++ ++ ++static ssize_t gpio_wdt_write(struct file *file, const char *buf, ++ size_t count, loff_t *ppos) ++{ ++ if (!count) ++ return -EIO; ++ gpio_wdt_reset(); ++ return count; ++} ++ ++static const struct file_operations gpio_wdt_fops = { ++ .owner = THIS_MODULE, ++ .llseek = no_llseek, ++ .unlocked_ioctl = gpio_wdt_ioctl, ++ .open = gpio_wdt_open, ++ .write = gpio_wdt_write, ++ .release = gpio_wdt_release, ++}; ++ ++ ++static struct miscdevice gpio_wdt_misc = { ++ .minor = WATCHDOG_MINOR, ++ .name = "watchdog", ++ .fops = &gpio_wdt_fops, ++}; ++ ++ ++static int gpio_wdt_probe(struct platform_device *pdev) ++{ ++ int ret; ++ struct gpio_wdt_platform_data *gpio_wdt_data = pdev->dev.platform_data; ++ ++ gpio_wdt_device.gpio = gpio_wdt_data->gpio; ++ gpio_wdt_device.interval = gpio_wdt_data->interval; ++ gpio_wdt_device.first_interval = gpio_wdt_data->first_interval; ++ if (gpio_wdt_device.first_interval <= 0) { ++ gpio_wdt_device.first_interval = gpio_wdt_device.interval; ++ } ++ ++ ret = gpio_request(gpio_wdt_device.gpio, "gpio-wdt"); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "failed to request gpio"); ++ return ret; ++ } ++ ++ spin_lock_init(&gpio_wdt_device.lock); ++ init_completion(&gpio_wdt_device.stop); ++ gpio_wdt_device.queue = 0; ++ clear_bit(0, &gpio_wdt_device.inuse); ++ setup_timer(&gpio_wdt_device.timer, gpio_wdt_trigger, 0L); ++ gpio_wdt_device.default_ticks = ticks; ++ ++ gpio_wdt_start(); ++ dev_info(&pdev->dev, "GPIO Hardware Watchdog driver (gpio=%i interval=%i/%i)\n", ++ gpio_wdt_data->gpio, gpio_wdt_data->first_interval, gpio_wdt_data->interval); ++ return 0; ++} ++ ++static int gpio_wdt_remove(struct platform_device *pdev) ++{ ++ /* FIXME: do we need to lock this test ? */ ++ if (gpio_wdt_device.queue) { ++ gpio_wdt_device.queue = 0; ++ wait_for_completion(&gpio_wdt_device.stop); ++ } ++ ++ gpio_free(gpio_wdt_device.gpio); ++ misc_deregister(&gpio_wdt_misc); ++ return 0; ++} ++ ++static struct platform_driver gpio_wdt_driver = { ++ .probe = gpio_wdt_probe, ++ .remove = gpio_wdt_remove, ++ .driver.name = "gpio-wdt", ++ .driver.owner = THIS_MODULE, ++}; ++ ++static int __init gpio_wdt_init(void) ++{ ++ return platform_driver_register(&gpio_wdt_driver); ++} ++arch_initcall(gpio_wdt_init); ++ ++/* ++ * We do wdt initialization in two steps: arch_initcall probes the wdt ++ * very early to start pinging the watchdog (misc devices are not yet ++ * available), and later module_init() just registers the misc device. ++ */ ++static int gpio_wdt_init_late(void) ++{ ++ int ret; ++ ++ ret = misc_register(&gpio_wdt_misc); ++ if (ret < 0) { ++ pr_err("GPIO_WDT: failed to register misc device\n"); ++ return ret; ++ } ++ return 0; ++} ++#ifndef MODULE ++module_init(gpio_wdt_init_late); ++#endif ++ ++static void __exit gpio_wdt_exit(void) ++{ ++ platform_driver_unregister(&gpio_wdt_driver); ++} ++module_exit(gpio_wdt_exit); ++ ++MODULE_AUTHOR("Michael Stickel, Florian Fainelli, Mathias Adam"); ++MODULE_DESCRIPTION("Driver for GPIO hardware watchdogs"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); ++MODULE_ALIAS("platform:gpio-wdt"); +--- /dev/null ++++ b/include/linux/old_gpio_wdt.h +@@ -0,0 +1,21 @@ ++/* ++ * Definitions for the GPIO watchdog driver ++ * ++ * Copyright (C) 2013 Mathias Adam ++ * ++ * 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. ++ * ++ */ ++ ++#ifndef _GPIO_WDT_H_ ++#define _GPIO_WDT_H_ ++ ++struct gpio_wdt_platform_data { ++ int gpio; /* GPIO line number */ ++ int interval; /* watchdog reset interval in system ticks */ ++ int first_interval; /* first wd reset interval in system ticks */ ++}; ++ ++#endif /* _GPIO_WDT_H_ */ diff --git a/target/linux/generic/patches-4.1/995-mangle_bootargs.patch b/target/linux/generic/patches-4.1/995-mangle_bootargs.patch new file mode 100644 index 0000000..1062a69 --- /dev/null +++ b/target/linux/generic/patches-4.1/995-mangle_bootargs.patch @@ -0,0 +1,58 @@ +--- a/init/main.c ++++ b/init/main.c +@@ -352,6 +352,29 @@ static inline void setup_nr_cpu_ids(void + static inline void smp_prepare_cpus(unsigned int maxcpus) { } + #endif + ++#ifdef CONFIG_MANGLE_BOOTARGS ++static void __init mangle_bootargs(char *command_line) ++{ ++ char *rootdev; ++ char *rootfs; ++ ++ rootdev = strstr(command_line, "root=/dev/mtdblock"); ++ ++ if (rootdev) ++ strncpy(rootdev, "mangled_rootblock=", 18); ++ ++ rootfs = strstr(command_line, "rootfstype"); ++ ++ if (rootfs) ++ strncpy(rootfs, "mangled_fs", 10); ++ ++} ++#else ++static void __init mangle_bootargs(char *command_line) ++{ ++} ++#endif ++ + /* + * We need to store the untouched command line for future reference. + * We also need to store the touched command line since the parameter +@@ -522,6 +545,7 @@ asmlinkage __visible void __init start_k + pr_notice("%s", linux_banner); + setup_arch(&command_line); + mm_init_cpumask(&init_mm); ++ mangle_bootargs(command_line); + setup_command_line(command_line); + setup_nr_cpu_ids(); + setup_per_cpu_areas(); +--- a/init/Kconfig ++++ b/init/Kconfig +@@ -1607,6 +1607,15 @@ config EMBEDDED + an embedded system so certain expert options are available + for configuration. + ++config MANGLE_BOOTARGS ++ bool "Rename offending bootargs" ++ depends on EXPERT ++ help ++ Sometimes the bootloader passed bogus root= and rootfstype= ++ parameters to the kernel, and while you want to ignore them, ++ you need to know the values f.e. to support dual firmware ++ layouts on the flash. ++ + config HAVE_PERF_EVENTS + bool + help diff --git a/target/linux/generic/patches-4.1/997-device_tree_cmdline.patch b/target/linux/generic/patches-4.1/997-device_tree_cmdline.patch new file mode 100644 index 0000000..076cb6d --- /dev/null +++ b/target/linux/generic/patches-4.1/997-device_tree_cmdline.patch @@ -0,0 +1,24 @@ +--- a/drivers/of/fdt.c ++++ b/drivers/of/fdt.c +@@ -935,6 +935,9 @@ int __init early_init_dt_scan_chosen(uns + p = of_get_flat_dt_prop(node, "bootargs", &l); + if (p != NULL && l > 0) + strlcpy(data, p, min((int)l, COMMAND_LINE_SIZE)); ++ p = of_get_flat_dt_prop(node, "bootargs-append", &l); ++ if (p != NULL && l > 0) ++ strlcat(data, p, min_t(int, strlen(data) + (int)l, COMMAND_LINE_SIZE)); + + /* + * CONFIG_CMDLINE is meant to be a default in case nothing else +--- a/arch/mips/kernel/prom.c ++++ b/arch/mips/kernel/prom.c +@@ -50,6 +50,9 @@ void * __init early_init_dt_alloc_memory + + void __init __dt_setup_arch(void *bph) + { ++ if (boot_command_line[0] == '\0') ++ strcpy(boot_command_line, arcs_cmdline); ++ + if (!early_init_dt_scan(bph)) + return; + diff --git a/target/linux/generic/patches-4.1/998-enable_wilink_platform_without_drivers.patch b/target/linux/generic/patches-4.1/998-enable_wilink_platform_without_drivers.patch new file mode 100644 index 0000000..d317de1 --- /dev/null +++ b/target/linux/generic/patches-4.1/998-enable_wilink_platform_without_drivers.patch @@ -0,0 +1,15 @@ +We use backports for driver updates - make sure we can compile in the glue code regardless + +Signed-off-by: Imre Kaloz + +--- a/drivers/net/wireless/ti/Kconfig ++++ b/drivers/net/wireless/ti/Kconfig +@@ -15,7 +15,7 @@ source "drivers/net/wireless/ti/wlcore/K + + config WILINK_PLATFORM_DATA + bool "TI WiLink platform data" +- depends on WLCORE_SDIO || WL1251_SDIO ++ depends on WLCORE_SDIO || WL1251_SDIO || ARCH_OMAP2PLUS + default y + ---help--- + Small platform data bit needed to pass data to the sdio modules. -- cgit v1.2.3